diff --git a/CodeWalker.Core/GameFiles/FileTypes/MrfFile.cs b/CodeWalker.Core/GameFiles/FileTypes/MrfFile.cs index 882c6ed..7fe55f2 100644 --- a/CodeWalker.Core/GameFiles/FileTypes/MrfFile.cs +++ b/CodeWalker.Core/GameFiles/FileTypes/MrfFile.cs @@ -6,6 +6,399 @@ using EXP = System.ComponentModel.ExpandableObjectConverter; namespace CodeWalker.GameFiles { + [TC(typeof(EXP))] public class MrfFile : GameFile, PackedFile + { + public byte[] RawFileData { get; set; } + public uint Magic { get; set; } = 0x45566F4D; // 'MoVE' + public uint Version { get; set; } = 2; + public uint HeaderUnk1 { get; set; } = 0; + public uint HeaderUnk2 { get; set; } = 0; + public uint HeaderUnk3 { get; set; } = 0; + public uint DataLength { get; set; } + public uint FlagsCount { get; set; } + public uint Unk1_Count { get; set; } + public uint Unk2_Count { get; set; } + public uint Unk3_Count { get; set; } + + public MrfStructHeaderUnk1[] Unk1_Items { get; set; } + public MrfStructHeaderUnk2[] Unk2_Items { get; set; } + public MrfStructHeaderUnk3[] Unk3_Items { get; set; } + public byte[] FlagsItems { get; set; } + + public MrfNode[] AllNodes { get; set; } + public MrfNode RootNode { get; set; } + + public MrfFile() : base(null, GameFileType.Mrf) + { + } + + public MrfFile(RpfFileEntry entry) : base(entry, GameFileType.Mrf) + { + RpfFileEntry = entry; + } + + public void Load(byte[] data, RpfFileEntry entry) + { + RawFileData = data; + if (entry != null) + { + RpfFileEntry = entry; + Name = entry.Name; + } + + using (MemoryStream ms = new MemoryStream(data)) + { + DataReader r = new DataReader(ms, Endianess.LittleEndian); + + Read(r); + }; + } + + public byte[] Save() + { + MemoryStream s = new MemoryStream(); + DataWriter w = new DataWriter(s); + + Write(w); + + var buf = new byte[s.Length]; + s.Position = 0; + s.Read(buf, 0, buf.Length); + return buf; + } + + private void Write(DataWriter w) + { + if (Magic != 0x45566F4D || Version != 2 || HeaderUnk1 != 0 || HeaderUnk2 != 0) + throw new Exception("Failed to write MRF, header is invalid!"); + + w.Write(Magic); + w.Write(Version); + w.Write(HeaderUnk1); + w.Write(HeaderUnk2); + w.Write(HeaderUnk3); + w.Write(DataLength); + w.Write(FlagsCount); + + // Unused in final game + w.Write(Unk1_Count); + + if (Unk1_Count > 0) + { + foreach (var entry in Unk1_Items) + { + w.Write(entry.Size); + w.Write(entry.Bytes); + } + } + + w.Write(Unk2_Count); + + if (Unk2_Count > 0) + { + foreach (var entry in Unk2_Items) + { + w.Write(entry.Unk1); + w.Write(entry.Unk2); + } + } + + w.Write(Unk3_Count); + + if (Unk3_Count > 0) + { + foreach (var entry in Unk3_Items) + { + w.Write(entry.Unk1); + w.Write(entry.Unk2); + } + } + + if (AllNodes != null) + { + foreach (var node in AllNodes) + node.Write(w); + } + + for (int i = 0; i < FlagsCount; i++) + w.Write(FlagsItems[i]); + } + + private void Read(DataReader r) + { + Magic = r.ReadUInt32(); // Should be 'MoVE' + Version = r.ReadUInt32(); // GTA5 = 2, RDR3 = 11 + HeaderUnk1 = r.ReadUInt32(); // Should be 0 + HeaderUnk2 = r.ReadUInt32(); + HeaderUnk3 = r.ReadUInt32(); // Should be 0 + DataLength = r.ReadUInt32(); + FlagsCount = r.ReadUInt32(); + + if (Magic != 0x45566F4D || Version != 2 || HeaderUnk1 != 0 || HeaderUnk2 != 0) + throw new Exception("Failed to read MRF, header is invalid!"); + + // Unused in final game + Unk1_Count = r.ReadUInt32(); + if (Unk1_Count > 0) + { + Unk1_Items = new MrfStructHeaderUnk1[Unk1_Count]; + + for (int i = 0; i < Unk1_Count; i++) + Unk1_Items[i] = new MrfStructHeaderUnk1(r); + } + + Unk2_Count = r.ReadUInt32(); + if (Unk2_Count > 0) + { + Unk2_Items = new MrfStructHeaderUnk2[Unk2_Count]; + + for (int i = 0; i < Unk2_Count; i++) + Unk2_Items[i] = new MrfStructHeaderUnk2(r); + } + + Unk3_Count = r.ReadUInt32(); + if (Unk3_Count > 0) + { + Unk3_Items = new MrfStructHeaderUnk3[Unk3_Count]; + + for (int i = 0; i < Unk3_Count; i++) + Unk3_Items[i] = new MrfStructHeaderUnk3(r); + } + + var nodes = new List(); + + while (true) + { + var index = nodes.Count; + var offset = (int)r.Position; + + var node = ReadNode(r); + + if (node == null) break; + + node.FileIndex = index; + node.FileOffset = offset; + node.FileDataSize = ((int)r.Position) - offset; + + nodes.Add(node); + } + + AllNodes = nodes.ToArray(); + + if (FlagsCount != 0) + { + FlagsItems = new byte[FlagsCount]; + + for (int i = 0; i < FlagsCount; i++) + FlagsItems[i] = r.ReadByte(); + } + + + BuildNodeHierarchy(); + + + if (r.Position != r.Length) + throw new Exception($"Failed to read MRF ({r.Position} / {r.Length})"); + } + + private MrfNode ReadNode(DataReader r) + { + var startPos = r.Position; + var nodeType = (MrfNodeType)r.ReadUInt16(); + r.Position = startPos; + + if (nodeType <= MrfNodeType.None || nodeType >= MrfNodeType.Max) + { + if (r.Position != r.Length)//should only be at EOF + { } + return null; + } + + var node = CreateNode(nodeType); + + node.Read(r); + + return node; + } + + private MrfNode CreateNode(MrfNodeType infoType) + { + switch (infoType) + { + case MrfNodeType.StateMachineClass: + return new MrfNodeStateMachineClass(); + case MrfNodeType.Tail: + return new MrfNodeTail(); + case MrfNodeType.InlinedStateMachine: + return new MrfNodeInlinedStateMachine(); + case MrfNodeType.Unk4: + return new MrfNodeUnk4(); + case MrfNodeType.Blend: + return new MrfNodeBlend(); + case MrfNodeType.AddSubtract: + return new MrfNodeAddSubstract(); + case MrfNodeType.Filter: + return new MrfNodeFilter(); + case MrfNodeType.Unk8: + return new MrfNodeUnk8(); + case MrfNodeType.Frame: + return new MrfNodeFrame(); + case MrfNodeType.Unk10: + return new MrfNodeUnk10(); + case MrfNodeType.BlendN: + return new MrfNodeBlendN(); + case MrfNodeType.Clip: + return new MrfNodeClip(); + case MrfNodeType.Unk17: + return new MrfNodeUnk17(); + case MrfNodeType.Unk18: + return new MrfNodeUnk18(); + case MrfNodeType.Expression: + return new MrfNodeExpression(); + case MrfNodeType.Unk20: + return new MrfNodeUnk20(); + case MrfNodeType.Proxy: + return new MrfNodeProxy(); + case MrfNodeType.AddN: + return new MrfNodeAddN(); + case MrfNodeType.Identity: + return new MrfNodeIdentity(); + case MrfNodeType.Unk24: + return new MrfNodeUnk24(); + case MrfNodeType.Unk25: + return new MrfNodeUnk25(); + case MrfNodeType.MergeN: + return new MrfNodeMergeN(); + case MrfNodeType.State: + return new MrfNodeState(); + case MrfNodeType.Invalid: + return new MrfNodeInvalid(); + case MrfNodeType.Unk29: + return new MrfNodeUnk29(); + case MrfNodeType.SubNetworkClass: + return new MrfNodeSubNetworkClass(); + case MrfNodeType.Unk31: + return new MrfNodeUnk31(); + } + + throw new Exception($"A handler for ({infoType}) mrf node type is not valid"); + } + + + private int BuildNodeHierarchy(MrfNode node = null, int index = 0) + { + if (AllNodes == null) return 0; + if (AllNodes.Length <= index) return 0; + + if (node == null) + { + var rlist = new List(); + for (int i = 0; i < AllNodes.Length; i++) + { + var rnode = AllNodes[i]; + rlist.Add(rnode); + i += BuildNodeHierarchy(rnode, i); + } + + var smlist = new List(); + var imlist = new List(); + var snlist = new List(); + foreach (var n in AllNodes) + { + if (n is MrfNodeStateMachineClass sm) + { + smlist.Add(sm); + if (sm.ChildNodes != null) for (int i = 0; i < sm.ChildNodes.Length; i++) if (sm.ChildNodes[i].NodeIndex != i) + { }//sanity check - don't get here + } + if (n is MrfNodeInlinedStateMachine im) + { + imlist.Add(im); + if (im.ChildNodes != null) for (int i = 0; i < im.ChildNodes.Length; i++) if (im.ChildNodes[i].NodeIndex != i) + { }//sanity check - don't get here + } + if (n is MrfNodeState sn) + { + snlist.Add(sn); + if (sn.ChildNodes != null) for (int i = 0; i < sn.ChildNodes.Length; i++) if (sn.ChildNodes[i].NodeIndex != i) + { }//sanity check - don't get here + } + } + + if (rlist.Count > 0) + { + RootNode = rlist[0]; + } + if (rlist.Count != 1) + { }//sanity check - don't get here + if (AllNodes.Length > 1000) + { } + return 0; + } + + if (node is MrfNodeStateBase snode) + { + var c = 0; + var clist = new List(); + int ccount = snode.StateChildCount; + if (ccount == 0) + { + return 0; + } + for (int i = 0; i <= ccount; i++) + { + if ((i == ccount) && (node is MrfNodeState)) + { break; } + var cind = index + c + i + 1; + if (cind >= AllNodes.Length) + { + if (i != ccount) + { }//don't get here (tried to continue past the end of the array!) + break; + } + var cnode = AllNodes[cind]; + if (cnode is MrfNodeTail) + { + i--; + c++; + if (clist.Count > 0) + { + var prevnode = clist[clist.Count - 1]; + if (prevnode is MrfNodeStateBase sprevnode) + { + if (sprevnode.TailNode != null) + { }//don't get here (tail node was already assigned?!?) + sprevnode.TailNode = cnode; + if (clist.Count == ccount) + { break; }//list is full, don't continue + } + else + { }//don't get here (previous node isn't a state??) + } + else + { }//don't get here (can't have tail without a previous node!) + continue; + } + else if (clist.Count == ccount) + { break; }//this node isn't a tail, but the list is already full, so it must belong to another node + if (cnode.NodeIndex != i) + { break; }//don't get here (node index mismatch!) + clist.Add(cnode); + c += BuildNodeHierarchy(cnode, cind);//recurse... + } + if (clist.Count != ccount) + { }//don't get here (sanity check) + snode.ChildNodes = clist.ToArray(); + return c + clist.Count; + } + + return 0; + } + + } + + + // Unused node indexes by GTAV: 11, 12, 14, 16 // Exist in GTAV but not used in MRFs: 4, 8, 10, 17, 21, 22, 28, 29, 31, 32 public enum MrfNodeType : ushort @@ -784,32 +1177,6 @@ namespace CodeWalker.GameFiles } } - [TC(typeof(EXP))] public class MrfStructStateSignalDataUnk3 : MrfStruct - { - public uint UnkValue { get; } - public uint UnkDefault { get; } - public ulong UnkRange { get; } - - public MrfStructStateSignalDataUnk3(DataReader r) - { - UnkValue = r.ReadUInt32(); - UnkDefault = r.ReadUInt32(); - UnkRange = r.ReadUInt64(); // 2 merged 32 bit values? - } - - public override void Write(DataWriter w) - { - w.Write(UnkValue); - w.Write(UnkDefault); - w.Write(UnkRange); - } - - public override string ToString() - { - return UnkValue.ToString() + " - " + UnkDefault.ToString() + " - " + UnkRange.ToString(); - } - } - [TC(typeof(EXP))] public class MrfStructStateMachineState : MrfStruct { public MetaHash StateName { get; } @@ -833,61 +1200,95 @@ namespace CodeWalker.GameFiles } } - - // FIXME: most likely broken - - [TC(typeof(EXP))] public class MrfStructStateSignalData : MrfStruct + [TC(typeof(EXP))] public class MrfStructStateSignalVariable : MrfStruct { - public uint UnkType { get; } - public uint NameHash { get; } - public uint Unk1 { get; } - public uint Unk2 { get; } - public uint Unk3_Count { get; } - public uint Unk4 { get; } + public float Value { get; }//always 0 - probably float? + public float Default { get; } + public float RangeMin { get; } + public float RangeMax { get; } - public MrfStructStateSignalDataUnk3[] Unk3_Items { get; } - - public MrfStructStateSignalData(DataReader r) + public MrfStructStateSignalVariable(DataReader r) { - UnkType = r.ReadUInt32(); - NameHash = r.ReadUInt32(); - - if (UnkType != 5) - return; - - Unk1 = r.ReadUInt32(); - Unk2 = r.ReadUInt32(); // Default value too? - Unk3_Count = r.ReadUInt32(); - Unk4 = r.ReadUInt32(); - - Unk3_Items = new MrfStructStateSignalDataUnk3[Unk3_Count]; - - for (int i = 0; i < Unk3_Count; i++) - Unk3_Items[i] = new MrfStructStateSignalDataUnk3(r); + Value = r.ReadSingle(); + Default = r.ReadSingle(); + RangeMin = r.ReadSingle(); + RangeMax = r.ReadSingle(); } public override void Write(DataWriter w) { - w.Write(UnkType); - w.Write(NameHash); - - if (UnkType != 5) - return; - - w.Write(Unk1); - w.Write(Unk2); - w.Write(Unk3_Count); - w.Write(Unk4); - - // FIXME: might be broken if changed outside - foreach (var item in Unk3_Items) - item.Write(w); + w.Write(Value); + w.Write(Default); + w.Write(RangeMin); + w.Write(RangeMax); } public override string ToString() { - return UnkType.ToString() + " - " + NameHash.ToString() + " - " + - Unk1.ToString() + " - " + Unk2.ToString() + " - C:" + Unk3_Count.ToString() + " - " + Unk4.ToString(); + return Value.ToString() + " - " + Default.ToString() + " - (" + RangeMin.ToString() + " - " + RangeMax.ToString() + ")"; + } + } + + [TC(typeof(EXP))] public class MrfStructStateSignalData : MrfStruct + { + public uint Type { get; set; } //0, 2, 4, 5 + public uint NameHash { get; set; } //only for Type==2, always 0 otherwise + public uint Unk1 { get; set; } //only for Type==5, always 4 + public float Unk2 { get; set; } //only for Type==5, values: 0.0, 0.95, 0.8, 1.4, 1.8, 2.2, 0.2, 0.5 - maybe min value? always less than Unk3 when nonzero + public float Unk3 { get; set; } //only for Type==5, values: 1.0, 1.4, 1.8, 2.2, 2.95, 0.8, 0.5 - maybe max value? + public uint ItemCount { get; set; } //only for Type==5 + public uint Unk4 { get; set; } //only for Type==5, always 4 + + public MrfStructStateSignalVariable[] Items { get; set; } + + public MrfStructStateSignalData(DataReader r) + { + Type = r.ReadUInt32(); + if (Type == 5) + { + Unk1 = r.ReadUInt32(); + Unk2 = r.ReadSingle(); + Unk3 = r.ReadSingle(); + ItemCount = r.ReadUInt32(); + Unk4 = r.ReadUInt32(); + Items = new MrfStructStateSignalVariable[ItemCount]; + for (int i = 0; i < ItemCount; i++) + { + Items[i] = new MrfStructStateSignalVariable(r); + } + } + else + { + NameHash = r.ReadUInt32(); + } + } + + public override void Write(DataWriter w) + { + w.Write(Type); + if (Type == 5) + { + w.Write(Unk1); + w.Write(Unk2); + w.Write(Unk3); + w.Write(ItemCount); + w.Write(Unk4); + + // FIXME: might be broken if changed outside + foreach (var item in Items) + item.Write(w); + } + else + { + w.Write(NameHash); + } + + } + + public override string ToString() + { + return Type.ToString() + " - " + NameHash.ToString() + " - " + + Unk1.ToString() + " - " + Unk2.ToString() + " - " + FloatUtil.ToString(Unk3) + " - " + Unk4.ToString() + " - C:" + ItemCount.ToString(); } } @@ -895,7 +1296,7 @@ namespace CodeWalker.GameFiles { public ushort Unk1 { get; } public ushort Unk2 { get; } - public ushort Unk3 { get; } + public ushort Unk3 { get; }//Items.Length * 8 public ushort Unk4 { get; } public MrfStructStateSignalData[] Items { get; } @@ -906,26 +1307,20 @@ namespace CodeWalker.GameFiles Unk3 = r.ReadUInt16(); Unk4 = r.ReadUInt16(); - uint shouldContinue; var itemsList = new List(); - // FIXME: those loops looks weird - do + while (true) { - while (true) + var item = new MrfStructStateSignalData(r); + itemsList.Add(item); + if (item.Type == 0) { - var data = new MrfStructStateSignalData(r); - itemsList.Add(data); - - shouldContinue = data.UnkType; - - if (data.UnkType != 5) - break; + break; } } - while (shouldContinue != 0); Items = itemsList.ToArray(); + } public override void Write(DataWriter w) @@ -946,6 +1341,9 @@ namespace CodeWalker.GameFiles } } + + // FIXME: most likely broken + [TC(typeof(EXP))] public class MrfStructNegativeDataUnk7 : MrfStruct { public uint Unk1 { get; set; } @@ -1910,394 +2308,4 @@ namespace CodeWalker.GameFiles #endregion - [TC(typeof(EXP))] public class MrfFile : GameFile, PackedFile - { - public byte[] RawFileData { get; set; } - public uint Magic { get; set; } = 0x45566F4D; // 'MoVE' - public uint Version { get; set; } = 2; - public uint HeaderUnk1 { get; set; } = 0; - public uint HeaderUnk2 { get; set; } = 0; - public uint HeaderUnk3 { get; set; } = 0; - public uint DataLength { get; set; } - public uint FlagsCount { get; set; } - public uint Unk1_Count { get; set; } - public uint Unk2_Count { get; set; } - public uint Unk3_Count { get; set; } - - public MrfStructHeaderUnk1[] Unk1_Items { get; set; } - public MrfStructHeaderUnk2[] Unk2_Items { get; set; } - public MrfStructHeaderUnk3[] Unk3_Items { get; set; } - public byte[] FlagsItems { get; set; } - - public MrfNode[] AllNodes { get; set; } - public MrfNode RootNode { get; set; } - - public MrfFile() : base(null, GameFileType.Mrf) - { - } - - public MrfFile(RpfFileEntry entry) : base(entry, GameFileType.Mrf) - { - RpfFileEntry = entry; - } - - public void Load(byte[] data, RpfFileEntry entry) - { - RawFileData = data; - if (entry != null) - { - RpfFileEntry = entry; - Name = entry.Name; - } - - using (MemoryStream ms = new MemoryStream(data)) - { - DataReader r = new DataReader(ms, Endianess.LittleEndian); - - Read(r); - }; - } - - public byte[] Save() - { - MemoryStream s = new MemoryStream(); - DataWriter w = new DataWriter(s); - - Write(w); - - var buf = new byte[s.Length]; - s.Position = 0; - s.Read(buf, 0, buf.Length); - return buf; - } - - private void Write(DataWriter w) - { - if (Magic != 0x45566F4D || Version != 2 || HeaderUnk1 != 0 || HeaderUnk2 != 0) - throw new Exception("Failed to write MRF, header is invalid!"); - - w.Write(Magic); - w.Write(Version); - w.Write(HeaderUnk1); - w.Write(HeaderUnk2); - w.Write(HeaderUnk3); - w.Write(DataLength); - w.Write(FlagsCount); - - // Unused in final game - w.Write(Unk1_Count); - - if (Unk1_Count > 0) - { - foreach (var entry in Unk1_Items) - { - w.Write(entry.Size); - w.Write(entry.Bytes); - } - } - - w.Write(Unk2_Count); - - if (Unk2_Count > 0) - { - foreach (var entry in Unk2_Items) - { - w.Write(entry.Unk1); - w.Write(entry.Unk2); - } - } - - w.Write(Unk3_Count); - - if (Unk3_Count > 0) - { - foreach (var entry in Unk3_Items) - { - w.Write(entry.Unk1); - w.Write(entry.Unk2); - } - } - - if (AllNodes != null) - { - foreach (var node in AllNodes) - node.Write(w); - } - - for (int i = 0; i < FlagsCount; i++) - w.Write(FlagsItems[i]); - } - - private void Read(DataReader r) - { - Magic = r.ReadUInt32(); // Should be 'MoVE' - Version = r.ReadUInt32(); // GTA5 = 2, RDR3 = 11 - HeaderUnk1 = r.ReadUInt32(); // Should be 0 - HeaderUnk2 = r.ReadUInt32(); - HeaderUnk3 = r.ReadUInt32(); // Should be 0 - DataLength = r.ReadUInt32(); - FlagsCount = r.ReadUInt32(); - - if (Magic != 0x45566F4D || Version != 2 || HeaderUnk1 != 0 || HeaderUnk2 != 0) - throw new Exception("Failed to read MRF, header is invalid!"); - - // Unused in final game - Unk1_Count = r.ReadUInt32(); - if (Unk1_Count > 0) - { - Unk1_Items = new MrfStructHeaderUnk1[Unk1_Count]; - - for (int i = 0; i < Unk1_Count; i++) - Unk1_Items[i] = new MrfStructHeaderUnk1(r); - } - - Unk2_Count = r.ReadUInt32(); - if (Unk2_Count > 0) - { - Unk2_Items = new MrfStructHeaderUnk2[Unk2_Count]; - - for (int i = 0; i < Unk2_Count; i++) - Unk2_Items[i] = new MrfStructHeaderUnk2(r); - } - - Unk3_Count = r.ReadUInt32(); - if (Unk3_Count > 0) - { - Unk3_Items = new MrfStructHeaderUnk3[Unk3_Count]; - - for (int i = 0; i < Unk3_Count; i++) - Unk3_Items[i] = new MrfStructHeaderUnk3(r); - } - - var nodes = new List(); - - while (true) - { - var index = nodes.Count; - var offset = (int)r.Position; - - var node = ReadNode(r); - - if (node == null) break; - - node.FileIndex = index; - node.FileOffset = offset; - node.FileDataSize = ((int)r.Position) - offset; - - nodes.Add(node); - } - - AllNodes = nodes.ToArray(); - - if (FlagsCount != 0) - { - FlagsItems = new byte[FlagsCount]; - - for (int i = 0; i < FlagsCount; i++) - FlagsItems[i] = r.ReadByte(); - } - - - BuildNodeHierarchy(); - - - if (r.Position != r.Length) - throw new Exception($"Failed to read MRF ({r.Position} / {r.Length})"); - } - - private MrfNode ReadNode(DataReader r) - { - var startPos = r.Position; - var nodeType = (MrfNodeType)r.ReadUInt16(); - r.Position = startPos; - - if (nodeType <= MrfNodeType.None || nodeType >= MrfNodeType.Max) - { - if (r.Position != r.Length)//should only be at EOF - { } - return null; - } - - var node = CreateNode(nodeType); - - node.Read(r); - - return node; - } - - private MrfNode CreateNode(MrfNodeType infoType) - { - switch (infoType) - { - case MrfNodeType.StateMachineClass: - return new MrfNodeStateMachineClass(); - case MrfNodeType.Tail: - return new MrfNodeTail(); - case MrfNodeType.InlinedStateMachine: - return new MrfNodeInlinedStateMachine(); - case MrfNodeType.Unk4: - return new MrfNodeUnk4(); - case MrfNodeType.Blend: - return new MrfNodeBlend(); - case MrfNodeType.AddSubtract: - return new MrfNodeAddSubstract(); - case MrfNodeType.Filter: - return new MrfNodeFilter(); - case MrfNodeType.Unk8: - return new MrfNodeUnk8(); - case MrfNodeType.Frame: - return new MrfNodeFrame(); - case MrfNodeType.Unk10: - return new MrfNodeUnk10(); - case MrfNodeType.BlendN: - return new MrfNodeBlendN(); - case MrfNodeType.Clip: - return new MrfNodeClip(); - case MrfNodeType.Unk17: - return new MrfNodeUnk17(); - case MrfNodeType.Unk18: - return new MrfNodeUnk18(); - case MrfNodeType.Expression: - return new MrfNodeExpression(); - case MrfNodeType.Unk20: - return new MrfNodeUnk20(); - case MrfNodeType.Proxy: - return new MrfNodeProxy(); - case MrfNodeType.AddN: - return new MrfNodeAddN(); - case MrfNodeType.Identity: - return new MrfNodeIdentity(); - case MrfNodeType.Unk24: - return new MrfNodeUnk24(); - case MrfNodeType.Unk25: - return new MrfNodeUnk25(); - case MrfNodeType.MergeN: - return new MrfNodeMergeN(); - case MrfNodeType.State: - return new MrfNodeState(); - case MrfNodeType.Invalid: - return new MrfNodeInvalid(); - case MrfNodeType.Unk29: - return new MrfNodeUnk29(); - case MrfNodeType.SubNetworkClass: - return new MrfNodeSubNetworkClass(); - case MrfNodeType.Unk31: - return new MrfNodeUnk31(); - } - - throw new Exception($"A handler for ({infoType}) mrf node type is not valid"); - } - - - private int BuildNodeHierarchy(MrfNode node = null, int index = 0) - { - if (AllNodes == null) return 0; - if (AllNodes.Length <= index) return 0; - - if (node == null) - { - var rlist = new List(); - for (int i = 0; i < AllNodes.Length; i++) - { - var rnode = AllNodes[i]; - rlist.Add(rnode); - i += BuildNodeHierarchy(rnode, i); - } - - var smlist = new List(); - var imlist = new List(); - var snlist = new List(); - foreach (var n in AllNodes) - { - if (n is MrfNodeStateMachineClass sm) - { - smlist.Add(sm); - if (sm.ChildNodes != null) for (int i = 0; i < sm.ChildNodes.Length; i++) if (sm.ChildNodes[i].NodeIndex != i) - { }//sanity check - don't get here - } - if (n is MrfNodeInlinedStateMachine im) - { - imlist.Add(im); - if (im.ChildNodes != null) for (int i = 0; i < im.ChildNodes.Length; i++) if (im.ChildNodes[i].NodeIndex != i) - { }//sanity check - don't get here - } - if (n is MrfNodeState sn) - { - snlist.Add(sn); - if (sn.ChildNodes != null) for (int i = 0; i < sn.ChildNodes.Length; i++) if (sn.ChildNodes[i].NodeIndex != i) - { }//sanity check - don't get here - } - } - - if (rlist.Count > 0) - { - RootNode = rlist[0]; - } - if (rlist.Count != 1) - { }//sanity check - don't get here - if (AllNodes.Length > 1000) - { } - return 0; - } - - if (node is MrfNodeStateBase snode) - { - var c = 0; - var clist = new List(); - int ccount = snode.StateChildCount; - if (ccount == 0) - { - return 0; - } - for (int i = 0; i <= ccount; i++) - { - if ((i == ccount) && (node is MrfNodeState)) - { break; } - var cind = index + c + i + 1; - if (cind >= AllNodes.Length) - { - if (i != ccount) - { }//don't get here (tried to continue past the end of the array!) - break; - } - var cnode = AllNodes[cind]; - if (cnode is MrfNodeTail) - { - i--; - c++; - if (clist.Count > 0) - { - var prevnode = clist[clist.Count - 1]; - if (prevnode is MrfNodeStateBase sprevnode) - { - if (sprevnode.TailNode != null) - { }//don't get here (tail node was already assigned?!?) - sprevnode.TailNode = cnode; - if (clist.Count == ccount) - { break; }//list is full, don't continue - } - else - { }//don't get here (previous node isn't a state??) - } - else - { }//don't get here (can't have tail without a previous node!) - continue; - } - else if (clist.Count == ccount) - { break; }//this node isn't a tail, but the list is already full, so it must belong to another node - if (cnode.NodeIndex != i) - { break; }//don't get here (node index mismatch!) - clist.Add(cnode); - c += BuildNodeHierarchy(cnode, cind);//recurse... - } - if (clist.Count != ccount) - { }//don't get here (sanity check) - snode.ChildNodes = clist.ToArray(); - return c + clist.Count; - } - - return 0; - } - - } }