public void LoadXml(string filename) { var srl = new NomadXmlSerializer(); NomadObject root = null; using (var fs = File.Open(filename, FileMode.Open)) { root = srl.Deserialize(fs); } Version = int.Parse(root.GetAttributeValue("Version")); MoveCount = int.Parse(root.GetAttributeValue("Count")); var resources = new List <MoveResourceData>(); var infos = new List <MoveResourceInfo>(); var size = 0; foreach (var child in root.Children) { var resource = new MoveResourceData(); resource.Deserialize(child); resources.Add(resource); var info = resource.GetInfo(); infos.Add(info); size += info.Size; } var buffer = new byte[size]; var offset = 0; for (int i = 0; i < resources.Count; i++) { var resource = resources[i]; var info = infos[i]; foreach (var param in resource.AllParams) { var globalParam = AllParams.First((p) => p.Name == param.Name); globalParam.Values.AddRange(param.Values); foreach (var fixup in param.Fixups) { var fixupInfo = new FixupInfo(fixup.Hash, fixup.Offset + offset); globalParam.Fixups.Add(fixupInfo); } } Buffer.BlockCopy(resource.MoveData, 0, buffer, offset, info.Size); offset += info.Size; } PerMoveResourceInfo.Infos = infos; MoveData = buffer; }
void ReadFixups(NomadObject obj) { var offsetsAttr = obj.GetAttribute("offsetsArray"); var hashesAttr = obj.GetAttribute("hashesArray"); if ((offsetsAttr != null) && (hashesAttr != null)) { var offsets = Utils.UnpackArray(offsetsAttr, BitConverter.ToInt32, 4, out int nOffsets); var hashes = Utils.UnpackArray(hashesAttr, BitConverter.ToInt32, 4, out int nHashes); if (nOffsets != nHashes) { throw new InvalidDataException("Yikes!"); } // doesn't matter which one we use // but we'll be verbose anyways :) var count = (nOffsets & nHashes); Fixups = new List <FixupInfo>(count); for (int i = 0; i < count; i++) { var offset = offsets[i]; var hash = hashes[i]; var fixup = new FixupInfo(hash, offset); Fixups.Add(fixup); } } else { foreach (var child in obj.Children) { if (child.Id != "FIXUP") { throw new InvalidDataException($"Expected a FIXUP but got '{child.Id}' instead."); } var fixup = ParseFixup(child); Fixups.Add(fixup); } } }
public void SaveXml(string filename) { var xml = new XDocument(); var root = new XElement("CombinedMoveFile"); root.SetAttributeValue("Version", 1); root.SetAttributeValue("Count", MoveCount); var srl = new NomadXmlSerializer(); //foreach (var child in Root.Children) // srl.CreateXmlElement(child, root); var fixups = new List <(int offset, int hash, string param)>(); foreach (var param in AllParams) { foreach (var fixup in param.Fixups) { fixups.Add((fixup.Offset, fixup.Hash, param.Name)); } } fixups = fixups.OrderBy((e) => e.offset).ToList(); var resources = new List <MoveResourceData>(); var offset = 0; foreach (var info in PerMoveResourceInfo.Infos) { var hash = BitConverter.ToInt32(MoveData, offset); var bound = (offset + info.Size); var resource = new MoveResourceData(); var hashes = new List <int>(); foreach (var fixup in fixups.Where((e) => e.offset > offset)) { if (fixup.offset > bound) { break; } var param = resource.AllParams.First((m) => m.Name == fixup.param); var globalParam = AllParams.First((m) => m.Name == fixup.param); var fixupInfo = new FixupInfo(fixup.hash, fixup.offset - offset); param.Fixups.Add(fixupInfo); // add value once if (!hashes.Contains(fixup.hash)) { hashes.Add(fixup.hash); foreach (var value in globalParam.Values) { var hashAttr = value.GetAttribute("hash"); var hashData = hashAttr.Data; int paramHash = 0; // HACKS!!!!! if (hashData.Size < 4) { if (hashData.Size == 1) { paramHash = (sbyte)hashData.Buffer[0]; } else { paramHash = Utils.UnpackData(hashAttr, BitConverter.ToInt16); } } else { paramHash = Utils.UnpackData(hashAttr, BitConverter.ToInt32); } if (paramHash == fixup.hash) { param.Values.Add(value); break; } } } } var buffer = new byte[info.Size]; Buffer.BlockCopy(MoveData, offset, buffer, 0, info.Size); resource.RootNodeId = info.RootNodeId; resource.MoveData = buffer; resources.Add(resource); offset += info.Size; } foreach (var resource in resources) { srl.CreateXmlElement(resource.ToObject(), root); } #if PATCH_FIXUP_TAGS var buffer = new byte[MoveData.Length]; Buffer.BlockCopy(MoveData, 0, buffer, 0, buffer.Length); foreach (var param in AllParams) { if (param.Tag == "xxxx") { continue; } MagicNumber mgx = param.Tag; var tag = BitConverter.GetBytes((int)mgx); foreach (var fixup in param.Fixups) { Buffer.BlockCopy(tag, 0, buffer, fixup.Offset, tag.Length); } } File.WriteAllBytes(Path.ChangeExtension(filename, ".tags.bin"), buffer); #endif #if DUMP_FIXUP_LOG_INFO var dbg = new List <(int offset, string name, int old, int hash)>(); var sb = new StringBuilder(); foreach (var param in AllParams) { var idx = 0; foreach (var fixup in param.Fixups) { var orig = BitConverter.ToInt32(MoveData, fixup.Offset); dbg.Add((fixup.Offset, $"{param.Name} fixup {idx++}", orig, fixup.Hash)); } } var fixups = dbg.OrderBy((e) => e.offset).ToList(); var infoOffset = 0; var infoIndex = 0; var rootDir = Path.GetDirectoryName(filename); var outDir = Path.Combine(rootDir, "movedata_files"); if (!Directory.Exists(outDir)) { Directory.CreateDirectory(outDir); } foreach (var info in PerMoveResourceInfo.Infos) { var hash = BitConverter.ToInt32(MoveData, infoOffset); var unk_04 = BitConverter.ToInt32(MoveData, infoOffset + 4); var unk_08 = MoveData[infoOffset + 8]; var unk_09 = MoveData[infoOffset + 9]; var unk_0a = MoveData[infoOffset + 10]; var unk_0b = MoveData[infoOffset + 11]; sb.AppendLine($"MoveData({hash:X8})[{infoIndex++}] @ {infoOffset:X8}"); sb.AppendLine($" Unk_04: {unk_04}"); sb.AppendLine($" Unk_08: ({unk_08}, {unk_09}, {unk_0a}, {unk_0b})"); sb.AppendLine($" RootNodeId: {info.RootNodeId:X8}"); var upperBound = (infoOffset + info.Size); var fixupOffset = infoOffset; foreach (var fixup in fixups.Where((e) => e.offset < upperBound)) { if (fixup.offset < infoOffset) { continue; } sb.AppendLine($" - {fixup.offset - infoOffset:X8}: {fixup.old:X8} -> {fixup.hash:X8} ; {fixup.name}"); } var buffer = new byte[info.Size]; Buffer.BlockCopy(MoveData, infoOffset, buffer, 0, info.Size); File.WriteAllBytes(Path.Combine(outDir, $"{unk_08}_{unk_09}_{unk_0a}_{unk_0b}#{hash:X8}.bin"), buffer); infoOffset += info.Size; } //var dbgTxt = String.Join("\r\n", dbg.OrderBy((e) => e.offset).Select((e) => $"{e.offset:X8}: {e.old:X8} -> {e.hash:X8} ; {e.name}")); //sb.Append(dbgTxt); File.WriteAllBytes(Path.ChangeExtension(filename, ".data.bin"), MoveData); File.WriteAllText(Path.ChangeExtension(filename, ".debug.log"), sb.ToString()); #endif xml.Add(root); xml.SaveFormatted(filename, true); }