From 47ded04673f70c1dd88dfc690d08b73e2f7d4493 Mon Sep 17 00:00:00 2001 From: MattFiler Date: Wed, 9 Aug 2023 17:59:04 +0100 Subject: [PATCH 01/30] continuing with collision map --- CathodeLib/Scripts/CATHODE/CollisionMaps.cs | 38 +++++++++++-------- .../CATHODE/CommandsPAK/Components/Entity.cs | 30 +++++++++++++-- .../Scripts/CATHODE/EnvironmentAnimations.cs | 4 ++ CathodeLib/Scripts/Utilities.cs | 4 +- 4 files changed, 55 insertions(+), 21 deletions(-) diff --git a/CathodeLib/Scripts/CATHODE/CollisionMaps.cs b/CathodeLib/Scripts/CATHODE/CollisionMaps.cs index 9c8ebc4..9b36874 100644 --- a/CathodeLib/Scripts/CATHODE/CollisionMaps.cs +++ b/CathodeLib/Scripts/CATHODE/CollisionMaps.cs @@ -21,17 +21,20 @@ override protected bool LoadInternal() { using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) { + //It seems typically in this file at the start there are a bunch of empty entries, and then there are a bunch of unresolvable ones, and then a bunch that can be resolved. + reader.BaseStream.Position = 4; int entryCount = reader.ReadInt32(); for (int i = 0; i < entryCount; i++) { Entry entry = new Entry(); - entry.Unknown1_ = reader.ReadInt32(); + entry.unk0 = reader.ReadInt32(); //flag? + entry.Unknown1_ = reader.ReadInt32(); //some sort of index ? + entry.ID = Utilities.Consume(reader); entry.entity = Utilities.Consume(reader); - entry.ResourcesBINID = reader.ReadInt32(); - entry.Unknown2_ = reader.ReadInt32(); + entry.Unknown2_ = reader.ReadInt32(); //Is sometimes -1 and other times a small positive integer. Is this tree node parent? entry.CollisionHKXEntryIndex = reader.ReadInt16(); - entry.Unknown3_ = reader.ReadInt16(); + entry.Unknown3_ = reader.ReadInt16(); //Most of the time it is -1. entry.MVRZoneIDThing = reader.ReadInt32(); entry.Unknown4_ = reader.ReadInt32(); entry.Unknown5_ = reader.ReadInt32(); @@ -53,8 +56,8 @@ override protected bool SaveInternal() for (int i = 0; i < Entries.Count; i++) { writer.Write(Entries[i].Unknown1_); + Utilities.Write(writer, Entries[i].ID); Utilities.Write(writer, Entries[i].entity); - writer.Write(Entries[i].ResourcesBINID); writer.Write(Entries[i].CollisionHKXEntryIndex); writer.Write(Entries[i].Unknown3_); writer.Write(Entries[i].MVRZoneIDThing); @@ -71,22 +74,25 @@ override protected bool SaveInternal() #region STRUCTURES public class Entry { - public int Unknown1_; // Is this tree node id? + public int unk0 = 0; //flags? + public int Unknown1_ = -1; // Is this tree node id? + + public ShortGuid ID = ShortGuid.Invalid; //This is the name of the entity hashed via ShortGuid, as a result, we can't resolve a lot of them. Does the game care about the value? I doubt it. We definitely don't. - public CommandsEntityReference entity; + public CommandsEntityReference entity = new CommandsEntityReference(); - public int ResourcesBINID; // NOTE: This might not be the correct name. It seems to correspond to the similarly named variable at alien_resources_bin_entry. - public int Unknown2_; // NOTE: Is sometimes -1 and other times a small positive integer. Is this tree node parent? + public int Unknown2_= -1; // NOTE: Is sometimes -1 and other times a small positive integer. Is this tree node parent? - public Int16 CollisionHKXEntryIndex; // NOTE: Most of the time is a positive integer, sometimes -1. + public Int16 CollisionHKXEntryIndex = -1; // NOTE: Most of the time is a positive integer, sometimes -1. - public Int16 Unknown3_; // NOTE: Most of the time it is -1. - public int MVRZoneIDThing; // NOTE: This is CollisionMapThingIDs[0] from alien_mvr_entry + public Int16 Unknown3_ = -1; // NOTE: Most of the time it is -1. + public int MVRZoneIDThing = 0; // NOTE: This is CollisionMapThingIDs[0] from alien_mvr_entry - public int Unknown4_; - public int Unknown5_; - public int Unknown6_; - public int Unknown7_; + //TODO: are these values ever not zero? need to assert. + public int Unknown4_ = 0; + public int Unknown5_ = 0; + public int Unknown6_ = 0; + public int Unknown7_ = 0; }; #endregion } diff --git a/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Entity.cs b/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Entity.cs index 79be6e0..aa19766 100644 --- a/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Entity.cs +++ b/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Entity.cs @@ -523,11 +523,35 @@ public UInt32 ToUInt32() return val; } - /* Get the entity this hierarchy points to */ - public Entity GetPointedEntity(Commands commands, Composite composite) + /* Get the entity this hierarchy points to: FROM THE ENTRY POINT OF THE COMMANDS */ + public Entity GetPointedEntity(Commands commands) { - return CommandsUtils.ResolveHierarchy(commands, composite, hierarchy, out Composite comp, out string str); + return CommandsUtils.ResolveHierarchy(commands, commands.EntryPoints[0], hierarchy, out Composite comp, out string str); } + + /* Get the entity this hierarchy points to: FROM THE ENTRY POINT OF THE COMMANDS, RETURNING THE CONTAINED COMPOSITE */ + public Entity GetPointedEntity(Commands commands, out Composite containedComposite) + { + Entity ent = CommandsUtils.ResolveHierarchy(commands, commands.EntryPoints[0], hierarchy, out Composite comp, out string str); + containedComposite = comp; + return ent; + } + + /* Get the entity this hierarchy points to: FROM A SPECIFIED COMPOSITE */ + public Entity GetPointedEntity(Commands commands, Composite startComposite) + { + return CommandsUtils.ResolveHierarchy(commands, startComposite, hierarchy, out Composite comp, out string str); + } + + /* Get the entity this hierarchy points to: FROM A SPECIFIED COMPOSITE, RETURNING THE CONTAINED COMPOSITE */ + public Entity GetPointedEntity(Commands commands, Composite startComposite, out Composite containedComposite) + { + Entity ent = CommandsUtils.ResolveHierarchy(commands, startComposite, hierarchy, out Composite comp, out string str); + containedComposite = comp; + return ent; + } + + /* Get the ID of the entity that this hierarchy points to */ public ShortGuid GetPointedEntityID() { hierarchy.Reverse(); diff --git a/CathodeLib/Scripts/CATHODE/EnvironmentAnimations.cs b/CathodeLib/Scripts/CATHODE/EnvironmentAnimations.cs index 6153056..37b5007 100644 --- a/CathodeLib/Scripts/CATHODE/EnvironmentAnimations.cs +++ b/CathodeLib/Scripts/CATHODE/EnvironmentAnimations.cs @@ -21,6 +21,10 @@ public EnvironmentAnimations(string path) : base(path) { } #region FILE_IO override protected bool LoadInternal() { + + //TODO: this is a mapping of ModelReference entities within the composite with EnvironmentModelReference in + // the IDs should line up. + using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) { //Read header diff --git a/CathodeLib/Scripts/Utilities.cs b/CathodeLib/Scripts/Utilities.cs index 6bd9a68..1ff0935 100644 --- a/CathodeLib/Scripts/Utilities.cs +++ b/CathodeLib/Scripts/Utilities.cs @@ -307,8 +307,8 @@ public OffsetPair(long _go, int _ec) [StructLayout(LayoutKind.Sequential, Pack = 1)] public class CommandsEntityReference { - public ShortGuid entity_id; //The ID of the entity within its written composite - public ShortGuid composite_instance_id; //The instance of the composite this entity is in when created via hierarchy + public ShortGuid entity_id = ShortGuid.Invalid; //The ID of the entity within its written composite + public ShortGuid composite_instance_id = ShortGuid.Invalid; //The instance of the composite this entity is in when created via hierarchy public CommandsEntityReference() { } public CommandsEntityReference(EntityHierarchy hierarchy) From 4f4e4e9c555ff0797887033a972df552ae827844 Mon Sep 17 00:00:00 2001 From: MattFiler Date: Wed, 9 Aug 2023 18:42:34 +0100 Subject: [PATCH 02/30] don't parse empty collision map stuff --- CathodeLib/Scripts/CATHODE/CollisionMaps.cs | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/CathodeLib/Scripts/CATHODE/CollisionMaps.cs b/CathodeLib/Scripts/CATHODE/CollisionMaps.cs index 9b36874..c18ba0b 100644 --- a/CathodeLib/Scripts/CATHODE/CollisionMaps.cs +++ b/CathodeLib/Scripts/CATHODE/CollisionMaps.cs @@ -36,10 +36,7 @@ override protected bool LoadInternal() entry.CollisionHKXEntryIndex = reader.ReadInt16(); entry.Unknown3_ = reader.ReadInt16(); //Most of the time it is -1. entry.MVRZoneIDThing = reader.ReadInt32(); - entry.Unknown4_ = reader.ReadInt32(); - entry.Unknown5_ = reader.ReadInt32(); - entry.Unknown6_ = reader.ReadInt32(); - entry.Unknown7_ = reader.ReadInt32(); + reader.BaseStream.Position += 16; Entries.Add(entry); } } @@ -61,10 +58,7 @@ override protected bool SaveInternal() writer.Write(Entries[i].CollisionHKXEntryIndex); writer.Write(Entries[i].Unknown3_); writer.Write(Entries[i].MVRZoneIDThing); - writer.Write(Entries[i].Unknown4_); - writer.Write(Entries[i].Unknown5_); - writer.Write(Entries[i].Unknown6_); - writer.Write(Entries[i].Unknown7_); + writer.Write(new byte[16]); } } return true; @@ -87,12 +81,6 @@ public class Entry public Int16 Unknown3_ = -1; // NOTE: Most of the time it is -1. public int MVRZoneIDThing = 0; // NOTE: This is CollisionMapThingIDs[0] from alien_mvr_entry - - //TODO: are these values ever not zero? need to assert. - public int Unknown4_ = 0; - public int Unknown5_ = 0; - public int Unknown6_ = 0; - public int Unknown7_ = 0; }; #endregion } From 97cfa26e69da0088afe965e8fe8434464def3532 Mon Sep 17 00:00:00 2001 From: MattFiler Date: Sun, 13 Aug 2023 19:30:29 +0100 Subject: [PATCH 03/30] fix instance generation --- CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Entity.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Entity.cs b/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Entity.cs index aa19766..007ff78 100644 --- a/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Entity.cs +++ b/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Entity.cs @@ -601,8 +601,8 @@ public ShortGuid GenerateInstance() ShortGuid instanceGenerated = hierarchy[0]; for (int i = 0; i < hierarchy.Count; i++) { + if (i == hierarchy.Count - 1) break; instanceGenerated = hierarchy[i + 1].Combine(instanceGenerated); - if (i == hierarchy.Count - 2) break; } hierarchy.Reverse(); hierarchy.RemoveAt(0); From 11b5438be28a48da8ee4a3ab0acfe92668ef1647 Mon Sep 17 00:00:00 2001 From: MattFiler Date: Sat, 19 Aug 2023 20:38:06 +0100 Subject: [PATCH 04/30] check for -1 --- CathodeLib/Scripts/CATHODE/Textures.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CathodeLib/Scripts/CATHODE/Textures.cs b/CathodeLib/Scripts/CATHODE/Textures.cs index 915f23a..0ba24cb 100644 --- a/CathodeLib/Scripts/CATHODE/Textures.cs +++ b/CathodeLib/Scripts/CATHODE/Textures.cs @@ -250,7 +250,7 @@ public int GetWriteIndex(TEX4 texture) * Note: if the file hasn't been saved for a while, the write index may differ from the index on-disk */ public TEX4 GetAtWriteIndex(int index) { - if (_writeList.Count <= index) return null; + if (index < 0 || _writeList.Count <= index) return null; return _writeList[index]; } #endregion From 330f99fc374898ec2c884906248886ad4f4cc960 Mon Sep 17 00:00:00 2001 From: MattFiler Date: Tue, 29 Aug 2023 19:17:56 +0100 Subject: [PATCH 05/30] bml fix --- AlienBML | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AlienBML b/AlienBML index 15e5345..a035789 160000 --- a/AlienBML +++ b/AlienBML @@ -1 +1 @@ -Subproject commit 15e53456fa0b6d402815dce0e5f74f51f1417532 +Subproject commit a035789090a19b7bc6ad92b18c9bdcb2c3b0b1a9 From 186550a2a5903c3c128b287364e9d2eed37962a7 Mon Sep 17 00:00:00 2001 From: MattFiler Date: Sun, 3 Sep 2023 14:25:23 +0100 Subject: [PATCH 06/30] parallel param reading --- CathodeLib/Scripts/CATHODE/Commands.cs | 100 +++++++++++++------------ 1 file changed, 54 insertions(+), 46 deletions(-) diff --git a/CathodeLib/Scripts/CATHODE/Commands.cs b/CathodeLib/Scripts/CATHODE/Commands.cs index 8209819..45b7812 100644 --- a/CathodeLib/Scripts/CATHODE/Commands.cs +++ b/CathodeLib/Scripts/CATHODE/Commands.cs @@ -57,56 +57,64 @@ override protected bool LoadInternal() //Read all parameters from the PAK Dictionary parameters = new Dictionary(parameter_count); - for (int i = 0; i < parameter_count; i++) { - reader.BaseStream.Position = parameterOffsets[i] * 4; - ParameterData this_parameter = new ParameterData(CommandsUtils.GetDataType(new ShortGuid(reader))); - switch (this_parameter.dataType) + ParameterData[] parametersArr = new ParameterData[parameter_count]; + Parallel.For(0, parameter_count, i => { - case DataType.TRANSFORM: - this_parameter = new cTransform(); - ((cTransform)this_parameter).position = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); - float _x, _y, _z; _y = reader.ReadSingle(); _x = reader.ReadSingle(); _z = reader.ReadSingle(); //This is Y/X/Z as it's stored as Yaw/Pitch/Roll - ((cTransform)this_parameter).rotation = new Vector3(_x, _y, _z); - break; - case DataType.INTEGER: - this_parameter = new cInteger(reader.ReadInt32()); - break; - case DataType.STRING: - reader.BaseStream.Position += 8; - this_parameter = new cString(Utilities.ReadString(reader).Replace("\u0092", "'")); - Utilities.Align(reader, 4); - break; - case DataType.BOOL: - this_parameter = new cBool((reader.ReadInt32() == 1)); - break; - case DataType.FLOAT: - this_parameter = new cFloat(reader.ReadSingle()); - break; - case DataType.RESOURCE: - this_parameter = new cResource(new ShortGuid(reader)); - break; - case DataType.VECTOR: - this_parameter = new cVector3(new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle())); - break; - case DataType.ENUM: - this_parameter = new cEnum(new ShortGuid(reader), reader.ReadInt32()); - break; - case DataType.SPLINE: - reader.BaseStream.Position += 4; - List points = new List(reader.ReadInt32()); - for (int x = 0; x < points.Capacity; x++) + using (BinaryReader reader_parallel = new BinaryReader(new MemoryStream(content))) + { + reader_parallel.BaseStream.Position = parameterOffsets[i] * 4; + parametersArr[i] = new ParameterData(CommandsUtils.GetDataType(new ShortGuid(reader_parallel))); + switch (parametersArr[i].dataType) { - cTransform spline_point = new cTransform(); - spline_point.position = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); - float __x, __y, __z; __y = reader.ReadSingle(); __x = reader.ReadSingle(); __z = reader.ReadSingle(); //This is Y/X/Z as it's stored as Yaw/Pitch/Roll - spline_point.rotation = new Vector3(__x, __y, __z); - points.Add(spline_point); + case DataType.TRANSFORM: + parametersArr[i] = new cTransform(); + ((cTransform)parametersArr[i]).position = new Vector3(reader_parallel.ReadSingle(), reader_parallel.ReadSingle(), reader_parallel.ReadSingle()); + float _x, _y, _z; _y = reader_parallel.ReadSingle(); _x = reader_parallel.ReadSingle(); _z = reader_parallel.ReadSingle(); //This is Y/X/Z as it's stored as Yaw/Pitch/Roll + ((cTransform)parametersArr[i]).rotation = new Vector3(_x, _y, _z); + break; + case DataType.INTEGER: + parametersArr[i] = new cInteger(reader_parallel.ReadInt32()); + break; + case DataType.STRING: + reader_parallel.BaseStream.Position += 8; + parametersArr[i] = new cString(Utilities.ReadString(reader_parallel).Replace("\u0092", "'")); + Utilities.Align(reader_parallel, 4); + break; + case DataType.BOOL: + parametersArr[i] = new cBool((reader_parallel.ReadInt32() == 1)); + break; + case DataType.FLOAT: + parametersArr[i] = new cFloat(reader_parallel.ReadSingle()); + break; + case DataType.RESOURCE: + parametersArr[i] = new cResource(new ShortGuid(reader_parallel)); + break; + case DataType.VECTOR: + parametersArr[i] = new cVector3(new Vector3(reader_parallel.ReadSingle(), reader_parallel.ReadSingle(), reader_parallel.ReadSingle())); + break; + case DataType.ENUM: + parametersArr[i] = new cEnum(new ShortGuid(reader_parallel), reader_parallel.ReadInt32()); + break; + case DataType.SPLINE: + reader_parallel.BaseStream.Position += 4; + List points = new List(reader_parallel.ReadInt32()); + for (int x = 0; x < points.Capacity; x++) + { + cTransform spline_point = new cTransform(); + spline_point.position = new Vector3(reader_parallel.ReadSingle(), reader_parallel.ReadSingle(), reader_parallel.ReadSingle()); + float __x, __y, __z; __y = reader_parallel.ReadSingle(); __x = reader_parallel.ReadSingle(); __z = reader_parallel.ReadSingle(); //This is Y/X/Z as it's stored as Yaw/Pitch/Roll + spline_point.rotation = new Vector3(__x, __y, __z); + points.Add(spline_point); + } + parametersArr[i] = new cSpline(points); + break; } - this_parameter = new cSpline(points); - break; - } - parameters.Add(parameterOffsets[i], this_parameter); + } + }); + + for (int i = 0; i < parameter_count; i++) + parameters.Add(parameterOffsets[i], parametersArr[i]); } //Read all composites from the PAK From 4581c90e125e829705af01839d8bdb5ea55644f3 Mon Sep 17 00:00:00 2001 From: MattFiler Date: Fri, 8 Sep 2023 20:35:16 +0100 Subject: [PATCH 07/30] misc comments --- CathodeLib/Scripts/CATHODE/Commands.cs | 28 ++++--------------- .../CATHODE/CommandsPAK/Components/Entity.cs | 2 +- 2 files changed, 7 insertions(+), 23 deletions(-) diff --git a/CathodeLib/Scripts/CATHODE/Commands.cs b/CathodeLib/Scripts/CATHODE/Commands.cs index 45b7812..aef9866 100644 --- a/CathodeLib/Scripts/CATHODE/Commands.cs +++ b/CathodeLib/Scripts/CATHODE/Commands.cs @@ -147,8 +147,8 @@ override protected bool LoadInternal() reader_parallel.BaseStream.Position = (scriptStartOffset * 4) + 4; composite.name = Utilities.ReadString(reader_parallel); #if DO_PRETTY_COMPOSITES - string prettyPath = CompositePathDB.GetPrettyPathForComposite(composite.shortGUID); - if (prettyPath != "") composite.name = prettyPath; + string prettyPath = CompositePathDB.GetPrettyPathForComposite(composite.shortGUID); + if (prettyPath != "") composite.name = prettyPath; #endif Utilities.Align(reader_parallel, 4); @@ -302,7 +302,7 @@ override protected bool LoadInternal() reader_parallel.BaseStream.Position = headerOffset + (z * 32); CAGEAnimation.Connection header = new CAGEAnimation.Connection(); - header.shortGUID = new ShortGuid(reader_parallel);//ID + header.shortGUID = new ShortGuid(reader_parallel); header.objectType = CommandsUtils.GetObjectType(new ShortGuid(reader_parallel)); header.keyframeID = new ShortGuid(reader_parallel); header.parameterID = new ShortGuid(reader_parallel); @@ -372,7 +372,9 @@ override protected bool LoadInternal() Entity thisEntity = composite.GetEntityByID(new ShortGuid(reader_parallel)); if (thisEntity.variant == EntityVariant.PROXY) { - break; // We don't handle this just yet... need to resolve the proxy. + //Logs indicate that these vanilla entities contain no parameters or links, so they're not very valuable. We should implement this anyways though so we can add them ourselves. + Console.WriteLine("WARNING: Skipping load of PROXY TriggerSequence in " + composite.name + "\n\t" + _filepath /*+ "\n\n" + JsonConvert.SerializeObject(thisEntity) + "\n\n"*/); + break; } TriggerSequence trigEntity = (TriggerSequence)thisEntity; @@ -493,24 +495,6 @@ override protected bool LoadInternal() Entries = composites.ToList(); } - //TODO: DOING THIS CAUSES THE NEW-DOOR-CREATION ISSUE WITH EXISTING DOORS - // DOING THE INVERSE CAUSES A CRASH - /* - foreach (Composite comp in Entries) - { - foreach (FunctionEntity ent in comp.functions) - { - if (ent.resources.Count != 0) - { - cResource res = new cResource(); - res.value.AddRange(ent.resources); - foreach (ResourceReference resRef in res.value) resRef.resourceID = res.shortGUID; - Parameter param = ent.AddParameter("resource", res); - ent.resources.Clear(); - } - } - }*/ - return true; } diff --git a/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Entity.cs b/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Entity.cs index 007ff78..9b96a15 100644 --- a/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Entity.cs +++ b/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Entity.cs @@ -313,7 +313,7 @@ public ProxyEntity(ShortGuid shortGUID) : base(shortGUID, EntityVariant.PROXY) { public EntityHierarchy connectedEntity = new EntityHierarchy(); } [Serializable] - public class OverrideEntity : Entity + public class OverrideEntity : Entity // Known as "alias" entities in-code { public OverrideEntity() : base(EntityVariant.OVERRIDE) { } public OverrideEntity(ShortGuid shortGUID) : base(shortGUID, EntityVariant.OVERRIDE) { } From 5f965a12b0580691b3afd7ca0795e5f304faf4b8 Mon Sep 17 00:00:00 2001 From: MattFiler Date: Fri, 8 Sep 2023 22:22:11 +0100 Subject: [PATCH 08/30] renaming overrides to aliases --- CathodeLib/Scripts/CATHODE/Commands.cs | 82 ++++----- .../CommandsPAK/Components/Composite.cs | 22 +-- .../CATHODE/CommandsPAK/Components/Entity.cs | 174 +++++++++--------- .../CommandsPAK/Components/TypeEnums.cs | 28 +-- .../CommandsPAK/Helpers/CommandsUtils.cs | 38 ++-- CathodeLib/Scripts/Utilities.cs | 2 +- 6 files changed, 172 insertions(+), 174 deletions(-) diff --git a/CathodeLib/Scripts/CATHODE/Commands.cs b/CathodeLib/Scripts/CATHODE/Commands.cs index aef9866..9aa3f48 100644 --- a/CathodeLib/Scripts/CATHODE/Commands.cs +++ b/CathodeLib/Scripts/CATHODE/Commands.cs @@ -168,7 +168,7 @@ override protected bool LoadInternal() reader_parallel.BaseStream.Position = (offsetPairs[x].GlobalOffset * 4) + (y * 12); entityLinks.Add(new CommandsEntityLinks(new ShortGuid(reader_parallel))); int NumberOfParams = JumpToOffset(reader_parallel); - entityLinks[entityLinks.Count - 1].childLinks.AddRange(Utilities.ConsumeArray(reader_parallel, NumberOfParams)); + entityLinks[entityLinks.Count - 1].childLinks.AddRange(Utilities.ConsumeArray(reader_parallel, NumberOfParams)); break; } case CompositeFileData.ENTITY_PARAMETERS: @@ -179,22 +179,22 @@ override protected bool LoadInternal() paramRefSets[paramRefSets.Count - 1].refs.AddRange(Utilities.ConsumeArray(reader_parallel, NumberOfParams)); break; } - case CompositeFileData.ENTITY_OVERRIDES: + case CompositeFileData.ALIASES: { reader_parallel.BaseStream.Position = (offsetPairs[x].GlobalOffset * 4) + (y * 12); - OverrideEntity overrider = new OverrideEntity(new ShortGuid(reader_parallel)); + AliasEntity overrider = new AliasEntity(new ShortGuid(reader_parallel)); int NumberOfParams = JumpToOffset(reader_parallel); - overrider.connectedEntity.hierarchy.AddRange(Utilities.ConsumeArray(reader_parallel, NumberOfParams)); - composite.overrides.Add(overrider); + overrider.connectedEntity.path.AddRange(Utilities.ConsumeArray(reader_parallel, NumberOfParams)); + composite.aliases.Add(overrider); break; } - case CompositeFileData.ENTITY_OVERRIDES_CHECKSUM: + case CompositeFileData.ALIAS_PATH_HASHES: { reader_parallel.BaseStream.Position = (offsetPairs[x].GlobalOffset * 4) + (y * 8); reader_parallel.BaseStream.Position += 8; break; } - case CompositeFileData.COMPOSITE_EXPOSED_PARAMETERS: + case CompositeFileData.VARIABLES: { reader_parallel.BaseStream.Position = (offsetPairs[x].GlobalOffset * 4) + (y * 12); VariableEntity dtEntity = new VariableEntity(new ShortGuid(reader_parallel)); @@ -203,13 +203,13 @@ override protected bool LoadInternal() composite.variables.Add(dtEntity); break; } - case CompositeFileData.ENTITY_PROXIES: + case CompositeFileData.PROXIES: { reader_parallel.BaseStream.Position = (offsetPairs[x].GlobalOffset * 4) + (y * 20); ProxyEntity thisProxy = new ProxyEntity(new ShortGuid(reader_parallel)); int resetPos = (int)reader_parallel.BaseStream.Position + 8; //TODO: This is a HACK - I need to rework JumpToOffset to make a temp stream int NumberOfParams = JumpToOffset(reader_parallel); - thisProxy.connectedEntity.hierarchy.AddRange(Utilities.ConsumeArray(reader_parallel, NumberOfParams)); //Last is always 0x00, 0x00, 0x00, 0x00 + thisProxy.connectedEntity.path.AddRange(Utilities.ConsumeArray(reader_parallel, NumberOfParams)); //Last is always 0x00, 0x00, 0x00, 0x00 reader_parallel.BaseStream.Position = resetPos; ShortGuid idCheck = new ShortGuid(reader_parallel); if (idCheck != thisProxy.shortGUID) throw new Exception("Proxy ID mismatch!"); @@ -217,7 +217,7 @@ override protected bool LoadInternal() composite.proxies.Add(thisProxy); break; } - case CompositeFileData.ENTITY_FUNCTIONS: + case CompositeFileData.FUNCTION_ENTITIES: { reader_parallel.BaseStream.Position = (offsetPairs[x].GlobalOffset * 4) + (y * 8); ShortGuid entityID = new ShortGuid(reader_parallel); @@ -310,7 +310,7 @@ override protected bool LoadInternal() header.parameterSubID = new ShortGuid(reader_parallel); int hierarchyCount = JumpToOffset(reader_parallel); - header.connectedEntity.hierarchy = Utilities.ConsumeArray(reader_parallel, hierarchyCount).ToList(); + header.connectedEntity.path = Utilities.ConsumeArray(reader_parallel, hierarchyCount).ToList(); animEntity.connections.Add(header); } @@ -392,7 +392,7 @@ override protected bool LoadInternal() TriggerSequence.Entity thisTrigger = new TriggerSequence.Entity(); thisTrigger.timing = reader_parallel.ReadSingle(); reader_parallel.BaseStream.Position = hierarchyOffset; - thisTrigger.connectedEntity.hierarchy = Utilities.ConsumeArray(reader_parallel, hierarchyCount).ToList(); + thisTrigger.connectedEntity.path = Utilities.ConsumeArray(reader_parallel, hierarchyCount).ToList(); trigEntity.entities.Add(thisTrigger); } @@ -615,8 +615,8 @@ override protected bool SaveInternal() List parameters = new List(); List[] linkedEntities = new List[Entries.Count]; List[] parameterisedEntities = new List[Entries.Count]; - List[] reshuffledOverrides = new List[Entries.Count]; - List[] reshuffledChecksums = new List[Entries.Count]; + List[] reshuffledAliases = new List[Entries.Count]; + List[] reshuffledAliasPathHashes = new List[Entries.Count]; List[] resourceReferences = new List[Entries.Count]; List[] cageAnimationEntities = new List[Entries.Count]; List[] triggerSequenceEntities = new List[Entries.Count]; @@ -626,8 +626,8 @@ override protected bool SaveInternal() List ents = Entries[i].GetEntities(); linkedEntities[i] = new List(ents.FindAll(o => o.childLinks.Count != 0)).OrderBy(o => o.shortGUID.ToUInt32()).ToList(); parameterisedEntities[i] = new List(ents.FindAll(o => o.parameters.Count != 0)).OrderBy(o => o.shortGUID.ToUInt32()).ToList(); - reshuffledOverrides[i] = Entries[i].overrides.OrderBy(o => o.shortGUID.ToUInt32()).ToList(); - reshuffledChecksums[i] = Entries[i].overrides.OrderBy(o => o.connectedEntity.GenerateChecksum().ToUInt32()).ToList(); + reshuffledAliases[i] = Entries[i].aliases.OrderBy(o => o.shortGUID.ToUInt32()).ToList(); + reshuffledAliasPathHashes[i] = Entries[i].aliases.OrderBy(o => o.connectedEntity.GeneratePathHash().ToUInt32()).ToList(); cageAnimationEntities[i] = new List(); triggerSequenceEntities[i] = new List(); @@ -788,7 +788,7 @@ override protected bool SaveInternal() { switch ((CompositeFileData)x) { - case CompositeFileData.COMPOSITE_HEADER: + case CompositeFileData.HEADER: { scriptPointerOffsetInfo[x] = new OffsetPair(writer.BaseStream.Position, 2); Utilities.Write(writer, Entries[i].shortGUID); @@ -801,7 +801,7 @@ override protected bool SaveInternal() foreach (Entity entityWithLink in linkedEntities[i]) { offsetPairs.Add(new OffsetPair(writer.BaseStream.Position, entityWithLink.childLinks.Count)); - Utilities.Write(writer, entityWithLink.childLinks); + Utilities.Write(writer, entityWithLink.childLinks); } scriptPointerOffsetInfo[x] = new OffsetPair(writer.BaseStream.Position, linkedEntities[i].Count); @@ -837,35 +837,35 @@ override protected bool SaveInternal() } break; } - case CompositeFileData.ENTITY_OVERRIDES: + case CompositeFileData.ALIASES: { - List offsetPairs = new List(reshuffledOverrides[i].Count); - for (int p = 0; p < reshuffledOverrides[i].Count; p++) + List offsetPairs = new List(reshuffledAliases[i].Count); + for (int p = 0; p < reshuffledAliases[i].Count; p++) { - offsetPairs.Add(new OffsetPair(writer.BaseStream.Position, reshuffledOverrides[i][p].connectedEntity.hierarchy.Count)); - Utilities.Write(writer, reshuffledOverrides[i][p].connectedEntity.hierarchy); + offsetPairs.Add(new OffsetPair(writer.BaseStream.Position, reshuffledAliases[i][p].connectedEntity.path.Count)); + Utilities.Write(writer, reshuffledAliases[i][p].connectedEntity.path); } - scriptPointerOffsetInfo[x] = new OffsetPair(writer.BaseStream.Position, reshuffledOverrides[i].Count); - for (int p = 0; p < reshuffledOverrides[i].Count; p++) + scriptPointerOffsetInfo[x] = new OffsetPair(writer.BaseStream.Position, reshuffledAliases[i].Count); + for (int p = 0; p < reshuffledAliases[i].Count; p++) { - writer.Write(reshuffledOverrides[i][p].shortGUID.val); + writer.Write(reshuffledAliases[i][p].shortGUID.val); writer.Write(offsetPairs[p].GlobalOffset / 4); writer.Write(offsetPairs[p].EntryCount); } break; } - case CompositeFileData.ENTITY_OVERRIDES_CHECKSUM: + case CompositeFileData.ALIAS_PATH_HASHES: { - scriptPointerOffsetInfo[x] = new OffsetPair(writer.BaseStream.Position, reshuffledChecksums[i].Count); - for (int p = 0; p < reshuffledChecksums[i].Count; p++) + scriptPointerOffsetInfo[x] = new OffsetPair(writer.BaseStream.Position, reshuffledAliasPathHashes[i].Count); + for (int p = 0; p < reshuffledAliasPathHashes[i].Count; p++) { - writer.Write(reshuffledChecksums[i][p].shortGUID.val); - writer.Write(reshuffledChecksums[i][p].connectedEntity.GenerateChecksum().val); + writer.Write(reshuffledAliasPathHashes[i][p].shortGUID.val); + writer.Write(reshuffledAliasPathHashes[i][p].connectedEntity.GeneratePathHash().val); } break; } - case CompositeFileData.COMPOSITE_EXPOSED_PARAMETERS: + case CompositeFileData.VARIABLES: { scriptPointerOffsetInfo[x] = new OffsetPair(writer.BaseStream.Position, Entries[i].variables.Count); for (int p = 0; p < Entries[i].variables.Count; p++) @@ -876,13 +876,13 @@ override protected bool SaveInternal() } break; } - case CompositeFileData.ENTITY_PROXIES: + case CompositeFileData.PROXIES: { List offsetPairs = new List(); for (int p = 0; p < Entries[i].proxies.Count; p++) { - offsetPairs.Add(new OffsetPair(writer.BaseStream.Position, Entries[i].proxies[p].connectedEntity.hierarchy.Count)); - Utilities.Write(writer, Entries[i].proxies[p].connectedEntity.hierarchy); + offsetPairs.Add(new OffsetPair(writer.BaseStream.Position, Entries[i].proxies[p].connectedEntity.path.Count)); + Utilities.Write(writer, Entries[i].proxies[p].connectedEntity.path); } scriptPointerOffsetInfo[x] = new OffsetPair(writer.BaseStream.Position, offsetPairs.Count); @@ -896,7 +896,7 @@ override protected bool SaveInternal() } break; } - case CompositeFileData.ENTITY_FUNCTIONS: + case CompositeFileData.FUNCTION_ENTITIES: { scriptPointerOffsetInfo[x] = new OffsetPair(writer.BaseStream.Position, Entries[i].functions.Count); for (int p = 0; p < Entries[i].functions.Count; p++) @@ -962,7 +962,7 @@ override protected bool SaveInternal() for (int pp = 0; pp < cageAnimationEntities[i][p].connections.Count; pp++) { hierarchyOffsets.Add((int)writer.BaseStream.Position); - Utilities.Write(writer, cageAnimationEntities[i][p].connections[pp].connectedEntity.hierarchy); + Utilities.Write(writer, cageAnimationEntities[i][p].connections[pp].connectedEntity.path); } int headerOffset = (int)writer.BaseStream.Position; @@ -976,7 +976,7 @@ override protected bool SaveInternal() Utilities.Write(writer, CommandsUtils.GetDataTypeGUID(header.parameterDataType)); Utilities.Write(writer, header.parameterSubID); writer.Write(hierarchyOffsets[pp] / 4); - writer.Write(header.connectedEntity.hierarchy.Count); + writer.Write(header.connectedEntity.path.Count); } List internalOffsets = new List(cageAnimationEntities[i][p].animations.Count); @@ -1080,14 +1080,14 @@ override protected bool SaveInternal() for (int pp = 0; pp < triggerSequenceEntities[i][p].entities.Count; pp++) { hierarchyOffsets.Add((int)writer.BaseStream.Position); - Utilities.Write(writer, triggerSequenceEntities[i][p].entities[pp].connectedEntity.hierarchy); + Utilities.Write(writer, triggerSequenceEntities[i][p].entities[pp].connectedEntity.path); } int triggerOffset = (int)writer.BaseStream.Position; for (int pp = 0; pp < triggerSequenceEntities[i][p].entities.Count; pp++) { writer.Write(hierarchyOffsets[pp] / 4); - writer.Write(triggerSequenceEntities[i][p].entities[pp].connectedEntity.hierarchy.Count); + writer.Write(triggerSequenceEntities[i][p].entities[pp].connectedEntity.path.Count); writer.Write(triggerSequenceEntities[i][p].entities[pp].timing); } @@ -1266,7 +1266,7 @@ private struct CathodeParameterReference private class CommandsEntityLinks { public ShortGuid parentID; - public List childLinks = new List(); + public List childLinks = new List(); public CommandsEntityLinks(ShortGuid _id) { diff --git a/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Composite.cs b/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Composite.cs index c4a90f1..7552571 100644 --- a/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Composite.cs +++ b/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Composite.cs @@ -22,18 +22,18 @@ public Composite(string name) public ShortGuid shortGUID; //The id when this composite is used as an entity in another composite public string name = ""; //The string name of the composite - public List variables = new List(); //Variables which can be accessed outside of this flowgraph as parameters, and connected to nodes as parameters internally + public List variables = new List(); //Variables which can be accessed outside of this composite as parameters, and connected to entities internally public List functions = new List(); //Functional nodes, including hard-coded functions and references to other composites - public List overrides = new List(); //Overrides of parameters in child composites - public List proxies = new List(); //Instances of entities from other composites + public List aliases = new List(); //Aliases of entities in child composites + public List proxies = new List(); //Entites acting as entities from other composites /* If an entity exists in the composite, return it */ public Entity GetEntityByID(ShortGuid id) { foreach (Entity entity in variables) if (entity.shortGUID == id) return entity; foreach (Entity entity in functions) if (entity.shortGUID == id) return entity; - foreach (Entity entity in overrides) if (entity.shortGUID == id) return entity; + foreach (Entity entity in aliases) if (entity.shortGUID == id) return entity; foreach (Entity entity in proxies) if (entity.shortGUID == id) return entity; return null; } @@ -41,10 +41,10 @@ public Entity GetEntityByID(ShortGuid id) /* Returns a collection of all entities in the composite */ public List GetEntities() { - List toReturn = new List(variables.Count + functions.Count + overrides.Count + proxies.Count); + List toReturn = new List(variables.Count + functions.Count + aliases.Count + proxies.Count); toReturn.AddRange(variables); toReturn.AddRange(functions); - toReturn.AddRange(overrides); + toReturn.AddRange(aliases); toReturn.AddRange(proxies); return toReturn; } @@ -94,12 +94,12 @@ public ProxyEntity AddProxy(Commands commands, List hierarchy, bool a return proxy; } - /* Add a new override entity */ - public OverrideEntity AddOverride(List hierarchy) + /* Add a new alias entity */ + public AliasEntity AddAlias(List hierarchy) { - OverrideEntity ovrride = new OverrideEntity(hierarchy); - overrides.Add(ovrride); - return ovrride; + AliasEntity alias = new AliasEntity(hierarchy); + aliases.Add(alias); + return alias; } public override string ToString() diff --git a/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Entity.cs b/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Entity.cs index 9b96a15..5413231 100644 --- a/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Entity.cs +++ b/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Entity.cs @@ -39,7 +39,7 @@ public Entity(ShortGuid shortGUID, EntityVariant variant) #endif public EntityVariant variant; - public List childLinks = new List(); + public List childLinks = new List(); public List parameters = new List(); /* Implements IComparable for searching */ @@ -163,7 +163,7 @@ public void RemoveParameter(string name) /* Add a link from a parameter on us out to a parameter on another entity */ public void AddParameterLink(string parameter, Entity childEntity, string childParameter) { - childLinks.Add(new EntityLink(childEntity.shortGUID, ShortGuidUtils.Generate(parameter), ShortGuidUtils.Generate(childParameter))); + childLinks.Add(new EntityConnector(childEntity.shortGUID, ShortGuidUtils.Generate(parameter), ShortGuidUtils.Generate(childParameter))); } /* Remove a link to another entity */ @@ -298,37 +298,37 @@ public ProxyEntity(ShortGuid shortGUID) : base(shortGUID, EntityVariant.PROXY) { public ProxyEntity(List hierarchy = null, ShortGuid targetType = new ShortGuid(), bool autoGenerateParameters = false) : base(EntityVariant.PROXY) { this.targetType = targetType; - if (hierarchy != null) this.connectedEntity.hierarchy = hierarchy; + if (hierarchy != null) this.connectedEntity.path = hierarchy; if (autoGenerateParameters) EntityUtils.ApplyDefaults(this); } public ProxyEntity(ShortGuid shortGUID, List hierarchy = null, ShortGuid targetType = new ShortGuid(), bool autoGenerateParameters = false) : base(shortGUID, EntityVariant.PROXY) { this.shortGUID = shortGUID; this.targetType = targetType; - if (hierarchy != null) this.connectedEntity.hierarchy = hierarchy; + if (hierarchy != null) this.connectedEntity.path = hierarchy; if (autoGenerateParameters) EntityUtils.ApplyDefaults(this); } public ShortGuid targetType; //The "function" value on the entity we're pointing to - public EntityHierarchy connectedEntity = new EntityHierarchy(); + public EntityPath connectedEntity = new EntityPath(); } [Serializable] - public class OverrideEntity : Entity // Known as "alias" entities in-code + public class AliasEntity : Entity { - public OverrideEntity() : base(EntityVariant.OVERRIDE) { } - public OverrideEntity(ShortGuid shortGUID) : base(shortGUID, EntityVariant.OVERRIDE) { } + public AliasEntity() : base(EntityVariant.ALIAS) { } + public AliasEntity(ShortGuid shortGUID) : base(shortGUID, EntityVariant.ALIAS) { } - public OverrideEntity(List hierarchy = null) : base(EntityVariant.OVERRIDE) + public AliasEntity(List hierarchy = null) : base(EntityVariant.ALIAS) { - if (hierarchy != null) this.connectedEntity.hierarchy = hierarchy; + if (hierarchy != null) this.connectedEntity.path = hierarchy; } - public OverrideEntity(ShortGuid shortGUID, List hierarchy = null) : base(shortGUID, EntityVariant.OVERRIDE) + public AliasEntity(ShortGuid shortGUID, List hierarchy = null) : base(shortGUID, EntityVariant.ALIAS) { this.shortGUID = shortGUID; - if (hierarchy != null) this.connectedEntity.hierarchy = hierarchy; + if (hierarchy != null) this.connectedEntity.path = hierarchy; } - public EntityHierarchy connectedEntity = new EntityHierarchy(); + public EntityPath connectedEntity = new EntityPath(); } #region SPECIAL FUNCTION ENTITIES @@ -362,7 +362,7 @@ public class Connection public ShortGuid parameterSubID; //if parameterID is position, this might be x for example //The path to the connected entity which has the above parameter - public EntityHierarchy connectedEntity = new EntityHierarchy(); + public EntityPath connectedEntity = new EntityPath(); } [Serializable] @@ -411,7 +411,7 @@ public TriggerSequence(ShortGuid id, bool autoGenerateParameters = false) : base public class Entity { public float timing = 0.0f; - public EntityHierarchy connectedEntity = new EntityHierarchy(); + public EntityPath connectedEntity = new EntityPath(); } [Serializable] public class Event @@ -433,9 +433,9 @@ public Event(ShortGuid start, ShortGuid end) [Serializable] [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct EntityLink + public struct EntityConnector { - public EntityLink(ShortGuid childEntityID, ShortGuid parentParam, ShortGuid childParam) + public EntityConnector(ShortGuid childEntityID, ShortGuid parentParam, ShortGuid childParam) { connectionID = ShortGuidUtils.GenerateRandom(); parentParamID = parentParam; @@ -450,142 +450,140 @@ public EntityLink(ShortGuid childEntityID, ShortGuid parentParam, ShortGuid chil } /// - /// This is a class to handle hierarchies pointing to entities in Commands. - /// Provides useful functionality for generating checksums (used for overrides in Commands), as well as composite instance IDs (used for legacy systems). - /// Also has methods of capturing the entity pointed to and writing the hierarchies neatly. - /// The hierarchy should always be written to Commands with a trailing ShortGuid.Invalid. + /// This provides a way to handle paths to instances of entities within the root composite instance. + /// The path should always be written to Commands with a trailing ShortGuid.Invalid. /// [Serializable] #if DEBUG - [JsonConverter(typeof(EntityHierarchyConverter))] + [JsonConverter(typeof(EntityPathConverter))] #endif - public class EntityHierarchy + public class EntityPath { - public EntityHierarchy() { } - public EntityHierarchy(List _hierarchy) + public EntityPath() { } + public EntityPath(List _path) { - hierarchy = _hierarchy; + path = _path; - if (hierarchy[hierarchy.Count - 1] != ShortGuid.Invalid) - hierarchy.Add(ShortGuid.Invalid); + if (path[path.Count - 1] != ShortGuid.Invalid) + path.Add(ShortGuid.Invalid); } - public List hierarchy = new List(); + public List path = new List(); - public static bool operator ==(EntityHierarchy x, EntityHierarchy y) + public static bool operator ==(EntityPath x, EntityPath y) { if (ReferenceEquals(x, null)) return ReferenceEquals(y, null); if (ReferenceEquals(y, null)) return ReferenceEquals(x, null); - if (x.hierarchy.Count != y.hierarchy.Count) return false; - for (int i = 0; i < x.hierarchy.Count; i++) + if (x.path.Count != y.path.Count) return false; + for (int i = 0; i < x.path.Count; i++) { - if (x.hierarchy[i].ToByteString() != y.hierarchy[i].ToByteString()) + if (x.path[i].ToByteString() != y.path[i].ToByteString()) return false; } return true; } - public static bool operator !=(EntityHierarchy x, EntityHierarchy y) + public static bool operator !=(EntityPath x, EntityPath y) { return !(x == y); } public override bool Equals(object obj) { - return obj is EntityHierarchy hierarchy && - EqualityComparer>.Default.Equals(this.hierarchy, hierarchy.hierarchy); + return obj is EntityPath hierarchy && + EqualityComparer>.Default.Equals(this.path, hierarchy.path); } public override int GetHashCode() { - return 218564712 + EqualityComparer>.Default.GetHashCode(hierarchy); + return 218564712 + EqualityComparer>.Default.GetHashCode(path); } - /* Get this hierarchy as a string */ - public string GetHierarchyAsString() + /* Get this path as a string */ + public string GetAsString() { string val = ""; - for (int i = 0; i < hierarchy.Count; i++) + for (int i = 0; i < path.Count; i++) { - val += hierarchy[i].ToByteString(); - if (i != hierarchy.Count - 1) val += " -> "; + val += path[i].ToByteString(); + if (i != path.Count - 1) val += " -> "; } return val; } - public string GetHierarchyAsString(Commands commands, Composite composite, bool withIDs = true) + public string GetAsString(Commands commands, Composite composite, bool withIDs = true) { - CommandsUtils.ResolveHierarchy(commands, composite, hierarchy, out Composite comp, out string str, withIDs); + CommandsUtils.ResolveHierarchy(commands, composite, path, out Composite comp, out string str, withIDs); return str; } public UInt32 ToUInt32() { UInt32 val = 0; - for (int i = 0; i < hierarchy.Count; i++) val += hierarchy[i].ToUInt32(); + for (int i = 0; i < path.Count; i++) val += path[i].ToUInt32(); return val; } - /* Get the entity this hierarchy points to: FROM THE ENTRY POINT OF THE COMMANDS */ + /* Get the entity this path points to: FROM THE ROOT OF THE COMMANDS */ public Entity GetPointedEntity(Commands commands) { - return CommandsUtils.ResolveHierarchy(commands, commands.EntryPoints[0], hierarchy, out Composite comp, out string str); + return CommandsUtils.ResolveHierarchy(commands, commands.EntryPoints[0], path, out Composite comp, out string str); } - /* Get the entity this hierarchy points to: FROM THE ENTRY POINT OF THE COMMANDS, RETURNING THE CONTAINED COMPOSITE */ + /* Get the entity this path points to: FROM THE ROOT OF THE COMMANDS, RETURNING THE CONTAINED COMPOSITE */ public Entity GetPointedEntity(Commands commands, out Composite containedComposite) { - Entity ent = CommandsUtils.ResolveHierarchy(commands, commands.EntryPoints[0], hierarchy, out Composite comp, out string str); + Entity ent = CommandsUtils.ResolveHierarchy(commands, commands.EntryPoints[0], path, out Composite comp, out string str); containedComposite = comp; return ent; } - /* Get the entity this hierarchy points to: FROM A SPECIFIED COMPOSITE */ + /* Get the entity this path points to: FROM A SPECIFIED COMPOSITE */ public Entity GetPointedEntity(Commands commands, Composite startComposite) { - return CommandsUtils.ResolveHierarchy(commands, startComposite, hierarchy, out Composite comp, out string str); + return CommandsUtils.ResolveHierarchy(commands, startComposite, path, out Composite comp, out string str); } - /* Get the entity this hierarchy points to: FROM A SPECIFIED COMPOSITE, RETURNING THE CONTAINED COMPOSITE */ + /* Get the entity this path points to: FROM A SPECIFIED COMPOSITE, RETURNING THE CONTAINED COMPOSITE */ public Entity GetPointedEntity(Commands commands, Composite startComposite, out Composite containedComposite) { - Entity ent = CommandsUtils.ResolveHierarchy(commands, startComposite, hierarchy, out Composite comp, out string str); + Entity ent = CommandsUtils.ResolveHierarchy(commands, startComposite, path, out Composite comp, out string str); containedComposite = comp; return ent; } - /* Get the ID of the entity that this hierarchy points to */ + /* Get the ID of the entity that this path points to */ public ShortGuid GetPointedEntityID() { - hierarchy.Reverse(); + path.Reverse(); ShortGuid id = ShortGuid.Invalid; - for (int i = 0; i < hierarchy.Count; i++) + for (int i = 0; i < path.Count; i++) { - if (hierarchy[i] == ShortGuid.Invalid) continue; - id = hierarchy[i]; + if (path[i] == ShortGuid.Invalid) continue; + id = path[i]; break; } - hierarchy.Reverse(); + path.Reverse(); return id; } - /* Does this hierarchy point to a valid entity? */ - public bool IsHierarchyValid(Commands commands, Composite composite) + /* Does this path point to a valid entity? */ + public bool IsPathValid(Commands commands, Composite composite) { return GetPointedEntity(commands, composite) != null; } - /* Generate the checksum used identify the hierarchy */ - public ShortGuid GenerateChecksum() + /* Generate the checksum used identify the path */ + public ShortGuid GeneratePathHash() { - if (hierarchy.Count == 0) return ShortGuid.Invalid; - if (hierarchy[hierarchy.Count - 1] != ShortGuid.Invalid) hierarchy.Add(ShortGuid.Invalid); + if (path.Count == 0) return ShortGuid.Invalid; + if (path[path.Count - 1] != ShortGuid.Invalid) path.Add(ShortGuid.Invalid); - hierarchy.Reverse(); - ShortGuid checksumGenerated = hierarchy[0]; - for (int i = 0; i < hierarchy.Count; i++) + path.Reverse(); + ShortGuid checksumGenerated = path[0]; + for (int i = 0; i < path.Count; i++) { - checksumGenerated = checksumGenerated.Combine(hierarchy[i + 1]); - if (i == hierarchy.Count - 2) break; + checksumGenerated = checksumGenerated.Combine(path[i + 1]); + if (i == path.Count - 2) break; } - hierarchy.Reverse(); + path.Reverse(); return checksumGenerated; } @@ -595,43 +593,43 @@ public ShortGuid GenerateInstance() { //TODO: This hijacks the usual use for this class, need to tidy it up ShortGuid entityID = GetPointedEntityID(); - hierarchy.Insert(0, ShortGuid.InitialiserBase); - hierarchy.Remove(entityID); - hierarchy.Reverse(); - ShortGuid instanceGenerated = hierarchy[0]; - for (int i = 0; i < hierarchy.Count; i++) + path.Insert(0, ShortGuid.InitialiserBase); + path.Remove(entityID); + path.Reverse(); + ShortGuid instanceGenerated = path[0]; + for (int i = 0; i < path.Count; i++) { - if (i == hierarchy.Count - 1) break; - instanceGenerated = hierarchy[i + 1].Combine(instanceGenerated); + if (i == path.Count - 1) break; + instanceGenerated = path[i + 1].Combine(instanceGenerated); } - hierarchy.Reverse(); - hierarchy.RemoveAt(0); - hierarchy.RemoveAll(o => o == ShortGuid.Invalid); - hierarchy.Add(entityID); - hierarchy.Add(ShortGuid.Invalid); + path.Reverse(); + path.RemoveAt(0); + path.RemoveAll(o => o == ShortGuid.Invalid); + path.Add(entityID); + path.Add(ShortGuid.Invalid); return instanceGenerated; } } #if DEBUG - public class EntityHierarchyConverter : JsonConverter + public class EntityPathConverter : JsonConverter { public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { - writer.WriteValue(((EntityHierarchy)value).GetHierarchyAsString()); + writer.WriteValue(((EntityPath)value).GetAsString()); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { - EntityHierarchy e = new EntityHierarchy(); + EntityPath e = new EntityPath(); List vals = reader.Value.ToString().Split(new[] { " -> " }, StringSplitOptions.None).ToList(); - for (int i = 0; i < vals.Count; i++) e.hierarchy.Add(new ShortGuid(vals[i])); + for (int i = 0; i < vals.Count; i++) e.path.Add(new ShortGuid(vals[i])); return e; } public override bool CanConvert(Type objectType) { - return objectType == typeof(EntityHierarchy); + return objectType == typeof(EntityPath); } } #endif diff --git a/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/TypeEnums.cs b/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/TypeEnums.cs index 1b1d90e..fa4251f 100644 --- a/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/TypeEnums.cs +++ b/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/TypeEnums.cs @@ -11,7 +11,7 @@ public enum EntityVariant FUNCTION, PROXY, - OVERRIDE, + ALIAS, } /* Parameter variants */ @@ -1082,20 +1082,20 @@ namespace CATHODE.Scripting.Internal /* Blocks of data in each compiled composite */ public enum CompositeFileData { - COMPOSITE_HEADER, //Defines the header of the composite, with global ID and string name - ENTITY_CONNECTIONS, //Defines the links between entities in the composite - ENTITY_PARAMETERS, //Defines parameters to be applied to entities in the composite - ENTITY_OVERRIDES, //Defines overrides to apply to nested instances of composites in this composite - ENTITY_OVERRIDES_CHECKSUM, //Defines a checksum value for the hierarchy override (TODO) - COMPOSITE_EXPOSED_PARAMETERS, //Defines variables which are exposed when instancing this composite which are then connected in to entities (think variable pins in UE4 blueprint) - ENTITY_PROXIES, //Defines "proxies" similar to the overrides hierarchy (TODO) - ENTITY_FUNCTIONS, //Defines entities with an attached script function within Cathode - RESOURCE_REFERENCES, //Defines renderable data which is referenced by entities in this composite - CAGEANIMATION_DATA, //Appears to define additional data for CAGEAnimation type entities (TODO) - TRIGGERSEQUENCE_DATA, //Appears to define additional data for TriggerSequence type entities (TODO) - UNUSED, //Unused values + HEADER, //Defines the header of the composite, with global ID and string name + ENTITY_CONNECTIONS, //Defines the links between entities in the composite + ENTITY_PARAMETERS, //Defines parameters to be applied to entities in the composite + ALIASES, //Defines aliases to entities within child instances of composites in this composite + ALIAS_PATH_HASHES, //Defines a hash of the instanced path to the aliased entity + VARIABLES, //Defines variables which are exposed when instancing this composite + PROXIES, //Defines proxies which can act as entities within other composites + FUNCTION_ENTITIES, //Defines entities with an attached script function within Cathode (or composite instance) + RESOURCE_REFERENCES, //Defines references to resources within the level used by entities inside the composite + CAGEANIMATION_DATA, //Defines keyframe data for CAGEAnimation type entities + TRIGGERSEQUENCE_DATA, //Defines sequenced data for TriggerSequence type entities + UNUSED, //Unused values (?) - NUMBER_OF_SCRIPT_BLOCKS, //THIS IS NOT A DATA BLOCK: merely used as an easy way of sanity checking the number of blocks in-code! + NUMBER_OF_SCRIPT_BLOCKS, //THIS IS NOT A DATA BLOCK: merely used as an easy way of sanity checking the number of blocks in-code! } /* Custom tables written at the end of the PAK to store extra info */ diff --git a/CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/CommandsUtils.cs b/CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/CommandsUtils.cs index e3a478e..e7b7a5a 100644 --- a/CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/CommandsUtils.cs +++ b/CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/CommandsUtils.cs @@ -223,9 +223,9 @@ public static Entity ResolveHierarchy(Commands commands, Composite composite, Li /* Generate all possible hierarchies for an entity */ private static List> _hierarchies = new List>(); - public static List GenerateHierarchies(Commands commands, Composite composite, Entity entity) + public static List GenerateHierarchies(Commands commands, Composite composite, Entity entity) { - List hierarchies = new List(); + List hierarchies = new List(); _hierarchies.Clear(); GenerateHierarchiesRecursive(commands, null, commands.EntryPoints[0], composite, new List()); @@ -233,7 +233,7 @@ public static List GenerateHierarchies(Commands commands, Compo for (int i = 0; i < _hierarchies.Count; i++) { _hierarchies[i].Add(entity.shortGUID); - hierarchies.Add(new EntityHierarchy(_hierarchies[i])); + hierarchies.Add(new EntityPath(_hierarchies[i])); } return hierarchies; @@ -262,8 +262,8 @@ public static void PurgeDeadLinks(Commands commands, Composite composite) int originalUnknownCount = 0; int originalProxyCount = 0; int newProxyCount = 0; - int originalOverrideCount = 0; - int newOverrideCount = 0; + int originalAliasCount = 0; + int newAliasCount = 0; int originalTriggerCount = 0; int newTriggerCount = 0; int originalAnimCount = 0; @@ -282,19 +282,19 @@ public static void PurgeDeadLinks(Commands commands, Composite composite) newFuncCount += functionsPurged.Count; composite.functions = functionsPurged; - //Clear overrides - List overridePurged = new List(); - for (int i = 0; i < composite.overrides.Count; i++) - if (ResolveHierarchy(commands, composite, composite.overrides[i].connectedEntity.hierarchy, out Composite flowTemp, out string hierarchy) != null) - overridePurged.Add(composite.overrides[i]); - originalOverrideCount += composite.overrides.Count; - newOverrideCount += overridePurged.Count; - composite.overrides = overridePurged; + //Clear aliases + List aliasesPurged = new List(); + for (int i = 0; i < composite.aliases.Count; i++) + if (ResolveHierarchy(commands, composite, composite.aliases[i].connectedEntity.path, out Composite flowTemp, out string hierarchy) != null) + aliasesPurged.Add(composite.aliases[i]); + originalAliasCount += composite.aliases.Count; + newAliasCount += aliasesPurged.Count; + composite.aliases = aliasesPurged; //Clear proxies List proxyPurged = new List(); for (int i = 0; i < composite.proxies.Count; i++) - if (ResolveHierarchy(commands, composite, composite.proxies[i].connectedEntity.hierarchy, out Composite flowTemp, out string hierarchy) != null) + if (ResolveHierarchy(commands, composite, composite.proxies[i].connectedEntity.path, out Composite flowTemp, out string hierarchy) != null) proxyPurged.Add(composite.proxies[i]); originalProxyCount += composite.proxies.Count; newProxyCount += proxyPurged.Count; @@ -310,7 +310,7 @@ public static void PurgeDeadLinks(Commands commands, Composite composite) TriggerSequence trig = (TriggerSequence)composite.functions[i]; List trigSeq = new List(); for (int x = 0; x < trig.entities.Count; x++) - if (ResolveHierarchy(commands, composite, trig.entities[x].connectedEntity.hierarchy, out Composite flowTemp, out string hierarchy) != null) + if (ResolveHierarchy(commands, composite, trig.entities[x].connectedEntity.path, out Composite flowTemp, out string hierarchy) != null) trigSeq.Add(trig.entities[x]); originalTriggerCount += trig.entities.Count; newTriggerCount += trigSeq.Count; @@ -324,7 +324,7 @@ public static void PurgeDeadLinks(Commands commands, Composite composite) List anim_target = anim.animations.FindAll(o => o.shortGUID == anim.connections[x].keyframeID); List event_target = anim.events.FindAll(o => o.shortGUID == anim.connections[x].keyframeID); if (!(anim_target.Count == 0 && event_target.Count == 0) && - ResolveHierarchy(commands, composite, anim.connections[x].connectedEntity.hierarchy, out Composite flowTemp, out string hierarchy) != null) + ResolveHierarchy(commands, composite, anim.connections[x].connectedEntity.path, out Composite flowTemp, out string hierarchy) != null) headers.Add(anim.connections[x]); } originalAnimCount += anim.connections.Count; @@ -338,7 +338,7 @@ public static void PurgeDeadLinks(Commands commands, Composite composite) List entities = composite.GetEntities(); for (int i = 0; i < entities.Count; i++) { - List childLinksPurged = new List(); + List childLinksPurged = new List(); for (int x = 0; x < entities[i].childLinks.Count; x++) if (composite.GetEntityByID(entities[i].childLinks[x].childID) != null) childLinksPurged.Add(entities[i].childLinks[x]); @@ -350,7 +350,7 @@ public static void PurgeDeadLinks(Commands commands, Composite composite) if (originalUnknownCount + (originalFuncCount - newFuncCount) + (originalProxyCount - newProxyCount) + - (originalOverrideCount - newOverrideCount) + + (originalAliasCount - newAliasCount) + (originalTriggerCount - newTriggerCount) + (originalAnimCount - newAnimCount) + (originalLinkCount - newLinkCount) == 0) @@ -360,7 +360,7 @@ public static void PurgeDeadLinks(Commands commands, Composite composite) "\n - " + originalUnknownCount + " unknown entities" + "\n - " + (originalFuncCount - newFuncCount) + " functions (of " + originalFuncCount + ")" + "\n - " + (originalProxyCount - newProxyCount) + " proxies (of " + originalProxyCount + ")" + - "\n - " + (originalOverrideCount - newOverrideCount) + " overrides (of " + originalOverrideCount + ")" + + "\n - " + (originalAliasCount - newAliasCount) + " aliases (of " + originalAliasCount + ")" + "\n - " + (originalTriggerCount - newTriggerCount) + " triggers (of " + originalTriggerCount + ")" + "\n - " + (originalAnimCount - newAnimCount) + " anim connections (of " + originalAnimCount + ")" + "\n - " + (originalLinkCount - newLinkCount) + " entity links (of " + originalLinkCount + ")"); diff --git a/CathodeLib/Scripts/Utilities.cs b/CathodeLib/Scripts/Utilities.cs index 1ff0935..b184f3d 100644 --- a/CathodeLib/Scripts/Utilities.cs +++ b/CathodeLib/Scripts/Utilities.cs @@ -311,7 +311,7 @@ public class CommandsEntityReference public ShortGuid composite_instance_id = ShortGuid.Invalid; //The instance of the composite this entity is in when created via hierarchy public CommandsEntityReference() { } - public CommandsEntityReference(EntityHierarchy hierarchy) + public CommandsEntityReference(EntityPath hierarchy) { entity_id = hierarchy.GetPointedEntityID(); composite_instance_id = hierarchy.GenerateInstance(); From f1afc1aed07b5ff9851e6ac1ef825ac410dc2571 Mon Sep 17 00:00:00 2001 From: MattFiler Date: Fri, 8 Sep 2023 22:25:44 +0100 Subject: [PATCH 09/30] renaming connectedEntity --- CathodeLib/Scripts/CATHODE/Commands.cs | 20 +++++++++---------- .../CATHODE/CommandsPAK/Components/Entity.cs | 18 ++++++++--------- .../CommandsPAK/Helpers/CommandsUtils.cs | 4 ++-- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/CathodeLib/Scripts/CATHODE/Commands.cs b/CathodeLib/Scripts/CATHODE/Commands.cs index 9aa3f48..0aa5cdd 100644 --- a/CathodeLib/Scripts/CATHODE/Commands.cs +++ b/CathodeLib/Scripts/CATHODE/Commands.cs @@ -184,7 +184,7 @@ override protected bool LoadInternal() reader_parallel.BaseStream.Position = (offsetPairs[x].GlobalOffset * 4) + (y * 12); AliasEntity overrider = new AliasEntity(new ShortGuid(reader_parallel)); int NumberOfParams = JumpToOffset(reader_parallel); - overrider.connectedEntity.path.AddRange(Utilities.ConsumeArray(reader_parallel, NumberOfParams)); + overrider.alias.path.AddRange(Utilities.ConsumeArray(reader_parallel, NumberOfParams)); composite.aliases.Add(overrider); break; } @@ -209,11 +209,11 @@ override protected bool LoadInternal() ProxyEntity thisProxy = new ProxyEntity(new ShortGuid(reader_parallel)); int resetPos = (int)reader_parallel.BaseStream.Position + 8; //TODO: This is a HACK - I need to rework JumpToOffset to make a temp stream int NumberOfParams = JumpToOffset(reader_parallel); - thisProxy.connectedEntity.path.AddRange(Utilities.ConsumeArray(reader_parallel, NumberOfParams)); //Last is always 0x00, 0x00, 0x00, 0x00 + thisProxy.proxy.path.AddRange(Utilities.ConsumeArray(reader_parallel, NumberOfParams)); //Last is always 0x00, 0x00, 0x00, 0x00 reader_parallel.BaseStream.Position = resetPos; ShortGuid idCheck = new ShortGuid(reader_parallel); if (idCheck != thisProxy.shortGUID) throw new Exception("Proxy ID mismatch!"); - thisProxy.targetType = new ShortGuid(reader_parallel); + thisProxy.function = new ShortGuid(reader_parallel); composite.proxies.Add(thisProxy); break; } @@ -627,7 +627,7 @@ override protected bool SaveInternal() linkedEntities[i] = new List(ents.FindAll(o => o.childLinks.Count != 0)).OrderBy(o => o.shortGUID.ToUInt32()).ToList(); parameterisedEntities[i] = new List(ents.FindAll(o => o.parameters.Count != 0)).OrderBy(o => o.shortGUID.ToUInt32()).ToList(); reshuffledAliases[i] = Entries[i].aliases.OrderBy(o => o.shortGUID.ToUInt32()).ToList(); - reshuffledAliasPathHashes[i] = Entries[i].aliases.OrderBy(o => o.connectedEntity.GeneratePathHash().ToUInt32()).ToList(); + reshuffledAliasPathHashes[i] = Entries[i].aliases.OrderBy(o => o.alias.GeneratePathHash().ToUInt32()).ToList(); cageAnimationEntities[i] = new List(); triggerSequenceEntities[i] = new List(); @@ -842,8 +842,8 @@ override protected bool SaveInternal() List offsetPairs = new List(reshuffledAliases[i].Count); for (int p = 0; p < reshuffledAliases[i].Count; p++) { - offsetPairs.Add(new OffsetPair(writer.BaseStream.Position, reshuffledAliases[i][p].connectedEntity.path.Count)); - Utilities.Write(writer, reshuffledAliases[i][p].connectedEntity.path); + offsetPairs.Add(new OffsetPair(writer.BaseStream.Position, reshuffledAliases[i][p].alias.path.Count)); + Utilities.Write(writer, reshuffledAliases[i][p].alias.path); } scriptPointerOffsetInfo[x] = new OffsetPair(writer.BaseStream.Position, reshuffledAliases[i].Count); @@ -861,7 +861,7 @@ override protected bool SaveInternal() for (int p = 0; p < reshuffledAliasPathHashes[i].Count; p++) { writer.Write(reshuffledAliasPathHashes[i][p].shortGUID.val); - writer.Write(reshuffledAliasPathHashes[i][p].connectedEntity.GeneratePathHash().val); + writer.Write(reshuffledAliasPathHashes[i][p].alias.GeneratePathHash().val); } break; } @@ -881,8 +881,8 @@ override protected bool SaveInternal() List offsetPairs = new List(); for (int p = 0; p < Entries[i].proxies.Count; p++) { - offsetPairs.Add(new OffsetPair(writer.BaseStream.Position, Entries[i].proxies[p].connectedEntity.path.Count)); - Utilities.Write(writer, Entries[i].proxies[p].connectedEntity.path); + offsetPairs.Add(new OffsetPair(writer.BaseStream.Position, Entries[i].proxies[p].proxy.path.Count)); + Utilities.Write(writer, Entries[i].proxies[p].proxy.path); } scriptPointerOffsetInfo[x] = new OffsetPair(writer.BaseStream.Position, offsetPairs.Count); @@ -892,7 +892,7 @@ override protected bool SaveInternal() writer.Write(offsetPairs[p].GlobalOffset / 4); writer.Write(offsetPairs[p].EntryCount); writer.Write(Entries[i].proxies[p].shortGUID.val); - writer.Write(Entries[i].proxies[p].targetType.val); + writer.Write(Entries[i].proxies[p].function.val); } break; } diff --git a/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Entity.cs b/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Entity.cs index 5413231..3a477e5 100644 --- a/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Entity.cs +++ b/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Entity.cs @@ -297,20 +297,20 @@ public ProxyEntity(ShortGuid shortGUID) : base(shortGUID, EntityVariant.PROXY) { public ProxyEntity(List hierarchy = null, ShortGuid targetType = new ShortGuid(), bool autoGenerateParameters = false) : base(EntityVariant.PROXY) { - this.targetType = targetType; - if (hierarchy != null) this.connectedEntity.path = hierarchy; + this.function = targetType; + if (hierarchy != null) this.proxy.path = hierarchy; if (autoGenerateParameters) EntityUtils.ApplyDefaults(this); } public ProxyEntity(ShortGuid shortGUID, List hierarchy = null, ShortGuid targetType = new ShortGuid(), bool autoGenerateParameters = false) : base(shortGUID, EntityVariant.PROXY) { this.shortGUID = shortGUID; - this.targetType = targetType; - if (hierarchy != null) this.connectedEntity.path = hierarchy; + this.function = targetType; + if (hierarchy != null) this.proxy.path = hierarchy; if (autoGenerateParameters) EntityUtils.ApplyDefaults(this); } - public ShortGuid targetType; //The "function" value on the entity we're pointing to - public EntityPath connectedEntity = new EntityPath(); + public ShortGuid function; //The "function" value on the entity we're proxying + public EntityPath proxy = new EntityPath(); //A path to the entity we're proxying } [Serializable] public class AliasEntity : Entity @@ -320,15 +320,15 @@ public AliasEntity(ShortGuid shortGUID) : base(shortGUID, EntityVariant.ALIAS) { public AliasEntity(List hierarchy = null) : base(EntityVariant.ALIAS) { - if (hierarchy != null) this.connectedEntity.path = hierarchy; + if (hierarchy != null) this.alias.path = hierarchy; } public AliasEntity(ShortGuid shortGUID, List hierarchy = null) : base(shortGUID, EntityVariant.ALIAS) { this.shortGUID = shortGUID; - if (hierarchy != null) this.connectedEntity.path = hierarchy; + if (hierarchy != null) this.alias.path = hierarchy; } - public EntityPath connectedEntity = new EntityPath(); + public EntityPath alias = new EntityPath(); //A path to the entity we're an alias of } #region SPECIAL FUNCTION ENTITIES diff --git a/CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/CommandsUtils.cs b/CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/CommandsUtils.cs index e7b7a5a..8a17e60 100644 --- a/CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/CommandsUtils.cs +++ b/CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/CommandsUtils.cs @@ -285,7 +285,7 @@ public static void PurgeDeadLinks(Commands commands, Composite composite) //Clear aliases List aliasesPurged = new List(); for (int i = 0; i < composite.aliases.Count; i++) - if (ResolveHierarchy(commands, composite, composite.aliases[i].connectedEntity.path, out Composite flowTemp, out string hierarchy) != null) + if (ResolveHierarchy(commands, composite, composite.aliases[i].alias.path, out Composite flowTemp, out string hierarchy) != null) aliasesPurged.Add(composite.aliases[i]); originalAliasCount += composite.aliases.Count; newAliasCount += aliasesPurged.Count; @@ -294,7 +294,7 @@ public static void PurgeDeadLinks(Commands commands, Composite composite) //Clear proxies List proxyPurged = new List(); for (int i = 0; i < composite.proxies.Count; i++) - if (ResolveHierarchy(commands, composite, composite.proxies[i].connectedEntity.path, out Composite flowTemp, out string hierarchy) != null) + if (ResolveHierarchy(commands, composite, composite.proxies[i].proxy.path, out Composite flowTemp, out string hierarchy) != null) proxyPurged.Add(composite.proxies[i]); originalProxyCount += composite.proxies.Count; newProxyCount += proxyPurged.Count; From 3091059356a14acec119f88525a174255ce648a9 Mon Sep 17 00:00:00 2001 From: MattFiler Date: Sun, 10 Sep 2023 16:58:49 +0100 Subject: [PATCH 10/30] transform + transform --- .../CATHODE/CommandsPAK/Components/ParameterData.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/ParameterData.cs b/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/ParameterData.cs index dd2f693..52f12d5 100644 --- a/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/ParameterData.cs +++ b/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/ParameterData.cs @@ -154,7 +154,15 @@ public cTransform(Vector3 position, Vector3 rotation) } public Vector3 position = new Vector3(); - public Vector3 rotation = new Vector3(); //In CATHODE this is named Roll/Pitch/Yaw + public Vector3 rotation = new Vector3(); //In CATHODE this is named Roll/Pitch/Yaw - but we handle it as euler X,Y,Z + + public static cTransform operator +(cTransform x, cTransform y) + { + if (x == null) return y; + if (y == null) return x; + + return new cTransform(x.position + y.position, x.rotation + y.rotation); + } public override string ToString() { From 37ffe536669a7efdd25cceb60d337e0828393211 Mon Sep 17 00:00:00 2001 From: MattFiler Date: Tue, 12 Sep 2023 23:42:02 +0100 Subject: [PATCH 11/30] sync new indexes from dan --- CathodeLib/Scripts/LEGACY_DAN/ShadersPAK.cs | 271 +++++++++++--------- 1 file changed, 153 insertions(+), 118 deletions(-) diff --git a/CathodeLib/Scripts/LEGACY_DAN/ShadersPAK.cs b/CathodeLib/Scripts/LEGACY_DAN/ShadersPAK.cs index df3541f..0a74132 100644 --- a/CathodeLib/Scripts/LEGACY_DAN/ShadersPAK.cs +++ b/CathodeLib/Scripts/LEGACY_DAN/ShadersPAK.cs @@ -1,4 +1,4 @@ -using CathodeLib; +using CathodeLib; using System; using System.Collections.Generic; using System.IO; @@ -62,106 +62,115 @@ private MaterialPropertyIndex GetMaterialPropertyIndexes(Materials.Material InMa switch ((ShaderCategory)Shader.Header2.ShaderCategory) { case ShaderCategory.CA_ENVIRONMENT: - toReturn.Unknown3_Index = 3; - toReturn.OpacityUVMultiplierIndex = 5; - toReturn.DiffuseUVMultiplierIndex = 6; - toReturn.DiffuseIndex = 7; - toReturn.SecondaryDiffuseUVMultiplierIndex = 8; - toReturn.SecondaryDiffuseIndex = 9; - toReturn.NormalUVMultiplierIndex = 10; - toReturn.NormalMapStrength0Index = 11; - toReturn.SecondaryNormalUVMultiplierIndex = 12; - toReturn.NormalMapStrength1Index = 13; - toReturn.SpecularFactorIndex = 14; - toReturn.SpecularUVMultiplierIndex = 15; - toReturn.MetallicFactorIndex = 16; - toReturn.SecondarySpecularFactorIndex = 17; - toReturn.SecondarySpecularUVMultiplierIndex = 18; - toReturn.SecondaryMetallicFactorIndex = 19; - toReturn.EnvironmentMapStrength2Index = 24; - toReturn.EnvironmentMapStrengthIndex = 25; - toReturn.DirtDiffuseIndex = -1; // TODO: ... - toReturn.OcclusionUVMultiplierIndex = 27; - toReturn.OcclusionTintIndex = 28; - toReturn.EmissiveFactorIndex = 29; - toReturn.EmissiveIndex = 30; - toReturn.ParallaxUVMultiplierIndex = 35; - toReturn.ParallaxFactorIndex = 36; - toReturn.ParallaxOffsetIndex = 37; - toReturn.IsTransparentIndex = 38; - toReturn.OpacityNoiseUVMultiplierIndex1 = 39; - toReturn.OpacityNoiseAmplitudeIndex = 40; - toReturn.DirtMapUVMultiplier0Index = 47; - toReturn.DirtMapUVMultiplier1Index = 48; - toReturn.DirtStrengthIndex = 49; + toReturn.Unknown3_ = 3; + toReturn.OpacityMapUVMultiplier = 5; + toReturn.DiffuseMap0UVMultiplier = 6; + toReturn.Diffuse0 = 7; + toReturn.DiffuseMap1UVMultiplier = 8; + toReturn.Diffuse1 = 9; + toReturn.NormalMap0UVMultiplier = 10; + toReturn.NormalMap0Strength = 11; + toReturn.NormalMap1UVMultiplier = 12; + toReturn.NormalMap1Strength = 13; + + toReturn.SpecularFactor0 = 14; + toReturn.SpecularMap0UVMultiplier = 15; + toReturn.MetallicFactor0 = 16; + + toReturn.SpecularFactor1 = 17; + toReturn.SpecularMap1UVMultiplier = 18; + toReturn.MetallicFactor1 = 19; + + toReturn.EnvironmentMapEmission = 24; + toReturn.EnvironmentMapStrength = 25; + + toReturn.OcclusionMapUVMultiplier = 27; + toReturn.OcclusionTint = 28; + + // NOTE: We should multiply 'StabilityHack' here instead, but we do it after the probe step + // to make the lighting more stable. Not sure if this is physically correct, but the result looks similar. + toReturn.EmissiveFactor = 29; + toReturn.Emission = 30; + + toReturn.ParallaxMapUVMultiplier = 35; + toReturn.ParallaxFactor = 36; + toReturn.ParallaxOffset = 37; + + toReturn.IsTransparent = 38; + + toReturn.OpacityNoiseMapUVMultiplier = 39; + toReturn.OpacityNoiseAmplitude = 40; + + toReturn.DirtPower = 47; + toReturn.DirtUVMultiplier = 48; + toReturn.DirtStrength = 49; break; case ShaderCategory.CA_CHARACTER: - toReturn.OpacityNoiseUVMultiplierIndex1 = 12; - toReturn.DiffuseUVMultiplierIndex = 15; - toReturn.DiffuseIndex = 16; - toReturn.SecondaryDiffuseUVMultiplierIndex = 17; - toReturn.SecondaryDiffuseIndex = 18; - toReturn.NormalUVMultiplierIndex = 19; - toReturn.SecondaryNormalUVMultiplierIndex = 21; - toReturn.SpecularUVMultiplierIndex = 24; - toReturn.SpecularFactorIndex = 25; - break; + toReturn.OpacityNoiseMapUVMultiplier = 12; + toReturn.DiffuseMap0UVMultiplier = 15; + toReturn.Diffuse0 = 16; - case ShaderCategory.CA_SKIN: - toReturn.DiffuseUVMultiplierIndex = 4; - toReturn.DiffuseIndex = 5; - toReturn.NormalUVMultiplierIndex = 8; - toReturn.NormalUVMultiplierOfMultiplierIndex = 10; - toReturn.SecondaryNormalUVMultiplierIndex = 11; - break; + toReturn.DiffuseMap1UVMultiplier = 17; + toReturn.Diffuse1 = 18; - case ShaderCategory.CA_HAIR: - toReturn.DiffuseIndex = 2; - break; + toReturn.NormalMap0UVMultiplier = 19; + toReturn.NormalMap0Strength = 20; + toReturn.NormalMap1UVMultiplier = 21; + toReturn.NormalMap1Strength = 22; - case ShaderCategory.CA_EYE: - toReturn.DiffuseUVAdderIndex = 3; - // TODO: These three determine the iris color. They map to rgb channels of the iris map. - // I am using the middle color for now for everything but we should not do that. - //toReturn.ColorIndex = 7; - toReturn.DiffuseIndex = 8; - //toReturn.ColorIndex = 9; - toReturn.DiffuseUVMultiplierIndex = 10; - - // TODO: This info is available in 'Shader->TextureEntries[CorrectIndex].TextureAddressMode'. - toReturn.DiffuseSamplerIndex = 0; - break; + toReturn.SpecularMap0UVMultiplier = 24; + toReturn.SpecularFactor0 = 25; - case ShaderCategory.CA_DECAL: - //toReturn.ColorIndex = 3; - //Material->BaseColor = {}; + // TODO: Find out about these? + //toReturn.MetallicFactor0 = 1; + //toReturn.OcclusionTint = + //toReturn.OpacityNoiseMapUVMultiplier = 1; break; - case ShaderCategory.CA_FOGPLANE: - //toReturn.DiffuseIndex = 8; - //Material.BaseColor = { }; - break; + case ShaderCategory.CA_SKIN: + toReturn.DiffuseMap0UVMultiplier = 4; + toReturn.Diffuse0 = 5; - case ShaderCategory.CA_REFRACTION: - toReturn.DiffuseUVMultiplierIndex = 3; + toReturn.NormalMap0UVMultiplier = 8; + toReturn.NormalMap0Strength = 9; + toReturn.NormalMap0UVMultiplierOfMultiplier = 10; + toReturn.NormalMap1UVMultiplier = 11; break; - case ShaderCategory.CA_TERRAIN: - toReturn.DiffuseIndex = 4; - break; + case ShaderCategory.CA_HAIR: + toReturn.DiffuseMap0UVMultiplier = 1; + toReturn.Diffuse0 = 2; - case ShaderCategory.CA_LIGHTMAP_ENVIRONMENT: - toReturn.DiffuseIndex = 12; + toReturn.NormalMap0Strength = 9; + toReturn.NormalMap0UVMultiplier = 8; + toReturn.SpecularMap0UVMultiplier = 7; break; - case ShaderCategory.CA_CAMERA_MAP: - //DiffuseFallback = V4(1); + case ShaderCategory.CA_EYE: + toReturn.Unknown0_ = 0; + toReturn.RetinaRadius = 1; + toReturn.IrisParallaxDisplacement = 2; + toReturn.LimbalSmoothRadius = 3; + toReturn.RetinaIndexOfRefraction = 4; // I think this is the index of refraction of a retina. + //Assert(toReturn.RetinaIndexOfRefraction >= 1; + toReturn.PupilDilation = 5; + toReturn.ScatterMapMultiplier = 6; + + toReturn.Iris0 = 7; + toReturn.Iris1 = 8; + toReturn.Iris2 = 9; + toReturn.NormalMapUVMultiplier = 10; + toReturn.NormalMapStrength = 11; + toReturn.EnvironmentMapStrength = 12; + toReturn.Unknown13_ = 13; + //toReturn.ScatterMap.SamplerIndex = ADDRESS_MODE_CLAMP_TO_BORDER; break; - case ShaderCategory.CA_PLANET: - //DiffuseFallback = V4(1); + case ShaderCategory.CA_LIGHTMAP_ENVIRONMENT: + toReturn.Diffuse0 = 12; break; + } return toReturn; @@ -440,41 +449,67 @@ public class MaterialTextureContext public class MaterialPropertyIndex { - public UInt16 DiffuseSamplerIndex = 1; - public int OpacityUVMultiplierIndex = -1; - public int DiffuseUVMultiplierIndex = -1; - public int DiffuseUVAdderIndex = -1; - public int SpecularFactorIndex = -1; - public int MetallicFactorIndex = -1; - public int SecondaryDiffuseUVMultiplierIndex = -1; - public int NormalUVMultiplierIndex = -1; - public int NormalUVMultiplierOfMultiplierIndex = -1; - public int NormalMapStrength0Index = -1; - public int NormalMapStrength1Index = -1; - public int SecondaryNormalUVMultiplierIndex = -1; - public int SpecularUVMultiplierIndex = -1; - public int SecondarySpecularUVMultiplierIndex = -1; - public int SecondarySpecularFactorIndex = -1; - public int SecondaryMetallicFactorIndex = -1; - public int DirtMapUVMultiplier0Index = -1; - public int DirtMapUVMultiplier1Index = -1; - public int DirtDiffuseIndex = -1; - public int DirtStrengthIndex = -1; - public int EmissiveFactorIndex = -1; - public int EmissiveIndex = -1; - public int EnvironmentMapStrengthIndex = -1; - public int OpacityNoiseUVMultiplierIndex1 = -1; - public int OpacityNoiseAmplitudeIndex = -1; - public int DiffuseIndex = -1; - public int SecondaryDiffuseIndex = -1; - public int OcclusionUVMultiplierIndex = -1; - public int OcclusionTintIndex = -1; - public int IsTransparentIndex = -1; - public int EnvironmentMapStrength2Index = -1; - public int Unknown3_Index = -1; - public int ParallaxUVMultiplierIndex = -1; - public int ParallaxFactorIndex = -1; - public int ParallaxOffsetIndex = -1; + public int Diffuse0; + public int Diffuse1; + public int DiffuseMap0; + public int DiffuseMap0UVMultiplier; + public int DiffuseMap1; + public int DiffuseMap1UVMultiplier; + public int DirtMap; + public int DirtPower; + public int DirtStrength; + public int DirtUVMultiplier; + public int Emission; + public int EmissiveFactor; + public int EnvironmentMap; + public int EnvironmentMapEmission; + public int EnvironmentMapStrength; + public int FresnelLUT; + public int Iris0; + public int Iris1; + public int Iris2; + public int IrisParallaxDisplacement; + public int IsTransparent; + public int LimbalSmoothRadius; + public int Metallic; + public int MetallicFactor0; + public int MetallicFactor1; + public int NormalMap0; + public int NormalMap0Strength; + public int NormalMap0UVMultiplier; + public int NormalMap0UVMultiplierOfMultiplier; + public int NormalMap1; + public int NormalMap1Strength; + public int NormalMap1UVMultiplier; + public int NormalMapStrength; + public int NormalMapUVMultiplier; + public int OcclusionMap; + public int OcclusionMapUVMultiplier; + public int OcclusionTint; + public int OpacityMap; + public int OpacityMapUVMultiplier; + public int OpacityNoiseAmplitude; + public int OpacityNoiseMap; + public int OpacityNoiseMapUVMultiplier; + public int ParallaxFactor; + public int ParallaxMap; + public int ParallaxMapUVMultiplier; + public int ParallaxOffset; + public int PupilDilation; + public int RetinaIndexOfRefraction; + public int RetinaRadius; + public int ScatterMapMultiplier; + public int SpecularFactor0; + public int SpecularFactor1; + public int SpecularMap0; + public int SpecularMap0UVMultiplier; + public int SpecularMap1; + public int SpecularMap1UVMultiplier; + public int Unknown0_; + public int Unknown13_; + public int Unknown1_; + public int Unknown3_; + public int WetnessNoiseMap; } public enum ShaderSlot From 89ec572396339512ea99e4f6b9c6dc20feb021bc Mon Sep 17 00:00:00 2001 From: MattFiler Date: Wed, 13 Sep 2023 20:50:01 +0100 Subject: [PATCH 12/30] env map stuff --- CathodeLib/Scripts/CATHODE/EnvironmentMaps.cs | 2 +- CathodeLib/Scripts/CATHODE/Movers.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CathodeLib/Scripts/CATHODE/EnvironmentMaps.cs b/CathodeLib/Scripts/CATHODE/EnvironmentMaps.cs index 2ecd62e..2fc6506 100644 --- a/CathodeLib/Scripts/CATHODE/EnvironmentMaps.cs +++ b/CathodeLib/Scripts/CATHODE/EnvironmentMaps.cs @@ -55,7 +55,7 @@ override protected bool SaveInternal() #region STRUCTURES public class Mapping { - public int EnvMapIndex; //Index of the environment map + public int EnvMapIndex; //Sequential index of the env map in texture BIN, when only parsing entries of type CUBEMAP - NOT WRITE INDEX public int MoverIndex; //Index of the mover in the MODELS.MVR file to apply the env map to }; #endregion diff --git a/CathodeLib/Scripts/CATHODE/Movers.cs b/CathodeLib/Scripts/CATHODE/Movers.cs index a31301b..ada7240 100644 --- a/CathodeLib/Scripts/CATHODE/Movers.cs +++ b/CathodeLib/Scripts/CATHODE/Movers.cs @@ -207,7 +207,7 @@ RenderableElementSet is always paired with a MOVER_DESCRIPTOR (see RenderableSce public CommandsEntityReference entity; //The entity in the Commands file //280 - public UInt32 environmentMapIndex; //environment_map.bin index - converted to short in code + public Int32 environmentMapIndex; //environment_map.bin index - converted to short in code //284 public float emissive_val1; //emissive surface val1 public float emissive_val2; //emissive surface val2 From 3303a8eb0541e243abb2a559d313d2833c38183b Mon Sep 17 00:00:00 2001 From: MattFiler Date: Tue, 26 Sep 2023 18:48:09 +0100 Subject: [PATCH 13/30] placeholder alphalight level --- CathodeLib/Scripts/CATHODE/AlphaLightLevel.cs | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 CathodeLib/Scripts/CATHODE/AlphaLightLevel.cs diff --git a/CathodeLib/Scripts/CATHODE/AlphaLightLevel.cs b/CathodeLib/Scripts/CATHODE/AlphaLightLevel.cs new file mode 100644 index 0000000..e2fdf26 --- /dev/null +++ b/CathodeLib/Scripts/CATHODE/AlphaLightLevel.cs @@ -0,0 +1,48 @@ +using CathodeLib; +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; + +namespace CATHODE.EXPERIMENTAL +{ + /* DATA/ENV/PRODUCTION/x/WORLD/ALPHALIGHT_LEVEL.BIN */ + public class AlphaLightLevel : CathodeFile + { + public List Entries = new List(); + public static new Implementation Implementation = Implementation.NONE; + public AlphaLightLevel(string path) : base(path) { } + + // Lighting information for objects with alpha (e.g. glass). Levels can load without this file, but look worse. + + #region FILE_IO + override protected bool LoadInternal() + { + using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) + { + //todo + } + return true; + } + + override protected bool SaveInternal() + { + using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) + { + writer.BaseStream.SetLength(0); + Utilities.WriteString("alph", writer); + + //todo + } + return true; + } + #endregion + + #region STRUCTURES + public class Entry + { + //todo + }; + #endregion + } +} \ No newline at end of file From 56c8e596c905ccbb2f579caa03ffa8cc915f3c75 Mon Sep 17 00:00:00 2001 From: MattFiler Date: Sun, 1 Oct 2023 12:24:19 +0100 Subject: [PATCH 14/30] commenting stuff --- .../Scripts/CATHODE/EnvironmentAnimations.cs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/CathodeLib/Scripts/CATHODE/EnvironmentAnimations.cs b/CathodeLib/Scripts/CATHODE/EnvironmentAnimations.cs index 37b5007..7d451cc 100644 --- a/CathodeLib/Scripts/CATHODE/EnvironmentAnimations.cs +++ b/CathodeLib/Scripts/CATHODE/EnvironmentAnimations.cs @@ -41,8 +41,8 @@ override protected bool LoadInternal() reader.BaseStream.Position = matrix0.GlobalOffset; Matrix4x4[] Matrices0 = Utilities.ConsumeArray(reader, matrix0.EntryCount); Matrix4x4[] Matrices1 = Utilities.ConsumeArray(reader, matrix1.EntryCount); - int[] IDs0 = Utilities.ConsumeArray(reader, ids0.EntryCount); - int[] IDs1 = Utilities.ConsumeArray(reader, ids1.EntryCount); + ShortGuid[] IDs0 = Utilities.ConsumeArray(reader, ids0.EntryCount); + ShortGuid[] IDs1 = Utilities.ConsumeArray(reader, ids1.EntryCount); EnvironmentAnimationInfo[] Entries1 = Utilities.ConsumeArray(reader, entries1.EntryCount); //Jump back to our main definition and read all additional content in @@ -50,18 +50,18 @@ override protected bool LoadInternal() for (int i = 0; i < entries0.EntryCount; i++) { EnvironmentAnimation anim = new EnvironmentAnimation(); - anim.Matrix = Utilities.Consume(reader); - anim.ID = Utilities.Consume(reader); + anim.Matrix = Utilities.Consume(reader); //Root maybe? it seems to be identify + anim.ID = Utilities.Consume(reader); //This ID is not unique... Is it defo an ID? It doesn't show up in COMMANDS reader.BaseStream.Position += 4; - anim.ResourceIndex = reader.ReadInt32(); + anim.ResourceIndex = reader.ReadInt32(); //the index which links through to the resource reference in COMMANDS - anim.Indexes0 = PopulateArray(reader, IDs0); - anim.Indexes1 = PopulateArray(reader, IDs1); + anim.Indexes0 = PopulateArray(reader, IDs0); //These values seem to only be found in this file, so don't see that they're IDs. + anim.Indexes1 = PopulateArray(reader, IDs1); //ShortGuids for the resource references in COMMANDS int matrix_count = reader.ReadInt32(); int matrix_index = reader.ReadInt32(); - anim.Matrices0 = PopulateArray(matrix_count, matrix_index, Matrices0); - anim.Matrices1 = PopulateArray(matrix_count, matrix_index, Matrices1); + anim.Matrices0 = PopulateArray(matrix_count, matrix_index, Matrices0); //matches length of Indexes0 + anim.Matrices1 = PopulateArray(matrix_count, matrix_index, Matrices1); //matches length of Indexes0 anim.Data0 = PopulateArray(reader, Entries1); @@ -108,8 +108,8 @@ public class EnvironmentAnimation public ShortGuid ID; public int ResourceIndex; //This matches the ANIMATED_MODEL resource reference - public List Indexes0; - public List Indexes1; + public List Indexes0; + public List Indexes1; public List Matrices0; public List Matrices1; @@ -120,7 +120,7 @@ public class EnvironmentAnimation [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct EnvironmentAnimationInfo { - public ShortGuid ID; + public ShortGuid ID; //id is only found in this file public Vector3 P; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] public float[] V; From be159a9198a5cdd274c2a2ab2f3f5aced64289ab Mon Sep 17 00:00:00 2001 From: MattFiler Date: Mon, 2 Oct 2023 20:35:04 +0100 Subject: [PATCH 15/30] continued --- .../Scripts/CATHODE/EnvironmentAnimations.cs | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/CathodeLib/Scripts/CATHODE/EnvironmentAnimations.cs b/CathodeLib/Scripts/CATHODE/EnvironmentAnimations.cs index 7d451cc..fa80691 100644 --- a/CathodeLib/Scripts/CATHODE/EnvironmentAnimations.cs +++ b/CathodeLib/Scripts/CATHODE/EnvironmentAnimations.cs @@ -49,14 +49,16 @@ override protected bool LoadInternal() reader.BaseStream.Position = entries0.GlobalOffset; for (int i = 0; i < entries0.EntryCount; i++) { + //Each entry here defines info for a Composite which has a EnvironmentModelReference entity + EnvironmentAnimation anim = new EnvironmentAnimation(); - anim.Matrix = Utilities.Consume(reader); //Root maybe? it seems to be identify + anim.Matrix = Utilities.Consume(reader); //This is always identity anim.ID = Utilities.Consume(reader); //This ID is not unique... Is it defo an ID? It doesn't show up in COMMANDS reader.BaseStream.Position += 4; anim.ResourceIndex = reader.ReadInt32(); //the index which links through to the resource reference in COMMANDS - anim.Indexes0 = PopulateArray(reader, IDs0); //These values seem to only be found in this file, so don't see that they're IDs. - anim.Indexes1 = PopulateArray(reader, IDs1); //ShortGuids for the resource references in COMMANDS + anim.Indexes0 = PopulateArray(reader, IDs0); + anim.Indexes1 = PopulateArray(reader, IDs1); //ShortGuids for all RENDERABLE_INSTANCE resource references in the composite int matrix_count = reader.ReadInt32(); int matrix_index = reader.ReadInt32(); @@ -65,7 +67,7 @@ override protected bool LoadInternal() anim.Data0 = PopulateArray(reader, Entries1); - reader.BaseStream.Position += 4; //TODO: i think this might be a flag - it's usually zero but has been 1 on hab_airport + anim.unk1 = reader.ReadInt32(); //This is always zero, but is 1 for some HAB_AIRPORT entries Entries.Add(anim); } } @@ -108,6 +110,18 @@ public class EnvironmentAnimation public ShortGuid ID; public int ResourceIndex; //This matches the ANIMATED_MODEL resource reference + //There are two types of EnvironmentAnimation: + // - Skinned - known as a DisplayModel (a composite defining a skinned mesh, used for a character) + // - Non-Skinned (a composite defining a mesh like a weapon, etc) + + //If the composite is skinned: + // - Indexes0 is used to define skinning data (unsure what) + // - Indexes1 is used to define RENDERABLE_INSTANCE IDs (which it turns out are ShortGuids of the model submesh name most the time). Can also include the node name for EnvironmentModelReference?? + + //If the composite is static: + // - Indexes0 is used to define RENDERABLE_INSTANCE IDs (see above) + // - Indexes1 is unused + public List Indexes0; public List Indexes1; @@ -115,6 +129,8 @@ public class EnvironmentAnimation public List Matrices1; public List Data0; + + public int unk1 = 0; } [StructLayout(LayoutKind.Sequential, Pack = 1)] From c89fbb750d8d222f88abec088272ec2686f30713 Mon Sep 17 00:00:00 2001 From: MattFiler Date: Mon, 2 Oct 2023 21:42:54 +0100 Subject: [PATCH 16/30] saving env anim --- .../Scripts/CATHODE/EnvironmentAnimations.cs | 88 ++++++++++++++++++- 1 file changed, 86 insertions(+), 2 deletions(-) diff --git a/CathodeLib/Scripts/CATHODE/EnvironmentAnimations.cs b/CathodeLib/Scripts/CATHODE/EnvironmentAnimations.cs index fa80691..e62e84b 100644 --- a/CathodeLib/Scripts/CATHODE/EnvironmentAnimations.cs +++ b/CathodeLib/Scripts/CATHODE/EnvironmentAnimations.cs @@ -3,6 +3,7 @@ using System.Runtime.InteropServices; using CATHODE.Scripting; using CathodeLib; +using System; #if UNITY_EDITOR || UNITY_STANDALONE_WIN using UnityEngine; #else @@ -35,7 +36,7 @@ override protected bool LoadInternal() OffsetPair entries0 = Utilities.Consume(reader); OffsetPair ids0 = Utilities.Consume(reader); OffsetPair ids1 = Utilities.Consume(reader); - reader.BaseStream.Position += 8; //Skip unknown + //Here there's always 112, 1 //Jump down and read all content we'll consume into our EnvironmentAnimation reader.BaseStream.Position = matrix0.GlobalOffset; @@ -73,6 +74,89 @@ override protected bool LoadInternal() } return true; } + + override protected bool SaveInternal() + { + using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) + { + writer.BaseStream.SetLength(0); + writer.Write((Int32)4); + writer.Write((Int32)0); + writer.Write(new byte[56]); + writer.Write(new byte[112 * Entries.Count]); + + OffsetPair Matrices0 = new OffsetPair() { GlobalOffset = (int)writer.BaseStream.Position }; + for (int i = 0; i < Entries.Count; i++) + { + Utilities.Write(writer, Entries[i].Matrices0); + Matrices0.EntryCount += Entries[i].Matrices0.Count; + } + OffsetPair Matrices1 = new OffsetPair() { GlobalOffset = (int)writer.BaseStream.Position }; + for (int i = 0; i < Entries.Count; i++) + { + Utilities.Write(writer, Entries[i].Matrices1); + Matrices1.EntryCount += Entries[i].Matrices1.Count; + } + OffsetPair IDs0 = new OffsetPair() { GlobalOffset = (int)writer.BaseStream.Position }; + for (int i = 0; i < Entries.Count; i++) + { + Utilities.Write(writer, Entries[i].Indexes0); + IDs0.EntryCount += Entries[i].Indexes0.Count; + } + OffsetPair IDs1 = new OffsetPair() { GlobalOffset = (int)writer.BaseStream.Position }; + for (int i = 0; i < Entries.Count; i++) + { + Utilities.Write(writer, Entries[i].Indexes1); + IDs1.EntryCount += Entries[i].Indexes1.Count; + } + OffsetPair Entries1 = new OffsetPair() { GlobalOffset = (int)writer.BaseStream.Position }; + for (int i = 0; i < Entries.Count; i++) + { + Utilities.Write(writer, Entries[i].Data0); + Entries1.EntryCount += Entries[i].Data0.Count; + } + + writer.BaseStream.Position = 4; + writer.Write((Int32)writer.BaseStream.Length); + Utilities.Write(writer, Matrices0); + Utilities.Write(writer, Matrices1); + Utilities.Write(writer, Entries1); + writer.Write((Int32)64); + writer.Write((Int32)Entries.Count); + Utilities.Write(writer, IDs0); + Utilities.Write(writer, IDs1); + writer.Write((Int32)112); + writer.Write((Int32)1); + + int stacked_Matrices = 0; + int stacked_IDs0 = 0; + int stacked_IDs1 = 0; + int stacked_Entries1 = 0; + for (int i = 0; i < Entries.Count; i++) + { + Utilities.Write(writer, Entries[i].Matrix); + Utilities.Write(writer, Entries[i].ID); + writer.Write((Int32)0); + Utilities.Write(writer, Entries[i].ResourceIndex); + + writer.Write(Entries[i].Indexes0.Count); + writer.Write((Int32)stacked_IDs0); + stacked_IDs0 += Entries[i].Indexes0.Count; + writer.Write(Entries[i].Indexes1.Count); + writer.Write((Int32)stacked_IDs1); + stacked_IDs1 += Entries[i].Indexes1.Count; + writer.Write(Entries[i].Matrices0.Count); + writer.Write((Int32)stacked_Matrices); + stacked_Matrices += Entries[i].Matrices0.Count; + writer.Write((Int32)stacked_Entries1); + writer.Write(Entries[i].Data0.Count); + stacked_Entries1 += Entries[i].Data0.Count; + + writer.Write(Entries[i].unk1); + } + } + return true; + } #endregion #region HELPERS @@ -111,7 +195,7 @@ public class EnvironmentAnimation public int ResourceIndex; //This matches the ANIMATED_MODEL resource reference //There are two types of EnvironmentAnimation: - // - Skinned - known as a DisplayModel (a composite defining a skinned mesh, used for a character) + // - Skinned - usually referenced by DisplayModel (a composite defining a skinned mesh, used for a character, etc) // - Non-Skinned (a composite defining a mesh like a weapon, etc) //If the composite is skinned: From aef6c38285c3ef669f3b7260e650a14acf8185c7 Mon Sep 17 00:00:00 2001 From: MattFiler Date: Sun, 8 Oct 2023 14:16:20 +0100 Subject: [PATCH 17/30] string lookup --- .../Scripts/CATHODE/EnvironmentAnimations.cs | 43 ++++++++++++++++--- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/CathodeLib/Scripts/CATHODE/EnvironmentAnimations.cs b/CathodeLib/Scripts/CATHODE/EnvironmentAnimations.cs index e62e84b..b2ff8ca 100644 --- a/CathodeLib/Scripts/CATHODE/EnvironmentAnimations.cs +++ b/CathodeLib/Scripts/CATHODE/EnvironmentAnimations.cs @@ -4,6 +4,7 @@ using CATHODE.Scripting; using CathodeLib; using System; +using System.Linq; #if UNITY_EDITOR || UNITY_STANDALONE_WIN using UnityEngine; #else @@ -16,12 +17,29 @@ namespace CATHODE public class EnvironmentAnimations : CathodeFile { public List Entries = new List(); - public static new Implementation Implementation = Implementation.LOAD; - public EnvironmentAnimations(string path) : base(path) { } + public static new Implementation Implementation = Implementation.LOAD | Implementation.CREATE | Implementation.SAVE; + + public EnvironmentAnimations(string path, AnimationStrings strings) : base(path) + { + _strings = strings; + + //TEMP + OnLoadBegin?.Invoke(_filepath); + if (LoadInternal()) + { + _loaded = true; + OnLoadSuccess?.Invoke(_filepath); + } + } + + private AnimationStrings _strings; #region FILE_IO override protected bool LoadInternal() { + if (_strings == null) + return false; + //TODO: this is a mapping of ModelReference entities within the composite with EnvironmentModelReference in // the IDs should line up. @@ -46,6 +64,12 @@ override protected bool LoadInternal() ShortGuid[] IDs1 = Utilities.ConsumeArray(reader, ids1.EntryCount); EnvironmentAnimationInfo[] Entries1 = Utilities.ConsumeArray(reader, entries1.EntryCount); + //Look up the string IDs + //string[] Strings0 = new string[IDs0.Length]; + //for (int i = 0; i < Strings0.Length; i++) Strings0[i] = _strings.Entries[IDs0[i]]; + //string[] Strings1 = new string[IDs1.Length]; + //for (int i = 0; i < Strings1.Length; i++) Strings1[i] = _strings.Entries[IDs1[i]]; + //Jump back to our main definition and read all additional content in reader.BaseStream.Position = entries0.GlobalOffset; for (int i = 0; i < entries0.EntryCount; i++) @@ -54,7 +78,9 @@ override protected bool LoadInternal() EnvironmentAnimation anim = new EnvironmentAnimation(); anim.Matrix = Utilities.Consume(reader); //This is always identity - anim.ID = Utilities.Consume(reader); //This ID is not unique... Is it defo an ID? It doesn't show up in COMMANDS + + uint id = reader.ReadUInt32(); + anim.Name = _strings.Entries[id]; reader.BaseStream.Position += 4; anim.ResourceIndex = reader.ReadInt32(); //the index which links through to the resource reference in COMMANDS @@ -135,7 +161,7 @@ override protected bool SaveInternal() for (int i = 0; i < Entries.Count; i++) { Utilities.Write(writer, Entries[i].Matrix); - Utilities.Write(writer, Entries[i].ID); + Utilities.Write(writer, Utilities.AnimationHashedString(Entries[i].Name)); writer.Write((Int32)0); Utilities.Write(writer, Entries[i].ResourceIndex); @@ -190,8 +216,8 @@ private List PopulateArray(int count, int index, T[] array) #region STRUCTURES public class EnvironmentAnimation { - public Matrix4x4 Matrix; - public ShortGuid ID; + public Matrix4x4 Matrix = Matrix4x4.Identity; //not sure this is actually used. changed it to a rotation and nothing seemed diff + public string Name; //we write this using AnimationHashedString public int ResourceIndex; //This matches the ANIMATED_MODEL resource reference //There are two types of EnvironmentAnimation: @@ -217,6 +243,11 @@ public class EnvironmentAnimation public int unk1 = 0; } + public class SkinnedEnvironmentAnimation : EnvironmentAnimation + { + + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct EnvironmentAnimationInfo { From bb19aa7d1aa5abaf74d2d93182a154523bed5d41 Mon Sep 17 00:00:00 2001 From: MattFiler Date: Sun, 8 Oct 2023 18:42:15 +0100 Subject: [PATCH 18/30] more anim/skeleton stuff --- CathodeLib/Scripts/CATHODE/AnimClipDB.cs | 90 +++++++++++++ .../Scripts/CATHODE/AnimationStrings.cs | 13 +- .../Scripts/CATHODE/EnvironmentAnimations.cs | 50 ++++---- CathodeLib/Scripts/CATHODE/SkeleDB.cs | 118 ++++++++++++++++++ 4 files changed, 237 insertions(+), 34 deletions(-) create mode 100644 CathodeLib/Scripts/CATHODE/AnimClipDB.cs create mode 100644 CathodeLib/Scripts/CATHODE/SkeleDB.cs diff --git a/CathodeLib/Scripts/CATHODE/AnimClipDB.cs b/CathodeLib/Scripts/CATHODE/AnimClipDB.cs new file mode 100644 index 0000000..4adb7a9 --- /dev/null +++ b/CathodeLib/Scripts/CATHODE/AnimClipDB.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Numerics; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.ComTypes; +using System.Text; +using CATHODE.Scripting; +using CathodeLib; + +namespace CATHODE +{ + /* DATA/GLOBAL/ANIMATION.PAK -> ANIM_CLIP_DB.BIN */ + public class AnimClipDB : CathodeFile + { + public Dictionary Entries = new Dictionary(); + public static new Implementation Implementation = Implementation.LOAD; + public AnimClipDB(string path) : base(path) { } + + #region FILE_IO + override protected bool LoadInternal() + { + using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) + { + int EntryCount1 = reader.ReadInt32(); + int EntryCount2 = reader.ReadInt32(); + IndexPair[] Entries1 = Utilities.ConsumeArray(reader, EntryCount1); + IndexPair[] Entries2 = Utilities.ConsumeArray(reader, EntryCount2); + + int Count0 = reader.ReadInt32(); + int Count1 = reader.ReadInt32(); + IndexPair[] Stuff0 = Utilities.ConsumeArray(reader, Count0); + OffsetPair[] Stuff1 = Utilities.ConsumeArray(reader, Count1); + + int Count2 = reader.ReadInt32(); + int[] Stuff2 = Utilities.ConsumeArray(reader, Count2); + + int Count4 = reader.ReadInt32(); + int Count5 = reader.ReadInt32(); + int Count6 = reader.ReadInt32(); + IndexPair[] Stuff5 = Utilities.ConsumeArray(reader, Count5); + int[] Stuff6 = Utilities.ConsumeArray(reader, Count6); + + int Count7 = reader.ReadInt32(); + int[] Stuff7 = Utilities.ConsumeArray(reader, Count7); + + byte[] HeaderCounts0 = Utilities.ConsumeArray(reader, 5); + float[] HeaderFloats0 = Utilities.ConsumeArray(reader, 6); // TODO: Is this HKX min/max floats for compression? + int[] HeaderStuff0 = Utilities.ConsumeArray(reader, 4); + + int[] ContentStuff0 = Utilities.ConsumeArray(reader, HeaderCounts0[1] * 4); + Vector2[] ContentStuff1 = Utilities.ConsumeArray(reader, HeaderCounts0[2]); + + bone_entry[] BoneEntries = Utilities.ConsumeArray(reader, HeaderCounts0[3]); + + // NOTE: Following content seems to be 4 unknown u8s followed by 4 u8s of which the 0th is ff and 1, 2 and 3 seem to + // sum to 255. I would guess those are bone weights? Bone weights tend to sum to 1. + } + return true; + } + + override protected bool SaveInternal() + { + using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) + { + writer.BaseStream.SetLength(0); + } + return true; + } + #endregion + + #region STRUCTURES + [StructLayout(LayoutKind.Sequential, Pack = 1)] + private struct IndexPair + { + public uint id; + public int index; + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + private struct bone_entry + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + byte[] Joints; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + byte[] Weights; + }; + #endregion + } +} diff --git a/CathodeLib/Scripts/CATHODE/AnimationStrings.cs b/CathodeLib/Scripts/CATHODE/AnimationStrings.cs index 657f3b8..8a3d720 100644 --- a/CathodeLib/Scripts/CATHODE/AnimationStrings.cs +++ b/CathodeLib/Scripts/CATHODE/AnimationStrings.cs @@ -19,15 +19,15 @@ public AnimationStrings(string path) : base(path) { } #region FILE_IO override protected bool LoadInternal() { - using (BinaryReader stream = new BinaryReader(File.OpenRead(_filepath))) + using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) { //Read all data in - int EntryCount = stream.ReadInt32(); - int StringCount = stream.ReadInt32(); - Entry[] entries = Utilities.ConsumeArray(stream, EntryCount); - int[] stringOffsets = Utilities.ConsumeArray(stream, StringCount); + int EntryCount = reader.ReadInt32(); + int StringCount = reader.ReadInt32(); + Entry[] entries = Utilities.ConsumeArray(reader, EntryCount); + int[] stringOffsets = Utilities.ConsumeArray(reader, StringCount); List strings = new List(); - for (int i = 0; i < StringCount; i++) strings.Add(Utilities.ReadString(stream)); + for (int i = 0; i < StringCount; i++) strings.Add(Utilities.ReadString(reader)); //Parse for (int i = 0; i < entries.Length; i++) Entries.Add(entries[i].StringID, strings[entries[i].StringIndex]); @@ -40,6 +40,7 @@ override protected bool SaveInternal() { using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) { + writer.BaseStream.SetLength(0); writer.Write(Entries.Count); writer.Write(Entries.Count); int count = 0; diff --git a/CathodeLib/Scripts/CATHODE/EnvironmentAnimations.cs b/CathodeLib/Scripts/CATHODE/EnvironmentAnimations.cs index b2ff8ca..e352442 100644 --- a/CathodeLib/Scripts/CATHODE/EnvironmentAnimations.cs +++ b/CathodeLib/Scripts/CATHODE/EnvironmentAnimations.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; using CATHODE.Scripting; @@ -62,13 +62,7 @@ override protected bool LoadInternal() Matrix4x4[] Matrices1 = Utilities.ConsumeArray(reader, matrix1.EntryCount); ShortGuid[] IDs0 = Utilities.ConsumeArray(reader, ids0.EntryCount); ShortGuid[] IDs1 = Utilities.ConsumeArray(reader, ids1.EntryCount); - EnvironmentAnimationInfo[] Entries1 = Utilities.ConsumeArray(reader, entries1.EntryCount); - - //Look up the string IDs - //string[] Strings0 = new string[IDs0.Length]; - //for (int i = 0; i < Strings0.Length; i++) Strings0[i] = _strings.Entries[IDs0[i]]; - //string[] Strings1 = new string[IDs1.Length]; - //for (int i = 0; i < Strings1.Length; i++) Strings1[i] = _strings.Entries[IDs1[i]]; + EnvironmentAnimation.Info[] Entries1 = Utilities.ConsumeArray(reader, entries1.EntryCount); //Jump back to our main definition and read all additional content in reader.BaseStream.Position = entries0.GlobalOffset; @@ -77,10 +71,11 @@ override protected bool LoadInternal() //Each entry here defines info for a Composite which has a EnvironmentModelReference entity EnvironmentAnimation anim = new EnvironmentAnimation(); - anim.Matrix = Utilities.Consume(reader); //This is always identity + + Matrix4x4 Matrix = Utilities.Consume(reader); //This is always identity uint id = reader.ReadUInt32(); - anim.Name = _strings.Entries[id]; + anim.SkeletonName = _strings.Entries[id]; reader.BaseStream.Position += 4; anim.ResourceIndex = reader.ReadInt32(); //the index which links through to the resource reference in COMMANDS @@ -92,7 +87,7 @@ override protected bool LoadInternal() anim.Matrices0 = PopulateArray(matrix_count, matrix_index, Matrices0); //matches length of Indexes0 anim.Matrices1 = PopulateArray(matrix_count, matrix_index, Matrices1); //matches length of Indexes0 - anim.Data0 = PopulateArray(reader, Entries1); + anim.Data0 = PopulateArray(reader, Entries1); anim.unk1 = reader.ReadInt32(); //This is always zero, but is 1 for some HAB_AIRPORT entries Entries.Add(anim); @@ -160,8 +155,8 @@ override protected bool SaveInternal() int stacked_Entries1 = 0; for (int i = 0; i < Entries.Count; i++) { - Utilities.Write(writer, Entries[i].Matrix); - Utilities.Write(writer, Utilities.AnimationHashedString(Entries[i].Name)); + Utilities.Write(writer, Matrix4x4.Identity); + Utilities.Write(writer, Utilities.AnimationHashedString(Entries[i].SkeletonName)); writer.Write((Int32)0); Utilities.Write(writer, Entries[i].ResourceIndex); @@ -191,7 +186,7 @@ private List PopulateArray(BinaryReader reader, T[] array) List arr = new List(); int count = reader.ReadInt32(); int index = reader.ReadInt32(); - if (typeof(T) == typeof(EnvironmentAnimationInfo)) + if (typeof(T) == typeof(EnvironmentAnimation.Info)) { //Hacky fix for EnvironmentAnimationInfo pointers count/index order being inverted for (int x = 0; x < index; x++) @@ -216,8 +211,7 @@ private List PopulateArray(int count, int index, T[] array) #region STRUCTURES public class EnvironmentAnimation { - public Matrix4x4 Matrix = Matrix4x4.Identity; //not sure this is actually used. changed it to a rotation and nothing seemed diff - public string Name; //we write this using AnimationHashedString + public string SkeletonName; //we write this using AnimationHashedString public int ResourceIndex; //This matches the ANIMATED_MODEL resource reference //There are two types of EnvironmentAnimation: @@ -238,26 +232,26 @@ public class EnvironmentAnimation public List Matrices0; public List Matrices1; - public List Data0; + public List Data0; public int unk1 = 0; + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct Info + { + public ShortGuid ID; //id is only found in this file + public Vector3 P; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public float[] V; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] Unknown_; + }; } public class SkinnedEnvironmentAnimation : EnvironmentAnimation { } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct EnvironmentAnimationInfo - { - public ShortGuid ID; //id is only found in this file - public Vector3 P; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] - public float[] V; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public byte[] Unknown_; - }; #endregion } } \ No newline at end of file diff --git a/CathodeLib/Scripts/CATHODE/SkeleDB.cs b/CathodeLib/Scripts/CATHODE/SkeleDB.cs new file mode 100644 index 0000000..995901f --- /dev/null +++ b/CathodeLib/Scripts/CATHODE/SkeleDB.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Numerics; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.ComTypes; +using System.Text; +using CATHODE.Scripting; +using CathodeLib; + +namespace CATHODE +{ + /* DATA/GLOBAL/ANIMATION.PAK -> ANIM_SYS/SKELE/DB.BIN */ + public class SkeleDB : CathodeFile + { + public Dictionary Entries = new Dictionary(); + public static new Implementation Implementation = Implementation.LOAD; + + public SkeleDB(string path, AnimationStrings strings) : base(path) + { + _strings = strings; + + //TEMP + OnLoadBegin?.Invoke(_filepath); + if (LoadInternal()) + { + _loaded = true; + OnLoadSuccess?.Invoke(_filepath); + } + } + + private AnimationStrings _strings; + + #region FILE_IO + override protected bool LoadInternal() + { + if (_strings == null) + return false; + + using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) + { + int pairCount = reader.ReadInt32(); + int idCount = reader.ReadInt32(); + + if (pairCount != idCount) + return false; + + Skeletons[] skeletons = new Skeletons[pairCount]; + for (int i = 0; i < pairCount; i++) + { + string name = _strings.Entries[reader.ReadUInt32()]; + skeletons[reader.ReadInt32()] = new Skeletons() { SkeletonName = name }; + } + for (int i = 0; i < idCount; i++) + { + skeletons[i].Filename = _strings.Entries[reader.ReadUInt32()]; + } + + int mappingIDCount = reader.ReadInt32(); + int mappingCount = reader.ReadInt32(); + + if (mappingIDCount != mappingCount) + return false; + + SkeletonMapping[] mappings = new SkeletonMapping[mappingIDCount]; + for (int i = 0; i < mappingCount; i++) + { + string skele1 = _strings.Entries[reader.ReadUInt32()]; + string skele2 = _strings.Entries[reader.ReadUInt32()]; + + mappings[reader.ReadInt32()] = new SkeletonMapping() + { + Skeleton1 = skele1, + Skeleton2 = skele2, + }; + reader.BaseStream.Position += 4; + } + for (int i = 0; i < mappingIDCount; i++) + { + mappings[i].Name = _strings.Entries[reader.ReadUInt32()]; + } + + string sdfsdf = ""; + } + return true; + } + + override protected bool SaveInternal() + { + using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) + { + writer.BaseStream.SetLength(0); + + writer.Write(Entries.Count); + writer.Write(Entries.Count); + } + return true; + } + #endregion + + #region STRUCTURES + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public class Skeletons + { + public string Filename; + public string SkeletonName; + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public class SkeletonMapping + { + public string Name; + public string Skeleton1; + public string Skeleton2; + }; + #endregion + } +} From f6cba058d7a4fe397cec79c775fc9511b849316a Mon Sep 17 00:00:00 2001 From: MattFiler Date: Sun, 8 Oct 2023 18:47:41 +0100 Subject: [PATCH 19/30] save functionality --- CathodeLib/Scripts/CATHODE/SkeleDB.cs | 45 ++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/CathodeLib/Scripts/CATHODE/SkeleDB.cs b/CathodeLib/Scripts/CATHODE/SkeleDB.cs index 995901f..7be6fdd 100644 --- a/CathodeLib/Scripts/CATHODE/SkeleDB.cs +++ b/CathodeLib/Scripts/CATHODE/SkeleDB.cs @@ -14,8 +14,8 @@ namespace CATHODE /* DATA/GLOBAL/ANIMATION.PAK -> ANIM_SYS/SKELE/DB.BIN */ public class SkeleDB : CathodeFile { - public Dictionary Entries = new Dictionary(); - public static new Implementation Implementation = Implementation.LOAD; + public Data Entries = new Data(); + public static new Implementation Implementation = Implementation.LOAD | Implementation.CREATE | Implementation.SAVE; public SkeleDB(string path, AnimationStrings strings) : base(path) { @@ -38,6 +38,8 @@ override protected bool LoadInternal() if (_strings == null) return false; + Entries = new Data(); + using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) { int pairCount = reader.ReadInt32(); @@ -81,25 +83,58 @@ override protected bool LoadInternal() mappings[i].Name = _strings.Entries[reader.ReadUInt32()]; } - string sdfsdf = ""; + Entries.Skeletons = skeletons.ToList(); + Entries.Mappings = mappings.ToList(); } return true; } override protected bool SaveInternal() { + //TODO: we should write these anim strings to the db + using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) { writer.BaseStream.SetLength(0); - writer.Write(Entries.Count); - writer.Write(Entries.Count); + writer.Write(Entries.Skeletons.Count); + writer.Write(Entries.Skeletons.Count); + + for (int i = 0; i < Entries.Skeletons.Count; i++) + { + writer.Write(Utilities.AnimationHashedString(Entries.Skeletons[i].SkeletonName)); + writer.Write(i); + } + for (int i = 0; i < Entries.Skeletons.Count; i++) + { + writer.Write(Utilities.AnimationHashedString(Entries.Skeletons[i].Filename)); + } + + writer.Write(Entries.Mappings.Count); + writer.Write(Entries.Mappings.Count); + + for (int i = 0; i < Entries.Mappings.Count; i++) + { + writer.Write(Utilities.AnimationHashedString(Entries.Mappings[i].Skeleton1)); + writer.Write(Utilities.AnimationHashedString(Entries.Mappings[i].Skeleton2)); + writer.Write(i); + writer.Write(0); + } + for (int i = 0; i < Entries.Mappings.Count; i++) + { + writer.Write(Utilities.AnimationHashedString(Entries.Mappings[i].Name)); + } } return true; } #endregion #region STRUCTURES + public class Data + { + public List Skeletons = new List(); + public List Mappings = new List(); + } [StructLayout(LayoutKind.Sequential, Pack = 1)] public class Skeletons { From 97483f9a454c17719412b3f1e44af793b8449476 Mon Sep 17 00:00:00 2001 From: MattFiler Date: Mon, 9 Oct 2023 19:48:42 +0100 Subject: [PATCH 20/30] load more level bits --- CathodeLib/Scripts/Level.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/CathodeLib/Scripts/Level.cs b/CathodeLib/Scripts/Level.cs index 02834d4..e4eafde 100644 --- a/CathodeLib/Scripts/Level.cs +++ b/CathodeLib/Scripts/Level.cs @@ -10,6 +10,12 @@ namespace CathodeLib { + public class Global + { + public AnimationStrings AnimationStrings; + public AnimationStrings AnimationStrings_Debug; + } + /* A helper class that holds all parse-able formats for a level, and saves them safely to update indexes across all */ public class Level { @@ -50,7 +56,7 @@ public class State public List StateResources = new List(); /* Load a level in the game's "ENV/PRODUCTION" folder */ - public Level(string path) + public Level(string path, Global global) { string pathDATA = path.Replace('\\', '/').Split(new string[] { "/DATA/ENV/PRODUCTION" }, StringSplitOptions.None)[0] + "/DATA"; string levelName = Directory.GetParent(path).Name; @@ -74,12 +80,12 @@ public Level(string path) /* WORLD */ RenderableElements = new RenderableElements(path + "/WORLD/REDS.BIN"); Movers = new Movers(path + "/WORLD/MODELS.MVR"); - //Commands = new Commands(path + "/WORLD/COMMANDS.PAK"); + Commands = new Commands(path + "/WORLD/COMMANDS.PAK"); //Resources = new Resources(path + "/WORLD/RESOURCES.BIN"); //PhysicsMaps = new PhysicsMaps(path + "/WORLD/PHYSICS.MAP"); EnvironmentMaps = new EnvironmentMaps(path + "/WORLD/ENVIRONMENTMAP.BIN"); //CollisionMaps = new CollisionMaps(path + "/WORLD/COLLISION.MAP"); - //EnvironmentAnimations = new EnvironmentAnimations(path + "/WORLD/ENVIRONMENT_ANIMATION.DAT"); + EnvironmentAnimations = new EnvironmentAnimations(path + "/WORLD/ENVIRONMENT_ANIMATION.DAT", global.AnimationStrings_Debug); //MaterialMappings = new MaterialMappings(path + "/WORLD/MATERIAL_MAPPINGS.PAK"); //PathBarrierResources = new PathBarrierResources(path + "/WORLD/PATH_BARRIER_RESOURCES"); Lights = new Lights(path + "/WORLD/LIGHTS.BIN"); @@ -150,6 +156,10 @@ public Level(string path) /* Save all modifications to the level - this currently assumes we aren't editing GLOBAL data */ public void Save() { + //TODO: This puts the assumption on the user that they have updated all the indexes correctly in Commands. Need to just pass direct objects. + Commands.Save(); + EnvironmentAnimations.Save(); + /* UPDATE MOVER INDEXES */ //Get links to mover entries as actual objects From a2ae3e5e19f517fb8c03c6df8311259759325a2b Mon Sep 17 00:00:00 2001 From: MattFiler Date: Sat, 14 Oct 2023 11:19:09 +0100 Subject: [PATCH 21/30] shader stuff --- CathodeLib/Scripts/CATHODE/Models.cs | 1 + CathodeLib/Scripts/CATHODE/Shaders.cs | 162 ++++++++++++++++++-------- CathodeLib/Scripts/Utilities.cs | 123 +++++++++++++++++-- 3 files changed, 225 insertions(+), 61 deletions(-) diff --git a/CathodeLib/Scripts/CATHODE/Models.cs b/CathodeLib/Scripts/CATHODE/Models.cs index 7420e31..a118946 100644 --- a/CathodeLib/Scripts/CATHODE/Models.cs +++ b/CathodeLib/Scripts/CATHODE/Models.cs @@ -628,6 +628,7 @@ public class Component public List LODs = new List(); //Storing some unknown info about LV426 stuff (Pt1 and Pt2 respectively) + //I think these are just garbage values that got dumped by accident public int UnkLv426Pt1 = 0; public int UnkLv426Pt2 = 0; diff --git a/CathodeLib/Scripts/CATHODE/Shaders.cs b/CathodeLib/Scripts/CATHODE/Shaders.cs index 670af70..ea2c2c9 100644 --- a/CathodeLib/Scripts/CATHODE/Shaders.cs +++ b/CathodeLib/Scripts/CATHODE/Shaders.cs @@ -3,12 +3,14 @@ using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; +using static CATHODE.LEGACY.ShadersPAK; namespace CATHODE { /* DATA/ENV/PRODUCTION/x/RENDERABLE/LEVEL_SHADERS_DX11.PAK & LEVEL_SHADERS_DX11_BIN.PAK & LEVEL_SHADERS_DX11_IDX_REMAP.PAK */ public class Shaders : CathodeFile { + public List Entries = new List(); public static new Implementation Implementation = Implementation.NONE; public Shaders(string path) : base(path) { } @@ -25,71 +27,132 @@ override protected bool LoadInternal() if (!File.Exists(_filepathBIN)) return false; if (!File.Exists(_filepathIDX)) return false; - using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepathBIN))) + List content = Utilities.ReadPAK(_filepathBIN, FileIdentifiers.SHADER_DATA); + for (int i = 0; i < content.Count; i++) { - reader.BaseStream.Position = 4; //skip magic - if ((FileIdentifiers)reader.ReadInt32() != FileIdentifiers.ASSET_FILE) return false; - if ((FileIdentifiers)reader.ReadInt32() != FileIdentifiers.SHADER_DATA) return false; - int binEntryCount = reader.ReadInt32(); - if (BigEndianUtils.ReadInt32(reader) != binEntryCount) return false; - - //Skip rest of the main header - reader.BaseStream.Position = 32; - - //Pull each entry's individual header - List _header = new List(); - for (int i = 0; i < binEntryCount; i++) - { - CathodeShaderHeader newStringEntry = new CathodeShaderHeader(); - reader.BaseStream.Position += 8; //skip blanks - - newStringEntry.FileLength = reader.ReadInt32(); - newStringEntry.FileLengthWithPadding = reader.ReadInt32(); - newStringEntry.FileOffset = reader.ReadInt32(); - - reader.BaseStream.Position += 8; //skip blanks - - newStringEntry.StringPart1 = reader.ReadBytes(4); - newStringEntry.FileIndex = reader.ReadInt32(); //potentially actually int8 or int16 not 32 - - reader.BaseStream.Position += 8; //skip blanks + if (content[i].BinIndex != i) return false; - newStringEntry.StringPart2 = reader.ReadBytes(4); - - //TEMP: For now I'm just setting the filename to be the index... need to work out how the _BIN relates to the initial .PAK to get names, etc - newStringEntry.FileName = newStringEntry.FileIndex + ".DXBC"; - //END OF TEMP - - _header.Add(newStringEntry); - } - int endOfHeaders = (int)reader.BaseStream.Position; - - //Pull each entry's file content - foreach (CathodeShaderHeader shaderEntry in _header) + using (BinaryReader reader = new BinaryReader(new MemoryStream(content[i].Data))) { - reader.BaseStream.Position = shaderEntry.FileOffset + endOfHeaders; - shaderEntry.FileContent = reader.ReadBytes(shaderEntry.FileLength); + } } - using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepathIDX))) + //Read the index remapping pak (this is actually just an incrementing count lol) + content = Utilities.ReadPAK(_filepathIDX, FileIdentifiers.SHADER_DATA); + for (int i = 0; i < content.Count; i++) { + if (content[i].BinIndex != i) return false; + using (BinaryReader reader = new BinaryReader(new MemoryStream(content[i].Data))) + { + int index = reader.ReadInt32(); + if (index != i) return false; + } } - using (BinaryReader reader = new BinaryReader(File.OpenRead(_filepath))) + content = Utilities.ReadPAK(_filepath, FileIdentifiers.SHADER_DATA); + for (int i = 0; i < content.Count; i++) { - reader.BaseStream.Position += 4; //Skip unused - if ((FileIdentifiers)reader.ReadInt32() != FileIdentifiers.ASSET_FILE) return false; - if ((FileIdentifiers)reader.ReadInt32() != FileIdentifiers.SHADER_DATA) return false; - int pakEntryCount = reader.ReadInt32(); - if (BigEndianUtils.ReadInt32(reader) != pakEntryCount) return false; + using (BinaryReader reader = new BinaryReader(new MemoryStream(content[i].Data))) + { + reader.BaseStream.Position = 8; //0x7725BBA4, 36, 1 + + int textureCount = reader.ReadInt16(); + int[] cstCounts = new int[5]; + for (int x = 0; x < 5; x++) cstCounts[x] = reader.ReadInt32(); + int textureLinkCount = reader.ReadInt16(); + string name = Utilities.ReadString(reader.ReadBytes(40)); + ShaderCategory category = (ShaderCategory)reader.ReadInt16(); + + // Index 0: 0x04: seems to be metal. 0x01: seems to be non-metal. But it has many exceptions so maybe check renderdoc. + // Index 1: ParallaxMap? It seems to be either 0x30 and 0x80 for the most part, sometimes it combines both into 0xB0. + // Index 2: Lower part of this byte is NormalMap0 related! 0x04 means it has normal map 0. No hits for 1, 2 or 8 yet. + // 0x03 is a thing, but not normal map. What is it? Can be 0x07 where it has normal map and both the 0x03 thing. + // 0x0C is also a thing (8 and 4), so it has normal map and something else? + // I'm gonna say 0x03 means DiffuseMap1. + // Index 3: 0x04 Not OcclusionTint. (NormalMap0 + NormalMap0UVMultiplier + NormalMap0Strength?) + // Index 4: Seems to tell me about AO. If 4, then it has AO tint. If 1 it has AO texture. + // Index 6: Seems to tell me about Dirt/OpacityNoise. + // 0x19 (0001 1001): has opacity noise and dirt maps. + // 0x38 (0011 1000): has dirt map. + // 0x39 (0011 1001): has opacity noise and dirt maps. + // Index 10: First half, only found 4, and it seems to be something included in all (Diffuse0 as well?). + // Seems like the least significant bit enables/disables opacity noise? + int[] flags = new int[20]; + for (int x = 0; x < 20; x++) flags[x] = reader.ReadByte(); + + int unk = reader.ReadInt32(); + + int entryCount = reader.ReadInt16(); + for (int x = 0; x < entryCount; x++) + { + int unk1 = reader.ReadInt16(); + int unk2 = reader.ReadInt32(); + } + + for (int x = 0; x < textureCount; x++) + { + int unk1 = reader.ReadByte(); + int unk2 = reader.ReadByte(); + int[] unk3 = new int[16]; + for (int z = 0; z < 16; z++) unk3[z] = reader.ReadInt16(); + float unk4 = reader.ReadSingle(); + int unk5 = reader.ReadInt16(); + float unk6 = reader.ReadSingle(); + } + + for (int x = 0; x < textureCount; x++) + { + int unk1 = reader.ReadByte(); + } + + int[][] cstLinks = new int[5][]; + for (int x = 0; x < 5; x++) + { + cstLinks[x] = new int[cstCounts[x]]; + for (int z = 0; z < cstCounts[x]; z++) + { + cstLinks[x][z] = reader.ReadByte(); + } + } + + int[] textureLinks = new int[textureLinkCount]; + for (int x = 0; x < textureLinkCount; x++) + { + textureLinks[x] = reader.ReadByte(); + } + + int vertexShader = reader.ReadInt32(); + int pixelShader = reader.ReadInt32(); + int hullShader = reader.ReadInt32(); + int domainShader = reader.ReadInt32(); + + //Interestingly, seems like neither of these are used + int geometryShader = reader.ReadInt32(); + int computeShader = reader.ReadInt32(); + } } + return true; } override protected bool SaveInternal() { + using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepathBIN))) + { + + } + using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepathIDX))) + { + writer.BaseStream.SetLength(0); + writer.Write(0); + writer.Write((int)FileIdentifiers.ASSET_FILE); + writer.Write((int)FileIdentifiers.MODEL_DATA); + writer.Write(Entries.Count); + writer.Write(Entries.Count); + writer.Write(new byte[12]); + } using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) { @@ -99,7 +162,7 @@ override protected bool SaveInternal() #endregion #region STRUCTURES - public class CathodeShaderHeader + public class Shader { public string FileName = ""; //The name of the file in the shader archive (unsure how to get this right now with the weird _BIN/PAK way of working) @@ -111,6 +174,7 @@ public class CathodeShaderHeader public byte[] FileContent; //The content for the file + //I think this is just garbage that got dumped by accident public byte[] StringPart1; //4 bytes that look like they're part of a filepath public byte[] StringPart2; //4 bytes that look like they're part of a filepath } diff --git a/CathodeLib/Scripts/Utilities.cs b/CathodeLib/Scripts/Utilities.cs index b184f3d..7a982eb 100644 --- a/CathodeLib/Scripts/Utilities.cs +++ b/CathodeLib/Scripts/Utilities.cs @@ -1,3 +1,4 @@ +using CATHODE; using CATHODE.Scripting; using System; using System.Collections.Generic; @@ -193,46 +194,144 @@ public static uint AnimationHashedString(string str) return hash; } + + //Read a PAK + public static List ReadPAK(string path, FileIdentifiers type) + { + List content = new List(); + bool e = type == FileIdentifiers.MODEL_DATA; + + using (BinaryReader reader = new BinaryReader(File.OpenRead(path))) + { + reader.BaseStream.Position += 4; + if ((FileIdentifiers)BigEndianUtils.ReadInt32(reader, e) != FileIdentifiers.ASSET_FILE) return null; + if ((FileIdentifiers)BigEndianUtils.ReadInt32(reader, e) != type) return null; + int entryCount = BigEndianUtils.ReadInt32(reader, e); + int entryCountActual = BigEndianUtils.ReadInt32(reader, e); + reader.BaseStream.Position += 12; + + int endOfHeaders = 32 + (entryCountActual * 48); + + List info = new List(); + for (int i = 0; i < entryCount; i++) + { + reader.BaseStream.Position += 8; + int length = BigEndianUtils.ReadInt32(reader, e); + reader.BaseStream.Position += 4; + int offset = BigEndianUtils.ReadInt32(reader, e); + reader.BaseStream.Position += 12; + int binIndex = BigEndianUtils.ReadInt32(reader, e); + reader.BaseStream.Position += 12; + + info.Add(new OffsetPair() { GlobalOffset = offset + endOfHeaders, EntryCount = length }); + content.Add(new PAKContent() { BinIndex = binIndex }); + } + + for (int i = 0; i < entryCount; i++) + { + reader.BaseStream.Position = info[i].GlobalOffset; + content[i].Data = reader.ReadBytes(info[i].EntryCount); + } + } + + return content; + } + + //Write a PAK + public static void WritePAK(string path, FileIdentifiers type, List content) + { + bool e = type == FileIdentifiers.MODEL_DATA; + + using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(path))) + { + //Write content + int contentOffset = 32 + (content.Count * 48); + writer.BaseStream.SetLength(contentOffset); + writer.BaseStream.Position = contentOffset; + List offsets = new List(); + List lengths = new List(); + for (int i = 0; i < content.Count; i++) + { + offsets.Add((int)writer.BaseStream.Position - contentOffset); + writer.Write(content[i].Data); + lengths.Add((int)writer.BaseStream.Position - contentOffset - offsets[offsets.Count - 1]); + } + + //Write model headers + writer.BaseStream.Position = 32; + for (int i = 0; i < content.Count; i++) + { + writer.Write(new byte[8]); + writer.Write(e ? BigEndianUtils.FlipEndian((Int32)lengths[i]) : BitConverter.GetBytes((Int32)lengths[i])); + writer.Write(e ? BigEndianUtils.FlipEndian((Int32)lengths[i]) : BitConverter.GetBytes((Int32)lengths[i])); + writer.Write(e ? BigEndianUtils.FlipEndian((Int32)offsets[i]) : BitConverter.GetBytes((Int32)offsets[i])); + + writer.Write(new byte[5]); + writer.Write(type == FileIdentifiers.MODEL_DATA ? new byte[2] { 0x01, 0x01 } : new byte[2]); + writer.Write(new byte[5]); + + writer.Write(e ? BigEndianUtils.FlipEndian((Int32)content[i].BinIndex) : BitConverter.GetBytes((Int32)content[i].BinIndex)); + writer.Write(new byte[12]); + } + + //Write header + writer.BaseStream.Position = 0; + writer.Write(new byte[4]); + writer.Write(e ? BigEndianUtils.FlipEndian((Int32)FileIdentifiers.ASSET_FILE) : BitConverter.GetBytes((Int32)FileIdentifiers.ASSET_FILE)); + writer.Write(e ? BigEndianUtils.FlipEndian((Int32)FileIdentifiers.MODEL_DATA) : BitConverter.GetBytes((Int32)FileIdentifiers.MODEL_DATA)); + writer.Write(e ? BigEndianUtils.FlipEndian((Int32)content.Count) : BitConverter.GetBytes((Int32)content.Count)); + writer.Write(e ? BigEndianUtils.FlipEndian((Int32)content.Count) : BitConverter.GetBytes((Int32)content.Count)); + writer.Write(e ? BigEndianUtils.FlipEndian((Int32)16) : BitConverter.GetBytes((Int32)16)); + writer.Write(e ? BigEndianUtils.FlipEndian((Int32)1) : BitConverter.GetBytes((Int32)1)); + writer.Write(e ? BigEndianUtils.FlipEndian((Int32)1) : BitConverter.GetBytes((Int32)1)); + } + } + + public class PAKContent + { + public int BinIndex; + public byte[] Data; + } } public static class BigEndianUtils { - public static Int64 ReadInt64(BinaryReader Reader) + public static Int64 ReadInt64(BinaryReader Reader, bool bigEndian = true) { var data = Reader.ReadBytes(8); - Array.Reverse(data); + if (bigEndian) Array.Reverse(data); return BitConverter.ToInt64(data, 0); } - public static UInt64 ReadUInt64(BinaryReader Reader) + public static UInt64 ReadUInt64(BinaryReader Reader, bool bigEndian = true) { var data = Reader.ReadBytes(8); - Array.Reverse(data); + if (bigEndian) Array.Reverse(data); return BitConverter.ToUInt64(data, 0); } - public static Int32 ReadInt32(BinaryReader Reader) + public static Int32 ReadInt32(BinaryReader Reader, bool bigEndian = true) { byte[] data = Reader.ReadBytes(4); - Array.Reverse(data); + if (bigEndian) Array.Reverse(data); return BitConverter.ToInt32(data, 0); } - public static UInt32 ReadUInt32(BinaryReader Reader) + public static UInt32 ReadUInt32(BinaryReader Reader, bool bigEndian = true) { var data = Reader.ReadBytes(4); - Array.Reverse(data); + if (bigEndian) Array.Reverse(data); return BitConverter.ToUInt32(data, 0); } - public static Int16 ReadInt16(BinaryReader Reader) + public static Int16 ReadInt16(BinaryReader Reader, bool bigEndian = true) { var data = Reader.ReadBytes(2); - Array.Reverse(data); + if (bigEndian) Array.Reverse(data); return BitConverter.ToInt16(data, 0); } - public static UInt16 ReadUInt16(BinaryReader Reader) + public static UInt16 ReadUInt16(BinaryReader Reader, bool bigEndian = true) { var data = Reader.ReadBytes(2); - Array.Reverse(data); + if (bigEndian) Array.Reverse(data); return BitConverter.ToUInt16(data, 0); } From 8eaf5dc6e24c80d68a4b580bc23676c0df364676 Mon Sep 17 00:00:00 2001 From: MattFiler Date: Sat, 14 Oct 2023 11:38:22 +0100 Subject: [PATCH 22/30] write idx --- CathodeLib/Scripts/CATHODE/Shaders.cs | 30 ++++++++++++++++++++------- CathodeLib/Scripts/Utilities.cs | 13 ++++++++---- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/CathodeLib/Scripts/CATHODE/Shaders.cs b/CathodeLib/Scripts/CATHODE/Shaders.cs index ea2c2c9..d3a3959 100644 --- a/CathodeLib/Scripts/CATHODE/Shaders.cs +++ b/CathodeLib/Scripts/CATHODE/Shaders.cs @@ -56,6 +56,8 @@ override protected bool LoadInternal() { using (BinaryReader reader = new BinaryReader(new MemoryStream(content[i].Data))) { + Entries.Add(new Shader()); + reader.BaseStream.Position = 8; //0x7725BBA4, 36, 1 int textureCount = reader.ReadInt16(); @@ -139,19 +141,31 @@ override protected bool LoadInternal() override protected bool SaveInternal() { + List content = new List(); + for (int i = 0; i < Entries.Count; i++) + { + + } using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepathBIN))) { } - using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepathIDX))) + + content = new List(); + for (int i = 0; i < Entries.Count; i++) + { + content.Add(new Utilities.PAKContent() + { + BinIndex = i, + Data = BitConverter.GetBytes((Int32)i) + }); + } + Utilities.WritePAK(_filepathIDX, FileIdentifiers.SHADER_DATA, content); + + content = new List(); + for (int i = 0; i < Entries.Count; i++) { - writer.BaseStream.SetLength(0); - writer.Write(0); - writer.Write((int)FileIdentifiers.ASSET_FILE); - writer.Write((int)FileIdentifiers.MODEL_DATA); - writer.Write(Entries.Count); - writer.Write(Entries.Count); - writer.Write(new byte[12]); + } using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) { diff --git a/CathodeLib/Scripts/Utilities.cs b/CathodeLib/Scripts/Utilities.cs index 7a982eb..644ba94 100644 --- a/CathodeLib/Scripts/Utilities.cs +++ b/CathodeLib/Scripts/Utilities.cs @@ -250,11 +250,14 @@ public static void WritePAK(string path, FileIdentifiers type, List writer.BaseStream.Position = contentOffset; List offsets = new List(); List lengths = new List(); + List lengthsAligned = new List(); for (int i = 0; i < content.Count; i++) { offsets.Add((int)writer.BaseStream.Position - contentOffset); writer.Write(content[i].Data); lengths.Add((int)writer.BaseStream.Position - contentOffset - offsets[offsets.Count - 1]); + Align(writer, 16); + lengthsAligned.Add((int)writer.BaseStream.Position - contentOffset - offsets[offsets.Count - 1]); } //Write model headers @@ -263,11 +266,11 @@ public static void WritePAK(string path, FileIdentifiers type, List { writer.Write(new byte[8]); writer.Write(e ? BigEndianUtils.FlipEndian((Int32)lengths[i]) : BitConverter.GetBytes((Int32)lengths[i])); - writer.Write(e ? BigEndianUtils.FlipEndian((Int32)lengths[i]) : BitConverter.GetBytes((Int32)lengths[i])); + writer.Write(e ? BigEndianUtils.FlipEndian((Int32)lengthsAligned[i]) : BitConverter.GetBytes((Int32)lengthsAligned[i])); writer.Write(e ? BigEndianUtils.FlipEndian((Int32)offsets[i]) : BitConverter.GetBytes((Int32)offsets[i])); writer.Write(new byte[5]); - writer.Write(type == FileIdentifiers.MODEL_DATA ? new byte[2] { 0x01, 0x01 } : new byte[2]); + writer.Write(type == FileIdentifiers.MODEL_DATA ? new byte[2] { 0x01, 0x01 } : new byte[2] { 0x00, 0x01 }); writer.Write(new byte[5]); writer.Write(e ? BigEndianUtils.FlipEndian((Int32)content[i].BinIndex) : BitConverter.GetBytes((Int32)content[i].BinIndex)); @@ -278,12 +281,14 @@ public static void WritePAK(string path, FileIdentifiers type, List writer.BaseStream.Position = 0; writer.Write(new byte[4]); writer.Write(e ? BigEndianUtils.FlipEndian((Int32)FileIdentifiers.ASSET_FILE) : BitConverter.GetBytes((Int32)FileIdentifiers.ASSET_FILE)); - writer.Write(e ? BigEndianUtils.FlipEndian((Int32)FileIdentifiers.MODEL_DATA) : BitConverter.GetBytes((Int32)FileIdentifiers.MODEL_DATA)); + writer.Write(e ? BigEndianUtils.FlipEndian((Int32)type) : BitConverter.GetBytes((Int32)type)); writer.Write(e ? BigEndianUtils.FlipEndian((Int32)content.Count) : BitConverter.GetBytes((Int32)content.Count)); writer.Write(e ? BigEndianUtils.FlipEndian((Int32)content.Count) : BitConverter.GetBytes((Int32)content.Count)); writer.Write(e ? BigEndianUtils.FlipEndian((Int32)16) : BitConverter.GetBytes((Int32)16)); writer.Write(e ? BigEndianUtils.FlipEndian((Int32)1) : BitConverter.GetBytes((Int32)1)); - writer.Write(e ? BigEndianUtils.FlipEndian((Int32)1) : BitConverter.GetBytes((Int32)1)); + + int unk = type == FileIdentifiers.MODEL_DATA ? 1 : 0; + writer.Write(e ? BigEndianUtils.FlipEndian((Int32)unk) : BitConverter.GetBytes((Int32)unk)); } } From c04447627013cbf989fa0d1c8fd252c016b0b90c Mon Sep 17 00:00:00 2001 From: MattFiler Date: Sun, 15 Oct 2023 14:29:31 +0100 Subject: [PATCH 23/30] shaders continued --- CathodeLib/Scripts/CATHODE/Shaders.cs | 307 +++++++++++++++++++++++++- CathodeLib/Scripts/Utilities.cs | 21 ++ 2 files changed, 318 insertions(+), 10 deletions(-) diff --git a/CathodeLib/Scripts/CATHODE/Shaders.cs b/CathodeLib/Scripts/CATHODE/Shaders.cs index d3a3959..ab44204 100644 --- a/CathodeLib/Scripts/CATHODE/Shaders.cs +++ b/CathodeLib/Scripts/CATHODE/Shaders.cs @@ -1,7 +1,9 @@ using CathodeLib; using System; using System.Collections.Generic; +using System.Collections.Specialized; using System.IO; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using static CATHODE.LEGACY.ShadersPAK; @@ -27,6 +29,13 @@ override protected bool LoadInternal() if (!File.Exists(_filepathBIN)) return false; if (!File.Exists(_filepathIDX)) return false; + int vertexShaderCount = 0; + int pixelShaderCount = 0; + int hullShaderCount = 0; + int domainShaderCount = 0; + int geometryShaderCount = 0; + int computeShaderCount = 0; + List content = Utilities.ReadPAK(_filepathBIN, FileIdentifiers.SHADER_DATA); for (int i = 0; i < content.Count; i++) { @@ -34,11 +43,223 @@ override protected bool LoadInternal() using (BinaryReader reader = new BinaryReader(new MemoryStream(content[i].Data))) { + //The first entry here acts as an additional header + if (i == 0) + { + vertexShaderCount = reader.ReadInt32(); + pixelShaderCount = reader.ReadInt32(); + hullShaderCount = reader.ReadInt32(); + domainShaderCount = reader.ReadInt32(); + geometryShaderCount = reader.ReadInt32(); + computeShaderCount = reader.ReadInt32(); + continue; + } + + fourcc fourcc = Utilities.Consume(reader); + if (fourcc.ToString() != "DXBC") + { + throw new Exception("Unexpected"); + } + + int[] checksums = Utilities.ConsumeArray(reader, 4); + + int one = reader.ReadInt32(); + if (one != 1) + { + throw new Exception("Unexpected"); + } + int size = reader.ReadInt32(); + int chunkCount = reader.ReadInt32(); + int[] chunkOffsets = Utilities.ConsumeArray(reader, chunkCount); + + for (int x = 0; x < chunkCount; x++) + { + if (reader.BaseStream.Position != chunkOffsets[x]) + { + string sdffsd = ""; + } + reader.BaseStream.Position = chunkOffsets[x]; + + fourcc chunkFourcc = Utilities.Consume(reader); + int chunkSize = reader.ReadInt32(); + + //TODO: should actually parse this eventually + byte[] chunkContent = reader.ReadBytes(chunkSize); + using (BinaryReader chunkReader = new BinaryReader(new MemoryStream(chunkContent))) + { + switch (chunkFourcc.ToString()) + { + case "RDEF": + { + int constantBufferCount = chunkReader.ReadInt32(); + int constantBufferOffset = chunkReader.ReadInt32(); + int resourceBindingCount = chunkReader.ReadInt32(); + int resourceBindingOffset = chunkReader.ReadInt32(); + + chunkReader.BaseStream.Position += 2; //0, 5 + + int type = chunkReader.ReadInt16(); + if (type != -2 && type != -1) + { + //Console.WriteLine(type); + string sdffd = ""; + } + else + { + string sfgsdfsf = ""; + } + //DXBCType programType = (DXBCType)chunkReader.ReadInt32(); + + int flags = chunkReader.ReadInt32(); + int creatorStringOffset = chunkReader.ReadInt32(); + + chunkReader.BaseStream.Position += 28; //RD11, 60, 24, 32, 40, 36, 12 + + int interfaceSlotCount = chunkReader.ReadInt32(); + + if (resourceBindingCount != 0 && chunkReader.BaseStream.Position != resourceBindingOffset) + throw new Exception("Unexpected"); + + int[] resourceNameOffsets = new int[resourceBindingCount]; + for (int z = 0; z < resourceBindingCount; z++) + { + resourceNameOffsets[z] = chunkReader.ReadInt32(); + int ShaderInputType = chunkReader.ReadInt32(); + int ResourceReturnType = chunkReader.ReadInt32(); + int ResourceViewDimension = chunkReader.ReadInt32(); + int SampleCount = chunkReader.ReadInt32(); + int BindPoint = chunkReader.ReadInt32(); + int BindCount = chunkReader.ReadInt32(); + int ShaderInputFlags = chunkReader.ReadInt32(); + } + for (int z = 0; z < resourceBindingCount; z++) + { + if (chunkReader.BaseStream.Position != resourceNameOffsets[z]) + throw new Exception("Unexpected"); + + string name = Utilities.ReadString(chunkReader); + //Console.WriteLine("Resource Binding Name: " + name); + } + + Utilities.Align(chunkReader); + + //chunkReader.BaseStream.Position = constantBufferOffset; + if (constantBufferCount != 0 && chunkReader.BaseStream.Position != constantBufferOffset) + throw new Exception("Unexpected"); + + int[] cbNameOffsets = new int[constantBufferCount]; + int[] cbVariableCounts = new int[constantBufferCount]; + int[] cbVariableOffsets = new int[constantBufferCount]; + int[][] cbVariableNameOffsets = new int[constantBufferCount][]; + for (int z = 0; z < constantBufferCount; z++) + { + cbNameOffsets[z] = chunkReader.ReadInt32(); + cbVariableCounts[z] = chunkReader.ReadInt32(); + cbVariableOffsets[z] = chunkReader.ReadInt32(); + int SizeInBytes = chunkReader.ReadInt32(); + int Flags = chunkReader.ReadInt32(); + int Type = chunkReader.ReadInt32(); + + if (Type != 0 || Flags != 0) + { + string sdfsdf = ""; + } + } + for (int z = 0; z < constantBufferCount; z++) + { + //string name = Utilities.ReadString(chunkReader, cbNameOffsets[z]); + //Console.WriteLine("Constant Bufffer Name: " + name); + + chunkReader.BaseStream.Position = cbVariableOffsets[z]; + //if (chunkReader.BaseStream.Position != cbVariableOffsets[z]) + // throw new Exception("Unexpected"); + + cbVariableNameOffsets[z] = new int[cbVariableCounts[z]]; + int[] typeOffsets = new int[cbVariableCounts[z]]; + for (int p = 0; p < cbVariableCounts[z]; p++) + { + cbVariableNameOffsets[z][p] = chunkReader.ReadInt32(); + int DataOffset = chunkReader.ReadInt32(); + int DataSize = chunkReader.ReadInt32(); + int Flags = chunkReader.ReadInt32(); + typeOffsets[p] = chunkReader.ReadInt32(); + int DefaultValueOffset = chunkReader.ReadInt32(); + + if (DefaultValueOffset != 0) + { + string sdfsdf = ""; + } + + // TODO: I think the version 5 is different than 4. This is not there on Version 4. + int[] unk = Utilities.ConsumeArray(chunkReader, 4); + } + for (int p = 0; p < cbVariableCounts[z]; p++) + { + chunkReader.BaseStream.Position = typeOffsets[p]; + //if (chunkReader.BaseStream.Position != typeOffsets[p]) + // throw new Exception("Unexpected"); + + int Class = chunkReader.ReadInt16(); + int Type = chunkReader.ReadInt16(); + int RowCount = chunkReader.ReadInt16(); + int ColumnCount = chunkReader.ReadInt16(); + int ArrayCount = chunkReader.ReadInt16(); + int MemberCount = chunkReader.ReadInt16(); + int MembersOffset = chunkReader.ReadInt16(); + + if (MembersOffset != 0) + { + string sdfsdf = ""; + } + + // TODO: I think the version 5 is different than 4. This is not there on Version 4. + short[] Unknown_ = Utilities.ConsumeArray(chunkReader, 9); + int NameStringOffset = chunkReader.ReadInt32(); + } + } + break; + } + + case "PCSG": + case "ISGN": + case "OSGN": + { + break; + } + + case "SHEX": + { + chunkReader.BaseStream.Position += 2; //80 + + dxbc_chunk_shex_type type = (dxbc_chunk_shex_type)chunkReader.ReadInt16(); + int count = chunkReader.ReadInt32(); + byte[] contentBytes = chunkReader.ReadBytes((count - 2) * 4); + + if (chunkReader.BaseStream.Length != chunkReader.BaseStream.Position) + throw new Exception(""); + break; + } + + + case "STAT": + { + dxbc_chunk_stat stat = Utilities.Consume(chunkReader); + + if (chunkReader.BaseStream.Length != chunkReader.BaseStream.Position) + throw new Exception(""); + break; + } + + default: + throw new Exception("Unexpected"); + } + } + } } } - //Read the index remapping pak (this is actually just an incrementing count lol) + //I don't think we need to read this really, it's just a count. content = Utilities.ReadPAK(_filepathIDX, FileIdentifiers.SHADER_DATA); for (int i = 0; i < content.Count; i++) { @@ -54,6 +275,13 @@ override protected bool LoadInternal() content = Utilities.ReadPAK(_filepath, FileIdentifiers.SHADER_DATA); for (int i = 0; i < content.Count; i++) { + //Console.WriteLine(content[i].BinIndex); + + if (content[i].BinIndex != i) + { + string sdfsdf = ""; + } + using (BinaryReader reader = new BinaryReader(new MemoryStream(content[i].Data))) { Entries.Add(new Shader()); @@ -176,21 +404,80 @@ override protected bool SaveInternal() #endregion #region STRUCTURES + + public enum DXBCType + { + VERTEX = -2, + PIXEL = -1, + } + + enum dxbc_chunk_shex_type + { + SHEXShader_Pixel, + SHEXShader_Vertex, + SHEXShader_Geometry, + SHEXShader_Hull, + SHEXShader_Domain, + SHEXShader_Compute, + }; + + struct dxbc_chunk_stat + { + public int InstructionCount; + public int TempRegisterCount; + public int DefineCount; + public int DeclarationCount; + public int FloatInstructionCount; + public int IntInstructionCount; + public int UIntInstructionCount; + public int StaticFlowControlCount; + public int DynamicFlowControlCount; + public int MacroInstructionCount; // Not sure. + public int TempArrayCount; + public int ArrayInstructionCount; + public int CutInstructionCount; + public int EmitInstructionCount; + public int TextureNormalInstructionCount; + public int TextureLoadInstructionCount; + public int TextureComparisonInstructionCount; + public int TextureBiasInstructionCount; + public int TextureGradientInstructionCount; + public int MovInstructionCount; + public int MovCInstructionCount; + public int Unknown0_; + public int InputPrimitiveForGeometryShaders; + public int PrimitiveTopologyForGeometryShaders; + public int MaxOutputVertexCountForGeometryShaders; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public int[] unk0; //zeros + + public int IsSampleFrequencyShader; // 1 for sample frequency shadeer, otherwise 0. + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)] + public int[] unk1; + }; + public class Shader { - public string FileName = ""; //The name of the file in the shader archive (unsure how to get this right now with the weird _BIN/PAK way of working) - public int FileLength = 0; //The length of the file in the archive for this header - public int FileLengthWithPadding = 0; //The length of the file in the archive for this header, with any padding at the end of the file included + } + + public class VertexShader : Shader + { + + } + public class PixelShader : Shader + { - public int FileOffset = 0; //Position in archive from end of header list - public int FileIndex = 0; //The index of the file + } + public class HullShader : Shader + { - public byte[] FileContent; //The content for the file + } + public class DomainShader : Shader + { - //I think this is just garbage that got dumped by accident - public byte[] StringPart1; //4 bytes that look like they're part of a filepath - public byte[] StringPart2; //4 bytes that look like they're part of a filepath } #endregion } diff --git a/CathodeLib/Scripts/Utilities.cs b/CathodeLib/Scripts/Utilities.cs index 644ba94..2c8e622 100644 --- a/CathodeLib/Scripts/Utilities.cs +++ b/CathodeLib/Scripts/Utilities.cs @@ -76,6 +76,22 @@ public static string ReadString(byte[] bytes, int position) } return to_return; } + public static string ReadString(BinaryReader reader, int position, bool resetPosition = true) + { + long startPos = reader.BaseStream.Position; + reader.BaseStream.Position = position; + + string to_return = ""; + for (int i = 0; i < int.MaxValue; i++) + { + byte this_byte = reader.ReadByte(); + if (this_byte == 0x00) break; + to_return += (char)this_byte; + } + + if (resetPosition) reader.BaseStream.Position = startPos; + return to_return; + } public static string ReadString(BinaryReader reader) { string to_return = ""; @@ -509,5 +525,10 @@ public struct fourcc { [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public char[] V; + + public override string ToString() + { + return new string(V); + } } } \ No newline at end of file From 5a17eb4b41b3c491096d33ff293fdee8b83deb30 Mon Sep 17 00:00:00 2001 From: MattFiler Date: Sun, 15 Oct 2023 19:21:24 +0100 Subject: [PATCH 24/30] shader write --- CathodeLib/Scripts/CATHODE/Materials.cs | 3 +- CathodeLib/Scripts/CATHODE/Shaders.cs | 813 +++++++++++++++--------- CathodeLib/Scripts/Utilities.cs | 2 +- 3 files changed, 500 insertions(+), 318 deletions(-) diff --git a/CathodeLib/Scripts/CATHODE/Materials.cs b/CathodeLib/Scripts/CATHODE/Materials.cs index cfe36bf..bc47b3d 100644 --- a/CathodeLib/Scripts/CATHODE/Materials.cs +++ b/CathodeLib/Scripts/CATHODE/Materials.cs @@ -67,8 +67,7 @@ override protected bool LoadInternal() material.TextureReferences[x] = texRef; } reader.BaseStream.Position += 8; - List cstIndexes = new List(); - for (int x = 0; x < 5; x++) cstIndexes.Add(reader.ReadInt32()); + int[] cstIndexes = Utilities.ConsumeArray(reader, 5); for (int x = 0; x < 5; x++) { int cstCount = reader.ReadByte(); diff --git a/CathodeLib/Scripts/CATHODE/Shaders.cs b/CathodeLib/Scripts/CATHODE/Shaders.cs index ab44204..02433b1 100644 --- a/CathodeLib/Scripts/CATHODE/Shaders.cs +++ b/CathodeLib/Scripts/CATHODE/Shaders.cs @@ -3,9 +3,14 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.IO; +using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Windows.Media.Animation; +using static CATHODE.EXPERIMENTAL.MissionSave; using static CATHODE.LEGACY.ShadersPAK; +using static CATHODE.Shaders; +using static CATHODE.Shaders.Shader; namespace CATHODE { @@ -13,7 +18,8 @@ namespace CATHODE public class Shaders : CathodeFile { public List Entries = new List(); - public static new Implementation Implementation = Implementation.NONE; + + public static new Implementation Implementation = Implementation.CREATE | Implementation.LOAD | Implementation.SAVE; public Shaders(string path) : base(path) { } private string _filepathBIN; @@ -29,13 +35,14 @@ override protected bool LoadInternal() if (!File.Exists(_filepathBIN)) return false; if (!File.Exists(_filepathIDX)) return false; - int vertexShaderCount = 0; - int pixelShaderCount = 0; - int hullShaderCount = 0; - int domainShaderCount = 0; - int geometryShaderCount = 0; - int computeShaderCount = 0; + List VertexShaders = new List(); + List PixelShaders = new List(); + List HullShaders = new List(); + List DomainShaders = new List(); + List GeometryShaders = new List(); + List ComputeShaders = new List(); + //This is all the raw DXBC shader data List content = Utilities.ReadPAK(_filepathBIN, FileIdentifiers.SHADER_DATA); for (int i = 0; i < content.Count; i++) { @@ -43,223 +50,44 @@ override protected bool LoadInternal() using (BinaryReader reader = new BinaryReader(new MemoryStream(content[i].Data))) { - //The first entry here acts as an additional header + //The first entry acts as an additional header if (i == 0) { - vertexShaderCount = reader.ReadInt32(); - pixelShaderCount = reader.ReadInt32(); - hullShaderCount = reader.ReadInt32(); - domainShaderCount = reader.ReadInt32(); - geometryShaderCount = reader.ReadInt32(); - computeShaderCount = reader.ReadInt32(); + VertexShaders.Capacity = reader.ReadInt32(); + PixelShaders.Capacity = reader.ReadInt32(); + HullShaders.Capacity = reader.ReadInt32(); + DomainShaders.Capacity = reader.ReadInt32(); + GeometryShaders.Capacity = reader.ReadInt32(); + ComputeShaders.Capacity = reader.ReadInt32(); continue; } - fourcc fourcc = Utilities.Consume(reader); - if (fourcc.ToString() != "DXBC") - { - throw new Exception("Unexpected"); - } - - int[] checksums = Utilities.ConsumeArray(reader, 4); - - int one = reader.ReadInt32(); - if (one != 1) - { - throw new Exception("Unexpected"); - } - - int size = reader.ReadInt32(); - int chunkCount = reader.ReadInt32(); - int[] chunkOffsets = Utilities.ConsumeArray(reader, chunkCount); - - for (int x = 0; x < chunkCount; x++) + ShaderType type = GetTypeFromDXBC(content[i].Data); + switch (type) { - if (reader.BaseStream.Position != chunkOffsets[x]) - { - string sdffsd = ""; - } - reader.BaseStream.Position = chunkOffsets[x]; - - fourcc chunkFourcc = Utilities.Consume(reader); - int chunkSize = reader.ReadInt32(); - - //TODO: should actually parse this eventually - byte[] chunkContent = reader.ReadBytes(chunkSize); - using (BinaryReader chunkReader = new BinaryReader(new MemoryStream(chunkContent))) - { - switch (chunkFourcc.ToString()) - { - case "RDEF": - { - int constantBufferCount = chunkReader.ReadInt32(); - int constantBufferOffset = chunkReader.ReadInt32(); - int resourceBindingCount = chunkReader.ReadInt32(); - int resourceBindingOffset = chunkReader.ReadInt32(); - - chunkReader.BaseStream.Position += 2; //0, 5 - - int type = chunkReader.ReadInt16(); - if (type != -2 && type != -1) - { - //Console.WriteLine(type); - string sdffd = ""; - } - else - { - string sfgsdfsf = ""; - } - //DXBCType programType = (DXBCType)chunkReader.ReadInt32(); - - int flags = chunkReader.ReadInt32(); - int creatorStringOffset = chunkReader.ReadInt32(); - - chunkReader.BaseStream.Position += 28; //RD11, 60, 24, 32, 40, 36, 12 - - int interfaceSlotCount = chunkReader.ReadInt32(); - - if (resourceBindingCount != 0 && chunkReader.BaseStream.Position != resourceBindingOffset) - throw new Exception("Unexpected"); - - int[] resourceNameOffsets = new int[resourceBindingCount]; - for (int z = 0; z < resourceBindingCount; z++) - { - resourceNameOffsets[z] = chunkReader.ReadInt32(); - int ShaderInputType = chunkReader.ReadInt32(); - int ResourceReturnType = chunkReader.ReadInt32(); - int ResourceViewDimension = chunkReader.ReadInt32(); - int SampleCount = chunkReader.ReadInt32(); - int BindPoint = chunkReader.ReadInt32(); - int BindCount = chunkReader.ReadInt32(); - int ShaderInputFlags = chunkReader.ReadInt32(); - } - for (int z = 0; z < resourceBindingCount; z++) - { - if (chunkReader.BaseStream.Position != resourceNameOffsets[z]) - throw new Exception("Unexpected"); - - string name = Utilities.ReadString(chunkReader); - //Console.WriteLine("Resource Binding Name: " + name); - } - - Utilities.Align(chunkReader); - - //chunkReader.BaseStream.Position = constantBufferOffset; - if (constantBufferCount != 0 && chunkReader.BaseStream.Position != constantBufferOffset) - throw new Exception("Unexpected"); - - int[] cbNameOffsets = new int[constantBufferCount]; - int[] cbVariableCounts = new int[constantBufferCount]; - int[] cbVariableOffsets = new int[constantBufferCount]; - int[][] cbVariableNameOffsets = new int[constantBufferCount][]; - for (int z = 0; z < constantBufferCount; z++) - { - cbNameOffsets[z] = chunkReader.ReadInt32(); - cbVariableCounts[z] = chunkReader.ReadInt32(); - cbVariableOffsets[z] = chunkReader.ReadInt32(); - int SizeInBytes = chunkReader.ReadInt32(); - int Flags = chunkReader.ReadInt32(); - int Type = chunkReader.ReadInt32(); - - if (Type != 0 || Flags != 0) - { - string sdfsdf = ""; - } - } - for (int z = 0; z < constantBufferCount; z++) - { - //string name = Utilities.ReadString(chunkReader, cbNameOffsets[z]); - //Console.WriteLine("Constant Bufffer Name: " + name); - - chunkReader.BaseStream.Position = cbVariableOffsets[z]; - //if (chunkReader.BaseStream.Position != cbVariableOffsets[z]) - // throw new Exception("Unexpected"); - - cbVariableNameOffsets[z] = new int[cbVariableCounts[z]]; - int[] typeOffsets = new int[cbVariableCounts[z]]; - for (int p = 0; p < cbVariableCounts[z]; p++) - { - cbVariableNameOffsets[z][p] = chunkReader.ReadInt32(); - int DataOffset = chunkReader.ReadInt32(); - int DataSize = chunkReader.ReadInt32(); - int Flags = chunkReader.ReadInt32(); - typeOffsets[p] = chunkReader.ReadInt32(); - int DefaultValueOffset = chunkReader.ReadInt32(); - - if (DefaultValueOffset != 0) - { - string sdfsdf = ""; - } - - // TODO: I think the version 5 is different than 4. This is not there on Version 4. - int[] unk = Utilities.ConsumeArray(chunkReader, 4); - } - for (int p = 0; p < cbVariableCounts[z]; p++) - { - chunkReader.BaseStream.Position = typeOffsets[p]; - //if (chunkReader.BaseStream.Position != typeOffsets[p]) - // throw new Exception("Unexpected"); - - int Class = chunkReader.ReadInt16(); - int Type = chunkReader.ReadInt16(); - int RowCount = chunkReader.ReadInt16(); - int ColumnCount = chunkReader.ReadInt16(); - int ArrayCount = chunkReader.ReadInt16(); - int MemberCount = chunkReader.ReadInt16(); - int MembersOffset = chunkReader.ReadInt16(); - - if (MembersOffset != 0) - { - string sdfsdf = ""; - } - - // TODO: I think the version 5 is different than 4. This is not there on Version 4. - short[] Unknown_ = Utilities.ConsumeArray(chunkReader, 9); - int NameStringOffset = chunkReader.ReadInt32(); - } - } - break; - } - - case "PCSG": - case "ISGN": - case "OSGN": - { - break; - } - - case "SHEX": - { - chunkReader.BaseStream.Position += 2; //80 - - dxbc_chunk_shex_type type = (dxbc_chunk_shex_type)chunkReader.ReadInt16(); - int count = chunkReader.ReadInt32(); - byte[] contentBytes = chunkReader.ReadBytes((count - 2) * 4); - - if (chunkReader.BaseStream.Length != chunkReader.BaseStream.Position) - throw new Exception(""); - break; - } - - - case "STAT": - { - dxbc_chunk_stat stat = Utilities.Consume(chunkReader); - - if (chunkReader.BaseStream.Length != chunkReader.BaseStream.Position) - throw new Exception(""); - break; - } - - default: - throw new Exception("Unexpected"); - } - } + case ShaderType.VERTEX: + VertexShaders.Add(content[i].Data); + break; + case ShaderType.PIXEL: + PixelShaders.Add(content[i].Data); + break; + case ShaderType.HULL: + HullShaders.Add(content[i].Data); + break; + case ShaderType.DOMAIN: + DomainShaders.Add(content[i].Data); + break; + case ShaderType.GEOMETRY: + GeometryShaders.Add(content[i].Data); + break; + case ShaderType.COMPUTE: + ComputeShaders.Add(content[i].Data); + break; } } } - //I don't think we need to read this really, it's just a count. + //I don't think we need to read this really, it's just a count content = Utilities.ReadPAK(_filepathIDX, FileIdentifiers.SHADER_DATA); for (int i = 0; i < content.Count; i++) { @@ -272,28 +100,23 @@ override protected bool LoadInternal() } } + //This is additional metadata content = Utilities.ReadPAK(_filepath, FileIdentifiers.SHADER_DATA); for (int i = 0; i < content.Count; i++) { - //Console.WriteLine(content[i].BinIndex); - - if (content[i].BinIndex != i) - { - string sdfsdf = ""; - } + if (content[i].BinIndex != i) return false; using (BinaryReader reader = new BinaryReader(new MemoryStream(content[i].Data))) { - Entries.Add(new Shader()); + Shader shader = new Shader(); reader.BaseStream.Position = 8; //0x7725BBA4, 36, 1 int textureCount = reader.ReadInt16(); - int[] cstCounts = new int[5]; - for (int x = 0; x < 5; x++) cstCounts[x] = reader.ReadInt32(); + int[] cstCounts = Utilities.ConsumeArray(reader, 5); int textureLinkCount = reader.ReadInt16(); - string name = Utilities.ReadString(reader.ReadBytes(40)); - ShaderCategory category = (ShaderCategory)reader.ReadInt16(); + reader.BaseStream.Position += 40; //String version of Category + shader.Category = (ShaderCategory)reader.ReadInt16(); // Index 0: 0x04: seems to be metal. 0x01: seems to be non-metal. But it has many exceptions so maybe check renderdoc. // Index 1: ParallaxMap? It seems to be either 0x30 and 0x80 for the most part, sometimes it combines both into 0xB0. @@ -309,58 +132,73 @@ override protected bool LoadInternal() // 0x39 (0011 1001): has opacity noise and dirt maps. // Index 10: First half, only found 4, and it seems to be something included in all (Diffuse0 as well?). // Seems like the least significant bit enables/disables opacity noise? - int[] flags = new int[20]; - for (int x = 0; x < 20; x++) flags[x] = reader.ReadByte(); + for (int x = 0; x < 20; x++) + shader.Flags[x] = reader.ReadByte(); - int unk = reader.ReadInt32(); + shader.Unknown1 = reader.ReadInt32(); int entryCount = reader.ReadInt16(); for (int x = 0; x < entryCount; x++) { - int unk1 = reader.ReadInt16(); - int unk2 = reader.ReadInt32(); + shader.Unknown2.Add(new Shader.UnknownPair() + { + unk1 = reader.ReadInt16(), + unk2 = reader.ReadInt32() + }); } for (int x = 0; x < textureCount; x++) { - int unk1 = reader.ReadByte(); - int unk2 = reader.ReadByte(); - int[] unk3 = new int[16]; - for (int z = 0; z < 16; z++) unk3[z] = reader.ReadInt16(); - float unk4 = reader.ReadSingle(); - int unk5 = reader.ReadInt16(); - float unk6 = reader.ReadSingle(); + UnknownTextureThing unk = new UnknownTextureThing(); + unk.unk1 = reader.ReadByte(); + unk.unk2 = reader.ReadByte(); + unk.unk3 = new short[16]; + for (int z = 0; z < 16; z++) + unk.unk3[z] = reader.ReadInt16(); + unk.unk4 = reader.ReadSingle(); + unk.unk5 = reader.ReadInt16(); + unk.unk6 = reader.ReadSingle(); + shader.Unknown3.Add(unk); } - for (int x = 0; x < textureCount; x++) { - int unk1 = reader.ReadByte(); + shader.Unknown3[x].unk7 = reader.ReadByte(); } - int[][] cstLinks = new int[5][]; + shader.CSTLinks = new int[5][]; for (int x = 0; x < 5; x++) { - cstLinks[x] = new int[cstCounts[x]]; + shader.CSTLinks[x] = new int[cstCounts[x]]; for (int z = 0; z < cstCounts[x]; z++) { - cstLinks[x][z] = reader.ReadByte(); + shader.CSTLinks[x][z] = reader.ReadByte(); } } - int[] textureLinks = new int[textureLinkCount]; + shader.TextureLinks = new int[textureLinkCount]; for (int x = 0; x < textureLinkCount; x++) { - textureLinks[x] = reader.ReadByte(); + shader.TextureLinks[x] = reader.ReadByte(); } - int vertexShader = reader.ReadInt32(); - int pixelShader = reader.ReadInt32(); - int hullShader = reader.ReadInt32(); - int domainShader = reader.ReadInt32(); + int vertexShaderIdx = reader.ReadInt32(); + int pixelShaderIdx = reader.ReadInt32(); + int hullShaderIdx = reader.ReadInt32(); + int domainShaderIdx = reader.ReadInt32(); + int geometryShaderIdx = reader.ReadInt32(); + int computeShaderIdx = reader.ReadInt32(); + + shader.VertexShader = vertexShaderIdx == -1 ? null : VertexShaders[vertexShaderIdx]; + shader.PixelShader = pixelShaderIdx == -1 ? null : PixelShaders[pixelShaderIdx]; + shader.HullShader = hullShaderIdx == -1 ? null : HullShaders[hullShaderIdx]; + shader.DomainShader = domainShaderIdx == -1 ? null : DomainShaders[domainShaderIdx]; + shader.GeometryShader = geometryShaderIdx == -1 ? null : GeometryShaders[geometryShaderIdx]; + shader.ComputeShader = computeShaderIdx == -1 ? null : ComputeShaders[computeShaderIdx]; + + int pos = (int)reader.BaseStream.Position; + int len = (int)reader.BaseStream.Length; - //Interestingly, seems like neither of these are used - int geometryShader = reader.ReadInt32(); - int computeShader = reader.ReadInt32(); + Entries.Add(shader); } } @@ -369,16 +207,59 @@ override protected bool LoadInternal() override protected bool SaveInternal() { - List content = new List(); + //Compile all shader data + List VertexShaders = new List(); + List PixelShaders = new List(); + List HullShaders = new List(); + List DomainShaders = new List(); + List GeometryShaders = new List(); + List ComputeShaders = new List(); for (int i = 0; i < Entries.Count; i++) { + if (Entries[i].VertexShader != null && !VertexShaders.Contains(Entries[i].VertexShader)) + VertexShaders.Add(Entries[i].VertexShader); + if (Entries[i].PixelShader != null && !PixelShaders.Contains(Entries[i].PixelShader)) + PixelShaders.Add(Entries[i].PixelShader); + if (Entries[i].HullShader != null && !HullShaders.Contains(Entries[i].HullShader)) + HullShaders.Add(Entries[i].HullShader); + if (Entries[i].DomainShader != null && !DomainShaders.Contains(Entries[i].DomainShader)) + DomainShaders.Add(Entries[i].DomainShader); + if (Entries[i].GeometryShader != null && !GeometryShaders.Contains(Entries[i].GeometryShader)) + GeometryShaders.Add(Entries[i].GeometryShader); + if (Entries[i].ComputeShader != null && !ComputeShaders.Contains(Entries[i].ComputeShader)) + ComputeShaders.Add(Entries[i].ComputeShader); + } + //Write out all shader data + List content = new List(); + { + List bytes = new List(); + bytes.AddRange(BitConverter.GetBytes(VertexShaders.Count)); + bytes.AddRange(BitConverter.GetBytes(PixelShaders.Count)); + bytes.AddRange(BitConverter.GetBytes(HullShaders.Count)); + bytes.AddRange(BitConverter.GetBytes(DomainShaders.Count)); + bytes.AddRange(BitConverter.GetBytes(GeometryShaders.Count)); + bytes.AddRange(BitConverter.GetBytes(ComputeShaders.Count)); + content.Add(new Utilities.PAKContent() { Data = bytes.ToArray() }); } - using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepathBIN))) + List AllShaders = new List(); + AllShaders.AddRange(VertexShaders); + AllShaders.AddRange(PixelShaders); + AllShaders.AddRange(HullShaders); + AllShaders.AddRange(DomainShaders); + AllShaders.AddRange(GeometryShaders); + AllShaders.AddRange(ComputeShaders); + for (int i = 0; i < AllShaders.Count; i++) { - + content.Add(new Utilities.PAKContent() + { + BinIndex = i + 1, + Data = AllShaders[i] + }); } + Utilities.WritePAK(_filepathBIN, FileIdentifiers.SHADER_DATA, content); + //Write out indexes content = new List(); for (int i = 0; i < Entries.Count; i++) { @@ -390,95 +271,397 @@ override protected bool SaveInternal() } Utilities.WritePAK(_filepathIDX, FileIdentifiers.SHADER_DATA, content); + //Write out metadata content = new List(); for (int i = 0; i < Entries.Count; i++) { - + MemoryStream data = new MemoryStream(); + using (BinaryWriter writer = new BinaryWriter(data)) + { + writer.Write(0x7725BBA4); + writer.Write((Int16)36); + writer.Write((Int16)1); + writer.Write((Int16)Entries[i].Unknown3.Count); + for (int z = 0; z < 5; z++) + writer.Write(Entries[i].CSTLinks[z].Length); + writer.Write((Int16)Entries[i].TextureLinks.Length); + Utilities.WriteString(Entries[i].Category.ToString(), writer); + writer.Write(new byte[40 - Entries[i].Category.ToString().Length]); + writer.Write((Int16)Entries[i].Category); + for (int z = 0; z < 20; z++) + writer.Write((byte)Entries[i].Flags[z]); + writer.Write(Entries[i].Unknown1); + writer.Write((Int16)Entries[i].Unknown2.Count); + for (int z = 0; z < Entries[i].Unknown2.Count; z++) + { + writer.Write((Int16)Entries[i].Unknown2[z].unk1); + writer.Write(Entries[i].Unknown2[z].unk2); + } + for (int z = 0; z < Entries[i].Unknown3.Count; z++) + { + writer.Write((byte)Entries[i].Unknown3[z].unk1); + writer.Write((byte)Entries[i].Unknown3[z].unk2); + for (int p = 0; p < 16; p++) + writer.Write((Int16)Entries[i].Unknown3[z].unk3[p]); + writer.Write(Entries[i].Unknown3[z].unk4); + writer.Write((Int16)Entries[i].Unknown3[z].unk5); + writer.Write(Entries[i].Unknown3[z].unk6); + } + for (int z = 0; z < Entries[i].Unknown3.Count; z++) + { + writer.Write((byte)Entries[i].Unknown3[z].unk7); + } + for (int z = 0; z < 5; z++) + { + for (int p = 0; p < Entries[i].CSTLinks[z].Length; p++) + { + writer.Write((byte)Entries[i].CSTLinks[z][p]); + } + } + for (int z = 0; z < Entries[i].TextureLinks.Length; z++) + { + writer.Write((byte)Entries[i].TextureLinks[z]); + } + writer.Write(Entries[i].VertexShader == null ? -1 : VertexShaders.IndexOf(Entries[i].VertexShader)); + writer.Write(Entries[i].PixelShader == null ? -1 : PixelShaders.IndexOf(Entries[i].PixelShader)); + writer.Write(Entries[i].HullShader == null ? -1 : HullShaders.IndexOf(Entries[i].HullShader)); + writer.Write(Entries[i].DomainShader == null ? -1 : DomainShaders.IndexOf(Entries[i].DomainShader)); + writer.Write(Entries[i].GeometryShader == null ? -1 : GeometryShaders.IndexOf(Entries[i].GeometryShader)); + writer.Write(Entries[i].ComputeShader == null ? -1 : ComputeShaders.IndexOf(Entries[i].ComputeShader)); + } + content.Add(new Utilities.PAKContent() + { + BinIndex = i, + Data = data.ToArray() + }); } - using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(_filepath))) + Utilities.WritePAK(_filepath, FileIdentifiers.SHADER_DATA, content); + return true; + } + #endregion + + private ShaderType GetTypeFromDXBC(byte[] dxbc) + { + using (BinaryReader reader = new BinaryReader(new MemoryStream(dxbc))) { + reader.BaseStream.Position += 4; //DXBC + int[] checksums = Utilities.ConsumeArray(reader, 4); + reader.BaseStream.Position += 4; //1 + + int size = reader.ReadInt32(); + int chunkCount = reader.ReadInt32(); + int[] chunkOffsets = Utilities.ConsumeArray(reader, chunkCount); + + for (int x = 0; x < chunkCount; x++) + { + reader.BaseStream.Position = chunkOffsets[x]; + + fourcc chunkFourcc = Utilities.Consume(reader); + Console.WriteLine(chunkFourcc.ToString()); + int chunkSize = reader.ReadInt32(); + byte[] chunkContent = reader.ReadBytes(chunkSize); + using (BinaryReader chunkReader = new BinaryReader(new MemoryStream(chunkContent))) + { + switch (chunkFourcc.ToString()) + { + /* + case "RDEF": //Resource definition. Describes constant buffers and resource bindings. + { + int constantBufferCount = chunkReader.ReadInt32(); + int constantBufferOffset = chunkReader.ReadInt32(); + int resourceBindingCount = chunkReader.ReadInt32(); + int resourceBindingOffset = chunkReader.ReadInt32(); + + chunkReader.BaseStream.Position += 2; //0, 5 + + shader.Type = chunkReader.ReadInt16(); + shader.Flags = chunkReader.ReadInt32(); + + int creatorStringOffset = chunkReader.ReadInt32(); + + chunkReader.BaseStream.Position += 28; //RD11, 60, 24, 32, 40, 36, 12 + + shader.InterfaceSlotCount = chunkReader.ReadInt32(); + + chunkReader.BaseStream.Position = resourceBindingOffset; + for (int z = 0; z < resourceBindingCount; z++) + { + int nameOffset = chunkReader.ReadInt32(); + shader.ResourceBindings.Add(new Shader.ResourceBinding() + { + Name = Utilities.ReadString(chunkReader, nameOffset), + ShaderInputType = chunkReader.ReadInt32(), + ResourceReturnType = chunkReader.ReadInt32(), + ResourceViewDimension = chunkReader.ReadInt32(), + SampleCount = chunkReader.ReadInt32(), + BindPoint = chunkReader.ReadInt32(), + BindCount = chunkReader.ReadInt32(), + ShaderInputFlags = chunkReader.ReadInt32() + }); + } + + //in consecutive order in the write: the string table is here, then byte aligned to 4 + + chunkReader.BaseStream.Position = constantBufferOffset; + int[] cbVariableCounts = new int[constantBufferCount]; + int[] cbVariableOffsets = new int[constantBufferCount]; + for (int z = 0; z < constantBufferCount; z++) + { + int nameOffset = chunkReader.ReadInt32(); + cbVariableCounts[z] = chunkReader.ReadInt32(); + cbVariableOffsets[z] = chunkReader.ReadInt32(); + int SizeInBytes = chunkReader.ReadInt32(); + chunkReader.BaseStream.Position += 8; //0,0 + + shader.ConstantBuffers.Add(new Shader.ConstantBuffer() + { + Name = Utilities.ReadString(chunkReader, nameOffset) + }); + } + for (int z = 0; z < constantBufferCount; z++) + { + chunkReader.BaseStream.Position = cbVariableOffsets[z]; + + int[] dataOffsets = new int[cbVariableCounts[z]]; + int[] dataLengths = new int[cbVariableCounts[z]]; + int[] typeOffsets = new int[cbVariableCounts[z]]; + for (int p = 0; p < cbVariableCounts[z]; p++) + { + int nameOffset = chunkReader.ReadInt32(); + dataOffsets[p] = chunkReader.ReadInt32(); + dataLengths[p] = chunkReader.ReadInt32(); + int flags = chunkReader.ReadInt32(); + typeOffsets[p] = chunkReader.ReadInt32(); + + chunkReader.BaseStream.Position += 20; //0,-1,0,-1,0 + + shader.ConstantBuffers[z].Variables.Add(new Shader.ConstantBuffer.Variable() + { + Name = Utilities.ReadString(chunkReader, nameOffset), + Flags = flags + }); + } + for (int p = 0; p < cbVariableCounts[z]; p++) + { + chunkReader.BaseStream.Position = typeOffsets[p]; + + int Class = chunkReader.ReadInt16(); + int Type = chunkReader.ReadInt16(); + int RowCount = chunkReader.ReadInt16(); + int ColumnCount = chunkReader.ReadInt16(); + int ArrayCount = chunkReader.ReadInt16(); + + short[] Unknown_ = Utilities.ConsumeArray(chunkReader, 11); + int nameOffset = chunkReader.ReadInt32(); + + shader.ConstantBuffers[z].Variables[p].TypeName = Utilities.ReadString(chunkReader, nameOffset); + } + } + + chunkReader.BaseStream.Position = creatorStringOffset; + shader.Creator = Utilities.ReadString(chunkReader); + break; + } + + case "PCSG": //Patch constant signature + case "ISGN": //Input signature + case "OSGN": //Output signature + { + int entryCount = chunkReader.ReadInt32(); + chunkReader.BaseStream.Position += 4; //8 + + for (int p = 0; p < entryCount; p++) + { + int nameOffset = chunkReader.ReadInt32(); + int SemanticIndex = chunkReader.ReadInt32(); + int SystemValueType = chunkReader.ReadInt32(); + SignatureComponentType ComponentType = (SignatureComponentType)chunkReader.ReadInt32(); + + int Register = chunkReader.ReadInt32(); + byte Mask = chunkReader.ReadByte(); // NOTE: Bitmask, each element means one vector element. 0 -> x, 1 -> y and so forth. + byte ReadWriteMask = chunkReader.ReadByte(); // NOTE: Same as above, but it is possible that not all elements are used by the shader. + chunkReader.BaseStream.Position += 2; + } + break; + } + */ + case "SHEX": //Shader (SM5) + { + chunkReader.BaseStream.Position += 2; //80 + + ShaderType type = (ShaderType)chunkReader.ReadInt16(); + + return type; + + int count = chunkReader.ReadInt32(); + byte[] contentBytes = chunkReader.ReadBytes((count - 2) * 4); + + if (chunkReader.BaseStream.Length != chunkReader.BaseStream.Position) + throw new Exception(""); + break; + } + + /* + case "STAT": //Statistics. Useful statistics about the shader, such as instruction count, declaration count, etc. + { + shader.Stats = Utilities.Consume(chunkReader); + break; + } + */ + } + } + } + throw new Exception("Invalid DXBC"); } - return true; } - #endregion #region STRUCTURES - public enum DXBCType + public class Shader { - VERTEX = -2, - PIXEL = -1, + public ShaderCategory Category; + public int[] Flags = new int[20]; + + public int Unknown1; + public List Unknown2 = new List(); + public List Unknown3 = new List(); + + //TODO: what are these actually pointing to + public int[][] CSTLinks = new int[5][]; + public int[] TextureLinks; + + public byte[] VertexShader; + public byte[] PixelShader; + public byte[] HullShader; + public byte[] DomainShader; + public byte[] GeometryShader; + public byte[] ComputeShader; + + public class UnknownPair + { + public int unk1; + public int unk2; + } + + public class UnknownTextureThing + { + public byte unk1; + public byte unk2; + public Int16[] unk3; //16 + public float unk4; + public Int16 unk5; + public float unk6; + + public byte unk7; + } } - enum dxbc_chunk_shex_type + enum ShaderType { - SHEXShader_Pixel, - SHEXShader_Vertex, - SHEXShader_Geometry, - SHEXShader_Hull, - SHEXShader_Domain, - SHEXShader_Compute, + PIXEL, + VERTEX, + GEOMETRY, + HULL, + DOMAIN, + COMPUTE, }; - struct dxbc_chunk_stat + /* + public enum DXBCType { - public int InstructionCount; - public int TempRegisterCount; - public int DefineCount; - public int DeclarationCount; - public int FloatInstructionCount; - public int IntInstructionCount; - public int UIntInstructionCount; - public int StaticFlowControlCount; - public int DynamicFlowControlCount; - public int MacroInstructionCount; // Not sure. - public int TempArrayCount; - public int ArrayInstructionCount; - public int CutInstructionCount; - public int EmitInstructionCount; - public int TextureNormalInstructionCount; - public int TextureLoadInstructionCount; - public int TextureComparisonInstructionCount; - public int TextureBiasInstructionCount; - public int TextureGradientInstructionCount; - public int MovInstructionCount; - public int MovCInstructionCount; - public int Unknown0_; - public int InputPrimitiveForGeometryShaders; - public int PrimitiveTopologyForGeometryShaders; - public int MaxOutputVertexCountForGeometryShaders; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - public int[] unk0; //zeros - - public int IsSampleFrequencyShader; // 1 for sample frequency shadeer, otherwise 0. - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)] - public int[] unk1; - }; + VERTEX = -2, + PIXEL = -1, + } - public class Shader + enum SignatureComponentType { - + UNSIGNED_INTEGER = 1, + SIGNED_INTEGER = 2, + FLOATING_POINT = 3, } - public class VertexShader : Shader + public class Shader { + public STAT Stats; - } - public class PixelShader : Shader - { + public string Creator; - } - public class HullShader : Shader - { + public int Type = 0; //DXBCType + public int Flags = 0; - } - public class DomainShader : Shader - { + public int InterfaceSlotCount = 0; + public List ResourceBindings = new List(); + public List ConstantBuffers = new List(); + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public class STAT + { + public int InstructionCount; + public int TempRegisterCount; + public int DefineCount; + public int DeclarationCount; + public int FloatInstructionCount; + public int IntInstructionCount; + public int UIntInstructionCount; + public int StaticFlowControlCount; + public int DynamicFlowControlCount; + public int MacroInstructionCount; // Not sure. + public int TempArrayCount; + public int ArrayInstructionCount; + public int CutInstructionCount; + public int EmitInstructionCount; + public int TextureNormalInstructionCount; + public int TextureLoadInstructionCount; + public int TextureComparisonInstructionCount; + public int TextureBiasInstructionCount; + public int TextureGradientInstructionCount; + public int MovInstructionCount; + public int MovCInstructionCount; + public int Unknown0_; + public int InputPrimitiveForGeometryShaders; + public int PrimitiveTopologyForGeometryShaders; + public int MaxOutputVertexCountForGeometryShaders; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public int[] unk0; //zeros + + public int IsSampleFrequencyShader; // 1 for sample frequency shadeer, otherwise 0. + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)] + public int[] unk1; + } + + public class ResourceBinding + { + public string Name; + + public int ShaderInputType; + public int ResourceReturnType; + public int ResourceViewDimension; + public int SampleCount; + public int BindPoint; + public int BindCount; + public int ShaderInputFlags; + } + + public class ConstantBuffer + { + public string Name; + + public List Variables = new List(); + + public class Variable + { + public string Name; + public string TypeName; + + public int Flags; + } + } } + */ #endregion } } \ No newline at end of file diff --git a/CathodeLib/Scripts/Utilities.cs b/CathodeLib/Scripts/Utilities.cs index 2c8e622..239811e 100644 --- a/CathodeLib/Scripts/Utilities.cs +++ b/CathodeLib/Scripts/Utilities.cs @@ -310,7 +310,7 @@ public static void WritePAK(string path, FileIdentifiers type, List public class PAKContent { - public int BinIndex; + public int BinIndex = 0; public byte[] Data; } } From cef33a0dc4b4e9cf810a23093bef5a0c43bbe569 Mon Sep 17 00:00:00 2001 From: MattFiler Date: Sun, 15 Oct 2023 19:22:34 +0100 Subject: [PATCH 25/30] usings --- CathodeLib/Scripts/CATHODE/Shaders.cs | 48 ++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/CathodeLib/Scripts/CATHODE/Shaders.cs b/CathodeLib/Scripts/CATHODE/Shaders.cs index 02433b1..1c310d9 100644 --- a/CathodeLib/Scripts/CATHODE/Shaders.cs +++ b/CathodeLib/Scripts/CATHODE/Shaders.cs @@ -7,10 +7,6 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Windows.Media.Animation; -using static CATHODE.EXPERIMENTAL.MissionSave; -using static CATHODE.LEGACY.ShadersPAK; -using static CATHODE.Shaders; -using static CATHODE.Shaders.Shader; namespace CATHODE { @@ -149,7 +145,7 @@ override protected bool LoadInternal() for (int x = 0; x < textureCount; x++) { - UnknownTextureThing unk = new UnknownTextureThing(); + Shader.UnknownTextureThing unk = new Shader.UnknownTextureThing(); unk.unk1 = reader.ReadByte(); unk.unk2 = reader.ReadByte(); unk.unk3 = new short[16]; @@ -567,6 +563,48 @@ enum ShaderType COMPUTE, }; + public enum ShaderCategory + { + NONE = 0, + + CA_PARTICLE = 12, + CA_RIBBON = 13, + CA_ENVIRONMENT = 17, + CA_SHADOWCASTER = 18, + CA_DECAL_ENVIRONMENT = 19, + CA_CHARACTER = 20, + CA_SKIN = 21, + CA_HAIR = 22, + CA_EYE = 23, + CA_SKIN_OCCLUSION = 24, + CA_DEFERRED = 27, + CA_DECAL = 30, + CA_FOGPLANE = 31, + CA_FOGSPHERE = 32, + CA_DEBUG = 33, + CA_POST_PROCESSING = 35, + CA_FILTERS = 37, + CA_LENS_FLARE = 38, + CA_LIQUID_ENVIRONMENT = 39, + CA_OCCLUSION_CULLING = 42, + CA_REFRACTION = 43, + CA_SIMPLE_REFRACTION = 44, + CA_DISTORTION_OVERLAY = 45, + CA_SURFACE_EFFECTS = 50, + CA_EFFECT_OVERLAY = 51, + CA_TERRAIN = 52, + CA_NONINTERACTIVE_WATER = 53, + CA_SIMPLEWATER = 54, + CA_PLANET = 55, + CA_LIGHTMAP_ENVIRONMENT = 58, + CA_LOW_LOD_CHARACTER = 60, + CA_LIGHT_DECAL = 61, + CA_VOLUME_LIGHT = 62, + CA_WATER_CAUSTICS_OVERLAY = 63, + CA_SPACESUIT_VISOR = 64, + CA_CAMERA_MAP = 65, + }; + /* public enum DXBCType { From d5cac5ef8f4c11029bd40f5942b193b86d9f8bd0 Mon Sep 17 00:00:00 2001 From: MattFiler Date: Sun, 15 Oct 2023 19:50:08 +0100 Subject: [PATCH 26/30] save shaders --- CathodeLib/Scripts/CATHODE/Materials.cs | 6 +++--- CathodeLib/Scripts/LEGACY_DAN/ShadersPAK.cs | 7 +++---- CathodeLib/Scripts/Level.cs | 1 + 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CathodeLib/Scripts/CATHODE/Materials.cs b/CathodeLib/Scripts/CATHODE/Materials.cs index bc47b3d..a247195 100644 --- a/CathodeLib/Scripts/CATHODE/Materials.cs +++ b/CathodeLib/Scripts/CATHODE/Materials.cs @@ -76,7 +76,7 @@ override protected bool LoadInternal() } reader.BaseStream.Position += 7; material.UnknownValue0 = reader.ReadInt32(); - material.UberShaderIndex = reader.ReadInt32(); + material.ShaderIndex = reader.ReadInt32(); reader.BaseStream.Position += 128; material.UnknownValue1 = reader.ReadInt32(); reader.BaseStream.Position += 48; @@ -158,7 +158,7 @@ override protected bool SaveInternal() } writer.Write(new byte[7]); writer.Write(Entries[i].UnknownValue0); - writer.Write(Entries[i].UberShaderIndex); + writer.Write(Entries[i].ShaderIndex); writer.Write(new byte[128]); writer.Write(Entries[i].UnknownValue1); writer.Write(new byte[48]); @@ -207,7 +207,7 @@ public class Material public ConstantBuffer[] ConstantBuffers = new ConstantBuffer[5]; //Should always be 5 (1 per CST block) - TODO: maybe just change this to 5 variables? public int UnknownValue0; - public int UberShaderIndex; + public int ShaderIndex; public int UnknownValue1; diff --git a/CathodeLib/Scripts/LEGACY_DAN/ShadersPAK.cs b/CathodeLib/Scripts/LEGACY_DAN/ShadersPAK.cs index 0a74132..c194517 100644 --- a/CathodeLib/Scripts/LEGACY_DAN/ShadersPAK.cs +++ b/CathodeLib/Scripts/LEGACY_DAN/ShadersPAK.cs @@ -55,7 +55,7 @@ public ShadersPAK(string FullFilePath) private MaterialPropertyIndex GetMaterialPropertyIndexes(Materials.Material InMaterial) { - ShaderEntry Shader = Shaders[InMaterial.UberShaderIndex]; + ShaderEntry Shader = Shaders[InMaterial.ShaderIndex]; MaterialPropertyIndex toReturn = new MaterialPropertyIndex(); @@ -176,10 +176,9 @@ private MaterialPropertyIndex GetMaterialPropertyIndexes(Materials.Material InMa return toReturn; } - public ShaderMaterialMetadata GetMaterialMetadataFromShader(Materials.Material InMaterial, IDXRemap idx) + public ShaderMaterialMetadata GetMaterialMetadataFromShader(Materials.Material InMaterial) { - int RemappedIndex = idx.Datas[InMaterial.UberShaderIndex].Index; - ShaderEntry Shader = Shaders[RemappedIndex]; + ShaderEntry Shader = Shaders[InMaterial.ShaderIndex]; ShaderMaterialMetadata metadata = new ShaderMaterialMetadata(); metadata.shaderCategory = (ShaderCategory)Shader.Header2.ShaderCategory; switch (metadata.shaderCategory) diff --git a/CathodeLib/Scripts/Level.cs b/CathodeLib/Scripts/Level.cs index e4eafde..6af3141 100644 --- a/CathodeLib/Scripts/Level.cs +++ b/CathodeLib/Scripts/Level.cs @@ -159,6 +159,7 @@ public void Save() //TODO: This puts the assumption on the user that they have updated all the indexes correctly in Commands. Need to just pass direct objects. Commands.Save(); EnvironmentAnimations.Save(); + Shaders.Save(); /* UPDATE MOVER INDEXES */ From c0f70d06010c562556b8b6f626aac140d22a7ac8 Mon Sep 17 00:00:00 2001 From: MattFiler Date: Fri, 2 Feb 2024 18:54:39 +0000 Subject: [PATCH 27/30] disable console log --- CathodeLib/Scripts/CATHODE/Shaders.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CathodeLib/Scripts/CATHODE/Shaders.cs b/CathodeLib/Scripts/CATHODE/Shaders.cs index 1c310d9..5137044 100644 --- a/CathodeLib/Scripts/CATHODE/Shaders.cs +++ b/CathodeLib/Scripts/CATHODE/Shaders.cs @@ -353,7 +353,7 @@ private ShaderType GetTypeFromDXBC(byte[] dxbc) reader.BaseStream.Position = chunkOffsets[x]; fourcc chunkFourcc = Utilities.Consume(reader); - Console.WriteLine(chunkFourcc.ToString()); + //Console.WriteLine(chunkFourcc.ToString()); int chunkSize = reader.ReadInt32(); byte[] chunkContent = reader.ReadBytes(chunkSize); using (BinaryReader chunkReader = new BinaryReader(new MemoryStream(chunkContent))) From 901fae497fe4de970535273e936f525435211a78 Mon Sep 17 00:00:00 2001 From: MattFiler Date: Tue, 6 Feb 2024 09:28:09 +0000 Subject: [PATCH 28/30] changing shortguid to handle as uint32 --- CathodeLib/Scripts/CATHODE/Commands.cs | 49 ++++++----- .../CATHODE/CommandsPAK/Components/Entity.cs | 13 +-- .../CommandsPAK/Components/ShortGuid.cs | 83 ++++++++++--------- .../CommandsPAK/Helpers/CommandsUtils.cs | 2 +- .../CommandsPAK/Helpers/ShortGuidUtils.cs | 7 +- 5 files changed, 83 insertions(+), 71 deletions(-) diff --git a/CathodeLib/Scripts/CATHODE/Commands.cs b/CathodeLib/Scripts/CATHODE/Commands.cs index 0aa5cdd..45762f7 100644 --- a/CathodeLib/Scripts/CATHODE/Commands.cs +++ b/CathodeLib/Scripts/CATHODE/Commands.cs @@ -503,7 +503,7 @@ override protected bool SaveInternal() //Validate entry points and composite count if (Entries.Count == 0) return false; if (_entryPoints == null) _entryPoints = new ShortGuid[3]; - if (_entryPoints[0].val == null && _entryPoints[1].val == null && _entryPoints[2].val == null && Entries.Count == 0) return false; + if (_entryPoints[0].IsInvalid || _entryPoints[1].IsInvalid || _entryPoints[2].IsInvalid || Entries.Count == 0) return false; #region FIX_POTENTIAL_ERRORS //If we have composites but the entry points are broken, correct them first! @@ -676,7 +676,7 @@ override protected bool SaveInternal() //Write entry points for (int i = 0; i < 3; i++) { - if (_entryPoints[i].val == null || GetComposite(_entryPoints[i]) == null) + if (_entryPoints[i].IsInvalid || GetComposite(_entryPoints[i]) == null) writer.Write(new byte[] { 0x00, 0x00, 0x00, 0x00 }); else Utilities.Write(writer, _entryPoints[i]); @@ -717,7 +717,7 @@ override protected bool SaveInternal() stringStartRaw[3] = 0x80; writer.Write(stringStartRaw); string str = ((cString)parameters[i]).value.Replace("\u0092", "'"); - writer.Write(ShortGuidUtils.Generate(str).val); + writer.Write(ShortGuidUtils.Generate(str).ToUInt32()); for (int x = 0; x < str.Length; x++) writer.Write(str[x]); writer.Write((char)0x00); Utilities.Align(writer, 4); @@ -807,7 +807,7 @@ override protected bool SaveInternal() scriptPointerOffsetInfo[x] = new OffsetPair(writer.BaseStream.Position, linkedEntities[i].Count); for (int p = 0; p < linkedEntities[i].Count; p++) { - writer.Write(linkedEntities[i][p].shortGUID.val); + writer.Write(linkedEntities[i][p].shortGUID.ToUInt32()); writer.Write(offsetPairs[p].GlobalOffset / 4); writer.Write(offsetPairs[p].EntryCount); } @@ -831,7 +831,7 @@ override protected bool SaveInternal() scriptPointerOffsetInfo[x] = new OffsetPair(writer.BaseStream.Position, offsetPairs.Count); for (int p = 0; p < parameterisedEntities[i].Count; p++) { - writer.Write(parameterisedEntities[i][p].shortGUID.val); + writer.Write(parameterisedEntities[i][p].shortGUID.ToUInt32()); writer.Write(offsetPairs[p].GlobalOffset / 4); writer.Write(offsetPairs[p].EntryCount); } @@ -849,7 +849,7 @@ override protected bool SaveInternal() scriptPointerOffsetInfo[x] = new OffsetPair(writer.BaseStream.Position, reshuffledAliases[i].Count); for (int p = 0; p < reshuffledAliases[i].Count; p++) { - writer.Write(reshuffledAliases[i][p].shortGUID.val); + writer.Write(reshuffledAliases[i][p].shortGUID.ToUInt32()); writer.Write(offsetPairs[p].GlobalOffset / 4); writer.Write(offsetPairs[p].EntryCount); } @@ -860,8 +860,8 @@ override protected bool SaveInternal() scriptPointerOffsetInfo[x] = new OffsetPair(writer.BaseStream.Position, reshuffledAliasPathHashes[i].Count); for (int p = 0; p < reshuffledAliasPathHashes[i].Count; p++) { - writer.Write(reshuffledAliasPathHashes[i][p].shortGUID.val); - writer.Write(reshuffledAliasPathHashes[i][p].alias.GeneratePathHash().val); + writer.Write(reshuffledAliasPathHashes[i][p].shortGUID.ToUInt32()); + writer.Write(reshuffledAliasPathHashes[i][p].alias.GeneratePathHash().ToUInt32()); } break; } @@ -870,9 +870,9 @@ override protected bool SaveInternal() scriptPointerOffsetInfo[x] = new OffsetPair(writer.BaseStream.Position, Entries[i].variables.Count); for (int p = 0; p < Entries[i].variables.Count; p++) { - writer.Write(Entries[i].variables[p].shortGUID.val); - writer.Write(CommandsUtils.GetDataTypeGUID(Entries[i].variables[p].type).val); - writer.Write(Entries[i].variables[p].name.val); + writer.Write(Entries[i].variables[p].shortGUID.ToUInt32()); + writer.Write(CommandsUtils.GetDataTypeGUID(Entries[i].variables[p].type).ToUInt32()); + writer.Write(Entries[i].variables[p].name.ToUInt32()); } break; } @@ -888,11 +888,11 @@ override protected bool SaveInternal() scriptPointerOffsetInfo[x] = new OffsetPair(writer.BaseStream.Position, offsetPairs.Count); for (int p = 0; p < Entries[i].proxies.Count; p++) { - writer.Write(Entries[i].proxies[p].shortGUID.val); + writer.Write(Entries[i].proxies[p].shortGUID.ToUInt32()); writer.Write(offsetPairs[p].GlobalOffset / 4); writer.Write(offsetPairs[p].EntryCount); - writer.Write(Entries[i].proxies[p].shortGUID.val); - writer.Write(Entries[i].proxies[p].function.val); + writer.Write(Entries[i].proxies[p].shortGUID.ToUInt32()); + writer.Write(Entries[i].proxies[p].function.ToUInt32()); } break; } @@ -901,8 +901,8 @@ override protected bool SaveInternal() scriptPointerOffsetInfo[x] = new OffsetPair(writer.BaseStream.Position, Entries[i].functions.Count); for (int p = 0; p < Entries[i].functions.Count; p++) { - writer.Write(Entries[i].functions[p].shortGUID.val); - writer.Write(Entries[i].functions[p].function.val); + writer.Write(Entries[i].functions[p].shortGUID.ToUInt32()); + writer.Write(Entries[i].functions[p].function.ToUInt32()); } break; } @@ -926,8 +926,8 @@ override protected bool SaveInternal() writer.Write(resourceReferences[i][p].rotation.Y); writer.Write(resourceReferences[i][p].rotation.Z); #endif - writer.Write(resourceReferences[i][p].resourceID.val); //Sometimes this is the entity ID that uses the resource, other times it's the "resource" parameter ID link - writer.Write(CommandsUtils.GetResourceEntryTypeGUID(resourceReferences[i][p].entryType).val); + writer.Write(resourceReferences[i][p].resourceID.ToUInt32()); //Sometimes this is the entity ID that uses the resource, other times it's the "resource" parameter ID link + writer.Write(CommandsUtils.GetResourceEntryTypeGUID(resourceReferences[i][p].entryType).ToUInt32()); switch (resourceReferences[i][p].entryType) { case ResourceType.RENDERABLE_INSTANCE: @@ -936,7 +936,7 @@ override protected bool SaveInternal() break; case ResourceType.COLLISION_MAPPING: writer.Write(resourceReferences[i][p].index); - writer.Write(resourceReferences[i][p].collisionID.val); + writer.Write(resourceReferences[i][p].collisionID.ToUInt32()); break; case ResourceType.ANIMATED_MODEL: case ResourceType.DYNAMIC_PHYSICS_SYSTEM: @@ -1055,7 +1055,7 @@ override protected bool SaveInternal() Utilities.Write(writer, internalOffsets); globalOffsets.Add((int)writer.BaseStream.Position); - writer.Write(cageAnimationEntities[i][p].shortGUID.val); + writer.Write(cageAnimationEntities[i][p].shortGUID.ToUInt32()); writer.Write(headerOffset / 4); writer.Write(cageAnimationEntities[i][p].connections.Count); writer.Write(animationOffset / 4); @@ -1094,13 +1094,13 @@ override protected bool SaveInternal() int eventOffset = (int)writer.BaseStream.Position; for (int pp = 0; pp < triggerSequenceEntities[i][p].events.Count; pp++) { - writer.Write(triggerSequenceEntities[i][p].events[pp].start.val); - writer.Write(triggerSequenceEntities[i][p].events[pp].shortGUID.val); - writer.Write(triggerSequenceEntities[i][p].events[pp].end.val); + writer.Write(triggerSequenceEntities[i][p].events[pp].start.ToUInt32()); + writer.Write(triggerSequenceEntities[i][p].events[pp].shortGUID.ToUInt32()); + writer.Write(triggerSequenceEntities[i][p].events[pp].end.ToUInt32()); } globalOffsets.Add((int)writer.BaseStream.Position); - writer.Write(triggerSequenceEntities[i][p].shortGUID.val); + writer.Write(triggerSequenceEntities[i][p].shortGUID.ToUInt32()); writer.Write(triggerOffset / 4); writer.Write(triggerSequenceEntities[i][p].entities.Count); writer.Write(eventOffset / 4); @@ -1189,7 +1189,6 @@ public Composite GetComposite(string name) } public Composite GetComposite(ShortGuid id) { - if (id.val == null) return null; return Entries.FirstOrDefault(o => o != null && o.shortGUID == id); } diff --git a/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Entity.cs b/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Entity.cs index 3a477e5..5045415 100644 --- a/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Entity.cs +++ b/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Entity.cs @@ -45,11 +45,14 @@ public Entity(ShortGuid shortGUID, EntityVariant variant) /* Implements IComparable for searching */ public int CompareTo(Entity other) { - int TotalThis = shortGUID.val[0] + shortGUID.val[1] + shortGUID.val[2] + shortGUID.val[3]; - int TotalOther = other.shortGUID.val[0] + other.shortGUID.val[1] + other.shortGUID.val[2] + other.shortGUID.val[3]; - if (TotalThis > TotalOther) return 1; - else if (TotalThis == TotalOther) return 0; - return -1; + if (other == null) return 1; + + if (this.shortGUID.ToUInt32() > other.shortGUID.ToUInt32()) + return 1; + else if (this.shortGUID.ToUInt32() < other.shortGUID.ToUInt32()) + return -1; + + return 0; } /* Get parameter by string name or ShortGuid */ diff --git a/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/ShortGuid.cs b/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/ShortGuid.cs index 400a1cc..5522269 100644 --- a/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/ShortGuid.cs +++ b/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/ShortGuid.cs @@ -19,60 +19,66 @@ public struct ShortGuid : IComparable public static readonly ShortGuid Invalid = new ShortGuid(0); public static readonly ShortGuid InitialiserBase = new ShortGuid("FE-5B-F0-4A"); - public ShortGuid(float num) + public bool IsInvalid => val == Invalid.val; + + private UInt32 val; + + public ShortGuid(BinaryReader reader) { - val = BitConverter.GetBytes(num); + val = reader.ReadUInt32(); } - public ShortGuid(int num) + public ShortGuid(float num) { - val = BitConverter.GetBytes(num); + val = Convert.ToUInt32(num); } - public ShortGuid(byte[] id) + public ShortGuid(uint num) { - val = id; + val = num; } - public ShortGuid(BinaryReader reader) + + [Obsolete("For performance reasons, it is recommended to initialse ShortGuid as an unsigned integer.")] + public ShortGuid(byte[] id) { - val = reader.ReadBytes(4); + val = BitConverter.ToUInt32(id, 0); } + + [Obsolete("For performance reasons, it is recommended to initialse ShortGuid as an unsigned integer.")] public ShortGuid(string id) { System.String[] arr = id.Split('-'); if (arr.Length != 4) throw new Exception("Tried to initialise ShortGuid without 4-byte ID string."); byte[] array = new byte[arr.Length]; for (int i = 0; i < arr.Length; i++) array[i] = Convert.ToByte(arr[i], 16); - val = array; + val = BitConverter.ToUInt32(array, 0); } - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public byte[] val; - public override bool Equals(object obj) { if (!(obj is ShortGuid)) return false; - if (((ShortGuid)obj).val == null) return this.val == null; - if (this.val == null) return ((ShortGuid)obj).val == null; - return ((ShortGuid)obj).val.SequenceEqual(this.val); + return ((ShortGuid)obj).val == this.val; } public static bool operator ==(ShortGuid x, ShortGuid y) { if (ReferenceEquals(x, null)) return ReferenceEquals(y, null); - if (x.val == null) return y.val == null; - if (y.val == null) return x.val == null; - return x.val.SequenceEqual(y.val); + return x.val == y.val; } public static bool operator !=(ShortGuid x, ShortGuid y) { - return !x.val.SequenceEqual(y.val); + return !(x.val == y.val); } + + [Obsolete("For performance reasons, it is recommended to compare as ShortGuid or integer.")] public static bool operator ==(ShortGuid x, string y) { return x.ToByteString() == y; } + + [Obsolete("For performance reasons, it is recommended to compare as ShortGuid or integer.")] public static bool operator !=(ShortGuid x, string y) { return x.ToByteString() != y; } + public static bool operator ==(ShortGuid x, uint y) { return x.ToUInt32() == y; @@ -81,40 +87,43 @@ public override bool Equals(object obj) { return x.ToUInt32() != y; } + public override int GetHashCode() { - if (val == null) return 0; - return BitConverter.ToInt32(val, 0); + return 1835847388 + val.GetHashCode(); } public int CompareTo(ShortGuid x) { - if (x == null) return 0; - if (x.val == null && val != null) return 0; - if (x.val != null && val == null) return 0; - if (x.val.Length != val.Length) return 0; + if (x == null) return 1; - int comp = 0; - for (int i = 0; i < x.val.Length; i++) - { - comp += x.val[i].CompareTo(val[i]); - } - comp /= x.val.Length; + if (this.val > x.val) + return 1; + else if (this.val < x.val) + return -1; - return comp; + return 0; } public override string ToString() { return ShortGuidUtils.FindString(this); } + public uint ToUInt32() + { + return val; + } + + [Obsolete("For performance reasons, it is recommended to use ToUInt32.")] public string ToByteString() { - return BitConverter.ToString(val); + return BitConverter.ToString(BitConverter.GetBytes(val)); } - public uint ToUInt32() + + [Obsolete("For performance reasons, it is recommended to use ToUInt32.")] + public byte[] ToBytes() { - return BitConverter.ToUInt32(val, 0); + return BitConverter.GetBytes(val); } } @@ -129,9 +138,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { - ShortGuid user = new ShortGuid(); - user.val = (byte[])reader.Value; - return user; + return new ShortGuid((byte[])reader.Value); } public override bool CanConvert(Type objectType) diff --git a/CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/CommandsUtils.cs b/CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/CommandsUtils.cs index 8a17e60..369b198 100644 --- a/CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/CommandsUtils.cs +++ b/CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/CommandsUtils.cs @@ -171,7 +171,7 @@ public static Entity ResolveHierarchy(Commands commands, Composite composite, Li List hierarchyCopy = new List(); for (int x = 0; x < hierarchy.Count; x++) - hierarchyCopy.Add(new ShortGuid((byte[])hierarchy[x].val.Clone())); + hierarchyCopy.Add(new ShortGuid(hierarchy[x].ToUInt32())); Composite currentFlowgraphToSearch = composite; if (currentFlowgraphToSearch == null || currentFlowgraphToSearch.GetEntityByID(hierarchyCopy[0]) == null) diff --git a/CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/ShortGuidUtils.cs b/CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/ShortGuidUtils.cs index f5e233e..3c864dd 100644 --- a/CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/ShortGuidUtils.cs +++ b/CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/ShortGuidUtils.cs @@ -77,9 +77,12 @@ public static ShortGuid Combine(this ShortGuid guid1, ShortGuid guid2) { if (guid1.ToUInt32() != 0) { - ulong hash = BitConverter.ToUInt64(new byte[8] { guid1.val[0], guid1.val[1], guid1.val[2], guid1.val[3], guid2.val[0], guid2.val[1], guid2.val[2], guid2.val[3] }, 0); + byte[] guid1_b = guid1.ToBytes(); + byte[] guid2_b = guid2.ToBytes(); + + ulong hash = BitConverter.ToUInt64(new byte[8] { guid1_b[0], guid1_b[1], guid1_b[2], guid1_b[3], guid2_b[0], guid2_b[1], guid2_b[2], guid2_b[3] }, 0); hash = ~hash + hash * 262144; hash = (hash ^ (hash >> 31)) * 21; hash = (hash ^ (hash >> 11)) * 65; - return new ShortGuid(BitConverter.GetBytes((uint)(hash >> 22) ^ (uint)hash)); + return new ShortGuid(((uint)(hash >> 22) ^ (uint)hash)); } return guid2; } From 9126fa16d7c5bbe395997e9e784af7113c0b6010 Mon Sep 17 00:00:00 2001 From: MattFiler Date: Tue, 6 Feb 2024 19:35:41 +0000 Subject: [PATCH 29/30] being super paranoid about memory --- CathodeLib/Scripts/CATHODE/Commands.cs | 5 ++++ .../CommandsPAK/Components/Composite.cs | 8 ++++++ .../CATHODE/CommandsPAK/Components/Entity.cs | 12 +++++++++ .../CommandsPAK/Components/Parameter.cs | 5 ++++ .../CommandsPAK/Helpers/EntityUtils.cs | 10 +++---- .../CommandsPAK/Helpers/ShortGuidUtils.cs | 1 + CathodeLib/Scripts/CATHODE/Models.cs | 27 +++++++++++++++++++ CathodeLib/Scripts/CATHODE/Shaders.cs | 18 +++++++++++++ CathodeLib/Scripts/CATHODE/Textures.cs | 17 ++++++++++++ 9 files changed, 98 insertions(+), 5 deletions(-) diff --git a/CathodeLib/Scripts/CATHODE/Commands.cs b/CathodeLib/Scripts/CATHODE/Commands.cs index 45762f7..b91e9fc 100644 --- a/CathodeLib/Scripts/CATHODE/Commands.cs +++ b/CathodeLib/Scripts/CATHODE/Commands.cs @@ -25,6 +25,11 @@ public class Commands : CathodeFile public static new Implementation Implementation = Implementation.CREATE | Implementation.LOAD | Implementation.SAVE; public Commands(string path) : base(path) { } + ~Commands() + { + Entries.Clear(); + } + // This is always: // - Root Instance (the map's entry composite, usually containing entities that call mission/environment composites) // - Global Instance (the main data handler for keeping track of mission number, etc - kinda like a big singleton) diff --git a/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Composite.cs b/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Composite.cs index 7552571..02760c3 100644 --- a/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Composite.cs +++ b/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Composite.cs @@ -19,6 +19,14 @@ public Composite(string name) this.name = name; } + ~Composite() + { + variables.Clear(); + functions.Clear(); + aliases.Clear(); + proxies.Clear(); + } + public ShortGuid shortGUID; //The id when this composite is used as an entity in another composite public string name = ""; //The string name of the composite diff --git a/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Entity.cs b/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Entity.cs index 5045415..de2579b 100644 --- a/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Entity.cs +++ b/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Entity.cs @@ -14,6 +14,7 @@ using System.Numerics; using System.IO; using CathodeLib; +using CathodeLib.Properties; #endif namespace CATHODE.Scripting.Internal @@ -42,6 +43,12 @@ public Entity(ShortGuid shortGUID, EntityVariant variant) public List childLinks = new List(); public List parameters = new List(); + ~Entity() + { + childLinks.Clear(); + parameters.Clear(); + } + /* Implements IComparable for searching */ public int CompareTo(Entity other) { @@ -224,6 +231,11 @@ public class FunctionEntity : Entity public FunctionEntity() : base(EntityVariant.FUNCTION) { } public FunctionEntity(ShortGuid shortGUID) : base(shortGUID, EntityVariant.FUNCTION) { } + ~FunctionEntity() + { + resources.Clear(); + } + public FunctionEntity(string function, bool autoGenerateParameters = false) : base(EntityVariant.FUNCTION) { this.function = ShortGuidUtils.Generate(function); diff --git a/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Parameter.cs b/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Parameter.cs index 2d42ef9..e53e99f 100644 --- a/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Parameter.cs +++ b/CathodeLib/Scripts/CATHODE/CommandsPAK/Components/Parameter.cs @@ -25,5 +25,10 @@ public Parameter(ShortGuid id, ParameterData data, ParameterVariant var = Parame public ShortGuid name; public ParameterData content = null; public ParameterVariant variant = ParameterVariant.PARAMETER; + + ~Parameter() + { + content = null; + } } } diff --git a/CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/EntityUtils.cs b/CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/EntityUtils.cs index 3d976a3..af4121b 100644 --- a/CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/EntityUtils.cs +++ b/CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/EntityUtils.cs @@ -20,6 +20,7 @@ public static class EntityUtils private static EntityNameTable _vanilla; private static EntityNameTable _custom; + public static Commands LinkedCommands => _commands; private static Commands _commands; /* Load all standard entity/composite names from our offline DB */ @@ -45,11 +46,10 @@ public static void LinkCommands(Commands commands) } _commands = commands; - if (_commands != null) - { - _commands.OnLoadSuccess += LoadCustomNames; - _commands.OnSaveSuccess += SaveCustomNames; - } + if (_commands == null) return; + + _commands.OnLoadSuccess += LoadCustomNames; + _commands.OnSaveSuccess += SaveCustomNames; LoadCustomNames(_commands.Filepath); } diff --git a/CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/ShortGuidUtils.cs b/CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/ShortGuidUtils.cs index 3c864dd..0155b1a 100644 --- a/CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/ShortGuidUtils.cs +++ b/CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/ShortGuidUtils.cs @@ -16,6 +16,7 @@ public static class ShortGuidUtils private static GuidNameTable _vanilla = null; private static GuidNameTable _custom = null; + public static Commands LinkedCommands => _commands; private static Commands _commands; /* Pull in strings we know are cached as ShortGuid in Cathode */ diff --git a/CathodeLib/Scripts/CATHODE/Models.cs b/CathodeLib/Scripts/CATHODE/Models.cs index a118946..7ef77db 100644 --- a/CathodeLib/Scripts/CATHODE/Models.cs +++ b/CathodeLib/Scripts/CATHODE/Models.cs @@ -21,6 +21,12 @@ public Models(string path) : base(path) { } private List _writeList = new List(); private string _filepathBIN; + ~Models() + { + Entries.Clear(); + _writeList.Clear(); + } + #region FILE_IO /* Load the file */ override protected bool LoadInternal() @@ -623,6 +629,11 @@ public class CS2 public string Name; public List Components = new List(); + ~CS2() + { + Components.Clear(); + } + public class Component { public List LODs = new List(); @@ -632,6 +643,11 @@ public class Component public int UnkLv426Pt1 = 0; public int UnkLv426Pt2 = 0; + ~Component() + { + LODs.Clear(); + } + public class LOD { public LOD(string name) @@ -642,6 +658,11 @@ public LOD(string name) public string Name; public List Submeshes = new List(); + ~LOD() + { + Submeshes.Clear(); + } + public class Submesh { public Vector3 AABBMin = new Vector3(-1,-1,-1); // <---- When importing a new model, setting these all to zero seem to make it invisible?? @@ -675,6 +696,12 @@ public class Submesh public List boneIndices = new List(); public byte[] content = new byte[0]; + + ~Submesh() + { + boneIndices.Clear(); + content = null; + } } public override string ToString() diff --git a/CathodeLib/Scripts/CATHODE/Shaders.cs b/CathodeLib/Scripts/CATHODE/Shaders.cs index 5137044..0e44ea2 100644 --- a/CathodeLib/Scripts/CATHODE/Shaders.cs +++ b/CathodeLib/Scripts/CATHODE/Shaders.cs @@ -21,6 +21,11 @@ public Shaders(string path) : base(path) { } private string _filepathBIN; private string _filepathIDX; + ~Shaders() + { + Entries.Clear(); + } + #region FILE_IO override protected bool LoadInternal() { @@ -534,6 +539,19 @@ public class Shader public byte[] GeometryShader; public byte[] ComputeShader; + ~Shader() + { + Unknown2.Clear(); + Unknown3.Clear(); + + VertexShader = null; + PixelShader = null; + HullShader = null; + DomainShader = null; + GeometryShader = null; + ComputeShader = null; + } + public class UnknownPair { public int unk1; diff --git a/CathodeLib/Scripts/CATHODE/Textures.cs b/CathodeLib/Scripts/CATHODE/Textures.cs index 0ba24cb..3d05bda 100644 --- a/CathodeLib/Scripts/CATHODE/Textures.cs +++ b/CathodeLib/Scripts/CATHODE/Textures.cs @@ -17,6 +17,12 @@ public Textures(string path) : base(path) { } public List _writeList = new List(); private string _filepathBIN; + ~Textures() + { + Entries.Clear(); + _writeList.Clear(); + } + #region FILE_IO override protected bool LoadInternal() { @@ -267,6 +273,12 @@ public class TEX4 public Part tex_LowRes = new Part(); public Part tex_HighRes = new Part(); + ~TEX4() + { + tex_LowRes = null; + tex_HighRes = null; + } + public class Part { public Int16 Width = 0; @@ -282,6 +294,11 @@ public class Part public UInt16 unk2 = 0; public UInt32 unk3 = 0; public UInt32 unk4 = 0; + + ~Part() + { + Content = null; + } } } From b3e1c9ce4a063df1caef4947fcdfa8e03b0a7d5d Mon Sep 17 00:00:00 2001 From: MattFiler Date: Tue, 6 Feb 2024 20:09:08 +0000 Subject: [PATCH 30/30] missing check for null --- .../Scripts/CATHODE/CommandsPAK/Helpers/ShortGuidUtils.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/ShortGuidUtils.cs b/CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/ShortGuidUtils.cs index 0155b1a..1212c8a 100644 --- a/CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/ShortGuidUtils.cs +++ b/CathodeLib/Scripts/CATHODE/CommandsPAK/Helpers/ShortGuidUtils.cs @@ -41,8 +41,9 @@ public static void LinkCommands(Commands commands) _commands.OnSaveSuccess -= SaveCustomNames; _commands = commands; - if (_commands != null) - _commands.OnSaveSuccess += SaveCustomNames; + if (_commands == null) return; + + _commands.OnSaveSuccess += SaveCustomNames; LoadCustomNames(commands.Filepath); }