From 5ce6b4658a636fc244534ffff23f5b0126a40336 Mon Sep 17 00:00:00 2001 From: "Nathan V." Date: Sun, 18 Oct 2026 14:20:03 -0400 Subject: [PATCH] modern C# formatting --- .editorconfig | 45 + BaseHandlers/AptData.cs | 1329 +++++------ BaseHandlers/BasePlugin.cs | 35 +- BaseHandlers/FlaptFile.cs | 733 +++--- BaseHandlers/GraphicsSpec.cs | 141 +- BaseHandlers/IDList.cs | 167 +- BaseHandlers/InstanceList.cs | 335 ++- BaseHandlers/InstanceListEditor.cs | 375 ++- BaseHandlers/MaterialEntry.cs | 101 +- BaseHandlers/ProgressionData.cs | 1093 +++++---- BaseHandlers/Renderable.cs | 1035 ++++---- BaseHandlers/StreetData.cs | 1139 +++++---- BaseHandlers/StreetDataEditor.cs | 741 +++--- BaseHandlers/TextureState.cs | 83 +- BaseHandlers/Traffic.cs | 287 ++- BaseHandlers/TriggerData.cs | 1780 +++++++------- BaseHandlers/TriggerDataEditor.cs | 61 +- BundleFormat/BundleArchive.cs | 1437 ++++++----- BundleFormat/BundleCache.cs | 83 +- BundleFormat/BundleDependency.cs | 63 +- BundleFormat/BundleEntry.cs | 685 +++--- BundleFormat/EntryType.cs | 261 +- BundleFormat/Extensions.cs | 137 +- BundleFormat/VertexDesc.cs | 267 ++- BundleManager/BetterListView.cs | 45 +- BundleManager/BundleResource.cs | 35 +- BundleManager/EntryEditor.cs | 1243 +++++----- BundleManager/FileView.cs | 693 +++--- BundleManager/ImageImportDialog.cs | 65 +- BundleManager/ImportResourceForm.cs | 453 ++-- BundleManager/MainForm.cs | 1160 +++++---- BundleManager/NativeSaveDialog.cs | 243 +- BundleManager/Program.cs | 205 +- BundleManager/ResourceImport.cs | 331 ++- BundleManager/SaveData.cs | 105 +- BundleManager/SearchDialog.cs | 74 +- .../TypeConverters/Vector4Converter.cs | 2 +- BundleManager/VertexSizePicker.cs | 62 +- BundleUtilities/BinaryReader2.cs | 269 ++- BundleUtilities/BinaryWriter2.cs | 207 +- BundleUtilities/BitScan.cs | 63 +- BundleUtilities/Colour.cs | 91 +- BundleUtilities/Config.cs | 9 +- BundleUtilities/Crc32.cs | 250 +- BundleUtilities/DebugTimer.cs | 57 +- BundleUtilities/EncryptedString.cs | 239 +- BundleUtilities/ILoader.cs | 11 +- BundleUtilities/LoadingDialog.cs | 174 +- BundleUtilities/Lookup8.cs | 139 +- BundleUtilities/ReadFailedError.cs | 15 +- BundleUtilities/TextureCache.cs | 51 +- BundleUtilities/Utilities.cs | 136 +- BurnoutImage/ClusterFit.cs | 47 +- BurnoutImage/ColourFit.cs | 45 +- BurnoutImage/ColourSet.cs | 173 +- BurnoutImage/CompressionTools.cs | 51 +- BurnoutImage/DirectBitmap.cs | 77 +- BurnoutImage/Extensions.cs | 27 +- BurnoutImage/GameImage.cs | 763 +++--- BurnoutImage/ImageUtil.cs | 119 +- BurnoutImage/RangeFit.cs | 67 +- BurnoutImage/SingleColourLookup.cs | 2125 ++++++++--------- BurnoutImage/Util.cs | 189 +- ComponentTester/Program.cs | 27 +- ComponentTester/Tester.cs | 125 +- HexEditor/HexView.cs | 197 +- LangEditor/InputDialog.cs | 87 +- LangEditor/LangEdit.cs | 471 ++-- LangEditor/LangPlugin.cs | 17 +- LangEditor/Language.cs | 295 ++- LoopModel/LoopModelData.cs | 753 +++--- LoopModel/LoopModelEditor.cs | 321 ++- LoopModel/LoopModelPlugin.cs | 17 +- LuaList/EncryptedStringConverter.cs | 89 +- LuaList/LuaList.cs | 347 +-- LuaList/LuaListEditor.cs | 53 +- LuaList/LuaListEntry.cs | 120 +- LuaList/LuaListPlugin.cs | 19 +- MathLib/BoxF.cs | 37 +- MathLib/IOExtensions.cs | 261 +- MathLib/MathUtils.cs | 39 +- MathLib/RectF.cs | 21 +- MathLib/Triangle.cs | 13 +- MathLib/Vector2i.cs | 159 +- MathLib/Vector3i.cs | 163 +- MathLib/Vector3s.cs | 43 +- ModelViewer/GenericMesh.cs | 69 +- ModelViewer/GenericModel.cs | 123 +- ModelViewer/GraphicsScene.cs | 175 +- ModelViewer/GraphicsUtil.cs | 31 +- ModelViewer/ICamera.cs | 11 +- ModelViewer/ModelViewerForm.cs | 103 +- ModelViewer/OBJImporter.cs | 335 ++- ModelViewer/OrbitCamera.cs | 79 +- ModelViewer/SceneData/Material.cs | 67 +- ModelViewer/SceneData/Mesh.cs | 563 +++-- ModelViewer/SceneData/Model.cs | 143 +- ModelViewer/SceneData/Scene.cs | 519 ++-- ModelViewer/SceneData/SceneObject.cs | 145 +- ModelViewer/SceneRenderControl.cs | 215 +- ModelViewer/Shader.cs | 103 +- ModelViewer/StaticCamera.cs | 33 +- ModelViewer/ThirdPersonCamera.cs | 39 +- PVSFormat/AddZone.cs | 45 +- PVSFormat/PVS.cs | 499 ++-- PVSFormat/PVSEditControl.cs | 517 ++-- PVSFormat/PVSEditor.cs | 615 +++-- PVSFormat/PVSPlugin.cs | 17 +- PVSFormat/Polygon.cs | 135 +- PluginAPI/EntryTypeRegistry.cs | 53 +- PluginAPI/IEntryData.cs | 15 +- PluginAPI/IEntryEditor.cs | 9 +- PluginAPI/IPlugin.cs | 13 +- PluginAPI/PluginCommand.cs | 31 +- PluginAPI/PluginCommandRegistry.cs | 66 +- PluginSystem/PluginLoader.cs | 65 +- VaultFormat/AttribSys.cs | 1087 +++++---- VaultFormat/AttribSysPlugin.cs | 17 +- VaultFormat/AttribSysVaultForm.cs | 237 +- VaultFormat/Burnoutcarasset.cs | 256 +- VaultFormat/Burnoutcargraphicsasset.cs | 180 +- VaultFormat/Camerabumperbehaviour.cs | 152 +- VaultFormat/Cameraexternalbehaviour.cs | 196 +- VaultFormat/IAttribute.cs | 18 +- VaultFormat/Physicsvehiclebaseattribs.cs | 594 +++-- VaultFormat/Physicsvehiclebodyrollattribs.cs | 150 +- VaultFormat/Physicsvehicleboostattribs.cs | 192 +- VaultFormat/Physicsvehiclecollisionattribs.cs | 82 +- VaultFormat/Physicsvehicledriftattribs.cs | 348 ++- VaultFormat/Physicsvehicleengineattribs.cs | 205 +- VaultFormat/Physicsvehiclehandling.cs | 126 +- VaultFormat/Physicsvehiclesteeringattribs.cs | 180 +- .../Physicsvehiclesuspensionattribs.cs | 214 +- VaultFormat/RefSpec.cs | 88 +- VaultFormat/UnimplementedAttribs.cs | 57 +- VehicleList/EncryptionData.cs | 567 +++-- VehicleList/VehicleEditor.cs | 1102 +++++---- VehicleList/VehicleListData.cs | 703 +++--- VehicleList/VehicleListForm.cs | 647 +++-- VehicleList/VehicleListPlugin.cs | 17 +- WheelList/WheelEditor.cs | 176 +- WheelList/WheelListData.cs | 169 +- WheelList/WheelListForm.cs | 437 ++-- WheelList/WheelListPlugin.cs | 17 +- WorldCollisionHandler/PolygonSoupList.cs | 1143 +++++---- WorldCollisionHandler/WorldColEditor.cs | 145 +- WorldCollisionHandler/WorldCollisionPlugin.cs | 153 +- 147 files changed, 20267 insertions(+), 20418 deletions(-) diff --git a/.editorconfig b/.editorconfig index fe609e3..6878780 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,6 +8,51 @@ indent_style = space indent_size = 4 dotnet_diagnostic.CA1416.severity = none +# Code style +csharp_style_namespace_declarations = file_scoped +csharp_style_var_for_built_in_types = false +csharp_style_var_when_type_is_apparent = false +csharp_style_var_elsewhere = false +csharp_style_implicit_object_creation_when_type_is_apparent = true +dotnet_style_prefer_collection_expression = when_types_loosely_match +dotnet_style_collection_initializer = true +csharp_prefer_simple_using_statement = true +csharp_style_pattern_matching_over_as_with_null_check = true +csharp_style_pattern_matching_over_is_with_cast_check = true +csharp_style_prefer_not_pattern = true +csharp_style_inlined_variable_declaration = true +csharp_prefer_simple_default_expression = true +dotnet_style_coalesce_expression = true +dotnet_style_null_propagation = true +csharp_style_prefer_index_operator = true +csharp_style_prefer_range_operator = true +dotnet_style_predefined_type_for_locals_parameters_members = true +dotnet_style_predefined_type_for_member_access = true +dotnet_diagnostic.IDE0005.severity = suggestion # unnecessary using +dotnet_diagnostic.IDE0008.severity = suggestion # explicit type instead of var +dotnet_diagnostic.IDE0018.severity = suggestion # inline out variable +dotnet_diagnostic.IDE0019.severity = suggestion # pattern matching over as + null check +dotnet_diagnostic.IDE0020.severity = suggestion # pattern matching over is + cast +dotnet_diagnostic.IDE0028.severity = suggestion # collection initializer +dotnet_diagnostic.IDE0029.severity = suggestion # ?? over null check +dotnet_diagnostic.IDE0031.severity = suggestion # ?. over null check +dotnet_diagnostic.IDE0034.severity = suggestion # default literal +dotnet_diagnostic.IDE0049.severity = suggestion # language keywords over framework type names +dotnet_diagnostic.IDE0056.severity = suggestion # index operator +dotnet_diagnostic.IDE0057.severity = suggestion # range operator +dotnet_diagnostic.IDE0063.severity = suggestion # using declaration +dotnet_diagnostic.IDE0083.severity = suggestion # is not pattern +dotnet_diagnostic.IDE0090.severity = suggestion # target-typed new +dotnet_diagnostic.IDE0161.severity = suggestion # file-scoped namespace +dotnet_diagnostic.IDE0300.severity = suggestion # collection expressions +dotnet_diagnostic.IDE0301.severity = suggestion +dotnet_diagnostic.IDE0303.severity = suggestion +dotnet_diagnostic.IDE0304.severity = suggestion +dotnet_diagnostic.IDE0305.severity = suggestion + +[*.Designer.cs] +generated_code = true + [*.csproj] indent_style = space indent_size = 2 diff --git a/BaseHandlers/AptData.cs b/BaseHandlers/AptData.cs index c638e8e..e686bf4 100644 --- a/BaseHandlers/AptData.cs +++ b/BaseHandlers/AptData.cs @@ -7,802 +7,801 @@ using OpenTK.Mathematics; using PluginAPI; -namespace BaseHandlers -{ - public class AptColor - { - public float Red; - public float Green; - public float Blue; - public float Alpha; +namespace BaseHandlers; - public AptColor(float red, float green, float blue, float alpha) - { - Red = red; - Green = green; - Blue = blue; - Alpha = alpha; - } - } +public class AptColor +{ + public float Red; + public float Green; + public float Blue; + public float Alpha; - public enum AptConstType + public AptColor(float red, float green, float blue, float alpha) { - String = 1, - RegisterNumber = 4 + Red = red; + Green = green; + Blue = blue; + Alpha = alpha; } +} - public class AptConst - { - public AptConstType Type; - public uint Data; - public string String; +public enum AptConstType +{ + String = 1, + RegisterNumber = 4 +} - public override string ToString() - { - if (Type == AptConstType.String) - { - return String; - } - else - { - return "Register Number: 0x" + Data.ToString("X2"); - } - } - } +public class AptConst +{ + public AptConstType Type; + public uint Data; + public string String; - public class Import + public override string ToString() { - public string ImportMovie; - public string ImportName; - public int CharacterID; - public uint Unknown1; - - public override string ToString() + if (Type == AptConstType.String) { - return "ID: " + CharacterID + ", Movie: " + ImportMovie + ", Name: " + ImportName + ", Unk1: " + Unknown1.ToString("X8"); + return String; } - } - - public class Export - { - public string ExportName; - public int CharacterID; - - public override string ToString() + else { - return "ID: " + CharacterID + ", Name: " + ExportName; + return "Register Number: 0x" + Data.ToString("X2"); } } +} - public class ClipActionRecord - { - // TODO: Clip Action Record - } - - public class ClipAction - { - public uint ClipActionRecordCount; - public ClipActionRecord[] ClipActionRecords; - } +public class Import +{ + public string ImportMovie; + public string ImportName; + public int CharacterID; + public uint Unknown1; - public enum FrameType + public override string ToString() { - Action = 1, - FrameLabel = 2, - PlaceObject = 3, - RemoveObject = 4, - BackgroundColor = 5, - StartSound = 6, - StartSoundStream = 7, - InitAction = 8 + return "ID: " + CharacterID + ", Movie: " + ImportMovie + ", Name: " + ImportName + ", Unk1: " + Unknown1.ToString("X8"); } +} - public class FrameItem - { - public FrameType Type; - } +public class Export +{ + public string ExportName; + public int CharacterID; - public class FrameItemAction : FrameItem + public override string ToString() { - public uint ActionPtr; - public ActionRecord[] Actions; + return "ID: " + CharacterID + ", Name: " + ExportName; } +} - public class FrameItemLabel : FrameItem - { - public string Label; - public uint Flags; - public uint FrameID; - } +public class ClipActionRecord +{ + // TODO: Clip Action Record +} - public class FrameItemPlaceObject : FrameItem - { - /** - * The flags are: - * • Move – bit 1 (LSB) – a bit different than the other flags. - * This determines whether a previous instance of the character to - * "place" (specified by the depth parameter) should be moved, rather than - * simply created as new. There is special behaviour if combined with - * HasCharacter: a new character is created and the previous character - * at the given depth is removed. - * • HasCharacter – bit 2 – signifies whether the characterID field is set. - * • HasMatrix – bit 3 – signifies whether the matrix field is set. - * • HasColourTransform – bit 4 – signifies whether the colourTransform field is set. - * • HasRatio – bit 5 – signifies whether the ratio field is set. - * • HasName – bit 6 – signifies whether the name field is set. - * • HasClipDepth – bit 7 – signifies whether the clipDepth field is set. - * • HasClipActions – bit 8 – signifies whether the clipActions field is set. - * */ - public uint PlaceFlags; - - public uint Depth; - public uint CharacterID; - public Matrix3x2 Matrix; - public AptColor ColorTransform; - public uint Unknown1; - public uint Ratio; - public uint ClipDepth; - public uint ClipActionsPtr; - - public string Name; - public ClipAction[] ClipActions; - } +public class ClipAction +{ + public uint ClipActionRecordCount; + public ClipActionRecord[] ClipActionRecords; +} - public class Frame - { - public FrameItem[] FrameItems; - } +public enum FrameType +{ + Action = 1, + FrameLabel = 2, + PlaceObject = 3, + RemoveObject = 4, + BackgroundColor = 5, + StartSound = 6, + StartSoundStream = 7, + InitAction = 8 +} - public class ButtonRecord - { - // TODO: Button Record - } +public class FrameItem +{ + public FrameType Type; +} - public class ButtonSound - { - // TODO: Button Sound - } +public class FrameItemAction : FrameItem +{ + public uint ActionPtr; + public ActionRecord[] Actions; +} - public class ActionRecord - { - - } +public class FrameItemLabel : FrameItem +{ + public string Label; + public uint Flags; + public uint FrameID; +} - public enum TextAlignment - { - Left = 0, - Right = 1, - Center = 2, - None = 3, - Justify = 4 - } +public class FrameItemPlaceObject : FrameItem +{ + /** + * The flags are: + * • Move – bit 1 (LSB) – a bit different than the other flags. + * This determines whether a previous instance of the character to + * "place" (specified by the depth parameter) should be moved, rather than + * simply created as new. There is special behaviour if combined with + * HasCharacter: a new character is created and the previous character + * at the given depth is removed. + * • HasCharacter – bit 2 – signifies whether the characterID field is set. + * • HasMatrix – bit 3 – signifies whether the matrix field is set. + * • HasColourTransform – bit 4 – signifies whether the colourTransform field is set. + * • HasRatio – bit 5 – signifies whether the ratio field is set. + * • HasName – bit 6 – signifies whether the name field is set. + * • HasClipDepth – bit 7 – signifies whether the clipDepth field is set. + * • HasClipActions – bit 8 – signifies whether the clipActions field is set. + * */ + public uint PlaceFlags; + + public uint Depth; + public uint CharacterID; + public Matrix3x2 Matrix; + public AptColor ColorTransform; + public uint Unknown1; + public uint Ratio; + public uint ClipDepth; + public uint ClipActionsPtr; + + public string Name; + public ClipAction[] ClipActions; +} - public enum CharacterType - { - Shape = 1, - EditText = 2, - Font = 3, - Button = 4, - Sprite = 5, - Sound = 6, - Image = 7, - Morph = 8, - Movie = 9, - StaticText = 10, - None = 11, - Video = 12 - } +public class Frame +{ + public FrameItem[] FrameItems; +} - public abstract class CharacterData - { +public class ButtonRecord +{ + // TODO: Button Record +} - } +public class ButtonSound +{ + // TODO: Button Sound +} - public class CharacterShape : CharacterData - { - public RectF Bounds; - public uint GeometryID; - } +public class ActionRecord +{ + +} - public class CharacterTextEdit : CharacterData - { - public RectF Bounds; - public uint FontID; - public TextAlignment Alignment; - public uint Color; - public float FontHeight; - public uint ReadOnly; - public uint Multiline; - public uint Wordwrap; - public string Text; - public string Variable; - } +public enum TextAlignment +{ + Left = 0, + Right = 1, + Center = 2, + None = 3, + Justify = 4 +} - public class CharacterFont : CharacterData - { - public string Name; +public enum CharacterType +{ + Shape = 1, + EditText = 2, + Font = 3, + Button = 4, + Sprite = 5, + Sound = 6, + Image = 7, + Morph = 8, + Movie = 9, + StaticText = 10, + None = 11, + Video = 12 +} - public Character[] Glyphs; - } +public abstract class CharacterData +{ - public class CharacterButton : CharacterData - { - public uint MenuButton; - public RectF Bounds; - public int TriangleCount; - public int VertexCount; - public uint VertexPtr; - public uint TrianglePtr; - public int RecordCount; - public uint RecordPtr; - public int ActionCount; - public uint ActionPtr; - public uint SoundPtr; - - public Vector2[] Vertices; - public Triangle[] Triangles; - public ButtonRecord[] Records; - public ActionRecord[] Actions; - public ButtonSound Sound; - } +} - public class CharacterSprite : CharacterData - { - public uint Unknown1; +public class CharacterShape : CharacterData +{ + public RectF Bounds; + public uint GeometryID; +} - public Frame[] Frames; - } +public class CharacterTextEdit : CharacterData +{ + public RectF Bounds; + public uint FontID; + public TextAlignment Alignment; + public uint Color; + public float FontHeight; + public uint ReadOnly; + public uint Multiline; + public uint Wordwrap; + public string Text; + public string Variable; +} - public class CharacterSound : CharacterData - { - // TODO: Sound - } +public class CharacterFont : CharacterData +{ + public string Name; - public class CharacterImage : CharacterData - { - public uint ImageID; - } + public Character[] Glyphs; +} - public class CharacterMorph : CharacterData - { - // TODO: Morph - } +public class CharacterButton : CharacterData +{ + public uint MenuButton; + public RectF Bounds; + public int TriangleCount; + public int VertexCount; + public uint VertexPtr; + public uint TrianglePtr; + public int RecordCount; + public uint RecordPtr; + public int ActionCount; + public uint ActionPtr; + public uint SoundPtr; + + public Vector2[] Vertices; + public Triangle[] Triangles; + public ButtonRecord[] Records; + public ActionRecord[] Actions; + public ButtonSound Sound; +} - public class CharacterMovie : CharacterData - { - public uint Unknown1; - public int ScreenWidth; - public int ScreenHeight; - public int MillisecondsPerFrame; - public uint Unknown2; - - public Frame[] Frames; - public Character[] Characters; - public Import[] Imports; - public Export[] Exports; - } +public class CharacterSprite : CharacterData +{ + public uint Unknown1; - public class CharacterStaticText : CharacterData - { - // TODO: Static Text - } + public Frame[] Frames; +} - public class CharacterVideo : CharacterData - { - // TODO: Video - } +public class CharacterSound : CharacterData +{ + // TODO: Sound +} - public class Character - { - // Header - public CharacterType Type; - public uint Signature; - public ushort Unknown1; - public ushort ID; - public uint Unknown2; +public class CharacterImage : CharacterData +{ + public uint ImageID; +} - // Data - public CharacterData Data; +public class CharacterMorph : CharacterData +{ + // TODO: Morph +} - private static Frame ReadFrame(BinaryReader2 br, uint dataStart) - { - Frame frame = new Frame(); +public class CharacterMovie : CharacterData +{ + public uint Unknown1; + public int ScreenWidth; + public int ScreenHeight; + public int MillisecondsPerFrame; + public uint Unknown2; + + public Frame[] Frames; + public Character[] Characters; + public Import[] Imports; + public Export[] Exports; +} - uint itemCount = br.ReadUInt32(); - uint frameItemPtr = dataStart + br.ReadUInt32(); +public class CharacterStaticText : CharacterData +{ + // TODO: Static Text +} - long fPos = br.BaseStream.Position; +public class CharacterVideo : CharacterData +{ + // TODO: Video +} - br.BaseStream.Position = frameItemPtr; - //MessageBox.Show("Pos: " + frameItemPtr.ToString("X8")); +public class Character +{ + // Header + public CharacterType Type; + public uint Signature; + public ushort Unknown1; + public ushort ID; + public uint Unknown2; - uint[] framePtrs = new uint[itemCount]; - for (int j = 0; j < framePtrs.Length; j++) - { - framePtrs[j] = dataStart + br.ReadUInt32(); - } + // Data + public CharacterData Data; - frame.FrameItems = new FrameItem[itemCount]; - for (int j = 0; j < frame.FrameItems.Length; j++) - { - br.BaseStream.Position = framePtrs[j]; + private static Frame ReadFrame(BinaryReader2 br, uint dataStart) + { + Frame frame = new(); - FrameItem item = null; - FrameType type = (FrameType) br.ReadUInt32(); - //MessageBox.Show("Type: " + type); - switch (type) - { - case FrameType.Action: - FrameItemAction actionFrame = new FrameItemAction(); - actionFrame.Type = type; - actionFrame.ActionPtr = br.ReadUInt32(); - - // TODO: ActionRecords - - item = actionFrame; - break; - case FrameType.FrameLabel: - FrameItemLabel frameLabel = new FrameItemLabel(); - frameLabel.Type = type; - uint labelPtr = dataStart + br.ReadUInt32(); - frameLabel.Flags = br.ReadUInt32(); - frameLabel.FrameID = br.ReadUInt32(); - - long blaPos = br.BaseStream.Position; - br.BaseStream.Position = labelPtr; - frameLabel.Label = br.ReadCStr(); - br.BaseStream.Position = blaPos; - - item = frameLabel; - break; - case FrameType.PlaceObject: - FrameItemPlaceObject framePlaceObject = new FrameItemPlaceObject(); - framePlaceObject.Type = type; - - // TODO: Place Object - framePlaceObject.PlaceFlags = br.ReadUInt32(); - framePlaceObject.Depth = br.ReadUInt32(); - framePlaceObject.CharacterID = br.ReadUInt32(); - framePlaceObject.Matrix = br.ReadMatrix3x2(); - float r = br.ReadSingle(); - float g = br.ReadSingle(); - float b = br.ReadSingle(); - float a = br.ReadSingle(); - framePlaceObject.ColorTransform = new AptColor(r, g, b, a); - framePlaceObject.Unknown1 = br.ReadUInt32(); - framePlaceObject.Ratio = br.ReadUInt32(); - uint namePtr = br.ReadUInt32(); - long cblaPos = br.BaseStream.Position; - br.BaseStream.Position = namePtr; - framePlaceObject.Name = br.ReadCStr(); - br.BaseStream.Position = cblaPos; - framePlaceObject.ClipDepth = br.ReadUInt32(); - framePlaceObject.ClipActionsPtr = br.ReadUInt32(); - - // TODO: ClipActions - - item = framePlaceObject; - break; - case FrameType.RemoveObject: - break; - case FrameType.BackgroundColor: - break; - case FrameType.StartSound: - break; - case FrameType.StartSoundStream: - break; - case FrameType.InitAction: - break; - default: - item = null; - break; - } + uint itemCount = br.ReadUInt32(); + uint frameItemPtr = dataStart + br.ReadUInt32(); - // TODO: FrameItem - // TODO: FrameItem - // TODO: FrameItem - // TODO: FrameItem - // TODO: FrameItem - // TODO: FrameItem - // TODO: FrameItem - // TODO: FrameItem - // TODO: FrameItem - // TODO: FrameItem - // TODO: FrameItem - // TODO: FrameItem - // TODO: FrameItem - // TODO: FrameItem - // TODO: FrameItem - // TODO: FrameItem - // TODO: FrameItem - // TODO: FrameItem - // TODO: FrameItem - // TODO: FrameItem - // TODO: FrameItem - // TODO: FrameItem - // TODO: FrameItem - // TODO: FrameItem - // TODO: FrameItem - // TODO: FrameItem - // TODO: FrameItem - // TODO: FrameItem - - frame.FrameItems[j] = item; - } + long fPos = br.BaseStream.Position; - br.BaseStream.Position = fPos; + br.BaseStream.Position = frameItemPtr; + //MessageBox.Show("Pos: " + frameItemPtr.ToString("X8")); - return frame; + uint[] framePtrs = new uint[itemCount]; + for (int j = 0; j < framePtrs.Length; j++) + { + framePtrs[j] = dataStart + br.ReadUInt32(); } - public static Character Read(BinaryReader2 br, uint dataStart) + frame.FrameItems = new FrameItem[itemCount]; + for (int j = 0; j < frame.FrameItems.Length; j++) { - Character result = new Character(); + br.BaseStream.Position = framePtrs[j]; - long startPos = br.BaseStream.Position; + FrameItem item = null; + FrameType type = (FrameType) br.ReadUInt32(); + //MessageBox.Show("Type: " + type); + switch (type) + { + case FrameType.Action: + FrameItemAction actionFrame = new(); + actionFrame.Type = type; + actionFrame.ActionPtr = br.ReadUInt32(); - result.Type = (CharacterType)br.ReadUInt32(); - result.Signature = br.ReadUInt32(); - result.Unknown1 = br.ReadUInt16(); - result.ID = br.ReadUInt16(); - result.Unknown2 = br.ReadUInt32(); + // TODO: ActionRecords - switch (result.Type) - { - case CharacterType.Shape: - CharacterShape shape = new CharacterShape(); - shape.Bounds = br.ReadRectF(); - shape.GeometryID = br.ReadUInt32(); - result.Data = shape; + item = actionFrame; break; - case CharacterType.EditText: - CharacterTextEdit textEdit = new CharacterTextEdit(); - textEdit.Bounds = br.ReadRectF(); - textEdit.FontID = br.ReadUInt32(); - textEdit.Alignment = (TextAlignment)br.ReadUInt32(); - textEdit.Color = br.ReadUInt32(); - textEdit.FontHeight = br.ReadSingle(); - textEdit.ReadOnly = br.ReadUInt32(); - textEdit.Multiline = br.ReadUInt32(); - textEdit.Wordwrap = br.ReadUInt32(); - uint textPtr = dataStart + br.ReadUInt32(); - uint variableNamePtr = dataStart + br.ReadUInt32(); - - long thePos = br.BaseStream.Position; - br.BaseStream.Position = textPtr; - textEdit.Text = br.ReadCStr(); - br.BaseStream.Position = variableNamePtr; - textEdit.Variable = br.ReadCStr(); - br.BaseStream.Position = thePos; - - result.Data = textEdit; + case FrameType.FrameLabel: + FrameItemLabel frameLabel = new(); + frameLabel.Type = type; + uint labelPtr = dataStart + br.ReadUInt32(); + frameLabel.Flags = br.ReadUInt32(); + frameLabel.FrameID = br.ReadUInt32(); + + long blaPos = br.BaseStream.Position; + br.BaseStream.Position = labelPtr; + frameLabel.Label = br.ReadCStr(); + br.BaseStream.Position = blaPos; + + item = frameLabel; break; - case CharacterType.Font: - CharacterFont font = new CharacterFont(); - uint namePtr = dataStart + br.ReadUInt32(); - long cPos = br.BaseStream.Position; + case FrameType.PlaceObject: + FrameItemPlaceObject framePlaceObject = new(); + framePlaceObject.Type = type; + + // TODO: Place Object + framePlaceObject.PlaceFlags = br.ReadUInt32(); + framePlaceObject.Depth = br.ReadUInt32(); + framePlaceObject.CharacterID = br.ReadUInt32(); + framePlaceObject.Matrix = br.ReadMatrix3x2(); + float r = br.ReadSingle(); + float g = br.ReadSingle(); + float b = br.ReadSingle(); + float a = br.ReadSingle(); + framePlaceObject.ColorTransform = new AptColor(r, g, b, a); + framePlaceObject.Unknown1 = br.ReadUInt32(); + framePlaceObject.Ratio = br.ReadUInt32(); + uint namePtr = br.ReadUInt32(); + long cblaPos = br.BaseStream.Position; br.BaseStream.Position = namePtr; - font.Name = br.ReadCStr(); - br.BaseStream.Position = cPos; - uint glyphCount = br.ReadUInt32(); - uint glyphPtr = br.ReadUInt32(); + framePlaceObject.Name = br.ReadCStr(); + br.BaseStream.Position = cblaPos; + framePlaceObject.ClipDepth = br.ReadUInt32(); + framePlaceObject.ClipActionsPtr = br.ReadUInt32(); - cPos = br.BaseStream.Position; - br.BaseStream.Position = dataStart + glyphPtr; + // TODO: ClipActions - font.Glyphs = new Character[glyphCount]; - for (int i = 0; i < font.Glyphs.Length; i++) - { - font.Glyphs[i] = Character.Read(br, dataStart); - } - - br.BaseStream.Position = cPos; - - result.Data = font; + item = framePlaceObject; break; - case CharacterType.Button: - CharacterButton button = new CharacterButton(); - button.MenuButton = br.ReadUInt32(); - button.Bounds = br.ReadRectF(); - button.TriangleCount = br.ReadInt32(); - button.VertexCount = br.ReadInt32(); - button.VertexPtr = br.ReadUInt32(); - button.TrianglePtr = br.ReadUInt32(); - button.RecordCount = br.ReadInt32(); - button.RecordPtr = br.ReadUInt32(); - button.ActionCount = br.ReadInt32(); - button.ActionPtr = br.ReadUInt32(); - button.SoundPtr = br.ReadUInt32(); - result.Data = button; + case FrameType.RemoveObject: break; - case CharacterType.Sprite: - CharacterSprite sprite = new CharacterSprite(); - uint frameCount2 = br.ReadUInt32(); - uint framePtr2 = br.ReadUInt32(); - sprite.Unknown1 = br.ReadUInt32(); - - // TODO: Verify Frames - br.BaseStream.Position = dataStart + framePtr2; - sprite.Frames = new Frame[frameCount2]; - for (int i = 0; i < sprite.Frames.Length; i++) - { - sprite.Frames[i] = ReadFrame(br, dataStart); - } - - result.Data = sprite; + case FrameType.BackgroundColor: break; - case CharacterType.Sound: - CharacterSound sound = new CharacterSound(); - // TODO: Sound - result.Data = sound; + case FrameType.StartSound: break; - case CharacterType.Image: - CharacterImage image = new CharacterImage(); - image.ImageID = br.ReadUInt32(); // TODO: Verify - result.Data = image; + case FrameType.StartSoundStream: break; - case CharacterType.Morph: - CharacterMorph morph = new CharacterMorph(); - // TODO: Morph - result.Data = morph; + case FrameType.InitAction: break; - case CharacterType.Movie: - CharacterMovie movie = new CharacterMovie(); - - uint frameCount = br.ReadUInt32(); - uint framePtr = br.ReadUInt32(); - movie.Unknown1 = br.ReadUInt32(); - uint characterCount = br.ReadUInt32(); - uint characterPtr = br.ReadUInt32(); - movie.ScreenWidth = br.ReadInt32(); - movie.ScreenHeight = br.ReadInt32(); - movie.MillisecondsPerFrame = br.ReadInt32(); - uint importCount = br.ReadUInt32(); - uint importPtr = br.ReadUInt32(); - uint exportCount = br.ReadUInt32(); - uint exportPtr = br.ReadUInt32(); - movie.Unknown2 = br.ReadUInt32(); - - //MessageBox.Show("Pos: " + br.BaseStream.Position.ToString("X8")); - //MessageBox.Show("Pos: " + characterPtr.ToString("X8")); - - long myPos = br.BaseStream.Position; - - - br.BaseStream.Position = dataStart + framePtr; - movie.Frames = new Frame[frameCount]; - for (int i = 0; i < movie.Frames.Length; i++) - { - movie.Frames[i] = ReadFrame(br, dataStart); - } + default: + item = null; + break; + } - br.BaseStream.Position = dataStart + characterPtr; + // TODO: FrameItem + // TODO: FrameItem + // TODO: FrameItem + // TODO: FrameItem + // TODO: FrameItem + // TODO: FrameItem + // TODO: FrameItem + // TODO: FrameItem + // TODO: FrameItem + // TODO: FrameItem + // TODO: FrameItem + // TODO: FrameItem + // TODO: FrameItem + // TODO: FrameItem + // TODO: FrameItem + // TODO: FrameItem + // TODO: FrameItem + // TODO: FrameItem + // TODO: FrameItem + // TODO: FrameItem + // TODO: FrameItem + // TODO: FrameItem + // TODO: FrameItem + // TODO: FrameItem + // TODO: FrameItem + // TODO: FrameItem + // TODO: FrameItem + // TODO: FrameItem + + frame.FrameItems[j] = item; + } - uint[] CharacterPtrs = new uint[characterCount]; - for (int i = 0; i < characterCount; i++) - { - CharacterPtrs[i] = dataStart + br.ReadUInt32(); - } + br.BaseStream.Position = fPos; - movie.Characters = new Character[characterCount]; - for (int i = 0; i < movie.Characters.Length; i++) - { - if (CharacterPtrs[i] == startPos) - { - movie.Characters[i] = result; - } - else - { - br.BaseStream.Position = CharacterPtrs[i]; - movie.Characters[i] = Character.Read(br, dataStart); - } - } + return frame; + } - br.BaseStream.Position = dataStart + importPtr; - movie.Imports = new Import[importCount]; - for (int i = 0; i < movie.Imports.Length; i++) - { - Import import = new Import(); - - uint importMoviePtr = dataStart + br.ReadUInt32(); - uint importNamePtr = dataStart + br.ReadUInt32(); - import.CharacterID = br.ReadInt32(); - import.Unknown1 = br.ReadUInt32(); + public static Character Read(BinaryReader2 br, uint dataStart) + { + Character result = new(); - long pos = br.BaseStream.Position; + long startPos = br.BaseStream.Position; - br.BaseStream.Position = importMoviePtr; - import.ImportMovie = br.ReadCStr(); + result.Type = (CharacterType)br.ReadUInt32(); + result.Signature = br.ReadUInt32(); + result.Unknown1 = br.ReadUInt16(); + result.ID = br.ReadUInt16(); + result.Unknown2 = br.ReadUInt32(); - br.BaseStream.Position = importNamePtr; - import.ImportName = br.ReadCStr(); + switch (result.Type) + { + case CharacterType.Shape: + CharacterShape shape = new(); + shape.Bounds = br.ReadRectF(); + shape.GeometryID = br.ReadUInt32(); + result.Data = shape; + break; + case CharacterType.EditText: + CharacterTextEdit textEdit = new(); + textEdit.Bounds = br.ReadRectF(); + textEdit.FontID = br.ReadUInt32(); + textEdit.Alignment = (TextAlignment)br.ReadUInt32(); + textEdit.Color = br.ReadUInt32(); + textEdit.FontHeight = br.ReadSingle(); + textEdit.ReadOnly = br.ReadUInt32(); + textEdit.Multiline = br.ReadUInt32(); + textEdit.Wordwrap = br.ReadUInt32(); + uint textPtr = dataStart + br.ReadUInt32(); + uint variableNamePtr = dataStart + br.ReadUInt32(); + + long thePos = br.BaseStream.Position; + br.BaseStream.Position = textPtr; + textEdit.Text = br.ReadCStr(); + br.BaseStream.Position = variableNamePtr; + textEdit.Variable = br.ReadCStr(); + br.BaseStream.Position = thePos; + + result.Data = textEdit; + break; + case CharacterType.Font: + CharacterFont font = new(); + uint namePtr = dataStart + br.ReadUInt32(); + long cPos = br.BaseStream.Position; + br.BaseStream.Position = namePtr; + font.Name = br.ReadCStr(); + br.BaseStream.Position = cPos; + uint glyphCount = br.ReadUInt32(); + uint glyphPtr = br.ReadUInt32(); + + cPos = br.BaseStream.Position; + br.BaseStream.Position = dataStart + glyphPtr; + + font.Glyphs = new Character[glyphCount]; + for (int i = 0; i < font.Glyphs.Length; i++) + { + font.Glyphs[i] = Character.Read(br, dataStart); + } - br.BaseStream.Position = pos; + br.BaseStream.Position = cPos; + + result.Data = font; + break; + case CharacterType.Button: + CharacterButton button = new(); + button.MenuButton = br.ReadUInt32(); + button.Bounds = br.ReadRectF(); + button.TriangleCount = br.ReadInt32(); + button.VertexCount = br.ReadInt32(); + button.VertexPtr = br.ReadUInt32(); + button.TrianglePtr = br.ReadUInt32(); + button.RecordCount = br.ReadInt32(); + button.RecordPtr = br.ReadUInt32(); + button.ActionCount = br.ReadInt32(); + button.ActionPtr = br.ReadUInt32(); + button.SoundPtr = br.ReadUInt32(); + result.Data = button; + break; + case CharacterType.Sprite: + CharacterSprite sprite = new(); + uint frameCount2 = br.ReadUInt32(); + uint framePtr2 = br.ReadUInt32(); + sprite.Unknown1 = br.ReadUInt32(); + + // TODO: Verify Frames + br.BaseStream.Position = dataStart + framePtr2; + sprite.Frames = new Frame[frameCount2]; + for (int i = 0; i < sprite.Frames.Length; i++) + { + sprite.Frames[i] = ReadFrame(br, dataStart); + } + + result.Data = sprite; + break; + case CharacterType.Sound: + CharacterSound sound = new(); + // TODO: Sound + result.Data = sound; + break; + case CharacterType.Image: + CharacterImage image = new(); + image.ImageID = br.ReadUInt32(); // TODO: Verify + result.Data = image; + break; + case CharacterType.Morph: + CharacterMorph morph = new(); + // TODO: Morph + result.Data = morph; + break; + case CharacterType.Movie: + CharacterMovie movie = new(); + + uint frameCount = br.ReadUInt32(); + uint framePtr = br.ReadUInt32(); + movie.Unknown1 = br.ReadUInt32(); + uint characterCount = br.ReadUInt32(); + uint characterPtr = br.ReadUInt32(); + movie.ScreenWidth = br.ReadInt32(); + movie.ScreenHeight = br.ReadInt32(); + movie.MillisecondsPerFrame = br.ReadInt32(); + uint importCount = br.ReadUInt32(); + uint importPtr = br.ReadUInt32(); + uint exportCount = br.ReadUInt32(); + uint exportPtr = br.ReadUInt32(); + movie.Unknown2 = br.ReadUInt32(); + + //MessageBox.Show("Pos: " + br.BaseStream.Position.ToString("X8")); + //MessageBox.Show("Pos: " + characterPtr.ToString("X8")); + + long myPos = br.BaseStream.Position; + + + br.BaseStream.Position = dataStart + framePtr; + movie.Frames = new Frame[frameCount]; + for (int i = 0; i < movie.Frames.Length; i++) + { + movie.Frames[i] = ReadFrame(br, dataStart); + } + + br.BaseStream.Position = dataStart + characterPtr; + + uint[] CharacterPtrs = new uint[characterCount]; + for (int i = 0; i < characterCount; i++) + { + CharacterPtrs[i] = dataStart + br.ReadUInt32(); + } - movie.Imports[i] = import; + movie.Characters = new Character[characterCount]; + for (int i = 0; i < movie.Characters.Length; i++) + { + if (CharacterPtrs[i] == startPos) + { + movie.Characters[i] = result; } - - br.BaseStream.Position = dataStart + exportPtr; - movie.Exports = new Export[exportCount]; - for (int i = 0; i < movie.Exports.Length; i++) + else { - Export export = new Export(); + br.BaseStream.Position = CharacterPtrs[i]; + movie.Characters[i] = Character.Read(br, dataStart); + } + } - uint exportNamePtr = dataStart + br.ReadUInt32(); - export.CharacterID = br.ReadInt32(); - - long pos = br.BaseStream.Position; + br.BaseStream.Position = dataStart + importPtr; + movie.Imports = new Import[importCount]; + for (int i = 0; i < movie.Imports.Length; i++) + { + Import import = new(); + + uint importMoviePtr = dataStart + br.ReadUInt32(); + uint importNamePtr = dataStart + br.ReadUInt32(); + import.CharacterID = br.ReadInt32(); + import.Unknown1 = br.ReadUInt32(); - br.BaseStream.Position = exportNamePtr; - export.ExportName = br.ReadCStr(); + long pos = br.BaseStream.Position; - br.BaseStream.Position = pos; + br.BaseStream.Position = importMoviePtr; + import.ImportMovie = br.ReadCStr(); - movie.Exports[i] = export; - } + br.BaseStream.Position = importNamePtr; + import.ImportName = br.ReadCStr(); - br.BaseStream.Position = myPos; + br.BaseStream.Position = pos; - // TODO: Init Arrays + movie.Imports[i] = import; + } + + br.BaseStream.Position = dataStart + exportPtr; + movie.Exports = new Export[exportCount]; + for (int i = 0; i < movie.Exports.Length; i++) + { + Export export = new(); - result.Data = movie; - break; - case CharacterType.StaticText: - CharacterStaticText staticText = new CharacterStaticText(); - // TODO: Static Text - result.Data = staticText; - break; - case CharacterType.None: - break; - case CharacterType.Video: - CharacterVideo video = new CharacterVideo(); - // TODO: Video - result.Data = video; - break; - default: - MessageBox.Show("Out of range Character Type: " + result.Type); - break; - } + uint exportNamePtr = dataStart + br.ReadUInt32(); + export.CharacterID = br.ReadInt32(); + + long pos = br.BaseStream.Position; - // TODO: Finish Read + br.BaseStream.Position = exportNamePtr; + export.ExportName = br.ReadCStr(); - return result; - } + br.BaseStream.Position = pos; - public void Write(BinaryWriter2 bw) - { - bw.Write((uint)Type); - bw.Write(Signature); - bw.Write(Unknown1); - bw.Write(ID); - bw.Write(Unknown2); + movie.Exports[i] = export; + } - // TODO: Finish Write + br.BaseStream.Position = myPos; + + // TODO: Init Arrays + + result.Data = movie; + break; + case CharacterType.StaticText: + CharacterStaticText staticText = new(); + // TODO: Static Text + result.Data = staticText; + break; + case CharacterType.None: + break; + case CharacterType.Video: + CharacterVideo video = new(); + // TODO: Video + result.Data = video; + break; + default: + MessageBox.Show("Out of range Character Type: " + result.Type); + break; } - public override string ToString() - { - return "Type: " + Type + ", Signature: " + Signature.ToString("X8") + ", Unk1: " + Unknown1.ToString("X4") + ", ID: " + ID.ToString("X4") + ", Unk2: " + Unknown2.ToString("X8"); - } + // TODO: Finish Read + + return result; } - public class AptData : IEntryData + public void Write(BinaryWriter2 bw) { - public string Component1Name; - public string Component2Name; + bw.Write((uint)Type); + bw.Write(Signature); + bw.Write(Unknown1); + bw.Write(ID); + bw.Write(Unknown2); - public Character RootMovie; + // TODO: Finish Write + } - public List Constants; + public override string ToString() + { + return "Type: " + Type + ", Signature: " + Signature.ToString("X8") + ", Unk1: " + Unknown1.ToString("X4") + ", ID: " + ID.ToString("X4") + ", Unk2: " + Unknown2.ToString("X8"); + } +} - public AptData() - { - Constants = new List(); - } +public class AptData : IEntryData +{ + public string Component1Name; + public string Component2Name; - private void Clear() - { - Component1Name = default; - Component2Name = default; + public Character RootMovie; - RootMovie = default; + public List Constants; - Constants.Clear(); - } + public AptData() + { + Constants = []; + } - public bool Read(BundleEntry entry, ILoader loader = null) - { - Clear(); + private void Clear() + { + Component1Name = default; + Component2Name = default; - MemoryStream ms = entry.MakeStream(); - BinaryReader2 br = new BinaryReader2(ms); - br.BigEndian = entry.Console; + RootMovie = default; - uint componentName2Ptr = br.ReadUInt32(); - uint componentName1Ptr = br.ReadUInt32(); - uint aptDataOffset = br.ReadUInt32(); - uint constOffset = br.ReadUInt32(); - uint geometryOffset = br.ReadUInt32(); - uint fileSize = br.ReadUInt32(); + Constants.Clear(); + } - /*int numPadding = (int)(16 - br.BaseStream.Position % 16); - for (int i = 0; i < numPadding; i++) - br.ReadByte();*/ + public bool Read(BundleEntry entry, ILoader loader = null) + { + Clear(); - br.BaseStream.Position = componentName1Ptr; - Component1Name = br.ReadCStr(); - br.BaseStream.Position = componentName2Ptr; - Component2Name = br.ReadCStr(); + MemoryStream ms = entry.MakeStream(); + BinaryReader2 br = new(ms); + br.BigEndian = entry.Console; - br.BaseStream.Position = constOffset; - byte[] constMagic = br.ReadBytes(20); + uint componentName2Ptr = br.ReadUInt32(); + uint componentName1Ptr = br.ReadUInt32(); + uint aptDataOffset = br.ReadUInt32(); + uint constOffset = br.ReadUInt32(); + uint geometryOffset = br.ReadUInt32(); + uint fileSize = br.ReadUInt32(); - uint movieOffset = br.ReadUInt32(); + /*int numPadding = (int)(16 - br.BaseStream.Position % 16); + for (int i = 0; i < numPadding; i++) + br.ReadByte();*/ - int constCount = br.ReadInt32(); - uint constantStartOffset = br.ReadUInt32(); + br.BaseStream.Position = componentName1Ptr; + Component1Name = br.ReadCStr(); + br.BaseStream.Position = componentName2Ptr; + Component2Name = br.ReadCStr(); - br.BaseStream.Position = constOffset + constantStartOffset; - for (int i = 0; i < constCount; i++) - { - AptConst constant = new AptConst(); + br.BaseStream.Position = constOffset; + byte[] constMagic = br.ReadBytes(20); - constant.Type = (AptConstType)br.ReadUInt32(); - constant.Data = br.ReadUInt32(); + uint movieOffset = br.ReadUInt32(); - Constants.Add(constant); - } + int constCount = br.ReadInt32(); + uint constantStartOffset = br.ReadUInt32(); - for (int i = 0; i < Constants.Count; i++) + br.BaseStream.Position = constOffset + constantStartOffset; + for (int i = 0; i < constCount; i++) + { + AptConst constant = new(); + + constant.Type = (AptConstType)br.ReadUInt32(); + constant.Data = br.ReadUInt32(); + + Constants.Add(constant); + } + + for (int i = 0; i < Constants.Count; i++) + { + if (Constants[i].Type == AptConstType.String) { - if (Constants[i].Type == AptConstType.String) - { - br.BaseStream.Position = constOffset + Constants[i].Data; - Constants[i].String = br.ReadCStr(); // 4 byte aligned - } + br.BaseStream.Position = constOffset + Constants[i].Data; + Constants[i].String = br.ReadCStr(); // 4 byte aligned } + } - br.BaseStream.Position = aptDataOffset; - byte[] dataMagic = br.ReadBytes(16); + br.BaseStream.Position = aptDataOffset; + byte[] dataMagic = br.ReadBytes(16); - br.BaseStream.Position = aptDataOffset + movieOffset; - RootMovie = Character.Read(br, aptDataOffset); + br.BaseStream.Position = aptDataOffset + movieOffset; + RootMovie = Character.Read(br, aptDataOffset); - // TODO: Finish Read + // TODO: Finish Read - br.Close(); - ms.Close(); + br.Close(); + ms.Close(); - return true; - } + return true; + } - public bool Write(BundleEntry entry) - { - MemoryStream ms = new MemoryStream(); - BinaryWriter2 bw = new BinaryWriter2(ms); - bw.BigEndian = entry.Console; + public bool Write(BundleEntry entry) + { + MemoryStream ms = new(); + BinaryWriter2 bw = new(ms); + bw.BigEndian = entry.Console; - // TODO: Write + // TODO: Write - bw.Flush(); - byte[] data = ms.ToArray(); - bw.Close(); - ms.Close(); + bw.Flush(); + byte[] data = ms.ToArray(); + bw.Close(); + ms.Close(); - entry.EntryBlocks[0].Data = data; - entry.Dirty = true; + entry.EntryBlocks[0].Data = data; + entry.Dirty = true; - return true; - } + return true; + } - public EntryType GetEntryType(BundleEntry entry) - { - return EntryType.AptData; - } + public EntryType GetEntryType(BundleEntry entry) + { + return EntryType.AptData; + } - public IEntryEditor GetEditor(BundleEntry entry) - { - return null; - } + public IEntryEditor GetEditor(BundleEntry entry) + { + return null; } } diff --git a/BaseHandlers/BasePlugin.cs b/BaseHandlers/BasePlugin.cs index 95841d1..d247cd6 100644 --- a/BaseHandlers/BasePlugin.cs +++ b/BaseHandlers/BasePlugin.cs @@ -1,25 +1,24 @@ using BundleFormat; using PluginAPI; -namespace BaseHandlers +namespace BaseHandlers; + +public class BasePlugin : IPlugin { - public class BasePlugin : IPlugin - { - public string Id => "baseplugin"; - public string Name => "Base Resource Handlers"; + public string Id => "baseplugin"; + public string Name => "Base Resource Handlers"; - public static void Init() - { - EntryTypeRegistry.Register(EntryType.Renderable, new Renderable()); - EntryTypeRegistry.Register(EntryType.EntryList, new IDList()); - //EntryTypeRegistry.Register(EntryType.AptData, new AptData()); - EntryTypeRegistry.Register(EntryType.InstanceList, new InstanceList()); - EntryTypeRegistry.Register(EntryType.TrafficData, new Traffic()); - EntryTypeRegistry.Register(EntryType.TriggerData, new TriggerData()); - EntryTypeRegistry.Register(EntryType.GraphicsSpec, new GraphicsSpec()); - EntryTypeRegistry.Register(EntryType.ProgressionData, new ProgressionData()); - EntryTypeRegistry.Register(EntryType.StreetData, new StreetData()); - EntryTypeRegistry.Register(EntryType.FlaptFile, new FlaptFile()); - } + public static void Init() + { + EntryTypeRegistry.Register(EntryType.Renderable, new Renderable()); + EntryTypeRegistry.Register(EntryType.EntryList, new IDList()); + //EntryTypeRegistry.Register(EntryType.AptData, new AptData()); + EntryTypeRegistry.Register(EntryType.InstanceList, new InstanceList()); + EntryTypeRegistry.Register(EntryType.TrafficData, new Traffic()); + EntryTypeRegistry.Register(EntryType.TriggerData, new TriggerData()); + EntryTypeRegistry.Register(EntryType.GraphicsSpec, new GraphicsSpec()); + EntryTypeRegistry.Register(EntryType.ProgressionData, new ProgressionData()); + EntryTypeRegistry.Register(EntryType.StreetData, new StreetData()); + EntryTypeRegistry.Register(EntryType.FlaptFile, new FlaptFile()); } } diff --git a/BaseHandlers/FlaptFile.cs b/BaseHandlers/FlaptFile.cs index d6b712d..3ba6941 100644 --- a/BaseHandlers/FlaptFile.cs +++ b/BaseHandlers/FlaptFile.cs @@ -4,449 +4,448 @@ using BundleUtilities; using PluginAPI; -namespace BaseHandlers +namespace BaseHandlers; + +public struct FlaptSection1Entry { - public struct FlaptSection1Entry - { - public byte Unknown00; - public byte Unknown01; - public byte Unknown02; - public byte Unknown03; - public byte Unknown04; - public byte Unknown05; - public byte Unknown06; - public byte Unknown07; - public short List1Count; - public short Unknown0A; - public int Unknown0C; // 0? - - public uint List1Offset; - public List List1; - public uint Unknown14; - public uint Unknown18; - public uint Unknown1C; - public uint Unknown20; - public uint Unknown24; - public uint Unknown28; - public uint Unknown2C; - public uint Unknown30; - public uint Unknown34; - public uint Unknown38; - public uint Unknown3C; - - public uint NameOffset; - public string Name; - - public override string ToString() => $"Name: {Name}"; - } + public byte Unknown00; + public byte Unknown01; + public byte Unknown02; + public byte Unknown03; + public byte Unknown04; + public byte Unknown05; + public byte Unknown06; + public byte Unknown07; + public short List1Count; + public short Unknown0A; + public int Unknown0C; // 0? + + public uint List1Offset; + public List List1; + public uint Unknown14; + public uint Unknown18; + public uint Unknown1C; + public uint Unknown20; + public uint Unknown24; + public uint Unknown28; + public uint Unknown2C; + public uint Unknown30; + public uint Unknown34; + public uint Unknown38; + public uint Unknown3C; + + public uint NameOffset; + public string Name; + + public override string ToString() => $"Name: {Name}"; +} - public struct GeometryVertex - { - public float X; - public float Y; - public U8Colour Colour; - public float U; - public float V; - } +public struct GeometryVertex +{ + public float X; + public float Y; + public U8Colour Colour; + public float U; + public float V; +} - // Text or font thing - public struct TextStyle - { - public uint FontNameOffset; - public string FontName; - public U8Colour Colour; - public float TextHeight; +// Text or font thing +public struct TextStyle +{ + public uint FontNameOffset; + public string FontName; + public U8Colour Colour; + public float TextHeight; - public override string ToString() => $"Font: {FontName}; Colour: {Colour}; Text height: {TextHeight}"; - } + public override string ToString() => $"Font: {FontName}; Colour: {Colour}; Text height: {TextHeight}"; +} - public struct FlaptSection5Entry - { - public uint Hash; - public uint CharacterNameOffset; - public string CharacterName; +public struct FlaptSection5Entry +{ + public uint Hash; + public uint CharacterNameOffset; + public string CharacterName; - public override string ToString() => $"Hash: 0x{Hash:X}; Character name: {CharacterName}"; - } + public override string ToString() => $"Hash: 0x{Hash:X}; Character name: {CharacterName}"; +} + +public struct FlaptEventBinding +{ + public uint CharacterNameOffset; + public string CharacterName; + public uint EventNameOffset; + public string EventName; + public uint ActionNameOffset; + public string ActionName; + public int UnusedInt; // 0? + + public override string ToString() => $"Character: {CharacterName}; Event: {EventName}; Action: {ActionName}"; +} - public struct FlaptEventBinding +public struct StringPointer +{ + public uint StringOffset; + public string String; + + public override string ToString() => String; +} + +public class FlaptFile : IEntryData +{ + public uint FileSize; + public float SecondsPerFrame; // 1/30 + public int Section1RecordCount; + public uint Section1Offset; + public int ImageIDCount; + public uint ImageIDListOffset; + public int GeometryVerticesCount; + public uint GeometryVerticesOffset; + public int TextStyleCount; + public uint TextStyleListOffset; + public int Section5And6RecordCount; + public uint Section5Offset; + public uint Section6Offset; + public int EventBindsCount; + public uint EventBindsOffset; + public int TextStringsCount; + public uint TextStringsOffset; + public int DependencyRefStringsCount; + public uint DependencyRefStringsOffset; + public int CharacterRefStringsCount; + public uint CharacterRefStringsOffset; + + public List Section1Entries; + public List ImageIDs; + public List GeometryVertices; + public List TextStyleEntries; + public List Section5Entries; + public List Section6Entries; + public List EventBinds; + public List TextStrings; + public List DependencyRefStrings; + public List CharacterRefStrings; + + public FlaptFile() { - public uint CharacterNameOffset; - public string CharacterName; - public uint EventNameOffset; - public string EventName; - public uint ActionNameOffset; - public string ActionName; - public int UnusedInt; // 0? - - public override string ToString() => $"Character: {CharacterName}; Event: {EventName}; Action: {ActionName}"; + Section1Entries = []; + ImageIDs = []; + GeometryVertices = []; + TextStyleEntries = []; + Section5Entries = []; + Section6Entries = []; + EventBinds = []; + TextStrings = []; + DependencyRefStrings = []; + CharacterRefStrings = []; } - public struct StringPointer + private void Clear() { - public uint StringOffset; - public string String; - - public override string ToString() => String; + FileSize = default; + SecondsPerFrame = default; + Section1RecordCount = default; + Section1Offset = default; + ImageIDCount = default; + ImageIDListOffset = default; + GeometryVerticesCount = default; + GeometryVerticesOffset = default; + TextStyleCount = default; + TextStyleListOffset = default; + Section5And6RecordCount = default; + Section5Offset = default; + Section6Offset = default; + EventBindsCount = default; + EventBindsOffset = default; + TextStringsCount = default; + TextStringsOffset = default; + DependencyRefStringsCount = default; + DependencyRefStringsOffset = default; + CharacterRefStringsCount = default; + CharacterRefStringsOffset = default; + + Section1Entries.Clear(); + ImageIDs.Clear(); + GeometryVertices.Clear(); + TextStyleEntries.Clear(); + Section5Entries.Clear(); + Section6Entries.Clear(); + EventBinds.Clear(); + TextStrings.Clear(); + DependencyRefStrings.Clear(); + CharacterRefStrings.Clear(); } - public class FlaptFile : IEntryData + public bool Read(BundleEntry entry, ILoader loader = null) { - public uint FileSize; - public float SecondsPerFrame; // 1/30 - public int Section1RecordCount; - public uint Section1Offset; - public int ImageIDCount; - public uint ImageIDListOffset; - public int GeometryVerticesCount; - public uint GeometryVerticesOffset; - public int TextStyleCount; - public uint TextStyleListOffset; - public int Section5And6RecordCount; - public uint Section5Offset; - public uint Section6Offset; - public int EventBindsCount; - public uint EventBindsOffset; - public int TextStringsCount; - public uint TextStringsOffset; - public int DependencyRefStringsCount; - public uint DependencyRefStringsOffset; - public int CharacterRefStringsCount; - public uint CharacterRefStringsOffset; - - public List Section1Entries; - public List ImageIDs; - public List GeometryVertices; - public List TextStyleEntries; - public List Section5Entries; - public List Section6Entries; - public List EventBinds; - public List TextStrings; - public List DependencyRefStrings; - public List CharacterRefStrings; - - public FlaptFile() - { - Section1Entries = new List(); - ImageIDs = new List(); - GeometryVertices = new List(); - TextStyleEntries = new List(); - Section5Entries = new List(); - Section6Entries = new List(); - EventBinds = new List(); - TextStrings = new List(); - DependencyRefStrings = new List(); - CharacterRefStrings = new List(); - } + Clear(); + + MemoryStream ms = entry.MakeStream(); + BinaryReader2 br = new(ms); + br.BigEndian = entry.Console; - private void Clear() + bool x64 = entry.Platform == BundlePlatform.PCx64; + uint ReadPtr() { - FileSize = default; - SecondsPerFrame = default; - Section1RecordCount = default; - Section1Offset = default; - ImageIDCount = default; - ImageIDListOffset = default; - GeometryVerticesCount = default; - GeometryVerticesOffset = default; - TextStyleCount = default; - TextStyleListOffset = default; - Section5And6RecordCount = default; - Section5Offset = default; - Section6Offset = default; - EventBindsCount = default; - EventBindsOffset = default; - TextStringsCount = default; - TextStringsOffset = default; - DependencyRefStringsCount = default; - DependencyRefStringsOffset = default; - CharacterRefStringsCount = default; - CharacterRefStringsOffset = default; - - Section1Entries.Clear(); - ImageIDs.Clear(); - GeometryVertices.Clear(); - TextStyleEntries.Clear(); - Section5Entries.Clear(); - Section6Entries.Clear(); - EventBinds.Clear(); - TextStrings.Clear(); - DependencyRefStrings.Clear(); - CharacterRefStrings.Clear(); + if (!x64) + return br.ReadUInt32(); + br.BaseStream.Position = (br.BaseStream.Position + 7) & ~7; + return (uint)br.ReadUInt64(); } - public bool Read(BundleEntry entry, ILoader loader = null) + br.BaseStream.Position += 4; // magic or something: 0C B0 B0 B0 + FileSize = br.ReadUInt32(); + SecondsPerFrame = br.ReadSingle(); + Section1RecordCount = br.ReadInt32(); + Section1Offset = ReadPtr(); + ImageIDCount = br.ReadInt32(); + ImageIDListOffset = ReadPtr(); + GeometryVerticesCount = br.ReadInt32(); + GeometryVerticesOffset = ReadPtr(); + TextStyleCount = br.ReadInt32(); + TextStyleListOffset = ReadPtr(); + Section5And6RecordCount = br.ReadInt32(); + Section5Offset = ReadPtr(); + Section6Offset = ReadPtr(); + EventBindsCount = br.ReadInt32(); + EventBindsOffset = ReadPtr(); + TextStringsCount = br.ReadInt32(); + TextStringsOffset = ReadPtr(); + DependencyRefStringsCount = br.ReadInt32(); + DependencyRefStringsOffset = ReadPtr(); + CharacterRefStringsCount = br.ReadInt32(); + CharacterRefStringsOffset = ReadPtr(); + + + br.BaseStream.Position = Section1Offset; + for (int i = 0; i < Section1RecordCount; i++) { - Clear(); - - MemoryStream ms = entry.MakeStream(); - BinaryReader2 br = new BinaryReader2(ms); - br.BigEndian = entry.Console; - - bool x64 = entry.Platform == BundlePlatform.PCx64; - uint ReadPtr() + FlaptSection1Entry section1Entry = new(); + + section1Entry.Unknown00 = br.ReadByte(); + section1Entry.Unknown01 = br.ReadByte(); + section1Entry.Unknown02 = br.ReadByte(); + section1Entry.Unknown03 = br.ReadByte(); + section1Entry.Unknown04 = br.ReadByte(); + section1Entry.Unknown05 = br.ReadByte(); + section1Entry.Unknown06 = br.ReadByte(); + section1Entry.Unknown07 = br.ReadByte(); + section1Entry.List1Count = br.ReadInt16(); + section1Entry.Unknown0A = br.ReadInt16(); + section1Entry.Unknown0C = (int)ReadPtr(); // File pointer, 0 on disk + + section1Entry.List1Offset = ReadPtr(); + section1Entry.Unknown14 = ReadPtr(); + section1Entry.Unknown18 = ReadPtr(); + section1Entry.Unknown1C = ReadPtr(); + section1Entry.Unknown20 = ReadPtr(); + section1Entry.Unknown24 = ReadPtr(); + section1Entry.Unknown28 = ReadPtr(); + section1Entry.Unknown2C = ReadPtr(); + section1Entry.Unknown30 = ReadPtr(); + section1Entry.Unknown34 = ReadPtr(); + section1Entry.Unknown38 = ReadPtr(); + section1Entry.Unknown3C = ReadPtr(); + + section1Entry.NameOffset = ReadPtr(); + + + long oldPos = br.BaseStream.Position; + + if (section1Entry.List1Offset != 0) { - if (!x64) - return br.ReadUInt32(); - br.BaseStream.Position = (br.BaseStream.Position + 7) & ~7; - return (uint)br.ReadUInt64(); + br.BaseStream.Position = section1Entry.List1Offset; + section1Entry.List1 = new List(section1Entry.List1Count); + for (int j = 0; j < section1Entry.List1Count; j++) + { + section1Entry.List1.Add(br.ReadInt16()); + } } - br.BaseStream.Position += 4; // magic or something: 0C B0 B0 B0 - FileSize = br.ReadUInt32(); - SecondsPerFrame = br.ReadSingle(); - Section1RecordCount = br.ReadInt32(); - Section1Offset = ReadPtr(); - ImageIDCount = br.ReadInt32(); - ImageIDListOffset = ReadPtr(); - GeometryVerticesCount = br.ReadInt32(); - GeometryVerticesOffset = ReadPtr(); - TextStyleCount = br.ReadInt32(); - TextStyleListOffset = ReadPtr(); - Section5And6RecordCount = br.ReadInt32(); - Section5Offset = ReadPtr(); - Section6Offset = ReadPtr(); - EventBindsCount = br.ReadInt32(); - EventBindsOffset = ReadPtr(); - TextStringsCount = br.ReadInt32(); - TextStringsOffset = ReadPtr(); - DependencyRefStringsCount = br.ReadInt32(); - DependencyRefStringsOffset = ReadPtr(); - CharacterRefStringsCount = br.ReadInt32(); - CharacterRefStringsOffset = ReadPtr(); - - - br.BaseStream.Position = Section1Offset; - for (int i = 0; i < Section1RecordCount; i++) + if (section1Entry.NameOffset != 0) { - FlaptSection1Entry section1Entry = new FlaptSection1Entry(); - - section1Entry.Unknown00 = br.ReadByte(); - section1Entry.Unknown01 = br.ReadByte(); - section1Entry.Unknown02 = br.ReadByte(); - section1Entry.Unknown03 = br.ReadByte(); - section1Entry.Unknown04 = br.ReadByte(); - section1Entry.Unknown05 = br.ReadByte(); - section1Entry.Unknown06 = br.ReadByte(); - section1Entry.Unknown07 = br.ReadByte(); - section1Entry.List1Count = br.ReadInt16(); - section1Entry.Unknown0A = br.ReadInt16(); - section1Entry.Unknown0C = (int)ReadPtr(); // File pointer, 0 on disk - - section1Entry.List1Offset = ReadPtr(); - section1Entry.Unknown14 = ReadPtr(); - section1Entry.Unknown18 = ReadPtr(); - section1Entry.Unknown1C = ReadPtr(); - section1Entry.Unknown20 = ReadPtr(); - section1Entry.Unknown24 = ReadPtr(); - section1Entry.Unknown28 = ReadPtr(); - section1Entry.Unknown2C = ReadPtr(); - section1Entry.Unknown30 = ReadPtr(); - section1Entry.Unknown34 = ReadPtr(); - section1Entry.Unknown38 = ReadPtr(); - section1Entry.Unknown3C = ReadPtr(); - - section1Entry.NameOffset = ReadPtr(); - - - long oldPos = br.BaseStream.Position; - - if (section1Entry.List1Offset != 0) - { - br.BaseStream.Position = section1Entry.List1Offset; - section1Entry.List1 = new List(section1Entry.List1Count); - for (int j = 0; j < section1Entry.List1Count; j++) - { - section1Entry.List1.Add(br.ReadInt16()); - } - } + br.BaseStream.Position = section1Entry.NameOffset; + section1Entry.Name = br.ReadCStr(); + } - if (section1Entry.NameOffset != 0) - { - br.BaseStream.Position = section1Entry.NameOffset; - section1Entry.Name = br.ReadCStr(); - } + br.BaseStream.Position = oldPos; - br.BaseStream.Position = oldPos; + Section1Entries.Add(section1Entry); + } - Section1Entries.Add(section1Entry); - } + br.BaseStream.Position = ImageIDListOffset; + for (int i = 0; i < ImageIDCount; i++) + { + ImageIDs.Add(br.ReadSByte()); + br.BaseStream.Position += x64 ? 7 : 3; // Weird padding? + } - br.BaseStream.Position = ImageIDListOffset; - for (int i = 0; i < ImageIDCount; i++) - { - ImageIDs.Add(br.ReadSByte()); - br.BaseStream.Position += x64 ? 7 : 3; // Weird padding? - } + br.BaseStream.Position = GeometryVerticesOffset; + for (int i = 0; i < GeometryVerticesCount; i++) + { + GeometryVertex vertex = new(); - br.BaseStream.Position = GeometryVerticesOffset; - for (int i = 0; i < GeometryVerticesCount; i++) - { - GeometryVertex vertex = new GeometryVertex(); + vertex.X = br.ReadSingle(); + vertex.Y = br.ReadSingle(); + vertex.Colour = U8Colour.FromARGB32(br.ReadUInt32()); + vertex.U = br.ReadSingle(); + vertex.V = br.ReadSingle(); - vertex.X = br.ReadSingle(); - vertex.Y = br.ReadSingle(); - vertex.Colour = U8Colour.FromARGB32(br.ReadUInt32()); - vertex.U = br.ReadSingle(); - vertex.V = br.ReadSingle(); + GeometryVertices.Add(vertex); + } - GeometryVertices.Add(vertex); - } + br.BaseStream.Position = TextStyleListOffset; + for (int i = 0; i < TextStyleCount; i++) + { + TextStyle textStyle = new(); - br.BaseStream.Position = TextStyleListOffset; - for (int i = 0; i < TextStyleCount; i++) - { - TextStyle textStyle = new TextStyle(); + textStyle.FontNameOffset = ReadPtr(); - textStyle.FontNameOffset = ReadPtr(); + long oldPos = br.BaseStream.Position; + br.BaseStream.Position = textStyle.FontNameOffset; + textStyle.FontName = br.ReadCStr(); + br.BaseStream.Position = oldPos; - long oldPos = br.BaseStream.Position; - br.BaseStream.Position = textStyle.FontNameOffset; - textStyle.FontName = br.ReadCStr(); - br.BaseStream.Position = oldPos; + textStyle.Colour = U8Colour.FromARGB32(br.ReadUInt32()); + textStyle.TextHeight = br.ReadSingle(); - textStyle.Colour = U8Colour.FromARGB32(br.ReadUInt32()); - textStyle.TextHeight = br.ReadSingle(); + TextStyleEntries.Add(textStyle); + } - TextStyleEntries.Add(textStyle); - } + br.BaseStream.Position = Section5Offset; + for (int i = 0; i < Section5And6RecordCount; i++) + { + FlaptSection5Entry section5Entry = new(); - br.BaseStream.Position = Section5Offset; - for (int i = 0; i < Section5And6RecordCount; i++) - { - FlaptSection5Entry section5Entry = new FlaptSection5Entry(); + section5Entry.Hash = br.ReadUInt32(); + section5Entry.CharacterNameOffset = ReadPtr(); - section5Entry.Hash = br.ReadUInt32(); - section5Entry.CharacterNameOffset = ReadPtr(); + long oldPos = br.BaseStream.Position; + br.BaseStream.Position = section5Entry.CharacterNameOffset; + section5Entry.CharacterName = br.ReadCStr(); + br.BaseStream.Position = oldPos; - long oldPos = br.BaseStream.Position; - br.BaseStream.Position = section5Entry.CharacterNameOffset; - section5Entry.CharacterName = br.ReadCStr(); - br.BaseStream.Position = oldPos; + Section5Entries.Add(section5Entry); + } - Section5Entries.Add(section5Entry); - } + br.BaseStream.Position = Section6Offset; + for (int i = 0; i < Section5And6RecordCount; i++) + { + byte[] bytes = new byte[33]; - br.BaseStream.Position = Section6Offset; - for (int i = 0; i < Section5And6RecordCount; i++) + for (int j = 0; j < 33; j++) { - byte[] bytes = new byte[33]; - - for (int j = 0; j < 33; j++) - { - bytes[j] = br.ReadByte(); - } - - Section6Entries.Add(bytes); + bytes[j] = br.ReadByte(); } + Section6Entries.Add(bytes); + } - br.BaseStream.Position = EventBindsOffset; - for (int i = 0; i < EventBindsCount; i++) - { - FlaptEventBinding eventBinding = new FlaptEventBinding(); - - eventBinding.CharacterNameOffset = ReadPtr(); - eventBinding.EventNameOffset = ReadPtr(); - eventBinding.ActionNameOffset = ReadPtr(); - eventBinding.UnusedInt = (int)ReadPtr(); - long oldPos = br.BaseStream.Position; + br.BaseStream.Position = EventBindsOffset; + for (int i = 0; i < EventBindsCount; i++) + { + FlaptEventBinding eventBinding = new(); - br.BaseStream.Position = eventBinding.CharacterNameOffset; - eventBinding.CharacterName = br.ReadCStr(); + eventBinding.CharacterNameOffset = ReadPtr(); + eventBinding.EventNameOffset = ReadPtr(); + eventBinding.ActionNameOffset = ReadPtr(); + eventBinding.UnusedInt = (int)ReadPtr(); - if (eventBinding.EventNameOffset != 0) - { - br.BaseStream.Position = eventBinding.EventNameOffset; - eventBinding.EventName = br.ReadCStr(); - } + long oldPos = br.BaseStream.Position; - if (eventBinding.ActionNameOffset != 0) - { - br.BaseStream.Position = eventBinding.ActionNameOffset; - eventBinding.ActionName = br.ReadCStr(); - } + br.BaseStream.Position = eventBinding.CharacterNameOffset; + eventBinding.CharacterName = br.ReadCStr(); - br.BaseStream.Position = oldPos; - - EventBinds.Add(eventBinding); + if (eventBinding.EventNameOffset != 0) + { + br.BaseStream.Position = eventBinding.EventNameOffset; + eventBinding.EventName = br.ReadCStr(); } - - br.BaseStream.Position = TextStringsOffset; - for (int i = 0; i < TextStringsCount; i++) + if (eventBinding.ActionNameOffset != 0) { - StringPointer textString = new StringPointer(); + br.BaseStream.Position = eventBinding.ActionNameOffset; + eventBinding.ActionName = br.ReadCStr(); + } - textString.StringOffset = ReadPtr(); + br.BaseStream.Position = oldPos; + + EventBinds.Add(eventBinding); + } - long oldPos = br.BaseStream.Position; - br.BaseStream.Position = textString.StringOffset; - textString.String = br.ReadCStr(); - br.BaseStream.Position = oldPos; - TextStrings.Add(textString); - } + br.BaseStream.Position = TextStringsOffset; + for (int i = 0; i < TextStringsCount; i++) + { + StringPointer textString = new(); + textString.StringOffset = ReadPtr(); - br.BaseStream.Position = DependencyRefStringsOffset; - for (int i = 0; i < DependencyRefStringsCount; i++) - { - StringPointer dependencyRefString = new StringPointer(); + long oldPos = br.BaseStream.Position; + br.BaseStream.Position = textString.StringOffset; + textString.String = br.ReadCStr(); + br.BaseStream.Position = oldPos; - dependencyRefString.StringOffset = ReadPtr(); + TextStrings.Add(textString); + } - long oldPos = br.BaseStream.Position; - br.BaseStream.Position = dependencyRefString.StringOffset; - dependencyRefString.String = br.ReadCStr(); - br.BaseStream.Position = oldPos; - DependencyRefStrings.Add(dependencyRefString); - } + br.BaseStream.Position = DependencyRefStringsOffset; + for (int i = 0; i < DependencyRefStringsCount; i++) + { + StringPointer dependencyRefString = new(); + dependencyRefString.StringOffset = ReadPtr(); - br.BaseStream.Position = CharacterRefStringsOffset; - for (int i = 0; i < CharacterRefStringsCount; i++) - { - StringPointer characterRefString = new StringPointer(); + long oldPos = br.BaseStream.Position; + br.BaseStream.Position = dependencyRefString.StringOffset; + dependencyRefString.String = br.ReadCStr(); + br.BaseStream.Position = oldPos; - characterRefString.StringOffset = ReadPtr(); + DependencyRefStrings.Add(dependencyRefString); + } - long oldPos = br.BaseStream.Position; - br.BaseStream.Position = characterRefString.StringOffset; - characterRefString.String = br.ReadCStr(); - br.BaseStream.Position = oldPos; - CharacterRefStrings.Add(characterRefString); - } + br.BaseStream.Position = CharacterRefStringsOffset; + for (int i = 0; i < CharacterRefStringsCount; i++) + { + StringPointer characterRefString = new(); + characterRefString.StringOffset = ReadPtr(); - br.Close(); - ms.Close(); + long oldPos = br.BaseStream.Position; + br.BaseStream.Position = characterRefString.StringOffset; + characterRefString.String = br.ReadCStr(); + br.BaseStream.Position = oldPos; - return true; + CharacterRefStrings.Add(characterRefString); } - public bool Write(BundleEntry entry) - { - // TODO - return true; - } - public EntryType GetEntryType(BundleEntry entry) - { - return EntryType.FlaptFile; - } + br.Close(); + ms.Close(); - public IEntryEditor GetEditor(BundleEntry entry) - { - return null; - } + return true; + } + + public bool Write(BundleEntry entry) + { + // TODO + return true; + } + + public EntryType GetEntryType(BundleEntry entry) + { + return EntryType.FlaptFile; + } + + public IEntryEditor GetEditor(BundleEntry entry) + { + return null; } } diff --git a/BaseHandlers/GraphicsSpec.cs b/BaseHandlers/GraphicsSpec.cs index 9aa1660..642f9e1 100644 --- a/BaseHandlers/GraphicsSpec.cs +++ b/BaseHandlers/GraphicsSpec.cs @@ -5,103 +5,102 @@ using ModelViewer.SceneData; using PluginAPI; -namespace BaseHandlers +namespace BaseHandlers; + +public class GraphicsSpec : IEntryData { - public class GraphicsSpec : IEntryData - { - private Scene _scene; + private Scene _scene; - public BundleEntry Entry; + public BundleEntry Entry; - public int Unknown1; - public List Instances; - public int Unknown2; - public int Unknown3; + public int Unknown1; + public List Instances; + public int Unknown2; + public int Unknown3; - public GraphicsSpec() - { - Instances = new List(); - } + public GraphicsSpec() + { + Instances = []; + } - private void Clear() - { - _scene = null; + private void Clear() + { + _scene = null; - Entry = default; + Entry = default; - Unknown1 = default; - Unknown2 = default; - Unknown3 = default; + Unknown1 = default; + Unknown2 = default; + Unknown3 = default; - Instances.Clear(); - } + Instances.Clear(); + } - public bool Read(BundleEntry entry, ILoader loader) - { - Clear(); + public bool Read(BundleEntry entry, ILoader loader) + { + Clear(); - Entry = entry; + Entry = entry; - // TODO: Process Data + // TODO: Process Data - for (int i = 0; i < entry.GetDependencies().Count; i++) - { - Instances.Add(entry.GetDependencies()[i].EntryID); - } + for (int i = 0; i < entry.GetDependencies().Count; i++) + { + Instances.Add(entry.GetDependencies()[i].EntryID); + } - _scene = MakeScene(loader); + _scene = MakeScene(loader); - return true; - } + return true; + } - public bool Write(BundleEntry entry) - { - return true; - } + public bool Write(BundleEntry entry) + { + return true; + } - public EntryType GetEntryType(BundleEntry entry) - { - return EntryType.GraphicsSpec; - } + public EntryType GetEntryType(BundleEntry entry) + { + return EntryType.GraphicsSpec; + } - public IEntryEditor GetEditor(BundleEntry entry) - { - ModelViewerForm viewer = new ModelViewerForm(); - viewer.Renderer.Scene = _scene; + public IEntryEditor GetEditor(BundleEntry entry) + { + ModelViewerForm viewer = new(); + viewer.Renderer.Scene = _scene; - return viewer; - } + return viewer; + } - public Scene MakeScene(ILoader loader) - { - Scene scene = new Scene(); + public Scene MakeScene(ILoader loader) + { + Scene scene = new(); - foreach (uint instance in Instances) + foreach (uint instance in Instances) + { + BundleEntry modelEntry = Entry.Archive.GetEntryByID(instance); + if (modelEntry == null) { - BundleEntry modelEntry = Entry.Archive.GetEntryByID(instance); - if (modelEntry == null) + string file = BundleCache.GetFileByEntryID(instance); + if (!string.IsNullOrEmpty(file)) { - string file = BundleCache.GetFileByEntryID(instance); - if (!string.IsNullOrEmpty(file)) - { - BundleArchive archive = BundleArchive.Read(file); - modelEntry = archive.GetEntryByID(instance); - } + BundleArchive archive = BundleArchive.Read(file); + modelEntry = archive.GetEntryByID(instance); } + } - if (modelEntry != null) - { - BundleEntry renderableEntry = modelEntry.GetDependencies()[0].Entry; - Renderable renderable = new Renderable(); - renderable.Read(renderableEntry, null); // TODO: Null Loader - SceneObject sceneObject = new SceneObject(instance.ToString("X8"), renderable.Model); - //sceneObject.Transform = instance.Transform; + if (modelEntry != null) + { + BundleEntry renderableEntry = modelEntry.GetDependencies()[0].Entry; + Renderable renderable = new(); + renderable.Read(renderableEntry, null); // TODO: Null Loader + SceneObject sceneObject = new(instance.ToString("X8"), renderable.Model); + //sceneObject.Transform = instance.Transform; - scene.AddObject(sceneObject); - } + scene.AddObject(sceneObject); } - - return scene; } + + return scene; } } diff --git a/BaseHandlers/IDList.cs b/BaseHandlers/IDList.cs index 139b247..3ea9f9b 100644 --- a/BaseHandlers/IDList.cs +++ b/BaseHandlers/IDList.cs @@ -3,91 +3,90 @@ using BundleUtilities; using PluginAPI; -namespace BaseHandlers +namespace BaseHandlers; + +public class IDList : IEntryData { - public class IDList : IEntryData + public int ReferenceEntryIDOffset; + public int Unknown2; // Might be a count of some sort + public int Unknown3; + public int Unknown4; + public ulong ReferenceEntryID; + public int Unknown6; + public int Unknown7; + + public IDList() + { + + } + + public IEntryEditor GetEditor(BundleEntry entry) + { + return null; + } + + public EntryType GetEntryType(BundleEntry entry) + { + return EntryType.EntryList; + } + + private void Clear() + { + ReferenceEntryIDOffset = default; + Unknown2 = default; + Unknown3 = default; + Unknown4 = default; + ReferenceEntryID = default; + Unknown6 = default; + Unknown7 = default; + } + + public bool Read(BundleEntry entry, ILoader loader = null) { - public int ReferenceEntryIDOffset; - public int Unknown2; // Might be a count of some sort - public int Unknown3; - public int Unknown4; - public ulong ReferenceEntryID; - public int Unknown6; - public int Unknown7; - - public IDList() - { - - } - - public IEntryEditor GetEditor(BundleEntry entry) - { - return null; - } - - public EntryType GetEntryType(BundleEntry entry) - { - return EntryType.EntryList; - } - - private void Clear() - { - ReferenceEntryIDOffset = default; - Unknown2 = default; - Unknown3 = default; - Unknown4 = default; - ReferenceEntryID = default; - Unknown6 = default; - Unknown7 = default; - } - - public bool Read(BundleEntry entry, ILoader loader = null) - { - Clear(); - - MemoryStream ms = entry.MakeStream(); - BinaryReader2 br = new BinaryReader2(ms); - br.BigEndian = entry.Console; - - ReferenceEntryIDOffset = br.ReadInt32(); - Unknown2 = br.ReadInt32(); - Unknown3 = br.ReadInt32(); - Unknown4 = br.ReadInt32(); - ReferenceEntryID = br.ReadUInt64(); - Unknown6 = br.ReadInt32(); - Unknown7 = br.ReadInt32(); - - br.Close(); - ms.Close(); - - return true; - } - - public bool Write(BundleEntry entry) - { - MemoryStream ms = new MemoryStream(); - BinaryWriter2 bw = new BinaryWriter2(ms); - bw.BigEndian = entry.Console; - - bw.Write(ReferenceEntryIDOffset); - bw.Write(Unknown2); - bw.Write(Unknown3); - bw.Write(Unknown4); - bw.Write(ReferenceEntryID); - bw.Write(Unknown6); - bw.Write(Unknown7); - - bw.Flush(); - - byte[] data = ms.ToArray(); - - bw.Close(); - ms.Close(); - - entry.EntryBlocks[0].Data = data; - entry.Dirty = true; - - return true; - } + Clear(); + + MemoryStream ms = entry.MakeStream(); + BinaryReader2 br = new(ms); + br.BigEndian = entry.Console; + + ReferenceEntryIDOffset = br.ReadInt32(); + Unknown2 = br.ReadInt32(); + Unknown3 = br.ReadInt32(); + Unknown4 = br.ReadInt32(); + ReferenceEntryID = br.ReadUInt64(); + Unknown6 = br.ReadInt32(); + Unknown7 = br.ReadInt32(); + + br.Close(); + ms.Close(); + + return true; + } + + public bool Write(BundleEntry entry) + { + MemoryStream ms = new(); + BinaryWriter2 bw = new(ms); + bw.BigEndian = entry.Console; + + bw.Write(ReferenceEntryIDOffset); + bw.Write(Unknown2); + bw.Write(Unknown3); + bw.Write(Unknown4); + bw.Write(ReferenceEntryID); + bw.Write(Unknown6); + bw.Write(Unknown7); + + bw.Flush(); + + byte[] data = ms.ToArray(); + + bw.Close(); + ms.Close(); + + entry.EntryBlocks[0].Data = data; + entry.Dirty = true; + + return true; } } diff --git a/BaseHandlers/InstanceList.cs b/BaseHandlers/InstanceList.cs index 628c642..be51e16 100644 --- a/BaseHandlers/InstanceList.cs +++ b/BaseHandlers/InstanceList.cs @@ -7,235 +7,234 @@ using OpenTK.Mathematics; using PluginAPI; -namespace BaseHandlers +namespace BaseHandlers; + +public class ModelInstance { - public class ModelInstance - { - public ulong ModelEntryID; + public ulong ModelEntryID; - public int ModelEntryPtr; - public int Unknown2; - public int Unknown3; - public int Unknown4; - public Matrix4 Transform; + public int ModelEntryPtr; + public int Unknown2; + public int Unknown3; + public int Unknown4; + public Matrix4 Transform; - public Vector3 Translation => Transform.ExtractTranslation(); + public Vector3 Translation => Transform.ExtractTranslation(); - public Vector3 Scale => Transform.ExtractScale(); + public Vector3 Scale => Transform.ExtractScale(); - public Vector4 Rotation => Transform.ExtractRotation().ToAxisAngle(); + public Vector4 Rotation => Transform.ExtractRotation().ToAxisAngle(); - public static ModelInstance Read(BinaryReader2 br) - { - ModelInstance result = new ModelInstance(); + public static ModelInstance Read(BinaryReader2 br) + { + ModelInstance result = new(); - result.ModelEntryPtr = br.ReadInt32(); - result.Unknown2 = br.ReadInt32(); - result.Unknown3 = br.ReadInt32(); - result.Unknown4 = br.ReadInt32(); - result.Transform = br.ReadMatrix4(); + result.ModelEntryPtr = br.ReadInt32(); + result.Unknown2 = br.ReadInt32(); + result.Unknown3 = br.ReadInt32(); + result.Unknown4 = br.ReadInt32(); + result.Transform = br.ReadMatrix4(); - return result; - } + return result; + } - public void Write(BinaryWriter2 bw) - { - bw.Write(ModelEntryPtr); - bw.Write(Unknown2); - bw.Write(Unknown3); - bw.Write(Unknown4); - bw.Write(Transform); - } + public void Write(BinaryWriter2 bw) + { + bw.Write(ModelEntryPtr); + bw.Write(Unknown2); + bw.Write(Unknown3); + bw.Write(Unknown4); + bw.Write(Transform); + } - public override string ToString() - { - return "Model ID: 0x" + ModelEntryID.ToString("X8") + ", Translation: (" + Translation + "), Scale: (" + Scale + "), Rotation: (" + Rotation + ")"; - } + public override string ToString() + { + return "Model ID: 0x" + ModelEntryID.ToString("X8") + ", Translation: (" + Translation + "), Scale: (" + Scale + "), Rotation: (" + Rotation + ")"; } +} + +public class InstanceList : IEntryData +{ + //private Scene _scene; + + public BundleEntry Entry; - public class InstanceList : IEntryData + public int Unknown1; + public List Instances; + public int Unknown2; + public int Unknown3; + + public byte[] RemainingBytes; + + public InstanceList() { - //private Scene _scene; + Instances = []; + } - public BundleEntry Entry; + private void Clear() + { + //_scene = null; - public int Unknown1; - public List Instances; - public int Unknown2; - public int Unknown3; + Entry = default; + Unknown1 = default; + Unknown2 = default; + Unknown3 = default; - public byte[] RemainingBytes; + Instances.Clear(); + } - public InstanceList() - { - Instances = new List(); - } + public bool Read(BundleEntry entry, ILoader loader = null) + { + Clear(); - private void Clear() - { - //_scene = null; + Entry = entry; - Entry = default; - Unknown1 = default; - Unknown2 = default; - Unknown3 = default; + MemoryStream ms = entry.MakeStream(); + BinaryReader2 br = new(ms); + br.BigEndian = entry.Console; - Instances.Clear(); - } + Unknown1 = br.ReadInt32(); + int instanceCount = br.ReadInt32(); + Unknown2 = br.ReadInt32(); + Unknown3 = br.ReadInt32(); - public bool Read(BundleEntry entry, ILoader loader = null) + for (int i = 0; i < instanceCount; i++) { - Clear(); + ModelInstance instance = ModelInstance.Read(br); - Entry = entry; + instance.ModelEntryID = entry.GetDependencies()[i].EntryID; - MemoryStream ms = entry.MakeStream(); - BinaryReader2 br = new BinaryReader2(ms); - br.BigEndian = entry.Console; + Instances.Add(instance); + } - Unknown1 = br.ReadInt32(); - int instanceCount = br.ReadInt32(); - Unknown2 = br.ReadInt32(); - Unknown3 = br.ReadInt32(); + RemainingBytes = br.ReadBytes((int)(br.BaseStream.Length - br.BaseStream.Position)); - for (int i = 0; i < instanceCount; i++) - { - ModelInstance instance = ModelInstance.Read(br); + br.Close(); + ms.Close(); - instance.ModelEntryID = entry.GetDependencies()[i].EntryID; + //_scene = MakeScene(loader); - Instances.Add(instance); - } + return true; + } - RemainingBytes = br.ReadBytes((int)(br.BaseStream.Length - br.BaseStream.Position)); + public bool Write(BundleEntry entry) + { + MemoryStream ms = new(); + BinaryWriter2 bw = new(ms); + bw.BigEndian = entry.Console; - br.Close(); - ms.Close(); + bw.Write(Unknown1); + bw.Write(Instances.Count); + bw.Write(Unknown2); + bw.Write(Unknown3); - //_scene = MakeScene(loader); + for (int i = 0; i < Instances.Count; i++) + { + ModelInstance instance = Instances[i]; - return true; + instance.Write(bw); } - public bool Write(BundleEntry entry) - { - MemoryStream ms = new MemoryStream(); - BinaryWriter2 bw = new BinaryWriter2(ms); - bw.BigEndian = entry.Console; - - bw.Write(Unknown1); - bw.Write(Instances.Count); - bw.Write(Unknown2); - bw.Write(Unknown3); + bw.Write(RemainingBytes); - for (int i = 0; i < Instances.Count; i++) - { - ModelInstance instance = Instances[i]; + bw.Flush(); + byte[] data = ms.GetBuffer(); + bw.Close(); + ms.Close(); - instance.Write(bw); - } + entry.EntryBlocks[0].Data = data; + entry.Dirty = true; - bw.Write(RemainingBytes); + return true; + } - bw.Flush(); - byte[] data = ms.GetBuffer(); - bw.Close(); - ms.Close(); + public Scene MakeScene(ILoader loader = null) + { + //TextureState.ResetCache(); - entry.EntryBlocks[0].Data = data; - entry.Dirty = true; + Scene scene = new(); - return true; - } + Dictionary models = []; - public Scene MakeScene(ILoader loader = null) + int i = 0; + int index = 1; + foreach (ModelInstance instance in Instances) { - //TextureState.ResetCache(); + int progress = (index - 1) * 100 / Instances.Count; + loader?.SetProgress(progress); - Scene scene = new Scene(); + loader?.SetStatus("Loading(" + progress.ToString("D2") + "%): ModelInstance: " + index + "/" + Instances.Count); + //DebugTimer t = DebugTimer.Start("ModelInstance[" + index + "/" + Instances.Count + "]"); + index++; - Dictionary models = new Dictionary(); + if (!InRange(instance)) + continue; - int i = 0; - int index = 1; - foreach (ModelInstance instance in Instances) + if (models.ContainsKey(instance.ModelEntryID)) { - int progress = (index - 1) * 100 / Instances.Count; - loader?.SetProgress(progress); - - loader?.SetStatus("Loading(" + progress.ToString("D2") + "%): ModelInstance: " + index + "/" + Instances.Count); - //DebugTimer t = DebugTimer.Start("ModelInstance[" + index + "/" + Instances.Count + "]"); - index++; + Renderable renderable = models[instance.ModelEntryID]; + SceneObject sceneObject = new(instance.ModelEntryID.ToString("X8"), renderable.Model); + sceneObject.ID = i.ToString(); + sceneObject.Transform = instance.Transform; - if (!InRange(instance)) - continue; + scene.AddObject(sceneObject); + } + else + { + BundleEntry modelEntry = Entry.Archive.GetEntryByID(instance.ModelEntryID); + if (modelEntry == null) + { + string file = BundleCache.GetFileByEntryID(instance.ModelEntryID); + if (!string.IsNullOrEmpty(file)) + { + BundleArchive archive = BundleArchive.Read(file); + modelEntry = archive.GetEntryByID(instance.ModelEntryID); + } + } - if (models.ContainsKey(instance.ModelEntryID)) + if (modelEntry != null) { - Renderable renderable = models[instance.ModelEntryID]; - SceneObject sceneObject = new SceneObject(instance.ModelEntryID.ToString("X8"), renderable.Model); + BundleEntry renderableEntry = modelEntry.GetDependencies()[0].Entry; + Renderable renderable = new(); + renderable.Read(renderableEntry, null); // TODO: Null Loader + models.Add(instance.ModelEntryID, renderable); + SceneObject sceneObject = + new(instance.ModelEntryID.ToString("X8"), renderable.Model); sceneObject.ID = i.ToString(); sceneObject.Transform = instance.Transform; scene.AddObject(sceneObject); } - else - { - BundleEntry modelEntry = Entry.Archive.GetEntryByID(instance.ModelEntryID); - if (modelEntry == null) - { - string file = BundleCache.GetFileByEntryID(instance.ModelEntryID); - if (!string.IsNullOrEmpty(file)) - { - BundleArchive archive = BundleArchive.Read(file); - modelEntry = archive.GetEntryByID(instance.ModelEntryID); - } - } - - if (modelEntry != null) - { - BundleEntry renderableEntry = modelEntry.GetDependencies()[0].Entry; - Renderable renderable = new Renderable(); - renderable.Read(renderableEntry, null); // TODO: Null Loader - models.Add(instance.ModelEntryID, renderable); - SceneObject sceneObject = - new SceneObject(instance.ModelEntryID.ToString("X8"), renderable.Model); - sceneObject.ID = i.ToString(); - sceneObject.Transform = instance.Transform; - - scene.AddObject(sceneObject); - } - } - i++; - //t.StopLog(); } - loader?.SetProgress(100); + i++; + //t.StopLog(); + } + loader?.SetProgress(100); - //TextureState.ResetCache(); + //TextureState.ResetCache(); - return scene; - } + return scene; + } - private bool InRange(ModelInstance instance) - { - return true; - } + private bool InRange(ModelInstance instance) + { + return true; + } - public EntryType GetEntryType(BundleEntry entry) - { - return EntryType.InstanceList; - } + public EntryType GetEntryType(BundleEntry entry) + { + return EntryType.InstanceList; + } - public IEntryEditor GetEditor(BundleEntry entry) + public IEntryEditor GetEditor(BundleEntry entry) + { + InstanceListEditor editor = new(); + editor.InstanceList = this; + editor.Changed += () => { - InstanceListEditor editor = new InstanceListEditor(); - editor.InstanceList = this; - editor.Changed += () => - { - Write(entry); - }; + Write(entry); + }; - return editor; - } + return editor; } } diff --git a/BaseHandlers/InstanceListEditor.cs b/BaseHandlers/InstanceListEditor.cs index d22aefe..396bec7 100644 --- a/BaseHandlers/InstanceListEditor.cs +++ b/BaseHandlers/InstanceListEditor.cs @@ -10,245 +10,244 @@ using System.Threading; using System.Windows.Forms; -namespace BaseHandlers +namespace BaseHandlers; + +public partial class InstanceListEditor : Form, IEntryEditor { - public partial class InstanceListEditor : Form, IEntryEditor - { - public delegate void OnChanged(); - public event OnChanged Changed; + public delegate void OnChanged(); + public event OnChanged Changed; - private InstanceList _instanceList; + private InstanceList _instanceList; - [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] - public InstanceList InstanceList + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public InstanceList InstanceList + { + get => _instanceList; + set { - get => _instanceList; - set - { - _instanceList = value; - UpdateDisplay(); - } + _instanceList = value; + UpdateDisplay(); } + } - private Dictionary _nameCache; + private Dictionary _nameCache; - public InstanceListEditor() - { - InitializeComponent(); + public InstanceListEditor() + { + InitializeComponent(); - _nameCache = new Dictionary(); - } + _nameCache = []; + } - private void UpdateDisplay() - { - lstMain.Items.Clear(); + private void UpdateDisplay() + { + lstMain.Items.Clear(); - if (InstanceList == null) - return; + if (InstanceList == null) + return; - for (int i = 0; i < InstanceList.Instances.Count; i++) - { - ModelInstance model = InstanceList.Instances[i]; + for (int i = 0; i < InstanceList.Instances.Count; i++) + { + ModelInstance model = InstanceList.Instances[i]; - string[] items = new string[] - { - GetModelName(model.ModelEntryID), - model.Translation.ToString(), - model.Rotation.ToString(), - model.Scale.ToString() - }; + string[] items = + [ + GetModelName(model.ModelEntryID), + model.Translation.ToString(), + model.Rotation.ToString(), + model.Scale.ToString() + ]; - lstMain.Items.Add(new ListViewItem(items)); - } + lstMain.Items.Add(new ListViewItem(items)); } + } - private void UpdateColumnWidth() - { - if (lstMain.Columns.Count <= 0) - return; + private void UpdateColumnWidth() + { + if (lstMain.Columns.Count <= 0) + return; - int totalColumnWidth = 0; - for (int i = 1; i < lstMain.Columns.Count; i++) - { - totalColumnWidth += lstMain.Columns[i].Width; - } + int totalColumnWidth = 0; + for (int i = 1; i < lstMain.Columns.Count; i++) + { + totalColumnWidth += lstMain.Columns[i].Width; + } - int remainingWidth = lstMain.Width - totalColumnWidth - 120; + int remainingWidth = lstMain.Width - totalColumnWidth - 120; - if (lstMain.Columns[0].Width != remainingWidth) - lstMain.Columns[0].Width = remainingWidth; - } + if (lstMain.Columns[0].Width != remainingWidth) + lstMain.Columns[0].Width = remainingWidth; + } - private string GetModelName(ulong id) - { - if (_nameCache.ContainsKey(id)) - return _nameCache[id]; + private string GetModelName(ulong id) + { + if (_nameCache.ContainsKey(id)) + return _nameCache[id]; - string result; + string result; - //BundleArchive archive = InstanceList.Entry.Archive; - //bool external = !archive.ContainsEntry(id); - //if (external) - result = BundleCache.GetEntryNameByID(id); - //else - // result = archive.GetEntryNameByID(id); + //BundleArchive archive = InstanceList.Entry.Archive; + //bool external = !archive.ContainsEntry(id); + //if (external) + result = BundleCache.GetEntryNameByID(id); + //else + // result = archive.GetEntryNameByID(id); - if (string.IsNullOrWhiteSpace(result)) - result = "0x" + id.ToString("X8"); - else - result = SimplifyModelName(result); + if (string.IsNullOrWhiteSpace(result)) + result = "0x" + id.ToString("X8"); + else + result = SimplifyModelName(result); - //if (external) - // result += " (External)"; + //if (external) + // result += " (External)"; - _nameCache.Add(id, result); - return result; - } + _nameCache.Add(id, result); + return result; + } - private string SimplifyModelName(string name) - { - string commonstring = "gamedb://burnout5/"; - if (name.StartsWith(commonstring)) - name = name.Substring(commonstring.Length); - - commonstring = "Burnout/Content_World/"; - if (name.StartsWith(commonstring)) - name = name.Substring(commonstring.Length); - - /*commonstring = "Scenes/"; - if (name.StartsWith(commonstring)) - name = name.Substring(commonstring.Length); - - commonstring = "Scenes_Final/"; - if (name.StartsWith(commonstring)) - name = name.Substring(commonstring.Length);*/ - - int qIndex = name.IndexOf("?"); - if (qIndex > -1) - name = name.Substring(0, qIndex); - return name; - } + private string SimplifyModelName(string name) + { + string commonstring = "gamedb://burnout5/"; + if (name.StartsWith(commonstring)) + name = name[commonstring.Length..]; + + commonstring = "Burnout/Content_World/"; + if (name.StartsWith(commonstring)) + name = name[commonstring.Length..]; + + /*commonstring = "Scenes/"; + if (name.StartsWith(commonstring)) + name = name.Substring(commonstring.Length); + + commonstring = "Scenes_Final/"; + if (name.StartsWith(commonstring)) + name = name.Substring(commonstring.Length);*/ + + int qIndex = name.IndexOf("?"); + if (qIndex > -1) + name = name[..qIndex]; + return name; + } - private void ViewSelectedModel() - { - if (lstMain.SelectedIndices.Count <= 0) - return; + private void ViewSelectedModel() + { + if (lstMain.SelectedIndices.Count <= 0) + return; - int selectedIndex = lstMain.SelectedIndices[0]; - ModelInstance model = InstanceList.Instances[selectedIndex]; + int selectedIndex = lstMain.SelectedIndices[0]; + ModelInstance model = InstanceList.Instances[selectedIndex]; - LoadingDialog loader = new LoadingDialog(); - BundleEntry renderableEntry = null; - Renderable renderable = null; + LoadingDialog loader = new(); + BundleEntry renderableEntry = null; + Renderable renderable = null; - Thread loadInstanceThread = null; - bool failure = false; + Thread loadInstanceThread = null; + bool failure = false; - loader.Done += (cancelled, value) => + loader.Done += (cancelled, value) => + { + if (cancelled) + loadInstanceThread?.Interrupt(); + else { - if (cancelled) - loadInstanceThread?.Interrupt(); - else + loader.Hide(); + if (!failure) { - loader.Hide(); - if (!failure) - { - IEntryEditor editor = renderable.GetEditor(renderableEntry); - editor.ShowDialog(this); - } + IEntryEditor editor = renderable.GetEditor(renderableEntry); + editor.ShowDialog(this); } - }; + } + }; - loadInstanceThread = new Thread(() => + loadInstanceThread = new Thread(() => + { + try { - try + BundleEntry modelEntry = InstanceList.Entry.Archive.GetEntryByID(model.ModelEntryID); + if (modelEntry == null) { - BundleEntry modelEntry = InstanceList.Entry.Archive.GetEntryByID(model.ModelEntryID); - if (modelEntry == null) + string file = BundleCache.GetFileByEntryID(model.ModelEntryID); + if (!string.IsNullOrEmpty(file)) { - string file = BundleCache.GetFileByEntryID(model.ModelEntryID); - if (!string.IsNullOrEmpty(file)) - { - BundleArchive archive = BundleArchive.Read(file); - modelEntry = archive.GetEntryByID(model.ModelEntryID); - } + BundleArchive archive = BundleArchive.Read(file); + modelEntry = archive.GetEntryByID(model.ModelEntryID); } - - if (modelEntry != null) - { - renderableEntry = modelEntry.GetDependencies()[0].Entry; - renderable = new Renderable(); - renderable.Read(renderableEntry, loader); - } - if (renderable == null) - failure = true; } - catch (Exception) + + if (modelEntry != null) { - failure = true; + renderableEntry = modelEntry.GetDependencies()[0].Entry; + renderable = new Renderable(); + renderable.Read(renderableEntry, loader); } - loader.IsDone = true; - }); - loadInstanceThread.Start(); - loader.ShowDialog(this); - } + if (renderable == null) + failure = true; + } + catch (Exception) + { + failure = true; + } + loader.IsDone = true; + }); + loadInstanceThread.Start(); + loader.ShowDialog(this); + } - private void InstanceListEditor_Load(object sender, EventArgs e) - { - UpdateColumnWidth(); - } + private void InstanceListEditor_Load(object sender, EventArgs e) + { + UpdateColumnWidth(); + } - private void RenderToolStripMenuItem_Click(object sender, EventArgs e) - { - LoadingDialog loader = new LoadingDialog(); - Scene scene = null; + private void RenderToolStripMenuItem_Click(object sender, EventArgs e) + { + LoadingDialog loader = new(); + Scene scene = null; - Thread loadInstanceThread = null; - bool failure = false; + Thread loadInstanceThread = null; + bool failure = false; - loader.Done += (cancelled, value) => + loader.Done += (cancelled, value) => + { + if (cancelled) + loadInstanceThread?.Interrupt(); + else { - if (cancelled) - loadInstanceThread?.Interrupt(); - else - { - loader.Hide(); - if (!failure) - ModelViewerForm.ShowModelViewer(this, scene); - } - }; + loader.Hide(); + if (!failure) + ModelViewerForm.ShowModelViewer(this, scene); + } + }; - loadInstanceThread = new Thread(() => + loadInstanceThread = new Thread(() => + { + try { - try - { - scene = InstanceList.MakeScene(loader); - if (scene == null) - failure = true; - } - catch (Exception) - { + scene = InstanceList.MakeScene(loader); + if (scene == null) failure = true; - } - loader.IsDone = true; - }); - loadInstanceThread.Start(); - loader.ShowDialog(this); - } + } + catch (Exception) + { + failure = true; + } + loader.IsDone = true; + }); + loadInstanceThread.Start(); + loader.ShowDialog(this); + } - private void DebugToolStripMenuItem_Click(object sender, EventArgs e) - { - DebugUtil.ShowDebug(this, InstanceList); - } + private void DebugToolStripMenuItem_Click(object sender, EventArgs e) + { + DebugUtil.ShowDebug(this, InstanceList); + } - private void LstMain_SizeChanged(object sender, EventArgs e) - { - UpdateColumnWidth(); - } + private void LstMain_SizeChanged(object sender, EventArgs e) + { + UpdateColumnWidth(); + } - private void LstMain_MouseDoubleClick(object sender, MouseEventArgs e) - { - ViewSelectedModel(); - } + private void LstMain_MouseDoubleClick(object sender, MouseEventArgs e) + { + ViewSelectedModel(); } } diff --git a/BaseHandlers/MaterialEntry.cs b/BaseHandlers/MaterialEntry.cs index 4c69f9f..b091bf8 100644 --- a/BaseHandlers/MaterialEntry.cs +++ b/BaseHandlers/MaterialEntry.cs @@ -4,73 +4,72 @@ using BundleFormat; using BundleUtilities; -namespace BaseHandlers +namespace BaseHandlers; + +public class MaterialEntry { - public class MaterialEntry - { - public List TextureStates; + public List TextureStates; - public Image DiffuseMap { get; set; } - public Image NormalMap { get; set; } - public Image SpecularMap { get; set; } - public Color Color { get; set; } + public Image DiffuseMap { get; set; } + public Image NormalMap { get; set; } + public Image SpecularMap { get; set; } + public Color Color { get; set; } - public MaterialEntry() - { - TextureStates = new List(); - } + public MaterialEntry() + { + TextureStates = []; + } - public static MaterialEntry Read(BundleEntry entry) + public static MaterialEntry Read(BundleEntry entry) + { + MaterialEntry result = new(); + + List dependencies = entry.GetDependencies(); + foreach (BundleDependency dependency in dependencies) { - MaterialEntry result = new MaterialEntry(); - - List dependencies = entry.GetDependencies(); - foreach (BundleDependency dependency in dependencies) - { - ulong id = dependency.EntryID; + ulong id = dependency.EntryID; - //DebugTimer t = DebugTimer.Start("LoadDep"); - BundleEntry descEntry1 = entry.Archive.GetEntryByID(id); - if (descEntry1 == null) + //DebugTimer t = DebugTimer.Start("LoadDep"); + BundleEntry descEntry1 = entry.Archive.GetEntryByID(id); + if (descEntry1 == null) + { + string file = BundleCache.GetFileByEntryID(id); + if (!string.IsNullOrEmpty(file)) { - string file = BundleCache.GetFileByEntryID(id); - if (!string.IsNullOrEmpty(file)) - { - BundleArchive archive = BundleArchive.Read(file); - descEntry1 = archive.GetEntryByID(id); - } + BundleArchive archive = BundleArchive.Read(file); + descEntry1 = archive.GetEntryByID(id); } - //t.StopLog(); + } + //t.StopLog(); - //DebugTimer t2 = DebugTimer.Start("LoadTextureState"); - if (descEntry1 != null && descEntry1.Type == EntryType.TextureState) - { - TextureState state = TextureState.Read(descEntry1); + //DebugTimer t2 = DebugTimer.Start("LoadTextureState"); + if (descEntry1 != null && descEntry1.Type == EntryType.TextureState) + { + TextureState state = TextureState.Read(descEntry1); - result.TextureStates.Add(state); - } - //t2.StopLog(); + result.TextureStates.Add(state); } + //t2.StopLog(); + } - MemoryStream ms = entry.MakeStream(); - BinaryReader2 br = new BinaryReader2(ms); - br.BigEndian = entry.Console; + MemoryStream ms = entry.MakeStream(); + BinaryReader2 br = new(ms); + br.BigEndian = entry.Console; - // TODO: Read Material + // TODO: Read Material - br.Close(); - ms.Close(); + br.Close(); + ms.Close(); - result.Color = Color.White; + result.Color = Color.White; - if (result.TextureStates.Count > 0) - result.DiffuseMap = result.TextureStates[0].Texture; - if (result.TextureStates.Count > 1) - result.NormalMap = result.TextureStates[1].Texture; - if (result.TextureStates.Count > 2) - result.SpecularMap = result.TextureStates[2].Texture; + if (result.TextureStates.Count > 0) + result.DiffuseMap = result.TextureStates[0].Texture; + if (result.TextureStates.Count > 1) + result.NormalMap = result.TextureStates[1].Texture; + if (result.TextureStates.Count > 2) + result.SpecularMap = result.TextureStates[2].Texture; - return result; - } + return result; } } diff --git a/BaseHandlers/ProgressionData.cs b/BaseHandlers/ProgressionData.cs index c88ec2d..32fcf5e 100644 --- a/BaseHandlers/ProgressionData.cs +++ b/BaseHandlers/ProgressionData.cs @@ -5,618 +5,617 @@ using BundleUtilities; using PluginAPI; -namespace BaseHandlers +namespace BaseHandlers; + +// This data would include: +// - Race Rivals Number +// - Large Vehicle Probability +// - Traffic Density Race +// - Traffic Density Road Rage +// - Traffic Density Burning Route +// - Traffic Density Survival (Marked Man) +public struct LicenceData { - // This data would include: - // - Race Rivals Number - // - Large Vehicle Probability - // - Traffic Density Race - // - Traffic Density Road Rage - // - Traffic Density Burning Route - // - Traffic Density Survival (Marked Man) - public struct LicenceData - { - public float Unknown00; - public float Unknown04; - public float Unknown08; // 1 - public float Unknown0C; - public float Unknown10; - public float Unknown14; - public float Unknown18; // 1 - public float Unknown1C; // 1 - public float Unknown20; // 1 - public float Unknown24; - public int GameDBID; // for what? - public float Unknown2C; - public float Unknown30; - public float Unknown34; - public float Unknown38; - public float Unknown3C; - public float Unknown40; - public float Unknown44; - public float Unknown48; - public short NumEventWinsRequired; - public short Unknown4E; // 0 - public short Unknown50; - public short Unknown52; // default SR time limits? - public short Unknown54; // 5 - public short Unknown56; // 10 (previously 5 pre-1.6) - public short Unknown58; // 5 - public short Unknown5A; // 5 - public byte Unknown5C; // 7 - public byte Unknown5D; // 0 - public byte Unknown5E; // 7 - public byte Unknown5F; // 0 - public byte Unknown60; - public byte Unknown61; - public byte Unknown62; - public byte Unknown63; - // 4 bytes padding - public EncryptedString VehicleUnlocked; - } + public float Unknown00; + public float Unknown04; + public float Unknown08; // 1 + public float Unknown0C; + public float Unknown10; + public float Unknown14; + public float Unknown18; // 1 + public float Unknown1C; // 1 + public float Unknown20; // 1 + public float Unknown24; + public int GameDBID; // for what? + public float Unknown2C; + public float Unknown30; + public float Unknown34; + public float Unknown38; + public float Unknown3C; + public float Unknown40; + public float Unknown44; + public float Unknown48; + public short NumEventWinsRequired; + public short Unknown4E; // 0 + public short Unknown50; + public short Unknown52; // default SR time limits? + public short Unknown54; // 5 + public short Unknown56; // 10 (previously 5 pre-1.6) + public short Unknown58; // 5 + public short Unknown5A; // 5 + public byte Unknown5C; // 7 + public byte Unknown5D; // 0 + public byte Unknown5E; // 7 + public byte Unknown5F; // 0 + public byte Unknown60; + public byte Unknown61; + public byte Unknown62; + public byte Unknown63; + // 4 bytes padding + public EncryptedString VehicleUnlocked; +} - public struct EventJunction - { - public int GameDBID; // to identify the event (used in save files) - public uint CarEventDataOffset; - public EventData CarEventData; - public uint BTTEventDataOffset; - public EventData BTTEventData; - public uint BikeEventDataOffset; - public EventData BikeEventData; - public int UnknownGameDBID; - - public override string ToString() => $"ID: {GameDBID}"; - } +public struct EventJunction +{ + public int GameDBID; // to identify the event (used in save files) + public uint CarEventDataOffset; + public EventData CarEventData; + public uint BTTEventDataOffset; + public EventData BTTEventData; + public uint BikeEventDataOffset; + public EventData BikeEventData; + public int UnknownGameDBID; + + public override string ToString() => $"ID: {GameDBID}"; +} - public struct EventData - { - public int GameDBID; // not used in save - public int AppearsWhen; // 0 = cars/daytime bikes, 3 = midnight bights, 4 = island - public float TrafficDensityMultiplier; - public float Unknown0C; // 1 - public EncryptedString LockVehicleID; // for Burning Routes but can apply to other events - public uint EventLandmarkDataOffset; - public EventLandmarkData[] EventLandmarkData; - public int EventLandmarkCount; - public float TargetTimeUnused; // 20 for marked man but never read - public float TargetTime; // 40 for marked man but never read - public int StuntRunTargetScoreTier1; - public int StuntRunTargetScoreTier2; - public int StuntRunTargetScoreTier3; - public int StuntRunTargetScoreTier4; - public int StuntRunTargetScoreTier5; - public int StuntRunTargetScoreTier6; - public float StuntRunTimeLimitTier1; - public float StuntRunTimeLimitTier2; - public float StuntRunTimeLimitTier3; - public float StuntRunTimeLimitTier4; - public float StuntRunTimeLimitTier5; - public float StuntRunTimeLimitTier6; - public int Unknown58; // 0 - public EventRivalData[] RivalData; - public int RivalDataCount; // 7 for non-races, despite not really being necessary? - public byte Type; // 0 = Race, 1 = Road Rage, 2 = Stunt Run, 3 = Marked Man, 4 = Burning Route (and bike events and island tour), 5 = Race but with the Marked Man map icon - public byte UnknownED; // 0, 2 (0 for non-races) - public byte NumberOfAIRivalsToUse; // 0 for non-races - public byte UnknownEF; // 0 - public int UnknownF0; // 0 - public byte UnknownF4; // 0 - public byte UnknownF5; // 0, 1, 2 (0 for RR & SR) - // 2 byte padding - - public override string ToString() => $"ID: {GameDBID}"; - } +public struct EventData +{ + public int GameDBID; // not used in save + public int AppearsWhen; // 0 = cars/daytime bikes, 3 = midnight bights, 4 = island + public float TrafficDensityMultiplier; + public float Unknown0C; // 1 + public EncryptedString LockVehicleID; // for Burning Routes but can apply to other events + public uint EventLandmarkDataOffset; + public EventLandmarkData[] EventLandmarkData; + public int EventLandmarkCount; + public float TargetTimeUnused; // 20 for marked man but never read + public float TargetTime; // 40 for marked man but never read + public int StuntRunTargetScoreTier1; + public int StuntRunTargetScoreTier2; + public int StuntRunTargetScoreTier3; + public int StuntRunTargetScoreTier4; + public int StuntRunTargetScoreTier5; + public int StuntRunTargetScoreTier6; + public float StuntRunTimeLimitTier1; + public float StuntRunTimeLimitTier2; + public float StuntRunTimeLimitTier3; + public float StuntRunTimeLimitTier4; + public float StuntRunTimeLimitTier5; + public float StuntRunTimeLimitTier6; + public int Unknown58; // 0 + public EventRivalData[] RivalData; + public int RivalDataCount; // 7 for non-races, despite not really being necessary? + public byte Type; // 0 = Race, 1 = Road Rage, 2 = Stunt Run, 3 = Marked Man, 4 = Burning Route (and bike events and island tour), 5 = Race but with the Marked Man map icon + public byte UnknownED; // 0, 2 (0 for non-races) + public byte NumberOfAIRivalsToUse; // 0 for non-races + public byte UnknownEF; // 0 + public int UnknownF0; // 0 + public byte UnknownF4; // 0 + public byte UnknownF5; // 0, 1, 2 (0 for RR & SR) + // 2 byte padding + + public override string ToString() => $"ID: {GameDBID}"; +} - public struct EventRivalData - { - public int Unknown00; - public int Unknown04; - public int Unknown08; - public int Unknown0C; - public byte Unknown10; - public byte Unknown11; - public byte Unknown12; // garbage - public byte Unknown13; // garbage - } +public struct EventRivalData +{ + public int Unknown00; + public int Unknown04; + public int Unknown08; + public int Unknown0C; + public byte Unknown10; + public byte Unknown11; + public byte Unknown12; // garbage + public byte Unknown13; // garbage +} - public struct EventLandmarkData - { - public int TriggerID; - public int NumAIGameDBIDs; - public int[] AIGameDBIDs; +public struct EventLandmarkData +{ + public int TriggerID; + public int NumAIGameDBIDs; + public int[] AIGameDBIDs; - public override string ToString() => $"Trigger {TriggerID} ({NumAIGameDBIDs} AI IDs)"; - } + public override string ToString() => $"Trigger {TriggerID} ({NumAIGameDBIDs} AI IDs)"; +} - public struct Rival - { - public long RivalID; - public EncryptedString VehicleID; - public short Unknown10; - public short Unknown12; // 1 - public byte Unknown14; - public byte Unknown15; // 7F - public byte WinsUntilRoam; - public bool DoesNotRoam; // Alternatively: unlocked via licence upgrade - public string Name; - - public override string ToString() => $"ID {RivalID}: {Name} ({VehicleID})"; - } +public struct Rival +{ + public long RivalID; + public EncryptedString VehicleID; + public short Unknown10; + public short Unknown12; // 1 + public byte Unknown14; + public byte Unknown15; // 7F + public byte WinsUntilRoam; + public bool DoesNotRoam; // Alternatively: unlocked via licence upgrade + public string Name; + + public override string ToString() => $"ID {RivalID}: {Name} ({VehicleID})"; +} + +public struct ProgressionSection6Entry +{ + public float Unknown00; + public float Unknown04; + public float Unknown08; + public float Unknown0C; + public float Unknown10; + public float Unknown14; + public float Unknown18; + public float Unknown1C; + public float Unknown20; + public float Unknown24; + public float Unknown28; + public float Unknown2C; + public float Unknown30; + public float Unknown34; + public float Unknown38; + public float Unknown3C; + public byte Unknown40; // CD + public byte Unknown41; // CC + public byte Unknown42; // 4C + public byte Unknown43; // 3F +} + +public struct ProgressionSection7Entry +{ + public float Unknown00; + public float Unknown04; + public float Unknown08; + public float Unknown0C; +} + +public struct CarbonCarUnlockData +{ + public int Unknown00; // 0 + public short Unknown04; + public byte Unknown06; // 0 in remaster, prob garbage + public byte Unknown07; // 0 in remaster, prob garbage + public EncryptedString VehicleID; + + public override string ToString() => $"Vehicle {VehicleID}"; +} - public struct ProgressionSection6Entry +public struct PlayerOpponentsData +{ + public EncryptedString PlayerVehicleID; + public int Unknown08; + public int Unknown0C; // 0 + public EncryptedString Opponent1VehicleID; + public int Unknown18; + public int Unknown1C; // 0 + public EncryptedString Opponent2VehicleID; + public int Unknown28; + public int Unknown2C; // 0 + public EncryptedString Opponent3VehicleID; + public int Unknown38; + public int Unknown3C; // 0 + public EncryptedString Opponent4VehicleID; + public int Unknown48; + public int Unknown4C; // 0 + public EncryptedString Opponent5VehicleID; + public int Unknown58; + public int Unknown5C; // 0 + public EncryptedString Opponent6VehicleID; + public int Unknown68; + public int Unknown6C; // 0 + public EncryptedString Opponent7VehicleID; + public int Unknown78; + public int Unknown7C; // 0 + public EncryptedString Opponent8VehicleID; + public int Unknown88; // 0, 2, 4 + public int NumOpponents; + + public override string ToString() => $"Player Vehicle ID {PlayerVehicleID}"; +} + +public class ProgressionData : IEntryData +{ + public int FormatRevision; + public uint FileSize; + public uint InitialCarIDListOffset; + public int InitialCarIDCount; + public uint LicenceDataOffset; + public int LicenceDataCount; + public uint EventJunctionOffset; + public int EventJunctionCount; + public uint EventDataOffset; + public int EventDataCount; + public uint RivalOffset; + public int RivalCount; + public uint Section6Offset; + public int Section6Count; + public uint Section7Offset; + public int Section7Count; + public uint CarbonCarUnlockDataOffset; + public int CarbonCarUnlockDataCount; + public uint PlayerOpponentsDataOffset; + public int PlayerOpponentsDataCount; + + public List InitialCarIDEntries; + public List LicenceDataEntries; + public List EventJunctionEntries; + public SortedDictionary EventDataEntries; + public List RivalEntries; + public List Section6Entries; + public List Section7Entries; + public List CarbonCarUnlockDataEntries; + public List PlayerOpponentsDataEntries; + + public ProgressionData() { - public float Unknown00; - public float Unknown04; - public float Unknown08; - public float Unknown0C; - public float Unknown10; - public float Unknown14; - public float Unknown18; - public float Unknown1C; - public float Unknown20; - public float Unknown24; - public float Unknown28; - public float Unknown2C; - public float Unknown30; - public float Unknown34; - public float Unknown38; - public float Unknown3C; - public byte Unknown40; // CD - public byte Unknown41; // CC - public byte Unknown42; // 4C - public byte Unknown43; // 3F + InitialCarIDEntries = []; + LicenceDataEntries = []; + EventJunctionEntries = []; + EventDataEntries = []; + RivalEntries = []; + Section6Entries = []; + Section7Entries = []; + CarbonCarUnlockDataEntries = []; + PlayerOpponentsDataEntries = []; } - public struct ProgressionSection7Entry + public IEntryEditor GetEditor(BundleEntry entry) { - public float Unknown00; - public float Unknown04; - public float Unknown08; - public float Unknown0C; + return null; } - public struct CarbonCarUnlockData + public EntryType GetEntryType(BundleEntry entry) { - public int Unknown00; // 0 - public short Unknown04; - public byte Unknown06; // 0 in remaster, prob garbage - public byte Unknown07; // 0 in remaster, prob garbage - public EncryptedString VehicleID; - - public override string ToString() => $"Vehicle {VehicleID}"; + return EntryType.ProgressionData; } - public struct PlayerOpponentsData + private void Clear() { - public EncryptedString PlayerVehicleID; - public int Unknown08; - public int Unknown0C; // 0 - public EncryptedString Opponent1VehicleID; - public int Unknown18; - public int Unknown1C; // 0 - public EncryptedString Opponent2VehicleID; - public int Unknown28; - public int Unknown2C; // 0 - public EncryptedString Opponent3VehicleID; - public int Unknown38; - public int Unknown3C; // 0 - public EncryptedString Opponent4VehicleID; - public int Unknown48; - public int Unknown4C; // 0 - public EncryptedString Opponent5VehicleID; - public int Unknown58; - public int Unknown5C; // 0 - public EncryptedString Opponent6VehicleID; - public int Unknown68; - public int Unknown6C; // 0 - public EncryptedString Opponent7VehicleID; - public int Unknown78; - public int Unknown7C; // 0 - public EncryptedString Opponent8VehicleID; - public int Unknown88; // 0, 2, 4 - public int NumOpponents; - - public override string ToString() => $"Player Vehicle ID {PlayerVehicleID}"; + } - public class ProgressionData : IEntryData + public bool Read(BundleEntry entry, ILoader loader = null) { - public int FormatRevision; - public uint FileSize; - public uint InitialCarIDListOffset; - public int InitialCarIDCount; - public uint LicenceDataOffset; - public int LicenceDataCount; - public uint EventJunctionOffset; - public int EventJunctionCount; - public uint EventDataOffset; - public int EventDataCount; - public uint RivalOffset; - public int RivalCount; - public uint Section6Offset; - public int Section6Count; - public uint Section7Offset; - public int Section7Count; - public uint CarbonCarUnlockDataOffset; - public int CarbonCarUnlockDataCount; - public uint PlayerOpponentsDataOffset; - public int PlayerOpponentsDataCount; - - public List InitialCarIDEntries; - public List LicenceDataEntries; - public List EventJunctionEntries; - public SortedDictionary EventDataEntries; - public List RivalEntries; - public List Section6Entries; - public List Section7Entries; - public List CarbonCarUnlockDataEntries; - public List PlayerOpponentsDataEntries; - - public ProgressionData() + Clear(); + + MemoryStream ms = entry.MakeStream(); + BinaryReader2 br = new(ms); + br.BigEndian = entry.Console; + + FormatRevision = br.ReadInt32(); + FileSize = br.ReadUInt32(); + InitialCarIDListOffset = br.ReadUInt32(); + InitialCarIDCount = br.ReadInt32(); + LicenceDataOffset = br.ReadUInt32(); + LicenceDataCount = br.ReadInt32(); + EventJunctionOffset = br.ReadUInt32(); + EventJunctionCount = br.ReadInt32(); + EventDataOffset = br.ReadUInt32(); + EventDataCount = br.ReadInt32(); + RivalOffset = br.ReadUInt32(); + RivalCount = br.ReadInt32(); + Section6Offset = br.ReadUInt32(); + Section6Count = br.ReadInt32(); + Section7Offset = br.ReadUInt32(); + Section7Count = br.ReadInt32(); + CarbonCarUnlockDataOffset = br.ReadUInt32(); + CarbonCarUnlockDataCount = br.ReadInt32(); + PlayerOpponentsDataOffset = br.ReadUInt32(); + PlayerOpponentsDataCount = br.ReadInt32(); + + + br.BaseStream.Position = InitialCarIDListOffset; + for (int i = 0; i < InitialCarIDCount; i++) { - InitialCarIDEntries = new List(); - LicenceDataEntries = new List(); - EventJunctionEntries = new List(); - EventDataEntries = new SortedDictionary(); - RivalEntries = new List(); - Section6Entries = new List(); - Section7Entries = new List(); - CarbonCarUnlockDataEntries = new List(); - PlayerOpponentsDataEntries = new List(); + InitialCarIDEntries.Add(new EncryptedString(br.ReadUInt64())); } - public IEntryEditor GetEditor(BundleEntry entry) - { - return null; - } - public EntryType GetEntryType(BundleEntry entry) + br.BaseStream.Position = LicenceDataOffset; + for (int i = 0; i < LicenceDataCount; i++) { - return EntryType.ProgressionData; + LicenceData licenceData = new(); + + licenceData.Unknown00 = br.ReadSingle(); + licenceData.Unknown04 = br.ReadSingle(); + licenceData.Unknown08 = br.ReadSingle(); + licenceData.Unknown0C = br.ReadSingle(); + licenceData.Unknown10 = br.ReadSingle(); + licenceData.Unknown14 = br.ReadSingle(); + licenceData.Unknown18 = br.ReadSingle(); + licenceData.Unknown1C = br.ReadSingle(); + licenceData.Unknown20 = br.ReadSingle(); + licenceData.Unknown24 = br.ReadSingle(); + licenceData.GameDBID = br.ReadInt32(); + licenceData.Unknown2C = br.ReadSingle(); + licenceData.Unknown30 = br.ReadSingle(); + licenceData.Unknown34 = br.ReadSingle(); + licenceData.Unknown38 = br.ReadSingle(); + licenceData.Unknown3C = br.ReadSingle(); + licenceData.Unknown40 = br.ReadSingle(); + licenceData.Unknown44 = br.ReadSingle(); + licenceData.Unknown48 = br.ReadSingle(); + licenceData.NumEventWinsRequired = br.ReadInt16(); + licenceData.Unknown4E = br.ReadInt16(); + licenceData.Unknown50 = br.ReadInt16(); + licenceData.Unknown52 = br.ReadInt16(); + licenceData.Unknown54 = br.ReadInt16(); + licenceData.Unknown56 = br.ReadInt16(); + licenceData.Unknown58 = br.ReadInt16(); + licenceData.Unknown5A = br.ReadInt16(); + licenceData.Unknown5C = br.ReadByte(); + licenceData.Unknown5D = br.ReadByte(); + licenceData.Unknown5E = br.ReadByte(); + licenceData.Unknown5F = br.ReadByte(); + licenceData.Unknown60 = br.ReadByte(); + licenceData.Unknown61 = br.ReadByte(); + licenceData.Unknown62 = br.ReadByte(); + licenceData.Unknown63 = br.ReadByte(); + br.BaseStream.Position += 4; // padding + licenceData.VehicleUnlocked = new EncryptedString(br.ReadUInt64()); + + LicenceDataEntries.Add(licenceData); } - private void Clear() - { - - } - public bool Read(BundleEntry entry, ILoader loader = null) + br.BaseStream.Position = EventJunctionOffset; + for (int i = 0; i < EventJunctionCount; i++) { - Clear(); - - MemoryStream ms = entry.MakeStream(); - BinaryReader2 br = new BinaryReader2(ms); - br.BigEndian = entry.Console; - - FormatRevision = br.ReadInt32(); - FileSize = br.ReadUInt32(); - InitialCarIDListOffset = br.ReadUInt32(); - InitialCarIDCount = br.ReadInt32(); - LicenceDataOffset = br.ReadUInt32(); - LicenceDataCount = br.ReadInt32(); - EventJunctionOffset = br.ReadUInt32(); - EventJunctionCount = br.ReadInt32(); - EventDataOffset = br.ReadUInt32(); - EventDataCount = br.ReadInt32(); - RivalOffset = br.ReadUInt32(); - RivalCount = br.ReadInt32(); - Section6Offset = br.ReadUInt32(); - Section6Count = br.ReadInt32(); - Section7Offset = br.ReadUInt32(); - Section7Count = br.ReadInt32(); - CarbonCarUnlockDataOffset = br.ReadUInt32(); - CarbonCarUnlockDataCount = br.ReadInt32(); - PlayerOpponentsDataOffset = br.ReadUInt32(); - PlayerOpponentsDataCount = br.ReadInt32(); - - - br.BaseStream.Position = InitialCarIDListOffset; - for (int i = 0; i < InitialCarIDCount; i++) - { - InitialCarIDEntries.Add(new EncryptedString(br.ReadUInt64())); - } + EventJunction eventJunction = new(); + eventJunction.GameDBID = br.ReadInt32(); + eventJunction.CarEventDataOffset = br.ReadUInt32(); + eventJunction.BTTEventDataOffset = br.ReadUInt32(); + if (FormatRevision >= 44) + eventJunction.BikeEventDataOffset = br.ReadUInt32(); + eventJunction.UnknownGameDBID = br.ReadInt32(); - br.BaseStream.Position = LicenceDataOffset; - for (int i = 0; i < LicenceDataCount; i++) - { - LicenceData licenceData = new LicenceData(); - - licenceData.Unknown00 = br.ReadSingle(); - licenceData.Unknown04 = br.ReadSingle(); - licenceData.Unknown08 = br.ReadSingle(); - licenceData.Unknown0C = br.ReadSingle(); - licenceData.Unknown10 = br.ReadSingle(); - licenceData.Unknown14 = br.ReadSingle(); - licenceData.Unknown18 = br.ReadSingle(); - licenceData.Unknown1C = br.ReadSingle(); - licenceData.Unknown20 = br.ReadSingle(); - licenceData.Unknown24 = br.ReadSingle(); - licenceData.GameDBID = br.ReadInt32(); - licenceData.Unknown2C = br.ReadSingle(); - licenceData.Unknown30 = br.ReadSingle(); - licenceData.Unknown34 = br.ReadSingle(); - licenceData.Unknown38 = br.ReadSingle(); - licenceData.Unknown3C = br.ReadSingle(); - licenceData.Unknown40 = br.ReadSingle(); - licenceData.Unknown44 = br.ReadSingle(); - licenceData.Unknown48 = br.ReadSingle(); - licenceData.NumEventWinsRequired = br.ReadInt16(); - licenceData.Unknown4E = br.ReadInt16(); - licenceData.Unknown50 = br.ReadInt16(); - licenceData.Unknown52 = br.ReadInt16(); - licenceData.Unknown54 = br.ReadInt16(); - licenceData.Unknown56 = br.ReadInt16(); - licenceData.Unknown58 = br.ReadInt16(); - licenceData.Unknown5A = br.ReadInt16(); - licenceData.Unknown5C = br.ReadByte(); - licenceData.Unknown5D = br.ReadByte(); - licenceData.Unknown5E = br.ReadByte(); - licenceData.Unknown5F = br.ReadByte(); - licenceData.Unknown60 = br.ReadByte(); - licenceData.Unknown61 = br.ReadByte(); - licenceData.Unknown62 = br.ReadByte(); - licenceData.Unknown63 = br.ReadByte(); - br.BaseStream.Position += 4; // padding - licenceData.VehicleUnlocked = new EncryptedString(br.ReadUInt64()); - - LicenceDataEntries.Add(licenceData); - } + EventJunctionEntries.Add(eventJunction); + } - br.BaseStream.Position = EventJunctionOffset; - for (int i = 0; i < EventJunctionCount; i++) + br.BaseStream.Position = EventDataOffset; + for (int i = 0; i < EventDataCount; i++) + { + long origPosition = br.BaseStream.Position; + + EventData eventData = new(); + + eventData.GameDBID = br.ReadInt32(); + eventData.AppearsWhen = br.ReadInt32(); + eventData.TrafficDensityMultiplier = br.ReadSingle(); + eventData.Unknown0C = br.ReadSingle(); + eventData.LockVehicleID = new EncryptedString(br.ReadUInt64()); + eventData.EventLandmarkDataOffset = br.ReadUInt32(); + eventData.EventLandmarkCount = br.ReadInt32(); + eventData.TargetTimeUnused = br.ReadSingle(); + eventData.TargetTime = br.ReadSingle(); + eventData.StuntRunTargetScoreTier1 = br.ReadInt32(); + eventData.StuntRunTargetScoreTier2 = br.ReadInt32(); + eventData.StuntRunTargetScoreTier3 = br.ReadInt32(); + eventData.StuntRunTargetScoreTier4 = br.ReadInt32(); + eventData.StuntRunTargetScoreTier5 = br.ReadInt32(); + eventData.StuntRunTargetScoreTier6 = br.ReadInt32(); + eventData.StuntRunTimeLimitTier1 = br.ReadSingle(); + eventData.StuntRunTimeLimitTier2 = br.ReadSingle(); + eventData.StuntRunTimeLimitTier3 = br.ReadSingle(); + eventData.StuntRunTimeLimitTier4 = br.ReadSingle(); + eventData.StuntRunTimeLimitTier5 = br.ReadSingle(); + eventData.StuntRunTimeLimitTier6 = br.ReadSingle(); + eventData.Unknown58 = br.ReadInt32(); + + eventData.RivalData = new EventRivalData[7]; + for (int j = 0; j < 7; j++) { - EventJunction eventJunction = new EventJunction(); - - eventJunction.GameDBID = br.ReadInt32(); - eventJunction.CarEventDataOffset = br.ReadUInt32(); - eventJunction.BTTEventDataOffset = br.ReadUInt32(); - if (FormatRevision >= 44) - eventJunction.BikeEventDataOffset = br.ReadUInt32(); - eventJunction.UnknownGameDBID = br.ReadInt32(); - - EventJunctionEntries.Add(eventJunction); + EventRivalData rivalData = new(); + + rivalData.Unknown00 = br.ReadInt32(); + rivalData.Unknown04 = br.ReadInt32(); + rivalData.Unknown08 = br.ReadInt32(); + rivalData.Unknown0C = br.ReadInt32(); + rivalData.Unknown10 = br.ReadByte(); + rivalData.Unknown11 = br.ReadByte(); + rivalData.Unknown12 = br.ReadByte(); + rivalData.Unknown13 = br.ReadByte(); + + eventData.RivalData[j] = rivalData; } - - - br.BaseStream.Position = EventDataOffset; - for (int i = 0; i < EventDataCount; i++) + + eventData.RivalDataCount = br.ReadInt32(); + Array.Resize(ref eventData.RivalData, eventData.RivalDataCount); + + eventData.Type = br.ReadByte(); + eventData.UnknownED = br.ReadByte(); + eventData.NumberOfAIRivalsToUse = br.ReadByte(); + eventData.UnknownEF = br.ReadByte(); + eventData.UnknownF0 = br.ReadInt32(); + eventData.UnknownF4 = br.ReadByte(); + eventData.UnknownF5 = br.ReadByte(); + br.BaseStream.Position += 2; // padding + + long oldPos = br.BaseStream.Position; + eventData.EventLandmarkData = new EventLandmarkData[eventData.EventLandmarkCount]; + br.BaseStream.Position = eventData.EventLandmarkDataOffset; + for (int j = 0; j < eventData.EventLandmarkCount; j++) { - long origPosition = br.BaseStream.Position; - - EventData eventData = new EventData(); - - eventData.GameDBID = br.ReadInt32(); - eventData.AppearsWhen = br.ReadInt32(); - eventData.TrafficDensityMultiplier = br.ReadSingle(); - eventData.Unknown0C = br.ReadSingle(); - eventData.LockVehicleID = new EncryptedString(br.ReadUInt64()); - eventData.EventLandmarkDataOffset = br.ReadUInt32(); - eventData.EventLandmarkCount = br.ReadInt32(); - eventData.TargetTimeUnused = br.ReadSingle(); - eventData.TargetTime = br.ReadSingle(); - eventData.StuntRunTargetScoreTier1 = br.ReadInt32(); - eventData.StuntRunTargetScoreTier2 = br.ReadInt32(); - eventData.StuntRunTargetScoreTier3 = br.ReadInt32(); - eventData.StuntRunTargetScoreTier4 = br.ReadInt32(); - eventData.StuntRunTargetScoreTier5 = br.ReadInt32(); - eventData.StuntRunTargetScoreTier6 = br.ReadInt32(); - eventData.StuntRunTimeLimitTier1 = br.ReadSingle(); - eventData.StuntRunTimeLimitTier2 = br.ReadSingle(); - eventData.StuntRunTimeLimitTier3 = br.ReadSingle(); - eventData.StuntRunTimeLimitTier4 = br.ReadSingle(); - eventData.StuntRunTimeLimitTier5 = br.ReadSingle(); - eventData.StuntRunTimeLimitTier6 = br.ReadSingle(); - eventData.Unknown58 = br.ReadInt32(); - - eventData.RivalData = new EventRivalData[7]; - for (int j = 0; j < 7; j++) - { - EventRivalData rivalData = new EventRivalData(); - - rivalData.Unknown00 = br.ReadInt32(); - rivalData.Unknown04 = br.ReadInt32(); - rivalData.Unknown08 = br.ReadInt32(); - rivalData.Unknown0C = br.ReadInt32(); - rivalData.Unknown10 = br.ReadByte(); - rivalData.Unknown11 = br.ReadByte(); - rivalData.Unknown12 = br.ReadByte(); - rivalData.Unknown13 = br.ReadByte(); - - eventData.RivalData[j] = rivalData; - } - - eventData.RivalDataCount = br.ReadInt32(); - Array.Resize(ref eventData.RivalData, eventData.RivalDataCount); - - eventData.Type = br.ReadByte(); - eventData.UnknownED = br.ReadByte(); - eventData.NumberOfAIRivalsToUse = br.ReadByte(); - eventData.UnknownEF = br.ReadByte(); - eventData.UnknownF0 = br.ReadInt32(); - eventData.UnknownF4 = br.ReadByte(); - eventData.UnknownF5 = br.ReadByte(); - br.BaseStream.Position += 2; // padding - - long oldPos = br.BaseStream.Position; - eventData.EventLandmarkData = new EventLandmarkData[eventData.EventLandmarkCount]; - br.BaseStream.Position = eventData.EventLandmarkDataOffset; - for (int j = 0; j < eventData.EventLandmarkCount; j++) + EventLandmarkData landmarkData = new(); + + landmarkData.TriggerID = br.ReadInt32(); + landmarkData.NumAIGameDBIDs = br.ReadInt32(); + landmarkData.AIGameDBIDs = new int[landmarkData.NumAIGameDBIDs]; + for (int k = 0; k < 8; k++) { - EventLandmarkData landmarkData = new EventLandmarkData(); - - landmarkData.TriggerID = br.ReadInt32(); - landmarkData.NumAIGameDBIDs = br.ReadInt32(); - landmarkData.AIGameDBIDs = new int[landmarkData.NumAIGameDBIDs]; - for (int k = 0; k < 8; k++) - { - int gameDBID = br.ReadInt32(); - if (k < landmarkData.NumAIGameDBIDs) - landmarkData.AIGameDBIDs[k] = gameDBID; - } - - eventData.EventLandmarkData[j] = landmarkData; + int gameDBID = br.ReadInt32(); + if (k < landmarkData.NumAIGameDBIDs) + landmarkData.AIGameDBIDs[k] = gameDBID; } - br.BaseStream.Position = oldPos; - EventDataEntries.Add((uint)origPosition, eventData); + eventData.EventLandmarkData[j] = landmarkData; } + br.BaseStream.Position = oldPos; - for (int i = 0; i < EventJunctionCount; i++) - { - EventJunction junction = EventJunctionEntries[i]; + EventDataEntries.Add((uint)origPosition, eventData); + } - if (junction.CarEventDataOffset != 0) - junction.CarEventData = EventDataEntries[junction.CarEventDataOffset]; - if (junction.BTTEventDataOffset != 0) - junction.BTTEventData = EventDataEntries[junction.BTTEventDataOffset]; - if (junction.BikeEventDataOffset != 0) - junction.BikeEventData = EventDataEntries[junction.BikeEventDataOffset]; + for (int i = 0; i < EventJunctionCount; i++) + { + EventJunction junction = EventJunctionEntries[i]; - EventJunctionEntries[i] = junction; - } + if (junction.CarEventDataOffset != 0) + junction.CarEventData = EventDataEntries[junction.CarEventDataOffset]; + if (junction.BTTEventDataOffset != 0) + junction.BTTEventData = EventDataEntries[junction.BTTEventDataOffset]; + if (junction.BikeEventDataOffset != 0) + junction.BikeEventData = EventDataEntries[junction.BikeEventDataOffset]; + EventJunctionEntries[i] = junction; + } - br.BaseStream.Position = RivalOffset; - for (int i = 0; i < RivalCount; i++) - { - Rival rival = new Rival(); - - rival.RivalID = br.ReadInt64(); - rival.VehicleID = new EncryptedString(br.ReadUInt64()); - rival.Unknown10 = br.ReadInt16(); - rival.Unknown12 = br.ReadInt16(); - rival.Unknown14 = br.ReadByte(); - rival.Unknown15 = br.ReadByte(); - rival.WinsUntilRoam = br.ReadByte(); - rival.DoesNotRoam = br.ReadBoolean(); - rival.Name = br.ReadLenString(0x20); - - RivalEntries.Add(rival); - } + + br.BaseStream.Position = RivalOffset; + for (int i = 0; i < RivalCount; i++) + { + Rival rival = new(); + + rival.RivalID = br.ReadInt64(); + rival.VehicleID = new EncryptedString(br.ReadUInt64()); + rival.Unknown10 = br.ReadInt16(); + rival.Unknown12 = br.ReadInt16(); + rival.Unknown14 = br.ReadByte(); + rival.Unknown15 = br.ReadByte(); + rival.WinsUntilRoam = br.ReadByte(); + rival.DoesNotRoam = br.ReadBoolean(); + rival.Name = br.ReadLenString(0x20); + + RivalEntries.Add(rival); + } - br.BaseStream.Position = Section6Offset; - for (int i = 0; i < Section6Count; i++) - { - ProgressionSection6Entry section6Entry = new ProgressionSection6Entry(); - - section6Entry.Unknown00 = br.ReadSingle(); - section6Entry.Unknown04 = br.ReadSingle(); - section6Entry.Unknown08 = br.ReadSingle(); - section6Entry.Unknown0C = br.ReadSingle(); - section6Entry.Unknown10 = br.ReadSingle(); - section6Entry.Unknown14 = br.ReadSingle(); - section6Entry.Unknown18 = br.ReadSingle(); - section6Entry.Unknown1C = br.ReadSingle(); - section6Entry.Unknown20 = br.ReadSingle(); - section6Entry.Unknown24 = br.ReadSingle(); - section6Entry.Unknown28 = br.ReadSingle(); - section6Entry.Unknown2C = br.ReadSingle(); - section6Entry.Unknown30 = br.ReadSingle(); - section6Entry.Unknown34 = br.ReadSingle(); - section6Entry.Unknown38 = br.ReadSingle(); - section6Entry.Unknown3C = br.ReadSingle(); - section6Entry.Unknown40 = br.ReadByte(); - section6Entry.Unknown41 = br.ReadByte(); - section6Entry.Unknown42 = br.ReadByte(); - section6Entry.Unknown43 = br.ReadByte(); - - Section6Entries.Add(section6Entry); - } + br.BaseStream.Position = Section6Offset; + for (int i = 0; i < Section6Count; i++) + { + ProgressionSection6Entry section6Entry = new(); + + section6Entry.Unknown00 = br.ReadSingle(); + section6Entry.Unknown04 = br.ReadSingle(); + section6Entry.Unknown08 = br.ReadSingle(); + section6Entry.Unknown0C = br.ReadSingle(); + section6Entry.Unknown10 = br.ReadSingle(); + section6Entry.Unknown14 = br.ReadSingle(); + section6Entry.Unknown18 = br.ReadSingle(); + section6Entry.Unknown1C = br.ReadSingle(); + section6Entry.Unknown20 = br.ReadSingle(); + section6Entry.Unknown24 = br.ReadSingle(); + section6Entry.Unknown28 = br.ReadSingle(); + section6Entry.Unknown2C = br.ReadSingle(); + section6Entry.Unknown30 = br.ReadSingle(); + section6Entry.Unknown34 = br.ReadSingle(); + section6Entry.Unknown38 = br.ReadSingle(); + section6Entry.Unknown3C = br.ReadSingle(); + section6Entry.Unknown40 = br.ReadByte(); + section6Entry.Unknown41 = br.ReadByte(); + section6Entry.Unknown42 = br.ReadByte(); + section6Entry.Unknown43 = br.ReadByte(); + + Section6Entries.Add(section6Entry); + } - br.BaseStream.Position = Section7Offset; - for (int i = 0; i < Section7Count; i++) - { - ProgressionSection7Entry section7Entry = new ProgressionSection7Entry(); + br.BaseStream.Position = Section7Offset; + for (int i = 0; i < Section7Count; i++) + { + ProgressionSection7Entry section7Entry = new(); - section7Entry.Unknown00 = br.ReadSingle(); - section7Entry.Unknown04 = br.ReadSingle(); - section7Entry.Unknown08 = br.ReadSingle(); - section7Entry.Unknown0C = br.ReadSingle(); + section7Entry.Unknown00 = br.ReadSingle(); + section7Entry.Unknown04 = br.ReadSingle(); + section7Entry.Unknown08 = br.ReadSingle(); + section7Entry.Unknown0C = br.ReadSingle(); - Section7Entries.Add(section7Entry); - } + Section7Entries.Add(section7Entry); + } - br.BaseStream.Position = CarbonCarUnlockDataOffset; - for (int i = 0; i < CarbonCarUnlockDataCount; i++) - { - CarbonCarUnlockData unlockData = new CarbonCarUnlockData(); + br.BaseStream.Position = CarbonCarUnlockDataOffset; + for (int i = 0; i < CarbonCarUnlockDataCount; i++) + { + CarbonCarUnlockData unlockData = new(); - unlockData.Unknown00 = br.ReadInt32(); - unlockData.Unknown04 = br.ReadInt16(); - unlockData.Unknown06 = br.ReadByte(); - unlockData.Unknown07 = br.ReadByte(); - unlockData.VehicleID = new EncryptedString(br.ReadUInt64()); + unlockData.Unknown00 = br.ReadInt32(); + unlockData.Unknown04 = br.ReadInt16(); + unlockData.Unknown06 = br.ReadByte(); + unlockData.Unknown07 = br.ReadByte(); + unlockData.VehicleID = new EncryptedString(br.ReadUInt64()); - CarbonCarUnlockDataEntries.Add(unlockData); - } + CarbonCarUnlockDataEntries.Add(unlockData); + } - br.BaseStream.Position = PlayerOpponentsDataOffset; - for (int i = 0; i < PlayerOpponentsDataCount; i++) - { - PlayerOpponentsData opponentsData = new PlayerOpponentsData(); - - opponentsData.PlayerVehicleID = new EncryptedString(br.ReadUInt64()); - opponentsData.Unknown08 = br.ReadInt32(); - opponentsData.Unknown0C = br.ReadInt32(); - opponentsData.Opponent1VehicleID = new EncryptedString(br.ReadUInt64()); - opponentsData.Unknown18 = br.ReadInt32(); - opponentsData.Unknown1C = br.ReadInt32(); - opponentsData.Opponent2VehicleID = new EncryptedString(br.ReadUInt64()); - opponentsData.Unknown28 = br.ReadInt32(); - opponentsData.Unknown2C = br.ReadInt32(); - opponentsData.Opponent3VehicleID = new EncryptedString(br.ReadUInt64()); - opponentsData.Unknown38 = br.ReadInt32(); - opponentsData.Unknown3C = br.ReadInt32(); - opponentsData.Opponent4VehicleID = new EncryptedString(br.ReadUInt64()); - opponentsData.Unknown48 = br.ReadInt32(); - opponentsData.Unknown4C = br.ReadInt32(); - opponentsData.Opponent5VehicleID = new EncryptedString(br.ReadUInt64()); - opponentsData.Unknown58 = br.ReadInt32(); - opponentsData.Unknown5C = br.ReadInt32(); - opponentsData.Opponent6VehicleID = new EncryptedString(br.ReadUInt64()); - opponentsData.Unknown68 = br.ReadInt32(); - opponentsData.Unknown6C = br.ReadInt32(); - opponentsData.Opponent7VehicleID = new EncryptedString(br.ReadUInt64()); - opponentsData.Unknown78 = br.ReadInt32(); - opponentsData.Unknown7C = br.ReadInt32(); - opponentsData.Opponent8VehicleID = new EncryptedString(br.ReadUInt64()); - opponentsData.Unknown88 = br.ReadInt32(); - opponentsData.NumOpponents = br.ReadInt32(); - - PlayerOpponentsDataEntries.Add(opponentsData); - } + br.BaseStream.Position = PlayerOpponentsDataOffset; + for (int i = 0; i < PlayerOpponentsDataCount; i++) + { + PlayerOpponentsData opponentsData = new(); + + opponentsData.PlayerVehicleID = new EncryptedString(br.ReadUInt64()); + opponentsData.Unknown08 = br.ReadInt32(); + opponentsData.Unknown0C = br.ReadInt32(); + opponentsData.Opponent1VehicleID = new EncryptedString(br.ReadUInt64()); + opponentsData.Unknown18 = br.ReadInt32(); + opponentsData.Unknown1C = br.ReadInt32(); + opponentsData.Opponent2VehicleID = new EncryptedString(br.ReadUInt64()); + opponentsData.Unknown28 = br.ReadInt32(); + opponentsData.Unknown2C = br.ReadInt32(); + opponentsData.Opponent3VehicleID = new EncryptedString(br.ReadUInt64()); + opponentsData.Unknown38 = br.ReadInt32(); + opponentsData.Unknown3C = br.ReadInt32(); + opponentsData.Opponent4VehicleID = new EncryptedString(br.ReadUInt64()); + opponentsData.Unknown48 = br.ReadInt32(); + opponentsData.Unknown4C = br.ReadInt32(); + opponentsData.Opponent5VehicleID = new EncryptedString(br.ReadUInt64()); + opponentsData.Unknown58 = br.ReadInt32(); + opponentsData.Unknown5C = br.ReadInt32(); + opponentsData.Opponent6VehicleID = new EncryptedString(br.ReadUInt64()); + opponentsData.Unknown68 = br.ReadInt32(); + opponentsData.Unknown6C = br.ReadInt32(); + opponentsData.Opponent7VehicleID = new EncryptedString(br.ReadUInt64()); + opponentsData.Unknown78 = br.ReadInt32(); + opponentsData.Unknown7C = br.ReadInt32(); + opponentsData.Opponent8VehicleID = new EncryptedString(br.ReadUInt64()); + opponentsData.Unknown88 = br.ReadInt32(); + opponentsData.NumOpponents = br.ReadInt32(); + + PlayerOpponentsDataEntries.Add(opponentsData); + } - br.Close(); - ms.Close(); + br.Close(); + ms.Close(); - return true; - } + return true; + } - public bool Write(BundleEntry entry) - { - MemoryStream ms = new MemoryStream(); - BinaryWriter2 bw = new BinaryWriter2(ms); - bw.BigEndian = entry.Console; + public bool Write(BundleEntry entry) + { + MemoryStream ms = new(); + BinaryWriter2 bw = new(ms); + bw.BigEndian = entry.Console; - // TODO: Write + // TODO: Write - bw.Flush(); - byte[] data = ms.ToArray(); - bw.Close(); - ms.Close(); + bw.Flush(); + byte[] data = ms.ToArray(); + bw.Close(); + ms.Close(); - entry.EntryBlocks[0].Data = data; - entry.Dirty = true; + entry.EntryBlocks[0].Data = data; + entry.Dirty = true; - return true; - } + return true; } } diff --git a/BaseHandlers/Renderable.cs b/BaseHandlers/Renderable.cs index 264cc17..b98986b 100644 --- a/BaseHandlers/Renderable.cs +++ b/BaseHandlers/Renderable.cs @@ -10,628 +10,627 @@ using OpenTK.Mathematics; using PluginAPI; -namespace BaseHandlers +namespace BaseHandlers; + +public struct VertexData { - public struct VertexData - { - public Vector3 Vertex; - public Vector3 Normal1; - public Vector3 Normal2; - public Vector2 UV1; - public Vector2 UV2; - public int ID1; - public int ID2; - } + public Vector3 Vertex; + public Vector3 Normal1; + public Vector3 Normal2; + public Vector2 UV1; + public Vector2 UV2; + public int ID1; + public int ID2; +} - public class RenderableMesh +public class RenderableMesh +{ + public Matrix4 RotationMatrix; + public int Unknown19; + public int Unknown20; + public int IndexOffsetCount; + public int NumVertices; + public int VertexOffsetCount; + public int NumFaces; + public int MaterialIDInternal; + public short Unknown21; + public short Unknown22; + public int NumIndicesOffset; + public int VerticesOffsetPtr; + public int[] VertexDescriptionsInternal; + + public ulong MaterialID; + public ulong[] VertexDescriptionIDs; + public VertexDesc[] VertexDescriptions; + + public int IndexOffset => IndexOffsetCount * 2; + public int IndexCount => NumFaces * 3; + + public MaterialEntry Material; + public List Indices; + public List Vertices; +} + +public class Renderable : IEntryData +{ + public static bool LoadMaterials => Config.LoadMaterials; + + private Scene _scene; + + public float Unknown1; + public float Unknown2; + public float Unknown3; + public float Unknown4; + public short Unknown5; + public short MeshCount; + public int StartOffset; + public int Unknown8; + public int Unknown9; + public short Unknown10; + public short Unknown10_1; + public int UnknownOffset; + public int Unknown12; + public int Unknown13; + public List MeshVertexOffsets; + public int NumIndices; + //public short Unknown; // Console Only (PS3, X360?) + public int Unknown15; + public int Unknown16; + public int Unknown17; + public int VertexBlockAddress; + public int Unknown18; + public int VertexBlockSize; + public List Meshes; + + public List Indices; + + public ulong ID; + public Model Model; + + public Renderable() { - public Matrix4 RotationMatrix; - public int Unknown19; - public int Unknown20; - public int IndexOffsetCount; - public int NumVertices; - public int VertexOffsetCount; - public int NumFaces; - public int MaterialIDInternal; - public short Unknown21; - public short Unknown22; - public int NumIndicesOffset; - public int VerticesOffsetPtr; - public int[] VertexDescriptionsInternal; - - public ulong MaterialID; - public ulong[] VertexDescriptionIDs; - public VertexDesc[] VertexDescriptions; - - public int IndexOffset => IndexOffsetCount * 2; - public int IndexCount => NumFaces * 3; - - public MaterialEntry Material; - public List Indices; - public List Vertices; + MeshVertexOffsets = []; + Meshes = []; + Indices = []; } - public class Renderable : IEntryData + public void BuildModel() { - public static bool LoadMaterials => Config.LoadMaterials; - - private Scene _scene; - - public float Unknown1; - public float Unknown2; - public float Unknown3; - public float Unknown4; - public short Unknown5; - public short MeshCount; - public int StartOffset; - public int Unknown8; - public int Unknown9; - public short Unknown10; - public short Unknown10_1; - public int UnknownOffset; - public int Unknown12; - public int Unknown13; - public List MeshVertexOffsets; - public int NumIndices; - //public short Unknown; // Console Only (PS3, X360?) - public int Unknown15; - public int Unknown16; - public int Unknown17; - public int VertexBlockAddress; - public int Unknown18; - public int VertexBlockSize; - public List Meshes; - - public List Indices; - - public ulong ID; - public Model Model; - - public Renderable() - { - MeshVertexOffsets = new List(); - Meshes = new List(); - Indices = new List(); - } + Mesh[] meshes = new Mesh[Meshes.Count]; - public void BuildModel() + for (int i = 0; i < meshes.Length; i++) { - Mesh[] meshes = new Mesh[Meshes.Count]; + RenderableMesh rMesh = Meshes[i]; + Mesh mesh = new(); - for (int i = 0; i < meshes.Length; i++) + if (rMesh.Material != null) { - RenderableMesh rMesh = Meshes[i]; - Mesh mesh = new Mesh(); - - if (rMesh.Material != null) - { - Color color = rMesh.Material.Color; - Image diffuse = rMesh.Material.DiffuseMap; - Image normal = rMesh.Material.NormalMap; - Image specular = rMesh.Material.SpecularMap; - - mesh.Material = new Material(rMesh.MaterialID.ToString("X8"), color, diffuse, normal, specular); - } + Color color = rMesh.Material.Color; + Image diffuse = rMesh.Material.DiffuseMap; + Image normal = rMesh.Material.NormalMap; + Image specular = rMesh.Material.SpecularMap; - mesh.Indices = rMesh.Indices; - - for (int j = 0; j < rMesh.Vertices.Count; j++) - { - VertexData data = rMesh.Vertices[j]; - mesh.Vertices.Add(data.Vertex); - mesh.Normals.Add(data.Normal1); - mesh.UV1.Add(data.UV1); - } - - meshes[i] = mesh; + mesh.Material = new Material(rMesh.MaterialID.ToString("X8"), color, diffuse, normal, specular); } - - Model = new Model(meshes); - } - public VertexData ReadVertex(BinaryReader2 br, VertexAttribute attribute) - { - switch (attribute.Size) // We don't use type here. This is wrong tbh. + mesh.Indices = rMesh.Indices; + + for (int j = 0; j < rMesh.Vertices.Count; j++) { - case 0xC: - return new VertexData() - { - Vertex = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()) - }; - case 0x20: - return new VertexData() - { - Vertex = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), - Normal1 = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), - UV1 = new Vector2(br.ReadSingle(), br.ReadSingle()) - }; - case 0x28: - return new VertexData() - { - Vertex = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), - Normal1 = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), - UV1 = new Vector2(br.ReadSingle(), br.ReadSingle()), - UV2 = new Vector2(br.ReadSingle(), br.ReadSingle()) - }; - case 0x2C: - return new VertexData() - { - Vertex = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), - Normal1 = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), - Normal2 = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), - UV2 = new Vector2(br.ReadSingle(), br.ReadSingle()) - }; - case 0x30: - return new VertexData() - { - Vertex = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), - Normal1 = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), - UV1 = new Vector2(br.ReadSingle(), br.ReadSingle()), - UV2 = new Vector2(br.ReadSingle(), br.ReadSingle()), - ID1 = br.ReadInt32(), - ID2 = br.ReadInt32() - }; - case 0x34: - return new VertexData() - { - Vertex = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), - Normal1 = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), - Normal2 = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), - UV1 = new Vector2(br.ReadSingle(), br.ReadSingle()), - ID1 = br.ReadInt32(), - ID2 = br.ReadInt32() - }; - case 0x3C: - return new VertexData() - { - Vertex = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), - Normal1 = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), - Normal2 = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), - UV1 = new Vector2(br.ReadSingle(), br.ReadSingle()), - UV2 = new Vector2(br.ReadSingle(), br.ReadSingle()), - ID1 = br.ReadInt32(), - ID2 = br.ReadInt32() - }; + VertexData data = rMesh.Vertices[j]; + mesh.Vertices.Add(data.Vertex); + mesh.Normals.Add(data.Normal1); + mesh.UV1.Add(data.UV1); } - return new VertexData(); + meshes[i] = mesh; } + + Model = new Model(meshes); + } - public void ReadBody(BinaryReader2 br) + public VertexData ReadVertex(BinaryReader2 br, VertexAttribute attribute) + { + switch (attribute.Size) // We don't use type here. This is wrong tbh. { - for (int i = 0; i < NumIndices; i++) - { - Indices.Add(br.ReadInt16()); - } + case 0xC: + return new VertexData() + { + Vertex = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()) + }; + case 0x20: + return new VertexData() + { + Vertex = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), + Normal1 = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), + UV1 = new Vector2(br.ReadSingle(), br.ReadSingle()) + }; + case 0x28: + return new VertexData() + { + Vertex = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), + Normal1 = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), + UV1 = new Vector2(br.ReadSingle(), br.ReadSingle()), + UV2 = new Vector2(br.ReadSingle(), br.ReadSingle()) + }; + case 0x2C: + return new VertexData() + { + Vertex = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), + Normal1 = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), + Normal2 = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), + UV2 = new Vector2(br.ReadSingle(), br.ReadSingle()) + }; + case 0x30: + return new VertexData() + { + Vertex = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), + Normal1 = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), + UV1 = new Vector2(br.ReadSingle(), br.ReadSingle()), + UV2 = new Vector2(br.ReadSingle(), br.ReadSingle()), + ID1 = br.ReadInt32(), + ID2 = br.ReadInt32() + }; + case 0x34: + return new VertexData() + { + Vertex = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), + Normal1 = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), + Normal2 = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), + UV1 = new Vector2(br.ReadSingle(), br.ReadSingle()), + ID1 = br.ReadInt32(), + ID2 = br.ReadInt32() + }; + case 0x3C: + return new VertexData() + { + Vertex = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), + Normal1 = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), + Normal2 = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), + UV1 = new Vector2(br.ReadSingle(), br.ReadSingle()), + UV2 = new Vector2(br.ReadSingle(), br.ReadSingle()), + ID1 = br.ReadInt32(), + ID2 = br.ReadInt32() + }; + } - for (int i = 0; i < Meshes.Count; i++) - { - RenderableMesh mesh = Meshes[i]; + return new VertexData(); + } - br.BaseStream.Position = mesh.IndexOffset; + public void ReadBody(BinaryReader2 br) + { + for (int i = 0; i < NumIndices; i++) + { + Indices.Add(br.ReadInt16()); + } - mesh.Indices = new List(); - for (int j = 0; j < mesh.IndexCount; j++) - { - uint index = br.ReadUInt16() - (uint)mesh.VertexOffsetCount; + for (int i = 0; i < Meshes.Count; i++) + { + RenderableMesh mesh = Meshes[i]; - mesh.Indices.Add(index); - } + br.BaseStream.Position = mesh.IndexOffset; - VertexAttribute attributeToUse = new VertexAttribute(); - foreach (VertexDesc desc in mesh.VertexDescriptions) - { - if (desc == null) - continue; + mesh.Indices = []; + for (int j = 0; j < mesh.IndexCount; j++) + { + uint index = br.ReadUInt16() - (uint)mesh.VertexOffsetCount; - foreach (VertexAttribute attribute in desc.Attributes) - { - if (attribute.Type != VertexAttributeType.Positions) - continue; // TODO + mesh.Indices.Add(index); + } - attributeToUse = attribute; // This is just wrong - } - } + VertexAttribute attributeToUse = new(); + foreach (VertexDesc desc in mesh.VertexDescriptions) + { + if (desc == null) + continue; - if (attributeToUse.Size == 0) + foreach (VertexAttribute attribute in desc.Attributes) { - break; - } + if (attribute.Type != VertexAttributeType.Positions) + continue; // TODO - mesh.Vertices = new List(); - br.BaseStream.Position = VertexBlockAddress + mesh.VertexOffsetCount * attributeToUse.Size + attributeToUse.Offset; - while (br.BaseStream.Position + attributeToUse.Size < br.BaseStream.Length) // Really, this should not be done like this. - { - mesh.Vertices.Add(ReadVertex(br, attributeToUse)); + attributeToUse = attribute; // This is just wrong } } - } - private void ReadBodyX64(BinaryReader2 header, BinaryReader2 br) - { - for (int i = 0; i < Meshes.Count; i++) + if (attributeToUse.Size == 0) { - RenderableMesh mesh = Meshes[i]; - mesh.Indices = new List(); - mesh.Vertices = new List(); + break; + } - VertexAttribute position = default, normal = default, uv = default; - foreach (VertexDesc desc in mesh.VertexDescriptions) - { - if (desc == null) - continue; + mesh.Vertices = []; + br.BaseStream.Position = VertexBlockAddress + mesh.VertexOffsetCount * attributeToUse.Size + attributeToUse.Offset; + while (br.BaseStream.Position + attributeToUse.Size < br.BaseStream.Length) // Really, this should not be done like this. + { + mesh.Vertices.Add(ReadVertex(br, attributeToUse)); + } + } + } - foreach (VertexAttribute attribute in desc.Attributes) - { - if (attribute.Type == VertexAttributeType.Positions) - position = attribute; - else if (attribute.Type == VertexAttributeType.Normals) - normal = attribute; - else if (attribute.Type == VertexAttributeType.UV1) - uv = attribute; - } - } + private void ReadBodyX64(BinaryReader2 header, BinaryReader2 br) + { + for (int i = 0; i < Meshes.Count; i++) + { + RenderableMesh mesh = Meshes[i]; + mesh.Indices = []; + mesh.Vertices = []; - if (position.Size == 0) + VertexAttribute position = default, normal = default, uv = default; + foreach (VertexDesc desc in mesh.VertexDescriptions) + { + if (desc == null) continue; - // DrawIndexedParameters - header.BaseStream.Position = MeshVertexOffsets[i] + 0x10; - mesh.Unknown19 = header.ReadInt32(); - mesh.Unknown20 = header.ReadInt32(); - mesh.IndexOffsetCount = header.ReadInt32(); - int indexCount = header.ReadInt32(); - header.BaseStream.Position = MeshVertexOffsets[i] + 0x29; - int instanceCount = header.ReadByte(); - if (instanceCount > 1) // only the first instance, the rest index the same vertices - indexCount = (indexCount + 1) / instanceCount; - - header.BaseStream.Position = mesh.NumIndicesOffset; - bool index32 = header.ReadInt32() < 0; - header.BaseStream.Position = mesh.NumIndicesOffset + 0x18; - int indexBase = header.ReadInt32() & ~3; - header.BaseStream.Position = mesh.VerticesOffsetPtr + 0x18; - int vertexBase = header.ReadInt32() & ~3; - header.BaseStream.Position += 4; - mesh.NumVertices = header.ReadInt32() / (int)position.Size; - - for (int j = 0; j < mesh.NumVertices; j++) + foreach (VertexAttribute attribute in desc.Attributes) { - long vertex = vertexBase + j * position.Size; - mesh.Vertices.Add(new VertexData() - { - Vertex = ReadElementX64(br, vertex, position), - Normal1 = ReadElementX64(br, vertex, normal), - UV1 = ReadElementX64(br, vertex, uv).Xy - }); + if (attribute.Type == VertexAttributeType.Positions) + position = attribute; + else if (attribute.Type == VertexAttributeType.Normals) + normal = attribute; + else if (attribute.Type == VertexAttributeType.UV1) + uv = attribute; } + } - br.BaseStream.Position = indexBase + mesh.IndexOffsetCount * (index32 ? 4 : 2); - uint a = 0, b = 0; - for (int j = 0, run = 0; j < indexCount; j++) + if (position.Size == 0) + continue; + + // DrawIndexedParameters + header.BaseStream.Position = MeshVertexOffsets[i] + 0x10; + mesh.Unknown19 = header.ReadInt32(); + mesh.Unknown20 = header.ReadInt32(); + mesh.IndexOffsetCount = header.ReadInt32(); + int indexCount = header.ReadInt32(); + header.BaseStream.Position = MeshVertexOffsets[i] + 0x29; + int instanceCount = header.ReadByte(); + if (instanceCount > 1) // only the first instance, the rest index the same vertices + indexCount = (indexCount + 1) / instanceCount; + + header.BaseStream.Position = mesh.NumIndicesOffset; + bool index32 = header.ReadInt32() < 0; + header.BaseStream.Position = mesh.NumIndicesOffset + 0x18; + int indexBase = header.ReadInt32() & ~3; + header.BaseStream.Position = mesh.VerticesOffsetPtr + 0x18; + int vertexBase = header.ReadInt32() & ~3; + header.BaseStream.Position += 4; + mesh.NumVertices = header.ReadInt32() / (int)position.Size; + + for (int j = 0; j < mesh.NumVertices; j++) + { + long vertex = vertexBase + j * position.Size; + mesh.Vertices.Add(new VertexData() { - uint index = index32 ? br.ReadUInt32() : br.ReadUInt16(); - if (index == (index32 ? uint.MaxValue : ushort.MaxValue)) // strip restart - { - run = 0; - continue; - } + Vertex = ReadElementX64(br, vertex, position), + Normal1 = ReadElementX64(br, vertex, normal), + UV1 = ReadElementX64(br, vertex, uv).Xy + }); + } - index += (uint)mesh.Unknown20; - if (mesh.Unknown19 != 6) // not a strip - mesh.Indices.Add(index); - else if (run >= 2 && a != b && b != index && a != index) // skip degenerates - mesh.Indices.AddRange(run % 2 == 0 ? new[] { a, b, index } : new[] { b, a, index }); - a = b; - b = index; - run++; + br.BaseStream.Position = indexBase + mesh.IndexOffsetCount * (index32 ? 4 : 2); + uint a = 0, b = 0; + for (int j = 0, run = 0; j < indexCount; j++) + { + uint index = index32 ? br.ReadUInt32() : br.ReadUInt16(); + if (index == (index32 ? uint.MaxValue : ushort.MaxValue)) // strip restart + { + run = 0; + continue; } - mesh.NumFaces = mesh.Indices.Count / 3; + + index += (uint)mesh.Unknown20; + if (mesh.Unknown19 != 6) // not a strip + mesh.Indices.Add(index); + else if (run >= 2 && a != b && b != index && a != index) // skip degenerates + mesh.Indices.AddRange(run % 2 == 0 ? new[] { a, b, index } : [b, a, index]); + a = b; + b = index; + run++; } + mesh.NumFaces = mesh.Indices.Count / 3; } + } - private static Vector3 ReadElementX64(BinaryReader2 br, long vertex, VertexAttribute attribute) + private static Vector3 ReadElementX64(BinaryReader2 br, long vertex, VertexAttribute attribute) + { + float Dec3N(uint value) => Math.Max(((int)(value << 22) >> 22) / 511f, -1f); // signed 10 bits + + br.BaseStream.Position = vertex + attribute.Offset; + switch (attribute.Unknown1) { - float Dec3N(uint value) => Math.Max(((int)(value << 22) >> 22) / 511f, -1f); // signed 10 bits + case 0x2A23B9: // FLOAT3 + return new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); + case 0x2C23A5: // FLOAT2 + return new Vector3(br.ReadSingle(), br.ReadSingle(), 0); + case 0x2C235F: // FLOAT16_2 + return new Vector3((float)br.ReadHalf(), (float)br.ReadHalf(), 0); + case 0x2A2187: // DEC3N + uint packed = br.ReadUInt32(); + return new Vector3(Dec3N(packed), Dec3N(packed >> 10), Dec3N(packed >> 20)); + } - br.BaseStream.Position = vertex + attribute.Offset; - switch (attribute.Unknown1) - { - case 0x2A23B9: // FLOAT3 - return new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); - case 0x2C23A5: // FLOAT2 - return new Vector3(br.ReadSingle(), br.ReadSingle(), 0); - case 0x2C235F: // FLOAT16_2 - return new Vector3((float)br.ReadHalf(), (float)br.ReadHalf(), 0); - case 0x2A2187: // DEC3N - uint packed = br.ReadUInt32(); - return new Vector3(Dec3N(packed), Dec3N(packed >> 10), Dec3N(packed >> 20)); - } + return Vector3.Zero; + } + + private void Clear() + { + _scene = null; + + Unknown1 = default; + Unknown2 = default; + Unknown3 = default; + Unknown4 = default; + Unknown5 = default; + MeshCount = default; + + StartOffset = default; + Unknown8 = default; + Unknown9 = default; + Unknown10 = default; + Unknown10_1 = default; + UnknownOffset = default; + Unknown12 = default; + Unknown13 = default; + + NumIndices = default; + Unknown15 = default; + Unknown16 = default; + Unknown17 = default; + VertexBlockAddress = default; + Unknown18 = default; + VertexBlockSize = default; + + ID = default; + Model = default; + + MeshVertexOffsets.Clear(); + Meshes.Clear(); + Indices.Clear(); + } + + public bool Read(BundleEntry entry, ILoader loader) + { + Clear(); + + List dependencies = entry.GetDependencies(); - return Vector3.Zero; + ID = entry.ID; + + MemoryStream ms = entry.MakeStream(); + BinaryReader2 br = new(ms); + br.BigEndian = entry.Console; + + bool x64 = entry.Platform == BundlePlatform.PCx64; + ulong ImportAt(long offset) => dependencies.Find(d => d.EntryPointerOffset == offset).EntryID; + + Unknown1 = br.ReadSingle(); + Unknown2 = br.ReadSingle(); + Unknown3 = br.ReadSingle(); + Unknown4 = br.ReadSingle(); + Unknown5 = br.ReadInt16(); + MeshCount = br.ReadInt16(); + if (x64) + { + br.BaseStream.Position = 0x18; + StartOffset = (int)br.ReadInt64(); + Unknown8 = (int)br.ReadInt64(); + Unknown9 = br.ReadInt32(); + } + else + { + StartOffset = br.ReadInt32(); + Unknown8 = br.ReadInt32(); + Unknown9 = br.ReadInt32(); + Unknown10 = br.ReadInt16(); + Unknown10_1 = br.ReadInt16(); + UnknownOffset = br.ReadInt32(); + Unknown12 = br.ReadInt32(); + Unknown13 = br.ReadInt32(); } - private void Clear() + br.BaseStream.Position = StartOffset; + + for (int i = 0; i < MeshCount; i++) { - _scene = null; - - Unknown1 = default; - Unknown2 = default; - Unknown3 = default; - Unknown4 = default; - Unknown5 = default; - MeshCount = default; - - StartOffset = default; - Unknown8 = default; - Unknown9 = default; - Unknown10 = default; - Unknown10_1 = default; - UnknownOffset = default; - Unknown12 = default; - Unknown13 = default; - - NumIndices = default; - Unknown15 = default; - Unknown16 = default; - Unknown17 = default; - VertexBlockAddress = default; - Unknown18 = default; - VertexBlockSize = default; - - ID = default; - Model = default; - - MeshVertexOffsets.Clear(); - Meshes.Clear(); - Indices.Clear(); + int offset = x64 ? (int)br.ReadInt64() : br.ReadInt32(); + MeshVertexOffsets.Add(offset); } - public bool Read(BundleEntry entry, ILoader loader) + if (!x64) // decomp meshes have their own index & vertex buffers { - Clear(); + /*if (entry.Platform == BundlePlatform.PS3) + { + br.BaseStream.Position += 16 - (br.BaseStream.Position % 16); + result.NumIndices = br.ReadInt16(); + result.Unknown = br.ReadInt16(); + } + else + {*/ + NumIndices = br.ReadInt32(); + //} - List dependencies = entry.GetDependencies(); + Unknown15 = br.ReadInt32(); + Unknown16 = br.ReadInt32(); + Unknown17 = br.ReadInt32(); + // some extra data here in BPR + + br.BaseStream.Position = UnknownOffset; + if (NumIndices == 0) // BPR + { + // ??? + br.BaseStream.Position += 12; + } + VertexBlockAddress = br.ReadInt32(); + Unknown18 = (NumIndices == 0) ? 0 : br.ReadInt32(); + VertexBlockSize = br.ReadInt32(); + } - ID = entry.ID; - MemoryStream ms = entry.MakeStream(); - BinaryReader2 br = new BinaryReader2(ms); - br.BigEndian = entry.Console; + for (int i = 0; i < MeshCount; i++) + { + br.BaseStream.Position = MeshVertexOffsets[i]; - bool x64 = entry.Platform == BundlePlatform.PCx64; - ulong ImportAt(long offset) => dependencies.Find(d => d.EntryPointerOffset == offset).EntryID; + RenderableMesh mesh = new(); - Unknown1 = br.ReadSingle(); - Unknown2 = br.ReadSingle(); - Unknown3 = br.ReadSingle(); - Unknown4 = br.ReadSingle(); - Unknown5 = br.ReadInt16(); - MeshCount = br.ReadInt16(); if (x64) { - br.BaseStream.Position = 0x18; - StartOffset = (int)br.ReadInt64(); - Unknown8 = (int)br.ReadInt64(); - Unknown9 = br.ReadInt32(); + mesh.MaterialID = ImportAt(MeshVertexOffsets[i] + 0x20); + br.BaseStream.Position += 0x28; + int numVD = br.ReadByte(); + br.ReadByte(); // instance count + int numVB = br.ReadByte(); + br.BaseStream.Position += 5; + mesh.NumIndicesOffset = (int)br.ReadInt64(); + mesh.VerticesOffsetPtr = (int)br.ReadInt64(); // first vertex buffer + + mesh.VertexDescriptionIDs = new ulong[numVD]; + for (int j = 0; j < numVD; j++) + mesh.VertexDescriptionIDs[j] = ImportAt(MeshVertexOffsets[i] + 0x38 + 8 * (numVB + j)); + + Meshes.Add(mesh); + continue; } - else + + mesh.RotationMatrix = br.ReadMatrix4(); + mesh.Unknown19 = br.ReadInt32(); + mesh.Unknown20 = br.ReadInt32(); + mesh.IndexOffsetCount = br.ReadInt32(); + if (NumIndices == 0) // BPR { - StartOffset = br.ReadInt32(); - Unknown8 = br.ReadInt32(); - Unknown9 = br.ReadInt32(); - Unknown10 = br.ReadInt16(); - Unknown10_1 = br.ReadInt16(); - UnknownOffset = br.ReadInt32(); - Unknown12 = br.ReadInt32(); - Unknown13 = br.ReadInt32(); + mesh.NumFaces = br.ReadInt32() / 3; } - - br.BaseStream.Position = StartOffset; - - for (int i = 0; i < MeshCount; i++) + else { - int offset = x64 ? (int)br.ReadInt64() : br.ReadInt32(); - MeshVertexOffsets.Add(offset); + mesh.NumVertices = br.ReadInt32(); + mesh.VertexOffsetCount = br.ReadInt32(); + mesh.VertexOffsetCount = 0; + mesh.NumFaces = br.ReadInt32(); } - - if (!x64) // decomp meshes have their own index & vertex buffers + int cPos = (int)br.BaseStream.Position; + mesh.MaterialIDInternal = br.ReadInt32(); + foreach (BundleDependency dependency in dependencies) { - /*if (entry.Platform == BundlePlatform.PS3) - { - br.BaseStream.Position += 16 - (br.BaseStream.Position % 16); - result.NumIndices = br.ReadInt16(); - result.Unknown = br.ReadInt16(); - } - else - {*/ - NumIndices = br.ReadInt32(); - //} - - Unknown15 = br.ReadInt32(); - Unknown16 = br.ReadInt32(); - Unknown17 = br.ReadInt32(); - // some extra data here in BPR - - br.BaseStream.Position = UnknownOffset; - if (NumIndices == 0) // BPR + if (dependency.EntryPointerOffset == cPos) { - // ??? - br.BaseStream.Position += 12; + mesh.MaterialID = dependency.EntryID; + break; } - VertexBlockAddress = br.ReadInt32(); - Unknown18 = (NumIndices == 0) ? 0 : br.ReadInt32(); - VertexBlockSize = br.ReadInt32(); } - - - for (int i = 0; i < MeshCount; i++) + mesh.Unknown21 = br.ReadInt16(); + mesh.Unknown22 = br.ReadInt16(); + mesh.NumIndicesOffset = br.ReadInt32(); + mesh.VerticesOffsetPtr = br.ReadInt32(); + + mesh.VertexDescriptionsInternal = new int[6]; + mesh.VertexDescriptionIDs = new ulong[6]; + for (int j = 0; j < mesh.VertexDescriptionsInternal.Length; j++) { - br.BaseStream.Position = MeshVertexOffsets[i]; - - RenderableMesh mesh = new RenderableMesh(); - - if (x64) - { - mesh.MaterialID = ImportAt(MeshVertexOffsets[i] + 0x20); - br.BaseStream.Position += 0x28; - int numVD = br.ReadByte(); - br.ReadByte(); // instance count - int numVB = br.ReadByte(); - br.BaseStream.Position += 5; - mesh.NumIndicesOffset = (int)br.ReadInt64(); - mesh.VerticesOffsetPtr = (int)br.ReadInt64(); // first vertex buffer - - mesh.VertexDescriptionIDs = new ulong[numVD]; - for (int j = 0; j < numVD; j++) - mesh.VertexDescriptionIDs[j] = ImportAt(MeshVertexOffsets[i] + 0x38 + 8 * (numVB + j)); - - Meshes.Add(mesh); - continue; - } - - mesh.RotationMatrix = br.ReadMatrix4(); - mesh.Unknown19 = br.ReadInt32(); - mesh.Unknown20 = br.ReadInt32(); - mesh.IndexOffsetCount = br.ReadInt32(); - if (NumIndices == 0) // BPR - { - mesh.NumFaces = br.ReadInt32() / 3; - } - else - { - mesh.NumVertices = br.ReadInt32(); - mesh.VertexOffsetCount = br.ReadInt32(); - mesh.VertexOffsetCount = 0; - mesh.NumFaces = br.ReadInt32(); - } - int cPos = (int)br.BaseStream.Position; - mesh.MaterialIDInternal = br.ReadInt32(); + int pos = (int)br.BaseStream.Position; foreach (BundleDependency dependency in dependencies) { - if (dependency.EntryPointerOffset == cPos) + if (dependency.EntryPointerOffset == pos) { - mesh.MaterialID = dependency.EntryID; + mesh.VertexDescriptionIDs[j] = dependency.EntryID; break; } } - mesh.Unknown21 = br.ReadInt16(); - mesh.Unknown22 = br.ReadInt16(); - mesh.NumIndicesOffset = br.ReadInt32(); - mesh.VerticesOffsetPtr = br.ReadInt32(); - - mesh.VertexDescriptionsInternal = new int[6]; - mesh.VertexDescriptionIDs = new ulong[6]; - for (int j = 0; j < mesh.VertexDescriptionsInternal.Length; j++) - { - int pos = (int)br.BaseStream.Position; - foreach (BundleDependency dependency in dependencies) - { - if (dependency.EntryPointerOffset == pos) - { - mesh.VertexDescriptionIDs[j] = dependency.EntryID; - break; - } - } - - mesh.VertexDescriptionsInternal[j] = br.ReadInt32(); - } - Meshes.Add(mesh); + mesh.VertexDescriptionsInternal[j] = br.ReadInt32(); } - br.Close(); - ms.Close(); - - loader?.SetStatus("Loading Meshes"); - for (int i = 0; i < Meshes.Count; i++) - { - RenderableMesh mesh = Meshes[i]; + Meshes.Add(mesh); + } - int progress = (i + 1) * 100 / Meshes.Count; + br.Close(); + ms.Close(); + + loader?.SetStatus("Loading Meshes"); + for (int i = 0; i < Meshes.Count; i++) + { + RenderableMesh mesh = Meshes[i]; + + int progress = (i + 1) * 100 / Meshes.Count; - loader?.SetStatus("Loading Meshes: " + (i + 1) + "/" + Meshes.Count); - loader?.SetProgress(progress); + loader?.SetStatus("Loading Meshes: " + (i + 1) + "/" + Meshes.Count); + loader?.SetProgress(progress); - if (LoadMaterials) + if (LoadMaterials) + { + BundleEntry descEntry1 = entry.Archive.GetEntryByID(mesh.MaterialID); + if (descEntry1 == null) { - BundleEntry descEntry1 = entry.Archive.GetEntryByID(mesh.MaterialID); - if (descEntry1 == null) + string file = BundleCache.GetFileByEntryID(mesh.MaterialID); + if (!string.IsNullOrEmpty(file)) { - string file = BundleCache.GetFileByEntryID(mesh.MaterialID); - if (!string.IsNullOrEmpty(file)) - { - BundleArchive archive = BundleArchive.Read(file); - descEntry1 = archive.GetEntryByID(mesh.MaterialID); - } + BundleArchive archive = BundleArchive.Read(file); + descEntry1 = archive.GetEntryByID(mesh.MaterialID); } - - if (descEntry1 != null) - mesh.Material = MaterialEntry.Read(descEntry1); } - mesh.VertexDescriptions = new VertexDesc[mesh.VertexDescriptionIDs.Length]; - for (int j = 0; j < mesh.VertexDescriptions.Length; j++) + if (descEntry1 != null) + mesh.Material = MaterialEntry.Read(descEntry1); + } + + mesh.VertexDescriptions = new VertexDesc[mesh.VertexDescriptionIDs.Length]; + for (int j = 0; j < mesh.VertexDescriptions.Length; j++) + { + ulong vertexDescID = mesh.VertexDescriptionIDs[j]; + BundleEntry descEntry = entry.Archive.GetEntryByID(vertexDescID); + if (descEntry == null) { - ulong vertexDescID = mesh.VertexDescriptionIDs[j]; - BundleEntry descEntry = entry.Archive.GetEntryByID(vertexDescID); - if (descEntry == null) + string file = BundleCache.GetFileByEntryID(vertexDescID); + if (!string.IsNullOrEmpty(file)) { - string file = BundleCache.GetFileByEntryID(vertexDescID); - if (!string.IsNullOrEmpty(file)) - { - BundleArchive archive = BundleArchive.Read(file); - descEntry = archive.GetEntryByID(vertexDescID); - } + BundleArchive archive = BundleArchive.Read(file); + descEntry = archive.GetEntryByID(vertexDescID); } - - if (descEntry != null) - mesh.VertexDescriptions[j] = VertexDesc.Read(descEntry); } + + if (descEntry != null) + mesh.VertexDescriptions[j] = VertexDesc.Read(descEntry); } + } - ms = entry.MakeStream(true); - br = new BinaryReader2(ms); - br.BigEndian = entry.Console; - if (x64) - ReadBodyX64(new BinaryReader2(entry.MakeStream()), br); - else - ReadBody(br); - br.Close(); - ms.Close(); + ms = entry.MakeStream(true); + br = new BinaryReader2(ms); + br.BigEndian = entry.Console; + if (x64) + ReadBodyX64(new BinaryReader2(entry.MakeStream()), br); + else + ReadBody(br); + br.Close(); + ms.Close(); - BuildModel(); + BuildModel(); - _scene = MakeScene(loader); + _scene = MakeScene(loader); - return true; - } + return true; + } - public bool Write(BundleEntry entry) - { - return true; - } + public bool Write(BundleEntry entry) + { + return true; + } - public EntryType GetEntryType(BundleEntry entry) - { - return EntryType.Renderable; - } + public EntryType GetEntryType(BundleEntry entry) + { + return EntryType.Renderable; + } - public IEntryEditor GetEditor(BundleEntry entry) - { - ModelViewerForm viewer = new ModelViewerForm(); - viewer.Renderer.Scene = _scene; + public IEntryEditor GetEditor(BundleEntry entry) + { + ModelViewerForm viewer = new(); + viewer.Renderer.Scene = _scene; - return viewer; - } + return viewer; + } - public Scene MakeScene(ILoader loader = null) - { - Scene scene = new Scene(); - SceneObject obj = new SceneObject(ID.ToString("X8"), Model); - scene.AddObject(obj); + public Scene MakeScene(ILoader loader = null) + { + Scene scene = new(); + SceneObject obj = new(ID.ToString("X8"), Model); + scene.AddObject(obj); - return scene; - } + return scene; } } diff --git a/BaseHandlers/StreetData.cs b/BaseHandlers/StreetData.cs index edb409a..7cf29d3 100644 --- a/BaseHandlers/StreetData.cs +++ b/BaseHandlers/StreetData.cs @@ -9,667 +9,666 @@ using OpenTK.Mathematics; using PluginAPI; -namespace BaseHandlers +namespace BaseHandlers; + +// Layout reference: https://burnout.wiki/wiki/Street_Data +// 32-bit PC and the decomp (PCx64). The decomp is version 5 with 8-byte +// pointers (b5-decomp BrnStreetData.h): the header pointers, +// Junction::mpaExits and Road::mpaSpans widen, and Road has no trailing +// unknown field. 64-bit (Remastered) and big-endian (X360/PS3) are not +// yet handled. + +public class ScoreList { - // Layout reference: https://burnout.wiki/wiki/Street_Data - // 32-bit PC and the decomp (PCx64). The decomp is version 5 with 8-byte - // pointers (b5-decomp BrnStreetData.h): the header pointers, - // Junction::mpaExits and Road::mpaSpans widen, and Road has no trailing - // unknown field. 64-bit (Remastered) and big-endian (X360/PS3) are not - // yet handled. + public int[] maScores { get; set; } = new int[2]; // 0x0 0x8 int32_t[2] maScores - public class ScoreList + public int Score0 + { + get => maScores[0]; + set => maScores[0] = value; + } + public int Score1 { - public int[] maScores { get; set; } = new int[2]; // 0x0 0x8 int32_t[2] maScores + get => maScores[1]; + set => maScores[1] = value; + } - public int Score0 - { - get => maScores[0]; - set => maScores[0] = value; - } - public int Score1 - { - get => maScores[1]; - set => maScores[1] = value; - } + public void Read(BinaryReader2 br) + { + maScores[0] = br.ReadInt32(); + maScores[1] = br.ReadInt32(); + } - public void Read(BinaryReader2 br) - { - maScores[0] = br.ReadInt32(); - maScores[1] = br.ReadInt32(); - } + public void Write(BinaryWriter2 bw) + { + bw.Write(maScores[0]); + bw.Write(maScores[1]); + } - public void Write(BinaryWriter2 bw) - { - bw.Write(maScores[0]); - bw.Write(maScores[1]); - } + public override string ToString() => "[" + maScores[0] + ", " + maScores[1] + "]"; +} - public override string ToString() => "[" + maScores[0] + ", " + maScores[1] + "]"; +public class ChallengeData +{ + public byte[] mDirty { get; set; } = new byte[8]; // 0x0 0x8 BitArray<2u> mDirty + public byte[] mValidScore { get; set; } = new byte[8]; // 0x8 0x8 BitArray<2u> mValidScores + public ScoreList mScoreList { get; set; } = new ScoreList(); // 0x10 0x8 + + public void Read(BinaryReader2 br) + { + mDirty = br.ReadBytes(8); + mValidScore = br.ReadBytes(8); + mScoreList.Read(br); } - public class ChallengeData + public void Write(BinaryWriter2 bw) { - public byte[] mDirty { get; set; } = new byte[8]; // 0x0 0x8 BitArray<2u> mDirty - public byte[] mValidScore { get; set; } = new byte[8]; // 0x8 0x8 BitArray<2u> mValidScores - public ScoreList mScoreList { get; set; } = new ScoreList(); // 0x10 0x8 + bw.Write(EnsureLen(mDirty, 8)); + bw.Write(EnsureLen(mValidScore, 8)); + mScoreList.Write(bw); + } - public void Read(BinaryReader2 br) - { - mDirty = br.ReadBytes(8); - mValidScore = br.ReadBytes(8); - mScoreList.Read(br); - } + private static byte[] EnsureLen(byte[] a, int n) + { + if (a != null && a.Length == n) return a; + byte[] r = new byte[n]; + if (a != null) Array.Copy(a, r, Math.Min(a.Length, n)); + return r; + } +} - public void Write(BinaryWriter2 bw) - { - bw.Write(EnsureLen(mDirty, 8)); - bw.Write(EnsureLen(mValidScore, 8)); - mScoreList.Write(bw); - } +public class Exit +{ + public short mSpan { get; set; } // 0x0 0x2 SpanIndex mSpan + [Browsable(false)] + public byte[] padding { get; set; } = new byte[2]; // 0x2 0x2 + public float mrAngle { get; set; } // 0x4 0x4 float - private static byte[] EnsureLen(byte[] a, int n) - { - if (a != null && a.Length == n) return a; - byte[] r = new byte[n]; - if (a != null) Array.Copy(a, r, Math.Min(a.Length, n)); - return r; - } + public override string ToString() => "Exit(span=" + mSpan + ", angle=" + mrAngle + ")"; + + public void Read(BinaryReader2 br) + { + mSpan = br.ReadInt16(); + padding = br.ReadBytes(2); + mrAngle = br.ReadSingle(); } - public class Exit + public void Write(BinaryWriter2 bw) { - public short mSpan { get; set; } // 0x0 0x2 SpanIndex mSpan - [Browsable(false)] - public byte[] padding { get; set; } = new byte[2]; // 0x2 0x2 - public float mrAngle { get; set; } // 0x4 0x4 float + bw.Write(mSpan); + bw.Write(padding != null && padding.Length == 2 ? padding : new byte[2]); + bw.Write(mrAngle); + } +} - public override string ToString() => "Exit(span=" + mSpan + ", angle=" + mrAngle + ")"; +public class AIInfo +{ + public byte muMaxSpeedMPS { get; set; } // 0x0 0x1 + public byte muMinSpeedMPS { get; set; } // 0x1 0x1 - public void Read(BinaryReader2 br) - { - mSpan = br.ReadInt16(); - padding = br.ReadBytes(2); - mrAngle = br.ReadSingle(); - } + public override string ToString() => "AI(max=" + muMaxSpeedMPS + ", min=" + muMinSpeedMPS + ")"; - public void Write(BinaryWriter2 bw) - { - bw.Write(mSpan); - bw.Write(padding != null && padding.Length == 2 ? padding : new byte[2]); - bw.Write(mrAngle); - } + public void Read(BinaryReader2 br) + { + muMaxSpeedMPS = br.ReadByte(); + muMinSpeedMPS = br.ReadByte(); } - public class AIInfo + public void Write(BinaryWriter2 bw) { - public byte muMaxSpeedMPS { get; set; } // 0x0 0x1 - public byte muMinSpeedMPS { get; set; } // 0x1 0x1 + bw.Write(muMaxSpeedMPS); + bw.Write(muMinSpeedMPS); + } +} - public override string ToString() => "AI(max=" + muMaxSpeedMPS + ", min=" + muMinSpeedMPS + ")"; +public enum ESpanType +{ + Street = 0, + Junction = 1, + Span_Type_Count = 2, +} - public void Read(BinaryReader2 br) - { - muMaxSpeedMPS = br.ReadByte(); - muMinSpeedMPS = br.ReadByte(); - } +public class SpanBase +{ + public int miRoadIndex { get; set; } // 0x0 0x4 + public short miSpanIndex { get; set; } // 0x4 0x2 + [Browsable(false)] + public byte[] padding { get; set; } = new byte[2]; // 0x6 0x2 + public ESpanType meSpanType { get; set; }// 0x8 0x4 - public void Write(BinaryWriter2 bw) - { - bw.Write(muMaxSpeedMPS); - bw.Write(muMinSpeedMPS); - } + public override string ToString() => + meSpanType + "(road=" + miRoadIndex + ", span=" + miSpanIndex + ")"; + + public void Read(BinaryReader2 br) + { + miRoadIndex = br.ReadInt32(); + miSpanIndex = br.ReadInt16(); + padding = br.ReadBytes(2); + meSpanType = (ESpanType)br.ReadInt32(); } - public enum ESpanType + public void Write(BinaryWriter2 bw) { - Street = 0, - Junction = 1, - Span_Type_Count = 2, + bw.Write(miRoadIndex); + bw.Write(miSpanIndex); + bw.Write(padding != null && padding.Length == 2 ? padding : new byte[2]); + bw.Write((int)meSpanType); } +} - public class SpanBase +public class Street +{ + public SpanBase super_SpanBase { get; set; } = new SpanBase(); // 0x0 0xC + public AIInfo mAiInfo { get; set; } = new AIInfo(); // 0xC 0x2 + [Browsable(false)] + public byte[] padding { get; set; } = new byte[2]; // 0xE 0x2 + + public int RoadIndex + { + get => super_SpanBase.miRoadIndex; + set => super_SpanBase.miRoadIndex = value; + } + public short SpanIndex + { + get => super_SpanBase.miSpanIndex; + set => super_SpanBase.miSpanIndex = value; + } + public ESpanType SpanType + { + get => super_SpanBase.meSpanType; + set => super_SpanBase.meSpanType = value; + } + public byte MaxSpeedMPS + { + get => mAiInfo.muMaxSpeedMPS; + set => mAiInfo.muMaxSpeedMPS = value; + } + public byte MinSpeedMPS { - public int miRoadIndex { get; set; } // 0x0 0x4 - public short miSpanIndex { get; set; } // 0x4 0x2 - [Browsable(false)] - public byte[] padding { get; set; } = new byte[2]; // 0x6 0x2 - public ESpanType meSpanType { get; set; }// 0x8 0x4 + get => mAiInfo.muMinSpeedMPS; + set => mAiInfo.muMinSpeedMPS = value; + } - public override string ToString() => - meSpanType + "(road=" + miRoadIndex + ", span=" + miSpanIndex + ")"; + public void Read(BinaryReader2 br) + { + super_SpanBase.Read(br); + mAiInfo.Read(br); + padding = br.ReadBytes(2); + } - public void Read(BinaryReader2 br) - { - miRoadIndex = br.ReadInt32(); - miSpanIndex = br.ReadInt16(); - padding = br.ReadBytes(2); - meSpanType = (ESpanType)br.ReadInt32(); - } + public void Write(BinaryWriter2 bw) + { + super_SpanBase.Write(bw); + mAiInfo.Write(bw); + bw.Write(padding != null && padding.Length == 2 ? padding : new byte[2]); + } +} - public void Write(BinaryWriter2 bw) - { - bw.Write(miRoadIndex); - bw.Write(miSpanIndex); - bw.Write(padding != null && padding.Length == 2 ? padding : new byte[2]); - bw.Write((int)meSpanType); - } +public class Junction +{ + public SpanBase super_SpanBase { get; set; } = new SpanBase(); // 0x0 0xC + // mpaExits / miExitCount are written as 0 by the writer because the + // game's StreetData::FixUp() corrupts the per-junction exit arrays + // (see Write() for details), so the on-disk values are unreliable. + // Kept on the type so the reader can still inspect the original + // pointer if a tool wants to. + [Browsable(false)] + public int mpaExits { get; set; } // 0xC 0x4 (32-bit) + [Browsable(false)] + public int miExitCount { get; set; } // 0x10 0x4 + public string macName { get; set; } // 0x14 0x10 + // Decomp only, see StreetData.Write. + [Browsable(false)] + public Exit[] maExits { get; set; } = []; + + public int RoadIndex + { + get => super_SpanBase.miRoadIndex; + set => super_SpanBase.miRoadIndex = value; + } + public short SpanIndex + { + get => super_SpanBase.miSpanIndex; + set => super_SpanBase.miSpanIndex = value; + } + public ESpanType SpanType + { + get => super_SpanBase.meSpanType; + set => super_SpanBase.meSpanType = value; + } + public string Name + { + get => (macName ?? string.Empty).TrimEnd('\0'); + set => macName = value ?? string.Empty; } - public class Street + public void Read(BinaryReader2 br, bool x64) { - public SpanBase super_SpanBase { get; set; } = new SpanBase(); // 0x0 0xC - public AIInfo mAiInfo { get; set; } = new AIInfo(); // 0xC 0x2 - [Browsable(false)] - public byte[] padding { get; set; } = new byte[2]; // 0xE 0x2 + super_SpanBase.Read(br); + if (x64) + br.ReadInt32(); // padding + mpaExits = x64 ? (int)br.ReadInt64() : br.ReadInt32(); + miExitCount = br.ReadInt32(); + macName = Encoding.ASCII.GetString(br.ReadBytes(16)); + // Intentionally NOT reading the exit array. StreetData::FixUp() + // in retail Burnout Paradise overwrites large parts of that + // region (see StreetData.Write for the writeup), so the on-disk + // bytes are not reliable Exit structs. + if (!x64) + return; + br.ReadInt32(); // padding + + // The decomp's are kept as-is + long pos = br.BaseStream.Position; + br.BaseStream.Position = mpaExits; + maExits = new Exit[miExitCount]; + for (int i = 0; i < miExitCount; i++) + { + maExits[i] = new Exit(); + maExits[i].Read(br); + } + br.BaseStream.Position = pos; + } - public int RoadIndex - { - get => super_SpanBase.miRoadIndex; - set => super_SpanBase.miRoadIndex = value; - } - public short SpanIndex - { - get => super_SpanBase.miSpanIndex; - set => super_SpanBase.miSpanIndex = value; - } - public ESpanType SpanType - { - get => super_SpanBase.meSpanType; - set => super_SpanBase.meSpanType = value; - } - public byte MaxSpeedMPS - { - get => mAiInfo.muMaxSpeedMPS; - set => mAiInfo.muMaxSpeedMPS = value; - } - public byte MinSpeedMPS + public void Write(BinaryWriter2 bw, bool x64) + { + super_SpanBase.Write(bw); + if (x64) { - get => mAiInfo.muMinSpeedMPS; - set => mAiInfo.muMinSpeedMPS = value; + bw.Write(0); // padding + bw.Write(0L); // mpaExits, patched by StreetData.Write + bw.Write(maExits.Length); } - - public void Read(BinaryReader2 br) + else { - super_SpanBase.Read(br); - mAiInfo.Read(br); - padding = br.ReadBytes(2); + // Always emit zeroed pointer + count. The game ignores these + // (the responsibilities live in AI Sections / Traffic Data / + // Trigger Data / collision resources) and Burnout's FixUp bug + // means the original on-disk values point at corrupt memory. + bw.Write(0); + bw.Write(0); } + bw.Write(PadName(macName, 16)); + if (x64) + bw.Write(0); // padding + } - public void Write(BinaryWriter2 bw) + internal static byte[] PadName(string name, int len) + { + byte[] buf = new byte[len]; + if (name != null) { - super_SpanBase.Write(bw); - mAiInfo.Write(bw); - bw.Write(padding != null && padding.Length == 2 ? padding : new byte[2]); + byte[] src = Encoding.ASCII.GetBytes(name); + Array.Copy(src, buf, Math.Min(src.Length, len)); } + return buf; } +} - public class Junction - { - public SpanBase super_SpanBase { get; set; } = new SpanBase(); // 0x0 0xC - // mpaExits / miExitCount are written as 0 by the writer because the - // game's StreetData::FixUp() corrupts the per-junction exit arrays - // (see Write() for details), so the on-disk values are unreliable. - // Kept on the type so the reader can still inspect the original - // pointer if a tool wants to. - [Browsable(false)] - public int mpaExits { get; set; } // 0xC 0x4 (32-bit) - [Browsable(false)] - public int miExitCount { get; set; } // 0x10 0x4 - public string macName { get; set; } // 0x14 0x10 - // Decomp only, see StreetData.Write. - [Browsable(false)] - public Exit[] maExits { get; set; } = Array.Empty(); - - public int RoadIndex - { - get => super_SpanBase.miRoadIndex; - set => super_SpanBase.miRoadIndex = value; - } - public short SpanIndex +public class Road +{ + public Vector3 mReferencePosition { get; set; } // 0x0 0xC + [Browsable(false)] + public int mpaSpans { get; set; } // 0xC 0x4 (32-bit) + public long mId { get; set; } // 0x10 0x8 + public long miRoadLimitId0 { get; set; } // 0x18 0x8 + public long miRoadLimitId1 { get; set; } // 0x20 0x8 + public string macDebugName { get; set; } // 0x28 0x10 + public int mChallenge { get; set; } // 0x38 0x4 + // miSpanCount is written as 0; see Write() for the rationale. + [Browsable(false)] + public int miSpanCount { get; set; } // 0x3C 0x4 + public int unknown { get; set; } // 0x40 0x4 (spec: uint32, always 1) + [Browsable(false)] + public byte[] padding { get; set; } = new byte[4]; // 0x44 0x4 + // Decomp only, see StreetData.Write. + [Browsable(false)] + public short[] maSpans { get; set; } = []; + + public string DebugName + { + get => (macDebugName ?? string.Empty).TrimEnd('\0'); + set => macDebugName = value ?? string.Empty; + } + public float RefX + { + get => mReferencePosition.X; + set { - get => super_SpanBase.miSpanIndex; - set => super_SpanBase.miSpanIndex = value; + Vector3 v = mReferencePosition; + v.X = value; + mReferencePosition = v; } - public ESpanType SpanType + } + public float RefY + { + get => mReferencePosition.Y; + set { - get => super_SpanBase.meSpanType; - set => super_SpanBase.meSpanType = value; + Vector3 v = mReferencePosition; + v.Y = value; + mReferencePosition = v; } - public string Name + } + public float RefZ + { + get => mReferencePosition.Z; + set { - get => (macName ?? string.Empty).TrimEnd('\0'); - set => macName = value ?? string.Empty; + Vector3 v = mReferencePosition; + v.Z = value; + mReferencePosition = v; } + } - public void Read(BinaryReader2 br, bool x64) - { - super_SpanBase.Read(br); - if (x64) - br.ReadInt32(); // padding - mpaExits = x64 ? (int)br.ReadInt64() : br.ReadInt32(); - miExitCount = br.ReadInt32(); - macName = Encoding.ASCII.GetString(br.ReadBytes(16)); - // Intentionally NOT reading the exit array. StreetData::FixUp() - // in retail Burnout Paradise overwrites large parts of that - // region (see StreetData.Write for the writeup), so the on-disk - // bytes are not reliable Exit structs. - if (!x64) - return; + public void Read(BinaryReader2 br, bool x64) + { + mReferencePosition = br.ReadVector3F(); + if (x64) br.ReadInt32(); // padding - - // The decomp's are kept as-is + mpaSpans = x64 ? (int)br.ReadInt64() : br.ReadInt32(); + mId = br.ReadInt64(); + miRoadLimitId0 = br.ReadInt64(); + miRoadLimitId1 = br.ReadInt64(); + macDebugName = Encoding.ASCII.GetString(br.ReadBytes(16)); + mChallenge = br.ReadInt32(); + miSpanCount = br.ReadInt32(); + if (x64) + { + // Version 5 ends here. Its span array is kept as-is long pos = br.BaseStream.Position; - br.BaseStream.Position = mpaExits; - maExits = new Exit[miExitCount]; - for (int i = 0; i < miExitCount; i++) - { - maExits[i] = new Exit(); - maExits[i].Read(br); - } + br.BaseStream.Position = mpaSpans; + maSpans = new short[miSpanCount]; + for (int i = 0; i < miSpanCount; i++) + maSpans[i] = br.ReadInt16(); br.BaseStream.Position = pos; + return; } + unknown = br.ReadInt32(); + padding = br.ReadBytes(4); + // Intentionally NOT reading the per-road span array. See + // StreetData.Write for the FixUp corruption details. + } - public void Write(BinaryWriter2 bw, bool x64) - { - super_SpanBase.Write(bw); - if (x64) - { - bw.Write(0); // padding - bw.Write(0L); // mpaExits, patched by StreetData.Write - bw.Write(maExits.Length); - } - else - { - // Always emit zeroed pointer + count. The game ignores these - // (the responsibilities live in AI Sections / Traffic Data / - // Trigger Data / collision resources) and Burnout's FixUp bug - // means the original on-disk values point at corrupt memory. - bw.Write(0); - bw.Write(0); - } - bw.Write(PadName(macName, 16)); - if (x64) - bw.Write(0); // padding - } - - internal static byte[] PadName(string name, int len) - { - byte[] buf = new byte[len]; - if (name != null) - { - byte[] src = Encoding.ASCII.GetBytes(name); - Array.Copy(src, buf, Math.Min(src.Length, len)); - } - return buf; - } + public void Write(BinaryWriter2 bw, bool x64) + { + bw.Write(mReferencePosition.X); + bw.Write(mReferencePosition.Y); + bw.Write(mReferencePosition.Z); + if (x64) + { + bw.Write(0); // padding + bw.Write(0L); // mpaSpans, patched by StreetData.Write + } + else + bw.Write(0); // Always emit zeroed pointer + count. See Junction.Write. + bw.Write(mId); + bw.Write(miRoadLimitId0); + bw.Write(miRoadLimitId1); + bw.Write(Junction.PadName(macDebugName, 16)); + bw.Write(mChallenge); + bw.Write(x64 ? maSpans.Length : 0); + if (x64) + return; + bw.Write(unknown); + bw.Write(padding != null && padding.Length == 4 ? padding : new byte[4]); } +} - public class Road - { - public Vector3 mReferencePosition { get; set; } // 0x0 0xC - [Browsable(false)] - public int mpaSpans { get; set; } // 0xC 0x4 (32-bit) - public long mId { get; set; } // 0x10 0x8 - public long miRoadLimitId0 { get; set; } // 0x18 0x8 - public long miRoadLimitId1 { get; set; } // 0x20 0x8 - public string macDebugName { get; set; } // 0x28 0x10 - public int mChallenge { get; set; } // 0x38 0x4 - // miSpanCount is written as 0; see Write() for the rationale. - [Browsable(false)] - public int miSpanCount { get; set; } // 0x3C 0x4 - public int unknown { get; set; } // 0x40 0x4 (spec: uint32, always 1) - [Browsable(false)] - public byte[] padding { get; set; } = new byte[4]; // 0x44 0x4 - // Decomp only, see StreetData.Write. - [Browsable(false)] - public short[] maSpans { get; set; } = Array.Empty(); - - public string DebugName - { - get => (macDebugName ?? string.Empty).TrimEnd('\0'); - set => macDebugName = value ?? string.Empty; - } - public float RefX - { - get => mReferencePosition.X; - set - { - Vector3 v = mReferencePosition; - v.X = value; - mReferencePosition = v; - } - } - public float RefY - { - get => mReferencePosition.Y; - set - { - Vector3 v = mReferencePosition; - v.Y = value; - mReferencePosition = v; - } - } - public float RefZ - { - get => mReferencePosition.Z; - set - { - Vector3 v = mReferencePosition; - v.Z = value; - mReferencePosition = v; - } - } +public class ChallengeParScores +{ + public ChallengeData challengeData { get; set; } = new ChallengeData(); // 0x0 0x18 + public long[] mRivals { get; set; } = new long[2]; // 0x18 0x10 - public void Read(BinaryReader2 br, bool x64) - { - mReferencePosition = br.ReadVector3F(); - if (x64) - br.ReadInt32(); // padding - mpaSpans = x64 ? (int)br.ReadInt64() : br.ReadInt32(); - mId = br.ReadInt64(); - miRoadLimitId0 = br.ReadInt64(); - miRoadLimitId1 = br.ReadInt64(); - macDebugName = Encoding.ASCII.GetString(br.ReadBytes(16)); - mChallenge = br.ReadInt32(); - miSpanCount = br.ReadInt32(); - if (x64) - { - // Version 5 ends here. Its span array is kept as-is - long pos = br.BaseStream.Position; - br.BaseStream.Position = mpaSpans; - maSpans = new short[miSpanCount]; - for (int i = 0; i < miSpanCount; i++) - maSpans[i] = br.ReadInt16(); - br.BaseStream.Position = pos; - return; - } - unknown = br.ReadInt32(); - padding = br.ReadBytes(4); - // Intentionally NOT reading the per-road span array. See - // StreetData.Write for the FixUp corruption details. - } + public int Score0 + { + get => challengeData.mScoreList.maScores[0]; + set => challengeData.mScoreList.maScores[0] = value; + } + public int Score1 + { + get => challengeData.mScoreList.maScores[1]; + set => challengeData.mScoreList.maScores[1] = value; + } + public long Rival0 + { + get => mRivals[0]; + set => mRivals[0] = value; + } + public long Rival1 + { + get => mRivals[1]; + set => mRivals[1] = value; + } - public void Write(BinaryWriter2 bw, bool x64) - { - bw.Write(mReferencePosition.X); - bw.Write(mReferencePosition.Y); - bw.Write(mReferencePosition.Z); - if (x64) - { - bw.Write(0); // padding - bw.Write(0L); // mpaSpans, patched by StreetData.Write - } - else - bw.Write(0); // Always emit zeroed pointer + count. See Junction.Write. - bw.Write(mId); - bw.Write(miRoadLimitId0); - bw.Write(miRoadLimitId1); - bw.Write(Junction.PadName(macDebugName, 16)); - bw.Write(mChallenge); - bw.Write(x64 ? maSpans.Length : 0); - if (x64) - return; - bw.Write(unknown); - bw.Write(padding != null && padding.Length == 4 ? padding : new byte[4]); - } + public void Read(BinaryReader2 br) + { + challengeData.Read(br); + mRivals[0] = br.ReadInt64(); + mRivals[1] = br.ReadInt64(); } - public class ChallengeParScores + public void Write(BinaryWriter2 bw) { - public ChallengeData challengeData { get; set; } = new ChallengeData(); // 0x0 0x18 - public long[] mRivals { get; set; } = new long[2]; // 0x18 0x10 + challengeData.Write(bw); + bw.Write(mRivals[0]); + bw.Write(mRivals[1]); + } +} - public int Score0 - { - get => challengeData.mScoreList.maScores[0]; - set => challengeData.mScoreList.maScores[0] = value; - } - public int Score1 - { - get => challengeData.mScoreList.maScores[1]; - set => challengeData.mScoreList.maScores[1] = value; - } - public long Rival0 - { - get => mRivals[0]; - set => mRivals[0] = value; - } - public long Rival1 - { - get => mRivals[1]; - set => mRivals[1] = value; - } +public class StreetData : IEntryData +{ + public int miVersion; // 0x0 0x4 (expected 6) + public int mpaStreets; // 0x8 0x4 + public int mpaJunctions; // 0xC 0x4 + public int mpaRoads; // 0x10 0x4 + public int mpaChallengeParScores; // 0x14 0x4 - public void Read(BinaryReader2 br) - { - challengeData.Read(br); - mRivals[0] = br.ReadInt64(); - mRivals[1] = br.ReadInt64(); - } + public List streets = []; + public List junctions = []; + public List roads = []; + public List challenges = []; - public void Write(BinaryWriter2 bw) - { - challengeData.Write(bw); - bw.Write(mRivals[0]); - bw.Write(mRivals[1]); - } + private const int SIZEOF_CHALLENGE_PAR_SCORES_ENTRY = 0x28; + + private void Clear() + { + miVersion = 0; + mpaStreets = 0; + mpaJunctions = 0; + mpaRoads = 0; + mpaChallengeParScores = 0; + streets.Clear(); + junctions.Clear(); + roads.Clear(); + challenges.Clear(); } - public class StreetData : IEntryData + public bool Read(BundleEntry entry, ILoader loader = null) { - public int miVersion; // 0x0 0x4 (expected 6) - public int mpaStreets; // 0x8 0x4 - public int mpaJunctions; // 0xC 0x4 - public int mpaRoads; // 0x10 0x4 - public int mpaChallengeParScores; // 0x14 0x4 + Clear(); + + MemoryStream ms = new(entry.EntryBlocks[0].Data); + BinaryReader2 br = new(ms); + br.BigEndian = entry.Console; - public List streets = new List(); - public List junctions = new List(); - public List roads = new List(); - public List challenges = new List(); + bool x64 = entry.Platform == BundlePlatform.PCx64; + int ReadPtr() => x64 ? (int)br.ReadInt64() : br.ReadInt32(); - private const int SIZEOF_CHALLENGE_PAR_SCORES_ENTRY = 0x28; + miVersion = br.ReadInt32(); + br.ReadInt32(); // miSize, recomputed on write + mpaStreets = ReadPtr(); + mpaJunctions = ReadPtr(); + mpaRoads = ReadPtr(); + mpaChallengeParScores = ReadPtr(); + int miStreetCount = br.ReadInt32(); + int miJunctionCount = br.ReadInt32(); + int miRoadCount = br.ReadInt32(); - private void Clear() + br.BaseStream.Position = mpaStreets; + for (int i = 0; i < miStreetCount; i++) { - miVersion = 0; - mpaStreets = 0; - mpaJunctions = 0; - mpaRoads = 0; - mpaChallengeParScores = 0; - streets.Clear(); - junctions.Clear(); - roads.Clear(); - challenges.Clear(); + Street s = new(); + s.Read(br); + streets.Add(s); } - public bool Read(BundleEntry entry, ILoader loader = null) + br.BaseStream.Position = mpaJunctions; + for (int i = 0; i < miJunctionCount; i++) { - Clear(); - - MemoryStream ms = new MemoryStream(entry.EntryBlocks[0].Data); - BinaryReader2 br = new BinaryReader2(ms); - br.BigEndian = entry.Console; - - bool x64 = entry.Platform == BundlePlatform.PCx64; - int ReadPtr() => x64 ? (int)br.ReadInt64() : br.ReadInt32(); - - miVersion = br.ReadInt32(); - br.ReadInt32(); // miSize, recomputed on write - mpaStreets = ReadPtr(); - mpaJunctions = ReadPtr(); - mpaRoads = ReadPtr(); - mpaChallengeParScores = ReadPtr(); - int miStreetCount = br.ReadInt32(); - int miJunctionCount = br.ReadInt32(); - int miRoadCount = br.ReadInt32(); - - br.BaseStream.Position = mpaStreets; - for (int i = 0; i < miStreetCount; i++) - { - Street s = new Street(); - s.Read(br); - streets.Add(s); - } + Junction j = new(); + j.Read(br, x64); + junctions.Add(j); + } - br.BaseStream.Position = mpaJunctions; - for (int i = 0; i < miJunctionCount; i++) - { - Junction j = new Junction(); - j.Read(br, x64); - junctions.Add(j); - } + br.BaseStream.Position = mpaRoads; + for (int i = 0; i < miRoadCount; i++) + { + Road r = new(); + r.Read(br, x64); + roads.Add(r); + } - br.BaseStream.Position = mpaRoads; - for (int i = 0; i < miRoadCount; i++) - { - Road r = new Road(); - r.Read(br, x64); - roads.Add(r); - } + // The header has no miChallengeCount; FixUp() in retail Burnout + // Paradise constructs miJunctionCount BitArrays here even though + // there are only miRoadCount real entries (this is a game bug - + // it should iterate miRoadCount times). The on-disk allocation + // matches the game allocation, so the file holds miRoadCount + // entries here followed by partially-corrupt bytes. + br.BaseStream.Position = mpaChallengeParScores; + for (int i = 0; i < miRoadCount; i++) + { + ChallengeParScores c = new(); + c.Read(br); + challenges.Add(c); + } - // The header has no miChallengeCount; FixUp() in retail Burnout - // Paradise constructs miJunctionCount BitArrays here even though - // there are only miRoadCount real entries (this is a game bug - - // it should iterate miRoadCount times). The on-disk allocation - // matches the game allocation, so the file holds miRoadCount - // entries here followed by partially-corrupt bytes. - br.BaseStream.Position = mpaChallengeParScores; - for (int i = 0; i < miRoadCount; i++) - { - ChallengeParScores c = new ChallengeParScores(); - c.Read(br); - challenges.Add(c); - } + br.Close(); + ms.Close(); + return true; + } - br.Close(); - ms.Close(); - return true; - } + public bool Write(BundleEntry entry) + { + // The spec has no explicit challenge count and the reader uses + // miRoadCount, so an unbalanced model would silently corrupt. + if (challenges.Count != roads.Count) + throw new InvalidOperationException( + "StreetData.Write: challenges.Count (" + challenges.Count + + ") must equal roads.Count (" + roads.Count + ")."); - public bool Write(BundleEntry entry) + MemoryStream ms = new(); + BinaryWriter2 bw = new(ms); + bw.BigEndian = entry.Console; + + bool x64 = entry.Platform == BundlePlatform.PCx64; + void WritePtr(int ptr) { - // The spec has no explicit challenge count and the reader uses - // miRoadCount, so an unbalanced model would silently corrupt. - if (challenges.Count != roads.Count) - throw new InvalidOperationException( - "StreetData.Write: challenges.Count (" + challenges.Count + - ") must equal roads.Count (" + roads.Count + ")."); - - MemoryStream ms = new MemoryStream(); - BinaryWriter2 bw = new BinaryWriter2(ms); - bw.BigEndian = entry.Console; - - bool x64 = entry.Platform == BundlePlatform.PCx64; - void WritePtr(int ptr) + if (x64) + bw.Write((long)ptr); + else + bw.Write(ptr); + } + + long headerPos = ms.Position; + bw.Write(miVersion); + bw.Write(0); // miSize + WritePtr(0); // mpaStreets + WritePtr(0); // mpaJunctions + WritePtr(0); // mpaRoads + WritePtr(0); // mpaChallengeParScores + bw.Write(streets.Count); + bw.Write(junctions.Count); + bw.Write(roads.Count); + + bw.WritePadding(); + int streetsOffset = (int)ms.Position; + for (int i = 0; i < streets.Count; i++) streets[i].Write(bw); + + bw.WritePadding(); + int junctionsOffset = (int)ms.Position; + for (int i = 0; i < junctions.Count; i++) junctions[i].Write(bw, x64); + + bw.WritePadding(); + int roadsOffset = (int)ms.Position; + for (int i = 0; i < roads.Count; i++) roads[i].Write(bw, x64); + + bw.WritePadding(); + int challengesOffset = (int)ms.Position; + for (int i = 0; i < challenges.Count; i++) challenges[i].Write(bw); + + // The game's StreetData::FixUp() iterates miJunctionCount times + // (a Burnout bug; it should be miRoadCount) when constructing + // mDirty / mValidScores BitArrays inside ChallengeParScoresEntry. + // The extra iterations write past the real challenge entries, so + // the resource MUST extend at least to + // + // mpaChallengeParScores + miJunctionCount * 0x28 + // + // or FixUp() will trample whatever lives after the resource at + // runtime. We pad with zeroes here to keep that memory writeable. + // + // Road span and junction exit arrays used to live in this region + // in retail data, but the FixUp bug overwrites them, so the + // values are unreliable and the game ignores them. We omit them + // entirely - per-road / per-junction mpaSpans, miSpanCount, + // mpaExits, miExitCount are all written as 0. + // + // The decomp is the exception: its arrays are kept, laid out the + // way its data compiler did (one 16-byte-aligned allocation per + // road, then per junction) so a round trip is byte-identical. + if (x64) + { + for (int i = 0; i < roads.Count; i++) { - if (x64) - bw.Write((long)ptr); - else - bw.Write(ptr); + bw.WritePadding(); + long spansPtr = ms.Position; + foreach (short span in roads[i].maSpans) bw.Write(span); + ms.Position = roadsOffset + i * 0x48 + 0x10; + bw.Write(spansPtr); + ms.Position = ms.Length; } - - long headerPos = ms.Position; - bw.Write(miVersion); - bw.Write(0); // miSize - WritePtr(0); // mpaStreets - WritePtr(0); // mpaJunctions - WritePtr(0); // mpaRoads - WritePtr(0); // mpaChallengeParScores - bw.Write(streets.Count); - bw.Write(junctions.Count); - bw.Write(roads.Count); - - bw.WritePadding(); - int streetsOffset = (int)ms.Position; - for (int i = 0; i < streets.Count; i++) streets[i].Write(bw); - - bw.WritePadding(); - int junctionsOffset = (int)ms.Position; - for (int i = 0; i < junctions.Count; i++) junctions[i].Write(bw, x64); - - bw.WritePadding(); - int roadsOffset = (int)ms.Position; - for (int i = 0; i < roads.Count; i++) roads[i].Write(bw, x64); - - bw.WritePadding(); - int challengesOffset = (int)ms.Position; - for (int i = 0; i < challenges.Count; i++) challenges[i].Write(bw); - - // The game's StreetData::FixUp() iterates miJunctionCount times - // (a Burnout bug; it should be miRoadCount) when constructing - // mDirty / mValidScores BitArrays inside ChallengeParScoresEntry. - // The extra iterations write past the real challenge entries, so - // the resource MUST extend at least to - // - // mpaChallengeParScores + miJunctionCount * 0x28 - // - // or FixUp() will trample whatever lives after the resource at - // runtime. We pad with zeroes here to keep that memory writeable. - // - // Road span and junction exit arrays used to live in this region - // in retail data, but the FixUp bug overwrites them, so the - // values are unreliable and the game ignores them. We omit them - // entirely - per-road / per-junction mpaSpans, miSpanCount, - // mpaExits, miExitCount are all written as 0. - // - // The decomp is the exception: its arrays are kept, laid out the - // way its data compiler did (one 16-byte-aligned allocation per - // road, then per junction) so a round trip is byte-identical. - if (x64) + for (int i = 0; i < junctions.Count; i++) { - for (int i = 0; i < roads.Count; i++) - { - bw.WritePadding(); - long spansPtr = ms.Position; - foreach (short span in roads[i].maSpans) bw.Write(span); - ms.Position = roadsOffset + i * 0x48 + 0x10; - bw.Write(spansPtr); - ms.Position = ms.Length; - } - for (int i = 0; i < junctions.Count; i++) - { - bw.WritePadding(); - long exitsPtr = ms.Position; - foreach (Exit exit in junctions[i].maExits) exit.Write(bw); - ms.Position = junctionsOffset + i * 0x30 + 0x10; - bw.Write(exitsPtr); - ms.Position = ms.Length; - } + bw.WritePadding(); + long exitsPtr = ms.Position; + foreach (Exit exit in junctions[i].maExits) exit.Write(bw); + ms.Position = junctionsOffset + i * 0x30 + 0x10; + bw.Write(exitsPtr); + ms.Position = ms.Length; } - int fixUpEnd = challengesOffset + junctions.Count * SIZEOF_CHALLENGE_PAR_SCORES_ENTRY; - while (ms.Position < fixUpEnd) bw.Write((byte)0); - int miSizeOut = (int)ms.Position; - bw.WritePadding(); - - ms.Position = headerPos + 4; - bw.Write(miSizeOut); - WritePtr(streetsOffset); - WritePtr(junctionsOffset); - WritePtr(roadsOffset); - WritePtr(challengesOffset); - - bw.Flush(); - byte[] data = ms.ToArray(); - bw.Close(); - ms.Close(); - entry.EntryBlocks[0].Data = data; - entry.Dirty = true; - return true; } + int fixUpEnd = challengesOffset + junctions.Count * SIZEOF_CHALLENGE_PAR_SCORES_ENTRY; + while (ms.Position < fixUpEnd) bw.Write((byte)0); + int miSizeOut = (int)ms.Position; + bw.WritePadding(); + + ms.Position = headerPos + 4; + bw.Write(miSizeOut); + WritePtr(streetsOffset); + WritePtr(junctionsOffset); + WritePtr(roadsOffset); + WritePtr(challengesOffset); + + bw.Flush(); + byte[] data = ms.ToArray(); + bw.Close(); + ms.Close(); + entry.EntryBlocks[0].Data = data; + entry.Dirty = true; + return true; + } - public EntryType GetEntryType(BundleEntry entry) - { - return EntryType.StreetData; - } + public EntryType GetEntryType(BundleEntry entry) + { + return EntryType.StreetData; + } - public IEntryEditor GetEditor(BundleEntry entry) - { - StreetDataEditor editor = new StreetDataEditor(); - editor.Model = this; - editor.EditEvent += () => Write(entry); - return editor; - } + public IEntryEditor GetEditor(BundleEntry entry) + { + StreetDataEditor editor = new(); + editor.Model = this; + editor.EditEvent += () => Write(entry); + return editor; } } diff --git a/BaseHandlers/StreetDataEditor.cs b/BaseHandlers/StreetDataEditor.cs index d4f37c9..48a0f9f 100644 --- a/BaseHandlers/StreetDataEditor.cs +++ b/BaseHandlers/StreetDataEditor.cs @@ -8,445 +8,444 @@ using System.Text.Json.Serialization; using System.Windows.Forms; -namespace BaseHandlers +namespace BaseHandlers; + +public partial class StreetDataEditor : Form, IEntryEditor { - public partial class StreetDataEditor : Form, IEntryEditor - { - public event Notify EditEvent; + public event Notify EditEvent; - private StreetData _model; - [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] - public StreetData Model + private StreetData _model; + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public StreetData Model + { + get => _model; + set { - get => _model; - set - { - _model = value; - Rebuild(); - } + _model = value; + Rebuild(); } + } - private TabContext _streetsCtx; - private TabContext _junctionsCtx; - private TabContext _roadsCtx; - private TabContext _challengesCtx; + private TabContext _streetsCtx; + private TabContext _junctionsCtx; + private TabContext _roadsCtx; + private TabContext _challengesCtx; - public StreetDataEditor() - { - InitializeComponent(); - _streetsCtx = new TabContext { View = streetsList, ContextMenu = streetsContextMenu }; - _junctionsCtx = new TabContext { View = junctionsList, ContextMenu = junctionsContextMenu }; - _roadsCtx = new TabContext { View = roadsList, ContextMenu = roadsContextMenu }; - _challengesCtx = new TabContext { View = challengesList, ContextMenu = challengesContextMenu }; - } + public StreetDataEditor() + { + InitializeComponent(); + _streetsCtx = new TabContext { View = streetsList, ContextMenu = streetsContextMenu }; + _junctionsCtx = new TabContext { View = junctionsList, ContextMenu = junctionsContextMenu }; + _roadsCtx = new TabContext { View = roadsList, ContextMenu = roadsContextMenu }; + _challengesCtx = new TabContext { View = challengesList, ContextMenu = challengesContextMenu }; + } - private sealed class TabContext - { - public ListView View; - public ContextMenuStrip ContextMenu; - public Func Get; - public Action Repopulate; - public Func Format; - public Action AddNew; - public Action Remove; - public Action Duplicate; - } + private sealed class TabContext + { + public ListView View; + public ContextMenuStrip ContextMenu; + public Func Get; + public Action Repopulate; + public Func Format; + public Action AddNew; + public Action Remove; + public Action Duplicate; + } - private void Rebuild() - { - streetsList.Items.Clear(); - junctionsList.Items.Clear(); - roadsList.Items.Clear(); - challengesList.Items.Clear(); - propertyGrid.SelectedObject = null; + private void Rebuild() + { + streetsList.Items.Clear(); + junctionsList.Items.Clear(); + roadsList.Items.Clear(); + challengesList.Items.Clear(); + propertyGrid.SelectedObject = null; - if (_model == null) return; + if (_model == null) return; - ConfigureStreetsTab(); - ConfigureJunctionsTab(); - ConfigureRoadsTab(); - ConfigureChallengesTab(); + ConfigureStreetsTab(); + ConfigureJunctionsTab(); + ConfigureRoadsTab(); + ConfigureChallengesTab(); - _streetsCtx.Repopulate(); - _junctionsCtx.Repopulate(); - _roadsCtx.Repopulate(); - _challengesCtx.Repopulate(); + _streetsCtx.Repopulate(); + _junctionsCtx.Repopulate(); + _roadsCtx.Repopulate(); + _challengesCtx.Repopulate(); - UpdateTabTitles(); - } + UpdateTabTitles(); + } - private void ConfigureStreetsTab() + private void ConfigureStreetsTab() + { + TabContext ctx = _streetsCtx; + ctx.Get = i => _model.streets[i]; + ctx.Format = i => { - TabContext ctx = _streetsCtx; - ctx.Get = i => _model.streets[i]; - ctx.Format = i => - { - Street s = _model.streets[i]; - return new[] - { - i.ToString(), - s.super_SpanBase.miRoadIndex.ToString(), - s.super_SpanBase.miSpanIndex.ToString(), - s.super_SpanBase.meSpanType.ToString(), - s.mAiInfo.muMaxSpeedMPS.ToString(), - s.mAiInfo.muMinSpeedMPS.ToString(), - }; - }; - ctx.Repopulate = () => RepopulateView(ctx, _model.streets.Count); - ctx.AddNew = () => _model.streets.Add(new Street()); - ctx.Remove = i => _model.streets.RemoveAt(i); - ctx.Duplicate = i => - { - Street src = _model.streets[i]; - _model.streets.Insert(i + 1, new Street - { - super_SpanBase = new SpanBase - { - miRoadIndex = src.super_SpanBase.miRoadIndex, - miSpanIndex = src.super_SpanBase.miSpanIndex, - meSpanType = src.super_SpanBase.meSpanType, - }, - mAiInfo = new AIInfo - { - muMaxSpeedMPS = src.mAiInfo.muMaxSpeedMPS, - muMinSpeedMPS = src.mAiInfo.muMinSpeedMPS, - }, - }); - }; - BuildContextMenu(ctx); - } - - private void ConfigureJunctionsTab() + Street s = _model.streets[i]; + return + [ + i.ToString(), + s.super_SpanBase.miRoadIndex.ToString(), + s.super_SpanBase.miSpanIndex.ToString(), + s.super_SpanBase.meSpanType.ToString(), + s.mAiInfo.muMaxSpeedMPS.ToString(), + s.mAiInfo.muMinSpeedMPS.ToString(), + ]; + }; + ctx.Repopulate = () => RepopulateView(ctx, _model.streets.Count); + ctx.AddNew = () => _model.streets.Add(new Street()); + ctx.Remove = i => _model.streets.RemoveAt(i); + ctx.Duplicate = i => { - TabContext ctx = _junctionsCtx; - ctx.Get = i => _model.junctions[i]; - ctx.Format = i => + Street src = _model.streets[i]; + _model.streets.Insert(i + 1, new Street { - Junction j = _model.junctions[i]; - // SpanBase.miRoadIndex is always -1 for junctions; display - // "-" so the column reads as n/a. - int roadIdx = j.super_SpanBase.miRoadIndex; - return new[] + super_SpanBase = new SpanBase { - i.ToString(), - roadIdx == -1 ? "-" : roadIdx.ToString(), - j.super_SpanBase.miSpanIndex.ToString(), - j.super_SpanBase.meSpanType.ToString(), - (j.macName ?? string.Empty).TrimEnd('\0'), - }; - }; - ctx.Repopulate = () => RepopulateView(ctx, _model.junctions.Count); - ctx.AddNew = () => _model.junctions.Add(new Junction - { - macName = new string('\0', 16), - }); - ctx.Remove = i => _model.junctions.RemoveAt(i); - ctx.Duplicate = i => - { - Junction src = _model.junctions[i]; - Junction copy = new Junction + miRoadIndex = src.super_SpanBase.miRoadIndex, + miSpanIndex = src.super_SpanBase.miSpanIndex, + meSpanType = src.super_SpanBase.meSpanType, + }, + mAiInfo = new AIInfo { - super_SpanBase = new SpanBase - { - miRoadIndex = src.super_SpanBase.miRoadIndex, - miSpanIndex = src.super_SpanBase.miSpanIndex, - meSpanType = src.super_SpanBase.meSpanType, - }, - macName = src.macName, - }; - _model.junctions.Insert(i + 1, copy); - }; - BuildContextMenu(ctx); - } + muMaxSpeedMPS = src.mAiInfo.muMaxSpeedMPS, + muMinSpeedMPS = src.mAiInfo.muMinSpeedMPS, + }, + }); + }; + BuildContextMenu(ctx); + } - private void ConfigureRoadsTab() + private void ConfigureJunctionsTab() + { + TabContext ctx = _junctionsCtx; + ctx.Get = i => _model.junctions[i]; + ctx.Format = i => { - TabContext ctx = _roadsCtx; - ctx.Get = i => _model.roads[i]; - ctx.Format = i => - { - Road r = _model.roads[i]; - return new[] - { - i.ToString(), - (r.macDebugName ?? string.Empty).TrimEnd('\0'), - r.mReferencePosition.X.ToString("0.###", CultureInfo.InvariantCulture), - r.mReferencePosition.Y.ToString("0.###", CultureInfo.InvariantCulture), - r.mReferencePosition.Z.ToString("0.###", CultureInfo.InvariantCulture), - r.mChallenge.ToString(), - r.mId.ToString(), - }; - }; - ctx.Repopulate = () => RepopulateView(ctx, _model.roads.Count); - ctx.AddNew = () => - { - // Roads and Challenges are 1:1; keep the counts aligned. - _model.roads.Add(new Road { macDebugName = new string('\0', 16) }); - _model.challenges.Add(new ChallengeParScores()); - }; - ctx.Remove = i => - { - _model.roads.RemoveAt(i); - if (i < _model.challenges.Count) - _model.challenges.RemoveAt(i); - }; - ctx.Duplicate = i => + Junction j = _model.junctions[i]; + // SpanBase.miRoadIndex is always -1 for junctions; display + // "-" so the column reads as n/a. + int roadIdx = j.super_SpanBase.miRoadIndex; + return + [ + i.ToString(), + roadIdx == -1 ? "-" : roadIdx.ToString(), + j.super_SpanBase.miSpanIndex.ToString(), + j.super_SpanBase.meSpanType.ToString(), + (j.macName ?? string.Empty).TrimEnd('\0'), + ]; + }; + ctx.Repopulate = () => RepopulateView(ctx, _model.junctions.Count); + ctx.AddNew = () => _model.junctions.Add(new Junction + { + macName = new string('\0', 16), + }); + ctx.Remove = i => _model.junctions.RemoveAt(i); + ctx.Duplicate = i => + { + Junction src = _model.junctions[i]; + Junction copy = new() { - Road src = _model.roads[i]; - Road copy = new Road + super_SpanBase = new SpanBase { - mReferencePosition = src.mReferencePosition, - mId = src.mId, - miRoadLimitId0 = src.miRoadLimitId0, - miRoadLimitId1 = src.miRoadLimitId1, - macDebugName = src.macDebugName, - mChallenge = src.mChallenge, - unknown = src.unknown, - }; - _model.roads.Insert(i + 1, copy); - _model.challenges.Insert(i + 1, new ChallengeParScores()); + miRoadIndex = src.super_SpanBase.miRoadIndex, + miSpanIndex = src.super_SpanBase.miSpanIndex, + meSpanType = src.super_SpanBase.meSpanType, + }, + macName = src.macName, }; - BuildContextMenu(ctx); - } + _model.junctions.Insert(i + 1, copy); + }; + BuildContextMenu(ctx); + } - private void ConfigureChallengesTab() + private void ConfigureRoadsTab() + { + TabContext ctx = _roadsCtx; + ctx.Get = i => _model.roads[i]; + ctx.Format = i => + { + Road r = _model.roads[i]; + return + [ + i.ToString(), + (r.macDebugName ?? string.Empty).TrimEnd('\0'), + r.mReferencePosition.X.ToString("0.###", CultureInfo.InvariantCulture), + r.mReferencePosition.Y.ToString("0.###", CultureInfo.InvariantCulture), + r.mReferencePosition.Z.ToString("0.###", CultureInfo.InvariantCulture), + r.mChallenge.ToString(), + r.mId.ToString(), + ]; + }; + ctx.Repopulate = () => RepopulateView(ctx, _model.roads.Count); + ctx.AddNew = () => { - TabContext ctx = _challengesCtx; - ctx.Get = i => _model.challenges[i]; - ctx.Format = i => + // Roads and Challenges are 1:1; keep the counts aligned. + _model.roads.Add(new Road { macDebugName = new string('\0', 16) }); + _model.challenges.Add(new ChallengeParScores()); + }; + ctx.Remove = i => + { + _model.roads.RemoveAt(i); + if (i < _model.challenges.Count) + _model.challenges.RemoveAt(i); + }; + ctx.Duplicate = i => + { + Road src = _model.roads[i]; + Road copy = new() { - ChallengeParScores c = _model.challenges[i]; - return new[] - { - i.ToString(), - c.challengeData.mScoreList.maScores[0].ToString(), - c.challengeData.mScoreList.maScores[1].ToString(), - c.mRivals[0].ToString("X16"), - c.mRivals[1].ToString("X16"), - }; + mReferencePosition = src.mReferencePosition, + mId = src.mId, + miRoadLimitId0 = src.miRoadLimitId0, + miRoadLimitId1 = src.miRoadLimitId1, + macDebugName = src.macDebugName, + mChallenge = src.mChallenge, + unknown = src.unknown, }; - ctx.Repopulate = () => RepopulateView(ctx, _model.challenges.Count); - // Add/remove happens via the Roads tab to keep the counts aligned. - ctx.AddNew = null; - ctx.Remove = null; - ctx.Duplicate = null; - BuildContextMenu(ctx); - } + _model.roads.Insert(i + 1, copy); + _model.challenges.Insert(i + 1, new ChallengeParScores()); + }; + BuildContextMenu(ctx); + } - private void BuildContextMenu(TabContext ctx) + private void ConfigureChallengesTab() + { + TabContext ctx = _challengesCtx; + ctx.Get = i => _model.challenges[i]; + ctx.Format = i => { - ctx.ContextMenu.Items.Clear(); + ChallengeParScores c = _model.challenges[i]; + return + [ + i.ToString(), + c.challengeData.mScoreList.maScores[0].ToString(), + c.challengeData.mScoreList.maScores[1].ToString(), + c.mRivals[0].ToString("X16"), + c.mRivals[1].ToString("X16"), + ]; + }; + ctx.Repopulate = () => RepopulateView(ctx, _model.challenges.Count); + // Add/remove happens via the Roads tab to keep the counts aligned. + ctx.AddNew = null; + ctx.Remove = null; + ctx.Duplicate = null; + BuildContextMenu(ctx); + } - ToolStripMenuItem addItem = new ToolStripMenuItem("Add new") { Enabled = ctx.AddNew != null }; - addItem.Click += (s, e) => - { - if (ctx.AddNew == null) return; - ctx.AddNew(); - AfterMutate(ctx); - }; + private void BuildContextMenu(TabContext ctx) + { + ctx.ContextMenu.Items.Clear(); - ToolStripMenuItem dupItem = new ToolStripMenuItem("Duplicate selected") { Enabled = ctx.Duplicate != null }; - dupItem.Click += (s, e) => - { - if (ctx.Duplicate == null) return; - int idx = SelectedModelIndex(ctx); - if (idx < 0) return; - ctx.Duplicate(idx); - AfterMutate(ctx); - }; + ToolStripMenuItem addItem = new("Add new") { Enabled = ctx.AddNew != null }; + addItem.Click += (s, e) => + { + if (ctx.AddNew == null) return; + ctx.AddNew(); + AfterMutate(ctx); + }; - ToolStripMenuItem rmItem = new ToolStripMenuItem("Remove selected") { Enabled = ctx.Remove != null }; - rmItem.Click += (s, e) => - { - if (ctx.Remove == null) return; - int idx = SelectedModelIndex(ctx); - if (idx < 0) return; - ctx.Remove(idx); - AfterMutate(ctx); - }; + ToolStripMenuItem dupItem = new("Duplicate selected") { Enabled = ctx.Duplicate != null }; + dupItem.Click += (s, e) => + { + if (ctx.Duplicate == null) return; + int idx = SelectedModelIndex(ctx); + if (idx < 0) return; + ctx.Duplicate(idx); + AfterMutate(ctx); + }; + + ToolStripMenuItem rmItem = new("Remove selected") { Enabled = ctx.Remove != null }; + rmItem.Click += (s, e) => + { + if (ctx.Remove == null) return; + int idx = SelectedModelIndex(ctx); + if (idx < 0) return; + ctx.Remove(idx); + AfterMutate(ctx); + }; + + ctx.ContextMenu.Items.Add(addItem); + ctx.ContextMenu.Items.Add(dupItem); + ctx.ContextMenu.Items.Add(rmItem); + } - ctx.ContextMenu.Items.Add(addItem); - ctx.ContextMenu.Items.Add(dupItem); - ctx.ContextMenu.Items.Add(rmItem); - } + private void AfterMutate(TabContext ctx) + { + ctx.Repopulate(); + // Roads and Challenges are 1:1, so a Roads mutation also needs + // the Challenges tab refreshed (and vice versa). + if (ctx == _roadsCtx) _challengesCtx.Repopulate(); + if (ctx == _challengesCtx) _roadsCtx.Repopulate(); + UpdateTabTitles(); + + // Re-fire EditEvent so the bundle on disk reflects the mutation. + _editFired = false; + RaiseEdit(); + } - private void AfterMutate(TabContext ctx) + // The ListView may be sorted; use the row's Tag (the live model + // object) to find the model index instead of the row index. + private int SelectedModelIndex(TabContext ctx) + { + if (ctx.View.SelectedItems.Count == 0) return -1; + object tag = ctx.View.SelectedItems[0].Tag; + switch (tag) { - ctx.Repopulate(); - // Roads and Challenges are 1:1, so a Roads mutation also needs - // the Challenges tab refreshed (and vice versa). - if (ctx == _roadsCtx) _challengesCtx.Repopulate(); - if (ctx == _challengesCtx) _roadsCtx.Repopulate(); - UpdateTabTitles(); - - // Re-fire EditEvent so the bundle on disk reflects the mutation. - _editFired = false; - RaiseEdit(); + case Street s: return _model.streets.IndexOf(s); + case Junction j: return _model.junctions.IndexOf(j); + case Road r: return _model.roads.IndexOf(r); + case ChallengeParScores c: return _model.challenges.IndexOf(c); + default: return -1; } + } - // The ListView may be sorted; use the row's Tag (the live model - // object) to find the model index instead of the row index. - private int SelectedModelIndex(TabContext ctx) + private void RepopulateView(TabContext ctx, int count) + { + ctx.View.BeginUpdate(); + try { - if (ctx.View.SelectedItems.Count == 0) return -1; - object tag = ctx.View.SelectedItems[0].Tag; - switch (tag) + ctx.View.Items.Clear(); + for (int i = 0; i < count; i++) { - case Street s: return _model.streets.IndexOf(s); - case Junction j: return _model.junctions.IndexOf(j); - case Road r: return _model.roads.IndexOf(r); - case ChallengeParScores c: return _model.challenges.IndexOf(c); - default: return -1; + string[] row = ctx.Format(i); + ListViewItem item = new(row) { Tag = ctx.Get(i) }; + ctx.View.Items.Add(item); } + foreach (ColumnHeader col in ctx.View.Columns) + col.Width = -2; // auto-size to content + header } - - private void RepopulateView(TabContext ctx, int count) + finally { - ctx.View.BeginUpdate(); - try - { - ctx.View.Items.Clear(); - for (int i = 0; i < count; i++) - { - string[] row = ctx.Format(i); - ListViewItem item = new ListViewItem(row) { Tag = ctx.Get(i) }; - ctx.View.Items.Add(item); - } - foreach (ColumnHeader col in ctx.View.Columns) - col.Width = -2; // auto-size to content + header - } - finally - { - ctx.View.EndUpdate(); - } + ctx.View.EndUpdate(); } + } - private void UpdateTabTitles() - { - if (_model == null) return; - streetsPage.Text = "Streets (" + _model.streets.Count + ")"; - junctionsPage.Text = "Junctions (" + _model.junctions.Count + ")"; - roadsPage.Text = "Roads (" + _model.roads.Count + ")"; - challengesPage.Text = "Challenges (" + _model.challenges.Count + ")"; - } + private void UpdateTabTitles() + { + if (_model == null) return; + streetsPage.Text = "Streets (" + _model.streets.Count + ")"; + junctionsPage.Text = "Junctions (" + _model.junctions.Count + ")"; + roadsPage.Text = "Roads (" + _model.roads.Count + ")"; + challengesPage.Text = "Challenges (" + _model.challenges.Count + ")"; + } + + private void list_DoubleClick(object sender, EventArgs e) + { + ListView list = (ListView)sender; + if (list.SelectedItems.Count == 0) return; + propertyGrid.SelectedObject = list.SelectedItems[0].Tag; + } + + private void list_KeyDown(object sender, KeyEventArgs e) + { + if (e.KeyCode != Keys.Enter) return; + ListView list = (ListView)sender; + if (list.SelectedItems.Count == 0) return; + propertyGrid.SelectedObject = list.SelectedItems[0].Tag; + e.Handled = true; + e.SuppressKeyPress = true; + } - private void list_DoubleClick(object sender, EventArgs e) + private void list_ColumnClick(object sender, ColumnClickEventArgs e) + { + ListView list = (ListView)sender; + if (list.ListViewItemSorter is ListItemSorter existing && existing.Column == e.Column) { - ListView list = (ListView)sender; - if (list.SelectedItems.Count == 0) return; - propertyGrid.SelectedObject = list.SelectedItems[0].Tag; + existing.Descending = !existing.Descending; } - - private void list_KeyDown(object sender, KeyEventArgs e) + else { - if (e.KeyCode != Keys.Enter) return; - ListView list = (ListView)sender; - if (list.SelectedItems.Count == 0) return; - propertyGrid.SelectedObject = list.SelectedItems[0].Tag; - e.Handled = true; - e.SuppressKeyPress = true; + list.ListViewItemSorter = new ListItemSorter(e.Column); } + list.Sort(); + } - private void list_ColumnClick(object sender, ColumnClickEventArgs e) + // Numeric-aware sorter, falls back to ordinal string compare. + private sealed class ListItemSorter : IComparer + { + public int Column { get; } + public bool Descending { get; set; } + + public ListItemSorter(int column) { - ListView list = (ListView)sender; - if (list.ListViewItemSorter is ListItemSorter existing && existing.Column == e.Column) - { - existing.Descending = !existing.Descending; - } - else - { - list.ListViewItemSorter = new ListItemSorter(e.Column); - } - list.Sort(); + Column = column; + Descending = false; } - // Numeric-aware sorter, falls back to ordinal string compare. - private sealed class ListItemSorter : IComparer + public int Compare(object x, object y) { - public int Column { get; } - public bool Descending { get; set; } + ListViewItem ix = (ListViewItem)x; + ListViewItem iy = (ListViewItem)y; + + if (Column >= ix.SubItems.Count || Column >= iy.SubItems.Count) + return 0; - public ListItemSorter(int column) + string sx = ix.SubItems[Column].Text; + string sy = iy.SubItems[Column].Text; + + int cmp; + if (long.TryParse(sx, NumberStyles.Integer, CultureInfo.InvariantCulture, out long lx) && + long.TryParse(sy, NumberStyles.Integer, CultureInfo.InvariantCulture, out long ly)) { - Column = column; - Descending = false; + cmp = lx.CompareTo(ly); } - - public int Compare(object x, object y) + else if (double.TryParse(sx, NumberStyles.Float, CultureInfo.InvariantCulture, out double fx) && + double.TryParse(sy, NumberStyles.Float, CultureInfo.InvariantCulture, out double fy)) { - ListViewItem ix = (ListViewItem)x; - ListViewItem iy = (ListViewItem)y; - - if (Column >= ix.SubItems.Count || Column >= iy.SubItems.Count) - return 0; - - string sx = ix.SubItems[Column].Text; - string sy = iy.SubItems[Column].Text; - - int cmp; - if (long.TryParse(sx, NumberStyles.Integer, CultureInfo.InvariantCulture, out long lx) && - long.TryParse(sy, NumberStyles.Integer, CultureInfo.InvariantCulture, out long ly)) - { - cmp = lx.CompareTo(ly); - } - else if (double.TryParse(sx, NumberStyles.Float, CultureInfo.InvariantCulture, out double fx) && - double.TryParse(sy, NumberStyles.Float, CultureInfo.InvariantCulture, out double fy)) - { - cmp = fx.CompareTo(fy); - } - else - { - cmp = string.CompareOrdinal(sx, sy); - } - return Descending ? -cmp : cmp; + cmp = fx.CompareTo(fy); } + else + { + cmp = string.CompareOrdinal(sx, sy); + } + return Descending ? -cmp : cmp; } + } - private void exportJsonItem_Click(object sender, EventArgs e) - { - if (_model == null) return; + private void exportJsonItem_Click(object sender, EventArgs e) + { + if (_model == null) return; - SaveFileDialog saveDialog = new SaveFileDialog(); - saveDialog.Filter = "JSON File (*.json)|*.json"; - saveDialog.Title = "Export StreetData as JSON"; - saveDialog.FileName = "StreetData.json"; + SaveFileDialog saveDialog = new(); + saveDialog.Filter = "JSON File (*.json)|*.json"; + saveDialog.Title = "Export StreetData as JSON"; + saveDialog.FileName = "StreetData.json"; - if (saveDialog.ShowDialog() != DialogResult.OK) - return; + if (saveDialog.ShowDialog() != DialogResult.OK) + return; - try - { - JsonSerializerOptions options = new JsonSerializerOptions - { - WriteIndented = true, - NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals, - }; - string content = JsonSerializer.Serialize(_model, options); - File.WriteAllText(saveDialog.FileName, content); - MessageBox.Show(this, - "Successfully exported to " + saveDialog.FileName, - "Export Complete", MessageBoxButtons.OK, MessageBoxIcon.Information); - } - catch (Exception ex) + try + { + JsonSerializerOptions options = new() { - MessageBox.Show(this, - "Failed to export file. Error: " + ex.Message, - "Export Failed", MessageBoxButtons.OK, MessageBoxIcon.Error); - } + WriteIndented = true, + NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals, + }; + string content = JsonSerializer.Serialize(_model, options); + File.WriteAllText(saveDialog.FileName, content); + MessageBox.Show(this, + "Successfully exported to " + saveDialog.FileName, + "Export Complete", MessageBoxButtons.OK, MessageBoxIcon.Information); } - - private bool _editFired; - private void RaiseEdit() + catch (Exception ex) { - if (_editFired) return; - _editFired = true; - EditEvent?.Invoke(); + MessageBox.Show(this, + "Failed to export file. Error: " + ex.Message, + "Export Failed", MessageBoxButtons.OK, MessageBoxIcon.Error); } + } - private void StreetDataEditor_FormClosed(object sender, FormClosedEventArgs e) - { - RaiseEdit(); - } + private bool _editFired; + private void RaiseEdit() + { + if (_editFired) return; + _editFired = true; + EditEvent?.Invoke(); + } + + private void StreetDataEditor_FormClosed(object sender, FormClosedEventArgs e) + { + RaiseEdit(); } } diff --git a/BaseHandlers/TextureState.cs b/BaseHandlers/TextureState.cs index 0b5de92..ca55751 100644 --- a/BaseHandlers/TextureState.cs +++ b/BaseHandlers/TextureState.cs @@ -5,66 +5,65 @@ using BundleUtilities; using BurnoutImage; -namespace BaseHandlers +namespace BaseHandlers; + +public class TextureState { - public class TextureState + public Image Texture; + + public TextureState() { - public Image Texture; + + } - public TextureState() - { - - } + public static TextureState Read(BundleEntry entry) + { + TextureState result = new(); - public static TextureState Read(BundleEntry entry) + List dependencies = entry.GetDependencies(); + foreach (BundleDependency dependency in dependencies) { - TextureState result = new TextureState(); + ulong id = dependency.EntryID; - List dependencies = entry.GetDependencies(); - foreach (BundleDependency dependency in dependencies) + if (TextureCache.Contains(id)) { - ulong id = dependency.EntryID; - - if (TextureCache.Contains(id)) - { - result.Texture = TextureCache.GetTexture(id); - } - else + result.Texture = TextureCache.GetTexture(id); + } + else + { + BundleEntry descEntry1 = entry.Archive.GetEntryByID(id); + if (descEntry1 == null) { - BundleEntry descEntry1 = entry.Archive.GetEntryByID(id); - if (descEntry1 == null) + string file = BundleCache.GetFileByEntryID(id); + if (!string.IsNullOrEmpty(file)) { - string file = BundleCache.GetFileByEntryID(id); - if (!string.IsNullOrEmpty(file)) - { - BundleArchive archive = BundleArchive.Read(file); - if (archive != null) - descEntry1 = archive.GetEntryByID(id); - } + BundleArchive archive = BundleArchive.Read(file); + if (archive != null) + descEntry1 = archive.GetEntryByID(id); } + } - if (descEntry1 != null && descEntry1.Type == EntryType.Texture) - { - result.Texture = GameImage.GetImage(descEntry1.EntryBlocks[0].Data, descEntry1.EntryBlocks[1].Data); + if (descEntry1 != null && descEntry1.Type == EntryType.Texture) + { + result.Texture = GameImage.GetImage(descEntry1.EntryBlocks[0].Data, descEntry1.EntryBlocks[1].Data); - if (result.Texture != null) - TextureCache.AddToCache(id, result.Texture); + if (result.Texture != null) + TextureCache.AddToCache(id, result.Texture); - break; - } + break; } } + } - MemoryStream ms = entry.MakeStream(); - BinaryReader2 br = new BinaryReader2(ms); - br.BigEndian = entry.Console; + MemoryStream ms = entry.MakeStream(); + BinaryReader2 br = new(ms); + br.BigEndian = entry.Console; - // TODO: Read Texture State + // TODO: Read Texture State - br.Close(); - ms.Close(); + br.Close(); + ms.Close(); - return result; - } + return result; } } diff --git a/BaseHandlers/Traffic.cs b/BaseHandlers/Traffic.cs index 3fcfc3b..6f91b96 100644 --- a/BaseHandlers/Traffic.cs +++ b/BaseHandlers/Traffic.cs @@ -4,158 +4,157 @@ using BundleUtilities; using PluginAPI; -namespace BaseHandlers +namespace BaseHandlers; + +public class Traffic : IEntryData { - public class Traffic : IEntryData + public short Unknown1; + public short Unknown2; + public int FileSize; + public int TrackCount; + public int Unknown3; + public int PointerOffset; + public short Unknown4; + public short Unknown5; + public byte Unknown6; + public byte Unknown7; + public short Unknown8; + public short Unknown9; + public short Unknown10; + public uint Section1Offset; + public uint Section2Offset; + public uint Section3Offset; + public uint Section4Offset; + public uint Section5Offset; + public uint Section6Offset; + public uint Section7Offset; + public uint Section8Offset; + public byte Unknown11; + public byte Unknown12; + public short Unknown13; + public uint UnknownOffset1; + public uint UnknownOffset2; + public uint UnknownOffset3; + public uint UnknownOffset4; + public uint UnknownOffset5; + public short Unknown14; + public short Unknown15; + + public List UnknownShorts; + + public Traffic() { - public short Unknown1; - public short Unknown2; - public int FileSize; - public int TrackCount; - public int Unknown3; - public int PointerOffset; - public short Unknown4; - public short Unknown5; - public byte Unknown6; - public byte Unknown7; - public short Unknown8; - public short Unknown9; - public short Unknown10; - public uint Section1Offset; - public uint Section2Offset; - public uint Section3Offset; - public uint Section4Offset; - public uint Section5Offset; - public uint Section6Offset; - public uint Section7Offset; - public uint Section8Offset; - public byte Unknown11; - public byte Unknown12; - public short Unknown13; - public uint UnknownOffset1; - public uint UnknownOffset2; - public uint UnknownOffset3; - public uint UnknownOffset4; - public uint UnknownOffset5; - public short Unknown14; - public short Unknown15; - - public List UnknownShorts; - - public Traffic() - { - UnknownShorts = new List(); - } + UnknownShorts = []; + } - public IEntryEditor GetEditor(BundleEntry entry) - { - return null; - } + public IEntryEditor GetEditor(BundleEntry entry) + { + return null; + } - public EntryType GetEntryType(BundleEntry entry) - { - return EntryType.TrafficData; - } + public EntryType GetEntryType(BundleEntry entry) + { + return EntryType.TrafficData; + } - private void Clear() - { - Unknown1 = default; - Unknown2 = default; - FileSize = default; - TrackCount = default; - Unknown3 = default; - PointerOffset = default; - Unknown4 = default; - Unknown5 = default; - Unknown6 = default; - Unknown7 = default; - Unknown8 = default; - Unknown9 = default; - Unknown10 = default; - Section1Offset = default; - Section2Offset = default; - Section3Offset = default; - Section4Offset = default; - Section5Offset = default; - Section6Offset = default; - Section7Offset = default; - Section8Offset = default; - Unknown11 = default; - Unknown12 = default; - Unknown13 = default; - UnknownOffset1 = default; - UnknownOffset2 = default; - UnknownOffset3 = default; - UnknownOffset4 = default; - UnknownOffset5 = default; - Unknown14 = default; - Unknown15 = default; - - UnknownShorts.Clear(); - } + private void Clear() + { + Unknown1 = default; + Unknown2 = default; + FileSize = default; + TrackCount = default; + Unknown3 = default; + PointerOffset = default; + Unknown4 = default; + Unknown5 = default; + Unknown6 = default; + Unknown7 = default; + Unknown8 = default; + Unknown9 = default; + Unknown10 = default; + Section1Offset = default; + Section2Offset = default; + Section3Offset = default; + Section4Offset = default; + Section5Offset = default; + Section6Offset = default; + Section7Offset = default; + Section8Offset = default; + Unknown11 = default; + Unknown12 = default; + Unknown13 = default; + UnknownOffset1 = default; + UnknownOffset2 = default; + UnknownOffset3 = default; + UnknownOffset4 = default; + UnknownOffset5 = default; + Unknown14 = default; + Unknown15 = default; - public bool Read(BundleEntry entry, ILoader loader = null) - { - Clear(); - - MemoryStream ms = entry.MakeStream(); - BinaryReader2 br = new BinaryReader2(ms); - br.BigEndian = entry.Console; - - // Decomp has 8-byte pointers, which also pad the fields before them to 8 bytes - bool x64 = entry.Platform == BundlePlatform.PCx64; - uint ReadPtr() => x64 ? (uint)br.ReadUInt64() : br.ReadUInt32(); - - Unknown1 = br.ReadInt16(); - Unknown2 = br.ReadInt16(); - FileSize = br.ReadInt32(); - TrackCount = (int)ReadPtr(); - Unknown3 = (int)ReadPtr(); - PointerOffset = (int)ReadPtr(); - Unknown4 = br.ReadInt16(); - Unknown5 = br.ReadInt16(); - Unknown6 = br.ReadByte(); - Unknown7 = br.ReadByte(); - Unknown8 = br.ReadInt16(); - Unknown9 = br.ReadInt16(); - Unknown10 = br.ReadInt16(); - if (x64) - br.ReadBytes(4); // Padding - Section1Offset = ReadPtr(); - Section2Offset = ReadPtr(); - Section3Offset = ReadPtr(); - Section4Offset = ReadPtr(); - Section5Offset = ReadPtr(); - Section6Offset = ReadPtr(); - Section7Offset = ReadPtr(); - Section8Offset = br.ReadUInt32(); // Not a pointer: two ushort counts - Unknown11 = br.ReadByte(); - Unknown12 = br.ReadByte(); - Unknown13 = br.ReadInt16(); - UnknownOffset1 = ReadPtr(); - UnknownOffset2 = ReadPtr(); - UnknownOffset3 = ReadPtr(); - UnknownOffset4 = ReadPtr(); - UnknownOffset5 = ReadPtr(); - Unknown14 = br.ReadInt16(); // Unknown14 and Unknown15 are one pointer - Unknown15 = br.ReadInt16(); - if (x64) - br.ReadBytes(4); // Upper half of that pointer - - for (int i = 0; i < 128; i++) - { - UnknownShorts.Add(br.ReadInt16()); - } - - br.Close(); - ms.Close(); - - return true; - } + UnknownShorts.Clear(); + } + + public bool Read(BundleEntry entry, ILoader loader = null) + { + Clear(); + + MemoryStream ms = entry.MakeStream(); + BinaryReader2 br = new(ms); + br.BigEndian = entry.Console; - public bool Write(BundleEntry entry) + // Decomp has 8-byte pointers, which also pad the fields before them to 8 bytes + bool x64 = entry.Platform == BundlePlatform.PCx64; + uint ReadPtr() => x64 ? (uint)br.ReadUInt64() : br.ReadUInt32(); + + Unknown1 = br.ReadInt16(); + Unknown2 = br.ReadInt16(); + FileSize = br.ReadInt32(); + TrackCount = (int)ReadPtr(); + Unknown3 = (int)ReadPtr(); + PointerOffset = (int)ReadPtr(); + Unknown4 = br.ReadInt16(); + Unknown5 = br.ReadInt16(); + Unknown6 = br.ReadByte(); + Unknown7 = br.ReadByte(); + Unknown8 = br.ReadInt16(); + Unknown9 = br.ReadInt16(); + Unknown10 = br.ReadInt16(); + if (x64) + br.ReadBytes(4); // Padding + Section1Offset = ReadPtr(); + Section2Offset = ReadPtr(); + Section3Offset = ReadPtr(); + Section4Offset = ReadPtr(); + Section5Offset = ReadPtr(); + Section6Offset = ReadPtr(); + Section7Offset = ReadPtr(); + Section8Offset = br.ReadUInt32(); // Not a pointer: two ushort counts + Unknown11 = br.ReadByte(); + Unknown12 = br.ReadByte(); + Unknown13 = br.ReadInt16(); + UnknownOffset1 = ReadPtr(); + UnknownOffset2 = ReadPtr(); + UnknownOffset3 = ReadPtr(); + UnknownOffset4 = ReadPtr(); + UnknownOffset5 = ReadPtr(); + Unknown14 = br.ReadInt16(); // Unknown14 and Unknown15 are one pointer + Unknown15 = br.ReadInt16(); + if (x64) + br.ReadBytes(4); // Upper half of that pointer + + for (int i = 0; i < 128; i++) { - return true; + UnknownShorts.Add(br.ReadInt16()); } + + br.Close(); + ms.Close(); + + return true; + } + + public bool Write(BundleEntry entry) + { + return true; } } diff --git a/BaseHandlers/TriggerData.cs b/BaseHandlers/TriggerData.cs index 8e45c16..a4f3ae3 100644 --- a/BaseHandlers/TriggerData.cs +++ b/BaseHandlers/TriggerData.cs @@ -10,1048 +10,1046 @@ using System.Numerics; using System.Windows.Forms; -namespace BaseHandlers +namespace BaseHandlers; + +class DescriptiveCollectionEditor : CollectionEditor { - class DescriptiveCollectionEditor : CollectionEditor + public DescriptiveCollectionEditor(Type type) : base(type) { } + protected override CollectionForm CreateCollectionForm() { - public DescriptiveCollectionEditor(Type type) : base(type) { } - protected override CollectionForm CreateCollectionForm() + CollectionForm form = base.CreateCollectionForm(); + form.Shown += delegate { - CollectionForm form = base.CreateCollectionForm(); - form.Shown += delegate - { - ShowDescription(form); - }; - return form; - } - static void ShowDescription(Control control) + ShowDescription(form); + }; + return form; + } + static void ShowDescription(Control control) + { + if (control is PropertyGrid grid) grid.HelpVisible = true; + foreach (Control child in control.Controls) { - PropertyGrid grid = control as PropertyGrid; - if (grid != null) grid.HelpVisible = true; - foreach (Control child in control.Controls) - { - ShowDescription(child); - } + ShowDescription(child); } } - public class CgsID +} +public class CgsID +{ + private ulong m_id = 0; + + public ulong ID { - private UInt64 m_id = 0; + get { return m_id; } + set { m_id = value; } + } - public UInt64 ID - { - get { return m_id; } - set { m_id = value; } - } + public static CgsID FromByteArray(byte[] data, int startIndex) + { + ulong id = BitConverter.ToUInt64(data, startIndex); + CgsID result = new(); + result.ID = id; + return new CgsID(); + } - public static CgsID FromByteArray(byte[] data, int startIndex) - { - UInt64 id = BitConverter.ToUInt64(data, startIndex); - CgsID result = new CgsID(); - result.ID = id; - return new CgsID(); - } + public byte[] ToByteArray() + { + return BitConverter.GetBytes(m_id); + } + + public void Read(BinaryReader2 br) + { + m_id = br.ReadUInt64(); + } + + public void Write(BinaryWriter2 bw) + { + bw.Write(m_id); + } - public byte[] ToByteArray() + public override string ToString() + { + return string.Format("{0:X16}", m_id); + } +} + +public class StartingGrid +{ + public List StartingPositions { get; set; } = []; + public List StartingDirections { get; set; } = []; + + public void Read(BinaryReader2 br) + { + StartingPositions = new List(8); + for (int i = 0; i < 8; i++) { - return BitConverter.GetBytes(m_id); + StartingPositions[i] = new Vector4( + br.ReadSingle(), + br.ReadSingle(), + br.ReadSingle(), + br.ReadSingle()); } - public void Read(BinaryReader2 br) + StartingDirections = new List(8); + for (int i = 0; i < 8; i++) { - m_id = br.ReadUInt64(); + StartingDirections[i] = new Vector4( + br.ReadSingle(), + br.ReadSingle(), + br.ReadSingle(), + br.ReadSingle()); } + } - public void Write(BinaryWriter2 bw) + public void Write(BinaryWriter2 bw) + { + for (int i = 0; i < 8; i++) { - bw.Write(m_id); + bw.Write(StartingPositions[i].X); + bw.Write(StartingPositions[i].Y); + bw.Write(StartingPositions[i].Z); + bw.Write(StartingPositions[i].W); } - public override string ToString() + for (int i = 0; i < 8; i++) { - return string.Format("{0:X16}", m_id); + bw.Write(StartingDirections[i].X); + bw.Write(StartingDirections[i].Y); + bw.Write(StartingDirections[i].Z); + bw.Write(StartingDirections[i].W); } } +} - public class StartingGrid +public class BoxRegion +{ + public float PositionX { get; set; } = 0; + public float PositionY { get; set; } = 0; + public float PositionZ { get; set; } = 0; + public float RotationX { get; set; } = 0; + public float RotationY { get; set; } = 0; + public float RotationZ { get; set; } = 0; + public float DimensionX { get; set; } = 0; + public float DimensionY { get; set; } = 0; + public float DimensionZ { get; set; } = 0; + + public void Read(BinaryReader2 br) { - public List StartingPositions { get; set; } = new List(); - public List StartingDirections { get; set; } = new List(); + PositionX = br.ReadSingle(); + PositionY = br.ReadSingle(); + PositionZ = br.ReadSingle(); + RotationX = br.ReadSingle(); + RotationY = br.ReadSingle(); + RotationZ = br.ReadSingle(); + DimensionX = br.ReadSingle(); + DimensionY = br.ReadSingle(); + DimensionZ = br.ReadSingle(); + } - public void Read(BinaryReader2 br) - { - StartingPositions = new List(8); - for (int i = 0; i < 8; i++) - { - StartingPositions[i] = new Vector4( - br.ReadSingle(), - br.ReadSingle(), - br.ReadSingle(), - br.ReadSingle()); - } - - StartingDirections = new List(8); - for (int i = 0; i < 8; i++) - { - StartingDirections[i] = new Vector4( - br.ReadSingle(), - br.ReadSingle(), - br.ReadSingle(), - br.ReadSingle()); - } - } + public void Write(BinaryWriter2 bw) + { + bw.Write(PositionX); + bw.Write(PositionY); + bw.Write(PositionZ); + bw.Write(RotationX); + bw.Write(RotationY); + bw.Write(RotationZ); + bw.Write(DimensionX); + bw.Write(DimensionY); + bw.Write(DimensionZ); + } +} - public void Write(BinaryWriter2 bw) - { - for (int i = 0; i < 8; i++) - { - bw.Write(StartingPositions[i].X); - bw.Write(StartingPositions[i].Y); - bw.Write(StartingPositions[i].Z); - bw.Write(StartingPositions[i].W); - } - - for (int i = 0; i < 8; i++) - { - bw.Write(StartingDirections[i].X); - bw.Write(StartingDirections[i].Y); - bw.Write(StartingDirections[i].Z); - bw.Write(StartingDirections[i].W); - } - } +public class TriggerRegion +{ + public enum RegionType + { + E_TYPE_LANDMARK = 0, + E_TYPE_BLACKSPOT = 1, + E_TYPE_GENERIC_REGION = 2, + E_TYPE_VFXBOX_REGION = 3 } - public class BoxRegion + [TypeConverter(typeof(ExpandableObjectConverter))] + public BoxRegion mBoxRegion { get; set; } = new BoxRegion(); + public int mId { get; set; } = 0; + public short miRegionIndex { get; set; } = 0; + public RegionType meType { get; set; } = RegionType.E_TYPE_LANDMARK; + private byte[] muPad { get; set; } = new byte[1]; + + public virtual void Read(BinaryReader2 br) { - public float PositionX { get; set; } = 0; - public float PositionY { get; set; } = 0; - public float PositionZ { get; set; } = 0; - public float RotationX { get; set; } = 0; - public float RotationY { get; set; } = 0; - public float RotationZ { get; set; } = 0; - public float DimensionX { get; set; } = 0; - public float DimensionY { get; set; } = 0; - public float DimensionZ { get; set; } = 0; - - public void Read(BinaryReader2 br) - { - PositionX = br.ReadSingle(); - PositionY = br.ReadSingle(); - PositionZ = br.ReadSingle(); - RotationX = br.ReadSingle(); - RotationY = br.ReadSingle(); - RotationZ = br.ReadSingle(); - DimensionX = br.ReadSingle(); - DimensionY = br.ReadSingle(); - DimensionZ = br.ReadSingle(); - } + mBoxRegion = new BoxRegion(); + mBoxRegion.Read(br); + mId = br.ReadInt32(); + miRegionIndex = br.ReadInt16(); + meType = (RegionType)br.ReadByte(); + muPad = br.ReadBytes(1); + } - public void Write(BinaryWriter2 bw) - { - bw.Write(PositionX); - bw.Write(PositionY); - bw.Write(PositionZ); - bw.Write(RotationX); - bw.Write(RotationY); - bw.Write(RotationZ); - bw.Write(DimensionX); - bw.Write(DimensionY); - bw.Write(DimensionZ); - } + public virtual void Write(BinaryWriter2 bw) + { + mBoxRegion.Write(bw); + + bw.Write(mId); + bw.Write(miRegionIndex); + bw.Write((byte)meType); + bw.Write(muPad); } +} - public class TriggerRegion +public class Landmark : TriggerRegion +{ + public Landmark() : base() { - public enum RegionType - { - E_TYPE_LANDMARK = 0, - E_TYPE_BLACKSPOT = 1, - E_TYPE_GENERIC_REGION = 2, - E_TYPE_VFXBOX_REGION = 3 - } + // Set meType to E_TYPE_LANDMARK + meType = RegionType.E_TYPE_LANDMARK; + } + + public List mpaStartingGrids { get; set; } = []; - [TypeConverter(typeof(ExpandableObjectConverter))] - public BoxRegion mBoxRegion { get; set; } = new BoxRegion(); - public int mId { get; set; } = 0; - public short miRegionIndex { get; set; } = 0; - public RegionType meType { get; set; } = RegionType.E_TYPE_LANDMARK; - private byte[] muPad { get; set; } = new byte[1]; + private long startingGridOffsetPosition = 0; + public byte muDesignIndex { get; set; } = 0; + public byte muDistrict { get; set; } = 0; + public byte mu8Flags { get; set; } = 0; - public virtual void Read(BinaryReader2 br) + public void Read(BinaryReader2 br, bool x64) + { + base.Read(br); + if (x64) + br.ReadBytes(4); // Padding before the 8-byte pointer + long startingGridOffset = TriggerData.ReadPtr(br, x64); + int miStartingGridCount = br.ReadByte(); + muDesignIndex = br.ReadByte(); + muDistrict = br.ReadByte(); + mu8Flags = br.ReadByte(); + if (x64) + br.ReadBytes(4); // Padding + + long currentPosition = br.BaseStream.Position; + br.BaseStream.Position = startingGridOffset; + + for (int i = 0; i < miStartingGridCount; i++) { - mBoxRegion = new BoxRegion(); - mBoxRegion.Read(br); - mId = br.ReadInt32(); - miRegionIndex = br.ReadInt16(); - meType = (RegionType)br.ReadByte(); - muPad = br.ReadBytes(1); + StartingGrid startingGrid = new(); + startingGrid.Read(br); + mpaStartingGrids.Add(startingGrid); } + br.BaseStream.Position = currentPosition; - public virtual void Write(BinaryWriter2 bw) - { - mBoxRegion.Write(bw); + } - bw.Write(mId); - bw.Write(miRegionIndex); - bw.Write((byte)meType); - bw.Write(muPad); + public void Write(BinaryWriter2 bw, bool x64) + { + base.Write(bw); + if (x64) + bw.WriteUniquePadding(4); + startingGridOffsetPosition = bw.BaseStream.Position; + bw.WriteUniquePadding(x64 ? 8 : 4); + bw.Write((byte)mpaStartingGrids.Count); + bw.Write(muDesignIndex); + bw.Write(muDistrict); + bw.Write(mu8Flags); + if (x64) + bw.WriteUniquePadding(4); + } + + public void WriteStartingGrid(BinaryWriter2 bw, bool x64){ + + long currentPosition = bw.BaseStream.Position; + bw.BaseStream.Position = startingGridOffsetPosition; + TriggerData.WritePtr(bw, currentPosition, x64); + bw.BaseStream.Position = currentPosition; + foreach (StartingGrid grid in mpaStartingGrids) { + grid.Write(bw); } } +} - public class Landmark : TriggerRegion +public class GenericRegion : TriggerRegion +{ + public enum StuntCameraType { - public Landmark() : base() - { - // Set meType to E_TYPE_LANDMARK - meType = RegionType.E_TYPE_LANDMARK; - } + E_STUNT_CAMERA_TYPE_NO_CUTS = 0, + E_STUNT_CAMERA_TYPE_CUSTOM = 1, + E_STUNT_CAMERA_TYPE_NORMAL = 2 + } - public List mpaStartingGrids { get; set; } = new List(); + public enum Type + { + E_TYPE_JUNK_YARD = 0, + E_TYPE_BIKE_SHOP = 1, + E_TYPE_GAS_STATION = 2, + E_TYPE_BODY_SHOP = 3, + E_TYPE_PAINT_SHOP = 4, + E_TYPE_CAR_PARK = 5, + E_TYPE_SIGNATURE_TAKEDOWN = 6, + E_TYPE_KILLZONE = 7, + E_TYPE_JUMP = 8, + E_TYPE_SMASH = 9, + E_TYPE_SIGNATURE_CRASH = 10, + E_TYPE_SIGNATURE_CRASH_CAMERA = 11, + E_TYPE_ROAD_LIMIT = 12, + E_TYPE_OVERDRIVE_BOOST = 13, + E_TYPE_OVERDRIVE_STRENGTH = 14, + E_TYPE_OVERDRIVE_SPEED = 15, + E_TYPE_OVERDRIVE_CONTROL = 16, + E_TYPE_TIRE_SHOP = 17, + E_TYPE_TUNING_SHOP = 18, + E_TYPE_PICTURE_PARADISE = 19, + E_TYPE_TUNNEL = 20, + E_TYPE_OVERPASS = 21, + E_TYPE_BRIDGE = 22, + E_TYPE_WAREHOUSE = 23, + E_TYPE_LARGE_OVERHEAD_OBJECT = 24, + E_TYPE_NARROW_ALLEY = 25, + E_TYPE_PASS_TUNNEL = 26, + E_TYPE_PASS_OVERPASS = 27, + E_TYPE_PASS_BRIDGE = 28, + E_TYPE_PASS_WAREHOUSE = 29, + E_TYPE_PASS_LARGEOVERHEADOBJECT = 30, + E_TYPE_PASS_NARROWALLEY = 31, + E_TYPE_RAMP = 32, + E_TYPE_GOLD = 33, + E_TYPE_ISLAND_ENTITLEMENT = 34 + } - private long startingGridOffsetPosition = 0; - public byte muDesignIndex { get; set; } = 0; - public byte muDistrict { get; set; } = 0; - public byte mu8Flags { get; set; } = 0; + public GenericRegion() : base() + { + // Set meType to E_TYPE_GENERIC_REGION + meType = RegionType.E_TYPE_GENERIC_REGION; + } - public void Read(BinaryReader2 br, bool x64) - { - base.Read(br); - if (x64) - br.ReadBytes(4); // Padding before the 8-byte pointer - long startingGridOffset = TriggerData.ReadPtr(br, x64); - int miStartingGridCount = br.ReadByte(); - muDesignIndex = br.ReadByte(); - muDistrict = br.ReadByte(); - mu8Flags = br.ReadByte(); - if (x64) - br.ReadBytes(4); // Padding + public int GroupID { get; set; } = 0; + public short CameraCut1 { get; set; } = 0; + public short CameraCut2 { get; set; } = 0; + public StuntCameraType CameraType1 { get; set; } = 0; + public StuntCameraType CameraType2 { get; set; } = 0; + public Type GenericRegionType { get; set; } = Type.E_TYPE_JUNK_YARD; + public sbyte IsOneWay { get; set; } = 0; - long currentPosition = br.BaseStream.Position; - br.BaseStream.Position = startingGridOffset; + public new void Read(BinaryReader2 br) + { + base.Read(br); + GroupID = br.ReadInt32(); + CameraCut1 = br.ReadInt16(); + CameraCut2 = br.ReadInt16(); + CameraType1 = (StuntCameraType)br.ReadSByte(); + CameraType2 = (StuntCameraType)br.ReadSByte(); + GenericRegionType = (Type)br.ReadByte(); + IsOneWay = br.ReadSByte(); + } - for (int i = 0; i < miStartingGridCount; i++) - { - StartingGrid startingGrid = new StartingGrid(); - startingGrid.Read(br); - mpaStartingGrids.Add(startingGrid); - } - br.BaseStream.Position = currentPosition; + public new void Write(BinaryWriter2 bw) + { + base.Write(bw); + bw.Write(GroupID); + bw.Write(CameraCut1); + bw.Write(CameraCut2); + bw.Write((sbyte)CameraType1); + bw.Write((sbyte)CameraType2); + bw.Write((byte)GenericRegionType); + bw.Write(IsOneWay); + } +} - } +public class Blackspot : TriggerRegion +{ + public enum ScoreType + { + E_SCORE_TYPE_DISTANCE = 0, + E_SCORE_TYPE_CAR_COUNT = 1 + } - public void Write(BinaryWriter2 bw, bool x64) - { - base.Write(bw); - if (x64) - bw.WriteUniquePadding(4); - startingGridOffsetPosition = bw.BaseStream.Position; - bw.WriteUniquePadding(x64 ? 8 : 4); - bw.Write((byte)mpaStartingGrids.Count); - bw.Write(muDesignIndex); - bw.Write(muDistrict); - bw.Write(mu8Flags); - if (x64) - bw.WriteUniquePadding(4); - } + public Blackspot() : base() + { + // Set meType to E_TYPE_BLACKSPOT + meType = RegionType.E_TYPE_BLACKSPOT; + } - public void WriteStartingGrid(BinaryWriter2 bw, bool x64){ + public ScoreType muScoreType { get; set; } = ScoreType.E_SCORE_TYPE_DISTANCE; + public int miScoreAmount { get; set; } = 0; - long currentPosition = bw.BaseStream.Position; - bw.BaseStream.Position = startingGridOffsetPosition; - TriggerData.WritePtr(bw, currentPosition, x64); - bw.BaseStream.Position = currentPosition; - foreach (StartingGrid grid in mpaStartingGrids) { - grid.Write(bw); - } - } + public override void Read(BinaryReader2 br) + { + base.Read(br); + + muScoreType = (ScoreType)br.ReadByte(); + br.ReadBytes(3); // Padding + miScoreAmount = br.ReadInt32(); + } + + public override void Write(BinaryWriter2 bw) + { + base.Write(bw); + + bw.Write((byte)muScoreType); + bw.Write(new byte[3]); // Padding + bw.Write(miScoreAmount); } +} + +public class Killzone +{ + [Description("Triggers as GenericRegions. Uses region.mId")] + public List TriggerIds { get; set; } = []; + public List RegionIds { get; set; } = []; - public class GenericRegion : TriggerRegion + private long TriggerOffsetPosition = 0; + + private long CGSIDOffsetPosition = 0; + public void Read(BinaryReader2 br, bool x64) { - public enum StuntCameraType + // Read the trigger pointer array + long genericRegionOffset = TriggerData.ReadPtr(br, x64); + int TriggerCount = br.ReadInt32(); + if (x64) + br.ReadBytes(4); // Padding + + // Read the region ID array + long cgsOffset = TriggerData.ReadPtr(br, x64); + int RegionIdCount = br.ReadInt32(); + if (x64) + br.ReadBytes(4); // Padding + long currentPosition = br.BaseStream.Position; + + br.BaseStream.Position = genericRegionOffset; + uint[] Triggers = new uint[TriggerCount]; + for (int i = 0; i < TriggerCount; i++) { - E_STUNT_CAMERA_TYPE_NO_CUTS = 0, - E_STUNT_CAMERA_TYPE_CUSTOM = 1, - E_STUNT_CAMERA_TYPE_NORMAL = 2 + Triggers[i] = (uint)TriggerData.ReadPtr(br, x64); } - public enum Type + TriggerIds = []; + foreach (uint trigger in Triggers) { - E_TYPE_JUNK_YARD = 0, - E_TYPE_BIKE_SHOP = 1, - E_TYPE_GAS_STATION = 2, - E_TYPE_BODY_SHOP = 3, - E_TYPE_PAINT_SHOP = 4, - E_TYPE_CAR_PARK = 5, - E_TYPE_SIGNATURE_TAKEDOWN = 6, - E_TYPE_KILLZONE = 7, - E_TYPE_JUMP = 8, - E_TYPE_SMASH = 9, - E_TYPE_SIGNATURE_CRASH = 10, - E_TYPE_SIGNATURE_CRASH_CAMERA = 11, - E_TYPE_ROAD_LIMIT = 12, - E_TYPE_OVERDRIVE_BOOST = 13, - E_TYPE_OVERDRIVE_STRENGTH = 14, - E_TYPE_OVERDRIVE_SPEED = 15, - E_TYPE_OVERDRIVE_CONTROL = 16, - E_TYPE_TIRE_SHOP = 17, - E_TYPE_TUNING_SHOP = 18, - E_TYPE_PICTURE_PARADISE = 19, - E_TYPE_TUNNEL = 20, - E_TYPE_OVERPASS = 21, - E_TYPE_BRIDGE = 22, - E_TYPE_WAREHOUSE = 23, - E_TYPE_LARGE_OVERHEAD_OBJECT = 24, - E_TYPE_NARROW_ALLEY = 25, - E_TYPE_PASS_TUNNEL = 26, - E_TYPE_PASS_OVERPASS = 27, - E_TYPE_PASS_BRIDGE = 28, - E_TYPE_PASS_WAREHOUSE = 29, - E_TYPE_PASS_LARGEOVERHEADOBJECT = 30, - E_TYPE_PASS_NARROWALLEY = 31, - E_TYPE_RAMP = 32, - E_TYPE_GOLD = 33, - E_TYPE_ISLAND_ENTITLEMENT = 34 + br.BaseStream.Position = trigger; + GenericRegion region = new(); + region.Read(br); + TriggerIds.Add(region.mId); } - public GenericRegion() : base() + br.BaseStream.Position = cgsOffset; + RegionIds = []; + for (int i = 0; i < RegionIdCount; i++) { - // Set meType to E_TYPE_GENERIC_REGION - meType = RegionType.E_TYPE_GENERIC_REGION; + CgsID id = new(); + id.Read(br); + RegionIds.Add(id); } - public int GroupID { get; set; } = 0; - public short CameraCut1 { get; set; } = 0; - public short CameraCut2 { get; set; } = 0; - public StuntCameraType CameraType1 { get; set; } = 0; - public StuntCameraType CameraType2 { get; set; } = 0; - public Type GenericRegionType { get; set; } = Type.E_TYPE_JUNK_YARD; - public sbyte IsOneWay { get; set; } = 0; + br.BaseStream.Position = currentPosition; + } - public new void Read(BinaryReader2 br) + public void Write(BinaryWriter2 bw, bool x64) + { + TriggerOffsetPosition = bw.BaseStream.Position; + bw.WriteUniquePadding(x64 ? 8 : 4); + bw.Write(TriggerIds.Count); + if (x64) + bw.WriteUniquePadding(4); + CGSIDOffsetPosition = bw.BaseStream.Position; + bw.WriteUniquePadding(x64 ? 8 : 4); + bw.Write(RegionIds.Count); + if (x64) + bw.WriteUniquePadding(4); + } + + public void WritePointerStuff(BinaryWriter2 bw, Dictionary genericRegionOffsets, bool x64) { + + long currentPosition = bw.BaseStream.Position; + bw.BaseStream.Position = TriggerOffsetPosition; + TriggerData.WritePtr(bw, currentPosition, x64); + bw.BaseStream.Position = currentPosition; + foreach (int trigger in TriggerIds) { - base.Read(br); - GroupID = br.ReadInt32(); - CameraCut1 = br.ReadInt16(); - CameraCut2 = br.ReadInt16(); - CameraType1 = (StuntCameraType)br.ReadSByte(); - CameraType2 = (StuntCameraType)br.ReadSByte(); - GenericRegionType = (Type)br.ReadByte(); - IsOneWay = br.ReadSByte(); + TriggerData.WritePtr(bw, genericRegionOffsets[trigger], x64); } - - public new void Write(BinaryWriter2 bw) + long paddingCount = 16 - (bw.BaseStream.Position % 16); + if (paddingCount < 16) + { + for (int i = 0; i < paddingCount; i++) + bw.Write((byte)0); + } + currentPosition = bw.BaseStream.Position; + bw.BaseStream.Position = CGSIDOffsetPosition; + TriggerData.WritePtr(bw, currentPosition, x64); + bw.BaseStream.Position = currentPosition; + foreach (CgsID ids in RegionIds) { - base.Write(bw); - bw.Write(GroupID); - bw.Write(CameraCut1); - bw.Write(CameraCut2); - bw.Write((sbyte)CameraType1); - bw.Write((sbyte)CameraType2); - bw.Write((byte)GenericRegionType); - bw.Write(IsOneWay); + ids.Write(bw); + } + paddingCount = 16 - (bw.BaseStream.Position % 16); + if (paddingCount < 16) + { + for (int i = 0; i < paddingCount; i++) + bw.Write((byte)0); } } +} - public class Blackspot : TriggerRegion +public class SignatureStunt +{ + [TypeConverter(typeof(ExpandableObjectConverter))] + public CgsID mId { get; set; } = new CgsID(); + public long miCamera { get; set; } = 0; + public List stuntElementRegions { get; set; } = []; + + private long StuntElementOffsetPosition = 0; + + public void Read(BinaryReader2 br, bool x64) { - public enum ScoreType + mId = new CgsID(); + mId.Read(br); + miCamera = br.ReadInt64(); + + uint mppStuntElementsOffset = (uint)TriggerData.ReadPtr(br, x64); + int miStuntElementCount = br.ReadInt32(); + if (x64) + br.ReadBytes(4); // Padding + + long currentPosition = br.BaseStream.Position; + br.BaseStream.Position = mppStuntElementsOffset; + uint[] Triggers = new uint[miStuntElementCount]; + for (int i = 0; i < miStuntElementCount; i++) { - E_SCORE_TYPE_DISTANCE = 0, - E_SCORE_TYPE_CAR_COUNT = 1 + Triggers[i] = (uint)TriggerData.ReadPtr(br, x64); } - public Blackspot() : base() + stuntElementRegions = []; + foreach (uint trigger in Triggers) { - // Set meType to E_TYPE_BLACKSPOT - meType = RegionType.E_TYPE_BLACKSPOT; + br.BaseStream.Position = trigger; + GenericRegion region = new(); + region.Read(br); + stuntElementRegions.Add(region.mId); } + br.BaseStream.Position = currentPosition; + } - public ScoreType muScoreType { get; set; } = ScoreType.E_SCORE_TYPE_DISTANCE; - public int miScoreAmount { get; set; } = 0; + // Write something in triggerIds, because we dont have the actual positions yet + public void Write(BinaryWriter2 bw, bool x64) + { + mId.Write(bw); + bw.Write(miCamera); + StuntElementOffsetPosition = bw.BaseStream.Position; + bw.WriteUniquePadding(x64 ? 8 : 4); + bw.Write(stuntElementRegions.Count); + if (x64) + bw.WriteUniquePadding(4); + } - public override void Read(BinaryReader2 br) + public void WriteStuntElements(BinaryWriter2 bw, Dictionary genericRegionOffsets, bool x64) { + long currentPosition = bw.BaseStream.Position; + bw.BaseStream.Position = StuntElementOffsetPosition; + bw.Write(currentPosition); + bw.BaseStream.Position = currentPosition; + foreach (int trigger in stuntElementRegions) { - base.Read(br); - - muScoreType = (ScoreType)br.ReadByte(); - br.ReadBytes(3); // Padding - miScoreAmount = br.ReadInt32(); + TriggerData.WritePtr(bw, genericRegionOffsets[trigger], x64); } + } +} - public override void Write(BinaryWriter2 bw) - { - base.Write(bw); +public class RoamingLocation +{ + [TypeConverter(typeof(ExpandableObjectConverter))] + public Vector4 Position { get; set; } = new Vector4(0,0,0,0); + public byte DistrictIndex { get; set; } = 0; - bw.Write((byte)muScoreType); - bw.Write(new byte[3]); // Padding - bw.Write(miScoreAmount); - } + public void Read(BinaryReader2 br) + { + Position = new Vector4( + br.ReadSingle(), + br.ReadSingle(), + br.ReadSingle(), + br.ReadSingle()); + DistrictIndex = br.ReadByte(); + // Read and discard padding + br.ReadBytes(15); } - public class Killzone + public void Write(BinaryWriter2 bw) { - [Description("Triggers as GenericRegions. Uses region.mId")] - public List TriggerIds { get; set; } = new List(); - public List RegionIds { get; set; } = new List(); + bw.Write(Position.X); + bw.Write(Position.Y); + bw.Write(Position.Z); + bw.Write(Position.W); + bw.Write(DistrictIndex); + + // Write padding + bw.Write(new byte[15]); + } +} - private long TriggerOffsetPosition = 0; +public class VFXBoxRegion : TriggerRegion +{ + public VFXBoxRegion() : base() + { + // Set meType to E_TYPE_VFXBOX_REGION + meType = RegionType.E_TYPE_VFXBOX_REGION; + } - private long CGSIDOffsetPosition = 0; - public void Read(BinaryReader2 br, bool x64) - { - // Read the trigger pointer array - long genericRegionOffset = TriggerData.ReadPtr(br, x64); - int TriggerCount = br.ReadInt32(); - if (x64) - br.ReadBytes(4); // Padding + public override void Read(BinaryReader2 br) + { + base.Read(br); + } - // Read the region ID array - long cgsOffset = TriggerData.ReadPtr(br, x64); - int RegionIdCount = br.ReadInt32(); - if (x64) - br.ReadBytes(4); // Padding - long currentPosition = br.BaseStream.Position; - - br.BaseStream.Position = genericRegionOffset; - uint[] Triggers = new uint[TriggerCount]; - for (int i = 0; i < TriggerCount; i++) - { - Triggers[i] = (uint)TriggerData.ReadPtr(br, x64); - } - - TriggerIds = new List(); - foreach (uint trigger in Triggers) - { - br.BaseStream.Position = trigger; - GenericRegion region = new GenericRegion(); - region.Read(br); - TriggerIds.Add(region.mId); - } - - br.BaseStream.Position = cgsOffset; - RegionIds = new List(); - for (int i = 0; i < RegionIdCount; i++) - { - CgsID id = new CgsID(); - id.Read(br); - RegionIds.Add(id); - } - - br.BaseStream.Position = currentPosition; - } + public override void Write(BinaryWriter2 bw) + { + base.Write(bw); + } +} - public void Write(BinaryWriter2 bw, bool x64) - { - TriggerOffsetPosition = bw.BaseStream.Position; - bw.WriteUniquePadding(x64 ? 8 : 4); - bw.Write(TriggerIds.Count); - if (x64) - bw.WriteUniquePadding(4); - CGSIDOffsetPosition = bw.BaseStream.Position; - bw.WriteUniquePadding(x64 ? 8 : 4); - bw.Write(RegionIds.Count); - if (x64) - bw.WriteUniquePadding(4); - } +public class SpawnLocation +{ + public enum Type + { + E_TYPE_PLAYER_SPAWN = 0, + E_TYPE_CAR_SELECT_LEFT = 1, + E_TYPE_CAR_SELECT_RIGHT = 2, + E_TYPE_CAR_UNLOCK = 3 + } - public void WritePointerStuff(BinaryWriter2 bw, Dictionary genericRegionOffsets, bool x64) { - - long currentPosition = bw.BaseStream.Position; - bw.BaseStream.Position = TriggerOffsetPosition; - TriggerData.WritePtr(bw, currentPosition, x64); - bw.BaseStream.Position = currentPosition; - foreach (int trigger in TriggerIds) - { - TriggerData.WritePtr(bw, genericRegionOffsets[trigger], x64); - } - long paddingCount = 16 - (bw.BaseStream.Position % 16); - if (paddingCount < 16) - { - for (int i = 0; i < paddingCount; i++) - bw.Write((byte)0); - } - currentPosition = bw.BaseStream.Position; - bw.BaseStream.Position = CGSIDOffsetPosition; - TriggerData.WritePtr(bw, currentPosition, x64); - bw.BaseStream.Position = currentPosition; - foreach (CgsID ids in RegionIds) - { - ids.Write(bw); - } - paddingCount = 16 - (bw.BaseStream.Position % 16); - if (paddingCount < 16) - { - for (int i = 0; i < paddingCount; i++) - bw.Write((byte)0); - } - } + [TypeConverter(typeof(ExpandableObjectConverter))] + public Vector4 mPosition { get; set; } = new Vector4(0, 0, 0, 0); + [TypeConverter(typeof(ExpandableObjectConverter))] + public Vector4 mDirection { get; set; } = new Vector4(0, 0, 0, 0); + [TypeConverter(typeof(ExpandableObjectConverter))] + public CgsID mJunkyardId { get; set; } = new CgsID(); + public Type muType { get; set; } = 0; + private byte[] padding = new byte[7]; + + public void Read(BinaryReader2 br) + { + mPosition = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); + mDirection = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); + mJunkyardId = new CgsID(); + mJunkyardId.Read(br); + muType = (Type)br.ReadByte(); + padding = br.ReadBytes(7); + } + + public void Write(BinaryWriter2 bw) + { + bw.Write(mPosition.X); + bw.Write(mPosition.Y); + bw.Write(mPosition.Z); + bw.Write(mPosition.W); + bw.Write(mDirection.X); + bw.Write(mDirection.Y); + bw.Write(mDirection.Z); + bw.Write(mDirection.W); + mJunkyardId.Write(bw); + bw.Write((byte)muType); + bw.Write(padding); } +} - public class SignatureStunt +public class TriggerData : IEntryData +{ + public int miVersionNumber { get; set; } + public uint muSize { get; set; } + public Vector4 mPlayerStartPosition { get; set; } + public Vector4 mPlayerStartDirection { get; set; } + public List mpLandmarks { get; set; } + public int miOnlineLandmarkCount { get; set; } + public List mpSignatureStunts { get; set; } + public List mpGenericRegions { get; set; } + + [Editor(typeof(DescriptiveCollectionEditor), typeof(UITypeEditor))] + public List mpKillzones { get; set; } + public List mpBlackspots { get; set; } + public List mpVFXBoxRegions { get; set; } + public List mpRoamingLocations { get; set; } + public List mpSpawnLocations { get; set; } + private List TriggerOffsets { get; set; } + + // Decomp has 8-byte pointers, so each pointer/count pair is padded out to 16 bytes + internal static long ReadPtr(BinaryReader2 br, bool x64) => x64 ? (long)br.ReadUInt64() : br.ReadUInt32(); + + internal static void WritePtr(BinaryWriter2 bw, long ptr, bool x64) { - [TypeConverter(typeof(ExpandableObjectConverter))] - public CgsID mId { get; set; } = new CgsID(); - public long miCamera { get; set; } = 0; - public List stuntElementRegions { get; set; } = new List(); + if (x64) + bw.Write((ulong)ptr); + else + bw.Write((uint)ptr); + } - private long StuntElementOffsetPosition = 0; + public bool Read(BundleEntry entry, ILoader loader = null) + { + MemoryStream ms = entry.MakeStream(); + BinaryReader2 reader = new(ms); + reader.BigEndian = entry.Console; - public void Read(BinaryReader2 br, bool x64) + bool x64 = entry.Platform == BundlePlatform.PCx64; + int ReadCount() { - mId = new CgsID(); - mId.Read(br); - miCamera = br.ReadInt64(); - - uint mppStuntElementsOffset = (uint)TriggerData.ReadPtr(br, x64); - int miStuntElementCount = br.ReadInt32(); + int count = reader.ReadInt32(); if (x64) - br.ReadBytes(4); // Padding - - long currentPosition = br.BaseStream.Position; - br.BaseStream.Position = mppStuntElementsOffset; - uint[] Triggers = new uint[miStuntElementCount]; - for (int i = 0; i < miStuntElementCount; i++) - { - Triggers[i] = (uint)TriggerData.ReadPtr(br, x64); - } - - stuntElementRegions = new List(); - foreach (uint trigger in Triggers) - { - br.BaseStream.Position = trigger; - GenericRegion region = new GenericRegion(); - region.Read(br); - stuntElementRegions.Add(region.mId); - } - br.BaseStream.Position = currentPosition; + reader.ReadBytes(4); // Padding + return count; } - // Write something in triggerIds, because we dont have the actual positions yet - public void Write(BinaryWriter2 bw, bool x64) + miVersionNumber = reader.ReadInt32(); + muSize = reader.ReadUInt32(); + reader.ReadBytes(8);// skip 8 bytes of padding + mPlayerStartPosition = new Vector4(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); + mPlayerStartDirection = new Vector4(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); + // read landmarks + long LandmarkTriggersOffset = ReadPtr(reader, x64); + int miLandmarkCount = reader.ReadInt32(); + miOnlineLandmarkCount = reader.ReadInt32(); + + long SignatureStuntsOffset = ReadPtr(reader, x64); + int miSignatureStuntCount = ReadCount(); + + long GenericRegionsOffset = ReadPtr(reader, x64); + int miGenericRegionCount = ReadCount(); + + long KillzoneOffset = ReadPtr(reader, x64); + int miKillzoneCount = ReadCount(); + + long BlackspotOffset = ReadPtr(reader, x64); + int miBlackspotCount = ReadCount(); + + long VFXBoxRegionOffset = ReadPtr(reader, x64); + int miVFXBoxRegionCount = ReadCount(); + + long RoamingLocationOffset = ReadPtr(reader, x64); + int miRoamingLocationCount = ReadCount(); + + long SpawnLocationOffset = ReadPtr(reader, x64); + int miSpawnLocationCount = ReadCount(); + + long TriggerRegionOffset = ReadPtr(reader, x64); + int miRegionCount = reader.ReadInt32(); + + reader.BaseStream.Position = LandmarkTriggersOffset; + mpLandmarks = []; + for (int i = 0; i < miLandmarkCount; i++) { - mId.Write(bw); - bw.Write(miCamera); - StuntElementOffsetPosition = bw.BaseStream.Position; - bw.WriteUniquePadding(x64 ? 8 : 4); - bw.Write(stuntElementRegions.Count); - if (x64) - bw.WriteUniquePadding(4); + Landmark landmark = new(); + landmark.Read(reader, x64); + mpLandmarks.Add(landmark); } - public void WriteStuntElements(BinaryWriter2 bw, Dictionary genericRegionOffsets, bool x64) { - long currentPosition = bw.BaseStream.Position; - bw.BaseStream.Position = StuntElementOffsetPosition; - bw.Write(currentPosition); - bw.BaseStream.Position = currentPosition; - foreach (int trigger in stuntElementRegions) - { - TriggerData.WritePtr(bw, genericRegionOffsets[trigger], x64); - } + reader.BaseStream.Position = SignatureStuntsOffset; + // read signature stunts + mpSignatureStunts = []; + for (int i = 0; i < miSignatureStuntCount; i++) + { + SignatureStunt stunt = new(); + stunt.Read(reader, x64); + mpSignatureStunts.Add(stunt); } - } + + reader.BaseStream.Position = GenericRegionsOffset; + // read generic regions + mpGenericRegions = []; + for (int i = 0; i < miGenericRegionCount; i++) + { + GenericRegion region = new(); + region.Read(reader); + mpGenericRegions.Add(region); + } + - public class RoamingLocation - { - [TypeConverter(typeof(ExpandableObjectConverter))] - public Vector4 Position { get; set; } = new Vector4(0,0,0,0); - public byte DistrictIndex { get; set; } = 0; + reader.BaseStream.Position = KillzoneOffset; + // read killzones + mpKillzones = []; + for (int i = 0; i < miKillzoneCount; i++) + { + Killzone killzone = new(); + killzone.Read(reader, x64); + mpKillzones.Add(killzone); + } - public void Read(BinaryReader2 br) + // read blackspots + reader.BaseStream.Position = BlackspotOffset; + mpBlackspots = []; + for (int i = 0; i < miBlackspotCount; i++) { - Position = new Vector4( - br.ReadSingle(), - br.ReadSingle(), - br.ReadSingle(), - br.ReadSingle()); - DistrictIndex = br.ReadByte(); - // Read and discard padding - br.ReadBytes(15); + Blackspot spot = new(); + spot.Read(reader); + mpBlackspots.Add(spot); } - public void Write(BinaryWriter2 bw) + reader.BaseStream.Position = VFXBoxRegionOffset; + + // read VFX box regions + mpVFXBoxRegions = []; + for (int i = 0; i < miVFXBoxRegionCount; i++) { - bw.Write(Position.X); - bw.Write(Position.Y); - bw.Write(Position.Z); - bw.Write(Position.W); - bw.Write(DistrictIndex); - - // Write padding - bw.Write(new byte[15]); + VFXBoxRegion box = new(); + box.Read(reader); + mpVFXBoxRegions.Add(box); } - } - public class VFXBoxRegion : TriggerRegion - { - public VFXBoxRegion() : base() + reader.BaseStream.Position = RoamingLocationOffset; + + // read roaming locations + mpRoamingLocations = []; + for (int i = 0; i < miRoamingLocationCount; i++) { - // Set meType to E_TYPE_VFXBOX_REGION - meType = RegionType.E_TYPE_VFXBOX_REGION; + RoamingLocation location = new(); + location.Read(reader); + mpRoamingLocations.Add(location); } + + reader.BaseStream.Position = SpawnLocationOffset; - public override void Read(BinaryReader2 br) + mpSpawnLocations = []; + for (int i = 0; i < miSpawnLocationCount; i++) { - base.Read(br); + SpawnLocation location = new(); + location.Read(reader); + mpSpawnLocations.Add(location); } - public override void Write(BinaryWriter2 bw) + reader.BaseStream.Position = TriggerRegionOffset; + + // read TriggerRegion (miGenericCount + miLandmarkCount) + TriggerOffsets = []; + for (int i = 0; i < miRegionCount; i++) { - base.Write(bw); + uint section6Entry = (uint)ReadPtr(reader, x64); + TriggerOffsets.Add(section6Entry); } + + return true; + } + + public IEntryEditor GetEditor(BundleEntry entry) + { + TriggerDataEditor triggerDataEditor = new(); + triggerDataEditor.trigger = this; + + triggerDataEditor.EditEvent += () => + { + Write(entry); + }; + return triggerDataEditor; } - public class SpawnLocation + public EntryType GetEntryType(BundleEntry entry) { - public enum Type + return EntryType.TriggerData; + } + + public bool Write(BundleEntry entry) + { + MemoryStream ms = new(); + BinaryWriter2 bw = new(ms); + bw.BigEndian = entry.Console; + + bool x64 = entry.Platform == BundlePlatform.PCx64; + int ptrSize = x64 ? 8 : 4; + void WriteCount(int count) { - E_TYPE_PLAYER_SPAWN = 0, - E_TYPE_CAR_SELECT_LEFT = 1, - E_TYPE_CAR_SELECT_RIGHT = 2, - E_TYPE_CAR_UNLOCK = 3 + bw.Write(count); + if (x64) + bw.WriteUniquePadding(4); // Padding } - [TypeConverter(typeof(ExpandableObjectConverter))] - public Vector4 mPosition { get; set; } = new Vector4(0, 0, 0, 0); - [TypeConverter(typeof(ExpandableObjectConverter))] - public Vector4 mDirection { get; set; } = new Vector4(0, 0, 0, 0); - [TypeConverter(typeof(ExpandableObjectConverter))] - public CgsID mJunkyardId { get; set; } = new CgsID(); - public Type muType { get; set; } = 0; - private byte[] padding = new byte[7]; + // The game looks regions up as mppRegions[miRegionIndex], so the table is ordered by index with no gaps. + // A region whose index is out of range or already taken (e.g. a newly added one) gets the first free index. + List regions = [.. mpVFXBoxRegions, .. mpBlackspots, .. mpGenericRegions, .. mpLandmarks]; + + // IDs are unique too (killzones and stunts reference generic regions by mId), so a duplicate gets a new one + int nextId = 0; + foreach (TriggerRegion region in regions) + nextId = Math.Max(nextId, region.mId + 1); + HashSet usedIds = []; + foreach (TriggerRegion region in regions) + if (!usedIds.Add(region.mId)) + region.mId = nextId++; + + TriggerRegion[] regionTable = new TriggerRegion[regions.Count]; + List unplacedRegions = []; + foreach (TriggerRegion region in regions) + { + if (region.miRegionIndex >= 0 && region.miRegionIndex < regionTable.Length && regionTable[region.miRegionIndex] == null) + regionTable[region.miRegionIndex] = region; + else + unplacedRegions.Add(region); + } + int freeIndex = 0; + foreach (TriggerRegion region in unplacedRegions) + { + while (regionTable[freeIndex] != null) + freeIndex++; + regionTable[freeIndex] = region; + region.miRegionIndex = (short)freeIndex; + } + Dictionary regionOffsets = []; + + bw.Write(miVersionNumber); + long SizePosition = bw.BaseStream.Position; + bw.WriteUniquePadding(4); + bw.WriteUniquePadding(8); //padding + bw.Write(mPlayerStartPosition.X); + bw.Write(mPlayerStartPosition.Y); + bw.Write(mPlayerStartPosition.Z); + bw.Write(mPlayerStartPosition.W); + bw.Write(mPlayerStartDirection.X); + bw.Write(mPlayerStartDirection.Y); + bw.Write(mPlayerStartDirection.Z); + bw.Write(mPlayerStartDirection.W); + + long LandmarkOffsetPosition = bw.BaseStream.Position; + bw.WriteUniquePadding(ptrSize); + bw.Write(mpLandmarks.Count); + bw.Write(miOnlineLandmarkCount); + long SignatureStuntskOffsetPosition = bw.BaseStream.Position; + bw.WriteUniquePadding(ptrSize); + WriteCount(mpSignatureStunts.Count); + long GenericRegionsOffsetPosition = bw.BaseStream.Position; + bw.WriteUniquePadding(ptrSize); + WriteCount(mpGenericRegions.Count); + long KillzoneOffsetPosition = bw.BaseStream.Position; + bw.WriteUniquePadding(ptrSize); + WriteCount(mpKillzones.Count); + long BlackspotOffsetPosition = bw.BaseStream.Position; + bw.WriteUniquePadding(ptrSize); + WriteCount(mpBlackspots.Count); + long VFXBoxRegionsOffsetPosition = bw.BaseStream.Position; + bw.WriteUniquePadding(ptrSize); + WriteCount(mpVFXBoxRegions.Count); + long RoamingLocationsOffsetPosition = bw.BaseStream.Position; + bw.WriteUniquePadding(ptrSize); + WriteCount(mpRoamingLocations.Count); + long SpawnLocationsOffsetPosition = bw.BaseStream.Position; + bw.WriteUniquePadding(ptrSize); + WriteCount(mpSpawnLocations.Count); + long TriggerOffsetPosition = bw.BaseStream.Position; + bw.WriteUniquePadding(ptrSize); + bw.Write(mpLandmarks.Count + mpGenericRegions.Count + mpBlackspots.Count + mpVFXBoxRegions.Count); + bw.WriteUniquePadding(4); // padding + + long currentPosition = bw.BaseStream.Position; + bw.BaseStream.Position = LandmarkOffsetPosition; + WritePtr(bw, currentPosition, x64); + bw.BaseStream.Position = currentPosition; + foreach (Landmark landmark in mpLandmarks) + { + regionOffsets.Add(landmark, (uint)bw.BaseStream.Position); + landmark.Write(bw, x64); + } + bw.WritePadding(); - public void Read(BinaryReader2 br) + currentPosition = bw.BaseStream.Position; + bw.BaseStream.Position = SignatureStuntskOffsetPosition; + WritePtr(bw, currentPosition, x64); + bw.BaseStream.Position = currentPosition; + foreach (SignatureStunt stunt in mpSignatureStunts) + { + stunt.Write(bw, x64); + } + bw.WritePadding(); + + currentPosition = bw.BaseStream.Position; + bw.BaseStream.Position = GenericRegionsOffsetPosition; + WritePtr(bw, currentPosition, x64); + bw.BaseStream.Position = currentPosition; + Dictionary genericRegionOffsets = []; + foreach (GenericRegion region in mpGenericRegions) { - mPosition = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); - mDirection = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); - mJunkyardId = new CgsID(); - mJunkyardId.Read(br); - muType = (Type)br.ReadByte(); - padding = br.ReadBytes(7); + genericRegionOffsets.Add(region.mId, (uint)bw.BaseStream.Position); + regionOffsets.Add(region, (uint)bw.BaseStream.Position); + region.Write(bw); } + bw.WritePadding(); - public void Write(BinaryWriter2 bw) + currentPosition = bw.BaseStream.Position; + bw.BaseStream.Position = KillzoneOffsetPosition; + WritePtr(bw, currentPosition, x64); + bw.BaseStream.Position = currentPosition; + foreach (Killzone killzone in mpKillzones) + { + killzone.Write(bw, x64); + }; + bw.WritePadding(); + + currentPosition = bw.BaseStream.Position; + bw.BaseStream.Position = BlackspotOffsetPosition; + WritePtr(bw, currentPosition, x64); + bw.BaseStream.Position = currentPosition; + foreach (Blackspot blackspot in mpBlackspots) { - bw.Write(mPosition.X); - bw.Write(mPosition.Y); - bw.Write(mPosition.Z); - bw.Write(mPosition.W); - bw.Write(mDirection.X); - bw.Write(mDirection.Y); - bw.Write(mDirection.Z); - bw.Write(mDirection.W); - mJunkyardId.Write(bw); - bw.Write((byte)muType); - bw.Write(padding); + regionOffsets.Add(blackspot, (uint)bw.BaseStream.Position); + blackspot.Write(bw); } - } + bw.WritePadding(); - public class TriggerData : IEntryData - { - public int miVersionNumber { get; set; } - public uint muSize { get; set; } - public Vector4 mPlayerStartPosition { get; set; } - public Vector4 mPlayerStartDirection { get; set; } - public List mpLandmarks { get; set; } - public int miOnlineLandmarkCount { get; set; } - public List mpSignatureStunts { get; set; } - public List mpGenericRegions { get; set; } - - [Editor(typeof(DescriptiveCollectionEditor), typeof(UITypeEditor))] - public List mpKillzones { get; set; } - public List mpBlackspots { get; set; } - public List mpVFXBoxRegions { get; set; } - public List mpRoamingLocations { get; set; } - public List mpSpawnLocations { get; set; } - private List TriggerOffsets { get; set; } - - // Decomp has 8-byte pointers, so each pointer/count pair is padded out to 16 bytes - internal static long ReadPtr(BinaryReader2 br, bool x64) => x64 ? (long)br.ReadUInt64() : br.ReadUInt32(); - - internal static void WritePtr(BinaryWriter2 bw, long ptr, bool x64) + currentPosition = bw.BaseStream.Position; + bw.BaseStream.Position = VFXBoxRegionsOffsetPosition; + WritePtr(bw, currentPosition, x64); + bw.BaseStream.Position = currentPosition; + foreach (VFXBoxRegion region in mpVFXBoxRegions) { - if (x64) - bw.Write((ulong)ptr); - else - bw.Write((uint)ptr); + regionOffsets.Add(region, (uint)bw.BaseStream.Position); + region.Write(bw); } + bw.WritePadding(); - public bool Read(BundleEntry entry, ILoader loader = null) + currentPosition = bw.BaseStream.Position; + bw.BaseStream.Position = RoamingLocationsOffsetPosition; + WritePtr(bw, currentPosition, x64); + bw.BaseStream.Position = currentPosition; + foreach (RoamingLocation location in mpRoamingLocations) { - MemoryStream ms = entry.MakeStream(); - BinaryReader2 reader = new BinaryReader2(ms); - reader.BigEndian = entry.Console; - - bool x64 = entry.Platform == BundlePlatform.PCx64; - int ReadCount() - { - int count = reader.ReadInt32(); - if (x64) - reader.ReadBytes(4); // Padding - return count; - } - - miVersionNumber = reader.ReadInt32(); - muSize = reader.ReadUInt32(); - reader.ReadBytes(8);// skip 8 bytes of padding - mPlayerStartPosition = new Vector4(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); - mPlayerStartDirection = new Vector4(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); - // read landmarks - long LandmarkTriggersOffset = ReadPtr(reader, x64); - int miLandmarkCount = reader.ReadInt32(); - miOnlineLandmarkCount = reader.ReadInt32(); - - long SignatureStuntsOffset = ReadPtr(reader, x64); - int miSignatureStuntCount = ReadCount(); - - long GenericRegionsOffset = ReadPtr(reader, x64); - int miGenericRegionCount = ReadCount(); - - long KillzoneOffset = ReadPtr(reader, x64); - int miKillzoneCount = ReadCount(); - - long BlackspotOffset = ReadPtr(reader, x64); - int miBlackspotCount = ReadCount(); - - long VFXBoxRegionOffset = ReadPtr(reader, x64); - int miVFXBoxRegionCount = ReadCount(); - - long RoamingLocationOffset = ReadPtr(reader, x64); - int miRoamingLocationCount = ReadCount(); - - long SpawnLocationOffset = ReadPtr(reader, x64); - int miSpawnLocationCount = ReadCount(); - - long TriggerRegionOffset = ReadPtr(reader, x64); - int miRegionCount = reader.ReadInt32(); - - reader.BaseStream.Position = LandmarkTriggersOffset; - mpLandmarks = new List(); - for (int i = 0; i < miLandmarkCount; i++) - { - Landmark landmark = new Landmark(); - landmark.Read(reader, x64); - mpLandmarks.Add(landmark); - } - - reader.BaseStream.Position = SignatureStuntsOffset; - // read signature stunts - mpSignatureStunts = new List(); - for (int i = 0; i < miSignatureStuntCount; i++) - { - SignatureStunt stunt = new SignatureStunt(); - stunt.Read(reader, x64); - mpSignatureStunts.Add(stunt); - } - - reader.BaseStream.Position = GenericRegionsOffset; - // read generic regions - mpGenericRegions = new List(); - for (int i = 0; i < miGenericRegionCount; i++) - { - GenericRegion region = new GenericRegion(); - region.Read(reader); - mpGenericRegions.Add(region); - } - - - reader.BaseStream.Position = KillzoneOffset; - // read killzones - mpKillzones = new List(); - for (int i = 0; i < miKillzoneCount; i++) - { - Killzone killzone = new Killzone(); - killzone.Read(reader, x64); - mpKillzones.Add(killzone); - } - - // read blackspots - reader.BaseStream.Position = BlackspotOffset; - mpBlackspots = new List(); - for (int i = 0; i < miBlackspotCount; i++) - { - Blackspot spot = new Blackspot(); - spot.Read(reader); - mpBlackspots.Add(spot); - } - - reader.BaseStream.Position = VFXBoxRegionOffset; - - // read VFX box regions - mpVFXBoxRegions = new List(); - for (int i = 0; i < miVFXBoxRegionCount; i++) - { - VFXBoxRegion box = new VFXBoxRegion(); - box.Read(reader); - mpVFXBoxRegions.Add(box); - } - - reader.BaseStream.Position = RoamingLocationOffset; - - // read roaming locations - mpRoamingLocations = new List(); - for (int i = 0; i < miRoamingLocationCount; i++) - { - RoamingLocation location = new RoamingLocation(); - location.Read(reader); - mpRoamingLocations.Add(location); - } - - reader.BaseStream.Position = SpawnLocationOffset; - - mpSpawnLocations = new List(); - for (int i = 0; i < miSpawnLocationCount; i++) - { - SpawnLocation location = new SpawnLocation(); - location.Read(reader); - mpSpawnLocations.Add(location); - } - - reader.BaseStream.Position = TriggerRegionOffset; - - // read TriggerRegion (miGenericCount + miLandmarkCount) - TriggerOffsets = new List(); - for (int i = 0; i < miRegionCount; i++) - { - uint section6Entry = (uint)ReadPtr(reader, x64); - TriggerOffsets.Add(section6Entry); - } - - return true; + location.Write(bw); } + bw.WritePadding(); - public IEntryEditor GetEditor(BundleEntry entry) + currentPosition = bw.BaseStream.Position; + bw.BaseStream.Position = SpawnLocationsOffsetPosition; + WritePtr(bw, currentPosition, x64); + bw.BaseStream.Position = currentPosition; + foreach (SpawnLocation location in mpSpawnLocations) { - TriggerDataEditor triggerDataEditor = new TriggerDataEditor(); - triggerDataEditor.trigger = this; - - triggerDataEditor.EditEvent += () => - { - Write(entry); - }; - return triggerDataEditor; + location.Write(bw); + } + bw.WritePadding(); + + foreach (Landmark land in mpLandmarks) { + land.WriteStartingGrid(bw, x64); } - public EntryType GetEntryType(BundleEntry entry) + foreach (SignatureStunt stunt in mpSignatureStunts) { - return EntryType.TriggerData; + stunt.WriteStuntElements(bw, genericRegionOffsets, x64); } - public bool Write(BundleEntry entry) + foreach (Killzone killzone in mpKillzones) { - MemoryStream ms = new MemoryStream(); - BinaryWriter2 bw = new BinaryWriter2(ms); - bw.BigEndian = entry.Console; - - bool x64 = entry.Platform == BundlePlatform.PCx64; - int ptrSize = x64 ? 8 : 4; - void WriteCount(int count) - { - bw.Write(count); - if (x64) - bw.WriteUniquePadding(4); // Padding - } - - // The game looks regions up as mppRegions[miRegionIndex], so the table is ordered by index with no gaps. - // A region whose index is out of range or already taken (e.g. a newly added one) gets the first free index. - List regions = [.. mpVFXBoxRegions, .. mpBlackspots, .. mpGenericRegions, .. mpLandmarks]; - - // IDs are unique too (killzones and stunts reference generic regions by mId), so a duplicate gets a new one - int nextId = 0; - foreach (TriggerRegion region in regions) - nextId = Math.Max(nextId, region.mId + 1); - HashSet usedIds = new HashSet(); - foreach (TriggerRegion region in regions) - if (!usedIds.Add(region.mId)) - region.mId = nextId++; - - TriggerRegion[] regionTable = new TriggerRegion[regions.Count]; - List unplacedRegions = new List(); - foreach (TriggerRegion region in regions) - { - if (region.miRegionIndex >= 0 && region.miRegionIndex < regionTable.Length && regionTable[region.miRegionIndex] == null) - regionTable[region.miRegionIndex] = region; - else - unplacedRegions.Add(region); - } - int freeIndex = 0; - foreach (TriggerRegion region in unplacedRegions) - { - while (regionTable[freeIndex] != null) - freeIndex++; - regionTable[freeIndex] = region; - region.miRegionIndex = (short)freeIndex; - } - Dictionary regionOffsets = new Dictionary(); - - bw.Write(miVersionNumber); - long SizePosition = bw.BaseStream.Position; - bw.WriteUniquePadding(4); - bw.WriteUniquePadding(8); //padding - bw.Write(mPlayerStartPosition.X); - bw.Write(mPlayerStartPosition.Y); - bw.Write(mPlayerStartPosition.Z); - bw.Write(mPlayerStartPosition.W); - bw.Write(mPlayerStartDirection.X); - bw.Write(mPlayerStartDirection.Y); - bw.Write(mPlayerStartDirection.Z); - bw.Write(mPlayerStartDirection.W); - - long LandmarkOffsetPosition = bw.BaseStream.Position; - bw.WriteUniquePadding(ptrSize); - bw.Write(mpLandmarks.Count); - bw.Write(miOnlineLandmarkCount); - long SignatureStuntskOffsetPosition = bw.BaseStream.Position; - bw.WriteUniquePadding(ptrSize); - WriteCount(mpSignatureStunts.Count); - long GenericRegionsOffsetPosition = bw.BaseStream.Position; - bw.WriteUniquePadding(ptrSize); - WriteCount(mpGenericRegions.Count); - long KillzoneOffsetPosition = bw.BaseStream.Position; - bw.WriteUniquePadding(ptrSize); - WriteCount(mpKillzones.Count); - long BlackspotOffsetPosition = bw.BaseStream.Position; - bw.WriteUniquePadding(ptrSize); - WriteCount(mpBlackspots.Count); - long VFXBoxRegionsOffsetPosition = bw.BaseStream.Position; - bw.WriteUniquePadding(ptrSize); - WriteCount(mpVFXBoxRegions.Count); - long RoamingLocationsOffsetPosition = bw.BaseStream.Position; - bw.WriteUniquePadding(ptrSize); - WriteCount(mpRoamingLocations.Count); - long SpawnLocationsOffsetPosition = bw.BaseStream.Position; - bw.WriteUniquePadding(ptrSize); - WriteCount(mpSpawnLocations.Count); - long TriggerOffsetPosition = bw.BaseStream.Position; - bw.WriteUniquePadding(ptrSize); - bw.Write(mpLandmarks.Count + mpGenericRegions.Count + mpBlackspots.Count + mpVFXBoxRegions.Count); - bw.WriteUniquePadding(4); // padding - - long currentPosition = bw.BaseStream.Position; - bw.BaseStream.Position = LandmarkOffsetPosition; - WritePtr(bw, currentPosition, x64); - bw.BaseStream.Position = currentPosition; - foreach (Landmark landmark in mpLandmarks) - { - regionOffsets.Add(landmark, (uint)bw.BaseStream.Position); - landmark.Write(bw, x64); - } - bw.WritePadding(); - - currentPosition = bw.BaseStream.Position; - bw.BaseStream.Position = SignatureStuntskOffsetPosition; - WritePtr(bw, currentPosition, x64); - bw.BaseStream.Position = currentPosition; - foreach (SignatureStunt stunt in mpSignatureStunts) - { - stunt.Write(bw, x64); - } - bw.WritePadding(); - - currentPosition = bw.BaseStream.Position; - bw.BaseStream.Position = GenericRegionsOffsetPosition; - WritePtr(bw, currentPosition, x64); - bw.BaseStream.Position = currentPosition; - Dictionary genericRegionOffsets = new Dictionary(); - foreach (GenericRegion region in mpGenericRegions) - { - genericRegionOffsets.Add(region.mId, (uint)bw.BaseStream.Position); - regionOffsets.Add(region, (uint)bw.BaseStream.Position); - region.Write(bw); - } - bw.WritePadding(); - - currentPosition = bw.BaseStream.Position; - bw.BaseStream.Position = KillzoneOffsetPosition; - WritePtr(bw, currentPosition, x64); - bw.BaseStream.Position = currentPosition; - foreach (Killzone killzone in mpKillzones) - { - killzone.Write(bw, x64); - }; - bw.WritePadding(); - - currentPosition = bw.BaseStream.Position; - bw.BaseStream.Position = BlackspotOffsetPosition; - WritePtr(bw, currentPosition, x64); - bw.BaseStream.Position = currentPosition; - foreach (Blackspot blackspot in mpBlackspots) - { - regionOffsets.Add(blackspot, (uint)bw.BaseStream.Position); - blackspot.Write(bw); - } - bw.WritePadding(); - - currentPosition = bw.BaseStream.Position; - bw.BaseStream.Position = VFXBoxRegionsOffsetPosition; - WritePtr(bw, currentPosition, x64); - bw.BaseStream.Position = currentPosition; - foreach (VFXBoxRegion region in mpVFXBoxRegions) - { - regionOffsets.Add(region, (uint)bw.BaseStream.Position); - region.Write(bw); - } - bw.WritePadding(); - - currentPosition = bw.BaseStream.Position; - bw.BaseStream.Position = RoamingLocationsOffsetPosition; - WritePtr(bw, currentPosition, x64); - bw.BaseStream.Position = currentPosition; - foreach (RoamingLocation location in mpRoamingLocations) - { - location.Write(bw); - } - bw.WritePadding(); - - currentPosition = bw.BaseStream.Position; - bw.BaseStream.Position = SpawnLocationsOffsetPosition; - WritePtr(bw, currentPosition, x64); - bw.BaseStream.Position = currentPosition; - foreach (SpawnLocation location in mpSpawnLocations) - { - location.Write(bw); - } - bw.WritePadding(); - - foreach (Landmark land in mpLandmarks) { - land.WriteStartingGrid(bw, x64); - } - - foreach (SignatureStunt stunt in mpSignatureStunts) - { - stunt.WriteStuntElements(bw, genericRegionOffsets, x64); - } - - foreach (Killzone killzone in mpKillzones) - { - killzone.WritePointerStuff(bw, genericRegionOffsets, x64); - }; - - currentPosition = bw.BaseStream.Position; - bw.BaseStream.Position = TriggerOffsetPosition; - WritePtr(bw, currentPosition, x64); - bw.BaseStream.Position = currentPosition; - foreach (TriggerRegion region in regionTable) WritePtr(bw, regionOffsets[region], x64); + killzone.WritePointerStuff(bw, genericRegionOffsets, x64); + }; - if (x64) - bw.WritePadding(); // Decomp's size includes the trailing padding - currentPosition = bw.BaseStream.Position; - bw.BaseStream.Position = SizePosition; - bw.Write((uint)currentPosition); - bw.BaseStream.Position = currentPosition; - bw.WritePadding(); + currentPosition = bw.BaseStream.Position; + bw.BaseStream.Position = TriggerOffsetPosition; + WritePtr(bw, currentPosition, x64); + bw.BaseStream.Position = currentPosition; + foreach (TriggerRegion region in regionTable) WritePtr(bw, regionOffsets[region], x64); - bw.Flush(); + if (x64) + bw.WritePadding(); // Decomp's size includes the trailing padding + currentPosition = bw.BaseStream.Position; + bw.BaseStream.Position = SizePosition; + bw.Write((uint)currentPosition); + bw.BaseStream.Position = currentPosition; + bw.WritePadding(); - byte[] data = ms.ToArray(); + bw.Flush(); - bw.Close(); - ms.Close(); + byte[] data = ms.ToArray(); - entry.EntryBlocks[0].Data = data; - entry.Dirty = true; + bw.Close(); + ms.Close(); - return true; - } + entry.EntryBlocks[0].Data = data; + entry.Dirty = true; + + return true; } } diff --git a/BaseHandlers/TriggerDataEditor.cs b/BaseHandlers/TriggerDataEditor.cs index 0aa77b4..fdd6f13 100644 --- a/BaseHandlers/TriggerDataEditor.cs +++ b/BaseHandlers/TriggerDataEditor.cs @@ -3,43 +3,42 @@ using System.ComponentModel; using System.Windows.Forms; -namespace BaseHandlers +namespace BaseHandlers; + +public delegate void Notify(); // delegate +public partial class TriggerDataEditor : Form, IEntryEditor { - public delegate void Notify(); // delegate - public partial class TriggerDataEditor : Form, IEntryEditor - { - public event Notify EditEvent; + public event Notify EditEvent; - private TriggerData _trigger; - [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] - public TriggerData trigger + private TriggerData _trigger; + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public TriggerData trigger + { + get => _trigger; + set { - get => _trigger; - set - { - _trigger = value; - Console.WriteLine(value.muSize); - Console.WriteLine(_trigger.muSize); - Console.WriteLine(trigger.muSize); - - UpdateComponent(); - } + _trigger = value; + Console.WriteLine(value.muSize); + Console.WriteLine(_trigger.muSize); + Console.WriteLine(trigger.muSize); + + UpdateComponent(); } + } - public void UpdateComponent() - { - propertyGrid1.SelectedObject = trigger; - } + public void UpdateComponent() + { + propertyGrid1.SelectedObject = trigger; + } - public TriggerDataEditor() - { - InitializeComponent(); - UpdateComponent(); - } + public TriggerDataEditor() + { + InitializeComponent(); + UpdateComponent(); + } - private void TriggerDataEditor_FormClosed(object s, FormClosedEventArgs e) - { - EditEvent?.Invoke(); - } + private void TriggerDataEditor_FormClosed(object s, FormClosedEventArgs e) + { + EditEvent?.Invoke(); } } diff --git a/BundleFormat/BundleArchive.cs b/BundleFormat/BundleArchive.cs index 537862a..862c123 100644 --- a/BundleFormat/BundleArchive.cs +++ b/BundleFormat/BundleArchive.cs @@ -8,960 +8,955 @@ using System.Xml; using BundleUtilities; -namespace BundleFormat +namespace BundleFormat; + +[Flags] +public enum Flags { - [Flags] - public enum Flags - { - Compressed = 1, - UnusedFlag1 = 2, // Always set - UnusedFlag2 = 4, // Always set - HasResourceStringTable = 8 - } + Compressed = 1, + UnusedFlag1 = 2, // Always set + UnusedFlag2 = 4, // Always set + HasResourceStringTable = 8 +} - public enum BundlePlatform - { - PC = 1, - X360 = 2,// << 24, // Big Endian - PS3 = 3, // << 24 // Big Endian - PCx64 = 4 - } +public enum BundlePlatform +{ + PC = 1, + X360 = 2,// << 24, // Big Endian + PS3 = 3, // << 24 // Big Endian + PCx64 = 4 +} - public class BundleArchive +public class BundleArchive +{ + public static readonly byte[] BND1Magic = [0x62, 0x6E, 0x64, 0x6C]; + public static readonly byte[] BND2Magic = [0x62, 0x6E, 0x64, 0x32]; + + public string Path; + public int BNDVersion; + + public int Version; + public BundlePlatform Platform; + public int RSTOffset; // Normally 30 + public int EntryCount; + public int IDBlockOffset; + //public int HeadStart; + //public int BodyStart; + //public int ArchiveSize; + public Flags Flags; + + public bool Console => Platform == BundlePlatform.X360 || Platform == BundlePlatform.PS3; + + public string ResourceStringTable; + public List Entries; + + private bool _dirty; + public bool Dirty { - public static readonly byte[] BND1Magic = new byte[] { 0x62, 0x6E, 0x64, 0x6C }; - public static readonly byte[] BND2Magic = new byte[] { 0x62, 0x6E, 0x64, 0x32 }; - - public string Path; - public int BNDVersion; - - public int Version; - public BundlePlatform Platform; - public int RSTOffset; // Normally 30 - public int EntryCount; - public int IDBlockOffset; - //public int HeadStart; - //public int BodyStart; - //public int ArchiveSize; - public Flags Flags; - - public bool Console => Platform == BundlePlatform.X360 || Platform == BundlePlatform.PS3; - - public string ResourceStringTable; - public List Entries; - - private bool _dirty; - public bool Dirty + get { - get + if (_dirty) + return true; + foreach (BundleEntry entry in Entries) { - if (_dirty) + if (entry.Dirty) return true; - foreach (BundleEntry entry in Entries) - { - if (entry.Dirty) - return true; - } - return false; } - set + return false; + } + set + { + _dirty = value; + if (!_dirty) { - _dirty = value; - if (!_dirty) + foreach(BundleEntry entry in Entries) { - foreach(BundleEntry entry in Entries) - { - entry.Dirty = false; - } + entry.Dirty = false; } } } + } - public BundleArchive() - { - this.Entries = new List(); - } + public BundleArchive() + { + this.Entries = []; + } - public BundleEntry GetEntryByID(ulong id) + public BundleEntry GetEntryByID(ulong id) + { + for (int i = 0; i < Entries.Count; i++) { - for (int i = 0; i < Entries.Count; i++) - { - BundleEntry entry = Entries[i]; - if (entry.ID == id) - return entry; - } - return null; + BundleEntry entry = Entries[i]; + if (entry.ID == id) + return entry; } + return null; + } - // Replaces any entry with the same ID. Retain ID sorting like retail bundles - public void AddEntry(BundleEntry entry) - { - Entries.RemoveAll(e => e.ID == entry.ID); - int index = Entries.FindIndex(e => e.ID > entry.ID); - Entries.Insert(index < 0 ? Entries.Count : index, entry); - for (int i = 0; i < Entries.Count; i++) - Entries[i].Index = i; - } + // Replaces any entry with the same ID. Retain ID sorting like retail bundles + public void AddEntry(BundleEntry entry) + { + Entries.RemoveAll(e => e.ID == entry.ID); + int index = Entries.FindIndex(e => e.ID > entry.ID); + Entries.Insert(index < 0 ? Entries.Count : index, entry); + for (int i = 0; i < Entries.Count; i++) + Entries[i].Index = i; + } - public BundleEntry CreateEntry(ulong id, EntryType type, string name, byte[] primary, int importCount, byte[] secondary = null) - { - BundleEntry template = Entries.FirstOrDefault(e => e.Type == type); + public BundleEntry CreateEntry(ulong id, EntryType type, string name, byte[] primary, int importCount, byte[] secondary = null) + { + BundleEntry template = Entries.FirstOrDefault(e => e.Type == type); - int secondaryBlock = template?.SecondaryBlock ?? (Platform == BundlePlatform.PS3 ? 2 : 1); + int secondaryBlock = template?.SecondaryBlock ?? (Platform == BundlePlatform.PS3 ? 2 : 1); - byte[][] data = new byte[3][]; - data[0] = primary; - data[secondaryBlock] = secondary; + byte[][] data = new byte[3][]; + data[0] = primary; + data[secondaryBlock] = secondary; - BundleEntry entry = new(this) - { - ID = id, - Type = type, - Platform = Platform, - DependencyCount = (short)importCount, - DependenciesListOffset = importCount > 0 ? primary.Length - importCount * Dependency.Size : 0, - DebugInfo = new() { Name = name, TypeName = type.ToString() }, - Dirty = true, - EntryBlocks = new EntryBlock[3] - }; - - for (int i = 0; i < entry.EntryBlocks.Length; i++) - { - EntryBlock block = new() { Compressed = false }; - if (data[i] != null) - { - block.Data = data[i]; - block.UncompressedAlignment = template != null && template.HasSection(i) ? template.EntryBlocks[i].UncompressedAlignment : 16; - } - entry.EntryBlocks[i] = block; - } - - return entry; - } - - public string GetEntryNameByID(ulong id) + BundleEntry entry = new(this) { - for (int i = 0; i < Entries.Count; i++) + ID = id, + Type = type, + Platform = Platform, + DependencyCount = (short)importCount, + DependenciesListOffset = importCount > 0 ? primary.Length - importCount * Dependency.Size : 0, + DebugInfo = new() { Name = name, TypeName = type.ToString() }, + Dirty = true, + EntryBlocks = new EntryBlock[3] + }; + + for (int i = 0; i < entry.EntryBlocks.Length; i++) + { + EntryBlock block = new() { Compressed = false }; + if (data[i] != null) { - BundleEntry entry = Entries[i]; - if (entry.ID == id) - return entry.DetectName(); + block.Data = data[i]; + block.UncompressedAlignment = template != null && template.HasSection(i) ? template.EntryBlocks[i].UncompressedAlignment : 16; } - return null; + entry.EntryBlocks[i] = block; } - public bool ContainsEntry(ulong id) + return entry; + } + + public string GetEntryNameByID(ulong id) + { + for (int i = 0; i < Entries.Count; i++) { - return GetEntryByID(id) != null; + BundleEntry entry = Entries[i]; + if (entry.ID == id) + return entry.DetectName(); } + return null; + } - private static Dictionary GetDebugInfoFromRST(string rst) - { - XmlDocument doc = new XmlDocument(); - doc.LoadXml(rst); + public bool ContainsEntry(ulong id) + { + return GetEntryByID(id) != null; + } - XmlElement root = doc["ResourceStringTable"]; - XmlNodeList resources = root.GetElementsByTagName("Resource"); + private static Dictionary GetDebugInfoFromRST(string rst) + { + XmlDocument doc = new(); + doc.LoadXml(rst); - Dictionary debugInfo = new Dictionary(); + XmlElement root = doc["ResourceStringTable"]; + XmlNodeList resources = root.GetElementsByTagName("Resource"); - foreach (XmlElement ele in resources) - { - if (ele.Name != "Resource") - continue; + Dictionary debugInfo = []; - if (!ulong.TryParse(ele.Attributes["id"].Value, NumberStyles.AllowHexSpecifier, CultureInfo.CurrentCulture, out ulong resourceID)) - continue; + foreach (XmlElement ele in resources) + { + if (ele.Name != "Resource") + continue; - DebugInfo debug; - debug.Name = ele.Attributes["name"].Value; - debug.TypeName = ele.Attributes["type"].Value; + if (!ulong.TryParse(ele.Attributes["id"].Value, NumberStyles.AllowHexSpecifier, CultureInfo.CurrentCulture, out ulong resourceID)) + continue; - debugInfo.Add(resourceID, debug); - } + DebugInfo debug; + debug.Name = ele.Attributes["name"].Value; + debug.TypeName = ele.Attributes["type"].Value; - return debugInfo; + debugInfo.Add(resourceID, debug); } - private void ProcessRST(string rst) - { - XmlDocument doc = new XmlDocument(); - doc.LoadXml(rst); - - XmlElement root = doc["ResourceStringTable"]; - XmlNodeList resources = root.GetElementsByTagName("Resource"); - - foreach (XmlElement ele in resources) - { - if (!ulong.TryParse(ele.Attributes["id"].Value, NumberStyles.AllowHexSpecifier, CultureInfo.CurrentCulture, out ulong resourceID)) - continue; + return debugInfo; + } - foreach (var entry in Entries) - { - if (entry.ID != resourceID) - continue; + private void ProcessRST(string rst) + { + XmlDocument doc = new(); + doc.LoadXml(rst); - entry.DebugInfo.Name = ele.Attributes["name"].Value; - entry.DebugInfo.TypeName = ele.Attributes["type"].Value; - break; - } - } - } + XmlElement root = doc["ResourceStringTable"]; + XmlNodeList resources = root.GetElementsByTagName("Resource"); - private void RebuildRST() + foreach (XmlElement ele in resources) { - XmlDocument doc = new XmlDocument(); - XmlElement root = doc.CreateElement("ResourceStringTable"); - doc.AppendChild(root); - - bool hasNamedResources = false; + if (!ulong.TryParse(ele.Attributes["id"].Value, NumberStyles.AllowHexSpecifier, CultureInfo.CurrentCulture, out ulong resourceID)) + continue; - foreach (BundleEntry entry in Entries) + foreach (var entry in Entries) { - string name = entry.DebugInfo.Name?.Trim(); - if (string.IsNullOrEmpty(name)) + if (entry.ID != resourceID) continue; - XmlElement resource = doc.CreateElement("Resource"); - resource.SetAttribute("id", entry.ID.ToString("X8")); - resource.SetAttribute("name", name); - resource.SetAttribute( - "type", - string.IsNullOrWhiteSpace(entry.DebugInfo.TypeName) - ? entry.Type.ToString() - : entry.DebugInfo.TypeName - ); - - root.AppendChild(resource); - hasNamedResources = true; - } - - if (!hasNamedResources) - { - ResourceStringTable = null; - Flags &= ~Flags.HasResourceStringTable; - return; + entry.DebugInfo.Name = ele.Attributes["name"].Value; + entry.DebugInfo.TypeName = ele.Attributes["type"].Value; + break; } - - ResourceStringTable = doc.OuterXml; - Flags |= Flags.HasResourceStringTable; } + } - public static BundleArchive Read(string path) - { - using (Stream s = File.OpenRead(path)) - { - try - { - BinaryReader2 br = new BinaryReader2(s); - - BundleArchive result = new BundleArchive(); - result.Path = path; - - if (!result.Read(br)) - { - br.Close(); + private void RebuildRST() + { + XmlDocument doc = new(); + XmlElement root = doc.CreateElement("ResourceStringTable"); + doc.AppendChild(root); - return null; - } + bool hasNamedResources = false; - br.Close(); + foreach (BundleEntry entry in Entries) + { + string name = entry.DebugInfo.Name?.Trim(); + if (string.IsNullOrEmpty(name)) + continue; + + XmlElement resource = doc.CreateElement("Resource"); + resource.SetAttribute("id", entry.ID.ToString("X8")); + resource.SetAttribute("name", name); + resource.SetAttribute( + "type", + string.IsNullOrWhiteSpace(entry.DebugInfo.TypeName) + ? entry.Type.ToString() + : entry.DebugInfo.TypeName + ); + + root.AppendChild(resource); + hasNamedResources = true; + } - return result; - } - catch (IOException ex) - { - Debug.WriteLine(ex.Message + "\n" + ex.StackTrace); - return null; - } catch (ReadFailedError ex) - { - Debug.WriteLine(ex.Message + "\n" + ex.StackTrace); - return null; - } - } + if (!hasNamedResources) + { + ResourceStringTable = null; + Flags &= ~Flags.HasResourceStringTable; + return; } - public bool Read(BinaryReader2 br) + ResourceStringTable = doc.OuterXml; + Flags |= Flags.HasResourceStringTable; + } + + public static BundleArchive Read(string path) + { + using Stream s = File.OpenRead(path); + try { - int type; - byte[] bytes = br.ReadBytes(4); - if (bytes.Matches(BND1Magic)) - type = 1; - else if (bytes.Matches(BND2Magic)) - type = 2; - else - return false; + BinaryReader2 br = new(s); - BNDVersion = type; + BundleArchive result = new(); + result.Path = path; - switch (type) + if (!result.Read(br)) { - case 1: - if (!ReadBND1(br)) - return false; - break; - case 2: - if (!ReadBND2(br)) - return false; - break; + br.Close(); + + return null; } br.Close(); - return true; + return result; } - - private bool ReadBND1(BinaryReader2 br) + catch (IOException ex) + { + Debug.WriteLine(ex.Message + "\n" + ex.StackTrace); + return null; + } + catch (ReadFailedError ex) { - br.BigEndian = true; + Debug.WriteLine(ex.Message + "\n" + ex.StackTrace); + return null; + } + } - // Version number? - br.ReadUInt32(); + public bool Read(BinaryReader2 br) + { + int type; + byte[] bytes = br.ReadBytes(4); + if (bytes.Matches(BND1Magic)) + type = 1; + else if (bytes.Matches(BND2Magic)) + type = 2; + else + return false; - uint entryCount = br.ReadUInt32(); + BNDVersion = type; - uint[] dataBlockSizes = new uint[5]; - for (int i = 0; i < dataBlockSizes.Length; i++) - { - dataBlockSizes[i] = br.ReadUInt32(); - br.BaseStream.Position += 4; // Padding - } + switch (type) + { + case 1: + if (!ReadBND1(br)) + return false; + break; + case 2: + if (!ReadBND2(br)) + return false; + break; + } - br.BaseStream.Position += 0x14; // Unknown Data + br.Close(); - uint idListOffset = br.ReadUInt32(); - uint idTableOffset = br.ReadUInt32(); + return true; + } - br.ReadUInt32(); // dependency block - br.ReadUInt32(); // start of data block + private bool ReadBND1(BinaryReader2 br) + { + br.BigEndian = true; - Platform = BundlePlatform.X360; // Xbox only for now - br.ReadUInt32(); // might be platform (2 being X360) + // Version number? + br.ReadUInt32(); - uint compressed = br.ReadUInt32(); - if (compressed != 0) - Flags = Flags.Compressed; // TODO - else - Flags = 0; + uint entryCount = br.ReadUInt32(); - br.ReadUInt32(); // unknown purpose sometimes the same as entryCount + uint[] dataBlockSizes = new uint[5]; + for (int i = 0; i < dataBlockSizes.Length; i++) + { + dataBlockSizes[i] = br.ReadUInt32(); + br.BaseStream.Position += 4; // Padding + } - uint uncompressedInfoOffset = br.ReadUInt32(); + br.BaseStream.Position += 0x14; // Unknown Data - br.ReadUInt32(); // main memory alignment - br.ReadUInt32(); // graphics memory alignment + uint idListOffset = br.ReadUInt32(); + uint idTableOffset = br.ReadUInt32(); - Entries.Clear(); + br.ReadUInt32(); // dependency block + br.ReadUInt32(); // start of data block - br.BaseStream.Position = idListOffset; + Platform = BundlePlatform.X360; // Xbox only for now + br.ReadUInt32(); // might be platform (2 being X360) - List resourceIds = new List(); - for (int i = 0; i < entryCount; i++) - resourceIds.Add(br.ReadUInt64()); + uint compressed = br.ReadUInt32(); + if (compressed != 0) + Flags = Flags.Compressed; // TODO + else + Flags = 0; - br.BaseStream.Position = idTableOffset; + br.ReadUInt32(); // unknown purpose sometimes the same as entryCount - foreach (ulong resourceId in resourceIds) - { - BundleEntry entry = new BundleEntry(this); - entry.EntryBlocks = new EntryBlock[3]; - entry.ID = resourceId; + uint uncompressedInfoOffset = br.ReadUInt32(); - br.ReadUInt32(); // unknown mem stuff + br.ReadUInt32(); // main memory alignment + br.ReadUInt32(); // graphics memory alignment - entry.DependenciesListOffset = br.ReadInt32(); - entry.Type = (EntryType)br.ReadUInt32(); + Entries.Clear(); - //uint[] sizes = new uint[2]; + br.BaseStream.Position = idListOffset; - if (compressed != 0) - { - //sizes[0] = br.ReadUInt32(); - entry.EntryBlocks[0] = new EntryBlock(); - entry.EntryBlocks[0].Compressed = true; - entry.EntryBlocks[0].CompressedSize = br.ReadUInt32(); - br.ReadUInt32(); // Alignment value, should be 1 - br.ReadUInt32(); // other blocks. Maybe used but I'm ignoring it. - br.ReadUInt32(); // Alignment value, should be 1 - //sizes[1] = br.ReadUInt32(); - entry.EntryBlocks[1] = new EntryBlock(); - entry.EntryBlocks[1].Compressed = true; - entry.EntryBlocks[1].CompressedSize = br.ReadUInt32(); - br.ReadUInt32(); // Alignment value, should be 1 - br.ReadUInt32(); // other blocks. Maybe used but I'm ignoring it. - br.ReadUInt32(); // Alignment value, should be 1 - br.ReadUInt32(); // other blocks. Maybe used but I'm ignoring it. - br.ReadUInt32(); // Alignment value, should be 1 - } else - { - //sizes[0] = br.ReadUInt32(); - entry.EntryBlocks[0] = new EntryBlock(); - entry.EntryBlocks[0].Compressed = false; - entry.EntryBlocks[0].UncompressedSize = br.ReadUInt32(); - entry.EntryBlocks[0].UncompressedAlignment = br.ReadUInt32(); - br.ReadUInt32(); // other blocks. Maybe used but I'm ignoring it. - br.ReadUInt32(); // Alignment value - //sizes[1] = br.ReadUInt32(); - entry.EntryBlocks[1] = new EntryBlock(); - entry.EntryBlocks[1].Compressed = false; - entry.EntryBlocks[1].UncompressedSize = br.ReadUInt32(); - entry.EntryBlocks[1].UncompressedAlignment = br.ReadUInt32(); - br.ReadUInt32(); // other blocks. Maybe used but I'm ignoring it. - br.ReadUInt32(); // Alignment value - br.ReadUInt32(); // other blocks. Maybe used but I'm ignoring it. - br.ReadUInt32(); // Alignment value - } + List resourceIds = []; + for (int i = 0; i < entryCount; i++) + resourceIds.Add(br.ReadUInt64()); - uint dataBlockStartOffset = 0; - for (int j = 0; j < dataBlockSizes.Length; j++) - { - if (j > 0) - dataBlockStartOffset += dataBlockSizes[j - 1]; + br.BaseStream.Position = idTableOffset; - uint readOffset = br.ReadUInt32() + dataBlockStartOffset; - br.ReadUInt32(); // 1 + foreach (ulong resourceId in resourceIds) + { + BundleEntry entry = new(this); + entry.EntryBlocks = new EntryBlock[3]; + entry.ID = resourceId; - if (j != 0 && j != 2) - continue; // Not supporting blocks 2, 4 and 5 right now. + br.ReadUInt32(); // unknown mem stuff - int mappedBlock = j; - if (j == 2) - mappedBlock = 1; + entry.DependenciesListOffset = br.ReadInt32(); + entry.Type = (EntryType)br.ReadUInt32(); - if (entry.EntryBlocks[mappedBlock] == null) - entry.EntryBlocks[mappedBlock] = new EntryBlock(); - EntryBlock entryBlock = entry.EntryBlocks[mappedBlock]; + //uint[] sizes = new uint[2]; - //uint readSize = sizes[mappedBlock]; - uint readSize = compressed != 0 ? entryBlock.CompressedSize : entryBlock.UncompressedSize; - if (readSize == 0) - { - entryBlock.RawData = null; - continue; - } + if (compressed != 0) + { + //sizes[0] = br.ReadUInt32(); + entry.EntryBlocks[0] = new EntryBlock(); + entry.EntryBlocks[0].Compressed = true; + entry.EntryBlocks[0].CompressedSize = br.ReadUInt32(); + br.ReadUInt32(); // Alignment value, should be 1 + br.ReadUInt32(); // other blocks. Maybe used but I'm ignoring it. + br.ReadUInt32(); // Alignment value, should be 1 + //sizes[1] = br.ReadUInt32(); + entry.EntryBlocks[1] = new EntryBlock(); + entry.EntryBlocks[1].Compressed = true; + entry.EntryBlocks[1].CompressedSize = br.ReadUInt32(); + br.ReadUInt32(); // Alignment value, should be 1 + br.ReadUInt32(); // other blocks. Maybe used but I'm ignoring it. + br.ReadUInt32(); // Alignment value, should be 1 + br.ReadUInt32(); // other blocks. Maybe used but I'm ignoring it. + br.ReadUInt32(); // Alignment value, should be 1 + } else + { + //sizes[0] = br.ReadUInt32(); + entry.EntryBlocks[0] = new EntryBlock(); + entry.EntryBlocks[0].Compressed = false; + entry.EntryBlocks[0].UncompressedSize = br.ReadUInt32(); + entry.EntryBlocks[0].UncompressedAlignment = br.ReadUInt32(); + br.ReadUInt32(); // other blocks. Maybe used but I'm ignoring it. + br.ReadUInt32(); // Alignment value + //sizes[1] = br.ReadUInt32(); + entry.EntryBlocks[1] = new EntryBlock(); + entry.EntryBlocks[1].Compressed = false; + entry.EntryBlocks[1].UncompressedSize = br.ReadUInt32(); + entry.EntryBlocks[1].UncompressedAlignment = br.ReadUInt32(); + br.ReadUInt32(); // other blocks. Maybe used but I'm ignoring it. + br.ReadUInt32(); // Alignment value + br.ReadUInt32(); // other blocks. Maybe used but I'm ignoring it. + br.ReadUInt32(); // Alignment value + } - long pos = br.BaseStream.Position; - br.BaseStream.Position = readOffset; + uint dataBlockStartOffset = 0; + for (int j = 0; j < dataBlockSizes.Length; j++) + { + if (j > 0) + dataBlockStartOffset += dataBlockSizes[j - 1]; - entryBlock.RawData = br.ReadBytes((int)readSize); + uint readOffset = br.ReadUInt32() + dataBlockStartOffset; + br.ReadUInt32(); // 1 - br.BaseStream.Position = pos; - } + if (j != 0 && j != 2) + continue; // Not supporting blocks 2, 4 and 5 right now. - br.BaseStream.Position += 0x14; // unknown mem stuff + int mappedBlock = j; + if (j == 2) + mappedBlock = 1; - Entries.Add(entry); - } + if (entry.EntryBlocks[mappedBlock] == null) + entry.EntryBlocks[mappedBlock] = new EntryBlock(); + EntryBlock entryBlock = entry.EntryBlocks[mappedBlock]; - if (compressed != 0) - { - br.BaseStream.Position = uncompressedInfoOffset; - for (int i = 0; i < Entries.Count; i++) + //uint readSize = sizes[mappedBlock]; + uint readSize = compressed != 0 ? entryBlock.CompressedSize : entryBlock.UncompressedSize; + if (readSize == 0) { - BundleEntry entry = Entries[i]; - - //uint[] sizes = new uint[2]; - - //sizes[0] = br.ReadUInt32(); - entry.EntryBlocks[0].UncompressedSize = br.ReadUInt32(); - entry.EntryBlocks[0].UncompressedAlignment = br.ReadUInt32(); - br.ReadUInt32(); // other blocks. Maybe used but I'm ignoring it. - br.ReadUInt32(); // Alignment value - //sizes[1] = br.ReadUInt32(); - entry.EntryBlocks[1].UncompressedSize = br.ReadUInt32(); - entry.EntryBlocks[1].UncompressedAlignment = br.ReadUInt32(); - br.ReadUInt32(); // other blocks. Maybe used but I'm ignoring it. - br.ReadUInt32(); // Alignment value - br.ReadUInt32(); // other blocks. Maybe used but I'm ignoring it. - br.ReadUInt32(); // Alignment value - - //for (int j = 0; j < 2; j++) - //{ - // EntryBlock entryBlock = entry.EntryBlocks[j]; - // if (sizes[j] > 0) - // entryBlock.Data = entryBlock.Data.Decompress((int)sizes[j]); - //} + entryBlock.RawData = null; + continue; } + + long pos = br.BaseStream.Position; + br.BaseStream.Position = readOffset; + + entryBlock.RawData = br.ReadBytes((int)readSize); + + br.BaseStream.Position = pos; } + br.BaseStream.Position += 0x14; // unknown mem stuff + + Entries.Add(entry); + } + + if (compressed != 0) + { + br.BaseStream.Position = uncompressedInfoOffset; for (int i = 0; i < Entries.Count; i++) { BundleEntry entry = Entries[i]; - uint depOffset = (uint)entry.DependenciesListOffset; - if (depOffset == 0) - continue; - - br.BaseStream.Position = depOffset; - entry.DependencyCount = (short)br.ReadUInt32(); - if (br.ReadUInt32() != 0) - return false; + //uint[] sizes = new uint[2]; - for (int j = 0; j < entry.DependencyCount; j++) - entry.Dependencies.Add(Dependency.Read(br)); + //sizes[0] = br.ReadUInt32(); + entry.EntryBlocks[0].UncompressedSize = br.ReadUInt32(); + entry.EntryBlocks[0].UncompressedAlignment = br.ReadUInt32(); + br.ReadUInt32(); // other blocks. Maybe used but I'm ignoring it. + br.ReadUInt32(); // Alignment value + //sizes[1] = br.ReadUInt32(); + entry.EntryBlocks[1].UncompressedSize = br.ReadUInt32(); + entry.EntryBlocks[1].UncompressedAlignment = br.ReadUInt32(); + br.ReadUInt32(); // other blocks. Maybe used but I'm ignoring it. + br.ReadUInt32(); // Alignment value + br.ReadUInt32(); // other blocks. Maybe used but I'm ignoring it. + br.ReadUInt32(); // Alignment value + + //for (int j = 0; j < 2; j++) + //{ + // EntryBlock entryBlock = entry.EntryBlocks[j]; + // if (sizes[j] > 0) + // entryBlock.Data = entryBlock.Data.Decompress((int)sizes[j]); + //} } + } - BundleEntry rst = GetEntryByID(0xC039284A); - if (rst == null) - return true; + for (int i = 0; i < Entries.Count; i++) + { + BundleEntry entry = Entries[i]; + uint depOffset = (uint)entry.DependenciesListOffset; + if (depOffset == 0) + continue; - BinaryReader2 br2 = new BinaryReader2(rst.MakeStream()); - br2.BigEndian = false; + br.BaseStream.Position = depOffset; - // TODO: Store only the debug info and not the full string - ResourceStringTable = br2.ReadLenString(br2.ReadInt32()); + entry.DependencyCount = (short)br.ReadUInt32(); + if (br.ReadUInt32() != 0) + return false; - br2.Close(); + for (int j = 0; j < entry.DependencyCount; j++) + entry.Dependencies.Add(Dependency.Read(br)); + } - // Cover Criterion's broken XML writer. - if (ResourceStringTable.StartsWith("")) - ResourceStringTable = ResourceStringTable.Remove(1, 1); - string badLine = "\n\t"; - int index = ResourceStringTable.IndexOf(badLine); - if (index > -1) - ResourceStringTable = ResourceStringTable.Remove(index, badLine.Length); + BundleEntry rst = GetEntryByID(0xC039284A); + if (rst == null) + return true; - ProcessRST(ResourceStringTable); + BinaryReader2 br2 = new(rst.MakeStream()); + br2.BigEndian = false; - Entries.Remove(rst); + // TODO: Store only the debug info and not the full string + ResourceStringTable = br2.ReadLenString(br2.ReadInt32()); - return true; - } + br2.Close(); - private bool ReadBND2(BinaryReader2 br) - { - br.BaseStream.Position += 4; + // Cover Criterion's broken XML writer. + if (ResourceStringTable.StartsWith("")) + ResourceStringTable = ResourceStringTable.Remove(1, 1); + string badLine = "\n\t"; + int index = ResourceStringTable.IndexOf(badLine); + if (index > -1) + ResourceStringTable = ResourceStringTable.Remove(index, badLine.Length); - Platform = ReadPlatform(br); + ProcessRST(ResourceStringTable); - br.BaseStream.Position -= 8; - Version = br.ReadInt32(); - if (Version != 2) - { - throw new ReadFailedError("Unsupported Bundle Version: " + Version); - } - br.BaseStream.Position += 4; + Entries.Remove(rst); - RSTOffset = br.ReadInt32(); - EntryCount = br.ReadInt32(); - IDBlockOffset = br.ReadInt32(); - uint[] fileBlockOffsets = new uint[3]; - fileBlockOffsets[0] = br.ReadUInt32(); - fileBlockOffsets[1] = br.ReadUInt32(); - fileBlockOffsets[2] = br.ReadUInt32(); - Flags = (Flags)br.ReadInt32(); + return true; + } - // 8 Bytes Padding + private bool ReadBND2(BinaryReader2 br) + { + br.BaseStream.Position += 4; - br.BaseStream.Position = IDBlockOffset; + Platform = ReadPlatform(br); - for (int i = 0; i < EntryCount; i++) - { - BundleEntry entry = new BundleEntry(this); + br.BaseStream.Position -= 8; + Version = br.ReadInt32(); + if (Version != 2) + { + throw new ReadFailedError("Unsupported Bundle Version: " + Version); + } + br.BaseStream.Position += 4; - entry.Index = i; + RSTOffset = br.ReadInt32(); + EntryCount = br.ReadInt32(); + IDBlockOffset = br.ReadInt32(); + uint[] fileBlockOffsets = [br.ReadUInt32(), br.ReadUInt32(), br.ReadUInt32()]; + Flags = (Flags)br.ReadInt32(); - entry.Platform = Platform; + // 8 Bytes Padding - entry.ID = br.ReadUInt64(); + br.BaseStream.Position = IDBlockOffset; - br.ReadUInt64(); // Import Resource ID, which we now recompute on write + for (int i = 0; i < EntryCount; i++) + { + BundleEntry entry = new(this); - entry.EntryBlocks = new EntryBlock[3]; - for (int j = 0; j < entry.EntryBlocks.Length; j++) - { - entry.EntryBlocks[j] = new EntryBlock(); - entry.EntryBlocks[j].Compressed = Flags.HasFlag(Flags.Compressed); - } + entry.Index = i; - //uint[] blockUncompressedSizes = new uint[3]; + entry.Platform = Platform; - for (int j = 0; j < entry.EntryBlocks.Length; j++) - { - uint uncompressedSize = br.ReadUInt32(); - //blockUncompressedSizes[j] = uncompressedSize & ~(0xFU << 28); - entry.EntryBlocks[j].UncompressedSize = uncompressedSize & ~(0xFU << 28); - entry.EntryBlocks[j].UncompressedAlignment = (uint)(1 << ((int)uncompressedSize >> 28)); - } + entry.ID = br.ReadUInt64(); - //uint[] blockCompressedSizes = new uint[3]; + br.ReadUInt64(); // Import Resource ID, which we now recompute on write - for (int j = 0; j < entry.EntryBlocks.Length; j++) - { - //blockCompressedSizes[j] = br.ReadUInt32(); - entry.EntryBlocks[j].CompressedSize = br.ReadUInt32(); - } - - for (int j = 0; j < entry.EntryBlocks.Length; j++) - { - uint blockOffset = br.ReadUInt32(); - long lastAddr = br.BaseStream.Position; - br.BaseStream.Position = blockOffset + fileBlockOffsets[j]; - - EntryBlock block = entry.EntryBlocks[j]; - - bool compressed = Flags.HasFlag(Flags.Compressed); - - //uint readSize = compressed ? blockCompressedSizes[j] : blockUncompressedSizes[j]; - uint readSize = compressed ? entry.EntryBlocks[j].CompressedSize : entry.EntryBlocks[j].UncompressedSize; - if (readSize == 0) - { - block.RawData = null; - br.BaseStream.Position = lastAddr; - continue; - } - - block.RawData = br.ReadBytes((int)readSize); - //if (compressed) - // block.Data = block.Data.Decompress((int)blockUncompressedSizes[j]); - br.BaseStream.Position = lastAddr; - } + entry.EntryBlocks = new EntryBlock[3]; + for (int j = 0; j < entry.EntryBlocks.Length; j++) + { + entry.EntryBlocks[j] = new EntryBlock(); + entry.EntryBlocks[j].Compressed = Flags.HasFlag(Flags.Compressed); + } - entry.DependenciesListOffset = br.ReadInt32(); - entry.Type = (EntryType)br.ReadInt32(); - entry.DependencyCount = br.ReadInt16(); + //uint[] blockUncompressedSizes = new uint[3]; - br.BaseStream.Position += 2; // Padding + for (int j = 0; j < entry.EntryBlocks.Length; j++) + { + uint uncompressedSize = br.ReadUInt32(); + //blockUncompressedSizes[j] = uncompressedSize & ~(0xFU << 28); + entry.EntryBlocks[j].UncompressedSize = uncompressedSize & ~(0xFU << 28); + entry.EntryBlocks[j].UncompressedAlignment = (uint)(1 << ((int)uncompressedSize >> 28)); + } - entry.Dirty = false; + //uint[] blockCompressedSizes = new uint[3]; - Entries.Add(entry); + for (int j = 0; j < entry.EntryBlocks.Length; j++) + { + //blockCompressedSizes[j] = br.ReadUInt32(); + entry.EntryBlocks[j].CompressedSize = br.ReadUInt32(); } - if (Flags.HasFlag(Flags.HasResourceStringTable)) + for (int j = 0; j < entry.EntryBlocks.Length; j++) { - br.BaseStream.Position = RSTOffset; + uint blockOffset = br.ReadUInt32(); + long lastAddr = br.BaseStream.Position; + br.BaseStream.Position = blockOffset + fileBlockOffsets[j]; - // TODO: Store only the debug info and not the full string - ResourceStringTable = br.ReadCStr(); + EntryBlock block = entry.EntryBlocks[j]; - ProcessRST(ResourceStringTable); + bool compressed = Flags.HasFlag(Flags.Compressed); + + //uint readSize = compressed ? blockCompressedSizes[j] : blockUncompressedSizes[j]; + uint readSize = compressed ? entry.EntryBlocks[j].CompressedSize : entry.EntryBlocks[j].UncompressedSize; + if (readSize == 0) + { + block.RawData = null; + br.BaseStream.Position = lastAddr; + continue; + } + + block.RawData = br.ReadBytes((int)readSize); + //if (compressed) + // block.Data = block.Data.Decompress((int)blockUncompressedSizes[j]); + br.BaseStream.Position = lastAddr; } - return true; + entry.DependenciesListOffset = br.ReadInt32(); + entry.Type = (EntryType)br.ReadInt32(); + entry.DependencyCount = br.ReadInt16(); + + br.BaseStream.Position += 2; // Padding + + entry.Dirty = false; + + Entries.Add(entry); } - public void Write(string path) + if (Flags.HasFlag(Flags.HasResourceStringTable)) { - Stream s = File.Open(path, FileMode.Create); - BinaryWriter2 bw = new BinaryWriter2(s); - bw.BigEndian = Console; + br.BaseStream.Position = RSTOffset; - Write(bw); + // TODO: Store only the debug info and not the full string + ResourceStringTable = br.ReadCStr(); - bw.Flush(); - bw.Close(); + ProcessRST(ResourceStringTable); } - public void Write(BinaryWriter2 bw) - { - RebuildRST(); + return true; + } - bw.Write(BND2Magic); - bw.Write(Version); - bw.Write((int)Platform); + public void Write(string path) + { + Stream s = File.Open(path, FileMode.Create); + BinaryWriter2 bw = new(s); + bw.BigEndian = Console; - long rstOffset = bw.BaseStream.Position; - bw.Write(0); + Write(bw); - bw.Write(Entries.Count); + bw.Flush(); + bw.Close(); + } - long idBlockOffsetPos = bw.BaseStream.Position; - bw.Write(0); + public void Write(BinaryWriter2 bw) + { + RebuildRST(); - long[] fileBlockOffsetsPos = new long[3]; + bw.Write(BND2Magic); + bw.Write(Version); + bw.Write((int)Platform); - for (int i = 0; i < fileBlockOffsetsPos.Length; i++) - { - fileBlockOffsetsPos[i] = bw.BaseStream.Position; - bw.BaseStream.Position += 4; - } + long rstOffset = bw.BaseStream.Position; + bw.Write(0); - bw.Write((int)Flags); + bw.Write(Entries.Count); - bw.Align(16); + long idBlockOffsetPos = bw.BaseStream.Position; + bw.Write(0); - long currentOffset = bw.BaseStream.Position; - bw.BaseStream.Position = rstOffset; - bw.Write((uint)currentOffset); - bw.BaseStream.Position = currentOffset; + long[] fileBlockOffsetsPos = new long[3]; - if (Flags.HasFlag(Flags.HasResourceStringTable)) - { - // TODO: Rebuild RST from DebugInfo - bw.WriteCStr(ResourceStringTable); + for (int i = 0; i < fileBlockOffsetsPos.Length; i++) + { + fileBlockOffsetsPos[i] = bw.BaseStream.Position; + bw.BaseStream.Position += 4; + } - bw.Align(16); - } + bw.Write((int)Flags); - // ID Block - currentOffset = bw.BaseStream.Position; - bw.Seek((int)idBlockOffsetPos, SeekOrigin.Begin); - bw.Write((int)currentOffset); - bw.Seek((int)currentOffset, SeekOrigin.Begin); + bw.Align(16); - List entryDataPointerPos = new List(); + long currentOffset = bw.BaseStream.Position; + bw.BaseStream.Position = rstOffset; + bw.Write((uint)currentOffset); + bw.BaseStream.Position = currentOffset; - List compressedBlocks = new List(); + if (Flags.HasFlag(Flags.HasResourceStringTable)) + { + // TODO: Rebuild RST from DebugInfo + bw.WriteCStr(ResourceStringTable); - for (int i = 0; i < this.Entries.Count; i++) - { - BundleEntry entry = this.Entries[i]; + bw.Align(16); + } - compressedBlocks.Add(new byte[3][]); + // ID Block + currentOffset = bw.BaseStream.Position; + bw.Seek((int)idBlockOffsetPos, SeekOrigin.Begin); + bw.Write((int)currentOffset); + bw.Seek((int)currentOffset, SeekOrigin.Begin); - bw.Write(entry.ID); - bw.Write(entry.ImportID); + List entryDataPointerPos = []; - for (int j = 0; j < entry.EntryBlocks.Length; j++) - { - EntryBlock entryBlock = entry.EntryBlocks[j]; - uint uncompressedSize = 0; - if (entryBlock.Data != null) - uncompressedSize = (uint)entryBlock.Data.Length; - //self.Write((entryBlock.UncompressedAlignment << 28) | uncompressedSize); - bw.Write((uint)(uncompressedSize | (BitScan.BitScanReverse(entryBlock.UncompressedAlignment) << 28))); - } + List compressedBlocks = []; - for (int j = 0; j < entry.EntryBlocks.Length; j++) - { - EntryBlock entryBlock = entry.EntryBlocks[j]; - if (entryBlock.Data == null) - bw.Write((uint)0); - else - { - compressedBlocks[i][j] = Flags.HasFlag(Flags.Compressed) ? entryBlock.Data.Compress() : entryBlock.Data; - bw.Write(compressedBlocks[i][j].Length); - } - } + for (int i = 0; i < this.Entries.Count; i++) + { + BundleEntry entry = this.Entries[i]; - entryDataPointerPos.Add(new long[3]); - for (int j = 0; j < entryDataPointerPos[i].Length; j++) - { - entryDataPointerPos[i][j] = bw.BaseStream.Position; - bw.BaseStream.Position += 4; - } + compressedBlocks.Add(new byte[3][]); - bw.Write(entry.DependenciesListOffset); - bw.Write((int)entry.Type); - bw.Write(entry.DependencyCount); + bw.Write(entry.ID); + bw.Write(entry.ImportID); - bw.BaseStream.Position += 2; // Padding + for (int j = 0; j < entry.EntryBlocks.Length; j++) + { + EntryBlock entryBlock = entry.EntryBlocks[j]; + uint uncompressedSize = 0; + if (entryBlock.Data != null) + uncompressedSize = (uint)entryBlock.Data.Length; + //self.Write((entryBlock.UncompressedAlignment << 28) | uncompressedSize); + bw.Write((uint)(uncompressedSize | (BitScan.BitScanReverse(entryBlock.UncompressedAlignment) << 28))); } - // Data Block - for (int i = 0; i < 3; i++) + for (int j = 0; j < entry.EntryBlocks.Length; j++) { - long blockStart = bw.BaseStream.Position; - bw.BaseStream.Position = fileBlockOffsetsPos[i]; - bw.Write((uint)blockStart); - bw.BaseStream.Position = blockStart; - - for (int j = 0; j < Entries.Count; j++) + EntryBlock entryBlock = entry.EntryBlocks[j]; + if (entryBlock.Data == null) + bw.Write((uint)0); + else { - byte[] diskData = compressedBlocks[j][i]; - - if (diskData != null && diskData.Length > 0) - { - long pos = bw.BaseStream.Position; - bw.BaseStream.Position = entryDataPointerPos[j][i]; - bw.Write((uint)(pos - blockStart)); - bw.BaseStream.Position = pos; - - bw.Write(diskData); - - bw.Align((i != 0 && j != Entries.Count - 1) ? (byte)0x80 : (byte)16); - } + compressedBlocks[i][j] = Flags.HasFlag(Flags.Compressed) ? entryBlock.Data.Compress() : entryBlock.Data; + bw.Write(compressedBlocks[i][j].Length); } + } - if (i != 2) - bw.Align(0x80); + entryDataPointerPos.Add(new long[3]); + for (int j = 0; j < entryDataPointerPos[i].Length; j++) + { + entryDataPointerPos[i][j] = bw.BaseStream.Position; + bw.BaseStream.Position += 4; } - } - private static BundlePlatform ReadPlatform(BinaryReader2 br) - { - int platform = br.ReadInt32(); - br.BigEndian = platform > 0xFF; - return (BundlePlatform)(br.BigEndian ? BinaryPrimitives.ReverseEndianness(platform) : platform); - } + bw.Write(entry.DependenciesListOffset); + bw.Write((int)entry.Type); + bw.Write(entry.DependencyCount); - public static bool VerifyMagic(BinaryReader2 br, byte[] magic) - { - byte[] readMagic = br.ReadBytes(magic.Length); - if (readMagic.Matches(magic)) - return true; - return false; + bw.BaseStream.Position += 2; // Padding } - public static bool IsBundle(string path) + // Data Block + for (int i = 0; i < 3; i++) { - bool result; + long blockStart = bw.BaseStream.Position; + bw.BaseStream.Position = fileBlockOffsetsPos[i]; + bw.Write((uint)blockStart); + bw.BaseStream.Position = blockStart; - try + for (int j = 0; j < Entries.Count; j++) { - Stream s = File.Open(path, FileMode.Open, FileAccess.Read); - BinaryReader2 br = new BinaryReader2(s); + byte[] diskData = compressedBlocks[j][i]; + + if (diskData != null && diskData.Length > 0) + { + long pos = bw.BaseStream.Position; + bw.BaseStream.Position = entryDataPointerPos[j][i]; + bw.Write((uint)(pos - blockStart)); + bw.BaseStream.Position = pos; - result = VerifyMagic(br, BND2Magic); + bw.Write(diskData); - br.Close(); - s.Close(); - } - catch (Exception ex) - { - Debug.WriteLine(ex.Message + "\n\n" + ex.StackTrace); - result = false; + bw.Align((i != 0 && j != Entries.Count - 1) ? (byte)0x80 : (byte)16); + } } - return result; + if (i != 2) + bw.Align(0x80); } + } - public static List GetEntryIDs(string path, bool console = false) - { - List result = new List(); + private static BundlePlatform ReadPlatform(BinaryReader2 br) + { + int platform = br.ReadInt32(); + br.BigEndian = platform > 0xFF; + return (BundlePlatform)(br.BigEndian ? BinaryPrimitives.ReverseEndianness(platform) : platform); + } - Stream s = File.Open(path, FileMode.Open, FileAccess.Read); - BinaryReader2 br = new BinaryReader2(s); + public static bool VerifyMagic(BinaryReader2 br, byte[] magic) + { + byte[] readMagic = br.ReadBytes(magic.Length); + if (readMagic.Matches(magic)) + return true; + return false; + } - if (!VerifyMagic(br, BND2Magic)) - { - br.Close(); - s.Close(); - return null; - } + public static bool IsBundle(string path) + { + bool result; - br.BaseStream.Position += 4; + try + { + Stream s = File.Open(path, FileMode.Open, FileAccess.Read); + BinaryReader2 br = new(s); - ReadPlatform(br); + result = VerifyMagic(br, BND2Magic); - br.BaseStream.Position = 0x10; - int fileCount = br.ReadInt32(); - int metaStart = br.ReadInt32(); + br.Close(); + s.Close(); + } + catch (Exception ex) + { + Debug.WriteLine(ex.Message + "\n\n" + ex.StackTrace); + result = false; + } - br.BaseStream.Position = metaStart; + return result; + } - for (int i = 0; i < fileCount; i++) - { - uint id = br.ReadUInt32(); - br.BaseStream.Position += 0x3C; + public static List GetEntryIDs(string path, bool console = false) + { + List result = []; - result.Add(id); - } + Stream s = File.Open(path, FileMode.Open, FileAccess.Read); + BinaryReader2 br = new(s); + if (!VerifyMagic(br, BND2Magic)) + { br.Close(); s.Close(); - - return result; + return null; } - public static List GetEntryInfos(string path, bool console = false) - { - List result = new List(); + br.BaseStream.Position += 4; - Stream s = File.Open(path, FileMode.Open, FileAccess.Read); - BinaryReader2 br = new BinaryReader2(s); + ReadPlatform(br); - if (!VerifyMagic(br, BND2Magic)) - { - br.Close(); - s.Close(); - return null; - } + br.BaseStream.Position = 0x10; + int fileCount = br.ReadInt32(); + int metaStart = br.ReadInt32(); - br.BaseStream.Position += 4; + br.BaseStream.Position = metaStart; - ReadPlatform(br); - - br.BaseStream.Position = 0xC; - uint rstOffset = br.ReadUInt32(); - int fileCount = br.ReadInt32(); - int metaStart = br.ReadInt32(); + for (int i = 0; i < fileCount; i++) + { + uint id = br.ReadUInt32(); + br.BaseStream.Position += 0x3C; - br.BaseStream.Position += 0xC; - Flags flags = (Flags)br.ReadInt32(); + result.Add(id); + } - Dictionary debugInfo = null; + br.Close(); + s.Close(); - if (flags.HasFlag(Flags.HasResourceStringTable)) - { - br.BaseStream.Position = rstOffset; + return result; + } + + public static List GetEntryInfos(string path, bool console = false) + { + List result = []; - // TODO: Store only the debug info and not the full string - string rst = br.ReadCStr(); + Stream s = File.Open(path, FileMode.Open, FileAccess.Read); + BinaryReader2 br = new(s); - debugInfo = GetDebugInfoFromRST(rst); - } + if (!VerifyMagic(br, BND2Magic)) + { + br.Close(); + s.Close(); + return null; + } - br.BaseStream.Position = metaStart; + br.BaseStream.Position += 4; - for (int i = 0; i < fileCount; i++) - { - uint id = br.ReadUInt32(); - br.BaseStream.Position += 0x34; - EntryType type = (EntryType)br.ReadUInt32(); - br.BaseStream.Position += 0x4; + ReadPlatform(br); + + br.BaseStream.Position = 0xC; + uint rstOffset = br.ReadUInt32(); + int fileCount = br.ReadInt32(); + int metaStart = br.ReadInt32(); - DebugInfo debug = default; - - if (debugInfo != null && debugInfo.ContainsKey(id)) - debug = debugInfo[id]; + br.BaseStream.Position += 0xC; + Flags flags = (Flags)br.ReadInt32(); - result.Add(new EntryInfo(id, type, path, debug)); - } + Dictionary debugInfo = null; - br.Close(); - s.Close(); + if (flags.HasFlag(Flags.HasResourceStringTable)) + { + br.BaseStream.Position = rstOffset; - return result; + // TODO: Store only the debug info and not the full string + string rst = br.ReadCStr(); + + debugInfo = GetDebugInfoFromRST(rst); } - public static EntryType GetEntryType(string path, uint id, bool console = false) - { - DebugTimer timer = DebugTimer.Start("GetEntryType"); - EntryType result = EntryType.Invalid; + br.BaseStream.Position = metaStart; - Stream s = File.Open(path, FileMode.Open, FileAccess.Read); - BinaryReader2 br = new BinaryReader2(s); + for (int i = 0; i < fileCount; i++) + { + uint id = br.ReadUInt32(); + br.BaseStream.Position += 0x34; + EntryType type = (EntryType)br.ReadUInt32(); + br.BaseStream.Position += 0x4; - if (!VerifyMagic(br, BND2Magic)) - { - timer.StopLog(); - br.Close(); - s.Close(); - return EntryType.Invalid; - } + DebugInfo debug = default; - br.BaseStream.Position += 4; + if (debugInfo != null && debugInfo.ContainsKey(id)) + debug = debugInfo[id]; - ReadPlatform(br); - - br.BaseStream.Position = 0x10; - int fileCount = br.ReadInt32(); - int metaStart = br.ReadInt32(); + result.Add(new EntryInfo(id, type, path, debug)); + } - br.BaseStream.Position = metaStart; + br.Close(); + s.Close(); - for (int i = 0; i < fileCount; i++) - { - uint id2 = br.ReadUInt32(); - br.BaseStream.Position += 0x34; - EntryType type = (EntryType) br.ReadUInt32(); - br.BaseStream.Position += 0x4; + return result; + } - if (id2 == id) - { - result = type; - break; - } - } + public static EntryType GetEntryType(string path, uint id, bool console = false) + { + DebugTimer timer = DebugTimer.Start("GetEntryType"); + EntryType result = EntryType.Invalid; + + Stream s = File.Open(path, FileMode.Open, FileAccess.Read); + BinaryReader2 br = new(s); + if (!VerifyMagic(br, BND2Magic)) + { + timer.StopLog(); br.Close(); s.Close(); + return EntryType.Invalid; + } + + br.BaseStream.Position += 4; - timer.StopLog(); + ReadPlatform(br); + + br.BaseStream.Position = 0x10; + int fileCount = br.ReadInt32(); + int metaStart = br.ReadInt32(); - return result; + br.BaseStream.Position = metaStart; + + for (int i = 0; i < fileCount; i++) + { + uint id2 = br.ReadUInt32(); + br.BaseStream.Position += 0x34; + EntryType type = (EntryType) br.ReadUInt32(); + br.BaseStream.Position += 0x4; + + if (id2 == id) + { + result = type; + break; + } } + + br.Close(); + s.Close(); + + timer.StopLog(); + + return result; } } diff --git a/BundleFormat/BundleCache.cs b/BundleFormat/BundleCache.cs index ffbe8f3..534be7d 100644 --- a/BundleFormat/BundleCache.cs +++ b/BundleFormat/BundleCache.cs @@ -1,48 +1,47 @@ using System.Collections.Generic; -namespace BundleFormat +namespace BundleFormat; + +public static class BundleCache { - public static class BundleCache + public static string CurrentPath; + public static List Paths = []; + public static Dictionary Files = []; + public static Dictionary EntryInfos = []; + + public static string GetFileByEntryID(ulong entryID) + { + if (!Files.ContainsKey(entryID)) + return null; + return Paths[Files[entryID]]; + } + + public static EntryInfo GetInfoByEntryID(ulong entryID) + { + if (!EntryInfos.ContainsKey(entryID)) + return null; + return EntryInfos[entryID]; + } + + public static DebugInfo GetEntryDebugInfoByID(ulong entryID) { - public static string CurrentPath; - public static List Paths = new List(); - public static Dictionary Files = new Dictionary(); - public static Dictionary EntryInfos = new Dictionary(); - - public static string GetFileByEntryID(ulong entryID) - { - if (!Files.ContainsKey(entryID)) - return null; - return Paths[Files[entryID]]; - } - - public static EntryInfo GetInfoByEntryID(ulong entryID) - { - if (!EntryInfos.ContainsKey(entryID)) - return null; - return EntryInfos[entryID]; - } - - public static DebugInfo GetEntryDebugInfoByID(ulong entryID) - { - if (!EntryInfos.ContainsKey(entryID)) - return default; - return EntryInfos[entryID].DebugInfo; - } - - public static string GetEntryNameByID(ulong entryID) - { - return GetEntryDebugInfoByID(entryID).Name; - } - - public static string GetRelativePath(string path) - { - string file = path.Replace('\\', '/').Replace(CurrentPath.Replace('\\', '/'), ""); - - if (file.StartsWith("/")) - file = file.Substring(1); - - return file; - } + if (!EntryInfos.ContainsKey(entryID)) + return default; + return EntryInfos[entryID].DebugInfo; + } + + public static string GetEntryNameByID(ulong entryID) + { + return GetEntryDebugInfoByID(entryID).Name; + } + + public static string GetRelativePath(string path) + { + string file = path.Replace('\\', '/').Replace(CurrentPath.Replace('\\', '/'), ""); + + if (file.StartsWith("/")) + file = file[1..]; + + return file; } } diff --git a/BundleFormat/BundleDependency.cs b/BundleFormat/BundleDependency.cs index 52612ed..eacf3c9 100644 --- a/BundleFormat/BundleDependency.cs +++ b/BundleFormat/BundleDependency.cs @@ -1,44 +1,43 @@ -namespace BundleFormat +namespace BundleFormat; + +public struct BundleDependency { - public struct BundleDependency - { - public ulong EntryID; - public int Unknown1; - public int EntryPointerOffset; + public ulong EntryID; + public int Unknown1; + public int EntryPointerOffset; - public int EntryIndex; - public BundleEntry Entry; + public int EntryIndex; + public BundleEntry Entry; - public override string ToString() - { - string value = ""; + public override string ToString() + { + string value = ""; - bool external = Entry == null; + bool external = Entry == null; - string extra = ""; - if (Entry == null) + string extra = ""; + if (Entry == null) + { + string file = BundleCache.GetFileByEntryID(EntryID); + if (!string.IsNullOrEmpty(file)) { - string file = BundleCache.GetFileByEntryID(EntryID); - if (!string.IsNullOrEmpty(file)) - { - extra = ", Path: " + BundleCache.GetRelativePath(file); - BundleArchive archive = BundleArchive.Read(file); - Entry = archive.GetEntryByID(EntryID); - } + extra = ", Path: " + BundleCache.GetRelativePath(file); + BundleArchive archive = BundleArchive.Read(file); + Entry = archive.GetEntryByID(EntryID); } + } - if (Entry != null && Entry.Type == EntryType.VertexDescriptor) - { - VertexDesc desc = VertexDesc.Read(Entry); - value = ", Attribute Count: " + desc.AttributeCount.ToString("D2"); - } + if (Entry != null && Entry.Type == EntryType.VertexDescriptor) + { + VertexDesc desc = VertexDesc.Read(Entry); + value = ", Attribute Count: " + desc.AttributeCount.ToString("D2"); + } - string location = external ? "External" : "Internal"; + string location = external ? "External" : "Internal"; - string info = "(External)"; - if (Entry != null) - info = "(" + location + ": " + EntryIndex.ToString("D3") + ", " + Entry.Type + value + extra + ")"; - return "ID: 0x" + EntryID.ToString("X8") + ", PtrOffset: 0x" + EntryPointerOffset.ToString("X8") + " " + info; - } + string info = "(External)"; + if (Entry != null) + info = "(" + location + ": " + EntryIndex.ToString("D3") + ", " + Entry.Type + value + extra + ")"; + return "ID: 0x" + EntryID.ToString("X8") + ", PtrOffset: 0x" + EntryPointerOffset.ToString("X8") + " " + info; } } diff --git a/BundleFormat/BundleEntry.cs b/BundleFormat/BundleEntry.cs index 7f5e457..78e3ef0 100644 --- a/BundleFormat/BundleEntry.cs +++ b/BundleFormat/BundleEntry.cs @@ -4,448 +4,447 @@ using System.Linq; using BundleUtilities; -namespace BundleFormat -{ - public class EntryBlock - { - public bool Compressed; - public uint CompressedSize; - public uint UncompressedSize; - public uint UncompressedAlignment = 1; // default depending on file type, 1 (what empty blocks use) so new blocks never write alignment 0 - public byte[] RawData; - public byte[] Data - { - get - { - if (RawData == null) - return null; - - if (Compressed) - return RawData.Decompress(); - - return RawData; - } - set - { - if (Compressed) - RawData = value.Compress(); - else - RawData = value; - - UncompressedSize = (uint)value.Length; - CompressedSize = (uint)RawData.Length; - } - } - } - - public class EntryInfo - { - public uint ID; - public EntryType Type; - public string Path; - public DebugInfo DebugInfo; - - public EntryInfo(uint id, EntryType type, string path, DebugInfo debugInfo) - { - ID = id; - Type = type; - Path = path; - DebugInfo = debugInfo; - } - } +namespace BundleFormat; - public struct Dependency +public class EntryBlock +{ + public bool Compressed; + public uint CompressedSize; + public uint UncompressedSize; + public uint UncompressedAlignment = 1; // default depending on file type, 1 (what empty blocks use) so new blocks never write alignment 0 + public byte[] RawData; + public byte[] Data { - public const int Size = 0x10; // uint64_t id, uint32_t pointer offset, uint32_t padding - public ulong ID; - public uint EntryPointerOffset; - - public static Dependency Read(BinaryReader2 br) + get { - Dependency dep = new() { ID = br.ReadUInt64(), EntryPointerOffset = br.ReadUInt32() }; - br.ReadUInt32(); // Padding, not always zero on console - return dep; - } + if (RawData == null) + return null; - public readonly void Write(BinaryWriter2 bw) - { - bw.Write(ID); - bw.Write(EntryPointerOffset); - bw.Write(0u); // Padding - } + if (Compressed) + return RawData.Decompress(); - private static byte[] WriteTable(List imports, bool bigEndian) - { - MemoryStream ms = new(); - BinaryWriter2 bw = new(ms, bigEndian); - foreach (Dependency dep in imports) - dep.Write(bw); - return ms.ToArray(); + return RawData; } - - // Whether primary data already ends with this import table - public static bool EndsWithTable(byte[] data, List imports, bool bigEndian) + set { - byte[] table = WriteTable(imports, bigEndian); - - // Compare id and offset only, padding isn't always zero on console - int start = data.Length - table.Length; - bool present = start >= 0; - for (int i = 0; present && i < table.Length; i++) - present = i % Size >= 12 || data[start + i] == table[i]; - return present; - } + if (Compressed) + RawData = value.Compress(); + else + RawData = value; - // Appends the import table to primary data unless it already ends with it - public static byte[] AppendTable(byte[] data, List imports, bool bigEndian) - { - if (EndsWithTable(data, imports, bigEndian)) - return data; - - byte[] table = WriteTable(imports, bigEndian); - int tableStart = (data.Length + 0xF) & ~0xF; - byte[] result = new byte[tableStart + table.Length]; - data.CopyTo(result, 0); - table.CopyTo(result, tableStart); - return result; + UncompressedSize = (uint)value.Length; + CompressedSize = (uint)RawData.Length; } + } +} - // Guesses the import table at the end of primary data - public static List ScanTable(byte[] data, bool bigEndian, int pointerSize) - { - List imports = []; - - if (data.Length % Size != 0) - return imports; - - using BinaryReader2 br = new(new MemoryStream(data), bigEndian); +public class EntryInfo +{ + public uint ID; + public EntryType Type; + public string Path; + public DebugInfo DebugInfo; - for (int start = data.Length - Size; start >= 0; start -= Size) - { - br.BaseStream.Position = start; - Dependency dep = Read(br); + public EntryInfo(uint id, EntryType type, string path, DebugInfo debugInfo) + { + ID = id; + Type = type; + Path = path; + DebugInfo = debugInfo; + } +} - if (dep.ID == 0 || dep.ID > uint.MaxValue || dep.EntryPointerOffset % 4 != 0 - || (imports.Count > 0 && dep.EntryPointerOffset >= imports[^1].EntryPointerOffset)) - break; +public struct Dependency +{ + public const int Size = 0x10; // uint64_t id, uint32_t pointer offset, uint32_t padding + public ulong ID; + public uint EntryPointerOffset; - imports.Add(dep); - } + public static Dependency Read(BinaryReader2 br) + { + Dependency dep = new() { ID = br.ReadUInt64(), EntryPointerOffset = br.ReadUInt32() }; + br.ReadUInt32(); // Padding, not always zero on console + return dep; + } - imports.Reverse(); + public readonly void Write(BinaryWriter2 bw) + { + bw.Write(ID); + bw.Write(EntryPointerOffset); + bw.Write(0u); // Padding + } - // Drop leading records until the last pointer slot fits before the table - while (imports.Count > 0 - && imports[^1].EntryPointerOffset + pointerSize > data.Length - imports.Count * Size) - imports.RemoveAt(0); + private static byte[] WriteTable(List imports, bool bigEndian) + { + MemoryStream ms = new(); + BinaryWriter2 bw = new(ms, bigEndian); + foreach (Dependency dep in imports) + dep.Write(bw); + return ms.ToArray(); + } - return imports; - } + // Whether primary data already ends with this import table + public static bool EndsWithTable(byte[] data, List imports, bool bigEndian) + { + byte[] table = WriteTable(imports, bigEndian); + + // Compare id and offset only, padding isn't always zero on console + int start = data.Length - table.Length; + bool present = start >= 0; + for (int i = 0; present && i < table.Length; i++) + present = i % Size >= 12 || data[start + i] == table[i]; + return present; } - public struct DebugInfo + // Appends the import table to primary data unless it already ends with it + public static byte[] AppendTable(byte[] data, List imports, bool bigEndian) { - public string Name; - public string TypeName; + if (EndsWithTable(data, imports, bigEndian)) + return data; + + byte[] table = WriteTable(imports, bigEndian); + int tableStart = (data.Length + 0xF) & ~0xF; + byte[] result = new byte[tableStart + table.Length]; + data.CopyTo(result, 0); + table.CopyTo(result, tableStart); + return result; } - public class BundleEntry + // Guesses the import table at the end of primary data + public static List ScanTable(byte[] data, bool bigEndian, int pointerSize) { - public BundleArchive Archive; - //public BundleReference Archive; + List imports = []; - public int Index; + if (data.Length % Size != 0) + return imports; - public ulong ID; - public int DependenciesListOffset; - public short DependencyCount; - public List Dependencies; + using BinaryReader2 br = new(new MemoryStream(data), bigEndian); - public DebugInfo DebugInfo; + for (int start = data.Length - Size; start >= 0; start -= Size) + { + br.BaseStream.Position = start; + Dependency dep = Read(br); - public EntryBlock[] EntryBlocks; + if (dep.ID == 0 || dep.ID > uint.MaxValue || dep.EntryPointerOffset % 4 != 0 + || (imports.Count > 0 && dep.EntryPointerOffset >= imports[^1].EntryPointerOffset)) + break; - public bool HasHeader => HasSection(0); - public bool HasBody => HasSection(1); - public bool HasThird => HasSection(2); + imports.Add(dep); + } - public EntryType Type; + imports.Reverse(); - public BundlePlatform Platform; - public bool Console => Platform == BundlePlatform.X360 || Platform == BundlePlatform.PS3; + // Drop leading records until the last pointer slot fits before the table + while (imports.Count > 0 + && imports[^1].EntryPointerOffset + pointerSize > data.Length - imports.Count * Size) + imports.RemoveAt(0); - public bool Dirty; + return imports; + } +} - public BundleEntry(BundleArchive archive) - { - Archive = archive; - /*Archive = new BundleReference(); - Archive.Path = archive.Path; - Archive.EntryCount = (uint)archive.Entries.Count;*/ - Dependencies = new List(); - } +public struct DebugInfo +{ + public string Name; + public string TypeName; +} - public ulong ImportID => - DependencyCount == 0 - ? 0 - : GetDependencies().Aggregate(0UL, (id, dep) => id | dep.EntryID); +public class BundleEntry +{ + public BundleArchive Archive; + //public BundleReference Archive; - // Secondary data is memory type 2 on PS3 and 1 elsewhere - public int SecondaryBlock => HasSection(1) ? 1 : (HasSection(2) || Platform == BundlePlatform.PS3) ? 2 : 1; + public int Index; - public bool HasSection(int section) - { - return EntryBlocks != null && - section < EntryBlocks.Length && - section >= 0 && - EntryBlocks[section] != null && - EntryBlocks[section].Data != null && - EntryBlocks[section].Data.Length > 0; - } + public ulong ID; + public int DependenciesListOffset; + public short DependencyCount; + public List Dependencies; - public MemoryStream MakeStream(bool body = false) - { - if (EntryBlocks == null) - return null; + public DebugInfo DebugInfo; - if (body) - return new MemoryStream(EntryBlocks[1].Data); - return new MemoryStream(EntryBlocks[0].Data); - } + public EntryBlock[] EntryBlocks; - public List GetDependencies() - { - List result = new List(); + public bool HasHeader => HasSection(0); + public bool HasBody => HasSection(1); + public bool HasThird => HasSection(2); - if (Dependencies.Count > 0) - { - for (int i = 0; i < Dependencies.Count; i++) - { - BundleDependency dependency = new BundleDependency(); + public EntryType Type; - dependency.EntryID = Dependencies[i].ID; - dependency.EntryPointerOffset = (int)Dependencies[i].EntryPointerOffset; + public BundlePlatform Platform; + public bool Console => Platform == BundlePlatform.X360 || Platform == BundlePlatform.PS3; - BundleEntry entry = null; + public bool Dirty; - /*string file = BundleCache.GetFileByEntryID(dependency.EntryID); - if (!string.IsNullOrEmpty(file)) - { - BundleArchive archive = BundleArchive.Read(file, dependency.EntryID); - entry = archive.GetEntryByID(dependency.EntryID); - }*/ - //} + public BundleEntry(BundleArchive archive) + { + Archive = archive; + /*Archive = new BundleReference(); + Archive.Path = archive.Path; + Archive.EntryCount = (uint)archive.Entries.Count;*/ + Dependencies = []; + } - // TODO - for (int j = 0; j < Archive.Entries.Count; j++) - { - if (Archive.Entries[j].ID != dependency.EntryID) - continue; + public ulong ImportID => + DependencyCount == 0 + ? 0 + : GetDependencies().Aggregate(0UL, (id, dep) => id | dep.EntryID); - dependency.EntryIndex = j; - entry = Archive.Entries[j]; - } + // Secondary data is memory type 2 on PS3 and 1 elsewhere + public int SecondaryBlock => HasSection(1) ? 1 : (HasSection(2) || Platform == BundlePlatform.PS3) ? 2 : 1; - dependency.Entry = entry; + public bool HasSection(int section) + { + return EntryBlocks != null && + section < EntryBlocks.Length && + section >= 0 && + EntryBlocks[section] != null && + EntryBlocks[section].Data != null && + EntryBlocks[section].Data.Length > 0; + } - result.Add(dependency); - } - return result; - } + public MemoryStream MakeStream(bool body = false) + { + if (EntryBlocks == null) + return null; - MemoryStream ms = MakeStream(); - BinaryReader2 br = new BinaryReader2(ms); - br.BigEndian = Console; + if (body) + return new MemoryStream(EntryBlocks[1].Data); + return new MemoryStream(EntryBlocks[0].Data); + } - br.BaseStream.Position = DependenciesListOffset; + public List GetDependencies() + { + List result = []; - for (int i = 0; i < DependencyCount; i++) + if (Dependencies.Count > 0) + { + for (int i = 0; i < Dependencies.Count; i++) { - BundleDependency bundleDependency = new BundleDependency(); + BundleDependency dependency = new(); - Dependency dep = Dependency.Read(br); - bundleDependency.EntryID = dep.ID; - bundleDependency.EntryPointerOffset = (int)dep.EntryPointerOffset; + dependency.EntryID = Dependencies[i].ID; + dependency.EntryPointerOffset = (int)Dependencies[i].EntryPointerOffset; BundleEntry entry = null; - /*string file = BundleCache.GetFileByEntryID(bundleDependency.EntryID); + /*string file = BundleCache.GetFileByEntryID(dependency.EntryID); if (!string.IsNullOrEmpty(file)) { - BundleArchive archive = BundleArchive.Read(file, bundleDependency.EntryID); - entry = archive.GetEntryByID(bundleDependency.EntryID); + BundleArchive archive = BundleArchive.Read(file, dependency.EntryID); + entry = archive.GetEntryByID(dependency.EntryID); }*/ + //} // TODO for (int j = 0; j < Archive.Entries.Count; j++) { - if (Archive.Entries[j].ID != bundleDependency.EntryID) + if (Archive.Entries[j].ID != dependency.EntryID) continue; - bundleDependency.EntryIndex = j; + dependency.EntryIndex = j; entry = Archive.Entries[j]; } - bundleDependency.Entry = entry; + dependency.Entry = entry; - result.Add(bundleDependency); + result.Add(dependency); } + return result; + } - br.Close(); - ms.Close(); + MemoryStream ms = MakeStream(); + BinaryReader2 br = new(ms); + br.BigEndian = Console; - return result; + br.BaseStream.Position = DependenciesListOffset; + + for (int i = 0; i < DependencyCount; i++) + { + BundleDependency bundleDependency = new(); + + Dependency dep = Dependency.Read(br); + bundleDependency.EntryID = dep.ID; + bundleDependency.EntryPointerOffset = (int)dep.EntryPointerOffset; + + BundleEntry entry = null; + + /*string file = BundleCache.GetFileByEntryID(bundleDependency.EntryID); + if (!string.IsNullOrEmpty(file)) + { + BundleArchive archive = BundleArchive.Read(file, bundleDependency.EntryID); + entry = archive.GetEntryByID(bundleDependency.EntryID); + }*/ + + // TODO + for (int j = 0; j < Archive.Entries.Count; j++) + { + if (Archive.Entries[j].ID != bundleDependency.EntryID) + continue; + + bundleDependency.EntryIndex = j; + entry = Archive.Entries[j]; + } + + bundleDependency.Entry = entry; + + result.Add(bundleDependency); + } + + br.Close(); + ms.Close(); + + return result; + } + + public string DetectName() + { + if (!string.IsNullOrWhiteSpace(DebugInfo.Name)) + return DebugInfo.Name; + + string theName = "worldvault"; + ulong theID = Crc32.HashCrc32B(theName); + if (theID == ID) + return theName; + theName = "postfxvault"; + theID = Crc32.HashCrc32B(theName); + if (theID == ID) + return theName; + theName = "cameravault"; + theID = Crc32.HashCrc32B(theName); + if (theID == ID) + return theName; + + string path = Path.GetFileNameWithoutExtension(Archive.Path); + string file = null; + if (path != null) + file = path.ToUpper(); + + if (file != null && file.StartsWith("TRK_UNIT") && file.EndsWith("_GR")) + { + string trackID = file[8..].Replace("_GR", "").ToLower(); + string name = "trk_unit" + trackID + "_list"; + ulong newID = Crc32.HashCrc32B(name); + if (newID == ID) + return name; + name = "prp_inst_" + trackID; + newID = Crc32.HashCrc32B(name); + if (newID == ID) + return name; + name = "prp_gl__" + trackID; + newID = Crc32.HashCrc32B(name); + if (newID == ID) + return name; + name = "trk_unit" + trackID + "_passby"; + newID = Crc32.HashCrc32B(name); + if (newID == ID) + return name; + name = "trk_unit" + trackID + "_emitter"; + newID = Crc32.HashCrc32B(name); + if (newID == ID) + return name; } - public string DetectName() + if (file != null) { - if (!string.IsNullOrWhiteSpace(DebugInfo.Name)) - return DebugInfo.Name; - - string theName = "worldvault"; - ulong theID = Crc32.HashCrc32B(theName); - if (theID == ID) - return theName; - theName = "postfxvault"; - theID = Crc32.HashCrc32B(theName); - if (theID == ID) - return theName; - theName = "cameravault"; - theID = Crc32.HashCrc32B(theName); - if (theID == ID) - return theName; - - string path = Path.GetFileNameWithoutExtension(Archive.Path); - string file = null; - if (path != null) - file = path.ToUpper(); - - if (file != null && file.StartsWith("TRK_UNIT") && file.EndsWith("_GR")) + string aptName = file.ToLower() + ".swf"; + ulong aptID = Crc32.HashCrc32B(aptName); + if (aptID == ID) + return aptName; + } + + if (file != null && file.StartsWith("WHE_") && file.EndsWith("_GR")) + { + string wheelID = file[4..].Replace("_GR", "").ToLower(); + string name = wheelID + "_graphics"; + ulong newID = Crc32.HashCrc32B(name); + if (newID == ID) + return name; + } + + if (file != null && file.StartsWith("VEH_")) + { + if (file.EndsWith("_AT")) { - string trackID = file.Substring(8).Replace("_GR", "").ToLower(); - string name = "trk_unit" + trackID + "_list"; + string vehicleID = file[4..].Replace("_AT", "").ToLower(); + string name = vehicleID + "_attribsys"; ulong newID = Crc32.HashCrc32B(name); if (newID == ID) return name; - name = "prp_inst_" + trackID; + name = vehicleID + "deformationmodel"; newID = Crc32.HashCrc32B(name); if (newID == ID) return name; - name = "prp_gl__" + trackID; + name = vehicleID + "_bpr"; newID = Crc32.HashCrc32B(name); if (newID == ID) return name; - name = "trk_unit" + trackID + "_passby"; + name = vehicleID + "_anim"; newID = Crc32.HashCrc32B(name); if (newID == ID) return name; - name = "trk_unit" + trackID + "_emitter"; + name = vehicleID + "_trafficstub"; newID = Crc32.HashCrc32B(name); if (newID == ID) return name; - } - - if (file != null) - { - string aptName = file.ToLower() + ".swf"; - ulong aptID = Crc32.HashCrc32B(aptName); - if (aptID == ID) - return aptName; - } - - if (file != null && file.StartsWith("WHE_") && file.EndsWith("_GR")) - { - string wheelID = file.Substring(4).Replace("_GR", "").ToLower(); - string name = wheelID + "_graphics"; - ulong newID = Crc32.HashCrc32B(name); + name = vehicleID + "_vanm"; + newID = Crc32.HashCrc32B(name); if (newID == ID) return name; - } - - if (file != null && file.StartsWith("VEH_")) + } else if (file.EndsWith("_CD")) { - if (file.EndsWith("_AT")) - { - string vehicleID = file.Substring(4).Replace("_AT", "").ToLower(); - string name = vehicleID + "_attribsys"; - ulong newID = Crc32.HashCrc32B(name); - if (newID == ID) - return name; - name = vehicleID + "deformationmodel"; - newID = Crc32.HashCrc32B(name); - if (newID == ID) - return name; - name = vehicleID + "_bpr"; - newID = Crc32.HashCrc32B(name); - if (newID == ID) - return name; - name = vehicleID + "_anim"; - newID = Crc32.HashCrc32B(name); - if (newID == ID) - return name; - name = vehicleID + "_trafficstub"; - newID = Crc32.HashCrc32B(name); - if (newID == ID) - return name; - name = vehicleID + "_vanm"; - newID = Crc32.HashCrc32B(name); - if (newID == ID) - return name; - } else if (file.EndsWith("_CD")) - { - string vehicleID = file.Substring(4).Replace("_CD", "").ToLower(); - string name = vehicleID; - ulong newID = Crc32.HashCrc32B(name); - if (newID == ID) - return name; - } else if (file.EndsWith("_GR")) - { - string vehicleID = file.Substring(4).Replace("_GR", "").ToLower(); - string name = vehicleID + "_graphics"; - ulong newID = Crc32.HashCrc32B(name); - if (newID == ID) - return name; - } - } - - // WorldCol Names - for (int i = 0; i < Archive.EntryCount; i++) - { - string name = "trk_col_" + i; + string vehicleID = file[4..].Replace("_CD", "").ToLower(); + string name = vehicleID; ulong newID = Crc32.HashCrc32B(name); if (newID == ID) return name; - name = "trk_clil" + i; - newID = Crc32.HashCrc32B(name); + } else if (file.EndsWith("_GR")) + { + string vehicleID = file[4..].Replace("_GR", "").ToLower(); + string name = vehicleID + "_graphics"; + ulong newID = Crc32.HashCrc32B(name); if (newID == ID) return name; } - - return ""; } - public static Color GetColor(EntryType type) => type switch + // WorldCol Names + for (int i = 0; i < Archive.EntryCount; i++) { - EntryType.Texture => Color.Orange, - EntryType.Material => Color.HotPink, - EntryType.Renderable => Color.Aquamarine, - EntryType.InstanceList => Color.BlueViolet, - EntryType.EntryList => Color.Tomato, - EntryType.Model => Color.Yellow, - EntryType.PolygonSoupList => Color.Goldenrod, - EntryType.GraphicsSpec => Color.SeaGreen, - _ => Color.Transparent - }; - - public static byte GetMemoryChunkCount(EntryType type) => type switch - { - EntryType.Texture => 2, - EntryType.IndexBuffer => 2, - EntryType.VertexBuffer => 2, - EntryType.Renderable => 2, - EntryType.ShaderProgramBuffer => 2, - EntryType.VFXMeshCollection => 2, - _ => 1, - }; + string name = "trk_col_" + i; + ulong newID = Crc32.HashCrc32B(name); + if (newID == ID) + return name; + name = "trk_clil" + i; + newID = Crc32.HashCrc32B(name); + if (newID == ID) + return name; + } + + return ""; } + + public static Color GetColor(EntryType type) => type switch + { + EntryType.Texture => Color.Orange, + EntryType.Material => Color.HotPink, + EntryType.Renderable => Color.Aquamarine, + EntryType.InstanceList => Color.BlueViolet, + EntryType.EntryList => Color.Tomato, + EntryType.Model => Color.Yellow, + EntryType.PolygonSoupList => Color.Goldenrod, + EntryType.GraphicsSpec => Color.SeaGreen, + _ => Color.Transparent + }; + + public static byte GetMemoryChunkCount(EntryType type) => type switch + { + EntryType.Texture => 2, + EntryType.IndexBuffer => 2, + EntryType.VertexBuffer => 2, + EntryType.Renderable => 2, + EntryType.ShaderProgramBuffer => 2, + EntryType.VFXMeshCollection => 2, + _ => 1, + }; } diff --git a/BundleFormat/EntryType.cs b/BundleFormat/EntryType.cs index 6976c35..0b87e5f 100644 --- a/BundleFormat/EntryType.cs +++ b/BundleFormat/EntryType.cs @@ -1,141 +1,140 @@ -namespace BundleFormat +namespace BundleFormat; + +public enum EntryType { - public enum EntryType - { - Invalid = -1, + Invalid = -1, - // Standard types, shared between games - Texture = 0x0, // Also called: RwRaster, PlaneTexture, TexturePage - Material = 0x1, // Also called: RwMaterial, MaterialAssembly - RenderableMesh = 0x2, // Also called: Renderable; likely deprecated - TextFile = 0x3, - DrawIndexParams = 0x4, - IndexBuffer = 0x5, - MeshState = 0x6, - TextureAuxInfo = 0x7, - VertexBufferItem = 0x8, - VertexBuffer = 0x9, - VertexDescriptor = 0xA, // Also called: RwVertexDesc - MaterialCRC32 = 0xB, // Also called: RwMaterialCRC32 - Renderable = 0xC, // Also called: RwRenderable, GtRenderable - MaterialTechnique = 0xD, - TextureState = 0xE, // Also called: RwTextureState - MaterialState = 0xF, // Also called: BlendState - DepthStencilState = 0x10, - RasterizerState = 0x11, - ShaderProgramBuffer = 0x12, // Also called: RwShaderProgramBuffer, PixelShader, VertexShader, ShaderProgramState - RenderTargetState = 0x13, - ShaderParameter = 0x14, // Also called: RwShaderParameter - RenderableAssembly = 0x15, - Debug = 0x16, // Also called: RwDebug - KdTree = 0x17, - VoiceHierarchy = 0x18, - Snr = 0x19, - InterpreterData = 0x1A, - AttribSysSchema = 0x1B, - AttribSysVault = 0x1C, - EntryList = 0x1D, - AptData = 0x1E, // Also called: AptDataHeader, Flash - Popup = 0x1F, // Also called: GuiPopup - Font = 0x21, - LuaCode = 0x22, - InstanceList = 0x23, - CollisionMeshData = 0x24, // Also called: ClusteredMesh - IdList = 0x25, // Also called: ResourceIdList - InstanceCollisionList = 0x26, - Language = 0x27, - SatNavTile = 0x28, - SatNavTileDirectory = 0x29, - Model = 0x2A, // Also called: VehicleModel, WheelModel, PropModel - ColourCube = 0x2B, // Also called: RwColourCube - HudMessage = 0x2C, // Also called: GuiHudMessage - HudMessageList = 0x2D, - HudMessageSequence = 0x2E, - HudMessageSequenceDictionary = 0x2F, - WorldPainter2D = 0x30, // Also called: World Painter 2D - PFXHookBundle = 0x31, // Also called: GuiPFXHook - ShaderTechnique = 0x32, // Also called: Shader + // Standard types, shared between games + Texture = 0x0, // Also called: RwRaster, PlaneTexture, TexturePage + Material = 0x1, // Also called: RwMaterial, MaterialAssembly + RenderableMesh = 0x2, // Also called: Renderable; likely deprecated + TextFile = 0x3, + DrawIndexParams = 0x4, + IndexBuffer = 0x5, + MeshState = 0x6, + TextureAuxInfo = 0x7, + VertexBufferItem = 0x8, + VertexBuffer = 0x9, + VertexDescriptor = 0xA, // Also called: RwVertexDesc + MaterialCRC32 = 0xB, // Also called: RwMaterialCRC32 + Renderable = 0xC, // Also called: RwRenderable, GtRenderable + MaterialTechnique = 0xD, + TextureState = 0xE, // Also called: RwTextureState + MaterialState = 0xF, // Also called: BlendState + DepthStencilState = 0x10, + RasterizerState = 0x11, + ShaderProgramBuffer = 0x12, // Also called: RwShaderProgramBuffer, PixelShader, VertexShader, ShaderProgramState + RenderTargetState = 0x13, + ShaderParameter = 0x14, // Also called: RwShaderParameter + RenderableAssembly = 0x15, + Debug = 0x16, // Also called: RwDebug + KdTree = 0x17, + VoiceHierarchy = 0x18, + Snr = 0x19, + InterpreterData = 0x1A, + AttribSysSchema = 0x1B, + AttribSysVault = 0x1C, + EntryList = 0x1D, + AptData = 0x1E, // Also called: AptDataHeader, Flash + Popup = 0x1F, // Also called: GuiPopup + Font = 0x21, + LuaCode = 0x22, + InstanceList = 0x23, + CollisionMeshData = 0x24, // Also called: ClusteredMesh + IdList = 0x25, // Also called: ResourceIdList + InstanceCollisionList = 0x26, + Language = 0x27, + SatNavTile = 0x28, + SatNavTileDirectory = 0x29, + Model = 0x2A, // Also called: VehicleModel, WheelModel, PropModel + ColourCube = 0x2B, // Also called: RwColourCube + HudMessage = 0x2C, // Also called: GuiHudMessage + HudMessageList = 0x2D, + HudMessageSequence = 0x2E, + HudMessageSequenceDictionary = 0x2F, + WorldPainter2D = 0x30, // Also called: World Painter 2D + PFXHookBundle = 0x31, // Also called: GuiPFXHook + ShaderTechnique = 0x32, // Also called: Shader - RawFile = 0x40, // Also called: RAW, File - ICETakeDictionary = 0x41, // Also called: ICEDictionary; base type: Dictionary - VideoData = 0x42, - PolygonSoupList = 0x43, // Also called: CollisionMeshData - DeveloperList = 0x44, - CommsToolListDefinition = 0x45, // Also called: CommsToolDef - CommsToolList = 0x46, // Also called: CoomsToolInst + RawFile = 0x40, // Also called: RAW, File + ICETakeDictionary = 0x41, // Also called: ICEDictionary; base type: Dictionary + VideoData = 0x42, + PolygonSoupList = 0x43, // Also called: CollisionMeshData + DeveloperList = 0x44, + CommsToolListDefinition = 0x45, // Also called: CommsToolDef + CommsToolList = 0x46, // Also called: CoomsToolInst - BinaryFile = 0x50, // Also called: AlignedBinaryFile; used as base type - AnimationCollection = 0x51, + BinaryFile = 0x50, // Also called: AlignedBinaryFile; used as base type + AnimationCollection = 0x51, - // Random type IDs from the Black builds, probably for testing - CharAnimBankFile = 0x2710, // Also called: Character Animation Bank Data - WeaponFile = 0x2711, // Also called: WEAPONDATA - VFXFile = 0x343E, // Also called: VFX Data - BearFile = 0x343F, // Also called: Bear Data - BkPropInstanceList = 0x3A98, + // Random type IDs from the Black builds, probably for testing + CharAnimBankFile = 0x2710, // Also called: Character Animation Bank Data + WeaponFile = 0x2711, // Also called: WEAPONDATA + VFXFile = 0x343E, // Also called: VFX Data + BearFile = 0x343F, // Also called: Bear Data + BkPropInstanceList = 0x3A98, - // Sound-related types - Registry = 0xA000, - GenericRwacFactoryConfiguration = 0xA010, - GenericRwacWaveContent = 0xA020, // Also called: Generic Wave Content - GinsuWaveContent = 0xA021, // Also called: Ginsu Wave Content - AemsBank = 0xA022, // Also called: AEMS Bank - Csis = 0xA023, // Also called: CSIS - Nicotine = 0xA024, // Also called: Nicotine Map - Splicer = 0xA025, // Also called: Splicer Data - FreqContent = 0xA026, - VoiceHierarchyCollection = 0xA027, - GenericRwacReverbIRContent = 0xA028, - SnapshotData = 0xA029, // Also called: Snapshot Data + // Sound-related types + Registry = 0xA000, + GenericRwacFactoryConfiguration = 0xA010, + GenericRwacWaveContent = 0xA020, // Also called: Generic Wave Content + GinsuWaveContent = 0xA021, // Also called: Ginsu Wave Content + AemsBank = 0xA022, // Also called: AEMS Bank + Csis = 0xA023, // Also called: CSIS + Nicotine = 0xA024, // Also called: Nicotine Map + Splicer = 0xA025, // Also called: Splicer Data + FreqContent = 0xA026, + VoiceHierarchyCollection = 0xA027, + GenericRwacReverbIRContent = 0xA028, + SnapshotData = 0xA029, // Also called: Snapshot Data - ZoneList = 0xB000, + ZoneList = 0xB000, - // Game-specific types - Burnout Paradise - LoopModel = 0x10000, - AISections = 0x10001, // Also called: AIMapData - TrafficData = 0x10002, - TriggerData = 0x10003, // Also called: Trigger - DeformationModel = 0x10004, - VehicleList = 0x10005, - GraphicsSpec = 0x10006, // Also called: VehicleGraphics - PhysicsSpec = 0x10007, - ParticleDescriptionCollection = 0x10008, - WheelList = 0x10009, - WheelGraphicsSpec = 0x1000A, // Also called: WheelGraphics; base type: GraphicsSpec - TextureNameMap = 0x1000B, - ICEList = 0x1000C, - ICEData = 0x1000D, // Also called: ICE - ProgressionData = 0x1000E, // Also called: Progression - PropPhysics = 0x1000F, - PropGraphicsList = 0x10010, - PropInstanceData = 0x10011, // Also called: PropInstances - BrnEnvironmentKeyframe = 0x10012, // Base type: Keyframe - BrnEnvironmentTimeLine = 0x10013, // Base type: TimeLine - BrnEnvironmentDictionary = 0x10014, // Base type: Dictionary - GraphicsStub = 0x10015, // Also called: TrafficStub, TrafficGraphicsStub - StaticSoundMap = 0x10016, - DEPRECATED_PFXHookBundle = 0x10017, // Replaced by type 0x31 shortly after 2006-11-13 - StreetData = 0x10018, - VFXMeshCollection = 0x10019, // Also called: BrnVFXMeshCollection - MassiveLookupTable = 0x1001A, - VFXPropCollection = 0x1001B, - StreamedDeformation = 0x1001C, // Also called: StreamedDeformationSpec - ParticleDescription = 0x1001D, - PlayerCarColours = 0x1001E, - ChallengeList = 0x1001F, - FlaptFile = 0x10020, - ProfileUpgrade = 0x10021, - OfflineChallengeList = 0x10022, - VehicleAnimation = 0x10023, - BodypartRemapData = 0x10024, // Also called: BodyPartRemapping - LUAList = 0x10025, // Also called: LUAInst - LUAScript = 0x10026, + // Game-specific types - Burnout Paradise + LoopModel = 0x10000, + AISections = 0x10001, // Also called: AIMapData + TrafficData = 0x10002, + TriggerData = 0x10003, // Also called: Trigger + DeformationModel = 0x10004, + VehicleList = 0x10005, + GraphicsSpec = 0x10006, // Also called: VehicleGraphics + PhysicsSpec = 0x10007, + ParticleDescriptionCollection = 0x10008, + WheelList = 0x10009, + WheelGraphicsSpec = 0x1000A, // Also called: WheelGraphics; base type: GraphicsSpec + TextureNameMap = 0x1000B, + ICEList = 0x1000C, + ICEData = 0x1000D, // Also called: ICE + ProgressionData = 0x1000E, // Also called: Progression + PropPhysics = 0x1000F, + PropGraphicsList = 0x10010, + PropInstanceData = 0x10011, // Also called: PropInstances + BrnEnvironmentKeyframe = 0x10012, // Base type: Keyframe + BrnEnvironmentTimeLine = 0x10013, // Base type: TimeLine + BrnEnvironmentDictionary = 0x10014, // Base type: Dictionary + GraphicsStub = 0x10015, // Also called: TrafficStub, TrafficGraphicsStub + StaticSoundMap = 0x10016, + DEPRECATED_PFXHookBundle = 0x10017, // Replaced by type 0x31 shortly after 2006-11-13 + StreetData = 0x10018, + VFXMeshCollection = 0x10019, // Also called: BrnVFXMeshCollection + MassiveLookupTable = 0x1001A, + VFXPropCollection = 0x1001B, + StreamedDeformation = 0x1001C, // Also called: StreamedDeformationSpec + ParticleDescription = 0x1001D, + PlayerCarColours = 0x1001E, + ChallengeList = 0x1001F, + FlaptFile = 0x10020, + ProfileUpgrade = 0x10021, + OfflineChallengeList = 0x10022, + VehicleAnimation = 0x10023, + BodypartRemapData = 0x10024, // Also called: BodyPartRemapping + LUAList = 0x10025, // Also called: LUAInst + LUAScript = 0x10026, - // Game-specific types - Black 360/Black 2 - BkSoundWeapon = 0x11000, // Also called: SoundWeapon Data - BkSoundGunsu = 0x11001, // Also called: SoundGunsu Data - BkSoundBulletImpact = 0x11002, // Also called: SoundBulletImpact Data - BkSoundBulletImpactList = 0x11003, // Also called: SoundBulletImpactList - BkSoundBulletImpactStream = 0x11004, // Also called: SoundBulletImpactStream Data - } + // Game-specific types - Black 360/Black 2 + BkSoundWeapon = 0x11000, // Also called: SoundWeapon Data + BkSoundGunsu = 0x11001, // Also called: SoundGunsu Data + BkSoundBulletImpact = 0x11002, // Also called: SoundBulletImpact Data + BkSoundBulletImpactList = 0x11003, // Also called: SoundBulletImpactList + BkSoundBulletImpactStream = 0x11004, // Also called: SoundBulletImpactStream Data } diff --git a/BundleFormat/Extensions.cs b/BundleFormat/Extensions.cs index 7caf4a5..3e342af 100644 --- a/BundleFormat/Extensions.cs +++ b/BundleFormat/Extensions.cs @@ -6,94 +6,93 @@ using System.Numerics; using System.Text; -namespace BundleFormat +namespace BundleFormat; + +public static class Extensions { - public static class Extensions + public static string AsString(this byte[] self) { - public static string AsString(this byte[] self) - { - if (self == null) - return ""; - StringBuilder sb = new StringBuilder(); - - for (int i = 0; i < self.Length; i++) - { - sb.Append(self[i].ToString("X2")); - if ((i + 1) % 16 == 0) - sb.Append("\r\n"); - else - sb.Append(" "); - } + if (self == null) + return ""; + StringBuilder sb = new(); - return sb.ToString(); + for (int i = 0; i < self.Length; i++) + { + sb.Append(self[i].ToString("X2")); + if ((i + 1) % 16 == 0) + sb.Append("\r\n"); + else + sb.Append(" "); } - public static string MakePreview(this byte[] self, int start, int end) + return sb.ToString(); + } + + public static string MakePreview(this byte[] self, int start, int end) + { + byte[] subArray = new byte[end - start]; + int index = 0; + for (int i = start; i < start + end; i++) { - byte[] subArray = new byte[end - start]; - int index = 0; - for (int i = start; i < start + end; i++) - { - subArray[index++] = self[i]; - } - return subArray.AsString(); + subArray[index++] = self[i]; } + return subArray.AsString(); + } - public static byte[] Compress(this byte[] self) + public static byte[] Compress(this byte[] self) + { + MemoryStream uncompressed = new(self); + MemoryStream compressed = new(); + using (ZLibStream zlibStream = new(compressed, CompressionLevel.SmallestSize, true)) { - MemoryStream uncompressed = new(self); - MemoryStream compressed = new(); - using (ZLibStream zlibStream = new(compressed, CompressionLevel.SmallestSize, true)) - { - uncompressed.CopyTo(zlibStream); - } - return compressed.ToArray(); + uncompressed.CopyTo(zlibStream); } - - public static byte[] Decompress(this byte[] self) + return compressed.ToArray(); + } + + public static byte[] Decompress(this byte[] self) + { + MemoryStream decompressed = new(); + using (ZLibStream zlibStream = new(new MemoryStream(self), CompressionMode.Decompress)) { - MemoryStream decompressed = new(); - using (ZLibStream zlibStream = new(new MemoryStream(self), CompressionMode.Decompress)) - { - zlibStream.CopyTo(decompressed); - } - return decompressed.ToArray(); + zlibStream.CopyTo(decompressed); } + return decompressed.ToArray(); + } + + public static bool Matches(this byte[] self, byte[] other) + { + if (self == null || other == null) + return false; + if (self.Length != other.Length) + return false; - public static bool Matches(this byte[] self, byte[] other) + for (int i = 0; i < self.Length; i++) { - if (self == null || other == null) - return false; - if (self.Length != other.Length) + if (self[i] != other[i]) return false; + } - for (int i = 0; i < self.Length; i++) - { - if (self[i] != other[i]) - return false; - } + return true; + } - return true; + public static byte[] toBytes(this Vector4 vec, bool swap = false) + { + List bytes = []; + if (swap) + { + bytes.AddRange(BitConverter.GetBytes(BinaryPrimitives.ReadSingleBigEndian(BitConverter.GetBytes(vec.X)))); + bytes.AddRange(BitConverter.GetBytes(BinaryPrimitives.ReadSingleBigEndian(BitConverter.GetBytes(vec.Y)))); + bytes.AddRange(BitConverter.GetBytes(BinaryPrimitives.ReadSingleBigEndian(BitConverter.GetBytes(vec.Z)))); + bytes.AddRange(BitConverter.GetBytes(BinaryPrimitives.ReadSingleBigEndian(BitConverter.GetBytes(vec.W)))); } - - public static byte[] toBytes(this Vector4 vec, bool swap = false) + else { - List bytes = new List(); - if (swap) - { - bytes.AddRange(BitConverter.GetBytes(BinaryPrimitives.ReadSingleBigEndian(BitConverter.GetBytes(vec.X)))); - bytes.AddRange(BitConverter.GetBytes(BinaryPrimitives.ReadSingleBigEndian(BitConverter.GetBytes(vec.Y)))); - bytes.AddRange(BitConverter.GetBytes(BinaryPrimitives.ReadSingleBigEndian(BitConverter.GetBytes(vec.Z)))); - bytes.AddRange(BitConverter.GetBytes(BinaryPrimitives.ReadSingleBigEndian(BitConverter.GetBytes(vec.W)))); - } - else - { - bytes.AddRange(BitConverter.GetBytes(vec.X)); - bytes.AddRange(BitConverter.GetBytes(vec.Y)); - bytes.AddRange(BitConverter.GetBytes(vec.Z)); - bytes.AddRange(BitConverter.GetBytes(vec.W)); - } - return bytes.ToArray(); + bytes.AddRange(BitConverter.GetBytes(vec.X)); + bytes.AddRange(BitConverter.GetBytes(vec.Y)); + bytes.AddRange(BitConverter.GetBytes(vec.Z)); + bytes.AddRange(BitConverter.GetBytes(vec.W)); } + return [.. bytes]; } } diff --git a/BundleFormat/VertexDesc.cs b/BundleFormat/VertexDesc.cs index b0be6e0..bf5199c 100644 --- a/BundleFormat/VertexDesc.cs +++ b/BundleFormat/VertexDesc.cs @@ -4,161 +4,160 @@ using System.Windows.Forms; using BundleUtilities; -namespace BundleFormat +namespace BundleFormat; + +public enum VertexAttributeType { - public enum VertexAttributeType - { - Invalid = 0, - Positions = 1, - Normals = 3, - UV1 = 5, - UV2 = 6, - BoneIndexes = 13, - BoneWeights = 14, - Tangents = 15 - }; - - public struct VertexAttribute + Invalid = 0, + Positions = 1, + Normals = 3, + UV1 = 5, + UV2 = 6, + BoneIndexes = 13, + BoneWeights = 14, + Tangents = 15 +}; + +public struct VertexAttribute +{ + public VertexAttributeType Type; + public uint Unknown1; + public uint Offset; + public uint Unknown2; + public uint Size; +} + +public class VertexDesc +{ + public int Unknown1; + public int Unknown2; + public int Unknown3; + public int AttributeCount; + public List Attributes; + + public VertexDesc() { - public VertexAttributeType Type; - public uint Unknown1; - public uint Offset; - public uint Unknown2; - public uint Size; + Attributes = []; } - public class VertexDesc + public static VertexDesc Read(BundleEntry entry) { - public int Unknown1; - public int Unknown2; - public int Unknown3; - public int AttributeCount; - public List Attributes; + VertexDesc result = new(); - public VertexDesc() - { - Attributes = new List(); - } + MemoryStream ms = entry.MakeStream(); + BinaryReader2 br = new(ms); + br.BigEndian = entry.Console; + bool x64 = entry.Platform == BundlePlatform.PCx64; // decomp is like the X360 layout but little endian + + result.Unknown1 = br.ReadInt32(); + result.Unknown2 = br.ReadInt32(); + result.Unknown3 = br.ReadInt32(); + result.AttributeCount = br.ReadInt32(); + if (x64) // u16 element count @0x08 + result.AttributeCount = (ushort)result.Unknown3; - public static VertexDesc Read(BundleEntry entry) + for (int i = 0; i < result.AttributeCount; i++) { - VertexDesc result = new VertexDesc(); + VertexAttribute attribute = new(); + + if (result.Unknown2 != 0 && !x64) // BPR + { + attribute.Type = (VertexAttributeType)br.ReadInt32(); + if (!Enum.IsDefined(typeof(VertexAttributeType), attribute.Type)) + MessageBox.Show("Unknown vertex attribute type: " + attribute.Type); + attribute.Unknown1 = br.ReadUInt32(); + attribute.Offset = br.ReadUInt32(); + attribute.Unknown2 = br.ReadUInt32(); + attribute.Size = br.ReadUInt32(); + } + else + { + br.BaseStream.Position += 1; + attribute.Size = br.ReadByte(); + attribute.Offset = br.ReadByte(); - MemoryStream ms = entry.MakeStream(); - BinaryReader2 br = new BinaryReader2(ms); - br.BigEndian = entry.Console; - bool x64 = entry.Platform == BundlePlatform.PCx64; // decomp is like the X360 layout but little endian + // These are probably in the following bytes but I'll need to check where. + attribute.Unknown1 = 0; + attribute.Unknown2 = 0; - result.Unknown1 = br.ReadInt32(); - result.Unknown2 = br.ReadInt32(); - result.Unknown3 = br.ReadInt32(); - result.AttributeCount = br.ReadInt32(); - if (x64) // u16 element count @0x08 - result.AttributeCount = (ushort)result.Unknown3; + br.BaseStream.Position += 8; - for (int i = 0; i < result.AttributeCount; i++) - { - VertexAttribute attribute = new VertexAttribute(); - - if (result.Unknown2 != 0 && !x64) // BPR + byte type = br.ReadByte(); + switch (type) { - attribute.Type = (VertexAttributeType)br.ReadInt32(); - if (!Enum.IsDefined(typeof(VertexAttributeType), attribute.Type)) - MessageBox.Show("Unknown vertex attribute type: " + attribute.Type); - attribute.Unknown1 = br.ReadUInt32(); - attribute.Offset = br.ReadUInt32(); - attribute.Unknown2 = br.ReadUInt32(); - attribute.Size = br.ReadUInt32(); - } - else - { - br.BaseStream.Position += 1; - attribute.Size = br.ReadByte(); - attribute.Offset = br.ReadByte(); - - // These are probably in the following bytes but I'll need to check where. - attribute.Unknown1 = 0; - attribute.Unknown2 = 0; - - br.BaseStream.Position += 8; - - byte type = br.ReadByte(); - switch (type) - { - case 1: - attribute.Type = VertexAttributeType.Positions; - break; - case 3: - attribute.Type = VertexAttributeType.Normals; - break; - case 6: - attribute.Type = VertexAttributeType.UV1; - break; - case 7: - attribute.Type = VertexAttributeType.UV2; - break; - case 14: - attribute.Type = VertexAttributeType.BoneIndexes; - break; - case 15: - attribute.Type = VertexAttributeType.BoneWeights; - break; - case 21: - attribute.Type = VertexAttributeType.Tangents; - break; - default: - attribute.Type = VertexAttributeType.Invalid; - MessageBox.Show("Unknown vertex attribute type: " + type); - break; - } - - br.BaseStream.Position += 4; - } - - if (x64) - { - byte[] data = entry.EntryBlocks[0].Data; - int element = 0x10 + 0x10 * i; - attribute.Offset = BitConverter.ToUInt16(data, element + 2); - attribute.Unknown1 = BitConverter.ToUInt32(data, element + 4); - attribute.Size = data[0x10 + 0x10 * result.AttributeCount + i]; + case 1: + attribute.Type = VertexAttributeType.Positions; + break; + case 3: + attribute.Type = VertexAttributeType.Normals; + break; + case 6: + attribute.Type = VertexAttributeType.UV1; + break; + case 7: + attribute.Type = VertexAttributeType.UV2; + break; + case 14: + attribute.Type = VertexAttributeType.BoneIndexes; + break; + case 15: + attribute.Type = VertexAttributeType.BoneWeights; + break; + case 21: + attribute.Type = VertexAttributeType.Tangents; + break; + default: + attribute.Type = VertexAttributeType.Invalid; + MessageBox.Show("Unknown vertex attribute type: " + type); + break; } - result.Attributes.Add(attribute); + br.BaseStream.Position += 4; } - br.Close(); - ms.Close(); + if (x64) + { + byte[] data = entry.EntryBlocks[0].Data; + int element = 0x10 + 0x10 * i; + attribute.Offset = BitConverter.ToUInt16(data, element + 2); + attribute.Unknown1 = BitConverter.ToUInt32(data, element + 4); + attribute.Size = data[0x10 + 0x10 * result.AttributeCount + i]; + } - return result; + result.Attributes.Add(attribute); } - public void Write(BundleEntry entry) - { - MemoryStream ms = new MemoryStream(); - BinaryWriter2 bw = new BinaryWriter2(ms); - bw.BigEndian = entry.Console; - - bw.Write(Unknown1); - bw.Write(Unknown2); - bw.Write(Unknown3); - bw.Write(Attributes.Count); - foreach (VertexAttribute attribute in Attributes) - { - bw.Write((int)attribute.Type); - bw.Write(attribute.Unknown1); - bw.Write(attribute.Offset); - bw.Write(attribute.Unknown2); - bw.Write(attribute.Size); - } + br.Close(); + ms.Close(); - bw.Flush(); - byte[] Data = ms.GetBuffer(); - bw.Close(); - ms.Close(); + return result; + } - entry.EntryBlocks[0].Data = Data; - entry.Dirty = true; + public void Write(BundleEntry entry) + { + MemoryStream ms = new(); + BinaryWriter2 bw = new(ms); + bw.BigEndian = entry.Console; + + bw.Write(Unknown1); + bw.Write(Unknown2); + bw.Write(Unknown3); + bw.Write(Attributes.Count); + foreach (VertexAttribute attribute in Attributes) + { + bw.Write((int)attribute.Type); + bw.Write(attribute.Unknown1); + bw.Write(attribute.Offset); + bw.Write(attribute.Unknown2); + bw.Write(attribute.Size); } + + bw.Flush(); + byte[] Data = ms.GetBuffer(); + bw.Close(); + ms.Close(); + + entry.EntryBlocks[0].Data = Data; + entry.Dirty = true; } } diff --git a/BundleManager/BetterListView.cs b/BundleManager/BetterListView.cs index dd55350..437fe9e 100644 --- a/BundleManager/BetterListView.cs +++ b/BundleManager/BetterListView.cs @@ -2,38 +2,37 @@ using System.Drawing; using System.Windows.Forms; -namespace BundleManager +namespace BundleManager; + +class BetterListView : System.Windows.Forms.ListView { - class BetterListView : System.Windows.Forms.ListView + public BetterListView() { - public BetterListView() - { - SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true); - SetStyle(ControlStyles.EnableNotifyMessage, true); - } + SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true); + SetStyle(ControlStyles.EnableNotifyMessage, true); + } - protected override void OnNotifyMessage(Message m) + protected override void OnNotifyMessage(Message m) + { + // Filter out the WM_ERASEBKGND message + if (m.Msg != 0x14) // WM_ERASEBKGND { - // Filter out the WM_ERASEBKGND message - if (m.Msg != 0x14) // WM_ERASEBKGND - { - base.OnNotifyMessage(m); - } + base.OnNotifyMessage(m); } + } - private void ScaleListViewColumns(SizeF factor) + private void ScaleListViewColumns(SizeF factor) + { + foreach (ColumnHeader column in Columns) { - foreach (ColumnHeader column in Columns) - { - column.Width = (int)Math.Round(column.Width * factor.Width); - } + column.Width = (int)Math.Round(column.Width * factor.Width); } + } - protected override void ScaleControl(SizeF factor, BoundsSpecified specified) - { - base.ScaleControl(factor, specified); - ScaleListViewColumns(factor); - } + protected override void ScaleControl(SizeF factor, BoundsSpecified specified) + { + base.ScaleControl(factor, specified); + ScaleListViewColumns(factor); } } diff --git a/BundleManager/BundleResource.cs b/BundleManager/BundleResource.cs index 5b57cd3..6c00334 100644 --- a/BundleManager/BundleResource.cs +++ b/BundleManager/BundleResource.cs @@ -2,27 +2,26 @@ using BundleFormat; using BundleUtilities; -namespace BundleManager -{ - public abstract class BundleResource - { - protected BundleEntry Entry; +namespace BundleManager; - public EntryType Type => Entry.Type; +public abstract class BundleResource +{ + protected BundleEntry Entry; - protected BundleResource(BundleEntry entry, ILoader loader = null) - { - Entry = entry; - _init(loader); - } + public EntryType Type => Entry.Type; - private void _init(ILoader loader) - { - Read(loader); - } + protected BundleResource(BundleEntry entry, ILoader loader = null) + { + Entry = entry; + _init(loader); + } - protected abstract void Read(ILoader loader = null); - protected abstract void Write(ILoader loader = null); - public abstract void ShowPreview(IWin32Window parent = null); + private void _init(ILoader loader) + { + Read(loader); } + + protected abstract void Read(ILoader loader = null); + protected abstract void Write(ILoader loader = null); + public abstract void ShowPreview(IWin32Window parent = null); } diff --git a/BundleManager/EntryEditor.cs b/BundleManager/EntryEditor.cs index c92af07..d5281fb 100644 --- a/BundleManager/EntryEditor.cs +++ b/BundleManager/EntryEditor.cs @@ -14,834 +14,833 @@ using BurnoutImage; using LangEditor; -namespace BundleManager +namespace BundleManager; + +public partial class EntryEditor : Form { - public partial class EntryEditor : Form - { - private const string DataFileFilter = "Binary Files (Bundle Manager & YAP)|*.dat|Binary Files (Legacy BM & bnd2-manager)|*.bin;*.dat|Binary Files (DGI)|*.dat"; - private const int YAPFilterIndex = 1; // Legacy and DGI keep the import table at the end of the primary data, without a yaml + private const string DataFileFilter = "Binary Files (Bundle Manager & YAP)|*.dat|Binary Files (Legacy BM & bnd2-manager)|*.bin;*.dat|Binary Files (DGI)|*.dat"; + private const int YAPFilterIndex = 1; // Legacy and DGI keep the import table at the end of the primary data, without a yaml - private delegate BundleEntry GetEntry(); - private delegate void SetEntry(BundleEntry entry); + private delegate BundleEntry GetEntry(); + private delegate void SetEntry(BundleEntry entry); - private BundleEntry _entry; - [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] - public BundleEntry Entry + private BundleEntry _entry; + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public BundleEntry Entry + { + get { - get + if (InvokeRequired) { - if (InvokeRequired) - { - GetEntry method = () => - { - return _entry; - }; - return (BundleEntry)Invoke(method); - } - else + GetEntry method = () => { return _entry; - } + }; + return (BundleEntry)Invoke(method); } - set + else { - if (InvokeRequired) - { - SetEntry method = (BundleEntry entry) => - { - _entry = entry; - Task.Run(() => UpdateDisplay()); - }; - Invoke(method, value); - } - else - { - _entry = value; - UpdateDisplay(); - } + return _entry; } } - - [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] - public bool ForceHex + set { - get; - set; + if (InvokeRequired) + { + SetEntry method = (BundleEntry entry) => + { + _entry = entry; + Task.Run(() => UpdateDisplay()); + }; + Invoke(method, value); + } + else + { + _entry = value; + UpdateDisplay(); + } } + } - public EntryEditor() - { - InitializeComponent(); + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public bool ForceHex + { + get; + set; + } - ImageMenuVisible = false; - BinaryMenuVisible = false; - ImageVisible = false; - ImageStatusPanelVisible = false; - TabsVisible = false; + public EntryEditor() + { + InitializeComponent(); - //txtData.MaxLength = int.MaxValue; - //txtExtraData.MaxLength = int.MaxValue; - } + ImageMenuVisible = false; + BinaryMenuVisible = false; + ImageVisible = false; + ImageStatusPanelVisible = false; + TabsVisible = false; + + //txtData.MaxLength = int.MaxValue; + //txtExtraData.MaxLength = int.MaxValue; + } - private void FocusTab() + private void FocusTab() + { + if (tabList.SelectedTab != null) { - if (tabList.SelectedTab != null) + if (tabList.SelectedTab.Controls.Count > 0) { - if (tabList.SelectedTab.Controls.Count > 0) - { - tabList.SelectedTab.Controls[0].Focus(); - } + tabList.SelectedTab.Controls[0].Focus(); } } + } - private delegate byte[] GetDataHex(); - private delegate void SetDataHex(byte[] hex); - private byte[] DataHex + private delegate byte[] GetDataHex(); + private delegate void SetDataHex(byte[] hex); + private byte[] DataHex + { + get { - get + if (hexData.InvokeRequired) { - if (hexData.InvokeRequired) - { - GetDataHex method = () => - { - return hexData.HexData; - }; - return (byte[])Invoke(method); - } - else + GetDataHex method = () => { return hexData.HexData; - } + }; + return (byte[])Invoke(method); } - set + else { - if (hexData.InvokeRequired) - { - SetDataHex method = (byte[] hex) => - { - hexData.HexData = hex; - }; - Invoke(method, value); - } - else + return hexData.HexData; + } + } + set + { + if (hexData.InvokeRequired) + { + SetDataHex method = (byte[] hex) => { - hexData.HexData = value; - } + hexData.HexData = hex; + }; + Invoke(method, value); + } + else + { + hexData.HexData = value; } } + } - private byte[] ExtraDataHex + private byte[] ExtraDataHex + { + get { - get + if (hexExtraData.InvokeRequired) { - if (hexExtraData.InvokeRequired) - { - GetDataHex method = () => - { - return hexExtraData.HexData; - }; - return (byte[])Invoke(method); - } - else + GetDataHex method = () => { return hexExtraData.HexData; - } + }; + return (byte[])Invoke(method); } - set + else { - if (hexExtraData.InvokeRequired) - { - SetDataHex method = (byte[] hex) => - { - hexExtraData.HexData = hex; - }; - Invoke(method, value); - } - else + return hexExtraData.HexData; + } + } + set + { + if (hexExtraData.InvokeRequired) + { + SetDataHex method = (byte[] hex) => { - hexExtraData.HexData = value; - } + hexExtraData.HexData = hex; + }; + Invoke(method, value); + } + else + { + hexExtraData.HexData = value; } } + } - private delegate Image GetImage(); - private delegate void SetImage(Image img); - private Image Image + private delegate Image GetImage(); + private delegate void SetImage(Image img); + private Image Image + { + get { - get + if (pboImage.InvokeRequired) { - if (pboImage.InvokeRequired) - { - GetImage method = () => - { - return pboImage.Image; - }; - return (Image)Invoke(method); - } - else + GetImage method = () => { return pboImage.Image; - } + }; + return (Image)Invoke(method); } - set + else { - if (pboImage.InvokeRequired) - { - SetImage method = (Image img) => - { - pboImage.Image = img; - }; - Invoke(method, value); - } - else + return pboImage.Image; + } + } + set + { + if (pboImage.InvokeRequired) + { + SetImage method = (Image img) => { - pboImage.Image = value; - } + pboImage.Image = img; + }; + Invoke(method, value); + } + else + { + pboImage.Image = value; } } + } - private delegate bool GetBool(); - private delegate void SetBool(bool visible); - private delegate string GetString(); - private delegate void SetString(string text); - private delegate TabControl.TabPageCollection GetTabPages(); - private delegate TabControl GetTabControl(); - private delegate TabPage GetTabPage(); - private bool ImageVisible + private delegate bool GetBool(); + private delegate void SetBool(bool visible); + private delegate string GetString(); + private delegate void SetString(string text); + private delegate TabControl.TabPageCollection GetTabPages(); + private delegate TabControl GetTabControl(); + private delegate TabPage GetTabPage(); + private bool ImageVisible + { + get { - get + if (pboImage.InvokeRequired) { - if (pboImage.InvokeRequired) - { - GetBool method = () => - { - return pboImage.Visible; - }; - return (bool)Invoke(method); - } - else + GetBool method = () => { return pboImage.Visible; - } + }; + return (bool)Invoke(method); } - set + else { - if (pboImage.InvokeRequired) - { - SetBool method = (bool visible) => - { - pboImage.Visible = visible; - }; - Invoke(method, value); - } - else + return pboImage.Visible; + } + } + set + { + if (pboImage.InvokeRequired) + { + SetBool method = (bool visible) => { - pboImage.Visible = value; - } + pboImage.Visible = visible; + }; + Invoke(method, value); + } + else + { + pboImage.Visible = value; } } + } - private delegate void SetTitleText(string val); - private string Title + private delegate void SetTitleText(string val); + private string Title + { + set { - set + if (InvokeRequired) { - if (InvokeRequired) + SetTitleText method = (string val) => { - SetTitleText method = (string val) => - { - Text = val; - }; - Invoke(method, value); - } - else - { - Text = value; - } + Text = val; + }; + Invoke(method, value); + } + else + { + Text = value; } } + } - private bool TabsVisible + private bool TabsVisible + { + get { - get + if (tabList.InvokeRequired) { - if (tabList.InvokeRequired) - { - GetBool method = () => - { - return tabList.Visible; - }; - return (bool)Invoke(method); - } - else + GetBool method = () => { return tabList.Visible; - } + }; + return (bool)Invoke(method); } - set + else { - if (tabList.InvokeRequired) - { - SetBool method = (bool visible) => - { - tabList.Visible = visible; - }; - Invoke(method, value); - } - else + return tabList.Visible; + } + } + set + { + if (tabList.InvokeRequired) + { + SetBool method = (bool visible) => { - tabList.Visible = value; - } + tabList.Visible = visible; + }; + Invoke(method, value); + } + else + { + tabList.Visible = value; } } + } - private bool ImageStatusPanelVisible + private bool ImageStatusPanelVisible + { + get { - get + if (mnuBar.InvokeRequired) { - if (mnuBar.InvokeRequired) - { - GetBool method = () => - { - return imageStatusLabel.Visible; - }; - return (bool)Invoke(method); - } - else + GetBool method = () => { return imageStatusLabel.Visible; - } + }; + return (bool)Invoke(method); } - set + else { - if (mnuBar.InvokeRequired) - { - SetBool method = (bool enabled) => - { - imageStatusLabel.Visible = enabled; - }; - Invoke(method, value); - } - else + return imageStatusLabel.Visible; + } + } + set + { + if (mnuBar.InvokeRequired) + { + SetBool method = (bool enabled) => { - imageStatusLabel.Visible = value; - } + imageStatusLabel.Visible = enabled; + }; + Invoke(method, value); + } + else + { + imageStatusLabel.Visible = value; } } + } - private bool ImageMenuVisible + private bool ImageMenuVisible + { + get { - get + if (mnuBar.InvokeRequired) { - if (mnuBar.InvokeRequired) - { - GetBool method = () => - { - return imageToolStripMenuItem.Visible; - }; - return (bool)Invoke(method); - } - else + GetBool method = () => { return imageToolStripMenuItem.Visible; - } + }; + return (bool)Invoke(method); } - set + else { - if (mnuBar.InvokeRequired) - { - SetBool method = (bool enabled) => - { - imageToolStripMenuItem.Visible = enabled; - }; - Invoke(method, value); - } - else + return imageToolStripMenuItem.Visible; + } + } + set + { + if (mnuBar.InvokeRequired) + { + SetBool method = (bool enabled) => { - imageToolStripMenuItem.Visible = value; - } + imageToolStripMenuItem.Visible = enabled; + }; + Invoke(method, value); + } + else + { + imageToolStripMenuItem.Visible = value; } } + } - private bool BinaryMenuVisible + private bool BinaryMenuVisible + { + get { - get + if (mnuBar.InvokeRequired) { - if (mnuBar.InvokeRequired) + GetBool method = () => { - GetBool method = () => - { - return binaryToolStripMenuItem.Visible; - }; - return (bool)Invoke(method); - } - else - { - return mnuBar.Visible; - } + return binaryToolStripMenuItem.Visible; + }; + return (bool)Invoke(method); } - set + else { - if (mnuBar.InvokeRequired) - { - SetBool method = (bool visible) => - { - binaryToolStripMenuItem.Visible = visible; - }; - Invoke(method, value); - } - else + return mnuBar.Visible; + } + } + set + { + if (mnuBar.InvokeRequired) + { + SetBool method = (bool visible) => { - mnuBar.Visible = value; - } + binaryToolStripMenuItem.Visible = visible; + }; + Invoke(method, value); + } + else + { + mnuBar.Visible = value; } } + } - private bool MenuVisible + private bool MenuVisible + { + get { - get + if (mnuBar.InvokeRequired) { - if (mnuBar.InvokeRequired) - { - GetBool method = () => - { - return mnuBar.Visible; - }; - return (bool)Invoke(method); - } - else + GetBool method = () => { return mnuBar.Visible; - } + }; + return (bool)Invoke(method); } - set + else { - if (mnuBar.InvokeRequired) - { - SetBool method = (bool visible) => - { - mnuBar.Visible = visible; - }; - Invoke(method, value); - } - else - { - mnuBar.Visible = value; - } + return mnuBar.Visible; } } - - private string InfoText + set { - get + if (mnuBar.InvokeRequired) { - if (mnuBar.InvokeRequired) - { - GetString method = () => - { - return txtInfo.Text; - }; - return (string)Invoke(method); - } - else + SetBool method = (bool visible) => { - return txtInfo.Text; - } + mnuBar.Visible = visible; + }; + Invoke(method, value); } - set + else { - if (mnuBar.InvokeRequired) - { - SetString method = (string text) => - { - txtInfo.Text = text; - }; - Invoke(method, value); - } - else - { - txtInfo.Text = value; - } + mnuBar.Visible = value; } } + } - private string GetInfo() + private string InfoText + { + get { - StringBuilder sb = new StringBuilder(); - - sb.AppendLine("ID: 0x" + _entry.ID.ToString("X8")); - sb.AppendLine("Type: " + _entry.Type); - sb.AppendLine("Has Header: " + _entry.HasHeader); - sb.AppendLine("Has Body: " + _entry.HasBody); - List dependencies = _entry.GetDependencies(); - if (dependencies.Count > 0) + if (mnuBar.InvokeRequired) { - sb.AppendLine("Dependencies[" + dependencies.Count + "] = {"); - for (int i = 0; i < dependencies.Count; i++) + GetString method = () => { - BundleDependency bundleDependency = dependencies[i]; - sb.AppendLine(" " + bundleDependency.ToString()); - } - sb.AppendLine("}"); + return txtInfo.Text; + }; + return (string)Invoke(method); } else { - sb.AppendLine("Dependencies[" + dependencies.Count + "];"); + return txtInfo.Text; } - - return sb.ToString(); } - - private void UpdateDisplay() + set { - Title = "Edit Entry: " + _entry.Index.ToString("d3"); - - if (ForceHex) + if (mnuBar.InvokeRequired) { - ImageVisible = false; + SetString method = (string text) => + { + txtInfo.Text = text; + }; + Invoke(method, value); } - else if (_entry.Type == EntryType.Texture) + else { - Image = GameImage.GetImage(_entry.EntryBlocks[0].Data, _entry.EntryBlocks[1].Data); - - ImageVisible = Image != null; - + txtInfo.Text = value; } - TabsVisible = !ImageVisible; - ImageMenuVisible = ImageVisible; - ImageStatusPanelVisible = ImageVisible; - BinaryMenuVisible = TabsVisible; + } + } - if (ImageStatusPanelVisible) - { - ImageHeader header = GameImage.GetImageHeader(_entry.EntryBlocks[0].Data); - imageStatusLabel.Text = - $"Platform: {header.Platform} " + - $"Size: {header.Width}x{header.Height} " + - $"Format: {header.CompressionType}"; - } + private string GetInfo() + { + StringBuilder sb = new(); - if (TabsVisible) + sb.AppendLine("ID: 0x" + _entry.ID.ToString("X8")); + sb.AppendLine("Type: " + _entry.Type); + sb.AppendLine("Has Header: " + _entry.HasHeader); + sb.AppendLine("Has Body: " + _entry.HasBody); + List dependencies = _entry.GetDependencies(); + if (dependencies.Count > 0) + { + sb.AppendLine("Dependencies[" + dependencies.Count + "] = {"); + for (int i = 0; i < dependencies.Count; i++) { - DataHex = _entry.EntryBlocks[0].Data; - ExtraDataHex = _entry.EntryBlocks[_entry.SecondaryBlock].Data; + BundleDependency bundleDependency = dependencies[i]; + sb.AppendLine(" " + bundleDependency.ToString()); } + sb.AppendLine("}"); + } + else + { + sb.AppendLine("Dependencies[" + dependencies.Count + "];"); + } - MenuVisible = true; + return sb.ToString(); + } - InfoText = GetInfo(); - } + private void UpdateDisplay() + { + Title = "Edit Entry: " + _entry.Index.ToString("d3"); - private void exportToolStripMenuItem_Click(object sender, EventArgs e) + if (ForceHex) { - SaveFileDialog sfd = new SaveFileDialog(); - sfd.Filter = "PNG Images|*.png"; - sfd.FileOk += Sfd_FileOk; - sfd.ShowDialog(this); + ImageVisible = false; } - - private void Sfd_FileOk(object sender, CancelEventArgs e) + else if (_entry.Type == EntryType.Texture) { - SaveFileDialog sfd = (SaveFileDialog)sender; + Image = GameImage.GetImage(_entry.EntryBlocks[0].Data, _entry.EntryBlocks[1].Data); - if (sfd.FileName == null || sfd.FileName.Length <= 0) - return; - - string path = sfd.FileName; + ImageVisible = Image != null; - Image.Save(path, ImageFormat.Png); } + TabsVisible = !ImageVisible; + ImageMenuVisible = ImageVisible; + ImageStatusPanelVisible = ImageVisible; + BinaryMenuVisible = TabsVisible; - private async void importToolStripMenuItem_Click(object sender, EventArgs e) + if (ImageStatusPanelVisible) { - using OpenFileDialog ofd = new() { Filter = GameImage.FileFilter + "|All files (*.*)|*.*" }; - if (ofd.ShowDialog(this) != DialogResult.OK) - return; + ImageHeader header = GameImage.GetImageHeader(_entry.EntryBlocks[0].Data); + imageStatusLabel.Text = + $"Platform: {header.Platform} " + + $"Size: {header.Width}x{header.Height} " + + $"Format: {header.CompressionType}"; + } - string path = ofd.FileName; - byte[] oldHeader = _entry.EntryBlocks[0].Data; - ImageInfo info; - try - { - ImageHeader header = GameImage.GetImageHeader(oldHeader); - CompressionType? compression = null; // DDS files keep their own format - if (!string.Equals(Path.GetExtension(path), ".dds", StringComparison.OrdinalIgnoreCase) - && (compression = ImageImportDialog.AskCompression(this, path)) == null) - return; + if (TabsVisible) + { + DataHex = _entry.EntryBlocks[0].Data; + ExtraDataHex = _entry.EntryBlocks[_entry.SecondaryBlock].Data; + } - info = await Task.Run(() => GameImage.SetImage(path, compression ?? header.CompressionType, header.Platform, oldHeader)); - } - catch (Exception ex) - { - MessageBox.Show(this, $"Unable to import {path}: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - return; - } + MenuVisible = true; - _entry.Dirty = true; - _entry.EntryBlocks[0].Data = info.Header; - _entry.EntryBlocks[1].Data = info.Data; + InfoText = GetInfo(); + } - ImageVisible = false; - TabsVisible = false; - ImageMenuVisible = false; - BinaryMenuVisible = false; - Task.Run(() => UpdateDisplay()); - } + private void exportToolStripMenuItem_Click(object sender, EventArgs e) + { + SaveFileDialog sfd = new(); + sfd.Filter = "PNG Images|*.png"; + sfd.FileOk += Sfd_FileOk; + sfd.ShowDialog(this); + } - private void importDataToolStripMenuItem_Click(object sender, EventArgs e) - { - using OpenFileDialog ofd = new() - { - FileName = ExportNames(secondary: false)[0], - DefaultExt = "dat", - Filter = DataFileFilter - }; + private void Sfd_FileOk(object sender, CancelEventArgs e) + { + SaveFileDialog sfd = (SaveFileDialog)sender; - if (ofd.ShowDialog(this) == DialogResult.OK) - ImportPrimary(ofd.FileName); - } + if (sfd.FileName == null || sfd.FileName.Length <= 0) + return; - private void ImportPrimary(string path) - { - byte[] data = ResourceImport.ReadPrimary(path, Entry.Console, out List imports); + string path = sfd.FileName; - if (imports == null) - { - List current = Entry.GetDependencies().Select(d => new Dependency { ID = d.EntryID, EntryPointerOffset = (uint)d.EntryPointerOffset }).ToList(); - if (current.Count > 0 && Dependency.EndsWithTable(data, current, Entry.Console)) - { - imports = current; - } - else - { - List found = ResourceImport.ScanImports(data, Entry.Platform); - imports = found.Count == 0 && current.Count == 0 ? [] : AskImports(found, current); - if (imports == null) - return; - } - data = Dependency.AppendTable(data, imports, Entry.Console); - } + Image.Save(path, ImageFormat.Png); + } - Entry.EntryBlocks[0].Data = data; - Entry.Dependencies.Clear(); // A BND1 import list would hide the table - Entry.DependencyCount = (short)imports.Count; - Entry.DependenciesListOffset = imports.Count > 0 ? data.Length - imports.Count * Dependency.Size : 0; - Entry.Dirty = true; + private async void importToolStripMenuItem_Click(object sender, EventArgs e) + { + using OpenFileDialog ofd = new() { Filter = GameImage.FileFilter + "|All files (*.*)|*.*" }; + if (ofd.ShowDialog(this) != DialogResult.OK) + return; + + string path = ofd.FileName; + byte[] oldHeader = _entry.EntryBlocks[0].Data; + ImageInfo info; + try + { + ImageHeader header = GameImage.GetImageHeader(oldHeader); + CompressionType? compression = null; // DDS files keep their own format + if (!string.Equals(Path.GetExtension(path), ".dds", StringComparison.OrdinalIgnoreCase) + && (compression = ImageImportDialog.AskCompression(this, path)) == null) + return; - Task.Run(() => UpdateDisplay()); + info = await Task.Run(() => GameImage.SetImage(path, compression ?? header.CompressionType, header.Platform, oldHeader)); } + catch (Exception ex) + { + MessageBox.Show(this, $"Unable to import {path}: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + _entry.Dirty = true; + _entry.EntryBlocks[0].Data = info.Header; + _entry.EntryBlocks[1].Data = info.Data; - private List AskImports(List found, List current) + ImageVisible = false; + TabsVisible = false; + ImageMenuVisible = false; + BinaryMenuVisible = false; + Task.Run(() => UpdateDisplay()); + } + + private void importDataToolStripMenuItem_Click(object sender, EventArgs e) + { + using OpenFileDialog ofd = new() { - static string Imports(int count) => count == 1 ? "1 import" : $"{count} imports"; + FileName = ExportNames(secondary: false)[0], + DefaultExt = "dat", + Filter = DataFileFilter + }; - TaskDialogCommandLinkButton useFound = new($"Use the {Imports(found.Count)} at the end of the file", "The file ends with its own import table."); - TaskDialogCommandLinkButton keep = new($"Keep the resource's {Imports(current.Count)}", "The file is the resource without its import table."); - TaskDialogCommandLinkButton none = new("No imports", "The new resource doesn't import anything."); + if (ofd.ShowDialog(this) == DialogResult.OK) + ImportPrimary(ofd.FileName); + } - TaskDialogPage page = new() - { - Caption = "Import Data", - Heading = found.Count > 0 - ? $"This file seems to end with {Imports(found.Count)}" - : $"This file doesn't end with the resource's {Imports(current.Count)}", - Text = "There's no _imports.yaml next to it to say which imports it has.", - Icon = TaskDialogIcon.Warning, - AllowCancel = true - }; + private void ImportPrimary(string path) + { + byte[] data = ResourceImport.ReadPrimary(path, Entry.Console, out List imports); - if (found.Count > 0) + if (imports == null) + { + List current = [.. Entry.GetDependencies().Select(d => new Dependency { ID = d.EntryID, EntryPointerOffset = (uint)d.EntryPointerOffset })]; + if (current.Count > 0 && Dependency.EndsWithTable(data, current, Entry.Console)) { - page.Buttons.Add(useFound); - page.Expander = new TaskDialogExpander(string.Join("\n", found.Select(d => - $"0x{d.EntryPointerOffset:X8} -> {d.ID:X8}" + (Entry.Archive.GetEntryByID(d.ID) is BundleEntry target ? $" ({target.Type} in this bundle)" : "")))) - { - CollapsedButtonText = "Show imports", - ExpandedButtonText = "Hide imports" - }; + imports = current; } - if (current.Count > 0) - page.Buttons.Add(keep); - page.Buttons.Add(none); - page.Buttons.Add(TaskDialogButton.Cancel); - - TaskDialogButton result = TaskDialog.ShowDialog(this, page); - return result == useFound ? found : result == keep ? current : result == none ? [] : null; + else + { + List found = ResourceImport.ScanImports(data, Entry.Platform); + imports = found.Count == 0 && current.Count == 0 ? [] : AskImports(found, current); + if (imports == null) + return; + } + data = Dependency.AppendTable(data, imports, Entry.Console); } - private void exportDataToolStripMenuItem_Click(object sender, EventArgs e) - { - string[] names = ExportNames(secondary: false); + Entry.EntryBlocks[0].Data = data; + Entry.Dependencies.Clear(); // A BND1 import list would hide the table + Entry.DependencyCount = (short)imports.Count; + Entry.DependenciesListOffset = imports.Count > 0 ? data.Length - imports.Count * Dependency.Size : 0; + Entry.Dirty = true; - // The native dialog so the name can follow the type - string path = NativeSaveDialog.Show(this, names[0], "dat", DataFileFilter, - (type, name) => NameForType(type, name, names), out int typeIndex); - if (path == null) - return; + Task.Run(() => UpdateDisplay()); + } - if (typeIndex == YAPFilterIndex) - ResourceImport.WritePrimary(path, Entry); - else - ResourceImport.WritePrimaryWithTable(path, Entry); - } + private List AskImports(List found, List current) + { + static string Imports(int count) => count == 1 ? "1 import" : $"{count} imports"; + + TaskDialogCommandLinkButton useFound = new($"Use the {Imports(found.Count)} at the end of the file", "The file ends with its own import table."); + TaskDialogCommandLinkButton keep = new($"Keep the resource's {Imports(current.Count)}", "The file is the resource without its import table."); + TaskDialogCommandLinkButton none = new("No imports", "The new resource doesn't import anything."); - private string[] ExportNames(bool secondary) + TaskDialogPage page = new() { - string id = _entry.ID.ToString("X8"); - byte[] bytes = BitConverter.GetBytes((uint)_entry.ID); - if (_entry.Console) - Array.Reverse(bytes); - string dgi = string.Join("_", bytes.Select(b => b.ToString("X2"))); + Caption = "Import Data", + Heading = found.Count > 0 + ? $"This file seems to end with {Imports(found.Count)}" + : $"This file doesn't end with the resource's {Imports(current.Count)}", + Text = "There's no _imports.yaml next to it to say which imports it has.", + Icon = TaskDialogIcon.Warning, + AllowCancel = true + }; - if (secondary) + if (found.Count > 0) + { + page.Buttons.Add(useFound); + page.Expander = new TaskDialogExpander(string.Join("\n", found.Select(d => + $"0x{d.EntryPointerOffset:X8} -> {d.ID:X8}" + (Entry.Archive.GetEntryByID(d.ID) is BundleEntry target ? $" ({target.Type} in this bundle)" : "")))) { - string dgiSuffix = _entry.Type switch - { - EntryType.Texture => "_texture", - EntryType.Renderable => "_model", - _ => "_secondary" - }; - return [$"{id}_secondary", $"{id}_secondary", dgi + dgiSuffix]; - } - - bool hasSecondary = _entry.HasSection(1) || _entry.HasSection(2); - return [hasSecondary ? $"{id}_primary" : id, id, dgi]; + CollapsedButtonText = "Show imports", + ExpandedButtonText = "Hide imports" + }; } + if (current.Count > 0) + page.Buttons.Add(keep); + page.Buttons.Add(none); + page.Buttons.Add(TaskDialogButton.Cancel); - // Swaps only the default names, keeping any extension in the box - private static string NameForType(int type, string name, string[] names) - { - string extension = Path.GetExtension(name); - string stem = name[..^extension.Length]; - return (names.Contains(stem) ? names[type - 1] : stem) + extension; - } + TaskDialogButton result = TaskDialog.ShowDialog(this, page); + return result == useFound ? found : result == keep ? current : result == none ? [] : null; + } + + private void exportDataToolStripMenuItem_Click(object sender, EventArgs e) + { + string[] names = ExportNames(secondary: false); + + // The native dialog so the name can follow the type + string path = NativeSaveDialog.Show(this, names[0], "dat", DataFileFilter, + (type, name) => NameForType(type, name, names), out int typeIndex); + if (path == null) + return; + + if (typeIndex == YAPFilterIndex) + ResourceImport.WritePrimary(path, Entry); + else + ResourceImport.WritePrimaryWithTable(path, Entry); + } + + private string[] ExportNames(bool secondary) + { + string id = _entry.ID.ToString("X8"); + byte[] bytes = BitConverter.GetBytes((uint)_entry.ID); + if (_entry.Console) + Array.Reverse(bytes); + string dgi = string.Join("_", bytes.Select(b => b.ToString("X2"))); - private void importExtraToolStripMenuItem_Click(object sender, EventArgs e) + if (secondary) { - OpenFileDialog ofd = new OpenFileDialog(); - ofd.FileName = $"{_entry.ID.ToString("X8")}_secondary"; - ofd.DefaultExt = "dat"; - ofd.Filter = DataFileFilter; - ofd.FileOk += Ofd_FileOk2; - ofd.ShowDialog(this); + string dgiSuffix = _entry.Type switch + { + EntryType.Texture => "_texture", + EntryType.Renderable => "_model", + _ => "_secondary" + }; + return [$"{id}_secondary", $"{id}_secondary", dgi + dgiSuffix]; } - private void Ofd_FileOk2(object sender, CancelEventArgs e) - { - OpenFileDialog ofd = (OpenFileDialog)sender; + bool hasSecondary = _entry.HasSection(1) || _entry.HasSection(2); + return [hasSecondary ? $"{id}_primary" : id, id, dgi]; + } - if (ofd.FileName == null || ofd.FileName.Length <= 0 || !File.Exists(ofd.FileName)) - return; + // Swaps only the default names, keeping any extension in the box + private static string NameForType(int type, string name, string[] names) + { + string extension = Path.GetExtension(name); + string stem = name[..^extension.Length]; + return (names.Contains(stem) ? names[type - 1] : stem) + extension; + } - Stream s = ofd.OpenFile(); - MemoryStream ms = new MemoryStream(); - s.CopyTo(ms); - s.Close(); - byte[] data = ms.ToArray(); - ms.Close(); + private void importExtraToolStripMenuItem_Click(object sender, EventArgs e) + { + OpenFileDialog ofd = new(); + ofd.FileName = $"{_entry.ID.ToString("X8")}_secondary"; + ofd.DefaultExt = "dat"; + ofd.Filter = DataFileFilter; + ofd.FileOk += Ofd_FileOk2; + ofd.ShowDialog(this); + } - Entry.EntryBlocks[Entry.SecondaryBlock].Data = data; - Entry.Dirty = true; + private void Ofd_FileOk2(object sender, CancelEventArgs e) + { + OpenFileDialog ofd = (OpenFileDialog)sender; - Task.Run(() => UpdateDisplay()); - } + if (ofd.FileName == null || ofd.FileName.Length <= 0 || !File.Exists(ofd.FileName)) + return; - private void exportExtraToolStripMenuItem_Click(object sender, EventArgs e) - { - string[] names = ExportNames(secondary: true); + Stream s = ofd.OpenFile(); + MemoryStream ms = new(); + s.CopyTo(ms); + s.Close(); + byte[] data = ms.ToArray(); + ms.Close(); - string path = NativeSaveDialog.Show(this, names[0], "dat", DataFileFilter, - (type, name) => NameForType(type, name, names), out _); - if (path != null) - File.WriteAllBytes(path, Entry.EntryBlocks[Entry.SecondaryBlock].Data); - } + Entry.EntryBlocks[Entry.SecondaryBlock].Data = data; + Entry.Dirty = true; - private void editId_Click(object sender, EventArgs e) - { - string value = InputDialog.ShowInput(this, "Please enter the value to hash."); - if (value == null) - return; - ulong result = Crc32.HashCrc32B(value.ToLower()); - _entry.Dirty = true; - Entry.ID = result; - Task.Run(() => UpdateDisplay()); - MessageBox.Show(this, "The new hashed value is: " + result.ToString("X8"), "Information", MessageBoxButtons.OK, MessageBoxIcon.Information); - } + Task.Run(() => UpdateDisplay()); + } - private void calcLookup8_Click(object sender, EventArgs e) - { - string value = InputDialog.ShowInput(this, "Please enter the value to get the lookup 8."); - if (value == null) - return; - ulong result = Utilities.CalcLookup8(value); - Task.Run(() => UpdateDisplay()); - MessageBox.Show(this, "The lookup 8 hashed value is: " + result.ToString("X16"), "Information", MessageBoxButtons.OK, MessageBoxIcon.Information); - } + private void exportExtraToolStripMenuItem_Click(object sender, EventArgs e) + { + string[] names = ExportNames(secondary: true); - protected override void OnMouseWheel(MouseEventArgs e) - { - base.OnMouseWheel(e); - FocusTab(); - } + string path = NativeSaveDialog.Show(this, names[0], "dat", DataFileFilter, + (type, name) => NameForType(type, name, names), out _); + if (path != null) + File.WriteAllBytes(path, Entry.EntryBlocks[Entry.SecondaryBlock].Data); + } - private void tabList_SelectedIndexChanged(object sender, EventArgs e) - { - FocusTab(); - } + private void editId_Click(object sender, EventArgs e) + { + string value = InputDialog.ShowInput(this, "Please enter the value to hash."); + if (value == null) + return; + ulong result = Crc32.HashCrc32B(value.ToLower()); + _entry.Dirty = true; + Entry.ID = result; + Task.Run(() => UpdateDisplay()); + MessageBox.Show(this, "The new hashed value is: " + result.ToString("X8"), "Information", MessageBoxButtons.OK, MessageBoxIcon.Information); + } - private void EntryEditor_Shown(object sender, EventArgs e) - { - FocusTab(); - } + private void calcLookup8_Click(object sender, EventArgs e) + { + string value = InputDialog.ShowInput(this, "Please enter the value to get the lookup 8."); + if (value == null) + return; + ulong result = Utilities.CalcLookup8(value); + Task.Run(() => UpdateDisplay()); + MessageBox.Show(this, "The lookup 8 hashed value is: " + result.ToString("X16"), "Information", MessageBoxButtons.OK, MessageBoxIcon.Information); + } - private struct Vertex - { - public float X, Y, Z; - } + protected override void OnMouseWheel(MouseEventArgs e) + { + base.OnMouseWheel(e); + FocusTab(); + } - private void infoToolStripMenuItem_Click(object sender, EventArgs e) - { - if (Entry.Type != EntryType.Renderable) - return; + private void tabList_SelectedIndexChanged(object sender, EventArgs e) + { + FocusTab(); + } - string modelInfo = ""; + private void EntryEditor_Shown(object sender, EventArgs e) + { + FocusTab(); + } - byte[] header = Entry.EntryBlocks[0].Data; + private struct Vertex + { + public float X, Y, Z; + } - MemoryStream ms = new MemoryStream(header); - BinaryReader2 br = new BinaryReader2(ms); - br.BigEndian = Entry.Console; + private void infoToolStripMenuItem_Click(object sender, EventArgs e) + { + if (Entry.Type != EntryType.Renderable) + return; - br.BaseStream.Position = 0x24; - int offset = br.ReadInt32(); - br.BaseStream.Position = offset; + string modelInfo = ""; - int vertexBlockOff = br.ReadInt32(); - int dummy = br.ReadInt32(); - int vertexBlockSize = br.ReadInt32(); + byte[] header = Entry.EntryBlocks[0].Data; - long paddingCount = 16 - (br.BaseStream.Position % 16); - br.BaseStream.Position += paddingCount; + MemoryStream ms = new(header); + BinaryReader2 br = new(ms); + br.BigEndian = Entry.Console; - long blablaOff = br.BaseStream.Position; + br.BaseStream.Position = 0x24; + int offset = br.ReadInt32(); + br.BaseStream.Position = offset; - br.BaseStream.Position = blablaOff + 0x4C; - int vertexCount = br.ReadInt32(); - br.BaseStream.Position = blablaOff + 0x54; - int polyCount = br.ReadInt32(); - int indexCount = polyCount * 3; + int vertexBlockOff = br.ReadInt32(); + int dummy = br.ReadInt32(); + int vertexBlockSize = br.ReadInt32(); - br.Close(); - ms.Close(); + long paddingCount = 16 - (br.BaseStream.Position % 16); + br.BaseStream.Position += paddingCount; - modelInfo = "Model Info:\n"; - modelInfo += "Vertex Block Offset: " + vertexBlockOff.ToString("X8") + "\n"; - modelInfo += "Vertex Block Size: " + vertexBlockSize.ToString("X8") + "\n"; - modelInfo += "Vertex Count: " + vertexCount.ToString() + "\n"; - modelInfo += "Polygon Count: " + polyCount.ToString() + "\n"; - modelInfo += "Index Count: " + indexCount.ToString() + "\n"; + long blablaOff = br.BaseStream.Position; - MessageBox.Show(this, modelInfo, "DEBUG", MessageBoxButtons.OK, MessageBoxIcon.Error); - } + br.BaseStream.Position = blablaOff + 0x4C; + int vertexCount = br.ReadInt32(); + br.BaseStream.Position = blablaOff + 0x54; + int polyCount = br.ReadInt32(); + int indexCount = polyCount * 3; + + br.Close(); + ms.Close(); + + modelInfo = "Model Info:\n"; + modelInfo += "Vertex Block Offset: " + vertexBlockOff.ToString("X8") + "\n"; + modelInfo += "Vertex Block Size: " + vertexBlockSize.ToString("X8") + "\n"; + modelInfo += "Vertex Count: " + vertexCount.ToString() + "\n"; + modelInfo += "Polygon Count: " + polyCount.ToString() + "\n"; + modelInfo += "Index Count: " + indexCount.ToString() + "\n"; + + MessageBox.Show(this, modelInfo, "DEBUG", MessageBoxButtons.OK, MessageBoxIcon.Error); } } diff --git a/BundleManager/FileView.cs b/BundleManager/FileView.cs index ddb7dec..1f86209 100644 --- a/BundleManager/FileView.cs +++ b/BundleManager/FileView.cs @@ -6,474 +6,473 @@ using BundleFormat; using BundleUtilities; -namespace BundleManager +namespace BundleManager; + +public partial class FileView : Form { - public partial class FileView : Form + private static bool _loadMaterials; + public static bool LoadMaterials { - private static bool _loadMaterials; - public static bool LoadMaterials + get => _loadMaterials; + set { - get => _loadMaterials; - set - { - _loadMaterials = value; - Config.LoadMaterials = _loadMaterials; - } + _loadMaterials = value; + Config.LoadMaterials = _loadMaterials; } + } - private bool AlwaysIgnore => ignoreIDConflictsToolStripMenuItem.CheckState == CheckState.Checked; - private string _currentPath - { - get => BundleCache.CurrentPath; - set => BundleCache.CurrentPath = value; - } + private bool AlwaysIgnore => ignoreIDConflictsToolStripMenuItem.CheckState == CheckState.Checked; + private string _currentPath + { + get => BundleCache.CurrentPath; + set => BundleCache.CurrentPath = value; + } - private bool HasPath => Utilities.IsValidPath(_currentPath); + private bool HasPath => Utilities.IsValidPath(_currentPath); - private Thread _updateDisplayThread; + private Thread _updateDisplayThread; - public FileView() - { - InitializeComponent(); + public FileView() + { + InitializeComponent(); - LoadMaterials = true; + LoadMaterials = true; - UpdateRecentFiles(); - } + UpdateRecentFiles(); + } - private void Clear() - { - _currentPath = null; - BundleCache.Files.Clear(); - BundleCache.Paths.Clear(); - BundleCache.EntryInfos.Clear(); - lstMain.Items.Clear(); - } + private void Clear() + { + _currentPath = null; + BundleCache.Files.Clear(); + BundleCache.Paths.Clear(); + BundleCache.EntryInfos.Clear(); + lstMain.Items.Clear(); + } - private void UpdateRecentFiles() - { - SaveData.Load(); + private void UpdateRecentFiles() + { + SaveData.Load(); - int index = fileToolStripMenuItem.DropDownItems.IndexOf(recentSeparatorToolStripMenu) + 1; + int index = fileToolStripMenuItem.DropDownItems.IndexOf(recentSeparatorToolStripMenu) + 1; - while (true) - { - if (index >= fileToolStripMenuItem.DropDownItems.Count) - break; + while (true) + { + if (index >= fileToolStripMenuItem.DropDownItems.Count) + break; - if (fileToolStripMenuItem.DropDownItems[index] is ToolStripSeparator) - break; + if (fileToolStripMenuItem.DropDownItems[index] is ToolStripSeparator) + break; - fileToolStripMenuItem.DropDownItems.RemoveAt(index); - } + fileToolStripMenuItem.DropDownItems.RemoveAt(index); + } - if (SaveData.RecentPaths.Count == 0) - { - ToolStripItem item = new ToolStripMenuItem("No Recent Items"); - item.Enabled = false; + if (SaveData.RecentPaths.Count == 0) + { + ToolStripItem item = new ToolStripMenuItem("No Recent Items"); + item.Enabled = false; - fileToolStripMenuItem.DropDownItems.Insert(index, item); - } - else + fileToolStripMenuItem.DropDownItems.Insert(index, item); + } + else + { + List paths = SaveData.RecentPaths; + paths.Reverse(); + for (int i = 0; i < paths.Count; i++) { - List paths = SaveData.RecentPaths; - paths.Reverse(); - for (int i = 0; i < paths.Count; i++) - { - string path = paths[i]; + string path = paths[i]; - ToolStripItem item = new ToolStripMenuItem(path); - item.Click += (sender, args) => Open(path); + ToolStripItem item = new ToolStripMenuItem(path); + item.Click += (sender, args) => Open(path); - fileToolStripMenuItem.DropDownItems.Insert(index + i, item); - } + fileToolStripMenuItem.DropDownItems.Insert(index + i, item); } } + } - private void UpdateDisplay() - { - Invoke(new Action(UpdateRecentFiles)); + private void UpdateDisplay() + { + Invoke(new Action(UpdateRecentFiles)); - if (!Utilities.IsValidPath(_currentPath)) - { - BundleCache.Files.Clear(); - BundleCache.Paths.Clear(); - BundleCache.EntryInfos.Clear(); - lstMain.Items.Clear(); - } - lstMain.Enabled = Utilities.IsValidPath(_currentPath); + if (!Utilities.IsValidPath(_currentPath)) + { + BundleCache.Files.Clear(); + BundleCache.Paths.Clear(); + BundleCache.EntryInfos.Clear(); + lstMain.Items.Clear(); + } + lstMain.Enabled = Utilities.IsValidPath(_currentPath); - foreach (string path in BundleCache.Paths) - { - string fixedPath = path.Replace('\\', '/'); - string fixedCurrentPath = _currentPath.Replace('\\', '/'); + foreach (string path in BundleCache.Paths) + { + string fixedPath = path.Replace('\\', '/'); + string fixedCurrentPath = _currentPath.Replace('\\', '/'); - fixedPath = fixedPath.Replace(fixedCurrentPath, ""); + fixedPath = fixedPath.Replace(fixedCurrentPath, ""); - if (fixedPath.StartsWith("/")) - fixedPath = fixedPath.Substring(1); + if (fixedPath.StartsWith("/")) + fixedPath = fixedPath[1..]; - string[] itemData = new string[] - { - fixedPath - }; + string[] itemData = + [ + fixedPath + ]; - lstMain.Items.Add(new ListViewItem(itemData)); - } + lstMain.Items.Add(new ListViewItem(itemData)); } + } - private void LoadFileList() + private void LoadFileList() + { + lstMain.Items.Clear(); + if (HasPath) { - lstMain.Items.Clear(); - if (HasPath) + LoadingDialog loader = new(); + loader.Status = "Loading: " + _currentPath; + loader.Done += (cancelled, value) => { - LoadingDialog loader = new LoadingDialog(); - loader.Status = "Loading: " + _currentPath; - loader.Done += (cancelled, value) => - { - if (cancelled) - { - _updateDisplayThread?.Interrupt(); - _currentPath = null; - } - UpdateDisplay(); - }; - _updateDisplayThread = new Thread(() => + if (cancelled) { - DoLoadFileList(loader); + _updateDisplayThread?.Interrupt(); + _currentPath = null; + } + UpdateDisplay(); + }; + _updateDisplayThread = new Thread(() => + { + DoLoadFileList(loader); - loader.Value = new object[] { _currentPath }; - loader.IsDone = true; - }); - _updateDisplayThread.Start(); - loader.ShowDialog(this); - } + loader.Value = new object[] { _currentPath }; + loader.IsDone = true; + }); + _updateDisplayThread.Start(); + loader.ShowDialog(this); } + } - private struct ConflictChoice - { - public bool Cancel { get; set; } - public bool IgnoreAll { get; set; } + private struct ConflictChoice + { + public bool Cancel { get; set; } + public bool IgnoreAll { get; set; } - public ConflictChoice(bool cancel, bool ignoreAll) - { - Cancel = cancel; - IgnoreAll = ignoreAll; - } + public ConflictChoice(bool cancel, bool ignoreAll) + { + Cancel = cancel; + IgnoreAll = ignoreAll; } + } + + private ConflictChoice ResolveConflict(uint entryID, string file1, string file2) + { + if (AlwaysIgnore) + return new ConflictChoice(false, true); - private ConflictChoice ResolveConflict(uint entryID, string file1, string file2) + return (ConflictChoice)Invoke(new Func(() => { - if (AlwaysIgnore) - return new ConflictChoice(false, true); + TaskDialogCommandLinkButton ignoreOnce = new("Ignore this conflict", "Keep the copy that was found first and continue loading."); + TaskDialogCommandLinkButton ignoreAll = new("Ignore all conflicts", "Don't ask again while loading this folder."); + TaskDialogCommandLinkButton stop = new("Stop loading"); - return (ConflictChoice)Invoke(new Func(() => + TaskDialogPage page = new() { - TaskDialogCommandLinkButton ignoreOnce = new("Ignore this conflict", "Keep the copy that was found first and continue loading."); - TaskDialogCommandLinkButton ignoreAll = new("Ignore all conflicts", "Don't ask again while loading this folder."); - TaskDialogCommandLinkButton stop = new("Stop loading"); - - TaskDialogPage page = new() - { - Caption = "ID Conflict", - Heading = $"Resource 0x{entryID:X8} is in more than one bundle", - Text = $"{file2}\n{file1}\n\nIgnoring this may cause other problems.", - Icon = TaskDialogIcon.Warning, - Buttons = { ignoreOnce, ignoreAll, stop }, - DefaultButton = stop - }; - - TaskDialogButton result = TaskDialog.ShowDialog(this, page); - return new ConflictChoice(result == stop, result == ignoreAll); - })); - } + Caption = "ID Conflict", + Heading = $"Resource 0x{entryID:X8} is in more than one bundle", + Text = $"{file2}\n{file1}\n\nIgnoring this may cause other problems.", + Icon = TaskDialogIcon.Warning, + Buttons = { ignoreOnce, ignoreAll, stop }, + DefaultButton = stop + }; + + TaskDialogButton result = TaskDialog.ShowDialog(this, page); + return new ConflictChoice(result == stop, result == ignoreAll); + })); + } - private void DoLoadFileList(ILoader loader) - { - BundleCache.Files.Clear(); - BundleCache.Paths.Clear(); - BundleCache.EntryInfos.Clear(); - string[] files = Directory.GetFiles(_currentPath, "*.*", SearchOption.AllDirectories); + private void DoLoadFileList(ILoader loader) + { + BundleCache.Files.Clear(); + BundleCache.Paths.Clear(); + BundleCache.EntryInfos.Clear(); + string[] files = Directory.GetFiles(_currentPath, "*.*", SearchOption.AllDirectories); - Dictionary fileTypes = new Dictionary(); + Dictionary fileTypes = []; - string cachePath = _currentPath + "/files.bmcache"; - if (File.Exists(cachePath)) + string cachePath = _currentPath + "/files.bmcache"; + if (File.Exists(cachePath)) + { + string[] lines = File.ReadAllLines(cachePath); + foreach (string line in lines) { - string[] lines = File.ReadAllLines(cachePath); - foreach (string line in lines) - { - string[] data = line.Split('|'); - if (data.Length < 2) - continue; + string[] data = line.Split('|'); + if (data.Length < 2) + continue; - if (File.Exists(data[0])) - fileTypes.Add(data[0], data[1] == "bundle"); - } + if (File.Exists(data[0])) + fileTypes.Add(data[0], data[1] == "bundle"); } + } - int i = 0; - int index = 0; - bool ignoreAllConflicts = false; - foreach (string file in files) + int i = 0; + int index = 0; + bool ignoreAllConflicts = false; + foreach (string file in files) + { + index++; + try { - index++; - try + if (!fileTypes.ContainsKey(file)) { - if (!fileTypes.ContainsKey(file)) - { - bool isBundle = BundleArchive.IsBundle(file); - fileTypes.Add(file, isBundle); + bool isBundle = BundleArchive.IsBundle(file); + fileTypes.Add(file, isBundle); - if (!isBundle) - continue; - } - else if (!fileTypes[file]) - { + if (!isBundle) continue; - } + } + else if (!fileTypes[file]) + { + continue; + } - int progress = index * 100 / files.Length; - loader.SetStatus("Loading(" + progress.ToString("D2") + "%): " + Path.GetFileName(file)); - loader.SetProgress(progress); + int progress = index * 100 / files.Length; + loader.SetStatus("Loading(" + progress.ToString("D2") + "%): " + Path.GetFileName(file)); + loader.SetProgress(progress); - string fixedPath = file.Replace('\\', '/'); - string fixedCurrentPath = _currentPath.Replace('\\', '/'); + string fixedPath = file.Replace('\\', '/'); + string fixedCurrentPath = _currentPath.Replace('\\', '/'); - fixedPath = fixedPath.Replace(fixedCurrentPath, ""); + fixedPath = fixedPath.Replace(fixedCurrentPath, ""); - if (fixedPath.StartsWith("/")) - fixedPath = fixedPath.Substring(1); + if (fixedPath.StartsWith("/")) + fixedPath = fixedPath[1..]; - string[] itemData = new string[] - { - fixedPath - }; + string[] itemData = + [ + fixedPath + ]; - bool cancel = false; + bool cancel = false; - List entryIDs = BundleArchive.GetEntryInfos(file, false); - foreach (EntryInfo info in entryIDs) + List entryIDs = BundleArchive.GetEntryInfos(file, false); + foreach (EntryInfo info in entryIDs) + { + uint entryID = info.ID; + if (BundleCache.Files.ContainsKey(entryID)) { - uint entryID = info.ID; - if (BundleCache.Files.ContainsKey(entryID)) - { - if (ignoreAllConflicts) - continue; - int index1 = BundleCache.Files[entryID]; - string otherFile = BundleCache.Paths[index1]; - ConflictChoice choice = ResolveConflict(entryID, file, otherFile); - if (choice.Cancel) - { - cancel = true; - break; - } - if (choice.IgnoreAll) - ignoreAllConflicts = true; + if (ignoreAllConflicts) continue; + int index1 = BundleCache.Files[entryID]; + string otherFile = BundleCache.Paths[index1]; + ConflictChoice choice = ResolveConflict(entryID, file, otherFile); + if (choice.Cancel) + { + cancel = true; + break; } - if (!BundleCache.EntryInfos.ContainsKey(entryID)) - BundleCache.EntryInfos.Add(entryID, info); - BundleCache.Files.Add(entryID, i); - } - - if (cancel) - { - BundleCache.Files.Clear(); - BundleCache.Paths.Clear(); - BundleCache.EntryInfos.Clear(); - lstMain.Items.Clear(); - break; + if (choice.IgnoreAll) + ignoreAllConflicts = true; + continue; } - - BundleCache.Paths.Add(file); + if (!BundleCache.EntryInfos.ContainsKey(entryID)) + BundleCache.EntryInfos.Add(entryID, info); + BundleCache.Files.Add(entryID, i); } - catch (ThreadAbortException) + + if (cancel) { BundleCache.Files.Clear(); BundleCache.Paths.Clear(); BundleCache.EntryInfos.Clear(); - - _currentPath = null; + lstMain.Items.Clear(); break; } - i++; + BundleCache.Paths.Add(file); } - - try + catch (ThreadAbortException) { - Stream s = File.Open(cachePath, FileMode.Create, FileAccess.Write); - StreamWriter sw = new StreamWriter(s); - - foreach (string key in fileTypes.Keys) - sw.WriteLine(key + "|" + (fileTypes[key] ? "bundle" : "other")); + BundleCache.Files.Clear(); + BundleCache.Paths.Clear(); + BundleCache.EntryInfos.Clear(); - sw.Flush(); - sw.Close(); - s.Close(); - } - catch (IOException ex) - { - Invoke(new Action(() => MessageBox.Show(this, "Failed to cache file types:\n" + ex.Message + "\n" + ex.StackTrace))); + _currentPath = null; + break; } + + i++; } - public void Open(string path = "") + try { - if (string.IsNullOrEmpty(path)) - { - FolderBrowserDialog fbd = new FolderBrowserDialog(); - SaveData.Load(); - if (SaveData.RecentPaths.Count > 0) - fbd.SelectedPath = SaveData.RecentPaths[SaveData.RecentPaths.Count - 1]; - DialogResult result = fbd.ShowDialog(this); - if (result == DialogResult.OK) - { - _currentPath = fbd.SelectedPath; - SaveData.AddRecentPath(_currentPath); - SaveData.Save(); - LoadFileList(); - } - } - else + Stream s = File.Open(cachePath, FileMode.Create, FileAccess.Write); + StreamWriter sw = new(s); + + foreach (string key in fileTypes.Keys) + sw.WriteLine(key + "|" + (fileTypes[key] ? "bundle" : "other")); + + sw.Flush(); + sw.Close(); + s.Close(); + } + catch (IOException ex) + { + Invoke(new Action(() => MessageBox.Show(this, "Failed to cache file types:\n" + ex.Message + "\n" + ex.StackTrace))); + } + } + + public void Open(string path = "") + { + if (string.IsNullOrEmpty(path)) + { + FolderBrowserDialog fbd = new(); + SaveData.Load(); + if (SaveData.RecentPaths.Count > 0) + fbd.SelectedPath = SaveData.RecentPaths[^1]; + DialogResult result = fbd.ShowDialog(this); + if (result == DialogResult.OK) { - _currentPath = path; + _currentPath = fbd.SelectedPath; SaveData.AddRecentPath(_currentPath); SaveData.Save(); LoadFileList(); } } - - private void OpenBundle(int index) + else { - string file = BundleCache.Paths[index]; - MainForm form = new MainForm(); - form.SubForm = true; - form.Open(file); - form.ShowDialog(this); + _currentPath = path; + SaveData.AddRecentPath(_currentPath); + SaveData.Save(); + LoadFileList(); } + } - private void Exit() - { - Application.Exit(); - } + private void OpenBundle(int index) + { + string file = BundleCache.Paths[index]; + MainForm form = new(); + form.SubForm = true; + form.Open(file); + form.ShowDialog(this); + } - private void openFolderToolStripMenuItem_Click(object sender, EventArgs e) - { - Open(); - } + private void Exit() + { + Application.Exit(); + } - private void exitToolStripMenuItem_Click(object sender, EventArgs e) - { - Exit(); - } + private void openFolderToolStripMenuItem_Click(object sender, EventArgs e) + { + Open(); + } - private void tsbOpen_Click(object sender, EventArgs e) - { - Open(); - } + private void exitToolStripMenuItem_Click(object sender, EventArgs e) + { + Exit(); + } - private void tsbSwitchMode_Click(object sender, EventArgs e) - { - Clear(); + private void tsbOpen_Click(object sender, EventArgs e) + { + Open(); + } - Hide(); - Program.SavePreferredMode(false); - Program.fileModeForm.Show(); - } + private void tsbSwitchMode_Click(object sender, EventArgs e) + { + Clear(); - private void FileView_FormClosing(object sender, FormClosingEventArgs e) - { - Application.Exit(); - } + Hide(); + Program.SavePreferredMode(false); + Program.fileModeForm.Show(); + } - private void lstMain_DoubleClick(object sender, EventArgs e) - { - if (lstMain.SelectedIndices.Count > 0) - { - OpenBundle(lstMain.SelectedIndices[0]); - } - } + private void FileView_FormClosing(object sender, FormClosingEventArgs e) + { + Application.Exit(); + } - private void ignoreIDConflictsToolStripMenuItem_Click(object sender, EventArgs e) + private void lstMain_DoubleClick(object sender, EventArgs e) + { + if (lstMain.SelectedIndices.Count > 0) { - if (ignoreIDConflictsToolStripMenuItem.CheckState == CheckState.Checked) - ignoreIDConflictsToolStripMenuItem.CheckState = CheckState.Unchecked; - else - ignoreIDConflictsToolStripMenuItem.CheckState = CheckState.Checked; + OpenBundle(lstMain.SelectedIndices[0]); } + } - private void loadMaterialsToolStripMenuItem_Click(object sender, EventArgs e) - { - if (loadMaterialsToolStripMenuItem.CheckState == CheckState.Checked) - loadMaterialsToolStripMenuItem.CheckState = CheckState.Unchecked; - else - loadMaterialsToolStripMenuItem.CheckState = CheckState.Checked; + private void ignoreIDConflictsToolStripMenuItem_Click(object sender, EventArgs e) + { + if (ignoreIDConflictsToolStripMenuItem.CheckState == CheckState.Checked) + ignoreIDConflictsToolStripMenuItem.CheckState = CheckState.Unchecked; + else + ignoreIDConflictsToolStripMenuItem.CheckState = CheckState.Checked; + } - LoadMaterials = loadMaterialsToolStripMenuItem.CheckState == CheckState.Checked; - } + private void loadMaterialsToolStripMenuItem_Click(object sender, EventArgs e) + { + if (loadMaterialsToolStripMenuItem.CheckState == CheckState.Checked) + loadMaterialsToolStripMenuItem.CheckState = CheckState.Unchecked; + else + loadMaterialsToolStripMenuItem.CheckState = CheckState.Checked; - private void dumpInfoToolStripMenuItem_Click(object sender, EventArgs e) - { - if (_currentPath == null) - { - MessageBox.Show("Please load a folder first!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return; - } + LoadMaterials = loadMaterialsToolStripMenuItem.CheckState == CheckState.Checked; + } - SaveFileDialog sfd = new SaveFileDialog(); - sfd.Filter = "Text Files|*.txt|All Files|*.*"; - DialogResult result = sfd.ShowDialog(this); - if (result == DialogResult.OK) - { - string path = sfd.FileName; + private void dumpInfoToolStripMenuItem_Click(object sender, EventArgs e) + { + if (_currentPath == null) + { + MessageBox.Show("Please load a folder first!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } - Stream s = File.Open(path, FileMode.Create, FileAccess.Write); - StreamWriter sw = new StreamWriter(s); + SaveFileDialog sfd = new(); + sfd.Filter = "Text Files|*.txt|All Files|*.*"; + DialogResult result = sfd.ShowDialog(this); + if (result == DialogResult.OK) + { + string path = sfd.FileName; - int maxLength = -1; + Stream s = File.Open(path, FileMode.Create, FileAccess.Write); + StreamWriter sw = new(s); - Array types = Enum.GetValues(typeof(EntryType)); + int maxLength = -1; - foreach (EntryType type in types) - { - int len = type.ToString().Length; + Array types = Enum.GetValues(typeof(EntryType)); - maxLength = Math.Max(len, maxLength); - } + foreach (EntryType type in types) + { + int len = type.ToString().Length; - foreach (uint key in BundleCache.EntryInfos.Keys) - { - EntryInfo info = BundleCache.EntryInfos[key]; + maxLength = Math.Max(len, maxLength); + } - string thePath = info.Path; - string fixedPath = thePath.Replace('\\', '/'); - string fixedCurrentPath = _currentPath.Replace('\\', '/'); + foreach (uint key in BundleCache.EntryInfos.Keys) + { + EntryInfo info = BundleCache.EntryInfos[key]; - fixedPath = fixedPath.Replace(fixedCurrentPath, ""); + string thePath = info.Path; + string fixedPath = thePath.Replace('\\', '/'); + string fixedCurrentPath = _currentPath.Replace('\\', '/'); - if (fixedPath.StartsWith("/")) - fixedPath = fixedPath.Substring(1); + fixedPath = fixedPath.Replace(fixedCurrentPath, ""); - string typeName = info.Type.ToString(); + if (fixedPath.StartsWith("/")) + fixedPath = fixedPath[1..]; - int len = typeName.Length; + string typeName = info.Type.ToString(); - int lenDiff = maxLength - len; + int len = typeName.Length; - string typeString = typeName; + int lenDiff = maxLength - len; - for (int i = 0; i < lenDiff; i++) - typeString += " "; + string typeString = typeName; - sw.WriteLine("0x" + info.ID.ToString("X8") + "\t\t" + typeString + "\t\t" + fixedPath); - } + for (int i = 0; i < lenDiff; i++) + typeString += " "; - sw.Flush(); - sw.Close(); - s.Close(); + sw.WriteLine("0x" + info.ID.ToString("X8") + "\t\t" + typeString + "\t\t" + fixedPath); } + + sw.Flush(); + sw.Close(); + s.Close(); } } } diff --git a/BundleManager/ImageImportDialog.cs b/BundleManager/ImageImportDialog.cs index 42be9bc..1fefe95 100644 --- a/BundleManager/ImageImportDialog.cs +++ b/BundleManager/ImageImportDialog.cs @@ -2,43 +2,42 @@ using System.IO; using System.Windows.Forms; -namespace BundleManager +namespace BundleManager; + +internal static class ImageImportDialog { - internal static class ImageImportDialog + public static CompressionType? AskCompression(IWin32Window owner, string imagePath) { - public static CompressionType? AskCompression(IWin32Window owner, string imagePath) - { - var (width, height, hasAlpha) = GameImage.InspectImage(imagePath); - CompressionType compressed = hasAlpha ? CompressionType.DXT5 : CompressionType.DXT1; - long compressedSize = GameImage.TextureSize(compressed, width, height); - long linearSize = GameImage.TextureSize(CompressionType.BGRA, width, height); - bool compressible = width % 4 == 0 && height % 4 == 0; // GameImage.SetImage refuses other sizes - - TaskDialogCommandLinkButton compressedButton = new("Compressed (recommended)", compressible - ? $"{compressed}{(hasAlpha ? ", keeps the transparency" : "")}. {Size(compressedSize)}." - : "Needs a width and height that are multiples of 4. Resize the image to use it.") - { - Enabled = compressible - }; - TaskDialogCommandLinkButton linear = new("High quality (linear)", - $"Uncompressed, exact colours{(hasAlpha ? " and transparency" : "")}. {Size(linearSize)}, {linearSize / compressedSize}× the size."); + var (width, height, hasAlpha) = GameImage.InspectImage(imagePath); + CompressionType compressed = hasAlpha ? CompressionType.DXT5 : CompressionType.DXT1; + long compressedSize = GameImage.TextureSize(compressed, width, height); + long linearSize = GameImage.TextureSize(CompressionType.BGRA, width, height); + bool compressible = width % 4 == 0 && height % 4 == 0; // GameImage.SetImage refuses other sizes - TaskDialogPage page = new() - { - Caption = "Import Image", - Heading = "How should this texture be stored?", - Text = $"{Path.GetFileName(imagePath)}, {width}×{height}", - Buttons = { compressedButton, linear, TaskDialogButton.Cancel }, - DefaultButton = compressible ? compressedButton : linear, - AllowCancel = true, - Footnote = new TaskDialogFootnote("High quality textures can quickly exhaust the game's memory budget.") { Icon = TaskDialogIcon.Warning } - }; + TaskDialogCommandLinkButton compressedButton = new("Compressed (recommended)", compressible + ? $"{compressed}{(hasAlpha ? ", keeps the transparency" : "")}. {Size(compressedSize)}." + : "Needs a width and height that are multiples of 4. Resize the image to use it.") + { + Enabled = compressible + }; + TaskDialogCommandLinkButton linear = new("High quality (linear)", + $"Uncompressed, exact colours{(hasAlpha ? " and transparency" : "")}. {Size(linearSize)}, {linearSize / compressedSize}× the size."); - TaskDialogButton result = owner == null ? TaskDialog.ShowDialog(page) : TaskDialog.ShowDialog(owner, page); - return result == compressedButton ? compressed : result == linear ? CompressionType.BGRA : null; - } + TaskDialogPage page = new() + { + Caption = "Import Image", + Heading = "How should this texture be stored?", + Text = $"{Path.GetFileName(imagePath)}, {width}×{height}", + Buttons = { compressedButton, linear, TaskDialogButton.Cancel }, + DefaultButton = compressible ? compressedButton : linear, + AllowCancel = true, + Footnote = new TaskDialogFootnote("High quality textures can quickly exhaust the game's memory budget.") { Icon = TaskDialogIcon.Warning } + }; - private static string Size(long bytes) => - bytes >= 1 << 20 ? $"{bytes / (double)(1 << 20):0.#} MB" : $"{bytes / 1024.0:0.#} KB"; + TaskDialogButton result = owner == null ? TaskDialog.ShowDialog(page) : TaskDialog.ShowDialog(owner, page); + return result == compressedButton ? compressed : result == linear ? CompressionType.BGRA : null; } + + private static string Size(long bytes) => + bytes >= 1 << 20 ? $"{bytes / (double)(1 << 20):0.#} MB" : $"{bytes / 1024.0:0.#} KB"; } diff --git a/BundleManager/ImportResourceForm.cs b/BundleManager/ImportResourceForm.cs index 5eb61e6..99243f5 100644 --- a/BundleManager/ImportResourceForm.cs +++ b/BundleManager/ImportResourceForm.cs @@ -6,294 +6,293 @@ using System.Linq; using System.Windows.Forms; -namespace BundleManager +namespace BundleManager; + +public partial class ImportResourceForm : Form { - public partial class ImportResourceForm : Form - { - private const string ResourceNamePrefix = "bundlemanager://"; + private const string ResourceNamePrefix = "bundlemanager://"; - private const string BinaryFilter = "Binary Files|*.dat;*.bin|All files (*.*)|*.*"; - private const string PrimaryFileFilter = "Binary Files|*.dat;*.bin|" + GameImage.FileFilter + "|All files (*.*)|*.*"; + private const string BinaryFilter = "Binary Files|*.dat;*.bin|All files (*.*)|*.*"; + private const string PrimaryFileFilter = "Binary Files|*.dat;*.bin|" + GameImage.FileFilter + "|All files (*.*)|*.*"; - private readonly BundleArchive _workingArchive; + private readonly BundleArchive _workingArchive; - private string _primaryPath; - private PrimaryResource _primary; + private string _primaryPath; + private PrimaryResource _primary; - private EntryType SelectedType => resourceTypeComboBox.SelectedItem is EntryType type ? type : EntryType.Invalid; - private string FullName => $"{resourceNameTextBox.Text}.{SelectedType}"; + private EntryType SelectedType => resourceTypeComboBox.SelectedItem is EntryType type ? type : EntryType.Invalid; + private string FullName => $"{resourceNameTextBox.Text}.{SelectedType}"; - public ImportResourceForm(BundleArchive destination, string primaryDataPath) - { - InitializeComponent(); + public ImportResourceForm(BundleArchive destination, string primaryDataPath) + { + InitializeComponent(); - _workingArchive = destination; + _workingArchive = destination; - resourceTypeComboBox.DataSource = Enum.GetValues(typeof(EntryType)); - resourceTypeComboBox.SelectedIndexChanged += (_, _) => OnTypeChanged(); - primaryResourcePathTextBox.Validating += primaryResourcePathTextBox_Validating; - importCountUpDown.ValueChanged += (_, _) => RefreshImportsList(); + resourceTypeComboBox.DataSource = Enum.GetValues(typeof(EntryType)); + resourceTypeComboBox.SelectedIndexChanged += (_, _) => OnTypeChanged(); + primaryResourcePathTextBox.Validating += primaryResourcePathTextBox_Validating; + importCountUpDown.ValueChanged += (_, _) => RefreshImportsList(); - LoadPrimary(primaryDataPath); - } + LoadPrimary(primaryDataPath); + } + + // Asks for the primary data, then shows the dialog. Returns whether a resource was imported. + public static bool ShowImport(IWin32Window owner, BundleArchive destination) + { + if (PickFile(owner, "primary", PrimaryFileFilter) is not string path) + return false; - // Asks for the primary data, then shows the dialog. Returns whether a resource was imported. - public static bool ShowImport(IWin32Window owner, BundleArchive destination) + ImportResourceForm form; + try + { + form = new(destination, path); + } + catch (OperationCanceledException) { - if (PickFile(owner, "primary", PrimaryFileFilter) is not string path) - return false; + return false; + } + catch (Exception ex) + { + MessageBox.Show(owner, $"Unable to import {path}: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return false; + } - ImportResourceForm form; - try - { - form = new(destination, path); - } - catch (OperationCanceledException) - { - return false; - } - catch (Exception ex) - { - MessageBox.Show(owner, $"Unable to import {path}: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - return false; - } + using (form) + return form.ShowDialog(owner) == DialogResult.OK; + } - using (form) - return form.ShowDialog(owner) == DialogResult.OK; - } + #region Event Handlers - #region Event Handlers + private void autoUpdateIDCheckBox_CheckedChanged(object sender, EventArgs e) + { + resourceIDTextBox.ReadOnly = autoUpdateIDCheckBox.Checked; - private void autoUpdateIDCheckBox_CheckedChanged(object sender, EventArgs e) - { - resourceIDTextBox.ReadOnly = autoUpdateIDCheckBox.Checked; + if (autoUpdateIDCheckBox.Checked) + RecalculateResourceIDTextBox(); + } - if (autoUpdateIDCheckBox.Checked) - RecalculateResourceIDTextBox(); - } + private void resourceNameTextBox_TextChanged(object sender, EventArgs e) + { + if (autoUpdateIDCheckBox.Checked) + RecalculateResourceIDTextBox(); + } - private void resourceNameTextBox_TextChanged(object sender, EventArgs e) - { - if (autoUpdateIDCheckBox.Checked) - RecalculateResourceIDTextBox(); - } + // Validating instead of Validated so a bad path also cancels the click that moved focus away + private void primaryResourcePathTextBox_Validating(object sender, System.ComponentModel.CancelEventArgs e) + { + if (primaryResourcePathTextBox.Text != _primaryPath) + e.Cancel = !TryLoadPrimary(primaryResourcePathTextBox.Text); + } - // Validating instead of Validated so a bad path also cancels the click that moved focus away - private void primaryResourcePathTextBox_Validating(object sender, System.ComponentModel.CancelEventArgs e) - { - if (primaryResourcePathTextBox.Text != _primaryPath) - e.Cancel = !TryLoadPrimary(primaryResourcePathTextBox.Text); - } + private void primaryDataPathSelectorButton_Click(object sender, EventArgs e) + { + if (PickFile(this, "primary", PrimaryFileFilter) is string path) + TryLoadPrimary(path); + } - private void primaryDataPathSelectorButton_Click(object sender, EventArgs e) - { - if (PickFile(this, "primary", PrimaryFileFilter) is string path) - TryLoadPrimary(path); - } + private void secondaryDataPathSelectorButton_Click(object sender, EventArgs e) + { + if (PickFile(this, "secondary", BinaryFilter) is string path) + secondaryResourcePathTextBox.Text = path; + } - private void secondaryDataPathSelectorButton_Click(object sender, EventArgs e) + private void importButton_Click(object sender, EventArgs e) + { + try { - if (PickFile(this, "secondary", BinaryFilter) is string path) - secondaryResourcePathTextBox.Text = path; + RunImportOperation(); } - - private void importButton_Click(object sender, EventArgs e) + catch (Exception ex) { - try - { - RunImportOperation(); - } - catch (Exception ex) - { - Warn("Failed to import the resource: " + ex.Message); - } + Warn("Failed to import the resource: " + ex.Message); } + } #endregion - void LoadPrimary(string path) + void LoadPrimary(string path) + { + _primary = ResourceImport.LoadPrimary(path, _workingArchive, AskPCTexturePlatform, p => ImageImportDialog.AskCompression(null, p)); + _primaryPath = path; + + primaryResourcePathTextBox.Text = path; + secondaryResourcePathTextBox.Text = string.Empty; // Belonged to the previous primary + resourceNameTextBox.Text = ResourceNamePrefix + ResourceImport.GetResourceBaseName(path); + resourceNameTextBox.SelectionStart = resourceNameTextBox.TextLength; + + resourceTypeComboBox.SelectedItem = _primary.Type; + resourceTypeComboBox.Enabled = _primary.ImageBody == null; + OnTypeChanged(); + + selectTypeLabel.Text = _primary.Type == EntryType.Invalid + ? "Unable to auto detect resource type, please select it from the box below:" + : "Select the resource type to import as:"; + + int importCount = _primary.Imports.Count; + importCountUpDown.Value = 0; + importCountUpDown.Maximum = importCount; + importCountUpDown.Value = importCount; + importCountUpDown.Enabled = _primary.ImportsSource == null && importCount > 0; + importsLabel.Text = _primary.ImageBody != null ? "Imports: none (texture built from the image)" + : _primary.ImportsSource != null ? $"Imports from {_primary.ImportsSource}:" + : importCount > 0 ? "Imports detected at the end of the primary data. Lower the count if the first rows are really resource data:" + : "Imports: none detected in the primary data"; + RefreshImportsList(); + + uint? fileID = ResourceImport.GetIDFromFileName(path); + autoUpdateIDCheckBox.Checked = fileID == null; + if (fileID is uint id) + resourceIDTextBox.Text = id.ToString("X8"); + } + + private bool TryLoadPrimary(string path) + { + try { - _primary = ResourceImport.LoadPrimary(path, _workingArchive, AskPCTexturePlatform, p => ImageImportDialog.AskCompression(null, p)); - _primaryPath = path; - - primaryResourcePathTextBox.Text = path; - secondaryResourcePathTextBox.Text = string.Empty; // Belonged to the previous primary - resourceNameTextBox.Text = ResourceNamePrefix + ResourceImport.GetResourceBaseName(path); - resourceNameTextBox.SelectionStart = resourceNameTextBox.TextLength; - - resourceTypeComboBox.SelectedItem = _primary.Type; - resourceTypeComboBox.Enabled = _primary.ImageBody == null; - OnTypeChanged(); - - selectTypeLabel.Text = _primary.Type == EntryType.Invalid - ? "Unable to auto detect resource type, please select it from the box below:" - : "Select the resource type to import as:"; - - int importCount = _primary.Imports.Count; - importCountUpDown.Value = 0; - importCountUpDown.Maximum = importCount; - importCountUpDown.Value = importCount; - importCountUpDown.Enabled = _primary.ImportsSource == null && importCount > 0; - importsLabel.Text = _primary.ImageBody != null ? "Imports: none (texture built from the image)" - : _primary.ImportsSource != null ? $"Imports from {_primary.ImportsSource}:" - : importCount > 0 ? "Imports detected at the end of the primary data. Lower the count if the first rows are really resource data:" - : "Imports: none detected in the primary data"; - RefreshImportsList(); - - uint? fileID = ResourceImport.GetIDFromFileName(path); - autoUpdateIDCheckBox.Checked = fileID == null; - if (fileID is uint id) - resourceIDTextBox.Text = id.ToString("X8"); + LoadPrimary(path); + return true; } - - private bool TryLoadPrimary(string path) + catch (Exception ex) { - try - { - LoadPrimary(path); - return true; - } - catch (Exception ex) - { - if (ex is not OperationCanceledException) - Warn($"Unable to use {path}: {ex.Message}"); - primaryResourcePathTextBox.Text = _primaryPath; // Put the old path back in the text box - return false; - } + if (ex is not OperationCanceledException) + Warn($"Unable to use {path}: {ex.Message}"); + primaryResourcePathTextBox.Text = _primaryPath; // Put the old path back in the text box + return false; } + } - private void OnTypeChanged() - { - bool needsSecondary = _primary.ImageBody == null && BundleEntry.GetMemoryChunkCount(SelectedType) > 1; - secondaryDataPathSelectorButton.Visible = secondaryResourcePathTextBox.Visible = secondaryImportPathLabel.Visible = needsSecondary; + private void OnTypeChanged() + { + bool needsSecondary = _primary.ImageBody == null && BundleEntry.GetMemoryChunkCount(SelectedType) > 1; + secondaryDataPathSelectorButton.Visible = secondaryResourcePathTextBox.Visible = secondaryImportPathLabel.Visible = needsSecondary; - if (needsSecondary && secondaryResourcePathTextBox.Text.Length == 0 && ResourceImport.FindSecondary(_primaryPath) is string secondary) - secondaryResourcePathTextBox.Text = secondary; + if (needsSecondary && secondaryResourcePathTextBox.Text.Length == 0 && ResourceImport.FindSecondary(_primaryPath) is string secondary) + secondaryResourcePathTextBox.Text = secondary; - if (autoUpdateIDCheckBox.Checked) - RecalculateResourceIDTextBox(); - } + if (autoUpdateIDCheckBox.Checked) + RecalculateResourceIDTextBox(); + } + + private static PlatformType AskPCTexturePlatform() + { + TaskDialogButton original = new ("PC (2009, The Ultimate Box)"); + TaskDialogButton remastered = new("Remastered"); - private static PlatformType AskPCTexturePlatform() + TaskDialogPage page = new() { - TaskDialogButton original = new ("PC (2009, The Ultimate Box)"); - TaskDialogButton remastered = new("Remastered"); + Caption = "Import Resource into Bundle", + Heading = "Which version of Burnout Paradise is this bundle for?", + Text = "Bundle Manager was unable to infer the platform for this bundle. Please select the version of Burnout Paradise that this bundle is for. This will determine how this texture and others are imported.", + Buttons = { original, remastered } + }; - TaskDialogPage page = new() - { - Caption = "Import Resource into Bundle", - Heading = "Which version of Burnout Paradise is this bundle for?", - Text = "Bundle Manager was unable to infer the platform for this bundle. Please select the version of Burnout Paradise that this bundle is for. This will determine how this texture and others are imported.", - Buttons = { original, remastered } - }; + return TaskDialog.ShowDialog(page) == remastered ? PlatformType.Remastered : PlatformType.PC; + } - return TaskDialog.ShowDialog(page) == remastered ? PlatformType.Remastered : PlatformType.PC; - } + private void RecalculateResourceIDTextBox() + { + resourceIDTextBox.Text = Crc32.HashEntryID(FullName).ToString("X8"); + } + + private void RefreshImportsList() + { + int count = (int)importCountUpDown.Value; - private void RecalculateResourceIDTextBox() + importsListBox.BeginUpdate(); + importsListBox.Items.Clear(); + foreach (Dependency dep in _primary.Imports.Skip(_primary.Imports.Count - count)) { - resourceIDTextBox.Text = Crc32.HashEntryID(FullName).ToString("X8"); + BundleEntry target = _workingArchive.GetEntryByID(dep.ID); + importsListBox.Items.Add($"0x{dep.EntryPointerOffset:X8} -> {dep.ID:X8}" + + (target == null ? string.Empty : $" ({target.Type} in this bundle)")); } + importsListBox.EndUpdate(); + } - private void RefreshImportsList() + private static string PickFile(IWin32Window owner, string chunkName, string filter) + { + using OpenFileDialog ofd = new() { - int count = (int)importCountUpDown.Value; + Title = $"Please select the {chunkName} resource to import", + Filter = filter + }; - importsListBox.BeginUpdate(); - importsListBox.Items.Clear(); - foreach (Dependency dep in _primary.Imports.Skip(_primary.Imports.Count - count)) - { - BundleEntry target = _workingArchive.GetEntryByID(dep.ID); - importsListBox.Items.Add($"0x{dep.EntryPointerOffset:X8} -> {dep.ID:X8}" - + (target == null ? string.Empty : $" ({target.Type} in this bundle)")); - } - importsListBox.EndUpdate(); - } + return ofd.ShowDialog(owner) == DialogResult.OK ? ofd.FileName : null; + } - private static string PickFile(IWin32Window owner, string chunkName, string filter) - { - using OpenFileDialog ofd = new() - { - Title = $"Please select the {chunkName} resource to import", - Filter = filter - }; + private void RunImportOperation() + { + EntryType type = SelectedType; + string name = resourceNameTextBox.Text; + if (name.StartsWith(ResourceNamePrefix, StringComparison.OrdinalIgnoreCase)) + name = name[ResourceNamePrefix.Length..]; - return ofd.ShowDialog(owner) == DialogResult.OK ? ofd.FileName : null; + if (string.IsNullOrWhiteSpace(name)) + { + Warn("Please enter a name for the resource."); + return; } - private void RunImportOperation() + if (type == EntryType.Invalid) { - EntryType type = SelectedType; - string name = resourceNameTextBox.Text; - if (name.StartsWith(ResourceNamePrefix, StringComparison.OrdinalIgnoreCase)) - name = name[ResourceNamePrefix.Length..]; - - if (string.IsNullOrWhiteSpace(name)) - { - Warn("Please enter a name for the resource."); - return; - } - - if (type == EntryType.Invalid) - { - Warn("Please select the resource type to import as."); - return; - } + Warn("Please select the resource type to import as."); + return; + } - if (!ResourceImport.TryParseHex(resourceIDTextBox.Text, out uint id)) - { - Warn("Please enter a valid hexadecimal resource ID."); - return; - } + if (!ResourceImport.TryParseHex(resourceIDTextBox.Text, out uint id)) + { + Warn("Please enter a valid hexadecimal resource ID."); + return; + } - byte[] secondary = _primary.ImageBody; - if (secondary == null) + byte[] secondary = _primary.ImageBody; + if (secondary == null) + { + if (BundleEntry.GetMemoryChunkCount(type) > 1) { - if (BundleEntry.GetMemoryChunkCount(type) > 1) + if (!File.Exists(secondaryResourcePathTextBox.Text)) { - if (!File.Exists(secondaryResourcePathTextBox.Text)) - { - Warn("Please select valid secondary data for the resource you are trying to import."); - return; - } - - secondary = File.ReadAllBytes(secondaryResourcePathTextBox.Text); + Warn("Please select valid secondary data for the resource you are trying to import."); + return; } - if (type == EntryType.Texture - && !ResourceImport.TextureMatchesBundle(_primary.Data, _workingArchive.Platform) - && !Confirm($"This texture header doesn't look like a {_workingArchive.Platform} texture.", "Import anyway")) - return; + secondary = File.ReadAllBytes(secondaryResourcePathTextBox.Text); } - BundleEntry existing = _workingArchive.GetEntryByID(id); - if (existing != null && !Confirm($"This bundle already has a resource with ID {id:X8} ({existing.Type}). Replace it?", "Replace")) + if (type == EntryType.Texture + && !ResourceImport.TextureMatchesBundle(_primary.Data, _workingArchive.Platform) + && !Confirm($"This texture header doesn't look like a {_workingArchive.Platform} texture.", "Import anyway")) return; + } - _workingArchive.AddEntry(_workingArchive.CreateEntry(id, type, FullName, _primary.Data, (int)importCountUpDown.Value, secondary)); + BundleEntry existing = _workingArchive.GetEntryByID(id); + if (existing != null && !Confirm($"This bundle already has a resource with ID {id:X8} ({existing.Type}). Replace it?", "Replace")) + return; - DialogResult = DialogResult.OK; - Close(); - } + _workingArchive.AddEntry(_workingArchive.CreateEntry(id, type, FullName, _primary.Data, (int)importCountUpDown.Value, secondary)); - private void Warn(string message) - { - MessageBox.Show(this, message, Text, MessageBoxButtons.OK, MessageBoxIcon.Warning); - } + DialogResult = DialogResult.OK; + Close(); + } - private bool Confirm(string message, string action) - { - TaskDialogButton confirm = new(action); + private void Warn(string message) + { + MessageBox.Show(this, message, Text, MessageBoxButtons.OK, MessageBoxIcon.Warning); + } - TaskDialogPage page = new() - { - Caption = Text, - Text = message, - Icon = TaskDialogIcon.Warning, - Buttons = { confirm, TaskDialogButton.Cancel }, - AllowCancel = true - }; - - return TaskDialog.ShowDialog(this, page) == confirm; - } + private bool Confirm(string message, string action) + { + TaskDialogButton confirm = new(action); + + TaskDialogPage page = new() + { + Caption = Text, + Text = message, + Icon = TaskDialogIcon.Warning, + Buttons = { confirm, TaskDialogButton.Cancel }, + AllowCancel = true + }; + + return TaskDialog.ShowDialog(this, page) == confirm; } } diff --git a/BundleManager/MainForm.cs b/BundleManager/MainForm.cs index bc4eb85..9688463 100644 --- a/BundleManager/MainForm.cs +++ b/BundleManager/MainForm.cs @@ -9,777 +9,775 @@ using DebugHelper; using PluginAPI; -namespace BundleManager +namespace BundleManager; + +public partial class MainForm : Form { - public partial class MainForm : Form - { - #region Variables and Properties + #region Variables and Properties - private bool _subForm; - [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] - public bool SubForm + private bool _subForm; + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public bool SubForm + { + get { return _subForm; } + set { - get { return _subForm; } - set - { - _subForm = value; - - tsbNew.Visible = !value; - toolStripSeparator1.Visible = !value; - tsbOpen.Visible = !value; - toolStripSeparator2.Visible = !value; - toolStripSeparator3.Visible = !value; - tsbSwitchMode.Visible = !value; - - newToolStripMenuItem.Visible = !value; - toolStripMenuItem3.Visible = !value; - openToolStripMenuItem.Visible = !value; - toolStripMenuItem1.Visible = !value; - - exitToolStripMenuItem.Visible = !value; - closeToolStripMenuItem.Visible = value; - } + _subForm = value; + + tsbNew.Visible = !value; + toolStripSeparator1.Visible = !value; + tsbOpen.Visible = !value; + toolStripSeparator2.Visible = !value; + toolStripSeparator3.Visible = !value; + tsbSwitchMode.Visible = !value; + + newToolStripMenuItem.Visible = !value; + toolStripMenuItem3.Visible = !value; + openToolStripMenuItem.Visible = !value; + toolStripMenuItem1.Visible = !value; + + exitToolStripMenuItem.Visible = !value; + closeToolStripMenuItem.Visible = value; } + } - private BundleArchive _archive; + private BundleArchive _archive; - private delegate BundleArchive GetArchive(); + private delegate BundleArchive GetArchive(); - private delegate void SetArchive(BundleArchive archive); + private delegate void SetArchive(BundleArchive archive); - private BundleArchive CurrentArchive + private BundleArchive CurrentArchive + { + get { - get + if (InvokeRequired) { - if (InvokeRequired) - { - GetArchive method = () => - { - return _archive; - }; - return (BundleArchive)Invoke(method); - } - else + GetArchive method = () => { return _archive; - } + }; + return (BundleArchive)Invoke(method); } - set + else { - if (InvokeRequired) - { - SetArchive method = (BundleArchive archive) => - { - _archive = archive; - }; - Invoke(method, value); - } - else + return _archive; + } + } + set + { + if (InvokeRequired) + { + SetArchive method = (BundleArchive archive) => { - _archive = value; - } + _archive = archive; + }; + Invoke(method, value); + } + else + { + _archive = value; } } + } - private string _currentFileName; + private string _currentFileName; - private delegate string GetString(); + private delegate string GetString(); - private delegate void SetString(string archive); + private delegate void SetString(string archive); - private string CurrentFileName + private string CurrentFileName + { + get { - get + if (InvokeRequired) { - if (InvokeRequired) - { - GetString method = () => - { - return _currentFileName; - }; - return (string)Invoke(method); - } - else + GetString method = () => { return _currentFileName; - } + }; + return (string)Invoke(method); } - set + else { - if (InvokeRequired) - { - SetString method = (string filename) => - { - _currentFileName = filename; - }; - Invoke(method, value); - } - else + return _currentFileName; + } + } + set + { + if (InvokeRequired) + { + SetString method = (string filename) => { - _currentFileName = value; - } + _currentFileName = filename; + }; + Invoke(method, value); + } + else + { + _currentFileName = value; } } + } - private delegate bool GetBool(); + private delegate bool GetBool(); - private delegate void SetBool(bool value); + private delegate void SetBool(bool value); - public bool _console => CurrentArchive.Console; + public bool _console => CurrentArchive.Console; - public bool ForceOnlySpecificEntry = false; + public bool ForceOnlySpecificEntry = false; - private Thread _openSaveThread; + private Thread _openSaveThread; - #endregion + #endregion - public MainForm() - { - InitializeComponent(); + public MainForm() + { + InitializeComponent(); - //doNew(); - UpdateDisplay(); - } + //doNew(); + UpdateDisplay(); + } + + private void UpdateDisplay() + { + lstEntries.Items.Clear(); - private void UpdateDisplay() + UpdatePluginMenu(); + addResourcesToBundleToolStripMenuItem.Enabled = CurrentArchive != null; + + if (CurrentArchive == null) + { + lstEntries.Enabled = false; + return; + } + else { - lstEntries.Items.Clear(); + lstEntries.Enabled = true; + } - UpdatePluginMenu(); - addResourcesToBundleToolStripMenuItem.Enabled = CurrentArchive != null; + lstEntries.BeginUpdate(); + lstEntries.ListViewItemSorter = null; // Disable sorting while adding - if (CurrentArchive == null) + foreach (BundleEntry entry in CurrentArchive.Entries) + { + if (entry.EntryBlocks[0].Data == null) // Exception occurred { + lstEntries.Items.Clear(); lstEntries.Enabled = false; + CurrentArchive = null; + CurrentFileName = null; + lstEntries.EndUpdate(); + UpdatePluginMenu(); return; } - else - { - lstEntries.Enabled = true; - } - - lstEntries.BeginUpdate(); - lstEntries.ListViewItemSorter = null; // Disable sorting while adding + string[] values = + [ + entry.Index.ToString("d3"), + entry.DetectName(), + "0x" + entry.ID.ToString("X8"), + entry.Type.ToString(), + entry.EntryBlocks[0].Data.Length.ToString(), + entry.EntryBlocks[0].Data.MakePreview(0, 16) + ]; - foreach (BundleEntry entry in CurrentArchive.Entries) - { - if (entry.EntryBlocks[0].Data == null) // Exception occurred - { - lstEntries.Items.Clear(); - lstEntries.Enabled = false; - CurrentArchive = null; - CurrentFileName = null; - lstEntries.EndUpdate(); - UpdatePluginMenu(); - return; - } - string[] values = new string[] - { - entry.Index.ToString("d3"), - entry.DetectName(), - "0x" + entry.ID.ToString("X8"), - entry.Type.ToString(), - entry.EntryBlocks[0].Data.Length.ToString(), - entry.EntryBlocks[0].Data.MakePreview(0, 16) - }; + ListViewItem item = new(values); + item.BackColor = BundleEntry.GetColor(entry.Type); + lstEntries.Items.Add(item); + } - ListViewItem item = new ListViewItem(values); - item.BackColor = BundleEntry.GetColor(entry.Type); - lstEntries.Items.Add(item); - } + lstEntries.ListViewItemSorter = new EntrySorter(0); // Also calls Sort + lstEntries.EndUpdate(); + } - lstEntries.ListViewItemSorter = new EntrySorter(0); // Also calls Sort - lstEntries.EndUpdate(); - } + private void UpdatePluginMenu() + { + int index = toolsToolStripMenuItem.DropDownItems.IndexOf(pluginToolsSeparatorItem) + 1; - private void UpdatePluginMenu() + while (true) { - int index = toolsToolStripMenuItem.DropDownItems.IndexOf(pluginToolsSeparatorItem) + 1; - - while (true) - { - if (index >= toolsToolStripMenuItem.DropDownItems.Count) - break; + if (index >= toolsToolStripMenuItem.DropDownItems.Count) + break; - if (toolsToolStripMenuItem.DropDownItems[index] is ToolStripSeparator) - break; + if (toolsToolStripMenuItem.DropDownItems[index] is ToolStripSeparator) + break; - toolsToolStripMenuItem.DropDownItems.RemoveAt(index); - } + toolsToolStripMenuItem.DropDownItems.RemoveAt(index); + } - PluginCommand[] commands = PluginCommandRegistry.Commands; + PluginCommand[] commands = PluginCommandRegistry.Commands; - if (commands.Length == 0) - { - ToolStripItem item = new ToolStripMenuItem("No Plugin Commands"); - item.Enabled = false; + if (commands.Length == 0) + { + ToolStripItem item = new ToolStripMenuItem("No Plugin Commands"); + item.Enabled = false; - toolsToolStripMenuItem.DropDownItems.Insert(index, item); - } - else + toolsToolStripMenuItem.DropDownItems.Insert(index, item); + } + else + { + for (int i = 0; i < commands.Length; i++) { - for (int i = 0; i < commands.Length; i++) - { - PluginCommand command = commands[i]; + PluginCommand command = commands[i]; - ToolStripItem item = new ToolStripMenuItem(command.Text); - if (CurrentArchive == null) - item.Enabled = false; - else if (command.CheckConditions == null) - item.Enabled = true; - else - item.Enabled = command.CheckConditions(CurrentArchive); + ToolStripItem item = new ToolStripMenuItem(command.Text); + if (CurrentArchive == null) + item.Enabled = false; + else if (command.CheckConditions == null) + item.Enabled = true; + else + item.Enabled = command.CheckConditions(CurrentArchive); - item.Click += (sender, args) => command.Use(this, CurrentArchive); + item.Click += (sender, args) => command.Use(this, CurrentArchive); - toolsToolStripMenuItem.DropDownItems.Insert(index + i, item); - } + toolsToolStripMenuItem.DropDownItems.Insert(index + i, item); } } + } - private void DoNew() - { - if (!CheckSave()) - return; - //CurrentArchive = new BundleArchive(); - //UpdateDisplay(); - - MessageBox.Show(this, - "This feature is currently not avaliable because we don't know enough about the Bundle format to create them from scratch yet.", - "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - } + private void DoNew() + { + if (!CheckSave()) + return; + //CurrentArchive = new BundleArchive(); + //UpdateDisplay(); + + MessageBox.Show(this, + "This feature is currently not avaliable because we don't know enough about the Bundle format to create them from scratch yet.", + "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + } - private void Open() - { - if (!CheckSave()) + private void Open() + { + if (!CheckSave()) + return; + OpenFileDialog ofd = new(); + ofd.Filter = "Supported Files|*.BUNDLE;*.BIN;*.BNDL;*.DAT;*.TEX|All Files|*.*"; + DialogResult result = ofd.ShowDialog(this); + if (result == DialogResult.OK) + { + if (!Utilities.FileExists(ofd.FileName)) return; - OpenFileDialog ofd = new OpenFileDialog(); - ofd.Filter = "Supported Files|*.BUNDLE;*.BIN;*.BNDL;*.DAT;*.TEX|All Files|*.*"; - DialogResult result = ofd.ShowDialog(this); - if (result == DialogResult.OK) - { - if (!Utilities.FileExists(ofd.FileName)) - return; - Open(ofd.FileName); - } + Open(ofd.FileName); } + } - public void Open(string path) + public void Open(string path) + { + LoadingDialog loader = new(); + loader.Status = "Loading: " + path; + loader.Done += Loader_OpenDone; + _openSaveThread = new Thread(() => DoOpenBundle(loader, path)); + _openSaveThread.Start(); + loader.ShowDialog(this); + } + + private void Loader_OpenDone(bool cancelled, object value) + { + if (cancelled) { - LoadingDialog loader = new LoadingDialog(); - loader.Status = "Loading: " + path; - loader.Done += Loader_OpenDone; - _openSaveThread = new Thread(() => DoOpenBundle(loader, path)); - _openSaveThread.Start(); - loader.ShowDialog(this); + _openSaveThread?.Interrupt(); + CurrentArchive = null; + CurrentFileName = null; } - - private void Loader_OpenDone(bool cancelled, object value) + else { - if (cancelled) + object[] values = (object[])value; + CurrentArchive = (BundleArchive)values[0]; + + if (CurrentArchive == null) { - _openSaveThread?.Interrupt(); - CurrentArchive = null; + MessageBox.Show(this, "There was an error opening archive: " + (string)values[1], "Error", + MessageBoxButtons.OK, MessageBoxIcon.Error); CurrentFileName = null; + Text = "Bundle Manager"; } else { - object[] values = (object[])value; - CurrentArchive = (BundleArchive)values[0]; - - if (CurrentArchive == null) - { - MessageBox.Show(this, "There was an error opening archive: " + (string)values[1], "Error", - MessageBoxButtons.OK, MessageBoxIcon.Error); - CurrentFileName = null; - Text = "Bundle Manager"; - } - else - { - CurrentFileName = (string)values[1]; - Text = "Bundle Manager - " + CurrentFileName; - } + CurrentFileName = (string)values[1]; + Text = "Bundle Manager - " + CurrentFileName; } - UpdateDisplay(); } + UpdateDisplay(); + } - public void DoOpenBundle(LoadingDialog loader, string path) - { - BundleArchive archive = BundleArchive.Read(path); + public void DoOpenBundle(LoadingDialog loader, string path) + { + BundleArchive archive = BundleArchive.Read(path); + + loader.Value = new object[] { archive, path }; + loader.IsDone = true; + } - loader.Value = new object[] { archive, path }; - loader.IsDone = true; + public bool Save() + { + if (CurrentArchive == null) + { + MessageBox.Show(this, "Nothing to save!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return true; } + if (string.IsNullOrEmpty(CurrentFileName)) + { + return SaveAs(); + } + + LoadingDialog loader = new(); + loader.Status = "Saving: " + CurrentFileName; + loader.Done += Loader_SaveDone; + _openSaveThread = new Thread(() => DoSaveBundle(loader, CurrentFileName)); + _openSaveThread.Start(); + loader.ShowDialog(this); + return true; + } - public bool Save() + public bool SaveAs() + { + if (CurrentArchive == null) { - if (CurrentArchive == null) - { - MessageBox.Show(this, "Nothing to save!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return true; - } - if (string.IsNullOrEmpty(CurrentFileName)) - { - return SaveAs(); - } + MessageBox.Show(this, "Nothing to save!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return true; + } + SaveFileDialog sfd = new(); + sfd.Filter = "Supported Files|*.BUNDLE;*.BIN;*.BNDL;*.DAT;*.TEX|All Files|*.*"; + DialogResult result = sfd.ShowDialog(this); + if (result == DialogResult.OK) + { + if (!Utilities.IsValidPath(sfd.FileName)) + return false; - LoadingDialog loader = new LoadingDialog(); - loader.Status = "Saving: " + CurrentFileName; + LoadingDialog loader = new(); + loader.Status = "Saving: " + sfd.FileName; loader.Done += Loader_SaveDone; - _openSaveThread = new Thread(() => DoSaveBundle(loader, CurrentFileName)); + _openSaveThread = new Thread(() => DoSaveBundle(loader, sfd.FileName)); _openSaveThread.Start(); loader.ShowDialog(this); + + CurrentFileName = sfd.FileName; + Text = "Bundle Manager - " + CurrentFileName; + UpdateDisplay(); + return true; } + return false; + } - public bool SaveAs() + private void Loader_SaveDone(bool cancelled, object value) + { + if (cancelled) { - if (CurrentArchive == null) - { - MessageBox.Show(this, "Nothing to save!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return true; - } - SaveFileDialog sfd = new SaveFileDialog(); - sfd.Filter = "Supported Files|*.BUNDLE;*.BIN;*.BNDL;*.DAT;*.TEX|All Files|*.*"; - DialogResult result = sfd.ShowDialog(this); - if (result == DialogResult.OK) - { - if (!Utilities.IsValidPath(sfd.FileName)) - return false; - - LoadingDialog loader = new LoadingDialog(); - loader.Status = "Saving: " + sfd.FileName; - loader.Done += Loader_SaveDone; - _openSaveThread = new Thread(() => DoSaveBundle(loader, sfd.FileName)); - _openSaveThread.Start(); - loader.ShowDialog(this); - - CurrentFileName = sfd.FileName; - Text = "Bundle Manager - " + CurrentFileName; - UpdateDisplay(); - - return true; - } - return false; + _openSaveThread?.Interrupt(); } - - private void Loader_SaveDone(bool cancelled, object value) + else { - if (cancelled) - { - _openSaveThread?.Interrupt(); - } - else - { - CurrentArchive.Dirty = false; - } + CurrentArchive.Dirty = false; } + } - public void DoSaveBundle(LoadingDialog loader, string path) - { - CurrentArchive.Write(path); + public void DoSaveBundle(LoadingDialog loader, string path) + { + CurrentArchive.Write(path); - loader.IsDone = true; - } + loader.IsDone = true; + } + + public void Exit() + { + Application.Exit(); + } - public void Exit() + private delegate BundleEntry GetEntryDelegate(int index); + public BundleEntry GetEntry(int index) + { + if (InvokeRequired) { - Application.Exit(); + GetEntryDelegate del = GetEntry; + return (BundleEntry)Invoke(del, index); } - - private delegate BundleEntry GetEntryDelegate(int index); - public BundleEntry GetEntry(int index) + else { - if (InvokeRequired) - { - GetEntryDelegate del = GetEntry; - return (BundleEntry)Invoke(del, index); - } - else - { - return CurrentArchive.Entries[index]; - } + return CurrentArchive.Entries[index]; } + } - public void EditSelectedEntry(bool forceHex = false, bool forceDebug = false) - { - int count = lstEntries.SelectedIndices.Count; - if (count <= 0) - return; + public void EditSelectedEntry(bool forceHex = false, bool forceDebug = false) + { + int count = lstEntries.SelectedIndices.Count; + if (count <= 0) + return; - int index; - if (!int.TryParse(lstEntries.SelectedItems[0].Text, out index)) - return; + if (!int.TryParse(lstEntries.SelectedItems[0].Text, out int index)) + return; - EditEntry(index, forceHex, forceDebug); - } + EditEntry(index, forceHex, forceDebug); + } - public void EditEntry(int index, bool forceHex = false, bool forceDebug = false) - { - BundleEntry entry = GetEntry(index); + public void EditEntry(int index, bool forceHex = false, bool forceDebug = false) + { + BundleEntry entry = GetEntry(index); - if (EntryTypeRegistry.IsRegistered(entry.Type) && !forceHex) - { - IEntryData data = EntryTypeRegistry.GetHandler(entry.Type); + if (EntryTypeRegistry.IsRegistered(entry.Type) && !forceHex) + { + IEntryData data = EntryTypeRegistry.GetHandler(entry.Type); - TextureCache.ResetCache(); - LoadingDialog loader = new LoadingDialog(); - loader.Status = "Loading: " + entry.ID.ToString("X8"); + TextureCache.ResetCache(); + LoadingDialog loader = new(); + loader.Status = "Loading: " + entry.ID.ToString("X8"); - Thread loadInstanceThread = null; - bool failure = false; + Thread loadInstanceThread = null; + bool failure = false; - loader.Done += (cancelled, value) => + loader.Done += (cancelled, value) => + { + if (cancelled) + loadInstanceThread?.Interrupt(); + else { - if (cancelled) - loadInstanceThread?.Interrupt(); + if (failure) + { + MessageBox.Show(this, "Failed to load Entry", "Error", MessageBoxButtons.OK, + MessageBoxIcon.Error); + } else { - if (failure) + loader.Hide(); + if (forceDebug) { - MessageBox.Show(this, "Failed to load Entry", "Error", MessageBoxButtons.OK, - MessageBoxIcon.Error); + DebugUtil.ShowDebug(this, data); } + IEntryEditor editor = data.GetEditor(entry); + if (editor != null) + editor.ShowDialog(this); else - { - loader.Hide(); - if (forceDebug) - { - DebugUtil.ShowDebug(this, data); - } - IEntryEditor editor = data.GetEditor(entry); - if (editor != null) - editor.ShowDialog(this); - else - DebugUtil.ShowDebug(this, data); - if (ForceOnlySpecificEntry) - Environment.Exit(0); - } + DebugUtil.ShowDebug(this, data); + if (ForceOnlySpecificEntry) + Environment.Exit(0); } - TextureCache.ResetCache(); - }; + } + TextureCache.ResetCache(); + }; - loadInstanceThread = new Thread(() => + loadInstanceThread = new Thread(() => + { + try { try { - try - { - failure = !data.Read(entry, loader); - } - catch (ReadFailedError ex) - { - - Console.Out.WriteLine(ex.ToString()); - MessageBox.Show(this, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - failure = true; - - throw; - } + failure = !data.Read(entry, loader); } - catch (Exception e) + catch (ReadFailedError ex) { - Console.Out.WriteLine(e.ToString()); - MessageBox.Show("Failed to load Entry", "Error", MessageBoxButtons.OK, - MessageBoxIcon.Error); + + Console.Out.WriteLine(ex.ToString()); + MessageBox.Show(this, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); failure = true; + + throw; } - loader.IsDone = true; - }); - loadInstanceThread.Start(); - loader.ShowDialog(this); - } - else - { - EntryEditor editor = new EntryEditor(); - editor.ForceHex = forceHex; - Task.Run(() => openEditor(editor, index)); - editor.ShowDialog(this); - } + } + catch (Exception e) + { + Console.Out.WriteLine(e.ToString()); + MessageBox.Show("Failed to load Entry", "Error", MessageBoxButtons.OK, + MessageBoxIcon.Error); + failure = true; + } + loader.IsDone = true; + }); + loadInstanceThread.Start(); + loader.ShowDialog(this); } - - - public void openEditor(EntryEditor editor, int index) + else { - editor.Entry = GetEntry(index); + EntryEditor editor = new(); + editor.ForceHex = forceHex; + Task.Run(() => openEditor(editor, index)); + editor.ShowDialog(this); } + } - #region Event Handlers - private void newToolStripMenuItem_Click(object sender, EventArgs e) - { - DoNew(); - } + public void openEditor(EntryEditor editor, int index) + { + editor.Entry = GetEntry(index); + } - private void openToolStripMenuItem_Click(object sender, EventArgs e) - { - Open(); - } + #region Event Handlers - private void saveToolStripMenuItem_Click(object sender, EventArgs e) - { - Save(); - } + private void newToolStripMenuItem_Click(object sender, EventArgs e) + { + DoNew(); + } - private void saveAsToolStripMenuItem_Click(object sender, EventArgs e) - { - SaveAs(); - } + private void openToolStripMenuItem_Click(object sender, EventArgs e) + { + Open(); + } - private void exitToolStripMenuItem_Click(object sender, EventArgs e) - { - Exit(); - } + private void saveToolStripMenuItem_Click(object sender, EventArgs e) + { + Save(); + } - private void tsbNew_Click(object sender, EventArgs e) - { - DoNew(); - } + private void saveAsToolStripMenuItem_Click(object sender, EventArgs e) + { + SaveAs(); + } - private void tsbOpen_Click(object sender, EventArgs e) - { - Open(); - } + private void exitToolStripMenuItem_Click(object sender, EventArgs e) + { + Exit(); + } - private void tsbSave_Click(object sender, EventArgs e) - { - Save(); - } + private void tsbNew_Click(object sender, EventArgs e) + { + DoNew(); + } - private void lstEntries_MouseDoubleClick(object sender, MouseEventArgs e) - { - EditSelectedEntry(false); - } + private void tsbOpen_Click(object sender, EventArgs e) + { + Open(); + } - private void previewToolStripMenuItem_Click(object sender, EventArgs e) - { - EditSelectedEntry(false); - } + private void tsbSave_Click(object sender, EventArgs e) + { + Save(); + } - private void viewDataToolStripMenuItem_Click(object sender, EventArgs e) - { - EditSelectedEntry(true); - } + private void lstEntries_MouseDoubleClick(object sender, MouseEventArgs e) + { + EditSelectedEntry(false); + } - private void viewDebugMenuStripMenuItem_Click(object sender, EventArgs e) - { - EditSelectedEntry(false, true); - } + private void previewToolStripMenuItem_Click(object sender, EventArgs e) + { + EditSelectedEntry(false); + } - private void MainForm_FormClosing(object sender, FormClosingEventArgs e) - { - if (!CheckSave()) - { - e.Cancel = true; - } + private void viewDataToolStripMenuItem_Click(object sender, EventArgs e) + { + EditSelectedEntry(true); + } - if (!SubForm) - Application.Exit(); - } + private void viewDebugMenuStripMenuItem_Click(object sender, EventArgs e) + { + EditSelectedEntry(false, true); + } - private void tsbSwitchMode_Click(object sender, EventArgs e) + private void MainForm_FormClosing(object sender, FormClosingEventArgs e) + { + if (!CheckSave()) { - SwitchMode(); + e.Cancel = true; } - private void closeToolStripMenuItem_Click(object sender, EventArgs e) - { - Close(); - } + if (!SubForm) + Application.Exit(); + } - private void lstEntries_ColumnClick(object sender, ColumnClickEventArgs e) - { - SortColumn(e.Column); - } + private void tsbSwitchMode_Click(object sender, EventArgs e) + { + SwitchMode(); + } - private void searchForEntryToolStripMenuItem_Click(object sender, EventArgs e) - { - Search(); - } + private void closeToolStripMenuItem_Click(object sender, EventArgs e) + { + Close(); + } - private void addResourcesToBundleToolStripMenuItem_Click(object sender, EventArgs e) - { - if (CurrentArchive != null && ImportResourceForm.ShowImport(this, CurrentArchive)) - UpdateDisplay(); - } + private void lstEntries_ColumnClick(object sender, ColumnClickEventArgs e) + { + SortColumn(e.Column); + } + + private void searchForEntryToolStripMenuItem_Click(object sender, EventArgs e) + { + Search(); + } + + private void addResourcesToBundleToolStripMenuItem_Click(object sender, EventArgs e) + { + if (CurrentArchive != null && ImportResourceForm.ShowImport(this, CurrentArchive)) + UpdateDisplay(); + } - #endregion + #endregion - #region Utility + #region Utility - private bool CheckSave() + private bool CheckSave() + { + if (CurrentArchive == null) { - if (CurrentArchive == null) + return true; + } + else if (CurrentArchive.Dirty) + { + TaskDialogButton save = new("Save"); + TaskDialogButton dontSave = new("Don't Save"); + + TaskDialogPage page = new() { - return true; + Caption = "Save", + Heading = "There are unsaved changes", + Text = "Would you like to save them first?", + Icon = TaskDialogIcon.Warning, + Buttons = { save, dontSave, TaskDialogButton.Cancel }, + AllowCancel = true + }; + + TaskDialogButton result = TaskDialog.ShowDialog(this, page); + if (result == save) + { + return Save(); } - else if (CurrentArchive.Dirty) + else if (result == dontSave) { - TaskDialogButton save = new("Save"); - TaskDialogButton dontSave = new("Don't Save"); - - TaskDialogPage page = new() - { - Caption = "Save", - Heading = "There are unsaved changes", - Text = "Would you like to save them first?", - Icon = TaskDialogIcon.Warning, - Buttons = { save, dontSave, TaskDialogButton.Cancel }, - AllowCancel = true - }; - - TaskDialogButton result = TaskDialog.ShowDialog(this, page); - if (result == save) - { - return Save(); - } - else if (result == dontSave) - { - CurrentArchive = null; - CurrentFileName = null; - UpdateDisplay(); - return true; - } - else - { - return false; - } - + CurrentArchive = null; + CurrentFileName = null; + UpdateDisplay(); + return true; } else { - return true; + return false; } + + } + else + { + return true; } + } - private void Search() + private void Search() + { + if (CurrentArchive == null) + return; + + SearchDialog search = new(); + search.Search += id => { - if (CurrentArchive == null) + BundleEntry entry = CurrentArchive.GetEntryByID(id); + if (entry == null) + { + MessageBox.Show(this, "Entry not found!", "Information", MessageBoxButtons.OK, + MessageBoxIcon.Information); return; + } - SearchDialog search = new SearchDialog(); - search.Search += id => + string indexText = CurrentArchive.Entries.IndexOf(entry).ToString("D3"); + int listIndex = -1; + for (int i = 0; i < lstEntries.Items.Count; i++) { - BundleEntry entry = CurrentArchive.GetEntryByID(id); - if (entry == null) + ListViewItem item = lstEntries.Items[i]; + if (item.Text == indexText) { - MessageBox.Show(this, "Entry not found!", "Information", MessageBoxButtons.OK, - MessageBoxIcon.Information); - return; + listIndex = i; + break; } + } - string indexText = CurrentArchive.Entries.IndexOf(entry).ToString("D3"); - int listIndex = -1; - for (int i = 0; i < lstEntries.Items.Count; i++) - { - ListViewItem item = lstEntries.Items[i]; - if (item.Text == indexText) - { - listIndex = i; - break; - } - } + lstEntries.SelectedIndices.Clear(); + lstEntries.SelectedIndices.Add(listIndex); + lstEntries.EnsureVisible(listIndex); + }; + search.ShowDialog(this); + } - lstEntries.SelectedIndices.Clear(); - lstEntries.SelectedIndices.Add(listIndex); - lstEntries.EnsureVisible(listIndex); - }; - search.ShowDialog(this); - } + private void SwitchMode() + { + if (!CheckSave()) + return; - private void SwitchMode() - { - if (!CheckSave()) - return; + CurrentArchive = null; + CurrentFileName = null; + UpdateDisplay(); - CurrentArchive = null; - CurrentFileName = null; - UpdateDisplay(); + Hide(); + Program.SavePreferredMode(true); + Program.folderModeForm.Show(); + } - Hide(); - Program.SavePreferredMode(true); - Program.folderModeForm.Show(); - } + private void SortColumn(int column) + { + EntrySorter sorter; - private void SortColumn(int column) + if (lstEntries.ListViewItemSorter is EntrySorter) + { + // every other time + sorter = lstEntries.ListViewItemSorter as EntrySorter; + sorter.Column = column; + } + else { - EntrySorter sorter; + // first time + sorter = new EntrySorter(column); + lstEntries.ListViewItemSorter = sorter; + } + // if you're clicking the same column already being sorted + //if (sorter.Column == column) + //{ + // change the direction state from true to false or vice-versa + sorter.Swap(); + // bop-it + lstEntries.Sort(); + //} + } - if (lstEntries.ListViewItemSorter is EntrySorter) - { - // every other time - sorter = lstEntries.ListViewItemSorter as EntrySorter; - sorter.Column = column; - } - else - { - // first time - sorter = new EntrySorter(column); - lstEntries.ListViewItemSorter = sorter; - } - // if you're clicking the same column already being sorted - //if (sorter.Column == column) - //{ - // change the direction state from true to false or vice-versa - sorter.Swap(); - // bop-it - lstEntries.Sort(); - //} + private class EntrySorter : IComparer + { + public int Column; + public bool Direction; + + public EntrySorter(int column) + { + this.Column = column; + this.Direction = false; } - private class EntrySorter : IComparer + public int Compare(object x, object y) { - public int Column; - public bool Direction; + ListViewItem itemX = (ListViewItem)x; + ListViewItem itemY = (ListViewItem)y; - public EntrySorter(int column) + if (Column > itemX?.SubItems.Count || Column > itemY?.SubItems.Count) { - this.Column = column; - this.Direction = false; + if (this.Direction) + return -1; + return 1; } - public int Compare(object x, object y) - { - ListViewItem itemX = (ListViewItem)x; - ListViewItem itemY = (ListViewItem)y; + string iX = itemX?.SubItems[Column].Text; + string iY = itemY?.SubItems[Column].Text; - if (Column > itemX?.SubItems.Count || Column > itemY?.SubItems.Count) + /* + if (int.TryParse(iX, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out var iXint)) + { + if (int.TryParse(iY, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out var iYint)) { + int val2 = iXint.CompareTo(iYint); if (this.Direction) - return -1; - return 1; + return val2 * -1; + return val2; } - - string iX = itemX?.SubItems[Column].Text; - string iY = itemY?.SubItems[Column].Text; - - /* - if (int.TryParse(iX, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out var iXint)) - { - if (int.TryParse(iY, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out var iYint)) - { - int val2 = iXint.CompareTo(iYint); - if (this.Direction) - return val2 * -1; - return val2; - } - } - */ - - int val = Math.Sign(string.Compare(iX, iY, StringComparison.CurrentCultureIgnoreCase)); - if (this.Direction) - return val * -1; - return val; - } + */ + + int val = Math.Sign(string.Compare(iX, iY, StringComparison.CurrentCultureIgnoreCase)); + if (this.Direction) + return val * -1; + return val; - public void Swap() - { - this.Direction = !this.Direction; - } } - #endregion + public void Swap() + { + this.Direction = !this.Direction; + } } + + #endregion } diff --git a/BundleManager/NativeSaveDialog.cs b/BundleManager/NativeSaveDialog.cs index 8b63544..a702ddf 100644 --- a/BundleManager/NativeSaveDialog.cs +++ b/BundleManager/NativeSaveDialog.cs @@ -4,148 +4,145 @@ using System.Threading; using System.Windows.Forms; -namespace BundleManager +namespace BundleManager; + +internal static class NativeSaveDialog { - internal static class NativeSaveDialog - { - private const uint FOS_OVERWRITEPROMPT = 0x2; - private const uint FOS_FORCEFILESYSTEM = 0x40; - private const uint SIGDN_FILESYSPATH = 0x80058000; - private const int ERROR_CANCELLED = unchecked((int)0x800704C7); + private const uint FOS_OVERWRITEPROMPT = 0x2; + private const uint FOS_FORCEFILESYSTEM = 0x40; + private const uint SIGDN_FILESYSPATH = 0x80058000; + private const int ERROR_CANCELLED = unchecked((int)0x800704C7); - public static string Show(IWin32Window owner, string fileName, string defaultExtension, string filter, Func onTypeChange, out int typeIndex) + public static string Show(IWin32Window owner, string fileName, string defaultExtension, string filter, Func onTypeChange, out int typeIndex) + { + IFileDialog dialog = (IFileDialog)new FileSaveDialog(); + try { - IFileDialog dialog = (IFileDialog)new FileSaveDialog(); + string[] parts = filter.Split('|'); + FilterSpec[] types = [.. Enumerable.Range(0, parts.Length / 2).Select(i => new FilterSpec { Name = parts[i * 2], Spec = parts[i * 2 + 1] })]; + + dialog.SetFileTypes((uint)types.Length, types); + dialog.SetFileTypeIndex(1); + dialog.SetDefaultExtension(defaultExtension); + dialog.SetFileName(fileName); + dialog.GetOptions(out uint options); + dialog.SetOptions(options | FOS_OVERWRITEPROMPT | FOS_FORCEFILESYSTEM); + + dialog.Advise(new Events(onTypeChange), out uint cookie); try { - string[] parts = filter.Split('|'); - FilterSpec[] types = Enumerable.Range(0, parts.Length / 2) - .Select(i => new FilterSpec { Name = parts[i * 2], Spec = parts[i * 2 + 1] }) - .ToArray(); - - dialog.SetFileTypes((uint)types.Length, types); - dialog.SetFileTypeIndex(1); - dialog.SetDefaultExtension(defaultExtension); - dialog.SetFileName(fileName); - dialog.GetOptions(out uint options); - dialog.SetOptions(options | FOS_OVERWRITEPROMPT | FOS_FORCEFILESYSTEM); - - dialog.Advise(new Events(onTypeChange), out uint cookie); - try - { - int hr = dialog.Show(owner?.Handle ?? IntPtr.Zero); - dialog.GetFileTypeIndex(out uint index); - typeIndex = (int)index; - - if (hr == ERROR_CANCELLED) - return null; - Marshal.ThrowExceptionForHR(hr); - - dialog.GetResult(out IShellItem item); - item.GetDisplayName(SIGDN_FILESYSPATH, out string path); - return path; - } - finally - { - dialog.Unadvise(cookie); - } + int hr = dialog.Show(owner?.Handle ?? IntPtr.Zero); + dialog.GetFileTypeIndex(out uint index); + typeIndex = (int)index; + + if (hr == ERROR_CANCELLED) + return null; + Marshal.ThrowExceptionForHR(hr); + + dialog.GetResult(out IShellItem item); + item.GetDisplayName(SIGDN_FILESYSPATH, out string path); + return path; } finally { - Marshal.FinalReleaseComObject(dialog); + dialog.Unadvise(cookie); } } - - private sealed class Events(Func onTypeChange) : IFileDialogEvents + finally { - private const int E_NOTIMPL = unchecked((int)0x80004001); + Marshal.FinalReleaseComObject(dialog); + } + } - public int OnTypeChange(IFileDialog pfd) - { - // The dialog rewrites the name's extension after this returns, so rename once it's done - if (SynchronizationContext.Current is SynchronizationContext context) - context.Post(_ => Rename(pfd), null); - else - Rename(pfd); - return 0; - } + private sealed class Events(Func onTypeChange) : IFileDialogEvents + { + private const int E_NOTIMPL = unchecked((int)0x80004001); - private void Rename(IFileDialog pfd) - { - pfd.GetFileTypeIndex(out uint index); - pfd.GetFileName(out string name); - string newName = onTypeChange((int)index, name ?? string.Empty); - if (newName != name) - pfd.SetFileName(newName); - } + public int OnTypeChange(IFileDialog pfd) + { + // The dialog rewrites the name's extension after this returns, so rename once it's done + if (SynchronizationContext.Current is SynchronizationContext context) + context.Post(_ => Rename(pfd), null); + else + Rename(pfd); + return 0; + } - public int OnFileOk(IFileDialog pfd) => 0; - public int OnFolderChanging(IFileDialog pfd, IShellItem psiFolder) => 0; - public int OnFolderChange(IFileDialog pfd) => 0; - public int OnSelectionChange(IFileDialog pfd) => 0; - public int OnShareViolation(IFileDialog pfd, IShellItem psi, out int pResponse) { pResponse = 0; return E_NOTIMPL; } - public int OnOverwrite(IFileDialog pfd, IShellItem psi, out int pResponse) { pResponse = 0; return E_NOTIMPL; } + private void Rename(IFileDialog pfd) + { + pfd.GetFileTypeIndex(out uint index); + pfd.GetFileName(out string name); + string newName = onTypeChange((int)index, name ?? string.Empty); + if (newName != name) + pfd.SetFileName(newName); } + + public int OnFileOk(IFileDialog pfd) => 0; + public int OnFolderChanging(IFileDialog pfd, IShellItem psiFolder) => 0; + public int OnFolderChange(IFileDialog pfd) => 0; + public int OnSelectionChange(IFileDialog pfd) => 0; + public int OnShareViolation(IFileDialog pfd, IShellItem psi, out int pResponse) { pResponse = 0; return E_NOTIMPL; } + public int OnOverwrite(IFileDialog pfd, IShellItem psi, out int pResponse) { pResponse = 0; return E_NOTIMPL; } } +} - [ComImport, Guid("C0B4E2F3-BA21-4773-8DBA-335EC946EB8B")] - internal class FileSaveDialog { } +[ComImport, Guid("C0B4E2F3-BA21-4773-8DBA-335EC946EB8B")] +internal class FileSaveDialog { } - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - internal struct FilterSpec - { - [MarshalAs(UnmanagedType.LPWStr)] public string Name; - [MarshalAs(UnmanagedType.LPWStr)] public string Spec; - } +[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] +internal struct FilterSpec +{ + [MarshalAs(UnmanagedType.LPWStr)] public string Name; + [MarshalAs(UnmanagedType.LPWStr)] public string Spec; +} - [ComImport, Guid("42f85136-db7e-439c-85f1-e4075d135fc8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - internal interface IFileDialog - { - [PreserveSig] int Show(IntPtr parent); - void SetFileTypes(uint cFileTypes, [MarshalAs(UnmanagedType.LPArray)] FilterSpec[] rgFilterSpec); - void SetFileTypeIndex(uint iFileType); - void GetFileTypeIndex(out uint piFileType); - void Advise(IFileDialogEvents pfde, out uint pdwCookie); - void Unadvise(uint dwCookie); - void SetOptions(uint fos); - void GetOptions(out uint pfos); - void SetDefaultFolder(IShellItem psi); - void SetFolder(IShellItem psi); - void GetFolder(out IShellItem ppsi); - void GetCurrentSelection(out IShellItem ppsi); - void SetFileName([MarshalAs(UnmanagedType.LPWStr)] string pszName); - void GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName); - void SetTitle([MarshalAs(UnmanagedType.LPWStr)] string pszTitle); - void SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string pszText); - void SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string pszLabel); - void GetResult(out IShellItem ppsi); - void AddPlace(IShellItem psi, int fdap); - void SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension); - void Close(int hr); - void SetClientGuid(ref Guid guid); - void ClearClientData(); - void SetFilter(IntPtr pFilter); - } +[ComImport, Guid("42f85136-db7e-439c-85f1-e4075d135fc8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +internal interface IFileDialog +{ + [PreserveSig] int Show(IntPtr parent); + void SetFileTypes(uint cFileTypes, [MarshalAs(UnmanagedType.LPArray)] FilterSpec[] rgFilterSpec); + void SetFileTypeIndex(uint iFileType); + void GetFileTypeIndex(out uint piFileType); + void Advise(IFileDialogEvents pfde, out uint pdwCookie); + void Unadvise(uint dwCookie); + void SetOptions(uint fos); + void GetOptions(out uint pfos); + void SetDefaultFolder(IShellItem psi); + void SetFolder(IShellItem psi); + void GetFolder(out IShellItem ppsi); + void GetCurrentSelection(out IShellItem ppsi); + void SetFileName([MarshalAs(UnmanagedType.LPWStr)] string pszName); + void GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName); + void SetTitle([MarshalAs(UnmanagedType.LPWStr)] string pszTitle); + void SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string pszText); + void SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string pszLabel); + void GetResult(out IShellItem ppsi); + void AddPlace(IShellItem psi, int fdap); + void SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension); + void Close(int hr); + void SetClientGuid(ref Guid guid); + void ClearClientData(); + void SetFilter(IntPtr pFilter); +} - [ComImport, Guid("973510db-7d7f-452b-8975-74a85828d354"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - internal interface IFileDialogEvents - { - [PreserveSig] int OnFileOk(IFileDialog pfd); - [PreserveSig] int OnFolderChanging(IFileDialog pfd, IShellItem psiFolder); - [PreserveSig] int OnFolderChange(IFileDialog pfd); - [PreserveSig] int OnSelectionChange(IFileDialog pfd); - [PreserveSig] int OnShareViolation(IFileDialog pfd, IShellItem psi, out int pResponse); - [PreserveSig] int OnTypeChange(IFileDialog pfd); - [PreserveSig] int OnOverwrite(IFileDialog pfd, IShellItem psi, out int pResponse); - } +[ComImport, Guid("973510db-7d7f-452b-8975-74a85828d354"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +internal interface IFileDialogEvents +{ + [PreserveSig] int OnFileOk(IFileDialog pfd); + [PreserveSig] int OnFolderChanging(IFileDialog pfd, IShellItem psiFolder); + [PreserveSig] int OnFolderChange(IFileDialog pfd); + [PreserveSig] int OnSelectionChange(IFileDialog pfd); + [PreserveSig] int OnShareViolation(IFileDialog pfd, IShellItem psi, out int pResponse); + [PreserveSig] int OnTypeChange(IFileDialog pfd); + [PreserveSig] int OnOverwrite(IFileDialog pfd, IShellItem psi, out int pResponse); +} - [ComImport, Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - internal interface IShellItem - { - void BindToHandler(IntPtr pbc, ref Guid bhid, ref Guid riid, out IntPtr ppv); - void GetParent(out IShellItem ppsi); - void GetDisplayName(uint sigdnName, [MarshalAs(UnmanagedType.LPWStr)] out string ppszName); - void GetAttributes(uint sfgaoMask, out uint psfgaoAttribs); - void Compare(IShellItem psi, uint hint, out int piOrder); - } +[ComImport, Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +internal interface IShellItem +{ + void BindToHandler(IntPtr pbc, ref Guid bhid, ref Guid riid, out IntPtr ppv); + void GetParent(out IShellItem ppsi); + void GetDisplayName(uint sigdnName, [MarshalAs(UnmanagedType.LPWStr)] out string ppszName); + void GetAttributes(uint sfgaoMask, out uint psfgaoAttribs); + void Compare(IShellItem psi, uint hint, out int piOrder); } diff --git a/BundleManager/Program.cs b/BundleManager/Program.cs index ebddf5c..7a07338 100644 --- a/BundleManager/Program.cs +++ b/BundleManager/Program.cs @@ -10,141 +10,138 @@ using BundleManager.TypeConverters; -namespace BundleManager +namespace BundleManager; + + +public static class Program { + public static MainForm fileModeForm; + public static FileView folderModeForm; + + private const string RegistryKeyPath = @"Software\BurnoutHints\BundleManager"; + private const string RegistryValueName = "PreferredMode"; // 1 = Studio, 0 = Bundle - public static class Program + /// + /// The main entry point for the application. + /// + [STAThread] + public static void Main(string[] args) { - public static MainForm fileModeForm; - public static FileView folderModeForm; + CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US"); - private const string RegistryKeyPath = @"Software\BurnoutHints\BundleManager"; - private const string RegistryValueName = "PreferredMode"; // 1 = Studio, 0 = Bundle + TypeDescriptor.AddAttributes(typeof(Vector4), new TypeConverterAttribute(typeof(Vector4Converter))); - /// - /// The main entry point for the application. - /// - [STAThread] - public static void Main(string[] args) - { - CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US"); + Application.EnableVisualStyles(); + Application.SetHighDpiMode(HighDpiMode.PerMonitorV2); + Application.SetCompatibleTextRenderingDefault(false); + + PluginLoader.InitializePlugins(); - TypeDescriptor.AddAttributes(typeof(Vector4), new TypeConverterAttribute(typeof(Vector4Converter))); + fileModeForm = new MainForm(); + folderModeForm = new FileView(); - Application.EnableVisualStyles(); - Application.SetHighDpiMode(HighDpiMode.PerMonitorV2); - Application.SetCompatibleTextRenderingDefault(false); + CheckElevation(); - PluginLoader.InitializePlugins(); + if (args.Length == 0) + { + bool? preferFolderMode = null; - fileModeForm = new MainForm(); - folderModeForm = new FileView(); + object? value = Registry.GetValue( + $@"HKEY_CURRENT_USER\{RegistryKeyPath}", + RegistryValueName, + null); - CheckElevation(); + if (value is int i) + preferFolderMode = i == 1; - if (args.Length == 0) + if (preferFolderMode is null) { - bool? preferFolderMode = null; + TaskDialogCommandLinkButton studio = new("Studio mode", + "Edit complex resources, such as models, that need dependent resources found in other bundles."); + TaskDialogCommandLinkButton bundle = new("Bundle mode", + "Make quicker, individual edits to a single bundle."); - object? value = Registry.GetValue( - $@"HKEY_CURRENT_USER\{RegistryKeyPath}", - RegistryValueName, - null); + TaskDialogPage page = new() + { + Caption = "Bundle Manager", + Heading = "Welcome to Bundle Manager.", + Text = "This program has two interchangable modes. Which one would you like to start in?\n\nYou can switch at any time with \"Switch to Bundle/Studio Mode\" at the top of the main window.", + Buttons = { bundle, studio, TaskDialogButton.Cancel }, + Footnote = "", + AllowCancel = true + }; - if (value is int i) - preferFolderMode = i == 1; + TaskDialogButton result = TaskDialog.ShowDialog(page); + if (result != studio && result != bundle) + return; - if (preferFolderMode is null) - { - TaskDialogCommandLinkButton studio = new("Studio mode", - "Edit complex resources, such as models, that need dependent resources found in other bundles."); - TaskDialogCommandLinkButton bundle = new("Bundle mode", - "Make quicker, individual edits to a single bundle."); + bool useFolderMode = result == studio; - TaskDialogPage page = new() - { - Caption = "Bundle Manager", - Heading = "Welcome to Bundle Manager.", - Text = "This program has two interchangable modes. Which one would you like to start in?\n\nYou can switch at any time with \"Switch to Bundle/Studio Mode\" at the top of the main window.", - Buttons = { bundle, studio, TaskDialogButton.Cancel }, - Footnote = "", - AllowCancel = true - }; - - TaskDialogButton result = TaskDialog.ShowDialog(page); - if (result != studio && result != bundle) - return; - - bool useFolderMode = result == studio; - - SavePreferredMode(useFolderMode); - - if (useFolderMode) - Application.Run(new FileView()); - else - Application.Run(new MainForm()); - } - else - { - if (preferFolderMode.Value) - Application.Run(new FileView()); - else - Application.Run(new MainForm()); - } + SavePreferredMode(useFolderMode); - return; + if (useFolderMode) + Application.Run(new FileView()); + else + Application.Run(new MainForm()); } else { - if (args.Length >= 1) + if (preferFolderMode.Value) + Application.Run(new FileView()); + else + Application.Run(new MainForm()); + } + + return; + } + else + { + if (args.Length >= 1) + { + string path = args[0]; + if (File.GetAttributes(path).HasFlag(FileAttributes.Directory)) { - string path = args[0]; - if (File.GetAttributes(path).HasFlag(FileAttributes.Directory)) - { - folderModeForm.Open(path); - Application.Run(folderModeForm); - } - else + folderModeForm.Open(path); + Application.Run(folderModeForm); + } + else + { + fileModeForm.Open(path); + if (args.Length >= 2) { - fileModeForm.Open(path); - if (args.Length >= 2) + string indexString = args[1]; + if (int.TryParse(indexString, out int index)) { - string indexString = args[1]; - if (int.TryParse(indexString, out int index)) - { - fileModeForm.ForceOnlySpecificEntry = true; - fileModeForm.EditEntry(index); - } + fileModeForm.ForceOnlySpecificEntry = true; + fileModeForm.EditEntry(index); } - Application.Run(fileModeForm); } + Application.Run(fileModeForm); } } } + } - public static void CheckElevation() + public static void CheckElevation() + { + using WindowsIdentity identity = WindowsIdentity.GetCurrent(); + WindowsPrincipal principal = new(identity); + if (!principal.IsInRole(WindowsBuiltInRole.Administrator)) { - using (WindowsIdentity identity = WindowsIdentity.GetCurrent()) - { - WindowsPrincipal principal = new(identity); - if (!principal.IsInRole(WindowsBuiltInRole.Administrator)) - { - MessageBox.Show("Bundle Manager is running with standard permissions.\n" - + "Saving may fail in write-protected locations.", - "Running non-elevated", - MessageBoxButtons.OK, - MessageBoxIcon.Warning); - } - } + MessageBox.Show("Bundle Manager is running with standard permissions.\n" + + "Saving may fail in write-protected locations.", + "Running non-elevated", + MessageBoxButtons.OK, + MessageBoxIcon.Warning); } + } - public static void SavePreferredMode(bool useFolderMode) - { - Registry.SetValue( - $@"HKEY_CURRENT_USER\{RegistryKeyPath}", - RegistryValueName, - useFolderMode ? 1 : 0, - RegistryValueKind.DWord); - } + public static void SavePreferredMode(bool useFolderMode) + { + Registry.SetValue( + $@"HKEY_CURRENT_USER\{RegistryKeyPath}", + RegistryValueName, + useFolderMode ? 1 : 0, + RegistryValueKind.DWord); } } diff --git a/BundleManager/ResourceImport.cs b/BundleManager/ResourceImport.cs index b2de4a3..6fa72ea 100644 --- a/BundleManager/ResourceImport.cs +++ b/BundleManager/ResourceImport.cs @@ -8,206 +8,205 @@ using System.Linq; using System.Text.RegularExpressions; -namespace BundleManager +namespace BundleManager; + +public record PrimaryResource(byte[] Data, byte[] ImageBody, List Imports, string ImportsSource, EntryType Type); + +public static partial class ResourceImport { - public record PrimaryResource(byte[] Data, byte[] ImageBody, List Imports, string ImportsSource, EntryType Type); + private static readonly string[] ImageExtensions = [".dds", ".bmp", ".gif", ".jpg", ".jpeg", ".png", ".tif", ".tiff"]; - public static partial class ResourceImport + public static PrimaryResource LoadPrimary(string path, BundleArchive archive, Func choosePCTexturePlatform, Func chooseCompression) { - private static readonly string[] ImageExtensions = [".dds", ".bmp", ".gif", ".jpg", ".jpeg", ".png", ".tif", ".tiff"]; - - public static PrimaryResource LoadPrimary(string path, BundleArchive archive, Func choosePCTexturePlatform, Func chooseCompression) + string extension = Path.GetExtension(path); + if (ImageExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase)) { - string extension = Path.GetExtension(path); - if (ImageExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase)) - { - BundleEntry sample = archive.Entries.FirstOrDefault(e => e.Type == EntryType.Texture && e.HasHeader); - PlatformType platform = GetImageTexturePlatform(archive, sample, choosePCTexturePlatform) - ?? throw new NotSupportedException($"Images can't be converted for {archive.Platform} bundles. Import the texture's header and body instead."); - - CompressionType compression = string.Equals(extension, ".dds", StringComparison.OrdinalIgnoreCase) - ? CompressionType.UNKNOWN // SetImage reads the DDS file's own format - : chooseCompression(path) ?? throw new OperationCanceledException(); - - // A blank header the size of the bundle's others, so 64-bit Remastered bundles get 64-bit headers - ImageInfo info = GameImage.SetImage(path, compression, platform, sample != null ? new byte[sample.EntryBlocks[0].Data.Length] : null); - return new(info.Header, info.Data, [], null, EntryType.Texture); - } - - byte[] data = ReadPrimary(path, archive.Console, out List imports); - string importsSource = imports != null ? Path.GetFileName(GetImportsYamlPath(path)) : null; - imports ??= ScanImports(data, archive.Platform); - - EntryType type = InferEntryType(data[..^(imports.Count * Dependency.Size)], imports.Count, archive.Console); - return new(data, null, imports, importsSource, type); - } + BundleEntry sample = archive.Entries.FirstOrDefault(e => e.Type == EntryType.Texture && e.HasHeader); + PlatformType platform = GetImageTexturePlatform(archive, sample, choosePCTexturePlatform) + ?? throw new NotSupportedException($"Images can't be converted for {archive.Platform} bundles. Import the texture's header and body instead."); - public static byte[] ReadPrimary(string path, bool bigEndian, out List imports) - { - byte[] data = File.ReadAllBytes(path); - string yamlPath = GetImportsYamlPath(path); - imports = yamlPath != null && File.Exists(yamlPath) ? LoadDependenciesFromYaml(yamlPath) : null; - return imports != null ? Dependency.AppendTable(data, imports, bigEndian) : data; + CompressionType compression = string.Equals(extension, ".dds", StringComparison.OrdinalIgnoreCase) + ? CompressionType.UNKNOWN // SetImage reads the DDS file's own format + : chooseCompression(path) ?? throw new OperationCanceledException(); + + // A blank header the size of the bundle's others, so 64-bit Remastered bundles get 64-bit headers + ImageInfo info = GameImage.SetImage(path, compression, platform, sample != null ? new byte[sample.EntryBlocks[0].Data.Length] : null); + return new(info.Header, info.Data, [], null, EntryType.Texture); } - // We now export the primary data without its import table and include a YAP-style yaml file for imports - public static void WritePrimary(string path, BundleEntry entry) - { - byte[] data = entry.EntryBlocks[0].Data; - List imports = entry.GetDependencies(); + byte[] data = ReadPrimary(path, archive.Console, out List imports); + string importsSource = imports != null ? Path.GetFileName(GetImportsYamlPath(path)) : null; + imports ??= ScanImports(data, archive.Platform); - int length = imports.Count > 0 && entry.Dependencies.Count == 0 ? entry.DependenciesListOffset : data.Length; - File.WriteAllBytes(path, data[..length]); + EntryType type = InferEntryType(data[..^(imports.Count * Dependency.Size)], imports.Count, archive.Console); + return new(data, null, imports, importsSource, type); + } - string yamlPath = GetImportsYamlPath(path); - if (imports.Count > 0) - File.WriteAllLines(yamlPath, imports.Select(d => $"- 0x{d.EntryPointerOffset:x8}: 0x{d.EntryID:x8}")); - else if (File.Exists(yamlPath)) - File.Delete(yamlPath); // From an earlier export of this resource, it would add imports back on import - } + public static byte[] ReadPrimary(string path, bool bigEndian, out List imports) + { + byte[] data = File.ReadAllBytes(path); + string yamlPath = GetImportsYamlPath(path); + imports = yamlPath != null && File.Exists(yamlPath) ? LoadDependenciesFromYaml(yamlPath) : null; + return imports != null ? Dependency.AppendTable(data, imports, bigEndian) : data; + } - public static void WritePrimaryWithTable(string path, BundleEntry entry) - { - File.WriteAllBytes(path, entry.EntryBlocks[0].Data); + // We now export the primary data without its import table and include a YAP-style yaml file for imports + public static void WritePrimary(string path, BundleEntry entry) + { + byte[] data = entry.EntryBlocks[0].Data; + List imports = entry.GetDependencies(); - string yamlPath = GetImportsYamlPath(path); - if (yamlPath == null || !File.Exists(yamlPath)) - return; + int length = imports.Count > 0 && entry.Dependencies.Count == 0 ? entry.DependenciesListOffset : data.Length; + File.WriteAllBytes(path, data[..length]); - var listed = LoadDependenciesFromYaml(yamlPath).Select(d => (d.ID, (long)d.EntryPointerOffset)); - var current = entry.GetDependencies().Select(d => (d.EntryID, (long)d.EntryPointerOffset)); - if (!listed.SequenceEqual(current)) - File.Delete(yamlPath); - } + string yamlPath = GetImportsYamlPath(path); + if (imports.Count > 0) + File.WriteAllLines(yamlPath, imports.Select(d => $"- 0x{d.EntryPointerOffset:x8}: 0x{d.EntryID:x8}")); + else if (File.Exists(yamlPath)) + File.Delete(yamlPath); // From an earlier export of this resource, it would add imports back on import + } - public static List ScanImports(byte[] data, BundlePlatform platform) - { - bool bigEndian = platform is BundlePlatform.X360 or BundlePlatform.PS3; - return Dependency.ScanTable(data, bigEndian, platform == BundlePlatform.PCx64 ? 8 : 4); - } + public static void WritePrimaryWithTable(string path, BundleEntry entry) + { + File.WriteAllBytes(path, entry.EntryBlocks[0].Data); - public static string GetResourceBaseName(string path) - { - const string primarySuffix = "_primary"; - string name = Path.GetFileNameWithoutExtension(path); + string yamlPath = GetImportsYamlPath(path); + if (yamlPath == null || !File.Exists(yamlPath)) + return; - return name.EndsWith(primarySuffix, StringComparison.OrdinalIgnoreCase) - ? name[..^primarySuffix.Length] - : name; - } + var listed = LoadDependenciesFromYaml(yamlPath).Select(d => (d.ID, (long)d.EntryPointerOffset)); + var current = entry.GetDependencies().Select(d => (d.EntryID, (long)d.EntryPointerOffset)); + if (!listed.SequenceEqual(current)) + File.Delete(yamlPath); + } - public static string FindSecondary(string primaryPath) - { - string secondary = Path.Combine(Path.GetDirectoryName(primaryPath), GetResourceBaseName(primaryPath) + "_secondary" + Path.GetExtension(primaryPath)); - return File.Exists(secondary) ? secondary : null; - } + public static List ScanImports(byte[] data, BundlePlatform platform) + { + bool bigEndian = platform is BundlePlatform.X360 or BundlePlatform.PS3; + return Dependency.ScanTable(data, bigEndian, platform == BundlePlatform.PCx64 ? 8 : 4); + } - // Exports are named after the resource ID, e.g. 0A7B302C_primary.dat - public static uint? GetIDFromFileName(string path) - { - Match match = ResourceIDPattern().Match(Path.GetFileNameWithoutExtension(path)); - return match.Success ? uint.Parse(match.Value, NumberStyles.HexNumber) : null; - } + public static string GetResourceBaseName(string path) + { + const string primarySuffix = "_primary"; + string name = Path.GetFileNameWithoutExtension(path); - public static bool TryParseHex(string s, out uint value) - { - return uint.TryParse(s.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? s[2..] : s, - NumberStyles.HexNumber, CultureInfo.InvariantCulture, out value); - } + return name.EndsWith(primarySuffix, StringComparison.OrdinalIgnoreCase) + ? name[..^primarySuffix.Length] + : name; + } - public static bool TextureMatchesBundle(byte[] header, BundlePlatform bundle) + public static string FindSecondary(string primaryPath) + { + string secondary = Path.Combine(Path.GetDirectoryName(primaryPath), GetResourceBaseName(primaryPath) + "_secondary" + Path.GetExtension(primaryPath)); + return File.Exists(secondary) ? secondary : null; + } + + // Exports are named after the resource ID, e.g. 0A7B302C_primary.dat + public static uint? GetIDFromFileName(string path) + { + Match match = ResourceIDPattern().Match(Path.GetFileNameWithoutExtension(path)); + return match.Success ? uint.Parse(match.Value, NumberStyles.HexNumber) : null; + } + + public static bool TryParseHex(string s, out uint value) + { + return uint.TryParse(s.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? s[2..] : s, + NumberStyles.HexNumber, CultureInfo.InvariantCulture, out value); + } + + public static bool TextureMatchesBundle(byte[] header, BundlePlatform bundle) + { + PlatformType texture = GameImage.DetectPlatform(header); + return texture == TexturePlatform(bundle) || (texture == PlatformType.Remastered && bundle == BundlePlatform.PC); + } + + private static PlatformType? TexturePlatform(BundlePlatform platform) => platform switch + { + BundlePlatform.PC => PlatformType.PC, + BundlePlatform.PCx64 => PlatformType.PCx64, + BundlePlatform.X360 => PlatformType.X360, + BundlePlatform.PS3 => PlatformType.PS3, + _ => null + }; + + private static PlatformType? GetImageTexturePlatform(BundleArchive archive, BundleEntry sample, Func choosePCTexturePlatform) + { + PlatformType? platform = sample != null + ? GameImage.DetectPlatform(sample.EntryBlocks[0].Data) + : archive.Platform == BundlePlatform.PC + ? choosePCTexturePlatform() + : TexturePlatform(archive.Platform); + + // GameImage.SetImage can only write these + return platform is PlatformType.PC or PlatformType.PCx64 or PlatformType.Remastered ? platform : null; + } + + private static EntryType InferEntryType(byte[] data, int importCount, bool bigEndian) + { + bool Has(ReadOnlySpan magic) => data.AsSpan().IndexOf(magic) >= 0; + + // AttribSysVault + if (bigEndian + ? Has("StrN"u8) && Has("Vers"u8) + : Has("NrtS"u8) && Has("sreV"u8)) { - PlatformType texture = GameImage.DetectPlatform(header); - return texture == TexturePlatform(bundle) || (texture == PlatformType.Remastered && bundle == BundlePlatform.PC); + return EntryType.AttribSysVault; } - private static PlatformType? TexturePlatform(BundlePlatform platform) => platform switch + EntryType type = EntryType.Invalid; + + // Texture + if (GameImage.DetectPlatform(data) is PlatformType p + && p != PlatformType.Invalid + && importCount == 0) { - BundlePlatform.PC => PlatformType.PC, - BundlePlatform.PCx64 => PlatformType.PCx64, - BundlePlatform.X360 => PlatformType.X360, - BundlePlatform.PS3 => PlatformType.PS3, - _ => null - }; - - private static PlatformType? GetImageTexturePlatform(BundleArchive archive, BundleEntry sample, Func choosePCTexturePlatform) + type = EntryType.Texture; + } + // Model + else if (data.Length <= 0x20) { - PlatformType? platform = sample != null - ? GameImage.DetectPlatform(sample.EntryBlocks[0].Data) - : archive.Platform == BundlePlatform.PC - ? choosePCTexturePlatform() - : TexturePlatform(archive.Platform); - - // GameImage.SetImage can only write these - return platform is PlatformType.PC or PlatformType.PCx64 or PlatformType.Remastered ? platform : null; + // 32 bit model, then 64 bit model (32 bit is technically padded to nearest 0x10, so this would run anyway) + if ((data.Length > 0x13 && data[0x13] == 0x2) + || (data.Length > 0x1F && data[0x1F] == 0x2)) + type = EntryType.Model; } - - private static EntryType InferEntryType(byte[] data, int importCount, bool bigEndian) + // Renderable + else { - bool Has(ReadOnlySpan magic) => data.AsSpan().IndexOf(magic) >= 0; - - // AttribSysVault - if (bigEndian - ? Has("StrN"u8) && Has("Vers"u8) - : Has("NrtS"u8) && Has("sreV"u8)) - { - return EntryType.AttribSysVault; - } - - EntryType type = EntryType.Invalid; - - // Texture - if (GameImage.DetectPlatform(data) is PlatformType p - && p != PlatformType.Invalid - && importCount == 0) - { - type = EntryType.Texture; - } - // Model - else if (data.Length <= 0x20) - { - // 32 bit model, then 64 bit model (32 bit is technically padded to nearest 0x10, so this would run anyway) - if ((data.Length > 0x13 && data[0x13] == 0x2) - || (data.Length > 0x1F && data[0x1F] == 0x2)) - type = EntryType.Model; - } - // Renderable - else - { - ReadOnlySpan version = data.AsSpan(0x10); // mu16VersionNumber - if ((bigEndian ? BinaryPrimitives.ReadUInt16BigEndian(version) : BinaryPrimitives.ReadUInt16LittleEndian(version)) == 11) - type = EntryType.Renderable; - } - - return type; + ReadOnlySpan version = data.AsSpan(0x10); // mu16VersionNumber + if ((bigEndian ? BinaryPrimitives.ReadUInt16BigEndian(version) : BinaryPrimitives.ReadUInt16LittleEndian(version)) == 11) + type = EntryType.Renderable; } - private static string GetImportsYamlPath(string primaryPath) - { - string dir = Path.GetDirectoryName(primaryPath); - string name = GetResourceBaseName(primaryPath); + return type; + } - if (string.IsNullOrEmpty(dir) || string.IsNullOrEmpty(name)) - return null; + private static string GetImportsYamlPath(string primaryPath) + { + string dir = Path.GetDirectoryName(primaryPath); + string name = GetResourceBaseName(primaryPath); - return Path.Combine(dir, name + "_imports.yaml"); - } + if (string.IsNullOrEmpty(dir) || string.IsNullOrEmpty(name)) + return null; - private static List LoadDependenciesFromYaml(string yamlPath) - { - List list = []; + return Path.Combine(dir, name + "_imports.yaml"); + } - foreach (string line in File.ReadLines(yamlPath)) - { - string[] parts = line.Trim().TrimStart('-').Split(':'); - if (parts.Length == 2 && TryParseHex(parts[0].Trim(), out uint offset) && TryParseHex(parts[1].Trim(), out uint id)) - list.Add(new Dependency { EntryPointerOffset = offset, ID = id }); - } + private static List LoadDependenciesFromYaml(string yamlPath) + { + List list = []; - return list; + foreach (string line in File.ReadLines(yamlPath)) + { + string[] parts = line.Trim().TrimStart('-').Split(':'); + if (parts.Length == 2 && TryParseHex(parts[0].Trim(), out uint offset) && TryParseHex(parts[1].Trim(), out uint id)) + list.Add(new Dependency { EntryPointerOffset = offset, ID = id }); } - [GeneratedRegex(@"^[0-9A-Fa-f]{8}(?![0-9A-Fa-f])")] - private static partial Regex ResourceIDPattern(); + return list; } + + [GeneratedRegex(@"^[0-9A-Fa-f]{8}(?![0-9A-Fa-f])")] + private static partial Regex ResourceIDPattern(); } diff --git a/BundleManager/SaveData.cs b/BundleManager/SaveData.cs index 951d67d..d0759d1 100644 --- a/BundleManager/SaveData.cs +++ b/BundleManager/SaveData.cs @@ -2,75 +2,74 @@ using System.Collections.Generic; using System.IO; -namespace BundleManager +namespace BundleManager; + +public static class SaveData { - public static class SaveData - { - public static string SaveFolder = Environment.GetEnvironmentVariable("APPDATA") + "\\BurnoutStudio\\"; - public static string RecentFilesPath = SaveFolder + "RecentFiles.txt"; + public static string SaveFolder = Environment.GetEnvironmentVariable("APPDATA") + "\\BurnoutStudio\\"; + public static string RecentFilesPath = SaveFolder + "RecentFiles.txt"; - public static List RecentPaths = new List(); + public static List RecentPaths = []; - private static bool _initialized; + private static bool _initialized; - public static void Init() - { - if (_initialized) - return; - _initialized = true; - - if (!Directory.Exists(SaveFolder)) - Directory.CreateDirectory(SaveFolder); - } + public static void Init() + { + if (_initialized) + return; + _initialized = true; - public static void Load() - { - Init(); + if (!Directory.Exists(SaveFolder)) + Directory.CreateDirectory(SaveFolder); + } - RecentPaths.Clear(); + public static void Load() + { + Init(); - if (!File.Exists(RecentFilesPath)) - return; + RecentPaths.Clear(); - Stream s = File.Open(RecentFilesPath, FileMode.Open, FileAccess.Read); - StreamReader sr = new StreamReader(s); + if (!File.Exists(RecentFilesPath)) + return; - while (!sr.EndOfStream) - { - string line = sr.ReadLine(); - if (line != null && line.Trim().Length > 0) - RecentPaths.Add(line); - } + Stream s = File.Open(RecentFilesPath, FileMode.Open, FileAccess.Read); + StreamReader sr = new(s); - sr.Close(); - s.Close(); - } - - public static void Save() + while (!sr.EndOfStream) { - Init(); + string line = sr.ReadLine(); + if (line != null && line.Trim().Length > 0) + RecentPaths.Add(line); + } - Stream s = File.Open(RecentFilesPath, FileMode.Create); - StreamWriter sw = new StreamWriter(s); + sr.Close(); + s.Close(); + } - for (int i = 0; i < RecentPaths.Count; i++) - { - sw.WriteLine(RecentPaths[i]); - } + public static void Save() + { + Init(); - sw.Flush(); - sw.Close(); - s.Close(); - } + Stream s = File.Open(RecentFilesPath, FileMode.Create); + StreamWriter sw = new(s); - public static void AddRecentPath(string path) + for (int i = 0; i < RecentPaths.Count; i++) { - Load(); - if (RecentPaths.Contains(path)) - RecentPaths.Remove(path); - RecentPaths.Add(path); - if (RecentPaths.Count > 10) - RecentPaths.RemoveAt(0); + sw.WriteLine(RecentPaths[i]); } + + sw.Flush(); + sw.Close(); + s.Close(); + } + + public static void AddRecentPath(string path) + { + Load(); + if (RecentPaths.Contains(path)) + RecentPaths.Remove(path); + RecentPaths.Add(path); + if (RecentPaths.Count > 10) + RecentPaths.RemoveAt(0); } } diff --git a/BundleManager/SearchDialog.cs b/BundleManager/SearchDialog.cs index 3644e44..dfa0c06 100644 --- a/BundleManager/SearchDialog.cs +++ b/BundleManager/SearchDialog.cs @@ -3,55 +3,53 @@ using System.Windows.Forms; using BundleUtilities; -namespace BundleManager +namespace BundleManager; + +public partial class SearchDialog : Form { - public partial class SearchDialog : Form - { - public static string LastSearch = ""; + public static string LastSearch = ""; - public delegate void OnSearch(ulong id); - public event OnSearch Search; + public delegate void OnSearch(ulong id); + public event OnSearch Search; - public SearchDialog() - { - InitializeComponent(); + public SearchDialog() + { + InitializeComponent(); - txtSearch.Text = LastSearch; - } + txtSearch.Text = LastSearch; + } - private void btnCancel_Click(object sender, EventArgs e) + private void btnCancel_Click(object sender, EventArgs e) + { + Close(); + } + + private void btnSearch_Click(object sender, EventArgs e) + { + string input = txtSearch.Text; + if (input.Length == 0) { - Close(); + MessageBox.Show(this, "Please enter a search query!", "Warning", MessageBoxButtons.OK, + MessageBoxIcon.Warning); + return; } - private void btnSearch_Click(object sender, EventArgs e) + LastSearch = txtSearch.Text; + + string numInput = input; + + if (numInput.StartsWith("0x")) + numInput = numInput[2..]; + + if (ulong.TryParse(numInput, NumberStyles.AllowHexSpecifier, CultureInfo.CurrentCulture, out ulong id)) { - string input = txtSearch.Text; - if (input.Length == 0) - { - MessageBox.Show(this, "Please enter a search query!", "Warning", MessageBoxButtons.OK, - MessageBoxIcon.Warning); - return; - } - - LastSearch = txtSearch.Text; - - string numInput = input; - - if (numInput.StartsWith("0x")) - numInput = numInput.Substring(2); - - ulong id; - if (ulong.TryParse(numInput, NumberStyles.AllowHexSpecifier, CultureInfo.CurrentCulture, out id)) - { - Search?.Invoke(id); - Close(); - return; - } - - id = Crc32.HashCrc32B(input); Search?.Invoke(id); Close(); + return; } + + id = Crc32.HashCrc32B(input); + Search?.Invoke(id); + Close(); } } diff --git a/BundleManager/TypeConverters/Vector4Converter.cs b/BundleManager/TypeConverters/Vector4Converter.cs index a7269d1..c1f54c8 100644 --- a/BundleManager/TypeConverters/Vector4Converter.cs +++ b/BundleManager/TypeConverters/Vector4Converter.cs @@ -17,7 +17,7 @@ sealed class FieldPD : PropertyDescriptor public override Type PropertyType => typeof(float); public override object GetValue(object component) { - var v = (Vector4)component; + Vector4 v = (Vector4)component; return n == "X" ? v.X : n == "Y" ? v.Y : n == "Z" ? v.Z : v.W; } public override void SetValue(object component, object value) { } diff --git a/BundleManager/VertexSizePicker.cs b/BundleManager/VertexSizePicker.cs index 08e1a7c..d1fbfeb 100644 --- a/BundleManager/VertexSizePicker.cs +++ b/BundleManager/VertexSizePicker.cs @@ -3,49 +3,47 @@ using System.ComponentModel; using System.Windows.Forms; -namespace BundleManager +namespace BundleManager; + +public partial class VertexSizePicker : Form { - public partial class VertexSizePicker : Form + public int VertexSize { - public int VertexSize + get { - get - { - string val = cboSelect.Text; + string val = cboSelect.Text; - int result; - if (!int.TryParse(val, out result)) - return -1; - return result; - } + if (!int.TryParse(val, out int result)) + return -1; + return result; } + } - private List _vertexSizeList; - [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] - public List VertexSizeList + private List _vertexSizeList; + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public List VertexSizeList + { + get { return _vertexSizeList; } + set { - get { return _vertexSizeList; } - set - { - _vertexSizeList = value; + _vertexSizeList = value; - cboSelect.Items.Clear(); - foreach (int size in _vertexSizeList) - { - cboSelect.Items.Add(size); - } - cboSelect.SelectedIndex = 0; + cboSelect.Items.Clear(); + foreach (int size in _vertexSizeList) + { + cboSelect.Items.Add(size); } + cboSelect.SelectedIndex = 0; } + } - public VertexSizePicker() - { - InitializeComponent(); - } + public VertexSizePicker() + { + InitializeComponent(); + } - private void btnOk_Click(object sender, EventArgs e) - { - Close(); - } + private void btnOk_Click(object sender, EventArgs e) + { + Close(); } } diff --git a/BundleUtilities/BinaryReader2.cs b/BundleUtilities/BinaryReader2.cs index d19570f..1e7fe38 100644 --- a/BundleUtilities/BinaryReader2.cs +++ b/BundleUtilities/BinaryReader2.cs @@ -3,168 +3,167 @@ using System.IO; using System.Text; -namespace BundleUtilities +namespace BundleUtilities; + +public class BinaryReader2 : BinaryReader { - public class BinaryReader2 : BinaryReader + public bool BigEndian { get; set; } + + public BinaryReader2(Stream input, bool bigEndian = false) : base(input) { - public bool BigEndian { get; set; } + BigEndian = bigEndian; + } - public BinaryReader2(Stream input, bool bigEndian = false) : base(input) - { - BigEndian = bigEndian; - } + public override short ReadInt16() + { + if (BaseStream.Length - BaseStream.Position < 2) + throw new EndOfStreamException(); + if (BigEndian) + return BinaryPrimitives.ReadInt16BigEndian(ReadBytes(2)); + return BinaryPrimitives.ReadInt16LittleEndian(ReadBytes(2)); + } - public override short ReadInt16() - { - if (BaseStream.Length - BaseStream.Position < 2) - throw new EndOfStreamException(); - if (BigEndian) - return BinaryPrimitives.ReadInt16BigEndian(ReadBytes(2)); - return BinaryPrimitives.ReadInt16LittleEndian(ReadBytes(2)); - } + public override int ReadInt32() + { + if (BaseStream.Length - BaseStream.Position < 4) + throw new EndOfStreamException(); + if (BigEndian) + return BinaryPrimitives.ReadInt32BigEndian(ReadBytes(4)); + return BinaryPrimitives.ReadInt32LittleEndian(ReadBytes(4)); + } - public override int ReadInt32() - { - if (BaseStream.Length - BaseStream.Position < 4) - throw new EndOfStreamException(); - if (BigEndian) - return BinaryPrimitives.ReadInt32BigEndian(ReadBytes(4)); - return BinaryPrimitives.ReadInt32LittleEndian(ReadBytes(4)); - } + public override long ReadInt64() + { + if (BaseStream.Length - BaseStream.Position < 8) + throw new EndOfStreamException(); + if (BigEndian) + return BinaryPrimitives.ReadInt64BigEndian(ReadBytes(8)); + return BinaryPrimitives.ReadInt64LittleEndian(ReadBytes(8)); + } - public override long ReadInt64() - { - if (BaseStream.Length - BaseStream.Position < 8) - throw new EndOfStreamException(); - if (BigEndian) - return BinaryPrimitives.ReadInt64BigEndian(ReadBytes(8)); - return BinaryPrimitives.ReadInt64LittleEndian(ReadBytes(8)); - } + public override ushort ReadUInt16() + { + if (BaseStream.Length - BaseStream.Position < 2) + throw new EndOfStreamException(); + if (BigEndian) + return BinaryPrimitives.ReadUInt16BigEndian(ReadBytes(2)); + return BinaryPrimitives.ReadUInt16LittleEndian(ReadBytes(2)); + } - public override ushort ReadUInt16() - { - if (BaseStream.Length - BaseStream.Position < 2) - throw new EndOfStreamException(); - if (BigEndian) - return BinaryPrimitives.ReadUInt16BigEndian(ReadBytes(2)); - return BinaryPrimitives.ReadUInt16LittleEndian(ReadBytes(2)); - } + public override uint ReadUInt32() + { + if (BaseStream.Length - BaseStream.Position < 4) + throw new EndOfStreamException(); + if (BigEndian) + return BinaryPrimitives.ReadUInt32BigEndian(ReadBytes(4)); + return BinaryPrimitives.ReadUInt32LittleEndian(ReadBytes(4)); + } - public override uint ReadUInt32() - { - if (BaseStream.Length - BaseStream.Position < 4) - throw new EndOfStreamException(); - if (BigEndian) - return BinaryPrimitives.ReadUInt32BigEndian(ReadBytes(4)); - return BinaryPrimitives.ReadUInt32LittleEndian(ReadBytes(4)); - } + public override ulong ReadUInt64() + { + if (BaseStream.Length - BaseStream.Position < 8) + throw new EndOfStreamException(); + if (BigEndian) + return BinaryPrimitives.ReadUInt64BigEndian(ReadBytes(8)); + return BinaryPrimitives.ReadUInt64LittleEndian(ReadBytes(8)); + } - public override ulong ReadUInt64() - { - if (BaseStream.Length - BaseStream.Position < 8) - throw new EndOfStreamException(); - if (BigEndian) - return BinaryPrimitives.ReadUInt64BigEndian(ReadBytes(8)); - return BinaryPrimitives.ReadUInt64LittleEndian(ReadBytes(8)); - } + public override float ReadSingle() + { + if (BaseStream.Length - BaseStream.Position < 4) + throw new EndOfStreamException(); + if (BigEndian) + return BinaryPrimitives.ReadSingleBigEndian(ReadBytes(4)); + return BinaryPrimitives.ReadSingleLittleEndian(ReadBytes(4)); + } - public override float ReadSingle() - { - if (BaseStream.Length - BaseStream.Position < 4) - throw new EndOfStreamException(); - if (BigEndian) - return BinaryPrimitives.ReadSingleBigEndian(ReadBytes(4)); - return BinaryPrimitives.ReadSingleLittleEndian(ReadBytes(4)); - } + public override double ReadDouble() + { + if (BaseStream.Length - BaseStream.Position < 8) + throw new EndOfStreamException(); + if (BigEndian) + return BinaryPrimitives.ReadDoubleBigEndian(ReadBytes(8)); + return BinaryPrimitives.ReadDoubleLittleEndian(ReadBytes(8)); + } - public override double ReadDouble() - { - if (BaseStream.Length - BaseStream.Position < 8) - throw new EndOfStreamException(); - if (BigEndian) - return BinaryPrimitives.ReadDoubleBigEndian(ReadBytes(8)); - return BinaryPrimitives.ReadDoubleLittleEndian(ReadBytes(8)); - } + public void Align(int alignment) + { + if (BaseStream.Position % alignment == 0) + return; + BaseStream.Position = alignment * ((BaseStream.Position + (alignment - 1)) / alignment); + } - public void Align(int alignment) - { - if (BaseStream.Position % alignment == 0) - return; - BaseStream.Position = alignment * ((BaseStream.Position + (alignment - 1)) / alignment); - } + public string ReadCStr() + { + List bytes = []; - public string ReadCStr() + try { - List bytes = new List(); - - try - { - while (true) - { - byte c = ReadByte(); - if (c == '\0') - break; - bytes.Add(c); - } - } - catch (EndOfStreamException) + while (true) { - // Ignore + byte c = ReadByte(); + if (c == '\0') + break; + bytes.Add(c); } - return Encoding.UTF8.GetString(bytes.ToArray()); } - - public string ReadCStringPtr() + catch (EndOfStreamException) { - uint ptr = ReadUInt32(); - long pos = BaseStream.Position; - BaseStream.Position = ptr; - string result = ReadCStr(); - BaseStream.Position = pos; - - return result; + // Ignore } + return Encoding.UTF8.GetString([.. bytes]); + } - public string ReadLenString(int size) - { - string result = ""; - bool readNull = false; - for (int i = 0; i < size; i++) - { - char c = (char)ReadByte(); - if (c == '\0') - readNull = true; - if (!readNull) - result += c; - } + public string ReadCStringPtr() + { + uint ptr = ReadUInt32(); + long pos = BaseStream.Position; + BaseStream.Position = ptr; + string result = ReadCStr(); + BaseStream.Position = pos; - return result; - } + return result; + } - public bool EOF() + public string ReadLenString(int size) + { + string result = ""; + bool readNull = false; + for (int i = 0; i < size; i++) { - return BaseStream.Position >= BaseStream.Length; + char c = (char)ReadByte(); + if (c == '\0') + readNull = true; + if (!readNull) + result += c; } - public byte Peek() - { - byte b = ReadByte(); - BaseStream.Seek(-1, SeekOrigin.Current); - return b; - } + return result; + } - public void SkipUniquePadding(int numberOfBytes) - { - BaseStream.Position = BaseStream.Position + numberOfBytes; - } + public bool EOF() + { + return BaseStream.Position >= BaseStream.Length; + } - public void SkipPadding() + public byte Peek() + { + byte b = ReadByte(); + BaseStream.Seek(-1, SeekOrigin.Current); + return b; + } + + public void SkipUniquePadding(int numberOfBytes) + { + BaseStream.Position = BaseStream.Position + numberOfBytes; + } + + public void SkipPadding() + { + long currentLength = BaseStream.Position; + if (currentLength % 16 != 0) { - long currentLength = BaseStream.Position; - if (currentLength % 16 != 0) - { - BaseStream.Position = BaseStream.Position + (16 - currentLength % 16); - }; - } + BaseStream.Position = BaseStream.Position + (16 - currentLength % 16); + }; } } diff --git a/BundleUtilities/BinaryWriter2.cs b/BundleUtilities/BinaryWriter2.cs index 486127c..eb02d32 100644 --- a/BundleUtilities/BinaryWriter2.cs +++ b/BundleUtilities/BinaryWriter2.cs @@ -3,132 +3,131 @@ using System.IO; using System.Text; -namespace BundleUtilities +namespace BundleUtilities; + +public class BinaryWriter2 : BinaryWriter { - public class BinaryWriter2 : BinaryWriter + public bool BigEndian { get; set; } + + public BinaryWriter2(Stream input, bool bigEndian = false) : base(input) { - public bool BigEndian { get; set; } + BigEndian = bigEndian; + } - public BinaryWriter2(Stream input, bool bigEndian = false) : base(input) - { - BigEndian = bigEndian; - } + public override void Write(short value) + { + if (BigEndian) + base.Write(BinaryPrimitives.ReverseEndianness(value)); + else + base.Write(value); + } - public override void Write(short value) - { - if (BigEndian) - base.Write(BinaryPrimitives.ReverseEndianness(value)); - else - base.Write(value); - } + public override void Write(int value) + { + if (BigEndian) + base.Write(BinaryPrimitives.ReverseEndianness(value)); + else + base.Write(value); + } - public override void Write(int value) - { - if (BigEndian) - base.Write(BinaryPrimitives.ReverseEndianness(value)); - else - base.Write(value); - } + public override void Write(long value) + { + if (BigEndian) + base.Write(BinaryPrimitives.ReverseEndianness(value)); + else + base.Write(value); + } - public override void Write(long value) - { - if (BigEndian) - base.Write(BinaryPrimitives.ReverseEndianness(value)); - else - base.Write(value); - } + public override void Write(ushort value) + { + if (BigEndian) + base.Write(BinaryPrimitives.ReverseEndianness(value)); + else + base.Write(value); + } - public override void Write(ushort value) - { - if (BigEndian) - base.Write(BinaryPrimitives.ReverseEndianness(value)); - else - base.Write(value); - } + public override void Write(uint value) + { + if (BigEndian) + base.Write(BinaryPrimitives.ReverseEndianness(value)); + else + base.Write(value); + } - public override void Write(uint value) - { - if (BigEndian) - base.Write(BinaryPrimitives.ReverseEndianness(value)); - else - base.Write(value); - } + public override void Write(ulong value) + { + if (BigEndian) + base.Write(BinaryPrimitives.ReverseEndianness(value)); + else + base.Write(value); + } - public override void Write(ulong value) + public override void Write(float value) + { + if (BigEndian) { - if (BigEndian) - base.Write(BinaryPrimitives.ReverseEndianness(value)); - else - base.Write(value); + var bytes = BitConverter.GetBytes(value); + Array.Reverse(bytes); + base.Write(bytes); } + else + base.Write(value); + } - public override void Write(float value) + public override void Write(double value) + { + if (BigEndian) { - if (BigEndian) - { - var bytes = BitConverter.GetBytes(value); - Array.Reverse(bytes); - base.Write(bytes); - } - else - base.Write(value); + var bytes = BitConverter.GetBytes(value); + Array.Reverse(bytes); + base.Write(bytes); } + else + base.Write(value); + } - public override void Write(double value) - { - if (BigEndian) - { - var bytes = BitConverter.GetBytes(value); - Array.Reverse(bytes); - base.Write(bytes); - } - else - base.Write(value); - } + public void Align(byte alignment) + { + if (BaseStream.Position % alignment == 0) + return; + BaseStream.Position = alignment * ((BaseStream.Position + (alignment - 1)) / alignment); + BaseStream.Position--; + Write((byte)0); + } - public void Align(byte alignment) - { - if (BaseStream.Position % alignment == 0) - return; - BaseStream.Position = alignment * ((BaseStream.Position + (alignment - 1)) / alignment); - BaseStream.Position--; - Write((byte)0); - } + public void WriteCStr(string value) + { + byte[] bytes = Encoding.UTF8.GetBytes(value); + for (int i = 0; i < bytes.Length; i++) + Write(bytes[i]); + Write((byte)0); + } - public void WriteCStr(string value) + public void WriteLenString(string s, int len) + { + for (int i = 0; i < len; i++) { - byte[] bytes = Encoding.UTF8.GetBytes(value); - for (int i = 0; i < bytes.Length; i++) - Write(bytes[i]); - Write((byte)0); + if (i < s.Length) + Write((byte)s[i]); + else + Write((byte)0); } + } - public void WriteLenString(string s, int len) - { - for (int i = 0; i < len; i++) - { - if (i < s.Length) - Write((byte)s[i]); - else - Write((byte)0); - } - } + public void WriteUniquePadding(int numberOfPadding) + { + for (int i = 0; i < numberOfPadding; i++) + Write((byte)0); + } - public void WriteUniquePadding(int numberOfPadding) + // Add padding: Has to be divisible by 16, else add padding + public void WritePadding() + { + long currentLength = BaseStream.Length; + if (currentLength % 16 != 0) { - for (int i = 0; i < numberOfPadding; i++) + for (int i = 0; i < (16 - currentLength % 16); i++) Write((byte)0); - } - - // Add padding: Has to be divisible by 16, else add padding - public void WritePadding() - { - long currentLength = BaseStream.Length; - if (currentLength % 16 != 0) - { - for (int i = 0; i < (16 - currentLength % 16); i++) - Write((byte)0); - }; - } + }; } } diff --git a/BundleUtilities/BitScan.cs b/BundleUtilities/BitScan.cs index 7e4a510..8577157 100644 --- a/BundleUtilities/BitScan.cs +++ b/BundleUtilities/BitScan.cs @@ -1,40 +1,39 @@ using System.Diagnostics; -namespace BundleUtilities +namespace BundleUtilities; + +public static class BitScan { - public static class BitScan - { - private const ulong DeBruijnSequence = 0x37E84A99DAE458F; + private const ulong DeBruijnSequence = 0x37E84A99DAE458F; - private static readonly int[] MultiplyDeBruijnBitPosition = - { - 0, 1, 17, 2, 18, 50, 3, 57, - 47, 19, 22, 51, 29, 4, 33, 58, - 15, 48, 20, 27, 25, 23, 52, 41, - 54, 30, 38, 5, 43, 34, 59, 8, - 63, 16, 49, 56, 46, 21, 28, 32, - 14, 26, 24, 40, 53, 37, 42, 7, - 62, 55, 45, 31, 13, 39, 36, 6, - 61, 44, 12, 35, 60, 11, 10, 9, - }; + private static readonly int[] MultiplyDeBruijnBitPosition = + [ + 0, 1, 17, 2, 18, 50, 3, 57, + 47, 19, 22, 51, 29, 4, 33, 58, + 15, 48, 20, 27, 25, 23, 52, 41, + 54, 30, 38, 5, 43, 34, 59, 8, + 63, 16, 49, 56, 46, 21, 28, 32, + 14, 26, 24, 40, 53, 37, 42, 7, + 62, 55, 45, 31, 13, 39, 36, 6, + 61, 44, 12, 35, 60, 11, 10, 9, +]; - /// - /// Search the mask data from least significant bit (LSB) to the most significant bit (MSB) for a set bit (1) - /// using De Bruijn sequence approach. Warning: Will return zero for b = 0. - /// - /// Target number. - /// Zero-based position of LSB (from right to left). - public static int BitScanForward(ulong b) - { - Debug.Assert(b > 0, "Target number should not be zero"); - return MultiplyDeBruijnBitPosition[((ulong)((long)b & -(long)b) * DeBruijnSequence) >> 58]; - } + /// + /// Search the mask data from least significant bit (LSB) to the most significant bit (MSB) for a set bit (1) + /// using De Bruijn sequence approach. Warning: Will return zero for b = 0. + /// + /// Target number. + /// Zero-based position of LSB (from right to left). + public static int BitScanForward(ulong b) + { + Debug.Assert(b > 0, "Target number should not be zero"); + return MultiplyDeBruijnBitPosition[((ulong)((long)b & -(long)b) * DeBruijnSequence) >> 58]; + } - public static int BitScanReverse(uint mask) - { - int i; - for (i = 31; (mask >> i) == 0 && i >= 0; i--) ; - return i; - } + public static int BitScanReverse(uint mask) + { + int i; + for (i = 31; (mask >> i) == 0 && i >= 0; i--) ; + return i; } } diff --git a/BundleUtilities/Colour.cs b/BundleUtilities/Colour.cs index acc9111..2f97a85 100644 --- a/BundleUtilities/Colour.cs +++ b/BundleUtilities/Colour.cs @@ -1,53 +1,52 @@ -namespace BundleUtilities +namespace BundleUtilities; + +public class U8Colour +{ + public byte Red; + public byte Green; + public byte Blue; + public byte Alpha; + + private U8Colour(byte red, byte green, byte blue, byte alpha) + { + Red = red; + Green = green; + Blue = blue; + Alpha = alpha; + } + + public static U8Colour FromRGBA(byte red, byte green, byte blue, byte alpha) + { + return new U8Colour(red, green, blue, alpha); + } + + public static U8Colour FromARGB32(uint value) + { + return new U8Colour((byte)((value & 0xFF0000) >> 16), (byte)((value & 0xFF00) >> 8), (byte)(value & 0xFF), (byte)((value & 0xFF000000) >> 24)); + } + + public override string ToString() => $"RGBA({Red}, {Green}, {Blue}, {Alpha})"; +} + +public class FColour { - public class U8Colour + public float Red; + public float Green; + public float Blue; + public float Alpha; + + private FColour(float red, float green, float blue, float alpha) { - public byte Red; - public byte Green; - public byte Blue; - public byte Alpha; - - private U8Colour(byte red, byte green, byte blue, byte alpha) - { - Red = red; - Green = green; - Blue = blue; - Alpha = alpha; - } - - public static U8Colour FromRGBA(byte red, byte green, byte blue, byte alpha) - { - return new U8Colour(red, green, blue, alpha); - } - - public static U8Colour FromARGB32(uint value) - { - return new U8Colour((byte)((value & 0xFF0000) >> 16), (byte)((value & 0xFF00) >> 8), (byte)(value & 0xFF), (byte)((value & 0xFF000000) >> 24)); - } - - public override string ToString() => $"RGBA({Red}, {Green}, {Blue}, {Alpha})"; + Red = red; + Green = green; + Blue = blue; + Alpha = alpha; } - public class FColour + public static FColour FromRGBA(float red, float green, float blue, float alpha) { - public float Red; - public float Green; - public float Blue; - public float Alpha; - - private FColour(float red, float green, float blue, float alpha) - { - Red = red; - Green = green; - Blue = blue; - Alpha = alpha; - } - - public static FColour FromRGBA(float red, float green, float blue, float alpha) - { - return new FColour(red, green, blue, alpha); - } - - public override string ToString() => $"RGBA({Red}, {Green}, {Blue}, {Alpha})"; + return new FColour(red, green, blue, alpha); } + + public override string ToString() => $"RGBA({Red}, {Green}, {Blue}, {Alpha})"; } diff --git a/BundleUtilities/Config.cs b/BundleUtilities/Config.cs index b3d1def..69fa3ba 100644 --- a/BundleUtilities/Config.cs +++ b/BundleUtilities/Config.cs @@ -1,7 +1,6 @@ -namespace BundleUtilities +namespace BundleUtilities; + +public static class Config { - public static class Config - { - public static bool LoadMaterials; - } + public static bool LoadMaterials; } diff --git a/BundleUtilities/Crc32.cs b/BundleUtilities/Crc32.cs index bd2c9a5..406ed71 100644 --- a/BundleUtilities/Crc32.cs +++ b/BundleUtilities/Crc32.cs @@ -1,148 +1,146 @@ // from https://github.com/Daniel-McCarthy/Net-Hash -using System; using System.Text; -namespace BundleUtilities -{ - public static class Crc32 - { - private static readonly UInt32[] Crc32Table = +namespace BundleUtilities; + +public static class Crc32 { - 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005, - 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD, - 0x4C11DB70, 0x48D0C6C7, 0x4593E01E, 0x4152FDA9, 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75, - 0x6A1936C8, 0x6ED82B7F, 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, 0x709F7B7A, 0x745E66CD, - 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039, 0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, - 0xBE2B5B58, 0xBAEA46EF, 0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033, 0xA4AD16EA, 0xA06C0B5D, - 0xD4326D90, 0xD0F37027, 0xDDB056FE, 0xD9714B49, 0xC7361B4C, 0xC3F706FB, 0xCEB42022, 0xCA753D95, - 0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1, 0xE13EF6F4, 0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, - 0x34867077, 0x30476DC0, 0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072, - 0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16, 0x018AEB13, 0x054BF6A4, 0x0808D07D, 0x0CC9CDCA, - 0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE, 0x6B93DDDB, 0x6F52C06C, 0x6211E6B5, 0x66D0FB02, - 0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1, 0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA, - 0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B, 0xBB60ADFC, 0xB6238B25, 0xB2E29692, - 0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6, 0x99A95DF3, 0x9D684044, 0x902B669D, 0x94EA7B2A, - 0xE0B41DE7, 0xE4750050, 0xE9362689, 0xEDF73B3E, 0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2, - 0xC6BCF05F, 0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34, 0xDC3ABDED, 0xD8FBA05A, - 0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637, 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB, - 0x4F040D56, 0x4BC510E1, 0x46863638, 0x42472B8F, 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53, - 0x251D3B9E, 0x21DC2629, 0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5, 0x3F9B762C, 0x3B5A6B9B, - 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF, 0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, - 0xF12F560E, 0xF5EE4BB9, 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65, 0xEBA91BBC, 0xEF68060B, - 0xD727BBB6, 0xD3E6A601, 0xDEA580D8, 0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD, 0xCDA1F604, 0xC960EBB3, - 0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7, 0xAE3AFBA2, 0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, - 0x9B3660C6, 0x9FF77D71, 0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3, - 0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640, 0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, 0x43CDC09C, - 0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8, 0x68860BFD, 0x6C47164A, 0x61043093, 0x65C52D24, - 0x119B4BE9, 0x155A565E, 0x18197087, 0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC, - 0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D, 0x2056CD3A, 0x2D15EBE3, 0x29D4F654, - 0xC5A92679, 0xC1683BCE, 0xCC2B1D17, 0xC8EA00A0, 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB, 0xDBEE767C, - 0xE3A1CBC1, 0xE760D676, 0xEA23F0AF, 0xEEE2ED18, 0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4, - 0x89B8FD09, 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662, 0x933EB0BB, 0x97FFAD0C, - 0xAFB010B1, 0xAB710D06, 0xA6322BDF, 0xA2F33668, 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4 - }; + private static readonly uint[] Crc32Table = +[ + 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005, + 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD, + 0x4C11DB70, 0x48D0C6C7, 0x4593E01E, 0x4152FDA9, 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75, + 0x6A1936C8, 0x6ED82B7F, 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, 0x709F7B7A, 0x745E66CD, + 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039, 0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, + 0xBE2B5B58, 0xBAEA46EF, 0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033, 0xA4AD16EA, 0xA06C0B5D, + 0xD4326D90, 0xD0F37027, 0xDDB056FE, 0xD9714B49, 0xC7361B4C, 0xC3F706FB, 0xCEB42022, 0xCA753D95, + 0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1, 0xE13EF6F4, 0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, + 0x34867077, 0x30476DC0, 0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072, + 0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16, 0x018AEB13, 0x054BF6A4, 0x0808D07D, 0x0CC9CDCA, + 0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE, 0x6B93DDDB, 0x6F52C06C, 0x6211E6B5, 0x66D0FB02, + 0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1, 0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA, + 0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B, 0xBB60ADFC, 0xB6238B25, 0xB2E29692, + 0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6, 0x99A95DF3, 0x9D684044, 0x902B669D, 0x94EA7B2A, + 0xE0B41DE7, 0xE4750050, 0xE9362689, 0xEDF73B3E, 0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2, + 0xC6BCF05F, 0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34, 0xDC3ABDED, 0xD8FBA05A, + 0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637, 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB, + 0x4F040D56, 0x4BC510E1, 0x46863638, 0x42472B8F, 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53, + 0x251D3B9E, 0x21DC2629, 0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5, 0x3F9B762C, 0x3B5A6B9B, + 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF, 0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, + 0xF12F560E, 0xF5EE4BB9, 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65, 0xEBA91BBC, 0xEF68060B, + 0xD727BBB6, 0xD3E6A601, 0xDEA580D8, 0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD, 0xCDA1F604, 0xC960EBB3, + 0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7, 0xAE3AFBA2, 0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, + 0x9B3660C6, 0x9FF77D71, 0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3, + 0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640, 0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, 0x43CDC09C, + 0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8, 0x68860BFD, 0x6C47164A, 0x61043093, 0x65C52D24, + 0x119B4BE9, 0x155A565E, 0x18197087, 0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC, + 0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D, 0x2056CD3A, 0x2D15EBE3, 0x29D4F654, + 0xC5A92679, 0xC1683BCE, 0xCC2B1D17, 0xC8EA00A0, 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB, 0xDBEE767C, + 0xE3A1CBC1, 0xE760D676, 0xEA23F0AF, 0xEEE2ED18, 0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4, + 0x89B8FD09, 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662, 0x933EB0BB, 0x97FFAD0C, + 0xAFB010B1, 0xAB710D06, 0xA6322BDF, 0xA2F33668, 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4 + ]; - public static readonly UInt32[] Crc32BTable = - { - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, - 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, - 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, - 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, - 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, - 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, - 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, - 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, - 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, - 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, - 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, - 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, - 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, - 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, - 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, - 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, - 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, - 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, - 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, - 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, - 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, - 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, - 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, - 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, - 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, - 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D - }; + public static readonly uint[] Crc32BTable = + [ + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D + ]; - public static string HashCrc32(byte[] message) - { - UInt32 hash = UInt32.MaxValue; + public static string HashCrc32(byte[] message) + { + uint hash = uint.MaxValue; - for(UInt32 i = 0; i < message.Length; i++) - { - UInt32 index = message[i]; - index ^= ((hash & 0xFF000000) >> 24); - hash = Crc32Table[index] ^ (hash << 8); - } - return ReverseEndian((~hash)).ToString("X8"); + for(uint i = 0; i < message.Length; i++) + { + uint index = message[i]; + index ^= ((hash & 0xFF000000) >> 24); + hash = Crc32Table[index] ^ (hash << 8); + } + return ReverseEndian((~hash)).ToString("X8"); - } + } - public static string HashCrc32B(byte[] message) + public static string HashCrc32B(byte[] message) + { + uint hash = uint.MaxValue; + for (uint i = 0; i < message.Length; i++) { - UInt32 hash = UInt32.MaxValue; - for (UInt32 i = 0; i < message.Length; i++) - { - UInt32 index = message[i]; - index ^= (hash & 0x000000FF); - hash = Crc32BTable[index] ^ (hash >> 8); - } - - return (~hash).ToString("X8"); + uint index = message[i]; + index ^= (hash & 0x000000FF); + hash = Crc32BTable[index] ^ (hash >> 8); } - public static ulong HashCrc32B(string text) - { - byte[] message = Encoding.ASCII.GetBytes(text); - UInt32 hash = UInt32.MaxValue; - for (UInt32 i = 0; i < message.Length; i++) - { - UInt32 index = message[i]; - index ^= (hash & 0x000000FF); - hash = Crc32BTable[index] ^ (hash >> 8); - } + return (~hash).ToString("X8"); + } - return (~hash); - } - - public static uint HashEntryID(string id) + public static ulong HashCrc32B(string text) + { + byte[] message = Encoding.ASCII.GetBytes(text); + uint hash = uint.MaxValue; + for (uint i = 0; i < message.Length; i++) { - uint result = 0xFFFFFFFF; - for (int i = 0; i < id.Length; i++) - { - byte b = (byte)id[i]; - byte newByte = (byte)((b - 0x41) & 0xFF); - if (newByte <= 0x19) - b += 0x20; - byte lowByte = (byte)(result & 0xFF); - lowByte = (byte)((lowByte ^ b) & 0xFF); - result = (result >> 8) & 0x00FFFFFF; - result = (result ^ Crc32BTable[lowByte]) & 0xFFFFFFFF; - } - result = (~result) & 0xFFFFFFFF; - - return result; + uint index = message[i]; + index ^= (hash & 0x000000FF); + hash = Crc32BTable[index] ^ (hash >> 8); } - static UInt32 ReverseEndian(UInt32 hash) + return (~hash); + } + + public static uint HashEntryID(string id) + { + uint result = 0xFFFFFFFF; + for (int i = 0; i < id.Length; i++) { - return (((hash & 0x000000FF) << 24) | ((hash & 0xFF000000) >> 24) | ((hash & 0x00FF0000) >> 8) | ((hash & 0x0000FF00) << 8)); + byte b = (byte)id[i]; + byte newByte = (byte)((b - 0x41) & 0xFF); + if (newByte <= 0x19) + b += 0x20; + byte lowByte = (byte)(result & 0xFF); + lowByte = (byte)((lowByte ^ b) & 0xFF); + result = (result >> 8) & 0x00FFFFFF; + result = (result ^ Crc32BTable[lowByte]) & 0xFFFFFFFF; } + result = (~result) & 0xFFFFFFFF; + + return result; + } + + static uint ReverseEndian(uint hash) + { + return (((hash & 0x000000FF) << 24) | ((hash & 0xFF000000) >> 24) | ((hash & 0x00FF0000) >> 8) | ((hash & 0x0000FF00) << 8)); } } diff --git a/BundleUtilities/DebugTimer.cs b/BundleUtilities/DebugTimer.cs index 60f6771..f970a8f 100644 --- a/BundleUtilities/DebugTimer.cs +++ b/BundleUtilities/DebugTimer.cs @@ -1,39 +1,38 @@ using System.Diagnostics; -namespace BundleUtilities +namespace BundleUtilities; + +public class DebugTimer { - public class DebugTimer - { - private readonly Stopwatch _stopwatch; - public readonly string Name; + private readonly Stopwatch _stopwatch; + public readonly string Name; - private DebugTimer(string name) - { - Name = name; + private DebugTimer(string name) + { + Name = name; - _stopwatch = new Stopwatch(); - _stopwatch.Start(); - } + _stopwatch = new Stopwatch(); + _stopwatch.Start(); + } - public static DebugTimer Start(string name = "") - { - return new DebugTimer(name); - } + public static DebugTimer Start(string name = "") + { + return new DebugTimer(name); + } - public double Stop() - { - _stopwatch.Stop(); - return _stopwatch.Elapsed.TotalMilliseconds; - } + public double Stop() + { + _stopwatch.Stop(); + return _stopwatch.Elapsed.TotalMilliseconds; + } - public double StopLog() - { - double elapsed = Stop(); - if (Name == "") - Debug.WriteLine("took " + elapsed + " ms"); - else - Debug.WriteLine(Name + " took " + elapsed + " ms"); - return elapsed; - } + public double StopLog() + { + double elapsed = Stop(); + if (Name == "") + Debug.WriteLine("took " + elapsed + " ms"); + else + Debug.WriteLine(Name + " took " + elapsed + " ms"); + return elapsed; } } diff --git a/BundleUtilities/EncryptedString.cs b/BundleUtilities/EncryptedString.cs index 52d1130..ee0b8c7 100644 --- a/BundleUtilities/EncryptedString.cs +++ b/BundleUtilities/EncryptedString.cs @@ -1,160 +1,159 @@ using System; using System.Text; -namespace BundleUtilities +namespace BundleUtilities; + +public class EncryptedString { - public class EncryptedString + private ulong _encrypted; + public ulong Encrypted { - private ulong _encrypted; - public ulong Encrypted + get { - get - { - return _encrypted; - } - set - { - _encrypted = value; - DecryptBytes(); - } + return _encrypted; } - - private string _value; - public string Value + set { - get - { - DecryptBytes(); // TEMP - return _value; - } - set - { - _value = value; - EncryptBytes(); - } + _encrypted = value; + DecryptBytes(); } + } - public EncryptedString(ulong encrypted) + private string _value; + public string Value + { + get { - Encrypted = encrypted; + DecryptBytes(); // TEMP + return _value; } - - public EncryptedString(string value) + set { - Value = value; + _value = value; + EncryptBytes(); } + } - private void DecryptBytes() - { - byte[] bytes = DecryptString(_encrypted); + public EncryptedString(ulong encrypted) + { + Encrypted = encrypted; + } - string val = Encoding.ASCII.GetString(bytes); - _value = val.Trim(); - } + public EncryptedString(string value) + { + Value = value; + } - private byte[] DecryptString(ulong val) + private void DecryptBytes() + { + byte[] bytes = DecryptString(_encrypted); + + string val = Encoding.ASCII.GetString(bytes); + _value = val.Trim(); + } + + private byte[] DecryptString(ulong val) + { + byte[] buf = new byte[12]; // Normally 13 but C# only needs 12 because \0 is automatically added + ulong current = val; + int index = 11; + byte c; + do { - byte[] buf = new byte[12]; // Normally 13 but C# only needs 12 because \0 is automatically added - ulong current = val; - int index = 11; - byte c; - do - { - ulong mod = current % 0x28; - current = current / 0x28; + ulong mod = current % 0x28; + current = current / 0x28; - if ((byte)mod == 39) - { - c = (byte)'_'; - } - else if ((sbyte)mod < 13) // signed + if ((byte)mod == 39) + { + c = (byte)'_'; + } + else if ((sbyte)mod < 13) // signed + { + if ((sbyte)mod < 3) // signed { - if ((sbyte)mod < 3) // signed + if ((byte)mod == 2) + { + c = (byte)'/'; + } + else if ((byte)mod == 1) { - if ((byte)mod == 2) - { - c = (byte)'/'; - } - else if ((byte)mod == 1) - { - c = (byte)'-'; - } - else - { - c = (byte)(mod != 0 ? 0 : ' '); - } + c = (byte)'-'; } else { - c = (byte)(mod + '-'); + c = (byte)(mod != 0 ? 0 : ' '); } } else { - c = (byte)(mod + '4'); + c = (byte)(mod + '-'); } - buf[--index + 1] = c; } - while (index >= 0); - - return buf; + else + { + c = (byte)(mod + '4'); + } + buf[--index + 1] = c; } + while (index >= 0); - private void EncryptBytes() - { - ulong value = EncryptString(Encoding.ASCII.GetBytes(_value)); - _encrypted = value; - } + return buf; + } - private ulong EncryptString(byte[] bytes) - { + private void EncryptBytes() + { + ulong value = EncryptString(Encoding.ASCII.GetBytes(_value)); + _encrypted = value; + } - unchecked - { - if (bytes.Length > 12) - throw new ArgumentException("Encrypted Strings cannot be larger than 12 characters!"); + private ulong EncryptString(byte[] bytes) + { - ulong current = 0; + unchecked + { + if (bytes.Length > 12) + throw new ArgumentException("Encrypted Strings cannot be larger than 12 characters!"); - int index = 0; - do - { - int ind = ++index - 1; - byte c = 0; - if (ind < bytes.Length) - c = bytes[ind]; - - if (c > 0x00 && c < 0x20) - throw new ArgumentException("Encrypted Strings cannot contain characters between ASCII 0x00 and ASCII 0x20!"); - else if (c > 0x39 && c < 0x41) - throw new ArgumentException("Encrypted Strings cannot contain characters between ASCII 0x39 and ASCII 0x40!"); - else if (c > 0x5F) //0x5A) - throw new ArgumentException("Encrypted Strings cannot contain characters over ASCII 0x5F!");//0x5A!"); - - byte mod = 0; - if (c == ' ') - mod = 0; - else if (c == '-') - mod = 1; - else if (c == '/') - mod = 2; - else if (c == '_') - mod = 39; - else if (c >= '-' && c < '4') - mod = (byte)(c - '-'); - else if (c >= '4' && c <= '9') - mod = (byte)(c - '4' + 7); - else if (c >= '4') - mod = (byte)(c - '4'); - - current = (current * 0x28) + mod; - - } while (index < 12); - return current; - } + ulong current = 0; + + int index = 0; + do + { + int ind = ++index - 1; + byte c = 0; + if (ind < bytes.Length) + c = bytes[ind]; + + if (c > 0x00 && c < 0x20) + throw new ArgumentException("Encrypted Strings cannot contain characters between ASCII 0x00 and ASCII 0x20!"); + else if (c > 0x39 && c < 0x41) + throw new ArgumentException("Encrypted Strings cannot contain characters between ASCII 0x39 and ASCII 0x40!"); + else if (c > 0x5F) //0x5A) + throw new ArgumentException("Encrypted Strings cannot contain characters over ASCII 0x5F!");//0x5A!"); + + byte mod = 0; + if (c == ' ') + mod = 0; + else if (c == '-') + mod = 1; + else if (c == '/') + mod = 2; + else if (c == '_') + mod = 39; + else if (c >= '-' && c < '4') + mod = (byte)(c - '-'); + else if (c >= '4' && c <= '9') + mod = (byte)(c - '4' + 7); + else if (c >= '4') + mod = (byte)(c - '4'); + + current = (current * 0x28) + mod; + + } while (index < 12); + return current; } + } - public override string ToString() => Value; - } + public override string ToString() => Value; } diff --git a/BundleUtilities/ILoader.cs b/BundleUtilities/ILoader.cs index a5ebbf4..e849275 100644 --- a/BundleUtilities/ILoader.cs +++ b/BundleUtilities/ILoader.cs @@ -1,8 +1,7 @@ -namespace BundleUtilities +namespace BundleUtilities; + +public interface ILoader { - public interface ILoader - { - void SetStatus(string status); - void SetProgress(int progress); - } + void SetStatus(string status); + void SetProgress(int progress); } diff --git a/BundleUtilities/LoadingDialog.cs b/BundleUtilities/LoadingDialog.cs index 759f607..9fee119 100644 --- a/BundleUtilities/LoadingDialog.cs +++ b/BundleUtilities/LoadingDialog.cs @@ -1,125 +1,123 @@ -using BundleUtilities; using System; using System.ComponentModel; using System.Windows.Forms; -namespace BundleUtilities +namespace BundleUtilities; + +public partial class LoadingDialog : Form, ILoader { - public partial class LoadingDialog : Form, ILoader - { - public delegate void OnDone(bool cancelled, object value); - public event OnDone Done; + public delegate void OnDone(bool cancelled, object value); + public event OnDone Done; - private delegate object GetObject(); - private delegate void SetObject(object obj); - private object _value; - [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] - public object Value + private delegate object GetObject(); + private delegate void SetObject(object obj); + private object _value; + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public object Value + { + get { - get + if (InvokeRequired) { - if (InvokeRequired) - { - GetObject method = () => - { - return _value; - }; - return Invoke(method); - } - else + GetObject method = () => { return _value; - } + }; + return Invoke(method); } - set + else { - if (InvokeRequired) - { - SetObject method = (object obj) => - { - _value = obj; - }; - Invoke(method, value); - } - else + return _value; + } + } + set + { + if (InvokeRequired) + { + SetObject method = (object obj) => { - _value = value; - } + _value = obj; + }; + Invoke(method, value); + } + else + { + _value = value; } } + } - [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] - public bool IsDone { get; set; } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public bool IsDone { get; set; } - [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] - public string Status - { - get => lblStatus.Text; - set => lblStatus.Text = value; - } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public string Status + { + get => lblStatus.Text; + set => lblStatus.Text = value; + } - [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] - public int Progress - { - get => pboMain.Value; - set => pboMain.Value = value; - } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public int Progress + { + get => pboMain.Value; + set => pboMain.Value = value; + } - public LoadingDialog() - { - InitializeComponent(); + public LoadingDialog() + { + InitializeComponent(); - IsDone = false; - } + IsDone = false; + } + + private void btnCancel_Click(object sender, EventArgs e) + { + Close(); + } + + private void LoadingDialog_FormClosing(object sender, FormClosingEventArgs e) + { + Done?.Invoke(!IsDone, Value); + } - private void btnCancel_Click(object sender, EventArgs e) + private void tmrDoneCheck_Tick(object sender, EventArgs e) + { + if (IsDone) { + tmrDoneCheck.Enabled = false; Close(); } + } - private void LoadingDialog_FormClosing(object sender, FormClosingEventArgs e) + private delegate void SetStatusDelegate(string status); + public void SetStatus(string status) + { + if (InvokeRequired) { - Done?.Invoke(!IsDone, Value); + Invoke(new SetStatusDelegate(SetStatus), status); } - - private void tmrDoneCheck_Tick(object sender, EventArgs e) + else { - if (IsDone) - { - tmrDoneCheck.Enabled = false; - Close(); - } + if (Status != status) + Status = status; } + } - private delegate void SetStatusDelegate(string status); - public void SetStatus(string status) + private delegate void SetProgressDelegate(int progress); + public void SetProgress(int progress) + { + if (InvokeRequired) { - if (InvokeRequired) - { - Invoke(new SetStatusDelegate(SetStatus), status); - } - else - { - if (Status != status) - Status = status; - } + Invoke(new SetProgressDelegate(SetProgress), progress); } - - private delegate void SetProgressDelegate(int progress); - public void SetProgress(int progress) + else { - if (InvokeRequired) - { - Invoke(new SetProgressDelegate(SetProgress), progress); - } - else + if (Progress != progress) + Progress = progress; + if (pboMain.Style == ProgressBarStyle.Marquee) { - if (Progress != progress) - Progress = progress; - if (pboMain.Style == ProgressBarStyle.Marquee) - { - pboMain.Style = ProgressBarStyle.Blocks; - } + pboMain.Style = ProgressBarStyle.Blocks; } } } diff --git a/BundleUtilities/Lookup8.cs b/BundleUtilities/Lookup8.cs index 4883c77..9f251f7 100644 --- a/BundleUtilities/Lookup8.cs +++ b/BundleUtilities/Lookup8.cs @@ -1,81 +1,78 @@ -using System; +namespace BundleUtilities; -namespace BundleUtilities +public static class Lookup8 { - public static class Lookup8 + public static ulong Hash(byte[] key, ulong length, ulong level) { - public static ulong Hash(byte[] key, ulong length, ulong level) - { - ulong a, b, c, len; - - /* Set up the internal state */ - len = length; - a = b = level; /* the previous hash value */ - c = 0x9e3779b97f4a7c13L; /* the golden ratio; an arbitrary value, CHECK REMOVED THE LAST L */ - int index = 0; - /*---------------------------------------- handle most of the key */ - while (len >= 24) - { - a += (key[index + 0] + ((ulong)key[index + 1] << 8) + ((ulong)key[index + 2] << 16) + ((ulong)key[index + 3] << 24) - + ((ulong)key[index + 4] << 32) + ((ulong)key[index + 5] << 40) + ((ulong)key[index + 6] << 48) + ((ulong)key[index + 7] << 56)); - b += (key[index + 8] + ((ulong)key[index + 9] << 8) + ((ulong)key[index + 10] << 16) + ((ulong)key[index + 11] << 24) - + ((ulong)key[index + 12] << 32) + ((ulong)key[index + 13] << 40) + ((ulong)key[index + 14] << 48) + ((ulong)key[index + 15] << 56)); - c += (key[index + 16] + ((ulong)key[index + 17] << 8) + ((ulong)key[index + 18] << 16) + ((ulong)key[index + 19] << 24) - + ((ulong)key[index + 20] << 32) + ((ulong)key[index + 21] << 40) + ((ulong)key[index + 22] << 48) + ((ulong)key[index + 23] << 56)); - Mix64(ref a, ref b, ref c); - index += 24; len -= 24; - } + ulong a, b, c, len; - /*------------------------------------- handle the last 23 bytes */ - c += length; - switch (len) /* all the case statements fall through */ - { - case 23: c += ((ulong)key[index + 22] << 56); goto case 22; - case 22: c += ((ulong)key[index + 21] << 48); goto case 21; - case 21: c += ((ulong)key[index + 20] << 40); goto case 20; - case 20: c += ((ulong)key[index + 19] << 32); goto case 19; - case 19: c += ((ulong)key[index + 18] << 24); goto case 18; - case 18: c += ((ulong)key[index + 17] << 16); goto case 17; - case 17: c += ((ulong)key[index + 16] << 8); goto case 16; - /* the first byte of c is reserved for the length */ - case 16: b += ((ulong)key[index + 15] << 56); goto case 15; - case 15: b += ((ulong)key[index + 14] << 48); goto case 14; - case 14: b += ((ulong)key[index + 13] << 40); goto case 13; - case 13: b += ((ulong)key[index + 12] << 32); goto case 12; - case 12: b += ((ulong)key[index + 11] << 24); goto case 11; - case 11: b += ((ulong)key[index + 10] << 16); goto case 10; - case 10: b += ((ulong)key[index + 9] << 8); goto case 9; - case 9: b += ((ulong)key[index + 8]); goto case 8; - case 8: a += ((ulong)key[index + 7] << 56); goto case 7; - case 7: a += ((ulong)key[index + 6] << 48); goto case 6; - case 6: a += ((ulong)key[index + 5] << 40); goto case 5; - case 5: a += ((ulong)key[index + 4] << 32); goto case 4; - case 4: a += ((ulong)key[index + 3] << 24); goto case 3; - case 3: a += ((ulong)key[index + 2] << 16); goto case 2; - case 2: a += ((ulong)key[index + 1] << 8); goto case 1; - case 1: a += ((ulong)key[index + 0]); break; - /* case 0: nothing left to add */ - } + /* Set up the internal state */ + len = length; + a = b = level; /* the previous hash value */ + c = 0x9e3779b97f4a7c13L; /* the golden ratio; an arbitrary value, CHECK REMOVED THE LAST L */ + int index = 0; + /*---------------------------------------- handle most of the key */ + while (len >= 24) + { + a += (key[index + 0] + ((ulong)key[index + 1] << 8) + ((ulong)key[index + 2] << 16) + ((ulong)key[index + 3] << 24) + + ((ulong)key[index + 4] << 32) + ((ulong)key[index + 5] << 40) + ((ulong)key[index + 6] << 48) + ((ulong)key[index + 7] << 56)); + b += (key[index + 8] + ((ulong)key[index + 9] << 8) + ((ulong)key[index + 10] << 16) + ((ulong)key[index + 11] << 24) + + ((ulong)key[index + 12] << 32) + ((ulong)key[index + 13] << 40) + ((ulong)key[index + 14] << 48) + ((ulong)key[index + 15] << 56)); + c += (key[index + 16] + ((ulong)key[index + 17] << 8) + ((ulong)key[index + 18] << 16) + ((ulong)key[index + 19] << 24) + + ((ulong)key[index + 20] << 32) + ((ulong)key[index + 21] << 40) + ((ulong)key[index + 22] << 48) + ((ulong)key[index + 23] << 56)); Mix64(ref a, ref b, ref c); - /*-------------------------------------------- report the result */ - return c; + index += 24; len -= 24; } - // Not sure if that works - public static void Mix64(ref ulong a, ref ulong b, ref ulong c) + + /*------------------------------------- handle the last 23 bytes */ + c += length; + switch (len) /* all the case statements fall through */ { - a -= b; a -= c; a ^= (c >> 43); - b -= c; b -= a; b ^= (a << 9); - c -= a; c -= b; c ^= (b >> 8); - a -= b; a -= c; a ^= (c >> 38); - b -= c; b -= a; b ^= (a << 23); - c -= a; c -= b; c ^= (b >> 5); - a -= b; a -= c; a ^= (c >> 35); - b -= c; b -= a; b ^= (a << 49); - c -= a; c -= b; c ^= (b >> 11); - a -= b; a -= c; a ^= (c >> 12); - b -= c; b -= a; b ^= (a << 18); - c -= a; c -= b; c ^= (b >> 22); + case 23: c += ((ulong)key[index + 22] << 56); goto case 22; + case 22: c += ((ulong)key[index + 21] << 48); goto case 21; + case 21: c += ((ulong)key[index + 20] << 40); goto case 20; + case 20: c += ((ulong)key[index + 19] << 32); goto case 19; + case 19: c += ((ulong)key[index + 18] << 24); goto case 18; + case 18: c += ((ulong)key[index + 17] << 16); goto case 17; + case 17: c += ((ulong)key[index + 16] << 8); goto case 16; + /* the first byte of c is reserved for the length */ + case 16: b += ((ulong)key[index + 15] << 56); goto case 15; + case 15: b += ((ulong)key[index + 14] << 48); goto case 14; + case 14: b += ((ulong)key[index + 13] << 40); goto case 13; + case 13: b += ((ulong)key[index + 12] << 32); goto case 12; + case 12: b += ((ulong)key[index + 11] << 24); goto case 11; + case 11: b += ((ulong)key[index + 10] << 16); goto case 10; + case 10: b += ((ulong)key[index + 9] << 8); goto case 9; + case 9: b += ((ulong)key[index + 8]); goto case 8; + case 8: a += ((ulong)key[index + 7] << 56); goto case 7; + case 7: a += ((ulong)key[index + 6] << 48); goto case 6; + case 6: a += ((ulong)key[index + 5] << 40); goto case 5; + case 5: a += ((ulong)key[index + 4] << 32); goto case 4; + case 4: a += ((ulong)key[index + 3] << 24); goto case 3; + case 3: a += ((ulong)key[index + 2] << 16); goto case 2; + case 2: a += ((ulong)key[index + 1] << 8); goto case 1; + case 1: a += ((ulong)key[index + 0]); break; + /* case 0: nothing left to add */ } - + Mix64(ref a, ref b, ref c); + /*-------------------------------------------- report the result */ + return c; + } + // Not sure if that works + public static void Mix64(ref ulong a, ref ulong b, ref ulong c) + { + a -= b; a -= c; a ^= (c >> 43); + b -= c; b -= a; b ^= (a << 9); + c -= a; c -= b; c ^= (b >> 8); + a -= b; a -= c; a ^= (c >> 38); + b -= c; b -= a; b ^= (a << 23); + c -= a; c -= b; c ^= (b >> 5); + a -= b; a -= c; a ^= (c >> 35); + b -= c; b -= a; b ^= (a << 49); + c -= a; c -= b; c ^= (b >> 11); + a -= b; a -= c; a ^= (c >> 12); + b -= c; b -= a; b ^= (a << 18); + c -= a; c -= b; c ^= (b >> 22); } + } diff --git a/BundleUtilities/ReadFailedError.cs b/BundleUtilities/ReadFailedError.cs index 5b322ad..bf0496e 100644 --- a/BundleUtilities/ReadFailedError.cs +++ b/BundleUtilities/ReadFailedError.cs @@ -1,17 +1,16 @@ using System; -namespace BundleUtilities +namespace BundleUtilities; + +public class ReadFailedError : Exception { - public class ReadFailedError : Exception + public ReadFailedError(string msg) : base(msg) { - public ReadFailedError(string msg) : base(msg) - { - } + } - public ReadFailedError(string msg, Exception innerException) : base(msg, innerException) - { + public ReadFailedError(string msg, Exception innerException) : base(msg, innerException) + { - } } } diff --git a/BundleUtilities/TextureCache.cs b/BundleUtilities/TextureCache.cs index 50c029d..eb07e90 100644 --- a/BundleUtilities/TextureCache.cs +++ b/BundleUtilities/TextureCache.cs @@ -2,38 +2,37 @@ using System.Collections.Generic; using System.Drawing; -namespace BundleUtilities +namespace BundleUtilities; + +public static class TextureCache { - public static class TextureCache - { - private static readonly Dictionary _cachedTextures = new Dictionary(); + private static readonly Dictionary _cachedTextures = []; - public static void ResetCache() + public static void ResetCache() + { + foreach (ulong key in _cachedTextures.Keys) { - foreach (ulong key in _cachedTextures.Keys) - { - Image img = _cachedTextures[key]; - img.Dispose(); - } - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - _cachedTextures.Clear(); + Image img = _cachedTextures[key]; + img.Dispose(); } + GC.Collect(); + GC.WaitForPendingFinalizers(); + GC.Collect(); + _cachedTextures.Clear(); + } - public static void AddToCache(ulong id, Image image) - { - _cachedTextures[id] = image; - } + public static void AddToCache(ulong id, Image image) + { + _cachedTextures[id] = image; + } - public static bool Contains(ulong key) - { - return _cachedTextures.ContainsKey(key); - } + public static bool Contains(ulong key) + { + return _cachedTextures.ContainsKey(key); + } - public static Image GetTexture(ulong key) - { - return _cachedTextures[key]; - } + public static Image GetTexture(ulong key) + { + return _cachedTextures[key]; } } diff --git a/BundleUtilities/Utilities.cs b/BundleUtilities/Utilities.cs index 40b1ba1..d40b645 100644 --- a/BundleUtilities/Utilities.cs +++ b/BundleUtilities/Utilities.cs @@ -1,101 +1,97 @@ using System; -using System.Buffers.Binary; using System.ComponentModel; using System.IO; using System.Text; using System.Reflection; -namespace BundleUtilities +namespace BundleUtilities; + +public class LogWriter { - public class LogWriter - { - private string m_exePath = string.Empty; + private string m_exePath = string.Empty; - public LogWriter(string logMessage) - { - LogWrite(logMessage); - } + public LogWriter(string logMessage) + { + LogWrite(logMessage); + } - public void LogWrite(string logMessage) + public void LogWrite(string logMessage) + { + m_exePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + try { - m_exePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - try - { - using (StreamWriter w = File.AppendText(m_exePath + "\\" + "log.txt")) - { - Log(logMessage, w); - } - } - catch (Exception ex) - { - } + using StreamWriter w = File.AppendText(m_exePath + "\\" + "log.txt"); + Log(logMessage, w); } - - public void Log(string logMessage, TextWriter txtWriter) + catch (Exception ex) { - try - { - txtWriter.WriteLine("{0} {1} : {2}", DateTime.Now.ToLongTimeString(), - DateTime.Now.ToLongDateString(), logMessage); - } - catch (Exception ex) - { - } } } - public static class Utilities + public void Log(string logMessage, TextWriter txtWriter) { - public static ulong CalcLookup8(string text) + try { - byte[] message = Encoding.ASCII.GetBytes(text); - var hashValue = Lookup8.Hash(message, (ulong)message.Length, 0xABCDEF0011223344); - - return hashValue; + txtWriter.WriteLine("{0} {1} : {2}", DateTime.Now.ToLongTimeString(), + DateTime.Now.ToLongDateString(), logMessage); } - - public static bool IsValidPath(string path) + catch (Exception ex) { - return !string.IsNullOrEmpty(path); } + } +} - public static bool FileExists(string path) - { - return IsValidPath(path) && File.Exists(path); - } +public static class Utilities +{ + public static ulong CalcLookup8(string text) + { + byte[] message = Encoding.ASCII.GetBytes(text); + var hashValue = Lookup8.Hash(message, (ulong)message.Length, 0xABCDEF0011223344); - public static byte[] Pad(this byte[] self, int bytes) - { - if (self.Length == bytes) - return self; + return hashValue; + } - if (self.Length > bytes) - throw new ArgumentException("Cannot pad to " + bytes); + public static bool IsValidPath(string path) + { + return !string.IsNullOrEmpty(path); + } + + public static bool FileExists(string path) + { + return IsValidPath(path) && File.Exists(path); + } - byte[] result = new byte[bytes]; + public static byte[] Pad(this byte[] self, int bytes) + { + if (self.Length == bytes) + return self; - for (int i = 0; i < self.Length; i++) - { - result[i] = self[i]; - } + if (self.Length > bytes) + throw new ArgumentException("Cannot pad to " + bytes); - return result; - } + byte[] result = new byte[bytes]; - /// - /// Converts the specified text to an object. - /// - /// The type of the output object - /// The text representation of the object to convert. - /// Parse the input string as a hexadecimal number even if the input string is not prefixed with "0x" - /// An output System.Object that represents the converted text. - /// The string cannot be converted into the appropriate object. - public static void Parse(string s, bool forceHex, out T value) + for (int i = 0; i < self.Length; i++) { - if (forceHex && !s.StartsWith("0x")) - s = "0x" + s; - TypeConverter converter = TypeDescriptor.GetConverter(typeof(T)); - value = (T)converter.ConvertFromString(s); + result[i] = self[i]; } + + return result; + } + + /// + /// Converts the specified text to an object. + /// + /// The type of the output object + /// The text representation of the object to convert. + /// Parse the input string as a hexadecimal number even if the input string is not prefixed with "0x" + /// An output System.Object that represents the converted text. + /// The string cannot be converted into the appropriate object. + public static void Parse(string s, bool forceHex, out T value) + { + if (forceHex && !s.StartsWith("0x")) + s = "0x" + s; + TypeConverter converter = TypeDescriptor.GetConverter(typeof(T)); + value = (T)converter.ConvertFromString(s); } } diff --git a/BurnoutImage/ClusterFit.cs b/BurnoutImage/ClusterFit.cs index dfa2638..aaac9f9 100644 --- a/BurnoutImage/ClusterFit.cs +++ b/BurnoutImage/ClusterFit.cs @@ -1,34 +1,33 @@ using System; using BCnEncoder.Shared; -namespace BurnoutImage +namespace BurnoutImage; + +internal class ClusterFit : ColourFit { - internal class ClusterFit : ColourFit - { - public const int MaxIterations = 8; + public const int MaxIterations = 8; - public int IterationCount; - public Vec3 Principle; - public byte[] Order; - public Vec4[] PointWeights; - public Vec4 XSumWSum; - public Vec4 Metric; - public Vec4 BestError; + public int IterationCount; + public Vec3 Principle; + public byte[] Order; + public Vec4[] PointWeights; + public Vec4 XSumWSum; + public Vec4 Metric; + public Vec4 BestError; - public ClusterFit(ColourSet colours, CompressionFormat compression) : base(colours, compression) - { - Order = new byte[16 * MaxIterations]; - PointWeights = new Vec4[16]; - } + public ClusterFit(ColourSet colours, CompressionFormat compression) : base(colours, compression) + { + Order = new byte[16 * MaxIterations]; + PointWeights = new Vec4[16]; + } - protected override void Compress3(byte[] block, int offset) - { - throw new NotImplementedException(); - } + protected override void Compress3(byte[] block, int offset) + { + throw new NotImplementedException(); + } - protected override void Compress4(byte[] block, int offset) - { - throw new NotImplementedException(); - } + protected override void Compress4(byte[] block, int offset) + { + throw new NotImplementedException(); } } diff --git a/BurnoutImage/ColourFit.cs b/BurnoutImage/ColourFit.cs index ed3d8ab..f637a5c 100644 --- a/BurnoutImage/ColourFit.cs +++ b/BurnoutImage/ColourFit.cs @@ -1,34 +1,33 @@ using BCnEncoder.Shared; -namespace BurnoutImage +namespace BurnoutImage; + +internal abstract class ColourFit { - internal abstract class ColourFit + protected ColourSet Colours; + protected CompressionFormat Compression; + + public ColourFit(ColourSet colours, CompressionFormat compression) { - protected ColourSet Colours; - protected CompressionFormat Compression; + Colours = colours; + Compression = compression; + } - public ColourFit(ColourSet colours, CompressionFormat compression) + public void Compress(byte[] block, int offset) + { + bool isDxt1 = Compression == CompressionFormat.Bc1; + if (isDxt1) { - Colours = colours; - Compression = compression; + Compress3(block, offset); + if (!Colours.Transparent) + Compress4(block, offset); } - - public void Compress(byte[] block, int offset) + else { - bool isDxt1 = Compression == CompressionFormat.Bc1; - if (isDxt1) - { - Compress3(block, offset); - if (!Colours.Transparent) - Compress4(block, offset); - } - else - { - Compress4(block, offset); - } + Compress4(block, offset); } - - protected abstract void Compress3(byte[] block, int offset); - protected abstract void Compress4(byte[] block, int offset); } + + protected abstract void Compress3(byte[] block, int offset); + protected abstract void Compress4(byte[] block, int offset); } diff --git a/BurnoutImage/ColourSet.cs b/BurnoutImage/ColourSet.cs index fb68491..7239f67 100644 --- a/BurnoutImage/ColourSet.cs +++ b/BurnoutImage/ColourSet.cs @@ -1,110 +1,109 @@ using System; using BCnEncoder.Shared; -namespace BurnoutImage +namespace BurnoutImage; + +internal class ColourSet { - internal class ColourSet + public int Count; + public Vec3[] Points; + public float[] Weights; + public int[] Remap; + public bool Transparent; + + public ColourSet(byte[] rgba, int mask, CompressionFormat compression) { - public int Count; - public Vec3[] Points; - public float[] Weights; - public int[] Remap; - public bool Transparent; + Count = 0; + Transparent = false; - public ColourSet(byte[] rgba, int mask, CompressionFormat compression) - { - Count = 0; - Transparent = false; + Points = new Vec3[16]; + Weights = new float[16]; + Remap = new int[16]; - Points = new Vec3[16]; - Weights = new float[16]; - Remap = new int[16]; + // Check the compression mode for dxt1 + bool isDxt1 = compression == CompressionFormat.Bc1; + bool weightByAlpha = false; - // Check the compression mode for dxt1 - bool isDxt1 = compression == CompressionFormat.Bc1; - bool weightByAlpha = false; + // Create the minimal set + for (int i = 0; i < 16; ++i) + { + // Check if this pixel is enabled + int bit = 1 << i; + if ((mask & bit) == 0) + { + Remap[i] = -1; + continue; + } - // Create the minimal set - for (int i = 0; i < 16; ++i) + // Check for transparent pixels when using dxt1 + if (isDxt1 && rgba[4 * i + 3] < 128) { - // Check if this pixel is enabled - int bit = 1 << i; - if ((mask & bit) == 0) - { - Remap[i] = -1; - continue; - } + Remap[i] = -1; + Transparent = true; + continue; + } - // Check for transparent pixels when using dxt1 - if (isDxt1 && rgba[4 * i + 3] < 128) + // Loop over previous points for a match + for (int j = 0; ; ++j) + { + // allocate a new point + if (j == i) { - Remap[i] = -1; - Transparent = true; - continue; + // normalize coordinates to [0,1] + float x = (float)rgba[4 * i + 0] / 255.0f; + float y = (float)rgba[4 * i + 1] / 255.0f; + float z = (float)rgba[4 * i + 2] / 255.0f; + + // ensure there is always non-zero weight even for zero alpha + float w = (float)(rgba[4 * i + 3] + 1) / 256.0f; + + // add the point + Points[Count] = new Vec3(x, y, z); + Weights[Count] = (weightByAlpha ? w : 1.0f); + Remap[i] = Count; + + // Advance + ++Count; + break; } - // Loop over previous points for a match - for (int j = 0; ; ++j) + // check for a match + int oldbit = 1 << j; + bool match = ((mask & oldbit) != 0) + && (rgba[4 * i + 0] == rgba[4 * j + 0]) + && (rgba[4 * i + 1] == rgba[4 * j + 1]) + && (rgba[4 * i + 2] == rgba[4 * j + 2]) + && (rgba[4 * j + 3] >= 128 || !isDxt1); + if (match) { - // allocate a new point - if (j == i) - { - // normalize coordinates to [0,1] - float x = (float)rgba[4 * i + 0] / 255.0f; - float y = (float)rgba[4 * i + 1] / 255.0f; - float z = (float)rgba[4 * i + 2] / 255.0f; - - // ensure there is always non-zero weight even for zero alpha - float w = (float)(rgba[4 * i + 3] + 1) / 256.0f; - - // add the point - Points[Count] = new Vec3(x, y, z); - Weights[Count] = (weightByAlpha ? w : 1.0f); - Remap[i] = Count; - - // Advance - ++Count; - break; - } - - // check for a match - int oldbit = 1 << j; - bool match = ((mask & oldbit) != 0) - && (rgba[4 * i + 0] == rgba[4 * j + 0]) - && (rgba[4 * i + 1] == rgba[4 * j + 1]) - && (rgba[4 * i + 2] == rgba[4 * j + 2]) - && (rgba[4 * j + 3] >= 128 || !isDxt1); - if (match) - { - // get the index of the match - int index = Remap[j]; - - // ensure there is always non-zero weight even for zero alpha - float w = (float)(rgba[4 * i + 3] + 1) / 256.0f; - - // map to this point and increase the weight - Weights[index] += (weightByAlpha ? w : 1.0f); - Remap[i] = index; - break; - } + // get the index of the match + int index = Remap[j]; + + // ensure there is always non-zero weight even for zero alpha + float w = (float)(rgba[4 * i + 3] + 1) / 256.0f; + + // map to this point and increase the weight + Weights[index] += (weightByAlpha ? w : 1.0f); + Remap[i] = index; + break; } } - - // square root the weights - for (int i = 0; i < Count; ++i) - Weights[i] = (float)Math.Sqrt(Weights[i]); } - public void RemapIndices(byte[] source, byte[] target) + // square root the weights + for (int i = 0; i < Count; ++i) + Weights[i] = (float)Math.Sqrt(Weights[i]); + } + + public void RemapIndices(byte[] source, byte[] target) + { + for (int i = 0; i < 16; ++i) { - for (int i = 0; i < 16; ++i) - { - int j = Remap[i]; - if (j == -1) - target[i] = 3; - else - target[i] = source[j]; - } + int j = Remap[i]; + if (j == -1) + target[i] = 3; + else + target[i] = source[j]; } } } diff --git a/BurnoutImage/CompressionTools.cs b/BurnoutImage/CompressionTools.cs index eb14a7c..97050c6 100644 --- a/BurnoutImage/CompressionTools.cs +++ b/BurnoutImage/CompressionTools.cs @@ -6,38 +6,37 @@ using BCnEncoder.Encoder; using BCnEncoder.Shared; -namespace BurnoutImage +namespace BurnoutImage; + +public static class CompressionTools { - public static class CompressionTools + public static byte[] CompressTexture(string source, CompressionFormat compression) { - public static byte[] CompressTexture(string source, CompressionFormat compression) - { - BcEncoder encoder = new BcEncoder(); - encoder.OutputOptions.Format = compression; - encoder.OutputOptions.GenerateMipMaps = false; - encoder.OutputOptions.Quality = CompressionQuality.BestQuality; + BcEncoder encoder = new(); + encoder.OutputOptions.Format = compression; + encoder.OutputOptions.GenerateMipMaps = false; + encoder.OutputOptions.Quality = CompressionQuality.BestQuality; - using Bitmap image = new Bitmap(source); - Rectangle area = new Rectangle(0, 0, image.Width, image.Height); - BitmapData bits = image.LockBits(area, ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); // BGRA in memory - try - { - byte[] pixels = new byte[image.Width * image.Height * 4]; - for (int y = 0; y < image.Height; y++) - Marshal.Copy(bits.Scan0 + y * bits.Stride, pixels, y * image.Width * 4, image.Width * 4); + using Bitmap image = new(source); + Rectangle area = new(0, 0, image.Width, image.Height); + BitmapData bits = image.LockBits(area, ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); // BGRA in memory + try + { + byte[] pixels = new byte[image.Width * image.Height * 4]; + for (int y = 0; y < image.Height; y++) + Marshal.Copy(bits.Scan0 + y * bits.Stride, pixels, y * image.Width * 4, image.Width * 4); - return encoder.EncodeToRawBytes(pixels, image.Width, image.Height, BCnEncoder.Encoder.PixelFormat.Bgra32)[0]; - } - finally - { - image.UnlockBits(bits); - } + return encoder.EncodeToRawBytes(pixels, image.Width, image.Height, BCnEncoder.Encoder.PixelFormat.Bgra32)[0]; } - - public static byte[] DecompressTexture(byte[] source, int width, int height, CompressionFormat compression) + finally { - ColorRgba32[] pixels = new BcDecoder().DecodeRaw(source, width, height, compression); - return MemoryMarshal.AsBytes(pixels.AsSpan()).ToArray(); + image.UnlockBits(bits); } } + + public static byte[] DecompressTexture(byte[] source, int width, int height, CompressionFormat compression) + { + ColorRgba32[] pixels = new BcDecoder().DecodeRaw(source, width, height, compression); + return MemoryMarshal.AsBytes(pixels.AsSpan()).ToArray(); + } } diff --git a/BurnoutImage/DirectBitmap.cs b/BurnoutImage/DirectBitmap.cs index 1a16a5b..90263a6 100644 --- a/BurnoutImage/DirectBitmap.cs +++ b/BurnoutImage/DirectBitmap.cs @@ -3,50 +3,49 @@ using System.Drawing.Imaging; using System.Runtime.InteropServices; -namespace BurnoutImage +namespace BurnoutImage; + +public class DirectBitmap : IDisposable { - public class DirectBitmap : IDisposable - { - public Bitmap Bitmap { get; private set; } - //public byte[] Bits { get; private set; } - public int[] Bits { get; private set; } - public bool Disposed { get; private set; } - public int Height { get; private set; } - public int Width { get; private set; } + public Bitmap Bitmap { get; private set; } + //public byte[] Bits { get; private set; } + public int[] Bits { get; private set; } + public bool Disposed { get; private set; } + public int Height { get; private set; } + public int Width { get; private set; } - protected GCHandle BitsHandle { get; private set; } + protected GCHandle BitsHandle { get; private set; } - public DirectBitmap(int width, int height) - { - Width = width; - Height = height; - //Bits = new byte[width * height * 4]; - Bits = new int[width * height]; - BitsHandle = GCHandle.Alloc(Bits, GCHandleType.Pinned); - Bitmap = new Bitmap(width, height, width * 4, PixelFormat.Format32bppArgb, BitsHandle.AddrOfPinnedObject()); - } + public DirectBitmap(int width, int height) + { + Width = width; + Height = height; + //Bits = new byte[width * height * 4]; + Bits = new int[width * height]; + BitsHandle = GCHandle.Alloc(Bits, GCHandleType.Pinned); + Bitmap = new Bitmap(width, height, width * 4, PixelFormat.Format32bppArgb, BitsHandle.AddrOfPinnedObject()); + } - public void SetPixel(int x, int y, Color colour) - { - int index = x + (y * Width); - int col = colour.ToArgb(); - Bits[index] = col; - } + public void SetPixel(int x, int y, Color colour) + { + int index = x + (y * Width); + int col = colour.ToArgb(); + Bits[index] = col; + } - public Color GetPixel(int x, int y) - { - int index = x + (y * Width); - int col = Bits[index]; - Color result = Color.FromArgb(col); - return result; - } + public Color GetPixel(int x, int y) + { + int index = x + (y * Width); + int col = Bits[index]; + Color result = Color.FromArgb(col); + return result; + } - public void Dispose() - { - if (Disposed) return; - Disposed = true; - Bitmap.Dispose(); - BitsHandle.Free(); - } + public void Dispose() + { + if (Disposed) return; + Disposed = true; + Bitmap.Dispose(); + BitsHandle.Free(); } } diff --git a/BurnoutImage/Extensions.cs b/BurnoutImage/Extensions.cs index 80c9dfd..30a3194 100644 --- a/BurnoutImage/Extensions.cs +++ b/BurnoutImage/Extensions.cs @@ -1,21 +1,20 @@ -namespace BurnoutImage +namespace BurnoutImage; + +internal static class Extensions { - internal static class Extensions + internal static bool Matches(this byte[] self, byte[] other) { - internal static bool Matches(this byte[] self, byte[] other) + if (self == null || other == null) + return false; + if (self.Length != other.Length) + return false; + + for (int i = 0; i < self.Length; i++) { - if (self == null || other == null) - return false; - if (self.Length != other.Length) + if (self[i] != other[i]) return false; - - for (int i = 0; i < self.Length; i++) - { - if (self[i] != other[i]) - return false; - } - - return true; } + + return true; } } diff --git a/BurnoutImage/GameImage.cs b/BurnoutImage/GameImage.cs index 92d1552..bc41e7a 100644 --- a/BurnoutImage/GameImage.cs +++ b/BurnoutImage/GameImage.cs @@ -6,490 +6,489 @@ using BCnEncoder.Shared; using BundleUtilities; -namespace BurnoutImage +namespace BurnoutImage; + +public struct ImageInfo { - public struct ImageInfo - { - public readonly byte[] Header; - public readonly byte[] Data; + public readonly byte[] Header; + public readonly byte[] Data; - public ImageInfo(byte[] header, byte[] data) - { - this.Header = header; - this.Data = data; - } + public ImageInfo(byte[] header, byte[] data) + { + this.Header = header; + this.Data = data; } +} - public class ImageHeader - { - public readonly PlatformType Platform; - public readonly CompressionType CompressionType; - public readonly int Width, Height; +public class ImageHeader +{ + public readonly PlatformType Platform; + public readonly CompressionType CompressionType; + public readonly int Width, Height; - public ImageHeader(CompressionType compression, int width, int height, PlatformType platform = PlatformType.Remastered) - { - CompressionType = compression; - Width = width; - Height = height; - Platform = platform; - } + public ImageHeader(CompressionType compression, int width, int height, PlatformType platform = PlatformType.Remastered) + { + CompressionType = compression; + Width = width; + Height = height; + Platform = platform; } +} - public static class GameImage - { - public const string FileFilter = "Image Files(*.dds,*.bmp;*.gif;*.jpg;*.png;*.tif)|*.dds;*.bmp;*.gif;*.jpg;*.jpeg;*.png;*.tif;*.tiff"; +public static class GameImage +{ + public const string FileFilter = "Image Files(*.dds,*.bmp;*.gif;*.jpg;*.png;*.tif)|*.dds;*.bmp;*.gif;*.jpg;*.jpeg;*.png;*.tif;*.tiff"; - public static (int Width, int Height, bool HasAlpha) InspectImage(string path) + public static (int Width, int Height, bool HasAlpha) InspectImage(string path) + { + using Bitmap image = new(path); + Rectangle area = new(0, 0, image.Width, image.Height); + System.Drawing.Imaging.BitmapData bits = image.LockBits(area, System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); + try { - using Bitmap image = new(path); - Rectangle area = new(0, 0, image.Width, image.Height); - System.Drawing.Imaging.BitmapData bits = image.LockBits(area, System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); - try - { - byte[] row = new byte[image.Width * 4]; // BGRA - for (int y = 0; y < image.Height; y++) - { - System.Runtime.InteropServices.Marshal.Copy(bits.Scan0 + y * bits.Stride, row, 0, row.Length); - for (int a = 3; a < row.Length; a += 4) - if (row[a] != 255) - return (image.Width, image.Height, true); - } - return (image.Width, image.Height, false); - } - finally + byte[] row = new byte[image.Width * 4]; // BGRA + for (int y = 0; y < image.Height; y++) { - image.UnlockBits(bits); + System.Runtime.InteropServices.Marshal.Copy(bits.Scan0 + y * bits.Stride, row, 0, row.Length); + for (int a = 3; a < row.Length; a += 4) + if (row[a] != 255) + return (image.Width, image.Height, true); } + return (image.Width, image.Height, false); } - - // Bytes of pixel data for a texture, including its smaller mips - public static int TextureSize(CompressionType compression, int width, int height, int mips = 1) + finally { - int size = 0; - for (int i = 0; i < mips; i++, width = Math.Max(1, width / 2), height = Math.Max(1, height / 2)) - size += compression is CompressionType.DXT1 or CompressionType.DXT5 - ? ((width + 3) / 4) * ((height + 3) / 4) * (compression == CompressionType.DXT1 ? 8 : 16) - : width * height * 4; - return size; + image.UnlockBits(bits); } + } - public static ImageInfo SetImage(string path, CompressionType compression, PlatformType platform = PlatformType.Remastered, byte[] template = null) - { - if (platform is not (PlatformType.PC or PlatformType.PCx64 or PlatformType.Remastered)) - throw new NotSupportedException($"Images can't be converted to {platform} textures yet."); + // Bytes of pixel data for a texture, including its smaller mips + public static int TextureSize(CompressionType compression, int width, int height, int mips = 1) + { + int size = 0; + for (int i = 0; i < mips; i++, width = Math.Max(1, width / 2), height = Math.Max(1, height / 2)) + size += compression is CompressionType.DXT1 or CompressionType.DXT5 + ? ((width + 3) / 4) * ((height + 3) / 4) * (compression == CompressionType.DXT1 ? 8 : 16) + : width * height * 4; + return size; + } - byte[] data; - int width = 0, height = 0, numMips = 1; + public static ImageInfo SetImage(string path, CompressionType compression, PlatformType platform = PlatformType.Remastered, byte[] template = null) + { + if (platform is not (PlatformType.PC or PlatformType.PCx64 or PlatformType.Remastered)) + throw new NotSupportedException($"Images can't be converted to {platform} textures yet."); - // Process body block + byte[] data; + int width = 0, height = 0, numMips = 1; - // Use direct DDS contents if provided (no extra processing) - if (string.Equals(Path.GetExtension(path), ".dds", StringComparison.OrdinalIgnoreCase)) - { - using FileStream fs = File.OpenRead(path); - using BinaryReader br = new(fs); - - uint magic = br.ReadUInt32(); - if (magic != 0x20534444) - throw new InvalidDataException("The provided DDS file is unsupported or corrupted."); - - fs.Seek(0xC, SeekOrigin.Begin); - height = br.ReadInt32(); - width = br.ReadInt32(); - - fs.Seek(0x1C, SeekOrigin.Begin); - numMips = br.ReadInt32(); - if (numMips <= 0) - numMips = 1; - - fs.Seek(0x4C, SeekOrigin.Begin); - uint pfSize = br.ReadUInt32(); - uint pfFlags = br.ReadUInt32(); - uint pfFourCC = br.ReadUInt32(); - uint pfRGBBits = br.ReadUInt32(); - uint pfRMask = br.ReadUInt32(); - uint pfGMask = br.ReadUInt32(); - uint pfBMask = br.ReadUInt32(); - uint pfAMask = br.ReadUInt32(); - - compression = ImageUtil.DetectDdsFormat( - pfFlags, - pfFourCC, - pfRGBBits, - pfRMask, - pfGMask, - pfBMask, - pfAMask - ); - - if (compression == CompressionType.UNKNOWN) - compression = CompressionType.RGBA; - - const int ddsHeaderSize = 0x80; - fs.Seek(ddsHeaderSize, SeekOrigin.Begin); - data = br.ReadBytes((int)(fs.Length - ddsHeaderSize)); + // Process body block - br.Close(); + // Use direct DDS contents if provided (no extra processing) + if (string.Equals(Path.GetExtension(path), ".dds", StringComparison.OrdinalIgnoreCase)) + { + using FileStream fs = File.OpenRead(path); + using BinaryReader br = new(fs); + + uint magic = br.ReadUInt32(); + if (magic != 0x20534444) + throw new InvalidDataException("The provided DDS file is unsupported or corrupted."); + + fs.Seek(0xC, SeekOrigin.Begin); + height = br.ReadInt32(); + width = br.ReadInt32(); + + fs.Seek(0x1C, SeekOrigin.Begin); + numMips = br.ReadInt32(); + if (numMips <= 0) + numMips = 1; + + fs.Seek(0x4C, SeekOrigin.Begin); + uint pfSize = br.ReadUInt32(); + uint pfFlags = br.ReadUInt32(); + uint pfFourCC = br.ReadUInt32(); + uint pfRGBBits = br.ReadUInt32(); + uint pfRMask = br.ReadUInt32(); + uint pfGMask = br.ReadUInt32(); + uint pfBMask = br.ReadUInt32(); + uint pfAMask = br.ReadUInt32(); + + compression = ImageUtil.DetectDdsFormat( + pfFlags, + pfFourCC, + pfRGBBits, + pfRMask, + pfGMask, + pfBMask, + pfAMask + ); + + if (compression == CompressionType.UNKNOWN) + compression = CompressionType.RGBA; + + const int ddsHeaderSize = 0x80; + fs.Seek(ddsHeaderSize, SeekOrigin.Begin); + data = br.ReadBytes((int)(fs.Length - ddsHeaderSize)); + + br.Close(); + + if (data.Length < TextureSize(compression, width, height, numMips)) + throw new InvalidDataException($"The DDS file has less pixel data than a {width}×{height} {compression} texture with {numMips} mips needs."); + } + // Process non-DDS textures + else + { + using Bitmap image = new(path); - if (data.Length < TextureSize(compression, width, height, numMips)) - throw new InvalidDataException($"The DDS file has less pixel data than a {width}×{height} {compression} texture with {numMips} mips needs."); - } - // Process non-DDS textures - else - { - using Bitmap image = new(path); + width = image.Width; + height = image.Height; - width = image.Width; - height = image.Height; + if (compression == CompressionType.BGRA) + { + MemoryStream mspixels = new(); - if (compression == CompressionType.BGRA) + for (int i = 0; i < height; i++) { - MemoryStream mspixels = new(); - - for (int i = 0; i < height; i++) + for (int j = 0; j < width; j++) { - for (int j = 0; j < width; j++) - { - Color pixel = image.GetPixel(j, i); - mspixels.WriteByte(pixel.B); - mspixels.WriteByte(pixel.G); - mspixels.WriteByte(pixel.R); - mspixels.WriteByte(pixel.A); - } + Color pixel = image.GetPixel(j, i); + mspixels.WriteByte(pixel.B); + mspixels.WriteByte(pixel.G); + mspixels.WriteByte(pixel.R); + mspixels.WriteByte(pixel.A); } + } - data = mspixels.ToArray(); + data = mspixels.ToArray(); - mspixels.Close(); - } - else + mspixels.Close(); + } + else + { + CompressionFormat dxt = compression switch { - CompressionFormat dxt = compression switch - { - CompressionType.DXT1 => CompressionFormat.Bc1, - CompressionType.DXT5 => CompressionFormat.Bc3, - _ => CompressionFormat.Unknown - }; + CompressionType.DXT1 => CompressionFormat.Bc1, + CompressionType.DXT5 => CompressionFormat.Bc3, + _ => CompressionFormat.Unknown + }; - data = ImageUtil.CompressImage(path, dxt); - } + data = ImageUtil.CompressImage(path, dxt); } + } - // Direct3D can't create block compressed textures of other sizes, and the game crashes on them - if (compression is CompressionType.DXT1 or CompressionType.DXT5 && (width % 4 != 0 || height % 4 != 0)) - throw new InvalidDataException($"{compression} textures need a width and height that are multiples of 4, but this image is {width}×{height}. Resize it or import it uncompressed."); + // Direct3D can't create block compressed textures of other sizes, and the game crashes on them + if (compression is CompressionType.DXT1 or CompressionType.DXT5 && (width % 4 != 0 || height % 4 != 0)) + throw new InvalidDataException($"{compression} textures need a width and height that are multiples of 4, but this image is {width}×{height}. Resize it or import it uncompressed."); - // Process header block - if (platform == PlatformType.Remastered) + // Process header block + if (platform == PlatformType.Remastered) + { + // Remastered Texture header: https://burnout.wiki/wiki/Texture/Burnout_Paradise/Remastered + byte[] header = template?.Length is 0x40 or 0x60 ? (byte[])template.Clone() : new byte[0x40]; + Span h = header; + int p = header.Length == 0x60 ? 4 : 0; // 64-bit pointers move Dimension 4 bytes + int f = header.Length == 0x60 ? 0x10 : 0; // and Format onwards 0x10 bytes + BinaryPrimitives.WriteInt32LittleEndian(h[(0x08 + p)..], 7); // Dimension: 2D + BinaryPrimitives.WriteInt32LittleEndian(h[(0x1C + f)..], compression switch { - // Remastered Texture header: https://burnout.wiki/wiki/Texture/Burnout_Paradise/Remastered - byte[] header = template?.Length is 0x40 or 0x60 ? (byte[])template.Clone() : new byte[0x40]; - Span h = header; - int p = header.Length == 0x60 ? 4 : 0; // 64-bit pointers move Dimension 4 bytes - int f = header.Length == 0x60 ? 0x10 : 0; // and Format onwards 0x10 bytes - BinaryPrimitives.WriteInt32LittleEndian(h[(0x08 + p)..], 7); // Dimension: 2D - BinaryPrimitives.WriteInt32LittleEndian(h[(0x1C + f)..], compression switch - { - CompressionType.ARGB => 0x1C, // v One of these may be incorrect - CompressionType.RGBA => 0x1C, // ^ - CompressionType.BGRA => 0x57, - CompressionType.DXT1 => 0x47, - CompressionType.DXT5 => 0x4D, - }); - BinaryPrimitives.WriteUInt16LittleEndian(h[(0x24 + f)..], (ushort)width); - BinaryPrimitives.WriteUInt16LittleEndian(h[(0x26 + f)..], (ushort)height); - BinaryPrimitives.WriteUInt16LittleEndian(h[(0x28 + f)..], 1); // Depth - BinaryPrimitives.WriteUInt16LittleEndian(h[(0x2A + f)..], 1); // Array size - h[0x2C + f] = 0; // Most detailed mip - h[0x2D + f] = (byte)numMips; // Mip levels - return new ImageInfo(header, data); - } + CompressionType.ARGB => 0x1C, // v One of these may be incorrect + CompressionType.RGBA => 0x1C, // ^ + CompressionType.BGRA => 0x57, + CompressionType.DXT1 => 0x47, + CompressionType.DXT5 => 0x4D, + }); + BinaryPrimitives.WriteUInt16LittleEndian(h[(0x24 + f)..], (ushort)width); + BinaryPrimitives.WriteUInt16LittleEndian(h[(0x26 + f)..], (ushort)height); + BinaryPrimitives.WriteUInt16LittleEndian(h[(0x28 + f)..], 1); // Depth + BinaryPrimitives.WriteUInt16LittleEndian(h[(0x2A + f)..], 1); // Array size + h[0x2C + f] = 0; // Most detailed mip + h[0x2D + f] = (byte)numMips; // Mip levels + return new ImageInfo(header, data); + } - MemoryStream msx = new(); - BinaryWriter2 bw = new(msx); + MemoryStream msx = new(); + BinaryWriter2 bw = new(msx); - if (platform == PlatformType.PC || platform == PlatformType.PCx64) + if (platform == PlatformType.PC || platform == PlatformType.PCx64) + { + if (platform == PlatformType.PC) { - if (platform == PlatformType.PC) - { - // TUB PC - bw.Write(0); // Data pointer - bw.Write(0); // Texture interface pointer - bw.Write(0); // Padding - bw.Write((ushort)1); // Pool - bw.Write((byte)0); // ? - bw.Write((byte)0); // ? - } - else - { - // Decomp. See b5-decomp src/pc/gcm/renderengine/texture.h - bw.Write(new byte[0x1C]); // 3 pointers, 4 bools - } - bw.Write(compression switch // D3DFORMAT - { - CompressionType.DXT1 => 0x31545844, // "DXT1" - CompressionType.DXT5 => 0x35545844, // "DXT5" - CompressionType.RGBA => 0x20, // A8B8G8R8 - _ => 0x15 // A8R8G8B8 - }); - bw.Write((ushort)width); // Width - bw.Write((short)height); // Height - bw.Write((byte)1); // Depth - bw.Write((byte)numMips); // MipLevels - bw.Write((byte)0); // Texture type - bw.Write((byte)0); // Flags - bw.Write(new byte[platform == PlatformType.PC ? 4 : 8]); // 0x10 alignment + // TUB PC + bw.Write(0); // Data pointer + bw.Write(0); // Texture interface pointer + bw.Write(0); // Padding + bw.Write((ushort)1); // Pool + bw.Write((byte)0); // ? + bw.Write((byte)0); // ? } + else + { + // Decomp. See b5-decomp src/pc/gcm/renderengine/texture.h + bw.Write(new byte[0x1C]); // 3 pointers, 4 bools + } + bw.Write(compression switch // D3DFORMAT + { + CompressionType.DXT1 => 0x31545844, // "DXT1" + CompressionType.DXT5 => 0x35545844, // "DXT5" + CompressionType.RGBA => 0x20, // A8B8G8R8 + _ => 0x15 // A8R8G8B8 + }); + bw.Write((ushort)width); // Width + bw.Write((short)height); // Height + bw.Write((byte)1); // Depth + bw.Write((byte)numMips); // MipLevels + bw.Write((byte)0); // Texture type + bw.Write((byte)0); // Flags + bw.Write(new byte[platform == PlatformType.PC ? 4 : 8]); // 0x10 alignment + } - bw.Flush(); - bw.Close(); + bw.Flush(); + bw.Close(); - return new ImageInfo(msx.ToArray(), data); - } + return new ImageInfo(msx.ToArray(), data); + } - public static ImageHeader GetImageHeader(byte[] data) + public static ImageHeader GetImageHeader(byte[] data) + { + try { - try + MemoryStream ms = new(data); + BinaryReader2 br = new(ms); + + PlatformType platform = DetectPlatform(data); + if (platform == PlatformType.X360) + { + throw new Exception("Xbox 360 textures are not supported yet."); + } + else if (platform == PlatformType.Remastered) { - MemoryStream ms = new(data); - BinaryReader2 br = new(ms); + br.BaseStream.Seek(0x00, SeekOrigin.Begin); - PlatformType platform = DetectPlatform(data); - if (platform == PlatformType.X360) + // 32/64 bit offsets + var (oFormat, oSize) = data.Length switch { - throw new Exception("Xbox 360 textures are not supported yet."); - } - else if (platform == PlatformType.Remastered) - { - br.BaseStream.Seek(0x00, SeekOrigin.Begin); + 0x40 => (0x1C, 0x24), + 0x60 => (0x2C, 0x34), + _ => throw new InvalidDataException() + }; - // 32/64 bit offsets - var (oFormat, oSize) = data.Length switch - { - 0x40 => (0x1C, 0x24), - 0x60 => (0x2C, 0x34), - _ => throw new InvalidDataException() - }; + br.BaseStream.Seek(oFormat, SeekOrigin.Begin); - br.BaseStream.Seek(oFormat, SeekOrigin.Begin); + // DXGI_Format + CompressionType type = br.ReadUInt32() switch + { + 0x00000057 => CompressionType.BGRA, + 0x0000001C => CompressionType.RGBA, + 0x000000FF => CompressionType.ARGB, + 0x00000047 => CompressionType.DXT1, + 0x0000004D => CompressionType.DXT5, + _ => CompressionType.UNKNOWN + }; - // DXGI_Format - CompressionType type = br.ReadUInt32() switch - { - 0x00000057 => CompressionType.BGRA, - 0x0000001C => CompressionType.RGBA, - 0x000000FF => CompressionType.ARGB, - 0x00000047 => CompressionType.DXT1, - 0x0000004D => CompressionType.DXT5, - _ => CompressionType.UNKNOWN - }; + br.BaseStream.Seek(oSize, SeekOrigin.Begin); - br.BaseStream.Seek(oSize, SeekOrigin.Begin); + int width = br.ReadInt16(); + int height = br.ReadInt16(); - int width = br.ReadInt16(); - int height = br.ReadInt16(); + br.Close(); - br.Close(); + return new ImageHeader(type, width, height, PlatformType.Remastered); + } + else if (platform == PlatformType.PC || platform == PlatformType.PCx64) + { + br.BaseStream.Seek(platform == PlatformType.PC ? 0x10 : 0x1C, SeekOrigin.Begin); - return new ImageHeader(type, width, height, PlatformType.Remastered); - } - else if (platform == PlatformType.PC || platform == PlatformType.PCx64) + // D3DFORMAT + CompressionType type = br.ReadInt32() switch { - br.BaseStream.Seek(platform == PlatformType.PC ? 0x10 : 0x1C, SeekOrigin.Begin); + 0x00000015 => CompressionType.BGRA, + 0x00000020 => CompressionType.RGBA, + 0x000000FF => CompressionType.ARGB, + 0x31545844 => CompressionType.DXT1, // "DXT1" + 0x35545844 => CompressionType.DXT5, // "DXT5" + _ => CompressionType.UNKNOWN + }; - // D3DFORMAT - CompressionType type = br.ReadInt32() switch - { - 0x00000015 => CompressionType.BGRA, - 0x00000020 => CompressionType.RGBA, - 0x000000FF => CompressionType.ARGB, - 0x31545844 => CompressionType.DXT1, // "DXT1" - 0x35545844 => CompressionType.DXT5, // "DXT5" - _ => CompressionType.UNKNOWN - }; + int width = br.ReadInt16(); + int height = br.ReadInt16(); - int width = br.ReadInt16(); - int height = br.ReadInt16(); + br.Close(); - br.Close(); + return new ImageHeader(type, width, height, platform); + } + else if (platform == PlatformType.PS3) // PS3 + { + br.BaseStream.Seek(0x00, SeekOrigin.Begin); - return new ImageHeader(type, width, height, platform); - } - else if (platform == PlatformType.PS3) // PS3 + CompressionType type = br.ReadByte() switch { - br.BaseStream.Seek(0x00, SeekOrigin.Begin); - - CompressionType type = br.ReadByte() switch - { - 0x85 => CompressionType.ARGB, - 0x86 => CompressionType.DXT1, - 0x88 => CompressionType.DXT5, - _ => CompressionType.UNKNOWN - }; + 0x85 => CompressionType.ARGB, + 0x86 => CompressionType.DXT1, + 0x88 => CompressionType.DXT5, + _ => CompressionType.UNKNOWN + }; - br.BaseStream.Seek(0x08, SeekOrigin.Begin); + br.BaseStream.Seek(0x08, SeekOrigin.Begin); - ushort width = Util.ReverseBytes(br.ReadUInt16()); - ushort height = Util.ReverseBytes(br.ReadUInt16()); + ushort width = Util.ReverseBytes(br.ReadUInt16()); + ushort height = Util.ReverseBytes(br.ReadUInt16()); - br.Close(); + br.Close(); - return new ImageHeader(type, width, height, PlatformType.PS3); - } - else - { - throw new InvalidDataException($"Unknown image header platform."); - } + return new ImageHeader(type, width, height, PlatformType.PS3); } - catch (Exception ex) + else { - MessageBox.Show(ex.Message + "\r\n" + ex.StackTrace); + throw new InvalidDataException($"Unknown image header platform."); } + } + catch (Exception ex) + { + MessageBox.Show(ex.Message + "\r\n" + ex.StackTrace); + } + + return null; + } + public static Image GetImage(byte[] data, byte[] extraData) + { + if (extraData == null) // ¯\_(ツ)_/¯ return null; - } - public static Image GetImage(byte[] data, byte[] extraData) + try { - if (extraData == null) // ¯\_(ツ)_/¯ - return null; + ImageHeader header = GetImageHeader(data); - try + if (header.Platform == PlatformType.X360) { - ImageHeader header = GetImageHeader(data); - - if (header.Platform == PlatformType.X360) - { - throw new Exception("Xbox 360 textures are not supported yet."); - } - else + throw new Exception("Xbox 360 textures are not supported yet."); + } + else + { + byte[] pixels = header.CompressionType switch { - byte[] pixels = header.CompressionType switch - { - CompressionType.DXT1 => ImageUtil.DecompressImage(extraData, header.Width, header.Height, CompressionFormat.Bc1), - CompressionType.DXT5 => ImageUtil.DecompressImage(extraData, header.Width, header.Height, CompressionFormat.Bc3), - _ => extraData - }; + CompressionType.DXT1 => ImageUtil.DecompressImage(extraData, header.Width, header.Height, CompressionFormat.Bc1), + CompressionType.DXT5 => ImageUtil.DecompressImage(extraData, header.Width, header.Height, CompressionFormat.Bc3), + _ => extraData + }; - DirectBitmap bitmap = new(header.Width, header.Height); + DirectBitmap bitmap = new(header.Width, header.Height); - int rO, gO, bO, aO; + int rO, gO, bO, aO; - if (header.CompressionType == CompressionType.DXT1 - || header.CompressionType == CompressionType.DXT5) + if (header.CompressionType == CompressionType.DXT1 + || header.CompressionType == CompressionType.DXT5) + { + if (header.Platform == PlatformType.PS3) { - if (header.Platform == PlatformType.PS3) - { - rO = 1; gO = 2; bO = 3; aO = 0; // ARGB - } - else - { - rO = 0; gO = 1; bO = 2; aO = 3; // RGBA - } + rO = 1; gO = 2; bO = 3; aO = 0; // ARGB } else { - switch (header.CompressionType) - { - case CompressionType.BGRA: - rO = 2; gO = 1; bO = 0; aO = 3; - break; - case CompressionType.ARGB: - rO = 1; gO = 2; bO = 3; aO = 0; - break; - default: - rO = 0; gO = 1; bO = 2; aO = 3; - break; - } + rO = 0; gO = 1; bO = 2; aO = 3; // RGBA } - - int srcIndex = 0; - int dstIndex = 0; - int pixelCount = header.Width * header.Height; - - for (int i = 0; i < pixelCount; i++) + } + else + { + switch (header.CompressionType) { - byte r = pixels[srcIndex + rO]; - byte g = pixels[srcIndex + gO]; - byte b = pixels[srcIndex + bO]; - byte a = pixels[srcIndex + aO]; + case CompressionType.BGRA: + rO = 2; gO = 1; bO = 0; aO = 3; + break; + case CompressionType.ARGB: + rO = 1; gO = 2; bO = 3; aO = 0; + break; + default: + rO = 0; gO = 1; bO = 2; aO = 3; + break; + } + } - int argb = (a << 24) | (r << 16) | (g << 8) | b; + int srcIndex = 0; + int dstIndex = 0; + int pixelCount = header.Width * header.Height; - bitmap.Bits[dstIndex] = argb; + for (int i = 0; i < pixelCount; i++) + { + byte r = pixels[srcIndex + rO]; + byte g = pixels[srcIndex + gO]; + byte b = pixels[srcIndex + bO]; + byte a = pixels[srcIndex + aO]; - srcIndex += 4; - dstIndex++; - } + int argb = (a << 24) | (r << 16) | (g << 8) | b; - return bitmap.Bitmap; + bitmap.Bits[dstIndex] = argb; + + srcIndex += 4; + dstIndex++; } - } - catch (Exception ex) - { - MessageBox.Show(ex.Message + "\r\n" + ex.StackTrace); - return null; + + return bitmap.Bitmap; } } - - public static PlatformType DetectPlatform(byte[] data) + catch (Exception ex) { - if (data == null) throw new ArgumentNullException(nameof(data)); - - int len = data.Length; - - using MemoryStream ms = new(data); - using BinaryReader2 br = new(ms); + MessageBox.Show(ex.Message + "\r\n" + ex.StackTrace); + return null; + } + } - if (len == 0x40 || len == 0x60) - { - if (len == 0x40) - { - ms.Seek(0x0, SeekOrigin.Begin); + public static PlatformType DetectPlatform(byte[] data) + { + if (data == null) throw new ArgumentNullException(nameof(data)); - if (br.ReadUInt32() != 0) - return PlatformType.X360; - } + int len = data.Length; - return PlatformType.Remastered; - } + using MemoryStream ms = new(data); + using BinaryReader2 br = new(ms); - if (len == 0x20) + if (len == 0x40 || len == 0x60) + { + if (len == 0x40) { - ms.Seek(0x4, SeekOrigin.Begin); + ms.Seek(0x0, SeekOrigin.Begin); - if (br.ReadUInt32() == 0) // Texture interface ptr - return PlatformType.PC; + if (br.ReadUInt32() != 0) + return PlatformType.X360; } - // PS3 starts with format/mip/dimension bytes; decomp x64 starts with null pointers and bools - if (len == 0x30) - return data.AsSpan(0, 0x1C).IndexOfAnyExcept((byte)0) < 0 ? PlatformType.PCx64 : PlatformType.PS3; + return PlatformType.Remastered; + } + + if (len == 0x20) + { + ms.Seek(0x4, SeekOrigin.Begin); - return PlatformType.Invalid; + if (br.ReadUInt32() == 0) // Texture interface ptr + return PlatformType.PC; } - } - public enum CompressionType - { - UNKNOWN = -1, + // PS3 starts with format/mip/dimension bytes; decomp x64 starts with null pointers and bools + if (len == 0x30) + return data.AsSpan(0, 0x1C).IndexOfAnyExcept((byte)0) < 0 ? PlatformType.PCx64 : PlatformType.PS3; - RGBA, - ARGB, - BGRA, - DXT1, - DXT5 + return PlatformType.Invalid; } +} - public enum PlatformType - { - Invalid = -1, +public enum CompressionType +{ + UNKNOWN = -1, - Remastered, - PC, - PS3, - X360, - PCx64 - } + RGBA, + ARGB, + BGRA, + DXT1, + DXT5 +} + +public enum PlatformType +{ + Invalid = -1, + + Remastered, + PC, + PS3, + X360, + PCx64 } diff --git a/BurnoutImage/ImageUtil.cs b/BurnoutImage/ImageUtil.cs index fa13f41..4b863d2 100644 --- a/BurnoutImage/ImageUtil.cs +++ b/BurnoutImage/ImageUtil.cs @@ -1,78 +1,77 @@ using System; using BCnEncoder.Shared; -namespace BurnoutImage +namespace BurnoutImage; + +internal static class ImageUtil { - internal static class ImageUtil + public static byte[] DecompressImage(byte[] data, int width, int height, CompressionFormat compression) { - public static byte[] DecompressImage(byte[] data, int width, int height, CompressionFormat compression) - { - return CompressionTools.DecompressTexture(data, width, height, compression); - } + return CompressionTools.DecompressTexture(data, width, height, compression); + } + + public static byte[] CompressImage(string path, CompressionFormat compression) + { + return CompressionTools.CompressTexture(path, compression); + } - public static byte[] CompressImage(string path, CompressionFormat compression) + public static CompressionType DetectDdsFormat( + uint pfFlags, + uint pfFourCC, + uint pfRGBBitCount, + uint pfRBitMask, + uint pfGBitMask, + uint pfBBitMask, + uint pfABitMask) + { + const uint DDPF_ALPHAPIXELS = 0x00000001; + const uint DDPF_FOURCC = 0x00000004; + const uint DDPF_RGB = 0x00000040; + + if ((pfFlags & DDPF_FOURCC) != 0) { - return CompressionTools.CompressTexture(path, compression); + switch (pfFourCC) + { + case 0x31545844u: + return CompressionType.DXT1; + case 0x35545844u: + return CompressionType.DXT5; + case 0x00000015u: + return CompressionType.BGRA; + case 0x0000001Cu: + return CompressionType.RGBA; + case 0x000000FFu: + return CompressionType.ARGB; + case 0x30315844u: + throw new NotSupportedException("DX10 DDS files are not supported by this reader."); + } + + return CompressionType.UNKNOWN; } - public static CompressionType DetectDdsFormat( - uint pfFlags, - uint pfFourCC, - uint pfRGBBitCount, - uint pfRBitMask, - uint pfGBitMask, - uint pfBBitMask, - uint pfABitMask) + if ((pfFlags & DDPF_RGB) != 0 && pfRGBBitCount == 32) { - const uint DDPF_ALPHAPIXELS = 0x00000001; - const uint DDPF_FOURCC = 0x00000004; - const uint DDPF_RGB = 0x00000040; - - if ((pfFlags & DDPF_FOURCC) != 0) + if (pfRBitMask == 0x00FF0000u && + pfGBitMask == 0x0000FF00u && + pfBBitMask == 0x000000FFu) { - switch (pfFourCC) - { - case 0x31545844u: - return CompressionType.DXT1; - case 0x35545844u: - return CompressionType.DXT5; - case 0x00000015u: - return CompressionType.BGRA; - case 0x0000001Cu: - return CompressionType.RGBA; - case 0x000000FFu: - return CompressionType.ARGB; - case 0x30315844u: - throw new NotSupportedException("DX10 DDS files are not supported by this reader."); - } - - return CompressionType.UNKNOWN; + if (pfABitMask == 0xFF000000u) + return CompressionType.BGRA; + if ((pfFlags & DDPF_ALPHAPIXELS) == 0 && pfABitMask == 0) + return CompressionType.BGRA; } - if ((pfFlags & DDPF_RGB) != 0 && pfRGBBitCount == 32) + if (pfRBitMask == 0x000000FFu && + pfGBitMask == 0x0000FF00u && + pfBBitMask == 0x00FF0000u) { - if (pfRBitMask == 0x00FF0000u && - pfGBitMask == 0x0000FF00u && - pfBBitMask == 0x000000FFu) - { - if (pfABitMask == 0xFF000000u) - return CompressionType.BGRA; - if ((pfFlags & DDPF_ALPHAPIXELS) == 0 && pfABitMask == 0) - return CompressionType.BGRA; - } - - if (pfRBitMask == 0x000000FFu && - pfGBitMask == 0x0000FF00u && - pfBBitMask == 0x00FF0000u) - { - if (pfABitMask == 0xFF000000u) - return CompressionType.RGBA; - if ((pfFlags & DDPF_ALPHAPIXELS) == 0 && pfABitMask == 0) - return CompressionType.RGBA; - } + if (pfABitMask == 0xFF000000u) + return CompressionType.RGBA; + if ((pfFlags & DDPF_ALPHAPIXELS) == 0 && pfABitMask == 0) + return CompressionType.RGBA; } - - return CompressionType.UNKNOWN; } + + return CompressionType.UNKNOWN; } } diff --git a/BurnoutImage/RangeFit.cs b/BurnoutImage/RangeFit.cs index 7b89570..72a76c4 100644 --- a/BurnoutImage/RangeFit.cs +++ b/BurnoutImage/RangeFit.cs @@ -1,46 +1,45 @@ using System; using BCnEncoder.Shared; -namespace BurnoutImage +namespace BurnoutImage; + +internal class RangeFit : ColourFit { - internal class RangeFit : ColourFit + public Vec3 Metric; + public Vec3 Start; + public Vec3 End; + public float BestError; + + public RangeFit(ColourSet colours, CompressionFormat compression) : base(colours, compression) { - public Vec3 Metric; - public Vec3 Start; - public Vec3 End; - public float BestError; + bool colourMetricPerceptual = false; - public RangeFit(ColourSet colours, CompressionFormat compression) : base(colours, compression) + // initialize the metric + bool perceptual = colourMetricPerceptual; + if (perceptual) { - bool colourMetricPerceptual = false; - - // initialize the metric - bool perceptual = colourMetricPerceptual; - if (perceptual) - { - Metric = new Vec3(0.2126f, 0.7152f, 0.0722f); - } else - { - Metric = new Vec3(0); - } - - // initialize the best error - BestError = float.MaxValue; - - // cache some values - int count = Colours.Count; - Vec3[] values = Colours.Points; - float[] weights = Colours.Weights; - } - - protected override void Compress3(byte[] block, int offset) + Metric = new Vec3(0.2126f, 0.7152f, 0.0722f); + } else { - throw new NotImplementedException(); + Metric = new Vec3(0); } - protected override void Compress4(byte[] block, int offset) - { - throw new NotImplementedException(); - } + // initialize the best error + BestError = float.MaxValue; + + // cache some values + int count = Colours.Count; + Vec3[] values = Colours.Points; + float[] weights = Colours.Weights; + } + + protected override void Compress3(byte[] block, int offset) + { + throw new NotImplementedException(); + } + + protected override void Compress4(byte[] block, int offset) + { + throw new NotImplementedException(); } } diff --git a/BurnoutImage/SingleColourLookup.cs b/BurnoutImage/SingleColourLookup.cs index e8136e2..a038743 100644 --- a/BurnoutImage/SingleColourLookup.cs +++ b/BurnoutImage/SingleColourLookup.cs @@ -1,1071 +1,1070 @@ -namespace BurnoutImage -{ - internal struct SourceBlock - { - public byte Start; - public byte End; - public byte Error; +namespace BurnoutImage; - public SourceBlock(byte start, byte end, byte error) - { - Start = start; - End = end; - Error = error; - } - } +internal struct SourceBlock +{ + public byte Start; + public byte End; + public byte Error; - internal struct SingleColourLookup + public SourceBlock(byte start, byte end, byte error) { - public SourceBlock[] sources; // Size 2 - - public SingleColourLookup(SourceBlock src1, SourceBlock src2) - { - sources = new SourceBlock[2]; - sources[0] = src1; - sources[1] = src2; - } + Start = start; + End = end; + Error = error; } +} - internal class SingleColourLookups +internal struct SingleColourLookup +{ + public SourceBlock[] sources; // Size 2 + + public SingleColourLookup(SourceBlock src1, SourceBlock src2) { - public static SingleColourLookup[] lookup_5_3 = new SingleColourLookup[] - { - new SingleColourLookup( new SourceBlock( 0, 0, 0 ), new SourceBlock( 0, 0, 0 ) ), - new SingleColourLookup( new SourceBlock( 0, 0, 1 ), new SourceBlock( 0, 0, 1 ) ), - new SingleColourLookup( new SourceBlock( 0, 0, 2 ), new SourceBlock( 0, 0, 2 ) ), - new SingleColourLookup( new SourceBlock( 0, 0, 3 ), new SourceBlock( 0, 1, 1 ) ), - new SingleColourLookup( new SourceBlock( 0, 0, 4 ), new SourceBlock( 0, 1, 0 ) ), - new SingleColourLookup( new SourceBlock( 1, 0, 3 ), new SourceBlock( 0, 1, 1 ) ), - new SingleColourLookup( new SourceBlock( 1, 0, 2 ), new SourceBlock( 0, 1, 2 ) ), - new SingleColourLookup( new SourceBlock( 1, 0, 1 ), new SourceBlock( 0, 2, 1 ) ), - new SingleColourLookup( new SourceBlock( 1, 0, 0 ), new SourceBlock( 0, 2, 0 ) ), - new SingleColourLookup( new SourceBlock( 1, 0, 1 ), new SourceBlock( 0, 2, 1 ) ), - new SingleColourLookup( new SourceBlock( 1, 0, 2 ), new SourceBlock( 0, 2, 2 ) ), - new SingleColourLookup( new SourceBlock( 1, 0, 3 ), new SourceBlock( 0, 3, 1 ) ), - new SingleColourLookup( new SourceBlock( 1, 0, 4 ), new SourceBlock( 0, 3, 0 ) ), - new SingleColourLookup( new SourceBlock( 2, 0, 3 ), new SourceBlock( 0, 3, 1 ) ), - new SingleColourLookup( new SourceBlock( 2, 0, 2 ), new SourceBlock( 0, 3, 2 ) ), - new SingleColourLookup( new SourceBlock( 2, 0, 1 ), new SourceBlock( 0, 4, 1 ) ), - new SingleColourLookup( new SourceBlock( 2, 0, 0 ), new SourceBlock( 0, 4, 0 ) ), - new SingleColourLookup( new SourceBlock( 2, 0, 1 ), new SourceBlock( 0, 4, 1 ) ), - new SingleColourLookup( new SourceBlock( 2, 0, 2 ), new SourceBlock( 0, 4, 2 ) ), - new SingleColourLookup( new SourceBlock( 2, 0, 3 ), new SourceBlock( 0, 5, 1 ) ), - new SingleColourLookup( new SourceBlock( 2, 0, 4 ), new SourceBlock( 0, 5, 0 ) ), - new SingleColourLookup( new SourceBlock( 3, 0, 3 ), new SourceBlock( 0, 5, 1 ) ), - new SingleColourLookup( new SourceBlock( 3, 0, 2 ), new SourceBlock( 0, 5, 2 ) ), - new SingleColourLookup( new SourceBlock( 3, 0, 1 ), new SourceBlock( 0, 6, 1 ) ), - new SingleColourLookup( new SourceBlock( 3, 0, 0 ), new SourceBlock( 0, 6, 0 ) ), - new SingleColourLookup( new SourceBlock( 3, 0, 1 ), new SourceBlock( 0, 6, 1 ) ), - new SingleColourLookup( new SourceBlock( 3, 0, 2 ), new SourceBlock( 0, 6, 2 ) ), - new SingleColourLookup( new SourceBlock( 3, 0, 3 ), new SourceBlock( 0, 7, 1 ) ), - new SingleColourLookup( new SourceBlock( 3, 0, 4 ), new SourceBlock( 0, 7, 0 ) ), - new SingleColourLookup( new SourceBlock( 4, 0, 4 ), new SourceBlock( 0, 7, 1 ) ), - new SingleColourLookup( new SourceBlock( 4, 0, 3 ), new SourceBlock( 0, 7, 2 ) ), - new SingleColourLookup( new SourceBlock( 4, 0, 2 ), new SourceBlock( 1, 7, 1 ) ), - new SingleColourLookup( new SourceBlock( 4, 0, 1 ), new SourceBlock( 1, 7, 0 ) ), - new SingleColourLookup( new SourceBlock( 4, 0, 0 ), new SourceBlock( 0, 8, 0 ) ), - new SingleColourLookup( new SourceBlock( 4, 0, 1 ), new SourceBlock( 0, 8, 1 ) ), - new SingleColourLookup( new SourceBlock( 4, 0, 2 ), new SourceBlock( 2, 7, 1 ) ), - new SingleColourLookup( new SourceBlock( 4, 0, 3 ), new SourceBlock( 2, 7, 0 ) ), - new SingleColourLookup( new SourceBlock( 4, 0, 4 ), new SourceBlock( 0, 9, 0 ) ), - new SingleColourLookup( new SourceBlock( 5, 0, 3 ), new SourceBlock( 0, 9, 1 ) ), - new SingleColourLookup( new SourceBlock( 5, 0, 2 ), new SourceBlock( 3, 7, 1 ) ), - new SingleColourLookup( new SourceBlock( 5, 0, 1 ), new SourceBlock( 3, 7, 0 ) ), - new SingleColourLookup( new SourceBlock( 5, 0, 0 ), new SourceBlock( 0, 10, 0 ) ), - new SingleColourLookup( new SourceBlock( 5, 0, 1 ), new SourceBlock( 0, 10, 1 ) ), - new SingleColourLookup( new SourceBlock( 5, 0, 2 ), new SourceBlock( 0, 10, 2 ) ), - new SingleColourLookup( new SourceBlock( 5, 0, 3 ), new SourceBlock( 0, 11, 1 ) ), - new SingleColourLookup( new SourceBlock( 5, 0, 4 ), new SourceBlock( 0, 11, 0 ) ), - new SingleColourLookup( new SourceBlock( 6, 0, 3 ), new SourceBlock( 0, 11, 1 ) ), - new SingleColourLookup( new SourceBlock( 6, 0, 2 ), new SourceBlock( 0, 11, 2 ) ), - new SingleColourLookup( new SourceBlock( 6, 0, 1 ), new SourceBlock( 0, 12, 1 ) ), - new SingleColourLookup( new SourceBlock( 6, 0, 0 ), new SourceBlock( 0, 12, 0 ) ), - new SingleColourLookup( new SourceBlock( 6, 0, 1 ), new SourceBlock( 0, 12, 1 ) ), - new SingleColourLookup( new SourceBlock( 6, 0, 2 ), new SourceBlock( 0, 12, 2 ) ), - new SingleColourLookup( new SourceBlock( 6, 0, 3 ), new SourceBlock( 0, 13, 1 ) ), - new SingleColourLookup( new SourceBlock( 6, 0, 4 ), new SourceBlock( 0, 13, 0 ) ), - new SingleColourLookup( new SourceBlock( 7, 0, 3 ), new SourceBlock( 0, 13, 1 ) ), - new SingleColourLookup( new SourceBlock( 7, 0, 2 ), new SourceBlock( 0, 13, 2 ) ), - new SingleColourLookup( new SourceBlock( 7, 0, 1 ), new SourceBlock( 0, 14, 1 ) ), - new SingleColourLookup( new SourceBlock( 7, 0, 0 ), new SourceBlock( 0, 14, 0 ) ), - new SingleColourLookup( new SourceBlock( 7, 0, 1 ), new SourceBlock( 0, 14, 1 ) ), - new SingleColourLookup( new SourceBlock( 7, 0, 2 ), new SourceBlock( 0, 14, 2 ) ), - new SingleColourLookup( new SourceBlock( 7, 0, 3 ), new SourceBlock( 0, 15, 1 ) ), - new SingleColourLookup( new SourceBlock( 7, 0, 4 ), new SourceBlock( 0, 15, 0 ) ), - new SingleColourLookup( new SourceBlock( 8, 0, 4 ), new SourceBlock( 0, 15, 1 ) ), - new SingleColourLookup( new SourceBlock( 8, 0, 3 ), new SourceBlock( 0, 15, 2 ) ), - new SingleColourLookup( new SourceBlock( 8, 0, 2 ), new SourceBlock( 1, 15, 1 ) ), - new SingleColourLookup( new SourceBlock( 8, 0, 1 ), new SourceBlock( 1, 15, 0 ) ), - new SingleColourLookup( new SourceBlock( 8, 0, 0 ), new SourceBlock( 0, 16, 0 ) ), - new SingleColourLookup( new SourceBlock( 8, 0, 1 ), new SourceBlock( 0, 16, 1 ) ), - new SingleColourLookup( new SourceBlock( 8, 0, 2 ), new SourceBlock( 2, 15, 1 ) ), - new SingleColourLookup( new SourceBlock( 8, 0, 3 ), new SourceBlock( 2, 15, 0 ) ), - new SingleColourLookup( new SourceBlock( 8, 0, 4 ), new SourceBlock( 0, 17, 0 ) ), - new SingleColourLookup( new SourceBlock( 9, 0, 3 ), new SourceBlock( 0, 17, 1 ) ), - new SingleColourLookup( new SourceBlock( 9, 0, 2 ), new SourceBlock( 3, 15, 1 ) ), - new SingleColourLookup( new SourceBlock( 9, 0, 1 ), new SourceBlock( 3, 15, 0 ) ), - new SingleColourLookup( new SourceBlock( 9, 0, 0 ), new SourceBlock( 0, 18, 0 ) ), - new SingleColourLookup( new SourceBlock( 9, 0, 1 ), new SourceBlock( 0, 18, 1 ) ), - new SingleColourLookup( new SourceBlock( 9, 0, 2 ), new SourceBlock( 0, 18, 2 ) ), - new SingleColourLookup( new SourceBlock( 9, 0, 3 ), new SourceBlock( 0, 19, 1 ) ), - new SingleColourLookup( new SourceBlock( 9, 0, 4 ), new SourceBlock( 0, 19, 0 ) ), - new SingleColourLookup( new SourceBlock( 10, 0, 3 ), new SourceBlock( 0, 19, 1 ) ), - new SingleColourLookup( new SourceBlock( 10, 0, 2 ), new SourceBlock( 0, 19, 2 ) ), - new SingleColourLookup( new SourceBlock( 10, 0, 1 ), new SourceBlock( 0, 20, 1 ) ), - new SingleColourLookup( new SourceBlock( 10, 0, 0 ), new SourceBlock( 0, 20, 0 ) ), - new SingleColourLookup( new SourceBlock( 10, 0, 1 ), new SourceBlock( 0, 20, 1 ) ), - new SingleColourLookup( new SourceBlock( 10, 0, 2 ), new SourceBlock( 0, 20, 2 ) ), - new SingleColourLookup( new SourceBlock( 10, 0, 3 ), new SourceBlock( 0, 21, 1 ) ), - new SingleColourLookup( new SourceBlock( 10, 0, 4 ), new SourceBlock( 0, 21, 0 ) ), - new SingleColourLookup( new SourceBlock( 11, 0, 3 ), new SourceBlock( 0, 21, 1 ) ), - new SingleColourLookup( new SourceBlock( 11, 0, 2 ), new SourceBlock( 0, 21, 2 ) ), - new SingleColourLookup( new SourceBlock( 11, 0, 1 ), new SourceBlock( 0, 22, 1 ) ), - new SingleColourLookup( new SourceBlock( 11, 0, 0 ), new SourceBlock( 0, 22, 0 ) ), - new SingleColourLookup( new SourceBlock( 11, 0, 1 ), new SourceBlock( 0, 22, 1 ) ), - new SingleColourLookup( new SourceBlock( 11, 0, 2 ), new SourceBlock( 0, 22, 2 ) ), - new SingleColourLookup( new SourceBlock( 11, 0, 3 ), new SourceBlock( 0, 23, 1 ) ), - new SingleColourLookup( new SourceBlock( 11, 0, 4 ), new SourceBlock( 0, 23, 0 ) ), - new SingleColourLookup( new SourceBlock( 12, 0, 4 ), new SourceBlock( 0, 23, 1 ) ), - new SingleColourLookup( new SourceBlock( 12, 0, 3 ), new SourceBlock( 0, 23, 2 ) ), - new SingleColourLookup( new SourceBlock( 12, 0, 2 ), new SourceBlock( 1, 23, 1 ) ), - new SingleColourLookup( new SourceBlock( 12, 0, 1 ), new SourceBlock( 1, 23, 0 ) ), - new SingleColourLookup( new SourceBlock( 12, 0, 0 ), new SourceBlock( 0, 24, 0 ) ), - new SingleColourLookup( new SourceBlock( 12, 0, 1 ), new SourceBlock( 0, 24, 1 ) ), - new SingleColourLookup( new SourceBlock( 12, 0, 2 ), new SourceBlock( 2, 23, 1 ) ), - new SingleColourLookup( new SourceBlock( 12, 0, 3 ), new SourceBlock( 2, 23, 0 ) ), - new SingleColourLookup( new SourceBlock( 12, 0, 4 ), new SourceBlock( 0, 25, 0 ) ), - new SingleColourLookup( new SourceBlock( 13, 0, 3 ), new SourceBlock( 0, 25, 1 ) ), - new SingleColourLookup( new SourceBlock( 13, 0, 2 ), new SourceBlock( 3, 23, 1 ) ), - new SingleColourLookup( new SourceBlock( 13, 0, 1 ), new SourceBlock( 3, 23, 0 ) ), - new SingleColourLookup( new SourceBlock( 13, 0, 0 ), new SourceBlock( 0, 26, 0 ) ), - new SingleColourLookup( new SourceBlock( 13, 0, 1 ), new SourceBlock( 0, 26, 1 ) ), - new SingleColourLookup( new SourceBlock( 13, 0, 2 ), new SourceBlock( 0, 26, 2 ) ), - new SingleColourLookup( new SourceBlock( 13, 0, 3 ), new SourceBlock( 0, 27, 1 ) ), - new SingleColourLookup( new SourceBlock( 13, 0, 4 ), new SourceBlock( 0, 27, 0 ) ), - new SingleColourLookup( new SourceBlock( 14, 0, 3 ), new SourceBlock( 0, 27, 1 ) ), - new SingleColourLookup( new SourceBlock( 14, 0, 2 ), new SourceBlock( 0, 27, 2 ) ), - new SingleColourLookup( new SourceBlock( 14, 0, 1 ), new SourceBlock( 0, 28, 1 ) ), - new SingleColourLookup( new SourceBlock( 14, 0, 0 ), new SourceBlock( 0, 28, 0 ) ), - new SingleColourLookup( new SourceBlock( 14, 0, 1 ), new SourceBlock( 0, 28, 1 ) ), - new SingleColourLookup( new SourceBlock( 14, 0, 2 ), new SourceBlock( 0, 28, 2 ) ), - new SingleColourLookup( new SourceBlock( 14, 0, 3 ), new SourceBlock( 0, 29, 1 ) ), - new SingleColourLookup( new SourceBlock( 14, 0, 4 ), new SourceBlock( 0, 29, 0 ) ), - new SingleColourLookup( new SourceBlock( 15, 0, 3 ), new SourceBlock( 0, 29, 1 ) ), - new SingleColourLookup( new SourceBlock( 15, 0, 2 ), new SourceBlock( 0, 29, 2 ) ), - new SingleColourLookup( new SourceBlock( 15, 0, 1 ), new SourceBlock( 0, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 15, 0, 0 ), new SourceBlock( 0, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 15, 0, 1 ), new SourceBlock( 0, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 15, 0, 2 ), new SourceBlock( 0, 30, 2 ) ), - new SingleColourLookup( new SourceBlock( 15, 0, 3 ), new SourceBlock( 0, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 15, 0, 4 ), new SourceBlock( 0, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 16, 0, 4 ), new SourceBlock( 0, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 16, 0, 3 ), new SourceBlock( 0, 31, 2 ) ), - new SingleColourLookup( new SourceBlock( 16, 0, 2 ), new SourceBlock( 1, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 16, 0, 1 ), new SourceBlock( 1, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 16, 0, 0 ), new SourceBlock( 4, 28, 0 ) ), - new SingleColourLookup( new SourceBlock( 16, 0, 1 ), new SourceBlock( 4, 28, 1 ) ), - new SingleColourLookup( new SourceBlock( 16, 0, 2 ), new SourceBlock( 2, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 16, 0, 3 ), new SourceBlock( 2, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 16, 0, 4 ), new SourceBlock( 4, 29, 0 ) ), - new SingleColourLookup( new SourceBlock( 17, 0, 3 ), new SourceBlock( 4, 29, 1 ) ), - new SingleColourLookup( new SourceBlock( 17, 0, 2 ), new SourceBlock( 3, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 17, 0, 1 ), new SourceBlock( 3, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 17, 0, 0 ), new SourceBlock( 4, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 17, 0, 1 ), new SourceBlock( 4, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 17, 0, 2 ), new SourceBlock( 4, 30, 2 ) ), - new SingleColourLookup( new SourceBlock( 17, 0, 3 ), new SourceBlock( 4, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 17, 0, 4 ), new SourceBlock( 4, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 18, 0, 3 ), new SourceBlock( 4, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 18, 0, 2 ), new SourceBlock( 4, 31, 2 ) ), - new SingleColourLookup( new SourceBlock( 18, 0, 1 ), new SourceBlock( 5, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 18, 0, 0 ), new SourceBlock( 5, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 18, 0, 1 ), new SourceBlock( 5, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 18, 0, 2 ), new SourceBlock( 5, 31, 2 ) ), - new SingleColourLookup( new SourceBlock( 18, 0, 3 ), new SourceBlock( 6, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 18, 0, 4 ), new SourceBlock( 6, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 19, 0, 3 ), new SourceBlock( 6, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 19, 0, 2 ), new SourceBlock( 6, 31, 2 ) ), - new SingleColourLookup( new SourceBlock( 19, 0, 1 ), new SourceBlock( 7, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 19, 0, 0 ), new SourceBlock( 7, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 19, 0, 1 ), new SourceBlock( 7, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 19, 0, 2 ), new SourceBlock( 7, 31, 2 ) ), - new SingleColourLookup( new SourceBlock( 19, 0, 3 ), new SourceBlock( 8, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 19, 0, 4 ), new SourceBlock( 8, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 20, 0, 4 ), new SourceBlock( 8, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 20, 0, 3 ), new SourceBlock( 8, 31, 2 ) ), - new SingleColourLookup( new SourceBlock( 20, 0, 2 ), new SourceBlock( 9, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 20, 0, 1 ), new SourceBlock( 9, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 20, 0, 0 ), new SourceBlock( 12, 28, 0 ) ), - new SingleColourLookup( new SourceBlock( 20, 0, 1 ), new SourceBlock( 12, 28, 1 ) ), - new SingleColourLookup( new SourceBlock( 20, 0, 2 ), new SourceBlock( 10, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 20, 0, 3 ), new SourceBlock( 10, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 20, 0, 4 ), new SourceBlock( 12, 29, 0 ) ), - new SingleColourLookup( new SourceBlock( 21, 0, 3 ), new SourceBlock( 12, 29, 1 ) ), - new SingleColourLookup( new SourceBlock( 21, 0, 2 ), new SourceBlock( 11, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 21, 0, 1 ), new SourceBlock( 11, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 21, 0, 0 ), new SourceBlock( 12, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 21, 0, 1 ), new SourceBlock( 12, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 21, 0, 2 ), new SourceBlock( 12, 30, 2 ) ), - new SingleColourLookup( new SourceBlock( 21, 0, 3 ), new SourceBlock( 12, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 21, 0, 4 ), new SourceBlock( 12, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 22, 0, 3 ), new SourceBlock( 12, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 22, 0, 2 ), new SourceBlock( 12, 31, 2 ) ), - new SingleColourLookup( new SourceBlock( 22, 0, 1 ), new SourceBlock( 13, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 22, 0, 0 ), new SourceBlock( 13, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 22, 0, 1 ), new SourceBlock( 13, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 22, 0, 2 ), new SourceBlock( 13, 31, 2 ) ), - new SingleColourLookup( new SourceBlock( 22, 0, 3 ), new SourceBlock( 14, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 22, 0, 4 ), new SourceBlock( 14, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 23, 0, 3 ), new SourceBlock( 14, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 23, 0, 2 ), new SourceBlock( 14, 31, 2 ) ), - new SingleColourLookup( new SourceBlock( 23, 0, 1 ), new SourceBlock( 15, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 23, 0, 0 ), new SourceBlock( 15, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 23, 0, 1 ), new SourceBlock( 15, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 23, 0, 2 ), new SourceBlock( 15, 31, 2 ) ), - new SingleColourLookup( new SourceBlock( 23, 0, 3 ), new SourceBlock( 16, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 23, 0, 4 ), new SourceBlock( 16, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 24, 0, 4 ), new SourceBlock( 16, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 24, 0, 3 ), new SourceBlock( 16, 31, 2 ) ), - new SingleColourLookup( new SourceBlock( 24, 0, 2 ), new SourceBlock( 17, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 24, 0, 1 ), new SourceBlock( 17, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 24, 0, 0 ), new SourceBlock( 20, 28, 0 ) ), - new SingleColourLookup( new SourceBlock( 24, 0, 1 ), new SourceBlock( 20, 28, 1 ) ), - new SingleColourLookup( new SourceBlock( 24, 0, 2 ), new SourceBlock( 18, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 24, 0, 3 ), new SourceBlock( 18, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 24, 0, 4 ), new SourceBlock( 20, 29, 0 ) ), - new SingleColourLookup( new SourceBlock( 25, 0, 3 ), new SourceBlock( 20, 29, 1 ) ), - new SingleColourLookup( new SourceBlock( 25, 0, 2 ), new SourceBlock( 19, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 25, 0, 1 ), new SourceBlock( 19, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 25, 0, 0 ), new SourceBlock( 20, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 25, 0, 1 ), new SourceBlock( 20, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 25, 0, 2 ), new SourceBlock( 20, 30, 2 ) ), - new SingleColourLookup( new SourceBlock( 25, 0, 3 ), new SourceBlock( 20, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 25, 0, 4 ), new SourceBlock( 20, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 26, 0, 3 ), new SourceBlock( 20, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 26, 0, 2 ), new SourceBlock( 20, 31, 2 ) ), - new SingleColourLookup( new SourceBlock( 26, 0, 1 ), new SourceBlock( 21, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 26, 0, 0 ), new SourceBlock( 21, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 26, 0, 1 ), new SourceBlock( 21, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 26, 0, 2 ), new SourceBlock( 21, 31, 2 ) ), - new SingleColourLookup( new SourceBlock( 26, 0, 3 ), new SourceBlock( 22, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 26, 0, 4 ), new SourceBlock( 22, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 27, 0, 3 ), new SourceBlock( 22, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 27, 0, 2 ), new SourceBlock( 22, 31, 2 ) ), - new SingleColourLookup( new SourceBlock( 27, 0, 1 ), new SourceBlock( 23, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 27, 0, 0 ), new SourceBlock( 23, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 27, 0, 1 ), new SourceBlock( 23, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 27, 0, 2 ), new SourceBlock( 23, 31, 2 ) ), - new SingleColourLookup( new SourceBlock( 27, 0, 3 ), new SourceBlock( 24, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 27, 0, 4 ), new SourceBlock( 24, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 28, 0, 4 ), new SourceBlock( 24, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 28, 0, 3 ), new SourceBlock( 24, 31, 2 ) ), - new SingleColourLookup( new SourceBlock( 28, 0, 2 ), new SourceBlock( 25, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 28, 0, 1 ), new SourceBlock( 25, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 28, 0, 0 ), new SourceBlock( 28, 28, 0 ) ), - new SingleColourLookup( new SourceBlock( 28, 0, 1 ), new SourceBlock( 28, 28, 1 ) ), - new SingleColourLookup( new SourceBlock( 28, 0, 2 ), new SourceBlock( 26, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 28, 0, 3 ), new SourceBlock( 26, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 28, 0, 4 ), new SourceBlock( 28, 29, 0 ) ), - new SingleColourLookup( new SourceBlock( 29, 0, 3 ), new SourceBlock( 28, 29, 1 ) ), - new SingleColourLookup( new SourceBlock( 29, 0, 2 ), new SourceBlock( 27, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 29, 0, 1 ), new SourceBlock( 27, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 29, 0, 0 ), new SourceBlock( 28, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 29, 0, 1 ), new SourceBlock( 28, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 29, 0, 2 ), new SourceBlock( 28, 30, 2 ) ), - new SingleColourLookup( new SourceBlock( 29, 0, 3 ), new SourceBlock( 28, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 29, 0, 4 ), new SourceBlock( 28, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 30, 0, 3 ), new SourceBlock( 28, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 30, 0, 2 ), new SourceBlock( 28, 31, 2 ) ), - new SingleColourLookup( new SourceBlock( 30, 0, 1 ), new SourceBlock( 29, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 30, 0, 0 ), new SourceBlock( 29, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 30, 0, 1 ), new SourceBlock( 29, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 30, 0, 2 ), new SourceBlock( 29, 31, 2 ) ), - new SingleColourLookup( new SourceBlock( 30, 0, 3 ), new SourceBlock( 30, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 30, 0, 4 ), new SourceBlock( 30, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 31, 0, 3 ), new SourceBlock( 30, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 31, 0, 2 ), new SourceBlock( 30, 31, 2 ) ), - new SingleColourLookup( new SourceBlock( 31, 0, 1 ), new SourceBlock( 31, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 31, 0, 0 ), new SourceBlock( 31, 31, 0 ) ) -}; - - public static SingleColourLookup[] lookup_6_3 = new SingleColourLookup[] - { - new SingleColourLookup( new SourceBlock( 0, 0, 0 ), new SourceBlock( 0, 0, 0 ) ), - new SingleColourLookup( new SourceBlock( 0, 0, 1 ), new SourceBlock( 0, 1, 1 ) ), - new SingleColourLookup( new SourceBlock( 0, 0, 2 ), new SourceBlock( 0, 1, 0 ) ), - new SingleColourLookup( new SourceBlock( 1, 0, 1 ), new SourceBlock( 0, 2, 1 ) ), - new SingleColourLookup( new SourceBlock( 1, 0, 0 ), new SourceBlock( 0, 2, 0 ) ), - new SingleColourLookup( new SourceBlock( 1, 0, 1 ), new SourceBlock( 0, 3, 1 ) ), - new SingleColourLookup( new SourceBlock( 1, 0, 2 ), new SourceBlock( 0, 3, 0 ) ), - new SingleColourLookup( new SourceBlock( 2, 0, 1 ), new SourceBlock( 0, 4, 1 ) ), - new SingleColourLookup( new SourceBlock( 2, 0, 0 ), new SourceBlock( 0, 4, 0 ) ), - new SingleColourLookup( new SourceBlock( 2, 0, 1 ), new SourceBlock( 0, 5, 1 ) ), - new SingleColourLookup( new SourceBlock( 2, 0, 2 ), new SourceBlock( 0, 5, 0 ) ), - new SingleColourLookup( new SourceBlock( 3, 0, 1 ), new SourceBlock( 0, 6, 1 ) ), - new SingleColourLookup( new SourceBlock( 3, 0, 0 ), new SourceBlock( 0, 6, 0 ) ), - new SingleColourLookup( new SourceBlock( 3, 0, 1 ), new SourceBlock( 0, 7, 1 ) ), - new SingleColourLookup( new SourceBlock( 3, 0, 2 ), new SourceBlock( 0, 7, 0 ) ), - new SingleColourLookup( new SourceBlock( 4, 0, 1 ), new SourceBlock( 0, 8, 1 ) ), - new SingleColourLookup( new SourceBlock( 4, 0, 0 ), new SourceBlock( 0, 8, 0 ) ), - new SingleColourLookup( new SourceBlock( 4, 0, 1 ), new SourceBlock( 0, 9, 1 ) ), - new SingleColourLookup( new SourceBlock( 4, 0, 2 ), new SourceBlock( 0, 9, 0 ) ), - new SingleColourLookup( new SourceBlock( 5, 0, 1 ), new SourceBlock( 0, 10, 1 ) ), - new SingleColourLookup( new SourceBlock( 5, 0, 0 ), new SourceBlock( 0, 10, 0 ) ), - new SingleColourLookup( new SourceBlock( 5, 0, 1 ), new SourceBlock( 0, 11, 1 ) ), - new SingleColourLookup( new SourceBlock( 5, 0, 2 ), new SourceBlock( 0, 11, 0 ) ), - new SingleColourLookup( new SourceBlock( 6, 0, 1 ), new SourceBlock( 0, 12, 1 ) ), - new SingleColourLookup( new SourceBlock( 6, 0, 0 ), new SourceBlock( 0, 12, 0 ) ), - new SingleColourLookup( new SourceBlock( 6, 0, 1 ), new SourceBlock( 0, 13, 1 ) ), - new SingleColourLookup( new SourceBlock( 6, 0, 2 ), new SourceBlock( 0, 13, 0 ) ), - new SingleColourLookup( new SourceBlock( 7, 0, 1 ), new SourceBlock( 0, 14, 1 ) ), - new SingleColourLookup( new SourceBlock( 7, 0, 0 ), new SourceBlock( 0, 14, 0 ) ), - new SingleColourLookup( new SourceBlock( 7, 0, 1 ), new SourceBlock( 0, 15, 1 ) ), - new SingleColourLookup( new SourceBlock( 7, 0, 2 ), new SourceBlock( 0, 15, 0 ) ), - new SingleColourLookup( new SourceBlock( 8, 0, 1 ), new SourceBlock( 0, 16, 1 ) ), - new SingleColourLookup( new SourceBlock( 8, 0, 0 ), new SourceBlock( 0, 16, 0 ) ), - new SingleColourLookup( new SourceBlock( 8, 0, 1 ), new SourceBlock( 0, 17, 1 ) ), - new SingleColourLookup( new SourceBlock( 8, 0, 2 ), new SourceBlock( 0, 17, 0 ) ), - new SingleColourLookup( new SourceBlock( 9, 0, 1 ), new SourceBlock( 0, 18, 1 ) ), - new SingleColourLookup( new SourceBlock( 9, 0, 0 ), new SourceBlock( 0, 18, 0 ) ), - new SingleColourLookup( new SourceBlock( 9, 0, 1 ), new SourceBlock( 0, 19, 1 ) ), - new SingleColourLookup( new SourceBlock( 9, 0, 2 ), new SourceBlock( 0, 19, 0 ) ), - new SingleColourLookup( new SourceBlock( 10, 0, 1 ), new SourceBlock( 0, 20, 1 ) ), - new SingleColourLookup( new SourceBlock( 10, 0, 0 ), new SourceBlock( 0, 20, 0 ) ), - new SingleColourLookup( new SourceBlock( 10, 0, 1 ), new SourceBlock( 0, 21, 1 ) ), - new SingleColourLookup( new SourceBlock( 10, 0, 2 ), new SourceBlock( 0, 21, 0 ) ), - new SingleColourLookup( new SourceBlock( 11, 0, 1 ), new SourceBlock( 0, 22, 1 ) ), - new SingleColourLookup( new SourceBlock( 11, 0, 0 ), new SourceBlock( 0, 22, 0 ) ), - new SingleColourLookup( new SourceBlock( 11, 0, 1 ), new SourceBlock( 0, 23, 1 ) ), - new SingleColourLookup( new SourceBlock( 11, 0, 2 ), new SourceBlock( 0, 23, 0 ) ), - new SingleColourLookup( new SourceBlock( 12, 0, 1 ), new SourceBlock( 0, 24, 1 ) ), - new SingleColourLookup( new SourceBlock( 12, 0, 0 ), new SourceBlock( 0, 24, 0 ) ), - new SingleColourLookup( new SourceBlock( 12, 0, 1 ), new SourceBlock( 0, 25, 1 ) ), - new SingleColourLookup( new SourceBlock( 12, 0, 2 ), new SourceBlock( 0, 25, 0 ) ), - new SingleColourLookup( new SourceBlock( 13, 0, 1 ), new SourceBlock( 0, 26, 1 ) ), - new SingleColourLookup( new SourceBlock( 13, 0, 0 ), new SourceBlock( 0, 26, 0 ) ), - new SingleColourLookup( new SourceBlock( 13, 0, 1 ), new SourceBlock( 0, 27, 1 ) ), - new SingleColourLookup( new SourceBlock( 13, 0, 2 ), new SourceBlock( 0, 27, 0 ) ), - new SingleColourLookup( new SourceBlock( 14, 0, 1 ), new SourceBlock( 0, 28, 1 ) ), - new SingleColourLookup( new SourceBlock( 14, 0, 0 ), new SourceBlock( 0, 28, 0 ) ), - new SingleColourLookup( new SourceBlock( 14, 0, 1 ), new SourceBlock( 0, 29, 1 ) ), - new SingleColourLookup( new SourceBlock( 14, 0, 2 ), new SourceBlock( 0, 29, 0 ) ), - new SingleColourLookup( new SourceBlock( 15, 0, 1 ), new SourceBlock( 0, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 15, 0, 0 ), new SourceBlock( 0, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 15, 0, 1 ), new SourceBlock( 0, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 15, 0, 2 ), new SourceBlock( 0, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 16, 0, 2 ), new SourceBlock( 1, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 16, 0, 1 ), new SourceBlock( 1, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 16, 0, 0 ), new SourceBlock( 0, 32, 0 ) ), - new SingleColourLookup( new SourceBlock( 16, 0, 1 ), new SourceBlock( 2, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 16, 0, 2 ), new SourceBlock( 0, 33, 0 ) ), - new SingleColourLookup( new SourceBlock( 17, 0, 1 ), new SourceBlock( 3, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 17, 0, 0 ), new SourceBlock( 0, 34, 0 ) ), - new SingleColourLookup( new SourceBlock( 17, 0, 1 ), new SourceBlock( 4, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 17, 0, 2 ), new SourceBlock( 0, 35, 0 ) ), - new SingleColourLookup( new SourceBlock( 18, 0, 1 ), new SourceBlock( 5, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 18, 0, 0 ), new SourceBlock( 0, 36, 0 ) ), - new SingleColourLookup( new SourceBlock( 18, 0, 1 ), new SourceBlock( 6, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 18, 0, 2 ), new SourceBlock( 0, 37, 0 ) ), - new SingleColourLookup( new SourceBlock( 19, 0, 1 ), new SourceBlock( 7, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 19, 0, 0 ), new SourceBlock( 0, 38, 0 ) ), - new SingleColourLookup( new SourceBlock( 19, 0, 1 ), new SourceBlock( 8, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 19, 0, 2 ), new SourceBlock( 0, 39, 0 ) ), - new SingleColourLookup( new SourceBlock( 20, 0, 1 ), new SourceBlock( 9, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 20, 0, 0 ), new SourceBlock( 0, 40, 0 ) ), - new SingleColourLookup( new SourceBlock( 20, 0, 1 ), new SourceBlock( 10, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 20, 0, 2 ), new SourceBlock( 0, 41, 0 ) ), - new SingleColourLookup( new SourceBlock( 21, 0, 1 ), new SourceBlock( 11, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 21, 0, 0 ), new SourceBlock( 0, 42, 0 ) ), - new SingleColourLookup( new SourceBlock( 21, 0, 1 ), new SourceBlock( 12, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 21, 0, 2 ), new SourceBlock( 0, 43, 0 ) ), - new SingleColourLookup( new SourceBlock( 22, 0, 1 ), new SourceBlock( 13, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 22, 0, 0 ), new SourceBlock( 0, 44, 0 ) ), - new SingleColourLookup( new SourceBlock( 22, 0, 1 ), new SourceBlock( 14, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 22, 0, 2 ), new SourceBlock( 0, 45, 0 ) ), - new SingleColourLookup( new SourceBlock( 23, 0, 1 ), new SourceBlock( 15, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 23, 0, 0 ), new SourceBlock( 0, 46, 0 ) ), - new SingleColourLookup( new SourceBlock( 23, 0, 1 ), new SourceBlock( 0, 47, 1 ) ), - new SingleColourLookup( new SourceBlock( 23, 0, 2 ), new SourceBlock( 0, 47, 0 ) ), - new SingleColourLookup( new SourceBlock( 24, 0, 1 ), new SourceBlock( 0, 48, 1 ) ), - new SingleColourLookup( new SourceBlock( 24, 0, 0 ), new SourceBlock( 0, 48, 0 ) ), - new SingleColourLookup( new SourceBlock( 24, 0, 1 ), new SourceBlock( 0, 49, 1 ) ), - new SingleColourLookup( new SourceBlock( 24, 0, 2 ), new SourceBlock( 0, 49, 0 ) ), - new SingleColourLookup( new SourceBlock( 25, 0, 1 ), new SourceBlock( 0, 50, 1 ) ), - new SingleColourLookup( new SourceBlock( 25, 0, 0 ), new SourceBlock( 0, 50, 0 ) ), - new SingleColourLookup( new SourceBlock( 25, 0, 1 ), new SourceBlock( 0, 51, 1 ) ), - new SingleColourLookup( new SourceBlock( 25, 0, 2 ), new SourceBlock( 0, 51, 0 ) ), - new SingleColourLookup( new SourceBlock( 26, 0, 1 ), new SourceBlock( 0, 52, 1 ) ), - new SingleColourLookup( new SourceBlock( 26, 0, 0 ), new SourceBlock( 0, 52, 0 ) ), - new SingleColourLookup( new SourceBlock( 26, 0, 1 ), new SourceBlock( 0, 53, 1 ) ), - new SingleColourLookup( new SourceBlock( 26, 0, 2 ), new SourceBlock( 0, 53, 0 ) ), - new SingleColourLookup( new SourceBlock( 27, 0, 1 ), new SourceBlock( 0, 54, 1 ) ), - new SingleColourLookup( new SourceBlock( 27, 0, 0 ), new SourceBlock( 0, 54, 0 ) ), - new SingleColourLookup( new SourceBlock( 27, 0, 1 ), new SourceBlock( 0, 55, 1 ) ), - new SingleColourLookup( new SourceBlock( 27, 0, 2 ), new SourceBlock( 0, 55, 0 ) ), - new SingleColourLookup( new SourceBlock( 28, 0, 1 ), new SourceBlock( 0, 56, 1 ) ), - new SingleColourLookup( new SourceBlock( 28, 0, 0 ), new SourceBlock( 0, 56, 0 ) ), - new SingleColourLookup( new SourceBlock( 28, 0, 1 ), new SourceBlock( 0, 57, 1 ) ), - new SingleColourLookup( new SourceBlock( 28, 0, 2 ), new SourceBlock( 0, 57, 0 ) ), - new SingleColourLookup( new SourceBlock( 29, 0, 1 ), new SourceBlock( 0, 58, 1 ) ), - new SingleColourLookup( new SourceBlock( 29, 0, 0 ), new SourceBlock( 0, 58, 0 ) ), - new SingleColourLookup( new SourceBlock( 29, 0, 1 ), new SourceBlock( 0, 59, 1 ) ), - new SingleColourLookup( new SourceBlock( 29, 0, 2 ), new SourceBlock( 0, 59, 0 ) ), - new SingleColourLookup( new SourceBlock( 30, 0, 1 ), new SourceBlock( 0, 60, 1 ) ), - new SingleColourLookup( new SourceBlock( 30, 0, 0 ), new SourceBlock( 0, 60, 0 ) ), - new SingleColourLookup( new SourceBlock( 30, 0, 1 ), new SourceBlock( 0, 61, 1 ) ), - new SingleColourLookup( new SourceBlock( 30, 0, 2 ), new SourceBlock( 0, 61, 0 ) ), - new SingleColourLookup( new SourceBlock( 31, 0, 1 ), new SourceBlock( 0, 62, 1 ) ), - new SingleColourLookup( new SourceBlock( 31, 0, 0 ), new SourceBlock( 0, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 31, 0, 1 ), new SourceBlock( 0, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 31, 0, 2 ), new SourceBlock( 0, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 32, 0, 2 ), new SourceBlock( 1, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 32, 0, 1 ), new SourceBlock( 1, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 32, 0, 0 ), new SourceBlock( 16, 48, 0 ) ), - new SingleColourLookup( new SourceBlock( 32, 0, 1 ), new SourceBlock( 2, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 32, 0, 2 ), new SourceBlock( 16, 49, 0 ) ), - new SingleColourLookup( new SourceBlock( 33, 0, 1 ), new SourceBlock( 3, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 33, 0, 0 ), new SourceBlock( 16, 50, 0 ) ), - new SingleColourLookup( new SourceBlock( 33, 0, 1 ), new SourceBlock( 4, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 33, 0, 2 ), new SourceBlock( 16, 51, 0 ) ), - new SingleColourLookup( new SourceBlock( 34, 0, 1 ), new SourceBlock( 5, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 34, 0, 0 ), new SourceBlock( 16, 52, 0 ) ), - new SingleColourLookup( new SourceBlock( 34, 0, 1 ), new SourceBlock( 6, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 34, 0, 2 ), new SourceBlock( 16, 53, 0 ) ), - new SingleColourLookup( new SourceBlock( 35, 0, 1 ), new SourceBlock( 7, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 35, 0, 0 ), new SourceBlock( 16, 54, 0 ) ), - new SingleColourLookup( new SourceBlock( 35, 0, 1 ), new SourceBlock( 8, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 35, 0, 2 ), new SourceBlock( 16, 55, 0 ) ), - new SingleColourLookup( new SourceBlock( 36, 0, 1 ), new SourceBlock( 9, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 36, 0, 0 ), new SourceBlock( 16, 56, 0 ) ), - new SingleColourLookup( new SourceBlock( 36, 0, 1 ), new SourceBlock( 10, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 36, 0, 2 ), new SourceBlock( 16, 57, 0 ) ), - new SingleColourLookup( new SourceBlock( 37, 0, 1 ), new SourceBlock( 11, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 37, 0, 0 ), new SourceBlock( 16, 58, 0 ) ), - new SingleColourLookup( new SourceBlock( 37, 0, 1 ), new SourceBlock( 12, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 37, 0, 2 ), new SourceBlock( 16, 59, 0 ) ), - new SingleColourLookup( new SourceBlock( 38, 0, 1 ), new SourceBlock( 13, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 38, 0, 0 ), new SourceBlock( 16, 60, 0 ) ), - new SingleColourLookup( new SourceBlock( 38, 0, 1 ), new SourceBlock( 14, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 38, 0, 2 ), new SourceBlock( 16, 61, 0 ) ), - new SingleColourLookup( new SourceBlock( 39, 0, 1 ), new SourceBlock( 15, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 39, 0, 0 ), new SourceBlock( 16, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 39, 0, 1 ), new SourceBlock( 16, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 39, 0, 2 ), new SourceBlock( 16, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 40, 0, 1 ), new SourceBlock( 17, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 40, 0, 0 ), new SourceBlock( 17, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 40, 0, 1 ), new SourceBlock( 18, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 40, 0, 2 ), new SourceBlock( 18, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 41, 0, 1 ), new SourceBlock( 19, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 41, 0, 0 ), new SourceBlock( 19, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 41, 0, 1 ), new SourceBlock( 20, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 41, 0, 2 ), new SourceBlock( 20, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 42, 0, 1 ), new SourceBlock( 21, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 42, 0, 0 ), new SourceBlock( 21, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 42, 0, 1 ), new SourceBlock( 22, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 42, 0, 2 ), new SourceBlock( 22, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 43, 0, 1 ), new SourceBlock( 23, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 43, 0, 0 ), new SourceBlock( 23, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 43, 0, 1 ), new SourceBlock( 24, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 43, 0, 2 ), new SourceBlock( 24, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 44, 0, 1 ), new SourceBlock( 25, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 44, 0, 0 ), new SourceBlock( 25, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 44, 0, 1 ), new SourceBlock( 26, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 44, 0, 2 ), new SourceBlock( 26, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 45, 0, 1 ), new SourceBlock( 27, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 45, 0, 0 ), new SourceBlock( 27, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 45, 0, 1 ), new SourceBlock( 28, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 45, 0, 2 ), new SourceBlock( 28, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 46, 0, 1 ), new SourceBlock( 29, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 46, 0, 0 ), new SourceBlock( 29, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 46, 0, 1 ), new SourceBlock( 30, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 46, 0, 2 ), new SourceBlock( 30, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 47, 0, 1 ), new SourceBlock( 31, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 47, 0, 0 ), new SourceBlock( 31, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 47, 0, 1 ), new SourceBlock( 32, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 47, 0, 2 ), new SourceBlock( 32, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 48, 0, 2 ), new SourceBlock( 33, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 48, 0, 1 ), new SourceBlock( 33, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 48, 0, 0 ), new SourceBlock( 48, 48, 0 ) ), - new SingleColourLookup( new SourceBlock( 48, 0, 1 ), new SourceBlock( 34, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 48, 0, 2 ), new SourceBlock( 48, 49, 0 ) ), - new SingleColourLookup( new SourceBlock( 49, 0, 1 ), new SourceBlock( 35, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 49, 0, 0 ), new SourceBlock( 48, 50, 0 ) ), - new SingleColourLookup( new SourceBlock( 49, 0, 1 ), new SourceBlock( 36, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 49, 0, 2 ), new SourceBlock( 48, 51, 0 ) ), - new SingleColourLookup( new SourceBlock( 50, 0, 1 ), new SourceBlock( 37, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 50, 0, 0 ), new SourceBlock( 48, 52, 0 ) ), - new SingleColourLookup( new SourceBlock( 50, 0, 1 ), new SourceBlock( 38, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 50, 0, 2 ), new SourceBlock( 48, 53, 0 ) ), - new SingleColourLookup( new SourceBlock( 51, 0, 1 ), new SourceBlock( 39, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 51, 0, 0 ), new SourceBlock( 48, 54, 0 ) ), - new SingleColourLookup( new SourceBlock( 51, 0, 1 ), new SourceBlock( 40, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 51, 0, 2 ), new SourceBlock( 48, 55, 0 ) ), - new SingleColourLookup( new SourceBlock( 52, 0, 1 ), new SourceBlock( 41, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 52, 0, 0 ), new SourceBlock( 48, 56, 0 ) ), - new SingleColourLookup( new SourceBlock( 52, 0, 1 ), new SourceBlock( 42, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 52, 0, 2 ), new SourceBlock( 48, 57, 0 ) ), - new SingleColourLookup( new SourceBlock( 53, 0, 1 ), new SourceBlock( 43, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 53, 0, 0 ), new SourceBlock( 48, 58, 0 ) ), - new SingleColourLookup( new SourceBlock( 53, 0, 1 ), new SourceBlock( 44, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 53, 0, 2 ), new SourceBlock( 48, 59, 0 ) ), - new SingleColourLookup( new SourceBlock( 54, 0, 1 ), new SourceBlock( 45, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 54, 0, 0 ), new SourceBlock( 48, 60, 0 ) ), - new SingleColourLookup( new SourceBlock( 54, 0, 1 ), new SourceBlock( 46, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 54, 0, 2 ), new SourceBlock( 48, 61, 0 ) ), - new SingleColourLookup( new SourceBlock( 55, 0, 1 ), new SourceBlock( 47, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 55, 0, 0 ), new SourceBlock( 48, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 55, 0, 1 ), new SourceBlock( 48, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 55, 0, 2 ), new SourceBlock( 48, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 56, 0, 1 ), new SourceBlock( 49, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 56, 0, 0 ), new SourceBlock( 49, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 56, 0, 1 ), new SourceBlock( 50, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 56, 0, 2 ), new SourceBlock( 50, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 57, 0, 1 ), new SourceBlock( 51, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 57, 0, 0 ), new SourceBlock( 51, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 57, 0, 1 ), new SourceBlock( 52, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 57, 0, 2 ), new SourceBlock( 52, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 58, 0, 1 ), new SourceBlock( 53, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 58, 0, 0 ), new SourceBlock( 53, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 58, 0, 1 ), new SourceBlock( 54, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 58, 0, 2 ), new SourceBlock( 54, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 59, 0, 1 ), new SourceBlock( 55, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 59, 0, 0 ), new SourceBlock( 55, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 59, 0, 1 ), new SourceBlock( 56, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 59, 0, 2 ), new SourceBlock( 56, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 60, 0, 1 ), new SourceBlock( 57, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 60, 0, 0 ), new SourceBlock( 57, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 60, 0, 1 ), new SourceBlock( 58, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 60, 0, 2 ), new SourceBlock( 58, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 61, 0, 1 ), new SourceBlock( 59, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 61, 0, 0 ), new SourceBlock( 59, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 61, 0, 1 ), new SourceBlock( 60, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 61, 0, 2 ), new SourceBlock( 60, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 62, 0, 1 ), new SourceBlock( 61, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 62, 0, 0 ), new SourceBlock( 61, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 62, 0, 1 ), new SourceBlock( 62, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 62, 0, 2 ), new SourceBlock( 62, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 63, 0, 1 ), new SourceBlock( 63, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 63, 0, 0 ), new SourceBlock( 63, 63, 0 ) ) - }; - - public static SingleColourLookup[] lookup_5_4 = new SingleColourLookup[] - { - new SingleColourLookup( new SourceBlock( 0, 0, 0 ), new SourceBlock( 0, 0, 0 ) ), - new SingleColourLookup( new SourceBlock( 0, 0, 1 ), new SourceBlock( 0, 1, 1 ) ), - new SingleColourLookup( new SourceBlock( 0, 0, 2 ), new SourceBlock( 0, 1, 0 ) ), - new SingleColourLookup( new SourceBlock( 0, 0, 3 ), new SourceBlock( 0, 1, 1 ) ), - new SingleColourLookup( new SourceBlock( 0, 0, 4 ), new SourceBlock( 0, 2, 1 ) ), - new SingleColourLookup( new SourceBlock( 1, 0, 3 ), new SourceBlock( 0, 2, 0 ) ), - new SingleColourLookup( new SourceBlock( 1, 0, 2 ), new SourceBlock( 0, 2, 1 ) ), - new SingleColourLookup( new SourceBlock( 1, 0, 1 ), new SourceBlock( 0, 3, 1 ) ), - new SingleColourLookup( new SourceBlock( 1, 0, 0 ), new SourceBlock( 0, 3, 0 ) ), - new SingleColourLookup( new SourceBlock( 1, 0, 1 ), new SourceBlock( 1, 2, 1 ) ), - new SingleColourLookup( new SourceBlock( 1, 0, 2 ), new SourceBlock( 1, 2, 0 ) ), - new SingleColourLookup( new SourceBlock( 1, 0, 3 ), new SourceBlock( 0, 4, 0 ) ), - new SingleColourLookup( new SourceBlock( 1, 0, 4 ), new SourceBlock( 0, 5, 1 ) ), - new SingleColourLookup( new SourceBlock( 2, 0, 3 ), new SourceBlock( 0, 5, 0 ) ), - new SingleColourLookup( new SourceBlock( 2, 0, 2 ), new SourceBlock( 0, 5, 1 ) ), - new SingleColourLookup( new SourceBlock( 2, 0, 1 ), new SourceBlock( 0, 6, 1 ) ), - new SingleColourLookup( new SourceBlock( 2, 0, 0 ), new SourceBlock( 0, 6, 0 ) ), - new SingleColourLookup( new SourceBlock( 2, 0, 1 ), new SourceBlock( 2, 3, 1 ) ), - new SingleColourLookup( new SourceBlock( 2, 0, 2 ), new SourceBlock( 2, 3, 0 ) ), - new SingleColourLookup( new SourceBlock( 2, 0, 3 ), new SourceBlock( 0, 7, 0 ) ), - new SingleColourLookup( new SourceBlock( 2, 0, 4 ), new SourceBlock( 1, 6, 1 ) ), - new SingleColourLookup( new SourceBlock( 3, 0, 3 ), new SourceBlock( 1, 6, 0 ) ), - new SingleColourLookup( new SourceBlock( 3, 0, 2 ), new SourceBlock( 0, 8, 0 ) ), - new SingleColourLookup( new SourceBlock( 3, 0, 1 ), new SourceBlock( 0, 9, 1 ) ), - new SingleColourLookup( new SourceBlock( 3, 0, 0 ), new SourceBlock( 0, 9, 0 ) ), - new SingleColourLookup( new SourceBlock( 3, 0, 1 ), new SourceBlock( 0, 9, 1 ) ), - new SingleColourLookup( new SourceBlock( 3, 0, 2 ), new SourceBlock( 0, 10, 1 ) ), - new SingleColourLookup( new SourceBlock( 3, 0, 3 ), new SourceBlock( 0, 10, 0 ) ), - new SingleColourLookup( new SourceBlock( 3, 0, 4 ), new SourceBlock( 2, 7, 1 ) ), - new SingleColourLookup( new SourceBlock( 4, 0, 4 ), new SourceBlock( 2, 7, 0 ) ), - new SingleColourLookup( new SourceBlock( 4, 0, 3 ), new SourceBlock( 0, 11, 0 ) ), - new SingleColourLookup( new SourceBlock( 4, 0, 2 ), new SourceBlock( 1, 10, 1 ) ), - new SingleColourLookup( new SourceBlock( 4, 0, 1 ), new SourceBlock( 1, 10, 0 ) ), - new SingleColourLookup( new SourceBlock( 4, 0, 0 ), new SourceBlock( 0, 12, 0 ) ), - new SingleColourLookup( new SourceBlock( 4, 0, 1 ), new SourceBlock( 0, 13, 1 ) ), - new SingleColourLookup( new SourceBlock( 4, 0, 2 ), new SourceBlock( 0, 13, 0 ) ), - new SingleColourLookup( new SourceBlock( 4, 0, 3 ), new SourceBlock( 0, 13, 1 ) ), - new SingleColourLookup( new SourceBlock( 4, 0, 4 ), new SourceBlock( 0, 14, 1 ) ), - new SingleColourLookup( new SourceBlock( 5, 0, 3 ), new SourceBlock( 0, 14, 0 ) ), - new SingleColourLookup( new SourceBlock( 5, 0, 2 ), new SourceBlock( 2, 11, 1 ) ), - new SingleColourLookup( new SourceBlock( 5, 0, 1 ), new SourceBlock( 2, 11, 0 ) ), - new SingleColourLookup( new SourceBlock( 5, 0, 0 ), new SourceBlock( 0, 15, 0 ) ), - new SingleColourLookup( new SourceBlock( 5, 0, 1 ), new SourceBlock( 1, 14, 1 ) ), - new SingleColourLookup( new SourceBlock( 5, 0, 2 ), new SourceBlock( 1, 14, 0 ) ), - new SingleColourLookup( new SourceBlock( 5, 0, 3 ), new SourceBlock( 0, 16, 0 ) ), - new SingleColourLookup( new SourceBlock( 5, 0, 4 ), new SourceBlock( 0, 17, 1 ) ), - new SingleColourLookup( new SourceBlock( 6, 0, 3 ), new SourceBlock( 0, 17, 0 ) ), - new SingleColourLookup( new SourceBlock( 6, 0, 2 ), new SourceBlock( 0, 17, 1 ) ), - new SingleColourLookup( new SourceBlock( 6, 0, 1 ), new SourceBlock( 0, 18, 1 ) ), - new SingleColourLookup( new SourceBlock( 6, 0, 0 ), new SourceBlock( 0, 18, 0 ) ), - new SingleColourLookup( new SourceBlock( 6, 0, 1 ), new SourceBlock( 2, 15, 1 ) ), - new SingleColourLookup( new SourceBlock( 6, 0, 2 ), new SourceBlock( 2, 15, 0 ) ), - new SingleColourLookup( new SourceBlock( 6, 0, 3 ), new SourceBlock( 0, 19, 0 ) ), - new SingleColourLookup( new SourceBlock( 6, 0, 4 ), new SourceBlock( 1, 18, 1 ) ), - new SingleColourLookup( new SourceBlock( 7, 0, 3 ), new SourceBlock( 1, 18, 0 ) ), - new SingleColourLookup( new SourceBlock( 7, 0, 2 ), new SourceBlock( 0, 20, 0 ) ), - new SingleColourLookup( new SourceBlock( 7, 0, 1 ), new SourceBlock( 0, 21, 1 ) ), - new SingleColourLookup( new SourceBlock( 7, 0, 0 ), new SourceBlock( 0, 21, 0 ) ), - new SingleColourLookup( new SourceBlock( 7, 0, 1 ), new SourceBlock( 0, 21, 1 ) ), - new SingleColourLookup( new SourceBlock( 7, 0, 2 ), new SourceBlock( 0, 22, 1 ) ), - new SingleColourLookup( new SourceBlock( 7, 0, 3 ), new SourceBlock( 0, 22, 0 ) ), - new SingleColourLookup( new SourceBlock( 7, 0, 4 ), new SourceBlock( 2, 19, 1 ) ), - new SingleColourLookup( new SourceBlock( 8, 0, 4 ), new SourceBlock( 2, 19, 0 ) ), - new SingleColourLookup( new SourceBlock( 8, 0, 3 ), new SourceBlock( 0, 23, 0 ) ), - new SingleColourLookup( new SourceBlock( 8, 0, 2 ), new SourceBlock( 1, 22, 1 ) ), - new SingleColourLookup( new SourceBlock( 8, 0, 1 ), new SourceBlock( 1, 22, 0 ) ), - new SingleColourLookup( new SourceBlock( 8, 0, 0 ), new SourceBlock( 0, 24, 0 ) ), - new SingleColourLookup( new SourceBlock( 8, 0, 1 ), new SourceBlock( 0, 25, 1 ) ), - new SingleColourLookup( new SourceBlock( 8, 0, 2 ), new SourceBlock( 0, 25, 0 ) ), - new SingleColourLookup( new SourceBlock( 8, 0, 3 ), new SourceBlock( 0, 25, 1 ) ), - new SingleColourLookup( new SourceBlock( 8, 0, 4 ), new SourceBlock( 0, 26, 1 ) ), - new SingleColourLookup( new SourceBlock( 9, 0, 3 ), new SourceBlock( 0, 26, 0 ) ), - new SingleColourLookup( new SourceBlock( 9, 0, 2 ), new SourceBlock( 2, 23, 1 ) ), - new SingleColourLookup( new SourceBlock( 9, 0, 1 ), new SourceBlock( 2, 23, 0 ) ), - new SingleColourLookup( new SourceBlock( 9, 0, 0 ), new SourceBlock( 0, 27, 0 ) ), - new SingleColourLookup( new SourceBlock( 9, 0, 1 ), new SourceBlock( 1, 26, 1 ) ), - new SingleColourLookup( new SourceBlock( 9, 0, 2 ), new SourceBlock( 1, 26, 0 ) ), - new SingleColourLookup( new SourceBlock( 9, 0, 3 ), new SourceBlock( 0, 28, 0 ) ), - new SingleColourLookup( new SourceBlock( 9, 0, 4 ), new SourceBlock( 0, 29, 1 ) ), - new SingleColourLookup( new SourceBlock( 10, 0, 3 ), new SourceBlock( 0, 29, 0 ) ), - new SingleColourLookup( new SourceBlock( 10, 0, 2 ), new SourceBlock( 0, 29, 1 ) ), - new SingleColourLookup( new SourceBlock( 10, 0, 1 ), new SourceBlock( 0, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 10, 0, 0 ), new SourceBlock( 0, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 10, 0, 1 ), new SourceBlock( 2, 27, 1 ) ), - new SingleColourLookup( new SourceBlock( 10, 0, 2 ), new SourceBlock( 2, 27, 0 ) ), - new SingleColourLookup( new SourceBlock( 10, 0, 3 ), new SourceBlock( 0, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 10, 0, 4 ), new SourceBlock( 1, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 11, 0, 3 ), new SourceBlock( 1, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 11, 0, 2 ), new SourceBlock( 4, 24, 0 ) ), - new SingleColourLookup( new SourceBlock( 11, 0, 1 ), new SourceBlock( 1, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 11, 0, 0 ), new SourceBlock( 1, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 11, 0, 1 ), new SourceBlock( 1, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 11, 0, 2 ), new SourceBlock( 2, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 11, 0, 3 ), new SourceBlock( 2, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 11, 0, 4 ), new SourceBlock( 2, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 12, 0, 4 ), new SourceBlock( 2, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 12, 0, 3 ), new SourceBlock( 4, 27, 0 ) ), - new SingleColourLookup( new SourceBlock( 12, 0, 2 ), new SourceBlock( 3, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 12, 0, 1 ), new SourceBlock( 3, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 12, 0, 0 ), new SourceBlock( 4, 28, 0 ) ), - new SingleColourLookup( new SourceBlock( 12, 0, 1 ), new SourceBlock( 3, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 12, 0, 2 ), new SourceBlock( 3, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 12, 0, 3 ), new SourceBlock( 3, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 12, 0, 4 ), new SourceBlock( 4, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 13, 0, 3 ), new SourceBlock( 4, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 13, 0, 2 ), new SourceBlock( 6, 27, 1 ) ), - new SingleColourLookup( new SourceBlock( 13, 0, 1 ), new SourceBlock( 6, 27, 0 ) ), - new SingleColourLookup( new SourceBlock( 13, 0, 0 ), new SourceBlock( 4, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 13, 0, 1 ), new SourceBlock( 5, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 13, 0, 2 ), new SourceBlock( 5, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 13, 0, 3 ), new SourceBlock( 8, 24, 0 ) ), - new SingleColourLookup( new SourceBlock( 13, 0, 4 ), new SourceBlock( 5, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 14, 0, 3 ), new SourceBlock( 5, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 14, 0, 2 ), new SourceBlock( 5, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 14, 0, 1 ), new SourceBlock( 6, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 14, 0, 0 ), new SourceBlock( 6, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 14, 0, 1 ), new SourceBlock( 6, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 14, 0, 2 ), new SourceBlock( 6, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 14, 0, 3 ), new SourceBlock( 8, 27, 0 ) ), - new SingleColourLookup( new SourceBlock( 14, 0, 4 ), new SourceBlock( 7, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 15, 0, 3 ), new SourceBlock( 7, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 15, 0, 2 ), new SourceBlock( 8, 28, 0 ) ), - new SingleColourLookup( new SourceBlock( 15, 0, 1 ), new SourceBlock( 7, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 15, 0, 0 ), new SourceBlock( 7, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 15, 0, 1 ), new SourceBlock( 7, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 15, 0, 2 ), new SourceBlock( 8, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 15, 0, 3 ), new SourceBlock( 8, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 15, 0, 4 ), new SourceBlock( 10, 27, 1 ) ), - new SingleColourLookup( new SourceBlock( 16, 0, 4 ), new SourceBlock( 10, 27, 0 ) ), - new SingleColourLookup( new SourceBlock( 16, 0, 3 ), new SourceBlock( 8, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 16, 0, 2 ), new SourceBlock( 9, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 16, 0, 1 ), new SourceBlock( 9, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 16, 0, 0 ), new SourceBlock( 12, 24, 0 ) ), - new SingleColourLookup( new SourceBlock( 16, 0, 1 ), new SourceBlock( 9, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 16, 0, 2 ), new SourceBlock( 9, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 16, 0, 3 ), new SourceBlock( 9, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 16, 0, 4 ), new SourceBlock( 10, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 17, 0, 3 ), new SourceBlock( 10, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 17, 0, 2 ), new SourceBlock( 10, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 17, 0, 1 ), new SourceBlock( 10, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 17, 0, 0 ), new SourceBlock( 12, 27, 0 ) ), - new SingleColourLookup( new SourceBlock( 17, 0, 1 ), new SourceBlock( 11, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 17, 0, 2 ), new SourceBlock( 11, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 17, 0, 3 ), new SourceBlock( 12, 28, 0 ) ), - new SingleColourLookup( new SourceBlock( 17, 0, 4 ), new SourceBlock( 11, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 18, 0, 3 ), new SourceBlock( 11, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 18, 0, 2 ), new SourceBlock( 11, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 18, 0, 1 ), new SourceBlock( 12, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 18, 0, 0 ), new SourceBlock( 12, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 18, 0, 1 ), new SourceBlock( 14, 27, 1 ) ), - new SingleColourLookup( new SourceBlock( 18, 0, 2 ), new SourceBlock( 14, 27, 0 ) ), - new SingleColourLookup( new SourceBlock( 18, 0, 3 ), new SourceBlock( 12, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 18, 0, 4 ), new SourceBlock( 13, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 19, 0, 3 ), new SourceBlock( 13, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 19, 0, 2 ), new SourceBlock( 16, 24, 0 ) ), - new SingleColourLookup( new SourceBlock( 19, 0, 1 ), new SourceBlock( 13, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 19, 0, 0 ), new SourceBlock( 13, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 19, 0, 1 ), new SourceBlock( 13, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 19, 0, 2 ), new SourceBlock( 14, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 19, 0, 3 ), new SourceBlock( 14, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 19, 0, 4 ), new SourceBlock( 14, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 20, 0, 4 ), new SourceBlock( 14, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 20, 0, 3 ), new SourceBlock( 16, 27, 0 ) ), - new SingleColourLookup( new SourceBlock( 20, 0, 2 ), new SourceBlock( 15, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 20, 0, 1 ), new SourceBlock( 15, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 20, 0, 0 ), new SourceBlock( 16, 28, 0 ) ), - new SingleColourLookup( new SourceBlock( 20, 0, 1 ), new SourceBlock( 15, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 20, 0, 2 ), new SourceBlock( 15, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 20, 0, 3 ), new SourceBlock( 15, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 20, 0, 4 ), new SourceBlock( 16, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 21, 0, 3 ), new SourceBlock( 16, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 21, 0, 2 ), new SourceBlock( 18, 27, 1 ) ), - new SingleColourLookup( new SourceBlock( 21, 0, 1 ), new SourceBlock( 18, 27, 0 ) ), - new SingleColourLookup( new SourceBlock( 21, 0, 0 ), new SourceBlock( 16, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 21, 0, 1 ), new SourceBlock( 17, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 21, 0, 2 ), new SourceBlock( 17, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 21, 0, 3 ), new SourceBlock( 20, 24, 0 ) ), - new SingleColourLookup( new SourceBlock( 21, 0, 4 ), new SourceBlock( 17, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 22, 0, 3 ), new SourceBlock( 17, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 22, 0, 2 ), new SourceBlock( 17, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 22, 0, 1 ), new SourceBlock( 18, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 22, 0, 0 ), new SourceBlock( 18, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 22, 0, 1 ), new SourceBlock( 18, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 22, 0, 2 ), new SourceBlock( 18, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 22, 0, 3 ), new SourceBlock( 20, 27, 0 ) ), - new SingleColourLookup( new SourceBlock( 22, 0, 4 ), new SourceBlock( 19, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 23, 0, 3 ), new SourceBlock( 19, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 23, 0, 2 ), new SourceBlock( 20, 28, 0 ) ), - new SingleColourLookup( new SourceBlock( 23, 0, 1 ), new SourceBlock( 19, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 23, 0, 0 ), new SourceBlock( 19, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 23, 0, 1 ), new SourceBlock( 19, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 23, 0, 2 ), new SourceBlock( 20, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 23, 0, 3 ), new SourceBlock( 20, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 23, 0, 4 ), new SourceBlock( 22, 27, 1 ) ), - new SingleColourLookup( new SourceBlock( 24, 0, 4 ), new SourceBlock( 22, 27, 0 ) ), - new SingleColourLookup( new SourceBlock( 24, 0, 3 ), new SourceBlock( 20, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 24, 0, 2 ), new SourceBlock( 21, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 24, 0, 1 ), new SourceBlock( 21, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 24, 0, 0 ), new SourceBlock( 24, 24, 0 ) ), - new SingleColourLookup( new SourceBlock( 24, 0, 1 ), new SourceBlock( 21, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 24, 0, 2 ), new SourceBlock( 21, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 24, 0, 3 ), new SourceBlock( 21, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 24, 0, 4 ), new SourceBlock( 22, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 25, 0, 3 ), new SourceBlock( 22, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 25, 0, 2 ), new SourceBlock( 22, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 25, 0, 1 ), new SourceBlock( 22, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 25, 0, 0 ), new SourceBlock( 24, 27, 0 ) ), - new SingleColourLookup( new SourceBlock( 25, 0, 1 ), new SourceBlock( 23, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 25, 0, 2 ), new SourceBlock( 23, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 25, 0, 3 ), new SourceBlock( 24, 28, 0 ) ), - new SingleColourLookup( new SourceBlock( 25, 0, 4 ), new SourceBlock( 23, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 26, 0, 3 ), new SourceBlock( 23, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 26, 0, 2 ), new SourceBlock( 23, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 26, 0, 1 ), new SourceBlock( 24, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 26, 0, 0 ), new SourceBlock( 24, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 26, 0, 1 ), new SourceBlock( 26, 27, 1 ) ), - new SingleColourLookup( new SourceBlock( 26, 0, 2 ), new SourceBlock( 26, 27, 0 ) ), - new SingleColourLookup( new SourceBlock( 26, 0, 3 ), new SourceBlock( 24, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 26, 0, 4 ), new SourceBlock( 25, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 27, 0, 3 ), new SourceBlock( 25, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 27, 0, 2 ), new SourceBlock( 28, 24, 0 ) ), - new SingleColourLookup( new SourceBlock( 27, 0, 1 ), new SourceBlock( 25, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 27, 0, 0 ), new SourceBlock( 25, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 27, 0, 1 ), new SourceBlock( 25, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 27, 0, 2 ), new SourceBlock( 26, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 27, 0, 3 ), new SourceBlock( 26, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 27, 0, 4 ), new SourceBlock( 26, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 28, 0, 4 ), new SourceBlock( 26, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 28, 0, 3 ), new SourceBlock( 28, 27, 0 ) ), - new SingleColourLookup( new SourceBlock( 28, 0, 2 ), new SourceBlock( 27, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 28, 0, 1 ), new SourceBlock( 27, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 28, 0, 0 ), new SourceBlock( 28, 28, 0 ) ), - new SingleColourLookup( new SourceBlock( 28, 0, 1 ), new SourceBlock( 27, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 28, 0, 2 ), new SourceBlock( 27, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 28, 0, 3 ), new SourceBlock( 27, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 28, 0, 4 ), new SourceBlock( 28, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 29, 0, 3 ), new SourceBlock( 28, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 29, 0, 2 ), new SourceBlock( 30, 27, 1 ) ), - new SingleColourLookup( new SourceBlock( 29, 0, 1 ), new SourceBlock( 30, 27, 0 ) ), - new SingleColourLookup( new SourceBlock( 29, 0, 0 ), new SourceBlock( 28, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 29, 0, 1 ), new SourceBlock( 29, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 29, 0, 2 ), new SourceBlock( 29, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 29, 0, 3 ), new SourceBlock( 29, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 29, 0, 4 ), new SourceBlock( 29, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 30, 0, 3 ), new SourceBlock( 29, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 30, 0, 2 ), new SourceBlock( 29, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 30, 0, 1 ), new SourceBlock( 30, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 30, 0, 0 ), new SourceBlock( 30, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 30, 0, 1 ), new SourceBlock( 30, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 30, 0, 2 ), new SourceBlock( 30, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 30, 0, 3 ), new SourceBlock( 30, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 30, 0, 4 ), new SourceBlock( 31, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 31, 0, 3 ), new SourceBlock( 31, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 31, 0, 2 ), new SourceBlock( 31, 30, 1 ) ), - new SingleColourLookup( new SourceBlock( 31, 0, 1 ), new SourceBlock( 31, 31, 1 ) ), - new SingleColourLookup( new SourceBlock( 31, 0, 0 ), new SourceBlock( 31, 31, 0 ) ) - }; - - public static SingleColourLookup[] lookup_6_4 = new SingleColourLookup[] - { - new SingleColourLookup( new SourceBlock( 0, 0, 0 ), new SourceBlock( 0, 0, 0 ) ), - new SingleColourLookup( new SourceBlock( 0, 0, 1 ), new SourceBlock( 0, 1, 0 ) ), - new SingleColourLookup( new SourceBlock( 0, 0, 2 ), new SourceBlock( 0, 2, 0 ) ), - new SingleColourLookup( new SourceBlock( 1, 0, 1 ), new SourceBlock( 0, 3, 1 ) ), - new SingleColourLookup( new SourceBlock( 1, 0, 0 ), new SourceBlock( 0, 3, 0 ) ), - new SingleColourLookup( new SourceBlock( 1, 0, 1 ), new SourceBlock( 0, 4, 0 ) ), - new SingleColourLookup( new SourceBlock( 1, 0, 2 ), new SourceBlock( 0, 5, 0 ) ), - new SingleColourLookup( new SourceBlock( 2, 0, 1 ), new SourceBlock( 0, 6, 1 ) ), - new SingleColourLookup( new SourceBlock( 2, 0, 0 ), new SourceBlock( 0, 6, 0 ) ), - new SingleColourLookup( new SourceBlock( 2, 0, 1 ), new SourceBlock( 0, 7, 0 ) ), - new SingleColourLookup( new SourceBlock( 2, 0, 2 ), new SourceBlock( 0, 8, 0 ) ), - new SingleColourLookup( new SourceBlock( 3, 0, 1 ), new SourceBlock( 0, 9, 1 ) ), - new SingleColourLookup( new SourceBlock( 3, 0, 0 ), new SourceBlock( 0, 9, 0 ) ), - new SingleColourLookup( new SourceBlock( 3, 0, 1 ), new SourceBlock( 0, 10, 0 ) ), - new SingleColourLookup( new SourceBlock( 3, 0, 2 ), new SourceBlock( 0, 11, 0 ) ), - new SingleColourLookup( new SourceBlock( 4, 0, 1 ), new SourceBlock( 0, 12, 1 ) ), - new SingleColourLookup( new SourceBlock( 4, 0, 0 ), new SourceBlock( 0, 12, 0 ) ), - new SingleColourLookup( new SourceBlock( 4, 0, 1 ), new SourceBlock( 0, 13, 0 ) ), - new SingleColourLookup( new SourceBlock( 4, 0, 2 ), new SourceBlock( 0, 14, 0 ) ), - new SingleColourLookup( new SourceBlock( 5, 0, 1 ), new SourceBlock( 0, 15, 1 ) ), - new SingleColourLookup( new SourceBlock( 5, 0, 0 ), new SourceBlock( 0, 15, 0 ) ), - new SingleColourLookup( new SourceBlock( 5, 0, 1 ), new SourceBlock( 0, 16, 0 ) ), - new SingleColourLookup( new SourceBlock( 5, 0, 2 ), new SourceBlock( 1, 15, 0 ) ), - new SingleColourLookup( new SourceBlock( 6, 0, 1 ), new SourceBlock( 0, 17, 0 ) ), - new SingleColourLookup( new SourceBlock( 6, 0, 0 ), new SourceBlock( 0, 18, 0 ) ), - new SingleColourLookup( new SourceBlock( 6, 0, 1 ), new SourceBlock( 0, 19, 0 ) ), - new SingleColourLookup( new SourceBlock( 6, 0, 2 ), new SourceBlock( 3, 14, 0 ) ), - new SingleColourLookup( new SourceBlock( 7, 0, 1 ), new SourceBlock( 0, 20, 0 ) ), - new SingleColourLookup( new SourceBlock( 7, 0, 0 ), new SourceBlock( 0, 21, 0 ) ), - new SingleColourLookup( new SourceBlock( 7, 0, 1 ), new SourceBlock( 0, 22, 0 ) ), - new SingleColourLookup( new SourceBlock( 7, 0, 2 ), new SourceBlock( 4, 15, 0 ) ), - new SingleColourLookup( new SourceBlock( 8, 0, 1 ), new SourceBlock( 0, 23, 0 ) ), - new SingleColourLookup( new SourceBlock( 8, 0, 0 ), new SourceBlock( 0, 24, 0 ) ), - new SingleColourLookup( new SourceBlock( 8, 0, 1 ), new SourceBlock( 0, 25, 0 ) ), - new SingleColourLookup( new SourceBlock( 8, 0, 2 ), new SourceBlock( 6, 14, 0 ) ), - new SingleColourLookup( new SourceBlock( 9, 0, 1 ), new SourceBlock( 0, 26, 0 ) ), - new SingleColourLookup( new SourceBlock( 9, 0, 0 ), new SourceBlock( 0, 27, 0 ) ), - new SingleColourLookup( new SourceBlock( 9, 0, 1 ), new SourceBlock( 0, 28, 0 ) ), - new SingleColourLookup( new SourceBlock( 9, 0, 2 ), new SourceBlock( 7, 15, 0 ) ), - new SingleColourLookup( new SourceBlock( 10, 0, 1 ), new SourceBlock( 0, 29, 0 ) ), - new SingleColourLookup( new SourceBlock( 10, 0, 0 ), new SourceBlock( 0, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 10, 0, 1 ), new SourceBlock( 0, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 10, 0, 2 ), new SourceBlock( 9, 14, 0 ) ), - new SingleColourLookup( new SourceBlock( 11, 0, 1 ), new SourceBlock( 0, 32, 0 ) ), - new SingleColourLookup( new SourceBlock( 11, 0, 0 ), new SourceBlock( 0, 33, 0 ) ), - new SingleColourLookup( new SourceBlock( 11, 0, 1 ), new SourceBlock( 2, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 11, 0, 2 ), new SourceBlock( 0, 34, 0 ) ), - new SingleColourLookup( new SourceBlock( 12, 0, 1 ), new SourceBlock( 0, 35, 0 ) ), - new SingleColourLookup( new SourceBlock( 12, 0, 0 ), new SourceBlock( 0, 36, 0 ) ), - new SingleColourLookup( new SourceBlock( 12, 0, 1 ), new SourceBlock( 3, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 12, 0, 2 ), new SourceBlock( 0, 37, 0 ) ), - new SingleColourLookup( new SourceBlock( 13, 0, 1 ), new SourceBlock( 0, 38, 0 ) ), - new SingleColourLookup( new SourceBlock( 13, 0, 0 ), new SourceBlock( 0, 39, 0 ) ), - new SingleColourLookup( new SourceBlock( 13, 0, 1 ), new SourceBlock( 5, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 13, 0, 2 ), new SourceBlock( 0, 40, 0 ) ), - new SingleColourLookup( new SourceBlock( 14, 0, 1 ), new SourceBlock( 0, 41, 0 ) ), - new SingleColourLookup( new SourceBlock( 14, 0, 0 ), new SourceBlock( 0, 42, 0 ) ), - new SingleColourLookup( new SourceBlock( 14, 0, 1 ), new SourceBlock( 6, 31, 0 ) ), - new SingleColourLookup( new SourceBlock( 14, 0, 2 ), new SourceBlock( 0, 43, 0 ) ), - new SingleColourLookup( new SourceBlock( 15, 0, 1 ), new SourceBlock( 0, 44, 0 ) ), - new SingleColourLookup( new SourceBlock( 15, 0, 0 ), new SourceBlock( 0, 45, 0 ) ), - new SingleColourLookup( new SourceBlock( 15, 0, 1 ), new SourceBlock( 8, 30, 0 ) ), - new SingleColourLookup( new SourceBlock( 15, 0, 2 ), new SourceBlock( 0, 46, 0 ) ), - new SingleColourLookup( new SourceBlock( 16, 0, 2 ), new SourceBlock( 0, 47, 0 ) ), - new SingleColourLookup( new SourceBlock( 16, 0, 1 ), new SourceBlock( 1, 46, 0 ) ), - new SingleColourLookup( new SourceBlock( 16, 0, 0 ), new SourceBlock( 0, 48, 0 ) ), - new SingleColourLookup( new SourceBlock( 16, 0, 1 ), new SourceBlock( 0, 49, 0 ) ), - new SingleColourLookup( new SourceBlock( 16, 0, 2 ), new SourceBlock( 0, 50, 0 ) ), - new SingleColourLookup( new SourceBlock( 17, 0, 1 ), new SourceBlock( 2, 47, 0 ) ), - new SingleColourLookup( new SourceBlock( 17, 0, 0 ), new SourceBlock( 0, 51, 0 ) ), - new SingleColourLookup( new SourceBlock( 17, 0, 1 ), new SourceBlock( 0, 52, 0 ) ), - new SingleColourLookup( new SourceBlock( 17, 0, 2 ), new SourceBlock( 0, 53, 0 ) ), - new SingleColourLookup( new SourceBlock( 18, 0, 1 ), new SourceBlock( 4, 46, 0 ) ), - new SingleColourLookup( new SourceBlock( 18, 0, 0 ), new SourceBlock( 0, 54, 0 ) ), - new SingleColourLookup( new SourceBlock( 18, 0, 1 ), new SourceBlock( 0, 55, 0 ) ), - new SingleColourLookup( new SourceBlock( 18, 0, 2 ), new SourceBlock( 0, 56, 0 ) ), - new SingleColourLookup( new SourceBlock( 19, 0, 1 ), new SourceBlock( 5, 47, 0 ) ), - new SingleColourLookup( new SourceBlock( 19, 0, 0 ), new SourceBlock( 0, 57, 0 ) ), - new SingleColourLookup( new SourceBlock( 19, 0, 1 ), new SourceBlock( 0, 58, 0 ) ), - new SingleColourLookup( new SourceBlock( 19, 0, 2 ), new SourceBlock( 0, 59, 0 ) ), - new SingleColourLookup( new SourceBlock( 20, 0, 1 ), new SourceBlock( 7, 46, 0 ) ), - new SingleColourLookup( new SourceBlock( 20, 0, 0 ), new SourceBlock( 0, 60, 0 ) ), - new SingleColourLookup( new SourceBlock( 20, 0, 1 ), new SourceBlock( 0, 61, 0 ) ), - new SingleColourLookup( new SourceBlock( 20, 0, 2 ), new SourceBlock( 0, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 21, 0, 1 ), new SourceBlock( 8, 47, 0 ) ), - new SingleColourLookup( new SourceBlock( 21, 0, 0 ), new SourceBlock( 0, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 21, 0, 1 ), new SourceBlock( 1, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 21, 0, 2 ), new SourceBlock( 1, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 22, 0, 1 ), new SourceBlock( 10, 46, 0 ) ), - new SingleColourLookup( new SourceBlock( 22, 0, 0 ), new SourceBlock( 2, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 22, 0, 1 ), new SourceBlock( 2, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 22, 0, 2 ), new SourceBlock( 3, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 23, 0, 1 ), new SourceBlock( 11, 47, 0 ) ), - new SingleColourLookup( new SourceBlock( 23, 0, 0 ), new SourceBlock( 3, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 23, 0, 1 ), new SourceBlock( 4, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 23, 0, 2 ), new SourceBlock( 4, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 24, 0, 1 ), new SourceBlock( 13, 46, 0 ) ), - new SingleColourLookup( new SourceBlock( 24, 0, 0 ), new SourceBlock( 5, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 24, 0, 1 ), new SourceBlock( 5, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 24, 0, 2 ), new SourceBlock( 6, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 25, 0, 1 ), new SourceBlock( 14, 47, 0 ) ), - new SingleColourLookup( new SourceBlock( 25, 0, 0 ), new SourceBlock( 6, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 25, 0, 1 ), new SourceBlock( 7, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 25, 0, 2 ), new SourceBlock( 7, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 26, 0, 1 ), new SourceBlock( 16, 45, 0 ) ), - new SingleColourLookup( new SourceBlock( 26, 0, 0 ), new SourceBlock( 8, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 26, 0, 1 ), new SourceBlock( 8, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 26, 0, 2 ), new SourceBlock( 9, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 27, 0, 1 ), new SourceBlock( 16, 48, 0 ) ), - new SingleColourLookup( new SourceBlock( 27, 0, 0 ), new SourceBlock( 9, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 27, 0, 1 ), new SourceBlock( 10, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 27, 0, 2 ), new SourceBlock( 10, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 28, 0, 1 ), new SourceBlock( 16, 51, 0 ) ), - new SingleColourLookup( new SourceBlock( 28, 0, 0 ), new SourceBlock( 11, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 28, 0, 1 ), new SourceBlock( 11, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 28, 0, 2 ), new SourceBlock( 12, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 29, 0, 1 ), new SourceBlock( 16, 54, 0 ) ), - new SingleColourLookup( new SourceBlock( 29, 0, 0 ), new SourceBlock( 12, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 29, 0, 1 ), new SourceBlock( 13, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 29, 0, 2 ), new SourceBlock( 13, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 30, 0, 1 ), new SourceBlock( 16, 57, 0 ) ), - new SingleColourLookup( new SourceBlock( 30, 0, 0 ), new SourceBlock( 14, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 30, 0, 1 ), new SourceBlock( 14, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 30, 0, 2 ), new SourceBlock( 15, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 31, 0, 1 ), new SourceBlock( 16, 60, 0 ) ), - new SingleColourLookup( new SourceBlock( 31, 0, 0 ), new SourceBlock( 15, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 31, 0, 1 ), new SourceBlock( 24, 46, 0 ) ), - new SingleColourLookup( new SourceBlock( 31, 0, 2 ), new SourceBlock( 16, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 32, 0, 2 ), new SourceBlock( 16, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 32, 0, 1 ), new SourceBlock( 17, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 32, 0, 0 ), new SourceBlock( 25, 47, 0 ) ), - new SingleColourLookup( new SourceBlock( 32, 0, 1 ), new SourceBlock( 17, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 32, 0, 2 ), new SourceBlock( 18, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 33, 0, 1 ), new SourceBlock( 18, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 33, 0, 0 ), new SourceBlock( 27, 46, 0 ) ), - new SingleColourLookup( new SourceBlock( 33, 0, 1 ), new SourceBlock( 19, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 33, 0, 2 ), new SourceBlock( 19, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 34, 0, 1 ), new SourceBlock( 20, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 34, 0, 0 ), new SourceBlock( 28, 47, 0 ) ), - new SingleColourLookup( new SourceBlock( 34, 0, 1 ), new SourceBlock( 20, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 34, 0, 2 ), new SourceBlock( 21, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 35, 0, 1 ), new SourceBlock( 21, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 35, 0, 0 ), new SourceBlock( 30, 46, 0 ) ), - new SingleColourLookup( new SourceBlock( 35, 0, 1 ), new SourceBlock( 22, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 35, 0, 2 ), new SourceBlock( 22, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 36, 0, 1 ), new SourceBlock( 23, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 36, 0, 0 ), new SourceBlock( 31, 47, 0 ) ), - new SingleColourLookup( new SourceBlock( 36, 0, 1 ), new SourceBlock( 23, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 36, 0, 2 ), new SourceBlock( 24, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 37, 0, 1 ), new SourceBlock( 24, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 37, 0, 0 ), new SourceBlock( 32, 47, 0 ) ), - new SingleColourLookup( new SourceBlock( 37, 0, 1 ), new SourceBlock( 25, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 37, 0, 2 ), new SourceBlock( 25, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 38, 0, 1 ), new SourceBlock( 26, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 38, 0, 0 ), new SourceBlock( 32, 50, 0 ) ), - new SingleColourLookup( new SourceBlock( 38, 0, 1 ), new SourceBlock( 26, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 38, 0, 2 ), new SourceBlock( 27, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 39, 0, 1 ), new SourceBlock( 27, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 39, 0, 0 ), new SourceBlock( 32, 53, 0 ) ), - new SingleColourLookup( new SourceBlock( 39, 0, 1 ), new SourceBlock( 28, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 39, 0, 2 ), new SourceBlock( 28, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 40, 0, 1 ), new SourceBlock( 29, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 40, 0, 0 ), new SourceBlock( 32, 56, 0 ) ), - new SingleColourLookup( new SourceBlock( 40, 0, 1 ), new SourceBlock( 29, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 40, 0, 2 ), new SourceBlock( 30, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 41, 0, 1 ), new SourceBlock( 30, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 41, 0, 0 ), new SourceBlock( 32, 59, 0 ) ), - new SingleColourLookup( new SourceBlock( 41, 0, 1 ), new SourceBlock( 31, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 41, 0, 2 ), new SourceBlock( 31, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 42, 0, 1 ), new SourceBlock( 32, 61, 0 ) ), - new SingleColourLookup( new SourceBlock( 42, 0, 0 ), new SourceBlock( 32, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 42, 0, 1 ), new SourceBlock( 32, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 42, 0, 2 ), new SourceBlock( 41, 46, 0 ) ), - new SingleColourLookup( new SourceBlock( 43, 0, 1 ), new SourceBlock( 33, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 43, 0, 0 ), new SourceBlock( 33, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 43, 0, 1 ), new SourceBlock( 34, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 43, 0, 2 ), new SourceBlock( 42, 47, 0 ) ), - new SingleColourLookup( new SourceBlock( 44, 0, 1 ), new SourceBlock( 34, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 44, 0, 0 ), new SourceBlock( 35, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 44, 0, 1 ), new SourceBlock( 35, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 44, 0, 2 ), new SourceBlock( 44, 46, 0 ) ), - new SingleColourLookup( new SourceBlock( 45, 0, 1 ), new SourceBlock( 36, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 45, 0, 0 ), new SourceBlock( 36, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 45, 0, 1 ), new SourceBlock( 37, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 45, 0, 2 ), new SourceBlock( 45, 47, 0 ) ), - new SingleColourLookup( new SourceBlock( 46, 0, 1 ), new SourceBlock( 37, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 46, 0, 0 ), new SourceBlock( 38, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 46, 0, 1 ), new SourceBlock( 38, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 46, 0, 2 ), new SourceBlock( 47, 46, 0 ) ), - new SingleColourLookup( new SourceBlock( 47, 0, 1 ), new SourceBlock( 39, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 47, 0, 0 ), new SourceBlock( 39, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 47, 0, 1 ), new SourceBlock( 40, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 47, 0, 2 ), new SourceBlock( 48, 46, 0 ) ), - new SingleColourLookup( new SourceBlock( 48, 0, 2 ), new SourceBlock( 40, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 48, 0, 1 ), new SourceBlock( 41, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 48, 0, 0 ), new SourceBlock( 41, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 48, 0, 1 ), new SourceBlock( 48, 49, 0 ) ), - new SingleColourLookup( new SourceBlock( 48, 0, 2 ), new SourceBlock( 42, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 49, 0, 1 ), new SourceBlock( 42, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 49, 0, 0 ), new SourceBlock( 43, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 49, 0, 1 ), new SourceBlock( 48, 52, 0 ) ), - new SingleColourLookup( new SourceBlock( 49, 0, 2 ), new SourceBlock( 43, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 50, 0, 1 ), new SourceBlock( 44, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 50, 0, 0 ), new SourceBlock( 44, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 50, 0, 1 ), new SourceBlock( 48, 55, 0 ) ), - new SingleColourLookup( new SourceBlock( 50, 0, 2 ), new SourceBlock( 45, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 51, 0, 1 ), new SourceBlock( 45, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 51, 0, 0 ), new SourceBlock( 46, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 51, 0, 1 ), new SourceBlock( 48, 58, 0 ) ), - new SingleColourLookup( new SourceBlock( 51, 0, 2 ), new SourceBlock( 46, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 52, 0, 1 ), new SourceBlock( 47, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 52, 0, 0 ), new SourceBlock( 47, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 52, 0, 1 ), new SourceBlock( 48, 61, 0 ) ), - new SingleColourLookup( new SourceBlock( 52, 0, 2 ), new SourceBlock( 48, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 53, 0, 1 ), new SourceBlock( 56, 47, 0 ) ), - new SingleColourLookup( new SourceBlock( 53, 0, 0 ), new SourceBlock( 48, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 53, 0, 1 ), new SourceBlock( 49, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 53, 0, 2 ), new SourceBlock( 49, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 54, 0, 1 ), new SourceBlock( 58, 46, 0 ) ), - new SingleColourLookup( new SourceBlock( 54, 0, 0 ), new SourceBlock( 50, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 54, 0, 1 ), new SourceBlock( 50, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 54, 0, 2 ), new SourceBlock( 51, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 55, 0, 1 ), new SourceBlock( 59, 47, 0 ) ), - new SingleColourLookup( new SourceBlock( 55, 0, 0 ), new SourceBlock( 51, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 55, 0, 1 ), new SourceBlock( 52, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 55, 0, 2 ), new SourceBlock( 52, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 56, 0, 1 ), new SourceBlock( 61, 46, 0 ) ), - new SingleColourLookup( new SourceBlock( 56, 0, 0 ), new SourceBlock( 53, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 56, 0, 1 ), new SourceBlock( 53, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 56, 0, 2 ), new SourceBlock( 54, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 57, 0, 1 ), new SourceBlock( 62, 47, 0 ) ), - new SingleColourLookup( new SourceBlock( 57, 0, 0 ), new SourceBlock( 54, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 57, 0, 1 ), new SourceBlock( 55, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 57, 0, 2 ), new SourceBlock( 55, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 58, 0, 1 ), new SourceBlock( 56, 62, 1 ) ), - new SingleColourLookup( new SourceBlock( 58, 0, 0 ), new SourceBlock( 56, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 58, 0, 1 ), new SourceBlock( 56, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 58, 0, 2 ), new SourceBlock( 57, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 59, 0, 1 ), new SourceBlock( 57, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 59, 0, 0 ), new SourceBlock( 57, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 59, 0, 1 ), new SourceBlock( 58, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 59, 0, 2 ), new SourceBlock( 58, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 60, 0, 1 ), new SourceBlock( 59, 62, 1 ) ), - new SingleColourLookup( new SourceBlock( 60, 0, 0 ), new SourceBlock( 59, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 60, 0, 1 ), new SourceBlock( 59, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 60, 0, 2 ), new SourceBlock( 60, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 61, 0, 1 ), new SourceBlock( 60, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 61, 0, 0 ), new SourceBlock( 60, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 61, 0, 1 ), new SourceBlock( 61, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 61, 0, 2 ), new SourceBlock( 61, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 62, 0, 1 ), new SourceBlock( 62, 62, 1 ) ), - new SingleColourLookup( new SourceBlock( 62, 0, 0 ), new SourceBlock( 62, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 62, 0, 1 ), new SourceBlock( 62, 63, 0 ) ), - new SingleColourLookup( new SourceBlock( 62, 0, 2 ), new SourceBlock( 63, 62, 0 ) ), - new SingleColourLookup( new SourceBlock( 63, 0, 1 ), new SourceBlock( 63, 63, 1 ) ), - new SingleColourLookup( new SourceBlock( 63, 0, 0 ), new SourceBlock( 63, 63, 0 ) ) - }; + sources = new SourceBlock[2]; + sources[0] = src1; + sources[1] = src2; } } + +internal class SingleColourLookups +{ + public static SingleColourLookup[] lookup_5_3 = + [ + new( new SourceBlock( 0, 0, 0 ), new SourceBlock( 0, 0, 0 ) ), + new( new SourceBlock( 0, 0, 1 ), new SourceBlock( 0, 0, 1 ) ), + new( new SourceBlock( 0, 0, 2 ), new SourceBlock( 0, 0, 2 ) ), + new( new SourceBlock( 0, 0, 3 ), new SourceBlock( 0, 1, 1 ) ), + new( new SourceBlock( 0, 0, 4 ), new SourceBlock( 0, 1, 0 ) ), + new( new SourceBlock( 1, 0, 3 ), new SourceBlock( 0, 1, 1 ) ), + new( new SourceBlock( 1, 0, 2 ), new SourceBlock( 0, 1, 2 ) ), + new( new SourceBlock( 1, 0, 1 ), new SourceBlock( 0, 2, 1 ) ), + new( new SourceBlock( 1, 0, 0 ), new SourceBlock( 0, 2, 0 ) ), + new( new SourceBlock( 1, 0, 1 ), new SourceBlock( 0, 2, 1 ) ), + new( new SourceBlock( 1, 0, 2 ), new SourceBlock( 0, 2, 2 ) ), + new( new SourceBlock( 1, 0, 3 ), new SourceBlock( 0, 3, 1 ) ), + new( new SourceBlock( 1, 0, 4 ), new SourceBlock( 0, 3, 0 ) ), + new( new SourceBlock( 2, 0, 3 ), new SourceBlock( 0, 3, 1 ) ), + new( new SourceBlock( 2, 0, 2 ), new SourceBlock( 0, 3, 2 ) ), + new( new SourceBlock( 2, 0, 1 ), new SourceBlock( 0, 4, 1 ) ), + new( new SourceBlock( 2, 0, 0 ), new SourceBlock( 0, 4, 0 ) ), + new( new SourceBlock( 2, 0, 1 ), new SourceBlock( 0, 4, 1 ) ), + new( new SourceBlock( 2, 0, 2 ), new SourceBlock( 0, 4, 2 ) ), + new( new SourceBlock( 2, 0, 3 ), new SourceBlock( 0, 5, 1 ) ), + new( new SourceBlock( 2, 0, 4 ), new SourceBlock( 0, 5, 0 ) ), + new( new SourceBlock( 3, 0, 3 ), new SourceBlock( 0, 5, 1 ) ), + new( new SourceBlock( 3, 0, 2 ), new SourceBlock( 0, 5, 2 ) ), + new( new SourceBlock( 3, 0, 1 ), new SourceBlock( 0, 6, 1 ) ), + new( new SourceBlock( 3, 0, 0 ), new SourceBlock( 0, 6, 0 ) ), + new( new SourceBlock( 3, 0, 1 ), new SourceBlock( 0, 6, 1 ) ), + new( new SourceBlock( 3, 0, 2 ), new SourceBlock( 0, 6, 2 ) ), + new( new SourceBlock( 3, 0, 3 ), new SourceBlock( 0, 7, 1 ) ), + new( new SourceBlock( 3, 0, 4 ), new SourceBlock( 0, 7, 0 ) ), + new( new SourceBlock( 4, 0, 4 ), new SourceBlock( 0, 7, 1 ) ), + new( new SourceBlock( 4, 0, 3 ), new SourceBlock( 0, 7, 2 ) ), + new( new SourceBlock( 4, 0, 2 ), new SourceBlock( 1, 7, 1 ) ), + new( new SourceBlock( 4, 0, 1 ), new SourceBlock( 1, 7, 0 ) ), + new( new SourceBlock( 4, 0, 0 ), new SourceBlock( 0, 8, 0 ) ), + new( new SourceBlock( 4, 0, 1 ), new SourceBlock( 0, 8, 1 ) ), + new( new SourceBlock( 4, 0, 2 ), new SourceBlock( 2, 7, 1 ) ), + new( new SourceBlock( 4, 0, 3 ), new SourceBlock( 2, 7, 0 ) ), + new( new SourceBlock( 4, 0, 4 ), new SourceBlock( 0, 9, 0 ) ), + new( new SourceBlock( 5, 0, 3 ), new SourceBlock( 0, 9, 1 ) ), + new( new SourceBlock( 5, 0, 2 ), new SourceBlock( 3, 7, 1 ) ), + new( new SourceBlock( 5, 0, 1 ), new SourceBlock( 3, 7, 0 ) ), + new( new SourceBlock( 5, 0, 0 ), new SourceBlock( 0, 10, 0 ) ), + new( new SourceBlock( 5, 0, 1 ), new SourceBlock( 0, 10, 1 ) ), + new( new SourceBlock( 5, 0, 2 ), new SourceBlock( 0, 10, 2 ) ), + new( new SourceBlock( 5, 0, 3 ), new SourceBlock( 0, 11, 1 ) ), + new( new SourceBlock( 5, 0, 4 ), new SourceBlock( 0, 11, 0 ) ), + new( new SourceBlock( 6, 0, 3 ), new SourceBlock( 0, 11, 1 ) ), + new( new SourceBlock( 6, 0, 2 ), new SourceBlock( 0, 11, 2 ) ), + new( new SourceBlock( 6, 0, 1 ), new SourceBlock( 0, 12, 1 ) ), + new( new SourceBlock( 6, 0, 0 ), new SourceBlock( 0, 12, 0 ) ), + new( new SourceBlock( 6, 0, 1 ), new SourceBlock( 0, 12, 1 ) ), + new( new SourceBlock( 6, 0, 2 ), new SourceBlock( 0, 12, 2 ) ), + new( new SourceBlock( 6, 0, 3 ), new SourceBlock( 0, 13, 1 ) ), + new( new SourceBlock( 6, 0, 4 ), new SourceBlock( 0, 13, 0 ) ), + new( new SourceBlock( 7, 0, 3 ), new SourceBlock( 0, 13, 1 ) ), + new( new SourceBlock( 7, 0, 2 ), new SourceBlock( 0, 13, 2 ) ), + new( new SourceBlock( 7, 0, 1 ), new SourceBlock( 0, 14, 1 ) ), + new( new SourceBlock( 7, 0, 0 ), new SourceBlock( 0, 14, 0 ) ), + new( new SourceBlock( 7, 0, 1 ), new SourceBlock( 0, 14, 1 ) ), + new( new SourceBlock( 7, 0, 2 ), new SourceBlock( 0, 14, 2 ) ), + new( new SourceBlock( 7, 0, 3 ), new SourceBlock( 0, 15, 1 ) ), + new( new SourceBlock( 7, 0, 4 ), new SourceBlock( 0, 15, 0 ) ), + new( new SourceBlock( 8, 0, 4 ), new SourceBlock( 0, 15, 1 ) ), + new( new SourceBlock( 8, 0, 3 ), new SourceBlock( 0, 15, 2 ) ), + new( new SourceBlock( 8, 0, 2 ), new SourceBlock( 1, 15, 1 ) ), + new( new SourceBlock( 8, 0, 1 ), new SourceBlock( 1, 15, 0 ) ), + new( new SourceBlock( 8, 0, 0 ), new SourceBlock( 0, 16, 0 ) ), + new( new SourceBlock( 8, 0, 1 ), new SourceBlock( 0, 16, 1 ) ), + new( new SourceBlock( 8, 0, 2 ), new SourceBlock( 2, 15, 1 ) ), + new( new SourceBlock( 8, 0, 3 ), new SourceBlock( 2, 15, 0 ) ), + new( new SourceBlock( 8, 0, 4 ), new SourceBlock( 0, 17, 0 ) ), + new( new SourceBlock( 9, 0, 3 ), new SourceBlock( 0, 17, 1 ) ), + new( new SourceBlock( 9, 0, 2 ), new SourceBlock( 3, 15, 1 ) ), + new( new SourceBlock( 9, 0, 1 ), new SourceBlock( 3, 15, 0 ) ), + new( new SourceBlock( 9, 0, 0 ), new SourceBlock( 0, 18, 0 ) ), + new( new SourceBlock( 9, 0, 1 ), new SourceBlock( 0, 18, 1 ) ), + new( new SourceBlock( 9, 0, 2 ), new SourceBlock( 0, 18, 2 ) ), + new( new SourceBlock( 9, 0, 3 ), new SourceBlock( 0, 19, 1 ) ), + new( new SourceBlock( 9, 0, 4 ), new SourceBlock( 0, 19, 0 ) ), + new( new SourceBlock( 10, 0, 3 ), new SourceBlock( 0, 19, 1 ) ), + new( new SourceBlock( 10, 0, 2 ), new SourceBlock( 0, 19, 2 ) ), + new( new SourceBlock( 10, 0, 1 ), new SourceBlock( 0, 20, 1 ) ), + new( new SourceBlock( 10, 0, 0 ), new SourceBlock( 0, 20, 0 ) ), + new( new SourceBlock( 10, 0, 1 ), new SourceBlock( 0, 20, 1 ) ), + new( new SourceBlock( 10, 0, 2 ), new SourceBlock( 0, 20, 2 ) ), + new( new SourceBlock( 10, 0, 3 ), new SourceBlock( 0, 21, 1 ) ), + new( new SourceBlock( 10, 0, 4 ), new SourceBlock( 0, 21, 0 ) ), + new( new SourceBlock( 11, 0, 3 ), new SourceBlock( 0, 21, 1 ) ), + new( new SourceBlock( 11, 0, 2 ), new SourceBlock( 0, 21, 2 ) ), + new( new SourceBlock( 11, 0, 1 ), new SourceBlock( 0, 22, 1 ) ), + new( new SourceBlock( 11, 0, 0 ), new SourceBlock( 0, 22, 0 ) ), + new( new SourceBlock( 11, 0, 1 ), new SourceBlock( 0, 22, 1 ) ), + new( new SourceBlock( 11, 0, 2 ), new SourceBlock( 0, 22, 2 ) ), + new( new SourceBlock( 11, 0, 3 ), new SourceBlock( 0, 23, 1 ) ), + new( new SourceBlock( 11, 0, 4 ), new SourceBlock( 0, 23, 0 ) ), + new( new SourceBlock( 12, 0, 4 ), new SourceBlock( 0, 23, 1 ) ), + new( new SourceBlock( 12, 0, 3 ), new SourceBlock( 0, 23, 2 ) ), + new( new SourceBlock( 12, 0, 2 ), new SourceBlock( 1, 23, 1 ) ), + new( new SourceBlock( 12, 0, 1 ), new SourceBlock( 1, 23, 0 ) ), + new( new SourceBlock( 12, 0, 0 ), new SourceBlock( 0, 24, 0 ) ), + new( new SourceBlock( 12, 0, 1 ), new SourceBlock( 0, 24, 1 ) ), + new( new SourceBlock( 12, 0, 2 ), new SourceBlock( 2, 23, 1 ) ), + new( new SourceBlock( 12, 0, 3 ), new SourceBlock( 2, 23, 0 ) ), + new( new SourceBlock( 12, 0, 4 ), new SourceBlock( 0, 25, 0 ) ), + new( new SourceBlock( 13, 0, 3 ), new SourceBlock( 0, 25, 1 ) ), + new( new SourceBlock( 13, 0, 2 ), new SourceBlock( 3, 23, 1 ) ), + new( new SourceBlock( 13, 0, 1 ), new SourceBlock( 3, 23, 0 ) ), + new( new SourceBlock( 13, 0, 0 ), new SourceBlock( 0, 26, 0 ) ), + new( new SourceBlock( 13, 0, 1 ), new SourceBlock( 0, 26, 1 ) ), + new( new SourceBlock( 13, 0, 2 ), new SourceBlock( 0, 26, 2 ) ), + new( new SourceBlock( 13, 0, 3 ), new SourceBlock( 0, 27, 1 ) ), + new( new SourceBlock( 13, 0, 4 ), new SourceBlock( 0, 27, 0 ) ), + new( new SourceBlock( 14, 0, 3 ), new SourceBlock( 0, 27, 1 ) ), + new( new SourceBlock( 14, 0, 2 ), new SourceBlock( 0, 27, 2 ) ), + new( new SourceBlock( 14, 0, 1 ), new SourceBlock( 0, 28, 1 ) ), + new( new SourceBlock( 14, 0, 0 ), new SourceBlock( 0, 28, 0 ) ), + new( new SourceBlock( 14, 0, 1 ), new SourceBlock( 0, 28, 1 ) ), + new( new SourceBlock( 14, 0, 2 ), new SourceBlock( 0, 28, 2 ) ), + new( new SourceBlock( 14, 0, 3 ), new SourceBlock( 0, 29, 1 ) ), + new( new SourceBlock( 14, 0, 4 ), new SourceBlock( 0, 29, 0 ) ), + new( new SourceBlock( 15, 0, 3 ), new SourceBlock( 0, 29, 1 ) ), + new( new SourceBlock( 15, 0, 2 ), new SourceBlock( 0, 29, 2 ) ), + new( new SourceBlock( 15, 0, 1 ), new SourceBlock( 0, 30, 1 ) ), + new( new SourceBlock( 15, 0, 0 ), new SourceBlock( 0, 30, 0 ) ), + new( new SourceBlock( 15, 0, 1 ), new SourceBlock( 0, 30, 1 ) ), + new( new SourceBlock( 15, 0, 2 ), new SourceBlock( 0, 30, 2 ) ), + new( new SourceBlock( 15, 0, 3 ), new SourceBlock( 0, 31, 1 ) ), + new( new SourceBlock( 15, 0, 4 ), new SourceBlock( 0, 31, 0 ) ), + new( new SourceBlock( 16, 0, 4 ), new SourceBlock( 0, 31, 1 ) ), + new( new SourceBlock( 16, 0, 3 ), new SourceBlock( 0, 31, 2 ) ), + new( new SourceBlock( 16, 0, 2 ), new SourceBlock( 1, 31, 1 ) ), + new( new SourceBlock( 16, 0, 1 ), new SourceBlock( 1, 31, 0 ) ), + new( new SourceBlock( 16, 0, 0 ), new SourceBlock( 4, 28, 0 ) ), + new( new SourceBlock( 16, 0, 1 ), new SourceBlock( 4, 28, 1 ) ), + new( new SourceBlock( 16, 0, 2 ), new SourceBlock( 2, 31, 1 ) ), + new( new SourceBlock( 16, 0, 3 ), new SourceBlock( 2, 31, 0 ) ), + new( new SourceBlock( 16, 0, 4 ), new SourceBlock( 4, 29, 0 ) ), + new( new SourceBlock( 17, 0, 3 ), new SourceBlock( 4, 29, 1 ) ), + new( new SourceBlock( 17, 0, 2 ), new SourceBlock( 3, 31, 1 ) ), + new( new SourceBlock( 17, 0, 1 ), new SourceBlock( 3, 31, 0 ) ), + new( new SourceBlock( 17, 0, 0 ), new SourceBlock( 4, 30, 0 ) ), + new( new SourceBlock( 17, 0, 1 ), new SourceBlock( 4, 30, 1 ) ), + new( new SourceBlock( 17, 0, 2 ), new SourceBlock( 4, 30, 2 ) ), + new( new SourceBlock( 17, 0, 3 ), new SourceBlock( 4, 31, 1 ) ), + new( new SourceBlock( 17, 0, 4 ), new SourceBlock( 4, 31, 0 ) ), + new( new SourceBlock( 18, 0, 3 ), new SourceBlock( 4, 31, 1 ) ), + new( new SourceBlock( 18, 0, 2 ), new SourceBlock( 4, 31, 2 ) ), + new( new SourceBlock( 18, 0, 1 ), new SourceBlock( 5, 31, 1 ) ), + new( new SourceBlock( 18, 0, 0 ), new SourceBlock( 5, 31, 0 ) ), + new( new SourceBlock( 18, 0, 1 ), new SourceBlock( 5, 31, 1 ) ), + new( new SourceBlock( 18, 0, 2 ), new SourceBlock( 5, 31, 2 ) ), + new( new SourceBlock( 18, 0, 3 ), new SourceBlock( 6, 31, 1 ) ), + new( new SourceBlock( 18, 0, 4 ), new SourceBlock( 6, 31, 0 ) ), + new( new SourceBlock( 19, 0, 3 ), new SourceBlock( 6, 31, 1 ) ), + new( new SourceBlock( 19, 0, 2 ), new SourceBlock( 6, 31, 2 ) ), + new( new SourceBlock( 19, 0, 1 ), new SourceBlock( 7, 31, 1 ) ), + new( new SourceBlock( 19, 0, 0 ), new SourceBlock( 7, 31, 0 ) ), + new( new SourceBlock( 19, 0, 1 ), new SourceBlock( 7, 31, 1 ) ), + new( new SourceBlock( 19, 0, 2 ), new SourceBlock( 7, 31, 2 ) ), + new( new SourceBlock( 19, 0, 3 ), new SourceBlock( 8, 31, 1 ) ), + new( new SourceBlock( 19, 0, 4 ), new SourceBlock( 8, 31, 0 ) ), + new( new SourceBlock( 20, 0, 4 ), new SourceBlock( 8, 31, 1 ) ), + new( new SourceBlock( 20, 0, 3 ), new SourceBlock( 8, 31, 2 ) ), + new( new SourceBlock( 20, 0, 2 ), new SourceBlock( 9, 31, 1 ) ), + new( new SourceBlock( 20, 0, 1 ), new SourceBlock( 9, 31, 0 ) ), + new( new SourceBlock( 20, 0, 0 ), new SourceBlock( 12, 28, 0 ) ), + new( new SourceBlock( 20, 0, 1 ), new SourceBlock( 12, 28, 1 ) ), + new( new SourceBlock( 20, 0, 2 ), new SourceBlock( 10, 31, 1 ) ), + new( new SourceBlock( 20, 0, 3 ), new SourceBlock( 10, 31, 0 ) ), + new( new SourceBlock( 20, 0, 4 ), new SourceBlock( 12, 29, 0 ) ), + new( new SourceBlock( 21, 0, 3 ), new SourceBlock( 12, 29, 1 ) ), + new( new SourceBlock( 21, 0, 2 ), new SourceBlock( 11, 31, 1 ) ), + new( new SourceBlock( 21, 0, 1 ), new SourceBlock( 11, 31, 0 ) ), + new( new SourceBlock( 21, 0, 0 ), new SourceBlock( 12, 30, 0 ) ), + new( new SourceBlock( 21, 0, 1 ), new SourceBlock( 12, 30, 1 ) ), + new( new SourceBlock( 21, 0, 2 ), new SourceBlock( 12, 30, 2 ) ), + new( new SourceBlock( 21, 0, 3 ), new SourceBlock( 12, 31, 1 ) ), + new( new SourceBlock( 21, 0, 4 ), new SourceBlock( 12, 31, 0 ) ), + new( new SourceBlock( 22, 0, 3 ), new SourceBlock( 12, 31, 1 ) ), + new( new SourceBlock( 22, 0, 2 ), new SourceBlock( 12, 31, 2 ) ), + new( new SourceBlock( 22, 0, 1 ), new SourceBlock( 13, 31, 1 ) ), + new( new SourceBlock( 22, 0, 0 ), new SourceBlock( 13, 31, 0 ) ), + new( new SourceBlock( 22, 0, 1 ), new SourceBlock( 13, 31, 1 ) ), + new( new SourceBlock( 22, 0, 2 ), new SourceBlock( 13, 31, 2 ) ), + new( new SourceBlock( 22, 0, 3 ), new SourceBlock( 14, 31, 1 ) ), + new( new SourceBlock( 22, 0, 4 ), new SourceBlock( 14, 31, 0 ) ), + new( new SourceBlock( 23, 0, 3 ), new SourceBlock( 14, 31, 1 ) ), + new( new SourceBlock( 23, 0, 2 ), new SourceBlock( 14, 31, 2 ) ), + new( new SourceBlock( 23, 0, 1 ), new SourceBlock( 15, 31, 1 ) ), + new( new SourceBlock( 23, 0, 0 ), new SourceBlock( 15, 31, 0 ) ), + new( new SourceBlock( 23, 0, 1 ), new SourceBlock( 15, 31, 1 ) ), + new( new SourceBlock( 23, 0, 2 ), new SourceBlock( 15, 31, 2 ) ), + new( new SourceBlock( 23, 0, 3 ), new SourceBlock( 16, 31, 1 ) ), + new( new SourceBlock( 23, 0, 4 ), new SourceBlock( 16, 31, 0 ) ), + new( new SourceBlock( 24, 0, 4 ), new SourceBlock( 16, 31, 1 ) ), + new( new SourceBlock( 24, 0, 3 ), new SourceBlock( 16, 31, 2 ) ), + new( new SourceBlock( 24, 0, 2 ), new SourceBlock( 17, 31, 1 ) ), + new( new SourceBlock( 24, 0, 1 ), new SourceBlock( 17, 31, 0 ) ), + new( new SourceBlock( 24, 0, 0 ), new SourceBlock( 20, 28, 0 ) ), + new( new SourceBlock( 24, 0, 1 ), new SourceBlock( 20, 28, 1 ) ), + new( new SourceBlock( 24, 0, 2 ), new SourceBlock( 18, 31, 1 ) ), + new( new SourceBlock( 24, 0, 3 ), new SourceBlock( 18, 31, 0 ) ), + new( new SourceBlock( 24, 0, 4 ), new SourceBlock( 20, 29, 0 ) ), + new( new SourceBlock( 25, 0, 3 ), new SourceBlock( 20, 29, 1 ) ), + new( new SourceBlock( 25, 0, 2 ), new SourceBlock( 19, 31, 1 ) ), + new( new SourceBlock( 25, 0, 1 ), new SourceBlock( 19, 31, 0 ) ), + new( new SourceBlock( 25, 0, 0 ), new SourceBlock( 20, 30, 0 ) ), + new( new SourceBlock( 25, 0, 1 ), new SourceBlock( 20, 30, 1 ) ), + new( new SourceBlock( 25, 0, 2 ), new SourceBlock( 20, 30, 2 ) ), + new( new SourceBlock( 25, 0, 3 ), new SourceBlock( 20, 31, 1 ) ), + new( new SourceBlock( 25, 0, 4 ), new SourceBlock( 20, 31, 0 ) ), + new( new SourceBlock( 26, 0, 3 ), new SourceBlock( 20, 31, 1 ) ), + new( new SourceBlock( 26, 0, 2 ), new SourceBlock( 20, 31, 2 ) ), + new( new SourceBlock( 26, 0, 1 ), new SourceBlock( 21, 31, 1 ) ), + new( new SourceBlock( 26, 0, 0 ), new SourceBlock( 21, 31, 0 ) ), + new( new SourceBlock( 26, 0, 1 ), new SourceBlock( 21, 31, 1 ) ), + new( new SourceBlock( 26, 0, 2 ), new SourceBlock( 21, 31, 2 ) ), + new( new SourceBlock( 26, 0, 3 ), new SourceBlock( 22, 31, 1 ) ), + new( new SourceBlock( 26, 0, 4 ), new SourceBlock( 22, 31, 0 ) ), + new( new SourceBlock( 27, 0, 3 ), new SourceBlock( 22, 31, 1 ) ), + new( new SourceBlock( 27, 0, 2 ), new SourceBlock( 22, 31, 2 ) ), + new( new SourceBlock( 27, 0, 1 ), new SourceBlock( 23, 31, 1 ) ), + new( new SourceBlock( 27, 0, 0 ), new SourceBlock( 23, 31, 0 ) ), + new( new SourceBlock( 27, 0, 1 ), new SourceBlock( 23, 31, 1 ) ), + new( new SourceBlock( 27, 0, 2 ), new SourceBlock( 23, 31, 2 ) ), + new( new SourceBlock( 27, 0, 3 ), new SourceBlock( 24, 31, 1 ) ), + new( new SourceBlock( 27, 0, 4 ), new SourceBlock( 24, 31, 0 ) ), + new( new SourceBlock( 28, 0, 4 ), new SourceBlock( 24, 31, 1 ) ), + new( new SourceBlock( 28, 0, 3 ), new SourceBlock( 24, 31, 2 ) ), + new( new SourceBlock( 28, 0, 2 ), new SourceBlock( 25, 31, 1 ) ), + new( new SourceBlock( 28, 0, 1 ), new SourceBlock( 25, 31, 0 ) ), + new( new SourceBlock( 28, 0, 0 ), new SourceBlock( 28, 28, 0 ) ), + new( new SourceBlock( 28, 0, 1 ), new SourceBlock( 28, 28, 1 ) ), + new( new SourceBlock( 28, 0, 2 ), new SourceBlock( 26, 31, 1 ) ), + new( new SourceBlock( 28, 0, 3 ), new SourceBlock( 26, 31, 0 ) ), + new( new SourceBlock( 28, 0, 4 ), new SourceBlock( 28, 29, 0 ) ), + new( new SourceBlock( 29, 0, 3 ), new SourceBlock( 28, 29, 1 ) ), + new( new SourceBlock( 29, 0, 2 ), new SourceBlock( 27, 31, 1 ) ), + new( new SourceBlock( 29, 0, 1 ), new SourceBlock( 27, 31, 0 ) ), + new( new SourceBlock( 29, 0, 0 ), new SourceBlock( 28, 30, 0 ) ), + new( new SourceBlock( 29, 0, 1 ), new SourceBlock( 28, 30, 1 ) ), + new( new SourceBlock( 29, 0, 2 ), new SourceBlock( 28, 30, 2 ) ), + new( new SourceBlock( 29, 0, 3 ), new SourceBlock( 28, 31, 1 ) ), + new( new SourceBlock( 29, 0, 4 ), new SourceBlock( 28, 31, 0 ) ), + new( new SourceBlock( 30, 0, 3 ), new SourceBlock( 28, 31, 1 ) ), + new( new SourceBlock( 30, 0, 2 ), new SourceBlock( 28, 31, 2 ) ), + new( new SourceBlock( 30, 0, 1 ), new SourceBlock( 29, 31, 1 ) ), + new( new SourceBlock( 30, 0, 0 ), new SourceBlock( 29, 31, 0 ) ), + new( new SourceBlock( 30, 0, 1 ), new SourceBlock( 29, 31, 1 ) ), + new( new SourceBlock( 30, 0, 2 ), new SourceBlock( 29, 31, 2 ) ), + new( new SourceBlock( 30, 0, 3 ), new SourceBlock( 30, 31, 1 ) ), + new( new SourceBlock( 30, 0, 4 ), new SourceBlock( 30, 31, 0 ) ), + new( new SourceBlock( 31, 0, 3 ), new SourceBlock( 30, 31, 1 ) ), + new( new SourceBlock( 31, 0, 2 ), new SourceBlock( 30, 31, 2 ) ), + new( new SourceBlock( 31, 0, 1 ), new SourceBlock( 31, 31, 1 ) ), + new( new SourceBlock( 31, 0, 0 ), new SourceBlock( 31, 31, 0 ) ) +]; + + public static SingleColourLookup[] lookup_6_3 = + [ + new( new SourceBlock( 0, 0, 0 ), new SourceBlock( 0, 0, 0 ) ), + new( new SourceBlock( 0, 0, 1 ), new SourceBlock( 0, 1, 1 ) ), + new( new SourceBlock( 0, 0, 2 ), new SourceBlock( 0, 1, 0 ) ), + new( new SourceBlock( 1, 0, 1 ), new SourceBlock( 0, 2, 1 ) ), + new( new SourceBlock( 1, 0, 0 ), new SourceBlock( 0, 2, 0 ) ), + new( new SourceBlock( 1, 0, 1 ), new SourceBlock( 0, 3, 1 ) ), + new( new SourceBlock( 1, 0, 2 ), new SourceBlock( 0, 3, 0 ) ), + new( new SourceBlock( 2, 0, 1 ), new SourceBlock( 0, 4, 1 ) ), + new( new SourceBlock( 2, 0, 0 ), new SourceBlock( 0, 4, 0 ) ), + new( new SourceBlock( 2, 0, 1 ), new SourceBlock( 0, 5, 1 ) ), + new( new SourceBlock( 2, 0, 2 ), new SourceBlock( 0, 5, 0 ) ), + new( new SourceBlock( 3, 0, 1 ), new SourceBlock( 0, 6, 1 ) ), + new( new SourceBlock( 3, 0, 0 ), new SourceBlock( 0, 6, 0 ) ), + new( new SourceBlock( 3, 0, 1 ), new SourceBlock( 0, 7, 1 ) ), + new( new SourceBlock( 3, 0, 2 ), new SourceBlock( 0, 7, 0 ) ), + new( new SourceBlock( 4, 0, 1 ), new SourceBlock( 0, 8, 1 ) ), + new( new SourceBlock( 4, 0, 0 ), new SourceBlock( 0, 8, 0 ) ), + new( new SourceBlock( 4, 0, 1 ), new SourceBlock( 0, 9, 1 ) ), + new( new SourceBlock( 4, 0, 2 ), new SourceBlock( 0, 9, 0 ) ), + new( new SourceBlock( 5, 0, 1 ), new SourceBlock( 0, 10, 1 ) ), + new( new SourceBlock( 5, 0, 0 ), new SourceBlock( 0, 10, 0 ) ), + new( new SourceBlock( 5, 0, 1 ), new SourceBlock( 0, 11, 1 ) ), + new( new SourceBlock( 5, 0, 2 ), new SourceBlock( 0, 11, 0 ) ), + new( new SourceBlock( 6, 0, 1 ), new SourceBlock( 0, 12, 1 ) ), + new( new SourceBlock( 6, 0, 0 ), new SourceBlock( 0, 12, 0 ) ), + new( new SourceBlock( 6, 0, 1 ), new SourceBlock( 0, 13, 1 ) ), + new( new SourceBlock( 6, 0, 2 ), new SourceBlock( 0, 13, 0 ) ), + new( new SourceBlock( 7, 0, 1 ), new SourceBlock( 0, 14, 1 ) ), + new( new SourceBlock( 7, 0, 0 ), new SourceBlock( 0, 14, 0 ) ), + new( new SourceBlock( 7, 0, 1 ), new SourceBlock( 0, 15, 1 ) ), + new( new SourceBlock( 7, 0, 2 ), new SourceBlock( 0, 15, 0 ) ), + new( new SourceBlock( 8, 0, 1 ), new SourceBlock( 0, 16, 1 ) ), + new( new SourceBlock( 8, 0, 0 ), new SourceBlock( 0, 16, 0 ) ), + new( new SourceBlock( 8, 0, 1 ), new SourceBlock( 0, 17, 1 ) ), + new( new SourceBlock( 8, 0, 2 ), new SourceBlock( 0, 17, 0 ) ), + new( new SourceBlock( 9, 0, 1 ), new SourceBlock( 0, 18, 1 ) ), + new( new SourceBlock( 9, 0, 0 ), new SourceBlock( 0, 18, 0 ) ), + new( new SourceBlock( 9, 0, 1 ), new SourceBlock( 0, 19, 1 ) ), + new( new SourceBlock( 9, 0, 2 ), new SourceBlock( 0, 19, 0 ) ), + new( new SourceBlock( 10, 0, 1 ), new SourceBlock( 0, 20, 1 ) ), + new( new SourceBlock( 10, 0, 0 ), new SourceBlock( 0, 20, 0 ) ), + new( new SourceBlock( 10, 0, 1 ), new SourceBlock( 0, 21, 1 ) ), + new( new SourceBlock( 10, 0, 2 ), new SourceBlock( 0, 21, 0 ) ), + new( new SourceBlock( 11, 0, 1 ), new SourceBlock( 0, 22, 1 ) ), + new( new SourceBlock( 11, 0, 0 ), new SourceBlock( 0, 22, 0 ) ), + new( new SourceBlock( 11, 0, 1 ), new SourceBlock( 0, 23, 1 ) ), + new( new SourceBlock( 11, 0, 2 ), new SourceBlock( 0, 23, 0 ) ), + new( new SourceBlock( 12, 0, 1 ), new SourceBlock( 0, 24, 1 ) ), + new( new SourceBlock( 12, 0, 0 ), new SourceBlock( 0, 24, 0 ) ), + new( new SourceBlock( 12, 0, 1 ), new SourceBlock( 0, 25, 1 ) ), + new( new SourceBlock( 12, 0, 2 ), new SourceBlock( 0, 25, 0 ) ), + new( new SourceBlock( 13, 0, 1 ), new SourceBlock( 0, 26, 1 ) ), + new( new SourceBlock( 13, 0, 0 ), new SourceBlock( 0, 26, 0 ) ), + new( new SourceBlock( 13, 0, 1 ), new SourceBlock( 0, 27, 1 ) ), + new( new SourceBlock( 13, 0, 2 ), new SourceBlock( 0, 27, 0 ) ), + new( new SourceBlock( 14, 0, 1 ), new SourceBlock( 0, 28, 1 ) ), + new( new SourceBlock( 14, 0, 0 ), new SourceBlock( 0, 28, 0 ) ), + new( new SourceBlock( 14, 0, 1 ), new SourceBlock( 0, 29, 1 ) ), + new( new SourceBlock( 14, 0, 2 ), new SourceBlock( 0, 29, 0 ) ), + new( new SourceBlock( 15, 0, 1 ), new SourceBlock( 0, 30, 1 ) ), + new( new SourceBlock( 15, 0, 0 ), new SourceBlock( 0, 30, 0 ) ), + new( new SourceBlock( 15, 0, 1 ), new SourceBlock( 0, 31, 1 ) ), + new( new SourceBlock( 15, 0, 2 ), new SourceBlock( 0, 31, 0 ) ), + new( new SourceBlock( 16, 0, 2 ), new SourceBlock( 1, 31, 1 ) ), + new( new SourceBlock( 16, 0, 1 ), new SourceBlock( 1, 31, 0 ) ), + new( new SourceBlock( 16, 0, 0 ), new SourceBlock( 0, 32, 0 ) ), + new( new SourceBlock( 16, 0, 1 ), new SourceBlock( 2, 31, 0 ) ), + new( new SourceBlock( 16, 0, 2 ), new SourceBlock( 0, 33, 0 ) ), + new( new SourceBlock( 17, 0, 1 ), new SourceBlock( 3, 31, 0 ) ), + new( new SourceBlock( 17, 0, 0 ), new SourceBlock( 0, 34, 0 ) ), + new( new SourceBlock( 17, 0, 1 ), new SourceBlock( 4, 31, 0 ) ), + new( new SourceBlock( 17, 0, 2 ), new SourceBlock( 0, 35, 0 ) ), + new( new SourceBlock( 18, 0, 1 ), new SourceBlock( 5, 31, 0 ) ), + new( new SourceBlock( 18, 0, 0 ), new SourceBlock( 0, 36, 0 ) ), + new( new SourceBlock( 18, 0, 1 ), new SourceBlock( 6, 31, 0 ) ), + new( new SourceBlock( 18, 0, 2 ), new SourceBlock( 0, 37, 0 ) ), + new( new SourceBlock( 19, 0, 1 ), new SourceBlock( 7, 31, 0 ) ), + new( new SourceBlock( 19, 0, 0 ), new SourceBlock( 0, 38, 0 ) ), + new( new SourceBlock( 19, 0, 1 ), new SourceBlock( 8, 31, 0 ) ), + new( new SourceBlock( 19, 0, 2 ), new SourceBlock( 0, 39, 0 ) ), + new( new SourceBlock( 20, 0, 1 ), new SourceBlock( 9, 31, 0 ) ), + new( new SourceBlock( 20, 0, 0 ), new SourceBlock( 0, 40, 0 ) ), + new( new SourceBlock( 20, 0, 1 ), new SourceBlock( 10, 31, 0 ) ), + new( new SourceBlock( 20, 0, 2 ), new SourceBlock( 0, 41, 0 ) ), + new( new SourceBlock( 21, 0, 1 ), new SourceBlock( 11, 31, 0 ) ), + new( new SourceBlock( 21, 0, 0 ), new SourceBlock( 0, 42, 0 ) ), + new( new SourceBlock( 21, 0, 1 ), new SourceBlock( 12, 31, 0 ) ), + new( new SourceBlock( 21, 0, 2 ), new SourceBlock( 0, 43, 0 ) ), + new( new SourceBlock( 22, 0, 1 ), new SourceBlock( 13, 31, 0 ) ), + new( new SourceBlock( 22, 0, 0 ), new SourceBlock( 0, 44, 0 ) ), + new( new SourceBlock( 22, 0, 1 ), new SourceBlock( 14, 31, 0 ) ), + new( new SourceBlock( 22, 0, 2 ), new SourceBlock( 0, 45, 0 ) ), + new( new SourceBlock( 23, 0, 1 ), new SourceBlock( 15, 31, 0 ) ), + new( new SourceBlock( 23, 0, 0 ), new SourceBlock( 0, 46, 0 ) ), + new( new SourceBlock( 23, 0, 1 ), new SourceBlock( 0, 47, 1 ) ), + new( new SourceBlock( 23, 0, 2 ), new SourceBlock( 0, 47, 0 ) ), + new( new SourceBlock( 24, 0, 1 ), new SourceBlock( 0, 48, 1 ) ), + new( new SourceBlock( 24, 0, 0 ), new SourceBlock( 0, 48, 0 ) ), + new( new SourceBlock( 24, 0, 1 ), new SourceBlock( 0, 49, 1 ) ), + new( new SourceBlock( 24, 0, 2 ), new SourceBlock( 0, 49, 0 ) ), + new( new SourceBlock( 25, 0, 1 ), new SourceBlock( 0, 50, 1 ) ), + new( new SourceBlock( 25, 0, 0 ), new SourceBlock( 0, 50, 0 ) ), + new( new SourceBlock( 25, 0, 1 ), new SourceBlock( 0, 51, 1 ) ), + new( new SourceBlock( 25, 0, 2 ), new SourceBlock( 0, 51, 0 ) ), + new( new SourceBlock( 26, 0, 1 ), new SourceBlock( 0, 52, 1 ) ), + new( new SourceBlock( 26, 0, 0 ), new SourceBlock( 0, 52, 0 ) ), + new( new SourceBlock( 26, 0, 1 ), new SourceBlock( 0, 53, 1 ) ), + new( new SourceBlock( 26, 0, 2 ), new SourceBlock( 0, 53, 0 ) ), + new( new SourceBlock( 27, 0, 1 ), new SourceBlock( 0, 54, 1 ) ), + new( new SourceBlock( 27, 0, 0 ), new SourceBlock( 0, 54, 0 ) ), + new( new SourceBlock( 27, 0, 1 ), new SourceBlock( 0, 55, 1 ) ), + new( new SourceBlock( 27, 0, 2 ), new SourceBlock( 0, 55, 0 ) ), + new( new SourceBlock( 28, 0, 1 ), new SourceBlock( 0, 56, 1 ) ), + new( new SourceBlock( 28, 0, 0 ), new SourceBlock( 0, 56, 0 ) ), + new( new SourceBlock( 28, 0, 1 ), new SourceBlock( 0, 57, 1 ) ), + new( new SourceBlock( 28, 0, 2 ), new SourceBlock( 0, 57, 0 ) ), + new( new SourceBlock( 29, 0, 1 ), new SourceBlock( 0, 58, 1 ) ), + new( new SourceBlock( 29, 0, 0 ), new SourceBlock( 0, 58, 0 ) ), + new( new SourceBlock( 29, 0, 1 ), new SourceBlock( 0, 59, 1 ) ), + new( new SourceBlock( 29, 0, 2 ), new SourceBlock( 0, 59, 0 ) ), + new( new SourceBlock( 30, 0, 1 ), new SourceBlock( 0, 60, 1 ) ), + new( new SourceBlock( 30, 0, 0 ), new SourceBlock( 0, 60, 0 ) ), + new( new SourceBlock( 30, 0, 1 ), new SourceBlock( 0, 61, 1 ) ), + new( new SourceBlock( 30, 0, 2 ), new SourceBlock( 0, 61, 0 ) ), + new( new SourceBlock( 31, 0, 1 ), new SourceBlock( 0, 62, 1 ) ), + new( new SourceBlock( 31, 0, 0 ), new SourceBlock( 0, 62, 0 ) ), + new( new SourceBlock( 31, 0, 1 ), new SourceBlock( 0, 63, 1 ) ), + new( new SourceBlock( 31, 0, 2 ), new SourceBlock( 0, 63, 0 ) ), + new( new SourceBlock( 32, 0, 2 ), new SourceBlock( 1, 63, 1 ) ), + new( new SourceBlock( 32, 0, 1 ), new SourceBlock( 1, 63, 0 ) ), + new( new SourceBlock( 32, 0, 0 ), new SourceBlock( 16, 48, 0 ) ), + new( new SourceBlock( 32, 0, 1 ), new SourceBlock( 2, 63, 0 ) ), + new( new SourceBlock( 32, 0, 2 ), new SourceBlock( 16, 49, 0 ) ), + new( new SourceBlock( 33, 0, 1 ), new SourceBlock( 3, 63, 0 ) ), + new( new SourceBlock( 33, 0, 0 ), new SourceBlock( 16, 50, 0 ) ), + new( new SourceBlock( 33, 0, 1 ), new SourceBlock( 4, 63, 0 ) ), + new( new SourceBlock( 33, 0, 2 ), new SourceBlock( 16, 51, 0 ) ), + new( new SourceBlock( 34, 0, 1 ), new SourceBlock( 5, 63, 0 ) ), + new( new SourceBlock( 34, 0, 0 ), new SourceBlock( 16, 52, 0 ) ), + new( new SourceBlock( 34, 0, 1 ), new SourceBlock( 6, 63, 0 ) ), + new( new SourceBlock( 34, 0, 2 ), new SourceBlock( 16, 53, 0 ) ), + new( new SourceBlock( 35, 0, 1 ), new SourceBlock( 7, 63, 0 ) ), + new( new SourceBlock( 35, 0, 0 ), new SourceBlock( 16, 54, 0 ) ), + new( new SourceBlock( 35, 0, 1 ), new SourceBlock( 8, 63, 0 ) ), + new( new SourceBlock( 35, 0, 2 ), new SourceBlock( 16, 55, 0 ) ), + new( new SourceBlock( 36, 0, 1 ), new SourceBlock( 9, 63, 0 ) ), + new( new SourceBlock( 36, 0, 0 ), new SourceBlock( 16, 56, 0 ) ), + new( new SourceBlock( 36, 0, 1 ), new SourceBlock( 10, 63, 0 ) ), + new( new SourceBlock( 36, 0, 2 ), new SourceBlock( 16, 57, 0 ) ), + new( new SourceBlock( 37, 0, 1 ), new SourceBlock( 11, 63, 0 ) ), + new( new SourceBlock( 37, 0, 0 ), new SourceBlock( 16, 58, 0 ) ), + new( new SourceBlock( 37, 0, 1 ), new SourceBlock( 12, 63, 0 ) ), + new( new SourceBlock( 37, 0, 2 ), new SourceBlock( 16, 59, 0 ) ), + new( new SourceBlock( 38, 0, 1 ), new SourceBlock( 13, 63, 0 ) ), + new( new SourceBlock( 38, 0, 0 ), new SourceBlock( 16, 60, 0 ) ), + new( new SourceBlock( 38, 0, 1 ), new SourceBlock( 14, 63, 0 ) ), + new( new SourceBlock( 38, 0, 2 ), new SourceBlock( 16, 61, 0 ) ), + new( new SourceBlock( 39, 0, 1 ), new SourceBlock( 15, 63, 0 ) ), + new( new SourceBlock( 39, 0, 0 ), new SourceBlock( 16, 62, 0 ) ), + new( new SourceBlock( 39, 0, 1 ), new SourceBlock( 16, 63, 1 ) ), + new( new SourceBlock( 39, 0, 2 ), new SourceBlock( 16, 63, 0 ) ), + new( new SourceBlock( 40, 0, 1 ), new SourceBlock( 17, 63, 1 ) ), + new( new SourceBlock( 40, 0, 0 ), new SourceBlock( 17, 63, 0 ) ), + new( new SourceBlock( 40, 0, 1 ), new SourceBlock( 18, 63, 1 ) ), + new( new SourceBlock( 40, 0, 2 ), new SourceBlock( 18, 63, 0 ) ), + new( new SourceBlock( 41, 0, 1 ), new SourceBlock( 19, 63, 1 ) ), + new( new SourceBlock( 41, 0, 0 ), new SourceBlock( 19, 63, 0 ) ), + new( new SourceBlock( 41, 0, 1 ), new SourceBlock( 20, 63, 1 ) ), + new( new SourceBlock( 41, 0, 2 ), new SourceBlock( 20, 63, 0 ) ), + new( new SourceBlock( 42, 0, 1 ), new SourceBlock( 21, 63, 1 ) ), + new( new SourceBlock( 42, 0, 0 ), new SourceBlock( 21, 63, 0 ) ), + new( new SourceBlock( 42, 0, 1 ), new SourceBlock( 22, 63, 1 ) ), + new( new SourceBlock( 42, 0, 2 ), new SourceBlock( 22, 63, 0 ) ), + new( new SourceBlock( 43, 0, 1 ), new SourceBlock( 23, 63, 1 ) ), + new( new SourceBlock( 43, 0, 0 ), new SourceBlock( 23, 63, 0 ) ), + new( new SourceBlock( 43, 0, 1 ), new SourceBlock( 24, 63, 1 ) ), + new( new SourceBlock( 43, 0, 2 ), new SourceBlock( 24, 63, 0 ) ), + new( new SourceBlock( 44, 0, 1 ), new SourceBlock( 25, 63, 1 ) ), + new( new SourceBlock( 44, 0, 0 ), new SourceBlock( 25, 63, 0 ) ), + new( new SourceBlock( 44, 0, 1 ), new SourceBlock( 26, 63, 1 ) ), + new( new SourceBlock( 44, 0, 2 ), new SourceBlock( 26, 63, 0 ) ), + new( new SourceBlock( 45, 0, 1 ), new SourceBlock( 27, 63, 1 ) ), + new( new SourceBlock( 45, 0, 0 ), new SourceBlock( 27, 63, 0 ) ), + new( new SourceBlock( 45, 0, 1 ), new SourceBlock( 28, 63, 1 ) ), + new( new SourceBlock( 45, 0, 2 ), new SourceBlock( 28, 63, 0 ) ), + new( new SourceBlock( 46, 0, 1 ), new SourceBlock( 29, 63, 1 ) ), + new( new SourceBlock( 46, 0, 0 ), new SourceBlock( 29, 63, 0 ) ), + new( new SourceBlock( 46, 0, 1 ), new SourceBlock( 30, 63, 1 ) ), + new( new SourceBlock( 46, 0, 2 ), new SourceBlock( 30, 63, 0 ) ), + new( new SourceBlock( 47, 0, 1 ), new SourceBlock( 31, 63, 1 ) ), + new( new SourceBlock( 47, 0, 0 ), new SourceBlock( 31, 63, 0 ) ), + new( new SourceBlock( 47, 0, 1 ), new SourceBlock( 32, 63, 1 ) ), + new( new SourceBlock( 47, 0, 2 ), new SourceBlock( 32, 63, 0 ) ), + new( new SourceBlock( 48, 0, 2 ), new SourceBlock( 33, 63, 1 ) ), + new( new SourceBlock( 48, 0, 1 ), new SourceBlock( 33, 63, 0 ) ), + new( new SourceBlock( 48, 0, 0 ), new SourceBlock( 48, 48, 0 ) ), + new( new SourceBlock( 48, 0, 1 ), new SourceBlock( 34, 63, 0 ) ), + new( new SourceBlock( 48, 0, 2 ), new SourceBlock( 48, 49, 0 ) ), + new( new SourceBlock( 49, 0, 1 ), new SourceBlock( 35, 63, 0 ) ), + new( new SourceBlock( 49, 0, 0 ), new SourceBlock( 48, 50, 0 ) ), + new( new SourceBlock( 49, 0, 1 ), new SourceBlock( 36, 63, 0 ) ), + new( new SourceBlock( 49, 0, 2 ), new SourceBlock( 48, 51, 0 ) ), + new( new SourceBlock( 50, 0, 1 ), new SourceBlock( 37, 63, 0 ) ), + new( new SourceBlock( 50, 0, 0 ), new SourceBlock( 48, 52, 0 ) ), + new( new SourceBlock( 50, 0, 1 ), new SourceBlock( 38, 63, 0 ) ), + new( new SourceBlock( 50, 0, 2 ), new SourceBlock( 48, 53, 0 ) ), + new( new SourceBlock( 51, 0, 1 ), new SourceBlock( 39, 63, 0 ) ), + new( new SourceBlock( 51, 0, 0 ), new SourceBlock( 48, 54, 0 ) ), + new( new SourceBlock( 51, 0, 1 ), new SourceBlock( 40, 63, 0 ) ), + new( new SourceBlock( 51, 0, 2 ), new SourceBlock( 48, 55, 0 ) ), + new( new SourceBlock( 52, 0, 1 ), new SourceBlock( 41, 63, 0 ) ), + new( new SourceBlock( 52, 0, 0 ), new SourceBlock( 48, 56, 0 ) ), + new( new SourceBlock( 52, 0, 1 ), new SourceBlock( 42, 63, 0 ) ), + new( new SourceBlock( 52, 0, 2 ), new SourceBlock( 48, 57, 0 ) ), + new( new SourceBlock( 53, 0, 1 ), new SourceBlock( 43, 63, 0 ) ), + new( new SourceBlock( 53, 0, 0 ), new SourceBlock( 48, 58, 0 ) ), + new( new SourceBlock( 53, 0, 1 ), new SourceBlock( 44, 63, 0 ) ), + new( new SourceBlock( 53, 0, 2 ), new SourceBlock( 48, 59, 0 ) ), + new( new SourceBlock( 54, 0, 1 ), new SourceBlock( 45, 63, 0 ) ), + new( new SourceBlock( 54, 0, 0 ), new SourceBlock( 48, 60, 0 ) ), + new( new SourceBlock( 54, 0, 1 ), new SourceBlock( 46, 63, 0 ) ), + new( new SourceBlock( 54, 0, 2 ), new SourceBlock( 48, 61, 0 ) ), + new( new SourceBlock( 55, 0, 1 ), new SourceBlock( 47, 63, 0 ) ), + new( new SourceBlock( 55, 0, 0 ), new SourceBlock( 48, 62, 0 ) ), + new( new SourceBlock( 55, 0, 1 ), new SourceBlock( 48, 63, 1 ) ), + new( new SourceBlock( 55, 0, 2 ), new SourceBlock( 48, 63, 0 ) ), + new( new SourceBlock( 56, 0, 1 ), new SourceBlock( 49, 63, 1 ) ), + new( new SourceBlock( 56, 0, 0 ), new SourceBlock( 49, 63, 0 ) ), + new( new SourceBlock( 56, 0, 1 ), new SourceBlock( 50, 63, 1 ) ), + new( new SourceBlock( 56, 0, 2 ), new SourceBlock( 50, 63, 0 ) ), + new( new SourceBlock( 57, 0, 1 ), new SourceBlock( 51, 63, 1 ) ), + new( new SourceBlock( 57, 0, 0 ), new SourceBlock( 51, 63, 0 ) ), + new( new SourceBlock( 57, 0, 1 ), new SourceBlock( 52, 63, 1 ) ), + new( new SourceBlock( 57, 0, 2 ), new SourceBlock( 52, 63, 0 ) ), + new( new SourceBlock( 58, 0, 1 ), new SourceBlock( 53, 63, 1 ) ), + new( new SourceBlock( 58, 0, 0 ), new SourceBlock( 53, 63, 0 ) ), + new( new SourceBlock( 58, 0, 1 ), new SourceBlock( 54, 63, 1 ) ), + new( new SourceBlock( 58, 0, 2 ), new SourceBlock( 54, 63, 0 ) ), + new( new SourceBlock( 59, 0, 1 ), new SourceBlock( 55, 63, 1 ) ), + new( new SourceBlock( 59, 0, 0 ), new SourceBlock( 55, 63, 0 ) ), + new( new SourceBlock( 59, 0, 1 ), new SourceBlock( 56, 63, 1 ) ), + new( new SourceBlock( 59, 0, 2 ), new SourceBlock( 56, 63, 0 ) ), + new( new SourceBlock( 60, 0, 1 ), new SourceBlock( 57, 63, 1 ) ), + new( new SourceBlock( 60, 0, 0 ), new SourceBlock( 57, 63, 0 ) ), + new( new SourceBlock( 60, 0, 1 ), new SourceBlock( 58, 63, 1 ) ), + new( new SourceBlock( 60, 0, 2 ), new SourceBlock( 58, 63, 0 ) ), + new( new SourceBlock( 61, 0, 1 ), new SourceBlock( 59, 63, 1 ) ), + new( new SourceBlock( 61, 0, 0 ), new SourceBlock( 59, 63, 0 ) ), + new( new SourceBlock( 61, 0, 1 ), new SourceBlock( 60, 63, 1 ) ), + new( new SourceBlock( 61, 0, 2 ), new SourceBlock( 60, 63, 0 ) ), + new( new SourceBlock( 62, 0, 1 ), new SourceBlock( 61, 63, 1 ) ), + new( new SourceBlock( 62, 0, 0 ), new SourceBlock( 61, 63, 0 ) ), + new( new SourceBlock( 62, 0, 1 ), new SourceBlock( 62, 63, 1 ) ), + new( new SourceBlock( 62, 0, 2 ), new SourceBlock( 62, 63, 0 ) ), + new( new SourceBlock( 63, 0, 1 ), new SourceBlock( 63, 63, 1 ) ), + new( new SourceBlock( 63, 0, 0 ), new SourceBlock( 63, 63, 0 ) ) + ]; + + public static SingleColourLookup[] lookup_5_4 = + [ + new( new SourceBlock( 0, 0, 0 ), new SourceBlock( 0, 0, 0 ) ), + new( new SourceBlock( 0, 0, 1 ), new SourceBlock( 0, 1, 1 ) ), + new( new SourceBlock( 0, 0, 2 ), new SourceBlock( 0, 1, 0 ) ), + new( new SourceBlock( 0, 0, 3 ), new SourceBlock( 0, 1, 1 ) ), + new( new SourceBlock( 0, 0, 4 ), new SourceBlock( 0, 2, 1 ) ), + new( new SourceBlock( 1, 0, 3 ), new SourceBlock( 0, 2, 0 ) ), + new( new SourceBlock( 1, 0, 2 ), new SourceBlock( 0, 2, 1 ) ), + new( new SourceBlock( 1, 0, 1 ), new SourceBlock( 0, 3, 1 ) ), + new( new SourceBlock( 1, 0, 0 ), new SourceBlock( 0, 3, 0 ) ), + new( new SourceBlock( 1, 0, 1 ), new SourceBlock( 1, 2, 1 ) ), + new( new SourceBlock( 1, 0, 2 ), new SourceBlock( 1, 2, 0 ) ), + new( new SourceBlock( 1, 0, 3 ), new SourceBlock( 0, 4, 0 ) ), + new( new SourceBlock( 1, 0, 4 ), new SourceBlock( 0, 5, 1 ) ), + new( new SourceBlock( 2, 0, 3 ), new SourceBlock( 0, 5, 0 ) ), + new( new SourceBlock( 2, 0, 2 ), new SourceBlock( 0, 5, 1 ) ), + new( new SourceBlock( 2, 0, 1 ), new SourceBlock( 0, 6, 1 ) ), + new( new SourceBlock( 2, 0, 0 ), new SourceBlock( 0, 6, 0 ) ), + new( new SourceBlock( 2, 0, 1 ), new SourceBlock( 2, 3, 1 ) ), + new( new SourceBlock( 2, 0, 2 ), new SourceBlock( 2, 3, 0 ) ), + new( new SourceBlock( 2, 0, 3 ), new SourceBlock( 0, 7, 0 ) ), + new( new SourceBlock( 2, 0, 4 ), new SourceBlock( 1, 6, 1 ) ), + new( new SourceBlock( 3, 0, 3 ), new SourceBlock( 1, 6, 0 ) ), + new( new SourceBlock( 3, 0, 2 ), new SourceBlock( 0, 8, 0 ) ), + new( new SourceBlock( 3, 0, 1 ), new SourceBlock( 0, 9, 1 ) ), + new( new SourceBlock( 3, 0, 0 ), new SourceBlock( 0, 9, 0 ) ), + new( new SourceBlock( 3, 0, 1 ), new SourceBlock( 0, 9, 1 ) ), + new( new SourceBlock( 3, 0, 2 ), new SourceBlock( 0, 10, 1 ) ), + new( new SourceBlock( 3, 0, 3 ), new SourceBlock( 0, 10, 0 ) ), + new( new SourceBlock( 3, 0, 4 ), new SourceBlock( 2, 7, 1 ) ), + new( new SourceBlock( 4, 0, 4 ), new SourceBlock( 2, 7, 0 ) ), + new( new SourceBlock( 4, 0, 3 ), new SourceBlock( 0, 11, 0 ) ), + new( new SourceBlock( 4, 0, 2 ), new SourceBlock( 1, 10, 1 ) ), + new( new SourceBlock( 4, 0, 1 ), new SourceBlock( 1, 10, 0 ) ), + new( new SourceBlock( 4, 0, 0 ), new SourceBlock( 0, 12, 0 ) ), + new( new SourceBlock( 4, 0, 1 ), new SourceBlock( 0, 13, 1 ) ), + new( new SourceBlock( 4, 0, 2 ), new SourceBlock( 0, 13, 0 ) ), + new( new SourceBlock( 4, 0, 3 ), new SourceBlock( 0, 13, 1 ) ), + new( new SourceBlock( 4, 0, 4 ), new SourceBlock( 0, 14, 1 ) ), + new( new SourceBlock( 5, 0, 3 ), new SourceBlock( 0, 14, 0 ) ), + new( new SourceBlock( 5, 0, 2 ), new SourceBlock( 2, 11, 1 ) ), + new( new SourceBlock( 5, 0, 1 ), new SourceBlock( 2, 11, 0 ) ), + new( new SourceBlock( 5, 0, 0 ), new SourceBlock( 0, 15, 0 ) ), + new( new SourceBlock( 5, 0, 1 ), new SourceBlock( 1, 14, 1 ) ), + new( new SourceBlock( 5, 0, 2 ), new SourceBlock( 1, 14, 0 ) ), + new( new SourceBlock( 5, 0, 3 ), new SourceBlock( 0, 16, 0 ) ), + new( new SourceBlock( 5, 0, 4 ), new SourceBlock( 0, 17, 1 ) ), + new( new SourceBlock( 6, 0, 3 ), new SourceBlock( 0, 17, 0 ) ), + new( new SourceBlock( 6, 0, 2 ), new SourceBlock( 0, 17, 1 ) ), + new( new SourceBlock( 6, 0, 1 ), new SourceBlock( 0, 18, 1 ) ), + new( new SourceBlock( 6, 0, 0 ), new SourceBlock( 0, 18, 0 ) ), + new( new SourceBlock( 6, 0, 1 ), new SourceBlock( 2, 15, 1 ) ), + new( new SourceBlock( 6, 0, 2 ), new SourceBlock( 2, 15, 0 ) ), + new( new SourceBlock( 6, 0, 3 ), new SourceBlock( 0, 19, 0 ) ), + new( new SourceBlock( 6, 0, 4 ), new SourceBlock( 1, 18, 1 ) ), + new( new SourceBlock( 7, 0, 3 ), new SourceBlock( 1, 18, 0 ) ), + new( new SourceBlock( 7, 0, 2 ), new SourceBlock( 0, 20, 0 ) ), + new( new SourceBlock( 7, 0, 1 ), new SourceBlock( 0, 21, 1 ) ), + new( new SourceBlock( 7, 0, 0 ), new SourceBlock( 0, 21, 0 ) ), + new( new SourceBlock( 7, 0, 1 ), new SourceBlock( 0, 21, 1 ) ), + new( new SourceBlock( 7, 0, 2 ), new SourceBlock( 0, 22, 1 ) ), + new( new SourceBlock( 7, 0, 3 ), new SourceBlock( 0, 22, 0 ) ), + new( new SourceBlock( 7, 0, 4 ), new SourceBlock( 2, 19, 1 ) ), + new( new SourceBlock( 8, 0, 4 ), new SourceBlock( 2, 19, 0 ) ), + new( new SourceBlock( 8, 0, 3 ), new SourceBlock( 0, 23, 0 ) ), + new( new SourceBlock( 8, 0, 2 ), new SourceBlock( 1, 22, 1 ) ), + new( new SourceBlock( 8, 0, 1 ), new SourceBlock( 1, 22, 0 ) ), + new( new SourceBlock( 8, 0, 0 ), new SourceBlock( 0, 24, 0 ) ), + new( new SourceBlock( 8, 0, 1 ), new SourceBlock( 0, 25, 1 ) ), + new( new SourceBlock( 8, 0, 2 ), new SourceBlock( 0, 25, 0 ) ), + new( new SourceBlock( 8, 0, 3 ), new SourceBlock( 0, 25, 1 ) ), + new( new SourceBlock( 8, 0, 4 ), new SourceBlock( 0, 26, 1 ) ), + new( new SourceBlock( 9, 0, 3 ), new SourceBlock( 0, 26, 0 ) ), + new( new SourceBlock( 9, 0, 2 ), new SourceBlock( 2, 23, 1 ) ), + new( new SourceBlock( 9, 0, 1 ), new SourceBlock( 2, 23, 0 ) ), + new( new SourceBlock( 9, 0, 0 ), new SourceBlock( 0, 27, 0 ) ), + new( new SourceBlock( 9, 0, 1 ), new SourceBlock( 1, 26, 1 ) ), + new( new SourceBlock( 9, 0, 2 ), new SourceBlock( 1, 26, 0 ) ), + new( new SourceBlock( 9, 0, 3 ), new SourceBlock( 0, 28, 0 ) ), + new( new SourceBlock( 9, 0, 4 ), new SourceBlock( 0, 29, 1 ) ), + new( new SourceBlock( 10, 0, 3 ), new SourceBlock( 0, 29, 0 ) ), + new( new SourceBlock( 10, 0, 2 ), new SourceBlock( 0, 29, 1 ) ), + new( new SourceBlock( 10, 0, 1 ), new SourceBlock( 0, 30, 1 ) ), + new( new SourceBlock( 10, 0, 0 ), new SourceBlock( 0, 30, 0 ) ), + new( new SourceBlock( 10, 0, 1 ), new SourceBlock( 2, 27, 1 ) ), + new( new SourceBlock( 10, 0, 2 ), new SourceBlock( 2, 27, 0 ) ), + new( new SourceBlock( 10, 0, 3 ), new SourceBlock( 0, 31, 0 ) ), + new( new SourceBlock( 10, 0, 4 ), new SourceBlock( 1, 30, 1 ) ), + new( new SourceBlock( 11, 0, 3 ), new SourceBlock( 1, 30, 0 ) ), + new( new SourceBlock( 11, 0, 2 ), new SourceBlock( 4, 24, 0 ) ), + new( new SourceBlock( 11, 0, 1 ), new SourceBlock( 1, 31, 1 ) ), + new( new SourceBlock( 11, 0, 0 ), new SourceBlock( 1, 31, 0 ) ), + new( new SourceBlock( 11, 0, 1 ), new SourceBlock( 1, 31, 1 ) ), + new( new SourceBlock( 11, 0, 2 ), new SourceBlock( 2, 30, 1 ) ), + new( new SourceBlock( 11, 0, 3 ), new SourceBlock( 2, 30, 0 ) ), + new( new SourceBlock( 11, 0, 4 ), new SourceBlock( 2, 31, 1 ) ), + new( new SourceBlock( 12, 0, 4 ), new SourceBlock( 2, 31, 0 ) ), + new( new SourceBlock( 12, 0, 3 ), new SourceBlock( 4, 27, 0 ) ), + new( new SourceBlock( 12, 0, 2 ), new SourceBlock( 3, 30, 1 ) ), + new( new SourceBlock( 12, 0, 1 ), new SourceBlock( 3, 30, 0 ) ), + new( new SourceBlock( 12, 0, 0 ), new SourceBlock( 4, 28, 0 ) ), + new( new SourceBlock( 12, 0, 1 ), new SourceBlock( 3, 31, 1 ) ), + new( new SourceBlock( 12, 0, 2 ), new SourceBlock( 3, 31, 0 ) ), + new( new SourceBlock( 12, 0, 3 ), new SourceBlock( 3, 31, 1 ) ), + new( new SourceBlock( 12, 0, 4 ), new SourceBlock( 4, 30, 1 ) ), + new( new SourceBlock( 13, 0, 3 ), new SourceBlock( 4, 30, 0 ) ), + new( new SourceBlock( 13, 0, 2 ), new SourceBlock( 6, 27, 1 ) ), + new( new SourceBlock( 13, 0, 1 ), new SourceBlock( 6, 27, 0 ) ), + new( new SourceBlock( 13, 0, 0 ), new SourceBlock( 4, 31, 0 ) ), + new( new SourceBlock( 13, 0, 1 ), new SourceBlock( 5, 30, 1 ) ), + new( new SourceBlock( 13, 0, 2 ), new SourceBlock( 5, 30, 0 ) ), + new( new SourceBlock( 13, 0, 3 ), new SourceBlock( 8, 24, 0 ) ), + new( new SourceBlock( 13, 0, 4 ), new SourceBlock( 5, 31, 1 ) ), + new( new SourceBlock( 14, 0, 3 ), new SourceBlock( 5, 31, 0 ) ), + new( new SourceBlock( 14, 0, 2 ), new SourceBlock( 5, 31, 1 ) ), + new( new SourceBlock( 14, 0, 1 ), new SourceBlock( 6, 30, 1 ) ), + new( new SourceBlock( 14, 0, 0 ), new SourceBlock( 6, 30, 0 ) ), + new( new SourceBlock( 14, 0, 1 ), new SourceBlock( 6, 31, 1 ) ), + new( new SourceBlock( 14, 0, 2 ), new SourceBlock( 6, 31, 0 ) ), + new( new SourceBlock( 14, 0, 3 ), new SourceBlock( 8, 27, 0 ) ), + new( new SourceBlock( 14, 0, 4 ), new SourceBlock( 7, 30, 1 ) ), + new( new SourceBlock( 15, 0, 3 ), new SourceBlock( 7, 30, 0 ) ), + new( new SourceBlock( 15, 0, 2 ), new SourceBlock( 8, 28, 0 ) ), + new( new SourceBlock( 15, 0, 1 ), new SourceBlock( 7, 31, 1 ) ), + new( new SourceBlock( 15, 0, 0 ), new SourceBlock( 7, 31, 0 ) ), + new( new SourceBlock( 15, 0, 1 ), new SourceBlock( 7, 31, 1 ) ), + new( new SourceBlock( 15, 0, 2 ), new SourceBlock( 8, 30, 1 ) ), + new( new SourceBlock( 15, 0, 3 ), new SourceBlock( 8, 30, 0 ) ), + new( new SourceBlock( 15, 0, 4 ), new SourceBlock( 10, 27, 1 ) ), + new( new SourceBlock( 16, 0, 4 ), new SourceBlock( 10, 27, 0 ) ), + new( new SourceBlock( 16, 0, 3 ), new SourceBlock( 8, 31, 0 ) ), + new( new SourceBlock( 16, 0, 2 ), new SourceBlock( 9, 30, 1 ) ), + new( new SourceBlock( 16, 0, 1 ), new SourceBlock( 9, 30, 0 ) ), + new( new SourceBlock( 16, 0, 0 ), new SourceBlock( 12, 24, 0 ) ), + new( new SourceBlock( 16, 0, 1 ), new SourceBlock( 9, 31, 1 ) ), + new( new SourceBlock( 16, 0, 2 ), new SourceBlock( 9, 31, 0 ) ), + new( new SourceBlock( 16, 0, 3 ), new SourceBlock( 9, 31, 1 ) ), + new( new SourceBlock( 16, 0, 4 ), new SourceBlock( 10, 30, 1 ) ), + new( new SourceBlock( 17, 0, 3 ), new SourceBlock( 10, 30, 0 ) ), + new( new SourceBlock( 17, 0, 2 ), new SourceBlock( 10, 31, 1 ) ), + new( new SourceBlock( 17, 0, 1 ), new SourceBlock( 10, 31, 0 ) ), + new( new SourceBlock( 17, 0, 0 ), new SourceBlock( 12, 27, 0 ) ), + new( new SourceBlock( 17, 0, 1 ), new SourceBlock( 11, 30, 1 ) ), + new( new SourceBlock( 17, 0, 2 ), new SourceBlock( 11, 30, 0 ) ), + new( new SourceBlock( 17, 0, 3 ), new SourceBlock( 12, 28, 0 ) ), + new( new SourceBlock( 17, 0, 4 ), new SourceBlock( 11, 31, 1 ) ), + new( new SourceBlock( 18, 0, 3 ), new SourceBlock( 11, 31, 0 ) ), + new( new SourceBlock( 18, 0, 2 ), new SourceBlock( 11, 31, 1 ) ), + new( new SourceBlock( 18, 0, 1 ), new SourceBlock( 12, 30, 1 ) ), + new( new SourceBlock( 18, 0, 0 ), new SourceBlock( 12, 30, 0 ) ), + new( new SourceBlock( 18, 0, 1 ), new SourceBlock( 14, 27, 1 ) ), + new( new SourceBlock( 18, 0, 2 ), new SourceBlock( 14, 27, 0 ) ), + new( new SourceBlock( 18, 0, 3 ), new SourceBlock( 12, 31, 0 ) ), + new( new SourceBlock( 18, 0, 4 ), new SourceBlock( 13, 30, 1 ) ), + new( new SourceBlock( 19, 0, 3 ), new SourceBlock( 13, 30, 0 ) ), + new( new SourceBlock( 19, 0, 2 ), new SourceBlock( 16, 24, 0 ) ), + new( new SourceBlock( 19, 0, 1 ), new SourceBlock( 13, 31, 1 ) ), + new( new SourceBlock( 19, 0, 0 ), new SourceBlock( 13, 31, 0 ) ), + new( new SourceBlock( 19, 0, 1 ), new SourceBlock( 13, 31, 1 ) ), + new( new SourceBlock( 19, 0, 2 ), new SourceBlock( 14, 30, 1 ) ), + new( new SourceBlock( 19, 0, 3 ), new SourceBlock( 14, 30, 0 ) ), + new( new SourceBlock( 19, 0, 4 ), new SourceBlock( 14, 31, 1 ) ), + new( new SourceBlock( 20, 0, 4 ), new SourceBlock( 14, 31, 0 ) ), + new( new SourceBlock( 20, 0, 3 ), new SourceBlock( 16, 27, 0 ) ), + new( new SourceBlock( 20, 0, 2 ), new SourceBlock( 15, 30, 1 ) ), + new( new SourceBlock( 20, 0, 1 ), new SourceBlock( 15, 30, 0 ) ), + new( new SourceBlock( 20, 0, 0 ), new SourceBlock( 16, 28, 0 ) ), + new( new SourceBlock( 20, 0, 1 ), new SourceBlock( 15, 31, 1 ) ), + new( new SourceBlock( 20, 0, 2 ), new SourceBlock( 15, 31, 0 ) ), + new( new SourceBlock( 20, 0, 3 ), new SourceBlock( 15, 31, 1 ) ), + new( new SourceBlock( 20, 0, 4 ), new SourceBlock( 16, 30, 1 ) ), + new( new SourceBlock( 21, 0, 3 ), new SourceBlock( 16, 30, 0 ) ), + new( new SourceBlock( 21, 0, 2 ), new SourceBlock( 18, 27, 1 ) ), + new( new SourceBlock( 21, 0, 1 ), new SourceBlock( 18, 27, 0 ) ), + new( new SourceBlock( 21, 0, 0 ), new SourceBlock( 16, 31, 0 ) ), + new( new SourceBlock( 21, 0, 1 ), new SourceBlock( 17, 30, 1 ) ), + new( new SourceBlock( 21, 0, 2 ), new SourceBlock( 17, 30, 0 ) ), + new( new SourceBlock( 21, 0, 3 ), new SourceBlock( 20, 24, 0 ) ), + new( new SourceBlock( 21, 0, 4 ), new SourceBlock( 17, 31, 1 ) ), + new( new SourceBlock( 22, 0, 3 ), new SourceBlock( 17, 31, 0 ) ), + new( new SourceBlock( 22, 0, 2 ), new SourceBlock( 17, 31, 1 ) ), + new( new SourceBlock( 22, 0, 1 ), new SourceBlock( 18, 30, 1 ) ), + new( new SourceBlock( 22, 0, 0 ), new SourceBlock( 18, 30, 0 ) ), + new( new SourceBlock( 22, 0, 1 ), new SourceBlock( 18, 31, 1 ) ), + new( new SourceBlock( 22, 0, 2 ), new SourceBlock( 18, 31, 0 ) ), + new( new SourceBlock( 22, 0, 3 ), new SourceBlock( 20, 27, 0 ) ), + new( new SourceBlock( 22, 0, 4 ), new SourceBlock( 19, 30, 1 ) ), + new( new SourceBlock( 23, 0, 3 ), new SourceBlock( 19, 30, 0 ) ), + new( new SourceBlock( 23, 0, 2 ), new SourceBlock( 20, 28, 0 ) ), + new( new SourceBlock( 23, 0, 1 ), new SourceBlock( 19, 31, 1 ) ), + new( new SourceBlock( 23, 0, 0 ), new SourceBlock( 19, 31, 0 ) ), + new( new SourceBlock( 23, 0, 1 ), new SourceBlock( 19, 31, 1 ) ), + new( new SourceBlock( 23, 0, 2 ), new SourceBlock( 20, 30, 1 ) ), + new( new SourceBlock( 23, 0, 3 ), new SourceBlock( 20, 30, 0 ) ), + new( new SourceBlock( 23, 0, 4 ), new SourceBlock( 22, 27, 1 ) ), + new( new SourceBlock( 24, 0, 4 ), new SourceBlock( 22, 27, 0 ) ), + new( new SourceBlock( 24, 0, 3 ), new SourceBlock( 20, 31, 0 ) ), + new( new SourceBlock( 24, 0, 2 ), new SourceBlock( 21, 30, 1 ) ), + new( new SourceBlock( 24, 0, 1 ), new SourceBlock( 21, 30, 0 ) ), + new( new SourceBlock( 24, 0, 0 ), new SourceBlock( 24, 24, 0 ) ), + new( new SourceBlock( 24, 0, 1 ), new SourceBlock( 21, 31, 1 ) ), + new( new SourceBlock( 24, 0, 2 ), new SourceBlock( 21, 31, 0 ) ), + new( new SourceBlock( 24, 0, 3 ), new SourceBlock( 21, 31, 1 ) ), + new( new SourceBlock( 24, 0, 4 ), new SourceBlock( 22, 30, 1 ) ), + new( new SourceBlock( 25, 0, 3 ), new SourceBlock( 22, 30, 0 ) ), + new( new SourceBlock( 25, 0, 2 ), new SourceBlock( 22, 31, 1 ) ), + new( new SourceBlock( 25, 0, 1 ), new SourceBlock( 22, 31, 0 ) ), + new( new SourceBlock( 25, 0, 0 ), new SourceBlock( 24, 27, 0 ) ), + new( new SourceBlock( 25, 0, 1 ), new SourceBlock( 23, 30, 1 ) ), + new( new SourceBlock( 25, 0, 2 ), new SourceBlock( 23, 30, 0 ) ), + new( new SourceBlock( 25, 0, 3 ), new SourceBlock( 24, 28, 0 ) ), + new( new SourceBlock( 25, 0, 4 ), new SourceBlock( 23, 31, 1 ) ), + new( new SourceBlock( 26, 0, 3 ), new SourceBlock( 23, 31, 0 ) ), + new( new SourceBlock( 26, 0, 2 ), new SourceBlock( 23, 31, 1 ) ), + new( new SourceBlock( 26, 0, 1 ), new SourceBlock( 24, 30, 1 ) ), + new( new SourceBlock( 26, 0, 0 ), new SourceBlock( 24, 30, 0 ) ), + new( new SourceBlock( 26, 0, 1 ), new SourceBlock( 26, 27, 1 ) ), + new( new SourceBlock( 26, 0, 2 ), new SourceBlock( 26, 27, 0 ) ), + new( new SourceBlock( 26, 0, 3 ), new SourceBlock( 24, 31, 0 ) ), + new( new SourceBlock( 26, 0, 4 ), new SourceBlock( 25, 30, 1 ) ), + new( new SourceBlock( 27, 0, 3 ), new SourceBlock( 25, 30, 0 ) ), + new( new SourceBlock( 27, 0, 2 ), new SourceBlock( 28, 24, 0 ) ), + new( new SourceBlock( 27, 0, 1 ), new SourceBlock( 25, 31, 1 ) ), + new( new SourceBlock( 27, 0, 0 ), new SourceBlock( 25, 31, 0 ) ), + new( new SourceBlock( 27, 0, 1 ), new SourceBlock( 25, 31, 1 ) ), + new( new SourceBlock( 27, 0, 2 ), new SourceBlock( 26, 30, 1 ) ), + new( new SourceBlock( 27, 0, 3 ), new SourceBlock( 26, 30, 0 ) ), + new( new SourceBlock( 27, 0, 4 ), new SourceBlock( 26, 31, 1 ) ), + new( new SourceBlock( 28, 0, 4 ), new SourceBlock( 26, 31, 0 ) ), + new( new SourceBlock( 28, 0, 3 ), new SourceBlock( 28, 27, 0 ) ), + new( new SourceBlock( 28, 0, 2 ), new SourceBlock( 27, 30, 1 ) ), + new( new SourceBlock( 28, 0, 1 ), new SourceBlock( 27, 30, 0 ) ), + new( new SourceBlock( 28, 0, 0 ), new SourceBlock( 28, 28, 0 ) ), + new( new SourceBlock( 28, 0, 1 ), new SourceBlock( 27, 31, 1 ) ), + new( new SourceBlock( 28, 0, 2 ), new SourceBlock( 27, 31, 0 ) ), + new( new SourceBlock( 28, 0, 3 ), new SourceBlock( 27, 31, 1 ) ), + new( new SourceBlock( 28, 0, 4 ), new SourceBlock( 28, 30, 1 ) ), + new( new SourceBlock( 29, 0, 3 ), new SourceBlock( 28, 30, 0 ) ), + new( new SourceBlock( 29, 0, 2 ), new SourceBlock( 30, 27, 1 ) ), + new( new SourceBlock( 29, 0, 1 ), new SourceBlock( 30, 27, 0 ) ), + new( new SourceBlock( 29, 0, 0 ), new SourceBlock( 28, 31, 0 ) ), + new( new SourceBlock( 29, 0, 1 ), new SourceBlock( 29, 30, 1 ) ), + new( new SourceBlock( 29, 0, 2 ), new SourceBlock( 29, 30, 0 ) ), + new( new SourceBlock( 29, 0, 3 ), new SourceBlock( 29, 30, 1 ) ), + new( new SourceBlock( 29, 0, 4 ), new SourceBlock( 29, 31, 1 ) ), + new( new SourceBlock( 30, 0, 3 ), new SourceBlock( 29, 31, 0 ) ), + new( new SourceBlock( 30, 0, 2 ), new SourceBlock( 29, 31, 1 ) ), + new( new SourceBlock( 30, 0, 1 ), new SourceBlock( 30, 30, 1 ) ), + new( new SourceBlock( 30, 0, 0 ), new SourceBlock( 30, 30, 0 ) ), + new( new SourceBlock( 30, 0, 1 ), new SourceBlock( 30, 31, 1 ) ), + new( new SourceBlock( 30, 0, 2 ), new SourceBlock( 30, 31, 0 ) ), + new( new SourceBlock( 30, 0, 3 ), new SourceBlock( 30, 31, 1 ) ), + new( new SourceBlock( 30, 0, 4 ), new SourceBlock( 31, 30, 1 ) ), + new( new SourceBlock( 31, 0, 3 ), new SourceBlock( 31, 30, 0 ) ), + new( new SourceBlock( 31, 0, 2 ), new SourceBlock( 31, 30, 1 ) ), + new( new SourceBlock( 31, 0, 1 ), new SourceBlock( 31, 31, 1 ) ), + new( new SourceBlock( 31, 0, 0 ), new SourceBlock( 31, 31, 0 ) ) + ]; + + public static SingleColourLookup[] lookup_6_4 = + [ + new( new SourceBlock( 0, 0, 0 ), new SourceBlock( 0, 0, 0 ) ), + new( new SourceBlock( 0, 0, 1 ), new SourceBlock( 0, 1, 0 ) ), + new( new SourceBlock( 0, 0, 2 ), new SourceBlock( 0, 2, 0 ) ), + new( new SourceBlock( 1, 0, 1 ), new SourceBlock( 0, 3, 1 ) ), + new( new SourceBlock( 1, 0, 0 ), new SourceBlock( 0, 3, 0 ) ), + new( new SourceBlock( 1, 0, 1 ), new SourceBlock( 0, 4, 0 ) ), + new( new SourceBlock( 1, 0, 2 ), new SourceBlock( 0, 5, 0 ) ), + new( new SourceBlock( 2, 0, 1 ), new SourceBlock( 0, 6, 1 ) ), + new( new SourceBlock( 2, 0, 0 ), new SourceBlock( 0, 6, 0 ) ), + new( new SourceBlock( 2, 0, 1 ), new SourceBlock( 0, 7, 0 ) ), + new( new SourceBlock( 2, 0, 2 ), new SourceBlock( 0, 8, 0 ) ), + new( new SourceBlock( 3, 0, 1 ), new SourceBlock( 0, 9, 1 ) ), + new( new SourceBlock( 3, 0, 0 ), new SourceBlock( 0, 9, 0 ) ), + new( new SourceBlock( 3, 0, 1 ), new SourceBlock( 0, 10, 0 ) ), + new( new SourceBlock( 3, 0, 2 ), new SourceBlock( 0, 11, 0 ) ), + new( new SourceBlock( 4, 0, 1 ), new SourceBlock( 0, 12, 1 ) ), + new( new SourceBlock( 4, 0, 0 ), new SourceBlock( 0, 12, 0 ) ), + new( new SourceBlock( 4, 0, 1 ), new SourceBlock( 0, 13, 0 ) ), + new( new SourceBlock( 4, 0, 2 ), new SourceBlock( 0, 14, 0 ) ), + new( new SourceBlock( 5, 0, 1 ), new SourceBlock( 0, 15, 1 ) ), + new( new SourceBlock( 5, 0, 0 ), new SourceBlock( 0, 15, 0 ) ), + new( new SourceBlock( 5, 0, 1 ), new SourceBlock( 0, 16, 0 ) ), + new( new SourceBlock( 5, 0, 2 ), new SourceBlock( 1, 15, 0 ) ), + new( new SourceBlock( 6, 0, 1 ), new SourceBlock( 0, 17, 0 ) ), + new( new SourceBlock( 6, 0, 0 ), new SourceBlock( 0, 18, 0 ) ), + new( new SourceBlock( 6, 0, 1 ), new SourceBlock( 0, 19, 0 ) ), + new( new SourceBlock( 6, 0, 2 ), new SourceBlock( 3, 14, 0 ) ), + new( new SourceBlock( 7, 0, 1 ), new SourceBlock( 0, 20, 0 ) ), + new( new SourceBlock( 7, 0, 0 ), new SourceBlock( 0, 21, 0 ) ), + new( new SourceBlock( 7, 0, 1 ), new SourceBlock( 0, 22, 0 ) ), + new( new SourceBlock( 7, 0, 2 ), new SourceBlock( 4, 15, 0 ) ), + new( new SourceBlock( 8, 0, 1 ), new SourceBlock( 0, 23, 0 ) ), + new( new SourceBlock( 8, 0, 0 ), new SourceBlock( 0, 24, 0 ) ), + new( new SourceBlock( 8, 0, 1 ), new SourceBlock( 0, 25, 0 ) ), + new( new SourceBlock( 8, 0, 2 ), new SourceBlock( 6, 14, 0 ) ), + new( new SourceBlock( 9, 0, 1 ), new SourceBlock( 0, 26, 0 ) ), + new( new SourceBlock( 9, 0, 0 ), new SourceBlock( 0, 27, 0 ) ), + new( new SourceBlock( 9, 0, 1 ), new SourceBlock( 0, 28, 0 ) ), + new( new SourceBlock( 9, 0, 2 ), new SourceBlock( 7, 15, 0 ) ), + new( new SourceBlock( 10, 0, 1 ), new SourceBlock( 0, 29, 0 ) ), + new( new SourceBlock( 10, 0, 0 ), new SourceBlock( 0, 30, 0 ) ), + new( new SourceBlock( 10, 0, 1 ), new SourceBlock( 0, 31, 0 ) ), + new( new SourceBlock( 10, 0, 2 ), new SourceBlock( 9, 14, 0 ) ), + new( new SourceBlock( 11, 0, 1 ), new SourceBlock( 0, 32, 0 ) ), + new( new SourceBlock( 11, 0, 0 ), new SourceBlock( 0, 33, 0 ) ), + new( new SourceBlock( 11, 0, 1 ), new SourceBlock( 2, 30, 0 ) ), + new( new SourceBlock( 11, 0, 2 ), new SourceBlock( 0, 34, 0 ) ), + new( new SourceBlock( 12, 0, 1 ), new SourceBlock( 0, 35, 0 ) ), + new( new SourceBlock( 12, 0, 0 ), new SourceBlock( 0, 36, 0 ) ), + new( new SourceBlock( 12, 0, 1 ), new SourceBlock( 3, 31, 0 ) ), + new( new SourceBlock( 12, 0, 2 ), new SourceBlock( 0, 37, 0 ) ), + new( new SourceBlock( 13, 0, 1 ), new SourceBlock( 0, 38, 0 ) ), + new( new SourceBlock( 13, 0, 0 ), new SourceBlock( 0, 39, 0 ) ), + new( new SourceBlock( 13, 0, 1 ), new SourceBlock( 5, 30, 0 ) ), + new( new SourceBlock( 13, 0, 2 ), new SourceBlock( 0, 40, 0 ) ), + new( new SourceBlock( 14, 0, 1 ), new SourceBlock( 0, 41, 0 ) ), + new( new SourceBlock( 14, 0, 0 ), new SourceBlock( 0, 42, 0 ) ), + new( new SourceBlock( 14, 0, 1 ), new SourceBlock( 6, 31, 0 ) ), + new( new SourceBlock( 14, 0, 2 ), new SourceBlock( 0, 43, 0 ) ), + new( new SourceBlock( 15, 0, 1 ), new SourceBlock( 0, 44, 0 ) ), + new( new SourceBlock( 15, 0, 0 ), new SourceBlock( 0, 45, 0 ) ), + new( new SourceBlock( 15, 0, 1 ), new SourceBlock( 8, 30, 0 ) ), + new( new SourceBlock( 15, 0, 2 ), new SourceBlock( 0, 46, 0 ) ), + new( new SourceBlock( 16, 0, 2 ), new SourceBlock( 0, 47, 0 ) ), + new( new SourceBlock( 16, 0, 1 ), new SourceBlock( 1, 46, 0 ) ), + new( new SourceBlock( 16, 0, 0 ), new SourceBlock( 0, 48, 0 ) ), + new( new SourceBlock( 16, 0, 1 ), new SourceBlock( 0, 49, 0 ) ), + new( new SourceBlock( 16, 0, 2 ), new SourceBlock( 0, 50, 0 ) ), + new( new SourceBlock( 17, 0, 1 ), new SourceBlock( 2, 47, 0 ) ), + new( new SourceBlock( 17, 0, 0 ), new SourceBlock( 0, 51, 0 ) ), + new( new SourceBlock( 17, 0, 1 ), new SourceBlock( 0, 52, 0 ) ), + new( new SourceBlock( 17, 0, 2 ), new SourceBlock( 0, 53, 0 ) ), + new( new SourceBlock( 18, 0, 1 ), new SourceBlock( 4, 46, 0 ) ), + new( new SourceBlock( 18, 0, 0 ), new SourceBlock( 0, 54, 0 ) ), + new( new SourceBlock( 18, 0, 1 ), new SourceBlock( 0, 55, 0 ) ), + new( new SourceBlock( 18, 0, 2 ), new SourceBlock( 0, 56, 0 ) ), + new( new SourceBlock( 19, 0, 1 ), new SourceBlock( 5, 47, 0 ) ), + new( new SourceBlock( 19, 0, 0 ), new SourceBlock( 0, 57, 0 ) ), + new( new SourceBlock( 19, 0, 1 ), new SourceBlock( 0, 58, 0 ) ), + new( new SourceBlock( 19, 0, 2 ), new SourceBlock( 0, 59, 0 ) ), + new( new SourceBlock( 20, 0, 1 ), new SourceBlock( 7, 46, 0 ) ), + new( new SourceBlock( 20, 0, 0 ), new SourceBlock( 0, 60, 0 ) ), + new( new SourceBlock( 20, 0, 1 ), new SourceBlock( 0, 61, 0 ) ), + new( new SourceBlock( 20, 0, 2 ), new SourceBlock( 0, 62, 0 ) ), + new( new SourceBlock( 21, 0, 1 ), new SourceBlock( 8, 47, 0 ) ), + new( new SourceBlock( 21, 0, 0 ), new SourceBlock( 0, 63, 0 ) ), + new( new SourceBlock( 21, 0, 1 ), new SourceBlock( 1, 62, 0 ) ), + new( new SourceBlock( 21, 0, 2 ), new SourceBlock( 1, 63, 0 ) ), + new( new SourceBlock( 22, 0, 1 ), new SourceBlock( 10, 46, 0 ) ), + new( new SourceBlock( 22, 0, 0 ), new SourceBlock( 2, 62, 0 ) ), + new( new SourceBlock( 22, 0, 1 ), new SourceBlock( 2, 63, 0 ) ), + new( new SourceBlock( 22, 0, 2 ), new SourceBlock( 3, 62, 0 ) ), + new( new SourceBlock( 23, 0, 1 ), new SourceBlock( 11, 47, 0 ) ), + new( new SourceBlock( 23, 0, 0 ), new SourceBlock( 3, 63, 0 ) ), + new( new SourceBlock( 23, 0, 1 ), new SourceBlock( 4, 62, 0 ) ), + new( new SourceBlock( 23, 0, 2 ), new SourceBlock( 4, 63, 0 ) ), + new( new SourceBlock( 24, 0, 1 ), new SourceBlock( 13, 46, 0 ) ), + new( new SourceBlock( 24, 0, 0 ), new SourceBlock( 5, 62, 0 ) ), + new( new SourceBlock( 24, 0, 1 ), new SourceBlock( 5, 63, 0 ) ), + new( new SourceBlock( 24, 0, 2 ), new SourceBlock( 6, 62, 0 ) ), + new( new SourceBlock( 25, 0, 1 ), new SourceBlock( 14, 47, 0 ) ), + new( new SourceBlock( 25, 0, 0 ), new SourceBlock( 6, 63, 0 ) ), + new( new SourceBlock( 25, 0, 1 ), new SourceBlock( 7, 62, 0 ) ), + new( new SourceBlock( 25, 0, 2 ), new SourceBlock( 7, 63, 0 ) ), + new( new SourceBlock( 26, 0, 1 ), new SourceBlock( 16, 45, 0 ) ), + new( new SourceBlock( 26, 0, 0 ), new SourceBlock( 8, 62, 0 ) ), + new( new SourceBlock( 26, 0, 1 ), new SourceBlock( 8, 63, 0 ) ), + new( new SourceBlock( 26, 0, 2 ), new SourceBlock( 9, 62, 0 ) ), + new( new SourceBlock( 27, 0, 1 ), new SourceBlock( 16, 48, 0 ) ), + new( new SourceBlock( 27, 0, 0 ), new SourceBlock( 9, 63, 0 ) ), + new( new SourceBlock( 27, 0, 1 ), new SourceBlock( 10, 62, 0 ) ), + new( new SourceBlock( 27, 0, 2 ), new SourceBlock( 10, 63, 0 ) ), + new( new SourceBlock( 28, 0, 1 ), new SourceBlock( 16, 51, 0 ) ), + new( new SourceBlock( 28, 0, 0 ), new SourceBlock( 11, 62, 0 ) ), + new( new SourceBlock( 28, 0, 1 ), new SourceBlock( 11, 63, 0 ) ), + new( new SourceBlock( 28, 0, 2 ), new SourceBlock( 12, 62, 0 ) ), + new( new SourceBlock( 29, 0, 1 ), new SourceBlock( 16, 54, 0 ) ), + new( new SourceBlock( 29, 0, 0 ), new SourceBlock( 12, 63, 0 ) ), + new( new SourceBlock( 29, 0, 1 ), new SourceBlock( 13, 62, 0 ) ), + new( new SourceBlock( 29, 0, 2 ), new SourceBlock( 13, 63, 0 ) ), + new( new SourceBlock( 30, 0, 1 ), new SourceBlock( 16, 57, 0 ) ), + new( new SourceBlock( 30, 0, 0 ), new SourceBlock( 14, 62, 0 ) ), + new( new SourceBlock( 30, 0, 1 ), new SourceBlock( 14, 63, 0 ) ), + new( new SourceBlock( 30, 0, 2 ), new SourceBlock( 15, 62, 0 ) ), + new( new SourceBlock( 31, 0, 1 ), new SourceBlock( 16, 60, 0 ) ), + new( new SourceBlock( 31, 0, 0 ), new SourceBlock( 15, 63, 0 ) ), + new( new SourceBlock( 31, 0, 1 ), new SourceBlock( 24, 46, 0 ) ), + new( new SourceBlock( 31, 0, 2 ), new SourceBlock( 16, 62, 0 ) ), + new( new SourceBlock( 32, 0, 2 ), new SourceBlock( 16, 63, 0 ) ), + new( new SourceBlock( 32, 0, 1 ), new SourceBlock( 17, 62, 0 ) ), + new( new SourceBlock( 32, 0, 0 ), new SourceBlock( 25, 47, 0 ) ), + new( new SourceBlock( 32, 0, 1 ), new SourceBlock( 17, 63, 0 ) ), + new( new SourceBlock( 32, 0, 2 ), new SourceBlock( 18, 62, 0 ) ), + new( new SourceBlock( 33, 0, 1 ), new SourceBlock( 18, 63, 0 ) ), + new( new SourceBlock( 33, 0, 0 ), new SourceBlock( 27, 46, 0 ) ), + new( new SourceBlock( 33, 0, 1 ), new SourceBlock( 19, 62, 0 ) ), + new( new SourceBlock( 33, 0, 2 ), new SourceBlock( 19, 63, 0 ) ), + new( new SourceBlock( 34, 0, 1 ), new SourceBlock( 20, 62, 0 ) ), + new( new SourceBlock( 34, 0, 0 ), new SourceBlock( 28, 47, 0 ) ), + new( new SourceBlock( 34, 0, 1 ), new SourceBlock( 20, 63, 0 ) ), + new( new SourceBlock( 34, 0, 2 ), new SourceBlock( 21, 62, 0 ) ), + new( new SourceBlock( 35, 0, 1 ), new SourceBlock( 21, 63, 0 ) ), + new( new SourceBlock( 35, 0, 0 ), new SourceBlock( 30, 46, 0 ) ), + new( new SourceBlock( 35, 0, 1 ), new SourceBlock( 22, 62, 0 ) ), + new( new SourceBlock( 35, 0, 2 ), new SourceBlock( 22, 63, 0 ) ), + new( new SourceBlock( 36, 0, 1 ), new SourceBlock( 23, 62, 0 ) ), + new( new SourceBlock( 36, 0, 0 ), new SourceBlock( 31, 47, 0 ) ), + new( new SourceBlock( 36, 0, 1 ), new SourceBlock( 23, 63, 0 ) ), + new( new SourceBlock( 36, 0, 2 ), new SourceBlock( 24, 62, 0 ) ), + new( new SourceBlock( 37, 0, 1 ), new SourceBlock( 24, 63, 0 ) ), + new( new SourceBlock( 37, 0, 0 ), new SourceBlock( 32, 47, 0 ) ), + new( new SourceBlock( 37, 0, 1 ), new SourceBlock( 25, 62, 0 ) ), + new( new SourceBlock( 37, 0, 2 ), new SourceBlock( 25, 63, 0 ) ), + new( new SourceBlock( 38, 0, 1 ), new SourceBlock( 26, 62, 0 ) ), + new( new SourceBlock( 38, 0, 0 ), new SourceBlock( 32, 50, 0 ) ), + new( new SourceBlock( 38, 0, 1 ), new SourceBlock( 26, 63, 0 ) ), + new( new SourceBlock( 38, 0, 2 ), new SourceBlock( 27, 62, 0 ) ), + new( new SourceBlock( 39, 0, 1 ), new SourceBlock( 27, 63, 0 ) ), + new( new SourceBlock( 39, 0, 0 ), new SourceBlock( 32, 53, 0 ) ), + new( new SourceBlock( 39, 0, 1 ), new SourceBlock( 28, 62, 0 ) ), + new( new SourceBlock( 39, 0, 2 ), new SourceBlock( 28, 63, 0 ) ), + new( new SourceBlock( 40, 0, 1 ), new SourceBlock( 29, 62, 0 ) ), + new( new SourceBlock( 40, 0, 0 ), new SourceBlock( 32, 56, 0 ) ), + new( new SourceBlock( 40, 0, 1 ), new SourceBlock( 29, 63, 0 ) ), + new( new SourceBlock( 40, 0, 2 ), new SourceBlock( 30, 62, 0 ) ), + new( new SourceBlock( 41, 0, 1 ), new SourceBlock( 30, 63, 0 ) ), + new( new SourceBlock( 41, 0, 0 ), new SourceBlock( 32, 59, 0 ) ), + new( new SourceBlock( 41, 0, 1 ), new SourceBlock( 31, 62, 0 ) ), + new( new SourceBlock( 41, 0, 2 ), new SourceBlock( 31, 63, 0 ) ), + new( new SourceBlock( 42, 0, 1 ), new SourceBlock( 32, 61, 0 ) ), + new( new SourceBlock( 42, 0, 0 ), new SourceBlock( 32, 62, 0 ) ), + new( new SourceBlock( 42, 0, 1 ), new SourceBlock( 32, 63, 0 ) ), + new( new SourceBlock( 42, 0, 2 ), new SourceBlock( 41, 46, 0 ) ), + new( new SourceBlock( 43, 0, 1 ), new SourceBlock( 33, 62, 0 ) ), + new( new SourceBlock( 43, 0, 0 ), new SourceBlock( 33, 63, 0 ) ), + new( new SourceBlock( 43, 0, 1 ), new SourceBlock( 34, 62, 0 ) ), + new( new SourceBlock( 43, 0, 2 ), new SourceBlock( 42, 47, 0 ) ), + new( new SourceBlock( 44, 0, 1 ), new SourceBlock( 34, 63, 0 ) ), + new( new SourceBlock( 44, 0, 0 ), new SourceBlock( 35, 62, 0 ) ), + new( new SourceBlock( 44, 0, 1 ), new SourceBlock( 35, 63, 0 ) ), + new( new SourceBlock( 44, 0, 2 ), new SourceBlock( 44, 46, 0 ) ), + new( new SourceBlock( 45, 0, 1 ), new SourceBlock( 36, 62, 0 ) ), + new( new SourceBlock( 45, 0, 0 ), new SourceBlock( 36, 63, 0 ) ), + new( new SourceBlock( 45, 0, 1 ), new SourceBlock( 37, 62, 0 ) ), + new( new SourceBlock( 45, 0, 2 ), new SourceBlock( 45, 47, 0 ) ), + new( new SourceBlock( 46, 0, 1 ), new SourceBlock( 37, 63, 0 ) ), + new( new SourceBlock( 46, 0, 0 ), new SourceBlock( 38, 62, 0 ) ), + new( new SourceBlock( 46, 0, 1 ), new SourceBlock( 38, 63, 0 ) ), + new( new SourceBlock( 46, 0, 2 ), new SourceBlock( 47, 46, 0 ) ), + new( new SourceBlock( 47, 0, 1 ), new SourceBlock( 39, 62, 0 ) ), + new( new SourceBlock( 47, 0, 0 ), new SourceBlock( 39, 63, 0 ) ), + new( new SourceBlock( 47, 0, 1 ), new SourceBlock( 40, 62, 0 ) ), + new( new SourceBlock( 47, 0, 2 ), new SourceBlock( 48, 46, 0 ) ), + new( new SourceBlock( 48, 0, 2 ), new SourceBlock( 40, 63, 0 ) ), + new( new SourceBlock( 48, 0, 1 ), new SourceBlock( 41, 62, 0 ) ), + new( new SourceBlock( 48, 0, 0 ), new SourceBlock( 41, 63, 0 ) ), + new( new SourceBlock( 48, 0, 1 ), new SourceBlock( 48, 49, 0 ) ), + new( new SourceBlock( 48, 0, 2 ), new SourceBlock( 42, 62, 0 ) ), + new( new SourceBlock( 49, 0, 1 ), new SourceBlock( 42, 63, 0 ) ), + new( new SourceBlock( 49, 0, 0 ), new SourceBlock( 43, 62, 0 ) ), + new( new SourceBlock( 49, 0, 1 ), new SourceBlock( 48, 52, 0 ) ), + new( new SourceBlock( 49, 0, 2 ), new SourceBlock( 43, 63, 0 ) ), + new( new SourceBlock( 50, 0, 1 ), new SourceBlock( 44, 62, 0 ) ), + new( new SourceBlock( 50, 0, 0 ), new SourceBlock( 44, 63, 0 ) ), + new( new SourceBlock( 50, 0, 1 ), new SourceBlock( 48, 55, 0 ) ), + new( new SourceBlock( 50, 0, 2 ), new SourceBlock( 45, 62, 0 ) ), + new( new SourceBlock( 51, 0, 1 ), new SourceBlock( 45, 63, 0 ) ), + new( new SourceBlock( 51, 0, 0 ), new SourceBlock( 46, 62, 0 ) ), + new( new SourceBlock( 51, 0, 1 ), new SourceBlock( 48, 58, 0 ) ), + new( new SourceBlock( 51, 0, 2 ), new SourceBlock( 46, 63, 0 ) ), + new( new SourceBlock( 52, 0, 1 ), new SourceBlock( 47, 62, 0 ) ), + new( new SourceBlock( 52, 0, 0 ), new SourceBlock( 47, 63, 0 ) ), + new( new SourceBlock( 52, 0, 1 ), new SourceBlock( 48, 61, 0 ) ), + new( new SourceBlock( 52, 0, 2 ), new SourceBlock( 48, 62, 0 ) ), + new( new SourceBlock( 53, 0, 1 ), new SourceBlock( 56, 47, 0 ) ), + new( new SourceBlock( 53, 0, 0 ), new SourceBlock( 48, 63, 0 ) ), + new( new SourceBlock( 53, 0, 1 ), new SourceBlock( 49, 62, 0 ) ), + new( new SourceBlock( 53, 0, 2 ), new SourceBlock( 49, 63, 0 ) ), + new( new SourceBlock( 54, 0, 1 ), new SourceBlock( 58, 46, 0 ) ), + new( new SourceBlock( 54, 0, 0 ), new SourceBlock( 50, 62, 0 ) ), + new( new SourceBlock( 54, 0, 1 ), new SourceBlock( 50, 63, 0 ) ), + new( new SourceBlock( 54, 0, 2 ), new SourceBlock( 51, 62, 0 ) ), + new( new SourceBlock( 55, 0, 1 ), new SourceBlock( 59, 47, 0 ) ), + new( new SourceBlock( 55, 0, 0 ), new SourceBlock( 51, 63, 0 ) ), + new( new SourceBlock( 55, 0, 1 ), new SourceBlock( 52, 62, 0 ) ), + new( new SourceBlock( 55, 0, 2 ), new SourceBlock( 52, 63, 0 ) ), + new( new SourceBlock( 56, 0, 1 ), new SourceBlock( 61, 46, 0 ) ), + new( new SourceBlock( 56, 0, 0 ), new SourceBlock( 53, 62, 0 ) ), + new( new SourceBlock( 56, 0, 1 ), new SourceBlock( 53, 63, 0 ) ), + new( new SourceBlock( 56, 0, 2 ), new SourceBlock( 54, 62, 0 ) ), + new( new SourceBlock( 57, 0, 1 ), new SourceBlock( 62, 47, 0 ) ), + new( new SourceBlock( 57, 0, 0 ), new SourceBlock( 54, 63, 0 ) ), + new( new SourceBlock( 57, 0, 1 ), new SourceBlock( 55, 62, 0 ) ), + new( new SourceBlock( 57, 0, 2 ), new SourceBlock( 55, 63, 0 ) ), + new( new SourceBlock( 58, 0, 1 ), new SourceBlock( 56, 62, 1 ) ), + new( new SourceBlock( 58, 0, 0 ), new SourceBlock( 56, 62, 0 ) ), + new( new SourceBlock( 58, 0, 1 ), new SourceBlock( 56, 63, 0 ) ), + new( new SourceBlock( 58, 0, 2 ), new SourceBlock( 57, 62, 0 ) ), + new( new SourceBlock( 59, 0, 1 ), new SourceBlock( 57, 63, 1 ) ), + new( new SourceBlock( 59, 0, 0 ), new SourceBlock( 57, 63, 0 ) ), + new( new SourceBlock( 59, 0, 1 ), new SourceBlock( 58, 62, 0 ) ), + new( new SourceBlock( 59, 0, 2 ), new SourceBlock( 58, 63, 0 ) ), + new( new SourceBlock( 60, 0, 1 ), new SourceBlock( 59, 62, 1 ) ), + new( new SourceBlock( 60, 0, 0 ), new SourceBlock( 59, 62, 0 ) ), + new( new SourceBlock( 60, 0, 1 ), new SourceBlock( 59, 63, 0 ) ), + new( new SourceBlock( 60, 0, 2 ), new SourceBlock( 60, 62, 0 ) ), + new( new SourceBlock( 61, 0, 1 ), new SourceBlock( 60, 63, 1 ) ), + new( new SourceBlock( 61, 0, 0 ), new SourceBlock( 60, 63, 0 ) ), + new( new SourceBlock( 61, 0, 1 ), new SourceBlock( 61, 62, 0 ) ), + new( new SourceBlock( 61, 0, 2 ), new SourceBlock( 61, 63, 0 ) ), + new( new SourceBlock( 62, 0, 1 ), new SourceBlock( 62, 62, 1 ) ), + new( new SourceBlock( 62, 0, 0 ), new SourceBlock( 62, 62, 0 ) ), + new( new SourceBlock( 62, 0, 1 ), new SourceBlock( 62, 63, 0 ) ), + new( new SourceBlock( 62, 0, 2 ), new SourceBlock( 63, 62, 0 ) ), + new( new SourceBlock( 63, 0, 1 ), new SourceBlock( 63, 63, 1 ) ), + new( new SourceBlock( 63, 0, 0 ), new SourceBlock( 63, 63, 0 ) ) + ]; +} diff --git a/BurnoutImage/Util.cs b/BurnoutImage/Util.cs index 0c5df37..b018e6f 100644 --- a/BurnoutImage/Util.cs +++ b/BurnoutImage/Util.cs @@ -1,110 +1,109 @@ using System; -namespace BurnoutImage +namespace BurnoutImage; + +internal static class Util { - internal static class Util + public static int FloatToInt(float a, int limit) + { + // use ANSI round-to-zero behaviour to get round-to-nearest + int i = (int)(a + 0.5f); + + // clamp to the limit + if (i < 0) + i = 0; + else if (i > limit) + i = limit; + + // done + return i; + } + + public static int FloatTo565(Vec3 colour) + { + // get the components in the correct range + int r = FloatToInt(31.0f * colour.X, 31); + int g = FloatToInt(63.0f * colour.X, 63); + int b = FloatToInt(31.0f * colour.X, 31); + + // pack into a single value + return (r << 11) | (g << 5) | b; + } + + // reverse byte order (16-bit) + public static ushort ReverseBytes(ushort value) + { + return (ushort)((value & 0xFFU) << 8 | (value & 0xFF00U) >> 8); + } + + // reverse byte order (32-bit) + public static uint ReverseBytes(uint value) + { + return (value & 0x000000FFU) << 24 | (value & 0x0000FF00U) << 8 | + (value & 0x00FF0000U) >> 8 | (value & 0xFF000000U) >> 24; + } + + // reverse byte order (64-bit) + public static ulong ReverseBytes(ulong value) { - public static int FloatToInt(float a, int limit) - { - // use ANSI round-to-zero behaviour to get round-to-nearest - int i = (int)(a + 0.5f); - - // clamp to the limit - if (i < 0) - i = 0; - else if (i > limit) - i = limit; - - // done - return i; - } - - public static int FloatTo565(Vec3 colour) - { - // get the components in the correct range - int r = FloatToInt(31.0f * colour.X, 31); - int g = FloatToInt(63.0f * colour.X, 63); - int b = FloatToInt(31.0f * colour.X, 31); - - // pack into a single value - return (r << 11) | (g << 5) | b; - } - - // reverse byte order (16-bit) - public static UInt16 ReverseBytes(UInt16 value) - { - return (UInt16)((value & 0xFFU) << 8 | (value & 0xFF00U) >> 8); - } - - // reverse byte order (32-bit) - public static UInt32 ReverseBytes(UInt32 value) - { - return (value & 0x000000FFU) << 24 | (value & 0x0000FF00U) << 8 | - (value & 0x00FF0000U) >> 8 | (value & 0xFF000000U) >> 24; - } - - // reverse byte order (64-bit) - public static UInt64 ReverseBytes(UInt64 value) - { - return (value & 0x00000000000000FFUL) << 56 | (value & 0x000000000000FF00UL) << 40 | - (value & 0x0000000000FF0000UL) << 24 | (value & 0x00000000FF000000UL) << 8 | - (value & 0x000000FF00000000UL) >> 8 | (value & 0x0000FF0000000000UL) >> 24 | - (value & 0x00FF000000000000UL) >> 40 | (value & 0xFF00000000000000UL) >> 56; - } - - // reverse byte order (16-bit) - public static Int16 ReverseBytes(Int16 value) - { - UInt16 v = (UInt16)value; - return (Int16)((v & 0xFFU) << 8 | (v & 0xFF00U) >> 8); - } - - // reverse byte order (32-bit) - public static Int32 ReverseBytes(Int32 value) - { - UInt32 v = (UInt32)value; - return (Int32)((v & 0x000000FFU) << 24 | (v & 0x0000FF00U) << 8 | - (v & 0x00FF0000U) >> 8 | (v & 0xFF000000U) >> 24); - } - - // reverse byte order (64-bit) - public static Int64 ReverseBytes(Int64 value) - { - UInt64 v = (UInt64)value; - return (Int64)((v & 0x00000000000000FFUL) << 56 | (v & 0x000000000000FF00UL) << 40 | - (v & 0x0000000000FF0000UL) << 24 | (v & 0x00000000FF000000UL) << 8 | - (v & 0x000000FF00000000UL) >> 8 | (v & 0x0000FF0000000000UL) >> 24 | - (v & 0x00FF000000000000UL) >> 40 | (v & 0xFF00000000000000UL) >> 56); - } + return (value & 0x00000000000000FFUL) << 56 | (value & 0x000000000000FF00UL) << 40 | + (value & 0x0000000000FF0000UL) << 24 | (value & 0x00000000FF000000UL) << 8 | + (value & 0x000000FF00000000UL) >> 8 | (value & 0x0000FF0000000000UL) >> 24 | + (value & 0x00FF000000000000UL) >> 40 | (value & 0xFF00000000000000UL) >> 56; } - internal struct Vec3 + // reverse byte order (16-bit) + public static short ReverseBytes(short value) { - public float X, Y, Z; + ushort v = (ushort)value; + return (short)((v & 0xFFU) << 8 | (v & 0xFF00U) >> 8); + } + + // reverse byte order (32-bit) + public static int ReverseBytes(int value) + { + uint v = (uint)value; + return (int)((v & 0x000000FFU) << 24 | (v & 0x0000FF00U) << 8 | + (v & 0x00FF0000U) >> 8 | (v & 0xFF000000U) >> 24); + } + + // reverse byte order (64-bit) + public static long ReverseBytes(long value) + { + ulong v = (ulong)value; + return (long)((v & 0x00000000000000FFUL) << 56 | (v & 0x000000000000FF00UL) << 40 | + (v & 0x0000000000FF0000UL) << 24 | (v & 0x00000000FF000000UL) << 8 | + (v & 0x000000FF00000000UL) >> 8 | (v & 0x0000FF0000000000UL) >> 24 | + (v & 0x00FF000000000000UL) >> 40 | (v & 0xFF00000000000000UL) >> 56); + } +} - public Vec3(float x, float y, float z) - { - X = x; - Y = y; - Z = z; - } +internal struct Vec3 +{ + public float X, Y, Z; + + public Vec3(float x, float y, float z) + { + X = x; + Y = y; + Z = z; + } - public Vec3(float xyz) : this(xyz, xyz, xyz) - { + public Vec3(float xyz) : this(xyz, xyz, xyz) + { - } } +} + +internal struct Vec4 +{ + public float X, Y, Z, W; - internal struct Vec4 + public Vec4(float x, float y, float z, float w) { - public float X, Y, Z, W; - - public Vec4(float x, float y, float z, float w) - { - X = x; - Y = y; - Z = z; - W = w; - } + X = x; + Y = y; + Z = z; + W = w; } } diff --git a/ComponentTester/Program.cs b/ComponentTester/Program.cs index 8c64f6e..bd44b0d 100644 --- a/ComponentTester/Program.cs +++ b/ComponentTester/Program.cs @@ -1,21 +1,20 @@ using System; using System.Windows.Forms; -namespace ComponentTester +namespace ComponentTester; + +static class Program { - static class Program + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() { - /// - /// The main entry point for the application. - /// - [STAThread] - static void Main() - { - Application.EnableVisualStyles(); - Application.SetHighDpiMode(HighDpiMode.SystemAware); - Application.SetCompatibleTextRenderingDefault(false); - - Application.Run(new Tester()); - } + Application.EnableVisualStyles(); + Application.SetHighDpiMode(HighDpiMode.SystemAware); + Application.SetCompatibleTextRenderingDefault(false); + + Application.Run(new Tester()); } } diff --git a/ComponentTester/Tester.cs b/ComponentTester/Tester.cs index 65525f9..4c8aa63 100644 --- a/ComponentTester/Tester.cs +++ b/ComponentTester/Tester.cs @@ -4,86 +4,85 @@ using System.IO; using System.Windows.Forms; -namespace ComponentTester +namespace ComponentTester; + +public partial class Tester : Form { - public partial class Tester : Form + public Tester() { - public Tester() - { - InitializeComponent(); - } - - private void New() - { - - } + InitializeComponent(); + } - private void Open() - { - OpenFileDialog ofd = new OpenFileDialog(); - ofd.Filter = "All Files|*.*"; - ofd.FileOk += Ofd_FileOk; - ofd.ShowDialog(this); - } + private void New() + { - private void Ofd_FileOk(object sender, CancelEventArgs e) - { - OpenFileDialog ofd = (OpenFileDialog)sender; + } - if (ofd.FileName == null || ofd.FileName.Length <= 0 || !File.Exists(ofd.FileName)) - return; + private void Open() + { + OpenFileDialog ofd = new(); + ofd.Filter = "All Files|*.*"; + ofd.FileOk += Ofd_FileOk; + ofd.ShowDialog(this); + } - Stream s = ofd.OpenFile(); - BinaryReader br = new BinaryReader(s); - List bytes = new List(); - while (br.BaseStream.Position < br.BaseStream.Length) - { - bytes.Add(br.ReadByte()); - } - br.Close(); + private void Ofd_FileOk(object sender, CancelEventArgs e) + { + OpenFileDialog ofd = (OpenFileDialog)sender; - hexView1.HexData = bytes.ToArray(); - } + if (ofd.FileName == null || ofd.FileName.Length <= 0 || !File.Exists(ofd.FileName)) + return; - private void Save() + Stream s = ofd.OpenFile(); + BinaryReader br = new(s); + List bytes = []; + while (br.BaseStream.Position < br.BaseStream.Length) { - // Temp - SaveAs(); + bytes.Add(br.ReadByte()); } + br.Close(); - private void SaveAs() - { + hexView1.HexData = [.. bytes]; + } - } + private void Save() + { + // Temp + SaveAs(); + } - private void Exit() - { - Application.Exit(); - } + private void SaveAs() + { - private void newToolStripMenuItem_Click(object sender, EventArgs e) - { - New(); - } + } - private void openToolStripMenuItem_Click(object sender, EventArgs e) - { - Open(); - } + private void Exit() + { + Application.Exit(); + } - private void saveToolStripMenuItem_Click(object sender, EventArgs e) - { - Save(); - } + private void newToolStripMenuItem_Click(object sender, EventArgs e) + { + New(); + } - private void saveAsToolStripMenuItem_Click(object sender, EventArgs e) - { - SaveAs(); - } + private void openToolStripMenuItem_Click(object sender, EventArgs e) + { + Open(); + } - private void exitToolStripMenuItem_Click(object sender, EventArgs e) - { - Exit(); - } + private void saveToolStripMenuItem_Click(object sender, EventArgs e) + { + Save(); + } + + private void saveAsToolStripMenuItem_Click(object sender, EventArgs e) + { + SaveAs(); + } + + private void exitToolStripMenuItem_Click(object sender, EventArgs e) + { + Exit(); } } diff --git a/HexEditor/HexView.cs b/HexEditor/HexView.cs index 4a6e670..54a2112 100644 --- a/HexEditor/HexView.cs +++ b/HexEditor/HexView.cs @@ -4,140 +4,139 @@ using System.Text; using System.Windows.Forms; -namespace HexEditor +namespace HexEditor; + +public class HexView : UserControl { - public class HexView : UserControl + private byte[] _hexData; + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public byte[] HexData { - private byte[] _hexData; - [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] - public byte[] HexData + get { - get - { - return _hexData; - } - set + return _hexData; + } + set + { + _hexData = value; + if (_hexData != null) { - _hexData = value; - if (_hexData != null) - { - vScroll.Minimum = 0; - vScroll.Maximum = _hexData.Length / 16; - } - Invalidate(); + vScroll.Minimum = 0; + vScroll.Maximum = _hexData.Length / 16; } + Invalidate(); } + } - private VScrollBar vScroll; + private VScrollBar vScroll; - public HexView() - { - DoubleBuffered = true; + public HexView() + { + DoubleBuffered = true; - BorderStyle = BorderStyle.FixedSingle; + BorderStyle = BorderStyle.FixedSingle; - BackColor = Color.White; + BackColor = Color.White; - Width = 100; - Height = 100; + Width = 100; + Height = 100; - Font = new Font(FontFamily.GenericMonospace, 10, FontStyle.Regular, GraphicsUnit.Point); + Font = new Font(FontFamily.GenericMonospace, 10, FontStyle.Regular, GraphicsUnit.Point); - vScroll = new VScrollBar(); - vScroll.Dock = DockStyle.Right; - vScroll.Scroll += VScroll_Scroll; - Controls.Add(vScroll); + vScroll = new VScrollBar(); + vScroll.Dock = DockStyle.Right; + vScroll.Scroll += VScroll_Scroll; + Controls.Add(vScroll); - Click += HexView_Click; - } + Click += HexView_Click; + } - private void HexView_Click(object sender, EventArgs e) - { - Focus(); - } + private void HexView_Click(object sender, EventArgs e) + { + Focus(); + } - private void VScroll_Scroll(object sender, ScrollEventArgs e) - { - Invalidate(); - } + private void VScroll_Scroll(object sender, ScrollEventArgs e) + { + Invalidate(); + } - protected override void OnMouseWheel(MouseEventArgs e) - { - int min = vScroll.Minimum; - int max = vScroll.Maximum; - int val = vScroll.Value; - int delta = e.Delta; - if (delta < 0) - val += 1; - else if (delta > 0) - val -= 1; - if (val < 0) - val = 0; - else if (val > max) - val = max; - vScroll.Value = val; - - Invalidate(); - base.OnMouseWheel(e); - } + protected override void OnMouseWheel(MouseEventArgs e) + { + int min = vScroll.Minimum; + int max = vScroll.Maximum; + int val = vScroll.Value; + int delta = e.Delta; + if (delta < 0) + val += 1; + else if (delta > 0) + val -= 1; + if (val < 0) + val = 0; + else if (val > max) + val = max; + vScroll.Value = val; + + Invalidate(); + base.OnMouseWheel(e); + } - protected override void OnPaint(PaintEventArgs e) - { - base.OnPaint(e); + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); - Graphics g = e.Graphics; + Graphics g = e.Graphics; - if (HexData == null) - return; + if (HexData == null) + return; - int padding = 5; - int separation = 5; + int padding = 5; + int separation = 5; - for (int i = 0; i < HexData.Length; i++) - { - float yVal = ((i / 16) * 14 + padding) - vScroll.Value * 14; - if (yVal > Height || yVal < 0) - continue; + for (int i = 0; i < HexData.Length; i++) + { + float yVal = ((i / 16) * 14 + padding) - vScroll.Value * 14; + if (yVal > Height || yVal < 0) + continue; - byte b = HexData[i]; + byte b = HexData[i]; - string byteString = b.ToString("X2"); - SizeF stringSize = g.MeasureString(byteString, Font); - float stringWidth = stringSize.Width + separation; - float stringHeight = stringSize.Height; + string byteString = b.ToString("X2"); + SizeF stringSize = g.MeasureString(byteString, Font); + float stringWidth = stringSize.Width + separation; + float stringHeight = stringSize.Height; - int x = i % 16; - int y = i / 16; + int x = i % 16; + int y = i / 16; - float xP = x * stringWidth + padding; - float yP = (y * stringHeight + padding) - vScroll.Value * stringHeight; + float xP = x * stringWidth + padding; + float yP = (y * stringHeight + padding) - vScroll.Value * stringHeight; - PointF point = new PointF(xP, yP); + PointF point = new(xP, yP); - g.DrawString(byteString, Font, Brushes.Black, point); + g.DrawString(byteString, Font, Brushes.Black, point); - string ascii = Encoding.ASCII.GetString(new byte[] { b }); - char aChar = ascii[0]; - if (char.IsControl(aChar)) - ascii = "."; + string ascii = Encoding.ASCII.GetString([b]); + char aChar = ascii[0]; + if (char.IsControl(aChar)) + ascii = "."; - SizeF stringSizeA = g.MeasureString(ascii, Font); - float stringWidthA = stringSizeA.Width; - float stringHeightA = stringSizeA.Height; + SizeF stringSizeA = g.MeasureString(ascii, Font); + float stringWidthA = stringSizeA.Width; + float stringHeightA = stringSizeA.Height; - float asciiXStart = 16 * stringWidth + padding; + float asciiXStart = 16 * stringWidth + padding; - float xPAscii = x * stringWidthA * 0.65f; + float xPAscii = x * stringWidthA * 0.65f; - PointF pointA = new PointF(xPAscii + asciiXStart, yP); + PointF pointA = new(xPAscii + asciiXStart, yP); - g.DrawString(ascii, Font, Brushes.Black, pointA); - } + g.DrawString(ascii, Font, Brushes.Black, pointA); } + } - protected override void OnPaintBackground(PaintEventArgs e) - { - base.OnPaintBackground(e); - } + protected override void OnPaintBackground(PaintEventArgs e) + { + base.OnPaintBackground(e); } } diff --git a/LangEditor/InputDialog.cs b/LangEditor/InputDialog.cs index dbe9dd2..9ca6245 100644 --- a/LangEditor/InputDialog.cs +++ b/LangEditor/InputDialog.cs @@ -1,51 +1,50 @@ using System; using System.Windows.Forms; -namespace LangEditor +namespace LangEditor; + +public partial class InputDialog : Form { - public partial class InputDialog : Form + public delegate void OnAccepted(string value); + public event OnAccepted Accepted; + + public InputDialog() + { + InitializeComponent(); + } + + private void btnAccept_Click(object sender, EventArgs e) + { + Accepted?.Invoke(txtInput.Text); + Close(); + } + + private void btnCancel_Click(object sender, EventArgs e) + { + Close(); + } + + public static string ShowInput(IWin32Window window, string question) { - public delegate void OnAccepted(string value); - public event OnAccepted Accepted; - - public InputDialog() - { - InitializeComponent(); - } - - private void btnAccept_Click(object sender, EventArgs e) - { - Accepted?.Invoke(txtInput.Text); - Close(); - } - - private void btnCancel_Click(object sender, EventArgs e) - { - Close(); - } - - public static string ShowInput(IWin32Window window, string question) - { - string response = null; - - InputDialog dialog = new InputDialog(); - dialog.lblQuestion.Text = question; - dialog.Accepted += value => response = value; - dialog.ShowDialog(window); - - return response; - } - - public static string ShowInput(string question) - { - string response = null; - - InputDialog dialog = new InputDialog(); - dialog.lblQuestion.Text = question; - dialog.Accepted += value => response = value; - dialog.ShowDialog(); - - return response; - } + string response = null; + + InputDialog dialog = new(); + dialog.lblQuestion.Text = question; + dialog.Accepted += value => response = value; + dialog.ShowDialog(window); + + return response; + } + + public static string ShowInput(string question) + { + string response = null; + + InputDialog dialog = new(); + dialog.lblQuestion.Text = question; + dialog.Accepted += value => response = value; + dialog.ShowDialog(); + + return response; } } diff --git a/LangEditor/LangEdit.cs b/LangEditor/LangEdit.cs index 41fea6a..ba616f0 100644 --- a/LangEditor/LangEdit.cs +++ b/LangEditor/LangEdit.cs @@ -7,310 +7,309 @@ using System.Text; using System.Windows.Forms; -namespace LangEditor -{ - public partial class LangEdit : Form, IEntryEditor - { - public delegate void OnChanged(); - public event OnChanged Changed; +namespace LangEditor; - private bool _ignoreChanges; +public partial class LangEdit : Form, IEntryEditor +{ + public delegate void OnChanged(); + public event OnChanged Changed; - private string searchVal; - private Dictionary dict; - private Language _lang; - [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] - public Language Lang - { - get => _lang; - set - { - _ignoreChanges = true; - _lang = value; - UpdateDisplay(); - _ignoreChanges = false; - } - } + private bool _ignoreChanges; - public LangEdit() + private string searchVal; + private Dictionary dict; + private Language _lang; + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public Language Lang + { + get => _lang; + set { _ignoreChanges = true; - InitializeComponent(); - GenerateDictionary(); + _lang = value; + UpdateDisplay(); _ignoreChanges = false; } + } - public void GenerateDictionary() + public LangEdit() + { + _ignoreChanges = true; + InitializeComponent(); + GenerateDictionary(); + _ignoreChanges = false; + } + + public void GenerateDictionary() + { + dict = []; + StreamReader keys = new(AppContext.BaseDirectory + "keys/keys.txt", Encoding.UTF8); + string key; + while ((key = keys.ReadLine()) != null) { - dict = new Dictionary(); - StreamReader keys = new StreamReader(AppContext.BaseDirectory + "keys/keys.txt", Encoding.UTF8); - string key; - while ((key = keys.ReadLine()) != null) + if (key.Contains("")]; + StreamReader subKeys = new(AppContext.BaseDirectory + "keys/" + subKeyFile + ".txt", Encoding.UTF8); + string subKey; + while ((subKey = subKeys.ReadLine()) != null) { - int subKeyFilePos = key.IndexOf("") - subKeyFilePos); - StreamReader subKeys = new StreamReader(AppContext.BaseDirectory + "keys/" + subKeyFile + ".txt", Encoding.UTF8); - string subKey; - while ((subKey = subKeys.ReadLine()) != null) + string fullSubKey = key.Replace(subKeyFile, subKey); // Replace file name with subkey + fullSubKey = fullSubKey.Remove(subKeyFilePos - 2, 2); // Remove + try { - string fullSubKey = key.Replace(subKeyFile, subKey); // Replace file name with subkey - fullSubKey = fullSubKey.Remove(subKeyFilePos - 2, 2); // Remove - try - { - dict.Add(Language.HashID(fullSubKey), fullSubKey); - } - catch - { - MessageBox.Show("ID " + fullSubKey + " (0x" + Language.HashID(fullSubKey).ToString("X8") + ") already exists.", "Error", MessageBoxButtons.OK); - continue; - } + dict.Add(Language.HashID(fullSubKey), fullSubKey); } - - subKeys.Close(); - - continue; - } - else if (key.Contains("") - subKeyRangePos); - int start = int.Parse(subKeyRange.Substring(0, subKeyRange.IndexOf('-'))); - int end = int.Parse(subKeyRange.Substring(subKeyRange.IndexOf('-') + 1)); - for (int i = start; i <= end; ++i) + catch { - string fullSubKey = key.Replace(subKeyRange, i.ToString()); - fullSubKey = fullSubKey.Remove(subKeyRangePos - 2, 2); // Remove - dict.Add(Language.HashID(fullSubKey), fullSubKey); + MessageBox.Show("ID " + fullSubKey + " (0x" + Language.HashID(fullSubKey).ToString("X8") + ") already exists.", "Error", MessageBoxButtons.OK); + continue; } } - dict.Add(Language.HashID(key), key); - } - - keys.Close(); - } + subKeys.Close(); - public void UpdateDisplay() - { - int resolved = 0, total = 0; - foreach (KeyValuePair entry in _lang.mpEntries) + continue; + } + else if (key.Contains("")]; + int start = int.Parse(subKeyRange[..subKeyRange.IndexOf('-')]); + int end = int.Parse(subKeyRange[(subKeyRange.IndexOf('-') + 1)..]); + for (int i = start; i <= end; ++i) { - dgvMain.Rows.Add("0x" + entry.Key.ToString("X8"), entry.Value); - total++; + string fullSubKey = key.Replace(subKeyRange, i.ToString()); + fullSubKey = fullSubKey.Remove(subKeyRangePos - 2, 2); // Remove + dict.Add(Language.HashID(fullSubKey), fullSubKey); } } - MessageBox.Show("Resolved " + resolved + "/" + total + " keys.", "Information", - MessageBoxButtons.OK); + + dict.Add(Language.HashID(key), key); } - public int RebuildLanguage() + keys.Close(); + } + + public void UpdateDisplay() + { + int resolved = 0, total = 0; + foreach (KeyValuePair entry in _lang.mpEntries) { - if (_ignoreChanges) - return 1; + if (dict.ContainsKey(entry.Key)) + { + dgvMain.Rows.Add(dict[entry.Key], entry.Value); + total++; + resolved++; + } + else + { + dgvMain.Rows.Add("0x" + entry.Key.ToString("X8"), entry.Value); + total++; + } + } + MessageBox.Show("Resolved " + resolved + "/" + total + " keys.", "Information", + MessageBoxButtons.OK); + } - Dictionary data = new Dictionary(); + public int RebuildLanguage() + { + if (_ignoreChanges) + return 1; - for (int i = 0; i < dgvMain.Rows.Count - 1; ++i) - { - string idString = (string)dgvMain.Rows[i].Cells[0].Value; + Dictionary data = []; - if (idString == null) - { - MessageBox.Show(this, "ID cannot be left blank", "Warning", - MessageBoxButtons.OK, MessageBoxIcon.Warning); - return 2; - } + for (int i = 0; i < dgvMain.Rows.Count - 1; ++i) + { + string idString = (string)dgvMain.Rows[i].Cells[0].Value; - uint id; - if (idString.StartsWith("0x") && idString.Length == 10) // Hash - { - if (!uint.TryParse(idString[2..], NumberStyles.AllowHexSpecifier, CultureInfo.CurrentCulture, out id)) - { - MessageBox.Show(this, "Failed to parse ID \"" + idString + "\"", "Warning", - MessageBoxButtons.OK, MessageBoxIcon.Warning); - return 3; - } - } - else // String - { - id = Language.HashID(idString); - } + if (idString == null) + { + MessageBox.Show(this, "ID cannot be left blank", "Warning", + MessageBoxButtons.OK, MessageBoxIcon.Warning); + return 2; + } - string value = (string)dgvMain.Rows[i].Cells[1].Value; - if (data.ContainsKey(id)) + uint id; + if (idString.StartsWith("0x") && idString.Length == 10) // Hash + { + if (!uint.TryParse(idString[2..], NumberStyles.AllowHexSpecifier, CultureInfo.CurrentCulture, out id)) { - MessageBox.Show(this, "ID " + idString + " already in use", "Warning", + MessageBox.Show(this, "Failed to parse ID \"" + idString + "\"", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return 4; + return 3; } - data.Add(id, value); + } + else // String + { + id = Language.HashID(idString); } - _lang.mpEntries = data; + string value = (string)dgvMain.Rows[i].Cells[1].Value; + if (data.ContainsKey(id)) + { + MessageBox.Show(this, "ID " + idString + " already in use", "Warning", + MessageBoxButtons.OK, MessageBoxIcon.Warning); + return 4; + } + data.Add(id, value); + } - Changed?.Invoke(); + _lang.mpEntries = data; - return 0; - } + Changed?.Invoke(); - private void importToolStripMenuItem_Click(object sender, EventArgs e) - { - OpenFileDialog openDialog = new OpenFileDialog(); - openDialog.Filter = "Column-separated values (*.csv)|*.csv|All files(*.*)|*.*"; - if (openDialog.ShowDialog() == DialogResult.Cancel) - return; + return 0; + } - Dictionary data = new Dictionary(); - StreamReader file = new StreamReader(openDialog.FileName, Encoding.UTF8); - string line; - while ((line = file.ReadLine()) != null) + private void importToolStripMenuItem_Click(object sender, EventArgs e) + { + OpenFileDialog openDialog = new(); + openDialog.Filter = "Column-separated values (*.csv)|*.csv|All files(*.*)|*.*"; + if (openDialog.ShowDialog() == DialogResult.Cancel) + return; + + Dictionary data = []; + StreamReader file = new(openDialog.FileName, Encoding.UTF8); + string line; + while ((line = file.ReadLine()) != null) + { + string[] pair = line.Split(',', 2); + pair[0] = pair[0][1..].Remove(pair[0].Length - 2, 1); // Remove quotes + uint key; + if (pair[0].StartsWith("0x") && pair[0].Length == 10) { - string[] pair = line.Split(',', 2); - pair[0] = pair[0].Remove(0, 1).Remove(pair[0].Length - 2, 1); // Remove quotes - uint key; - if (pair[0].StartsWith("0x") && pair[0].Length == 10) - { - if (!uint.TryParse(pair[0][2..], NumberStyles.AllowHexSpecifier, CultureInfo.CurrentCulture, out key)) - { - MessageBox.Show("Could not parse ID " + pair[0] + ". Import cancelled.", "Error", MessageBoxButtons.OK); - return; - } - } - else - key = Language.HashID(pair[0]); - - if (pair[1].Length != 0) // Non-empty value + if (!uint.TryParse(pair[0][2..], NumberStyles.AllowHexSpecifier, CultureInfo.CurrentCulture, out key)) { - pair[1] = pair[1].Substring(1, pair[1].Length - 2); // Remove enclosing double quotes - pair[1] = pair[1].Replace("\"\"", "\""); // Convert double quotes - pair[1] = pair[1].Replace("\\r", "\xD").Replace("\\n", "\xA"); // Convert newlines + MessageBox.Show("Could not parse ID " + pair[0] + ". Import cancelled.", "Error", MessageBoxButtons.OK); + return; } - - data.Add(key, pair[1]); } + else + key = Language.HashID(pair[0]); - _lang.mpEntries = data; + if (pair[1].Length != 0) // Non-empty value + { + pair[1] = pair[1][1..^1]; // Remove enclosing double quotes + pair[1] = pair[1].Replace("\"\"", "\""); // Convert double quotes + pair[1] = pair[1].Replace("\\r", "\xD").Replace("\\n", "\xA"); // Convert newlines + } - dgvMain.Rows.Clear(); - UpdateDisplay(); + data.Add(key, pair[1]); } - private void exportToolStripMenuItem_Click(object sender, EventArgs e) - { - SaveFileDialog saveDialog = new SaveFileDialog(); - saveDialog.Filter = "Column-separated values (*.csv)|*.csv"; - if (saveDialog.ShowDialog() == DialogResult.Cancel) - return; + _lang.mpEntries = data; - // CSV content as a single contiguous string. - // Keys are prepended with 0x and padded to 8 characters. - // In values, incompatible characters are escaped. - // Both keys and values are enclosed in double quotes. - string languageContent = ""; - for (int i = 0; i < dgvMain.Rows.Count - 1; ++i) + dgvMain.Rows.Clear(); + UpdateDisplay(); + } + + private void exportToolStripMenuItem_Click(object sender, EventArgs e) + { + SaveFileDialog saveDialog = new(); + saveDialog.Filter = "Column-separated values (*.csv)|*.csv"; + if (saveDialog.ShowDialog() == DialogResult.Cancel) + return; + + // CSV content as a single contiguous string. + // Keys are prepended with 0x and padded to 8 characters. + // In values, incompatible characters are escaped. + // Both keys and values are enclosed in double quotes. + string languageContent = ""; + for (int i = 0; i < dgvMain.Rows.Count - 1; ++i) + { + languageContent += "\"" + (string)(dgvMain.Rows[i].Cells[0].Value) + "\","; + string tempValue = (string)dgvMain.Rows[i].Cells[1].Value; + tempValue = tempValue.Replace("\xD", "\\r").Replace("\xA", "\\n"); // Convert newlines + tempValue = tempValue.Replace("\"", "\"\""); // Convert double quotes + if (tempValue.Length != 0) // Enclose non-empty strings in double quotes { - languageContent += "\"" + (string)(dgvMain.Rows[i].Cells[0].Value) + "\","; - string tempValue = (string)dgvMain.Rows[i].Cells[1].Value; - tempValue = tempValue.Replace("\xD", "\\r").Replace("\xA", "\\n"); // Convert newlines - tempValue = tempValue.Replace("\"", "\"\""); // Convert double quotes - if (tempValue.Length != 0) // Enclose non-empty strings in double quotes - { - tempValue = "\"" + tempValue; - tempValue += "\""; - } - languageContent += tempValue + "\r\n"; + tempValue = "\"" + tempValue; + tempValue += "\""; } + languageContent += tempValue + "\r\n"; + } - FileStream file = (FileStream)saveDialog.OpenFile(); - file.Write(Encoding.UTF8.GetBytes(languageContent)); - file.Flush(); - file.Close(); + FileStream file = (FileStream)saveDialog.OpenFile(); + file.Write(Encoding.UTF8.GetBytes(languageContent)); + file.Flush(); + file.Close(); - MessageBox.Show("Export successful.", "Information", MessageBoxButtons.OK); - } + MessageBox.Show("Export successful.", "Information", MessageBoxButtons.OK); + } - private void applyChangesToolStripMenuItem_Click(object sender, EventArgs e) - { - int result = RebuildLanguage(); + private void applyChangesToolStripMenuItem_Click(object sender, EventArgs e) + { + int result = RebuildLanguage(); - if (result == 0) - MessageBox.Show(this, "Done!", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information); - } + if (result == 0) + MessageBox.Show(this, "Done!", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information); + } - private void findToolStripMenuItem_Click(object sender, EventArgs e) - { - string value = InputDialog.ShowInput(this, "Please enter the value to search for."); - if (value == null) - return; - searchVal = value; - findNextToolStripMenuItem.Enabled = true; + private void findToolStripMenuItem_Click(object sender, EventArgs e) + { + string value = InputDialog.ShowInput(this, "Please enter the value to search for."); + if (value == null) + return; + searchVal = value; + findNextToolStripMenuItem.Enabled = true; - foreach (DataGridViewRow row in dgvMain.Rows) + foreach (DataGridViewRow row in dgvMain.Rows) + { + if ((row.Cells[0].Value != null && ((string)row.Cells[0].Value).Contains(value, StringComparison.CurrentCultureIgnoreCase)) + || (row.Cells[1].Value != null && ((string)row.Cells[1].Value).Contains(value, StringComparison.CurrentCultureIgnoreCase))) { - if ((row.Cells[0].Value != null && ((string)row.Cells[0].Value).Contains(value, StringComparison.CurrentCultureIgnoreCase)) - || (row.Cells[1].Value != null && ((string)row.Cells[1].Value).Contains(value, StringComparison.CurrentCultureIgnoreCase))) - { - dgvMain.ClearSelection(); - dgvMain.CurrentCell = row.Cells[0]; - row.Selected = true; - return; - } + dgvMain.ClearSelection(); + dgvMain.CurrentCell = row.Cells[0]; + row.Selected = true; + return; } + } + MessageBox.Show(this, "Hash not found!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + } + + private void findNextToolStripMenuItem_Click(object sender, EventArgs e) + { + if (searchVal == null) + return; + int start = dgvMain.SelectedCells[0].RowIndex + 1; + if (start > dgvMain.Rows.Count - 1) + { MessageBox.Show(this, "Hash not found!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; } - - private void findNextToolStripMenuItem_Click(object sender, EventArgs e) + for (int i = start; i < dgvMain.Rows.Count - 1; ++i) { - if (searchVal == null) - return; - int start = dgvMain.SelectedCells[0].RowIndex + 1; - if (start > dgvMain.Rows.Count - 1) + if (((string)dgvMain.Rows[i].Cells[0].Value).Contains(searchVal, StringComparison.CurrentCultureIgnoreCase) + || ((string)dgvMain.Rows[i].Cells[1].Value).Contains(searchVal, StringComparison.CurrentCultureIgnoreCase)) { - MessageBox.Show(this, "Hash not found!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + dgvMain.ClearSelection(); + dgvMain.CurrentCell = dgvMain.Rows[i].Cells[0]; + dgvMain.Rows[i].Selected = true; return; } - for (int i = start; i < dgvMain.Rows.Count - 1; ++i) - { - if (((string)dgvMain.Rows[i].Cells[0].Value).Contains(searchVal, StringComparison.CurrentCultureIgnoreCase) - || ((string)dgvMain.Rows[i].Cells[1].Value).Contains(searchVal, StringComparison.CurrentCultureIgnoreCase)) - { - dgvMain.ClearSelection(); - dgvMain.CurrentCell = dgvMain.Rows[i].Cells[0]; - dgvMain.Rows[i].Selected = true; - return; - } - } - - MessageBox.Show(this, "Hash not found!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); } - private void hashToolStripMenuItem_Click(object sender, EventArgs e) - { - string value = InputDialog.ShowInput(this, "Please enter the value to hash."); - if (value == null) - return; - uint result = Language.HashID(value); + MessageBox.Show(this, "Hash not found!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + } - MessageBox.Show(this, "Hashed value is: " + result.ToString("X8"), "Information", - MessageBoxButtons.OK, MessageBoxIcon.Information); - } + private void hashToolStripMenuItem_Click(object sender, EventArgs e) + { + string value = InputDialog.ShowInput(this, "Please enter the value to hash."); + if (value == null) + return; + uint result = Language.HashID(value); - private void dgvMain_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e) - { - dgvMain.Rows[e.RowIndex].ReadOnly = false; - } + MessageBox.Show(this, "Hashed value is: " + result.ToString("X8"), "Information", + MessageBoxButtons.OK, MessageBoxIcon.Information); + } + + private void dgvMain_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e) + { + dgvMain.Rows[e.RowIndex].ReadOnly = false; } } diff --git a/LangEditor/LangPlugin.cs b/LangEditor/LangPlugin.cs index 8ccb527..14bec23 100644 --- a/LangEditor/LangPlugin.cs +++ b/LangEditor/LangPlugin.cs @@ -1,16 +1,15 @@ using BundleFormat; using PluginAPI; -namespace LangEditor +namespace LangEditor; + +public class LangPlugin : IPlugin { - public class LangPlugin : IPlugin - { - public string Id => "langplugin"; - public string Name => "Language Resource Handler"; + public string Id => "langplugin"; + public string Name => "Language Resource Handler"; - public static void Init() - { - EntryTypeRegistry.Register(EntryType.Language, new Language()); - } + public static void Init() + { + EntryTypeRegistry.Register(EntryType.Language, new Language()); } } diff --git a/LangEditor/Language.cs b/LangEditor/Language.cs index e77ce72..52af94f 100644 --- a/LangEditor/Language.cs +++ b/LangEditor/Language.cs @@ -6,179 +6,178 @@ using BundleUtilities; using PluginAPI; -namespace LangEditor +namespace LangEditor; + +public class Language : IEntryData { - public class Language : IEntryData + private enum LanguageId : uint { - private enum LanguageId : uint - { - E_LANGUAGE_ARABIC, - E_LANGUAGE_CHINESE, - E_LANGUAGE_CHINESE_SIMPLIFIED, - E_LANGUAGE_CHINESE_TRADITIONAL, - E_LANGUAGE_CZECH, - E_LANGUAGE_DANISH, - E_LANGUAGE_DUTCH, - E_LANGUAGE_ENGLISH_US, - E_LANGUAGE_ENGLISH_UK, - E_LANGUAGE_FINNISH, - E_LANGUAGE_FRENCH, - E_LANGUAGE_GERMAN, - E_LANGUAGE_GREEK, - E_LANGUAGE_HEBREW, - E_LANGUAGE_HUNGARIAN, - E_LANGUAGE_ITALIAN, - E_LANGUAGE_JAPANESE, - E_LANGUAGE_KOREAN, - E_LANGUAGE_NORWEGIAN, - E_LANGUAGE_POLISH, - E_LANGUAGE_PORTUGUESE_BRAZIL, - E_LANGUAGE_PORTUGUESE_PORTUGAL, - E_LANGUAGE_SPANISH, - E_LANGUAGE_SWEDISH, - E_LANGUAGE_THAI - } - - private LanguageId meLanguageID; - private uint muSize; // Number of entries - internal Dictionary mpEntries; - - public Language() - { - mpEntries = new Dictionary(); - } - - public bool Read(BundleEntry entry, ILoader loader = null) - { - mpEntries.Clear(); // Clear any entries from a previous Bundle + E_LANGUAGE_ARABIC, + E_LANGUAGE_CHINESE, + E_LANGUAGE_CHINESE_SIMPLIFIED, + E_LANGUAGE_CHINESE_TRADITIONAL, + E_LANGUAGE_CZECH, + E_LANGUAGE_DANISH, + E_LANGUAGE_DUTCH, + E_LANGUAGE_ENGLISH_US, + E_LANGUAGE_ENGLISH_UK, + E_LANGUAGE_FINNISH, + E_LANGUAGE_FRENCH, + E_LANGUAGE_GERMAN, + E_LANGUAGE_GREEK, + E_LANGUAGE_HEBREW, + E_LANGUAGE_HUNGARIAN, + E_LANGUAGE_ITALIAN, + E_LANGUAGE_JAPANESE, + E_LANGUAGE_KOREAN, + E_LANGUAGE_NORWEGIAN, + E_LANGUAGE_POLISH, + E_LANGUAGE_PORTUGUESE_BRAZIL, + E_LANGUAGE_PORTUGUESE_PORTUGAL, + E_LANGUAGE_SPANISH, + E_LANGUAGE_SWEDISH, + E_LANGUAGE_THAI + } + + private LanguageId meLanguageID; + private uint muSize; // Number of entries + internal Dictionary mpEntries; - MemoryStream ms = entry.MakeStream(); - BinaryReader2 br = new BinaryReader2(ms); - br.BigEndian = entry.Console; + public Language() + { + mpEntries = []; + } - bool x64 = entry.Platform == BundlePlatform.PCx64; + public bool Read(BundleEntry entry, ILoader loader = null) + { + mpEntries.Clear(); // Clear any entries from a previous Bundle - meLanguageID = (LanguageId)br.ReadUInt32(); - muSize = br.ReadUInt32(); - ms.Position = x64 ? (long)br.ReadUInt64() : br.ReadUInt32(); + MemoryStream ms = entry.MakeStream(); + BinaryReader2 br = new(ms); + br.BigEndian = entry.Console; - for (int i = 0; i < muSize; ++i) - { - uint hash = br.ReadUInt32(); - if (x64) - br.ReadUInt32(); // Padding - mpEntries.Add(hash, br.ReadCStringPtr()); - if (x64) - br.ReadUInt32(); // High half of the string pointer - } - mpEntries.Remove(0); // If padding is present, remove it + bool x64 = entry.Platform == BundlePlatform.PCx64; - br.Close(); + meLanguageID = (LanguageId)br.ReadUInt32(); + muSize = br.ReadUInt32(); + ms.Position = x64 ? (long)br.ReadUInt64() : br.ReadUInt32(); - return true; + for (int i = 0; i < muSize; ++i) + { + uint hash = br.ReadUInt32(); + if (x64) + br.ReadUInt32(); // Padding + mpEntries.Add(hash, br.ReadCStringPtr()); + if (x64) + br.ReadUInt32(); // High half of the string pointer } + mpEntries.Remove(0); // If padding is present, remove it - public bool Write(BundleEntry entry) - { - MemoryStream ms = new MemoryStream(); - BinaryWriter2 bw = new BinaryWriter2(ms); - bw.BigEndian = entry.Console; - - bool x64 = entry.Platform == BundlePlatform.PCx64; - int entriesPtr = x64 ? 0x10 : 0xC; - int entrySize = x64 ? 0x10 : 8; - - bw.Write((uint)meLanguageID); - bw.Write(mpEntries.Count); - if (x64) // Pointer is always the same - bw.Write((long)entriesPtr); - else - bw.Write(entriesPtr); + br.Close(); - // Write at entries position so string position calculations are not needed later - // and to avoid double iteration - ms.Position = mpEntries.Count * entrySize + entriesPtr - 1; - bw.Write((byte)0); - ms.Position = entriesPtr; + return true; + } - long lastPos; - foreach (KeyValuePair langEntry in mpEntries) + public bool Write(BundleEntry entry) + { + MemoryStream ms = new(); + BinaryWriter2 bw = new(ms); + bw.BigEndian = entry.Console; + + bool x64 = entry.Platform == BundlePlatform.PCx64; + int entriesPtr = x64 ? 0x10 : 0xC; + int entrySize = x64 ? 0x10 : 8; + + bw.Write((uint)meLanguageID); + bw.Write(mpEntries.Count); + if (x64) // Pointer is always the same + bw.Write((long)entriesPtr); + else + bw.Write(entriesPtr); + + // Write at entries position so string position calculations are not needed later + // and to avoid double iteration + ms.Position = mpEntries.Count * entrySize + entriesPtr - 1; + bw.Write((byte)0); + ms.Position = entriesPtr; + + long lastPos; + foreach (KeyValuePair langEntry in mpEntries) + { + bw.Write(langEntry.Key); // Hash + padding + if (x64) { - bw.Write(langEntry.Key); // Hash + padding - if (x64) - { - bw.Write(0); // Padding - bw.Write(ms.Length); // String pointer - } - else - bw.Write((uint)ms.Length); // String pointer - lastPos = ms.Position; - ms.Position = ms.Length; - if (langEntry.Value != null) - bw.Write(langEntry.Value.ToCharArray()); // String data - bw.Write((byte)0); // Null terminator - ms.Position = lastPos; + bw.Write(0); // Padding + bw.Write(ms.Length); // String pointer } - - bw.Flush(); + else + bw.Write((uint)ms.Length); // String pointer + lastPos = ms.Position; ms.Position = ms.Length; - bw.Align(0x10); - byte[] data = ms.ToArray(); - bw.Close(); + if (langEntry.Value != null) + bw.Write(langEntry.Value.ToCharArray()); // String data + bw.Write((byte)0); // Null terminator + ms.Position = lastPos; + } - entry.EntryBlocks[0].Data = data; - entry.Dirty = true; + bw.Flush(); + ms.Position = ms.Length; + bw.Align(0x10); + byte[] data = ms.ToArray(); + bw.Close(); - return true; - } + entry.EntryBlocks[0].Data = data; + entry.Dirty = true; - public EntryType GetEntryType(BundleEntry entry) - { - return EntryType.Language; - } + return true; + } - public IEntryEditor GetEditor(BundleEntry entry) + public EntryType GetEntryType(BundleEntry entry) + { + return EntryType.Language; + } + + public IEntryEditor GetEditor(BundleEntry entry) + { + LangEdit edit = new(); + edit.Lang = this; + edit.Changed += () => { - LangEdit edit = new LangEdit(); - edit.Lang = this; - edit.Changed += () => - { - edit.Lang.Write(entry); - }; + edit.Lang.Write(entry); + }; - return edit; - } + return edit; + } - public static uint HashID(string id) + public static uint HashID(string id) + { + /*uint result = 0xFFFFFFFF; + for (int i = 0; i < id.Length; i++) { - /*uint result = 0xFFFFFFFF; - for (int i = 0; i < id.Length; i++) - { - byte b = (byte)id[i]; - //if (b == 0) - // break; - byte newByte = (byte)((b - 0x41) & 0xFF); - if (newByte <= 0x19) - b += 0x20; - byte lowByte = (byte)(result & 0xFF); - lowByte = (byte)((lowByte ^ b) & 0xFF); - result = (result >> 8) & 0x00FFFFFF; - result = (result ^ Crc32.Crc32BTable[lowByte]) & 0xFFFFFFFF; - } - result = (~result) & 0xFFFFFFFF; - - return result;*/ + byte b = (byte)id[i]; + //if (b == 0) + // break; + byte newByte = (byte)((b - 0x41) & 0xFF); + if (newByte <= 0x19) + b += 0x20; + byte lowByte = (byte)(result & 0xFF); + lowByte = (byte)((lowByte ^ b) & 0xFF); + result = (result >> 8) & 0x00FFFFFF; + result = (result ^ Crc32.Crc32BTable[lowByte]) & 0xFFFFFFFF; + } + result = (~result) & 0xFFFFFFFF; - byte[] message = Encoding.UTF8.GetBytes(id); - UInt32 hash = UInt32.MaxValue; - for (UInt32 i = 0; i < message.Length; i++) - { - UInt32 index = message[i]; - index ^= (hash & 0x000000FF); - hash = Crc32.Crc32BTable[index] ^ (hash >> 8); - } + return result;*/ - return hash; + byte[] message = Encoding.UTF8.GetBytes(id); + uint hash = uint.MaxValue; + for (uint i = 0; i < message.Length; i++) + { + uint index = message[i]; + index ^= (hash & 0x000000FF); + hash = Crc32.Crc32BTable[index] ^ (hash >> 8); } + + return hash; } } diff --git a/LoopModel/LoopModelData.cs b/LoopModel/LoopModelData.cs index 7f88728..81b2cdf 100644 --- a/LoopModel/LoopModelData.cs +++ b/LoopModel/LoopModelData.cs @@ -6,470 +6,469 @@ using System.IO; using System.Windows.Forms; -namespace LoopModel +namespace LoopModel; + +public class LoopModelData : IEntryData { - public class LoopModelData : IEntryData + private const uint version = 7; + private const uint magic = 0x59444E41; + private bool is64Bit = false; + + private List _partials; + public List Partials { get => _partials; } + + public LoopModelData() { - private const UInt32 version = 7; - private const UInt32 magic = 0x59444E41; - private bool is64Bit = false; + _partials = []; + } - private List _partials; - public List Partials { get => _partials; } + public void Clear() + { + _partials.Clear(); + } + + public EntryType GetEntryType(BundleEntry entry) + { + return EntryType.LoopModel; + } - public LoopModelData() + public IEntryEditor GetEditor(BundleEntry entry) + { + LoopModelEditor loopModel = new(); + loopModel.Data = this; + loopModel.Edit += () => { - _partials = []; - } + Write(entry); + }; - public void Clear() + return loopModel; + } + + public bool Read(BundleEntry entry, ILoader loader = null) + { + Clear(); + + MemoryStream ms = new(entry.EntryBlocks[0].Data); + BinaryReader2 br = new(ms, entry.Console); + + bool x64 = entry.Platform == BundlePlatform.PCx64; + + uint versionCheck = br.ReadUInt32(); + if (versionCheck != version) { - _partials.Clear(); + MessageBox.Show("Unknown version: expected " + version.ToString() + ", got " + versionCheck.ToString(), "Failed to read resource", MessageBoxButtons.OK); + return false; } - - public EntryType GetEntryType(BundleEntry entry) + + uint magicCheck = br.ReadUInt32(); + if (magicCheck != magic) { - return EntryType.LoopModel; + MessageBox.Show("Unknown magic: expected 0x" + magic.ToString("X8") + ", got 0x" + magicCheck.ToString("X8"), "Failed to read resource", MessageBoxButtons.OK); + return false; } - public IEntryEditor GetEditor(BundleEntry entry) - { - LoopModelEditor loopModel = new(); - loopModel.Data = this; - loopModel.Edit += () => - { - Write(entry); - }; + uint partialsPointer = br.ReadUInt32(); - return loopModel; + // The above is actually 64-bit on some systems, but will never exceed 32-bit storage in practice. + // Use a hack to make reading/writing cross-platform under the assumption there are no loop models without partials. + uint numPartials = br.ReadUInt32(); + if (numPartials == 0) + { + numPartials = br.ReadUInt32(); + is64Bit = true; } - public bool Read(BundleEntry entry, ILoader loader = null) + // Game hardcodes the number of partials to be 10 + if (numPartials != 10) { - Clear(); - - MemoryStream ms = new(entry.EntryBlocks[0].Data); - BinaryReader2 br = new(ms, entry.Console); + MessageBox.Show("Incorrect number of partials: expected 10, got " + numPartials.ToString(), "Error"); + return false; + } - bool x64 = entry.Platform == BundlePlatform.PCx64; + // Read LoopModel data + for (int i = 0; i < numPartials; ++i) + { + br.BaseStream.Position = partialsPointer + i * (x64 ? 0x18 : is64Bit ? 0x10 : 0xC); + _partials.Add(new Partial(br, is64Bit, x64)); + } - UInt32 versionCheck = br.ReadUInt32(); - if (versionCheck != version) - { - MessageBox.Show("Unknown version: expected " + version.ToString() + ", got " + versionCheck.ToString(), "Failed to read resource", MessageBoxButtons.OK); - return false; - } + if (!CheckGraphErrors()) + return false; - UInt32 magicCheck = br.ReadUInt32(); - if (magicCheck != magic) + // Read Registry resource to obtain the wave hashes/strings + var registryResources = entry.Archive.Entries.FindAll(e => e.Type == EntryType.Registry); + if (registryResources.Count < 1 || registryResources.Count > 1) + { + MessageBox.Show("Expected 1 Registry resource, but " + registryResources.Count.ToString() + "were found.\n" + + "Partial names will fall back to hashes.", "Warning"); + foreach (Partial partial in _partials) + partial.SetWaveNameAsHash(); + } + else + { + Dictionary waveNameDict = GetRegistryWaveStringMap(registryResources[0]); + foreach (Partial partial in _partials) { - MessageBox.Show("Unknown magic: expected 0x" + magic.ToString("X8") + ", got 0x" + magicCheck.ToString("X8"), "Failed to read resource", MessageBoxButtons.OK); - return false; + if (waveNameDict.TryGetValue(partial.WaveNameHash, out string waveName)) + partial.SetWaveName(waveName); + else + partial.SetWaveNameAsHash(); // Should never be hit } + } - UInt32 partialsPointer = br.ReadUInt32(); - - // The above is actually 64-bit on some systems, but will never exceed 32-bit storage in practice. - // Use a hack to make reading/writing cross-platform under the assumption there are no loop models without partials. - UInt32 numPartials = br.ReadUInt32(); - if (numPartials == 0) - { - numPartials = br.ReadUInt32(); - is64Bit = true; - } + br.Close(); + ms.Close(); + return true; + } - // Game hardcodes the number of partials to be 10 - if (numPartials != 10) + private bool CheckGraphErrors() + { + for (int i = 0; i < _partials.Count; ++i) + { + // Game hardcodes the number of graphs in each partial to be 3 + if (_partials[i].Graphs.Count != 3) { - MessageBox.Show("Incorrect number of partials: expected 10, got " + numPartials.ToString(), "Error"); + MessageBox.Show("Incorrect number of graphs: expected 3, got " + _partials[i].Graphs.Count.ToString() + + "\nfor partial at index " + i.ToString(), "Error"); return false; } - // Read LoopModel data - for (int i = 0; i < numPartials; ++i) + for (int j = 0; j < _partials[i].Graphs.Count; ++j) { - br.BaseStream.Position = partialsPointer + i * (x64 ? 0x18 : is64Bit ? 0x10 : 0xC); - _partials.Add(new Partial(br, is64Bit, x64)); - } - - if (!CheckGraphErrors()) - return false; - - // Read Registry resource to obtain the wave hashes/strings - var registryResources = entry.Archive.Entries.FindAll(e => e.Type == EntryType.Registry); - if (registryResources.Count < 1 || registryResources.Count > 1) - { - MessageBox.Show("Expected 1 Registry resource, but " + registryResources.Count.ToString() + "were found.\n" - + "Partial names will fall back to hashes.", "Warning"); - foreach (Partial partial in _partials) - partial.SetWaveNameAsHash(); - } - else - { - Dictionary waveNameDict = GetRegistryWaveStringMap(registryResources[0]); - foreach (Partial partial in _partials) + // Game hardcodes the axes of each graph + if (j == 0 && _partials[i].Graphs[j].XAxis != 1) { - if (waveNameDict.TryGetValue(partial.WaveNameHash, out String waveName)) - partial.SetWaveName(waveName); - else - partial.SetWaveNameAsHash(); // Should never be hit + MessageBox.Show("Incorrect X axis on graph index " + j.ToString() + ", partial index " + i.ToString() + + "\nExpected 1 (E_RPM), got " + _partials[i].Graphs[j].XAxis.ToString(), "Error"); + return false; + } + if (j == 0 && _partials[i].Graphs[j].YAxis != 2) + { + MessageBox.Show("Incorrect Y axis on graph index " + j.ToString() + ", partial index " + i.ToString() + + "\nExpected 2 (E_PITCH), got " + _partials[i].Graphs[j].YAxis.ToString(), "Error"); + return false; + } + if (j == 1 && _partials[i].Graphs[j].XAxis != 1) + { + MessageBox.Show("Incorrect X axis on graph index " + j.ToString() + ", partial index " + i.ToString() + + "\nExpected 1 (E_RPM), got " + _partials[i].Graphs[j].XAxis.ToString(), "Error"); + return false; + } + if (j == 1 && _partials[i].Graphs[j].YAxis != 1) + { + MessageBox.Show("Incorrect Y axis on graph index " + j.ToString() + ", partial index " + i.ToString() + + "\nExpected 2 (E_GAIN), got " + _partials[i].Graphs[j].YAxis.ToString(), "Error"); + return false; + } + if (j == 2 && _partials[i].Graphs[j].XAxis != 3) + { + MessageBox.Show("Incorrect X axis on graph index " + j.ToString() + ", partial index " + i.ToString() + + "\nExpected 1 (E_ACCELERATOR), got " + _partials[i].Graphs[j].XAxis.ToString(), "Error"); + return false; + } + if (j == 2 && _partials[i].Graphs[j].YAxis != 1) + { + MessageBox.Show("Incorrect Y axis on graph index " + j.ToString() + ", partial index " + i.ToString() + + "\nExpected 1 (E_GAIN), got " + _partials[i].Graphs[j].YAxis.ToString(), "Error"); + return false; } - } - - br.Close(); - ms.Close(); - return true; - } - private bool CheckGraphErrors() - { - for (int i = 0; i < _partials.Count; ++i) - { - // Game hardcodes the number of graphs in each partial to be 3 - if (_partials[i].Graphs.Count != 3) + // Game hardcodes the number of points in Pitch/RPM graph as 2 + if (j == 0 && _partials[i].Graphs[j].Points.Count != 2) { - MessageBox.Show("Incorrect number of graphs: expected 3, got " + _partials[i].Graphs.Count.ToString() - + "\nfor partial at index " + i.ToString(), "Error"); + MessageBox.Show("Incorrect number of points in Pitch/RPM graph for partial at index " + i.ToString() + + "\nExpected 2, got " + _partials[i].Graphs[j].Points.Count.ToString()); return false; } - for (int j = 0; j < _partials[i].Graphs.Count; ++j) + // Game requires there to be more than 1 point in each graph + if (_partials[i].Graphs[j].Points.Count < 2) { - // Game hardcodes the axes of each graph - if (j == 0 && _partials[i].Graphs[j].XAxis != 1) - { - MessageBox.Show("Incorrect X axis on graph index " + j.ToString() + ", partial index " + i.ToString() - + "\nExpected 1 (E_RPM), got " + _partials[i].Graphs[j].XAxis.ToString(), "Error"); - return false; - } - if (j == 0 && _partials[i].Graphs[j].YAxis != 2) - { - MessageBox.Show("Incorrect Y axis on graph index " + j.ToString() + ", partial index " + i.ToString() - + "\nExpected 2 (E_PITCH), got " + _partials[i].Graphs[j].YAxis.ToString(), "Error"); - return false; - } - if (j == 1 && _partials[i].Graphs[j].XAxis != 1) - { - MessageBox.Show("Incorrect X axis on graph index " + j.ToString() + ", partial index " + i.ToString() - + "\nExpected 1 (E_RPM), got " + _partials[i].Graphs[j].XAxis.ToString(), "Error"); - return false; - } - if (j == 1 && _partials[i].Graphs[j].YAxis != 1) - { - MessageBox.Show("Incorrect Y axis on graph index " + j.ToString() + ", partial index " + i.ToString() - + "\nExpected 2 (E_GAIN), got " + _partials[i].Graphs[j].YAxis.ToString(), "Error"); - return false; - } - if (j == 2 && _partials[i].Graphs[j].XAxis != 3) - { - MessageBox.Show("Incorrect X axis on graph index " + j.ToString() + ", partial index " + i.ToString() - + "\nExpected 1 (E_ACCELERATOR), got " + _partials[i].Graphs[j].XAxis.ToString(), "Error"); - return false; - } - if (j == 2 && _partials[i].Graphs[j].YAxis != 1) - { - MessageBox.Show("Incorrect Y axis on graph index " + j.ToString() + ", partial index " + i.ToString() - + "\nExpected 1 (E_GAIN), got " + _partials[i].Graphs[j].YAxis.ToString(), "Error"); - return false; - } - - // Game hardcodes the number of points in Pitch/RPM graph as 2 - if (j == 0 && _partials[i].Graphs[j].Points.Count != 2) - { - MessageBox.Show("Incorrect number of points in Pitch/RPM graph for partial at index " + i.ToString() - + "\nExpected 2, got " + _partials[i].Graphs[j].Points.Count.ToString()); - return false; - } - - // Game requires there to be more than 1 point in each graph - if (_partials[i].Graphs[j].Points.Count < 2) - { - MessageBox.Show("Not enough points in graph " + j.ToString() + " in partial " + i.ToString() - + "\nAt least 2 required, but only " + _partials[i].Graphs[j].Points.Count.ToString() + " present", "Error"); - return false; - } + MessageBox.Show("Not enough points in graph " + j.ToString() + " in partial " + i.ToString() + + "\nAt least 2 required, but only " + _partials[i].Graphs[j].Points.Count.ToString() + " present", "Error"); + return false; } } - - return true; } - private Dictionary GetRegistryWaveStringMap(BundleEntry entry) - { - // Only works on 32-bit platforms except for decomp. (Not PS4/XB1/NX) - - MemoryStream ms = new(entry.EntryBlocks[0].Data); - BinaryReader2 br = new(ms, entry.Console); - Dictionary dict = new(); - - bool x64 = entry.Platform == BundlePlatform.PCx64; - long ReadPtr() => x64 ? br.ReadInt64() : br.ReadUInt32(); - - UInt32 entityCount = br.ReadUInt32(); - UInt32 entityCapacity = br.ReadUInt32(); - long entityDataSize = ReadPtr(); - long entityDataEnd = ReadPtr(); - long stringTableSize = ReadPtr(); - long stringTableEnd = ReadPtr(); - long nameHashMask = ReadPtr(); - List entityPointers = new((int)entityCount); - for (int i = 0; i < entityCapacity; ++i) - { - long ptr = ReadPtr(); - if (ptr != 0) - entityPointers.Add(ptr); - } - for (int i = 0; i < entityCount; ++i) - { - br.BaseStream.Position = entityPointers[i]; - UInt32 nameHash = br.ReadUInt32(); - UInt32 typeNameHash = br.ReadUInt32(); - if (typeNameHash != 0x511A448B) // ~ContentSpec~ - continue; - long contentTypeHash = ReadPtr(); - if (contentTypeHash != 0x7CCDA2E7) // ~GenericRwacWaveContent::SK_WAVE_DATA_CONTENT_TYPE~ - continue; - UInt16 pathLength = br.ReadUInt16(); - Byte loadMethod = br.ReadByte(); - Byte loadTime = br.ReadByte(); - String name = br.ReadLenString(pathLength); - if (name.Contains(".GinsuFile")) - continue; - dict.TryAdd(nameHash, name); // There will be duplicates that don't get added - } + return true; + } - return dict; + private Dictionary GetRegistryWaveStringMap(BundleEntry entry) + { + // Only works on 32-bit platforms except for decomp. (Not PS4/XB1/NX) + + MemoryStream ms = new(entry.EntryBlocks[0].Data); + BinaryReader2 br = new(ms, entry.Console); + Dictionary dict = []; + + bool x64 = entry.Platform == BundlePlatform.PCx64; + long ReadPtr() => x64 ? br.ReadInt64() : br.ReadUInt32(); + + uint entityCount = br.ReadUInt32(); + uint entityCapacity = br.ReadUInt32(); + long entityDataSize = ReadPtr(); + long entityDataEnd = ReadPtr(); + long stringTableSize = ReadPtr(); + long stringTableEnd = ReadPtr(); + long nameHashMask = ReadPtr(); + List entityPointers = new((int)entityCount); + for (int i = 0; i < entityCapacity; ++i) + { + long ptr = ReadPtr(); + if (ptr != 0) + entityPointers.Add(ptr); } + for (int i = 0; i < entityCount; ++i) + { + br.BaseStream.Position = entityPointers[i]; + uint nameHash = br.ReadUInt32(); + uint typeNameHash = br.ReadUInt32(); + if (typeNameHash != 0x511A448B) // ~ContentSpec~ + continue; + long contentTypeHash = ReadPtr(); + if (contentTypeHash != 0x7CCDA2E7) // ~GenericRwacWaveContent::SK_WAVE_DATA_CONTENT_TYPE~ + continue; + ushort pathLength = br.ReadUInt16(); + byte loadMethod = br.ReadByte(); + byte loadTime = br.ReadByte(); + string name = br.ReadLenString(pathLength); + if (name.Contains(".GinsuFile")) + continue; + dict.TryAdd(nameHash, name); // There will be duplicates that don't get added + } + + return dict; + } - public bool Write(BundleEntry entry) + public bool Write(BundleEntry entry) + { + MemoryStream ms = new(); + BinaryWriter2 bw = new(ms, entry.Console); + bool x64 = entry.Platform == BundlePlatform.PCx64; + + bw.Write(version); + bw.Write(magic); + int partialsPointer = is64Bit ? 0x18 : 0x14; + if (is64Bit) + bw.Write((long)partialsPointer); + else + bw.Write(partialsPointer); + bw.Write(_partials.Count); + + // Write partials without graphs pointers + int numPriorGraphs = 0; + int numPriorPoints = 0; + for (int i = 0; i < _partials.Count; ++i) { - MemoryStream ms = new(); - BinaryWriter2 bw = new(ms, entry.Console); - bool x64 = entry.Platform == BundlePlatform.PCx64; - - bw.Write(version); - bw.Write(magic); - Int32 partialsPointer = is64Bit ? 0x18 : 0x14; - if (is64Bit) - bw.Write((Int64)partialsPointer); - else - bw.Write(partialsPointer); - bw.Write(_partials.Count); - - // Write partials without graphs pointers - int numPriorGraphs = 0; - int numPriorPoints = 0; - for (int i = 0; i < _partials.Count; ++i) - { - bw.BaseStream.Position = partialsPointer + i * (x64 ? 0x18 : is64Bit ? 0x10 : 0xC); - _partials[i].Write(bw, is64Bit, x64, partialsPointer, _partials.Count, ref numPriorGraphs, ref numPriorPoints); - } + bw.BaseStream.Position = partialsPointer + i * (x64 ? 0x18 : is64Bit ? 0x10 : 0xC); + _partials[i].Write(bw, is64Bit, x64, partialsPointer, _partials.Count, ref numPriorGraphs, ref numPriorPoints); + } - for (int i = 0; i < 2; ++i) // No idea why, but they write 16 null bytes after everything, and it's consistent - bw.Write((UInt64)0); - UInt32 resourceLength = (UInt32)bw.BaseStream.Position; - bw.Align(0x10); - bw.BaseStream.Position = is64Bit ? 0x14 : 0x10; - bw.Write(resourceLength); + for (int i = 0; i < 2; ++i) // No idea why, but they write 16 null bytes after everything, and it's consistent + bw.Write((ulong)0); + uint resourceLength = (uint)bw.BaseStream.Position; + bw.Align(0x10); + bw.BaseStream.Position = is64Bit ? 0x14 : 0x10; + bw.Write(resourceLength); - bw.Flush(); - byte[] data = ms.ToArray(); - bw.Close(); - ms.Close(); + bw.Flush(); + byte[] data = ms.ToArray(); + bw.Close(); + ms.Close(); - entry.EntryBlocks[0].Data = data; - entry.Dirty = true; + entry.EntryBlocks[0].Data = data; + entry.Dirty = true; - return true; - } + return true; } +} + +public class Partial +{ + private uint _waveNameHash = 0; // Name hash + internal uint WaveNameHash { get => _waveNameHash; } + private string _waveName; + public string WaveName { get => _waveName; } + + private List _graphs; + public List Graphs { get => _graphs; } - public class Partial + public Partial() { - private UInt32 _waveNameHash = 0; // Name hash - internal UInt32 WaveNameHash { get => _waveNameHash; } - private String _waveName; - public String WaveName { get => _waveName; } + _graphs = []; + } - private List _graphs; - public List Graphs { get => _graphs; } + public Partial(BinaryReader2 br, bool is64Bit, bool x64) + { + _graphs = []; - public Partial() + // Position differs between 32-bit and 64-bit + long graphsPointer = 0; + if (x64) { - _graphs = []; + _waveNameHash = br.ReadUInt32(); + br.BaseStream.Position += 4; + graphsPointer = br.ReadInt64(); } - - public Partial(BinaryReader2 br, bool is64Bit, bool x64) + else if (is64Bit) { - _graphs = []; - - // Position differs between 32-bit and 64-bit - Int64 graphsPointer = 0; - if (x64) - { - _waveNameHash = br.ReadUInt32(); - br.BaseStream.Position += 4; - graphsPointer = br.ReadInt64(); - } - else if (is64Bit) - { - graphsPointer = br.ReadInt64(); - _waveNameHash = br.ReadUInt32(); - } - else - { - _waveNameHash = br.ReadUInt32(); - graphsPointer = br.ReadInt32(); - } - Byte numGraphs = br.ReadByte(); - - for (int i = 0; i < numGraphs; ++i) - { - br.BaseStream.Position = graphsPointer + i * (is64Bit ? 0x10 : 8); - _graphs.Add(new Graph(br, is64Bit)); - } + graphsPointer = br.ReadInt64(); + _waveNameHash = br.ReadUInt32(); } - - public void Write(BinaryWriter2 bw, bool is64Bit, bool x64, Int64 partialsPointer, int numPartials, ref int numPriorGraphs, ref int numPriorPoints) + else { - Int64 graphsPointer = partialsPointer; - if (x64) - { - graphsPointer += numPartials * 0x18 + numPriorGraphs * 0x10 + numPriorPoints * 8; - bw.Write(_waveNameHash); - bw.Write(0); - bw.Write(graphsPointer); - } - else if (is64Bit) - { - graphsPointer += numPartials * 0x10 + numPriorGraphs * 0x10 + numPriorPoints * 8; - bw.Write(graphsPointer); - bw.Write(_waveNameHash); - } - else - { - graphsPointer += numPartials * 0xC + numPriorGraphs * 8 + numPriorPoints * 8; - bw.Write(_waveNameHash); - bw.Write((Int32)graphsPointer); - } - bw.Write((Byte)_graphs.Count); - bw.WriteUniquePadding(x64 ? 7 : 3); - - bw.BaseStream.Position = graphsPointer; - int numPriorPointsInGraph = 0; - for (int i = 0; i < _graphs.Count; ++i) - { - bw.BaseStream.Position = graphsPointer + i * (is64Bit ? 0x10 : 8); - _graphs[i].Write(bw, is64Bit, graphsPointer, _graphs.Count, ref numPriorPoints, ref numPriorPointsInGraph); - numPriorGraphs++; - } + _waveNameHash = br.ReadUInt32(); + graphsPointer = br.ReadInt32(); } + byte numGraphs = br.ReadByte(); - public void Clear() + for (int i = 0; i < numGraphs; ++i) { - _graphs.Clear(); + br.BaseStream.Position = graphsPointer + i * (is64Bit ? 0x10 : 8); + _graphs.Add(new Graph(br, is64Bit)); } + } - internal void SetWaveNameAsHash() + public void Write(BinaryWriter2 bw, bool is64Bit, bool x64, long partialsPointer, int numPartials, ref int numPriorGraphs, ref int numPriorPoints) + { + long graphsPointer = partialsPointer; + if (x64) + { + graphsPointer += numPartials * 0x18 + numPriorGraphs * 0x10 + numPriorPoints * 8; + bw.Write(_waveNameHash); + bw.Write(0); + bw.Write(graphsPointer); + } + else if (is64Bit) { - _waveName = "0x" + _waveNameHash.ToString("X8"); + graphsPointer += numPartials * 0x10 + numPriorGraphs * 0x10 + numPriorPoints * 8; + bw.Write(graphsPointer); + bw.Write(_waveNameHash); } + else + { + graphsPointer += numPartials * 0xC + numPriorGraphs * 8 + numPriorPoints * 8; + bw.Write(_waveNameHash); + bw.Write((int)graphsPointer); + } + bw.Write((byte)_graphs.Count); + bw.WriteUniquePadding(x64 ? 7 : 3); - internal void SetWaveName(string waveName) + bw.BaseStream.Position = graphsPointer; + int numPriorPointsInGraph = 0; + for (int i = 0; i < _graphs.Count; ++i) { - if (waveName.StartsWith("gamedb://")) - { - var subStrStart = waveName.LastIndexOf('/') + 1; - var subStrLen = waveName.IndexOf(".WaveFile") - subStrStart; - String shortWaveName = waveName.Substring(subStrStart, subStrLen); - _waveName = shortWaveName; - } - else - { - _waveName = waveName; - } + bw.BaseStream.Position = graphsPointer + i * (is64Bit ? 0x10 : 8); + _graphs[i].Write(bw, is64Bit, graphsPointer, _graphs.Count, ref numPriorPoints, ref numPriorPointsInGraph); + numPriorGraphs++; } } - public class Graph + public void Clear() { - private SByte _xAxis = 0; - internal SByte XAxis { get => _xAxis; } - private SByte _yAxis = 0; - internal SByte YAxis { get => _yAxis; } + _graphs.Clear(); + } - private List _points; - public List Points { get => _points; } + internal void SetWaveNameAsHash() + { + _waveName = "0x" + _waveNameHash.ToString("X8"); + } - public Graph() + internal void SetWaveName(string waveName) + { + if (waveName.StartsWith("gamedb://")) { - _points = []; + var subStrStart = waveName.LastIndexOf('/') + 1; + var subStrLen = waveName.IndexOf(".WaveFile") - subStrStart; + string shortWaveName = waveName.Substring(subStrStart, subStrLen); + _waveName = shortWaveName; } - - public Graph(BinaryReader2 br, bool is64Bit) + else { - _points = []; - - Int64 pointsPointer = is64Bit ? br.ReadInt64() : br.ReadInt32(); - Byte numPoints = br.ReadByte(); - _xAxis = br.ReadSByte(); - _yAxis = br.ReadSByte(); - - for (int i = 0; i < numPoints; ++i) - { - br.BaseStream.Position = pointsPointer + i * 8; - _points.Add(new Point(br)); - } + _waveName = waveName; } + } +} - public void Clear() - { - _points.Clear(); - } +public class Graph +{ + private sbyte _xAxis = 0; + internal sbyte XAxis { get => _xAxis; } + private sbyte _yAxis = 0; + internal sbyte YAxis { get => _yAxis; } - public void Write(BinaryWriter2 bw, bool is64Bit, Int64 graphsPointer, int numGraphs, ref int numPriorPoints, ref int numPriorPointsInGraph) - { - Int64 pointsPointer = graphsPointer + numGraphs * (is64Bit ? 0x10 : 8) + numPriorPointsInGraph * 8; - if (is64Bit) - bw.Write(pointsPointer); - else - bw.Write((Int32)pointsPointer); - bw.Write((Byte)_points.Count); - bw.Write(_xAxis); - bw.Write(_yAxis); - if (is64Bit) - bw.WriteUniquePadding(5); - else - bw.WriteUniquePadding(1); - - bw.BaseStream.Position = pointsPointer; - for (int i = 0; i < _points.Count; ++i) - { - _points[i].Write(bw); - numPriorPoints++; - numPriorPointsInGraph++; - } - } + private List _points; + public List Points { get => _points; } + + public Graph() + { + _points = []; } - public class Point + public Graph(BinaryReader2 br, bool is64Bit) { - private float _x = 0; - public float X { get => _x; set => _x = value; } + _points = []; - private float _y = 0; - public float Y { get => _y; set => _y = value; } + long pointsPointer = is64Bit ? br.ReadInt64() : br.ReadInt32(); + byte numPoints = br.ReadByte(); + _xAxis = br.ReadSByte(); + _yAxis = br.ReadSByte(); - public Point(BinaryReader2 br) + for (int i = 0; i < numPoints; ++i) { - _x = br.ReadSingle(); - _y = br.ReadSingle(); + br.BaseStream.Position = pointsPointer + i * 8; + _points.Add(new Point(br)); } + } - public void Write(BinaryWriter2 bw) + public void Clear() + { + _points.Clear(); + } + + public void Write(BinaryWriter2 bw, bool is64Bit, long graphsPointer, int numGraphs, ref int numPriorPoints, ref int numPriorPointsInGraph) + { + long pointsPointer = graphsPointer + numGraphs * (is64Bit ? 0x10 : 8) + numPriorPointsInGraph * 8; + if (is64Bit) + bw.Write(pointsPointer); + else + bw.Write((int)pointsPointer); + bw.Write((byte)_points.Count); + bw.Write(_xAxis); + bw.Write(_yAxis); + if (is64Bit) + bw.WriteUniquePadding(5); + else + bw.WriteUniquePadding(1); + + bw.BaseStream.Position = pointsPointer; + for (int i = 0; i < _points.Count; ++i) { - bw.Write(_x); - bw.Write(_y); + _points[i].Write(bw); + numPriorPoints++; + numPriorPointsInGraph++; } } } + +public class Point +{ + private float _x = 0; + public float X { get => _x; set => _x = value; } + + private float _y = 0; + public float Y { get => _y; set => _y = value; } + + public Point(BinaryReader2 br) + { + _x = br.ReadSingle(); + _y = br.ReadSingle(); + } + + public void Write(BinaryWriter2 bw) + { + bw.Write(_x); + bw.Write(_y); + } +} diff --git a/LoopModel/LoopModelEditor.cs b/LoopModel/LoopModelEditor.cs index 1b2ec87..b1f990b 100644 --- a/LoopModel/LoopModelEditor.cs +++ b/LoopModel/LoopModelEditor.cs @@ -4,200 +4,199 @@ using System.ComponentModel; using System.Windows.Forms; -namespace LoopModel +namespace LoopModel; + +public partial class LoopModelEditor : Form, IEntryEditor { - public partial class LoopModelEditor : Form, IEntryEditor + public delegate void OnEdit(); + public event OnEdit Edit; + + // Used in handling changes to the plots + private bool[] partialsShown = new bool[10]; + private ScottPlot.Color[] partialsColors = + [ + Colors.Red, + Colors.Green, + Colors.Blue, + Colors.Cyan, + Colors.Magenta, + Colors.Yellow, + Colors.Orange, + Colors.Purple, + Colors.Brown, + Colors.Grey + ]; + private int selectedGraphIndex = 0; + + private LoopModelData _data; + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public LoopModelData Data { - public delegate void OnEdit(); - public event OnEdit Edit; - - // Used in handling changes to the plots - private bool[] partialsShown = new bool[10]; - private ScottPlot.Color[] partialsColors = + get => _data; + set { - Colors.Red, - Colors.Green, - Colors.Blue, - Colors.Cyan, - Colors.Magenta, - Colors.Yellow, - Colors.Orange, - Colors.Purple, - Colors.Brown, - Colors.Grey - }; - private int selectedGraphIndex = 0; - - private LoopModelData _data; - [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] - public LoopModelData Data - { - get => _data; - set - { - _data = value; - UpdatePartialsGrid(); - UpdatePointsGrid(0, 0); - UpdateAllPlots(); - } + _data = value; + UpdatePartialsGrid(); + UpdatePointsGrid(0, 0); + UpdateAllPlots(); } + } - public LoopModelEditor() - { - InitializeComponent(); - - // Create axis labels - rpmPitchPlot.Plot.XLabel("RPM"); - rpmPitchPlot.Plot.YLabel("Pitch"); - rpmGainPlot.Plot.XLabel("RPM"); - rpmGainPlot.Plot.YLabel("Gain"); - accelGainPlot.Plot.XLabel("Accelerator"); - accelGainPlot.Plot.YLabel("Gain"); - - // Show legend on each plot. This must be done only once or it will duplicate itself. - rpmPitchPlot.Plot.ShowLegend(Edge.Right); - rpmGainPlot.Plot.ShowLegend(Edge.Right); - accelGainPlot.Plot.ShowLegend(Edge.Right); - - // Create graph grid rows (they're always the same) - string[] graphNames = { "Pitch/RPM", "Gain/RPM", "Gain/Accelerator" }; - for (int i = 0; i < graphNames.Length; ++i) - graphsGrid.Rows.Add(graphNames[i]); - - // Set up shown partials (all are shown at first) - Array.Fill(partialsShown, true); - } + public LoopModelEditor() + { + InitializeComponent(); + + // Create axis labels + rpmPitchPlot.Plot.XLabel("RPM"); + rpmPitchPlot.Plot.YLabel("Pitch"); + rpmGainPlot.Plot.XLabel("RPM"); + rpmGainPlot.Plot.YLabel("Gain"); + accelGainPlot.Plot.XLabel("Accelerator"); + accelGainPlot.Plot.YLabel("Gain"); + + // Show legend on each plot. This must be done only once or it will duplicate itself. + rpmPitchPlot.Plot.ShowLegend(Edge.Right); + rpmGainPlot.Plot.ShowLegend(Edge.Right); + accelGainPlot.Plot.ShowLegend(Edge.Right); + + // Create graph grid rows (they're always the same) + string[] graphNames = ["Pitch/RPM", "Gain/RPM", "Gain/Accelerator"]; + for (int i = 0; i < graphNames.Length; ++i) + graphsGrid.Rows.Add(graphNames[i]); + + // Set up shown partials (all are shown at first) + Array.Fill(partialsShown, true); + } - public void UpdatePartialsGrid() + public void UpdatePartialsGrid() + { + partialsGrid.Rows.Clear(); + for (int i = 0; i < _data.Partials.Count; ++i) { - partialsGrid.Rows.Clear(); - for (int i = 0; i < _data.Partials.Count; ++i) - { - partialsGrid.Rows.Add(new DataGridViewRow()); - partialsGrid[0, i].Value = true; - partialsGrid[1, i].Value = _data.Partials[i].WaveName; - partialsGrid[2, i].Value = "0x" + _data.Partials[i].WaveNameHash.ToString("X8"); - } + partialsGrid.Rows.Add(new DataGridViewRow()); + partialsGrid[0, i].Value = true; + partialsGrid[1, i].Value = _data.Partials[i].WaveName; + partialsGrid[2, i].Value = "0x" + _data.Partials[i].WaveNameHash.ToString("X8"); } + } - public void UpdatePointsGrid(int partialIndex, int graphIndex) + public void UpdatePointsGrid(int partialIndex, int graphIndex) + { + pointsGrid.Rows.Clear(); + for (int i = 0; i < _data.Partials[partialIndex].Graphs[graphIndex].Points.Count; ++i) { - pointsGrid.Rows.Clear(); - for (int i = 0; i < _data.Partials[partialIndex].Graphs[graphIndex].Points.Count; ++i) - { - pointsGrid.Rows.Add(new DataGridViewRow()); - pointsGrid[0, i].Value = _data.Partials[partialIndex].Graphs[graphIndex].Points[i].X; - pointsGrid[1, i].Value = _data.Partials[partialIndex].Graphs[graphIndex].Points[i].Y; - } + pointsGrid.Rows.Add(new DataGridViewRow()); + pointsGrid[0, i].Value = _data.Partials[partialIndex].Graphs[graphIndex].Points[i].X; + pointsGrid[1, i].Value = _data.Partials[partialIndex].Graphs[graphIndex].Points[i].Y; } + } - public void UpdateAllPlots() - { - MakeNewScatterPlot(rpmPitchPlot, 0); - MakeNewScatterPlot(rpmGainPlot, 1); - MakeNewScatterPlot(accelGainPlot, 2); - } + public void UpdateAllPlots() + { + MakeNewScatterPlot(rpmPitchPlot, 0); + MakeNewScatterPlot(rpmGainPlot, 1); + MakeNewScatterPlot(accelGainPlot, 2); + } - public void MakeNewScatterPlot(ScottPlot.WinForms.FormsPlot plot, int graphIndex) + public void MakeNewScatterPlot(ScottPlot.WinForms.FormsPlot plot, int graphIndex) + { + plot.Plot.Clear(); + for (int i = 0; i < _data.Partials.Count; ++i) { - plot.Plot.Clear(); - for (int i = 0; i < _data.Partials.Count; ++i) + if ((bool)partialsGrid.Rows[i].Cells[0].Value == false) + continue; + ScottPlot.Coordinates[] coords = new ScottPlot.Coordinates[_data.Partials[i].Graphs[graphIndex].Points.Count]; + for (int j = 0; j < _data.Partials[i].Graphs[graphIndex].Points.Count; ++j) { - if ((bool)partialsGrid.Rows[i].Cells[0].Value == false) - continue; - ScottPlot.Coordinates[] coords = new ScottPlot.Coordinates[_data.Partials[i].Graphs[graphIndex].Points.Count]; - for (int j = 0; j < _data.Partials[i].Graphs[graphIndex].Points.Count; ++j) - { - coords[j].X = _data.Partials[i].Graphs[graphIndex].Points[j].X; - coords[j].Y = _data.Partials[i].Graphs[graphIndex].Points[j].Y; - } - var scatter = plot.Plot.Add.Scatter(coords, partialsColors[i]); - scatter.LegendText = _data.Partials[i].WaveName; + coords[j].X = _data.Partials[i].Graphs[graphIndex].Points[j].X; + coords[j].Y = _data.Partials[i].Graphs[graphIndex].Points[j].Y; } - plot.Plot.Legend.FontSize = 10; - plot.Refresh(); + var scatter = plot.Plot.Add.Scatter(coords, partialsColors[i]); + scatter.LegendText = _data.Partials[i].WaveName; } + plot.Plot.Legend.FontSize = 10; + plot.Refresh(); + } - private void UpdateSinglePlot(int changedRowIndex, int changedColumnIndex) + private void UpdateSinglePlot(int changedRowIndex, int changedColumnIndex) + { + if (changedColumnIndex == 0) { - if (changedColumnIndex == 0) - { - _data.Partials[partialsGrid.SelectedRows[0].Index] - .Graphs[graphsGrid.SelectedRows[0].Index] - .Points[changedRowIndex] - .X = Convert.ToSingle(pointsGrid.Rows[changedRowIndex].Cells[changedColumnIndex].Value); - } - else if (changedColumnIndex == 1) - { - _data.Partials[partialsGrid.SelectedRows[0].Index] - .Graphs[graphsGrid.SelectedRows[0].Index] - .Points[changedRowIndex] - .Y = Convert.ToSingle(pointsGrid.Rows[changedRowIndex].Cells[changedColumnIndex].Value); - } - if (graphsGrid.SelectedRows[0].Index == 0) - MakeNewScatterPlot(rpmPitchPlot, 0); - else if (graphsGrid.SelectedRows[0].Index == 1) - MakeNewScatterPlot(rpmGainPlot, 1); - else if (graphsGrid.SelectedRows[0].Index == 2) - MakeNewScatterPlot(accelGainPlot, 2); + _data.Partials[partialsGrid.SelectedRows[0].Index] + .Graphs[graphsGrid.SelectedRows[0].Index] + .Points[changedRowIndex] + .X = Convert.ToSingle(pointsGrid.Rows[changedRowIndex].Cells[changedColumnIndex].Value); } - - private void partialsGrid_CurrentCellDirtyStateChanged(object sender, EventArgs e) + else if (changedColumnIndex == 1) { - if (partialsGrid.IsCurrentCellDirty) - partialsGrid.CommitEdit(DataGridViewDataErrorContexts.Commit); + _data.Partials[partialsGrid.SelectedRows[0].Index] + .Graphs[graphsGrid.SelectedRows[0].Index] + .Points[changedRowIndex] + .Y = Convert.ToSingle(pointsGrid.Rows[changedRowIndex].Cells[changedColumnIndex].Value); } + if (graphsGrid.SelectedRows[0].Index == 0) + MakeNewScatterPlot(rpmPitchPlot, 0); + else if (graphsGrid.SelectedRows[0].Index == 1) + MakeNewScatterPlot(rpmGainPlot, 1); + else if (graphsGrid.SelectedRows[0].Index == 2) + MakeNewScatterPlot(accelGainPlot, 2); + } - private void partialsGrid_CellValueChanged(object sender, DataGridViewCellEventArgs e) - { - if (partialsGrid.SelectedRows.Count < 1) - return; - bool isPartialShown = (bool)partialsGrid.Rows[e.RowIndex].Cells[0].Value; - if (isPartialShown != partialsShown[e.RowIndex]) - { - partialsShown[e.RowIndex] = isPartialShown; - UpdateAllPlots(); - } - } + private void partialsGrid_CurrentCellDirtyStateChanged(object sender, EventArgs e) + { + if (partialsGrid.IsCurrentCellDirty) + partialsGrid.CommitEdit(DataGridViewDataErrorContexts.Commit); + } - private void partialsGrid_RowEnter(object sender, DataGridViewCellEventArgs e) + private void partialsGrid_CellValueChanged(object sender, DataGridViewCellEventArgs e) + { + if (partialsGrid.SelectedRows.Count < 1) + return; + bool isPartialShown = (bool)partialsGrid.Rows[e.RowIndex].Cells[0].Value; + if (isPartialShown != partialsShown[e.RowIndex]) { - if (partialsGrid.SelectedRows.Count > 0) - UpdatePointsGrid(partialsGrid.SelectedRows[0].Index, selectedGraphIndex); + partialsShown[e.RowIndex] = isPartialShown; + UpdateAllPlots(); } + } + + private void partialsGrid_RowEnter(object sender, DataGridViewCellEventArgs e) + { + if (partialsGrid.SelectedRows.Count > 0) + UpdatePointsGrid(partialsGrid.SelectedRows[0].Index, selectedGraphIndex); + } - private void graphsGrid_RowEnter(object sender, DataGridViewCellEventArgs e) + private void graphsGrid_RowEnter(object sender, DataGridViewCellEventArgs e) + { + if (graphsGrid.SelectedRows.Count > 0 && graphsGrid.SelectedRows[0].Index != selectedGraphIndex) { - if (graphsGrid.SelectedRows.Count > 0 && graphsGrid.SelectedRows[0].Index != selectedGraphIndex) - { - selectedGraphIndex = graphsGrid.SelectedRows[0].Index; - UpdatePointsGrid(partialsGrid.SelectedRows[0].Index, selectedGraphIndex); - } + selectedGraphIndex = graphsGrid.SelectedRows[0].Index; + UpdatePointsGrid(partialsGrid.SelectedRows[0].Index, selectedGraphIndex); } + } - private void pointsGrid_CellEndEdit(object sender, DataGridViewCellEventArgs e) + private void pointsGrid_CellEndEdit(object sender, DataGridViewCellEventArgs e) + { + float changedValue = Convert.ToSingle(pointsGrid.Rows[e.RowIndex].Cells[e.ColumnIndex].Value); + float originalValue = 0; + if (e.ColumnIndex == 0) { - Single changedValue = Convert.ToSingle(pointsGrid.Rows[e.RowIndex].Cells[e.ColumnIndex].Value); - Single originalValue = 0; - if (e.ColumnIndex == 0) - { - originalValue = _data.Partials[partialsGrid.SelectedRows[0].Index] - .Graphs[graphsGrid.SelectedRows[0].Index] - .Points[e.RowIndex].X; - } - else - { - originalValue = _data.Partials[partialsGrid.SelectedRows[0].Index] - .Graphs[graphsGrid.SelectedRows[0].Index] - .Points[e.RowIndex].Y; - } - if (originalValue != changedValue) - UpdateSinglePlot(e.RowIndex, e.ColumnIndex); + originalValue = _data.Partials[partialsGrid.SelectedRows[0].Index] + .Graphs[graphsGrid.SelectedRows[0].Index] + .Points[e.RowIndex].X; } - - private void LoopModelEditor_FormClosed(object sender, EventArgs e) + else { - Edit(); + originalValue = _data.Partials[partialsGrid.SelectedRows[0].Index] + .Graphs[graphsGrid.SelectedRows[0].Index] + .Points[e.RowIndex].Y; } + if (originalValue != changedValue) + UpdateSinglePlot(e.RowIndex, e.ColumnIndex); + } + + private void LoopModelEditor_FormClosed(object sender, EventArgs e) + { + Edit(); } } diff --git a/LoopModel/LoopModelPlugin.cs b/LoopModel/LoopModelPlugin.cs index 72d150b..fa2ada6 100644 --- a/LoopModel/LoopModelPlugin.cs +++ b/LoopModel/LoopModelPlugin.cs @@ -1,16 +1,15 @@ using BundleFormat; using PluginAPI; -namespace LoopModel +namespace LoopModel; + +public class LoopModelPlugin : IPlugin { - public class LoopModelPlugin : IPlugin - { - public string Id => "loopmodelplugin"; - public string Name => "LoopModel Resource Handler"; + public string Id => "loopmodelplugin"; + public string Name => "LoopModel Resource Handler"; - public static void Init() - { - EntryTypeRegistry.Register(EntryType.LoopModel, new LoopModelData()); - } + public static void Init() + { + EntryTypeRegistry.Register(EntryType.LoopModel, new LoopModelData()); } } diff --git a/LuaList/EncryptedStringConverter.cs b/LuaList/EncryptedStringConverter.cs index 44027b5..faf4eac 100644 --- a/LuaList/EncryptedStringConverter.cs +++ b/LuaList/EncryptedStringConverter.cs @@ -1,64 +1,63 @@ using System; using System.ComponentModel; -namespace LuaList -{ - // Included... - // [1] Define TypeConverter class for hex. - // [2] use it when defining a member of a data class using attribute TypeConverter. - // [3] Connect the data class to a PropertyGrid. +namespace LuaList; + +// Included... +// [1] Define TypeConverter class for hex. +// [2] use it when defining a member of a data class using attribute TypeConverter. +// [3] Connect the data class to a PropertyGrid. - // [1] define UInt32HexTypeConverter is-a TypeConverter - public class EncryptedStringConverter : TypeConverter +// [1] define UInt32HexTypeConverter is-a TypeConverter +public class EncryptedStringConverter : TypeConverter +{ + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + if (sourceType == typeof(string)) + { + return true; + } + else { - if (sourceType == typeof(string)) - { - return true; - } - else - { - return base.CanConvertFrom(context, sourceType); - } + return base.CanConvertFrom(context, sourceType); } + } - public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(string)) + { + return true; + } + else { - if (destinationType == typeof(string)) - { - return true; - } - else - { - return base.CanConvertTo(context, destinationType); - } + return base.CanConvertTo(context, destinationType); } + } - public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) + public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) + { + if (destinationType == typeof(string) && value.GetType() == typeof(BundleUtilities.EncryptedString)) + { + return ((BundleUtilities.EncryptedString)value).Value; + } + else { - if (destinationType == typeof(string) && value.GetType() == typeof(BundleUtilities.EncryptedString)) - { - return ((BundleUtilities.EncryptedString)value).Value; - } - else - { - return base.ConvertTo(context, culture, value, destinationType); - } + return base.ConvertTo(context, culture, value, destinationType); } + } - public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) + public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) + { + if (value.GetType() == typeof(string)) + { + string input = (string)value; + return new BundleUtilities.EncryptedString(input); + } + else { - if (value.GetType() == typeof(string)) - { - string input = (string)value; - return new BundleUtilities.EncryptedString(input); - } - else - { - return base.ConvertFrom(context, culture, value); - } + return base.ConvertFrom(context, culture, value); } } } diff --git a/LuaList/LuaList.cs b/LuaList/LuaList.cs index 0d7fd39..eed7cea 100644 --- a/LuaList/LuaList.cs +++ b/LuaList/LuaList.cs @@ -8,204 +8,205 @@ using System.ComponentModel; using System; -namespace LuaList +namespace LuaList; + +public class LuaList : IEntryData { - public class LuaList : IEntryData - { - public int version { get; set; } + public int version { get; set; } - [TypeConverter(typeof(EncryptedStringConverter))] - public EncryptedString CgsId { get; set; } + [TypeConverter(typeof(EncryptedStringConverter))] + public EncryptedString CgsId { get; set; } - public int dataLength; - public string listTitle { get; set; } - public List entries { get; set; } - public List types { get; set; } - public List variables { get; set; } - public IEntryEditor GetEditor(BundleEntry entry) + public int dataLength; + public string listTitle { get; set; } + public List entries { get; set; } + public List types { get; set; } + public List variables { get; set; } + public IEntryEditor GetEditor(BundleEntry entry) + { + LuaListEditor luaListEditor = new(); + luaListEditor.LuaList = this; + luaListEditor.EditEvent += () => { - LuaListEditor luaListEditor = new LuaListEditor(); - luaListEditor.LuaList = this; - luaListEditor.EditEvent += () => - { - Write(entry); - }; - return luaListEditor; - } + Write(entry); + }; + return luaListEditor; + } - public EntryType GetEntryType(BundleEntry entry) - { - return EntryType.LUAList; - } + public EntryType GetEntryType(BundleEntry entry) + { + return EntryType.LUAList; + } - public int getLengthOfHeader() + public int getLengthOfHeader() + { + List bytes = + [ + BitConverter.GetBytes(version), + new byte[4], + BitConverter.GetBytes(CgsId.Encrypted), + BitConverter.GetBytes(192), + BitConverter.GetBytes(1231), + BitConverter.GetBytes(312312), + BitConverter.GetBytes(entries.Count), + BitConverter.GetBytes(dataLength), + Encoding.ASCII.GetBytes((listTitle.PadRight(128)[..128].ToCharArray())), + [(byte)types.Count()], + [(byte)variables.Count()], + new byte[26], + ]; + return bytes.SelectMany(i => i).Count(); + } + + public int getLengthOfTypes() + { + if (types.Count == 0) { - List bytes = new List(); - bytes.Add(BitConverter.GetBytes(version)); - bytes.Add(new byte[4]); - bytes.Add(BitConverter.GetBytes(CgsId.Encrypted)); - bytes.Add(BitConverter.GetBytes(192)); - bytes.Add(BitConverter.GetBytes(1231)); - bytes.Add(BitConverter.GetBytes(312312)); - bytes.Add(BitConverter.GetBytes(entries.Count)); - bytes.Add(BitConverter.GetBytes(dataLength)); - bytes.Add(Encoding.ASCII.GetBytes((listTitle.PadRight(128).Substring(0, 128).ToCharArray()))); - bytes.Add(new byte[] { (byte)types.Count() }); - bytes.Add(new byte[] { (byte)variables.Count() }); - bytes.Add(new byte[26]); - return bytes.SelectMany(i => i).Count(); + return 0; } + return (types.Count * 32) + 32; // Pointer Array of 32 bytes + } - public int getLengthOfTypes() + public int getLengthOfVariables() + { + if (variables.Count == 0) { - if (types.Count == 0) - { - return 0; - } - return (types.Count * 32) + 32; // Pointer Array of 32 bytes + return 0; } + return (variables.Count * 32) + 32; // Pointer Array of 32 bytes + } + + public int getLengthOfEntries() + { + return entries.Sum(i => i.getDataSize()); + } + + public bool Read(BundleEntry entry, ILoader loader = null) + { + MemoryStream ms = entry.MakeStream(); + BinaryReader2 br = new(ms); + br.BigEndian = entry.Console; + + version = br.ReadInt32(); + br.ReadBytes(4); + CgsId = new EncryptedString(br.ReadUInt64()); + var entriesPointer = br.ReadInt32(); + var typePointer = br.ReadInt32(); + var variablePointer = br.ReadInt32(); + var numScripts = br.ReadInt32(); + var dataLength = br.ReadInt32(); + listTitle = br.ReadLenString(128); + var numTypes = br.ReadByte(); + var numVariables = br.ReadByte(); + br.ReadBytes(26); - public int getLengthOfVariables() + entries = []; + for (int i = 0; i < numScripts; i++) { - if (variables.Count == 0) - { - return 0; - } - return (variables.Count * 32) + 32; // Pointer Array of 32 bytes + LuaListEntry luaentry = new(); + luaentry.Read(loader, br); + entries.Add(luaentry); } - public int getLengthOfEntries() + br.BaseStream.Position = typePointer; + long currentAddress = br.BaseStream.Position; + types = []; + for (int i = 0; i < numTypes; i++) { - return entries.Sum(i => i.getDataSize()); + int pointer = br.ReadInt32(); + currentAddress = br.BaseStream.Position; + br.BaseStream.Position = pointer; + types.Add(br.ReadLenString(32)); + br.BaseStream.Position = currentAddress; } - - public bool Read(BundleEntry entry, ILoader loader = null) + br.BaseStream.Position = variablePointer; + variables = []; + for (int i = 0; i < numVariables; i++) { - MemoryStream ms = entry.MakeStream(); - BinaryReader2 br = new BinaryReader2(ms); - br.BigEndian = entry.Console; - - version = br.ReadInt32(); - br.ReadBytes(4); - CgsId = new EncryptedString(br.ReadUInt64()); - var entriesPointer = br.ReadInt32(); - var typePointer = br.ReadInt32(); - var variablePointer = br.ReadInt32(); - var numScripts = br.ReadInt32(); - var dataLength = br.ReadInt32(); - listTitle = br.ReadLenString(128); - var numTypes = br.ReadByte(); - var numVariables = br.ReadByte(); - br.ReadBytes(26); - - entries = new List(); - for (int i = 0; i < numScripts; i++) - { - LuaListEntry luaentry = new LuaListEntry(); - luaentry.Read(loader, br); - entries.Add(luaentry); - } - - br.BaseStream.Position = typePointer; - long currentAddress = br.BaseStream.Position; - types = new List(); - for (int i = 0; i < numTypes; i++) + int pointer = br.ReadInt32(); + currentAddress = br.BaseStream.Position; + br.BaseStream.Position = pointer; + if (dataLength - pointer > 31) { - int pointer = br.ReadInt32(); - currentAddress = br.BaseStream.Position; - br.BaseStream.Position = pointer; - types.Add(br.ReadLenString(32)); - br.BaseStream.Position = currentAddress; + variables.Add(br.ReadLenString(32)); } - br.BaseStream.Position = variablePointer; - variables = new List(); - for (int i = 0; i < numVariables; i++) + else { - int pointer = br.ReadInt32(); - currentAddress = br.BaseStream.Position; - br.BaseStream.Position = pointer; - if (dataLength - pointer > 31) - { - variables.Add(br.ReadLenString(32)); - } - else - { - Console.WriteLine(dataLength - pointer); - variables.Add(br.ReadLenString(dataLength - pointer)); - } - br.BaseStream.Position = currentAddress; + Console.WriteLine(dataLength - pointer); + variables.Add(br.ReadLenString(dataLength - pointer)); } - Console.WriteLine(getLengthOfHeader() + getLengthOfEntries() + getLengthOfTypes() + getLengthOfVariables()); - Console.WriteLine(dataLength); - br.Close(); - ms.Close(); - - return true; + br.BaseStream.Position = currentAddress; } + Console.WriteLine(getLengthOfHeader() + getLengthOfEntries() + getLengthOfTypes() + getLengthOfVariables()); + Console.WriteLine(dataLength); + br.Close(); + ms.Close(); - public bool Write(BundleEntry entry) + return true; + } + + public bool Write(BundleEntry entry) + { + MemoryStream ms = new(); + BinaryWriter2 bw = new(ms); + bw.BigEndian = entry.Console; + bw.Write(version); + bw.WriteUniquePadding(4); + bw.Write(CgsId.Encrypted); + bw.Write(getLengthOfHeader()); + bw.Write(getLengthOfHeader() + getLengthOfEntries()); + bw.Write(getLengthOfHeader() + getLengthOfEntries() + getLengthOfTypes()); + bw.Write(entries.Count); + bw.Write(getLengthOfHeader() + getLengthOfEntries() + getLengthOfTypes() + getLengthOfVariables()); //Calculate this + bw.Write(listTitle.PadRight(128, '\0')[..128].ToCharArray()); + bw.Write((byte)types.Count); + bw.Write((byte)variables.Count); + bw.WriteUniquePadding(26); + foreach (LuaListEntry luaentry in entries) { - MemoryStream ms = new MemoryStream(); - BinaryWriter2 bw = new BinaryWriter2(ms); - bw.BigEndian = entry.Console; - bw.Write(version); - bw.WriteUniquePadding(4); - bw.Write(CgsId.Encrypted); - bw.Write(getLengthOfHeader()); - bw.Write(getLengthOfHeader() + getLengthOfEntries()); - bw.Write(getLengthOfHeader() + getLengthOfEntries() + getLengthOfTypes()); - bw.Write(entries.Count); - bw.Write(getLengthOfHeader() + getLengthOfEntries() + getLengthOfTypes() + getLengthOfVariables()); //Calculate this - bw.Write(listTitle.PadRight(128, '\0').Substring(0, 128).ToCharArray()); - bw.Write((byte)types.Count); - bw.Write((byte)variables.Count); - bw.WriteUniquePadding(26); - foreach (LuaListEntry luaentry in entries) - { - luaentry.Write(bw); - } - var counter = 0; - var pointerAddress = bw.BaseStream.Position; - // Skip pointer address for now - bw.BaseStream.Position = bw.BaseStream.Position + 32; - foreach (string type in types) - { - // Save pointer to text - int pointer = (int)bw.BaseStream.Position; - bw.Write(type.PadRight(32, '\0').Substring(0, 32).ToCharArray()); - long currentAddress = bw.BaseStream.Position; - // Go to pointer array - bw.BaseStream.Position = pointerAddress + (4 * counter); - bw.Write(pointer); - counter++; - // Go back to old position - bw.BaseStream.Position = currentAddress; - } - counter = 0; - pointerAddress = bw.BaseStream.Position; - // Skip pointer address for now - bw.BaseStream.Position = bw.BaseStream.Position + 32; - foreach (string variable in variables) - { - // Save pointer to text - int pointer = (int)bw.BaseStream.Position; - bw.Write(variable.PadRight(32, '\0').Substring(0, 32).ToCharArray()); - long currentAddress = bw.BaseStream.Position; - // Go to pointer array - bw.BaseStream.Position = pointerAddress + (4 * counter); - bw.Write(pointer); - counter++; - // Go back to old position - bw.BaseStream.Position = currentAddress; - } - bw.Flush(); - byte[] data = ms.ToArray(); - bw.Close(); - ms.Close(); - - entry.EntryBlocks[0].Data = data; - entry.Dirty = true; - return true; + luaentry.Write(bw); } + var counter = 0; + var pointerAddress = bw.BaseStream.Position; + // Skip pointer address for now + bw.BaseStream.Position = bw.BaseStream.Position + 32; + foreach (string type in types) + { + // Save pointer to text + int pointer = (int)bw.BaseStream.Position; + bw.Write(type.PadRight(32, '\0')[..32].ToCharArray()); + long currentAddress = bw.BaseStream.Position; + // Go to pointer array + bw.BaseStream.Position = pointerAddress + (4 * counter); + bw.Write(pointer); + counter++; + // Go back to old position + bw.BaseStream.Position = currentAddress; + } + counter = 0; + pointerAddress = bw.BaseStream.Position; + // Skip pointer address for now + bw.BaseStream.Position = bw.BaseStream.Position + 32; + foreach (string variable in variables) + { + // Save pointer to text + int pointer = (int)bw.BaseStream.Position; + bw.Write(variable.PadRight(32, '\0')[..32].ToCharArray()); + long currentAddress = bw.BaseStream.Position; + // Go to pointer array + bw.BaseStream.Position = pointerAddress + (4 * counter); + bw.Write(pointer); + counter++; + // Go back to old position + bw.BaseStream.Position = currentAddress; + } + bw.Flush(); + byte[] data = ms.ToArray(); + bw.Close(); + ms.Close(); + + entry.EntryBlocks[0].Data = data; + entry.Dirty = true; + return true; } } diff --git a/LuaList/LuaListEditor.cs b/LuaList/LuaListEditor.cs index 3b85173..68cdb63 100644 --- a/LuaList/LuaListEditor.cs +++ b/LuaList/LuaListEditor.cs @@ -2,39 +2,38 @@ using System.ComponentModel; using System.Windows.Forms; -namespace LuaList +namespace LuaList; + +public delegate void Notify(); // delegate +public partial class LuaListEditor : Form, IEntryEditor { - public delegate void Notify(); // delegate - public partial class LuaListEditor : Form, IEntryEditor - { - public event Notify EditEvent; + public event Notify EditEvent; - private LuaList _luaList; - [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] - public LuaList LuaList + private LuaList _luaList; + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public LuaList LuaList + { + get => _luaList; + set { - get => _luaList; - set - { - _luaList = value; - UpdateComponent(); - } + _luaList = value; + UpdateComponent(); } + } - public void UpdateComponent() - { - propertyGrid1.SelectedObject = LuaList; - } + public void UpdateComponent() + { + propertyGrid1.SelectedObject = LuaList; + } - public LuaListEditor() - { - InitializeComponent(); - UpdateComponent(); - } + public LuaListEditor() + { + InitializeComponent(); + UpdateComponent(); + } - private void LuaListEditor_FormClosed(object s, FormClosedEventArgs e) - { - EditEvent?.Invoke(); - } + private void LuaListEditor_FormClosed(object s, FormClosedEventArgs e) + { + EditEvent?.Invoke(); } } diff --git a/LuaList/LuaListEntry.cs b/LuaList/LuaListEntry.cs index 50be58d..02567a6 100644 --- a/LuaList/LuaListEntry.cs +++ b/LuaList/LuaListEntry.cs @@ -1,76 +1,74 @@ using BundleUtilities; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Text; using System.ComponentModel; using System; -namespace LuaList +namespace LuaList; + +public enum ScoreMultiplier { + StandardPoints = 0, + DoublePoints = 1 , + TriplePoints = 2 +} + +public enum ScoringMethod +{ + ScoreByPosition = 0, + ScoreBySuccessOrFail = 1 +} + +public class LuaListEntry { - public enum ScoreMultiplier { - StandardPoints = 0, - DoublePoints = 1 , - TriplePoints = 2 + [TypeConverter(typeof(EncryptedStringConverter))] + public EncryptedString CgsId { get; set; } = new EncryptedString("SC_1000000"); + public string Name { get; set; } = ""; + public string Goal { get; set; } = ""; + public string Description { get; set; } = ""; + public ScoreMultiplier ScoreMultiplier { get; set; } = ScoreMultiplier.StandardPoints; + public ScoringMethod ScoringMethod { get; set; } = ScoringMethod.ScoreBySuccessOrFail; + public int Type { get; set; } = 0; + public int Variables { get; set; } = 0; + + public int getDataSize() { + List bytes = + [ + BitConverter.GetBytes(CgsId.Encrypted), + Encoding.ASCII.GetBytes((Name.PadRight(128, '\0')[..128].ToCharArray())), + Encoding.ASCII.GetBytes((Goal.PadRight(128, '\0')[..128].ToCharArray())), + Encoding.ASCII.GetBytes((Description.PadRight(256, '\0')[..256].ToCharArray())), + BitConverter.GetBytes((int)ScoreMultiplier), + BitConverter.GetBytes((int)ScoringMethod), + BitConverter.GetBytes((int)Type), + BitConverter.GetBytes((int)Variables), + new byte[8] + ]; + return bytes.SelectMany(i => i).Count(); } - public enum ScoringMethod - { - ScoreByPosition = 0, - ScoreBySuccessOrFail = 1 + public void Read(ILoader loader, BinaryReader2 br) { + CgsId = new EncryptedString(br.ReadUInt64()); + Name = br.ReadLenString(128); + Goal = br.ReadLenString(128); + Description = br.ReadLenString(256); + ScoreMultiplier = (ScoreMultiplier) br.ReadInt32(); + ScoringMethod = (ScoringMethod) br.ReadInt32(); + Type = br.ReadInt32(); + Variables = br.ReadInt32(); + br.ReadBytes(8); // padding } - public class LuaListEntry + public void Write(BinaryWriter2 bw) { - [TypeConverter(typeof(EncryptedStringConverter))] - public EncryptedString CgsId { get; set; } = new EncryptedString("SC_1000000"); - public string Name { get; set; } = ""; - public string Goal { get; set; } = ""; - public string Description { get; set; } = ""; - public ScoreMultiplier ScoreMultiplier { get; set; } = ScoreMultiplier.StandardPoints; - public ScoringMethod ScoringMethod { get; set; } = ScoringMethod.ScoreBySuccessOrFail; - public int Type { get; set; } = 0; - public int Variables { get; set; } = 0; - - public int getDataSize() { - List bytes = new List - { - BitConverter.GetBytes(CgsId.Encrypted), - Encoding.ASCII.GetBytes((Name.PadRight(128, '\0').Substring(0, 128).ToCharArray())), - Encoding.ASCII.GetBytes((Goal.PadRight(128, '\0').Substring(0, 128).ToCharArray())), - Encoding.ASCII.GetBytes((Description.PadRight(256, '\0').Substring(0, 256).ToCharArray())), - BitConverter.GetBytes((int)ScoreMultiplier), - BitConverter.GetBytes((int)ScoringMethod), - BitConverter.GetBytes((int)Type), - BitConverter.GetBytes((int)Variables), - new byte[8] - }; - return bytes.SelectMany(i => i).Count(); - } - - public void Read(ILoader loader, BinaryReader2 br) { - CgsId = new EncryptedString(br.ReadUInt64()); - Name = br.ReadLenString(128); - Goal = br.ReadLenString(128); - Description = br.ReadLenString(256); - ScoreMultiplier = (ScoreMultiplier) br.ReadInt32(); - ScoringMethod = (ScoringMethod) br.ReadInt32(); - Type = br.ReadInt32(); - Variables = br.ReadInt32(); - br.ReadBytes(8); // padding - } - - public void Write(BinaryWriter2 bw) - { - bw.Write(CgsId.Encrypted); - bw.Write(Encoding.ASCII.GetBytes((Name.PadRight(128, '\0').Substring(0, 128).ToCharArray()))); - bw.Write(Encoding.ASCII.GetBytes((Goal.PadRight(128, '\0').Substring(0, 128).ToCharArray()))); - bw.Write(Encoding.ASCII.GetBytes((Description.PadRight(256, '\0').Substring(0, 256).ToCharArray()))); - bw.Write((int)ScoreMultiplier); - bw.Write((int)ScoringMethod); - bw.Write(Type); - bw.Write(Variables); - bw.WriteUniquePadding(8); - } + bw.Write(CgsId.Encrypted); + bw.Write(Encoding.ASCII.GetBytes((Name.PadRight(128, '\0')[..128].ToCharArray()))); + bw.Write(Encoding.ASCII.GetBytes((Goal.PadRight(128, '\0')[..128].ToCharArray()))); + bw.Write(Encoding.ASCII.GetBytes((Description.PadRight(256, '\0')[..256].ToCharArray()))); + bw.Write((int)ScoreMultiplier); + bw.Write((int)ScoringMethod); + bw.Write(Type); + bw.Write(Variables); + bw.WriteUniquePadding(8); } } diff --git a/LuaList/LuaListPlugin.cs b/LuaList/LuaListPlugin.cs index 7dae64a..0e123e1 100644 --- a/LuaList/LuaListPlugin.cs +++ b/LuaList/LuaListPlugin.cs @@ -1,17 +1,16 @@ using BundleFormat; using PluginAPI; -namespace LuaList -{ +namespace LuaList; + - public class LuaListPlugin : IPlugin +public class LuaListPlugin : IPlugin +{ + public string Id => "lualistplugin"; + public string Name => "Lua List Resource Handler"; + + public static void Init() { - public string Id => "lualistplugin"; - public string Name => "Lua List Resource Handler"; - - public static void Init() - { - EntryTypeRegistry.Register(EntryType.LUAList, new LuaList()); - } + EntryTypeRegistry.Register(EntryType.LUAList, new LuaList()); } } diff --git a/MathLib/BoxF.cs b/MathLib/BoxF.cs index bcab9ba..97e06d0 100644 --- a/MathLib/BoxF.cs +++ b/MathLib/BoxF.cs @@ -1,27 +1,26 @@ using OpenTK.Mathematics; -namespace MathLib +namespace MathLib; + +public class BoxF { - public class BoxF - { - public Vector3 Min; - public Vector3 Max; + public Vector3 Min; + public Vector3 Max; - public BoxF() - { - Min = Vector3.Zero; - Max = Vector3.One; - } + public BoxF() + { + Min = Vector3.Zero; + Max = Vector3.One; + } - public BoxF(Vector3 min, Vector3 max) - { - Min = min; - Max = max; - } + public BoxF(Vector3 min, Vector3 max) + { + Min = min; + Max = max; + } - public override string ToString() - { - return "(" + Min.ToString() + ", " + Max.ToString() + ")"; - } + public override string ToString() + { + return "(" + Min.ToString() + ", " + Max.ToString() + ")"; } } diff --git a/MathLib/IOExtensions.cs b/MathLib/IOExtensions.cs index 4706da4..3e11ba8 100644 --- a/MathLib/IOExtensions.cs +++ b/MathLib/IOExtensions.cs @@ -1,184 +1,183 @@ using OpenTK.Mathematics; using System.IO; -namespace MathLib +namespace MathLib; + +public static class IOExtensions { - public static class IOExtensions + public static Matrix4 ReadMatrix4(this BinaryReader self) { - public static Matrix4 ReadMatrix4(this BinaryReader self) + Matrix4 result = new(); + + for (int i = 0; i < 4; i++) { - Matrix4 result = new Matrix4(); - - for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) { - for (int j = 0; j < 4; j++) - { - result[i, j] = self.ReadSingle(); - } + result[i, j] = self.ReadSingle(); } - - return result; } + + return result; + } - public static void Write(this BinaryWriter self, Matrix4 value) + public static void Write(this BinaryWriter self, Matrix4 value) + { + for (int i = 0; i < 4; i++) { - for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) { - for (int j = 0; j < 4; j++) - { - self.Write(value[i, j]); - } + self.Write(value[i, j]); } } + } - public static Vector3 ReadVector3F(this BinaryReader self) - { - Vector3 result = new Vector3(); + public static Vector3 ReadVector3F(this BinaryReader self) + { + Vector3 result = new(); - result.X = self.ReadSingle(); - result.Y = self.ReadSingle(); - result.Z = self.ReadSingle(); + result.X = self.ReadSingle(); + result.Y = self.ReadSingle(); + result.Z = self.ReadSingle(); - return result; - } + return result; + } - public static void Write(this BinaryWriter self, Vector3 value) - { - self.Write(value.X); - self.Write(value.Y); - self.Write(value.Z); - } + public static void Write(this BinaryWriter self, Vector3 value) + { + self.Write(value.X); + self.Write(value.Y); + self.Write(value.Z); + } - public static Vector3I ReadVector3I(this BinaryReader self) - { - Vector3I result = new Vector3I(); + public static Vector3I ReadVector3I(this BinaryReader self) + { + Vector3I result = new(); - result.X = self.ReadInt32(); - result.Y = self.ReadInt32(); - result.Z = self.ReadInt32(); + result.X = self.ReadInt32(); + result.Y = self.ReadInt32(); + result.Z = self.ReadInt32(); - return result; - } + return result; + } - public static void Write(this BinaryWriter self, Vector3I value) - { - self.Write(value.X); - self.Write(value.Y); - self.Write(value.Z); - } + public static void Write(this BinaryWriter self, Vector3I value) + { + self.Write(value.X); + self.Write(value.Y); + self.Write(value.Z); + } - public static Vector2I ReadVector2I(this BinaryReader self) - { - Vector2I result = new Vector2I(); + public static Vector2I ReadVector2I(this BinaryReader self) + { + Vector2I result = new(); - result.X = self.ReadInt32(); - result.Y = self.ReadInt32(); + result.X = self.ReadInt32(); + result.Y = self.ReadInt32(); - return result; - } + return result; + } - public static void Write(this BinaryWriter self, Vector2I value) - { - self.Write(value.X); - self.Write(value.Y); - } + public static void Write(this BinaryWriter self, Vector2I value) + { + self.Write(value.X); + self.Write(value.Y); + } - public static Vector3S ReadVector3S(this BinaryReader self) - { - Vector3S result = new Vector3S(); + public static Vector3S ReadVector3S(this BinaryReader self) + { + Vector3S result = new(); - result.X = self.ReadInt16(); - result.Y = self.ReadInt16(); - result.Z = self.ReadInt16(); + result.X = self.ReadInt16(); + result.Y = self.ReadInt16(); + result.Z = self.ReadInt16(); - return result; - } + return result; + } - public static void Write(this BinaryWriter self, Vector3S value) - { - self.Write(value.X); - self.Write(value.Y); - self.Write(value.Z); - } + public static void Write(this BinaryWriter self, Vector3S value) + { + self.Write(value.X); + self.Write(value.Y); + self.Write(value.Z); + } - public static BoxF ReadBoxF(this BinaryReader self) - { - BoxF result = new BoxF(); + public static BoxF ReadBoxF(this BinaryReader self) + { + BoxF result = new(); - result.Min = self.ReadVector3F(); - result.Max = self.ReadVector3F(); + result.Min = self.ReadVector3F(); + result.Max = self.ReadVector3F(); - return result; - } + return result; + } - public static void Write(this BinaryWriter self, BoxF value) - { - self.Write(value.Min); - self.Write(value.Max); - } + public static void Write(this BinaryWriter self, BoxF value) + { + self.Write(value.Min); + self.Write(value.Max); + } - public static RectF ReadRectF(this BinaryReader self) - { - RectF result = new RectF(); + public static RectF ReadRectF(this BinaryReader self) + { + RectF result = new(); - result.X = self.ReadSingle(); - result.Width = self.ReadSingle(); - result.Y = self.ReadSingle(); - result.Height = self.ReadSingle(); + result.X = self.ReadSingle(); + result.Width = self.ReadSingle(); + result.Y = self.ReadSingle(); + result.Height = self.ReadSingle(); - return result; - } + return result; + } - public static void Write(this BinaryWriter self, RectF value) - { - self.Write(value.X); - self.Write(value.Width); - self.Write(value.Y); - self.Write(value.Height); - } + public static void Write(this BinaryWriter self, RectF value) + { + self.Write(value.X); + self.Write(value.Width); + self.Write(value.Y); + self.Write(value.Height); + } - public static Triangle ReadTriangle(this BinaryReader self) - { - Triangle result = new Triangle(); + public static Triangle ReadTriangle(this BinaryReader self) + { + Triangle result = new(); - result.Index0 = self.ReadInt16(); - result.Index1 = self.ReadInt16(); - result.Index2 = self.ReadInt16(); + result.Index0 = self.ReadInt16(); + result.Index1 = self.ReadInt16(); + result.Index2 = self.ReadInt16(); - return result; - } + return result; + } - public static void Write(this BinaryWriter self, Triangle value) - { - self.Write(value.Index0); - self.Write(value.Index1); - self.Write(value.Index2); - } + public static void Write(this BinaryWriter self, Triangle value) + { + self.Write(value.Index0); + self.Write(value.Index1); + self.Write(value.Index2); + } - public static Matrix3x2 ReadMatrix3x2(this BinaryReader self) - { - Matrix3x2 result = new Matrix3x2(); + public static Matrix3x2 ReadMatrix3x2(this BinaryReader self) + { + Matrix3x2 result = new(); - // TODO: Verify - for (int i = 0; i < 3; i++) + // TODO: Verify + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 2; j++) { - for (int j = 0; j < 2; j++) - { - result[i, j] = self.ReadSingle(); - } + result[i, j] = self.ReadSingle(); } - - return result; } - public static void Write(this BinaryWriter self, Matrix3x2 value) + return result; + } + + public static void Write(this BinaryWriter self, Matrix3x2 value) + { + for (int i = 0; i < 3; i++) { - for (int i = 0; i < 3; i++) + for (int j = 0; j < 2; j++) { - for (int j = 0; j < 2; j++) - { - self.Write(value[i, j]); - } + self.Write(value[i, j]); } } } diff --git a/MathLib/MathUtils.cs b/MathLib/MathUtils.cs index bf047e0..b83e907 100644 --- a/MathLib/MathUtils.cs +++ b/MathLib/MathUtils.cs @@ -1,32 +1,31 @@ using OpenTK.Mathematics; using System; -namespace MathLib +namespace MathLib; + +public static class MathUtils { - public static class MathUtils + public static Vector3 MinBounds(params Vector3[] points) { - public static Vector3 MinBounds(params Vector3[] points) + Vector3 result = new(points[0].X, points[0].Y, points[0].Z); + for (int i = 1; i < points.Length; i++) { - Vector3 result = new Vector3(points[0].X, points[0].Y, points[0].Z); - for (int i = 1; i < points.Length; i++) - { - result.X = Math.Min(points[i].X, result.X); - result.Y = Math.Min(points[i].Y, result.Y); - result.Z = Math.Min(points[i].Z, result.Z); - } - return result; + result.X = Math.Min(points[i].X, result.X); + result.Y = Math.Min(points[i].Y, result.Y); + result.Z = Math.Min(points[i].Z, result.Z); } + return result; + } - public static Vector3 MaxBounds(params Vector3[] points) + public static Vector3 MaxBounds(params Vector3[] points) + { + Vector3 result = new(points[0].X, points[0].Y, points[0].Z); + for (int i = 1; i < points.Length; i++) { - Vector3 result = new Vector3(points[0].X, points[0].Y, points[0].Z); - for (int i = 1; i < points.Length; i++) - { - result.X = Math.Max(points[i].X, result.X); - result.Y = Math.Max(points[i].Y, result.Y); - result.Z = Math.Max(points[i].Z, result.Z); - } - return result; + result.X = Math.Max(points[i].X, result.X); + result.Y = Math.Max(points[i].Y, result.Y); + result.Z = Math.Max(points[i].Z, result.Z); } + return result; } } diff --git a/MathLib/RectF.cs b/MathLib/RectF.cs index 6dfe997..bdbb684 100644 --- a/MathLib/RectF.cs +++ b/MathLib/RectF.cs @@ -1,15 +1,14 @@ -namespace MathLib +namespace MathLib; + +public class RectF { - public class RectF - { - public float X; - public float Width; - public float Y; - public float Height; + public float X; + public float Width; + public float Y; + public float Height; - public override string ToString() - { - return "{X: " + X + ", Y: " + Y + ", Width: " + Width + ", Height: " + Height + "}"; - } + public override string ToString() + { + return "{X: " + X + ", Y: " + Y + ", Width: " + Width + ", Height: " + Height + "}"; } } diff --git a/MathLib/Triangle.cs b/MathLib/Triangle.cs index 2ef0c29..ea3ba8b 100644 --- a/MathLib/Triangle.cs +++ b/MathLib/Triangle.cs @@ -1,9 +1,8 @@ -namespace MathLib +namespace MathLib; + +public class Triangle { - public class Triangle - { - public short Index0; - public short Index1; - public short Index2; - } + public short Index0; + public short Index1; + public short Index2; } diff --git a/MathLib/Vector2i.cs b/MathLib/Vector2i.cs index dd76145..001ad32 100644 --- a/MathLib/Vector2i.cs +++ b/MathLib/Vector2i.cs @@ -1,87 +1,86 @@ using System; using OpenTK.Mathematics; -namespace MathLib +namespace MathLib; + +public struct Vector2I { - public struct Vector2I + public int X, Y; + + public Vector2I(int x, int y) + { + X = x; + Y = y; + } + + public Vector2I(Vector2 vec2) + { + X = (int)Math.Round(vec2.X); + Y = (int)Math.Round(vec2.Y); + } + + public static Vector2I operator +(Vector2I v1, Vector2I v2) + { + return new Vector2I(v1.X + v2.X, v1.Y + v2.Y); + } + + public static Vector2I operator +(Vector2I v, int i) + { + return new Vector2I(v.X + i, v.Y + i); + } + + public static Vector2I operator +(Vector2I v, float f) + { + return new Vector2I((int)(v.X + f), (int)(v.Y + f)); + } + + public static Vector2I operator -(Vector2I v1, Vector2I v2) + { + return new Vector2I(v1.X - v2.X, v1.Y - v2.Y); + } + + public static Vector2I operator -(Vector2I v, int i) + { + return new Vector2I(v.X - i, v.Y - i); + } + + public static Vector2I operator -(Vector2I v, float f) + { + return new Vector2I((int)(v.X - f), (int)(v.Y - f)); + } + + public static Vector2I operator *(Vector2I v1, Vector2I v2) + { + return new Vector2I(v1.X * v2.X, v1.Y * v2.Y); + } + + public static Vector2I operator *(Vector2I v, int i) + { + return new Vector2I(v.X * i, v.Y * i); + } + + public static Vector2I operator *(Vector2I v, float f) + { + return new Vector2I((int)(v.X * f), (int)(v.Y * f)); + } + + public static Vector2I operator /(Vector2I v1, Vector2I v2) + { + return new Vector2I(v1.X / v2.X, v1.Y / v2.Y); + } + + public static Vector2I operator /(Vector2I v, int i) + { + return new Vector2I(v.X / i, v.Y / i); + } + + public static Vector2I operator /(Vector2I v, float f) + { + return new Vector2I((int)(v.X / f), (int)(v.Y / f)); + } + + public override string ToString() { - public int X, Y; - - public Vector2I(int x, int y) - { - X = x; - Y = y; - } - - public Vector2I(Vector2 vec2) - { - X = (int)Math.Round(vec2.X); - Y = (int)Math.Round(vec2.Y); - } - - public static Vector2I operator +(Vector2I v1, Vector2I v2) - { - return new Vector2I(v1.X + v2.X, v1.Y + v2.Y); - } - - public static Vector2I operator +(Vector2I v, int i) - { - return new Vector2I(v.X + i, v.Y + i); - } - - public static Vector2I operator +(Vector2I v, float f) - { - return new Vector2I((int)(v.X + f), (int)(v.Y + f)); - } - - public static Vector2I operator -(Vector2I v1, Vector2I v2) - { - return new Vector2I(v1.X - v2.X, v1.Y - v2.Y); - } - - public static Vector2I operator -(Vector2I v, int i) - { - return new Vector2I(v.X - i, v.Y - i); - } - - public static Vector2I operator -(Vector2I v, float f) - { - return new Vector2I((int)(v.X - f), (int)(v.Y - f)); - } - - public static Vector2I operator *(Vector2I v1, Vector2I v2) - { - return new Vector2I(v1.X * v2.X, v1.Y * v2.Y); - } - - public static Vector2I operator *(Vector2I v, int i) - { - return new Vector2I(v.X * i, v.Y * i); - } - - public static Vector2I operator *(Vector2I v, float f) - { - return new Vector2I((int)(v.X * f), (int)(v.Y * f)); - } - - public static Vector2I operator /(Vector2I v1, Vector2I v2) - { - return new Vector2I(v1.X / v2.X, v1.Y / v2.Y); - } - - public static Vector2I operator /(Vector2I v, int i) - { - return new Vector2I(v.X / i, v.Y / i); - } - - public static Vector2I operator /(Vector2I v, float f) - { - return new Vector2I((int)(v.X / f), (int)(v.Y / f)); - } - - public override string ToString() - { - return "(" + X + ", " + Y + ")"; - } + return "(" + X + ", " + Y + ")"; } } diff --git a/MathLib/Vector3i.cs b/MathLib/Vector3i.cs index 5185cc3..d318d66 100644 --- a/MathLib/Vector3i.cs +++ b/MathLib/Vector3i.cs @@ -1,89 +1,88 @@ using System; using OpenTK.Mathematics; -namespace MathLib +namespace MathLib; + +public struct Vector3I { - public struct Vector3I + public int X, Y, Z; + + public Vector3I(int x, int y, int z) + { + X = x; + Y = y; + Z = z; + } + + public Vector3I(Vector3 vec3) + { + X = (int)Math.Round(vec3.X); + Y = (int)Math.Round(vec3.Y); + Z = (int)Math.Round(vec3.Z); + } + + public static Vector3I operator +(Vector3I v1, Vector3I v2) + { + return new Vector3I(v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z); + } + + public static Vector3I operator +(Vector3I v, int i) + { + return new Vector3I(v.X + i, v.Y + i, v.Z + i); + } + + public static Vector3I operator +(Vector3I v, float f) + { + return new Vector3I((int)(v.X + f), (int)(v.Y + f), (int)(v.Z + f)); + } + + public static Vector3I operator -(Vector3I v1, Vector3I v2) + { + return new Vector3I(v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z); + } + + public static Vector3I operator -(Vector3I v, int i) + { + return new Vector3I(v.X - i, v.Y - i, v.Z - i); + } + + public static Vector3I operator -(Vector3I v, float f) + { + return new Vector3I((int)(v.X - f), (int)(v.Y - f), (int)(v.Z - f)); + } + + public static Vector3I operator *(Vector3I v1, Vector3I v2) + { + return new Vector3I(v1.X * v2.X, v1.Y * v2.Y, v1.Z * v2.Z); + } + + public static Vector3I operator *(Vector3I v, int i) + { + return new Vector3I(v.X * i, v.Y * i, v.Z * i); + } + + public static Vector3I operator *(Vector3I v, float f) + { + return new Vector3I((int)(v.X * f), (int)(v.Y * f), (int)(v.Z * f)); + } + + public static Vector3I operator /(Vector3I v1, Vector3I v2) + { + return new Vector3I(v1.X / v2.X, v1.Y / v2.Y, v1.Z / v2.Z); + } + + public static Vector3I operator /(Vector3I v, int i) + { + return new Vector3I(v.X / i, v.Y / i, v.Z / i); + } + + public static Vector3I operator /(Vector3I v, float f) + { + return new Vector3I((int)(v.X / f), (int)(v.Y / f), (int)(v.Z / f)); + } + + public override string ToString() { - public int X, Y, Z; - - public Vector3I(int x, int y, int z) - { - X = x; - Y = y; - Z = z; - } - - public Vector3I(Vector3 vec3) - { - X = (int)Math.Round(vec3.X); - Y = (int)Math.Round(vec3.Y); - Z = (int)Math.Round(vec3.Z); - } - - public static Vector3I operator +(Vector3I v1, Vector3I v2) - { - return new Vector3I(v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z); - } - - public static Vector3I operator +(Vector3I v, int i) - { - return new Vector3I(v.X + i, v.Y + i, v.Z + i); - } - - public static Vector3I operator +(Vector3I v, float f) - { - return new Vector3I((int)(v.X + f), (int)(v.Y + f), (int)(v.Z + f)); - } - - public static Vector3I operator -(Vector3I v1, Vector3I v2) - { - return new Vector3I(v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z); - } - - public static Vector3I operator -(Vector3I v, int i) - { - return new Vector3I(v.X - i, v.Y - i, v.Z - i); - } - - public static Vector3I operator -(Vector3I v, float f) - { - return new Vector3I((int)(v.X - f), (int)(v.Y - f), (int)(v.Z - f)); - } - - public static Vector3I operator *(Vector3I v1, Vector3I v2) - { - return new Vector3I(v1.X * v2.X, v1.Y * v2.Y, v1.Z * v2.Z); - } - - public static Vector3I operator *(Vector3I v, int i) - { - return new Vector3I(v.X * i, v.Y * i, v.Z * i); - } - - public static Vector3I operator *(Vector3I v, float f) - { - return new Vector3I((int)(v.X * f), (int)(v.Y * f), (int)(v.Z * f)); - } - - public static Vector3I operator /(Vector3I v1, Vector3I v2) - { - return new Vector3I(v1.X / v2.X, v1.Y / v2.Y, v1.Z / v2.Z); - } - - public static Vector3I operator /(Vector3I v, int i) - { - return new Vector3I(v.X / i, v.Y / i, v.Z / i); - } - - public static Vector3I operator /(Vector3I v, float f) - { - return new Vector3I((int)(v.X / f), (int)(v.Y / f), (int)(v.Z / f)); - } - - public override string ToString() - { - return "(" + X + ", " + Y + ", " + Z + ")"; - } + return "(" + X + ", " + Y + ", " + Z + ")"; } } diff --git a/MathLib/Vector3s.cs b/MathLib/Vector3s.cs index 16c42bb..7999a15 100644 --- a/MathLib/Vector3s.cs +++ b/MathLib/Vector3s.cs @@ -1,31 +1,30 @@ using System; using OpenTK.Mathematics; -namespace MathLib +namespace MathLib; + +public struct Vector3S { - public struct Vector3S - { - public short X; - public short Y; - public short Z; + public short X; + public short Y; + public short Z; - public Vector3S(short x, short y, short z) - { - X = x; - Y = y; - Z = z; - } + public Vector3S(short x, short y, short z) + { + X = x; + Y = y; + Z = z; + } - public Vector3S(Vector3 vec3) - { - X = (short)Math.Round(vec3.X); - Y = (short)Math.Round(vec3.Y); - Z = (short)Math.Round(vec3.Z); - } + public Vector3S(Vector3 vec3) + { + X = (short)Math.Round(vec3.X); + Y = (short)Math.Round(vec3.Y); + Z = (short)Math.Round(vec3.Z); + } - public override string ToString() - { - return "(" + X + ", " + Y + ", " + Z + ")"; - } + public override string ToString() + { + return "(" + X + ", " + Y + ", " + Z + ")"; } } diff --git a/ModelViewer/GenericMesh.cs b/ModelViewer/GenericMesh.cs index 8f19b69..4da1d87 100644 --- a/ModelViewer/GenericMesh.cs +++ b/ModelViewer/GenericMesh.cs @@ -2,47 +2,46 @@ using ModelViewer.SceneData; using OpenTK.Mathematics; -namespace ModelViewer -{ - public class Face - { - public List Indices; - public List UVIndices; - public Material Material; +namespace ModelViewer; - public Face(Material material = null) - { - Indices = new List(); - UVIndices = new List(); - Material = material; - } +public class Face +{ + public List Indices; + public List UVIndices; + public Material Material; - public Face(uint[] indices, uint[] uvIndices = null, Material material = null) : this(material) - { - Indices.AddRange(indices); - if (uvIndices != null) - UVIndices.AddRange(uvIndices); - } + public Face(Material material = null) + { + Indices = []; + UVIndices = []; + Material = material; } - public class GenericMesh + public Face(uint[] indices, uint[] uvIndices = null, Material material = null) : this(material) { - public string Name; - public Dictionary Vertices; - public Dictionary UVs; - public List Faces; + Indices.AddRange(indices); + if (uvIndices != null) + UVIndices.AddRange(uvIndices); + } +} - public GenericMesh() - { - Name = ""; - Vertices = new Dictionary(); - UVs = new Dictionary(); - Faces = new List(); - } +public class GenericMesh +{ + public string Name; + public Dictionary Vertices; + public Dictionary UVs; + public List Faces; - public GenericMesh(string name) : this() - { - Name = name; - } + public GenericMesh() + { + Name = ""; + Vertices = []; + UVs = []; + Faces = []; + } + + public GenericMesh(string name) : this() + { + Name = name; } } diff --git a/ModelViewer/GenericModel.cs b/ModelViewer/GenericModel.cs index fab2fa3..a22fddb 100644 --- a/ModelViewer/GenericModel.cs +++ b/ModelViewer/GenericModel.cs @@ -1,87 +1,86 @@ using System.Collections.Generic; -namespace ModelViewer +namespace ModelViewer; + +public class GenericModel { - public class GenericModel - { - public List Meshes; + public List Meshes; - public GenericModel() - { - Meshes = new List(); - } + public GenericModel() + { + Meshes = []; + } - public void SplitByPointCount(int pointCount) - { - //pointCount /= 3; - /*List newMeshes = new List(); + public void SplitByPointCount(int pointCount) + { + //pointCount /= 3; + /*List newMeshes = new List(); - List meshesToSplit = new List(); + List meshesToSplit = new List(); - for (int i = 0; i < Meshes.Count; i++) + for (int i = 0; i < Meshes.Count; i++) + { + GenericMesh mesh = Meshes[i]; + uint count = 0; + foreach (uint key in mesh.Vertices.Keys) { - GenericMesh mesh = Meshes[i]; - uint count = 0; - foreach (uint key in mesh.Vertices.Keys) - { - if (count < key) - { - count = key; - } - } - count++; - - if (count > 256) - { - meshesToSplit.Add(i); - } - else + if (count < key) { - newMeshes.Add(mesh); + count = key; } } + count++; - foreach (int meshIndex in meshesToSplit) + if (count > 256) { - GenericMesh mesh = Meshes[meshIndex]; + meshesToSplit.Add(i); + } + else + { + newMeshes.Add(mesh); + } + } - List newFaces = new List(); - - for (int i = 0; i < mesh.Faces.Count; i += pointCount) - { - int remaining = mesh.Faces.Count - i; - if (remaining < pointCount) - newFaces.AddRange(mesh.Faces.GetRange(i, Math.Abs(remaining))); - else - newFaces.AddRange(mesh.Faces.GetRange(i, pointCount)); - } + foreach (int meshIndex in meshesToSplit) + { + GenericMesh mesh = Meshes[meshIndex]; + + List newFaces = new List(); + + for (int i = 0; i < mesh.Faces.Count; i += pointCount) + { + int remaining = mesh.Faces.Count - i; + if (remaining < pointCount) + newFaces.AddRange(mesh.Faces.GetRange(i, Math.Abs(remaining))); + else + newFaces.AddRange(mesh.Faces.GetRange(i, pointCount)); + } - for (int i = 0; i < newFaces.Count; i++) + for (int i = 0; i < newFaces.Count; i++) + { + Face face = newFaces[i]; + GenericMesh newMesh = new GenericMesh(); + for (int j = 0; j < face.Indices.Count; j++) { - Face face = newFaces[i]; - GenericMesh newMesh = new GenericMesh(); - for (int j = 0; j < face.Indices.Count; j++) + uint oldIndex = face.Indices[j]; + while (face.Indices[j] > pointCount) { - uint oldIndex = face.Indices[j]; - while (face.Indices[j] > pointCount) - { - face.Indices[j] -= (uint) pointCount; - } - Vector3 point = mesh.Vertices[oldIndex]; - newMesh.Vertices.Add(face.Indices[j], point); + face.Indices[j] -= (uint) pointCount; } - newMesh.Faces.Add(face); - newMesh.Name = mesh.Name + "." + i; + Vector3 point = mesh.Vertices[oldIndex]; + newMesh.Vertices.Add(face.Indices[j], point); + } + newMesh.Faces.Add(face); + newMesh.Name = mesh.Name + "." + i; - // TODO: Deal with UVs + // TODO: Deal with UVs - newMeshes.Add(newMesh); - } + newMeshes.Add(newMesh); } + } - Meshes = newMeshes;*/ + Meshes = newMeshes;*/ - // TODO: Split Meshes by Point Count - } + // TODO: Split Meshes by Point Count } } diff --git a/ModelViewer/GraphicsScene.cs b/ModelViewer/GraphicsScene.cs index 30ea339..c4f0f38 100644 --- a/ModelViewer/GraphicsScene.cs +++ b/ModelViewer/GraphicsScene.cs @@ -6,120 +6,119 @@ using OpenTK.Mathematics; using OpenTK.Graphics.OpenGL; -namespace ModelViewer +namespace ModelViewer; + +public class GraphicsScene { - public class GraphicsScene - { - private Shader _shader; + private Shader _shader; - private ICamera _camera; - private Matrix4 _projection; + private ICamera _camera; + private Matrix4 _projection; - public delegate void OnFrameRendered(); - public event OnFrameRendered FrameRendered; + public delegate void OnFrameRendered(); + public event OnFrameRendered FrameRendered; - public int Width { get; set; } - public int Height { get; set; } + public int Width { get; set; } + public int Height { get; set; } - public bool CanRender { get; set; } + public bool CanRender { get; set; } - public Scene Scene { get; } + public Scene Scene { get; } - public GraphicsScene(Scene scene, int width, int height) - { - Scene = scene; - Width = width; - Height = height; - } + public GraphicsScene(Scene scene, int width, int height) + { + Scene = scene; + Width = width; + Height = height; + } - public void Resize(int width, int height) - { - Width = width; - Height = height; - } + public void Resize(int width, int height) + { + Width = width; + Height = height; + } + + private void CreateProjection() + { + float aspectRatio = (float)Width / Height; + _projection = + Matrix4.CreatePerspectiveFieldOfView(60.0f * ((float) Math.PI / 180.0f), aspectRatio, 0.1f, 4000.0f); + } + + public void Init() + { + if (Scene == null) + return; - private void CreateProjection() + CreateProjection(); + + try { - float aspectRatio = (float)Width / Height; - _projection = - Matrix4.CreatePerspectiveFieldOfView(60.0f * ((float) Math.PI / 180.0f), aspectRatio, 0.1f, 4000.0f); + _shader = new Shader("standard"); } - - public void Init() + catch (IOException ex) { - if (Scene == null) - return; - - CreateProjection(); - - try - { - _shader = new Shader("standard"); - } - catch (IOException ex) - { - Debug.WriteLine(ex.Message + "\n" + ex.StackTrace); - - CanRender = false; - return; - } - _shader.Compile(); - - if (!Scene.InitGraphics()) - return; - - _camera = new OrbitCamera(Scene); - //_camera = new StaticCamera(new Vector3(0, 2, -5), new Vector3(0, 0, 0)); - - GL.ClearColor(Color.CornflowerBlue); - GL.ClearDepth(1.0f); - GL.Enable(EnableCap.Texture2D); - GL.Enable(EnableCap.DepthTest); - GL.DepthFunc(DepthFunction.Lequal); - //glShadeModel(GL_SMOOTH); - GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest); - - CanRender = true; + Debug.WriteLine(ex.Message + "\n" + ex.StackTrace); + + CanRender = false; + return; } + _shader.Compile(); - public void Update() - { - if (!CanRender) - return; + if (!Scene.InitGraphics()) + return; - _camera?.Update(); - Scene?.Update(); + _camera = new OrbitCamera(Scene); + //_camera = new StaticCamera(new Vector3(0, 2, -5), new Vector3(0, 0, 0)); - // TODO: Implement - } + GL.ClearColor(Color.CornflowerBlue); + GL.ClearDepth(1.0f); + GL.Enable(EnableCap.Texture2D); + GL.Enable(EnableCap.DepthTest); + GL.DepthFunc(DepthFunction.Lequal); + //glShadeModel(GL_SMOOTH); + GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest); - public void Render() - { - GL.Viewport(0, 0, Width, Height); + CanRender = true; + } - GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); + public void Update() + { + if (!CanRender) + return; - if (CanRender) - { - _shader.Bind(); + _camera?.Update(); + Scene?.Update(); - GL.UniformMatrix4(20, false, ref _projection); + // TODO: Implement + } - Scene?.Render(_camera); - } + public void Render() + { + GL.Viewport(0, 0, Width, Height); - GL.Flush(); + GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); - FrameRendered?.Invoke(); + if (CanRender) + { + _shader.Bind(); + + GL.UniformMatrix4(20, false, ref _projection); + + Scene?.Render(_camera); } - public void Cleanup() + GL.Flush(); + + FrameRendered?.Invoke(); + } + + public void Cleanup() + { + if (CanRender) { - if (CanRender) - { - Scene?.Dispose(); - _shader.Dispose(); - } + Scene?.Dispose(); + _shader.Dispose(); } } } diff --git a/ModelViewer/GraphicsUtil.cs b/ModelViewer/GraphicsUtil.cs index 97d14ea..4a1e4bc 100644 --- a/ModelViewer/GraphicsUtil.cs +++ b/ModelViewer/GraphicsUtil.cs @@ -1,26 +1,25 @@ using System.Drawing; -namespace ModelViewer +namespace ModelViewer; + +public static class GraphicsUtil { - public static class GraphicsUtil + public static float[] GetTextureData(Bitmap bitmap) { - public static float[] GetTextureData(Bitmap bitmap) + float[] r = new float[bitmap.Width * bitmap.Height * 4]; + int index = 0; + for (int y = 0; y < bitmap.Height; y++) { - float[] r = new float[bitmap.Width * bitmap.Height * 4]; - int index = 0; - for (int y = 0; y < bitmap.Height; y++) + for (int x = 0; x < bitmap.Width; x++) { - for (int x = 0; x < bitmap.Width; x++) - { - var pixel = bitmap.GetPixel(x, y); - r[index++] = pixel.R / 255.0f; - r[index++] = pixel.G / 255.0f; - r[index++] = pixel.B / 255.0f; - r[index++] = pixel.A / 255.0f; - } + var pixel = bitmap.GetPixel(x, y); + r[index++] = pixel.R / 255.0f; + r[index++] = pixel.G / 255.0f; + r[index++] = pixel.B / 255.0f; + r[index++] = pixel.A / 255.0f; } - - return r; } + + return r; } } diff --git a/ModelViewer/ICamera.cs b/ModelViewer/ICamera.cs index 578de79..a2f0fd8 100644 --- a/ModelViewer/ICamera.cs +++ b/ModelViewer/ICamera.cs @@ -1,10 +1,9 @@ using OpenTK.Mathematics; -namespace ModelViewer +namespace ModelViewer; + +public interface ICamera { - public interface ICamera - { - Matrix4 LookAtMatrix { get; } - void Update(); - } + Matrix4 LookAtMatrix { get; } + void Update(); } diff --git a/ModelViewer/ModelViewerForm.cs b/ModelViewer/ModelViewerForm.cs index 6b1d794..3f18cf3 100644 --- a/ModelViewer/ModelViewerForm.cs +++ b/ModelViewer/ModelViewerForm.cs @@ -3,72 +3,71 @@ using ModelViewer.SceneData; using PluginAPI; -namespace ModelViewer +namespace ModelViewer; + +public partial class ModelViewerForm : Form, IEntryEditor { - public partial class ModelViewerForm : Form, IEntryEditor - { - public SceneRenderControl Renderer => rndMain; + public SceneRenderControl Renderer => rndMain; - public ModelViewerForm() - { - InitializeComponent(); - } + public ModelViewerForm() + { + InitializeComponent(); + } - public static void ShowModelViewer(Scene scene) - { - ModelViewerForm viewer = new ModelViewerForm(); - viewer.rndMain.Scene = scene; - viewer.ShowDialog(); - } + public static void ShowModelViewer(Scene scene) + { + ModelViewerForm viewer = new(); + viewer.rndMain.Scene = scene; + viewer.ShowDialog(); + } - public static void ShowModelViewer(IWin32Window owner, Scene scene) - { - ModelViewerForm viewer = new ModelViewerForm(); - viewer.rndMain.Scene = scene; - viewer.ShowDialog(owner); - } + public static void ShowModelViewer(IWin32Window owner, Scene scene) + { + ModelViewerForm viewer = new(); + viewer.rndMain.Scene = scene; + viewer.ShowDialog(owner); + } - public void ExportCollada14() + public void ExportCollada14() + { + SaveFileDialog sfd = new(); + sfd.Filter = "Collada Document|*.dae|All Files|*.*"; + DialogResult result = sfd.ShowDialog(this); + if (result == DialogResult.OK) { - SaveFileDialog sfd = new SaveFileDialog(); - sfd.Filter = "Collada Document|*.dae|All Files|*.*"; - DialogResult result = sfd.ShowDialog(this); - if (result == DialogResult.OK) - { - if (string.IsNullOrEmpty(sfd.FileName)) - return; + if (string.IsNullOrEmpty(sfd.FileName)) + return; - rndMain.Scene.ExportCollada14(sfd.FileName); - } + rndMain.Scene.ExportCollada14(sfd.FileName); } + } - public void ExportWavefrontObj() + public void ExportWavefrontObj() + { + SaveFileDialog sfd = new(); + sfd.Filter = "Wavefront OBJ|*.obj|All Files|*.*"; + DialogResult result = sfd.ShowDialog(this); + if (result == DialogResult.OK) { - SaveFileDialog sfd = new SaveFileDialog(); - sfd.Filter = "Wavefront OBJ|*.obj|All Files|*.*"; - DialogResult result = sfd.ShowDialog(this); - if (result == DialogResult.OK) - { - if (string.IsNullOrEmpty(sfd.FileName)) - return; + if (string.IsNullOrEmpty(sfd.FileName)) + return; - rndMain.Scene.ExportWavefrontObj(sfd.FileName); - } + rndMain.Scene.ExportWavefrontObj(sfd.FileName); } + } - private void closeToolStripMenuItem_Click(object sender, EventArgs e) - { - Close(); - } + private void closeToolStripMenuItem_Click(object sender, EventArgs e) + { + Close(); + } - private void collada14ToolStripMenuItem_Click(object sender, EventArgs e) - { - ExportCollada14(); - } + private void collada14ToolStripMenuItem_Click(object sender, EventArgs e) + { + ExportCollada14(); + } - private void wavefrontOBJToolStripMenuItem_Click(object sender, EventArgs e) - { - ExportWavefrontObj(); - } + private void wavefrontOBJToolStripMenuItem_Click(object sender, EventArgs e) + { + ExportWavefrontObj(); } } diff --git a/ModelViewer/OBJImporter.cs b/ModelViewer/OBJImporter.cs index 0551794..b59c14c 100644 --- a/ModelViewer/OBJImporter.cs +++ b/ModelViewer/OBJImporter.cs @@ -6,204 +6,203 @@ using ModelViewer.SceneData; using OpenTK.Mathematics; -namespace ModelViewer +namespace ModelViewer; + +public static class OBJImporter { - public static class OBJImporter + public static GenericModel ImportOBJ(string path) { - public static GenericModel ImportOBJ(string path) - { - Stream s = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read); - GenericModel result = ImportOBJ(s); - s.Close(); + Stream s = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read); + GenericModel result = ImportOBJ(s); + s.Close(); - return result; - } + return result; + } - public static GenericModel ImportOBJ(Stream s) - { - GenericModel result = new GenericModel(); + public static GenericModel ImportOBJ(Stream s) + { + GenericModel result = new(); + + MemoryStream ms = new(); + s.CopyTo(ms); - MemoryStream ms = new MemoryStream(); - s.CopyTo(ms); + ms.Position = 0; - ms.Position = 0; + StreamReader sr = new(ms); + + try + { + List globalVertices = []; + List globalUVs = []; - StreamReader sr = new StreamReader(ms); + int currentMesh = -1; + uint startIndex = 0; + uint startUVIndex = 0; + Material lastMaterial = null; - try + while (!sr.EndOfStream) { - List globalVertices = new List(); - List globalUVs = new List(); + string line = sr.ReadLine(); - int currentMesh = -1; - uint startIndex = 0; - uint startUVIndex = 0; - Material lastMaterial = null; + if (string.IsNullOrEmpty(line)) + continue; - while (!sr.EndOfStream) - { - string line = sr.ReadLine(); + line = line.Trim(); - if (string.IsNullOrEmpty(line)) - continue; + if (string.IsNullOrEmpty(line)) + continue; - line = line.Trim(); + if (line.StartsWith("v ")) + { + string[] split = line.Split([' '], StringSplitOptions.RemoveEmptyEntries); + if (split.Length < 4) + throw new ReadFailedError("Invalid Vertex: " + line); + + Utilities.Parse(split[1], false, out float x); + Utilities.Parse(split[2], false, out float y); + Utilities.Parse(split[3], false, out float z); + + // Add to global vertices as we might not have a mesh yet. + globalVertices.Add(new Vector3(x, y, z)); + } + else if (line.StartsWith("vt ")) + { + string[] split = line.Split([' '], StringSplitOptions.RemoveEmptyEntries); + if (split.Length < 3) + throw new ReadFailedError("Invalid UV: " + line); - if (string.IsNullOrEmpty(line)) - continue; + Utilities.Parse(split[1], false, out float u); + Utilities.Parse(split[2], false, out float v); - if (line.StartsWith("v ")) + // Add to global uvs as we might not have a mesh yet. + globalUVs.Add(new Vector2(u, v)); + } + else if (line.StartsWith("f ")) + { + string[] split = line.Split([' '], StringSplitOptions.RemoveEmptyEntries); + if (split.Length < 4) + throw new ReadFailedError("Invalid Face: " + line); + + string[] i1 = split[1].Split(['/'], StringSplitOptions.RemoveEmptyEntries); + string[] i2 = split[2].Split(['/'], StringSplitOptions.RemoveEmptyEntries); + string[] i3 = split[3].Split(['/'], StringSplitOptions.RemoveEmptyEntries); + + Utilities.Parse(i1[0], false, out uint v1); + Utilities.Parse(i2[0], false, out uint v2); + Utilities.Parse(i3[0], false, out uint v3); + + bool isQuad = false; + uint v4 = 0; + uint uv4 = 1; + if (split.Length > 5) { - string[] split = line.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries); - if (split.Length < 4) - throw new ReadFailedError("Invalid Vertex: " + line); - - Utilities.Parse(split[1], false, out float x); - Utilities.Parse(split[2], false, out float y); - Utilities.Parse(split[3], false, out float z); - - // Add to global vertices as we might not have a mesh yet. - globalVertices.Add(new Vector3(x, y, z)); + isQuad = true; + string[] i4 = split[5].Split(['/'], StringSplitOptions.RemoveEmptyEntries); + Utilities.Parse(i4[0], false, out v4); + + if (i4.Length > 1) + Utilities.Parse(i4[1], false, out uv4); } - else if (line.StartsWith("vt ")) - { - string[] split = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); - if (split.Length < 3) - throw new ReadFailedError("Invalid UV: " + line); - Utilities.Parse(split[1], false, out float u); - Utilities.Parse(split[2], false, out float v); + uint uv1 = 1; + uint uv2 = 1; + uint uv3 = 1; - // Add to global uvs as we might not have a mesh yet. - globalUVs.Add(new Vector2(u, v)); + if (i1.Length > 1 && i2.Length > 1 && i3.Length > 1) + { + Utilities.Parse(i1[1], false, out uv1); + Utilities.Parse(i2[1], false, out uv2); + Utilities.Parse(i3[1], false, out uv3); } - else if (line.StartsWith("f ")) + + // OBJ is 1-indexed, so convert it to be 0-indexed + v1--; + v2--; + v3--; + if (isQuad) + v4--; + uv1--; + uv2--; + uv3--; + if (isQuad) + uv4--; + + Face face; + if (isQuad) { - string[] split = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); - if (split.Length < 4) - throw new ReadFailedError("Invalid Face: " + line); - - string[] i1 = split[1].Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); - string[] i2 = split[2].Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); - string[] i3 = split[3].Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); - - Utilities.Parse(i1[0], false, out uint v1); - Utilities.Parse(i2[0], false, out uint v2); - Utilities.Parse(i3[0], false, out uint v3); - - bool isQuad = false; - uint v4 = 0; - uint uv4 = 1; - if (split.Length > 5) - { - isQuad = true; - string[] i4 = split[5].Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); - Utilities.Parse(i4[0], false, out v4); - - if (i4.Length > 1) - Utilities.Parse(i4[1], false, out uv4); - } - - uint uv1 = 1; - uint uv2 = 1; - uint uv3 = 1; - - if (i1.Length > 1 && i2.Length > 1 && i3.Length > 1) - { - Utilities.Parse(i1[1], false, out uv1); - Utilities.Parse(i2[1], false, out uv2); - Utilities.Parse(i3[1], false, out uv3); - } - - // OBJ is 1-indexed, so convert it to be 0-indexed - v1--; - v2--; - v3--; - if (isQuad) - v4--; - uv1--; - uv2--; - uv3--; - if (isQuad) - uv4--; - - Face face; - if (isQuad) - { - face = new Face(new[] { v1 - startIndex, v2 - startIndex, v3 - startIndex, v4 - startUVIndex }, - new[] { uv1 - startUVIndex, uv2 - startUVIndex, uv3 - startUVIndex, uv4 - startUVIndex }, lastMaterial); - } - else - { - face = new Face(new[] {v1 - startIndex, v2 - startIndex, v3 - startIndex}, - new[] {uv1 - startUVIndex, uv2 - startUVIndex, uv3 - startUVIndex}, lastMaterial); - } - - // If there is no mesh yet, the file isn't split up into meshes, - // so we should just make one here. - if (currentMesh == -1) - { - result.Meshes.Add(new GenericMesh()); - currentMesh++; - } - - while (globalUVs.Count <= uv1 || globalUVs.Count <= uv2 || globalUVs.Count <= uv3 || (isQuad && globalUVs.Count <= uv4)) - { - globalUVs.Add(new Vector2(0, 0)); - } - - if (!result.Meshes[currentMesh].UVs.ContainsKey(face.UVIndices[0])) - result.Meshes[currentMesh].UVs.Add(face.UVIndices[0], globalUVs[(int)uv1]); - if (!result.Meshes[currentMesh].UVs.ContainsKey(face.UVIndices[1])) - result.Meshes[currentMesh].UVs.Add(face.UVIndices[1], globalUVs[(int)uv2]); - if (!result.Meshes[currentMesh].UVs.ContainsKey(face.UVIndices[2])) - result.Meshes[currentMesh].UVs.Add(face.UVIndices[2], globalUVs[(int)uv3]); - if (isQuad && (!result.Meshes[currentMesh].UVs.ContainsKey(face.UVIndices[3]))) - result.Meshes[currentMesh].UVs.Add(face.UVIndices[3], globalUVs[(int)uv4]); - - if (!result.Meshes[currentMesh].Vertices.ContainsKey(face.Indices[0])) - result.Meshes[currentMesh].Vertices.Add(face.Indices[0], globalVertices[(int)v1]); - if (!result.Meshes[currentMesh].Vertices.ContainsKey(face.Indices[1])) - result.Meshes[currentMesh].Vertices.Add(face.Indices[1], globalVertices[(int)v2]); - if (!result.Meshes[currentMesh].Vertices.ContainsKey(face.Indices[2])) - result.Meshes[currentMesh].Vertices.Add(face.Indices[2], globalVertices[(int)v3]); - if (isQuad && (!result.Meshes[currentMesh].Vertices.ContainsKey(face.Indices[3]))) - result.Meshes[currentMesh].Vertices.Add(face.Indices[3], globalVertices[(int)v4]); - - result.Meshes[currentMesh].Faces.Add(face); + face = new Face([v1 - startIndex, v2 - startIndex, v3 - startIndex, v4 - startUVIndex], + [uv1 - startUVIndex, uv2 - startUVIndex, uv3 - startUVIndex, uv4 - startUVIndex], lastMaterial); } - else if (line.StartsWith("usemtl ")) + else { - string[] split = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); - if (split.Length < 2) - throw new ReadFailedError("Invalid Material: " + line); - lastMaterial = new Material(split[1], Color.White); + face = new Face([v1 - startIndex, v2 - startIndex, v3 - startIndex], + [uv1 - startUVIndex, uv2 - startUVIndex, uv3 - startUVIndex], lastMaterial); } - else if (line.StartsWith("g ")) + + // If there is no mesh yet, the file isn't split up into meshes, + // so we should just make one here. + if (currentMesh == -1) { - string meshName = ""; - string[] split = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); - if (split.Length >= 2) - meshName = split[1]; - result.Meshes.Add(new GenericMesh(meshName)); + result.Meshes.Add(new GenericMesh()); currentMesh++; + } - startIndex = (uint) globalVertices.Count; - startUVIndex = (uint) globalUVs.Count; + while (globalUVs.Count <= uv1 || globalUVs.Count <= uv2 || globalUVs.Count <= uv3 || (isQuad && globalUVs.Count <= uv4)) + { + globalUVs.Add(new Vector2(0, 0)); } + + if (!result.Meshes[currentMesh].UVs.ContainsKey(face.UVIndices[0])) + result.Meshes[currentMesh].UVs.Add(face.UVIndices[0], globalUVs[(int)uv1]); + if (!result.Meshes[currentMesh].UVs.ContainsKey(face.UVIndices[1])) + result.Meshes[currentMesh].UVs.Add(face.UVIndices[1], globalUVs[(int)uv2]); + if (!result.Meshes[currentMesh].UVs.ContainsKey(face.UVIndices[2])) + result.Meshes[currentMesh].UVs.Add(face.UVIndices[2], globalUVs[(int)uv3]); + if (isQuad && (!result.Meshes[currentMesh].UVs.ContainsKey(face.UVIndices[3]))) + result.Meshes[currentMesh].UVs.Add(face.UVIndices[3], globalUVs[(int)uv4]); + + if (!result.Meshes[currentMesh].Vertices.ContainsKey(face.Indices[0])) + result.Meshes[currentMesh].Vertices.Add(face.Indices[0], globalVertices[(int)v1]); + if (!result.Meshes[currentMesh].Vertices.ContainsKey(face.Indices[1])) + result.Meshes[currentMesh].Vertices.Add(face.Indices[1], globalVertices[(int)v2]); + if (!result.Meshes[currentMesh].Vertices.ContainsKey(face.Indices[2])) + result.Meshes[currentMesh].Vertices.Add(face.Indices[2], globalVertices[(int)v3]); + if (isQuad && (!result.Meshes[currentMesh].Vertices.ContainsKey(face.Indices[3]))) + result.Meshes[currentMesh].Vertices.Add(face.Indices[3], globalVertices[(int)v4]); + + result.Meshes[currentMesh].Faces.Add(face); + } + else if (line.StartsWith("usemtl ")) + { + string[] split = line.Split([' '], StringSplitOptions.RemoveEmptyEntries); + if (split.Length < 2) + throw new ReadFailedError("Invalid Material: " + line); + lastMaterial = new Material(split[1], Color.White); + } + else if (line.StartsWith("g ")) + { + string meshName = ""; + string[] split = line.Split([' '], StringSplitOptions.RemoveEmptyEntries); + if (split.Length >= 2) + meshName = split[1]; + result.Meshes.Add(new GenericMesh(meshName)); + currentMesh++; + + startIndex = (uint) globalVertices.Count; + startUVIndex = (uint) globalUVs.Count; } } - catch (NotSupportedException) - { - throw new ReadFailedError("Invalid Values"); - } - finally - { - sr.Close(); - ms.Close(); - } - - return result; } + catch (NotSupportedException) + { + throw new ReadFailedError("Invalid Values"); + } + finally + { + sr.Close(); + ms.Close(); + } + + return result; } } diff --git a/ModelViewer/OrbitCamera.cs b/ModelViewer/OrbitCamera.cs index 2179a28..75af7a1 100644 --- a/ModelViewer/OrbitCamera.cs +++ b/ModelViewer/OrbitCamera.cs @@ -2,53 +2,52 @@ using ModelViewer.SceneData; using OpenTK.Mathematics; -namespace ModelViewer +namespace ModelViewer; + +public class OrbitCamera : ICamera { - public class OrbitCamera : ICamera + public Matrix4 LookAtMatrix { get; private set; } + private readonly Scene _scene; + //private readonly Vector3 _target; + //private readonly float _horizDist; + //private readonly float _vertDist; + private float _angle; + + public OrbitCamera(Scene scene, float startAngle = 0) { - public Matrix4 LookAtMatrix { get; private set; } - private readonly Scene _scene; - //private readonly Vector3 _target; - //private readonly float _horizDist; - //private readonly float _vertDist; - private float _angle; - - public OrbitCamera(Scene scene, float startAngle = 0) - { - //Scene.Center, Scene.HorizSize, Scene.VertSize / 2.0f - //_target = target; - //_horizDist = horizDist; - //_vertDist = vertDist; - _scene = scene; - _angle = startAngle; - } - - public void Update() - { - //float xPos = (float)Math.Cos(MathHelper.DegreesToRadians(_angle)) * _horizDist; - //float yPos = (float)Math.Tan(MathHelper.DegreesToRadians(_angle)) * _horizDist; + //Scene.Center, Scene.HorizSize, Scene.VertSize / 2.0f + //_target = target; + //_horizDist = horizDist; + //_vertDist = vertDist; + _scene = scene; + _angle = startAngle; + } - //Vector3 eye = new Vector3(xPos, _horizDist, yPos); - //eye = new Vector3(0, 2, -5); + public void Update() + { + //float xPos = (float)Math.Cos(MathHelper.DegreesToRadians(_angle)) * _horizDist; + //float yPos = (float)Math.Tan(MathHelper.DegreesToRadians(_angle)) * _horizDist; + + //Vector3 eye = new Vector3(xPos, _horizDist, yPos); + //eye = new Vector3(0, 2, -5); - Vector3 target = _scene.Center; - float horizDist = _scene.HorizSize; - float vertDist = _scene.VertSize; + Vector3 target = _scene.Center; + float horizDist = _scene.HorizSize; + float vertDist = _scene.VertSize; - /*if (Math.Abs(vertDist - target.Y) < 1.2f) - { - vertDist += 4; - horizDist -= 5; - }*/ + /*if (Math.Abs(vertDist - target.Y) < 1.2f) + { + vertDist += 4; + horizDist -= 5; + }*/ - Vector3 eye = new Vector3((float)-Math.Sin(_angle) * horizDist, vertDist, (float)-Math.Cos(_angle) * horizDist); - eye += target; + Vector3 eye = new((float)-Math.Sin(_angle) * horizDist, vertDist, (float)-Math.Cos(_angle) * horizDist); + eye += target; - LookAtMatrix = Matrix4.LookAt(eye, target, Vector3.UnitY); + LookAtMatrix = Matrix4.LookAt(eye, target, Vector3.UnitY); - _angle += 0.025f; - if (_angle >= 2 * Math.PI) - _angle -= 2 * (float)Math.PI; - } + _angle += 0.025f; + if (_angle >= 2 * Math.PI) + _angle -= 2 * (float)Math.PI; } } diff --git a/ModelViewer/SceneData/Material.cs b/ModelViewer/SceneData/Material.cs index 5c76dc0..1d87212 100644 --- a/ModelViewer/SceneData/Material.cs +++ b/ModelViewer/SceneData/Material.cs @@ -1,47 +1,46 @@ using System.Diagnostics.CodeAnalysis; using System.Drawing; -namespace ModelViewer.SceneData +namespace ModelViewer.SceneData; + +public class Material { - public class Material - { - public string Name; - public Image DiffuseMap { get; set; } - public Image NormalMap { get; set; } - public Image SpecularMap { get; set; } + public string Name; + public Image DiffuseMap { get; set; } + public Image NormalMap { get; set; } + public Image SpecularMap { get; set; } - public Color Color { get; set; } + public Color Color { get; set; } - public Material(string name, Color color, Image diffuse = null, Image normal = null, Image specular = null) - { - Name = name; - Color = color; - DiffuseMap = diffuse; - NormalMap = normal; - SpecularMap = specular; - } + public Material(string name, Color color, Image diffuse = null, Image normal = null, Image specular = null) + { + Name = name; + Color = color; + DiffuseMap = diffuse; + NormalMap = normal; + SpecularMap = specular; + } - public override bool Equals(object obj) - { - if (!(obj is Material other)) - return false; + public override bool Equals(object obj) + { + if (obj is not Material other) + return false; - return other.Name == Name && other.DiffuseMap == DiffuseMap && other.NormalMap == NormalMap && - other.SpecularMap == SpecularMap; - } + return other.Name == Name && other.DiffuseMap == DiffuseMap && other.NormalMap == NormalMap && + other.SpecularMap == SpecularMap; + } - [SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")] - public override int GetHashCode() + [SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")] + public override int GetHashCode() + { + unchecked { - unchecked - { - var hashCode = (Name != null ? Name.GetHashCode() : 0); - hashCode = (hashCode * 397) ^ (DiffuseMap != null ? DiffuseMap.GetHashCode() : 0); - hashCode = (hashCode * 397) ^ (NormalMap != null ? NormalMap.GetHashCode() : 0); - hashCode = (hashCode * 397) ^ (SpecularMap != null ? SpecularMap.GetHashCode() : 0); - hashCode = (hashCode * 397) ^ Color.GetHashCode(); - return hashCode; - } + var hashCode = (Name != null ? Name.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ (DiffuseMap != null ? DiffuseMap.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ (NormalMap != null ? NormalMap.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ (SpecularMap != null ? SpecularMap.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ Color.GetHashCode(); + return hashCode; } } } diff --git a/ModelViewer/SceneData/Mesh.cs b/ModelViewer/SceneData/Mesh.cs index 47c8df3..75cbcd0 100644 --- a/ModelViewer/SceneData/Mesh.cs +++ b/ModelViewer/SceneData/Mesh.cs @@ -6,293 +6,262 @@ using OpenTK.Graphics.OpenGL; using PixelFormat = OpenTK.Graphics.OpenGL.PixelFormat; -namespace ModelViewer.SceneData +namespace ModelViewer.SceneData; + +public struct TexturedVertex { - public struct TexturedVertex - { - public static readonly int SizeInBytes = Vector3.SizeInBytes + Vector2.SizeInBytes; + public static readonly int SizeInBytes = Vector3.SizeInBytes + Vector2.SizeInBytes; - public Vector3 Pos; - public Vector2 UV; + public Vector3 Pos; + public Vector2 UV; - public TexturedVertex(Vector3 pos, Vector2 uv) - { - Pos = pos; - UV = uv; - } + public TexturedVertex(Vector3 pos, Vector2 uv) + { + Pos = pos; + UV = uv; } +} - public class MeshFace +public class MeshFace +{ + public List Indices; + public Material Material; + + public MeshFace() { - public List Indices; - public Material Material; + Indices = []; + } +} - public MeshFace() - { - Indices = new List(); - } +public class Mesh +{ + private int _vertexArray; + private int _indexArray; + private int _texture; + + public Material Material { get; set; } + + public List Vertices { get; set; } + public List Normals { get; set; } + public List Normals2 { get; set; } + public List Indices { get; set; } + private List TempIndices; + public List Faces { get; set; } + public List UV1 { get; set; } + public List UV2 { get; set; } + public int ID1 { get; set; } + public int ID2 { get; set; } + + //public Dictionary Materials { get; set; } + + public Mesh() + { + Vertices = []; + Normals = []; + Normals2 = []; + Indices = []; + UV1 = []; + UV2 = []; + ID1 = 0; + ID2 = 0; + + //Materials = new Dictionary(); } - public class Mesh + public Mesh Copy() { - private int _vertexArray; - private int _indexArray; - private int _texture; - - public Material Material { get; set; } - - public List Vertices { get; set; } - public List Normals { get; set; } - public List Normals2 { get; set; } - public List Indices { get; set; } - private List TempIndices; - public List Faces { get; set; } - public List UV1 { get; set; } - public List UV2 { get; set; } - public int ID1 { get; set; } - public int ID2 { get; set; } - - //public Dictionary Materials { get; set; } - - public Mesh() - { - Vertices = new List(); - Normals = new List(); - Normals2 = new List(); - Indices = new List(); - UV1 = new List(); - UV2 = new List(); - ID1 = 0; - ID2 = 0; - - //Materials = new Dictionary(); - } + Mesh result = new(); - public Mesh Copy() - { - Mesh result = new Mesh(); + result.Material = Material; - result.Material = Material; + result.Vertices = new List(Vertices); + result.Normals = new List(Normals); + result.Normals2 = new List(Normals2); + result.Indices = new List(Indices); + result.UV1 = new List(UV1); + result.UV2 = new List(UV2); + result.ID1 = ID1; + result.ID2 = ID2; - result.Vertices = new List(Vertices); - result.Normals = new List(Normals); - result.Normals2 = new List(Normals2); - result.Indices = new List(Indices); - result.UV1 = new List(UV1); - result.UV2 = new List(UV2); - result.ID1 = ID1; - result.ID2 = ID2; + if (Faces != null) + result.Faces = new List(Faces); - if (Faces != null) - result.Faces = new List(Faces); + return result; + } - return result; - } + public Mesh Merged(Mesh mesh) + { + Mesh result = Copy(); - public Mesh Merged(Mesh mesh) + for (int i = 0; i < mesh.Indices.Count; i++) { - Mesh result = Copy(); + // TODO: Verify + result.Indices.Add((uint)result.Vertices.Count + mesh.Indices[i]); + } - for (int i = 0; i < mesh.Indices.Count; i++) - { - // TODO: Verify - result.Indices.Add((uint)result.Vertices.Count + mesh.Indices[i]); - } + result.Vertices.AddRange(mesh.Vertices); - result.Vertices.AddRange(mesh.Vertices); + // TODO: Merge Normals, and UVs correclty for indices + // TODO: Merge Materials somehow (make texture atlas?) - // TODO: Merge Normals, and UVs correclty for indices - // TODO: Merge Materials somehow (make texture atlas?) + return result; + } - return result; - } + public Mesh Transformed(Matrix4 transform) + { + Vector3 scale = transform.ExtractScale(); + Vector3 translation = transform.ExtractTranslation(); + Quaternion rotation = transform.ExtractRotation(); - public Mesh Transformed(Matrix4 transform) - { - Vector3 scale = transform.ExtractScale(); - Vector3 translation = transform.ExtractTranslation(); - Quaternion rotation = transform.ExtractRotation(); + Mesh result = Copy(); - Mesh result = Copy(); + result.Vertices.Clear(); - result.Vertices.Clear(); + for (int i = 0; i < Vertices.Count; i++) + { + Vector3 v = Vertices[i]; + v *= scale; + v = Vector3.Transform(v, rotation); + v += translation; + result.Vertices.Add(v); + } - for (int i = 0; i < Vertices.Count; i++) - { - Vector3 v = Vertices[i]; - v *= scale; - v = Vector3.Transform(v, rotation); - v += translation; - result.Vertices.Add(v); - } + return result; + } - return result; - } + public bool InitGraphics() + { + /*List vertices = new List(); - public bool InitGraphics() + for (int i = 0; i < Vertices.Count; i++) { - /*List vertices = new List(); - - for (int i = 0; i < Vertices.Count; i++) - { - Vector3 pos = Vertices[i]; - Vector2 uv = Vector2.Zero; - if (i < UV1.Count) - uv = UV1[i]; - vertices.Add(new TexturedVertex(pos, uv)); - } + Vector3 pos = Vertices[i]; + Vector2 uv = Vector2.Zero; + if (i < UV1.Count) + uv = UV1[i]; + vertices.Add(new TexturedVertex(pos, uv)); + } - // Vertices - _vertexArray = GL.GenBuffer(); - GL.BindBuffer(BufferTarget.ArrayBuffer, _vertexArray); - GL.BufferData(BufferTarget.ArrayBuffer, TexturedVertex.SizeInBytes * vertices.Count, vertices.ToArray(), BufferUsageHint.StaticDraw); - - // Indices - _indexArray = GL.GenBuffer(); - GL.BindBuffer(BufferTarget.ElementArrayBuffer, _indexArray); - GL.BufferData(BufferTarget.ElementArrayBuffer, sizeof(uint) * Indices.Count, Indices.ToArray(), BufferUsageHint.StaticDraw); - */ + // Vertices + _vertexArray = GL.GenBuffer(); + GL.BindBuffer(BufferTarget.ArrayBuffer, _vertexArray); + GL.BufferData(BufferTarget.ArrayBuffer, TexturedVertex.SizeInBytes * vertices.Count, vertices.ToArray(), BufferUsageHint.StaticDraw); + + // Indices + _indexArray = GL.GenBuffer(); + GL.BindBuffer(BufferTarget.ElementArrayBuffer, _indexArray); + GL.BufferData(BufferTarget.ElementArrayBuffer, sizeof(uint) * Indices.Count, Indices.ToArray(), BufferUsageHint.StaticDraw); + */ - List indices = Indices; + List indices = Indices; - if (Faces != null) + if (Faces != null) + { + indices = []; + foreach (MeshFace face in Faces) { - indices = new List(); - foreach (MeshFace face in Faces) + /*for (int i = 2; i < face.Indices.Count; i++) { - /*for (int i = 2; i < face.Indices.Count; i++) + if ((i - 2) % 2 == 0) + { + indices.Add(face.Indices[i] - 0); + indices.Add(face.Indices[i] - 1); + indices.Add(face.Indices[i] - 2); + } + else { - if ((i - 2) % 2 == 0) - { - indices.Add(face.Indices[i] - 0); - indices.Add(face.Indices[i] - 1); - indices.Add(face.Indices[i] - 2); - } - else - { - indices.Add(face.Indices[i] - 2); - indices.Add(face.Indices[i] - 1); - indices.Add(face.Indices[i] - 0); - } - }*/ - - indices.AddRange(face.Indices); - } + indices.Add(face.Indices[i] - 2); + indices.Add(face.Indices[i] - 1); + indices.Add(face.Indices[i] - 0); + } + }*/ + + indices.AddRange(face.Indices); } + } - List vertices = new List(); - if (indices.Count == 0) + List vertices = []; + if (indices.Count == 0) + { + for (int i = 0; i < Vertices.Count; i++) { - for (int i = 0; i < Vertices.Count; i++) - { - indices.Add((uint)i); - } + indices.Add((uint)i); } + } - List indices2 = indices; - /*List indices2 = new List(); + List indices2 = indices; + /*List indices2 = new List(); - // Triangulate Faces - for (int i = 2; i < indices.Count; i++) + // Triangulate Faces + for (int i = 2; i < indices.Count; i++) + { + if ((i - 2) % 2 == 0) { - if ((i - 2) % 2 == 0) - { - indices2.Add(indices[i] - 0); - indices2.Add(indices[i] - 1); - indices2.Add(indices[i] - 2); - } - else - { - indices2.Add(indices[i] - 2); - indices2.Add(indices[i] - 1); - indices2.Add(indices[i] - 0); - } - }*/ - - for (int i = 0; i < indices2.Count; i++) + indices2.Add(indices[i] - 0); + indices2.Add(indices[i] - 1); + indices2.Add(indices[i] - 2); + } + else { - if (indices2[i] >= Vertices.Count) - { - //MessageBox.Show("Index too large: " + indices[i].ToString("X2") + " >= " + Vertices.Count.ToString("X8")); - continue; - } - Vector3 pos = Vertices[(int)indices2[i]]; - //Vector2 uv = new Vector2(); - //if (UV1.Count < indices[i]) - // uv = UV1[(int) indices[i]]; - Vector2 uv1; - if (indices2[i] < UV1.Count) - uv1 = UV1[(int)indices2[i]]; - else - uv1 = new Vector2(0, 0); - - Vector2 uv = new Vector2(uv1.X, uv1.Y); - - vertices.Add(new TexturedVertex(pos, uv)); + indices2.Add(indices[i] - 2); + indices2.Add(indices[i] - 1); + indices2.Add(indices[i] - 0); } + }*/ - TempIndices = new List(indices2); - - _vertexArray = GL.GenVertexArray(); - int buffer = GL.GenBuffer(); - GL.BindVertexArray(_vertexArray); - GL.BindBuffer(BufferTarget.ArrayBuffer, buffer); - - GL.NamedBufferStorage(buffer, TexturedVertex.SizeInBytes*vertices.Count, vertices.ToArray(), BufferStorageFlags.MapWriteBit); - - GL.VertexArrayAttribBinding(_vertexArray, 0, 0); - GL.EnableVertexArrayAttrib(_vertexArray, 0); - GL.VertexArrayAttribFormat(_vertexArray, 0, 3, VertexAttribType.Float, false, 0); - - GL.VertexArrayAttribBinding(_vertexArray, 1, 0); - GL.EnableVertexArrayAttrib(_vertexArray, 1); - GL.VertexArrayAttribFormat(_vertexArray, 1, 2, VertexAttribType.Float, false, Vector3.SizeInBytes); + for (int i = 0; i < indices2.Count; i++) + { + if (indices2[i] >= Vertices.Count) + { + //MessageBox.Show("Index too large: " + indices[i].ToString("X2") + " >= " + Vertices.Count.ToString("X8")); + continue; + } + Vector3 pos = Vertices[(int)indices2[i]]; + //Vector2 uv = new Vector2(); + //if (UV1.Count < indices[i]) + // uv = UV1[(int) indices[i]]; + Vector2 uv1; + if (indices2[i] < UV1.Count) + uv1 = UV1[(int)indices2[i]]; + else + uv1 = new Vector2(0, 0); - GL.VertexArrayVertexBuffer(_vertexArray, 0, buffer, IntPtr.Zero, TexturedVertex.SizeInBytes); + Vector2 uv = new(uv1.X, uv1.Y); + vertices.Add(new TexturedVertex(pos, uv)); + } + TempIndices = new List(indices2); - //_indexArray = GL.GenBuffer(); - //GL.BindBuffer(BufferTarget.ElementArrayBuffer, _indexArray); - //GL.NamedBufferStorage(_indexArray, sizeof(uint) * Indices.Count, Indices.ToArray(), BufferStorageFlags.MapWriteBit); + _vertexArray = GL.GenVertexArray(); + int buffer = GL.GenBuffer(); + GL.BindVertexArray(_vertexArray); + GL.BindBuffer(BufferTarget.ArrayBuffer, buffer); - if (Material?.DiffuseMap != null) - { - try - { - int width = Material.DiffuseMap.Width; - int height = Material.DiffuseMap.Height; + GL.NamedBufferStorage(buffer, TexturedVertex.SizeInBytes*vertices.Count, vertices.ToArray(), BufferStorageFlags.MapWriteBit); - _texture = GL.GenTexture(); - GL.BindTexture(TextureTarget.Texture2D, _texture); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear); + GL.VertexArrayAttribBinding(_vertexArray, 0, 0); + GL.EnableVertexArrayAttrib(_vertexArray, 0); + GL.VertexArrayAttribFormat(_vertexArray, 0, 3, VertexAttribType.Float, false, 0); - GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, width, height, 0, PixelFormat.Bgra, - PixelType.UnsignedByte, IntPtr.Zero); - Bitmap bitmap = new Bitmap(Material.DiffuseMap); - BitmapData data = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, - System.Drawing.Imaging.PixelFormat.Format32bppArgb); + GL.VertexArrayAttribBinding(_vertexArray, 1, 0); + GL.EnableVertexArrayAttrib(_vertexArray, 1); + GL.VertexArrayAttribFormat(_vertexArray, 1, 2, VertexAttribType.Float, false, Vector3.SizeInBytes); - GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, width, height, PixelFormat.Bgra, - PixelType.UnsignedByte, data.Scan0); + GL.VertexArrayVertexBuffer(_vertexArray, 0, buffer, IntPtr.Zero, TexturedVertex.SizeInBytes); - bitmap.UnlockBits(data); - bitmap.Dispose(); - GL.BindTexture(TextureTarget.Texture2D, 0); + //_indexArray = GL.GenBuffer(); + //GL.BindBuffer(BufferTarget.ElementArrayBuffer, _indexArray); + //GL.NamedBufferStorage(_indexArray, sizeof(uint) * Indices.Count, Indices.ToArray(), BufferStorageFlags.MapWriteBit); - GL.Enable(EnableCap.Texture2D); - } catch (ArgumentException ex) - { - Console.WriteLine(ex.Message + "\n\n" + ex.StackTrace); - } - } - else + if (Material?.DiffuseMap != null) + { + try { - int width = 16; - int height = 16; + int width = Material.DiffuseMap.Width; + int height = Material.DiffuseMap.Height; _texture = GL.GenTexture(); GL.BindTexture(TextureTarget.Texture2D, _texture); @@ -301,11 +270,7 @@ public bool InitGraphics() GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, width, height, 0, PixelFormat.Bgra, PixelType.UnsignedByte, IntPtr.Zero); - Bitmap bitmap = new Bitmap(width, height); - for (int y = 0; y < height; y++) - for (int x = 0; x < width; x++) - bitmap.SetPixel(x, y, Color.DarkGray); - + Bitmap bitmap = new(Material.DiffuseMap); BitmapData data = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); @@ -319,65 +284,99 @@ public bool InitGraphics() GL.BindTexture(TextureTarget.Texture2D, 0); GL.Enable(EnableCap.Texture2D); + } catch (ArgumentException ex) + { + Console.WriteLine(ex.Message + "\n\n" + ex.StackTrace); } - - return true; } - - public void Update() + else { - - } + int width = 16; + int height = 16; - public void Render(ICamera camera, Matrix4 transform) - { - GL.ActiveTexture(TextureUnit.Texture0); + _texture = GL.GenTexture(); GL.BindTexture(TextureTarget.Texture2D, _texture); - //GL.Uniform1(21, 0); - - Matrix4 translation = Matrix4.CreateTranslation(transform.ExtractTranslation()); - Matrix4 rotation = Matrix4.CreateFromQuaternion(transform.ExtractRotation()); - Matrix4 scale = Matrix4.CreateScale(transform.ExtractScale()); - - Matrix4 modelView = rotation * scale * translation; - if (camera != null) - modelView *= camera.LookAtMatrix; - - GL.UniformMatrix4(21, false, ref modelView); - - GL.BindVertexArray(_vertexArray); - //GL.PointSize(4.0f); - if (TempIndices != null) - GL.DrawArrays(PrimitiveType.Triangles, 0, TempIndices.Count); - else - GL.DrawArrays(PrimitiveType.Triangles, 0, Indices.Count); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear); - /*GL.EnableClientState(ArrayCap.VertexArray); - GL.EnableClientState(ArrayCap.IndexArray); + GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, width, height, 0, PixelFormat.Bgra, + PixelType.UnsignedByte, IntPtr.Zero); + Bitmap bitmap = new(width, height); + for (int y = 0; y < height; y++) + for (int x = 0; x < width; x++) + bitmap.SetPixel(x, y, Color.DarkGray); - GL.EnableVertexAttribArray(0); - GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, TexturedVertex.SizeInBytes, IntPtr.Zero); + BitmapData data = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, + System.Drawing.Imaging.PixelFormat.Format32bppArgb); - GL.EnableVertexAttribArray(1); - GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, TexturedVertex.SizeInBytes, Vector3.SizeInBytes); + GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, width, height, PixelFormat.Bgra, + PixelType.UnsignedByte, data.Scan0); - GL.VertexAttrib3(0, transform.ExtractTranslation()); - GL.VertexPointer(5, VertexPointerType.Float, TexturedVertex.SizeInBytes, 0); - - GL.BindBuffer(BufferTarget.ArrayBuffer, _vertexArray); - GL.BindBuffer(BufferTarget.ElementArrayBuffer, _indexArray); - GL.DrawElements(PrimitiveType.Triangles, Indices.Count, DrawElementsType.UnsignedInt, 0); + bitmap.UnlockBits(data); - GL.DisableVertexAttribArray(1); - GL.DisableVertexAttribArray(0); + bitmap.Dispose(); - GL.DisableClientState(ArrayCap.IndexArray); - GL.DisableClientState(ArrayCap.VertexArray);*/ - } + GL.BindTexture(TextureTarget.Texture2D, 0); - public void Dispose() - { - GL.DeleteVertexArrays(1, ref _vertexArray); + GL.Enable(EnableCap.Texture2D); } + + return true; + } + + public void Update() + { + + } + + public void Render(ICamera camera, Matrix4 transform) + { + GL.ActiveTexture(TextureUnit.Texture0); + GL.BindTexture(TextureTarget.Texture2D, _texture); + //GL.Uniform1(21, 0); + + Matrix4 translation = Matrix4.CreateTranslation(transform.ExtractTranslation()); + Matrix4 rotation = Matrix4.CreateFromQuaternion(transform.ExtractRotation()); + Matrix4 scale = Matrix4.CreateScale(transform.ExtractScale()); + + Matrix4 modelView = rotation * scale * translation; + if (camera != null) + modelView *= camera.LookAtMatrix; + + GL.UniformMatrix4(21, false, ref modelView); + + GL.BindVertexArray(_vertexArray); + //GL.PointSize(4.0f); + if (TempIndices != null) + GL.DrawArrays(PrimitiveType.Triangles, 0, TempIndices.Count); + else + GL.DrawArrays(PrimitiveType.Triangles, 0, Indices.Count); + + /*GL.EnableClientState(ArrayCap.VertexArray); + GL.EnableClientState(ArrayCap.IndexArray); + + GL.EnableVertexAttribArray(0); + GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, TexturedVertex.SizeInBytes, IntPtr.Zero); + + GL.EnableVertexAttribArray(1); + GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, TexturedVertex.SizeInBytes, Vector3.SizeInBytes); + + GL.VertexAttrib3(0, transform.ExtractTranslation()); + GL.VertexPointer(5, VertexPointerType.Float, TexturedVertex.SizeInBytes, 0); + + GL.BindBuffer(BufferTarget.ArrayBuffer, _vertexArray); + GL.BindBuffer(BufferTarget.ElementArrayBuffer, _indexArray); + GL.DrawElements(PrimitiveType.Triangles, Indices.Count, DrawElementsType.UnsignedInt, 0); + + GL.DisableVertexAttribArray(1); + GL.DisableVertexAttribArray(0); + + GL.DisableClientState(ArrayCap.IndexArray); + GL.DisableClientState(ArrayCap.VertexArray);*/ + } + + public void Dispose() + { + GL.DeleteVertexArrays(1, ref _vertexArray); } } diff --git a/ModelViewer/SceneData/Model.cs b/ModelViewer/SceneData/Model.cs index c5c14f4..8e13f8d 100644 --- a/ModelViewer/SceneData/Model.cs +++ b/ModelViewer/SceneData/Model.cs @@ -1,101 +1,98 @@ using System.Collections.Generic; using OpenTK.Mathematics; -namespace ModelViewer.SceneData +namespace ModelViewer.SceneData; + +public class Model { - public class Model + internal List Meshes; + + public int MeshCount => Meshes.Count; + + public Model(params Mesh[] meshes) { - internal List Meshes; + Meshes = [.. meshes]; + } - public int MeshCount => Meshes.Count; + public Model Copy() + { + Model result = new(); - public Model(params Mesh[] meshes) + foreach (Mesh mesh in Meshes) { - Meshes = new List(); - - Meshes.AddRange(meshes); + result.Meshes.Add(mesh.Copy()); } - public Model Copy() - { - Model result = new Model(); + return result; + } - foreach (Mesh mesh in Meshes) - { - result.Meshes.Add(mesh.Copy()); - } + public void AddMesh(Mesh mesh) + { + Meshes.Add(mesh); + } - return result; - } + public void RemoveMesh(int index) + { + Meshes.RemoveAt(index); + } - public void AddMesh(Mesh mesh) - { - Meshes.Add(mesh); - } + public void RemoveMesh(Mesh mesh) + { + Meshes.Remove(mesh); + } - public void RemoveMesh(int index) - { - Meshes.RemoveAt(index); - } + public bool ContainsMesh(Mesh mesh) + { + return Meshes.Contains(mesh); + } - public void RemoveMesh(Mesh mesh) - { - Meshes.Remove(mesh); - } + public Model Transformed(Matrix4 transform) + { + Model result = new(); - public bool ContainsMesh(Mesh mesh) + foreach (Mesh mesh in Meshes) { - return Meshes.Contains(mesh); + result.Meshes.Add(mesh.Transformed(transform)); } - public Model Transformed(Matrix4 transform) - { - Model result = new Model(); - - foreach (Mesh mesh in Meshes) - { - result.Meshes.Add(mesh.Transformed(transform)); - } - - return result; - } + return result; + } - public Mesh MergeMeshes() + public Mesh MergeMeshes() + { + Mesh result = new(); + + foreach (Mesh mesh in Meshes) { - Mesh result = new Mesh(); - - foreach (Mesh mesh in Meshes) - { - result = result.Merged(mesh); - } - - return result; + result = result.Merged(mesh); } - public bool InitGraphics() - { - foreach (Mesh mesh in Meshes) - mesh.InitGraphics(); - - return true; - } + return result; + } - public void Update() - { - foreach (Mesh mesh in Meshes) - mesh.Update(); - } + public bool InitGraphics() + { + foreach (Mesh mesh in Meshes) + mesh.InitGraphics(); + + return true; + } - public void Render(ICamera camera, Matrix4 transform) - { - foreach (Mesh mesh in Meshes) - mesh.Render(camera, transform); - } + public void Update() + { + foreach (Mesh mesh in Meshes) + mesh.Update(); + } - public void Dispose() - { - foreach (Mesh mesh in Meshes) - mesh.Dispose(); - } + public void Render(ICamera camera, Matrix4 transform) + { + foreach (Mesh mesh in Meshes) + mesh.Render(camera, transform); + } + + public void Dispose() + { + foreach (Mesh mesh in Meshes) + mesh.Dispose(); } } diff --git a/ModelViewer/SceneData/Scene.cs b/ModelViewer/SceneData/Scene.cs index 713eade..bfcc4e0 100644 --- a/ModelViewer/SceneData/Scene.cs +++ b/ModelViewer/SceneData/Scene.cs @@ -8,359 +8,358 @@ using System.Windows.Forms; using OpenTK.Mathematics; -namespace ModelViewer.SceneData +namespace ModelViewer.SceneData; + +public class Scene { - public class Scene - { - public Vector3 Center { get; private set; } - public float HorizSize { get; private set; } - public float VertSize { get; private set; } + public Vector3 Center { get; private set; } + public float HorizSize { get; private set; } + public float VertSize { get; private set; } - internal Dictionary SceneObjects; - - public int ObjectCount => SceneObjects.Count; + internal Dictionary SceneObjects; + + public int ObjectCount => SceneObjects.Count; - public Scene() - { - SceneObjects = new Dictionary(); + public Scene() + { + SceneObjects = []; - Center = Vector3.Zero; - HorizSize = 3.0f; - VertSize = 1.0f; - } + Center = Vector3.Zero; + HorizSize = 3.0f; + VertSize = 1.0f; + } - public void ClearObjects() + public void ClearObjects() + { + SceneObjects.Clear(); + } + + public void AddObject(SceneObject obj) + { + while (SceneObjects.ContainsKey(obj.Name)) { - SceneObjects.Clear(); + obj.Name += "_"; } + SceneObjects.Add(obj.Name, obj); - public void AddObject(SceneObject obj) - { - while (SceneObjects.ContainsKey(obj.Name)) - { - obj.Name += "_"; - } - SceneObjects.Add(obj.Name, obj); + UpdateSizing(); + } - UpdateSizing(); - } + public void RemoveObject(string name) + { + SceneObjects.Remove(name); + } - public void RemoveObject(string name) - { - SceneObjects.Remove(name); - } + public bool ContainsObject(string name) + { + return SceneObjects.ContainsKey(name); + } - public bool ContainsObject(string name) - { - return SceneObjects.ContainsKey(name); - } + public bool ContainsObject(SceneObject obj) + { + return SceneObjects.ContainsValue(obj); + } - public bool ContainsObject(SceneObject obj) + public SceneObject MergeSceneObjects() + { + Model mergedModel = new(); + foreach (SceneObject obj in SceneObjects.Values) { - return SceneObjects.ContainsValue(obj); + mergedModel.Meshes.Add(obj.MergeMeshes()); } - public SceneObject MergeSceneObjects() - { - Model mergedModel = new Model(); - foreach (SceneObject obj in SceneObjects.Values) - { - mergedModel.Meshes.Add(obj.MergeMeshes()); - } + Model resultModel = new(mergedModel.MergeMeshes()); + + return new SceneObject("Merged", resultModel); + } - Model resultModel = new Model(mergedModel.MergeMeshes()); - - return new SceneObject("Merged", resultModel); - } + public List GetAllMaterials() + { + List result = []; - public List GetAllMaterials() + foreach (SceneObject obj in SceneObjects.Values) { - List result = new List(); - - foreach (SceneObject obj in SceneObjects.Values) + foreach (Mesh mesh in obj.Model.Meshes) { - foreach (Mesh mesh in obj.Model.Meshes) - { - Material material = mesh.Material; - - if (material != null && !result.Contains(material)) - result.Add(material); + Material material = mesh.Material; + + if (material != null && !result.Contains(material)) + result.Add(material); - if (material == null && mesh.Faces != null) + if (material == null && mesh.Faces != null) + { + foreach (MeshFace face in mesh.Faces) { - foreach (MeshFace face in mesh.Faces) - { - Material mat = face.Material; + Material mat = face.Material; - if (mat != null && !result.Contains(mat)) - result.Add(mat); - } + if (mat != null && !result.Contains(mat)) + result.Add(mat); } } } - - return result; } - public void ExportCollada14(string path) - { - // TODO: Implement Collada Export - } + return result; + } + + public void ExportCollada14(string path) + { + // TODO: Implement Collada Export + } - private void ExportMTL(string mtlPath, string materialDir, string materialDirPath, List materials) + private void ExportMTL(string mtlPath, string materialDir, string materialDirPath, List materials) + { + Stream s1 = File.Open(mtlPath, FileMode.Create); + StreamWriter sw1 = new(s1); + for (int i = 0; i < materials.Count; i++) { - Stream s1 = File.Open(mtlPath, FileMode.Create); - StreamWriter sw1 = new StreamWriter(s1); - for (int i = 0; i < materials.Count; i++) - { - Material material = materials[i]; - if (material == null) - continue; + Material material = materials[i]; + if (material == null) + continue; - string materialFileName = "material_" + material.Name + ".png"; - string materialRelativePathName = materialDir + materialFileName; - string materialPathName = materialDirPath + materialFileName; + string materialFileName = "material_" + material.Name + ".png"; + string materialRelativePathName = materialDir + materialFileName; + string materialPathName = materialDirPath + materialFileName; - Image image = material.DiffuseMap; + Image image = material.DiffuseMap; - float r = material.Color.R / 255.0f; - float g = material.Color.G / 255.0f; - float b = material.Color.B / 255.0f; + float r = material.Color.R / 255.0f; + float g = material.Color.G / 255.0f; + float b = material.Color.B / 255.0f; - sw1.WriteLine("newmtl material_" + material.Name); - sw1.WriteLine("Kd " + r + " " + g + " " + b); - if (image != null) - sw1.WriteLine("map_Kd " + materialRelativePathName); + sw1.WriteLine("newmtl material_" + material.Name); + sw1.WriteLine("Kd " + r + " " + g + " " + b); + if (image != null) + sw1.WriteLine("map_Kd " + materialRelativePathName); - sw1.WriteLine(); + sw1.WriteLine(); - if (image != null) + if (image != null) + { + try { - try - { - image?.Save(materialPathName, ImageFormat.Png); - } - catch (Exception ex) - { - Debug.WriteLine(ex.Message + "\n" + ex.StackTrace); - } + image?.Save(materialPathName, ImageFormat.Png); + } + catch (Exception ex) + { + Debug.WriteLine(ex.Message + "\n" + ex.StackTrace); } } - - sw1.Flush(); - sw1.Close(); - s1.Close(); } - public void ExportWavefrontObj(string path) - { - List materials = GetAllMaterials(); - string fullPath = Path.GetFullPath(path).Replace(Path.GetFileName(path), ""); - string mtlPath = fullPath + Path.GetFileNameWithoutExtension(path) + ".mtl"; - string materialDir = Path.GetFileNameWithoutExtension(path) + "_materials\\"; - string materialDirPath = fullPath + "/" + materialDir; + sw1.Flush(); + sw1.Close(); + s1.Close(); + } - if (materials.Count > 0) + public void ExportWavefrontObj(string path) + { + List materials = GetAllMaterials(); + string fullPath = Path.GetFullPath(path).Replace(Path.GetFileName(path), ""); + string mtlPath = fullPath + Path.GetFileNameWithoutExtension(path) + ".mtl"; + string materialDir = Path.GetFileNameWithoutExtension(path) + "_materials\\"; + string materialDirPath = fullPath + "/" + materialDir; + + if (materials.Count > 0) + { + bool hasMaterials = false; + bool hasTextures = false; + foreach (Material mat in materials) { - bool hasMaterials = false; - bool hasTextures = false; - foreach (Material mat in materials) + if (mat != null) { - if (mat != null) - { - hasMaterials = true; - if (mat.DiffuseMap != null || mat.NormalMap != null || mat.SpecularMap != null) - hasTextures = true; - } + hasMaterials = true; + if (mat.DiffuseMap != null || mat.NormalMap != null || mat.SpecularMap != null) + hasTextures = true; } - if (hasMaterials) - { - if (hasTextures && !Directory.Exists(materialDirPath)) - Directory.CreateDirectory(materialDirPath); + } + if (hasMaterials) + { + if (hasTextures && !Directory.Exists(materialDirPath)) + Directory.CreateDirectory(materialDirPath); - ExportMTL(mtlPath, materialDir, materialDirPath, materials); - } + ExportMTL(mtlPath, materialDir, materialDirPath, materials); } + } - try - { - Stream s = File.Open(path, FileMode.Create); - StreamWriter sw = new StreamWriter(s); + try + { + Stream s = File.Open(path, FileMode.Create); + StreamWriter sw = new(s); - if (materials.Count > 0) - sw.WriteLine("mtllib " + mtlPath); + if (materials.Count > 0) + sw.WriteLine("mtllib " + mtlPath); - int meshIndex = 0; + int meshIndex = 0; - uint usedIndices = 0; - foreach (SceneObject obj in SceneObjects.Values) - { - string name = obj.Name; - sw.WriteLine("# Model " + name); + uint usedIndices = 0; + foreach (SceneObject obj in SceneObjects.Values) + { + string name = obj.Name; + sw.WriteLine("# Model " + name); - Model model = obj.Model.Transformed(obj.Transform); - foreach (Mesh mesh in model.Meshes) + Model model = obj.Model.Transformed(obj.Transform); + foreach (Mesh mesh in model.Meshes) + { + foreach (Vector3 vertex in mesh.Vertices) { - foreach (Vector3 vertex in mesh.Vertices) - { - sw.WriteLine("v " + vertex.X + " " + vertex.Y + " " + vertex.Z); - } + sw.WriteLine("v " + vertex.X + " " + vertex.Y + " " + vertex.Z); + } - foreach (Vector2 uv1 in mesh.UV1) - { - sw.WriteLine("vt " + uv1.X + " " + -uv1.Y); - } + foreach (Vector2 uv1 in mesh.UV1) + { + sw.WriteLine("vt " + uv1.X + " " + -uv1.Y); + } - sw.WriteLine(); + sw.WriteLine(); - if (string.IsNullOrEmpty(obj.ID)) - sw.WriteLine("g mesh" + meshIndex); - else - sw.WriteLine("g mesh" + meshIndex + "_" + obj.ID); + if (string.IsNullOrEmpty(obj.ID)) + sw.WriteLine("g mesh" + meshIndex); + else + sw.WriteLine("g mesh" + meshIndex + "_" + obj.ID); - if (mesh.Material != null) - sw.WriteLine("usemtl material_" + mesh.Material.Name); + if (mesh.Material != null) + sw.WriteLine("usemtl material_" + mesh.Material.Name); - sw.WriteLine(); + sw.WriteLine(); - List verts = mesh.Vertices; + List verts = mesh.Vertices; - if (mesh.Faces != null) + if (mesh.Faces != null) + { + foreach (MeshFace face in mesh.Faces) { - foreach (MeshFace face in mesh.Faces) + if (face.Material != null) + sw.WriteLine("usemtl material_" + face.Material.Name); + + StringBuilder sb = new("f"); + foreach (uint index in face.Indices) { - if (face.Material != null) - sw.WriteLine("usemtl material_" + face.Material.Name); - - StringBuilder sb = new StringBuilder("f"); - foreach (uint index in face.Indices) - { - uint ind = index + 1 + usedIndices; - sb.Append(" " + ind + "/" + ind); - } - sw.WriteLine(sb.ToString()); + uint ind = index + 1 + usedIndices; + sb.Append(" " + ind + "/" + ind); } + sw.WriteLine(sb.ToString()); } - else - { - List inds = mesh.Indices; + } + else + { + List inds = mesh.Indices; - if (inds.Count == 0) + if (inds.Count == 0) + { + for (int i = 0; i < verts.Count; i++) { - for (int i = 0; i < verts.Count; i++) - { - inds.Add((uint) i); - } + inds.Add((uint) i); } + } - //Dictionary usedMats = new Dictionary(); + //Dictionary usedMats = new Dictionary(); - for (int j = 0; j < inds.Count; j += 3) + for (int j = 0; j < inds.Count; j += 3) + { + if (j + 2 >= inds.Count) + break; + + /*if (mesh.Materials != null && mesh.Materials.ContainsKey(inds[j])) { - if (j + 2 >= inds.Count) - break; - - /*if (mesh.Materials != null && mesh.Materials.ContainsKey(inds[j])) - { - Material mat = mesh.Materials[inds[j]]; - if (mat != null) - sw.WriteLine("usemtl material_" + mat.Name); - }*/ - - uint v0 = inds[j + 0] + 1 + usedIndices; - uint v1 = inds[j + 1] + 1 + usedIndices; - uint v2 = inds[j + 2] + 1 + usedIndices; - sw.WriteLine("f " + v0 + "/" + v0 + " " + v1 + "/" + v1 + " " + v2 + "/" + v2); - } + Material mat = mesh.Materials[inds[j]]; + if (mat != null) + sw.WriteLine("usemtl material_" + mat.Name); + }*/ + + uint v0 = inds[j + 0] + 1 + usedIndices; + uint v1 = inds[j + 1] + 1 + usedIndices; + uint v2 = inds[j + 2] + 1 + usedIndices; + sw.WriteLine("f " + v0 + "/" + v0 + " " + v1 + "/" + v1 + " " + v2 + "/" + v2); } - usedIndices += (uint)verts.Count; + } + usedIndices += (uint)verts.Count; - sw.WriteLine(); + sw.WriteLine(); - meshIndex++; - } + meshIndex++; } - - sw.Flush(); - sw.Close(); - s.Close(); - } - catch (Exception ex) - { - MessageBox.Show(ex.Message + "\r\n" + ex.StackTrace, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } - } - public void UpdateSizing() + sw.Flush(); + sw.Close(); + s.Close(); + } + catch (Exception ex) { - float maxX = float.MinValue; - float minX = float.MaxValue; - float maxY = float.MinValue; - float minY = float.MaxValue; - float maxZ = float.MinValue; - float minZ = float.MaxValue; + MessageBox.Show(ex.Message + "\r\n" + ex.StackTrace, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } - //Vector3 closestToCenter = new Vector3(float.NaN); + public void UpdateSizing() + { + float maxX = float.MinValue; + float minX = float.MaxValue; + float maxY = float.MinValue; + float minY = float.MaxValue; + float maxZ = float.MinValue; + float minZ = float.MaxValue; - //int numVerts = 0; + //Vector3 closestToCenter = new Vector3(float.NaN); - foreach (SceneObject obj in SceneObjects.Values) + //int numVerts = 0; + + foreach (SceneObject obj in SceneObjects.Values) + { + foreach (Mesh mesh in obj.Model.Meshes) { - foreach (Mesh mesh in obj.Model.Meshes) + for (int i = 0; i < mesh.Vertices.Count; i++) { - for (int i = 0; i < mesh.Vertices.Count; i++) - { - Vector3 vert = mesh.Vertices[i]; + Vector3 vert = mesh.Vertices[i]; - maxX = Math.Max(vert.X, maxX); - minX = Math.Min(vert.X, minX); - maxY = Math.Max(vert.Y, maxY); - minY = Math.Min(vert.Y, minY); - maxZ = Math.Max(vert.Z, maxZ); - minZ = Math.Min(vert.Z, minZ); + maxX = Math.Max(vert.X, maxX); + minX = Math.Min(vert.X, minX); + maxY = Math.Max(vert.Y, maxY); + minY = Math.Min(vert.Y, minY); + maxZ = Math.Max(vert.Z, maxZ); + minZ = Math.Min(vert.Z, minZ); - //numVerts++; - } + //numVerts++; } } + } - float midX = (minX + maxX) / 2; - float midY = (minY + maxY) / 2; - float midZ = (minZ + maxZ) / 2; + float midX = (minX + maxX) / 2; + float midY = (minY + maxY) / 2; + float midZ = (minZ + maxZ) / 2; - HorizSize = Math.Max(maxX - minX, maxZ - minZ) / 2 * 1.5f; - VertSize = (maxY - minY) / 2 * 1.5f; + HorizSize = Math.Max(maxX - minX, maxZ - minZ) / 2 * 1.5f; + VertSize = (maxY - minY) / 2 * 1.5f; - Center = new Vector3(midX, midY, midZ); - } + Center = new Vector3(midX, midY, midZ); + } - public bool InitGraphics() + public bool InitGraphics() + { + foreach (SceneObject obj in SceneObjects.Values) { - foreach (SceneObject obj in SceneObjects.Values) - { - if (!obj.InitGraphics()) - return false; - } - - return true; + if (!obj.InitGraphics()) + return false; } - public void Update() - { - foreach (SceneObject obj in SceneObjects.Values) - obj.Update(); - } + return true; + } - public void Render(ICamera camera) - { - foreach (SceneObject obj in SceneObjects.Values) - obj.Render(camera); - } + public void Update() + { + foreach (SceneObject obj in SceneObjects.Values) + obj.Update(); + } - public void Dispose() - { - foreach (SceneObject obj in SceneObjects.Values) - obj.Dispose(); - } + public void Render(ICamera camera) + { + foreach (SceneObject obj in SceneObjects.Values) + obj.Render(camera); + } + + public void Dispose() + { + foreach (SceneObject obj in SceneObjects.Values) + obj.Dispose(); } } diff --git a/ModelViewer/SceneData/SceneObject.cs b/ModelViewer/SceneData/SceneObject.cs index bde5be8..c39c8bf 100644 --- a/ModelViewer/SceneData/SceneObject.cs +++ b/ModelViewer/SceneData/SceneObject.cs @@ -1,79 +1,78 @@ using OpenTK.Mathematics; -namespace ModelViewer.SceneData +namespace ModelViewer.SceneData; + +public class SceneObject { - public class SceneObject + public Model Model { get; set; } + public Matrix4 Transform { get; set; } + public string Name { get; set; } + + public Vector3 Position => Transform.ExtractTranslation(); + public Vector3 Scale => Transform.ExtractScale(); + public Quaternion Rotation => Transform.ExtractRotation(); + public Vector3 Direction { get; set; } + + public string ID { get; set; } + + public SceneObject(string name, Model model) + { + Name = name; + Model = model; + Transform = Matrix4.Identity; + + Direction = Vector3.UnitZ; + + //SetPosition(new Vector3(0, 0, -10.0f)); + //var t = Matrix4.CreateTranslation(0, 0, -4.0f); + //var r = Matrix4.CreateFromAxisAngle(new Vector3(0.0f, -1.0f, 0.0f), MathHelper.DegreesToRadians(90.0f)); + //Transform = r * t; + } + + public SceneObject(string name, Model model, Matrix4 transform) + { + Name = name; + Model = model; + Transform = transform; + + Direction = Vector3.UnitZ; + } + + public Mesh MergeMeshes() + { + return Model.MergeMeshes().Transformed(Transform); + } + + public Model MergeMeshesToModel() + { + return new Model(MergeMeshes()); + } + + public bool InitGraphics() + { + Model.InitGraphics(); + + return true; + } + + public void Update() + { + Model.Update(); + } + + public void Render(ICamera camera) + { + Model.Render(camera, Transform); + } + + public void Dispose() + { + Model.Dispose(); + } + + public void SetPosition(Vector3 pos) { - public Model Model { get; set; } - public Matrix4 Transform { get; set; } - public string Name { get; set; } - - public Vector3 Position => Transform.ExtractTranslation(); - public Vector3 Scale => Transform.ExtractScale(); - public Quaternion Rotation => Transform.ExtractRotation(); - public Vector3 Direction { get; set; } - - public string ID { get; set; } - - public SceneObject(string name, Model model) - { - Name = name; - Model = model; - Transform = Matrix4.Identity; - - Direction = Vector3.UnitZ; - - //SetPosition(new Vector3(0, 0, -10.0f)); - //var t = Matrix4.CreateTranslation(0, 0, -4.0f); - //var r = Matrix4.CreateFromAxisAngle(new Vector3(0.0f, -1.0f, 0.0f), MathHelper.DegreesToRadians(90.0f)); - //Transform = r * t; - } - - public SceneObject(string name, Model model, Matrix4 transform) - { - Name = name; - Model = model; - Transform = transform; - - Direction = Vector3.UnitZ; - } - - public Mesh MergeMeshes() - { - return Model.MergeMeshes().Transformed(Transform); - } - - public Model MergeMeshesToModel() - { - return new Model(MergeMeshes()); - } - - public bool InitGraphics() - { - Model.InitGraphics(); - - return true; - } - - public void Update() - { - Model.Update(); - } - - public void Render(ICamera camera) - { - Model.Render(camera, Transform); - } - - public void Dispose() - { - Model.Dispose(); - } - - public void SetPosition(Vector3 pos) - { - Matrix4 mat = Matrix4.CreateTranslation(pos); - Transform = Matrix4.Add(Transform, mat); - } + Matrix4 mat = Matrix4.CreateTranslation(pos); + Transform = Matrix4.Add(Transform, mat); } } diff --git a/ModelViewer/SceneRenderControl.cs b/ModelViewer/SceneRenderControl.cs index 18d2ead..db35936 100644 --- a/ModelViewer/SceneRenderControl.cs +++ b/ModelViewer/SceneRenderControl.cs @@ -5,153 +5,152 @@ using ModelViewer.SceneData; using OpenTK.GLControl; -namespace ModelViewer +namespace ModelViewer; + +public partial class SceneRenderControl : UserControl { - public partial class SceneRenderControl : UserControl + private GLControl glcMain; + private GraphicsScene _graphicsScene; + + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public Scene Scene { - private GLControl glcMain; - private GraphicsScene _graphicsScene; + get => _graphicsScene?.Scene; + set => InitScene(value); + } - [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] - public Scene Scene - { - get => _graphicsScene?.Scene; - set => InitScene(value); - } + private readonly bool _designMode; - private readonly bool _designMode; + private bool _sceneChanged; - private bool _sceneChanged; + public SceneRenderControl() + { + InitializeComponent(); + _designMode = LicenseManager.UsageMode == LicenseUsageMode.Designtime; + if (!_designMode) + SetupGLControl(); + _sceneChanged = true; + } - public SceneRenderControl() + private void SetupGLControl() + { + glcMain = new() { - InitializeComponent(); - _designMode = LicenseManager.UsageMode == LicenseUsageMode.Designtime; - if (!_designMode) - SetupGLControl(); - _sceneChanged = true; - } + BackColor = Color.Black, + Dock = DockStyle.Fill, + Location = new Point(0, 0), + Name = "glcMain", + Size = new Size(150, 150), + TabIndex = 1 + }; + glcMain.Paint += new PaintEventHandler(this.glcMain_Paint); + Controls.Add(glcMain); + } - private void SetupGLControl() + protected override void OnResize(EventArgs e) + { + base.OnResize(e); + if (!_designMode) { - glcMain = new() - { - BackColor = Color.Black, - Dock = DockStyle.Fill, - Location = new Point(0, 0), - Name = "glcMain", - Size = new Size(150, 150), - TabIndex = 1 - }; - glcMain.Paint += new PaintEventHandler(this.glcMain_Paint); - Controls.Add(glcMain); + _graphicsScene?.Resize(glcMain.Width, glcMain.Height); } + } - protected override void OnResize(EventArgs e) + private void InitScene(Scene scene) + { + if (!_designMode) { - base.OnResize(e); - if (!_designMode) + if (_graphicsScene != null) { - _graphicsScene?.Resize(glcMain.Width, glcMain.Height); + _graphicsScene.FrameRendered -= GraphicsSceneOnFrameRendered; + _graphicsScene.Cleanup(); + _graphicsScene = null; } - } + _graphicsScene = new GraphicsScene(scene, glcMain.Width, glcMain.Height); + _graphicsScene.FrameRendered += GraphicsSceneOnFrameRendered; - private void InitScene(Scene scene) - { - if (!_designMode) - { - if (_graphicsScene != null) - { - _graphicsScene.FrameRendered -= GraphicsSceneOnFrameRendered; - _graphicsScene.Cleanup(); - _graphicsScene = null; - } - _graphicsScene = new GraphicsScene(scene, glcMain.Width, glcMain.Height); - _graphicsScene.FrameRendered += GraphicsSceneOnFrameRendered; - - tmrUpdate.Enabled = true; - - _sceneChanged = true; - } - } + tmrUpdate.Enabled = true; - private void GraphicsSceneOnFrameRendered() - { - glcMain.SwapBuffers(); + _sceneChanged = true; } + } + + private void GraphicsSceneOnFrameRendered() + { + glcMain.SwapBuffers(); + } - public void ExportCollada14() + public void ExportCollada14() + { + if (Scene == null) + return; + SaveFileDialog sfd = new(); + sfd.Filter = "Collada Document|*.dae|All Files|*.*"; + DialogResult result = sfd.ShowDialog(this); + if (result == DialogResult.OK) { - if (Scene == null) + if (string.IsNullOrEmpty(sfd.FileName)) return; - SaveFileDialog sfd = new SaveFileDialog(); - sfd.Filter = "Collada Document|*.dae|All Files|*.*"; - DialogResult result = sfd.ShowDialog(this); - if (result == DialogResult.OK) - { - if (string.IsNullOrEmpty(sfd.FileName)) - return; - Scene.ExportCollada14(sfd.FileName); - } + Scene.ExportCollada14(sfd.FileName); } + } - public void ExportWavefrontObj() + public void ExportWavefrontObj() + { + if (Scene == null) + return; + SaveFileDialog sfd = new(); + sfd.Filter = "Wavefront OBJ|*.obj|All Files|*.*"; + DialogResult result = sfd.ShowDialog(this); + if (result == DialogResult.OK) { - if (Scene == null) + if (string.IsNullOrEmpty(sfd.FileName)) return; - SaveFileDialog sfd = new SaveFileDialog(); - sfd.Filter = "Wavefront OBJ|*.obj|All Files|*.*"; - DialogResult result = sfd.ShowDialog(this); - if (result == DialogResult.OK) - { - if (string.IsNullOrEmpty(sfd.FileName)) - return; - Scene.ExportWavefrontObj(sfd.FileName); - } + Scene.ExportWavefrontObj(sfd.FileName); } + } - private void glcMain_Paint(object sender, PaintEventArgs e) + private void glcMain_Paint(object sender, PaintEventArgs e) + { + if (!_designMode) { - if (!_designMode) + if (_sceneChanged) { - if (_sceneChanged) - { - _graphicsScene?.Init(); - _sceneChanged = false; - } - _graphicsScene?.Render(); + _graphicsScene?.Init(); + _sceneChanged = false; } + _graphicsScene?.Render(); } + } - public new void Dispose() + public new void Dispose() + { + if (!_designMode) { - if (!_designMode) - { - tmrUpdate.Enabled = false; - _graphicsScene?.Cleanup(); - } - base.Dispose(); + tmrUpdate.Enabled = false; + _graphicsScene?.Cleanup(); } + base.Dispose(); + } - private int _updateCount; - private void tmrUpdate_Tick(object sender, EventArgs e) + private int _updateCount; + private void tmrUpdate_Tick(object sender, EventArgs e) + { + if (!_designMode) { - if (!_designMode) + if (_updateCount < 2) + tmrUpdate.Interval = 17; + else { - if (_updateCount < 2) - tmrUpdate.Interval = 17; - else - { - tmrUpdate.Interval = 16; - _updateCount = 0; - } - _updateCount++; - - _graphicsScene?.Update(); - glcMain.Refresh(); + tmrUpdate.Interval = 16; + _updateCount = 0; } + _updateCount++; + + _graphicsScene?.Update(); + glcMain.Refresh(); } } } diff --git a/ModelViewer/Shader.cs b/ModelViewer/Shader.cs index 5586e83..af66ec1 100644 --- a/ModelViewer/Shader.cs +++ b/ModelViewer/Shader.cs @@ -3,68 +3,67 @@ using System.IO; using OpenTK.Graphics.OpenGL; -namespace ModelViewer +namespace ModelViewer; + +public class Shader { - public class Shader - { - private readonly string _vertex; - private readonly string _fragment; + private readonly string _vertex; + private readonly string _fragment; - public int ShaderID - { - get; - private set; - } + public int ShaderID + { + get; + private set; + } - public Shader(string vertex, string fragment) - { - ShaderID = -1; - _vertex = vertex; - _fragment = fragment; - } + public Shader(string vertex, string fragment) + { + ShaderID = -1; + _vertex = vertex; + _fragment = fragment; + } - public Shader(string name) - { - ShaderID = -1; - _vertex = File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Shaders/" + name + "V.glsl")); - _fragment = File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Shaders/" + name + "P.glsl")); - } + public Shader(string name) + { + ShaderID = -1; + _vertex = File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Shaders/" + name + "V.glsl")); + _fragment = File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Shaders/" + name + "P.glsl")); + } - public int Compile() - { - int vertexShader = GL.CreateShader(ShaderType.VertexShader); - GL.ShaderSource(vertexShader, _vertex); - GL.CompileShader(vertexShader); + public int Compile() + { + int vertexShader = GL.CreateShader(ShaderType.VertexShader); + GL.ShaderSource(vertexShader, _vertex); + GL.CompileShader(vertexShader); - int fragmentShader = GL.CreateShader(ShaderType.FragmentShader); - GL.ShaderSource(fragmentShader, _fragment); - GL.CompileShader(fragmentShader); + int fragmentShader = GL.CreateShader(ShaderType.FragmentShader); + GL.ShaderSource(fragmentShader, _fragment); + GL.CompileShader(fragmentShader); - ShaderID = GL.CreateProgram(); - GL.AttachShader(ShaderID, vertexShader); - GL.AttachShader(ShaderID, fragmentShader); - GL.LinkProgram(ShaderID); - string info = GL.GetProgramInfoLog(ShaderID); - if (!string.IsNullOrEmpty(info)) - Debug.WriteLine($"GL.LinkProgram had info log: {info}"); + ShaderID = GL.CreateProgram(); + GL.AttachShader(ShaderID, vertexShader); + GL.AttachShader(ShaderID, fragmentShader); + GL.LinkProgram(ShaderID); + string info = GL.GetProgramInfoLog(ShaderID); + if (!string.IsNullOrEmpty(info)) + Debug.WriteLine($"GL.LinkProgram had info log: {info}"); - GL.DetachShader(ShaderID, vertexShader); - GL.DetachShader(ShaderID, fragmentShader); - GL.DeleteShader(vertexShader); - GL.DeleteShader(fragmentShader); + GL.DetachShader(ShaderID, vertexShader); + GL.DetachShader(ShaderID, fragmentShader); + GL.DeleteShader(vertexShader); + GL.DeleteShader(fragmentShader); - return ShaderID; - } + return ShaderID; + } - public void Bind() - { - GL.UseProgram(ShaderID); - } + public void Bind() + { + GL.UseProgram(ShaderID); + } - public void Dispose() - { - ShaderID = -1; - GL.DeleteProgram(ShaderID); - } + public void Dispose() + { + ShaderID = -1; + GL.DeleteProgram(ShaderID); } } diff --git a/ModelViewer/StaticCamera.cs b/ModelViewer/StaticCamera.cs index 8d22ec4..3a99d00 100644 --- a/ModelViewer/StaticCamera.cs +++ b/ModelViewer/StaticCamera.cs @@ -1,25 +1,24 @@ using OpenTK.Mathematics; -namespace ModelViewer +namespace ModelViewer; + +public class StaticCamera : ICamera { - public class StaticCamera : ICamera - { - public Matrix4 LookAtMatrix { get; } + public Matrix4 LookAtMatrix { get; } - public StaticCamera() - { - Vector3 position = new Vector3(0, 0, 0); - LookAtMatrix = Matrix4.LookAt(position, -Vector3.UnitZ, Vector3.UnitY); - } + public StaticCamera() + { + Vector3 position = new(0, 0, 0); + LookAtMatrix = Matrix4.LookAt(position, -Vector3.UnitZ, Vector3.UnitY); + } - public StaticCamera(Vector3 position, Vector3 target) - { - LookAtMatrix = Matrix4.LookAt(position, target, Vector3.UnitY); - } + public StaticCamera(Vector3 position, Vector3 target) + { + LookAtMatrix = Matrix4.LookAt(position, target, Vector3.UnitY); + } - public void Update() - { - - } + public void Update() + { + } } diff --git a/ModelViewer/ThirdPersonCamera.cs b/ModelViewer/ThirdPersonCamera.cs index d10bef5..91ef85c 100644 --- a/ModelViewer/ThirdPersonCamera.cs +++ b/ModelViewer/ThirdPersonCamera.cs @@ -1,29 +1,28 @@ using ModelViewer.SceneData; using OpenTK.Mathematics; -namespace ModelViewer +namespace ModelViewer; + +public class ThirdPersonCamera : ICamera { - public class ThirdPersonCamera : ICamera - { - public Matrix4 LookAtMatrix { get; private set; } - private readonly SceneObject _target; - private readonly Vector3 _offset; + public Matrix4 LookAtMatrix { get; private set; } + private readonly SceneObject _target; + private readonly Vector3 _offset; - public ThirdPersonCamera(SceneObject target) : this(target, Vector3.Zero) - { - - } + public ThirdPersonCamera(SceneObject target) : this(target, Vector3.Zero) + { + + } - public ThirdPersonCamera(SceneObject target, Vector3 offset) - { - _target = target; - _offset = offset; - } + public ThirdPersonCamera(SceneObject target, Vector3 offset) + { + _target = target; + _offset = offset; + } - public void Update() - { - LookAtMatrix = Matrix4.LookAt(_target.Position + (_offset * _target.Direction), _target.Position, - Vector3.UnitY); - } + public void Update() + { + LookAtMatrix = Matrix4.LookAt(_target.Position + (_offset * _target.Direction), _target.Position, + Vector3.UnitY); } } diff --git a/PVSFormat/AddZone.cs b/PVSFormat/AddZone.cs index 4c74134..57b36ec 100644 --- a/PVSFormat/AddZone.cs +++ b/PVSFormat/AddZone.cs @@ -1,33 +1,32 @@ using System; using System.Windows.Forms; -namespace PVSFormat +namespace PVSFormat; + +public partial class AddZone : Form { - public partial class AddZone : Form - { - ulong zone; + ulong zone; - public AddZone() - { - InitializeComponent(); - } + public AddZone() + { + InitializeComponent(); + } - public ulong GetNewZoneId() - { - ShowDialog(); - return zone; - } + public ulong GetNewZoneId() + { + ShowDialog(); + return zone; + } - private void okButton_Click(object sender, EventArgs e) - { - zone = (ulong)zoneIdNumericUpDown.Value; - Close(); - } + private void okButton_Click(object sender, EventArgs e) + { + zone = (ulong)zoneIdNumericUpDown.Value; + Close(); + } - private void cancelButton_Click(object sender, EventArgs e) - { - zone = ulong.MaxValue; - Close(); - } + private void cancelButton_Click(object sender, EventArgs e) + { + zone = ulong.MaxValue; + Close(); } } diff --git a/PVSFormat/PVS.cs b/PVSFormat/PVS.cs index e2bba7f..5d433cb 100644 --- a/PVSFormat/PVS.cs +++ b/PVSFormat/PVS.cs @@ -8,309 +8,308 @@ using BurnoutImage; using PluginAPI; -namespace PVSFormat +namespace PVSFormat; + +public struct ZoneList { - public struct ZoneList + //public List Points; // Redundant; use Zones[zoneIndex].Points + public List Zones; + //public List ZonePointStarts; // Per-zone start point index. Unnecessary as they are always sequential multiples of 4 + //public List ZonePointCounts; // Per-zone point count. Unnecessary as there are always 4 points + public uint TotalZones; + //public uint TotalPoints; // Unnecessary, calculated during writing + + public ZoneList() { - //public List Points; // Redundant; use Zones[zoneIndex].Points - public List Zones; - //public List ZonePointStarts; // Per-zone start point index. Unnecessary as they are always sequential multiples of 4 - //public List ZonePointCounts; // Per-zone point count. Unnecessary as there are always 4 points - public uint TotalZones; - //public uint TotalPoints; // Unnecessary, calculated during writing - - public ZoneList() - { - Zones = new(); - //ZonePointStarts = new(); - //ZonePointCounts = new(); - } + Zones = []; + //ZonePointStarts = new(); + //ZonePointCounts = new(); } +} - public struct Zone +public struct Zone +{ + public List Points; + //public List SafeNeighbours; // Unnecessary, always empty + public List UnsafeNeighbours; + public ulong ZoneId; + //public short ZoneType; // Unnecessary, always 0 + //public short NumPoints; // Unnecessary, always 4 + //public short NumSafeNeighbours; // Unnecessary, always 0 + public short NumUnsafeNeighbours; + //public ulong Flags; // Unnecessary, always 0 + + public Zone() { - public List Points; - //public List SafeNeighbours; // Unnecessary, always empty - public List UnsafeNeighbours; - public ulong ZoneId; - //public short ZoneType; // Unnecessary, always 0 - //public short NumPoints; // Unnecessary, always 4 - //public short NumSafeNeighbours; // Unnecessary, always 0 - public short NumUnsafeNeighbours; - //public ulong Flags; // Unnecessary, always 0 - - public Zone() - { - Points = new(); - for (int i = 0; i < 400; i += 100) - Points.Add(new(i % 200, i > 100 ? 0 : 100)); // 0x0,100x0,0x100,100x100 - //SafeNeighbours = new(); - UnsafeNeighbours = new(); - } + Points = []; + for (int i = 0; i < 400; i += 100) + Points.Add(new(i % 200, i > 100 ? 0 : 100)); // 0x0,100x0,0x100,100x100 + //SafeNeighbours = new(); + UnsafeNeighbours = []; } +} - public struct Neighbour - { - //Zone Zone; // Redundant, replaced by ZoneId - public ulong ZoneId; - public NeighbourFlags Flags; - } +public struct Neighbour +{ + //Zone Zone; // Redundant, replaced by ZoneId + public ulong ZoneId; + public NeighbourFlags Flags; +} - [Flags] - public enum NeighbourFlags - { - E_RENDERFLAG_NONE = 0x0, - E_NEIGHBOURFLAG_RENDER = 0x1, - E_NEIGHBOURFLAG_IMMEDIATE = 0x2 - } +[Flags] +public enum NeighbourFlags +{ + E_RENDERFLAG_NONE = 0x0, + E_NEIGHBOURFLAG_RENDER = 0x1, + E_NEIGHBOURFLAG_IMMEDIATE = 0x2 +} - public class PVS : IEntryData - { - public ZoneList data; +public class PVS : IEntryData +{ + public ZoneList data; - private Image _gameMap; - internal ulong selectedZoneId = ulong.MaxValue; + private Image _gameMap; + internal ulong selectedZoneId = ulong.MaxValue; - public bool Read(BundleEntry entry, ILoader loader = null) + public bool Read(BundleEntry entry, ILoader loader = null) + { + data = new(); + + BinaryReader2 br = new(entry.MakeStream()); + br.BigEndian = entry.Console; + + // Decomp has 8-byte pointers so the zone fields after the pointers shift by 8 + bool x64 = entry.Platform == BundlePlatform.PCx64; + int ptrSize = x64 ? 8 : 4; + int zoneIdOffset = x64 ? 0x18 : 0x10; + long ReadPtr() => x64 ? (long)br.ReadUInt64() : br.ReadUInt32(); + + // Get zone count + br.BaseStream.Position = 4 * ptrSize; + data.TotalZones = br.ReadUInt32(); + + // Get zones + br.BaseStream.Position = ptrSize; + br.BaseStream.Position = ReadPtr(); + long zonePos; + long unsafeNeighboursPos; + long unsafeNeighbourZonePos; + for (int i = 0; i < data.TotalZones; ++i) { - data = new(); - - BinaryReader2 br = new(entry.MakeStream()); - br.BigEndian = entry.Console; - - // Decomp has 8-byte pointers so the zone fields after the pointers shift by 8 - bool x64 = entry.Platform == BundlePlatform.PCx64; - int ptrSize = x64 ? 8 : 4; - int zoneIdOffset = x64 ? 0x18 : 0x10; - long ReadPtr() => x64 ? (long)br.ReadUInt64() : br.ReadUInt32(); + Zone zone = new(); + zonePos = br.BaseStream.Position; - // Get zone count - br.BaseStream.Position = 4 * ptrSize; - data.TotalZones = br.ReadUInt32(); - - // Get zones - br.BaseStream.Position = ptrSize; + // Get points br.BaseStream.Position = ReadPtr(); - long zonePos; - long unsafeNeighboursPos; - long unsafeNeighbourZonePos; - for (int i = 0; i < data.TotalZones; ++i) + for (int j = 0; j < 4; ++j) { - Zone zone = new(); - zonePos = br.BaseStream.Position; + zone.Points[j] = new(br.ReadSingle(), br.ReadSingle()); + br.SkipUniquePadding(8); + } - // Get points - br.BaseStream.Position = ReadPtr(); - for (int j = 0; j < 4; ++j) - { - zone.Points[j] = new(br.ReadSingle(), br.ReadSingle()); - br.SkipUniquePadding(8); - } + // Get unsafe neighbours + br.BaseStream.Position = zonePos + zoneIdOffset + 0xE; + zone.NumUnsafeNeighbours = br.ReadInt16(); + br.BaseStream.Position = zonePos + 2 * ptrSize; + unsafeNeighboursPos = ReadPtr(); + for (int j = 0; j < zone.NumUnsafeNeighbours; ++j) + { + Neighbour neighbour = new(); + br.BaseStream.Position = unsafeNeighboursPos + 0x10 * j; + unsafeNeighbourZonePos = ReadPtr(); + neighbour.Flags = (NeighbourFlags)br.ReadUInt32(); + br.BaseStream.Position = unsafeNeighbourZonePos + zoneIdOffset; + neighbour.ZoneId = br.ReadUInt64(); + zone.UnsafeNeighbours.Add(neighbour); + } - // Get unsafe neighbours - br.BaseStream.Position = zonePos + zoneIdOffset + 0xE; - zone.NumUnsafeNeighbours = br.ReadInt16(); - br.BaseStream.Position = zonePos + 2 * ptrSize; - unsafeNeighboursPos = ReadPtr(); - for (int j = 0; j < zone.NumUnsafeNeighbours; ++j) - { - Neighbour neighbour = new(); - br.BaseStream.Position = unsafeNeighboursPos + 0x10 * j; - unsafeNeighbourZonePos = ReadPtr(); - neighbour.Flags = (NeighbourFlags)br.ReadUInt32(); - br.BaseStream.Position = unsafeNeighbourZonePos + zoneIdOffset; - neighbour.ZoneId = br.ReadUInt64(); - zone.UnsafeNeighbours.Add(neighbour); - } + // Get zone ID + br.BaseStream.Position = zonePos + zoneIdOffset; + zone.ZoneId = br.ReadUInt64(); + br.BaseStream.Position = zonePos + 0x30; // Seek to next zone - // Get zone ID - br.BaseStream.Position = zonePos + zoneIdOffset; - zone.ZoneId = br.ReadUInt64(); - br.BaseStream.Position = zonePos + 0x30; // Seek to next zone + data.Zones.Add(zone); + } - data.Zones.Add(zone); - } + br.Close(); - br.Close(); + _gameMap = GetGameMap(entry.Archive); - _gameMap = GetGameMap(entry.Archive); + return true; + } - return true; - } + public bool Write(BundleEntry entry) + { + MemoryStream ms = new(); + BinaryWriter2 bw = new(ms); + bw.BigEndian = entry.Console; - public bool Write(BundleEntry entry) + bool x64 = entry.Platform == BundlePlatform.PCx64; + void WritePtr(uint ptr) { - MemoryStream ms = new MemoryStream(); - BinaryWriter2 bw = new BinaryWriter2(ms); - bw.BigEndian = entry.Console; - - bool x64 = entry.Platform == BundlePlatform.PCx64; - void WritePtr(uint ptr) - { - if (x64) - bw.Write((ulong)ptr); - else - bw.Write(ptr); - } + if (x64) + bw.Write((ulong)ptr); + else + bw.Write(ptr); + } - // Update neighbours in case of zone deletion - for (int i = 0; i < data.TotalZones; ++i) + // Update neighbours in case of zone deletion + for (int i = 0; i < data.TotalZones; ++i) + { + for (int j = 0; j < data.Zones[i].NumUnsafeNeighbours; ++j) { - for (int j = 0; j < data.Zones[i].NumUnsafeNeighbours; ++j) + if (data.Zones.FindIndex(z => z.ZoneId == data.Zones[i].UnsafeNeighbours[j].ZoneId) == -1) { - if (data.Zones.FindIndex(z => z.ZoneId == data.Zones[i].UnsafeNeighbours[j].ZoneId) == -1) - { - Zone zone = data.Zones[i]; - zone.UnsafeNeighbours.RemoveAt(j); - zone.NumUnsafeNeighbours--; - data.Zones[i] = zone; - } + Zone zone = data.Zones[i]; + zone.UnsafeNeighbours.RemoveAt(j); + zone.NumUnsafeNeighbours--; + data.Zones[i] = zone; } } + } - // Get necessary information before writing - uint zonesPtr = x64 ? 0x30u : 0x20u; - uint zonesLength = data.TotalZones * 0x30; - uint neighboursPtr = zonesPtr + zonesLength; - uint neighborsLength = 0; - for (int i = 0; i < data.Zones.Count; ++i) - neighborsLength += (uint)data.Zones[i].NumUnsafeNeighbours * 0x10; - uint pointsPtr = neighboursPtr + neighborsLength; - uint pointsLength = (uint)(data.Zones.Count * 0x4 * 0x10); - uint zoneStartsPtr = pointsPtr + pointsLength; - uint zoneStartsLength = data.TotalZones * 0x4; - uint zoneCountsPtr = zoneStartsPtr + zoneStartsLength; - if (zoneCountsPtr % 0x10 != 0) // Align - zoneCountsPtr = (zoneCountsPtr & 0xFFFFFFF0) + 0x10; - - // Write ZoneList - WritePtr(pointsPtr); - WritePtr(zonesPtr); - WritePtr(zoneStartsPtr); - WritePtr(zoneCountsPtr); - bw.Write(data.TotalZones); - bw.Write(data.TotalZones * 0x4); - - // Write zones - uint neighboursPosition = 0; - for (int i = 0; i < data.TotalZones; ++i) + // Get necessary information before writing + uint zonesPtr = x64 ? 0x30u : 0x20u; + uint zonesLength = data.TotalZones * 0x30; + uint neighboursPtr = zonesPtr + zonesLength; + uint neighborsLength = 0; + for (int i = 0; i < data.Zones.Count; ++i) + neighborsLength += (uint)data.Zones[i].NumUnsafeNeighbours * 0x10; + uint pointsPtr = neighboursPtr + neighborsLength; + uint pointsLength = (uint)(data.Zones.Count * 0x4 * 0x10); + uint zoneStartsPtr = pointsPtr + pointsLength; + uint zoneStartsLength = data.TotalZones * 0x4; + uint zoneCountsPtr = zoneStartsPtr + zoneStartsLength; + if (zoneCountsPtr % 0x10 != 0) // Align + zoneCountsPtr = (zoneCountsPtr & 0xFFFFFFF0) + 0x10; + + // Write ZoneList + WritePtr(pointsPtr); + WritePtr(zonesPtr); + WritePtr(zoneStartsPtr); + WritePtr(zoneCountsPtr); + bw.Write(data.TotalZones); + bw.Write(data.TotalZones * 0x4); + + // Write zones + uint neighboursPosition = 0; + for (int i = 0; i < data.TotalZones; ++i) + { + bw.BaseStream.Position = zonesPtr + i * 0x30; + WritePtr((uint)(pointsPtr + i * 0x4 * 0x10)); // Points + WritePtr(0); // Safe neighbours + if (data.Zones[i].NumUnsafeNeighbours == 0) // Unsafe neighbours + WritePtr(0); + else + WritePtr(neighboursPtr + neighboursPosition); + if (!x64) + bw.Write(0); // Padding + bw.Write(data.Zones[i].ZoneId); + bw.Write((short)0); // Zone type + bw.Write((short)4); // Point count + bw.Write((short)0); // Safe neighbour count + bw.Write(data.Zones[i].NumUnsafeNeighbours); // Unsafe neighbour count + bw.Write(0); // Flags + + // Write points + bw.BaseStream.Position = pointsPtr + i * 0x4 * 0x10; + for (int j = 0; j < 4; ++j) { - bw.BaseStream.Position = zonesPtr + i * 0x30; - WritePtr((uint)(pointsPtr + i * 0x4 * 0x10)); // Points - WritePtr(0); // Safe neighbours - if (data.Zones[i].NumUnsafeNeighbours == 0) // Unsafe neighbours - WritePtr(0); - else - WritePtr(neighboursPtr + neighboursPosition); - if (!x64) - bw.Write(0); // Padding - bw.Write(data.Zones[i].ZoneId); - bw.Write((short)0); // Zone type - bw.Write((short)4); // Point count - bw.Write((short)0); // Safe neighbour count - bw.Write(data.Zones[i].NumUnsafeNeighbours); // Unsafe neighbour count - bw.Write(0); // Flags - - // Write points - bw.BaseStream.Position = pointsPtr + i * 0x4 * 0x10; - for (int j = 0; j < 4; ++j) - { - bw.Write(data.Zones[i].Points[j].X); - bw.Write(data.Zones[i].Points[j].Y); - bw.BaseStream.Position += 0x8; - } + bw.Write(data.Zones[i].Points[j].X); + bw.Write(data.Zones[i].Points[j].Y); + bw.BaseStream.Position += 0x8; + } - // Write neighbours - for (int j = 0; j < data.Zones[i].NumUnsafeNeighbours; ++j) - { - bw.BaseStream.Position = neighboursPtr + neighboursPosition; - ulong zoneId = data.Zones[i].UnsafeNeighbours[j].ZoneId; - int neighbourZoneIndex = data.Zones.FindIndex(z => z.ZoneId == zoneId); - uint neighbourZonePtr = (uint)(zonesPtr + neighbourZoneIndex * 0x30); - WritePtr(neighbourZonePtr); - bw.Write((uint)data.Zones[i].UnsafeNeighbours[j].Flags); - neighboursPosition += 0x10; - } + // Write neighbours + for (int j = 0; j < data.Zones[i].NumUnsafeNeighbours; ++j) + { + bw.BaseStream.Position = neighboursPtr + neighboursPosition; + ulong zoneId = data.Zones[i].UnsafeNeighbours[j].ZoneId; + int neighbourZoneIndex = data.Zones.FindIndex(z => z.ZoneId == zoneId); + uint neighbourZonePtr = (uint)(zonesPtr + neighbourZoneIndex * 0x30); + WritePtr(neighbourZonePtr); + bw.Write((uint)data.Zones[i].UnsafeNeighbours[j].Flags); + neighboursPosition += 0x10; } + } - // Write zone start point indices - bw.BaseStream.Position = zoneStartsPtr; - for (int i = 0; i < data.TotalZones * 4; i += 4) - bw.Write(i); + // Write zone start point indices + bw.BaseStream.Position = zoneStartsPtr; + for (int i = 0; i < data.TotalZones * 4; i += 4) + bw.Write(i); - // Write zone point counts - bw.BaseStream.Position = zoneCountsPtr; - for (int i = 0; i < data.TotalZones; ++i) - bw.Write((short)4); + // Write zone point counts + bw.BaseStream.Position = zoneCountsPtr; + for (int i = 0; i < data.TotalZones; ++i) + bw.Write((short)4); - bw.Align(16); + bw.Align(16); - bw.Flush(); - byte[] rawData = ms.ToArray(); - bw.Close(); - ms.Close(); + bw.Flush(); + byte[] rawData = ms.ToArray(); + bw.Close(); + ms.Close(); - entry.EntryBlocks[0].Data = rawData; - entry.Dirty = true; + entry.EntryBlocks[0].Data = rawData; + entry.Dirty = true; - return true; - } + return true; + } - public EntryType GetEntryType(BundleEntry entry) - { - return EntryType.ZoneList; - } + public EntryType GetEntryType(BundleEntry entry) + { + return EntryType.ZoneList; + } - public IEntryEditor GetEditor(BundleEntry entry) - { - PVSEditor pvsForm = new(); - pvsForm.GameMap = _gameMap; - pvsForm.Open(this); + public IEntryEditor GetEditor(BundleEntry entry) + { + PVSEditor pvsForm = new(); + pvsForm.GameMap = _gameMap; + pvsForm.Open(this); - pvsForm.Edit += () => - { - Write(entry); - }; + pvsForm.Edit += () => + { + Write(entry); + }; - return pvsForm; - } + return pvsForm; + } - private Image GetGameMap(BundleArchive archive) + private Image GetGameMap(BundleArchive archive) + { + ulong id = 0x9F55039D; + BundleEntry descEntry1 = archive.GetEntryByID(id); + if (descEntry1 == null) { - ulong id = 0x9F55039D; - BundleEntry descEntry1 = archive.GetEntryByID(id); - if (descEntry1 == null) + string file = BundleCache.GetFileByEntryID(id); + if (!string.IsNullOrEmpty(file)) { - string file = BundleCache.GetFileByEntryID(id); - if (!string.IsNullOrEmpty(file)) - { - BundleArchive archive2 = BundleArchive.Read(file); - if (archive2 != null) - descEntry1 = archive2.GetEntryByID(id); - } + BundleArchive archive2 = BundleArchive.Read(file); + if (archive2 != null) + descEntry1 = archive2.GetEntryByID(id); } + } - if (descEntry1 == null) + if (descEntry1 == null) + { + string path = Path.GetDirectoryName(archive.Path) + Path.DirectorySeparatorChar + "GUITEXTURES.BIN"; + if (Path.Exists(path)) { - string path = Path.GetDirectoryName(archive.Path) + Path.DirectorySeparatorChar + "GUITEXTURES.BIN"; - if (Path.Exists(path)) - { - BundleArchive archive2 = BundleArchive.Read(path); - if (archive2 != null) - descEntry1 = archive2.GetEntryByID(id); - } + BundleArchive archive2 = BundleArchive.Read(path); + if (archive2 != null) + descEntry1 = archive2.GetEntryByID(id); } + } - Image image = null; + Image image = null; - if (descEntry1 != null && descEntry1.Type == EntryType.Texture) - { - image = GameImage.GetImage(descEntry1.EntryBlocks[0].Data, descEntry1.EntryBlocks[1].Data); + if (descEntry1 != null && descEntry1.Type == EntryType.Texture) + { + image = GameImage.GetImage(descEntry1.EntryBlocks[0].Data, descEntry1.EntryBlocks[1].Data); - if (image != null) - TextureCache.AddToCache(id, image); - } - return image; + if (image != null) + TextureCache.AddToCache(id, image); } + return image; } } diff --git a/PVSFormat/PVSEditControl.cs b/PVSFormat/PVSEditControl.cs index cd0cdb8..9fa69ed 100644 --- a/PVSFormat/PVSEditControl.cs +++ b/PVSFormat/PVSEditControl.cs @@ -5,344 +5,341 @@ using System.Numerics; using System.Windows.Forms; -namespace PVSFormat +namespace PVSFormat; + +public class PVSEditControl : Control { - public class PVSEditControl : Control + private PVS _pvsFile; + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public PVS PVS { - private PVS _pvsFile; - [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] - public PVS PVS + get => _pvsFile; + set { - get => _pvsFile; - set - { - _pvsFile = value; - OnPVSUpdated(); - } + _pvsFile = value; + OnPVSUpdated(); } + } - public Image GameMap; + public Image GameMap; - protected const float Multiplier = 0.1f; + protected const float Multiplier = 0.1f; - protected float RenderScale; - //protected float Zoom; - protected PointF CameraPosition; - protected PointF RenderOffset => new PointF(-CameraPosition.X + ClientRectangle.Width / 2.0f, -CameraPosition.Y + ClientRectangle.Height / 2.0f); - protected float MapSize => (RenderScale * 32); - protected bool isDragging; - protected Point lastMouse; - protected Point mousePos; + protected float RenderScale; + //protected float Zoom; + protected PointF CameraPosition; + protected PointF RenderOffset => new(-CameraPosition.X + ClientRectangle.Width / 2.0f, -CameraPosition.Y + ClientRectangle.Height / 2.0f); + protected float MapSize => (RenderScale * 32); + protected bool isDragging; + protected Point lastMouse; + protected Point mousePos; - protected enum MapSectionType - { - Unloaded, - Current, - Neighbour - } + protected enum MapSectionType + { + Unloaded, + Current, + Neighbour + } - internal PointF MousePosOnMap + internal PointF MousePosOnMap + { + get { - get - { - return new PointF((mousePos.X - ClientRectangle.Width / 2.0f + CameraPosition.X) / RenderScale / Multiplier, (mousePos.Y - ClientRectangle.Height / 2.0f + CameraPosition.Y) / RenderScale / Multiplier); - } + return new PointF((mousePos.X - ClientRectangle.Width / 2.0f + CameraPosition.X) / RenderScale / Multiplier, (mousePos.Y - ClientRectangle.Height / 2.0f + CameraPosition.Y) / RenderScale / Multiplier); } + } - protected PointF ScaledMousePosOnMap + protected PointF ScaledMousePosOnMap + { + get { - get - { - return new PointF(mousePos.X - ClientRectangle.Width / 2.0f + CameraPosition.X, mousePos.Y - ClientRectangle.Height / 2.0f + CameraPosition.Y); - } + return new PointF(mousePos.X - ClientRectangle.Width / 2.0f + CameraPosition.X, mousePos.Y - ClientRectangle.Height / 2.0f + CameraPosition.Y); } + } - public PVSEditControl() - { - Width = 400; - Height = 300; - ForeColor = Color.White; - BackColor = Color.Black; - Font = new Font(FontFamily.GenericMonospace, 10.0f); - DoubleBuffered = true; + public PVSEditControl() + { + Width = 400; + Height = 300; + ForeColor = Color.White; + BackColor = Color.Black; + Font = new Font(FontFamily.GenericMonospace, 10.0f); + DoubleBuffered = true; - RenderScale = 1; + RenderScale = 1; - CameraPosition = new Point(0, 0); - } + CameraPosition = new Point(0, 0); + } - // Get zone ID for UI update - public ulong GetZoneId() + // Get zone ID for UI update + public ulong GetZoneId() + { + ulong id = ulong.MaxValue; + foreach (Zone zone in PVS.data.Zones) { - ulong id = ulong.MaxValue; - foreach (Zone zone in PVS.data.Zones) + List points = []; + foreach (Vector2 point in zone.Points) + points.Add(new PointF(point.X, point.Y)); + Polygon polygon = new(points); + if (MousePosOnMap.X >= polygon.MinX && MousePosOnMap.X < polygon.MaxX + && MousePosOnMap.Y >= polygon.MinY && MousePosOnMap.Y < polygon.MaxY) { - List points = new(); - foreach (Vector2 point in zone.Points) - points.Add(new PointF(point.X, point.Y)); - Polygon polygon = new Polygon(points); - if (MousePosOnMap.X >= polygon.MinX && MousePosOnMap.X < polygon.MaxX - && MousePosOnMap.Y >= polygon.MinY && MousePosOnMap.Y < polygon.MaxY) - { - id = zone.ZoneId; - break; - } + id = zone.ZoneId; + break; } - return id; - } - - // Get zone index for UI update - public int GetZoneIndex(ulong zoneId) - { - return PVS.data.Zones.FindIndex(z => z.ZoneId == zoneId); - } - - // Get zone info for UI update - public List GetZonePoints(ulong zoneId) - { - List points = new(); - foreach (Vector2 point in PVS.data.Zones[GetZoneIndex(zoneId)].Points) - points.Add(new Vector2(point.X, point.Y)); - return points; } + return id; + } - // Get zone neighbours for UI update - public List GetZoneNeighbours(ulong zoneId) - { - List neighbours = new(); - foreach (Neighbour neighbour in PVS.data.Zones[GetZoneIndex(zoneId)].UnsafeNeighbours) - neighbours.Add(neighbour); - return neighbours; - } + // Get zone index for UI update + public int GetZoneIndex(ulong zoneId) + { + return PVS.data.Zones.FindIndex(z => z.ZoneId == zoneId); + } - protected override void OnMouseDown(MouseEventArgs e) - { - // Move the camera - if (e.Button == MouseButtons.Left) - { - lastMouse = e.Location; + // Get zone info for UI update + public List GetZonePoints(ulong zoneId) + { + List points = []; + foreach (Vector2 point in PVS.data.Zones[GetZoneIndex(zoneId)].Points) + points.Add(new Vector2(point.X, point.Y)); + return points; + } - isDragging = true; - } - } + // Get zone neighbours for UI update + public List GetZoneNeighbours(ulong zoneId) + { + List neighbours = [.. PVS.data.Zones[GetZoneIndex(zoneId)].UnsafeNeighbours]; + return neighbours; + } - protected override void OnMouseUp(MouseEventArgs e) + protected override void OnMouseDown(MouseEventArgs e) + { + // Move the camera + if (e.Button == MouseButtons.Left) { - if (e.Button == MouseButtons.Left) - { - isDragging = false; - lastMouse = new Point(0, 0); - } - } + lastMouse = e.Location; - protected override void OnKeyDown(KeyEventArgs e) - { - // Reset the camera - if (e.KeyData == Keys.R) - { - RenderScale = 1; - CameraPosition.X = 0; - CameraPosition.Y = 0; - Invalidate(); - } + isDragging = true; } + } - protected override void OnKeyUp(KeyEventArgs e) + protected override void OnMouseUp(MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) { + isDragging = false; lastMouse = new Point(0, 0); } + } - // Move the camera - protected override void OnMouseMove(MouseEventArgs e) + protected override void OnKeyDown(KeyEventArgs e) + { + // Reset the camera + if (e.KeyData == Keys.R) { - mousePos = e.Location; + RenderScale = 1; + CameraPosition.X = 0; + CameraPosition.Y = 0; Invalidate(); - if (isDragging) - { - Size difference = new Size(e.X - lastMouse.X, e.Y - lastMouse.Y); - lastMouse = new Point(e.X, e.Y); - - CameraPosition -= difference; - Invalidate(); - } } + } + + protected override void OnKeyUp(KeyEventArgs e) + { + lastMouse = new Point(0, 0); + } - // Zoom - protected override void OnMouseWheel(MouseEventArgs e) + // Move the camera + protected override void OnMouseMove(MouseEventArgs e) + { + mousePos = e.Location; + Invalidate(); + if (isDragging) { - int wheelDelta = 120; + Size difference = new(e.X - lastMouse.X, e.Y - lastMouse.Y); + lastMouse = new Point(e.X, e.Y); - float oldScale = RenderScale; + CameraPosition -= difference; + Invalidate(); + } + } - RenderScale += (e.Delta * (RenderScale / 4)) / (wheelDelta * 1.0f); + // Zoom + protected override void OnMouseWheel(MouseEventArgs e) + { + int wheelDelta = 120; - if (RenderScale < 1) - { - RenderScale = 1; - } - else if (RenderScale > 500) - { - RenderScale = oldScale; - } + float oldScale = RenderScale; - if (oldScale != RenderScale) - { - CameraPosition.X += (ScaledMousePosOnMap.X / 4) * Math.Sign(e.Delta); - CameraPosition.Y += (ScaledMousePosOnMap.Y / 4) * Math.Sign(e.Delta); - } + RenderScale += (e.Delta * (RenderScale / 4)) / (wheelDelta * 1.0f); - Invalidate(); + if (RenderScale < 1) + { + RenderScale = 1; } - - protected override void OnPaint(PaintEventArgs e) + else if (RenderScale > 500) { - Graphics g = e.Graphics; - - DrawMap(g); - DrawPVS(g); - DrawOverlay(g); + RenderScale = oldScale; } - protected void DrawMap(Graphics g) + if (oldScale != RenderScale) { - if (GameMap == null) - return; + CameraPosition.X += (ScaledMousePosOnMap.X / 4) * Math.Sign(e.Delta); + CameraPosition.Y += (ScaledMousePosOnMap.Y / 4) * Math.Sign(e.Delta); + } + + Invalidate(); + } - float x = -4148.0f; //-GameMap.Width / 2 + 4148.0f;// + 200 - 50; - float y = -5858.0f; //-GameMap.Height / 2 + 5858.0f;// - 400 - 250; - float width = 10200.0f;// - 4148.0f; //GameMap.Width; - float height = 9718.0f;// - 5858.0f; // GameMap.Height; + protected override void OnPaint(PaintEventArgs e) + { + Graphics g = e.Graphics; - float mult = 0.1f; + DrawMap(g); + DrawPVS(g); + DrawOverlay(g); + } - //x = x + RenderOffset.X; - //y = y + RenderOffset.Y; + protected void DrawMap(Graphics g) + { + if (GameMap == null) + return; - x = x * mult * RenderScale + RenderOffset.X; - y = y * mult * RenderScale + RenderOffset.Y; - width = width * mult * RenderScale; - height = height * mult * RenderScale; + float x = -4148.0f; //-GameMap.Width / 2 + 4148.0f;// + 200 - 50; + float y = -5858.0f; //-GameMap.Height / 2 + 5858.0f;// - 400 - 250; + float width = 10200.0f;// - 4148.0f; //GameMap.Width; + float height = 9718.0f;// - 5858.0f; // GameMap.Height; - RectangleF rect = new RectangleF(x, y, width, height); + float mult = 0.1f; - g.DrawImage(GameMap, rect); - } + //x = x + RenderOffset.X; + //y = y + RenderOffset.Y; - protected void DrawPVS(Graphics g) + x = x * mult * RenderScale + RenderOffset.X; + y = y * mult * RenderScale + RenderOffset.Y; + width = width * mult * RenderScale; + height = height * mult * RenderScale; + + RectangleF rect = new(x, y, width, height); + + g.DrawImage(GameMap, rect); + } + + protected void DrawPVS(Graphics g) + { + if (PVS == null) + return; + + // Draw all plates + int selectedZoneIndex = PVS.data.Zones.FindIndex(z => z.ZoneId == PVS.selectedZoneId); + for (int i = 0; i < PVS.data.Zones.Count; i++) { - if (PVS == null) - return; + Zone plate = PVS.data.Zones[i]; - // Draw all plates - int selectedZoneIndex = PVS.data.Zones.FindIndex(z => z.ZoneId == PVS.selectedZoneId); - for (int i = 0; i < PVS.data.Zones.Count; i++) + if (selectedZoneIndex != -1) { - Zone plate = PVS.data.Zones[i]; - - if (selectedZoneIndex != -1) + if (i == selectedZoneIndex) + { + DrawMapSection(g, plate, MapSectionType.Current); + continue; + } + if (PVS.data.Zones[selectedZoneIndex].UnsafeNeighbours.FindIndex(n => n.ZoneId == plate.ZoneId) != -1) { - if (i == selectedZoneIndex) - { - DrawMapSection(g, plate, MapSectionType.Current); - continue; - } - if (PVS.data.Zones[selectedZoneIndex].UnsafeNeighbours.FindIndex(n => n.ZoneId == plate.ZoneId) != -1) - { - DrawMapSection(g, plate, MapSectionType.Neighbour); - continue; - } + DrawMapSection(g, plate, MapSectionType.Neighbour); + continue; } - - DrawMapSection(g, plate); } + + DrawMapSection(g, plate); } + } - protected void DrawMapSection(Graphics g, Zone entry, MapSectionType type = MapSectionType.Unloaded) + protected void DrawMapSection(Graphics g, Zone entry, MapSectionType type = MapSectionType.Unloaded) + { + PointF[] points = new PointF[entry.Points.Count]; + for (int i = 0; i < entry.Points.Count; i++) { - PointF[] points = new PointF[entry.Points.Count]; - for (int i = 0; i < entry.Points.Count; i++) - { - Vector2 data = entry.Points[i]; - points[i] = new PointF(data.X * Multiplier * RenderScale + RenderOffset.X, data.Y * Multiplier * RenderScale + RenderOffset.Y); - } + Vector2 data = entry.Points[i]; + points[i] = new PointF(data.X * Multiplier * RenderScale + RenderOffset.X, data.Y * Multiplier * RenderScale + RenderOffset.Y); + } - Polygon poly = new Polygon(points); - RectangleF bounds = poly.Bounds; + Polygon poly = new(points); + RectangleF bounds = poly.Bounds; - if (bounds.IntersectsWith(ClientRectangle)) - { - if (type == MapSectionType.Current) - g.FillPolygon(new SolidBrush(Color.FromArgb(127, 255, 0, 0)), points); // Red - else if (type == MapSectionType.Neighbour) - g.FillPolygon(new SolidBrush(Color.FromArgb(127, 255, 255, 0)), points); // Yellow - g.DrawPolygon(new Pen(Color.Cyan), points); + if (bounds.IntersectsWith(ClientRectangle)) + { + if (type == MapSectionType.Current) + g.FillPolygon(new SolidBrush(Color.FromArgb(127, 255, 0, 0)), points); // Red + else if (type == MapSectionType.Neighbour) + g.FillPolygon(new SolidBrush(Color.FromArgb(127, 255, 255, 0)), points); // Yellow + g.DrawPolygon(new Pen(Color.Cyan), points); - Font font; + Font font; - string infoText; - SizeF textSize; + string infoText; + SizeF textSize; - int times = 0; + int times = 0; - // Scale font to fit within rectangle - bool noRender = false; - do - { - if (RenderScale / Multiplier - times < 0.01f) - { - font = null; - infoText = null; - textSize = new SizeF(); - noRender = true; - break; - } - float textScale = RenderScale / (Multiplier * 2) - times; - font = new Font(Font.FontFamily, textScale); - infoText = entry.ZoneId.ToString(); - textSize = g.MeasureString(infoText, font); - - times++; - } while (textSize.Width > bounds.Width || textSize.Height > bounds.Height); - - if (!noRender) + // Scale font to fit within rectangle + bool noRender = false; + do + { + if (RenderScale / Multiplier - times < 0.01f) { - // Render text - StringFormat format = new StringFormat(StringFormat.GenericDefault); - format.Alignment = StringAlignment.Center; - g.DrawString(infoText, font, new SolidBrush(ForeColor), bounds.X + bounds.Width / 2, bounds.Y + bounds.Height / 2 - textSize.Height / 2, format); + font = null; + infoText = null; + textSize = new SizeF(); + noRender = true; + break; } + float textScale = RenderScale / (Multiplier * 2) - times; + font = new Font(Font.FontFamily, textScale); + infoText = entry.ZoneId.ToString(); + textSize = g.MeasureString(infoText, font); + + times++; + } while (textSize.Width > bounds.Width || textSize.Height > bounds.Height); + + if (!noRender) + { + // Render text + StringFormat format = new(StringFormat.GenericDefault); + format.Alignment = StringAlignment.Center; + g.DrawString(infoText, font, new SolidBrush(ForeColor), bounds.X + bounds.Width / 2, bounds.Y + bounds.Height / 2 - textSize.Height / 2, format); } } + } - protected void DrawOverlay(Graphics g) - { - // Render Overlay Text - string status = PVS == null ? "Nothing Loaded" : "Loaded"; - g.DrawString(status, Font, new SolidBrush(ForeColor), 10, 10); - - g.DrawString("Zoom x" + (int)RenderScale, Font, new SolidBrush(ForeColor), 10, 25); - g.DrawString("Camera (" + CameraPosition.X + ", " + CameraPosition.Y + ")", Font, new SolidBrush(ForeColor), 10, 40); - g.DrawString("Mouse (" + mousePos.X + ", " + mousePos.Y + ")", Font, new SolidBrush(ForeColor), 10, 55); - //g.DrawString("Map Size " + MapSize + "px", Font, new SolidBrush(ForeColor), 10, 70); - g.DrawString("Mouse Pos On Map (" + MousePosOnMap.X + ", " + MousePosOnMap.Y + ")", Font, new SolidBrush(ForeColor), 10, 85); - //g.DrawString("Scaled Mouse Pos On Map (" + ScaledMousePosOnMap.X + ", " + ScaledMousePosOnMap.Y + ")", Font, new SolidBrush(ForeColor), 10, 100); - } + protected void DrawOverlay(Graphics g) + { + // Render Overlay Text + string status = PVS == null ? "Nothing Loaded" : "Loaded"; + g.DrawString(status, Font, new SolidBrush(ForeColor), 10, 10); + + g.DrawString("Zoom x" + (int)RenderScale, Font, new SolidBrush(ForeColor), 10, 25); + g.DrawString("Camera (" + CameraPosition.X + ", " + CameraPosition.Y + ")", Font, new SolidBrush(ForeColor), 10, 40); + g.DrawString("Mouse (" + mousePos.X + ", " + mousePos.Y + ")", Font, new SolidBrush(ForeColor), 10, 55); + //g.DrawString("Map Size " + MapSize + "px", Font, new SolidBrush(ForeColor), 10, 70); + g.DrawString("Mouse Pos On Map (" + MousePosOnMap.X + ", " + MousePosOnMap.Y + ")", Font, new SolidBrush(ForeColor), 10, 85); + //g.DrawString("Scaled Mouse Pos On Map (" + ScaledMousePosOnMap.X + ", " + ScaledMousePosOnMap.Y + ")", Font, new SolidBrush(ForeColor), 10, 100); + } - protected override void OnPaintBackground(PaintEventArgs e) - { - Graphics g = e.Graphics; - g.FillRectangle(new SolidBrush(BackColor), ClientRectangle); - } + protected override void OnPaintBackground(PaintEventArgs e) + { + Graphics g = e.Graphics; + g.FillRectangle(new SolidBrush(BackColor), ClientRectangle); + } - protected override void OnResize(EventArgs e) - { - Invalidate(); - } + protected override void OnResize(EventArgs e) + { + Invalidate(); + } - private void OnPVSUpdated() - { - Refresh(); - Invalidate(); - } + private void OnPVSUpdated() + { + Refresh(); + Invalidate(); } } diff --git a/PVSFormat/PVSEditor.cs b/PVSFormat/PVSEditor.cs index 6cf2050..2dae367 100644 --- a/PVSFormat/PVSEditor.cs +++ b/PVSFormat/PVSEditor.cs @@ -6,358 +6,357 @@ using System.Numerics; using System.Windows.Forms; -namespace PVSFormat +namespace PVSFormat; + +public partial class PVSEditor : Form, IEntryEditor { - public partial class PVSEditor : Form, IEntryEditor - { - public delegate void OnEdit(); - public event OnEdit Edit; + public delegate void OnEdit(); + public event OnEdit Edit; - private PVS _currentPVS; + private PVS _currentPVS; - [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] - public Image GameMap - { - get => pvsMain.GameMap; - set => pvsMain.GameMap = value; - } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public Image GameMap + { + get => pvsMain.GameMap; + set => pvsMain.GameMap = value; + } - public PVSEditor() - { - InitializeComponent(); - } + public PVSEditor() + { + InitializeComponent(); + } - public void UpdateDisplay() - { - //dbgMain.SelectedObject = _currentPVS; - pvsMain.PVS = _currentPVS; + public void UpdateDisplay() + { + //dbgMain.SelectedObject = _currentPVS; + pvsMain.PVS = _currentPVS; - foreach (Zone zone in pvsMain.PVS.data.Zones) - zonesListBox.Items.Add(zone.ZoneId.ToString("000")); - } + foreach (Zone zone in pvsMain.PVS.data.Zones) + zonesListBox.Items.Add(zone.ZoneId.ToString("000")); + } - public void Open(PVS pvs) - { - _currentPVS = pvs; + public void Open(PVS pvs) + { + _currentPVS = pvs; - UpdateDisplay(); - } + UpdateDisplay(); + } - private List GetZones() - { - return pvsMain.PVS.data.Zones; - } + private List GetZones() + { + return pvsMain.PVS.data.Zones; + } - private List GetPoints() - { - return pvsMain.PVS.data.Zones[pvsMain.GetZoneIndex(ulong.Parse(zonesListBox.SelectedItem.ToString()))].Points; - } + private List GetPoints() + { + return pvsMain.PVS.data.Zones[pvsMain.GetZoneIndex(ulong.Parse(zonesListBox.SelectedItem.ToString()))].Points; + } - private List GetUnsafeNeighbours() - { - return pvsMain.PVS.data.Zones[pvsMain.GetZoneIndex(ulong.Parse(zonesListBox.SelectedItem.ToString()))].UnsafeNeighbours; - } + private List GetUnsafeNeighbours() + { + return pvsMain.PVS.data.Zones[pvsMain.GetZoneIndex(ulong.Parse(zonesListBox.SelectedItem.ToString()))].UnsafeNeighbours; + } - private void SelectZone(ulong zoneId) - { - neighboursListBox.Items.Clear(); - renderCheckBox.Checked = false; - immediateCheckBox.Checked = false; + private void SelectZone(ulong zoneId) + { + neighboursListBox.Items.Clear(); + renderCheckBox.Checked = false; + immediateCheckBox.Checked = false; + + pvsMain.PVS.selectedZoneId = zoneId; + + List points = pvsMain.GetZonePoints(zoneId); + List neighbours = pvsMain.GetZoneNeighbours(zoneId); + + point1XNumericUpDown.Value = (decimal)points[0].X; + point1YNumericUpDown.Value = (decimal)points[0].Y; + point2XNumericUpDown.Value = (decimal)points[1].X; + point2YNumericUpDown.Value = (decimal)points[1].Y; + point3XNumericUpDown.Value = (decimal)points[2].X; + point3YNumericUpDown.Value = (decimal)points[2].Y; + point4XNumericUpDown.Value = (decimal)points[3].X; + point4YNumericUpDown.Value = (decimal)points[3].Y; + + foreach (Neighbour neighbour in neighbours) + neighboursListBox.Items.Add(neighbour.ZoneId.ToString("000")); + + point1XNumericUpDown.Enabled = true; + point1YNumericUpDown.Enabled = true; + point2XNumericUpDown.Enabled = true; + point2YNumericUpDown.Enabled = true; + point3XNumericUpDown.Enabled = true; + point3YNumericUpDown.Enabled = true; + point4XNumericUpDown.Enabled = true; + point4YNumericUpDown.Enabled = true; + neighboursListBox.Enabled = true; + addNeighbourButton.Enabled = true; + deleteNeighbourButton.Enabled = false; + renderCheckBox.Enabled = false; + immediateCheckBox.Enabled = false; + } - pvsMain.PVS.selectedZoneId = zoneId; - - List points = pvsMain.GetZonePoints(zoneId); - List neighbours = pvsMain.GetZoneNeighbours(zoneId); - - point1XNumericUpDown.Value = (decimal)points[0].X; - point1YNumericUpDown.Value = (decimal)points[0].Y; - point2XNumericUpDown.Value = (decimal)points[1].X; - point2YNumericUpDown.Value = (decimal)points[1].Y; - point3XNumericUpDown.Value = (decimal)points[2].X; - point3YNumericUpDown.Value = (decimal)points[2].Y; - point4XNumericUpDown.Value = (decimal)points[3].X; - point4YNumericUpDown.Value = (decimal)points[3].Y; - - foreach (Neighbour neighbour in neighbours) - neighboursListBox.Items.Add(neighbour.ZoneId.ToString("000")); - - point1XNumericUpDown.Enabled = true; - point1YNumericUpDown.Enabled = true; - point2XNumericUpDown.Enabled = true; - point2YNumericUpDown.Enabled = true; - point3XNumericUpDown.Enabled = true; - point3YNumericUpDown.Enabled = true; - point4XNumericUpDown.Enabled = true; - point4YNumericUpDown.Enabled = true; - neighboursListBox.Enabled = true; - addNeighbourButton.Enabled = true; - deleteNeighbourButton.Enabled = false; - renderCheckBox.Enabled = false; - immediateCheckBox.Enabled = false; - } + private void PVSEditor_FormClosing(object sender, FormClosingEventArgs e) + { + pvsMain.PVS.selectedZoneId = ulong.MaxValue; + Edit?.Invoke(); + } - private void PVSEditor_FormClosing(object sender, FormClosingEventArgs e) - { - pvsMain.PVS.selectedZoneId = ulong.MaxValue; - Edit?.Invoke(); - } + private void pvsMain_DoubleClick(object sender, EventArgs e) + { + ulong zoneId = pvsMain.GetZoneId(); + if (zoneId == ulong.MaxValue) + return; - private void pvsMain_DoubleClick(object sender, EventArgs e) - { - ulong zoneId = pvsMain.GetZoneId(); - if (zoneId == ulong.MaxValue) - return; + zonesListBox.SelectedIndex = zonesListBox.FindStringExact(zoneId.ToString("000")); + } - zonesListBox.SelectedIndex = zonesListBox.FindStringExact(zoneId.ToString("000")); - } + private void pvsMain_Click(object sender, EventArgs e) + { + if (((MouseEventArgs)e).Button == MouseButtons.Right + && pvsMain.PVS.selectedZoneId != ulong.MaxValue) + OpenContextMenu(); + } - private void pvsMain_Click(object sender, EventArgs e) + private void OpenContextMenu() + { + ContextMenuStrip menu = new(); + for (int i = 0; i < 4; ++i) + menu.Items.Add("Use as point " + (i + 1).ToString()); + menu.Items[0].Click += (s, e) => { - if (((MouseEventArgs)e).Button == MouseButtons.Right - && pvsMain.PVS.selectedZoneId != ulong.MaxValue) - OpenContextMenu(); - } - - private void OpenContextMenu() + Vector2 pos = pvsMain.MousePosOnMap.ToVector2(); + point1XNumericUpDown.Value = (decimal)pos.X; + point1YNumericUpDown.Value = (decimal)pos.Y; + }; + menu.Items[1].Click += (s, e) => { - ContextMenuStrip menu = new(); - for (int i = 0; i < 4; ++i) - menu.Items.Add("Use as point " + (i + 1).ToString()); - menu.Items[0].Click += (s, e) => - { - Vector2 pos = pvsMain.MousePosOnMap.ToVector2(); - point1XNumericUpDown.Value = (decimal)pos.X; - point1YNumericUpDown.Value = (decimal)pos.Y; - }; - menu.Items[1].Click += (s, e) => - { - Vector2 pos = pvsMain.MousePosOnMap.ToVector2(); - point2XNumericUpDown.Value = (decimal)pos.X; - point2YNumericUpDown.Value = (decimal)pos.Y; - }; - menu.Items[2].Click += (s, e) => - { - Vector2 pos = pvsMain.MousePosOnMap.ToVector2(); - point3XNumericUpDown.Value = (decimal)pos.X; - point3YNumericUpDown.Value = (decimal)pos.Y; - }; - menu.Items[3].Click += (s, e) => - { - Vector2 pos = pvsMain.MousePosOnMap.ToVector2(); - point4XNumericUpDown.Value = (decimal)pos.X; - point4YNumericUpDown.Value = (decimal)pos.Y; - }; - menu.Show(Cursor.Position); - } - - private void zonesListBox_SelectedIndexChanged(object sender, EventArgs e) + Vector2 pos = pvsMain.MousePosOnMap.ToVector2(); + point2XNumericUpDown.Value = (decimal)pos.X; + point2YNumericUpDown.Value = (decimal)pos.Y; + }; + menu.Items[2].Click += (s, e) => + { + Vector2 pos = pvsMain.MousePosOnMap.ToVector2(); + point3XNumericUpDown.Value = (decimal)pos.X; + point3YNumericUpDown.Value = (decimal)pos.Y; + }; + menu.Items[3].Click += (s, e) => { - if (zonesListBox.SelectedIndex == -1) - return; - ulong zoneId = ulong.Parse(zonesListBox.SelectedItem.ToString()); - SelectZone(zoneId); + Vector2 pos = pvsMain.MousePosOnMap.ToVector2(); + point4XNumericUpDown.Value = (decimal)pos.X; + point4YNumericUpDown.Value = (decimal)pos.Y; + }; + menu.Show(Cursor.Position); + } - deleteZoneButton.Enabled = true; - } + private void zonesListBox_SelectedIndexChanged(object sender, EventArgs e) + { + if (zonesListBox.SelectedIndex == -1) + return; + ulong zoneId = ulong.Parse(zonesListBox.SelectedItem.ToString()); + SelectZone(zoneId); + + deleteZoneButton.Enabled = true; + } - private void addZoneButton_Click(object sender, EventArgs e) + private void addZoneButton_Click(object sender, EventArgs e) + { + var zones = GetZones(); + ulong newZoneId; + while (true) { - var zones = GetZones(); - ulong newZoneId; - while (true) + newZoneId = new AddZone().GetNewZoneId(); + if (zones.FindIndex(z => z.ZoneId == newZoneId) != -1) { - newZoneId = new AddZone().GetNewZoneId(); - if (zones.FindIndex(z => z.ZoneId == newZoneId) != -1) - { - MessageBox.Show("A zone with ID " + newZoneId + " already exists."); - continue; - } - break; + MessageBox.Show("A zone with ID " + newZoneId + " already exists."); + continue; } - if (newZoneId == ulong.MaxValue) - return; - - Zone newZone = new(); - newZone.ZoneId = newZoneId; - zones.Add(newZone); - pvsMain.PVS.data.TotalZones++; - - zonesListBox.Items.Add(newZoneId.ToString("000")); - zonesListBox.SelectedIndex = zonesListBox.FindStringExact(newZoneId.ToString("000")); - if (zonesListBox.Items.Count == 1) - deleteZoneButton.Enabled = true; + break; } + if (newZoneId == ulong.MaxValue) + return; - private void deleteZoneButton_Click(object sender, EventArgs e) - { - int index = zonesListBox.SelectedIndex; - ulong zoneId = ulong.Parse(zonesListBox.Items[index].ToString()); - GetZones().Remove(GetZones().Find(z => z.ZoneId == zoneId)); - pvsMain.PVS.data.TotalZones--; + Zone newZone = new(); + newZone.ZoneId = newZoneId; + zones.Add(newZone); + pvsMain.PVS.data.TotalZones++; - zonesListBox.Items.RemoveAt(index); - if (zonesListBox.Items.Count == 0) - { - deleteZoneButton.Enabled = false; - return; - } - if (index == zonesListBox.Items.Count) - zonesListBox.SelectedIndex = zonesListBox.Items.Count - 1; - else - zonesListBox.SelectedIndex = index; - } + zonesListBox.Items.Add(newZoneId.ToString("000")); + zonesListBox.SelectedIndex = zonesListBox.FindStringExact(newZoneId.ToString("000")); + if (zonesListBox.Items.Count == 1) + deleteZoneButton.Enabled = true; + } - private void point1XNumericUpDown_ValueChanged(object sender, EventArgs e) - { - Vector2 point = GetPoints()[0]; - point.X = (float)point1XNumericUpDown.Value; - GetPoints()[0] = point; - pvsMain.Invalidate(); - } + private void deleteZoneButton_Click(object sender, EventArgs e) + { + int index = zonesListBox.SelectedIndex; + ulong zoneId = ulong.Parse(zonesListBox.Items[index].ToString()); + GetZones().Remove(GetZones().Find(z => z.ZoneId == zoneId)); + pvsMain.PVS.data.TotalZones--; - private void point1YNumericUpDown_ValueChanged(object sender, EventArgs e) + zonesListBox.Items.RemoveAt(index); + if (zonesListBox.Items.Count == 0) { - Vector2 point = GetPoints()[0]; - point.Y = (float)point1YNumericUpDown.Value; - GetPoints()[0] = point; - pvsMain.Invalidate(); + deleteZoneButton.Enabled = false; + return; } + if (index == zonesListBox.Items.Count) + zonesListBox.SelectedIndex = zonesListBox.Items.Count - 1; + else + zonesListBox.SelectedIndex = index; + } - private void point2XNumericUpDown_ValueChanged(object sender, EventArgs e) - { - Vector2 point = GetPoints()[1]; - point.X = (float)point2XNumericUpDown.Value; - GetPoints()[1] = point; - pvsMain.Invalidate(); - } + private void point1XNumericUpDown_ValueChanged(object sender, EventArgs e) + { + Vector2 point = GetPoints()[0]; + point.X = (float)point1XNumericUpDown.Value; + GetPoints()[0] = point; + pvsMain.Invalidate(); + } - private void point2YNumericUpDown_ValueChanged(object sender, EventArgs e) - { - Vector2 point = GetPoints()[1]; - point.Y = (float)point2YNumericUpDown.Value; - GetPoints()[1] = point; - pvsMain.Invalidate(); - } + private void point1YNumericUpDown_ValueChanged(object sender, EventArgs e) + { + Vector2 point = GetPoints()[0]; + point.Y = (float)point1YNumericUpDown.Value; + GetPoints()[0] = point; + pvsMain.Invalidate(); + } - private void point3XNumericUpDown_ValueChanged(object sender, EventArgs e) - { - Vector2 point = GetPoints()[2]; - point.X = (float)point3XNumericUpDown.Value; - GetPoints()[2] = point; - pvsMain.Invalidate(); - } + private void point2XNumericUpDown_ValueChanged(object sender, EventArgs e) + { + Vector2 point = GetPoints()[1]; + point.X = (float)point2XNumericUpDown.Value; + GetPoints()[1] = point; + pvsMain.Invalidate(); + } - private void point3YNumericUpDown_ValueChanged(object sender, EventArgs e) - { - Vector2 point = GetPoints()[2]; - point.Y = (float)point3YNumericUpDown.Value; - GetPoints()[2] = point; - pvsMain.Invalidate(); - } + private void point2YNumericUpDown_ValueChanged(object sender, EventArgs e) + { + Vector2 point = GetPoints()[1]; + point.Y = (float)point2YNumericUpDown.Value; + GetPoints()[1] = point; + pvsMain.Invalidate(); + } - private void point4XNumericUpDown_ValueChanged(object sender, EventArgs e) - { - Vector2 point = GetPoints()[3]; - point.X = (float)point4XNumericUpDown.Value; - GetPoints()[3] = point; - pvsMain.Invalidate(); - } + private void point3XNumericUpDown_ValueChanged(object sender, EventArgs e) + { + Vector2 point = GetPoints()[2]; + point.X = (float)point3XNumericUpDown.Value; + GetPoints()[2] = point; + pvsMain.Invalidate(); + } - private void point4YNumericUpDown_ValueChanged(object sender, EventArgs e) - { - Vector2 point = GetPoints()[3]; - point.Y = (float)point4YNumericUpDown.Value; - GetPoints()[3] = point; - pvsMain.Invalidate(); - } + private void point3YNumericUpDown_ValueChanged(object sender, EventArgs e) + { + Vector2 point = GetPoints()[2]; + point.Y = (float)point3YNumericUpDown.Value; + GetPoints()[2] = point; + pvsMain.Invalidate(); + } - private void neighboursListBox_SelectedIndexChanged(object sender, EventArgs e) - { - if (neighboursListBox.SelectedIndex == -1) - return; - int neighbourIndex = GetUnsafeNeighbours().FindIndex(n => n.ZoneId == ulong.Parse(neighboursListBox.SelectedItem.ToString())); - Neighbour neighbour = GetUnsafeNeighbours()[neighbourIndex]; - renderCheckBox.Checked = neighbour.Flags.HasFlag(NeighbourFlags.E_NEIGHBOURFLAG_RENDER); - immediateCheckBox.Checked = neighbour.Flags.HasFlag(NeighbourFlags.E_NEIGHBOURFLAG_IMMEDIATE); - - if (neighboursListBox.Items.Count != 0) - deleteNeighbourButton.Enabled = true; - renderCheckBox.Enabled = true; - immediateCheckBox.Enabled = true; - } + private void point4XNumericUpDown_ValueChanged(object sender, EventArgs e) + { + Vector2 point = GetPoints()[3]; + point.X = (float)point4XNumericUpDown.Value; + GetPoints()[3] = point; + pvsMain.Invalidate(); + } - private void addNeighbourButton_Click(object sender, EventArgs e) - { - ulong newZoneId = new AddZone().GetNewZoneId(); - if (newZoneId == ulong.MaxValue) - return; - var neighbours = GetUnsafeNeighbours(); - Neighbour newNeighbour = new(); - newNeighbour.ZoneId = newZoneId; - neighbours.Add(newNeighbour); - int parentIndex = GetZones().FindIndex(z => z.ZoneId == ulong.Parse(zonesListBox.SelectedItem.ToString())); - Zone parent = GetZones()[parentIndex]; - parent.NumUnsafeNeighbours++; - GetZones()[parentIndex] = parent; - - neighboursListBox.Items.Add(newZoneId.ToString("000")); - neighboursListBox.SelectedIndex = neighboursListBox.FindStringExact(newZoneId.ToString("000")); - pvsMain.Invalidate(); - if (neighboursListBox.Items.Count == 1) - deleteNeighbourButton.Enabled = true; - } + private void point4YNumericUpDown_ValueChanged(object sender, EventArgs e) + { + Vector2 point = GetPoints()[3]; + point.Y = (float)point4YNumericUpDown.Value; + GetPoints()[3] = point; + pvsMain.Invalidate(); + } - private void deleteNeighbourButton_Click(object sender, EventArgs e) - { - int index = neighboursListBox.SelectedIndex; - ulong zoneId = ulong.Parse(neighboursListBox.Items[index].ToString()); - GetUnsafeNeighbours().Remove(GetUnsafeNeighbours().Find(n => n.ZoneId == zoneId)); - int parentIndex = GetZones().FindIndex(z => z.ZoneId == ulong.Parse(zonesListBox.SelectedItem.ToString())); - Zone parent = GetZones()[parentIndex]; - parent.NumUnsafeNeighbours--; - GetZones()[parentIndex] = parent; - - neighboursListBox.Items.RemoveAt(index); - pvsMain.Invalidate(); - if (neighboursListBox.Items.Count == 0) - { - deleteNeighbourButton.Enabled = false; - renderCheckBox.Enabled = false; - immediateCheckBox.Enabled = false; - renderCheckBox.Checked = false; - immediateCheckBox.Checked = false; - return; - } - if (index == neighboursListBox.Items.Count) - neighboursListBox.SelectedIndex = neighboursListBox.Items.Count - 1; - else - neighboursListBox.SelectedIndex = index; - } + private void neighboursListBox_SelectedIndexChanged(object sender, EventArgs e) + { + if (neighboursListBox.SelectedIndex == -1) + return; + int neighbourIndex = GetUnsafeNeighbours().FindIndex(n => n.ZoneId == ulong.Parse(neighboursListBox.SelectedItem.ToString())); + Neighbour neighbour = GetUnsafeNeighbours()[neighbourIndex]; + renderCheckBox.Checked = neighbour.Flags.HasFlag(NeighbourFlags.E_NEIGHBOURFLAG_RENDER); + immediateCheckBox.Checked = neighbour.Flags.HasFlag(NeighbourFlags.E_NEIGHBOURFLAG_IMMEDIATE); + + if (neighboursListBox.Items.Count != 0) + deleteNeighbourButton.Enabled = true; + renderCheckBox.Enabled = true; + immediateCheckBox.Enabled = true; + } - private void renderCheckBox_CheckedChanged(object sender, EventArgs e) - { - if (neighboursListBox.SelectedIndex == -1) - return; - int neighbourIndex = GetUnsafeNeighbours().FindIndex(n => n.ZoneId == ulong.Parse(neighboursListBox.SelectedItem.ToString())); - Neighbour neighbour = GetUnsafeNeighbours()[neighbourIndex]; - if (renderCheckBox.Checked) - neighbour.Flags |= NeighbourFlags.E_NEIGHBOURFLAG_RENDER; - else - neighbour.Flags &= ~NeighbourFlags.E_NEIGHBOURFLAG_RENDER; - GetUnsafeNeighbours()[neighbourIndex] = neighbour; - } + private void addNeighbourButton_Click(object sender, EventArgs e) + { + ulong newZoneId = new AddZone().GetNewZoneId(); + if (newZoneId == ulong.MaxValue) + return; + var neighbours = GetUnsafeNeighbours(); + Neighbour newNeighbour = new(); + newNeighbour.ZoneId = newZoneId; + neighbours.Add(newNeighbour); + int parentIndex = GetZones().FindIndex(z => z.ZoneId == ulong.Parse(zonesListBox.SelectedItem.ToString())); + Zone parent = GetZones()[parentIndex]; + parent.NumUnsafeNeighbours++; + GetZones()[parentIndex] = parent; + + neighboursListBox.Items.Add(newZoneId.ToString("000")); + neighboursListBox.SelectedIndex = neighboursListBox.FindStringExact(newZoneId.ToString("000")); + pvsMain.Invalidate(); + if (neighboursListBox.Items.Count == 1) + deleteNeighbourButton.Enabled = true; + } - private void immediateCheckBox_CheckedChanged(object sender, EventArgs e) + private void deleteNeighbourButton_Click(object sender, EventArgs e) + { + int index = neighboursListBox.SelectedIndex; + ulong zoneId = ulong.Parse(neighboursListBox.Items[index].ToString()); + GetUnsafeNeighbours().Remove(GetUnsafeNeighbours().Find(n => n.ZoneId == zoneId)); + int parentIndex = GetZones().FindIndex(z => z.ZoneId == ulong.Parse(zonesListBox.SelectedItem.ToString())); + Zone parent = GetZones()[parentIndex]; + parent.NumUnsafeNeighbours--; + GetZones()[parentIndex] = parent; + + neighboursListBox.Items.RemoveAt(index); + pvsMain.Invalidate(); + if (neighboursListBox.Items.Count == 0) { - if (neighboursListBox.SelectedIndex == -1) - return; - int neighbourIndex = GetUnsafeNeighbours().FindIndex(n => n.ZoneId == ulong.Parse(neighboursListBox.SelectedItem.ToString())); - Neighbour neighbour = GetUnsafeNeighbours()[neighbourIndex]; - if (immediateCheckBox.Checked) - neighbour.Flags |= NeighbourFlags.E_NEIGHBOURFLAG_IMMEDIATE; - else - neighbour.Flags &= ~NeighbourFlags.E_NEIGHBOURFLAG_IMMEDIATE; - GetUnsafeNeighbours()[neighbourIndex] = neighbour; + deleteNeighbourButton.Enabled = false; + renderCheckBox.Enabled = false; + immediateCheckBox.Enabled = false; + renderCheckBox.Checked = false; + immediateCheckBox.Checked = false; + return; } + if (index == neighboursListBox.Items.Count) + neighboursListBox.SelectedIndex = neighboursListBox.Items.Count - 1; + else + neighboursListBox.SelectedIndex = index; + } + + private void renderCheckBox_CheckedChanged(object sender, EventArgs e) + { + if (neighboursListBox.SelectedIndex == -1) + return; + int neighbourIndex = GetUnsafeNeighbours().FindIndex(n => n.ZoneId == ulong.Parse(neighboursListBox.SelectedItem.ToString())); + Neighbour neighbour = GetUnsafeNeighbours()[neighbourIndex]; + if (renderCheckBox.Checked) + neighbour.Flags |= NeighbourFlags.E_NEIGHBOURFLAG_RENDER; + else + neighbour.Flags &= ~NeighbourFlags.E_NEIGHBOURFLAG_RENDER; + GetUnsafeNeighbours()[neighbourIndex] = neighbour; + } + + private void immediateCheckBox_CheckedChanged(object sender, EventArgs e) + { + if (neighboursListBox.SelectedIndex == -1) + return; + int neighbourIndex = GetUnsafeNeighbours().FindIndex(n => n.ZoneId == ulong.Parse(neighboursListBox.SelectedItem.ToString())); + Neighbour neighbour = GetUnsafeNeighbours()[neighbourIndex]; + if (immediateCheckBox.Checked) + neighbour.Flags |= NeighbourFlags.E_NEIGHBOURFLAG_IMMEDIATE; + else + neighbour.Flags &= ~NeighbourFlags.E_NEIGHBOURFLAG_IMMEDIATE; + GetUnsafeNeighbours()[neighbourIndex] = neighbour; } } diff --git a/PVSFormat/PVSPlugin.cs b/PVSFormat/PVSPlugin.cs index 0ccae64..6191fe4 100644 --- a/PVSFormat/PVSPlugin.cs +++ b/PVSFormat/PVSPlugin.cs @@ -1,16 +1,15 @@ using BundleFormat; using PluginAPI; -namespace PVSFormat +namespace PVSFormat; + +public class PVSPlugin : IPlugin { - public class PVSPlugin : IPlugin - { - public string Id => "pvsplugin"; - public string Name => "PVS Resource Handler"; + public string Id => "pvsplugin"; + public string Name => "PVS Resource Handler"; - public static void Init() - { - EntryTypeRegistry.Register(EntryType.ZoneList, new PVS()); - } + public static void Init() + { + EntryTypeRegistry.Register(EntryType.ZoneList, new PVS()); } } diff --git a/PVSFormat/Polygon.cs b/PVSFormat/Polygon.cs index 8688817..d6b7513 100644 --- a/PVSFormat/Polygon.cs +++ b/PVSFormat/Polygon.cs @@ -1,104 +1,103 @@ using System.Collections.Generic; using System.Drawing; -namespace PVSFormat +namespace PVSFormat; + +public class Polygon { - public class Polygon + public PointF[] Points { - public PointF[] Points - { - get; - set; - } + get; + set; + } - public float MinX + public float MinX + { + get { - get - { - float min = float.MaxValue; - - foreach (PointF point in Points) - { - float current = point.X; + float min = float.MaxValue; - if (current < min) - min = current; - } + foreach (PointF point in Points) + { + float current = point.X; - return min; + if (current < min) + min = current; } + + return min; } + } - public float MinY + public float MinY + { + get { - get - { - float min = float.MaxValue; - - foreach (PointF point in Points) - { - float current = point.Y; + float min = float.MaxValue; - if (current < min) - min = current; - } + foreach (PointF point in Points) + { + float current = point.Y; - return min; + if (current < min) + min = current; } + + return min; } + } - public float MaxX + public float MaxX + { + get { - get - { - float max = float.MinValue; + float max = float.MinValue; - foreach (PointF point in Points) - { - float current = point.X; - - if (current > max) - max = current; - } + foreach (PointF point in Points) + { + float current = point.X; - return max; + if (current > max) + max = current; } + + return max; } + } - public float MaxY + public float MaxY + { + get { - get - { - float max = float.MinValue; - - foreach (PointF point in Points) - { - float current = point.Y; + float max = float.MinValue; - if (current > max) - max = current; - } + foreach (PointF point in Points) + { + float current = point.Y; - return max; + if (current > max) + max = current; } - } - public RectangleF Bounds - { - get - { - return new RectangleF(MinX, MinY, MaxX - MinX, MaxY - MinY); - } + return max; } + } - public Polygon(params PointF[] points) + public RectangleF Bounds + { + get { - Points = points; + return new RectangleF(MinX, MinY, MaxX - MinX, MaxY - MinY); } + } - public Polygon(List points) - { - Points = points.ToArray(); - } + public Polygon(params PointF[] points) + { + Points = points; + } + + public Polygon(List points) + { + Points = [.. points]; } } diff --git a/PluginAPI/EntryTypeRegistry.cs b/PluginAPI/EntryTypeRegistry.cs index 533de0d..b56687a 100644 --- a/PluginAPI/EntryTypeRegistry.cs +++ b/PluginAPI/EntryTypeRegistry.cs @@ -2,40 +2,39 @@ using System; using System.Collections.Generic; -namespace PluginAPI +namespace PluginAPI; + +public static class EntryTypeRegistry { - public static class EntryTypeRegistry - { - private static Dictionary _handlers = new Dictionary(); + private static Dictionary _handlers = []; - public static void Register(EntryType type, IEntryData handler) + public static void Register(EntryType type, IEntryData handler) + { + if (IsRegistered(type)) { - if (IsRegistered(type)) - { - Console.WriteLine("WARN: Handler for " + type.ToString() + " already registered!"); - return; - } - _handlers.Add(type, handler); + Console.WriteLine("WARN: Handler for " + type.ToString() + " already registered!"); + return; } + _handlers.Add(type, handler); + } - public static void Unregister(EntryType type) - { - if (!IsRegistered(type)) - return; - _handlers.Remove(type); - } + public static void Unregister(EntryType type) + { + if (!IsRegistered(type)) + return; + _handlers.Remove(type); + } - public static IEntryData GetHandler(EntryType type) - { - if (!IsRegistered(type)) - return null; + public static IEntryData GetHandler(EntryType type) + { + if (!IsRegistered(type)) + return null; - return _handlers[type]; - } + return _handlers[type]; + } - public static bool IsRegistered(EntryType type) - { - return _handlers.ContainsKey(type); - } + public static bool IsRegistered(EntryType type) + { + return _handlers.ContainsKey(type); } } diff --git a/PluginAPI/IEntryData.cs b/PluginAPI/IEntryData.cs index e3a1bf2..207e4f4 100644 --- a/PluginAPI/IEntryData.cs +++ b/PluginAPI/IEntryData.cs @@ -1,16 +1,15 @@ using BundleFormat; using BundleUtilities; -namespace PluginAPI +namespace PluginAPI; + +public interface IEntryData { - public interface IEntryData - { - bool Read(BundleEntry entry, ILoader loader = null); + bool Read(BundleEntry entry, ILoader loader = null); - bool Write(BundleEntry entry); + bool Write(BundleEntry entry); - EntryType GetEntryType(BundleEntry entry); + EntryType GetEntryType(BundleEntry entry); - IEntryEditor GetEditor(BundleEntry entry); - } + IEntryEditor GetEditor(BundleEntry entry); } diff --git a/PluginAPI/IEntryEditor.cs b/PluginAPI/IEntryEditor.cs index dce6e70..385b1da 100644 --- a/PluginAPI/IEntryEditor.cs +++ b/PluginAPI/IEntryEditor.cs @@ -1,9 +1,8 @@ using System.Windows.Forms; -namespace PluginAPI +namespace PluginAPI; + +public interface IEntryEditor { - public interface IEntryEditor - { - DialogResult ShowDialog(IWin32Window owner); - } + DialogResult ShowDialog(IWin32Window owner); } diff --git a/PluginAPI/IPlugin.cs b/PluginAPI/IPlugin.cs index a75a787..837acf9 100644 --- a/PluginAPI/IPlugin.cs +++ b/PluginAPI/IPlugin.cs @@ -1,10 +1,9 @@ -namespace PluginAPI +namespace PluginAPI; + +public interface IPlugin { - public interface IPlugin - { - string Id { get; } - string Name { get; } + string Id { get; } + string Name { get; } - public static abstract void Init(); - } + public static abstract void Init(); } diff --git a/PluginAPI/PluginCommand.cs b/PluginAPI/PluginCommand.cs index 838136a..2de54d0 100644 --- a/PluginAPI/PluginCommand.cs +++ b/PluginAPI/PluginCommand.cs @@ -1,24 +1,23 @@ using BundleFormat; using System.Windows.Forms; -namespace PluginAPI +namespace PluginAPI; + +public struct PluginCommand { - public struct PluginCommand - { - public delegate void OnUse(IWin32Window window, BundleArchive archive); - public delegate bool OnCheckConditions(BundleArchive archive); + public delegate void OnUse(IWin32Window window, BundleArchive archive); + public delegate bool OnCheckConditions(BundleArchive archive); - public string ID; - public string Text; - public OnUse Use; - public OnCheckConditions CheckConditions; + public string ID; + public string Text; + public OnUse Use; + public OnCheckConditions CheckConditions; - public PluginCommand(string id, string text, OnUse use, OnCheckConditions checkConditions = null) - { - ID = id; - Text = text; - CheckConditions = checkConditions; - Use = use; - } + public PluginCommand(string id, string text, OnUse use, OnCheckConditions checkConditions = null) + { + ID = id; + Text = text; + CheckConditions = checkConditions; + Use = use; } } diff --git a/PluginAPI/PluginCommandRegistry.cs b/PluginAPI/PluginCommandRegistry.cs index 4c14430..47fed82 100644 --- a/PluginAPI/PluginCommandRegistry.cs +++ b/PluginAPI/PluginCommandRegistry.cs @@ -1,50 +1,48 @@ using System; using System.Collections.Generic; -using System.Linq; -namespace PluginAPI +namespace PluginAPI; + +public static class PluginCommandRegistry { - public static class PluginCommandRegistry - { - private static Dictionary _commands = new Dictionary(); + private static Dictionary _commands = []; - public static PluginCommand[] Commands => _commands.Values.ToArray(); + public static PluginCommand[] Commands => [.. _commands.Values]; - public static void Register(string id, string text, PluginCommand.OnUse use, PluginCommand.OnCheckConditions checkConditions = null) - { - Register(new PluginCommand(id, text, use, checkConditions)); - } + public static void Register(string id, string text, PluginCommand.OnUse use, PluginCommand.OnCheckConditions checkConditions = null) + { + Register(new PluginCommand(id, text, use, checkConditions)); + } - public static void Register(PluginCommand command) + public static void Register(PluginCommand command) + { + if (IsRegistered(command.ID)) { - if (IsRegistered(command.ID)) - { - Console.WriteLine("WARN: Command " + command.ID.ToString() + " already registered!"); - return; - } - - _commands.Add(command.ID, command); + Console.WriteLine("WARN: Command " + command.ID.ToString() + " already registered!"); + return; } - public static void Unregister(string id) - { - if (!IsRegistered(id)) - return; + _commands.Add(command.ID, command); + } - _commands.Remove(id); - } + public static void Unregister(string id) + { + if (!IsRegistered(id)) + return; - public static PluginCommand GetCommand(string id) - { - if (!IsRegistered(id)) - return default; + _commands.Remove(id); + } - return _commands[id]; - } + public static PluginCommand GetCommand(string id) + { + if (!IsRegistered(id)) + return default; - public static bool IsRegistered(string id) - { - return _commands.ContainsKey(id); - } + return _commands[id]; + } + + public static bool IsRegistered(string id) + { + return _commands.ContainsKey(id); } } diff --git a/PluginSystem/PluginLoader.cs b/PluginSystem/PluginLoader.cs index 71801d7..775ad29 100644 --- a/PluginSystem/PluginLoader.cs +++ b/PluginSystem/PluginLoader.cs @@ -3,44 +3,43 @@ using System.Collections.Generic; using System.Reflection; -namespace PluginSystem +namespace PluginSystem; + +public static class PluginLoader { - public static class PluginLoader - { - // Plugin classes. To add an entry here, the plugin's containing project - // must be added as a reference. - private static readonly List registeredPlugins = - [ - typeof(BaseHandlers.BasePlugin), - typeof(LangEditor.LangPlugin), - typeof(LoopModel.LoopModelPlugin), - typeof(LuaList.LuaListPlugin), - typeof(PVSFormat.PVSPlugin), - typeof(VaultFormat.AttribSysPlugin), - typeof(VehicleList.VehicleListPlugin), - typeof(WheelList.WheelListPlugin), - typeof(WorldCollisionHandler.WorldCollisionPlugin) - ]; + // Plugin classes. To add an entry here, the plugin's containing project + // must be added as a reference. + private static readonly List registeredPlugins = + [ + typeof(BaseHandlers.BasePlugin), + typeof(LangEditor.LangPlugin), + typeof(LoopModel.LoopModelPlugin), + typeof(LuaList.LuaListPlugin), + typeof(PVSFormat.PVSPlugin), + typeof(VaultFormat.AttribSysPlugin), + typeof(VehicleList.VehicleListPlugin), + typeof(WheelList.WheelListPlugin), + typeof(WorldCollisionHandler.WorldCollisionPlugin) + ]; - // Runs each plugin's static initialization method. - public static void InitializePlugins() + // Runs each plugin's static initialization method. + public static void InitializePlugins() + { + Console.WriteLine("Initializing plugins..."); + int numPluginsInitialized = 0; + foreach (Type pluginType in registeredPlugins) { - Console.WriteLine("Initializing plugins..."); - int numPluginsInitialized = 0; - foreach (Type pluginType in registeredPlugins) + if (pluginType.IsAssignableTo(typeof(IPlugin))) + { + MethodInfo initInfo = pluginType.GetMethod(nameof(IPlugin.Init)); + initInfo.Invoke(null, []); + numPluginsInitialized++; + } + else { - if (pluginType.IsAssignableTo(typeof(IPlugin))) - { - MethodInfo initInfo = pluginType.GetMethod(nameof(IPlugin.Init)); - initInfo.Invoke(null, []); - numPluginsInitialized++; - } - else - { - Console.WriteLine($"{pluginType.AssemblyQualifiedName} is not a valid plugin. Skipping."); - } + Console.WriteLine($"{pluginType.AssemblyQualifiedName} is not a valid plugin. Skipping."); } - Console.WriteLine($"Initialized {numPluginsInitialized} plugins."); } + Console.WriteLine($"Initialized {numPluginsInitialized} plugins."); } } diff --git a/VaultFormat/AttribSys.cs b/VaultFormat/AttribSys.cs index fe93971..6ac8906 100644 --- a/VaultFormat/AttribSys.cs +++ b/VaultFormat/AttribSys.cs @@ -7,656 +7,655 @@ using BundleUtilities; using PluginAPI; -namespace VaultFormat +namespace VaultFormat; + +public class CountingUtilities { - public class CountingUtilities + public static int AddPadding(List bytes) { - public static int AddPadding(List bytes) + if (bytes.SelectMany(i => i).Count() % 16 == 0) { - if (bytes.SelectMany(i => i).Count() % 16 == 0) - { - return bytes.SelectMany(i => i).Count(); - } - else - { - return bytes.SelectMany(i => i).Count() + (16 - (bytes.SelectMany(i => i).Count() % 16)); - } + return bytes.SelectMany(i => i).Count(); } - public static int AddEightPadding(int value) + else { - if (value % 8 == 0) - { - return value; - } - else - { - return value + (8 - (value % 8)); - } + return bytes.SelectMany(i => i).Count() + (16 - (bytes.SelectMany(i => i).Count() % 16)); } } - - public class SizeAndPositionInformation + public static int AddEightPadding(int value) { - public ulong Hash; - public ulong EntryTypeHash; - public int DataChunkSize; - public int DataChunkPosition; + if (value % 8 == 0) + { + return value; + } + else + { + return value + (8 - (value % 8)); + } } +} + +public class SizeAndPositionInformation +{ + public ulong Hash; + public ulong EntryTypeHash; + public int DataChunkSize; + public int DataChunkPosition; +} - public class AttributeHeader +public class AttributeHeader +{ + public string ClassName; + public ulong CollectionHash; + public ulong ClassHash; + public byte[] Unknown1; // always 0? + public int ItemCount; + public int Unknown2; + public int ItemCountDup; // ? + public short ParameterCount; + public short ParametersToRead; + public byte[] Unknown3; // always 0? + public ulong[] ParameterTypeHashes; + public DataItem[] Items; + + + public IAttribute GetAttributeEntity(SizeAndPositionInformation chunk, AttributeHeader dataChunk) { - public string ClassName; - public ulong CollectionHash; - public ulong ClassHash; - public byte[] Unknown1; // always 0? - public int ItemCount; - public int Unknown2; - public int ItemCountDup; // ? - public short ParameterCount; - public short ParametersToRead; - public byte[] Unknown3; // always 0? - public ulong[] ParameterTypeHashes; - public DataItem[] Items; - - - public IAttribute GetAttributeEntity(SizeAndPositionInformation chunk, AttributeHeader dataChunk) + if (ClassHash == 0x2e3b1dc7d248445e) { - if (ClassHash == 0x2e3b1dc7d248445e) - { - this.ClassName = "physicsvehiclebodyrollattribs"; - return new Physicsvehiclebodyrollattribs(chunk, dataChunk); - } - if (ClassHash == 0x52B81656F3ADF675) - { - this.ClassName = "burnoutcarasset"; - return new Burnoutcarasset(chunk, dataChunk); - } - if (ClassHash == 0xF850281CA54C9B92) - { - this.ClassName = "physicsvehicleengineattribs"; - return new Physicsvehicleengineattribs(chunk, dataChunk); - } - if (ClassHash == 0x3F9370FCF8D767AC) - { - this.ClassName = "physicsvehicledriftattribs"; - return new Physicsvehicledriftattribs(chunk, dataChunk); - } - if (ClassHash == 0xDF956BC0568F138C) - { - this.ClassName = "physicsvehiclecollisionattribs"; - return new Physicsvehiclecollisionattribs(chunk, dataChunk); - } - if (ClassHash == 0x4297B5841F5231CF) - { - this.ClassName = "physicsvehiclesuspensionattribs"; - return new Physicsvehiclesuspensionattribs(chunk, dataChunk); - } - if (ClassHash == 0x43462C59212A23CC) - { - this.ClassName = "physicsvehiclesteeringattribs"; - return new Physicsvehiclesteeringattribs(chunk, dataChunk); - } - if (ClassHash == 0xE9EDA3B8C4EA3C84) - { - this.ClassName = "cameraexternalbehaviour"; - return new Cameraexternalbehaviour(chunk, dataChunk); - } - if (ClassHash == 0xF79C545E141DFFA6) - { - this.ClassName = "physicsvehiclebaseattribs"; - return new Physicsvehiclebaseattribs(chunk, dataChunk); - } - if (ClassHash == 0xF0FF4DFD660F5A54) - { - this.ClassName = "burnoutcargraphicsasset"; - return new Burnoutcargraphicsasset(chunk, dataChunk); - } - if (ClassHash == 0xF3E3F8EF855F4F99) - { - this.ClassName = "camerabumperbehaviour"; - return new Camerabumperbehaviour(chunk, dataChunk); - } - if (ClassHash == 0xEADE7049AF7AB31E) - { - this.ClassName = "physicsvehicleboostattribs"; - return new Physicsvehicleboostattribs(chunk, dataChunk); - } - if (ClassHash == 0x966121397B502EED) - { - this.ClassName = "physicsvehiclehandling"; - return new Physicsvehiclehandling(chunk, dataChunk); - } - if (ClassHash == 0x7F161D94482CB3BF) - { - this.ClassName = "vehicleengine"; - } - return new UnimplementedAttribs(chunk, dataChunk); + this.ClassName = "physicsvehiclebodyrollattribs"; + return new Physicsvehiclebodyrollattribs(chunk, dataChunk); + } + if (ClassHash == 0x52B81656F3ADF675) + { + this.ClassName = "burnoutcarasset"; + return new Burnoutcarasset(chunk, dataChunk); + } + if (ClassHash == 0xF850281CA54C9B92) + { + this.ClassName = "physicsvehicleengineattribs"; + return new Physicsvehicleengineattribs(chunk, dataChunk); + } + if (ClassHash == 0x3F9370FCF8D767AC) + { + this.ClassName = "physicsvehicledriftattribs"; + return new Physicsvehicledriftattribs(chunk, dataChunk); + } + if (ClassHash == 0xDF956BC0568F138C) + { + this.ClassName = "physicsvehiclecollisionattribs"; + return new Physicsvehiclecollisionattribs(chunk, dataChunk); } + if (ClassHash == 0x4297B5841F5231CF) + { + this.ClassName = "physicsvehiclesuspensionattribs"; + return new Physicsvehiclesuspensionattribs(chunk, dataChunk); + } + if (ClassHash == 0x43462C59212A23CC) + { + this.ClassName = "physicsvehiclesteeringattribs"; + return new Physicsvehiclesteeringattribs(chunk, dataChunk); + } + if (ClassHash == 0xE9EDA3B8C4EA3C84) + { + this.ClassName = "cameraexternalbehaviour"; + return new Cameraexternalbehaviour(chunk, dataChunk); + } + if (ClassHash == 0xF79C545E141DFFA6) + { + this.ClassName = "physicsvehiclebaseattribs"; + return new Physicsvehiclebaseattribs(chunk, dataChunk); + } + if (ClassHash == 0xF0FF4DFD660F5A54) + { + this.ClassName = "burnoutcargraphicsasset"; + return new Burnoutcargraphicsasset(chunk, dataChunk); + } + if (ClassHash == 0xF3E3F8EF855F4F99) + { + this.ClassName = "camerabumperbehaviour"; + return new Camerabumperbehaviour(chunk, dataChunk); + } + if (ClassHash == 0xEADE7049AF7AB31E) + { + this.ClassName = "physicsvehicleboostattribs"; + return new Physicsvehicleboostattribs(chunk, dataChunk); + } + if (ClassHash == 0x966121397B502EED) + { + this.ClassName = "physicsvehiclehandling"; + return new Physicsvehiclehandling(chunk, dataChunk); + } + if (ClassHash == 0x7F161D94482CB3BF) + { + this.ClassName = "vehicleengine"; + } + return new UnimplementedAttribs(chunk, dataChunk); } +} - public class DataItem - { - public ulong Hash; - public byte[] Unknown1; // 4 bytes, undetermined data type - public short ParameterIdx; // guess? - public short Unknown2; - } +public class DataItem +{ + public ulong Hash; + public byte[] Unknown1; // 4 bytes, undetermined data type + public short ParameterIdx; // guess? + public short Unknown2; +} - public class PtrChunk - { - public List allData; - } +public class PtrChunk +{ + public List allData; +} - public class PtrChunkData - { - public uint Ptr; - public short type; - public short flag; - public ulong Data; - } +public class PtrChunkData +{ + public uint Ptr; + public short type; + public short flag; + public ulong Data; +} - public class AttribSys : IEntryData - { - public ulong VersionHash; +public class AttribSys : IEntryData +{ + public ulong VersionHash; - public ulong DepHash1; - public ulong DepHash2; - public int DepNop; - public List Dependencies; + public ulong DepHash1; + public ulong DepHash2; + public int DepNop; + public List Dependencies; - public long StrUnknown1; + public long StrUnknown1; - public List Attributes; + public List Attributes; - public List Strings; + public List Strings; - public PtrChunk PtrN; + public PtrChunk PtrN; - public byte[] Data; + public byte[] Data; - // Decomp stores DepN/ExpN counts as {uint32_t pad, uint32_t count} - private bool _x64; + // Decomp stores DepN/ExpN counts as {uint32_t pad, uint32_t count} + private bool _x64; - public AttribSys() - { - Dependencies = new List(); - Attributes = new List(); - Strings = new List(); - } + public AttribSys() + { + Dependencies = []; + Attributes = []; + Strings = []; + } - private void ReadChunk(ILoader loader, BinaryReader2 br) + private void ReadChunk(ILoader loader, BinaryReader2 br) + { + long initialPos = br.BaseStream.Position; + uint fourcc = br.ReadUInt32(); + int size = br.ReadInt32(); + switch (fourcc) { - long initialPos = br.BaseStream.Position; - uint fourcc = br.ReadUInt32(); - int size = br.ReadInt32(); - switch (fourcc) - { - case 0x56657273: // Vers - VersionHash = br.ReadUInt64(); - break; - case 0x4465704E: // DepN - long entryCount = ReadCount(br); - DepHash1 = br.ReadUInt64(); - DepHash2 = br.ReadUInt64(); - DepNop = br.ReadInt32(); - int sz = br.ReadInt32(); - for (long i = 0; i < entryCount; i++) - { - string name = br.ReadLenString(sz); - Dependencies.Add(name); - } + case 0x56657273: // Vers + VersionHash = br.ReadUInt64(); + break; + case 0x4465704E: // DepN + long entryCount = ReadCount(br); + DepHash1 = br.ReadUInt64(); + DepHash2 = br.ReadUInt64(); + DepNop = br.ReadInt32(); + int sz = br.ReadInt32(); + for (long i = 0; i < entryCount; i++) + { + string name = br.ReadLenString(sz); + Dependencies.Add(name); + } - break; - case 0x5374724E: // StrN - StrUnknown1 = br.ReadInt64(); - break; - case 0x4461744E: // DatN - // Handled in ExpN - break; - case 0x4578704E: // ExpN - long nestedChunkCount = ReadCount(br); - for (long i = 0; i < nestedChunkCount; i++) - { - SizeAndPositionInformation chunk = new SizeAndPositionInformation(); - chunk.Hash = br.ReadUInt64(); - chunk.EntryTypeHash = br.ReadUInt64(); - chunk.DataChunkSize = br.ReadInt32(); - chunk.DataChunkPosition = br.ReadInt32(); + break; + case 0x5374724E: // StrN + StrUnknown1 = br.ReadInt64(); + break; + case 0x4461744E: // DatN + // Handled in ExpN + break; + case 0x4578704E: // ExpN + long nestedChunkCount = ReadCount(br); + for (long i = 0; i < nestedChunkCount; i++) + { + SizeAndPositionInformation chunk = new(); + chunk.Hash = br.ReadUInt64(); + chunk.EntryTypeHash = br.ReadUInt64(); + chunk.DataChunkSize = br.ReadInt32(); + chunk.DataChunkPosition = br.ReadInt32(); - long pos = br.BaseStream.Position; - br.BaseStream.Position = chunk.DataChunkPosition; + long pos = br.BaseStream.Position; + br.BaseStream.Position = chunk.DataChunkPosition; - if (chunk.EntryTypeHash == 0xAD303B8F42B3307E) - { - AttributeHeader dataChunk = new AttributeHeader(); - dataChunk.CollectionHash = br.ReadUInt64(); - dataChunk.ClassHash = br.ReadUInt64(); - dataChunk.Unknown1 = br.ReadBytes(8); - dataChunk.ItemCount = br.ReadInt32(); - dataChunk.Unknown2 = br.ReadInt32(); - dataChunk.ItemCountDup = br.ReadInt32(); - dataChunk.ParameterCount = br.ReadInt16(); - dataChunk.ParametersToRead = br.ReadInt16(); - dataChunk.Unknown3 = br.ReadBytes(8); - dataChunk.ParameterTypeHashes = new ulong[dataChunk.ParameterCount]; - for (int j = 0; j < dataChunk.ParameterCount; j++) - dataChunk.ParameterTypeHashes[j] = br.ReadUInt64(); - for (int j = 0; j < (dataChunk.ParametersToRead - dataChunk.ParameterCount); j++) - br.ReadUInt64(); // zero - dataChunk.Items = new DataItem[dataChunk.ItemCount]; - for (int j = 0; j < dataChunk.ItemCount; j++) - { - DataItem item = new DataItem(); - item.Hash = br.ReadUInt64(); - item.Unknown1 = br.ReadBytes(4); - item.ParameterIdx = br.ReadInt16(); - item.Unknown2 = br.ReadInt16(); - dataChunk.Items[j] = item; - } - Attributes.Add(dataChunk.GetAttributeEntity(chunk, dataChunk)); - } - else + if (chunk.EntryTypeHash == 0xAD303B8F42B3307E) + { + AttributeHeader dataChunk = new(); + dataChunk.CollectionHash = br.ReadUInt64(); + dataChunk.ClassHash = br.ReadUInt64(); + dataChunk.Unknown1 = br.ReadBytes(8); + dataChunk.ItemCount = br.ReadInt32(); + dataChunk.Unknown2 = br.ReadInt32(); + dataChunk.ItemCountDup = br.ReadInt32(); + dataChunk.ParameterCount = br.ReadInt16(); + dataChunk.ParametersToRead = br.ReadInt16(); + dataChunk.Unknown3 = br.ReadBytes(8); + dataChunk.ParameterTypeHashes = new ulong[dataChunk.ParameterCount]; + for (int j = 0; j < dataChunk.ParameterCount; j++) + dataChunk.ParameterTypeHashes[j] = br.ReadUInt64(); + for (int j = 0; j < (dataChunk.ParametersToRead - dataChunk.ParameterCount); j++) + br.ReadUInt64(); // zero + dataChunk.Items = new DataItem[dataChunk.ItemCount]; + for (int j = 0; j < dataChunk.ItemCount; j++) { - throw new ReadFailedError("Unknown entry type: " + chunk.EntryTypeHash); + DataItem item = new(); + item.Hash = br.ReadUInt64(); + item.Unknown1 = br.ReadBytes(4); + item.ParameterIdx = br.ReadInt16(); + item.Unknown2 = br.ReadInt16(); + dataChunk.Items[j] = item; } - br.BaseStream.Position = pos; + Attributes.Add(dataChunk.GetAttributeEntity(chunk, dataChunk)); } - break; - case 0x5074724E: // PtrN - // Unknown - int dataSize = size - 8; - PtrN = new PtrChunk(); - PtrN.allData = new List(); - for (int i = 0; i < dataSize / 16; i++) + else { - PtrChunkData data = new PtrChunkData(); - data.Ptr = br.ReadUInt32(); - data.type = br.ReadInt16(); - data.flag = br.ReadInt16(); - data.Data = br.ReadUInt64(); - PtrN.allData.Add(data); + throw new ReadFailedError("Unknown entry type: " + chunk.EntryTypeHash); } - break; - default: - throw new ReadFailedError("Unknown Chunk: " + fourcc); - } - - br.BaseStream.Position = initialPos + size; + br.BaseStream.Position = pos; + } + break; + case 0x5074724E: // PtrN + // Unknown + int dataSize = size - 8; + PtrN = new PtrChunk(); + PtrN.allData = []; + for (int i = 0; i < dataSize / 16; i++) + { + PtrChunkData data = new(); + data.Ptr = br.ReadUInt32(); + data.type = br.ReadInt16(); + data.flag = br.ReadInt16(); + data.Data = br.ReadUInt64(); + PtrN.allData.Add(data); + } + break; + default: + throw new ReadFailedError("Unknown Chunk: " + fourcc); } - private long ReadCount(BinaryReader2 br) => _x64 ? br.ReadInt64() >> 32 : br.ReadInt64(); + br.BaseStream.Position = initialPos + size; + } - private void WriteCount(BinaryWriter2 bw, int count) => bw.Write(_x64 ? (ulong)count << 32 : (ulong)count); + private long ReadCount(BinaryReader2 br) => _x64 ? br.ReadInt64() >> 32 : br.ReadInt64(); - private void ReadVlt(ILoader loader, BinaryReader2 br) - { - while (!br.EOF()) - ReadChunk(loader, br); - } + private void WriteCount(BinaryWriter2 bw, int count) => bw.Write(_x64 ? (ulong)count << 32 : (ulong)count); + + private void ReadVlt(ILoader loader, BinaryReader2 br) + { + while (!br.EOF()) + ReadChunk(loader, br); + } - private void ReadBin(ILoader loader, BinaryReader2 br) + private void ReadBin(ILoader loader, BinaryReader2 br) + { + try { - try - { - long initialPos = br.BaseStream.Position; - uint fourcc = br.ReadUInt32(); - // StrE - int size = br.ReadInt32(); // Size of Strings Array in hex - while (br.BaseStream.Position < initialPos + size) - Strings.Add(br.ReadCStr()); - Strings = Strings.AsEnumerable().Reverse().SkipWhile(str => str.Length == 0).Reverse().ToList(); - br.BaseStream.Position = initialPos + size; - - int dataSize = (int)(br.BaseStream.Length - br.BaseStream.Position); - Console.WriteLine(dataSize); - foreach (IAttribute attribute in Attributes) - { - attribute.Read(loader, br); - } - Console.WriteLine(Attributes.Sum(attribute => attribute.getDataSize())); - // Read Data of Unimplemented types - Data = br.ReadBytes(dataSize - Attributes.Sum(attribute => attribute.getDataSize())); + long initialPos = br.BaseStream.Position; + uint fourcc = br.ReadUInt32(); + // StrE + int size = br.ReadInt32(); // Size of Strings Array in hex + while (br.BaseStream.Position < initialPos + size) + Strings.Add(br.ReadCStr()); + Strings = [.. Strings.AsEnumerable().Reverse().SkipWhile(str => str.Length == 0).Reverse()]; + br.BaseStream.Position = initialPos + size; - } - catch (IOException ex) + int dataSize = (int)(br.BaseStream.Length - br.BaseStream.Position); + Console.WriteLine(dataSize); + foreach (IAttribute attribute in Attributes) { - throw new ReadFailedError("Failed to read bin data", ex.InnerException); + attribute.Read(loader, br); } + Console.WriteLine(Attributes.Sum(attribute => attribute.getDataSize())); + // Read Data of Unimplemented types + Data = br.ReadBytes(dataSize - Attributes.Sum(attribute => attribute.getDataSize())); + + } + catch (IOException ex) + { + throw new ReadFailedError("Failed to read bin data", ex.InnerException); } + } - private void WriteBin(BinaryWriter2 bw) + private void WriteBin(BinaryWriter2 bw) + { + try { - try - { - bw.Write(0x53747245); // StrE - bw.Write(getSizeOfStrE()); - foreach (string String in Strings) - bw.WriteCStr(String); - bw.WritePadding(); - foreach (IAttribute attribute in Attributes) - attribute.Write(bw); - // Write Data of Unimplemented types - bw.Write(Data); - bw.WritePadding(); - } - catch (IOException ex) - { - throw new ReadFailedError("Failed to write bin data", ex.InnerException); - } + bw.Write(0x53747245); // StrE + bw.Write(getSizeOfStrE()); + foreach (string String in Strings) + bw.WriteCStr(String); + bw.WritePadding(); + foreach (IAttribute attribute in Attributes) + attribute.Write(bw); + // Write Data of Unimplemented types + bw.Write(Data); + bw.WritePadding(); } + catch (IOException ex) + { + throw new ReadFailedError("Failed to write bin data", ex.InnerException); + } + } - public int addPadding(List bytes) + public int addPadding(List bytes) + { + if (bytes.SelectMany(i => i).Count() % 16 == 0) + return bytes.SelectMany(i => i).Count(); + else + return ((bytes.SelectMany(i => i).Count() / 16) * 16) + 16; + } + + private int getSizeOfStrE() + { + List bytes = + [ + Encoding.ASCII.GetBytes("StrE"), + BitConverter.GetBytes(16) + ]; + foreach (string String in Strings) { - if (bytes.SelectMany(i => i).Count() % 16 == 0) - return bytes.SelectMany(i => i).Count(); - else - return ((bytes.SelectMany(i => i).Count() / 16) * 16) + 16; + byte[] nullterminating = [(byte)0]; + bytes.Add([.. Encoding.ASCII.GetBytes(String), .. nullterminating]); } + return addPadding(bytes); + } + + private int getSizeOfVers() + { + List bytes = + [ + Encoding.ASCII.GetBytes("Vers"), + BitConverter.GetBytes(16), + BitConverter.GetBytes(VersionHash) + ]; + return addPadding(bytes); + } - private int getSizeOfStrE() + private int getSizeOfDepN() + { + List bytes = + [ + Encoding.ASCII.GetBytes("DepN"), + BitConverter.GetBytes(96), + BitConverter.GetBytes((ulong)Dependencies.Count()), + BitConverter.GetBytes(DepHash1), + BitConverter.GetBytes(DepHash2), + BitConverter.GetBytes(DepNop), + BitConverter.GetBytes(Dependencies[0].Length + 1) + ]; + foreach (string d in Dependencies) { - List bytes = new List - { - Encoding.ASCII.GetBytes("StrE"), - BitConverter.GetBytes(16) - }; - foreach (string String in Strings) + byte[] nullterminating = [0]; + bytes.Add([.. Encoding.ASCII.GetBytes(d), .. nullterminating]); + } + return addPadding(bytes); + } + + private int getSizeOfDatN() + { + List bytes = + [ + Encoding.ASCII.GetBytes("DatN") + ]; + foreach (AttributeHeader dataChunk in Attributes.Select(x => x.getHeader())) + { + bytes.Add(BitConverter.GetBytes(dataChunk.CollectionHash)); + bytes.Add(BitConverter.GetBytes(dataChunk.ClassHash)); + bytes.Add(dataChunk.Unknown1); + bytes.Add(BitConverter.GetBytes(dataChunk.ItemCount)); + bytes.Add(BitConverter.GetBytes(dataChunk.Unknown2)); + bytes.Add(BitConverter.GetBytes(dataChunk.ItemCountDup)); + bytes.Add(BitConverter.GetBytes(dataChunk.ParameterCount)); + bytes.Add(BitConverter.GetBytes(dataChunk.ParametersToRead)); + bytes.Add(dataChunk.Unknown3); + for (int j = 0; j < dataChunk.ParameterCount; j++) + bytes.Add(BitConverter.GetBytes((dataChunk.ParameterTypeHashes[j]))); + for (int j = 0; j < (dataChunk.ParametersToRead - dataChunk.ParameterCount); j++) + { + bytes.Add(BitConverter.GetBytes((ulong)0)); + } + foreach (DataItem item in dataChunk.Items) { - byte[] nullterminating = { (byte)0 }; - bytes.Add(Encoding.ASCII.GetBytes(String).Concat(nullterminating).ToArray()); + bytes.Add(BitConverter.GetBytes(item.Hash)); + bytes.Add(item.Unknown1); + bytes.Add(BitConverter.GetBytes(item.ParameterIdx)); + bytes.Add(BitConverter.GetBytes(item.Unknown2)); } - return addPadding(bytes); } + return addPadding(bytes); + } - private int getSizeOfVers() + private int getSizeOfExpN() + { + List bytes = + [ + Encoding.ASCII.GetBytes("ExpN"), + BitConverter.GetBytes(16), + BitConverter.GetBytes((ulong)Attributes.Select(x => x.getInfo()).Count()) + ]; + foreach (SizeAndPositionInformation chunk in Attributes.Select(x => x.getInfo())) { - List bytes = new List - { - Encoding.ASCII.GetBytes("Vers"), - BitConverter.GetBytes(16), - BitConverter.GetBytes(VersionHash) - }; - return addPadding(bytes); + bytes.Add(BitConverter.GetBytes(chunk.Hash)); + bytes.Add(BitConverter.GetBytes(chunk.EntryTypeHash)); + bytes.Add(BitConverter.GetBytes(chunk.DataChunkSize)); + bytes.Add(BitConverter.GetBytes(chunk.DataChunkPosition)); } + return addPadding(bytes); + } - private int getSizeOfDepN() + private int getSizeOfStrN() + { + List bytes = + [ + Encoding.ASCII.GetBytes("StrN"), + BitConverter.GetBytes(16), + BitConverter.GetBytes(StrUnknown1) + ]; + return addPadding(bytes); + } + + private int getSizeOfPtrN() + { + List bytes = + [ + Encoding.ASCII.GetBytes("PtrN"), + BitConverter.GetBytes(16) + ]; + foreach (PtrChunkData data in PtrN.allData) { - List bytes = new List - { - Encoding.ASCII.GetBytes("DepN"), - BitConverter.GetBytes(96), - BitConverter.GetBytes((UInt64)Dependencies.Count()), - BitConverter.GetBytes(DepHash1), - BitConverter.GetBytes(DepHash2), - BitConverter.GetBytes(DepNop), - BitConverter.GetBytes(Dependencies[0].Length + 1) - }; - foreach (string d in Dependencies) - { - byte[] nullterminating = { 0 }; - bytes.Add(Encoding.ASCII.GetBytes(d).Concat(nullterminating).ToArray()); - } - return addPadding(bytes); + bytes.Add(BitConverter.GetBytes(data.Ptr)); + bytes.Add(BitConverter.GetBytes(data.type)); + bytes.Add(BitConverter.GetBytes(data.flag)); + bytes.Add(BitConverter.GetBytes(data.Data)); } + return addPadding(bytes); + } - private int getSizeOfDatN() + private void WriteVlt(BinaryWriter2 bw) + { + try { - List bytes = new List - { - Encoding.ASCII.GetBytes("DatN") - }; + bw.Write(0x56657273); // Vers + bw.Write(getSizeOfVers()); + bw.Write(VersionHash); + bw.WritePadding(); + + bw.Write(0x4465704E); // DepN + bw.Write(getSizeOfDepN()); + WriteCount(bw, Dependencies.Count); + bw.Write(DepHash1); + bw.Write(DepHash2); + bw.Write(DepNop); + // Have to add null terminating byte to length + bw.Write(Dependencies[0].Length + 1); + foreach (string d in Dependencies) + bw.WriteCStr(d); + bw.WritePadding(); + + bw.Write(0x5374724E); // StrN + bw.Write(getSizeOfStrN()); + bw.Write(StrUnknown1); + bw.WritePadding(); + + bw.Write(0x4461744E); // DatN + bw.Write(getSizeOfDatN()); foreach (AttributeHeader dataChunk in Attributes.Select(x => x.getHeader())) { - bytes.Add(BitConverter.GetBytes(dataChunk.CollectionHash)); - bytes.Add(BitConverter.GetBytes(dataChunk.ClassHash)); - bytes.Add(dataChunk.Unknown1); - bytes.Add(BitConverter.GetBytes(dataChunk.ItemCount)); - bytes.Add(BitConverter.GetBytes(dataChunk.Unknown2)); - bytes.Add(BitConverter.GetBytes(dataChunk.ItemCountDup)); - bytes.Add(BitConverter.GetBytes(dataChunk.ParameterCount)); - bytes.Add(BitConverter.GetBytes(dataChunk.ParametersToRead)); - bytes.Add(dataChunk.Unknown3); + bw.Write(dataChunk.CollectionHash); + bw.Write(dataChunk.ClassHash); + bw.Write(dataChunk.Unknown1); + bw.Write(dataChunk.ItemCount); + bw.Write(dataChunk.Unknown2); + bw.Write(dataChunk.ItemCountDup); + bw.Write(dataChunk.ParameterCount); + bw.Write(dataChunk.ParametersToRead); + bw.Write(dataChunk.Unknown3); for (int j = 0; j < dataChunk.ParameterCount; j++) - bytes.Add(BitConverter.GetBytes((dataChunk.ParameterTypeHashes[j]))); + bw.Write(dataChunk.ParameterTypeHashes[j]); for (int j = 0; j < (dataChunk.ParametersToRead - dataChunk.ParameterCount); j++) - { - bytes.Add(BitConverter.GetBytes((ulong)0)); - } + bw.Write((ulong)0); foreach (DataItem item in dataChunk.Items) { - bytes.Add(BitConverter.GetBytes(item.Hash)); - bytes.Add(item.Unknown1); - bytes.Add(BitConverter.GetBytes(item.ParameterIdx)); - bytes.Add(BitConverter.GetBytes(item.Unknown2)); + bw.Write(item.Hash); + bw.Write(item.Unknown1); + bw.Write(item.ParameterIdx); + bw.Write(item.Unknown2); } } - return addPadding(bytes); - } + bw.WritePadding(); - private int getSizeOfExpN() - { - List bytes = new List - { - Encoding.ASCII.GetBytes("ExpN"), - BitConverter.GetBytes(16), - BitConverter.GetBytes((UInt64)Attributes.Select(x => x.getInfo()).Count()) - }; + bw.Write(0x4578704E); // ExpN + bw.Write(getSizeOfExpN()); + WriteCount(bw, Attributes.Count); foreach (SizeAndPositionInformation chunk in Attributes.Select(x => x.getInfo())) { - bytes.Add(BitConverter.GetBytes(chunk.Hash)); - bytes.Add(BitConverter.GetBytes(chunk.EntryTypeHash)); - bytes.Add(BitConverter.GetBytes(chunk.DataChunkSize)); - bytes.Add(BitConverter.GetBytes(chunk.DataChunkPosition)); + bw.Write(chunk.Hash); + bw.Write(chunk.EntryTypeHash); + bw.Write(chunk.DataChunkSize); + bw.Write(chunk.DataChunkPosition); } - return addPadding(bytes); - } + bw.WritePadding(); - private int getSizeOfStrN() - { - List bytes = new List - { - Encoding.ASCII.GetBytes("StrN"), - BitConverter.GetBytes(16), - BitConverter.GetBytes(StrUnknown1) - }; - return addPadding(bytes); - } - - private int getSizeOfPtrN() - { - List bytes = new List - { - Encoding.ASCII.GetBytes("PtrN"), - BitConverter.GetBytes(16) - }; + bw.Write(0x5074724E); // PtrN + bw.Write(getSizeOfPtrN()); foreach (PtrChunkData data in PtrN.allData) { - bytes.Add(BitConverter.GetBytes(data.Ptr)); - bytes.Add(BitConverter.GetBytes(data.type)); - bytes.Add(BitConverter.GetBytes(data.flag)); - bytes.Add(BitConverter.GetBytes(data.Data)); + bw.Write(data.Ptr); + bw.Write(data.type); + bw.Write(data.flag); + bw.Write(data.Data); } - return addPadding(bytes); + bw.WritePadding(); } - - private void WriteVlt(BinaryWriter2 bw) + catch (IOException ex) { - try - { - bw.Write(0x56657273); // Vers - bw.Write(getSizeOfVers()); - bw.Write(VersionHash); - bw.WritePadding(); - - bw.Write(0x4465704E); // DepN - bw.Write(getSizeOfDepN()); - WriteCount(bw, Dependencies.Count); - bw.Write(DepHash1); - bw.Write(DepHash2); - bw.Write(DepNop); - // Have to add null terminating byte to length - bw.Write(Dependencies[0].Length + 1); - foreach (string d in Dependencies) - bw.WriteCStr(d); - bw.WritePadding(); - - bw.Write(0x5374724E); // StrN - bw.Write(getSizeOfStrN()); - bw.Write(StrUnknown1); - bw.WritePadding(); - - bw.Write(0x4461744E); // DatN - bw.Write(getSizeOfDatN()); - foreach (AttributeHeader dataChunk in Attributes.Select(x => x.getHeader())) - { - bw.Write(dataChunk.CollectionHash); - bw.Write(dataChunk.ClassHash); - bw.Write(dataChunk.Unknown1); - bw.Write(dataChunk.ItemCount); - bw.Write(dataChunk.Unknown2); - bw.Write(dataChunk.ItemCountDup); - bw.Write(dataChunk.ParameterCount); - bw.Write(dataChunk.ParametersToRead); - bw.Write(dataChunk.Unknown3); - for (int j = 0; j < dataChunk.ParameterCount; j++) - bw.Write(dataChunk.ParameterTypeHashes[j]); - for (int j = 0; j < (dataChunk.ParametersToRead - dataChunk.ParameterCount); j++) - bw.Write((ulong)0); - foreach (DataItem item in dataChunk.Items) - { - bw.Write(item.Hash); - bw.Write(item.Unknown1); - bw.Write(item.ParameterIdx); - bw.Write(item.Unknown2); - } - } - bw.WritePadding(); - - bw.Write(0x4578704E); // ExpN - bw.Write(getSizeOfExpN()); - WriteCount(bw, Attributes.Count); - foreach (SizeAndPositionInformation chunk in Attributes.Select(x => x.getInfo())) - { - bw.Write(chunk.Hash); - bw.Write(chunk.EntryTypeHash); - bw.Write(chunk.DataChunkSize); - bw.Write(chunk.DataChunkPosition); - } - bw.WritePadding(); - - bw.Write(0x5074724E); // PtrN - bw.Write(getSizeOfPtrN()); - foreach (PtrChunkData data in PtrN.allData) - { - bw.Write(data.Ptr); - bw.Write(data.type); - bw.Write(data.flag); - bw.Write(data.Data); - } - bw.WritePadding(); - } - catch (IOException ex) - { - throw new ReadFailedError("Failed to write bin data", ex.InnerException); - } + throw new ReadFailedError("Failed to write bin data", ex.InnerException); } + } - private void Clear() - { - VersionHash = default; - DepHash1 = default; - DepHash2 = default; - DepNop = default; - Attributes.Clear(); - StrUnknown1 = default; + private void Clear() + { + VersionHash = default; + DepHash1 = default; + DepHash2 = default; + DepNop = default; + Attributes.Clear(); + StrUnknown1 = default; - PtrN = default; + PtrN = default; - Dependencies.Clear(); - Strings.Clear(); - } + Dependencies.Clear(); + Strings.Clear(); + } - public bool Read(BundleEntry entry, ILoader loader = null) - { - Clear(); - _x64 = entry.Platform == BundlePlatform.PCx64; + public bool Read(BundleEntry entry, ILoader loader = null) + { + Clear(); + _x64 = entry.Platform == BundlePlatform.PCx64; - MemoryStream ms = entry.MakeStream(); - BinaryReader2 br = new BinaryReader2(ms); - br.BigEndian = entry.Console; + MemoryStream ms = entry.MakeStream(); + BinaryReader2 br = new(ms); + br.BigEndian = entry.Console; - int vltPos = br.ReadInt32(); - int vltSize = br.ReadInt32(); - int binPos = br.ReadInt32(); - int binSize = br.ReadInt32(); - br.BaseStream.Position = vltPos; + int vltPos = br.ReadInt32(); + int vltSize = br.ReadInt32(); + int binPos = br.ReadInt32(); + int binSize = br.ReadInt32(); + br.BaseStream.Position = vltPos; - byte[] vlt = br.ReadBytes(vltSize); + byte[] vlt = br.ReadBytes(vltSize); - MemoryStream vltStream = new MemoryStream(vlt); - BinaryReader2 vltBr = new BinaryReader2(vltStream); - vltBr.BigEndian = entry.Console; - ReadVlt(loader, vltBr); - vltBr.Close(); + MemoryStream vltStream = new(vlt); + BinaryReader2 vltBr = new(vltStream); + vltBr.BigEndian = entry.Console; + ReadVlt(loader, vltBr); + vltBr.Close(); - br.BaseStream.Position = binPos; + br.BaseStream.Position = binPos; - byte[] bin = br.ReadBytes(binSize); - MemoryStream binStream = new MemoryStream(bin); - BinaryReader2 binBr = new BinaryReader2(binStream); - binBr.BigEndian = entry.Console; - ReadBin(loader, binBr); - binBr.Close(); + byte[] bin = br.ReadBytes(binSize); + MemoryStream binStream = new(bin); + BinaryReader2 binBr = new(binStream); + binBr.BigEndian = entry.Console; + ReadBin(loader, binBr); + binBr.Close(); - br.Close(); - ms.Close(); + br.Close(); + ms.Close(); - return true; - } + return true; + } - public bool Write(BundleEntry entry) - { - MemoryStream ms = new MemoryStream(); - BinaryWriter2 bw = new BinaryWriter2(ms); - bw.BigEndian = entry.Console; + public bool Write(BundleEntry entry) + { + MemoryStream ms = new(); + BinaryWriter2 bw = new(ms); + bw.BigEndian = entry.Console; - int vltPos = 16; // Because vlt begins after the sizes - int vltSize = getSizeOfDatN() + getSizeOfDepN() + getSizeOfExpN() + getSizeOfPtrN() + getSizeOfStrN() + getSizeOfVers(); + int vltPos = 16; // Because vlt begins after the sizes + int vltSize = getSizeOfDatN() + getSizeOfDepN() + getSizeOfExpN() + getSizeOfPtrN() + getSizeOfStrN() + getSizeOfVers(); - bw.Write(vltPos); //vltPos: - bw.Write(vltSize); //vltSize - bw.Write(vltSize + vltPos);//binPos; - bw.Write(CountingUtilities.AddEightPadding(Attributes.Sum(attribute => attribute.getDataSize()) + Data.Length + getSizeOfStrE())); // binSize + bw.Write(vltPos); //vltPos: + bw.Write(vltSize); //vltSize + bw.Write(vltSize + vltPos);//binPos; + bw.Write(CountingUtilities.AddEightPadding(Attributes.Sum(attribute => attribute.getDataSize()) + Data.Length + getSizeOfStrE())); // binSize - WriteVlt(bw); - WriteBin(bw); + WriteVlt(bw); + WriteBin(bw); - bw.Flush(); - byte[] data = ms.ToArray(); - bw.Close(); - ms.Close(); + bw.Flush(); + byte[] data = ms.ToArray(); + bw.Close(); + ms.Close(); - entry.EntryBlocks[0].Data = data; - entry.Dirty = true; + entry.EntryBlocks[0].Data = data; + entry.Dirty = true; - return true; - } + return true; + } - public EntryType GetEntryType(BundleEntry entry) - { - return EntryType.AttribSysVault; - } + public EntryType GetEntryType(BundleEntry entry) + { + return EntryType.AttribSysVault; + } - public IEntryEditor GetEditor(BundleEntry entry) + public IEntryEditor GetEditor(BundleEntry entry) + { + AttribSysVaultForm attribSysVaultForm = new(); + attribSysVaultForm.AttribSys = this; + attribSysVaultForm.EditEvent += () => { - AttribSysVaultForm attribSysVaultForm = new AttribSysVaultForm(); - attribSysVaultForm.AttribSys = this; - attribSysVaultForm.EditEvent += () => - { - Write(entry); - }; + Write(entry); + }; - return attribSysVaultForm; - } + return attribSysVaultForm; } } diff --git a/VaultFormat/AttribSysPlugin.cs b/VaultFormat/AttribSysPlugin.cs index 7e20e36..0bf8004 100644 --- a/VaultFormat/AttribSysPlugin.cs +++ b/VaultFormat/AttribSysPlugin.cs @@ -1,16 +1,15 @@ using BundleFormat; using PluginAPI; -namespace VaultFormat +namespace VaultFormat; + +public class AttribSysPlugin : IPlugin { - public class AttribSysPlugin : IPlugin - { - public string Id => "attribsysplugin"; - public string Name => "AttribSys Resource Handler"; + public string Id => "attribsysplugin"; + public string Name => "AttribSys Resource Handler"; - public static void Init() - { - EntryTypeRegistry.Register(EntryType.AttribSysVault, new AttribSys()); - } + public static void Init() + { + EntryTypeRegistry.Register(EntryType.AttribSysVault, new AttribSys()); } } diff --git a/VaultFormat/AttribSysVaultForm.cs b/VaultFormat/AttribSysVaultForm.cs index 35c2005..e5406ca 100644 --- a/VaultFormat/AttribSysVaultForm.cs +++ b/VaultFormat/AttribSysVaultForm.cs @@ -9,161 +9,158 @@ using System.Text.Json; using System.Windows.Forms; -namespace VaultFormat +namespace VaultFormat; + +public delegate void Notify(); // delegate +public partial class AttribSysVaultForm : Form, IEntryEditor { - public delegate void Notify(); // delegate - public partial class AttribSysVaultForm : Form, IEntryEditor + private readonly JsonSerializerOptions jsonSerializerOptions = new() { - private readonly JsonSerializerOptions jsonSerializerOptions = new() - { - WriteIndented = true - }; + WriteIndented = true + }; - public AttribSysVaultForm() - { - InitializeComponent(); - } - - public event Notify EditEvent; + public AttribSysVaultForm() + { + InitializeComponent(); + } + + public event Notify EditEvent; - private AttribSys _attribSys; - [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] - public AttribSys AttribSys + private AttribSys _attribSys; + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public AttribSys AttribSys + { + get => _attribSys; + set { - get => _attribSys; - set - { - _attribSys = value; - UpdateDisplay(); - } + _attribSys = value; + UpdateDisplay(); } + } + + private void UpdateDisplay() + { + lstDataChunks.Items.Clear(); + + if (AttribSys == null) + return; - private void UpdateDisplay() + for (int i = 0; i < AttribSys.Attributes.Count; i++) { - lstDataChunks.Items.Clear(); + IAttribute chunk = AttribSys.Attributes[i]; + + string[] value = [ + chunk.getHeader().ClassName, + chunk.getHeader().ClassHash.ToString("X16"), + chunk.getHeader().CollectionHash.ToString("X16"), + ]; + lstDataChunks.Items.Add(new ListViewItem(value)); + } - if (AttribSys == null) - return; + lstDataChunks.ListViewItemSorter = new AttribSysVaultSorter(0); + lstDataChunks.Sort(); + } - for (int i = 0; i < AttribSys.Attributes.Count; i++) - { - IAttribute chunk = AttribSys.Attributes[i]; - - string[] value = { - chunk.getHeader().ClassName, - chunk.getHeader().ClassHash.ToString("X16"), - chunk.getHeader().CollectionHash.ToString("X16"), - }; - lstDataChunks.Items.Add(new ListViewItem(value)); - } + private class AttribSysVaultSorter : IComparer + { + public readonly int Column; + public bool Direction; - lstDataChunks.ListViewItemSorter = new AttribSysVaultSorter(0); - lstDataChunks.Sort(); + public AttribSysVaultSorter(int column) + { + this.Column = column; + this.Direction = false; } - private class AttribSysVaultSorter : IComparer + public int Compare(object x, object y) { - public readonly int Column; - public bool Direction; + ListViewItem itemX = (ListViewItem)x; + ListViewItem itemY = (ListViewItem)y; - public AttribSysVaultSorter(int column) + if (Column > itemX.SubItems.Count || Column > itemY.SubItems.Count) { - this.Column = column; - this.Direction = false; + if (this.Direction) + return -1; + return 1; } - public int Compare(object x, object y) - { - ListViewItem itemX = (ListViewItem)x; - ListViewItem itemY = (ListViewItem)y; - - if (Column > itemX.SubItems.Count || Column > itemY.SubItems.Count) - { - if (this.Direction) - return -1; - return 1; - } - - string iX = itemX.SubItems[Column].Text; - string iY = itemY.SubItems[Column].Text; + string iX = itemX.SubItems[Column].Text; + string iY = itemY.SubItems[Column].Text; - int iXint; - int iYint; - if (int.TryParse(iX, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out iXint)) + if (int.TryParse(iX, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out int iXint)) + { + if (int.TryParse(iY, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out int iYint)) { - if (int.TryParse(iY, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out iYint)) - { - int val2 = iXint.CompareTo(iYint); - if (this.Direction) - return val2 * -1; - return val2; - } + int val2 = iXint.CompareTo(iYint); + if (this.Direction) + return val2 * -1; + return val2; } - - int val = String.CompareOrdinal(iX, iY); - if (this.Direction) - return val * -1; - return val; } - public void Swap() - { - this.Direction = !this.Direction; - } + int val = string.CompareOrdinal(iX, iY); + if (this.Direction) + return val * -1; + return val; } - private void changeCollectionHashToolStripMenuItem_Click(object sender, EventArgs e) + public void Swap() { - string value = InputDialog.ShowInput(this, "Please enter the value to get the lookup 8."); - if (value == null) - return; - ulong result = Utilities.CalcLookup8(value); - int index = AttribSys.Attributes.FindIndex(i => i.getHeader().ClassName == lstDataChunks.SelectedItems[0].Text); - AttribSys.Attributes[index].getHeader().CollectionHash = result; - MessageBox.Show(this, "The lookup 8 hashed value is: " + result.ToString("X16"), "Information", MessageBoxButtons.OK, MessageBoxIcon.Information); - EditEvent?.Invoke(); - UpdateDisplay(); + this.Direction = !this.Direction; } + } - private void lstDataChunks_DoubleClick(object sender, EventArgs e) - { - Console.WriteLine(lstDataChunks.SelectedItems[0].Text); - int index = AttribSys.Attributes.FindIndex(i => i.getHeader().ClassName == lstDataChunks.SelectedItems[0].Text); - propertyGrid2.SelectedObject = AttribSys.Attributes[index]; - } + private void changeCollectionHashToolStripMenuItem_Click(object sender, EventArgs e) + { + string value = InputDialog.ShowInput(this, "Please enter the value to get the lookup 8."); + if (value == null) + return; + ulong result = Utilities.CalcLookup8(value); + int index = AttribSys.Attributes.FindIndex(i => i.getHeader().ClassName == lstDataChunks.SelectedItems[0].Text); + AttribSys.Attributes[index].getHeader().CollectionHash = result; + MessageBox.Show(this, "The lookup 8 hashed value is: " + result.ToString("X16"), "Information", MessageBoxButtons.OK, MessageBoxIcon.Information); + EditEvent?.Invoke(); + UpdateDisplay(); + } - private void AttribSysVaultForm_FormClosed(object s, FormClosedEventArgs e) - { - EditEvent?.Invoke(); - UpdateDisplay(); - } + private void lstDataChunks_DoubleClick(object sender, EventArgs e) + { + Console.WriteLine(lstDataChunks.SelectedItems[0].Text); + int index = AttribSys.Attributes.FindIndex(i => i.getHeader().ClassName == lstDataChunks.SelectedItems[0].Text); + propertyGrid2.SelectedObject = AttribSys.Attributes[index]; + } - private void exportVaultToolStripMenuItem_Click(object sender, EventArgs e) + private void AttribSysVaultForm_FormClosed(object s, FormClosedEventArgs e) + { + EditEvent?.Invoke(); + UpdateDisplay(); + } + + private void exportVaultToolStripMenuItem_Click(object sender, EventArgs e) + { + // Dialog Creation + SaveFileDialog saveDialog = new(); + saveDialog.Filter = "JSON File (*.json)|*.json"; + saveDialog.Title = "Save AttribSys as JSON"; + saveDialog.FileName = "AttribSys.json"; + + // Dialog Logic + if (saveDialog.ShowDialog() == DialogResult.OK) { - // Dialog Creation - SaveFileDialog saveDialog = new SaveFileDialog(); - saveDialog.Filter = "JSON File (*.json)|*.json"; - saveDialog.Title = "Save AttribSys as JSON"; - saveDialog.FileName = "AttribSys.json"; - - // Dialog Logic - if (saveDialog.ShowDialog() == DialogResult.OK) + try { - try - { - // Convertion of the AttribSys. Might need smarter structure to only keep the essential data concerning the configuration of the vehicle - - string jsonContent = JsonSerializer.Serialize(AttribSys, jsonSerializerOptions); + // Convertion of the AttribSys. Might need smarter structure to only keep the essential data concerning the configuration of the vehicle + + string jsonContent = JsonSerializer.Serialize(AttribSys, jsonSerializerOptions); - File.WriteAllText(saveDialog.FileName, jsonContent); + File.WriteAllText(saveDialog.FileName, jsonContent); - MessageBox.Show("Successfully exported to " + saveDialog.FileName, "Export Complete", MessageBoxButtons.OK, MessageBoxIcon.Information); - } - catch (Exception ex) - { - MessageBox.Show("Failed to export file. Error: " + ex.Message, "Export Failed", MessageBoxButtons.OK, MessageBoxIcon.Error); - } + MessageBox.Show("Successfully exported to " + saveDialog.FileName, "Export Complete", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + catch (Exception ex) + { + MessageBox.Show("Failed to export file. Error: " + ex.Message, "Export Failed", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } diff --git a/VaultFormat/Burnoutcarasset.cs b/VaultFormat/Burnoutcarasset.cs index c54ce4a..f6871d1 100644 --- a/VaultFormat/Burnoutcarasset.cs +++ b/VaultFormat/Burnoutcarasset.cs @@ -1,146 +1,144 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using BundleUtilities; -namespace VaultFormat +namespace VaultFormat; + +public class Burnoutcarasset : IAttribute { - public class Burnoutcarasset : IAttribute - { - public RefSpec[] Offences { get; set; } //RefSpec[12] - public RefSpec SoundExhaustAsset { get; set; } - public RefSpec SoundEngineAsset { get; set; } - public RefSpec PhysicsVehicleHandlingAsset { get; set; } - public RefSpec GraphicsAsset { get; set; } - public RefSpec CarUnlockShot { get; set; } - public RefSpec CameraExternalBehaviourAsset { get; set; } - public RefSpec CameraBumperBehaviourAsset { get; set; } - public byte[] VehicleID;//See StrE - public long PhysicsAsset { get; set; } - public long MasterSceneMayaBinaryFile { get; set; } - public byte[] InGameName;// See StrE - public long GameplayAsset { get; set; } - public byte[] ExhaustName;//See StrE - public long ExhaustEntityKey { get; set; } - public byte[] EngineName; //See StrE - public long EngineEntityKey { get; set; } - public long DefaultWheel { get; set; } - public bool BuildThisVehicle { get; set; } + public RefSpec[] Offences { get; set; } //RefSpec[12] + public RefSpec SoundExhaustAsset { get; set; } + public RefSpec SoundEngineAsset { get; set; } + public RefSpec PhysicsVehicleHandlingAsset { get; set; } + public RefSpec GraphicsAsset { get; set; } + public RefSpec CarUnlockShot { get; set; } + public RefSpec CameraExternalBehaviourAsset { get; set; } + public RefSpec CameraBumperBehaviourAsset { get; set; } + public byte[] VehicleID;//See StrE + public long PhysicsAsset { get; set; } + public long MasterSceneMayaBinaryFile { get; set; } + public byte[] InGameName;// See StrE + public long GameplayAsset { get; set; } + public byte[] ExhaustName;//See StrE + public long ExhaustEntityKey { get; set; } + public byte[] EngineName; //See StrE + public long EngineEntityKey { get; set; } + public long DefaultWheel { get; set; } + public bool BuildThisVehicle { get; set; } - public AttributeHeader header { get; set; } - public SizeAndPositionInformation info { get; set; } + public AttributeHeader header { get; set; } + public SizeAndPositionInformation info { get; set; } - public Burnoutcarasset(SizeAndPositionInformation chunk, AttributeHeader dataChunk) - { - header = dataChunk; - info = chunk; - } + public Burnoutcarasset(SizeAndPositionInformation chunk, AttributeHeader dataChunk) + { + header = dataChunk; + info = chunk; + } - public int getDataSize() + public int getDataSize() + { + List bytes = []; + foreach (RefSpec r in Offences) { - List bytes = new List(); - foreach (RefSpec r in Offences) - { - bytes.Add(r.ToBytes()); //RefSpec[12] - } // 288 - bytes.Add(SoundExhaustAsset.ToBytes()); - bytes.Add(SoundEngineAsset.ToBytes()); - bytes.Add(PhysicsVehicleHandlingAsset.ToBytes()); - bytes.Add(GraphicsAsset.ToBytes()); - bytes.Add(CarUnlockShot.ToBytes()); - bytes.Add(CameraExternalBehaviourAsset.ToBytes()); - bytes.Add(CameraBumperBehaviourAsset.ToBytes()); // 168 + 80 + 4 - bytes.Add(VehicleID); - bytes.Add(BitConverter.GetBytes(PhysicsAsset)); - bytes.Add(BitConverter.GetBytes(MasterSceneMayaBinaryFile)); - bytes.Add(InGameName); - bytes.Add(BitConverter.GetBytes(GameplayAsset)); - bytes.Add(ExhaustName); - bytes.Add(BitConverter.GetBytes(ExhaustEntityKey)); - bytes.Add(EngineName); - bytes.Add(BitConverter.GetBytes(EngineEntityKey)); - bytes.Add(BitConverter.GetBytes(DefaultWheel)); - bytes.Add(BitConverter.GetBytes(BuildThisVehicle)); - // To-Do: The program want 3 bytes for some reason - Console.WriteLine("Before " + bytes.SelectMany(i => i).Count()); - int newValue = AddPadding(bytes).Count(); - Console.WriteLine("After " + newValue); - // Should be 540 is 514 -> probably the text tbh - return newValue; - } + bytes.Add(r.ToBytes()); //RefSpec[12] + } // 288 + bytes.Add(SoundExhaustAsset.ToBytes()); + bytes.Add(SoundEngineAsset.ToBytes()); + bytes.Add(PhysicsVehicleHandlingAsset.ToBytes()); + bytes.Add(GraphicsAsset.ToBytes()); + bytes.Add(CarUnlockShot.ToBytes()); + bytes.Add(CameraExternalBehaviourAsset.ToBytes()); + bytes.Add(CameraBumperBehaviourAsset.ToBytes()); // 168 + 80 + 4 + bytes.Add(VehicleID); + bytes.Add(BitConverter.GetBytes(PhysicsAsset)); + bytes.Add(BitConverter.GetBytes(MasterSceneMayaBinaryFile)); + bytes.Add(InGameName); + bytes.Add(BitConverter.GetBytes(GameplayAsset)); + bytes.Add(ExhaustName); + bytes.Add(BitConverter.GetBytes(ExhaustEntityKey)); + bytes.Add(EngineName); + bytes.Add(BitConverter.GetBytes(EngineEntityKey)); + bytes.Add(BitConverter.GetBytes(DefaultWheel)); + bytes.Add(BitConverter.GetBytes(BuildThisVehicle)); + // To-Do: The program want 3 bytes for some reason + Console.WriteLine("Before " + bytes.SelectMany(i => i).Count()); + int newValue = AddPadding(bytes).Count(); + Console.WriteLine("After " + newValue); + // Should be 540 is 514 -> probably the text tbh + return newValue; + } - private byte[] AddPadding(List bytes) - { - List padding = new List - { - 0, - 0, - 0 - }; - bytes.Add(padding.ToArray()); - return bytes.SelectMany(i => i).ToArray(); - } + private byte[] AddPadding(List bytes) + { + List padding = + [ + 0, + 0, + 0 + ]; + bytes.Add([.. padding]); + return [.. bytes.SelectMany(i => i)]; + } - public AttributeHeader getHeader() - { - return header; - } + public AttributeHeader getHeader() + { + return header; + } - public SizeAndPositionInformation getInfo() - { - return info; - } + public SizeAndPositionInformation getInfo() + { + return info; + } - public void Read(ILoader loader, BinaryReader2 br) - { - Offences = new RefSpec[12]; - for (int i = 0; i < 12; i++) - Offences[i] = new RefSpec(loader, br); - SoundExhaustAsset = new RefSpec(loader, br); - SoundEngineAsset = new RefSpec(loader, br); - PhysicsVehicleHandlingAsset = new RefSpec(loader, br); - GraphicsAsset = new RefSpec(loader, br); - CarUnlockShot = new RefSpec(loader, br); - CameraExternalBehaviourAsset = new RefSpec(loader, br); - CameraBumperBehaviourAsset = new RefSpec(loader, br); - VehicleID = br.ReadBytes(8); - PhysicsAsset = br.ReadInt64(); - MasterSceneMayaBinaryFile = br.ReadInt64(); - InGameName = br.ReadBytes(8); - GameplayAsset = br.ReadInt64(); - ExhaustName = br.ReadBytes(8); - ExhaustEntityKey = br.ReadInt64(); - EngineName = br.ReadBytes(8); - EngineEntityKey = br.ReadInt64(); - DefaultWheel = br.ReadInt64(); - BuildThisVehicle = br.ReadBoolean(); - br.SkipUniquePadding(3); - } + public void Read(ILoader loader, BinaryReader2 br) + { + Offences = new RefSpec[12]; + for (int i = 0; i < 12; i++) + Offences[i] = new RefSpec(loader, br); + SoundExhaustAsset = new RefSpec(loader, br); + SoundEngineAsset = new RefSpec(loader, br); + PhysicsVehicleHandlingAsset = new RefSpec(loader, br); + GraphicsAsset = new RefSpec(loader, br); + CarUnlockShot = new RefSpec(loader, br); + CameraExternalBehaviourAsset = new RefSpec(loader, br); + CameraBumperBehaviourAsset = new RefSpec(loader, br); + VehicleID = br.ReadBytes(8); + PhysicsAsset = br.ReadInt64(); + MasterSceneMayaBinaryFile = br.ReadInt64(); + InGameName = br.ReadBytes(8); + GameplayAsset = br.ReadInt64(); + ExhaustName = br.ReadBytes(8); + ExhaustEntityKey = br.ReadInt64(); + EngineName = br.ReadBytes(8); + EngineEntityKey = br.ReadInt64(); + DefaultWheel = br.ReadInt64(); + BuildThisVehicle = br.ReadBoolean(); + br.SkipUniquePadding(3); + } - public void Write(BinaryWriter2 bw) - { - foreach (RefSpec r in Offences) - r.Write(bw); - SoundExhaustAsset.Write(bw); - SoundEngineAsset.Write(bw); - PhysicsVehicleHandlingAsset.Write(bw); - GraphicsAsset.Write(bw); - CarUnlockShot.Write(bw); - CameraExternalBehaviourAsset.Write(bw); - CameraBumperBehaviourAsset.Write(bw); - bw.Write(VehicleID); - bw.Write(PhysicsAsset); - bw.Write(MasterSceneMayaBinaryFile); - bw.Write(InGameName); - bw.Write(GameplayAsset); - bw.Write(ExhaustName); - bw.Write(ExhaustEntityKey); - bw.Write(EngineName); - bw.Write(EngineEntityKey); - bw.Write(DefaultWheel); - bw.Write(BuildThisVehicle); - bw.WriteUniquePadding(3); - } + public void Write(BinaryWriter2 bw) + { + foreach (RefSpec r in Offences) + r.Write(bw); + SoundExhaustAsset.Write(bw); + SoundEngineAsset.Write(bw); + PhysicsVehicleHandlingAsset.Write(bw); + GraphicsAsset.Write(bw); + CarUnlockShot.Write(bw); + CameraExternalBehaviourAsset.Write(bw); + CameraBumperBehaviourAsset.Write(bw); + bw.Write(VehicleID); + bw.Write(PhysicsAsset); + bw.Write(MasterSceneMayaBinaryFile); + bw.Write(InGameName); + bw.Write(GameplayAsset); + bw.Write(ExhaustName); + bw.Write(ExhaustEntityKey); + bw.Write(EngineName); + bw.Write(EngineEntityKey); + bw.Write(DefaultWheel); + bw.Write(BuildThisVehicle); + bw.WriteUniquePadding(3); } } diff --git a/VaultFormat/Burnoutcargraphicsasset.cs b/VaultFormat/Burnoutcargraphicsasset.cs index b52a978..34b026c 100644 --- a/VaultFormat/Burnoutcargraphicsasset.cs +++ b/VaultFormat/Burnoutcargraphicsasset.cs @@ -1,105 +1,105 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using BundleUtilities; -namespace VaultFormat +namespace VaultFormat; + +public class Burnoutcargraphicsasset : IAttribute { - public class Burnoutcargraphicsasset : IAttribute - { - public int PlayerPalletteIndex { get; set; } - public int PlayerColourIndex { get; set; } - public short Alloc { get; set; } // Allocate space for x* Size. Always 1 in VEH_P* - public short Num_RandomTrafficColours { get; set; } // Count - public short Size { get; set; } // Size of each entry - public short EncodedTypePad { get; set; } // Padding - public List RandomTrafficColours { get; set; } - public short Alloc_Offences { get; set; } // Allocate space for x* Size - public short Num_Offences { get; set; } // Count - public short Size_Offences { get; set; } // Size of each entry - public short EncodedTypePad_Offences { get; set; } // Padding + public int PlayerPalletteIndex { get; set; } + public int PlayerColourIndex { get; set; } + public short Alloc { get; set; } // Allocate space for x* Size. Always 1 in VEH_P* + public short Num_RandomTrafficColours { get; set; } // Count + public short Size { get; set; } // Size of each entry + public short EncodedTypePad { get; set; } // Padding + public List RandomTrafficColours { get; set; } + public short Alloc_Offences { get; set; } // Allocate space for x* Size + public short Num_Offences { get; set; } // Count + public short Size_Offences { get; set; } // Size of each entry + public short EncodedTypePad_Offences { get; set; } // Padding - public AttributeHeader header { get; set; } - public SizeAndPositionInformation info { get; set; } + public AttributeHeader header { get; set; } + public SizeAndPositionInformation info { get; set; } - public Burnoutcargraphicsasset(SizeAndPositionInformation chunk, AttributeHeader dataChunk) - { - header = dataChunk; - info = chunk; - RandomTrafficColours = new List(); - } + public Burnoutcargraphicsasset(SizeAndPositionInformation chunk, AttributeHeader dataChunk) + { + header = dataChunk; + info = chunk; + RandomTrafficColours = []; + } - public int getDataSize() - { - List bytes = new List(); - bytes.Add(BitConverter.GetBytes(PlayerPalletteIndex)); - bytes.Add(BitConverter.GetBytes(PlayerColourIndex)); - bytes.Add(BitConverter.GetBytes(Alloc)); - bytes.Add(BitConverter.GetBytes(Num_RandomTrafficColours)); - bytes.Add(BitConverter.GetBytes(Size)); - bytes.Add(BitConverter.GetBytes(EncodedTypePad)); - for (int i = 0; i < Num_RandomTrafficColours; i++) - bytes.Add(BitConverter.GetBytes(RandomTrafficColours[i])); - for (int i = Num_RandomTrafficColours; i < Alloc; i++) - bytes.Add(BitConverter.GetBytes(0)); - bytes.Add(BitConverter.GetBytes(Alloc_Offences)); - bytes.Add(BitConverter.GetBytes(Num_Offences)); - bytes.Add(BitConverter.GetBytes(Size_Offences)); - bytes.Add(BitConverter.GetBytes(EncodedTypePad_Offences)); - Console.Write("Length:" + bytes.SelectMany(i => i).Count()); - // 28 bytes but not padding... - return bytes.SelectMany(i => i).Count(); - } + public int getDataSize() + { + List bytes = + [ + BitConverter.GetBytes(PlayerPalletteIndex), + BitConverter.GetBytes(PlayerColourIndex), + BitConverter.GetBytes(Alloc), + BitConverter.GetBytes(Num_RandomTrafficColours), + BitConverter.GetBytes(Size), + BitConverter.GetBytes(EncodedTypePad), + ]; + for (int i = 0; i < Num_RandomTrafficColours; i++) + bytes.Add(BitConverter.GetBytes(RandomTrafficColours[i])); + for (int i = Num_RandomTrafficColours; i < Alloc; i++) + bytes.Add(BitConverter.GetBytes(0)); + bytes.Add(BitConverter.GetBytes(Alloc_Offences)); + bytes.Add(BitConverter.GetBytes(Num_Offences)); + bytes.Add(BitConverter.GetBytes(Size_Offences)); + bytes.Add(BitConverter.GetBytes(EncodedTypePad_Offences)); + Console.Write("Length:" + bytes.SelectMany(i => i).Count()); + // 28 bytes but not padding... + return bytes.SelectMany(i => i).Count(); + } - public AttributeHeader getHeader() - { - return header; - } + public AttributeHeader getHeader() + { + return header; + } - public SizeAndPositionInformation getInfo() - { - return info; - } + public SizeAndPositionInformation getInfo() + { + return info; + } - public void Read(ILoader loader, BinaryReader2 br) - { - PlayerPalletteIndex = br.ReadInt32(); - PlayerColourIndex = br.ReadInt32(); - Alloc = br.ReadInt16(); - Num_RandomTrafficColours = br.ReadInt16(); - Size = br.ReadInt16(); - EncodedTypePad = br.ReadInt16(); - for (int i = 0; i < Num_RandomTrafficColours; i++) - RandomTrafficColours.Add(br.ReadInt32()); - for (int i = Num_RandomTrafficColours; i < Alloc; i++) - br.SkipUniquePadding(4); - Alloc_Offences = br.ReadInt16(); - Num_Offences = br.ReadInt16(); - Size_Offences = br.ReadInt16(); - EncodedTypePad_Offences = br.ReadInt16(); - } + public void Read(ILoader loader, BinaryReader2 br) + { + PlayerPalletteIndex = br.ReadInt32(); + PlayerColourIndex = br.ReadInt32(); + Alloc = br.ReadInt16(); + Num_RandomTrafficColours = br.ReadInt16(); + Size = br.ReadInt16(); + EncodedTypePad = br.ReadInt16(); + for (int i = 0; i < Num_RandomTrafficColours; i++) + RandomTrafficColours.Add(br.ReadInt32()); + for (int i = Num_RandomTrafficColours; i < Alloc; i++) + br.SkipUniquePadding(4); + Alloc_Offences = br.ReadInt16(); + Num_Offences = br.ReadInt16(); + Size_Offences = br.ReadInt16(); + EncodedTypePad_Offences = br.ReadInt16(); + } - public void Write(BinaryWriter2 bw) - { - bw.Write(PlayerPalletteIndex); - bw.Write(PlayerColourIndex); - // Allocate space for x* Size. Always 1 in VEH_P* - if (Alloc < Num_RandomTrafficColours) - bw.Write(Num_RandomTrafficColours); - else - bw.Write(Alloc); - bw.Write(Num_RandomTrafficColours); // Count - bw.Write(Size); // Size of each entry - bw.Write(EncodedTypePad); // Padding - for (int i = 0; i < Num_RandomTrafficColours; i++) - bw.Write(RandomTrafficColours[i]); - for (int i = Num_RandomTrafficColours; i < Alloc; i++) - bw.Write(0); - bw.Write(Alloc_Offences); // Allocate space for x* Size - bw.Write(Num_Offences); // Count - bw.Write(Size_Offences); // Size of each entry - bw.Write(EncodedTypePad_Offences); // Padding - } + public void Write(BinaryWriter2 bw) + { + bw.Write(PlayerPalletteIndex); + bw.Write(PlayerColourIndex); + // Allocate space for x* Size. Always 1 in VEH_P* + if (Alloc < Num_RandomTrafficColours) + bw.Write(Num_RandomTrafficColours); + else + bw.Write(Alloc); + bw.Write(Num_RandomTrafficColours); // Count + bw.Write(Size); // Size of each entry + bw.Write(EncodedTypePad); // Padding + for (int i = 0; i < Num_RandomTrafficColours; i++) + bw.Write(RandomTrafficColours[i]); + for (int i = Num_RandomTrafficColours; i < Alloc; i++) + bw.Write(0); + bw.Write(Alloc_Offences); // Allocate space for x* Size + bw.Write(Num_Offences); // Count + bw.Write(Size_Offences); // Size of each entry + bw.Write(EncodedTypePad_Offences); // Padding } } diff --git a/VaultFormat/Camerabumperbehaviour.cs b/VaultFormat/Camerabumperbehaviour.cs index 94ca85c..35624f5 100644 --- a/VaultFormat/Camerabumperbehaviour.cs +++ b/VaultFormat/Camerabumperbehaviour.cs @@ -1,91 +1,89 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using BundleUtilities; -namespace VaultFormat +namespace VaultFormat; + +public class Camerabumperbehaviour : IAttribute { - public class Camerabumperbehaviour : IAttribute - { - public AttributeHeader header { get; set; } - public SizeAndPositionInformation info { get; set; } + public AttributeHeader header { get; set; } + public SizeAndPositionInformation info { get; set; } - public float ZOffset { get; set; } - public float YOffset { get; set; } - public float YawSpring { get; set; } - public float RollSpring { get; set; } - public float PitchSpring { get; set; } - public float FieldOfView { get; set; } - public float BoostFieldOfView { get; set; } - public float BodyRollScale { get; set; } - public float BodyPitchScale { get; set; } - public float AccelerationResponse { get; set; } - public float AccelerationDampening { get; set; } - public Camerabumperbehaviour(SizeAndPositionInformation chunk, AttributeHeader dataChunk) - { - header = dataChunk; - info = chunk; - } + public float ZOffset { get; set; } + public float YOffset { get; set; } + public float YawSpring { get; set; } + public float RollSpring { get; set; } + public float PitchSpring { get; set; } + public float FieldOfView { get; set; } + public float BoostFieldOfView { get; set; } + public float BodyRollScale { get; set; } + public float BodyPitchScale { get; set; } + public float AccelerationResponse { get; set; } + public float AccelerationDampening { get; set; } + public Camerabumperbehaviour(SizeAndPositionInformation chunk, AttributeHeader dataChunk) + { + header = dataChunk; + info = chunk; + } - public int getDataSize() - { - List bytes = new List - { - BitConverter.GetBytes(ZOffset), - BitConverter.GetBytes(YOffset), - BitConverter.GetBytes(YawSpring), - BitConverter.GetBytes(RollSpring), - BitConverter.GetBytes(PitchSpring), - BitConverter.GetBytes(FieldOfView), - BitConverter.GetBytes(BoostFieldOfView), - BitConverter.GetBytes(BodyRollScale), - BitConverter.GetBytes(BodyPitchScale), - BitConverter.GetBytes(AccelerationResponse), - BitConverter.GetBytes(AccelerationDampening) - }; - //To-Do: again here we have not padding, but usually we should have it - return bytes.SelectMany(i => i).Count(); - } + public int getDataSize() + { + List bytes = + [ + BitConverter.GetBytes(ZOffset), + BitConverter.GetBytes(YOffset), + BitConverter.GetBytes(YawSpring), + BitConverter.GetBytes(RollSpring), + BitConverter.GetBytes(PitchSpring), + BitConverter.GetBytes(FieldOfView), + BitConverter.GetBytes(BoostFieldOfView), + BitConverter.GetBytes(BodyRollScale), + BitConverter.GetBytes(BodyPitchScale), + BitConverter.GetBytes(AccelerationResponse), + BitConverter.GetBytes(AccelerationDampening) + ]; + //To-Do: again here we have not padding, but usually we should have it + return bytes.SelectMany(i => i).Count(); + } - public AttributeHeader getHeader() - { - return header; - } + public AttributeHeader getHeader() + { + return header; + } - public SizeAndPositionInformation getInfo() - { - return info; - } + public SizeAndPositionInformation getInfo() + { + return info; + } - public void Read(ILoader loader, BinaryReader2 br) - { - ZOffset = br.ReadSingle(); - YOffset = br.ReadSingle(); - YawSpring = br.ReadSingle(); - RollSpring = br.ReadSingle(); - PitchSpring = br.ReadSingle(); - FieldOfView = br.ReadSingle(); - BoostFieldOfView = br.ReadSingle(); - BodyRollScale = br.ReadSingle(); - BodyPitchScale = br.ReadSingle(); - AccelerationResponse = br.ReadSingle(); - AccelerationDampening = br.ReadSingle(); - } + public void Read(ILoader loader, BinaryReader2 br) + { + ZOffset = br.ReadSingle(); + YOffset = br.ReadSingle(); + YawSpring = br.ReadSingle(); + RollSpring = br.ReadSingle(); + PitchSpring = br.ReadSingle(); + FieldOfView = br.ReadSingle(); + BoostFieldOfView = br.ReadSingle(); + BodyRollScale = br.ReadSingle(); + BodyPitchScale = br.ReadSingle(); + AccelerationResponse = br.ReadSingle(); + AccelerationDampening = br.ReadSingle(); + } - public void Write(BinaryWriter2 bw) - { - bw.Write(ZOffset); - bw.Write(YOffset); - bw.Write(YawSpring); - bw.Write(RollSpring); - bw.Write(PitchSpring); - bw.Write(FieldOfView); - bw.Write(BoostFieldOfView); - bw.Write(BodyRollScale); - bw.Write(BodyPitchScale); - bw.Write(AccelerationResponse); - bw.Write(AccelerationDampening); - } + public void Write(BinaryWriter2 bw) + { + bw.Write(ZOffset); + bw.Write(YOffset); + bw.Write(YawSpring); + bw.Write(RollSpring); + bw.Write(PitchSpring); + bw.Write(FieldOfView); + bw.Write(BoostFieldOfView); + bw.Write(BodyRollScale); + bw.Write(BodyPitchScale); + bw.Write(AccelerationResponse); + bw.Write(AccelerationDampening); } } diff --git a/VaultFormat/Cameraexternalbehaviour.cs b/VaultFormat/Cameraexternalbehaviour.cs index 9ae68e9..715e060 100644 --- a/VaultFormat/Cameraexternalbehaviour.cs +++ b/VaultFormat/Cameraexternalbehaviour.cs @@ -1,113 +1,111 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using BundleUtilities; -namespace VaultFormat +namespace VaultFormat; + +public class Cameraexternalbehaviour : IAttribute { - public class Cameraexternalbehaviour : IAttribute + public AttributeHeader header { get; set; } + public SizeAndPositionInformation info { get; set; } + public float ZDistanceScale { get; set; } + public float ZAndTiltCutoffSpeedMPH { get; set; } + public float YawSpring { get; set; } + public float TiltCameraScale { get; set; } + public float TiltAroundCar { get; set; } + public float SlideZOffsetMax { get; set; } + public float SlideYScale { get; set; } + public float SlideXScale { get; set; } + public float PivotZOffset { get; set; } + public float PivotLength { get; set; } + public float PivotHeight { get; set; } + public float PitchSpring { get; set; } + public float FieldOfView { get; set; } + public float DriftYawSpring { get; set; } + public float DownAngle { get; set; } + public float BoostFieldOfViewZoom { get; set; } + public float BoostFieldOfView { get; set; } + public Cameraexternalbehaviour(SizeAndPositionInformation chunk, AttributeHeader dataChunk) { - public AttributeHeader header { get; set; } - public SizeAndPositionInformation info { get; set; } - public float ZDistanceScale { get; set; } - public float ZAndTiltCutoffSpeedMPH { get; set; } - public float YawSpring { get; set; } - public float TiltCameraScale { get; set; } - public float TiltAroundCar { get; set; } - public float SlideZOffsetMax { get; set; } - public float SlideYScale { get; set; } - public float SlideXScale { get; set; } - public float PivotZOffset { get; set; } - public float PivotLength { get; set; } - public float PivotHeight { get; set; } - public float PitchSpring { get; set; } - public float FieldOfView { get; set; } - public float DriftYawSpring { get; set; } - public float DownAngle { get; set; } - public float BoostFieldOfViewZoom { get; set; } - public float BoostFieldOfView { get; set; } - public Cameraexternalbehaviour(SizeAndPositionInformation chunk, AttributeHeader dataChunk) - { - header = dataChunk; - info = chunk; - } + header = dataChunk; + info = chunk; + } - public int getDataSize() - { - List bytes = new List - { - BitConverter.GetBytes(ZDistanceScale), - BitConverter.GetBytes(ZAndTiltCutoffSpeedMPH), - BitConverter.GetBytes(YawSpring), - BitConverter.GetBytes(TiltCameraScale), - BitConverter.GetBytes(TiltAroundCar), - BitConverter.GetBytes(SlideZOffsetMax), - BitConverter.GetBytes(SlideYScale), - BitConverter.GetBytes(SlideXScale), - BitConverter.GetBytes(PivotZOffset), - BitConverter.GetBytes(PivotLength), - BitConverter.GetBytes(PivotHeight), - BitConverter.GetBytes(PitchSpring), - BitConverter.GetBytes(FieldOfView), - BitConverter.GetBytes(DriftYawSpring), - BitConverter.GetBytes(DownAngle), - BitConverter.GetBytes(BoostFieldOfViewZoom), - BitConverter.GetBytes(BoostFieldOfView) - }; - return bytes.SelectMany(i => i).Count(); - } + public int getDataSize() + { + List bytes = + [ + BitConverter.GetBytes(ZDistanceScale), + BitConverter.GetBytes(ZAndTiltCutoffSpeedMPH), + BitConverter.GetBytes(YawSpring), + BitConverter.GetBytes(TiltCameraScale), + BitConverter.GetBytes(TiltAroundCar), + BitConverter.GetBytes(SlideZOffsetMax), + BitConverter.GetBytes(SlideYScale), + BitConverter.GetBytes(SlideXScale), + BitConverter.GetBytes(PivotZOffset), + BitConverter.GetBytes(PivotLength), + BitConverter.GetBytes(PivotHeight), + BitConverter.GetBytes(PitchSpring), + BitConverter.GetBytes(FieldOfView), + BitConverter.GetBytes(DriftYawSpring), + BitConverter.GetBytes(DownAngle), + BitConverter.GetBytes(BoostFieldOfViewZoom), + BitConverter.GetBytes(BoostFieldOfView) + ]; + return bytes.SelectMany(i => i).Count(); + } - public AttributeHeader getHeader() - { - return header; - } + public AttributeHeader getHeader() + { + return header; + } - public SizeAndPositionInformation getInfo() - { - return info; - } + public SizeAndPositionInformation getInfo() + { + return info; + } - public void Read(ILoader loader, BinaryReader2 br) - { - ZDistanceScale = br.ReadSingle(); - ZAndTiltCutoffSpeedMPH = br.ReadSingle(); - YawSpring = br.ReadSingle(); - TiltCameraScale = br.ReadSingle(); - TiltAroundCar = br.ReadSingle(); - SlideZOffsetMax = br.ReadSingle(); - SlideYScale = br.ReadSingle(); - SlideXScale = br.ReadSingle(); - PivotZOffset = br.ReadSingle(); - PivotLength = br.ReadSingle(); - PivotHeight = br.ReadSingle(); - PitchSpring = br.ReadSingle(); - FieldOfView = br.ReadSingle(); - DriftYawSpring = br.ReadSingle(); - DownAngle = br.ReadSingle(); - BoostFieldOfViewZoom = br.ReadSingle(); - BoostFieldOfView = br.ReadSingle(); - } + public void Read(ILoader loader, BinaryReader2 br) + { + ZDistanceScale = br.ReadSingle(); + ZAndTiltCutoffSpeedMPH = br.ReadSingle(); + YawSpring = br.ReadSingle(); + TiltCameraScale = br.ReadSingle(); + TiltAroundCar = br.ReadSingle(); + SlideZOffsetMax = br.ReadSingle(); + SlideYScale = br.ReadSingle(); + SlideXScale = br.ReadSingle(); + PivotZOffset = br.ReadSingle(); + PivotLength = br.ReadSingle(); + PivotHeight = br.ReadSingle(); + PitchSpring = br.ReadSingle(); + FieldOfView = br.ReadSingle(); + DriftYawSpring = br.ReadSingle(); + DownAngle = br.ReadSingle(); + BoostFieldOfViewZoom = br.ReadSingle(); + BoostFieldOfView = br.ReadSingle(); + } - public void Write(BinaryWriter2 bw) - { - bw.Write(ZDistanceScale); - bw.Write(ZAndTiltCutoffSpeedMPH); - bw.Write(YawSpring); - bw.Write(TiltCameraScale); - bw.Write(TiltAroundCar); - bw.Write(SlideZOffsetMax); - bw.Write(SlideYScale); - bw.Write(SlideXScale); - bw.Write(PivotZOffset); - bw.Write(PivotLength); - bw.Write(PivotHeight); - bw.Write(PitchSpring); - bw.Write(FieldOfView); - bw.Write(DriftYawSpring); - bw.Write(DownAngle); - bw.Write(BoostFieldOfViewZoom); - bw.Write(BoostFieldOfView); - } + public void Write(BinaryWriter2 bw) + { + bw.Write(ZDistanceScale); + bw.Write(ZAndTiltCutoffSpeedMPH); + bw.Write(YawSpring); + bw.Write(TiltCameraScale); + bw.Write(TiltAroundCar); + bw.Write(SlideZOffsetMax); + bw.Write(SlideYScale); + bw.Write(SlideXScale); + bw.Write(PivotZOffset); + bw.Write(PivotLength); + bw.Write(PivotHeight); + bw.Write(PitchSpring); + bw.Write(FieldOfView); + bw.Write(DriftYawSpring); + bw.Write(DownAngle); + bw.Write(BoostFieldOfViewZoom); + bw.Write(BoostFieldOfView); } } diff --git a/VaultFormat/IAttribute.cs b/VaultFormat/IAttribute.cs index be30ee9..f60acd7 100644 --- a/VaultFormat/IAttribute.cs +++ b/VaultFormat/IAttribute.cs @@ -1,18 +1,16 @@ -using System.IO; using BundleUtilities; -namespace VaultFormat +namespace VaultFormat; + +public interface IAttribute { - public interface IAttribute - { - AttributeHeader getHeader(); + AttributeHeader getHeader(); - SizeAndPositionInformation getInfo(); + SizeAndPositionInformation getInfo(); - int getDataSize(); + int getDataSize(); - void Read(ILoader loader, BinaryReader2 br); + void Read(ILoader loader, BinaryReader2 br); - void Write(BinaryWriter2 bw); - } + void Write(BinaryWriter2 bw); } diff --git a/VaultFormat/Physicsvehiclebaseattribs.cs b/VaultFormat/Physicsvehiclebaseattribs.cs index 255af5d..9eda970 100644 --- a/VaultFormat/Physicsvehiclebaseattribs.cs +++ b/VaultFormat/Physicsvehiclebaseattribs.cs @@ -1,314 +1,312 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Numerics; using BundleFormat; using BundleUtilities; -namespace VaultFormat +namespace VaultFormat; + +public class Physicsvehiclebaseattribs : IAttribute { - public class Physicsvehiclebaseattribs : IAttribute - { - public Vector4 RearRightWheelPosition { get; set; } - public Vector4 FrontRightWheelPosition { get; set; } - public Vector4 CoMOffset { get; set; } - public Vector4 BrakeScaleToFactor { get; set; } - public float YawDampingOnTakeOff { get; set; } - public float TractionLineLength { get; set; } - public float TimeForFullBrake { get; set; } - public float SurfaceRoughnessFactor { get; set; } - public float SurfaceRearGripFactor { get; set; } - public float SurfaceFrontGripFactor { get; set; } - public float SurfaceDragFactor { get; set; } - public float RollLimitOnTakeOff { get; set; } - public float RollDampingOnTakeOff { get; set; } - public float RearWheelMass { get; set; } - public float RearTireStaticFrictionCoefficient { get; set; } - public float RearTireLongForceBias { get; set; } - public float RearTireDynamicFrictionCoefficient { get; set; } - public float RearTireAdhesiveLimit { get; set; } - public float RearLongGripCurvePeakSlipRatio { get; set; } - public float RearLongGripCurvePeakCoefficient { get; set; } - public float RearLongGripCurveFloorSlipRatio { get; set; } - public float RearLongGripCurveFallCoefficient { get; set; } - public float RearLatGripCurvePeakSlipRatio { get; set; } - public float RearLatGripCurvePeakCoefficient { get; set; } - public float RearLatGripCurveFloorSlipRatio { get; set; } - public float RearLatGripCurveFallCoefficient { get; set; } - public float RearLatGripCurveDriftPeakSlipRatio { get; set; } - public float PowerToRear { get; set; } - public float PowerToFront { get; set; } - public float PitchDampingOnTakeOff { get; set; } - public float MaxSpeed { get; set; } - public float MagicBrakeFactorTurning { get; set; } + public Vector4 RearRightWheelPosition { get; set; } + public Vector4 FrontRightWheelPosition { get; set; } + public Vector4 CoMOffset { get; set; } + public Vector4 BrakeScaleToFactor { get; set; } + public float YawDampingOnTakeOff { get; set; } + public float TractionLineLength { get; set; } + public float TimeForFullBrake { get; set; } + public float SurfaceRoughnessFactor { get; set; } + public float SurfaceRearGripFactor { get; set; } + public float SurfaceFrontGripFactor { get; set; } + public float SurfaceDragFactor { get; set; } + public float RollLimitOnTakeOff { get; set; } + public float RollDampingOnTakeOff { get; set; } + public float RearWheelMass { get; set; } + public float RearTireStaticFrictionCoefficient { get; set; } + public float RearTireLongForceBias { get; set; } + public float RearTireDynamicFrictionCoefficient { get; set; } + public float RearTireAdhesiveLimit { get; set; } + public float RearLongGripCurvePeakSlipRatio { get; set; } + public float RearLongGripCurvePeakCoefficient { get; set; } + public float RearLongGripCurveFloorSlipRatio { get; set; } + public float RearLongGripCurveFallCoefficient { get; set; } + public float RearLatGripCurvePeakSlipRatio { get; set; } + public float RearLatGripCurvePeakCoefficient { get; set; } + public float RearLatGripCurveFloorSlipRatio { get; set; } + public float RearLatGripCurveFallCoefficient { get; set; } + public float RearLatGripCurveDriftPeakSlipRatio { get; set; } + public float PowerToRear { get; set; } + public float PowerToFront { get; set; } + public float PitchDampingOnTakeOff { get; set; } + public float MaxSpeed { get; set; } + public float MagicBrakeFactorTurning { get; set; } - public float MagicBrakeFactorStraightLine { get; set; } - public float LowSpeedTyreFrictionTractionControl { get; set; } - public float LowSpeedThrottleTractionControl { get; set; } - public float LowSpeedDrivingSpeed { get; set; } - public float LockBrakeScale { get; set; } - public float LinearDrag { get; set; } - public float HighSpeedAngularDamping { get; set; } - public float FrontWheelMass { get; set; } - public float FrontTireStaticFrictionCoefficient { get; set; } - public float FrontTireLongForceBias { get; set; } - public float FrontTireDynamicFrictionCoefficient { get; set; } - public float FrontTireAdhesiveLimit { get; set; } - public float FrontLongGripCurvePeakSlipRatio { get; set; } - public float FrontLongGripCurvePeakCoefficient { get; set; } - public float FrontLongGripCurveFloorSlipRatio { get; set; } - public float FrontLongGripCurveFallCoefficient { get; set; } - public float FrontLatGripCurvePeakSlipRatio { get; set; } - public float FrontLatGripCurvePeakCoefficient { get; set; } - public float FrontLatGripCurveFloorSlipRatio { get; set; } - public float FrontLatGripCurveFallCoefficient { get; set; } - public float FrontLatGripCurveDriftPeakSlipRatio { get; set; } - public float DrivingMass { get; set; } - public float DriveTimeDeformLimitX { get; set; } - public float DriveTimeDeformLimitPosZ { get; set; } - public float DriveTimeDeformLimitNegZ { get; set; } - public float DriveTimeDeformLimitNegY { get; set; } - public float DownForceZOffset { get; set; } - public float DownForce { get; set; } - public float CrashExtraYawVelocityFactor { get; set; } - public float CrashExtraRollVelocityFactor { get; set; } - public float CrashExtraPitchVelocityFactor { get; set; } - public float CrashExtraLinearVelocityFactor { get; set; } - public float AngularDrag { get; set; } - public int PaddingLength { get; set; } - public AttributeHeader header { get; set; } - public SizeAndPositionInformation info { get; set; } - public Physicsvehiclebaseattribs(SizeAndPositionInformation chunk, AttributeHeader dataChunk) - { - header = dataChunk; - info = chunk; - } + public float MagicBrakeFactorStraightLine { get; set; } + public float LowSpeedTyreFrictionTractionControl { get; set; } + public float LowSpeedThrottleTractionControl { get; set; } + public float LowSpeedDrivingSpeed { get; set; } + public float LockBrakeScale { get; set; } + public float LinearDrag { get; set; } + public float HighSpeedAngularDamping { get; set; } + public float FrontWheelMass { get; set; } + public float FrontTireStaticFrictionCoefficient { get; set; } + public float FrontTireLongForceBias { get; set; } + public float FrontTireDynamicFrictionCoefficient { get; set; } + public float FrontTireAdhesiveLimit { get; set; } + public float FrontLongGripCurvePeakSlipRatio { get; set; } + public float FrontLongGripCurvePeakCoefficient { get; set; } + public float FrontLongGripCurveFloorSlipRatio { get; set; } + public float FrontLongGripCurveFallCoefficient { get; set; } + public float FrontLatGripCurvePeakSlipRatio { get; set; } + public float FrontLatGripCurvePeakCoefficient { get; set; } + public float FrontLatGripCurveFloorSlipRatio { get; set; } + public float FrontLatGripCurveFallCoefficient { get; set; } + public float FrontLatGripCurveDriftPeakSlipRatio { get; set; } + public float DrivingMass { get; set; } + public float DriveTimeDeformLimitX { get; set; } + public float DriveTimeDeformLimitPosZ { get; set; } + public float DriveTimeDeformLimitNegZ { get; set; } + public float DriveTimeDeformLimitNegY { get; set; } + public float DownForceZOffset { get; set; } + public float DownForce { get; set; } + public float CrashExtraYawVelocityFactor { get; set; } + public float CrashExtraRollVelocityFactor { get; set; } + public float CrashExtraPitchVelocityFactor { get; set; } + public float CrashExtraLinearVelocityFactor { get; set; } + public float AngularDrag { get; set; } + public int PaddingLength { get; set; } + public AttributeHeader header { get; set; } + public SizeAndPositionInformation info { get; set; } + public Physicsvehiclebaseattribs(SizeAndPositionInformation chunk, AttributeHeader dataChunk) + { + header = dataChunk; + info = chunk; + } - public int getDataSize() - { - List bytes = new List - { - RearRightWheelPosition.toBytes(), - FrontRightWheelPosition.toBytes(), - CoMOffset.toBytes(), - BrakeScaleToFactor.toBytes(), - BitConverter.GetBytes(YawDampingOnTakeOff), - BitConverter.GetBytes(TractionLineLength), - BitConverter.GetBytes(TimeForFullBrake), - BitConverter.GetBytes(SurfaceRoughnessFactor), - BitConverter.GetBytes(SurfaceRearGripFactor), - BitConverter.GetBytes(SurfaceFrontGripFactor), - BitConverter.GetBytes(SurfaceDragFactor), - BitConverter.GetBytes(RollLimitOnTakeOff), - BitConverter.GetBytes(RollDampingOnTakeOff), - BitConverter.GetBytes(RearWheelMass), - BitConverter.GetBytes(RearTireStaticFrictionCoefficient), - BitConverter.GetBytes(RearTireLongForceBias), - BitConverter.GetBytes(RearTireDynamicFrictionCoefficient), - BitConverter.GetBytes(RearTireAdhesiveLimit), - BitConverter.GetBytes(RearLongGripCurvePeakSlipRatio), - BitConverter.GetBytes(RearLongGripCurvePeakCoefficient), - BitConverter.GetBytes(RearLongGripCurveFloorSlipRatio), - BitConverter.GetBytes(RearLongGripCurveFallCoefficient), - BitConverter.GetBytes(RearLatGripCurvePeakSlipRatio), - BitConverter.GetBytes(RearLatGripCurvePeakCoefficient), - BitConverter.GetBytes(RearLatGripCurveFloorSlipRatio), - BitConverter.GetBytes(RearLatGripCurveFallCoefficient), - BitConverter.GetBytes(RearLatGripCurveDriftPeakSlipRatio), - BitConverter.GetBytes(PowerToRear), - BitConverter.GetBytes(PowerToFront), - BitConverter.GetBytes(PitchDampingOnTakeOff), - BitConverter.GetBytes(MaxSpeed), - BitConverter.GetBytes(MagicBrakeFactorTurning), - BitConverter.GetBytes(MagicBrakeFactorStraightLine), - BitConverter.GetBytes(LowSpeedTyreFrictionTractionControl), - BitConverter.GetBytes(LowSpeedThrottleTractionControl), - BitConverter.GetBytes(LowSpeedDrivingSpeed), - BitConverter.GetBytes(LockBrakeScale), - BitConverter.GetBytes(LinearDrag), - BitConverter.GetBytes(HighSpeedAngularDamping), - BitConverter.GetBytes(FrontWheelMass), - BitConverter.GetBytes(FrontTireStaticFrictionCoefficient), - BitConverter.GetBytes(FrontTireLongForceBias), - BitConverter.GetBytes(FrontTireDynamicFrictionCoefficient), - BitConverter.GetBytes(FrontTireAdhesiveLimit), - BitConverter.GetBytes(FrontLongGripCurvePeakSlipRatio), - BitConverter.GetBytes(FrontLongGripCurvePeakCoefficient), - BitConverter.GetBytes(FrontLongGripCurveFloorSlipRatio), - BitConverter.GetBytes(FrontLongGripCurveFallCoefficient), - BitConverter.GetBytes(FrontLatGripCurvePeakSlipRatio), - BitConverter.GetBytes(FrontLatGripCurvePeakCoefficient), - BitConverter.GetBytes(FrontLatGripCurveFloorSlipRatio), - BitConverter.GetBytes(FrontLatGripCurveFallCoefficient), - BitConverter.GetBytes(FrontLatGripCurveDriftPeakSlipRatio), - BitConverter.GetBytes(DrivingMass), - BitConverter.GetBytes(DriveTimeDeformLimitX), - BitConverter.GetBytes(DriveTimeDeformLimitPosZ), - BitConverter.GetBytes(DriveTimeDeformLimitNegZ), - BitConverter.GetBytes(DriveTimeDeformLimitNegY), - BitConverter.GetBytes(DownForceZOffset), - BitConverter.GetBytes(DownForce), - BitConverter.GetBytes(CrashExtraYawVelocityFactor), - BitConverter.GetBytes(CrashExtraRollVelocityFactor), - BitConverter.GetBytes(CrashExtraPitchVelocityFactor), - BitConverter.GetBytes(CrashExtraLinearVelocityFactor), - BitConverter.GetBytes(AngularDrag) - }; - // No padding needed - return bytes.SelectMany(i => i).Count() + PaddingLength; - } + public int getDataSize() + { + List bytes = + [ + RearRightWheelPosition.toBytes(), + FrontRightWheelPosition.toBytes(), + CoMOffset.toBytes(), + BrakeScaleToFactor.toBytes(), + BitConverter.GetBytes(YawDampingOnTakeOff), + BitConverter.GetBytes(TractionLineLength), + BitConverter.GetBytes(TimeForFullBrake), + BitConverter.GetBytes(SurfaceRoughnessFactor), + BitConverter.GetBytes(SurfaceRearGripFactor), + BitConverter.GetBytes(SurfaceFrontGripFactor), + BitConverter.GetBytes(SurfaceDragFactor), + BitConverter.GetBytes(RollLimitOnTakeOff), + BitConverter.GetBytes(RollDampingOnTakeOff), + BitConverter.GetBytes(RearWheelMass), + BitConverter.GetBytes(RearTireStaticFrictionCoefficient), + BitConverter.GetBytes(RearTireLongForceBias), + BitConverter.GetBytes(RearTireDynamicFrictionCoefficient), + BitConverter.GetBytes(RearTireAdhesiveLimit), + BitConverter.GetBytes(RearLongGripCurvePeakSlipRatio), + BitConverter.GetBytes(RearLongGripCurvePeakCoefficient), + BitConverter.GetBytes(RearLongGripCurveFloorSlipRatio), + BitConverter.GetBytes(RearLongGripCurveFallCoefficient), + BitConverter.GetBytes(RearLatGripCurvePeakSlipRatio), + BitConverter.GetBytes(RearLatGripCurvePeakCoefficient), + BitConverter.GetBytes(RearLatGripCurveFloorSlipRatio), + BitConverter.GetBytes(RearLatGripCurveFallCoefficient), + BitConverter.GetBytes(RearLatGripCurveDriftPeakSlipRatio), + BitConverter.GetBytes(PowerToRear), + BitConverter.GetBytes(PowerToFront), + BitConverter.GetBytes(PitchDampingOnTakeOff), + BitConverter.GetBytes(MaxSpeed), + BitConverter.GetBytes(MagicBrakeFactorTurning), + BitConverter.GetBytes(MagicBrakeFactorStraightLine), + BitConverter.GetBytes(LowSpeedTyreFrictionTractionControl), + BitConverter.GetBytes(LowSpeedThrottleTractionControl), + BitConverter.GetBytes(LowSpeedDrivingSpeed), + BitConverter.GetBytes(LockBrakeScale), + BitConverter.GetBytes(LinearDrag), + BitConverter.GetBytes(HighSpeedAngularDamping), + BitConverter.GetBytes(FrontWheelMass), + BitConverter.GetBytes(FrontTireStaticFrictionCoefficient), + BitConverter.GetBytes(FrontTireLongForceBias), + BitConverter.GetBytes(FrontTireDynamicFrictionCoefficient), + BitConverter.GetBytes(FrontTireAdhesiveLimit), + BitConverter.GetBytes(FrontLongGripCurvePeakSlipRatio), + BitConverter.GetBytes(FrontLongGripCurvePeakCoefficient), + BitConverter.GetBytes(FrontLongGripCurveFloorSlipRatio), + BitConverter.GetBytes(FrontLongGripCurveFallCoefficient), + BitConverter.GetBytes(FrontLatGripCurvePeakSlipRatio), + BitConverter.GetBytes(FrontLatGripCurvePeakCoefficient), + BitConverter.GetBytes(FrontLatGripCurveFloorSlipRatio), + BitConverter.GetBytes(FrontLatGripCurveFallCoefficient), + BitConverter.GetBytes(FrontLatGripCurveDriftPeakSlipRatio), + BitConverter.GetBytes(DrivingMass), + BitConverter.GetBytes(DriveTimeDeformLimitX), + BitConverter.GetBytes(DriveTimeDeformLimitPosZ), + BitConverter.GetBytes(DriveTimeDeformLimitNegZ), + BitConverter.GetBytes(DriveTimeDeformLimitNegY), + BitConverter.GetBytes(DownForceZOffset), + BitConverter.GetBytes(DownForce), + BitConverter.GetBytes(CrashExtraYawVelocityFactor), + BitConverter.GetBytes(CrashExtraRollVelocityFactor), + BitConverter.GetBytes(CrashExtraPitchVelocityFactor), + BitConverter.GetBytes(CrashExtraLinearVelocityFactor), + BitConverter.GetBytes(AngularDrag) + ]; + // No padding needed + return bytes.SelectMany(i => i).Count() + PaddingLength; + } - public AttributeHeader getHeader() - { - return header; - } + public AttributeHeader getHeader() + { + return header; + } - public SizeAndPositionInformation getInfo() - { - return info; - } + public SizeAndPositionInformation getInfo() + { + return info; + } - public void Read(ILoader loader, BinaryReader2 br) - { - int pos = (int)br.BaseStream.Position; - br.Align(0x10); - PaddingLength = (int)br.BaseStream.Position - pos; - RearRightWheelPosition = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); - FrontRightWheelPosition = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); - CoMOffset = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); - BrakeScaleToFactor = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); - YawDampingOnTakeOff = br.ReadSingle(); - TractionLineLength = br.ReadSingle(); - TimeForFullBrake = br.ReadSingle(); - SurfaceRoughnessFactor = br.ReadSingle(); - SurfaceRearGripFactor = br.ReadSingle(); - SurfaceFrontGripFactor = br.ReadSingle(); - SurfaceDragFactor = br.ReadSingle(); - RollLimitOnTakeOff = br.ReadSingle(); - RollDampingOnTakeOff = br.ReadSingle(); - RearWheelMass = br.ReadSingle(); - RearTireStaticFrictionCoefficient = br.ReadSingle(); - RearTireLongForceBias = br.ReadSingle(); - RearTireDynamicFrictionCoefficient = br.ReadSingle(); - RearTireAdhesiveLimit = br.ReadSingle(); - RearLongGripCurvePeakSlipRatio = br.ReadSingle(); - RearLongGripCurvePeakCoefficient = br.ReadSingle(); - RearLongGripCurveFloorSlipRatio = br.ReadSingle(); - RearLongGripCurveFallCoefficient = br.ReadSingle(); - RearLatGripCurvePeakSlipRatio = br.ReadSingle(); - RearLatGripCurvePeakCoefficient = br.ReadSingle(); - RearLatGripCurveFloorSlipRatio = br.ReadSingle(); - RearLatGripCurveFallCoefficient = br.ReadSingle(); - RearLatGripCurveDriftPeakSlipRatio = br.ReadSingle(); - PowerToRear = br.ReadSingle(); - PowerToFront = br.ReadSingle(); - PitchDampingOnTakeOff = br.ReadSingle(); - MaxSpeed = br.ReadSingle(); - MagicBrakeFactorTurning = br.ReadSingle(); - MagicBrakeFactorStraightLine = br.ReadSingle(); - LowSpeedTyreFrictionTractionControl = br.ReadSingle(); - LowSpeedThrottleTractionControl = br.ReadSingle(); - LowSpeedDrivingSpeed = br.ReadSingle(); - LockBrakeScale = br.ReadSingle(); - LinearDrag = br.ReadSingle(); - HighSpeedAngularDamping = br.ReadSingle(); - FrontWheelMass = br.ReadSingle(); - FrontTireStaticFrictionCoefficient = br.ReadSingle(); - FrontTireLongForceBias = br.ReadSingle(); - FrontTireDynamicFrictionCoefficient = br.ReadSingle(); - FrontTireAdhesiveLimit = br.ReadSingle(); - FrontLongGripCurvePeakSlipRatio = br.ReadSingle(); - FrontLongGripCurvePeakCoefficient = br.ReadSingle(); - FrontLongGripCurveFloorSlipRatio = br.ReadSingle(); - FrontLongGripCurveFallCoefficient = br.ReadSingle(); - FrontLatGripCurvePeakSlipRatio = br.ReadSingle(); - FrontLatGripCurvePeakCoefficient = br.ReadSingle(); - FrontLatGripCurveFloorSlipRatio = br.ReadSingle(); - FrontLatGripCurveFallCoefficient = br.ReadSingle(); - FrontLatGripCurveDriftPeakSlipRatio = br.ReadSingle(); - DrivingMass = br.ReadSingle(); - DriveTimeDeformLimitX = br.ReadSingle(); - DriveTimeDeformLimitPosZ = br.ReadSingle(); - DriveTimeDeformLimitNegZ = br.ReadSingle(); - DriveTimeDeformLimitNegY = br.ReadSingle(); - DownForceZOffset = br.ReadSingle(); - DownForce = br.ReadSingle(); - CrashExtraYawVelocityFactor = br.ReadSingle(); - CrashExtraRollVelocityFactor = br.ReadSingle(); - CrashExtraPitchVelocityFactor = br.ReadSingle(); - CrashExtraLinearVelocityFactor = br.ReadSingle(); - AngularDrag = br.ReadSingle(); - } + public void Read(ILoader loader, BinaryReader2 br) + { + int pos = (int)br.BaseStream.Position; + br.Align(0x10); + PaddingLength = (int)br.BaseStream.Position - pos; + RearRightWheelPosition = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); + FrontRightWheelPosition = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); + CoMOffset = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); + BrakeScaleToFactor = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); + YawDampingOnTakeOff = br.ReadSingle(); + TractionLineLength = br.ReadSingle(); + TimeForFullBrake = br.ReadSingle(); + SurfaceRoughnessFactor = br.ReadSingle(); + SurfaceRearGripFactor = br.ReadSingle(); + SurfaceFrontGripFactor = br.ReadSingle(); + SurfaceDragFactor = br.ReadSingle(); + RollLimitOnTakeOff = br.ReadSingle(); + RollDampingOnTakeOff = br.ReadSingle(); + RearWheelMass = br.ReadSingle(); + RearTireStaticFrictionCoefficient = br.ReadSingle(); + RearTireLongForceBias = br.ReadSingle(); + RearTireDynamicFrictionCoefficient = br.ReadSingle(); + RearTireAdhesiveLimit = br.ReadSingle(); + RearLongGripCurvePeakSlipRatio = br.ReadSingle(); + RearLongGripCurvePeakCoefficient = br.ReadSingle(); + RearLongGripCurveFloorSlipRatio = br.ReadSingle(); + RearLongGripCurveFallCoefficient = br.ReadSingle(); + RearLatGripCurvePeakSlipRatio = br.ReadSingle(); + RearLatGripCurvePeakCoefficient = br.ReadSingle(); + RearLatGripCurveFloorSlipRatio = br.ReadSingle(); + RearLatGripCurveFallCoefficient = br.ReadSingle(); + RearLatGripCurveDriftPeakSlipRatio = br.ReadSingle(); + PowerToRear = br.ReadSingle(); + PowerToFront = br.ReadSingle(); + PitchDampingOnTakeOff = br.ReadSingle(); + MaxSpeed = br.ReadSingle(); + MagicBrakeFactorTurning = br.ReadSingle(); + MagicBrakeFactorStraightLine = br.ReadSingle(); + LowSpeedTyreFrictionTractionControl = br.ReadSingle(); + LowSpeedThrottleTractionControl = br.ReadSingle(); + LowSpeedDrivingSpeed = br.ReadSingle(); + LockBrakeScale = br.ReadSingle(); + LinearDrag = br.ReadSingle(); + HighSpeedAngularDamping = br.ReadSingle(); + FrontWheelMass = br.ReadSingle(); + FrontTireStaticFrictionCoefficient = br.ReadSingle(); + FrontTireLongForceBias = br.ReadSingle(); + FrontTireDynamicFrictionCoefficient = br.ReadSingle(); + FrontTireAdhesiveLimit = br.ReadSingle(); + FrontLongGripCurvePeakSlipRatio = br.ReadSingle(); + FrontLongGripCurvePeakCoefficient = br.ReadSingle(); + FrontLongGripCurveFloorSlipRatio = br.ReadSingle(); + FrontLongGripCurveFallCoefficient = br.ReadSingle(); + FrontLatGripCurvePeakSlipRatio = br.ReadSingle(); + FrontLatGripCurvePeakCoefficient = br.ReadSingle(); + FrontLatGripCurveFloorSlipRatio = br.ReadSingle(); + FrontLatGripCurveFallCoefficient = br.ReadSingle(); + FrontLatGripCurveDriftPeakSlipRatio = br.ReadSingle(); + DrivingMass = br.ReadSingle(); + DriveTimeDeformLimitX = br.ReadSingle(); + DriveTimeDeformLimitPosZ = br.ReadSingle(); + DriveTimeDeformLimitNegZ = br.ReadSingle(); + DriveTimeDeformLimitNegY = br.ReadSingle(); + DownForceZOffset = br.ReadSingle(); + DownForce = br.ReadSingle(); + CrashExtraYawVelocityFactor = br.ReadSingle(); + CrashExtraRollVelocityFactor = br.ReadSingle(); + CrashExtraPitchVelocityFactor = br.ReadSingle(); + CrashExtraLinearVelocityFactor = br.ReadSingle(); + AngularDrag = br.ReadSingle(); + } - public void Write(BinaryWriter2 bw) - { - bw.Align(0x10); - bw.Write(RearRightWheelPosition.toBytes(bw.BigEndian)); - bw.Write(FrontRightWheelPosition.toBytes(bw.BigEndian)); - bw.Write(CoMOffset.toBytes(bw.BigEndian)); - bw.Write(BrakeScaleToFactor.toBytes(bw.BigEndian)); - bw.Write(YawDampingOnTakeOff); - bw.Write(TractionLineLength); - bw.Write(TimeForFullBrake); - bw.Write(SurfaceRoughnessFactor); - bw.Write(SurfaceRearGripFactor); - bw.Write(SurfaceFrontGripFactor); - bw.Write(SurfaceDragFactor); - bw.Write(RollLimitOnTakeOff); - bw.Write(RollDampingOnTakeOff); - bw.Write(RearWheelMass); - bw.Write(RearTireStaticFrictionCoefficient); - bw.Write(RearTireLongForceBias); - bw.Write(RearTireDynamicFrictionCoefficient); - bw.Write(RearTireAdhesiveLimit); - bw.Write(RearLongGripCurvePeakSlipRatio); - bw.Write(RearLongGripCurvePeakCoefficient); - bw.Write(RearLongGripCurveFloorSlipRatio); - bw.Write(RearLongGripCurveFallCoefficient); - bw.Write(RearLatGripCurvePeakSlipRatio); - bw.Write(RearLatGripCurvePeakCoefficient); - bw.Write(RearLatGripCurveFloorSlipRatio); - bw.Write(RearLatGripCurveFallCoefficient); - bw.Write(RearLatGripCurveDriftPeakSlipRatio); - bw.Write(PowerToRear); - bw.Write(PowerToFront); - bw.Write(PitchDampingOnTakeOff); - bw.Write(MaxSpeed); - bw.Write(MagicBrakeFactorTurning); - bw.Write(MagicBrakeFactorStraightLine); - bw.Write(LowSpeedTyreFrictionTractionControl); - bw.Write(LowSpeedThrottleTractionControl); - bw.Write(LowSpeedDrivingSpeed); - bw.Write(LockBrakeScale); - bw.Write(LinearDrag); - bw.Write(HighSpeedAngularDamping); - bw.Write(FrontWheelMass); - bw.Write(FrontTireStaticFrictionCoefficient); - bw.Write(FrontTireLongForceBias); - bw.Write(FrontTireDynamicFrictionCoefficient); - bw.Write(FrontTireAdhesiveLimit); - bw.Write(FrontLongGripCurvePeakSlipRatio); - bw.Write(FrontLongGripCurvePeakCoefficient); - bw.Write(FrontLongGripCurveFloorSlipRatio); - bw.Write(FrontLongGripCurveFallCoefficient); - bw.Write(FrontLatGripCurvePeakSlipRatio); - bw.Write(FrontLatGripCurvePeakCoefficient); - bw.Write(FrontLatGripCurveFloorSlipRatio); - bw.Write(FrontLatGripCurveFallCoefficient); - bw.Write(FrontLatGripCurveDriftPeakSlipRatio); - bw.Write(DrivingMass); - bw.Write(DriveTimeDeformLimitX); - bw.Write(DriveTimeDeformLimitPosZ); - bw.Write(DriveTimeDeformLimitNegZ); - bw.Write(DriveTimeDeformLimitNegY); - bw.Write(DownForceZOffset); - bw.Write(DownForce); - bw.Write(CrashExtraYawVelocityFactor); - bw.Write(CrashExtraRollVelocityFactor); - bw.Write(CrashExtraPitchVelocityFactor); - bw.Write(CrashExtraLinearVelocityFactor); - bw.Write(AngularDrag); - } + public void Write(BinaryWriter2 bw) + { + bw.Align(0x10); + bw.Write(RearRightWheelPosition.toBytes(bw.BigEndian)); + bw.Write(FrontRightWheelPosition.toBytes(bw.BigEndian)); + bw.Write(CoMOffset.toBytes(bw.BigEndian)); + bw.Write(BrakeScaleToFactor.toBytes(bw.BigEndian)); + bw.Write(YawDampingOnTakeOff); + bw.Write(TractionLineLength); + bw.Write(TimeForFullBrake); + bw.Write(SurfaceRoughnessFactor); + bw.Write(SurfaceRearGripFactor); + bw.Write(SurfaceFrontGripFactor); + bw.Write(SurfaceDragFactor); + bw.Write(RollLimitOnTakeOff); + bw.Write(RollDampingOnTakeOff); + bw.Write(RearWheelMass); + bw.Write(RearTireStaticFrictionCoefficient); + bw.Write(RearTireLongForceBias); + bw.Write(RearTireDynamicFrictionCoefficient); + bw.Write(RearTireAdhesiveLimit); + bw.Write(RearLongGripCurvePeakSlipRatio); + bw.Write(RearLongGripCurvePeakCoefficient); + bw.Write(RearLongGripCurveFloorSlipRatio); + bw.Write(RearLongGripCurveFallCoefficient); + bw.Write(RearLatGripCurvePeakSlipRatio); + bw.Write(RearLatGripCurvePeakCoefficient); + bw.Write(RearLatGripCurveFloorSlipRatio); + bw.Write(RearLatGripCurveFallCoefficient); + bw.Write(RearLatGripCurveDriftPeakSlipRatio); + bw.Write(PowerToRear); + bw.Write(PowerToFront); + bw.Write(PitchDampingOnTakeOff); + bw.Write(MaxSpeed); + bw.Write(MagicBrakeFactorTurning); + bw.Write(MagicBrakeFactorStraightLine); + bw.Write(LowSpeedTyreFrictionTractionControl); + bw.Write(LowSpeedThrottleTractionControl); + bw.Write(LowSpeedDrivingSpeed); + bw.Write(LockBrakeScale); + bw.Write(LinearDrag); + bw.Write(HighSpeedAngularDamping); + bw.Write(FrontWheelMass); + bw.Write(FrontTireStaticFrictionCoefficient); + bw.Write(FrontTireLongForceBias); + bw.Write(FrontTireDynamicFrictionCoefficient); + bw.Write(FrontTireAdhesiveLimit); + bw.Write(FrontLongGripCurvePeakSlipRatio); + bw.Write(FrontLongGripCurvePeakCoefficient); + bw.Write(FrontLongGripCurveFloorSlipRatio); + bw.Write(FrontLongGripCurveFallCoefficient); + bw.Write(FrontLatGripCurvePeakSlipRatio); + bw.Write(FrontLatGripCurvePeakCoefficient); + bw.Write(FrontLatGripCurveFloorSlipRatio); + bw.Write(FrontLatGripCurveFallCoefficient); + bw.Write(FrontLatGripCurveDriftPeakSlipRatio); + bw.Write(DrivingMass); + bw.Write(DriveTimeDeformLimitX); + bw.Write(DriveTimeDeformLimitPosZ); + bw.Write(DriveTimeDeformLimitNegZ); + bw.Write(DriveTimeDeformLimitNegY); + bw.Write(DownForceZOffset); + bw.Write(DownForce); + bw.Write(CrashExtraYawVelocityFactor); + bw.Write(CrashExtraRollVelocityFactor); + bw.Write(CrashExtraPitchVelocityFactor); + bw.Write(CrashExtraLinearVelocityFactor); + bw.Write(AngularDrag); } } diff --git a/VaultFormat/Physicsvehiclebodyrollattribs.cs b/VaultFormat/Physicsvehiclebodyrollattribs.cs index c08d377..407f918 100644 --- a/VaultFormat/Physicsvehiclebodyrollattribs.cs +++ b/VaultFormat/Physicsvehiclebodyrollattribs.cs @@ -1,90 +1,88 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using BundleUtilities; -namespace VaultFormat +namespace VaultFormat; + +public class Physicsvehiclebodyrollattribs : IAttribute { - public class Physicsvehiclebodyrollattribs : IAttribute - { - public AttributeHeader header { get; set; } - public SizeAndPositionInformation info { get; set; } + public AttributeHeader header { get; set; } + public SizeAndPositionInformation info { get; set; } - public float WheelLongForceHeightOffset { get; set; } - public float WheelLatForceHeightOffset { get; set; } - public float WeightTransferDecayZ { get; set; } - public float WeightTransferDecayX { get; set; } - public float RollSpringStiffness { get; set; } - public float RollSpringDampening { get; set; } - public float PitchSpringStiffness { get; set; } - public float PitchSpringDampening { get; set; } - public float FactorOfWeightZ { get; set; } - public float FactorOfWeightX { get; set; } - public Physicsvehiclebodyrollattribs(SizeAndPositionInformation chunk, AttributeHeader dataChunk) - { - header = dataChunk; - info = chunk; - } + public float WheelLongForceHeightOffset { get; set; } + public float WheelLatForceHeightOffset { get; set; } + public float WeightTransferDecayZ { get; set; } + public float WeightTransferDecayX { get; set; } + public float RollSpringStiffness { get; set; } + public float RollSpringDampening { get; set; } + public float PitchSpringStiffness { get; set; } + public float PitchSpringDampening { get; set; } + public float FactorOfWeightZ { get; set; } + public float FactorOfWeightX { get; set; } + public Physicsvehiclebodyrollattribs(SizeAndPositionInformation chunk, AttributeHeader dataChunk) + { + header = dataChunk; + info = chunk; + } - public int getDataSize() - { - List bytes = new List - { - BitConverter.GetBytes(WheelLongForceHeightOffset), - BitConverter.GetBytes(WheelLatForceHeightOffset), - BitConverter.GetBytes(WeightTransferDecayZ), - BitConverter.GetBytes(WeightTransferDecayX), - BitConverter.GetBytes(RollSpringStiffness), - BitConverter.GetBytes(RollSpringDampening), - BitConverter.GetBytes(PitchSpringStiffness), - BitConverter.GetBytes(PitchSpringDampening), - BitConverter.GetBytes(FactorOfWeightZ), - BitConverter.GetBytes(FactorOfWeightX), - //4 bytes padding is Wrong! - BitConverter.GetBytes((float)0) - }; - return bytes.SelectMany(i => i).Count(); - } + public int getDataSize() + { + List bytes = + [ + BitConverter.GetBytes(WheelLongForceHeightOffset), + BitConverter.GetBytes(WheelLatForceHeightOffset), + BitConverter.GetBytes(WeightTransferDecayZ), + BitConverter.GetBytes(WeightTransferDecayX), + BitConverter.GetBytes(RollSpringStiffness), + BitConverter.GetBytes(RollSpringDampening), + BitConverter.GetBytes(PitchSpringStiffness), + BitConverter.GetBytes(PitchSpringDampening), + BitConverter.GetBytes(FactorOfWeightZ), + BitConverter.GetBytes(FactorOfWeightX), + //4 bytes padding is Wrong! + BitConverter.GetBytes((float)0) + ]; + return bytes.SelectMany(i => i).Count(); + } - public AttributeHeader getHeader() - { - return header; - } + public AttributeHeader getHeader() + { + return header; + } - public SizeAndPositionInformation getInfo() - { - return info; - } + public SizeAndPositionInformation getInfo() + { + return info; + } - public void Read(ILoader loader, BinaryReader2 br) - { - WheelLongForceHeightOffset = br.ReadSingle(); - WheelLatForceHeightOffset = br.ReadSingle(); - WeightTransferDecayZ = br.ReadSingle(); - WeightTransferDecayX = br.ReadSingle(); - RollSpringStiffness = br.ReadSingle(); - RollSpringDampening = br.ReadSingle(); - PitchSpringStiffness = br.ReadSingle(); - PitchSpringDampening = br.ReadSingle(); - FactorOfWeightZ = br.ReadSingle(); - FactorOfWeightX = br.ReadSingle(); - br.SkipUniquePadding(4); - } + public void Read(ILoader loader, BinaryReader2 br) + { + WheelLongForceHeightOffset = br.ReadSingle(); + WheelLatForceHeightOffset = br.ReadSingle(); + WeightTransferDecayZ = br.ReadSingle(); + WeightTransferDecayX = br.ReadSingle(); + RollSpringStiffness = br.ReadSingle(); + RollSpringDampening = br.ReadSingle(); + PitchSpringStiffness = br.ReadSingle(); + PitchSpringDampening = br.ReadSingle(); + FactorOfWeightZ = br.ReadSingle(); + FactorOfWeightX = br.ReadSingle(); + br.SkipUniquePadding(4); + } - public void Write(BinaryWriter2 bw) - { - bw.Write(WheelLongForceHeightOffset); - bw.Write(WheelLatForceHeightOffset); - bw.Write(WeightTransferDecayZ); - bw.Write(WeightTransferDecayX); - bw.Write(RollSpringStiffness); - bw.Write(RollSpringDampening); - bw.Write(PitchSpringStiffness); - bw.Write(PitchSpringDampening); - bw.Write(FactorOfWeightZ); - bw.Write(FactorOfWeightX); - bw.WriteUniquePadding(4); - } + public void Write(BinaryWriter2 bw) + { + bw.Write(WheelLongForceHeightOffset); + bw.Write(WheelLatForceHeightOffset); + bw.Write(WeightTransferDecayZ); + bw.Write(WeightTransferDecayX); + bw.Write(RollSpringStiffness); + bw.Write(RollSpringDampening); + bw.Write(PitchSpringStiffness); + bw.Write(PitchSpringDampening); + bw.Write(FactorOfWeightZ); + bw.Write(FactorOfWeightX); + bw.WriteUniquePadding(4); } } diff --git a/VaultFormat/Physicsvehicleboostattribs.cs b/VaultFormat/Physicsvehicleboostattribs.cs index 314ba11..a4c1801 100644 --- a/VaultFormat/Physicsvehicleboostattribs.cs +++ b/VaultFormat/Physicsvehicleboostattribs.cs @@ -1,111 +1,109 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using BundleUtilities; -namespace VaultFormat +namespace VaultFormat; + +public class Physicsvehicleboostattribs : IAttribute { - public class Physicsvehicleboostattribs : IAttribute - { - public AttributeHeader header { get; set; } - public SizeAndPositionInformation info { get; set; } - public float MaxBoostSpeed { get; set; } - public int BoostRule { get; set; } - public float BoostKickTime { get; set; } - public float BoostKickMinTime { get; set; } - public float BoostKickMaxTime { get; set; } - public float BoostKickMaxStartSpeed { get; set; } - public float BoostKickHeightOffset { get; set; } - public float BoostKickAcceleration { get; set; } - public float BoostKick { get; set; } - public float BoostHeightOffset { get; set; } - public float BoostBase { get; set; } - public float BoostAcceleration { get; set; } - public float BlueMaxBoostSpeed { get; set; } - public float BlueBoostKickTime { get; set; } - public float BlueBoostKick { get; set; } - public float BlueBoostBase { get; set; } + public AttributeHeader header { get; set; } + public SizeAndPositionInformation info { get; set; } + public float MaxBoostSpeed { get; set; } + public int BoostRule { get; set; } + public float BoostKickTime { get; set; } + public float BoostKickMinTime { get; set; } + public float BoostKickMaxTime { get; set; } + public float BoostKickMaxStartSpeed { get; set; } + public float BoostKickHeightOffset { get; set; } + public float BoostKickAcceleration { get; set; } + public float BoostKick { get; set; } + public float BoostHeightOffset { get; set; } + public float BoostBase { get; set; } + public float BoostAcceleration { get; set; } + public float BlueMaxBoostSpeed { get; set; } + public float BlueBoostKickTime { get; set; } + public float BlueBoostKick { get; set; } + public float BlueBoostBase { get; set; } - public Physicsvehicleboostattribs(SizeAndPositionInformation chunk, AttributeHeader dataChunk) - { - header = dataChunk; - info = chunk; - } + public Physicsvehicleboostattribs(SizeAndPositionInformation chunk, AttributeHeader dataChunk) + { + header = dataChunk; + info = chunk; + } - public int getDataSize() - { - List bytes = new List - { - BitConverter.GetBytes(MaxBoostSpeed), - BitConverter.GetBytes(BoostRule), - BitConverter.GetBytes(BoostKickTime), - BitConverter.GetBytes(BoostKickMinTime), - BitConverter.GetBytes(BoostKickMaxTime), - BitConverter.GetBytes(BoostKickMaxStartSpeed), - BitConverter.GetBytes(BoostKickHeightOffset), - BitConverter.GetBytes(BoostKickAcceleration), - BitConverter.GetBytes(BoostKick), - BitConverter.GetBytes(BoostHeightOffset), - BitConverter.GetBytes(BoostBase), - BitConverter.GetBytes(BoostAcceleration), - BitConverter.GetBytes(BlueMaxBoostSpeed), - BitConverter.GetBytes(BlueBoostKickTime), - BitConverter.GetBytes(BlueBoostKick), - BitConverter.GetBytes(BlueBoostBase) - }; - Console.WriteLine(bytes.SelectMany(i => i).Count()); - return CountingUtilities.AddPadding(bytes); - } + public int getDataSize() + { + List bytes = + [ + BitConverter.GetBytes(MaxBoostSpeed), + BitConverter.GetBytes(BoostRule), + BitConverter.GetBytes(BoostKickTime), + BitConverter.GetBytes(BoostKickMinTime), + BitConverter.GetBytes(BoostKickMaxTime), + BitConverter.GetBytes(BoostKickMaxStartSpeed), + BitConverter.GetBytes(BoostKickHeightOffset), + BitConverter.GetBytes(BoostKickAcceleration), + BitConverter.GetBytes(BoostKick), + BitConverter.GetBytes(BoostHeightOffset), + BitConverter.GetBytes(BoostBase), + BitConverter.GetBytes(BoostAcceleration), + BitConverter.GetBytes(BlueMaxBoostSpeed), + BitConverter.GetBytes(BlueBoostKickTime), + BitConverter.GetBytes(BlueBoostKick), + BitConverter.GetBytes(BlueBoostBase) + ]; + Console.WriteLine(bytes.SelectMany(i => i).Count()); + return CountingUtilities.AddPadding(bytes); + } - public AttributeHeader getHeader() - { - return header; - } + public AttributeHeader getHeader() + { + return header; + } - public SizeAndPositionInformation getInfo() - { - return info; - } + public SizeAndPositionInformation getInfo() + { + return info; + } - public void Read(ILoader loader, BinaryReader2 br) - { - MaxBoostSpeed = br.ReadSingle(); - BoostRule = br.ReadInt32(); - BoostKickTime = br.ReadSingle(); - BoostKickMinTime = br.ReadSingle(); - BoostKickMaxTime = br.ReadSingle(); - BoostKickMaxStartSpeed = br.ReadSingle(); - BoostKickHeightOffset = br.ReadSingle(); - BoostKickAcceleration = br.ReadSingle(); - BoostKick = br.ReadSingle(); - BoostHeightOffset = br.ReadSingle(); - BoostBase = br.ReadSingle(); - BoostAcceleration = br.ReadSingle(); - BlueMaxBoostSpeed = br.ReadSingle(); - BlueBoostKickTime = br.ReadSingle(); - BlueBoostKick = br.ReadSingle(); - BlueBoostBase = br.ReadSingle(); - } + public void Read(ILoader loader, BinaryReader2 br) + { + MaxBoostSpeed = br.ReadSingle(); + BoostRule = br.ReadInt32(); + BoostKickTime = br.ReadSingle(); + BoostKickMinTime = br.ReadSingle(); + BoostKickMaxTime = br.ReadSingle(); + BoostKickMaxStartSpeed = br.ReadSingle(); + BoostKickHeightOffset = br.ReadSingle(); + BoostKickAcceleration = br.ReadSingle(); + BoostKick = br.ReadSingle(); + BoostHeightOffset = br.ReadSingle(); + BoostBase = br.ReadSingle(); + BoostAcceleration = br.ReadSingle(); + BlueMaxBoostSpeed = br.ReadSingle(); + BlueBoostKickTime = br.ReadSingle(); + BlueBoostKick = br.ReadSingle(); + BlueBoostBase = br.ReadSingle(); + } - public void Write(BinaryWriter2 bw) - { - bw.Write(MaxBoostSpeed); - bw.Write(BoostRule); - bw.Write(BoostKickTime); - bw.Write(BoostKickMinTime); - bw.Write(BoostKickMaxTime); - bw.Write(BoostKickMaxStartSpeed); - bw.Write(BoostKickHeightOffset); - bw.Write(BoostKickAcceleration); - bw.Write(BoostKick); - bw.Write(BoostHeightOffset); - bw.Write(BoostBase); - bw.Write(BoostAcceleration); - bw.Write(BlueMaxBoostSpeed); - bw.Write(BlueBoostKickTime); - bw.Write(BlueBoostKick); - bw.Write(BlueBoostBase); - } + public void Write(BinaryWriter2 bw) + { + bw.Write(MaxBoostSpeed); + bw.Write(BoostRule); + bw.Write(BoostKickTime); + bw.Write(BoostKickMinTime); + bw.Write(BoostKickMaxTime); + bw.Write(BoostKickMaxStartSpeed); + bw.Write(BoostKickHeightOffset); + bw.Write(BoostKickAcceleration); + bw.Write(BoostKick); + bw.Write(BoostHeightOffset); + bw.Write(BoostBase); + bw.Write(BoostAcceleration); + bw.Write(BlueMaxBoostSpeed); + bw.Write(BlueBoostKickTime); + bw.Write(BlueBoostKick); + bw.Write(BlueBoostBase); } } diff --git a/VaultFormat/Physicsvehiclecollisionattribs.cs b/VaultFormat/Physicsvehiclecollisionattribs.cs index 74b56cf..9b1aeed 100644 --- a/VaultFormat/Physicsvehiclecollisionattribs.cs +++ b/VaultFormat/Physicsvehiclecollisionattribs.cs @@ -1,53 +1,51 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Numerics; using BundleFormat; using BundleUtilities; -namespace VaultFormat +namespace VaultFormat; + +public class Physicsvehiclecollisionattribs : IAttribute { - public class Physicsvehiclecollisionattribs : IAttribute + public AttributeHeader header { get; set; } + public SizeAndPositionInformation info { get; set; } + + public Vector4 BodyBox { get; set; } + public Physicsvehiclecollisionattribs(SizeAndPositionInformation chunk, AttributeHeader dataChunk) + { + header = dataChunk; + info = chunk; + } + + public int getDataSize() + { + List bytes = + [ + BodyBox.toBytes() + ]; + Console.WriteLine(bytes.SelectMany(i => i).Count()); + return CountingUtilities.AddPadding(bytes); + } + + public AttributeHeader getHeader() + { + return header; + } + + public SizeAndPositionInformation getInfo() + { + return info; + } + + public void Read(ILoader loader, BinaryReader2 br) + { + BodyBox = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); + } + + public void Write(BinaryWriter2 bw) { - public AttributeHeader header { get; set; } - public SizeAndPositionInformation info { get; set; } - - public Vector4 BodyBox { get; set; } - public Physicsvehiclecollisionattribs(SizeAndPositionInformation chunk, AttributeHeader dataChunk) - { - header = dataChunk; - info = chunk; - } - - public int getDataSize() - { - List bytes = new List - { - BodyBox.toBytes() - }; - Console.WriteLine(bytes.SelectMany(i => i).Count()); - return CountingUtilities.AddPadding(bytes); - } - - public AttributeHeader getHeader() - { - return header; - } - - public SizeAndPositionInformation getInfo() - { - return info; - } - - public void Read(ILoader loader, BinaryReader2 br) - { - BodyBox = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); - } - - public void Write(BinaryWriter2 bw) - { - bw.Write(BodyBox.toBytes(bw.BigEndian)); - } + bw.Write(BodyBox.toBytes(bw.BigEndian)); } } diff --git a/VaultFormat/Physicsvehicledriftattribs.cs b/VaultFormat/Physicsvehicledriftattribs.cs index 6286c41..02f0c5f 100644 --- a/VaultFormat/Physicsvehicledriftattribs.cs +++ b/VaultFormat/Physicsvehicledriftattribs.cs @@ -1,192 +1,190 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Numerics; using BundleFormat; using BundleUtilities; -namespace VaultFormat +namespace VaultFormat; + +public class Physicsvehicledriftattribs : IAttribute { - public class Physicsvehicledriftattribs : IAttribute - { - public AttributeHeader header { get; set; } - public SizeAndPositionInformation info { get; set; } + public AttributeHeader header { get; set; } + public SizeAndPositionInformation info { get; set; } - public Vector4 DriftScaleToYawTorque { get; set; } - public float WheelSlip { get; set; } - public float TimeToCapScale { get; set; } - public float TimeForNaturalDrift { get; set; } - public float SteeringDriftScaleFactor { get; set; } - public float SideForcePeakDriftAngle { get; set; } - public float SideForceMagnitude { get; set; } - public float SideForceDriftSpeedCutOff { get; set; } - public float SideForceDriftAngleCutOff { get; set; } - public float SideForceDirftScaleCutOff { get; set; } - public float NeutralTimeToReduceDrift { get; set; } - public float NaturalYawTorqueCutOffAngle { get; set; } - public float NaturalYawTorque { get; set; } - public float NaturalDriftTimeToReachBaseSlip { get; set; } - public float NaturalDriftStartSlip { get; set; } - public float NaturalDriftScaleDecay { get; set; } - public float MinSpeedForDrift { get; set; } - public float InitialDriftPushTime { get; set; } - public float InitialDriftPushScaleLimit { get; set; } - public float InitialDriftPushDynamicInc { get; set; } - public float InitialDriftPushBaseInc { get; set; } - public float GripFromSteering { get; set; } - public float GripFromGasLetOff { get; set; } - public float GripFromBrake { get; set; } - public float GasDriftScaleFactor { get; set; } - public float ForcedDriftTimeToReachBaseSlip { get; set; } - public float ForcedDriftStartSlip { get; set; } - public float DriftTorqueFallOff { get; set; } - public float DriftSidewaysDamping { get; set; } - public float DriftMaxAngle { get; set; } - public float DriftAngularDamping { get; set; } - public float CounterSteeringDriftScaleFactor { get; set; } - public float CappedScale { get; set; } - public float BrakingDriftScaleFactor { get; set; } - public float BaseCounterSteeringDriftScaleFactor { get; set; } + public Vector4 DriftScaleToYawTorque { get; set; } + public float WheelSlip { get; set; } + public float TimeToCapScale { get; set; } + public float TimeForNaturalDrift { get; set; } + public float SteeringDriftScaleFactor { get; set; } + public float SideForcePeakDriftAngle { get; set; } + public float SideForceMagnitude { get; set; } + public float SideForceDriftSpeedCutOff { get; set; } + public float SideForceDriftAngleCutOff { get; set; } + public float SideForceDirftScaleCutOff { get; set; } + public float NeutralTimeToReduceDrift { get; set; } + public float NaturalYawTorqueCutOffAngle { get; set; } + public float NaturalYawTorque { get; set; } + public float NaturalDriftTimeToReachBaseSlip { get; set; } + public float NaturalDriftStartSlip { get; set; } + public float NaturalDriftScaleDecay { get; set; } + public float MinSpeedForDrift { get; set; } + public float InitialDriftPushTime { get; set; } + public float InitialDriftPushScaleLimit { get; set; } + public float InitialDriftPushDynamicInc { get; set; } + public float InitialDriftPushBaseInc { get; set; } + public float GripFromSteering { get; set; } + public float GripFromGasLetOff { get; set; } + public float GripFromBrake { get; set; } + public float GasDriftScaleFactor { get; set; } + public float ForcedDriftTimeToReachBaseSlip { get; set; } + public float ForcedDriftStartSlip { get; set; } + public float DriftTorqueFallOff { get; set; } + public float DriftSidewaysDamping { get; set; } + public float DriftMaxAngle { get; set; } + public float DriftAngularDamping { get; set; } + public float CounterSteeringDriftScaleFactor { get; set; } + public float CappedScale { get; set; } + public float BrakingDriftScaleFactor { get; set; } + public float BaseCounterSteeringDriftScaleFactor { get; set; } - public Physicsvehicledriftattribs(SizeAndPositionInformation chunk, AttributeHeader dataChunk) - { - header = dataChunk; - info = chunk; - } + public Physicsvehicledriftattribs(SizeAndPositionInformation chunk, AttributeHeader dataChunk) + { + header = dataChunk; + info = chunk; + } - public int getDataSize() - { - List bytes = new List - { - DriftScaleToYawTorque.toBytes(), - BitConverter.GetBytes(WheelSlip), - BitConverter.GetBytes(TimeToCapScale), - BitConverter.GetBytes(TimeForNaturalDrift), - BitConverter.GetBytes(SteeringDriftScaleFactor), - BitConverter.GetBytes(SideForcePeakDriftAngle), - BitConverter.GetBytes(SideForceMagnitude), - BitConverter.GetBytes(SideForceDriftSpeedCutOff), - BitConverter.GetBytes(SideForceDriftAngleCutOff), - BitConverter.GetBytes(SideForceDirftScaleCutOff), - BitConverter.GetBytes(NeutralTimeToReduceDrift), - BitConverter.GetBytes(NaturalYawTorqueCutOffAngle), - BitConverter.GetBytes(NaturalYawTorque), - BitConverter.GetBytes(NaturalDriftTimeToReachBaseSlip), - BitConverter.GetBytes(NaturalDriftStartSlip), - BitConverter.GetBytes(NaturalDriftScaleDecay), - BitConverter.GetBytes(MinSpeedForDrift), - BitConverter.GetBytes(InitialDriftPushTime), - BitConverter.GetBytes(InitialDriftPushScaleLimit), - BitConverter.GetBytes(InitialDriftPushDynamicInc), - BitConverter.GetBytes(InitialDriftPushBaseInc), - BitConverter.GetBytes(GripFromSteering), - BitConverter.GetBytes(GripFromGasLetOff), - BitConverter.GetBytes(GripFromBrake), - BitConverter.GetBytes(GasDriftScaleFactor), - BitConverter.GetBytes(ForcedDriftTimeToReachBaseSlip), - BitConverter.GetBytes(ForcedDriftStartSlip), - BitConverter.GetBytes(DriftTorqueFallOff), - BitConverter.GetBytes(DriftSidewaysDamping), - BitConverter.GetBytes(DriftMaxAngle), - BitConverter.GetBytes(DriftAngularDamping), - BitConverter.GetBytes(CounterSteeringDriftScaleFactor), - BitConverter.GetBytes(CappedScale), - BitConverter.GetBytes(BrakingDriftScaleFactor), - BitConverter.GetBytes(BaseCounterSteeringDriftScaleFactor) - }; - Console.WriteLine(bytes.SelectMany(i => i).Count()); - return CountingUtilities.AddPadding(bytes); - } + public int getDataSize() + { + List bytes = + [ + DriftScaleToYawTorque.toBytes(), + BitConverter.GetBytes(WheelSlip), + BitConverter.GetBytes(TimeToCapScale), + BitConverter.GetBytes(TimeForNaturalDrift), + BitConverter.GetBytes(SteeringDriftScaleFactor), + BitConverter.GetBytes(SideForcePeakDriftAngle), + BitConverter.GetBytes(SideForceMagnitude), + BitConverter.GetBytes(SideForceDriftSpeedCutOff), + BitConverter.GetBytes(SideForceDriftAngleCutOff), + BitConverter.GetBytes(SideForceDirftScaleCutOff), + BitConverter.GetBytes(NeutralTimeToReduceDrift), + BitConverter.GetBytes(NaturalYawTorqueCutOffAngle), + BitConverter.GetBytes(NaturalYawTorque), + BitConverter.GetBytes(NaturalDriftTimeToReachBaseSlip), + BitConverter.GetBytes(NaturalDriftStartSlip), + BitConverter.GetBytes(NaturalDriftScaleDecay), + BitConverter.GetBytes(MinSpeedForDrift), + BitConverter.GetBytes(InitialDriftPushTime), + BitConverter.GetBytes(InitialDriftPushScaleLimit), + BitConverter.GetBytes(InitialDriftPushDynamicInc), + BitConverter.GetBytes(InitialDriftPushBaseInc), + BitConverter.GetBytes(GripFromSteering), + BitConverter.GetBytes(GripFromGasLetOff), + BitConverter.GetBytes(GripFromBrake), + BitConverter.GetBytes(GasDriftScaleFactor), + BitConverter.GetBytes(ForcedDriftTimeToReachBaseSlip), + BitConverter.GetBytes(ForcedDriftStartSlip), + BitConverter.GetBytes(DriftTorqueFallOff), + BitConverter.GetBytes(DriftSidewaysDamping), + BitConverter.GetBytes(DriftMaxAngle), + BitConverter.GetBytes(DriftAngularDamping), + BitConverter.GetBytes(CounterSteeringDriftScaleFactor), + BitConverter.GetBytes(CappedScale), + BitConverter.GetBytes(BrakingDriftScaleFactor), + BitConverter.GetBytes(BaseCounterSteeringDriftScaleFactor) + ]; + Console.WriteLine(bytes.SelectMany(i => i).Count()); + return CountingUtilities.AddPadding(bytes); + } - public AttributeHeader getHeader() - { - return header; - } + public AttributeHeader getHeader() + { + return header; + } - public SizeAndPositionInformation getInfo() - { - return info; - } + public SizeAndPositionInformation getInfo() + { + return info; + } - public void Read(ILoader loader, BinaryReader2 br) - { - DriftScaleToYawTorque = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); - WheelSlip = br.ReadSingle(); - TimeToCapScale = br.ReadSingle(); - TimeForNaturalDrift = br.ReadSingle(); - SteeringDriftScaleFactor = br.ReadSingle(); - SideForcePeakDriftAngle = br.ReadSingle(); - SideForceMagnitude = br.ReadSingle(); - SideForceDriftSpeedCutOff = br.ReadSingle(); - SideForceDriftAngleCutOff = br.ReadSingle(); - SideForceDirftScaleCutOff = br.ReadSingle(); - NeutralTimeToReduceDrift = br.ReadSingle(); - NaturalYawTorqueCutOffAngle = br.ReadSingle(); - NaturalYawTorque = br.ReadSingle(); - NaturalDriftTimeToReachBaseSlip = br.ReadSingle(); - NaturalDriftStartSlip = br.ReadSingle(); - NaturalDriftScaleDecay = br.ReadSingle(); - MinSpeedForDrift = br.ReadSingle(); - InitialDriftPushTime = br.ReadSingle(); - InitialDriftPushScaleLimit = br.ReadSingle(); - InitialDriftPushDynamicInc = br.ReadSingle(); - InitialDriftPushBaseInc = br.ReadSingle(); - GripFromSteering = br.ReadSingle(); - GripFromGasLetOff = br.ReadSingle(); - GripFromBrake = br.ReadSingle(); - GasDriftScaleFactor = br.ReadSingle(); - ForcedDriftTimeToReachBaseSlip = br.ReadSingle(); - ForcedDriftStartSlip = br.ReadSingle(); - DriftTorqueFallOff = br.ReadSingle(); - DriftSidewaysDamping = br.ReadSingle(); - DriftMaxAngle = br.ReadSingle(); - DriftAngularDamping = br.ReadSingle(); - CounterSteeringDriftScaleFactor = br.ReadSingle(); - CappedScale = br.ReadSingle(); - BrakingDriftScaleFactor = br.ReadSingle(); - BaseCounterSteeringDriftScaleFactor = br.ReadSingle(); - br.SkipPadding(); - } + public void Read(ILoader loader, BinaryReader2 br) + { + DriftScaleToYawTorque = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); + WheelSlip = br.ReadSingle(); + TimeToCapScale = br.ReadSingle(); + TimeForNaturalDrift = br.ReadSingle(); + SteeringDriftScaleFactor = br.ReadSingle(); + SideForcePeakDriftAngle = br.ReadSingle(); + SideForceMagnitude = br.ReadSingle(); + SideForceDriftSpeedCutOff = br.ReadSingle(); + SideForceDriftAngleCutOff = br.ReadSingle(); + SideForceDirftScaleCutOff = br.ReadSingle(); + NeutralTimeToReduceDrift = br.ReadSingle(); + NaturalYawTorqueCutOffAngle = br.ReadSingle(); + NaturalYawTorque = br.ReadSingle(); + NaturalDriftTimeToReachBaseSlip = br.ReadSingle(); + NaturalDriftStartSlip = br.ReadSingle(); + NaturalDriftScaleDecay = br.ReadSingle(); + MinSpeedForDrift = br.ReadSingle(); + InitialDriftPushTime = br.ReadSingle(); + InitialDriftPushScaleLimit = br.ReadSingle(); + InitialDriftPushDynamicInc = br.ReadSingle(); + InitialDriftPushBaseInc = br.ReadSingle(); + GripFromSteering = br.ReadSingle(); + GripFromGasLetOff = br.ReadSingle(); + GripFromBrake = br.ReadSingle(); + GasDriftScaleFactor = br.ReadSingle(); + ForcedDriftTimeToReachBaseSlip = br.ReadSingle(); + ForcedDriftStartSlip = br.ReadSingle(); + DriftTorqueFallOff = br.ReadSingle(); + DriftSidewaysDamping = br.ReadSingle(); + DriftMaxAngle = br.ReadSingle(); + DriftAngularDamping = br.ReadSingle(); + CounterSteeringDriftScaleFactor = br.ReadSingle(); + CappedScale = br.ReadSingle(); + BrakingDriftScaleFactor = br.ReadSingle(); + BaseCounterSteeringDriftScaleFactor = br.ReadSingle(); + br.SkipPadding(); + } - public void Write(BinaryWriter2 bw) - { - bw.Write(DriftScaleToYawTorque.toBytes(bw.BigEndian)); - bw.Write(WheelSlip); - bw.Write(TimeToCapScale); - bw.Write(TimeForNaturalDrift); - bw.Write(SteeringDriftScaleFactor); - bw.Write(SideForcePeakDriftAngle); - bw.Write(SideForceMagnitude); - bw.Write(SideForceDriftSpeedCutOff); - bw.Write(SideForceDriftAngleCutOff); - bw.Write(SideForceDirftScaleCutOff); - bw.Write(NeutralTimeToReduceDrift); - bw.Write(NaturalYawTorqueCutOffAngle); - bw.Write(NaturalYawTorque); - bw.Write(NaturalDriftTimeToReachBaseSlip); - bw.Write(NaturalDriftStartSlip); - bw.Write(NaturalDriftScaleDecay); - bw.Write(MinSpeedForDrift); - bw.Write(InitialDriftPushTime); - bw.Write(InitialDriftPushScaleLimit); - bw.Write(InitialDriftPushDynamicInc); - bw.Write(InitialDriftPushBaseInc); - bw.Write(GripFromSteering); - bw.Write(GripFromGasLetOff); - bw.Write(GripFromBrake); - bw.Write(GasDriftScaleFactor); - bw.Write(ForcedDriftTimeToReachBaseSlip); - bw.Write(ForcedDriftStartSlip); - bw.Write(DriftTorqueFallOff); - bw.Write(DriftSidewaysDamping); - bw.Write(DriftMaxAngle); - bw.Write(DriftAngularDamping); - bw.Write(CounterSteeringDriftScaleFactor); - bw.Write(CappedScale); - bw.Write(BrakingDriftScaleFactor); - bw.Write(BaseCounterSteeringDriftScaleFactor); - bw.WritePadding(); - } + public void Write(BinaryWriter2 bw) + { + bw.Write(DriftScaleToYawTorque.toBytes(bw.BigEndian)); + bw.Write(WheelSlip); + bw.Write(TimeToCapScale); + bw.Write(TimeForNaturalDrift); + bw.Write(SteeringDriftScaleFactor); + bw.Write(SideForcePeakDriftAngle); + bw.Write(SideForceMagnitude); + bw.Write(SideForceDriftSpeedCutOff); + bw.Write(SideForceDriftAngleCutOff); + bw.Write(SideForceDirftScaleCutOff); + bw.Write(NeutralTimeToReduceDrift); + bw.Write(NaturalYawTorqueCutOffAngle); + bw.Write(NaturalYawTorque); + bw.Write(NaturalDriftTimeToReachBaseSlip); + bw.Write(NaturalDriftStartSlip); + bw.Write(NaturalDriftScaleDecay); + bw.Write(MinSpeedForDrift); + bw.Write(InitialDriftPushTime); + bw.Write(InitialDriftPushScaleLimit); + bw.Write(InitialDriftPushDynamicInc); + bw.Write(InitialDriftPushBaseInc); + bw.Write(GripFromSteering); + bw.Write(GripFromGasLetOff); + bw.Write(GripFromBrake); + bw.Write(GasDriftScaleFactor); + bw.Write(ForcedDriftTimeToReachBaseSlip); + bw.Write(ForcedDriftStartSlip); + bw.Write(DriftTorqueFallOff); + bw.Write(DriftSidewaysDamping); + bw.Write(DriftMaxAngle); + bw.Write(DriftAngularDamping); + bw.Write(CounterSteeringDriftScaleFactor); + bw.Write(CappedScale); + bw.Write(BrakingDriftScaleFactor); + bw.Write(BaseCounterSteeringDriftScaleFactor); + bw.WritePadding(); } } diff --git a/VaultFormat/Physicsvehicleengineattribs.cs b/VaultFormat/Physicsvehicleengineattribs.cs index 6190574..1348033 100644 --- a/VaultFormat/Physicsvehicleengineattribs.cs +++ b/VaultFormat/Physicsvehicleengineattribs.cs @@ -4,115 +4,116 @@ using BundleFormat; using BundleUtilities; -namespace VaultFormat -{ - public class Physicsvehicleengineattribs : IAttribute - { - public AttributeHeader header { get; set; } - public SizeAndPositionInformation info { get; set; } +namespace VaultFormat; - public Vector4 TorqueScales2 { get; set; } - public Vector4 TorqueScales1 { get; set; } - public Vector4 GearUpRPMs2 { get; set; } - public Vector4 GearUpRPMs1 { get; set; } - public Vector4 GearRatios2 { get; set; } - public Vector4 GearRatios1 { get; set; } - public float TransmissionEfficiency { get; set; } - public float TorqueFallOffRPM { get; set; } - public float MaxTorque { get; set; } - public float MaxRPM { get; set; } - public float LSDMGearUpSpeed { get; set; } - public float GearChangeTime { get; set; } - public float FlyWheelInertia { get; set; } - public float FlyWheelFriction { get; set; } - public float EngineResistance { get; set; } - public float EngineLowEndTorqueFactor { get; set; } - public float EngineBraking { get; set; } - public float Differential { get; set; } +public class Physicsvehicleengineattribs : IAttribute +{ + public AttributeHeader header { get; set; } + public SizeAndPositionInformation info { get; set; } - public Physicsvehicleengineattribs(SizeAndPositionInformation chunk, AttributeHeader dataChunk) - { - header = dataChunk; - info = chunk; - } + public Vector4 TorqueScales2 { get; set; } + public Vector4 TorqueScales1 { get; set; } + public Vector4 GearUpRPMs2 { get; set; } + public Vector4 GearUpRPMs1 { get; set; } + public Vector4 GearRatios2 { get; set; } + public Vector4 GearRatios1 { get; set; } + public float TransmissionEfficiency { get; set; } + public float TorqueFallOffRPM { get; set; } + public float MaxTorque { get; set; } + public float MaxRPM { get; set; } + public float LSDMGearUpSpeed { get; set; } + public float GearChangeTime { get; set; } + public float FlyWheelInertia { get; set; } + public float FlyWheelFriction { get; set; } + public float EngineResistance { get; set; } + public float EngineLowEndTorqueFactor { get; set; } + public float EngineBraking { get; set; } + public float Differential { get; set; } - public int getDataSize() - { - List bytes = new List(); - bytes.Add(TorqueScales2.toBytes()); - bytes.Add(TorqueScales1.toBytes()); - bytes.Add(GearUpRPMs2.toBytes()); - bytes.Add(GearUpRPMs1.toBytes()); - bytes.Add(GearRatios2.toBytes()); - bytes.Add(GearRatios1.toBytes()); - bytes.Add(BitConverter.GetBytes(TransmissionEfficiency)); - bytes.Add(BitConverter.GetBytes(TorqueFallOffRPM)); - bytes.Add(BitConverter.GetBytes(MaxTorque)); - bytes.Add(BitConverter.GetBytes(MaxRPM)); - bytes.Add(BitConverter.GetBytes(LSDMGearUpSpeed)); - bytes.Add(BitConverter.GetBytes(GearChangeTime)); - bytes.Add(BitConverter.GetBytes(FlyWheelInertia)); - bytes.Add(BitConverter.GetBytes(FlyWheelFriction)); - bytes.Add(BitConverter.GetBytes(EngineResistance)); - bytes.Add(BitConverter.GetBytes(EngineLowEndTorqueFactor)); - bytes.Add(BitConverter.GetBytes(EngineBraking)); - bytes.Add(BitConverter.GetBytes(Differential)); - return CountingUtilities.AddPadding(bytes); - } + public Physicsvehicleengineattribs(SizeAndPositionInformation chunk, AttributeHeader dataChunk) + { + header = dataChunk; + info = chunk; + } - public void Write(BinaryWriter2 bw) - { - bw.Write(TorqueScales2.toBytes(bw.BigEndian)); - bw.Write(TorqueScales1.toBytes(bw.BigEndian)); - bw.Write(GearUpRPMs2.toBytes(bw.BigEndian)); - bw.Write(GearUpRPMs1.toBytes(bw.BigEndian)); - bw.Write(GearRatios2.toBytes(bw.BigEndian)); - bw.Write(GearRatios1.toBytes(bw.BigEndian)); - bw.Write(TransmissionEfficiency); - bw.Write(TorqueFallOffRPM); - bw.Write(MaxTorque); - bw.Write(MaxRPM); - bw.Write(LSDMGearUpSpeed); - bw.Write(GearChangeTime); - bw.Write(FlyWheelInertia); - bw.Write(FlyWheelFriction); - bw.Write(EngineResistance); - bw.Write(EngineLowEndTorqueFactor); - bw.Write(EngineBraking); - bw.Write(Differential); - } + public int getDataSize() + { + List bytes = + [ + TorqueScales2.toBytes(), + TorqueScales1.toBytes(), + GearUpRPMs2.toBytes(), + GearUpRPMs1.toBytes(), + GearRatios2.toBytes(), + GearRatios1.toBytes(), + BitConverter.GetBytes(TransmissionEfficiency), + BitConverter.GetBytes(TorqueFallOffRPM), + BitConverter.GetBytes(MaxTorque), + BitConverter.GetBytes(MaxRPM), + BitConverter.GetBytes(LSDMGearUpSpeed), + BitConverter.GetBytes(GearChangeTime), + BitConverter.GetBytes(FlyWheelInertia), + BitConverter.GetBytes(FlyWheelFriction), + BitConverter.GetBytes(EngineResistance), + BitConverter.GetBytes(EngineLowEndTorqueFactor), + BitConverter.GetBytes(EngineBraking), + BitConverter.GetBytes(Differential), + ]; + return CountingUtilities.AddPadding(bytes); + } - public void Read(ILoader loader, BinaryReader2 br) - { - TorqueScales2 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); - TorqueScales1 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); - GearUpRPMs2 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); - GearUpRPMs1 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); - GearRatios2 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); - GearRatios1 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); - TransmissionEfficiency = br.ReadSingle(); - TorqueFallOffRPM = br.ReadSingle(); - MaxTorque = br.ReadSingle(); - MaxRPM = br.ReadSingle(); - LSDMGearUpSpeed = br.ReadSingle(); - GearChangeTime = br.ReadSingle(); - FlyWheelInertia = br.ReadSingle(); - FlyWheelFriction = br.ReadSingle(); - EngineResistance = br.ReadSingle(); - EngineLowEndTorqueFactor = br.ReadSingle(); - EngineBraking = br.ReadSingle(); - Differential = br.ReadSingle(); - } + public void Write(BinaryWriter2 bw) + { + bw.Write(TorqueScales2.toBytes(bw.BigEndian)); + bw.Write(TorqueScales1.toBytes(bw.BigEndian)); + bw.Write(GearUpRPMs2.toBytes(bw.BigEndian)); + bw.Write(GearUpRPMs1.toBytes(bw.BigEndian)); + bw.Write(GearRatios2.toBytes(bw.BigEndian)); + bw.Write(GearRatios1.toBytes(bw.BigEndian)); + bw.Write(TransmissionEfficiency); + bw.Write(TorqueFallOffRPM); + bw.Write(MaxTorque); + bw.Write(MaxRPM); + bw.Write(LSDMGearUpSpeed); + bw.Write(GearChangeTime); + bw.Write(FlyWheelInertia); + bw.Write(FlyWheelFriction); + bw.Write(EngineResistance); + bw.Write(EngineLowEndTorqueFactor); + bw.Write(EngineBraking); + bw.Write(Differential); + } - public AttributeHeader getHeader() - { - return header; - } + public void Read(ILoader loader, BinaryReader2 br) + { + TorqueScales2 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); + TorqueScales1 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); + GearUpRPMs2 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); + GearUpRPMs1 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); + GearRatios2 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); + GearRatios1 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); + TransmissionEfficiency = br.ReadSingle(); + TorqueFallOffRPM = br.ReadSingle(); + MaxTorque = br.ReadSingle(); + MaxRPM = br.ReadSingle(); + LSDMGearUpSpeed = br.ReadSingle(); + GearChangeTime = br.ReadSingle(); + FlyWheelInertia = br.ReadSingle(); + FlyWheelFriction = br.ReadSingle(); + EngineResistance = br.ReadSingle(); + EngineLowEndTorqueFactor = br.ReadSingle(); + EngineBraking = br.ReadSingle(); + Differential = br.ReadSingle(); + } - public SizeAndPositionInformation getInfo() - { - return info; - } + public AttributeHeader getHeader() + { + return header; + } + public SizeAndPositionInformation getInfo() + { + return info; } + } diff --git a/VaultFormat/Physicsvehiclehandling.cs b/VaultFormat/Physicsvehiclehandling.cs index 5955fe9..0a4daaf 100644 --- a/VaultFormat/Physicsvehiclehandling.cs +++ b/VaultFormat/Physicsvehiclehandling.cs @@ -1,78 +1,76 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using BundleUtilities; -namespace VaultFormat +namespace VaultFormat; + +public class Physicsvehiclehandling : IAttribute { - public class Physicsvehiclehandling : IAttribute + public AttributeHeader header { get; set; } + public SizeAndPositionInformation info { get; set; } + public RefSpec PhysicsVehicleSuspensionAttribs { get; set; } + public RefSpec PhysicsVehicleSteeringAttribs { get; set; } + public RefSpec PhysicsVehicleEngineAttribs { get; set; } + public RefSpec PhysicsVehicleDriftAttribs { get; set; } + public RefSpec PhysicsVehicleCollisionAttribs { get; set; } + public RefSpec PhysicsVehicleBoostAttribs { get; set; } + public RefSpec PhysicsVehicleBodyRollAttribs { get; set; } + public RefSpec PhysicsVehicleBaseAttribs { get; set; } + public Physicsvehiclehandling(SizeAndPositionInformation chunk, AttributeHeader dataChunk) { - public AttributeHeader header { get; set; } - public SizeAndPositionInformation info { get; set; } - public RefSpec PhysicsVehicleSuspensionAttribs { get; set; } - public RefSpec PhysicsVehicleSteeringAttribs { get; set; } - public RefSpec PhysicsVehicleEngineAttribs { get; set; } - public RefSpec PhysicsVehicleDriftAttribs { get; set; } - public RefSpec PhysicsVehicleCollisionAttribs { get; set; } - public RefSpec PhysicsVehicleBoostAttribs { get; set; } - public RefSpec PhysicsVehicleBodyRollAttribs { get; set; } - public RefSpec PhysicsVehicleBaseAttribs { get; set; } - public Physicsvehiclehandling(SizeAndPositionInformation chunk, AttributeHeader dataChunk) - { - header = dataChunk; - info = chunk; - } + header = dataChunk; + info = chunk; + } - public int getDataSize() - { - List bytes = new List - { - PhysicsVehicleSuspensionAttribs.ToBytes(), - PhysicsVehicleSteeringAttribs.ToBytes(), - PhysicsVehicleEngineAttribs.ToBytes(), - PhysicsVehicleDriftAttribs.ToBytes(), - PhysicsVehicleCollisionAttribs.ToBytes(), - PhysicsVehicleBoostAttribs.ToBytes(), - PhysicsVehicleBodyRollAttribs.ToBytes(), - PhysicsVehicleBaseAttribs.ToBytes() - }; - Console.WriteLine(bytes.SelectMany(i => i).Count()); - return CountingUtilities.AddPadding(bytes); - } + public int getDataSize() + { + List bytes = + [ + PhysicsVehicleSuspensionAttribs.ToBytes(), + PhysicsVehicleSteeringAttribs.ToBytes(), + PhysicsVehicleEngineAttribs.ToBytes(), + PhysicsVehicleDriftAttribs.ToBytes(), + PhysicsVehicleCollisionAttribs.ToBytes(), + PhysicsVehicleBoostAttribs.ToBytes(), + PhysicsVehicleBodyRollAttribs.ToBytes(), + PhysicsVehicleBaseAttribs.ToBytes() + ]; + Console.WriteLine(bytes.SelectMany(i => i).Count()); + return CountingUtilities.AddPadding(bytes); + } - public AttributeHeader getHeader() - { - return header; - } + public AttributeHeader getHeader() + { + return header; + } - public SizeAndPositionInformation getInfo() - { - return info; - } + public SizeAndPositionInformation getInfo() + { + return info; + } - public void Read(ILoader loader, BinaryReader2 br) - { - PhysicsVehicleSuspensionAttribs = new RefSpec(loader, br); - PhysicsVehicleSteeringAttribs = new RefSpec(loader, br); - PhysicsVehicleEngineAttribs = new RefSpec(loader, br); - PhysicsVehicleDriftAttribs = new RefSpec(loader, br); - PhysicsVehicleCollisionAttribs = new RefSpec(loader, br); - PhysicsVehicleBoostAttribs = new RefSpec(loader, br); - PhysicsVehicleBodyRollAttribs = new RefSpec(loader, br); - PhysicsVehicleBaseAttribs = new RefSpec(loader, br); - } + public void Read(ILoader loader, BinaryReader2 br) + { + PhysicsVehicleSuspensionAttribs = new RefSpec(loader, br); + PhysicsVehicleSteeringAttribs = new RefSpec(loader, br); + PhysicsVehicleEngineAttribs = new RefSpec(loader, br); + PhysicsVehicleDriftAttribs = new RefSpec(loader, br); + PhysicsVehicleCollisionAttribs = new RefSpec(loader, br); + PhysicsVehicleBoostAttribs = new RefSpec(loader, br); + PhysicsVehicleBodyRollAttribs = new RefSpec(loader, br); + PhysicsVehicleBaseAttribs = new RefSpec(loader, br); + } - public void Write(BinaryWriter2 bw) - { - PhysicsVehicleSuspensionAttribs.Write(bw); - PhysicsVehicleSteeringAttribs.Write(bw); - PhysicsVehicleEngineAttribs.Write(bw); - PhysicsVehicleDriftAttribs.Write(bw); - PhysicsVehicleCollisionAttribs.Write(bw); - PhysicsVehicleBoostAttribs.Write(bw); - PhysicsVehicleBodyRollAttribs.Write(bw); - PhysicsVehicleBaseAttribs.Write(bw); - } + public void Write(BinaryWriter2 bw) + { + PhysicsVehicleSuspensionAttribs.Write(bw); + PhysicsVehicleSteeringAttribs.Write(bw); + PhysicsVehicleEngineAttribs.Write(bw); + PhysicsVehicleDriftAttribs.Write(bw); + PhysicsVehicleCollisionAttribs.Write(bw); + PhysicsVehicleBoostAttribs.Write(bw); + PhysicsVehicleBodyRollAttribs.Write(bw); + PhysicsVehicleBaseAttribs.Write(bw); } } diff --git a/VaultFormat/Physicsvehiclesteeringattribs.cs b/VaultFormat/Physicsvehiclesteeringattribs.cs index e356604..9c9df53 100644 --- a/VaultFormat/Physicsvehiclesteeringattribs.cs +++ b/VaultFormat/Physicsvehiclesteeringattribs.cs @@ -1,107 +1,105 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using BundleUtilities; -namespace VaultFormat +namespace VaultFormat; + +public class Physicsvehiclesteeringattribs : IAttribute { - public class Physicsvehiclesteeringattribs : IAttribute + public AttributeHeader header { get; set; } + public SizeAndPositionInformation info { get; set; } + public float TimeForLock { get; set; } + public float StraightReactionBias { get; set; } + public float SpeedForMinAngle { get; set; } + public float SpeedForMaxAngle { get; set; } + public float MinAngle { get; set; } + public float MaxAngle { get; set; } + public float AiPidCoefficientP { get; set; } + public float AiPidCoefficientI { get; set; } + public float AiPidCoefficientDriftP { get; set; } + public float AiPidCoefficientDriftI { get; set; } + public float AiPidCoefficientDriftD { get; set; } + public float AiPidCoefficientD { get; set; } + public float AiMinLookAheadDistanceForDrift { get; set; } + public float AiLookAheadTimeForDrift { get; set; } + public Physicsvehiclesteeringattribs(SizeAndPositionInformation chunk, AttributeHeader dataChunk) { - public AttributeHeader header { get; set; } - public SizeAndPositionInformation info { get; set; } - public float TimeForLock { get; set; } - public float StraightReactionBias { get; set; } - public float SpeedForMinAngle { get; set; } - public float SpeedForMaxAngle { get; set; } - public float MinAngle { get; set; } - public float MaxAngle { get; set; } - public float AiPidCoefficientP { get; set; } - public float AiPidCoefficientI { get; set; } - public float AiPidCoefficientDriftP { get; set; } - public float AiPidCoefficientDriftI { get; set; } - public float AiPidCoefficientDriftD { get; set; } - public float AiPidCoefficientD { get; set; } - public float AiMinLookAheadDistanceForDrift { get; set; } - public float AiLookAheadTimeForDrift { get; set; } - public Physicsvehiclesteeringattribs(SizeAndPositionInformation chunk, AttributeHeader dataChunk) - { - header = dataChunk; - info = chunk; - } + header = dataChunk; + info = chunk; + } - public int getDataSize() - { - List bytes = new List - { - BitConverter.GetBytes(TimeForLock), - BitConverter.GetBytes(StraightReactionBias), - BitConverter.GetBytes(SpeedForMinAngle), - BitConverter.GetBytes(SpeedForMaxAngle), - BitConverter.GetBytes(MinAngle), - BitConverter.GetBytes(MaxAngle), - BitConverter.GetBytes(AiPidCoefficientP), - BitConverter.GetBytes(AiPidCoefficientI), - BitConverter.GetBytes(AiPidCoefficientDriftP), - BitConverter.GetBytes(AiPidCoefficientDriftI), - BitConverter.GetBytes(AiPidCoefficientDriftD), - BitConverter.GetBytes(AiPidCoefficientD), - BitConverter.GetBytes(AiMinLookAheadDistanceForDrift), - BitConverter.GetBytes(AiLookAheadTimeForDrift) - }; + public int getDataSize() + { + List bytes = + [ + BitConverter.GetBytes(TimeForLock), + BitConverter.GetBytes(StraightReactionBias), + BitConverter.GetBytes(SpeedForMinAngle), + BitConverter.GetBytes(SpeedForMaxAngle), + BitConverter.GetBytes(MinAngle), + BitConverter.GetBytes(MaxAngle), + BitConverter.GetBytes(AiPidCoefficientP), + BitConverter.GetBytes(AiPidCoefficientI), + BitConverter.GetBytes(AiPidCoefficientDriftP), + BitConverter.GetBytes(AiPidCoefficientDriftI), + BitConverter.GetBytes(AiPidCoefficientDriftD), + BitConverter.GetBytes(AiPidCoefficientD), + BitConverter.GetBytes(AiMinLookAheadDistanceForDrift), + BitConverter.GetBytes(AiLookAheadTimeForDrift), // Hack, because of weird padding of suspension attribs - bytes.AddRange(Physicsvehiclesuspensionattribs.getDefaultBytes()); - Console.WriteLine(bytes.SelectMany(i => i).Count()); - return CountingUtilities.AddPadding(bytes); - } + .. Physicsvehiclesuspensionattribs.getDefaultBytes(), + ]; + Console.WriteLine(bytes.SelectMany(i => i).Count()); + return CountingUtilities.AddPadding(bytes); + } - public AttributeHeader getHeader() - { - return header; - } + public AttributeHeader getHeader() + { + return header; + } - public SizeAndPositionInformation getInfo() - { - return info; - } + public SizeAndPositionInformation getInfo() + { + return info; + } - public void Read(ILoader loader, BinaryReader2 br) - { - TimeForLock = br.ReadSingle(); - StraightReactionBias = br.ReadSingle(); - SpeedForMinAngle = br.ReadSingle(); - SpeedForMaxAngle = br.ReadSingle(); - MinAngle = br.ReadSingle(); - MaxAngle = br.ReadSingle(); - AiPidCoefficientP = br.ReadSingle(); - AiPidCoefficientI = br.ReadSingle(); - AiPidCoefficientDriftP = br.ReadSingle(); - AiPidCoefficientDriftI = br.ReadSingle(); - AiPidCoefficientDriftD = br.ReadSingle(); - AiPidCoefficientD = br.ReadSingle(); - AiMinLookAheadDistanceForDrift = br.ReadSingle(); - AiLookAheadTimeForDrift = br.ReadSingle(); - br.SkipPadding(); - } + public void Read(ILoader loader, BinaryReader2 br) + { + TimeForLock = br.ReadSingle(); + StraightReactionBias = br.ReadSingle(); + SpeedForMinAngle = br.ReadSingle(); + SpeedForMaxAngle = br.ReadSingle(); + MinAngle = br.ReadSingle(); + MaxAngle = br.ReadSingle(); + AiPidCoefficientP = br.ReadSingle(); + AiPidCoefficientI = br.ReadSingle(); + AiPidCoefficientDriftP = br.ReadSingle(); + AiPidCoefficientDriftI = br.ReadSingle(); + AiPidCoefficientDriftD = br.ReadSingle(); + AiPidCoefficientD = br.ReadSingle(); + AiMinLookAheadDistanceForDrift = br.ReadSingle(); + AiLookAheadTimeForDrift = br.ReadSingle(); + br.SkipPadding(); + } - public void Write(BinaryWriter2 bw) - { - bw.Write(TimeForLock); - bw.Write(StraightReactionBias); - bw.Write(SpeedForMinAngle); - bw.Write(SpeedForMaxAngle); - bw.Write(MinAngle); - bw.Write(MaxAngle); - bw.Write(AiPidCoefficientP); - bw.Write(AiPidCoefficientI); - bw.Write(AiPidCoefficientDriftP); - bw.Write(AiPidCoefficientDriftI); - bw.Write(AiPidCoefficientDriftD); - bw.Write(AiPidCoefficientD); - bw.Write(AiMinLookAheadDistanceForDrift); - bw.Write(AiLookAheadTimeForDrift); - bw.WritePadding(); - } + public void Write(BinaryWriter2 bw) + { + bw.Write(TimeForLock); + bw.Write(StraightReactionBias); + bw.Write(SpeedForMinAngle); + bw.Write(SpeedForMaxAngle); + bw.Write(MinAngle); + bw.Write(MaxAngle); + bw.Write(AiPidCoefficientP); + bw.Write(AiPidCoefficientI); + bw.Write(AiPidCoefficientDriftP); + bw.Write(AiPidCoefficientDriftI); + bw.Write(AiPidCoefficientDriftD); + bw.Write(AiPidCoefficientD); + bw.Write(AiMinLookAheadDistanceForDrift); + bw.Write(AiLookAheadTimeForDrift); + bw.WritePadding(); } } diff --git a/VaultFormat/Physicsvehiclesuspensionattribs.cs b/VaultFormat/Physicsvehiclesuspensionattribs.cs index 6d3744a..ce959bd 100644 --- a/VaultFormat/Physicsvehiclesuspensionattribs.cs +++ b/VaultFormat/Physicsvehiclesuspensionattribs.cs @@ -1,123 +1,121 @@ using System; using System.Collections.Generic; -using System.IO; using BundleUtilities; -namespace VaultFormat +namespace VaultFormat; + +// To-Do: This is class is weird, because it's not divisible by 16 but has no padding... +public class Physicsvehiclesuspensionattribs : IAttribute { - // To-Do: This is class is weird, because it's not divisible by 16 but has no padding... - public class Physicsvehiclesuspensionattribs : IAttribute - { - public AttributeHeader header { get; set; } - public SizeAndPositionInformation info { get; set; } + public AttributeHeader header { get; set; } + public SizeAndPositionInformation info { get; set; } - public float UpwardMovement { get; set; } - public float TimeToDampAfterLanding { get; set; } - public float Strength { get; set; } - public float SpringLength { get; set; } - public float RearHeight { get; set; } - public float MaxYawDampingOnLanding { get; set; } - public float MaxVertVelocityDampingOnLanding { get; set; } - public float MaxRollDampingOnLanding { get; set; } - public float MaxPitchDampingOnLanding { get; set; } - public float InAirDamping { get; set; } - public float FrontHeight { get; set; } - public float DownwardMovement { get; set; } - public float Dampening { get; set; } + public float UpwardMovement { get; set; } + public float TimeToDampAfterLanding { get; set; } + public float Strength { get; set; } + public float SpringLength { get; set; } + public float RearHeight { get; set; } + public float MaxYawDampingOnLanding { get; set; } + public float MaxVertVelocityDampingOnLanding { get; set; } + public float MaxRollDampingOnLanding { get; set; } + public float MaxPitchDampingOnLanding { get; set; } + public float InAirDamping { get; set; } + public float FrontHeight { get; set; } + public float DownwardMovement { get; set; } + public float Dampening { get; set; } - public Physicsvehiclesuspensionattribs(SizeAndPositionInformation chunk, AttributeHeader dataChunk) - { - this.info = chunk; - this.header = dataChunk; - } - // Hack, because of weird padding of suspension attribs - public static byte[][] getDefaultBytes() { - float value = 0; - List bytes = new List - { - BitConverter.GetBytes(value), // UpwardMovement - BitConverter.GetBytes(0), // TimeToDampAfterLanding - BitConverter.GetBytes(0), // Strength - BitConverter.GetBytes(0), // etc - BitConverter.GetBytes(0), - BitConverter.GetBytes(0), - BitConverter.GetBytes(0), - BitConverter.GetBytes(0), - BitConverter.GetBytes(0), - BitConverter.GetBytes(0), - BitConverter.GetBytes(0), - BitConverter.GetBytes(0), - BitConverter.GetBytes(0) - }; - return bytes.ToArray(); - } + public Physicsvehiclesuspensionattribs(SizeAndPositionInformation chunk, AttributeHeader dataChunk) + { + this.info = chunk; + this.header = dataChunk; + } + // Hack, because of weird padding of suspension attribs + public static byte[][] getDefaultBytes() { + float value = 0; + List bytes = + [ + BitConverter.GetBytes(value), // UpwardMovement + BitConverter.GetBytes(0), // TimeToDampAfterLanding + BitConverter.GetBytes(0), // Strength + BitConverter.GetBytes(0), // etc + BitConverter.GetBytes(0), + BitConverter.GetBytes(0), + BitConverter.GetBytes(0), + BitConverter.GetBytes(0), + BitConverter.GetBytes(0), + BitConverter.GetBytes(0), + BitConverter.GetBytes(0), + BitConverter.GetBytes(0), + BitConverter.GetBytes(0) + ]; + return [.. bytes]; + } - public int getDataSize() - { - // Hack, because of weird padding of suspension attribs - /** - List bytes = new List(); - bytes.Add(BitConverter.GetBytes(UpwardMovement)); - bytes.Add(BitConverter.GetBytes(TimeToDampAfterLanding)); - bytes.Add(BitConverter.GetBytes(Strength)); - bytes.Add(BitConverter.GetBytes(SpringLength)); - bytes.Add(BitConverter.GetBytes(RearHeight)); - bytes.Add(BitConverter.GetBytes(MaxYawDampingOnLanding)); - bytes.Add(BitConverter.GetBytes(MaxVertVelocityDampingOnLanding)); - bytes.Add(BitConverter.GetBytes(MaxRollDampingOnLanding)); - bytes.Add(BitConverter.GetBytes(MaxPitchDampingOnLanding)); - bytes.Add(BitConverter.GetBytes(InAirDamping)); - bytes.Add(BitConverter.GetBytes(FrontHeight)); - bytes.Add(BitConverter.GetBytes(DownwardMovement)); - bytes.Add(BitConverter.GetBytes(Dampening)); - return bytes.SelectMany(i => i).Count(); - **/ - return 0; - } + public int getDataSize() + { + // Hack, because of weird padding of suspension attribs + /** + List bytes = new List(); + bytes.Add(BitConverter.GetBytes(UpwardMovement)); + bytes.Add(BitConverter.GetBytes(TimeToDampAfterLanding)); + bytes.Add(BitConverter.GetBytes(Strength)); + bytes.Add(BitConverter.GetBytes(SpringLength)); + bytes.Add(BitConverter.GetBytes(RearHeight)); + bytes.Add(BitConverter.GetBytes(MaxYawDampingOnLanding)); + bytes.Add(BitConverter.GetBytes(MaxVertVelocityDampingOnLanding)); + bytes.Add(BitConverter.GetBytes(MaxRollDampingOnLanding)); + bytes.Add(BitConverter.GetBytes(MaxPitchDampingOnLanding)); + bytes.Add(BitConverter.GetBytes(InAirDamping)); + bytes.Add(BitConverter.GetBytes(FrontHeight)); + bytes.Add(BitConverter.GetBytes(DownwardMovement)); + bytes.Add(BitConverter.GetBytes(Dampening)); + return bytes.SelectMany(i => i).Count(); + **/ + return 0; + } - public AttributeHeader getHeader() - { - return header; - } + public AttributeHeader getHeader() + { + return header; + } - public SizeAndPositionInformation getInfo() - { - return info; - } + public SizeAndPositionInformation getInfo() + { + return info; + } - public void Read(ILoader loader, BinaryReader2 br) - { - UpwardMovement = br.ReadSingle(); - TimeToDampAfterLanding = br.ReadSingle(); - Strength = br.ReadSingle(); - SpringLength = br.ReadSingle(); - RearHeight = br.ReadSingle(); - MaxYawDampingOnLanding = br.ReadSingle(); - MaxVertVelocityDampingOnLanding = br.ReadSingle(); - MaxRollDampingOnLanding = br.ReadSingle(); - MaxPitchDampingOnLanding = br.ReadSingle(); - InAirDamping = br.ReadSingle(); - FrontHeight = br.ReadSingle(); - DownwardMovement = br.ReadSingle(); - Dampening = br.ReadSingle(); - } + public void Read(ILoader loader, BinaryReader2 br) + { + UpwardMovement = br.ReadSingle(); + TimeToDampAfterLanding = br.ReadSingle(); + Strength = br.ReadSingle(); + SpringLength = br.ReadSingle(); + RearHeight = br.ReadSingle(); + MaxYawDampingOnLanding = br.ReadSingle(); + MaxVertVelocityDampingOnLanding = br.ReadSingle(); + MaxRollDampingOnLanding = br.ReadSingle(); + MaxPitchDampingOnLanding = br.ReadSingle(); + InAirDamping = br.ReadSingle(); + FrontHeight = br.ReadSingle(); + DownwardMovement = br.ReadSingle(); + Dampening = br.ReadSingle(); + } - public void Write(BinaryWriter2 bw) - { - bw.Write(UpwardMovement); - bw.Write(TimeToDampAfterLanding); - bw.Write(Strength); - bw.Write(SpringLength); - bw.Write(RearHeight); - bw.Write(MaxYawDampingOnLanding); - bw.Write(MaxVertVelocityDampingOnLanding); - bw.Write(MaxRollDampingOnLanding); - bw.Write(MaxPitchDampingOnLanding); - bw.Write(InAirDamping); - bw.Write(FrontHeight); - bw.Write(DownwardMovement); - bw.Write(Dampening); - } + public void Write(BinaryWriter2 bw) + { + bw.Write(UpwardMovement); + bw.Write(TimeToDampAfterLanding); + bw.Write(Strength); + bw.Write(SpringLength); + bw.Write(RearHeight); + bw.Write(MaxYawDampingOnLanding); + bw.Write(MaxVertVelocityDampingOnLanding); + bw.Write(MaxRollDampingOnLanding); + bw.Write(MaxPitchDampingOnLanding); + bw.Write(InAirDamping); + bw.Write(FrontHeight); + bw.Write(DownwardMovement); + bw.Write(Dampening); } } diff --git a/VaultFormat/RefSpec.cs b/VaultFormat/RefSpec.cs index 1bdd1bc..80a1523 100644 --- a/VaultFormat/RefSpec.cs +++ b/VaultFormat/RefSpec.cs @@ -1,57 +1,55 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using BundleUtilities; -namespace VaultFormat +namespace VaultFormat; + +//To-Do: Weird, because one RefSpec equals 0x18 aka 24 and is not divisible by 16 +public class RefSpec { - //To-Do: Weird, because one RefSpec equals 0x18 aka 24 and is not divisible by 16 - public class RefSpec - { - public ulong ClassKey; - public ulong CollectionKey; - public uint CollectionPtr; + public ulong ClassKey; + public ulong CollectionKey; + public uint CollectionPtr; - public RefSpec(ILoader loader, BinaryReader2 br) - { - ClassKey = br.ReadUInt64(); - CollectionKey = br.ReadUInt64(); - CollectionPtr = br.ReadUInt32(); - br.SkipUniquePadding(4); - } + public RefSpec(ILoader loader, BinaryReader2 br) + { + ClassKey = br.ReadUInt64(); + CollectionKey = br.ReadUInt64(); + CollectionPtr = br.ReadUInt32(); + br.SkipUniquePadding(4); + } - public byte[] ToBytes() - { - List bytes = new List - { - BitConverter.GetBytes(ClassKey), - BitConverter.GetBytes(CollectionKey), - BitConverter.GetBytes(CollectionPtr) - }; - return AddPadding(bytes); - } + public byte[] ToBytes() + { + List bytes = + [ + BitConverter.GetBytes(ClassKey), + BitConverter.GetBytes(CollectionKey), + BitConverter.GetBytes(CollectionPtr) + ]; + return AddPadding(bytes); + } - private byte[] AddPadding(List bytes) - { - List padding = new List - { - 0, - 0, - 0, - 0 - }; - bytes.Add(padding.ToArray()); - return bytes.SelectMany(i => i).ToArray(); - } - public void Write(BinaryWriter2 bw) - { - bw.Write(ClassKey); - bw.Write(CollectionKey); - bw.Write(CollectionPtr); - bw.WriteUniquePadding(4); - } + private byte[] AddPadding(List bytes) + { + List padding = + [ + 0, + 0, + 0, + 0 + ]; + bytes.Add([.. padding]); + return [.. bytes.SelectMany(i => i)]; + } + public void Write(BinaryWriter2 bw) + { + bw.Write(ClassKey); + bw.Write(CollectionKey); + bw.Write(CollectionPtr); + bw.WriteUniquePadding(4); + } - } } diff --git a/VaultFormat/UnimplementedAttribs.cs b/VaultFormat/UnimplementedAttribs.cs index aa4c486..9a9555d 100644 --- a/VaultFormat/UnimplementedAttribs.cs +++ b/VaultFormat/UnimplementedAttribs.cs @@ -1,42 +1,41 @@ using BundleUtilities; -namespace VaultFormat +namespace VaultFormat; + +public class UnimplementedAttribs : IAttribute { - public class UnimplementedAttribs : IAttribute - { - public AttributeHeader header { get; set; } - public SizeAndPositionInformation info { get; set; } - public byte[] data { get; set; } + public AttributeHeader header { get; set; } + public SizeAndPositionInformation info { get; set; } + public byte[] data { get; set; } - public UnimplementedAttribs(SizeAndPositionInformation chunk, AttributeHeader dataChunk) - { - info = chunk; - header = dataChunk; - } + public UnimplementedAttribs(SizeAndPositionInformation chunk, AttributeHeader dataChunk) + { + info = chunk; + header = dataChunk; + } - public int getDataSize() - { - return 0; - } + public int getDataSize() + { + return 0; + } - public AttributeHeader getHeader() - { - return header; - } + public AttributeHeader getHeader() + { + return header; + } - public SizeAndPositionInformation getInfo() - { - return info; - } + public SizeAndPositionInformation getInfo() + { + return info; + } - public void Read(ILoader loader, BinaryReader2 br) - { + public void Read(ILoader loader, BinaryReader2 br) + { - } + } - public void Write(BinaryWriter2 bw) - { + public void Write(BinaryWriter2 bw) + { - } } } diff --git a/VehicleList/EncryptionData.cs b/VehicleList/EncryptionData.cs index d50905e..12eb120 100644 --- a/VehicleList/EncryptionData.cs +++ b/VehicleList/EncryptionData.cs @@ -1,296 +1,295 @@ -namespace VehicleList +namespace VehicleList; + +public static class EncryptionData { - public static class EncryptionData + private static uint[] _data; + public static uint[] Data { - private static uint[] _data; - public static uint[] Data + get { - get - { - if (_data == null) - InitData(); - return _data; - } + if (_data == null) + InitData(); + return _data; } - private static void InitData() - { - _data = new uint[256]; + } + private static void InitData() + { + _data = new uint[256]; - _data[000] = 0x00000000; - _data[001] = 0x77073096; - _data[002] = 0xEE0E612C; - _data[003] = 0x990951BA; - _data[004] = 0x076DC419; - _data[005] = 0x706AF48F; - _data[006] = 0xE963A535; - _data[007] = 0x9E6495A3; - _data[008] = 0x0EDB8832; - _data[009] = 0x79DCB8A4; - _data[010] = 0xE0D5E91E; - _data[011] = 0x97D2D988; - _data[012] = 0x09B64C2B; - _data[013] = 0x7EB17CBD; - _data[014] = 0xE7B82D07; - _data[015] = 0x90BF1D91; - _data[016] = 0x1DB71064; - _data[017] = 0x6AB020F2; - _data[018] = 0xF3B97148; - _data[019] = 0x84BE41DE; - _data[020] = 0x1ADAD47D; - _data[021] = 0x6DDDE4EB; - _data[022] = 0xF4D4B551; - _data[023] = 0x83D385C7; - _data[024] = 0x136C9856; - _data[025] = 0x646BA8C0; - _data[026] = 0xFD62F97A; - _data[027] = 0x8A65C9EC; - _data[028] = 0x14015C4F; - _data[029] = 0x63066CD9; - _data[030] = 0xFA0F3D63; - _data[031] = 0x8D080DF5; - _data[032] = 0x3B6E20C8; - _data[033] = 0x4C69105E; - _data[034] = 0xD56041E4; - _data[035] = 0xA2677172; - _data[036] = 0x3C03E4D1; - _data[037] = 0x4B04D447; - _data[038] = 0xD20D85FD; - _data[039] = 0xA50AB56B; - _data[040] = 0x35B5A8FA; - _data[041] = 0x42B2986C; - _data[042] = 0xDBBBC9D6; - _data[043] = 0xACBCF940; - _data[044] = 0x32D86CE3; - _data[045] = 0x45DF5C75; - _data[046] = 0xDCD60DCF; - _data[047] = 0xABD13D59; - _data[048] = 0x26D930AC; - _data[049] = 0x51DE003A; - _data[050] = 0xC8D75180; - _data[051] = 0xBFD06116; - _data[052] = 0x21B4F4B5; - _data[053] = 0x56B3C423; - _data[054] = 0xCFBA9599; - _data[055] = 0xB8BDA50F; - _data[056] = 0x2802B89E; - _data[057] = 0x5F058808; - _data[058] = 0xC60CD9B2; - _data[059] = 0xB10BE924; - _data[060] = 0x2F6F7C87; - _data[061] = 0x58684C11; - _data[062] = 0xC1611DAB; - _data[063] = 0xB6662D3D; - _data[064] = 0x76DC4190; - _data[065] = 0x01DB7106; - _data[066] = 0x98D220BC; - _data[067] = 0xEFD5102A; - _data[068] = 0x71B18589; - _data[069] = 0x06B6B51F; - _data[070] = 0x9FBFE4A5; - _data[071] = 0xE8B8D433; - _data[072] = 0x7807C9A2; - _data[073] = 0x0F00F934; - _data[074] = 0x9609A88E; - _data[075] = 0xE10E9818; - _data[076] = 0x7F6A0DBB; - _data[077] = 0x086D3D2D; - _data[078] = 0x91646C97; - _data[079] = 0xE6635C01; - _data[080] = 0x6B6B51F4; - _data[081] = 0x1C6C6162; - _data[082] = 0x856530D8; - _data[083] = 0xF262004E; - _data[084] = 0x6C0695ED; - _data[085] = 0x1B01A57B; - _data[086] = 0x8208F4C1; - _data[087] = 0xF50FC457; - _data[088] = 0x65B0D9C6; - _data[089] = 0x12B7E950; - _data[090] = 0x8BBEB8EA; - _data[091] = 0xFCB9887C; - _data[092] = 0x62DD1DDF; - _data[093] = 0x15DA2D49; - _data[094] = 0x8CD37CF3; - _data[095] = 0xFBD44C65; - _data[096] = 0x4DB26158; - _data[097] = 0x3AB551CE; - _data[098] = 0xA3BC0074; - _data[099] = 0xD4BB30E2; - _data[100] = 0x4ADFA541; - _data[101] = 0x3DD895D7; - _data[102] = 0xA4D1C46D; - _data[103] = 0xD3D6F4FB; - _data[104] = 0x4369E96A; - _data[105] = 0x346ED9FC; - _data[106] = 0xAD678846; - _data[107] = 0xDA60B8D0; - _data[108] = 0x44042D73; - _data[109] = 0x33031DE5; - _data[110] = 0xAA0A4C5F; - _data[111] = 0xDD0D7CC9; - _data[112] = 0x5005713C; - _data[113] = 0x270241AA; - _data[114] = 0xBE0B1010; - _data[115] = 0xC90C2086; - _data[116] = 0x5768B525; - _data[117] = 0x206F85B3; - _data[118] = 0xB966D409; - _data[119] = 0xCE61E49F; - _data[120] = 0x5EDEF90E; - _data[121] = 0x29D9C998; - _data[122] = 0xB0D09822; - _data[123] = 0xC7D7A8B4; - _data[124] = 0x59B33D17; - _data[125] = 0x2EB40D81; - _data[126] = 0xB7BD5C3B; - _data[127] = 0xC0BA6CAD; - _data[128] = 0xEDB88320; - _data[129] = 0x9ABFB3B6; - _data[130] = 0x03B6E20C; - _data[131] = 0x74B1D29A; - _data[132] = 0xEAD54739; - _data[133] = 0x9DD277AF; - _data[134] = 0x04DB2615; - _data[135] = 0x73DC1683; - _data[136] = 0xE3630B12; - _data[137] = 0x94643B84; - _data[138] = 0x0D6D6A3E; - _data[139] = 0x7A6A5AA8; - _data[140] = 0xE40ECF0B; - _data[141] = 0x9309FF9D; - _data[142] = 0x0A00AE27; - _data[143] = 0x7D079EB1; - _data[144] = 0xF00F9344; - _data[145] = 0x8708A3D2; - _data[146] = 0x1E01F268; - _data[147] = 0x6906C2FE; - _data[148] = 0xF762575D; - _data[149] = 0x806567CB; - _data[150] = 0x196C3671; - _data[151] = 0x6E6B06E7; - _data[152] = 0xFED41B76; - _data[153] = 0x89D32BE0; - _data[154] = 0x10DA7A5A; - _data[155] = 0x67DD4ACC; - _data[156] = 0xF9B9DF6F; - _data[157] = 0x8EBEEFF9; - _data[158] = 0x17B7BE43; - _data[159] = 0x60B08ED5; - _data[160] = 0xD6D6A3E8; - _data[161] = 0xA1D1937E; - _data[162] = 0x38D8C2C4; - _data[163] = 0x4FDFF252; - _data[164] = 0xD1BB67F1; - _data[165] = 0xA6BC5767; - _data[166] = 0x3FB506DD; - _data[167] = 0x48B2364B; - _data[168] = 0xD80D2BDA; - _data[169] = 0xAF0A1B4C; - _data[170] = 0x36034AF6; - _data[171] = 0x41047A60; - _data[172] = 0xDF60EFC3; - _data[173] = 0xA867DF55; - _data[174] = 0x316E8EEF; - _data[175] = 0x4669BE79; - _data[176] = 0xCB61B38C; - _data[177] = 0xBC66831A; - _data[178] = 0x256FD2A0; - _data[179] = 0x5268E236; - _data[180] = 0xCC0C7795; - _data[181] = 0xBB0B4703; - _data[182] = 0x220216B9; - _data[183] = 0x5505262F; - _data[184] = 0xC5BA3BBE; - _data[185] = 0xB2BD0B28; - _data[186] = 0x2BB45A92; - _data[187] = 0x5CB36A04; - _data[188] = 0xC2D7FFA7; - _data[189] = 0xB5D0CF31; - _data[190] = 0x2CD99E8B; - _data[191] = 0x5BDEAE1D; - _data[192] = 0x9B64C2B0; - _data[193] = 0xEC63F226; - _data[194] = 0x756AA39C; - _data[195] = 0x026D930A; - _data[196] = 0x9C0906A9; - _data[197] = 0xEB0E363F; - _data[198] = 0x72076785; - _data[199] = 0x05005713; - _data[200] = 0x95BF4A82; - _data[201] = 0xE2B87A14; - _data[202] = 0x7BB12BAE; - _data[203] = 0x0CB61B38; - _data[204] = 0x92D28E9B; - _data[205] = 0xE5D5BE0D; - _data[206] = 0x7CDCEFB7; - _data[207] = 0x0BDBDF21; - _data[208] = 0x86D3D2D4; - _data[209] = 0xF1D4E242; - _data[210] = 0x68DDB3F8; - _data[211] = 0x1FDA836E; - _data[212] = 0x81BE16CD; - _data[213] = 0xF6B9265B; - _data[214] = 0x6FB077E1; - _data[215] = 0x18B74777; - _data[216] = 0x88085AE6; - _data[217] = 0xFF0F6A70; - _data[218] = 0x66063BCA; - _data[219] = 0x11010B5C; - _data[220] = 0x8F659EFF; - _data[221] = 0xF862AE69; - _data[222] = 0x616BFFD3; - _data[223] = 0x166CCF45; - _data[224] = 0xA00AE278; - _data[225] = 0xD70DD2EE; - _data[226] = 0x4E048354; - _data[227] = 0x3903B3C2; - _data[228] = 0xA7672661; - _data[229] = 0xD06016F7; - _data[230] = 0x4969474D; - _data[231] = 0x3E6E77DB; - _data[232] = 0xAED16A4A; - _data[233] = 0xD9D65ADC; - _data[234] = 0x40DF0B66; - _data[235] = 0x37D83BF0; - _data[236] = 0xA9BCAE53; - _data[237] = 0xDEBB9EC5; - _data[238] = 0x47B2CF7F; - _data[239] = 0x30B5FFE9; - _data[240] = 0xBDBDF21C; - _data[241] = 0xCABAC28A; - _data[242] = 0x53B39330; - _data[243] = 0x24B4A3A6; - _data[244] = 0xBAD03605; - _data[245] = 0xCDD70693; - _data[246] = 0x54DE5729; - _data[247] = 0x23D967BF; - _data[248] = 0xB3667A2E; - _data[249] = 0xC4614AB8; - _data[250] = 0x5D681B02; - _data[251] = 0x2A6F2B94; - _data[252] = 0xB40BBE37; - _data[253] = 0xC30C8EA1; - _data[254] = 0x5A05DF1B; - _data[255] = 0x2D02EF8D; - } + _data[000] = 0x00000000; + _data[001] = 0x77073096; + _data[002] = 0xEE0E612C; + _data[003] = 0x990951BA; + _data[004] = 0x076DC419; + _data[005] = 0x706AF48F; + _data[006] = 0xE963A535; + _data[007] = 0x9E6495A3; + _data[008] = 0x0EDB8832; + _data[009] = 0x79DCB8A4; + _data[010] = 0xE0D5E91E; + _data[011] = 0x97D2D988; + _data[012] = 0x09B64C2B; + _data[013] = 0x7EB17CBD; + _data[014] = 0xE7B82D07; + _data[015] = 0x90BF1D91; + _data[016] = 0x1DB71064; + _data[017] = 0x6AB020F2; + _data[018] = 0xF3B97148; + _data[019] = 0x84BE41DE; + _data[020] = 0x1ADAD47D; + _data[021] = 0x6DDDE4EB; + _data[022] = 0xF4D4B551; + _data[023] = 0x83D385C7; + _data[024] = 0x136C9856; + _data[025] = 0x646BA8C0; + _data[026] = 0xFD62F97A; + _data[027] = 0x8A65C9EC; + _data[028] = 0x14015C4F; + _data[029] = 0x63066CD9; + _data[030] = 0xFA0F3D63; + _data[031] = 0x8D080DF5; + _data[032] = 0x3B6E20C8; + _data[033] = 0x4C69105E; + _data[034] = 0xD56041E4; + _data[035] = 0xA2677172; + _data[036] = 0x3C03E4D1; + _data[037] = 0x4B04D447; + _data[038] = 0xD20D85FD; + _data[039] = 0xA50AB56B; + _data[040] = 0x35B5A8FA; + _data[041] = 0x42B2986C; + _data[042] = 0xDBBBC9D6; + _data[043] = 0xACBCF940; + _data[044] = 0x32D86CE3; + _data[045] = 0x45DF5C75; + _data[046] = 0xDCD60DCF; + _data[047] = 0xABD13D59; + _data[048] = 0x26D930AC; + _data[049] = 0x51DE003A; + _data[050] = 0xC8D75180; + _data[051] = 0xBFD06116; + _data[052] = 0x21B4F4B5; + _data[053] = 0x56B3C423; + _data[054] = 0xCFBA9599; + _data[055] = 0xB8BDA50F; + _data[056] = 0x2802B89E; + _data[057] = 0x5F058808; + _data[058] = 0xC60CD9B2; + _data[059] = 0xB10BE924; + _data[060] = 0x2F6F7C87; + _data[061] = 0x58684C11; + _data[062] = 0xC1611DAB; + _data[063] = 0xB6662D3D; + _data[064] = 0x76DC4190; + _data[065] = 0x01DB7106; + _data[066] = 0x98D220BC; + _data[067] = 0xEFD5102A; + _data[068] = 0x71B18589; + _data[069] = 0x06B6B51F; + _data[070] = 0x9FBFE4A5; + _data[071] = 0xE8B8D433; + _data[072] = 0x7807C9A2; + _data[073] = 0x0F00F934; + _data[074] = 0x9609A88E; + _data[075] = 0xE10E9818; + _data[076] = 0x7F6A0DBB; + _data[077] = 0x086D3D2D; + _data[078] = 0x91646C97; + _data[079] = 0xE6635C01; + _data[080] = 0x6B6B51F4; + _data[081] = 0x1C6C6162; + _data[082] = 0x856530D8; + _data[083] = 0xF262004E; + _data[084] = 0x6C0695ED; + _data[085] = 0x1B01A57B; + _data[086] = 0x8208F4C1; + _data[087] = 0xF50FC457; + _data[088] = 0x65B0D9C6; + _data[089] = 0x12B7E950; + _data[090] = 0x8BBEB8EA; + _data[091] = 0xFCB9887C; + _data[092] = 0x62DD1DDF; + _data[093] = 0x15DA2D49; + _data[094] = 0x8CD37CF3; + _data[095] = 0xFBD44C65; + _data[096] = 0x4DB26158; + _data[097] = 0x3AB551CE; + _data[098] = 0xA3BC0074; + _data[099] = 0xD4BB30E2; + _data[100] = 0x4ADFA541; + _data[101] = 0x3DD895D7; + _data[102] = 0xA4D1C46D; + _data[103] = 0xD3D6F4FB; + _data[104] = 0x4369E96A; + _data[105] = 0x346ED9FC; + _data[106] = 0xAD678846; + _data[107] = 0xDA60B8D0; + _data[108] = 0x44042D73; + _data[109] = 0x33031DE5; + _data[110] = 0xAA0A4C5F; + _data[111] = 0xDD0D7CC9; + _data[112] = 0x5005713C; + _data[113] = 0x270241AA; + _data[114] = 0xBE0B1010; + _data[115] = 0xC90C2086; + _data[116] = 0x5768B525; + _data[117] = 0x206F85B3; + _data[118] = 0xB966D409; + _data[119] = 0xCE61E49F; + _data[120] = 0x5EDEF90E; + _data[121] = 0x29D9C998; + _data[122] = 0xB0D09822; + _data[123] = 0xC7D7A8B4; + _data[124] = 0x59B33D17; + _data[125] = 0x2EB40D81; + _data[126] = 0xB7BD5C3B; + _data[127] = 0xC0BA6CAD; + _data[128] = 0xEDB88320; + _data[129] = 0x9ABFB3B6; + _data[130] = 0x03B6E20C; + _data[131] = 0x74B1D29A; + _data[132] = 0xEAD54739; + _data[133] = 0x9DD277AF; + _data[134] = 0x04DB2615; + _data[135] = 0x73DC1683; + _data[136] = 0xE3630B12; + _data[137] = 0x94643B84; + _data[138] = 0x0D6D6A3E; + _data[139] = 0x7A6A5AA8; + _data[140] = 0xE40ECF0B; + _data[141] = 0x9309FF9D; + _data[142] = 0x0A00AE27; + _data[143] = 0x7D079EB1; + _data[144] = 0xF00F9344; + _data[145] = 0x8708A3D2; + _data[146] = 0x1E01F268; + _data[147] = 0x6906C2FE; + _data[148] = 0xF762575D; + _data[149] = 0x806567CB; + _data[150] = 0x196C3671; + _data[151] = 0x6E6B06E7; + _data[152] = 0xFED41B76; + _data[153] = 0x89D32BE0; + _data[154] = 0x10DA7A5A; + _data[155] = 0x67DD4ACC; + _data[156] = 0xF9B9DF6F; + _data[157] = 0x8EBEEFF9; + _data[158] = 0x17B7BE43; + _data[159] = 0x60B08ED5; + _data[160] = 0xD6D6A3E8; + _data[161] = 0xA1D1937E; + _data[162] = 0x38D8C2C4; + _data[163] = 0x4FDFF252; + _data[164] = 0xD1BB67F1; + _data[165] = 0xA6BC5767; + _data[166] = 0x3FB506DD; + _data[167] = 0x48B2364B; + _data[168] = 0xD80D2BDA; + _data[169] = 0xAF0A1B4C; + _data[170] = 0x36034AF6; + _data[171] = 0x41047A60; + _data[172] = 0xDF60EFC3; + _data[173] = 0xA867DF55; + _data[174] = 0x316E8EEF; + _data[175] = 0x4669BE79; + _data[176] = 0xCB61B38C; + _data[177] = 0xBC66831A; + _data[178] = 0x256FD2A0; + _data[179] = 0x5268E236; + _data[180] = 0xCC0C7795; + _data[181] = 0xBB0B4703; + _data[182] = 0x220216B9; + _data[183] = 0x5505262F; + _data[184] = 0xC5BA3BBE; + _data[185] = 0xB2BD0B28; + _data[186] = 0x2BB45A92; + _data[187] = 0x5CB36A04; + _data[188] = 0xC2D7FFA7; + _data[189] = 0xB5D0CF31; + _data[190] = 0x2CD99E8B; + _data[191] = 0x5BDEAE1D; + _data[192] = 0x9B64C2B0; + _data[193] = 0xEC63F226; + _data[194] = 0x756AA39C; + _data[195] = 0x026D930A; + _data[196] = 0x9C0906A9; + _data[197] = 0xEB0E363F; + _data[198] = 0x72076785; + _data[199] = 0x05005713; + _data[200] = 0x95BF4A82; + _data[201] = 0xE2B87A14; + _data[202] = 0x7BB12BAE; + _data[203] = 0x0CB61B38; + _data[204] = 0x92D28E9B; + _data[205] = 0xE5D5BE0D; + _data[206] = 0x7CDCEFB7; + _data[207] = 0x0BDBDF21; + _data[208] = 0x86D3D2D4; + _data[209] = 0xF1D4E242; + _data[210] = 0x68DDB3F8; + _data[211] = 0x1FDA836E; + _data[212] = 0x81BE16CD; + _data[213] = 0xF6B9265B; + _data[214] = 0x6FB077E1; + _data[215] = 0x18B74777; + _data[216] = 0x88085AE6; + _data[217] = 0xFF0F6A70; + _data[218] = 0x66063BCA; + _data[219] = 0x11010B5C; + _data[220] = 0x8F659EFF; + _data[221] = 0xF862AE69; + _data[222] = 0x616BFFD3; + _data[223] = 0x166CCF45; + _data[224] = 0xA00AE278; + _data[225] = 0xD70DD2EE; + _data[226] = 0x4E048354; + _data[227] = 0x3903B3C2; + _data[228] = 0xA7672661; + _data[229] = 0xD06016F7; + _data[230] = 0x4969474D; + _data[231] = 0x3E6E77DB; + _data[232] = 0xAED16A4A; + _data[233] = 0xD9D65ADC; + _data[234] = 0x40DF0B66; + _data[235] = 0x37D83BF0; + _data[236] = 0xA9BCAE53; + _data[237] = 0xDEBB9EC5; + _data[238] = 0x47B2CF7F; + _data[239] = 0x30B5FFE9; + _data[240] = 0xBDBDF21C; + _data[241] = 0xCABAC28A; + _data[242] = 0x53B39330; + _data[243] = 0x24B4A3A6; + _data[244] = 0xBAD03605; + _data[245] = 0xCDD70693; + _data[246] = 0x54DE5729; + _data[247] = 0x23D967BF; + _data[248] = 0xB3667A2E; + _data[249] = 0xC4614AB8; + _data[250] = 0x5D681B02; + _data[251] = 0x2A6F2B94; + _data[252] = 0xB40BBE37; + _data[253] = 0xC30C8EA1; + _data[254] = 0x5A05DF1B; + _data[255] = 0x2D02EF8D; + } - public static uint EncryptString(string str) + public static uint EncryptString(string str) + { + unchecked { - unchecked + uint v4 = (uint)-1; + for (int i = 0; i < str.Length; i++) { - uint v4 = (uint)-1; - for (int i = 0; i < str.Length; i++) - { - byte c = (byte)str[i]; - if ((byte)(c - 65) <= 0x19) - c += 32; - int v5 = c ^ (byte)v4; - v4 = Data[v5] ^ (v4 >> 8); - } - v4 = ~v4; - - return v4; + byte c = (byte)str[i]; + if ((byte)(c - 65) <= 0x19) + c += 32; + int v5 = c ^ (byte)v4; + v4 = Data[v5] ^ (v4 >> 8); } + v4 = ~v4; + + return v4; } } } diff --git a/VehicleList/VehicleEditor.cs b/VehicleList/VehicleEditor.cs index fe753b0..35ecf41 100644 --- a/VehicleList/VehicleEditor.cs +++ b/VehicleList/VehicleEditor.cs @@ -3,636 +3,634 @@ using System.ComponentModel; using System.Windows.Forms; -namespace VehicleList +namespace VehicleList; + +public partial class VehicleEditor : Form { - public partial class VehicleEditor : Form + public delegate void Done(Vehicle vehicle); + public event Done OnDone; + private Vehicle _vehicle; + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public Vehicle Vehicle + { + get + { + return _vehicle; + } + set + { + _vehicle = value; + UpdateDisplay(); + } + } + + public VehicleEditor() + { + InitializeComponent(); + } + + private int maxIndex; + public VehicleEditor(int max) + { + InitializeComponent(); + maxIndex = max; + } + + private void UpdateDisplay() { - public delegate void Done(Vehicle vehicle); - public event Done OnDone; - private Vehicle _vehicle; - [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] - public Vehicle Vehicle + Text = "Edit Vehicle: " + Vehicle.Index; + + txtIndex.Text = Vehicle.Index.ToString(); + txtID.Text = Vehicle.ID.Value; + txtParentID.Text = Vehicle.ParentID.Value; + txtWheels.Text = Vehicle.WheelType; + txtName.Text = Vehicle.CarName; + txtBrand.Text = Vehicle.CarBrand; + txtDamageLimit.Text = Vehicle.DamageLimit.ToString(); + + // Flags + // Loop through all items + for (int i = 0; i < chlFlags.Items.Count; ++i) { - get + // If the flag is set, check the item at this index + if ((((uint)Vehicle.Flags) & (1 << i)) == (1 << i)) { - return _vehicle; + chlFlags.SetItemChecked(i, true); } - set + else { - _vehicle = value; - UpdateDisplay(); + // Ensure nothing is checked incorrectly + chlFlags.SetItemCheckState(i, CheckState.Unchecked); } } - public VehicleEditor() + txtBoostLength.Text = Vehicle.BoostLength.ToString(); + cboRank.SelectedIndex = (int)Vehicle.VehicleRank; + txtBoostCapacity.Text = Vehicle.BoostCapacity.ToString(); + txtStrengthStat.Text = Vehicle.DisplayStrength.ToString(); + txtAttribSysCollectionKey.Text = Vehicle.AttribSysCollectionKey.ToString(); + txtExhaustName.Text = Vehicle.ExhaustName.Value; + txtExhaustID.Text = Vehicle.ExhaustID.ToString(); + txtEngineID.Text = Vehicle.EngineID.ToString(); + txtEngineName.Text = Vehicle.EngineName.Value; + + // Class Unlock Stream Hash + uint classUnlockHash = (uint)Vehicle.ClassUnlockStreamHash; + // Set the selected index based on hash + switch (classUnlockHash) { - InitializeComponent(); + case 0x0470A5BF: + cboClassUnlock.SelectedIndex = 0; + break; + case 0x48346FEF: + cboClassUnlock.SelectedIndex = 1; + break; + case 0x817B91D9: + cboClassUnlock.SelectedIndex = 2; + break; + case 0xA3E2D8C9: + cboClassUnlock.SelectedIndex = 3; + break; + case 0xB3845465: + cboClassUnlock.SelectedIndex = 4; + break; + case 0xEBE39AE9: + cboClassUnlock.SelectedIndex = 5; + break; } - private int maxIndex; - public VehicleEditor(int max) - { - InitializeComponent(); - maxIndex = max; - } + txtCarWon.Text = Vehicle.CarShutdownStreamID.ToString(); + txtCarReleased.Text = Vehicle.CarReleasedStreamID.ToString(); - private void UpdateDisplay() + //AI Music Hash + uint aiMusicHash = (uint)Vehicle.AIMusicHash; + switch (aiMusicHash) { - Text = "Edit Vehicle: " + Vehicle.Index; - - txtIndex.Text = Vehicle.Index.ToString(); - txtID.Text = Vehicle.ID.Value; - txtParentID.Text = Vehicle.ParentID.Value; - txtWheels.Text = Vehicle.WheelType; - txtName.Text = Vehicle.CarName; - txtBrand.Text = Vehicle.CarBrand; - txtDamageLimit.Text = Vehicle.DamageLimit.ToString(); + case 0: + cboAIMusic.SelectedIndex = 0; + break; + case 0xA9813C9D: + cboAIMusic.SelectedIndex = 1; + break; + case 0xCB72AEA7: + cboAIMusic.SelectedIndex = 2; + break; + case 0x284D944B: + cboAIMusic.SelectedIndex = 3; + break; + case 0xD95C2309: + cboAIMusic.SelectedIndex = 4; + break; + case 0x8A1A90E9: + cboAIMusic.SelectedIndex = 5; + break; + case 0xB12A34DD: + cboAIMusic.SelectedIndex = 6; + break; + } - // Flags - // Loop through all items - for (int i = 0; i < chlFlags.Items.Count; ++i) - { - // If the flag is set, check the item at this index - if ((((uint)Vehicle.Flags) & (1 << i)) == (1 << i)) - { - chlFlags.SetItemChecked(i, true); - } - else - { - // Ensure nothing is checked incorrectly - chlFlags.SetItemCheckState(i, CheckState.Unchecked); - } - } + cboAIExhaust1.SelectedIndex = (int)Vehicle.AIExhaustIndex; + cboAIExhaust2.SelectedIndex = (int)Vehicle.AIExhaustIndex2; + cboAIExhaust3.SelectedIndex = (int)Vehicle.AIExhaustIndex3; - txtBoostLength.Text = Vehicle.BoostLength.ToString(); - cboRank.SelectedIndex = (int)Vehicle.VehicleRank; - txtBoostCapacity.Text = Vehicle.BoostCapacity.ToString(); - txtStrengthStat.Text = Vehicle.DisplayStrength.ToString(); - txtAttribSysCollectionKey.Text = Vehicle.AttribSysCollectionKey.ToString(); - txtExhaustName.Text = Vehicle.ExhaustName.Value; - txtExhaustID.Text = Vehicle.ExhaustID.ToString(); - txtEngineID.Text = Vehicle.EngineID.ToString(); - txtEngineName.Text = Vehicle.EngineName.Value; - - // Class Unlock Stream Hash - uint classUnlockHash = (uint)Vehicle.ClassUnlockStreamHash; - // Set the selected index based on hash - switch (classUnlockHash) + // Category + for (int i = 0; i < chlCategory.Items.Count; ++i) + { + if ((((uint)Vehicle.Category) & (1 << i)) == (1 << i)) { - case 0x0470A5BF: - cboClassUnlock.SelectedIndex = 0; - break; - case 0x48346FEF: - cboClassUnlock.SelectedIndex = 1; - break; - case 0x817B91D9: - cboClassUnlock.SelectedIndex = 2; - break; - case 0xA3E2D8C9: - cboClassUnlock.SelectedIndex = 3; - break; - case 0xB3845465: - cboClassUnlock.SelectedIndex = 4; - break; - case 0xEBE39AE9: - cboClassUnlock.SelectedIndex = 5; - break; + chlCategory.SetItemChecked(i, true); } - - txtCarWon.Text = Vehicle.CarShutdownStreamID.ToString(); - txtCarReleased.Text = Vehicle.CarReleasedStreamID.ToString(); - - //AI Music Hash - uint aiMusicHash = (uint)Vehicle.AIMusicHash; - switch (aiMusicHash) + else { - case 0: - cboAIMusic.SelectedIndex = 0; - break; - case 0xA9813C9D: - cboAIMusic.SelectedIndex = 1; - break; - case 0xCB72AEA7: - cboAIMusic.SelectedIndex = 2; - break; - case 0x284D944B: - cboAIMusic.SelectedIndex = 3; - break; - case 0xD95C2309: - cboAIMusic.SelectedIndex = 4; - break; - case 0x8A1A90E9: - cboAIMusic.SelectedIndex = 5; - break; - case 0xB12A34DD: - cboAIMusic.SelectedIndex = 6; - break; + chlCategory.SetItemCheckState(i, CheckState.Unchecked); } + } - cboAIExhaust1.SelectedIndex = (int)Vehicle.AIExhaustIndex; - cboAIExhaust2.SelectedIndex = (int)Vehicle.AIExhaustIndex2; - cboAIExhaust3.SelectedIndex = (int)Vehicle.AIExhaustIndex3; - - // Category - for (int i = 0; i < chlCategory.Items.Count; ++i) - { - if ((((uint)Vehicle.Category) & (1 << i)) == (1 << i)) - { - chlCategory.SetItemChecked(i, true); - } - else - { - chlCategory.SetItemCheckState(i, CheckState.Unchecked); - } - } + cboVehicleType.SelectedIndex = (int)Vehicle.VehicleType; + cboBoostType.SelectedIndex = (int)Vehicle.BoostType; + cboFinishType.SelectedIndex = (int)Vehicle.FinishType; + txtMaxSpeed.Text = Vehicle.MaxSpeedNoBoost.ToString(); + txtMaxBoostSpeed.Text = Vehicle.MaxSpeedBoost.ToString(); + txtSpeedStat.Text = Vehicle.DisplaySpeed.ToString(); + txtBoostStat.Text = Vehicle.DisplayBoost.ToString(); + txtColor.Text = Vehicle.Color.ToString(); + cboColorType.SelectedIndex = (int)Vehicle.ColorType; + } - cboVehicleType.SelectedIndex = (int)Vehicle.VehicleType; - cboBoostType.SelectedIndex = (int)Vehicle.BoostType; - cboFinishType.SelectedIndex = (int)Vehicle.FinishType; - txtMaxSpeed.Text = Vehicle.MaxSpeedNoBoost.ToString(); - txtMaxBoostSpeed.Text = Vehicle.MaxSpeedBoost.ToString(); - txtSpeedStat.Text = Vehicle.DisplaySpeed.ToString(); - txtBoostStat.Text = Vehicle.DisplayBoost.ToString(); - txtColor.Text = Vehicle.Color.ToString(); - cboColorType.SelectedIndex = (int)Vehicle.ColorType; - } + private Vehicle GetModifiedVehicle() + { + Vehicle result = new(Vehicle); - private Vehicle GetModifiedVehicle() + // Index + if (int.TryParse(txtIndex.Text, out int index)) { - Vehicle result = new Vehicle(Vehicle); - - // Index - int index; - if (int.TryParse(txtIndex.Text, out index)) - { - if (index <= maxIndex) - result.Index = index; - else - { - MessageBox.Show(this, "Index out of bounds.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } - } + if (index <= maxIndex) + result.Index = index; else { - MessageBox.Show(this, "Index is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } - // Vehicle ID - if (txtID.Text.Trim().Length == 0) - { - MessageBox.Show(this, "ID cannot be left blank.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } - try - { - EncryptedString ID = new EncryptedString(txtID.Text); - result.ID = ID; - } - catch (ArgumentException e) - { - MessageBox.Show(this, e.Message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + MessageBox.Show(this, "Index out of bounds.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); return null; } + } + else + { + MessageBox.Show(this, "Index is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } + // Vehicle ID + if (txtID.Text.Trim().Length == 0) + { + MessageBox.Show(this, "ID cannot be left blank.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } + try + { + EncryptedString ID = new(txtID.Text); + result.ID = ID; + } + catch (ArgumentException e) + { + MessageBox.Show(this, e.Message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - // Parent ID - try - { - EncryptedString ParentID = new EncryptedString(txtParentID.Text); - result.ParentID = ParentID; - } - catch (ArgumentException e) - { - MessageBox.Show(this, e.Message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } + // Parent ID + try + { + EncryptedString ParentID = new(txtParentID.Text); + result.ParentID = ParentID; + } + catch (ArgumentException e) + { + MessageBox.Show(this, e.Message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - // Wheel name - result.WheelType = txtWheels.Text; - if (result.WheelType.Trim().Length == 0) - { - MessageBox.Show(this, "Wheel name cannot be left blank.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } + // Wheel name + result.WheelType = txtWheels.Text; + if (result.WheelType.Trim().Length == 0) + { + MessageBox.Show(this, "Wheel name cannot be left blank.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - // Vehicle name - result.CarName = txtName.Text; - if (result.CarName.Trim().Length == 0) - { - MessageBox.Show(this, "Car name cannot be left blank.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } + // Vehicle name + result.CarName = txtName.Text; + if (result.CarName.Trim().Length == 0) + { + MessageBox.Show(this, "Car name cannot be left blank.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - // Manufacturer name - result.CarBrand = txtBrand.Text; - if (result.CarBrand.Trim().Length == 0) - { - MessageBox.Show(this, "Manufacturer cannot be left blank.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } + // Manufacturer name + result.CarBrand = txtBrand.Text; + if (result.CarBrand.Trim().Length == 0) + { + MessageBox.Show(this, "Manufacturer cannot be left blank.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - // Damage limit - if (float.TryParse(txtDamageLimit.Text, out float damageLimit)) - { - result.DamageLimit = damageLimit; - } - else - { - MessageBox.Show(this, "Damage limit is invalid.\nEnsure the value is a decimal number.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } + // Damage limit + if (float.TryParse(txtDamageLimit.Text, out float damageLimit)) + { + result.DamageLimit = damageLimit; + } + else + { + MessageBox.Show(this, "Damage limit is invalid.\nEnsure the value is a decimal number.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - // Flags - // Ensure only valid flags are used - if ((uint)Vehicle.Flags < 0x4000000) + // Flags + // Ensure only valid flags are used + if ((uint)Vehicle.Flags < 0x4000000) + { + // Write flags based on whether CheckedListBox fields are checked + uint flags = 0; + for (int i = 0; i < chlFlags.Items.Count; ++i) { - // Write flags based on whether CheckedListBox fields are checked - uint flags = 0; - for (int i = 0; i < chlFlags.Items.Count; ++i) + if ((int)chlFlags.GetItemCheckState(i) == 1) { - if ((int)chlFlags.GetItemCheckState(i) == 1) - { - flags += (uint)(1 << i); - } + flags += (uint)(1 << i); } - result.Flags = (Flags)flags; - } - else - { - MessageBox.Show(this, "Invalid flags used.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; } + result.Flags = (Flags)flags; + } + else + { + MessageBox.Show(this, "Invalid flags used.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - // Boost length - if (byte.TryParse(txtBoostLength.Text, out byte boostLength)) - { - result.BoostLength = boostLength; - } - else - { - MessageBox.Show(this, "Boost length is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } + // Boost length + if (byte.TryParse(txtBoostLength.Text, out byte boostLength)) + { + result.BoostLength = boostLength; + } + else + { + MessageBox.Show(this, "Boost length is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - // Rank - if (byte.TryParse(cboRank.SelectedIndex.ToString(), out byte rank)) - { - result.VehicleRank = (VehicleRank)rank; - } - else - { - MessageBox.Show(this, "Rank is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } + // Rank + if (byte.TryParse(cboRank.SelectedIndex.ToString(), out byte rank)) + { + result.VehicleRank = (VehicleRank)rank; + } + else + { + MessageBox.Show(this, "Rank is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - // Boost capacity - if (byte.TryParse(txtBoostCapacity.Text, out byte boostCapacity)) - { - result.BoostCapacity = boostCapacity; - } - else - { - MessageBox.Show(this, "Boost capacity is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } + // Boost capacity + if (byte.TryParse(txtBoostCapacity.Text, out byte boostCapacity)) + { + result.BoostCapacity = boostCapacity; + } + else + { + MessageBox.Show(this, "Boost capacity is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - // Strength stat - if (byte.TryParse(txtStrengthStat.Text, out byte displayStrength)) - { - result.DisplayStrength = displayStrength; - } - else - { - MessageBox.Show(this, "Strength stat is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } + // Strength stat + if (byte.TryParse(txtStrengthStat.Text, out byte displayStrength)) + { + result.DisplayStrength = displayStrength; + } + else + { + MessageBox.Show(this, "Strength stat is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - // AttribSys ID - if (long.TryParse(txtAttribSysCollectionKey.Text, out long attribsysId)) - { - result.AttribSysCollectionKey = attribsysId; - } - else - { - MessageBox.Show(this, "AttribSys ID is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } + // AttribSys ID + if (long.TryParse(txtAttribSysCollectionKey.Text, out long attribsysId)) + { + result.AttribSysCollectionKey = attribsysId; + } + else + { + MessageBox.Show(this, "AttribSys ID is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - // Exhaust name - if (txtExhaustName.Text.Trim().Length == 0) - { - MessageBox.Show(this, "Exhaust name cannot be left blank.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } - try - { - EncryptedString OtherID1 = new EncryptedString(txtExhaustName.Text); - result.ExhaustName = OtherID1; - } - catch (ArgumentException e) - { - MessageBox.Show(this, e.Message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } + // Exhaust name + if (txtExhaustName.Text.Trim().Length == 0) + { + MessageBox.Show(this, "Exhaust name cannot be left blank.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } + try + { + EncryptedString OtherID1 = new(txtExhaustName.Text); + result.ExhaustName = OtherID1; + } + catch (ArgumentException e) + { + MessageBox.Show(this, e.Message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - // Exhaust ID - if (long.TryParse(txtExhaustID.Text, out long group1)) - { - result.ExhaustID = group1; - } - else - { - MessageBox.Show(this, "Exhaust ID is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } + // Exhaust ID + if (long.TryParse(txtExhaustID.Text, out long group1)) + { + result.ExhaustID = group1; + } + else + { + MessageBox.Show(this, "Exhaust ID is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - // Engine ID - if (long.TryParse(txtEngineID.Text, out long group2)) - { - result.EngineID = group2; - } - else - { - MessageBox.Show(this, "Engine ID is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } + // Engine ID + if (long.TryParse(txtEngineID.Text, out long group2)) + { + result.EngineID = group2; + } + else + { + MessageBox.Show(this, "Engine ID is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - // Engine name - if (txtEngineName.Text.Trim().Length == 0) - { - MessageBox.Show(this, "Engine name cannot be left blank.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } - try - { - EncryptedString OtherID2 = new EncryptedString(txtEngineName.Text); - result.EngineName = OtherID2; - } - catch (ArgumentException e) - { - MessageBox.Show(this, e.Message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } + // Engine name + if (txtEngineName.Text.Trim().Length == 0) + { + MessageBox.Show(this, "Engine name cannot be left blank.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } + try + { + EncryptedString OtherID2 = new(txtEngineName.Text); + result.EngineName = OtherID2; + } + catch (ArgumentException e) + { + MessageBox.Show(this, e.Message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - // Class unlock stream hash - if (uint.TryParse(cboClassUnlock.SelectedIndex.ToString(), out uint classUnlock)) - { - switch (classUnlock) - { - case 0: - classUnlock = 0x0470A5BF; - break; - case 1: - classUnlock = 0x48346FEF; - break; - case 2: - classUnlock = 0x817B91D9; - break; - case 3: - classUnlock = 0xA3E2D8C9; - break; - case 4: - classUnlock = 0xB3845465; - break; - case 5: - classUnlock = 0xEBE39AE9; - break; - } - result.ClassUnlockStreamHash = (ClassUnlock)classUnlock; - } - else + // Class unlock stream hash + if (uint.TryParse(cboClassUnlock.SelectedIndex.ToString(), out uint classUnlock)) + { + switch (classUnlock) { - MessageBox.Show(this, "Please select a class unlock stream option.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; + case 0: + classUnlock = 0x0470A5BF; + break; + case 1: + classUnlock = 0x48346FEF; + break; + case 2: + classUnlock = 0x817B91D9; + break; + case 3: + classUnlock = 0xA3E2D8C9; + break; + case 4: + classUnlock = 0xB3845465; + break; + case 5: + classUnlock = 0xEBE39AE9; + break; } + result.ClassUnlockStreamHash = (ClassUnlock)classUnlock; + } + else + { + MessageBox.Show(this, "Please select a class unlock stream option.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - // Car won stream ID - if (long.TryParse(txtCarWon.Text, out long carWon)) - { - result.CarShutdownStreamID = carWon; - } - else - { - MessageBox.Show(this, "Car won voiceover stream ID is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } + // Car won stream ID + if (long.TryParse(txtCarWon.Text, out long carWon)) + { + result.CarShutdownStreamID = carWon; + } + else + { + MessageBox.Show(this, "Car won voiceover stream ID is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - // Car released stream ID - if (long.TryParse(txtCarReleased.Text, out long carReleased)) - { - result.CarReleasedStreamID = carReleased; - } - else - { - MessageBox.Show(this, "Car released voiceover stream ID is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } + // Car released stream ID + if (long.TryParse(txtCarReleased.Text, out long carReleased)) + { + result.CarReleasedStreamID = carReleased; + } + else + { + MessageBox.Show(this, "Car released voiceover stream ID is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - // AI music loop stream hash - if (uint.TryParse(cboAIMusic.SelectedIndex.ToString(), out uint aiMusic)) - { - switch (aiMusic) - { - case 0: - aiMusic = 0; - break; - case 1: - aiMusic = 0xA9813C9D; - break; - case 2: - aiMusic = 0xCB72AEA7; - break; - case 3: - aiMusic = 0x284D944B; - break; - case 4: - aiMusic = 0xD95C2309; - break; - case 5: - aiMusic = 0x8A1A90E9; - break; - case 6: - aiMusic = 0xB12A34DD; - break; - } - result.AIMusicHash = (AIMusic)aiMusic; - } - else + // AI music loop stream hash + if (uint.TryParse(cboAIMusic.SelectedIndex.ToString(), out uint aiMusic)) + { + switch (aiMusic) { - MessageBox.Show(this, "Please select an AI music loop option.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; + case 0: + aiMusic = 0; + break; + case 1: + aiMusic = 0xA9813C9D; + break; + case 2: + aiMusic = 0xCB72AEA7; + break; + case 3: + aiMusic = 0x284D944B; + break; + case 4: + aiMusic = 0xD95C2309; + break; + case 5: + aiMusic = 0x8A1A90E9; + break; + case 6: + aiMusic = 0xB12A34DD; + break; } + result.AIMusicHash = (AIMusic)aiMusic; + } + else + { + MessageBox.Show(this, "Please select an AI music loop option.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - // AI exhuast index - if (byte.TryParse(cboAIExhaust1.SelectedIndex.ToString(), out byte aiEx1)) - { - result.AIExhaustIndex = (AIExhaustIndex)aiEx1; - } - else - { - MessageBox.Show(this, "Please select an AI exhaust option.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } + // AI exhuast index + if (byte.TryParse(cboAIExhaust1.SelectedIndex.ToString(), out byte aiEx1)) + { + result.AIExhaustIndex = (AIExhaustIndex)aiEx1; + } + else + { + MessageBox.Show(this, "Please select an AI exhaust option.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - // AI exhuast index 2 - if (byte.TryParse(cboAIExhaust2.SelectedIndex.ToString(), out byte aiEx2)) - { - result.AIExhaustIndex2 = (AIExhaustIndex)aiEx2; - } - else - { - MessageBox.Show(this, "Please select an AI exhuast 2 option.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } + // AI exhuast index 2 + if (byte.TryParse(cboAIExhaust2.SelectedIndex.ToString(), out byte aiEx2)) + { + result.AIExhaustIndex2 = (AIExhaustIndex)aiEx2; + } + else + { + MessageBox.Show(this, "Please select an AI exhuast 2 option.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - // AI exhuast index 3 - if (byte.TryParse(cboAIExhaust3.SelectedIndex.ToString(), out byte aiEx3)) - { - result.AIExhaustIndex3 = (AIExhaustIndex)aiEx3; - } - else - { - MessageBox.Show(this, "Please select an AI exhuast 3 option.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } + // AI exhuast index 3 + if (byte.TryParse(cboAIExhaust3.SelectedIndex.ToString(), out byte aiEx3)) + { + result.AIExhaustIndex3 = (AIExhaustIndex)aiEx3; + } + else + { + MessageBox.Show(this, "Please select an AI exhuast 3 option.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - // Vehicle category - if ((uint)Vehicle.Category < 0x100) + // Vehicle category + if ((uint)Vehicle.Category < 0x100) + { + uint cat = 0; + for (int i = 0; i < chlCategory.Items.Count; ++i) { - uint cat = 0; - for (int i = 0; i < chlCategory.Items.Count; ++i) + if ((int)chlCategory.GetItemCheckState(i) == 1) { - if ((int)chlCategory.GetItemCheckState(i) == 1) - { - cat += (uint)(1 << i); - } + cat += (uint)(1 << i); } - result.Category = (VehicleCategory)cat; - } - else - { - MessageBox.Show(this, "Invalid category selected.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } - - // Vehicle type - if (int.TryParse(cboVehicleType.SelectedIndex.ToString(), out int vehType)) - { - result.VehicleType = (VehicleType)vehType; - } - else - { - MessageBox.Show(this, "Please select a vehicle type.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } - - // Boost type - if (byte.TryParse(cboBoostType.SelectedIndex.ToString(), out byte boostType)) - { - result.BoostType = (BoostType)boostType; - } - else - { - MessageBox.Show(this, "Please select a boost type.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } - - // Finish type - if (byte.TryParse(cboFinishType.SelectedIndex.ToString(), out byte finishType)) - { - result.FinishType = (FinishType)cboFinishType.SelectedIndex; - } - else - { - MessageBox.Show(this, "Please select a finish type.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; } + result.Category = (VehicleCategory)cat; + } + else + { + MessageBox.Show(this, "Invalid category selected.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - // Max speed - if (byte.TryParse(txtMaxSpeed.Text, out byte maxSpeed)) - { - result.MaxSpeedNoBoost = maxSpeed; - } - else - { - MessageBox.Show(this, "Max speed is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } + // Vehicle type + if (int.TryParse(cboVehicleType.SelectedIndex.ToString(), out int vehType)) + { + result.VehicleType = (VehicleType)vehType; + } + else + { + MessageBox.Show(this, "Please select a vehicle type.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - // Max boost speed - if (byte.TryParse(txtMaxBoostSpeed.Text, out byte maxBoostSpeed)) - { - result.MaxSpeedBoost = maxBoostSpeed; - } - else - { - MessageBox.Show(this, "Max boost speed is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } + // Boost type + if (byte.TryParse(cboBoostType.SelectedIndex.ToString(), out byte boostType)) + { + result.BoostType = (BoostType)boostType; + } + else + { + MessageBox.Show(this, "Please select a boost type.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - // Speed stat - if (byte.TryParse(txtSpeedStat.Text, out byte displaySpeed)) - { - result.DisplaySpeed = displaySpeed; - } - else - { - MessageBox.Show(this, "Speed stat is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } + // Finish type + if (byte.TryParse(cboFinishType.SelectedIndex.ToString(), out byte finishType)) + { + result.FinishType = (FinishType)cboFinishType.SelectedIndex; + } + else + { + MessageBox.Show(this, "Please select a finish type.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - // Boost stat - if (byte.TryParse(txtBoostStat.Text, out byte displayBoost)) - { - result.DisplayBoost = displayBoost; - } - else - { - MessageBox.Show(this, "Boost stat is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } + // Max speed + if (byte.TryParse(txtMaxSpeed.Text, out byte maxSpeed)) + { + result.MaxSpeedNoBoost = maxSpeed; + } + else + { + MessageBox.Show(this, "Max speed is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - // Color index - if (byte.TryParse(txtColor.Text, out byte color)) - { - result.Color = color; - } - else - { - MessageBox.Show(this, "Color index is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } + // Max boost speed + if (byte.TryParse(txtMaxBoostSpeed.Text, out byte maxBoostSpeed)) + { + result.MaxSpeedBoost = maxBoostSpeed; + } + else + { + MessageBox.Show(this, "Max boost speed is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - // Color type - if (byte.TryParse(cboColorType.SelectedIndex.ToString(), out byte colorType)) - { - result.ColorType = (ColorType)colorType; - } - else - { - MessageBox.Show(this, "Please select a color type.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } + // Speed stat + if (byte.TryParse(txtSpeedStat.Text, out byte displaySpeed)) + { + result.DisplaySpeed = displaySpeed; + } + else + { + MessageBox.Show(this, "Speed stat is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - return result; + // Boost stat + if (byte.TryParse(txtBoostStat.Text, out byte displayBoost)) + { + result.DisplayBoost = displayBoost; + } + else + { + MessageBox.Show(this, "Boost stat is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; } - private void btnCancel_Click(object sender, EventArgs e) + // Color index + if (byte.TryParse(txtColor.Text, out byte color)) { - Close(); + result.Color = color; + } + else + { + MessageBox.Show(this, "Color index is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; } - private void btnOk_Click(object sender, EventArgs e) + // Color type + if (byte.TryParse(cboColorType.SelectedIndex.ToString(), out byte colorType)) { - Vehicle retVehicle = GetModifiedVehicle(); - if (retVehicle == null) - { - return; - } + result.ColorType = (ColorType)colorType; + } + else + { + MessageBox.Show(this, "Please select a color type.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } + + return result; + } - OnDone?.Invoke(retVehicle); + private void btnCancel_Click(object sender, EventArgs e) + { + Close(); + } - Close(); + private void btnOk_Click(object sender, EventArgs e) + { + Vehicle retVehicle = GetModifiedVehicle(); + if (retVehicle == null) + { + return; } + + OnDone?.Invoke(retVehicle); + + Close(); } } diff --git a/VehicleList/VehicleListData.cs b/VehicleList/VehicleListData.cs index d78683f..25257ab 100644 --- a/VehicleList/VehicleListData.cs +++ b/VehicleList/VehicleListData.cs @@ -6,399 +6,398 @@ using System.IO; using System.Text; -namespace VehicleList +namespace VehicleList; + +[Flags] +public enum Flags { - [Flags] - public enum Flags - { - IsRaceVehicle = 1, - CanCheckTraffic = 1 << 1, - CanBeChecked = 1 << 2, - IsTrailer = 1 << 3, - CanTowTrailer = 1 << 4, - CanBePainted = 1 << 5, - Unknown0 = 1 << 6, - IsFirstInSpeedRange = 1 << 7, - HasSwitchableBoost = 1 << 8, - Unknown1 = 1 << 9, - Unknown2 = 1 << 10, - IsWIP = 1 << 11, - IsFromV10 = 1 << 12, - IsFromV13 = 1 << 13, - IsFromV14 = 1 << 14, - IsFromV15 = 1 << 15, - IsFromV16 = 1 << 16, - IsFromV17 = 1 << 17, - IsFromV18 = 1 << 18, - IsFromV19 = 1 << 19 - } + IsRaceVehicle = 1, + CanCheckTraffic = 1 << 1, + CanBeChecked = 1 << 2, + IsTrailer = 1 << 3, + CanTowTrailer = 1 << 4, + CanBePainted = 1 << 5, + Unknown0 = 1 << 6, + IsFirstInSpeedRange = 1 << 7, + HasSwitchableBoost = 1 << 8, + Unknown1 = 1 << 9, + Unknown2 = 1 << 10, + IsWIP = 1 << 11, + IsFromV10 = 1 << 12, + IsFromV13 = 1 << 13, + IsFromV14 = 1 << 14, + IsFromV15 = 1 << 15, + IsFromV16 = 1 << 16, + IsFromV17 = 1 << 17, + IsFromV18 = 1 << 18, + IsFromV19 = 1 << 19 +} - public enum VehicleRank - { - LEARNER, - D_CLASS, - C_CLASS, - B_CLASS, - A_CLASS, - BURNOUT - } +public enum VehicleRank +{ + LEARNER, + D_CLASS, + C_CLASS, + B_CLASS, + A_CLASS, + BURNOUT +} - public enum ClassUnlock : uint - { - SuperClassUnlock = 0x0470A5BF, - MuscleClassUnlock = 0x48346FEF, - F1ClassUnlock = 0x817B91D9, - TunerClassUnlock = 0xA3E2D8C9, - HotRodClassUnlock = 0xB3845465, - RivalGen = 0xEBE39AE9 - } +public enum ClassUnlock : uint +{ + SuperClassUnlock = 0x0470A5BF, + MuscleClassUnlock = 0x48346FEF, + F1ClassUnlock = 0x817B91D9, + TunerClassUnlock = 0xA3E2D8C9, + HotRodClassUnlock = 0xB3845465, + RivalGen = 0xEBE39AE9 +} - public enum AIMusic : uint - { - None, - Muscle = 0xA9813C9D, - Truck = 0xCB72AEA7, - Tuner = 0x284D944B, - Sedan = 0xD95C2309, - Exotic = 0x8A1A90E9, - Super = 0xB12A34DD - } +public enum AIMusic : uint +{ + None, + Muscle = 0xA9813C9D, + Truck = 0xCB72AEA7, + Tuner = 0x284D944B, + Sedan = 0xD95C2309, + Exotic = 0x8A1A90E9, + Super = 0xB12A34DD +} - public enum AIExhaustIndex - { - None, - AIROD_EX, - AI_CIVIC_EX, - AI_GT_ENG, - AI_MUST_EX, - AI_F1_EX - } +public enum AIExhaustIndex +{ + None, + AIROD_EX, + AI_CIVIC_EX, + AI_GT_ENG, + AI_MUST_EX, + AI_F1_EX +} - [Flags] - public enum VehicleCategory - { - NONE, - PARADISE_CARS = 1, - PARADISE_BIKES = 1 << 1, - ONLINE_CARS = 1 << 2, - TOYS = 1 << 3, - LEGENDARY_CARS = 1 << 4, - BOOST_SPECIALS = 1 << 5, - COP_CARS = 1 << 6, - ISLAND_CARS = 1 << 7 - } - - public enum VehicleType +[Flags] +public enum VehicleCategory +{ + NONE, + PARADISE_CARS = 1, + PARADISE_BIKES = 1 << 1, + ONLINE_CARS = 1 << 2, + TOYS = 1 << 3, + LEGENDARY_CARS = 1 << 4, + BOOST_SPECIALS = 1 << 5, + COP_CARS = 1 << 6, + ISLAND_CARS = 1 << 7 +} + +public enum VehicleType +{ + CAR, + BIKE, + PLANE +} + +public enum BoostType +{ + SPEED, + AGGRESSION, + STUNT, + NONE, + LOCKED +} + +public enum FinishType +{ + DEFAULT, + COLOUR, + PATTERN, + SILVER, + GOLD, + COMMUNITY +} + +public enum ColorType +{ + GLOSS, + METALLIC, + PEARLESCENT, + SPECIAL, + UNKNOWN +} + +public class VehicleListData : IEntryData +{ + public int Unknown1; + public int Unknown2; + public List Entries; + + public VehicleListData() { - CAR, - BIKE, - PLANE + Entries = []; } - public enum BoostType + public IEntryEditor GetEditor(BundleEntry entry) { - SPEED, - AGGRESSION, - STUNT, - NONE, - LOCKED + VehicleListForm vehicleList = new(); + vehicleList.List = this; + vehicleList.Edit += () => + { + Write(entry); + }; + + return vehicleList; } - public enum FinishType + public EntryType GetEntryType(BundleEntry entry) { - DEFAULT, - COLOUR, - PATTERN, - SILVER, - GOLD, - COMMUNITY + return EntryType.VehicleList; } - public enum ColorType + private void Clear() { - GLOSS, - METALLIC, - PEARLESCENT, - SPECIAL, - UNKNOWN + Unknown1 = default; + Unknown2 = default; + Entries.Clear(); } - public class VehicleListData : IEntryData + public bool Read(BundleEntry entry, ILoader loader = null) { - public int Unknown1; - public int Unknown2; - public List Entries; + Clear(); - public VehicleListData() - { - Entries = new List(); - } - - public IEntryEditor GetEditor(BundleEntry entry) - { - VehicleListForm vehicleList = new VehicleListForm(); - vehicleList.List = this; - vehicleList.Edit += () => - { - Write(entry); - }; + MemoryStream ms = new(entry.EntryBlocks[0].Data); + BinaryReader2 br = new(ms); + br.BigEndian = entry.Console; - return vehicleList; - } + bool x64 = entry.Platform == BundlePlatform.PCx64; - public EntryType GetEntryType(BundleEntry entry) - { - return EntryType.VehicleList; - } + int count = br.ReadInt32(); + int startOff = br.ReadInt32(); - private void Clear() - { - Unknown1 = default; - Unknown2 = default; - Entries.Clear(); - } + Unknown1 = br.ReadInt32(); + Unknown2 = br.ReadInt32(); - public bool Read(BundleEntry entry, ILoader loader = null) + for (int i = 0; i < count; i++) { - Clear(); - - MemoryStream ms = new MemoryStream(entry.EntryBlocks[0].Data); - BinaryReader2 br = new BinaryReader2(ms); - br.BigEndian = entry.Console; - - bool x64 = entry.Platform == BundlePlatform.PCx64; - - int count = br.ReadInt32(); - int startOff = br.ReadInt32(); - - Unknown1 = br.ReadInt32(); - Unknown2 = br.ReadInt32(); - - for (int i = 0; i < count; i++) + Vehicle vehicle = new(); + + vehicle.Index = i; + + vehicle.ID = new EncryptedString(br.ReadUInt64()); + vehicle.ParentID = new EncryptedString(br.ReadUInt64()); + vehicle.WheelType = Encoding.ASCII.GetString(br.ReadBytes(32)); + vehicle.CarName = Encoding.ASCII.GetString(br.ReadBytes(64)); + vehicle.CarBrand = Encoding.ASCII.GetString(br.ReadBytes(32)); + vehicle.DamageLimit = br.ReadSingle(); + vehicle.Flags = (Flags)br.ReadInt32(); + vehicle.BoostLength = br.ReadByte(); + vehicle.VehicleRank = (VehicleRank)br.ReadByte(); + vehicle.BoostCapacity = br.ReadByte(); + vehicle.DisplayStrength = br.ReadByte(); + vehicle.padding0 = br.ReadInt32(); + vehicle.AttribSysCollectionKey = br.ReadInt64(); + vehicle.ExhaustName = new EncryptedString(br.ReadUInt64()); + vehicle.ExhaustID = br.ReadInt64(); + vehicle.EngineID = br.ReadInt64(); + vehicle.EngineName = new EncryptedString(br.ReadUInt64()); + vehicle.ClassUnlockStreamHash = (ClassUnlock)br.ReadInt32(); + vehicle.padding1 = br.ReadInt32(); + vehicle.CarShutdownStreamID = br.ReadInt64(); + vehicle.CarReleasedStreamID = br.ReadInt64(); + vehicle.AIMusicHash = (AIMusic)br.ReadInt32(); + vehicle.AIExhaustIndex = (AIExhaustIndex)br.ReadByte(); + vehicle.AIExhaustIndex2 = (AIExhaustIndex)br.ReadByte(); + vehicle.AIExhaustIndex3 = (AIExhaustIndex)br.ReadByte(); + vehicle.padding2 = br.ReadByte(); + if (!x64) { - Vehicle vehicle = new Vehicle(); - - vehicle.Index = i; - - vehicle.ID = new EncryptedString(br.ReadUInt64()); - vehicle.ParentID = new EncryptedString(br.ReadUInt64()); - vehicle.WheelType = Encoding.ASCII.GetString(br.ReadBytes(32)); - vehicle.CarName = Encoding.ASCII.GetString(br.ReadBytes(64)); - vehicle.CarBrand = Encoding.ASCII.GetString(br.ReadBytes(32)); - vehicle.DamageLimit = br.ReadSingle(); - vehicle.Flags = (Flags)br.ReadInt32(); - vehicle.BoostLength = br.ReadByte(); - vehicle.VehicleRank = (VehicleRank)br.ReadByte(); - vehicle.BoostCapacity = br.ReadByte(); - vehicle.DisplayStrength = br.ReadByte(); - vehicle.padding0 = br.ReadInt32(); - vehicle.AttribSysCollectionKey = br.ReadInt64(); - vehicle.ExhaustName = new EncryptedString(br.ReadUInt64()); - vehicle.ExhaustID = br.ReadInt64(); - vehicle.EngineID = br.ReadInt64(); - vehicle.EngineName = new EncryptedString(br.ReadUInt64()); - vehicle.ClassUnlockStreamHash = (ClassUnlock)br.ReadInt32(); - vehicle.padding1 = br.ReadInt32(); - vehicle.CarShutdownStreamID = br.ReadInt64(); - vehicle.CarReleasedStreamID = br.ReadInt64(); - vehicle.AIMusicHash = (AIMusic)br.ReadInt32(); - vehicle.AIExhaustIndex = (AIExhaustIndex)br.ReadByte(); - vehicle.AIExhaustIndex2 = (AIExhaustIndex)br.ReadByte(); - vehicle.AIExhaustIndex3 = (AIExhaustIndex)br.ReadByte(); - vehicle.padding2 = br.ReadByte(); - if (!x64) - { - vehicle.Unknown[0] = br.ReadInt64(); - vehicle.Unknown[1] = br.ReadInt64(); - vehicle.Category = (VehicleCategory)br.ReadInt32(); - } - vehicle.VehicleAndBoostType = br.ReadByte(); - vehicle.FinishType = (FinishType)br.ReadByte(); - vehicle.MaxSpeedNoBoost = br.ReadByte(); - vehicle.MaxSpeedBoost = br.ReadByte(); - vehicle.DisplaySpeed = br.ReadByte(); - vehicle.DisplayBoost = br.ReadByte(); - vehicle.Color = br.ReadByte(); - vehicle.ColorType = (ColorType)br.ReadByte(); - if (!x64) - vehicle.padding3 = br.ReadInt32(); - - vehicle.VehicleType = (VehicleType)(vehicle.VehicleAndBoostType >> 4 & 0xF); // High nibble - vehicle.BoostType = (BoostType)(vehicle.VehicleAndBoostType & 0xF); // Low nibble - - Entries.Add(vehicle); + vehicle.Unknown[0] = br.ReadInt64(); + vehicle.Unknown[1] = br.ReadInt64(); + vehicle.Category = (VehicleCategory)br.ReadInt32(); } - - br.Close(); - return true; + vehicle.VehicleAndBoostType = br.ReadByte(); + vehicle.FinishType = (FinishType)br.ReadByte(); + vehicle.MaxSpeedNoBoost = br.ReadByte(); + vehicle.MaxSpeedBoost = br.ReadByte(); + vehicle.DisplaySpeed = br.ReadByte(); + vehicle.DisplayBoost = br.ReadByte(); + vehicle.Color = br.ReadByte(); + vehicle.ColorType = (ColorType)br.ReadByte(); + if (!x64) + vehicle.padding3 = br.ReadInt32(); + + vehicle.VehicleType = (VehicleType)(vehicle.VehicleAndBoostType >> 4 & 0xF); // High nibble + vehicle.BoostType = (BoostType)(vehicle.VehicleAndBoostType & 0xF); // Low nibble + + Entries.Add(vehicle); } - public bool Write(BundleEntry entry) - { - MemoryStream ms = new MemoryStream(); - BinaryWriter2 bw = new BinaryWriter2(ms); - bw.BigEndian = entry.Console; + br.Close(); + return true; + } - bool x64 = entry.Platform == BundlePlatform.PCx64; + public bool Write(BundleEntry entry) + { + MemoryStream ms = new(); + BinaryWriter2 bw = new(ms); + bw.BigEndian = entry.Console; + + bool x64 = entry.Platform == BundlePlatform.PCx64; - bw.Write(Entries.Count); - bw.Write(0x10); - bw.Write(Unknown1); - bw.Write(Unknown2); + bw.Write(Entries.Count); + bw.Write(0x10); + bw.Write(Unknown1); + bw.Write(Unknown2); - for (int i = 0; i < Entries.Count; i++) + for (int i = 0; i < Entries.Count; i++) + { + Vehicle vehicle = Entries[i]; + + // Need to create the correct byte before writing + vehicle.VehicleAndBoostType = (byte)(((byte)vehicle.VehicleType << 4) + (byte)vehicle.BoostType); + + bw.Write(vehicle.ID.Encrypted); + bw.Write(vehicle.ParentID.Encrypted); + bw.WriteLenString(vehicle.WheelType, 32); + bw.WriteLenString(vehicle.CarName, 64); + bw.WriteLenString(vehicle.CarBrand, 32); + bw.Write(vehicle.DamageLimit); + bw.Write((uint)vehicle.Flags); + bw.Write(vehicle.BoostLength); + bw.Write((byte)vehicle.VehicleRank); + bw.Write(vehicle.BoostCapacity); + bw.Write(vehicle.DisplayStrength); + bw.Write(vehicle.padding0); + bw.Write(vehicle.AttribSysCollectionKey); + bw.Write(vehicle.ExhaustName.Encrypted); + bw.Write(vehicle.ExhaustID); + bw.Write(vehicle.EngineID); + bw.Write(vehicle.EngineName.Encrypted); + bw.Write((uint)vehicle.ClassUnlockStreamHash); + bw.Write(vehicle.padding1); + bw.Write(vehicle.CarShutdownStreamID); + bw.Write(vehicle.CarReleasedStreamID); + bw.Write((uint)vehicle.AIMusicHash); + bw.Write((byte)vehicle.AIExhaustIndex); + bw.Write((byte)vehicle.AIExhaustIndex2); + bw.Write((byte)vehicle.AIExhaustIndex3); + bw.Write(vehicle.padding2); + if (!x64) { - Vehicle vehicle = Entries[i]; - - // Need to create the correct byte before writing - vehicle.VehicleAndBoostType = (byte)(((byte)vehicle.VehicleType << 4) + (byte)vehicle.BoostType); - - bw.Write(vehicle.ID.Encrypted); - bw.Write(vehicle.ParentID.Encrypted); - bw.WriteLenString(vehicle.WheelType, 32); - bw.WriteLenString(vehicle.CarName, 64); - bw.WriteLenString(vehicle.CarBrand, 32); - bw.Write(vehicle.DamageLimit); - bw.Write((uint)vehicle.Flags); - bw.Write(vehicle.BoostLength); - bw.Write((byte)vehicle.VehicleRank); - bw.Write(vehicle.BoostCapacity); - bw.Write(vehicle.DisplayStrength); - bw.Write(vehicle.padding0); - bw.Write(vehicle.AttribSysCollectionKey); - bw.Write(vehicle.ExhaustName.Encrypted); - bw.Write(vehicle.ExhaustID); - bw.Write(vehicle.EngineID); - bw.Write(vehicle.EngineName.Encrypted); - bw.Write((uint)vehicle.ClassUnlockStreamHash); - bw.Write(vehicle.padding1); - bw.Write(vehicle.CarShutdownStreamID); - bw.Write(vehicle.CarReleasedStreamID); - bw.Write((uint)vehicle.AIMusicHash); - bw.Write((byte)vehicle.AIExhaustIndex); - bw.Write((byte)vehicle.AIExhaustIndex2); - bw.Write((byte)vehicle.AIExhaustIndex3); - bw.Write(vehicle.padding2); - if (!x64) - { - bw.Write(vehicle.Unknown[0]); - bw.Write(vehicle.Unknown[1]); - bw.Write((uint)vehicle.Category); - } - bw.Write(vehicle.VehicleAndBoostType); - bw.Write((byte)vehicle.FinishType); - bw.Write(vehicle.MaxSpeedNoBoost); - bw.Write(vehicle.MaxSpeedBoost); - bw.Write(vehicle.DisplaySpeed); - bw.Write(vehicle.DisplayBoost); - bw.Write(vehicle.Color); - bw.Write((byte)vehicle.ColorType); - if (!x64) - bw.Write(vehicle.padding3); + bw.Write(vehicle.Unknown[0]); + bw.Write(vehicle.Unknown[1]); + bw.Write((uint)vehicle.Category); } + bw.Write(vehicle.VehicleAndBoostType); + bw.Write((byte)vehicle.FinishType); + bw.Write(vehicle.MaxSpeedNoBoost); + bw.Write(vehicle.MaxSpeedBoost); + bw.Write(vehicle.DisplaySpeed); + bw.Write(vehicle.DisplayBoost); + bw.Write(vehicle.Color); + bw.Write((byte)vehicle.ColorType); + if (!x64) + bw.Write(vehicle.padding3); + } - bw.Flush(); - byte[] data = ms.ToArray(); - bw.Close(); - ms.Close(); + bw.Flush(); + byte[] data = ms.ToArray(); + bw.Close(); + ms.Close(); - entry.EntryBlocks[0].Data = data; - entry.Dirty = true; + entry.EntryBlocks[0].Data = data; + entry.Dirty = true; - return true; - } + return true; } +} - public class Vehicle +public class Vehicle +{ + public int Index; + public EncryptedString ID; + public EncryptedString ParentID; + public string WheelType; + public string CarName; + public string CarBrand; + public float DamageLimit; + public Flags Flags; + public byte BoostLength; + public VehicleRank VehicleRank; + public byte BoostCapacity; + public byte DisplayStrength; + public int padding0; + public long AttribSysCollectionKey; + public EncryptedString ExhaustName; + public long ExhaustID; + public long EngineID; + public EncryptedString EngineName; + public ClassUnlock ClassUnlockStreamHash; + public int padding1; + public long CarShutdownStreamID; + public long CarReleasedStreamID; + public AIMusic AIMusicHash; + public AIExhaustIndex AIExhaustIndex; + public AIExhaustIndex AIExhaustIndex2; + public AIExhaustIndex AIExhaustIndex3; + public byte padding2; + public long[] Unknown = [0, 0]; // idk C# at all so this forces reading 128 bits in a probably dumb way + public VehicleCategory Category; + public byte VehicleAndBoostType; + public VehicleType VehicleType; + public BoostType BoostType; + public FinishType FinishType; + public byte MaxSpeedNoBoost; + public byte MaxSpeedBoost; + public byte DisplaySpeed; + public byte DisplayBoost; + public byte Color; + public ColorType ColorType; + public int padding3; + + public Vehicle() { - public int Index; - public EncryptedString ID; - public EncryptedString ParentID; - public string WheelType; - public string CarName; - public string CarBrand; - public float DamageLimit; - public Flags Flags; - public byte BoostLength; - public VehicleRank VehicleRank; - public byte BoostCapacity; - public byte DisplayStrength; - public int padding0; - public long AttribSysCollectionKey; - public EncryptedString ExhaustName; - public long ExhaustID; - public long EngineID; - public EncryptedString EngineName; - public ClassUnlock ClassUnlockStreamHash; - public int padding1; - public long CarShutdownStreamID; - public long CarReleasedStreamID; - public AIMusic AIMusicHash; - public AIExhaustIndex AIExhaustIndex; - public AIExhaustIndex AIExhaustIndex2; - public AIExhaustIndex AIExhaustIndex3; - public byte padding2; - public long[] Unknown = {0, 0}; // idk C# at all so this forces reading 128 bits in a probably dumb way - public VehicleCategory Category; - public byte VehicleAndBoostType; - public VehicleType VehicleType; - public BoostType BoostType; - public FinishType FinishType; - public byte MaxSpeedNoBoost; - public byte MaxSpeedBoost; - public byte DisplaySpeed; - public byte DisplayBoost; - public byte Color; - public ColorType ColorType; - public int padding3; - - public Vehicle() - { - } + } - public Vehicle(Vehicle copy) - { - Index = copy.Index; - ID = copy.ID; - ParentID = copy.ParentID; - WheelType = copy.WheelType; - CarName = copy.CarName; - CarBrand = copy.CarBrand; - DamageLimit = copy.DamageLimit; - Flags = copy.Flags; - BoostLength = copy.BoostLength; - VehicleRank = copy.VehicleRank; - BoostCapacity = copy.BoostCapacity; - DisplayStrength = copy.DisplayStrength; - padding0 = copy.padding0; - AttribSysCollectionKey = copy.AttribSysCollectionKey; - ExhaustName = copy.ExhaustName; - ExhaustID = copy.ExhaustID; - EngineID = copy.EngineID; - EngineName = copy.EngineName; - ClassUnlockStreamHash = copy.ClassUnlockStreamHash; - padding1 = copy.padding1; - CarShutdownStreamID = copy.CarShutdownStreamID; - CarReleasedStreamID = copy.CarReleasedStreamID; - AIMusicHash = copy.AIMusicHash; - AIExhaustIndex = copy.AIExhaustIndex; - AIExhaustIndex2 = copy.AIExhaustIndex2; - AIExhaustIndex3 = copy.AIExhaustIndex3; - padding2 = copy.padding2; - Unknown = copy.Unknown; - Category = copy.Category; - VehicleAndBoostType = copy.VehicleAndBoostType; - VehicleType = copy.VehicleType; - BoostType = copy.BoostType; - FinishType = copy.FinishType; - MaxSpeedNoBoost = copy.MaxSpeedNoBoost; - MaxSpeedBoost = copy.MaxSpeedBoost; - Color = copy.Color; - ColorType = copy.ColorType; - DisplaySpeed = copy.DisplaySpeed; - DisplayBoost = copy.DisplayBoost; - padding3 = copy.padding3; - } + public Vehicle(Vehicle copy) + { + Index = copy.Index; + ID = copy.ID; + ParentID = copy.ParentID; + WheelType = copy.WheelType; + CarName = copy.CarName; + CarBrand = copy.CarBrand; + DamageLimit = copy.DamageLimit; + Flags = copy.Flags; + BoostLength = copy.BoostLength; + VehicleRank = copy.VehicleRank; + BoostCapacity = copy.BoostCapacity; + DisplayStrength = copy.DisplayStrength; + padding0 = copy.padding0; + AttribSysCollectionKey = copy.AttribSysCollectionKey; + ExhaustName = copy.ExhaustName; + ExhaustID = copy.ExhaustID; + EngineID = copy.EngineID; + EngineName = copy.EngineName; + ClassUnlockStreamHash = copy.ClassUnlockStreamHash; + padding1 = copy.padding1; + CarShutdownStreamID = copy.CarShutdownStreamID; + CarReleasedStreamID = copy.CarReleasedStreamID; + AIMusicHash = copy.AIMusicHash; + AIExhaustIndex = copy.AIExhaustIndex; + AIExhaustIndex2 = copy.AIExhaustIndex2; + AIExhaustIndex3 = copy.AIExhaustIndex3; + padding2 = copy.padding2; + Unknown = copy.Unknown; + Category = copy.Category; + VehicleAndBoostType = copy.VehicleAndBoostType; + VehicleType = copy.VehicleType; + BoostType = copy.BoostType; + FinishType = copy.FinishType; + MaxSpeedNoBoost = copy.MaxSpeedNoBoost; + MaxSpeedBoost = copy.MaxSpeedBoost; + Color = copy.Color; + ColorType = copy.ColorType; + DisplaySpeed = copy.DisplaySpeed; + DisplayBoost = copy.DisplayBoost; + padding3 = copy.padding3; } } diff --git a/VehicleList/VehicleListForm.cs b/VehicleList/VehicleListForm.cs index dd07343..2faafe0 100644 --- a/VehicleList/VehicleListForm.cs +++ b/VehicleList/VehicleListForm.cs @@ -8,436 +8,435 @@ using System.Linq; using System.Windows.Forms; -namespace VehicleList +namespace VehicleList; + +public partial class VehicleListForm : Form, IEntryEditor { - public partial class VehicleListForm : Form, IEntryEditor - { - public delegate void OnEdit(); - public event OnEdit Edit; + public delegate void OnEdit(); + public event OnEdit Edit; - private VehicleListData _list; - private System.Windows.Forms.Timer _searchTimer; + private VehicleListData _list; + private System.Windows.Forms.Timer _searchTimer; - [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] - public VehicleListData List + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public VehicleListData List + { + get => _list; + set { - get => _list; - set - { - _list = value; - UpdateDisplay(); - } + _list = value; + UpdateDisplay(); } + } - public VehicleListForm() - { - InitializeComponent(); - _searchTimer = new System.Windows.Forms.Timer(); - _searchTimer.Interval = 300; - _searchTimer.Tick += SearchTimer_Tick; + public VehicleListForm() + { + InitializeComponent(); + _searchTimer = new System.Windows.Forms.Timer(); + _searchTimer.Interval = 300; + _searchTimer.Tick += SearchTimer_Tick; - tstbSearchItem.Text = "Search by ID, Parent ID, Vehicle or Manufacturer"; - tstbSearchItem.ForeColor = System.Drawing.SystemColors.GrayText; - } + tstbSearchItem.Text = "Search by ID, Parent ID, Vehicle or Manufacturer"; + tstbSearchItem.ForeColor = System.Drawing.SystemColors.GrayText; + } - private void UpdateDisplay(IEnumerable vehiclesToDisplay = null) + private void UpdateDisplay(IEnumerable vehiclesToDisplay = null) + { + lstVehicles.Items.Clear(); + + if (List == null) { - lstVehicles.Items.Clear(); + return; + } - if (List == null) - { - return; - } + // Use provided list for filtered results, otherwise use the full list. + IEnumerable sourceList = vehiclesToDisplay ?? List.Entries; - // Use provided list for filtered results, otherwise use the full list. - IEnumerable sourceList = vehiclesToDisplay ?? List.Entries; + foreach (Vehicle vehicle in sourceList) + { + // The order of these strings must match the order of ColumnHeaders in your ListView. + string[] value = [ + vehicle.Index.ToString(), + vehicle.ID.Value, + vehicle.ParentID.Value, + vehicle.WheelType, + vehicle.CarName, + vehicle.CarBrand, + vehicle.DamageLimit.ToString(), + vehicle.Flags.ToString(), + vehicle.BoostLength.ToString(), + vehicle.VehicleRank.ToString(), + vehicle.BoostCapacity.ToString(), + vehicle.DisplayStrength.ToString(), + vehicle.AttribSysCollectionKey.ToString(), + vehicle.ExhaustName.Value, + vehicle.ExhaustID.ToString(), + vehicle.EngineID.ToString(), + vehicle.EngineName.Value, + vehicle.ClassUnlockStreamHash.ToString(), + vehicle.CarShutdownStreamID.ToString(), + vehicle.CarReleasedStreamID.ToString(), + vehicle.AIMusicHash.ToString(), + vehicle.AIExhaustIndex.ToString(), + vehicle.AIExhaustIndex2.ToString(), + vehicle.AIExhaustIndex3.ToString(), + vehicle.Category.ToString(), + vehicle.VehicleType.ToString(), + vehicle.BoostType.ToString(), + vehicle.FinishType.ToString(), + vehicle.MaxSpeedNoBoost.ToString(), + vehicle.MaxSpeedBoost.ToString(), + vehicle.DisplaySpeed.ToString(), + vehicle.DisplayBoost.ToString(), + vehicle.Color.ToString(), + vehicle.ColorType.ToString() + ]; + lstVehicles.Items.Add(new ListViewItem(value)); + } - foreach (Vehicle vehicle in sourceList) - { - // The order of these strings must match the order of ColumnHeaders in your ListView. - string[] value = { - vehicle.Index.ToString(), - vehicle.ID.Value, - vehicle.ParentID.Value, - vehicle.WheelType, - vehicle.CarName, - vehicle.CarBrand, - vehicle.DamageLimit.ToString(), - vehicle.Flags.ToString(), - vehicle.BoostLength.ToString(), - vehicle.VehicleRank.ToString(), - vehicle.BoostCapacity.ToString(), - vehicle.DisplayStrength.ToString(), - vehicle.AttribSysCollectionKey.ToString(), - vehicle.ExhaustName.Value, - vehicle.ExhaustID.ToString(), - vehicle.EngineID.ToString(), - vehicle.EngineName.Value, - vehicle.ClassUnlockStreamHash.ToString(), - vehicle.CarShutdownStreamID.ToString(), - vehicle.CarReleasedStreamID.ToString(), - vehicle.AIMusicHash.ToString(), - vehicle.AIExhaustIndex.ToString(), - vehicle.AIExhaustIndex2.ToString(), - vehicle.AIExhaustIndex3.ToString(), - vehicle.Category.ToString(), - vehicle.VehicleType.ToString(), - vehicle.BoostType.ToString(), - vehicle.FinishType.ToString(), - vehicle.MaxSpeedNoBoost.ToString(), - vehicle.MaxSpeedBoost.ToString(), - vehicle.DisplaySpeed.ToString(), - vehicle.DisplayBoost.ToString(), - vehicle.Color.ToString(), - vehicle.ColorType.ToString() - }; - lstVehicles.Items.Add(new ListViewItem(value)); - } + // Reapply sorting if a sorter is active. + if (lstVehicles.ListViewItemSorter is VehicleSorter sorter) + { + lstVehicles.Sort(); + } - // Reapply sorting if a sorter is active. - if (lstVehicles.ListViewItemSorter is VehicleSorter sorter) - { - lstVehicles.Sort(); - } + stlStatusLabel.Text = $"{lstVehicles.Items.Count} Item(s) Displayed"; - stlStatusLabel.Text = $"{lstVehicles.Items.Count} Item(s) Displayed"; + // Disable copy/delete buttons as no items are selected after a fresh display/filter. + copyItemToolStripMenuItem.Enabled = false; + deleteItemToolStripMenuItem.Enabled = false; + tsbCopyItem.Enabled = false; + tsbDeleteItem.Enabled = false; + } - // Disable copy/delete buttons as no items are selected after a fresh display/filter. - copyItemToolStripMenuItem.Enabled = false; - deleteItemToolStripMenuItem.Enabled = false; - tsbCopyItem.Enabled = false; - tsbDeleteItem.Enabled = false; + private void PerformSearch(string searchText) + { + if (string.IsNullOrWhiteSpace(searchText) || searchText == "Search by ID, Parent ID, Vehicle or Manufacturer") + { + UpdateDisplay(); + return; } - private void PerformSearch(string searchText) + string lowerSearchText = searchText.ToLowerInvariant(); + + List filteredVehicles = List.Entries.Where(vehicle => { - if (string.IsNullOrWhiteSpace(searchText) || searchText == "Search by ID, Parent ID, Vehicle or Manufacturer") - { - UpdateDisplay(); - return; - } + string[] searchableData = [ + vehicle.ID.Value, + vehicle.ParentID.Value, + vehicle.CarName, + vehicle.CarBrand + ]; - string lowerSearchText = searchText.ToLowerInvariant(); + return searchableData.Any(data => data != null && data.ToLowerInvariant().Contains(lowerSearchText)); + }).ToList(); - var filteredVehicles = List.Entries.Where(vehicle => - { - string[] searchableData = { - vehicle.ID.Value, - vehicle.ParentID.Value, - vehicle.CarName, - vehicle.CarBrand - }; + UpdateDisplay(filteredVehicles); + } - return searchableData.Any(data => data != null && data.ToLowerInvariant().Contains(lowerSearchText)); - }).ToList(); + private void SearchTimer_Tick(object sender, EventArgs e) + { + _searchTimer.Stop(); + PerformSearch(tstbSearchItem.Text); + } - UpdateDisplay(filteredVehicles); + private void EditSelectedEntry() + { + if (lstVehicles.SelectedItems.Count > 1 || List == null || lstVehicles.SelectedIndices.Count <= 0) + { + return; } - private void SearchTimer_Tick(object sender, EventArgs e) + if (!int.TryParse(lstVehicles.SelectedItems[0].Text, out int index)) { - _searchTimer.Stop(); - PerformSearch(tstbSearchItem.Text); + return; } - private void EditSelectedEntry() + Vehicle vehicle = List.Entries[index]; + VehicleEditor editor = new(List.Entries.Count - 1); + editor.Vehicle = vehicle; + editor.OnDone += Editor_OnDone; + editor.ShowDialog(this); + } + + private void AddItem() + { + if (List == null) { - if (lstVehicles.SelectedItems.Count > 1 || List == null || lstVehicles.SelectedIndices.Count <= 0) - { - return; - } + return; + } - if (!int.TryParse(lstVehicles.SelectedItems[0].Text, out int index)) - { - return; - } + Vehicle vehicle = new(); + vehicle.Index = List.Entries.Count; + vehicle.ID = new EncryptedString(""); + vehicle.ParentID = new EncryptedString(""); + vehicle.ExhaustName = new EncryptedString(""); + vehicle.EngineName = new EncryptedString(""); + + VehicleEditor editor = new(List.Entries.Count); + editor.Vehicle = vehicle; + editor.OnDone += Editor_OnDone1; + editor.ShowDialog(this); + } - Vehicle vehicle = List.Entries[index]; - VehicleEditor editor = new VehicleEditor(List.Entries.Count - 1); - editor.Vehicle = vehicle; - editor.OnDone += Editor_OnDone; - editor.ShowDialog(this); + private void CopyItem() + { + if (List == null || lstVehicles.SelectedItems.Count != 1 || lstVehicles.SelectedIndices.Count <= 0) + { + return; } - private void AddItem() + if (!int.TryParse(lstVehicles.SelectedItems[0].Text, out int index)) { - if (List == null) - { - return; - } - - Vehicle vehicle = new Vehicle(); - vehicle.Index = List.Entries.Count; - vehicle.ID = new EncryptedString(""); - vehicle.ParentID = new EncryptedString(""); - vehicle.ExhaustName = new EncryptedString(""); - vehicle.EngineName = new EncryptedString(""); - - VehicleEditor editor = new VehicleEditor(List.Entries.Count); - editor.Vehicle = vehicle; - editor.OnDone += Editor_OnDone1; - editor.ShowDialog(this); + return; } - private void CopyItem() - { - if (List == null || lstVehicles.SelectedItems.Count != 1 || lstVehicles.SelectedIndices.Count <= 0) - { - return; - } + Vehicle vehicle = new(List.Entries[index]); + vehicle.Index = List.Entries.Count; - if (!int.TryParse(lstVehicles.SelectedItems[0].Text, out int index)) - { - return; - } + VehicleEditor editor = new(List.Entries.Count); + editor.Vehicle = vehicle; + editor.OnDone += Editor_OnDone1; + editor.ShowDialog(this); + } - Vehicle vehicle = new Vehicle(List.Entries[index]); - vehicle.Index = List.Entries.Count; + private void DeleteItem() + { + if (List == null || lstVehicles.SelectedItems.Count != 1 || lstVehicles.SelectedIndices.Count <= 0) + { + return; + } - VehicleEditor editor = new VehicleEditor(List.Entries.Count); - editor.Vehicle = vehicle; - editor.OnDone += Editor_OnDone1; - editor.ShowDialog(this); + if (!int.TryParse(lstVehicles.SelectedItems[0].Text, out int index)) + { + return; } - private void DeleteItem() + List.Entries.RemoveAt(index); + + for (int i = index; i < List.Entries.Count; ++i) { - if (List == null || lstVehicles.SelectedItems.Count != 1 || lstVehicles.SelectedIndices.Count <= 0) - { - return; - } + List.Entries[i].Index--; + } - if (!int.TryParse(lstVehicles.SelectedItems[0].Text, out int index)) - { - return; - } + Edit?.Invoke(); + PerformSearch(tstbSearchItem.Text); + } - List.Entries.RemoveAt(index); + private void Editor_OnDone1(Vehicle vehicle) + { + if (vehicle.Index != List.Entries.Count) + { + List.Entries.Insert(vehicle.Index, vehicle); - for (int i = index; i < List.Entries.Count; ++i) + for (int i = 0; i < List.Entries.Count; ++i) { - List.Entries[i].Index--; + List.Entries[i].Index = i; } - - Edit?.Invoke(); - PerformSearch(tstbSearchItem.Text); } - - private void Editor_OnDone1(Vehicle vehicle) + else { - if (vehicle.Index != List.Entries.Count) - { - List.Entries.Insert(vehicle.Index, vehicle); + List.Entries.Add(vehicle); + } - for (int i = 0; i < List.Entries.Count; ++i) - { - List.Entries[i].Index = i; - } - } - else - { - List.Entries.Add(vehicle); - } + Edit?.Invoke(); + PerformSearch(tstbSearchItem.Text); + } - Edit?.Invoke(); - PerformSearch(tstbSearchItem.Text); - } + private void Editor_OnDone(Vehicle vehicle) + { + int oldIndex = int.Parse(lstVehicles.SelectedItems[0].Text); - private void Editor_OnDone(Vehicle vehicle) + if (oldIndex != vehicle.Index) { - int oldIndex = int.Parse(lstVehicles.SelectedItems[0].Text); + Vehicle old = List.Entries[oldIndex]; + List.Entries.RemoveAt(oldIndex); + List.Entries.Insert(vehicle.Index, old); - if (oldIndex != vehicle.Index) + for (int i = 0; i < List.Entries.Count; ++i) { - Vehicle old = List.Entries[oldIndex]; - List.Entries.RemoveAt(oldIndex); - List.Entries.Insert(vehicle.Index, old); - - for (int i = 0; i < List.Entries.Count; ++i) - { - List.Entries[i].Index = i; - } + List.Entries[i].Index = i; } - - List.Entries[vehicle.Index] = vehicle; - Edit?.Invoke(); - PerformSearch(tstbSearchItem.Text); } - private void lstVehicles_MouseDoubleClick(object sender, MouseEventArgs e) - { - EditSelectedEntry(); - } + List.Entries[vehicle.Index] = vehicle; + Edit?.Invoke(); + PerformSearch(tstbSearchItem.Text); + } - private void lstVehicles_SelectedIndexChanged(object sender, EventArgs e) + private void lstVehicles_MouseDoubleClick(object sender, MouseEventArgs e) + { + EditSelectedEntry(); + } + + private void lstVehicles_SelectedIndexChanged(object sender, EventArgs e) + { + stlStatusLabel.Text = lstVehicles.SelectedItems.Count + " Item(s) Selected"; + copyItemToolStripMenuItem.Enabled = true; + deleteItemToolStripMenuItem.Enabled = true; + tsbCopyItem.Enabled = true; + tsbDeleteItem.Enabled = true; + } + + private void lstVehicles_ColumnClick(object sender, ColumnClickEventArgs e) + { + int column = e.Column; + bool direction = false; + + if (lstVehicles.ListViewItemSorter is VehicleSorter sorter) { - stlStatusLabel.Text = lstVehicles.SelectedItems.Count + " Item(s) Selected"; - copyItemToolStripMenuItem.Enabled = true; - deleteItemToolStripMenuItem.Enabled = true; - tsbCopyItem.Enabled = true; - tsbDeleteItem.Enabled = true; + if (sorter.Column == column) + { + sorter.Swap(); + lstVehicles.Sort(); + return; + } + direction = sorter.Direction; } - private void lstVehicles_ColumnClick(object sender, ColumnClickEventArgs e) + VehicleSorter newSorter = new(column) { - int column = e.Column; - bool direction = false; + Direction = !direction + }; - if (lstVehicles.ListViewItemSorter is VehicleSorter sorter) - { - if (sorter.Column == column) - { - sorter.Swap(); - lstVehicles.Sort(); - return; - } - direction = sorter.Direction; - } + lstVehicles.ListViewItemSorter = newSorter; + lstVehicles.Sort(); + } - VehicleSorter newSorter = new VehicleSorter(column) - { - Direction = !direction - }; + private class VehicleSorter : IComparer + { + public readonly int Column; + public bool Direction; - lstVehicles.ListViewItemSorter = newSorter; - lstVehicles.Sort(); + public VehicleSorter(int column) + { + Column = column; + Direction = false; } - private class VehicleSorter : IComparer + public int Compare(object x, object y) { - public readonly int Column; - public bool Direction; - - public VehicleSorter(int column) - { - Column = column; - Direction = false; - } + ListViewItem itemX = (ListViewItem)x; + ListViewItem itemY = (ListViewItem)y; - public int Compare(object x, object y) + if (Column > itemX.SubItems.Count || Column > itemY.SubItems.Count) { - ListViewItem itemX = (ListViewItem)x; - ListViewItem itemY = (ListViewItem)y; - - if (Column > itemX.SubItems.Count || Column > itemY.SubItems.Count) + if (Direction) { - if (Direction) - { - return -1; - } - return 1; + return -1; } + return 1; + } - string iX = itemX.SubItems[Column].Text; - string iY = itemY.SubItems[Column].Text; + string iX = itemX.SubItems[Column].Text; + string iY = itemY.SubItems[Column].Text; - if (int.TryParse(iX, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out int iXint)) + if (int.TryParse(iX, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out int iXint)) + { + if (int.TryParse(iY, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out int iYint)) { - if (int.TryParse(iY, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out int iYint)) + int val2 = iXint.CompareTo(iYint); + if (this.Direction) { - int val2 = iXint.CompareTo(iYint); - if (this.Direction) - { - return val2 * -1; - } - return val2; + return val2 * -1; } + return val2; } - - int val = string.CompareOrdinal(iX, iY); - if (Direction) - { - return val * -1; - } - return val; } - public void Swap() + int val = string.CompareOrdinal(iX, iY); + if (Direction) { - Direction = !Direction; + return val * -1; } + return val; } - private void addItemToolStripMenuItem_Click(object sender, EventArgs e) - { - AddItem(); - } - - private void tsbAddItem_Click(object sender, EventArgs e) + public void Swap() { - AddItem(); + Direction = !Direction; } + } - private void copyItemToolStripMenuItem_Click(object sender, EventArgs e) - { - CopyItem(); - } + private void addItemToolStripMenuItem_Click(object sender, EventArgs e) + { + AddItem(); + } - private void tsbCopyItem_Click(object sender, EventArgs e) - { - CopyItem(); - } + private void tsbAddItem_Click(object sender, EventArgs e) + { + AddItem(); + } - private void deleteItemToolStripMenuItem_Click(object sender, EventArgs e) - { - DeleteItem(); - } + private void copyItemToolStripMenuItem_Click(object sender, EventArgs e) + { + CopyItem(); + } - private void tsbDeleteItem_Click(object sender, EventArgs e) - { - DeleteItem(); - } + private void tsbCopyItem_Click(object sender, EventArgs e) + { + CopyItem(); + } - private void tsbSearchItem_Click(object sender, EventArgs e) - { - PerformSearch(tstbSearchItem.Text); - } + private void deleteItemToolStripMenuItem_Click(object sender, EventArgs e) + { + DeleteItem(); + } - private void tstbSearchItem_TextChanged(object sender, EventArgs e) - { - if (tstbSearchItem.Text == "Search by ID, Parent ID, Vehicle or Manufacturer") - { - return; - } + private void tsbDeleteItem_Click(object sender, EventArgs e) + { + DeleteItem(); + } - _searchTimer.Stop(); - _searchTimer.Start(); - } + private void tsbSearchItem_Click(object sender, EventArgs e) + { + PerformSearch(tstbSearchItem.Text); + } - private void tstbSearchItem_KeyPress(object sender, KeyPressEventArgs e) + private void tstbSearchItem_TextChanged(object sender, EventArgs e) + { + if (tstbSearchItem.Text == "Search by ID, Parent ID, Vehicle or Manufacturer") { - if (e.KeyChar == (char)Keys.Enter) - { - e.Handled = true; - } + return; } - private void tstbSearchItem_Enter(object sender, EventArgs e) - { - if (tstbSearchItem.Text == "Search by ID, Parent ID, Vehicle or Manufacturer") - { - tstbSearchItem.Text = ""; - tstbSearchItem.ForeColor = System.Drawing.SystemColors.WindowText; + _searchTimer.Stop(); + _searchTimer.Start(); + } - _searchTimer.Stop(); - } + private void tstbSearchItem_KeyPress(object sender, KeyPressEventArgs e) + { + if (e.KeyChar == (char)Keys.Enter) + { + e.Handled = true; } + } - private void tstbSearchItem_Leave(object sender, EventArgs e) + private void tstbSearchItem_Enter(object sender, EventArgs e) + { + if (tstbSearchItem.Text == "Search by ID, Parent ID, Vehicle or Manufacturer") { - if (string.IsNullOrWhiteSpace(tstbSearchItem.Text)) - { - tstbSearchItem.Text = "Search by ID, Parent ID, Vehicle or Manufacturer"; - tstbSearchItem.ForeColor = System.Drawing.SystemColors.GrayText; - } + tstbSearchItem.Text = ""; + tstbSearchItem.ForeColor = System.Drawing.SystemColors.WindowText; + + _searchTimer.Stop(); } + } - private void tsbClearSearch_Click(object sender, EventArgs e) + private void tstbSearchItem_Leave(object sender, EventArgs e) + { + if (string.IsNullOrWhiteSpace(tstbSearchItem.Text)) { tstbSearchItem.Text = "Search by ID, Parent ID, Vehicle or Manufacturer"; tstbSearchItem.ForeColor = System.Drawing.SystemColors.GrayText; - - UpdateDisplay(); } } + + private void tsbClearSearch_Click(object sender, EventArgs e) + { + tstbSearchItem.Text = "Search by ID, Parent ID, Vehicle or Manufacturer"; + tstbSearchItem.ForeColor = System.Drawing.SystemColors.GrayText; + + UpdateDisplay(); + } } diff --git a/VehicleList/VehicleListPlugin.cs b/VehicleList/VehicleListPlugin.cs index 467bfaf..456dba4 100644 --- a/VehicleList/VehicleListPlugin.cs +++ b/VehicleList/VehicleListPlugin.cs @@ -1,16 +1,15 @@ using BundleFormat; using PluginAPI; -namespace VehicleList +namespace VehicleList; + +public class VehicleListPlugin : IPlugin { - public class VehicleListPlugin : IPlugin - { - public string Id => "vehiclelistplugin"; - public string Name => "VehicleList Resource Handler"; + public string Id => "vehiclelistplugin"; + public string Name => "VehicleList Resource Handler"; - public static void Init() - { - EntryTypeRegistry.Register(EntryType.VehicleList, new VehicleListData()); - } + public static void Init() + { + EntryTypeRegistry.Register(EntryType.VehicleList, new VehicleListData()); } } diff --git a/WheelList/WheelEditor.cs b/WheelList/WheelEditor.cs index cc90dea..b3d6f72 100644 --- a/WheelList/WheelEditor.cs +++ b/WheelList/WheelEditor.cs @@ -1,123 +1,113 @@ using BundleUtilities; using System; -using System.Collections.Generic; using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Reflection.PortableExecutable; -using System.Text; -using System.Threading.Tasks; using System.Windows.Forms; -using System.Xml.Linq; -namespace WheelList +namespace WheelList; + +public partial class WheelEditor : Form { - public partial class WheelEditor : Form + public delegate void Done(Wheel wheel); + public event Done OnDone; + private Wheel _wheel; + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public Wheel Wheel { - public delegate void Done(Wheel wheel); - public event Done OnDone; - private Wheel _wheel; - [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] - public Wheel Wheel + get { - get - { - return _wheel; - } - set - { - _wheel = value; - UpdateDisplay(); - } + return _wheel; } - - public WheelEditor() + set { - InitializeComponent(); + _wheel = value; + UpdateDisplay(); } + } - private int maxIndex; - public WheelEditor(int max) - { - InitializeComponent(); - maxIndex = max; - } + public WheelEditor() + { + InitializeComponent(); + } - private void UpdateDisplay() - { - Text = "Edit Wheel: " + Wheel.Index; + private int maxIndex; + public WheelEditor(int max) + { + InitializeComponent(); + maxIndex = max; + } - txtIndex.Text = Wheel.Index.ToString(); - txtID.Text = Wheel.ID.Value; - txtName.Text = Wheel.Name; - } + private void UpdateDisplay() + { + Text = "Edit Wheel: " + Wheel.Index; - private Wheel GetModifiedWheel() - { - Wheel result = new Wheel(Wheel); + txtIndex.Text = Wheel.Index.ToString(); + txtID.Text = Wheel.ID.Value; + txtName.Text = Wheel.Name; + } - // Index - int index; - if (int.TryParse(txtIndex.Text, out index)) - { - if (index <= maxIndex) - result.Index = index; - else - { - MessageBox.Show(this, "Index out of bounds.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } - } - else - { - MessageBox.Show(this, "Index is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } - // Wheel ID - if (txtID.Text.Trim().Length == 0) - { - MessageBox.Show(this, "ID cannot be left blank.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } - try - { - EncryptedString ID = new EncryptedString(txtID.Text); - result.ID = ID; - } - catch (ArgumentException e) - { - MessageBox.Show(this, e.Message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return null; - } + private Wheel GetModifiedWheel() + { + Wheel result = new(Wheel); - // Vehicle name - result.Name = txtName.Text; - if (result.Name.Trim().Length == 0) + // Index + if (int.TryParse(txtIndex.Text, out int index)) + { + if (index <= maxIndex) + result.Index = index; + else { - MessageBox.Show(this, "Car name cannot be left blank.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + MessageBox.Show(this, "Index out of bounds.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); return null; } - - return result; } - - private void btnCancel_Click(object sender, EventArgs e) + else + { + MessageBox.Show(this, "Index is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } + // Wheel ID + if (txtID.Text.Trim().Length == 0) + { + MessageBox.Show(this, "ID cannot be left blank.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } + try { - Close(); + EncryptedString ID = new(txtID.Text); + result.ID = ID; + } + catch (ArgumentException e) + { + MessageBox.Show(this, e.Message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; } - private void btnOk_Click(object sender, EventArgs e) + // Vehicle name + result.Name = txtName.Text; + if (result.Name.Trim().Length == 0) { - Wheel retWheel = GetModifiedWheel(); - if (retWheel == null) - { - return; - } + MessageBox.Show(this, "Car name cannot be left blank.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } - OnDone?.Invoke(retWheel); + return result; + } - Close(); + private void btnCancel_Click(object sender, EventArgs e) + { + Close(); + } + + private void btnOk_Click(object sender, EventArgs e) + { + Wheel retWheel = GetModifiedWheel(); + if (retWheel == null) + { + return; } + + OnDone?.Invoke(retWheel); + + Close(); } } diff --git a/WheelList/WheelListData.cs b/WheelList/WheelListData.cs index 1eee49b..520e4e5 100644 --- a/WheelList/WheelListData.cs +++ b/WheelList/WheelListData.cs @@ -5,118 +5,117 @@ using System.IO; using System.Text; -namespace WheelList +namespace WheelList; + +public class WheelListData : IEntryData { - public class WheelListData : IEntryData - { - public int NumWheels = 0; - public int EntriesPtr = 0; - public List Entries = []; + public int NumWheels = 0; + public int EntriesPtr = 0; + public List Entries = []; - public WheelListData() - { - - } + public WheelListData() + { + + } - public IEntryEditor GetEditor(BundleEntry entry) + public IEntryEditor GetEditor(BundleEntry entry) + { + WheelListForm wheelList = new(); + wheelList.List = this; + wheelList.Edit += () => { - WheelListForm wheelList = new WheelListForm(); - wheelList.List = this; - wheelList.Edit += () => - { - Write(entry); - }; - - return wheelList; - } + Write(entry); + }; - public EntryType GetEntryType(BundleEntry entry) - { - return EntryType.WheelList; - } - - public bool Read(BundleEntry entry, ILoader loader = null) - { - Clear(); + return wheelList; + } - MemoryStream ms = new MemoryStream(entry.EntryBlocks[0].Data); - BinaryReader2 br = new BinaryReader2(ms); - br.BigEndian = entry.Console; + public EntryType GetEntryType(BundleEntry entry) + { + return EntryType.WheelList; + } - NumWheels = br.ReadInt32(); - EntriesPtr = br.ReadInt32(); - br.BaseStream.Position = EntriesPtr; + public bool Read(BundleEntry entry, ILoader loader = null) + { + Clear(); - for (int i = 0; i < NumWheels; i++) - { - Wheel wheel = new(); + MemoryStream ms = new(entry.EntryBlocks[0].Data); + BinaryReader2 br = new(ms); + br.BigEndian = entry.Console; - wheel.Index = i; - wheel.ID = new EncryptedString(br.ReadUInt64()); - wheel.Name = Encoding.ASCII.GetString(br.ReadBytes(64)); + NumWheels = br.ReadInt32(); + EntriesPtr = br.ReadInt32(); + br.BaseStream.Position = EntriesPtr; - Entries.Add(wheel); - } + for (int i = 0; i < NumWheels; i++) + { + Wheel wheel = new(); - br.Close(); + wheel.Index = i; + wheel.ID = new EncryptedString(br.ReadUInt64()); + wheel.Name = Encoding.ASCII.GetString(br.ReadBytes(64)); - return true; + Entries.Add(wheel); } - public bool Write(BundleEntry entry) - { - MemoryStream ms = new MemoryStream(); - BinaryWriter2 bw = new BinaryWriter2(ms); - bw.BigEndian = entry.Console; + br.Close(); - bw.Write(Entries.Count); - bw.Write(EntriesPtr); - bw.BaseStream.Position = EntriesPtr; + return true; + } - for (int i = 0; i < Entries.Count; i++) - { - Wheel wheel = Entries[i]; + public bool Write(BundleEntry entry) + { + MemoryStream ms = new(); + BinaryWriter2 bw = new(ms); + bw.BigEndian = entry.Console; - bw.Write(wheel.ID.Encrypted); - bw.WriteLenString(wheel.Name, 64); - } + bw.Write(Entries.Count); + bw.Write(EntriesPtr); + bw.BaseStream.Position = EntriesPtr; - bw.Align(0x10); + for (int i = 0; i < Entries.Count; i++) + { + Wheel wheel = Entries[i]; - bw.Flush(); - byte[] data = ms.ToArray(); - bw.Close(); + bw.Write(wheel.ID.Encrypted); + bw.WriteLenString(wheel.Name, 64); + } - entry.EntryBlocks[0].Data = data; - entry.Dirty = true; + bw.Align(0x10); - return true; - } + bw.Flush(); + byte[] data = ms.ToArray(); + bw.Close(); - private void Clear() - { - NumWheels = default; - EntriesPtr = default; - Entries.Clear(); - } + entry.EntryBlocks[0].Data = data; + entry.Dirty = true; + + return true; } - public class Wheel + private void Clear() { - public int Index = -1; - public EncryptedString ID = new(0); - public string Name = new(""); + NumWheels = default; + EntriesPtr = default; + Entries.Clear(); + } +} - public Wheel() - { +public class Wheel +{ + public int Index = -1; + public EncryptedString ID = new(0); + public string Name = new(""); - } + public Wheel() + { - public Wheel(Wheel copy) - { - Index = copy.Index; - ID = copy.ID; - Name = copy.Name; - } + } + + public Wheel(Wheel copy) + { + Index = copy.Index; + ID = copy.ID; + Name = copy.Name; } } diff --git a/WheelList/WheelListForm.cs b/WheelList/WheelListForm.cs index b26cece..1c9015a 100644 --- a/WheelList/WheelListForm.cs +++ b/WheelList/WheelListForm.cs @@ -2,290 +2,283 @@ using PluginAPI; using System; using System.Collections; -using System.Collections.Generic; using System.ComponentModel; -using System.Data; -using System.Drawing; using System.Globalization; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Windows.Forms; -namespace WheelList +namespace WheelList; + +public partial class WheelListForm : Form, IEntryEditor { - public partial class WheelListForm : Form, IEntryEditor - { - public delegate void OnEdit(); - public event OnEdit Edit; + public delegate void OnEdit(); + public event OnEdit Edit; - private WheelListData _list; - [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] - public WheelListData List + private WheelListData _list; + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public WheelListData List + { + get => _list; + set { - get => _list; - set - { - _list = value; - UpdateDisplay(); - } + _list = value; + UpdateDisplay(); } + } - public WheelListForm() + public WheelListForm() + { + InitializeComponent(); + } + + private void UpdateDisplay() + { + lstWheels.Items.Clear(); + + if (List == null) + return; + + for (int i = 0; i < List.Entries.Count; i++) { - InitializeComponent(); + Wheel wheel = List.Entries[i]; + + string[] value = [ + wheel.Index.ToString(), + wheel.ID.Value, + wheel.Name + ]; + lstWheels.Items.Add(new ListViewItem(value)); } - private void UpdateDisplay() - { - lstWheels.Items.Clear(); + lstWheels.ListViewItemSorter = new WheelSorter(0); + lstWheels.Sort(); - if (List == null) - return; + stlStatusLabel.Text = ""; + copyItemToolStripMenuItem.Enabled = false; + deleteItemToolStripMenuItem.Enabled = false; + tsbCopyItem.Enabled = false; + tsbDeleteItem.Enabled = false; + } - for (int i = 0; i < List.Entries.Count; i++) - { - Wheel wheel = List.Entries[i]; - - string[] value = { - wheel.Index.ToString(), - wheel.ID.Value, - wheel.Name - }; - lstWheels.Items.Add(new ListViewItem(value)); - } + private void EditSelectedEntry() + { + if (lstWheels.SelectedItems.Count > 1) + return; + if (List == null || lstWheels.SelectedIndices.Count <= 0) + return; + + if (!int.TryParse(lstWheels.SelectedItems[0].Text, out int index)) + return; + Wheel wheel = List.Entries[index]; + + WheelEditor editor = new(List.Entries.Count - 1); + editor.Wheel = wheel; + editor.OnDone += Editor_OnDone; + editor.ShowDialog(this); + } - lstWheels.ListViewItemSorter = new WheelSorter(0); - lstWheels.Sort(); + private void AddItem() + { + if (List == null) + return; + Wheel wheel = new(); + wheel.Index = List.Entries.Count; + wheel.ID = new EncryptedString(""); + wheel.Name = ""; + + WheelEditor editor = new(List.Entries.Count); + editor.Wheel = wheel; + editor.OnDone += Editor_OnDone1; ; + editor.ShowDialog(this); + } - stlStatusLabel.Text = ""; - copyItemToolStripMenuItem.Enabled = false; - deleteItemToolStripMenuItem.Enabled = false; - tsbCopyItem.Enabled = false; - tsbDeleteItem.Enabled = false; - } + private void CopyItem() + { + if (List == null || lstWheels.SelectedItems.Count != 1 + || lstWheels.SelectedIndices.Count <= 0) + return; + + if (!int.TryParse(lstWheels.SelectedItems[0].Text, out int index)) + return; + Wheel wheel = new(List.Entries[index]); + wheel.Index = List.Entries.Count; + + WheelEditor editor = new(List.Entries.Count); + editor.Wheel = wheel; + editor.OnDone += Editor_OnDone1; + editor.ShowDialog(this); + } - private void EditSelectedEntry() - { - if (lstWheels.SelectedItems.Count > 1) - return; - if (List == null || lstWheels.SelectedIndices.Count <= 0) - return; + private void DeleteItem() + { + if (List == null || lstWheels.SelectedItems.Count != 1 + || lstWheels.SelectedIndices.Count <= 0) + return; + + if (!int.TryParse(lstWheels.SelectedItems[0].Text, out int index)) + return; + List.Entries.RemoveAt(index); + for (int i = index; i < List.Entries.Count; ++i) + List.Entries[i].Index--; + + Edit?.Invoke(); + UpdateDisplay(); + } - if (!int.TryParse(lstWheels.SelectedItems[0].Text, out int index)) - return; - Wheel wheel = List.Entries[index]; + private void Editor_OnDone1(Wheel wheel) + { + // Insert if not at end, else add + if (wheel.Index != List.Entries.Count) + { + List.Entries.Insert(wheel.Index, wheel); - WheelEditor editor = new WheelEditor(List.Entries.Count - 1); - editor.Wheel = wheel; - editor.OnDone += Editor_OnDone; - editor.ShowDialog(this); + for (int i = 0; i < List.Entries.Count; ++i) + List.Entries[i].Index = i; } - - private void AddItem() + else { - if (List == null) - return; - Wheel wheel = new(); - wheel.Index = List.Entries.Count; - wheel.ID = new EncryptedString(""); - wheel.Name = ""; - - WheelEditor editor = new WheelEditor(List.Entries.Count); - editor.Wheel = wheel; - editor.OnDone += Editor_OnDone1; ; - editor.ShowDialog(this); + List.Entries.Add(wheel); } - private void CopyItem() - { - if (List == null || lstWheels.SelectedItems.Count != 1 - || lstWheels.SelectedIndices.Count <= 0) - return; + Edit?.Invoke(); + UpdateDisplay(); + } - if (!int.TryParse(lstWheels.SelectedItems[0].Text, out int index)) - return; - Wheel wheel = new Wheel(List.Entries[index]); - wheel.Index = List.Entries.Count; + private void Editor_OnDone(Wheel wheel) + { + // If the index has changed, edit the list + int oldIndex = int.Parse(lstWheels.SelectedItems[0].Text); // Tried in EditSelectedEntry() + if (oldIndex != wheel.Index) + { + Wheel old = List.Entries[oldIndex]; + List.Entries.RemoveAt(oldIndex); + List.Entries.Insert(wheel.Index, old); - WheelEditor editor = new WheelEditor(List.Entries.Count); - editor.Wheel = wheel; - editor.OnDone += Editor_OnDone1; - editor.ShowDialog(this); + for (int i = 0; i < List.Entries.Count; ++i) + List.Entries[i].Index = i; } - private void DeleteItem() - { - if (List == null || lstWheels.SelectedItems.Count != 1 - || lstWheels.SelectedIndices.Count <= 0) - return; - - if (!int.TryParse(lstWheels.SelectedItems[0].Text, out int index)) - return; - List.Entries.RemoveAt(index); - for (int i = index; i < List.Entries.Count; ++i) - List.Entries[i].Index--; + // Edit the wheel + List.Entries[wheel.Index] = wheel; + Edit?.Invoke(); + UpdateDisplay(); + } - Edit?.Invoke(); - UpdateDisplay(); - } + private void lstWheels_MouseDoubleClick(object sender, MouseEventArgs e) + { + EditSelectedEntry(); + } - private void Editor_OnDone1(Wheel wheel) - { - // Insert if not at end, else add - if (wheel.Index != List.Entries.Count) - { - List.Entries.Insert(wheel.Index, wheel); + private void lstWheels_SelectedIndexChanged(object sender, EventArgs e) + { + stlStatusLabel.Text = lstWheels.SelectedItems.Count + " Item(s) Selected"; + copyItemToolStripMenuItem.Enabled = true; + deleteItemToolStripMenuItem.Enabled = true; + tsbCopyItem.Enabled = true; + tsbDeleteItem.Enabled = true; + } - for (int i = 0; i < List.Entries.Count; ++i) - List.Entries[i].Index = i; - } - else - { - List.Entries.Add(wheel); - } + private void lstWheels_ColumnClick(object sender, ColumnClickEventArgs e) + { + int column = e.Column; - Edit?.Invoke(); - UpdateDisplay(); - } + bool direction = false; - private void Editor_OnDone(Wheel wheel) + if (lstWheels.ListViewItemSorter is WheelSorter sorter) { - // If the index has changed, edit the list - int oldIndex = int.Parse(lstWheels.SelectedItems[0].Text); // Tried in EditSelectedEntry() - if (oldIndex != wheel.Index) + if (sorter.Column == column) { - Wheel old = List.Entries[oldIndex]; - List.Entries.RemoveAt(oldIndex); - List.Entries.Insert(wheel.Index, old); - - for (int i = 0; i < List.Entries.Count; ++i) - List.Entries[i].Index = i; + sorter.Swap(); + lstWheels.Sort(); + return; } - - // Edit the wheel - List.Entries[wheel.Index] = wheel; - Edit?.Invoke(); - UpdateDisplay(); + direction = sorter.Direction; } - private void lstWheels_MouseDoubleClick(object sender, MouseEventArgs e) + WheelSorter newSorter = new(column) { - EditSelectedEntry(); - } + Direction = !direction + }; + lstWheels.ListViewItemSorter = newSorter; + lstWheels.Sort(); + } - private void lstWheels_SelectedIndexChanged(object sender, EventArgs e) - { - stlStatusLabel.Text = lstWheels.SelectedItems.Count + " Item(s) Selected"; - copyItemToolStripMenuItem.Enabled = true; - deleteItemToolStripMenuItem.Enabled = true; - tsbCopyItem.Enabled = true; - tsbDeleteItem.Enabled = true; - } + private class WheelSorter : IComparer + { + public readonly int Column; + public bool Direction; - private void lstWheels_ColumnClick(object sender, ColumnClickEventArgs e) + public WheelSorter(int column) { - int column = e.Column; - - bool direction = false; - - if (lstWheels.ListViewItemSorter is WheelSorter sorter) - { - if (sorter.Column == column) - { - sorter.Swap(); - lstWheels.Sort(); - return; - } - direction = sorter.Direction; - } - - WheelSorter newSorter = new WheelSorter(column) - { - Direction = !direction - }; - lstWheels.ListViewItemSorter = newSorter; - lstWheels.Sort(); + Column = column; + Direction = false; } - private class WheelSorter : IComparer + public int Compare(object x, object y) { - public readonly int Column; - public bool Direction; + ListViewItem itemX = (ListViewItem)x; + ListViewItem itemY = (ListViewItem)y; - public WheelSorter(int column) + if (Column > itemX.SubItems.Count || Column > itemY.SubItems.Count) { - Column = column; - Direction = false; + if (Direction) + return -1; + return 1; } - public int Compare(object x, object y) - { - ListViewItem itemX = (ListViewItem)x; - ListViewItem itemY = (ListViewItem)y; + string iX = itemX.SubItems[Column].Text; + string iY = itemY.SubItems[Column].Text; - if (Column > itemX.SubItems.Count || Column > itemY.SubItems.Count) - { - if (Direction) - return -1; - return 1; - } - string iX = itemX.SubItems[Column].Text; - string iY = itemY.SubItems[Column].Text; - - - if (int.TryParse(iX, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out int iXint)) + if (int.TryParse(iX, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out int iXint)) + { + if (int.TryParse(iY, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out int iYint)) { - if (int.TryParse(iY, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out int iYint)) - { - int val2 = iXint.CompareTo(iYint); - if (this.Direction) - return val2 * -1; - return val2; - } + int val2 = iXint.CompareTo(iYint); + if (this.Direction) + return val2 * -1; + return val2; } - - int val = string.CompareOrdinal(iX, iY); - if (Direction) - return val * -1; - return val; } - public void Swap() - { - Direction = !Direction; - } + int val = string.CompareOrdinal(iX, iY); + if (Direction) + return val * -1; + return val; } - private void addItemToolStripMenuItem_Click(object sender, EventArgs e) + public void Swap() { - AddItem(); + Direction = !Direction; } + } - private void tsbAddItem_Click(object sender, EventArgs e) - { - AddItem(); - } + private void addItemToolStripMenuItem_Click(object sender, EventArgs e) + { + AddItem(); + } - private void copyItemToolStripMenuItem_Click(object sender, EventArgs e) - { - CopyItem(); - } + private void tsbAddItem_Click(object sender, EventArgs e) + { + AddItem(); + } - private void tsbCopyItem_Click(object sender, EventArgs e) - { - CopyItem(); - } + private void copyItemToolStripMenuItem_Click(object sender, EventArgs e) + { + CopyItem(); + } - private void deleteItemToolStripMenuItem_Click(object sender, EventArgs e) - { - DeleteItem(); - } + private void tsbCopyItem_Click(object sender, EventArgs e) + { + CopyItem(); + } - private void tsbDeleteItem_Click(object sender, EventArgs e) - { - DeleteItem(); - } + private void deleteItemToolStripMenuItem_Click(object sender, EventArgs e) + { + DeleteItem(); + } + + private void tsbDeleteItem_Click(object sender, EventArgs e) + { + DeleteItem(); } } diff --git a/WheelList/WheelListPlugin.cs b/WheelList/WheelListPlugin.cs index bd8ac19..705fd27 100644 --- a/WheelList/WheelListPlugin.cs +++ b/WheelList/WheelListPlugin.cs @@ -1,16 +1,15 @@ using BundleFormat; using PluginAPI; -namespace WheelList +namespace WheelList; + +public class WheelListPlugin : IPlugin { - public class WheelListPlugin : IPlugin + public string Id => "wheellistplugin"; + public string Name => "WheelList Resource Handler"; + + public static void Init() { - public string Id => "wheellistplugin"; - public string Name => "WheelList Resource Handler"; - - public static void Init() - { - EntryTypeRegistry.Register(EntryType.WheelList, new WheelListData()); - } + EntryTypeRegistry.Register(EntryType.WheelList, new WheelListData()); } } diff --git a/WorldCollisionHandler/PolygonSoupList.cs b/WorldCollisionHandler/PolygonSoupList.cs index 2ad3c66..05f5c0c 100644 --- a/WorldCollisionHandler/PolygonSoupList.cs +++ b/WorldCollisionHandler/PolygonSoupList.cs @@ -11,733 +11,732 @@ using OpenTK.Mathematics; using PluginAPI; -namespace WorldCollisionHandler +namespace WorldCollisionHandler; + +public class PolygonSoupProperty { - public class PolygonSoupProperty + public uint UnknownProperty; + public byte[] Indices; + public byte[] UnknownBytes; + + public PolygonSoupProperty() { - public uint UnknownProperty; - public byte[] Indices; - public byte[] UnknownBytes; + Indices = new byte[4]; + UnknownBytes = new byte[4]; + } - public PolygonSoupProperty() - { - Indices = new byte[4]; - UnknownBytes = new byte[4]; - } + public PolygonSoupProperty Copy() + { + PolygonSoupProperty result = new(); - public PolygonSoupProperty Copy() + result.UnknownProperty = UnknownProperty; + for (int i = 0; i < Indices.Length; i++) { - PolygonSoupProperty result = new PolygonSoupProperty(); - - result.UnknownProperty = UnknownProperty; - for (int i = 0; i < Indices.Length; i++) - { - result.Indices[i] = Indices[i]; - } - for (int i = 0; i < UnknownBytes.Length; i++) - { - result.UnknownBytes[i] = UnknownBytes[i]; - } - - return result; + result.Indices[i] = Indices[i]; } - - public static PolygonSoupProperty Read(BinaryReader2 br) + for (int i = 0; i < UnknownBytes.Length; i++) { - PolygonSoupProperty result = new PolygonSoupProperty(); + result.UnknownBytes[i] = UnknownBytes[i]; + } - result.UnknownProperty = br.ReadUInt32(); + return result; + } - for (int i = 0; i < result.Indices.Length; i++) - { - result.Indices[i] = br.ReadByte(); - } + public static PolygonSoupProperty Read(BinaryReader2 br) + { + PolygonSoupProperty result = new(); - for (int i = 0; i < result.UnknownBytes.Length; i++) - { - result.UnknownBytes[i] = br.ReadByte(); - } + result.UnknownProperty = br.ReadUInt32(); - return result; + for (int i = 0; i < result.Indices.Length; i++) + { + result.Indices[i] = br.ReadByte(); } - public void Write(BinaryWriter2 bw, bool x64) + for (int i = 0; i < result.UnknownBytes.Length; i++) { - // Cap to 0x9D64 for PC - ushort unknownProperty1 = (ushort)(UnknownProperty & 0xFFFF); + result.UnknownBytes[i] = br.ReadByte(); + } - // Patch values that are too high (from console) with Schembri Pass - if (!x64 && unknownProperty1 > 0x9D64 && unknownProperty1 != 0xFFFF) - { - // 0x8316, 0x9531, 0x9007, 0x8511, 0x8316, 0xFFFF - unknownProperty1 = 0x8316; - } + return result; + } + + public void Write(BinaryWriter2 bw, bool x64) + { + // Cap to 0x9D64 for PC + ushort unknownProperty1 = (ushort)(UnknownProperty & 0xFFFF); - // Patch values that are too high(from console) with 0xFFFF - //if (unknownProperty1 > 0x9D64) - // unknownProperty1 = 0xFFFF; + // Patch values that are too high (from console) with Schembri Pass + if (!x64 && unknownProperty1 > 0x9D64 && unknownProperty1 != 0xFFFF) + { + // 0x8316, 0x9531, 0x9007, 0x8511, 0x8316, 0xFFFF + unknownProperty1 = 0x8316; + } - ushort unknownProperty2 = (ushort) ((UnknownProperty >> 16) & 0xFFFF); + // Patch values that are too high(from console) with 0xFFFF + //if (unknownProperty1 > 0x9D64) + // unknownProperty1 = 0xFFFF; - // Remove wreck surfaces - TODO: tmp - //unknownProperty2 &= unchecked((ushort)~0x4000); + ushort unknownProperty2 = (ushort) ((UnknownProperty >> 16) & 0xFFFF); - uint unknownProperty = (uint)((unknownProperty2 << 16) | unknownProperty1); + // Remove wreck surfaces - TODO: tmp + //unknownProperty2 &= unchecked((ushort)~0x4000); - bw.Write(unknownProperty); + uint unknownProperty = (uint)((unknownProperty2 << 16) | unknownProperty1); - for (int i = 0; i < Indices.Length; i++) - { - bw.Write(Indices[i]); - } + bw.Write(unknownProperty); - for (int i = 0; i < UnknownBytes.Length; i++) - { - bw.Write(UnknownBytes[i]); - } + for (int i = 0; i < Indices.Length; i++) + { + bw.Write(Indices[i]); } - public override string ToString() + for (int i = 0; i < UnknownBytes.Length; i++) { - return "Prop: " + UnknownProperty.ToString("X8"); + bw.Write(UnknownBytes[i]); } } - public class PolygonSoupBoundingBox + public override string ToString() { - public BoxF Box; - public int Terminator; + return "Prop: " + UnknownProperty.ToString("X8"); + } +} + +public class PolygonSoupBoundingBox +{ + public BoxF Box; + public int Terminator; + + public PolygonSoupBoundingBox(BoxF box, int terminator) + { + Box = box; + Terminator = terminator; + } - public PolygonSoupBoundingBox(BoxF box, int terminator) + public override string ToString() + { + return Box.ToString() + ", " + Terminator; + } +} + +public class PolygonSoupChunk +{ + public MathLib.Vector3I Position; + public float Scale; + public byte QuadCount; + public byte Unknown10; + public short Unknown11; + + public List PointList; + public List PropertyList; + + public PolygonSoupChunk() + { + PointList = []; + PropertyList = []; + } + + public static PolygonSoupChunk Read(BinaryReader2 br, bool x64) + { + PolygonSoupChunk result = new(); + long ReadPtr() => x64 ? (long)br.ReadUInt64() : br.ReadUInt32(); + + result.Position = br.ReadVector3I(); + result.Scale = br.ReadSingle(); + long propertyListStart = ReadPtr(); + long pointListStart = ReadPtr(); + br.ReadInt16(); // Length + byte propertyListCount = br.ReadByte(); + result.QuadCount = br.ReadByte(); + int pointCount = br.ReadByte(); + result.Unknown10 = br.ReadByte(); + result.Unknown11 = br.ReadInt16(); + + br.BaseStream.Position = pointListStart; + for (int i = 0; i < pointCount; i++) { - Box = box; - Terminator = terminator; + result.PointList.Add(br.ReadVector3S()); } - public override string ToString() + br.BaseStream.Position = propertyListStart; + + for (int i = 0; i < propertyListCount; i++) { - return Box.ToString() + ", " + Terminator; + result.PropertyList.Add(PolygonSoupProperty.Read(br)); } + + return result; } - public class PolygonSoupChunk + public void Write(BinaryWriter2 bw, bool x64) { - public MathLib.Vector3I Position; - public float Scale; - public byte QuadCount; - public byte Unknown10; - public short Unknown11; + void WritePtr(long ptr) { if (x64) bw.Write((ulong)ptr); else bw.Write((uint)ptr); } + + long chunkStartPtr = bw.BaseStream.Position; + bw.Write(Position); + bw.Write(Scale); + long propListStartPtr = bw.BaseStream.Position; + WritePtr(0); + long pointListStartPtr = bw.BaseStream.Position; + WritePtr(0); + long lengthPtr = bw.BaseStream.Position; + bw.Write((ushort) 0); + bw.Write((byte)PropertyList.Count); + bw.Write(QuadCount); + bw.Write((byte)PointList.Count); + bw.Write(Unknown10); + bw.Write(Unknown11); + + long cPos = bw.BaseStream.Position; + bw.BaseStream.Position = pointListStartPtr; + WritePtr(cPos); + bw.BaseStream.Position = cPos; + + for (int i = 0; i < PointList.Count; i++) + { + bw.Write(PointList[i]); + } - public List PointList; - public List PropertyList; + bw.BaseStream.Position = (16 * ((bw.BaseStream.Position + 15) / 16)); + cPos = bw.BaseStream.Position; + bw.BaseStream.Position = propListStartPtr; + WritePtr(cPos); + bw.BaseStream.Position = cPos; - public PolygonSoupChunk() + for (int i = 0; i < PropertyList.Count; i++) { - PointList = new List(); - PropertyList = new List(); + PropertyList[i].Write(bw, x64); } + cPos = bw.BaseStream.Position; + bw.BaseStream.Position = lengthPtr; + bw.Write((short)(bw.BaseStream.Length - chunkStartPtr)); + bw.BaseStream.Position = cPos; - public static PolygonSoupChunk Read(BinaryReader2 br, bool x64) - { - PolygonSoupChunk result = new PolygonSoupChunk(); - long ReadPtr() => x64 ? (long)br.ReadUInt64() : br.ReadUInt32(); - - result.Position = br.ReadVector3I(); - result.Scale = br.ReadSingle(); - long propertyListStart = ReadPtr(); - long pointListStart = ReadPtr(); - br.ReadInt16(); // Length - byte propertyListCount = br.ReadByte(); - result.QuadCount = br.ReadByte(); - int pointCount = br.ReadByte(); - result.Unknown10 = br.ReadByte(); - result.Unknown11 = br.ReadInt16(); - - br.BaseStream.Position = pointListStart; - for (int i = 0; i < pointCount; i++) - { - result.PointList.Add(br.ReadVector3S()); - } + } - br.BaseStream.Position = propertyListStart; + public Mesh BuildMesh(MathLib.Vector3I pos, float scale) + { + Mesh mesh = new(); + mesh.Faces = []; - for (int i = 0; i < propertyListCount; i++) + for (int i = 0; i < PropertyList.Count; i++) + { + MeshFace face = new(); + PolygonSoupProperty property = PropertyList[i]; + face.Indices.Add(property.Indices[0]); + face.Indices.Add(property.Indices[1]); + face.Indices.Add(property.Indices[2]); + + ushort unknownProperty1 = (ushort) (property.UnknownProperty & 0xFFFF); + ushort unknownProperty2 = (ushort) ((property.UnknownProperty >> 16)); // & 0xFFFF); + + string unknownBytes = property.UnknownBytes[0].ToString("X2") + "_" + + property.UnknownBytes[1].ToString("X2") + "_" + + property.UnknownBytes[2].ToString("X2") + "_" + + property.UnknownBytes[3].ToString("X2"); + face.Material = new Material( + unknownProperty1.ToString("X4") + "_" + unknownProperty2.ToString("X4") + "_" + unknownBytes, + Color.White); + + mesh.Faces.Add(face); + + if (property.Indices[3] != 0xFF) { - result.PropertyList.Add(PolygonSoupProperty.Read(br)); + MeshFace face2 = new(); + face2.Material = face.Material; + face2.Indices.Add(property.Indices[3]); + face2.Indices.Add(property.Indices[2]); + face2.Indices.Add(property.Indices[1]); + mesh.Faces.Add(face2); } - - return result; } - public void Write(BinaryWriter2 bw, bool x64) - { - void WritePtr(long ptr) { if (x64) bw.Write((ulong)ptr); else bw.Write((uint)ptr); } - long chunkStartPtr = bw.BaseStream.Position; - bw.Write(Position); - bw.Write(Scale); - long propListStartPtr = bw.BaseStream.Position; - WritePtr(0); - long pointListStartPtr = bw.BaseStream.Position; - WritePtr(0); - long lengthPtr = bw.BaseStream.Position; - bw.Write((ushort) 0); - bw.Write((byte)PropertyList.Count); - bw.Write(QuadCount); - bw.Write((byte)PointList.Count); - bw.Write(Unknown10); - bw.Write(Unknown11); - - long cPos = bw.BaseStream.Position; - bw.BaseStream.Position = pointListStartPtr; - WritePtr(cPos); - bw.BaseStream.Position = cPos; + List points = PointList; - for (int i = 0; i < PointList.Count; i++) - { - bw.Write(PointList[i]); - } + for (int i = 0; i < points.Count; i++) + { + Vector3S vert = points[i]; + mesh.Vertices.Add(new Vector3((vert.X + pos.X) * scale, (vert.Y + pos.Y) * scale, (vert.Z + pos.Z) * scale)); + } - bw.BaseStream.Position = (16 * ((bw.BaseStream.Position + 15) / 16)); - cPos = bw.BaseStream.Position; - bw.BaseStream.Position = propListStartPtr; - WritePtr(cPos); - bw.BaseStream.Position = cPos; + return mesh; + } - for (int i = 0; i < PropertyList.Count; i++) - { - PropertyList[i].Write(bw, x64); - } - cPos = bw.BaseStream.Position; - bw.BaseStream.Position = lengthPtr; - bw.Write((short)(bw.BaseStream.Length - chunkStartPtr)); - bw.BaseStream.Position = cPos; + public override string ToString() + { + return "Pos: " + Position + ", Scale: " + Scale + ", PointCount: " + PointList.Count; + } +} - } +public class PolygonSoupList : IEntryData +{ + public Vector3 Min; + public int Unknown4; + public Vector3 Max; + public int Unknown8; + //public uint ChunkPointerStart; + //public uint BoxListStart; + //public int ChunkCount; + //public uint FileSize; + + //public List ChunkPointers; + public List BoundingBoxes; + public List Chunks; + + public PolygonSoupList() + { + //ChunkPointers = new List(); + BoundingBoxes = []; + Chunks = []; + } - public Mesh BuildMesh(MathLib.Vector3I pos, float scale) + public void RemoveWreckSurfaces() + { + foreach (PolygonSoupChunk chunk in Chunks) { - Mesh mesh = new Mesh(); - mesh.Faces = new List(); - - for (int i = 0; i < PropertyList.Count; i++) + foreach (PolygonSoupProperty property in chunk.PropertyList) { - MeshFace face = new MeshFace(); - PolygonSoupProperty property = PropertyList[i]; - face.Indices.Add(property.Indices[0]); - face.Indices.Add(property.Indices[1]); - face.Indices.Add(property.Indices[2]); - - ushort unknownProperty1 = (ushort) (property.UnknownProperty & 0xFFFF); - ushort unknownProperty2 = (ushort) ((property.UnknownProperty >> 16)); // & 0xFFFF); - - string unknownBytes = property.UnknownBytes[0].ToString("X2") + "_" + - property.UnknownBytes[1].ToString("X2") + "_" + - property.UnknownBytes[2].ToString("X2") + "_" + - property.UnknownBytes[3].ToString("X2"); - face.Material = new Material( - unknownProperty1.ToString("X4") + "_" + unknownProperty2.ToString("X4") + "_" + unknownBytes, - Color.White); - - mesh.Faces.Add(face); - - if (property.Indices[3] != 0xFF) - { - MeshFace face2 = new MeshFace(); - face2.Material = face.Material; - face2.Indices.Add(property.Indices[3]); - face2.Indices.Add(property.Indices[2]); - face2.Indices.Add(property.Indices[1]); - mesh.Faces.Add(face2); - } - } + ushort unknownProperty1 = (ushort)(property.UnknownProperty & 0xFFFF); + ushort unknownProperty2 = (ushort)((property.UnknownProperty >> 16) & 0xFFFF); - List points = PointList; + // Remove wreck surfaces - TODO: tmp + unknownProperty2 &= unchecked((ushort)~0x4000); - for (int i = 0; i < points.Count; i++) - { - Vector3S vert = points[i]; - mesh.Vertices.Add(new Vector3((vert.X + pos.X) * scale, (vert.Y + pos.Y) * scale, (vert.Z + pos.Z) * scale)); - } + uint unknownProperty = (uint)((unknownProperty2 << 16) | unknownProperty1); - return mesh; + property.UnknownProperty = unknownProperty; + } } + } + + public Scene MakeScene(ILoader loader = null) + { + Scene scene = new(); - public override string ToString() + int index = 0; + foreach (PolygonSoupChunk chunk in Chunks) { - return "Pos: " + Position + ", Scale: " + Scale + ", PointCount: " + PointList.Count; + string id = index.ToString(); + + MathLib.Vector3I pos = chunk.Position; + float scale = chunk.Scale; + Model model = new(chunk.BuildMesh(pos, scale)); + SceneObject sceneObject = new(id, model); + scene.AddObject(sceneObject); + index++; } + + return scene; } - public class PolygonSoupList : IEntryData + public void ImportObj(string path) { - public Vector3 Min; - public int Unknown4; - public Vector3 Max; - public int Unknown8; - //public uint ChunkPointerStart; - //public uint BoxListStart; - //public int ChunkCount; - //public uint FileSize; - - //public List ChunkPointers; - public List BoundingBoxes; - public List Chunks; - - public PolygonSoupList() - { - //ChunkPointers = new List(); - BoundingBoxes = new List(); - Chunks = new List(); - } + GenericModel model = OBJImporter.ImportOBJ(path); + model.SplitByPointCount(255); - public void RemoveWreckSurfaces() + // Verify data before applying + foreach (GenericMesh mesh in model.Meshes) { - foreach (PolygonSoupChunk chunk in Chunks) + // Get highest point + uint pointCount = 0; + foreach (uint key in mesh.Vertices.Keys) { - foreach (PolygonSoupProperty property in chunk.PropertyList) + if (pointCount < key) { - ushort unknownProperty1 = (ushort)(property.UnknownProperty & 0xFFFF); - - ushort unknownProperty2 = (ushort)((property.UnknownProperty >> 16) & 0xFFFF); + pointCount = key; + } + } + pointCount++; + // Is it too big for a byte? + if (pointCount > 256) + throw new ReadFailedError("Too many points for mesh: " + mesh.Name + ", " + pointCount + " > 256"); + foreach (Face face in mesh.Faces) + { + // Triangulation required for now. + if (face.Indices.Count > 3) + throw new ReadFailedError("Please triangulate your mesh: " + mesh.Name); - // Remove wreck surfaces - TODO: tmp - unknownProperty2 &= unchecked((ushort)~0x4000); + // Material names are required + if (string.IsNullOrEmpty(face.Material?.Name)) + throw new ReadFailedError("Invalid Material for mesh: " + mesh.Name); - uint unknownProperty = (uint)((unknownProperty2 << 16) | unknownProperty1); + // Verify that all data is there + string[] split = face.Material.Name.Split('_'); + if (split.Length < 7) + throw new ReadFailedError("Invalid Material Data: " + face.Material.Name + ", for mesh: " + mesh.Name); - property.UnknownProperty = unknownProperty; + // Verify that all data can be parsed + try + { + Utilities.Parse(split[1], true, out ushort _); + Utilities.Parse(split[2], true, out ushort _); + Utilities.Parse(split[3], true, out byte _); + Utilities.Parse(split[4], true, out byte _); + Utilities.Parse(split[5], true, out byte _); + Utilities.Parse(split[6], true, out byte _); + } + catch (NotSupportedException) + { + throw new ReadFailedError("Unable to Parse Material Data: " + face.Material.Name + ", for mesh: " + mesh.Name); } } } - public Scene MakeScene(ILoader loader = null) - { - Scene scene = new Scene(); + // Clear existing data + Chunks.Clear(); + BoundingBoxes.Clear(); + + // Global vertices list to calculate the bounding box + List vertices = []; - int index = 0; - foreach (PolygonSoupChunk chunk in Chunks) + // Generate PolygonSoupChunks and BoundingBoxes + foreach (GenericMesh mesh in model.Meshes) + { + PolygonSoupChunk chunk = new(); + foreach (Face face in mesh.Faces) { - string id = index.ToString(); - - MathLib.Vector3I pos = chunk.Position; - float scale = chunk.Scale; - Model model = new Model(chunk.BuildMesh(pos, scale)); - SceneObject sceneObject = new SceneObject(id, model); - scene.AddObject(sceneObject); - index++; + PolygonSoupProperty property = new(); + + // Set Indices + property.Indices[0] = (byte)face.Indices[0]; + property.Indices[1] = (byte)face.Indices[1]; + property.Indices[2] = (byte)face.Indices[2]; + + if (face.Indices.Count > 3) + property.Indices[3] = (byte) face.Indices[3]; + else + property.Indices[3] = 0xFF; + + // Get data from material name + string materialName = face.Material.Name; + string[] split = materialName.Split('_'); + + // Parse the values + Utilities.Parse(split[1], true, out ushort unknownProperty1); + Utilities.Parse(split[2], true, out ushort unknownProperty2); + Utilities.Parse(split[3], true, out byte unknownByte1); + Utilities.Parse(split[4], true, out byte unknownByte2); + Utilities.Parse(split[5], true, out byte unknownByte3); + Utilities.Parse(split[6], true, out byte unknownByte4); + + // Combine unknownProperty1 and unknownProperty2 + property.UnknownProperty = (uint) ((unknownProperty2 << 16) | unknownProperty1); + + // Set unknown bytes + property.UnknownBytes[0] = unknownByte1; + property.UnknownBytes[1] = unknownByte2; + property.UnknownBytes[2] = unknownByte3; + property.UnknownBytes[3] = unknownByte4; + + // Add the property + chunk.PropertyList.Add(property); } - return scene; - } + // Add the vertices to the global vertices list + vertices.AddRange(mesh.Vertices.Values.ToArray()); - public void ImportObj(string path) - { - GenericModel model = OBJImporter.ImportOBJ(path); - model.SplitByPointCount(255); + // Get the minimum and maximum point of the mesh + Vector3 min = MathUtils.MinBounds([.. mesh.Vertices.Values]); + Vector3 max = MathUtils.MaxBounds([.. mesh.Vertices.Values]); + + // Use the minimum as the position + Vector3 position = min; - // Verify data before applying - foreach (GenericMesh mesh in model.Meshes) + // Set the scale to something standard + float scale = 0.015f; + + // Get the point count + uint pointCount = 0; + foreach (uint key in mesh.Vertices.Keys) { - // Get highest point - uint pointCount = 0; - foreach (uint key in mesh.Vertices.Keys) - { - if (pointCount < key) - { - pointCount = key; - } - } - pointCount++; - // Is it too big for a byte? - if (pointCount > 256) - throw new ReadFailedError("Too many points for mesh: " + mesh.Name + ", " + pointCount + " > 256"); - foreach (Face face in mesh.Faces) + if (pointCount < key) { - // Triangulation required for now. - if (face.Indices.Count > 3) - throw new ReadFailedError("Please triangulate your mesh: " + mesh.Name); - - // Material names are required - if (string.IsNullOrEmpty(face.Material?.Name)) - throw new ReadFailedError("Invalid Material for mesh: " + mesh.Name); - - // Verify that all data is there - string[] split = face.Material.Name.Split('_'); - if (split.Length < 7) - throw new ReadFailedError("Invalid Material Data: " + face.Material.Name + ", for mesh: " + mesh.Name); - - // Verify that all data can be parsed - try - { - Utilities.Parse(split[1], true, out ushort _); - Utilities.Parse(split[2], true, out ushort _); - Utilities.Parse(split[3], true, out byte _); - Utilities.Parse(split[4], true, out byte _); - Utilities.Parse(split[5], true, out byte _); - Utilities.Parse(split[6], true, out byte _); - } - catch (NotSupportedException) - { - throw new ReadFailedError("Unable to Parse Material Data: " + face.Material.Name + ", for mesh: " + mesh.Name); - } + pointCount = key; } } + pointCount++; + Vector3S[] verts = new Vector3S[pointCount]; + foreach (uint key in mesh.Vertices.Keys) + { + // Convert the point to a short and apply position and scale + verts[key] = new Vector3S((mesh.Vertices[key] - position) / scale); + } + chunk.PointList = [.. verts]; + + // Quads are currently unsupported + chunk.QuadCount = 0; - // Clear existing data - Chunks.Clear(); - BoundingBoxes.Clear(); + chunk.Scale = scale; - // Global vertices list to calculate the bounding box - List vertices = new List(); + // Set the position and apply scale + chunk.Position = new MathLib.Vector3I(position / scale); - // Generate PolygonSoupChunks and BoundingBoxes - foreach (GenericMesh mesh in model.Meshes) - { - PolygonSoupChunk chunk = new PolygonSoupChunk(); - foreach (Face face in mesh.Faces) - { - PolygonSoupProperty property = new PolygonSoupProperty(); - - // Set Indices - property.Indices[0] = (byte)face.Indices[0]; - property.Indices[1] = (byte)face.Indices[1]; - property.Indices[2] = (byte)face.Indices[2]; - - if (face.Indices.Count > 3) - property.Indices[3] = (byte) face.Indices[3]; - else - property.Indices[3] = 0xFF; - - // Get data from material name - string materialName = face.Material.Name; - string[] split = materialName.Split('_'); - - // Parse the values - Utilities.Parse(split[1], true, out ushort unknownProperty1); - Utilities.Parse(split[2], true, out ushort unknownProperty2); - Utilities.Parse(split[3], true, out byte unknownByte1); - Utilities.Parse(split[4], true, out byte unknownByte2); - Utilities.Parse(split[5], true, out byte unknownByte3); - Utilities.Parse(split[6], true, out byte unknownByte4); - - // Combine unknownProperty1 and unknownProperty2 - property.UnknownProperty = (uint) ((unknownProperty2 << 16) | unknownProperty1); - - // Set unknown bytes - property.UnknownBytes[0] = unknownByte1; - property.UnknownBytes[1] = unknownByte2; - property.UnknownBytes[2] = unknownByte3; - property.UnknownBytes[3] = unknownByte4; - - // Add the property - chunk.PropertyList.Add(property); - } + // Add the chunk + Chunks.Add(chunk); - // Add the vertices to the global vertices list - vertices.AddRange(mesh.Vertices.Values.ToArray()); + // Add the bounding box + BoundingBoxes.Add(new PolygonSoupBoundingBox(new BoxF(min, max), -1)); + } - // Get the minimum and maximum point of the mesh - Vector3 min = MathUtils.MinBounds(mesh.Vertices.Values.ToArray()); - Vector3 max = MathUtils.MaxBounds(mesh.Vertices.Values.ToArray()); + // Calculate Bounding Box + Min = MathUtils.MinBounds([.. vertices]); + Max = MathUtils.MaxBounds([.. vertices]); + } - // Use the minimum as the position - Vector3 position = min; + private void Clear() + { + Min = default; + Unknown4 = default; + Max = default; + Unknown8 = default; + BoundingBoxes.Clear(); + Chunks.Clear(); + } - // Set the scale to something standard - float scale = 0.015f; - - // Get the point count - uint pointCount = 0; - foreach (uint key in mesh.Vertices.Keys) - { - if (pointCount < key) - { - pointCount = key; - } - } - pointCount++; - Vector3S[] verts = new Vector3S[pointCount]; - foreach (uint key in mesh.Vertices.Keys) - { - // Convert the point to a short and apply position and scale - verts[key] = new Vector3S((mesh.Vertices[key] - position) / scale); - } - chunk.PointList = verts.ToList(); - - // Quads are currently unsupported - chunk.QuadCount = 0; + public bool Read(BundleEntry entry, ILoader loader = null) + { + Clear(); - chunk.Scale = scale; + MemoryStream ms = entry.MakeStream(); + BinaryReader2 br = new(ms); + br.BigEndian = entry.Console; - // Set the position and apply scale - chunk.Position = new MathLib.Vector3I(position / scale); + bool x64 = entry.Platform == BundlePlatform.PCx64; + long ReadPtr() => x64 ? (long)br.ReadUInt64() : br.ReadUInt32(); - // Add the chunk - Chunks.Add(chunk); + Min = br.ReadVector3F(); + Unknown4 = br.ReadInt32(); + Max = br.ReadVector3F(); + Unknown8 = br.ReadInt32(); + long chunkPointerStart = ReadPtr(); + long boxListStart = ReadPtr(); + int chunkCount = br.ReadInt32(); + br.ReadUInt32(); // FileSize - // Add the bounding box - BoundingBoxes.Add(new PolygonSoupBoundingBox(new BoxF(min, max), -1)); - } + List chunkPointers = []; - // Calculate Bounding Box - Min = MathUtils.MinBounds(vertices.ToArray()); - Max = MathUtils.MaxBounds(vertices.ToArray()); + // No Data + if (chunkCount == 0) + { + br.Close(); + ms.Close(); + return true; } - private void Clear() + br.BaseStream.Position = chunkPointerStart; + + for (int i = 0; i < chunkCount; i++) { - Min = default; - Unknown4 = default; - Max = default; - Unknown8 = default; - BoundingBoxes.Clear(); - Chunks.Clear(); + chunkPointers.Add(ReadPtr()); } - public bool Read(BundleEntry entry, ILoader loader = null) + for (int i = 0; i < chunkCount; i++) { - Clear(); + // Read Vertically - MemoryStream ms = entry.MakeStream(); - BinaryReader2 br = new BinaryReader2(ms); - br.BigEndian = entry.Console; + long pos = boxListStart + 0x70 * (i / 4) + 4 * (i % 4); - bool x64 = entry.Platform == BundlePlatform.PCx64; - long ReadPtr() => x64 ? (long)br.ReadUInt64() : br.ReadUInt32(); + BoxF boundingBox = new(); + br.BaseStream.Position = pos; + float minX = br.ReadSingle(); + br.BaseStream.Position += 12; + float minY = br.ReadSingle(); + br.BaseStream.Position += 12; + float minZ = br.ReadSingle(); - Min = br.ReadVector3F(); - Unknown4 = br.ReadInt32(); - Max = br.ReadVector3F(); - Unknown8 = br.ReadInt32(); - long chunkPointerStart = ReadPtr(); - long boxListStart = ReadPtr(); - int chunkCount = br.ReadInt32(); - br.ReadUInt32(); // FileSize + boundingBox.Min = new Vector3(minX, minY, minZ); - List chunkPointers = new List(); + br.BaseStream.Position += 12; + float maxX = br.ReadSingle(); + br.BaseStream.Position += 12; + float maxY = br.ReadSingle(); + br.BaseStream.Position += 12; + float maxZ = br.ReadSingle(); + br.BaseStream.Position += 12; - // No Data - if (chunkCount == 0) - { - br.Close(); - ms.Close(); - return true; - } + boundingBox.Max = new Vector3(maxX, maxY, maxZ); - br.BaseStream.Position = chunkPointerStart; + PolygonSoupBoundingBox box = new(boundingBox, br.ReadInt32()); - for (int i = 0; i < chunkCount; i++) - { - chunkPointers.Add(ReadPtr()); - } - - for (int i = 0; i < chunkCount; i++) - { - // Read Vertically - - long pos = boxListStart + 0x70 * (i / 4) + 4 * (i % 4); - - BoxF boundingBox = new BoxF(); - br.BaseStream.Position = pos; - float minX = br.ReadSingle(); - br.BaseStream.Position += 12; - float minY = br.ReadSingle(); - br.BaseStream.Position += 12; - float minZ = br.ReadSingle(); - - boundingBox.Min = new Vector3(minX, minY, minZ); + BoundingBoxes.Add(box); + } - br.BaseStream.Position += 12; - float maxX = br.ReadSingle(); - br.BaseStream.Position += 12; - float maxY = br.ReadSingle(); - br.BaseStream.Position += 12; - float maxZ = br.ReadSingle(); - br.BaseStream.Position += 12; + for (int i = 0; i < chunkPointers.Count; i++) + { + br.BaseStream.Position = chunkPointers[i]; - boundingBox.Max = new Vector3(maxX, maxY, maxZ); + Chunks.Add(PolygonSoupChunk.Read(br, x64)); + } - PolygonSoupBoundingBox box = new PolygonSoupBoundingBox(boundingBox, br.ReadInt32()); + br.Close(); + ms.Close(); - BoundingBoxes.Add(box); - } + return true; + } - for (int i = 0; i < chunkPointers.Count; i++) + public bool Write(BundleEntry entry) + { + MemoryStream ms = new(); + BinaryWriter2 bw = new(ms); + bw.BigEndian = entry.Console; + + bool x64 = entry.Platform == BundlePlatform.PCx64; + void WritePtr(long ptr) { if (x64) bw.Write((ulong)ptr); else bw.Write((uint)ptr); } + + bw.Write(Min); + bw.Write(Unknown4); + bw.Write(Max); + bw.Write(Unknown8); + long chunkPointerStartPos = bw.BaseStream.Position; + WritePtr(0); + long boxListStartPos = bw.BaseStream.Position; + WritePtr(0); + bw.Write(Chunks.Count); + long fileSizePos = bw.BaseStream.Position; + bw.Write((uint)0); + + uint[] chunkPointers = new uint[Chunks.Count]; + + // No Data + if (Chunks.Count == 0) + { + if (x64) { - br.BaseStream.Position = chunkPointers[i]; - - Chunks.Add(PolygonSoupChunk.Read(br, x64)); + bw.BaseStream.Position = fileSizePos; + bw.Write((uint)bw.BaseStream.Length); + bw.BaseStream.SetLength(0x40); } - br.Close(); + bw.Flush(); + byte[] data2 = ms.ToArray(); + bw.Close(); ms.Close(); + entry.EntryBlocks[0].Data = data2; + entry.Dirty = true; return true; } - public bool Write(BundleEntry entry) + long cPos = bw.BaseStream.Position; + uint chunkPointerStart = (uint)bw.BaseStream.Position; + bw.BaseStream.Position = chunkPointerStartPos; + bw.Write((uint)cPos); + bw.BaseStream.Position = cPos; + + for (int i = 0; i < Chunks.Count; i++) { - MemoryStream ms = new MemoryStream(); - BinaryWriter2 bw = new BinaryWriter2(ms); - bw.BigEndian = entry.Console; - - bool x64 = entry.Platform == BundlePlatform.PCx64; - void WritePtr(long ptr) { if (x64) bw.Write((ulong)ptr); else bw.Write((uint)ptr); } - - bw.Write(Min); - bw.Write(Unknown4); - bw.Write(Max); - bw.Write(Unknown8); - long chunkPointerStartPos = bw.BaseStream.Position; - WritePtr(0); - long boxListStartPos = bw.BaseStream.Position; WritePtr(0); - bw.Write(Chunks.Count); - long fileSizePos = bw.BaseStream.Position; - bw.Write((uint)0); - - uint[] chunkPointers = new uint[Chunks.Count]; - - // No Data - if (Chunks.Count == 0) - { - if (x64) - { - bw.BaseStream.Position = fileSizePos; - bw.Write((uint)bw.BaseStream.Length); - bw.BaseStream.SetLength(0x40); - } - - bw.Flush(); - byte[] data2 = ms.ToArray(); - bw.Close(); - ms.Close(); - - entry.EntryBlocks[0].Data = data2; - entry.Dirty = true; - return true; - } - - long cPos = bw.BaseStream.Position; - uint chunkPointerStart = (uint)bw.BaseStream.Position; - bw.BaseStream.Position = chunkPointerStartPos; - bw.Write((uint)cPos); - bw.BaseStream.Position = cPos; + } - for (int i = 0; i < Chunks.Count; i++) - { - WritePtr(0); - } + bw.BaseStream.Position = (16 * ((bw.BaseStream.Position + 15) / 16)); + cPos = bw.BaseStream.Position; + uint boxListStart = (uint)bw.BaseStream.Position; + bw.BaseStream.Position = boxListStartPos; + WritePtr(cPos); - bw.BaseStream.Position = (16 * ((bw.BaseStream.Position + 15) / 16)); - cPos = bw.BaseStream.Position; - uint boxListStart = (uint)bw.BaseStream.Position; - bw.BaseStream.Position = boxListStartPos; - WritePtr(cPos); + for (int i = 0; i < Chunks.Count; i++) + { + // Write Vertically - for (int i = 0; i < Chunks.Count; i++) - { - // Write Vertically + long pos = boxListStart + 0x70 * (i / 4) + 4 * (i % 4); - long pos = boxListStart + 0x70 * (i / 4) + 4 * (i % 4); + PolygonSoupBoundingBox box = BoundingBoxes[i]; - PolygonSoupBoundingBox box = BoundingBoxes[i]; + bw.BaseStream.Position = pos; + bw.Write(box.Box.Min.X); + bw.BaseStream.Position += 12; + bw.Write(box.Box.Min.Y); + bw.BaseStream.Position += 12; + bw.Write(box.Box.Min.Z); - bw.BaseStream.Position = pos; - bw.Write(box.Box.Min.X); - bw.BaseStream.Position += 12; - bw.Write(box.Box.Min.Y); - bw.BaseStream.Position += 12; - bw.Write(box.Box.Min.Z); + bw.BaseStream.Position += 12; + bw.Write(box.Box.Max.X); + bw.BaseStream.Position += 12; + bw.Write(box.Box.Max.Y); + bw.BaseStream.Position += 12; + bw.Write(box.Box.Max.Z); - bw.BaseStream.Position += 12; - bw.Write(box.Box.Max.X); - bw.BaseStream.Position += 12; - bw.Write(box.Box.Max.Y); - bw.BaseStream.Position += 12; - bw.Write(box.Box.Max.Z); + bw.BaseStream.Position += 12; + bw.Write(box.Terminator); + } - bw.BaseStream.Position += 12; - bw.Write(box.Terminator); - } + bw.BaseStream.Position = (16 * ((bw.BaseStream.Position + 15) / 16)); - bw.BaseStream.Position = (16 * ((bw.BaseStream.Position + 15) / 16)); + if (!x64) + { + bw.BaseStream.Position = (128 * ((bw.BaseStream.Position + 127) / 128)); - if (!x64) + for (int i = 0; i < Chunks.Count / 4; i++) { - bw.BaseStream.Position = (128 * ((bw.BaseStream.Position + 127) / 128)); - - for (int i = 0; i < Chunks.Count / 4; i++) + if ((i % 8) % 3 == 0) { - if ((i % 8) % 3 == 0) - { - bw.BaseStream.Position += 256; - } - else - { - bw.BaseStream.Position += 384; - } + bw.BaseStream.Position += 256; + } + else + { + bw.BaseStream.Position += 384; } } + } - for (int i = 0; i < chunkPointers.Length; i++) - { - bw.BaseStream.Position = (128 * ((bw.BaseStream.Position + 127) / 128)); + for (int i = 0; i < chunkPointers.Length; i++) + { + bw.BaseStream.Position = (128 * ((bw.BaseStream.Position + 127) / 128)); - chunkPointers[i] = (uint)bw.BaseStream.Position; + chunkPointers[i] = (uint)bw.BaseStream.Position; - Chunks[i].Write(bw, x64); - } + Chunks[i].Write(bw, x64); + } - if (x64) - { - cPos = bw.BaseStream.Position + 0x60; - bw.BaseStream.SetLength(16 * ((cPos + 15) / 16)); - } - else - { - bw.BaseStream.Position = (16 * ((bw.BaseStream.Position + 15) / 16)) + 0x5F; - bw.Write((byte)0); - cPos = bw.BaseStream.Position; - } + if (x64) + { + cPos = bw.BaseStream.Position + 0x60; + bw.BaseStream.SetLength(16 * ((cPos + 15) / 16)); + } + else + { + bw.BaseStream.Position = (16 * ((bw.BaseStream.Position + 15) / 16)) + 0x5F; + bw.Write((byte)0); + cPos = bw.BaseStream.Position; + } - bw.BaseStream.Position = fileSizePos; - bw.Write((uint)cPos); + bw.BaseStream.Position = fileSizePos; + bw.Write((uint)cPos); - bw.BaseStream.Position = chunkPointerStart; - for (int i = 0; i < Chunks.Count; i++) - { - WritePtr(chunkPointers[i]); - } + bw.BaseStream.Position = chunkPointerStart; + for (int i = 0; i < Chunks.Count; i++) + { + WritePtr(chunkPointers[i]); + } - bw.Flush(); - byte[] data = ms.ToArray(); - bw.Close(); - ms.Close(); + bw.Flush(); + byte[] data = ms.ToArray(); + bw.Close(); + ms.Close(); - entry.EntryBlocks[0].Data = data; - entry.Dirty = true; + entry.EntryBlocks[0].Data = data; + entry.Dirty = true; - return true; - } + return true; + } - public EntryType GetEntryType(BundleEntry entry) - { - return EntryType.PolygonSoupList; - } + public EntryType GetEntryType(BundleEntry entry) + { + return EntryType.PolygonSoupList; + } - public IEntryEditor GetEditor(BundleEntry entry) + public IEntryEditor GetEditor(BundleEntry entry) + { + WorldColEditor editor = new(); + editor.Poly = this; + editor.Changed += () => { - WorldColEditor editor = new WorldColEditor(); - editor.Poly = this; - editor.Changed += () => - { - Write(entry); - }; + Write(entry); + }; - return editor; - } + return editor; } } diff --git a/WorldCollisionHandler/WorldColEditor.cs b/WorldCollisionHandler/WorldColEditor.cs index 106fd83..0826513 100644 --- a/WorldCollisionHandler/WorldColEditor.cs +++ b/WorldCollisionHandler/WorldColEditor.cs @@ -5,96 +5,95 @@ using System.ComponentModel; using System.Windows.Forms; -namespace WorldCollisionHandler +namespace WorldCollisionHandler; + +public partial class WorldColEditor : Form, IEntryEditor { - public partial class WorldColEditor : Form, IEntryEditor - { - public delegate void OnChanged(); - public event OnChanged Changed; + public delegate void OnChanged(); + public event OnChanged Changed; - private PolygonSoupList _poly; - [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] - public PolygonSoupList Poly + private PolygonSoupList _poly; + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public PolygonSoupList Poly + { + get => _poly; + set { - get => _poly; - set - { - _poly = value; - UpdateDisplay(); - } + _poly = value; + UpdateDisplay(); } + } - public WorldColEditor() - { - InitializeComponent(); - } + public WorldColEditor() + { + InitializeComponent(); + } - private void UpdateDisplay() - { - rndMain.Scene = _poly?.MakeScene(); - } + private void UpdateDisplay() + { + rndMain.Scene = _poly?.MakeScene(); + } - private void ImportModel() + private void ImportModel() + { + OpenFileDialog ofd = new(); + ofd.Filter = "Wavefront OBJ|*.obj"; + DialogResult result = ofd.ShowDialog(this); + if (result == DialogResult.OK) { - OpenFileDialog ofd = new OpenFileDialog(); - ofd.Filter = "Wavefront OBJ|*.obj"; - DialogResult result = ofd.ShowDialog(this); - if (result == DialogResult.OK) - { - string path = ofd.FileName; - if (string.IsNullOrEmpty(path) || path.Trim().Length == 0) - return; - - bool success; - try - { - _poly.ImportObj(path); - success = true; - } - catch (ReadFailedError ex) - { - MessageBox.Show(this, ex.Message, "Read Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - success = false; - } - UpdateDisplay(); + string path = ofd.FileName; + if (string.IsNullOrEmpty(path) || path.Trim().Length == 0) + return; - if (success) - Changed?.Invoke(); + bool success; + try + { + _poly.ImportObj(path); + success = true; } - } + catch (ReadFailedError ex) + { + MessageBox.Show(this, ex.Message, "Read Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + success = false; + } + UpdateDisplay(); - private void ExportModel() - { - rndMain.ExportWavefrontObj(); + if (success) + Changed?.Invoke(); } + } - private void importModelToolStripMenuItem_Click(object sender, EventArgs e) - { - ImportModel(); - } + private void ExportModel() + { + rndMain.ExportWavefrontObj(); + } - private void exportModelToolStripMenuItem_Click(object sender, EventArgs e) - { - ExportModel(); - } + private void importModelToolStripMenuItem_Click(object sender, EventArgs e) + { + ImportModel(); + } - private void closeToolStripMenuItem_Click(object sender, EventArgs e) - { - Close(); - } + private void exportModelToolStripMenuItem_Click(object sender, EventArgs e) + { + ExportModel(); + } - private void debugInfoToolStripMenuItem_Click(object sender, EventArgs e) - { - if (_poly != null) - DebugUtil.ShowDebug(this, _poly); - } + private void closeToolStripMenuItem_Click(object sender, EventArgs e) + { + Close(); + } - private void removeWreckSurfacesToolStripMenuItem_Click(object sender, EventArgs e) - { - _poly?.RemoveWreckSurfaces(); - UpdateDisplay(); + private void debugInfoToolStripMenuItem_Click(object sender, EventArgs e) + { + if (_poly != null) + DebugUtil.ShowDebug(this, _poly); + } - Changed?.Invoke(); - } + private void removeWreckSurfacesToolStripMenuItem_Click(object sender, EventArgs e) + { + _poly?.RemoveWreckSurfaces(); + UpdateDisplay(); + + Changed?.Invoke(); } } diff --git a/WorldCollisionHandler/WorldCollisionPlugin.cs b/WorldCollisionHandler/WorldCollisionPlugin.cs index e55c908..f898b68 100644 --- a/WorldCollisionHandler/WorldCollisionPlugin.cs +++ b/WorldCollisionHandler/WorldCollisionPlugin.cs @@ -5,101 +5,100 @@ using System.IO; using System.Windows.Forms; -namespace WorldCollisionHandler +namespace WorldCollisionHandler; + +public class WorldCollisionPlugin : IPlugin { - public class WorldCollisionPlugin : IPlugin + public string Id => "worldcolplugin"; + public string Name => "World Collision Handler"; + + public static void Init() { - public string Id => "worldcolplugin"; - public string Name => "World Collision Handler"; - - public static void Init() - { - EntryTypeRegistry.Register(EntryType.PolygonSoupList, new PolygonSoupList()); + EntryTypeRegistry.Register(EntryType.PolygonSoupList, new PolygonSoupList()); - PluginCommandRegistry.Register("dump_all_collisions", "Dump All Collisions", DumpAllCollisions, IsWorldCol); - PluginCommandRegistry.Register("remove_wreck_surfaces", "Remove Wreck Surfaces", RemoveWreckSurfaces, IsWorldCol); - } + PluginCommandRegistry.Register("dump_all_collisions", "Dump All Collisions", DumpAllCollisions, IsWorldCol); + PluginCommandRegistry.Register("remove_wreck_surfaces", "Remove Wreck Surfaces", RemoveWreckSurfaces, IsWorldCol); + } - #region Extra Tools + #region Extra Tools - private static bool IsWorldCol(BundleArchive archive) + private static bool IsWorldCol(BundleArchive archive) + { + for (int i = 0; i < archive.Entries.Count; i++) { - for (int i = 0; i < archive.Entries.Count; i++) - { - BundleEntry entry = archive.Entries[i]; - - if (entry.Type == EntryType.PolygonSoupList) - return true; - } + BundleEntry entry = archive.Entries[i]; - return false; + if (entry.Type == EntryType.PolygonSoupList) + return true; } - private static void DumpAllCollisions(IWin32Window window, BundleArchive archive) + return false; + } + + private static void DumpAllCollisions(IWin32Window window, BundleArchive archive) + { + if (archive == null) + return; + + FolderBrowserDialog fbd = new(); + DialogResult result = fbd.ShowDialog(window); + if (result == DialogResult.OK) { - if (archive == null) - return; + string path = fbd.SelectedPath; - FolderBrowserDialog fbd = new FolderBrowserDialog(); - DialogResult result = fbd.ShowDialog(window); - if (result == DialogResult.OK) + for (int i = 0; ; i++) { - string path = fbd.SelectedPath; - - for (int i = 0; ; i++) - { - string idListName = "trk_clil" + i; - string polyName = "trk_col_" + i; - - ulong idListID = Crc32.HashCrc32B(idListName); - ulong polyID = Crc32.HashCrc32B(polyName); - - BundleEntry entry = archive.GetEntryByID(idListID); - if (entry == null) - break; - Stream outFile = File.Open(path + "/" + idListName + ".bin", FileMode.Create, FileAccess.Write); - BinaryWriter2 bw = new BinaryWriter2(outFile); - bw.Write(entry.EntryBlocks[0].Data); - bw.Flush(); - bw.Close(); - outFile.Close(); - - BundleEntry polyEntry = archive.GetEntryByID(polyID); - if (polyEntry == null) - break; - Stream outFilePoly = File.Open(path + "/" + polyName + ".bin", FileMode.Create, FileAccess.Write); - BinaryWriter2 bwPoly = new BinaryWriter2(outFilePoly); - bwPoly.Write(polyEntry.EntryBlocks[0].Data); - bwPoly.Flush(); - bwPoly.Close(); - outFilePoly.Close(); - - PolygonSoupList poly = new PolygonSoupList(); - poly.Read(polyEntry); - Scene scene = poly.MakeScene(); - scene.ExportWavefrontObj(path + "/" + polyName + ".obj"); - } - - MessageBox.Show(window, "Done!", "Success", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + string idListName = "trk_clil" + i; + string polyName = "trk_col_" + i; + + ulong idListID = Crc32.HashCrc32B(idListName); + ulong polyID = Crc32.HashCrc32B(polyName); + + BundleEntry entry = archive.GetEntryByID(idListID); + if (entry == null) + break; + Stream outFile = File.Open(path + "/" + idListName + ".bin", FileMode.Create, FileAccess.Write); + BinaryWriter2 bw = new(outFile); + bw.Write(entry.EntryBlocks[0].Data); + bw.Flush(); + bw.Close(); + outFile.Close(); + + BundleEntry polyEntry = archive.GetEntryByID(polyID); + if (polyEntry == null) + break; + Stream outFilePoly = File.Open(path + "/" + polyName + ".bin", FileMode.Create, FileAccess.Write); + BinaryWriter2 bwPoly = new(outFilePoly); + bwPoly.Write(polyEntry.EntryBlocks[0].Data); + bwPoly.Flush(); + bwPoly.Close(); + outFilePoly.Close(); + + PolygonSoupList poly = new(); + poly.Read(polyEntry); + Scene scene = poly.MakeScene(); + scene.ExportWavefrontObj(path + "/" + polyName + ".obj"); } + + MessageBox.Show(window, "Done!", "Success", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } + } - private static void RemoveWreckSurfaces(IWin32Window window, BundleArchive archive) + private static void RemoveWreckSurfaces(IWin32Window window, BundleArchive archive) + { + for (int i = 0; i < archive.Entries.Count; i++) { - for (int i = 0; i < archive.Entries.Count; i++) + BundleEntry entry = archive.Entries[i]; + + if (entry.Type == EntryType.PolygonSoupList) { - BundleEntry entry = archive.Entries[i]; - - if (entry.Type == EntryType.PolygonSoupList) - { - PolygonSoupList list = new PolygonSoupList(); - list.Read(entry); - list.RemoveWreckSurfaces(); - list.Write(entry); - } + PolygonSoupList list = new(); + list.Read(entry); + list.RemoveWreckSurfaces(); + list.Write(entry); } } - - #endregion } + + #endregion }