Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
223 changes: 223 additions & 0 deletions CodeWalker.Core/GameFiles/FileTypes/AudioSectorsFile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
using System;
using System.IO;
using System.Text;
using System.Xml;
using EXP = System.ComponentModel.ExpandableObjectConverter;
using TC = System.ComponentModel.TypeConverterAttribute;

namespace CodeWalker.GameFiles
{
public class AudioWorldSectorsFile : GameFile, PackedFile
{
public byte[] RawFileData { get; set; }

public const int NumSectorsX = 100;
public const int NumSectorsY = 100;
public const int NumSectors = NumSectorsX * NumSectorsY;

[TC(typeof(EXP))]
public struct AudSector
{
public byte numHighwayNodes { get; set; }
public byte tallestBuilding { get; set; }
public byte numBuildings { get; set; }
public byte numTrees { get; set; }
public bool isWaterSector { get; set; }

public override string ToString()
{
return numHighwayNodes.ToString() + ": " + tallestBuilding.ToString() + ": " + numBuildings.ToString() + ": " + numTrees.ToString() + ": " + isWaterSector.ToString();
}
}

public AudSector[] Sectors { get; set; } = new AudSector[NumSectors];
public AudioWorldSectorsFile() : base(null, GameFileType.AudioWorldSectors) { }
public AudioWorldSectorsFile(RpfFileEntry entry) : base(entry, GameFileType.AudioWorldSectors)
{
RpfFileEntry = entry;
}

public void Load(byte[] data, RpfFileEntry entry)
{
RawFileData = data;
if (entry != null)
{
RpfFileEntry = entry;
Name = entry.Name;
}

using (var ms = new MemoryStream(data, false))
{
var r = new DataReader(ms);
Read(r, (int)ms.Length);
}
}

public byte[] Save()
{
using (var s = new MemoryStream())
{
var w = new DataWriter(s);
Write(w);
return s.ToArray();
}
}

private void Read(DataReader r, int dataLength)
{
int expectedBytes = NumSectors * 4;
int toReadBytes = Math.Min(expectedBytes, dataLength);

for (int i = 0; i < NumSectors; i++)
{
if ((i * 4 + 4) > toReadBytes)
{
Sectors[i] = default;
continue;
}

byte numHighwayNodes = r.ReadByte();
byte tallestBuilding = r.ReadByte();
byte numBuildings = r.ReadByte();
byte bitfield = r.ReadByte();

Sectors[i] = new AudSector
{
numHighwayNodes = numHighwayNodes,
tallestBuilding = tallestBuilding,
numBuildings = numBuildings,
numTrees = (byte)(bitfield >> 1),
isWaterSector = (bitfield & 0x1) != 0
};
}
}

private void Write(DataWriter w)
{
for (int i = 0; i < NumSectors; i++)
{
var s = Sectors[i];
byte bitfield = (byte)((s.numTrees << 1) | (s.isWaterSector ? 0x1 : 0x0));

w.Write(s.numHighwayNodes);
w.Write(s.tallestBuilding);
w.Write(s.numBuildings);
w.Write(bitfield);
}
}

public void WriteXml(StringBuilder sb, int indent)
{
AudXml.OpenTag(sb, indent, "Sectors");

for (int y = 0; y < NumSectorsY; y++)
{
for (int x = 0; x < NumSectorsX; x++)
{
int i = y * NumSectorsX + x;
var s = Sectors[i];

AudXml.OpenTag(sb, indent + 1, $"Sector Index=\"{i}\" X=\"{x}\" Y=\"{y}\"");
AudXml.SelfClosingTag(sb, indent + 2, $"HighwayNodes value=\"{s.numHighwayNodes}\"");
AudXml.SelfClosingTag(sb, indent + 2, $"TallestBuilding value=\"{s.tallestBuilding}\"");
AudXml.SelfClosingTag(sb, indent + 2, $"NumBuildings value=\"{s.numBuildings}\"");
AudXml.SelfClosingTag(sb, indent + 2, $"NumTrees value=\"{s.numTrees}\"");
AudXml.SelfClosingTag(sb, indent + 2, $"IsWaterSector value=\"{(s.isWaterSector ? "true" : "false")}\"");
AudXml.CloseTag(sb, indent + 1, "Sector");
}
}
AudXml.CloseTag(sb, indent, "Sectors");
}

public void ReadXml(XmlNode node)
{
var sectorsNode = Xml.GetChild((XmlElement)node, "Sectors");
if (sectorsNode == null) throw new InvalidDataException("Missing <Sectors> node");

var tmp = new AudSector[NumSectors];

foreach (XmlNode sectorNode in sectorsNode.ChildNodes)
{
var se = sectorNode as XmlElement;
if (se == null || se.Name != "Sector")
continue;

int x = -1, y = -1, idx = -1;

var sx = Xml.GetStringAttribute(se, "X");
var sy = Xml.GetStringAttribute(se, "Y");
var sIdx = Xml.GetStringAttribute(se, "Index");

if (!string.IsNullOrEmpty(sx)) int.TryParse(sx, out x);
if (!string.IsNullOrEmpty(sy)) int.TryParse(sy, out y);
if (!string.IsNullOrEmpty(sIdx)) int.TryParse(sIdx, out idx);

if (x < 0 || y < 0)
{
if (idx < 0)
throw new InvalidDataException("Sector missing X/Y and Index");
y = idx / NumSectorsX;
x = idx - (y * NumSectorsX);
}

if ((uint)x >= NumSectorsX || (uint)y >= NumSectorsY)
throw new InvalidDataException($"Sector out of range X={x}, Y={y}");

int i = y * NumSectorsX + x;

byte numHighwayNodes = (byte)Xml.GetChildIntAttribute(se, "HighwayNodes", "value");
byte tallestBuilding = (byte)Xml.GetChildIntAttribute(se, "TallestBuilding", "value");
byte numBuildings = (byte)Xml.GetChildIntAttribute(se, "NumBuildings", "value");
byte numTrees = (byte)Xml.GetChildIntAttribute(se, "NumTrees", "value");
bool isWaterSector = Xml.GetChildBoolAttribute(se, "IsWaterSector", "value");

tmp[i] = new AudSector
{
numHighwayNodes = numHighwayNodes,
tallestBuilding = tallestBuilding,
numBuildings = numBuildings,
numTrees = numTrees,
isWaterSector = isWaterSector
};
}

Sectors = tmp;
}
}
public class AudXml : MetaXmlBase
{
public static string GetXml(AudioWorldSectorsFile awsf)
{
var sb = new StringBuilder();
sb.AppendLine(XmlHeader);

if (awsf != null && awsf.Sectors != null)
{
var name = "AudioWorldSectors";
OpenTag(sb, 0, name);

awsf.WriteXml(sb, 1);

CloseTag(sb, 0, name);
}

return sb.ToString();
}
}
public class XmlAud
{
public static AudioWorldSectorsFile GetAudWorldSectors(string xml)
{
var doc = new XmlDocument();
doc.LoadXml(xml);
return GetAudWorldSectors(doc);
}

public static AudioWorldSectorsFile GetAudWorldSectors(XmlDocument doc)
{
var awsf = new AudioWorldSectorsFile();
awsf.ReadXml(doc.DocumentElement);
return awsf;
}
}
}
1 change: 1 addition & 0 deletions CodeWalker.Core/GameFiles/GameFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ public enum GameFileType : int
Mrf = 29,
DistantLights = 30,
Ypdb = 31,
AudioWorldSectors = 32,
}


Expand Down
13 changes: 13 additions & 0 deletions CodeWalker.Core/GameFiles/MetaTypes/MetaXml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@ public static string GetXml(RpfFileEntry e, byte[] data, out string filename, st
HeightmapFile hmf = RpfFile.GetFile<HeightmapFile>(e, data);
return GetXml(hmf, out filename, outputfolder);
}
else if (fnl.EndsWith(".dat") && fnl.StartsWith("audioworld"))
{
AudioWorldSectorsFile aws = RpfFile.GetFile<AudioWorldSectorsFile>(e, data);
return GetXml(aws, out filename, outputfolder);
}
else if (fnl.EndsWith(".mrf"))
{
MrfFile mrf = RpfFile.GetFile<MrfFile>(e, data);
Expand Down Expand Up @@ -337,6 +342,13 @@ public static string GetXml(MrfFile mrf, out string filename, string outputfolde
return MrfXml.GetXml(mrf);
}

public static string GetXml(AudioWorldSectorsFile aws, out string filename, string outputfolder)
{
var fn = (aws?.Name) ?? "";
filename = fn + ".xml";
return AudXml.GetXml(aws);
}




Expand Down Expand Up @@ -2304,6 +2316,7 @@ public enum MetaFormat
Ypdb = 22,
Mrf = 23,
Yfd = 24,
AudioWorldSectors = 25,
}

}
14 changes: 14 additions & 0 deletions CodeWalker.Core/GameFiles/MetaTypes/XmlMeta.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ public static byte[] GetData(XmlDocument doc, MetaFormat mformat, string fpathin
return GetYfdData(doc);
case MetaFormat.Mrf:
return GetMrfData(doc);
case MetaFormat.AudioWorldSectors:
return GetAudioWorldSectorsData(doc);
}
return null;
}
Expand Down Expand Up @@ -211,6 +213,13 @@ public static byte[] GetMrfData(XmlDocument doc)
return mrf.Save();
}

public static byte[] GetAudioWorldSectorsData(XmlDocument doc)
{
var aws = XmlAud.GetAudWorldSectors(doc);
if (aws.Sectors == null) return null;
return aws.Save();
}


public static string GetXMLFormatName(MetaFormat mformat)
{
Expand All @@ -237,6 +246,7 @@ public static string GetXMLFormatName(MetaFormat mformat)
case MetaFormat.Fxc: return "FXC XML";
case MetaFormat.CacheFile: return "CacheFile XML";
case MetaFormat.Heightmap: return "Heightmap XML";
case MetaFormat.AudioWorldSectors: return "AudioWorldSectorsInfo XML";
case MetaFormat.Ypdb: return "YPDB XML";
case MetaFormat.Mrf: return "MRF XML";
case MetaFormat.Yfd: return "YFD XML";
Expand Down Expand Up @@ -334,6 +344,10 @@ public static MetaFormat GetXMLFormat(string fnamel, out int trimlength)
{
mformat = MetaFormat.Heightmap;
}
if (fnamel.EndsWith(".dat.xml") && fnamel.StartsWith("audioworld"))
{
mformat = MetaFormat.AudioWorldSectors;
}
if (fnamel.EndsWith(".ypdb.xml"))
{
mformat = MetaFormat.Ypdb;
Expand Down
14 changes: 14 additions & 0 deletions CodeWalker/ExploreForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ private void InitFileTypes()

InitSubFileType(".dat", "cache_y.dat", "Cache File", 6, FileTypeAction.ViewCacheDat, true);
InitSubFileType(".dat", "heightmap.dat", "Heightmap", 6, FileTypeAction.ViewHeightmap, true);
InitSubFileType(".dat", "audioworldsectorsinfo.dat", "Audio Sectors", 6, FileTypeAction.ViewAudioWorldSectors, true);
InitSubFileType(".dat", "heightmapheistisland.dat", "Heightmap", 6, FileTypeAction.ViewHeightmap, true);
InitSubFileType(".dat", "distantlights.dat", "Distant Lights", 6, FileTypeAction.ViewDistantLights);
InitSubFileType(".dat", "distantlights_hd.dat", "Distant Lights", 6, FileTypeAction.ViewDistantLights);
Expand Down Expand Up @@ -1560,6 +1561,7 @@ private bool CanViewFile(MainListItem item)
case FileTypeAction.ViewYld:
case FileTypeAction.ViewYfd:
case FileTypeAction.ViewHeightmap:
case FileTypeAction.ViewAudioWorldSectors:
case FileTypeAction.ViewMrf:
case FileTypeAction.ViewDistantLights:
return true;
Expand Down Expand Up @@ -1691,6 +1693,9 @@ private void View(MainListItem item)
case FileTypeAction.ViewHeightmap:
ViewHeightmap(name, path, data, fe);
break;
case FileTypeAction.ViewAudioWorldSectors:
ViewAudioWorldSectors(name, path, data, fe);
break;
case FileTypeAction.ViewMrf:
ViewMrf(name, path, data, fe);
break;
Expand Down Expand Up @@ -1944,6 +1949,14 @@ private void ViewHeightmap(string name, string path, byte[] data, RpfFileEntry e
f.Show();
f.LoadMeta(heightmap);
}

private void ViewAudioWorldSectors(string name, string path, byte[] data, RpfFileEntry e)
{
var audiosectors = RpfFile.GetFile<AudioWorldSectorsFile>(e, data);
MetaForm f = new MetaForm(this);
f.Show();
f.LoadMeta(audiosectors);
}
private void ViewMrf(string name, string path, byte[] data, RpfFileEntry e)
{
var mrf = RpfFile.GetFile<MrfFile>(e, data);
Expand Down Expand Up @@ -4998,6 +5011,7 @@ public enum FileTypeAction
ViewNametable = 25,
ViewDistantLights = 26,
ViewYpdb = 27,
ViewAudioWorldSectors = 28,
}


Expand Down
15 changes: 15 additions & 0 deletions CodeWalker/Forms/MetaForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,21 @@ public void LoadMeta(HeightmapFile heightmap)
metaFormat = MetaFormat.Heightmap;
}
}

public void LoadMeta(AudioWorldSectorsFile audioworldsectors)
{
var fn = ((audioworldsectors?.RpfFileEntry?.Name) ?? "") + ".xml";
Xml = AudXml.GetXml(audioworldsectors);
FileName = fn;
RawPropertyGrid.SelectedObject = audioworldsectors;
rpfFileEntry = audioworldsectors?.RpfFileEntry;
modified = false;
metaFormat = MetaFormat.XML;
if (audioworldsectors?.RpfFileEntry != null)
{
metaFormat = MetaFormat.AudioWorldSectors;
}
}
public void LoadMeta(YpdbFile ypdb)
{
var fn = ((ypdb?.RpfFileEntry?.Name) ?? "") + ".xml";
Expand Down