From d31c3120950d670d1efbbfdd15024812131c14b3 Mon Sep 17 00:00:00 2001 From: ihatecompvir Date: Tue, 7 Jan 2025 19:09:54 -0800 Subject: [PATCH] RB3 RndMat, RB3 OutfitConfig, CharMeshHide --- MiloEditor/Panels/EditorPanel.cs | 75 ++- MiloLib/Assets/Band/BandCrowdMeterDir.cs | 4 +- MiloLib/Assets/Band/BandPatchMesh.cs | 145 ++++++ MiloLib/Assets/Char/CharMeshHide.cs | 182 +++++++ MiloLib/Assets/Char/Character.cs | 5 + MiloLib/Assets/DirectoryMeta.cs | 622 ++++++++++++----------- MiloLib/Assets/EventTrigger.cs | 118 +++++ MiloLib/Assets/OutfitConfig.cs | 335 ++++++++++-- MiloLib/Assets/Rnd/RndMat.cs | 316 +++++------- MiloLib/MiloFile.cs | 5 +- 10 files changed, 1255 insertions(+), 552 deletions(-) create mode 100644 MiloLib/Assets/Band/BandPatchMesh.cs create mode 100644 MiloLib/Assets/Char/CharMeshHide.cs diff --git a/MiloEditor/Panels/EditorPanel.cs b/MiloEditor/Panels/EditorPanel.cs index 38583e4..1b2aaa3 100644 --- a/MiloEditor/Panels/EditorPanel.cs +++ b/MiloEditor/Panels/EditorPanel.cs @@ -280,13 +280,13 @@ private void BuildUI(object obj, int startX, int startY, bool drawTypeLabels) { // color pickers for a HmxColor4 List (inside ColorPalettes, mainly, but can appear other places) case List colorList: - inputControl = BuildColorPicker(colorList, field); + inputControl = BuildListColorPicker(colorList, field); break; case HmxColor4 color: - inputControl = BuildColorPicker(new List { color }, field); + inputControl = BuildColor4Picker(color, field); break; - case HmxColor3 color: // TODO: make a real Color3 picker - inputControl = BuildColorPicker(new List { new HmxColor4(color.r, color.g, color.b, 1.0f) }, field); + case HmxColor3 color: + inputControl = BuildColor3Picker(color, field); break; // list of bytes case List byteValue: @@ -363,8 +363,73 @@ private void BuildUI(object obj, int startX, int startY, bool drawTypeLabels) } } + private Control BuildColor4Picker(HmxColor4 color, FieldInfo field) + { + var colorPicker = new ColorPicker + { + Width = 100, + Height = 30, + Margin = new Padding(5), + BorderStyle = BorderStyle.FixedSingle, + Color = Color.FromArgb(255, (int)(color.r * 255), (int)(color.g * 255), (int)(color.b * 255)) + }; + + colorPicker.ColorChanged += (sender, args) => + { + var picker = (ColorPicker)sender; + var selectedColor = picker.Color; + float a = selectedColor.A / 255.0f; + float r = selectedColor.R / 255.0f; + float g = selectedColor.G / 255.0f; + float b = selectedColor.B / 255.0f; + + object ownerObject = ResolveFieldOwner(targetObject, field); + + if (ownerObject != null) + { + // Update the field value + HmxColor4 updatedColor = new HmxColor4 { a = a, r = r, g = g, b = b }; + field.SetValue(ownerObject, updatedColor); + } + }; + + return colorPicker; + } + + private Control BuildColor3Picker(HmxColor3 color, FieldInfo field) + { + var colorPicker = new ColorPicker + { + Width = 100, + Height = 30, + Margin = new Padding(5), + BorderStyle = BorderStyle.FixedSingle, + Color = Color.FromArgb(255, (int)(color.r * 255), (int)(color.g * 255), (int)(color.b * 255)) + }; + + colorPicker.ColorChanged += (sender, args) => + { + var picker = (ColorPicker)sender; + var selectedColor = picker.Color; + float r = selectedColor.R / 255.0f; + float g = selectedColor.G / 255.0f; + float b = selectedColor.B / 255.0f; + + object ownerObject = ResolveFieldOwner(targetObject, field); + + if (ownerObject != null) + { + // Update the field value + HmxColor3 updatedColor = new HmxColor3 { r = r, g = g, b = b }; + field.SetValue(ownerObject, updatedColor); + } + }; + + return colorPicker; + } + - private Control BuildColorPicker(List colorList, FieldInfo field) + private Control BuildListColorPicker(List colorList, FieldInfo field) { var scrollingPanel = new Panel { diff --git a/MiloLib/Assets/Band/BandCrowdMeterDir.cs b/MiloLib/Assets/Band/BandCrowdMeterDir.cs index 51338a5..7eb2f22 100644 --- a/MiloLib/Assets/Band/BandCrowdMeterDir.cs +++ b/MiloLib/Assets/Band/BandCrowdMeterDir.cs @@ -24,8 +24,8 @@ public class BandCrowdMeterDir : RndDir //{ Game.MiloGame.GreenDayRockBand, 22 }, { Game.MiloGame.RockBand3, 3 }, }; - public ushort altRevision; - public ushort revision; + private ushort altRevision; + private ushort revision; private uint colorCount; diff --git a/MiloLib/Assets/Band/BandPatchMesh.cs b/MiloLib/Assets/Band/BandPatchMesh.cs new file mode 100644 index 0000000..2d1846a --- /dev/null +++ b/MiloLib/Assets/Band/BandPatchMesh.cs @@ -0,0 +1,145 @@ +using MiloLib.Classes; +using MiloLib.Utils; + +namespace MiloLib.Assets.Band +{ + public class BandPatchMesh + { + + + public class MeshPair + { + public class PatchPair + { + public Symbol patch = new(0, ""); + public Symbol tex = new(0, ""); + + public PatchPair Read(EndianReader reader) + { + patch = Symbol.Read(reader); + tex = Symbol.Read(reader); + return this; + } + + public void Write(EndianWriter writer) + { + Symbol.Write(writer, patch); + Symbol.Write(writer, tex); + } + } + + public Symbol mesh = new(0, ""); + private uint patchPairCount; + public List patchPairs = new(); + + public class MeshVert + { + + } + + public MeshPair Read(EndianReader reader) + { + mesh = Symbol.Read(reader); + return this; + } + + public void Write(EndianWriter writer) + { + Symbol.Write(writer, mesh); + } + + + } + + private ushort altRevision; + private ushort revision; + + private uint meshPairCount; + public List meshPairs = new(); + + public bool renderTo; + + public Symbol source = new(0, ""); + + public int category; + + public Symbol unkSymbol1 = new(0, ""); + public Symbol unkSymbol2 = new(0, ""); + + public Symbol unkSymbol3 = new(0, ""); + + public BandPatchMesh Read(EndianReader reader, bool standalone, DirectoryMeta parent, DirectoryMeta.Entry entry) + { + uint combinedRevision = reader.ReadUInt32(); + if (BitConverter.IsLittleEndian) (revision, altRevision) = ((ushort)(combinedRevision & 0xFFFF), (ushort)((combinedRevision >> 16) & 0xFFFF)); + else (altRevision, revision) = ((ushort)(combinedRevision & 0xFFFF), (ushort)((combinedRevision >> 16) & 0xFFFF)); + + source = Symbol.Read(reader); + + if (revision > 3) + { + meshPairCount = reader.ReadUInt32(); + for (int i = 0; i < meshPairCount; i++) + meshPairs.Add(new MeshPair().Read(reader)); + } + else + { + meshPairs.Add(new MeshPair().Read(reader)); + } + if (revision < 1) + unkSymbol1 = Symbol.Read(reader); + + if (revision < 4) + unkSymbol2 = Symbol.Read(reader); + + if (revision > 1) + { + if (revision > 2) + renderTo = reader.ReadBoolean(); + else + unkSymbol3 = Symbol.Read(reader); + } + + if (revision > 3) + category = reader.ReadInt32(); + + return this; + } + + public void Write(EndianWriter writer, bool standalone, DirectoryMeta parent, DirectoryMeta.Entry? entry) + { + writer.WriteUInt32(BitConverter.IsLittleEndian ? (uint)(altRevision << 16 | revision) : (uint)(revision << 16 | altRevision)); + + Symbol.Write(writer, source); + + if (revision > 3) + { + writer.WriteUInt32((uint)meshPairs.Count); + foreach (MeshPair meshPair in meshPairs) + meshPair.Write(writer); + } + else + { + meshPairs[0].Write(writer); + } + + if (revision < 1) + Symbol.Write(writer, unkSymbol1); + + if (revision < 4) + Symbol.Write(writer, unkSymbol2); + + if (revision > 1) + { + if (revision > 2) + writer.WriteBoolean(renderTo); + else + Symbol.Write(writer, unkSymbol3); + } + + if (revision > 3) + writer.WriteInt32(category); + } + + } +} diff --git a/MiloLib/Assets/Char/CharMeshHide.cs b/MiloLib/Assets/Char/CharMeshHide.cs new file mode 100644 index 0000000..d4b91d7 --- /dev/null +++ b/MiloLib/Assets/Char/CharMeshHide.cs @@ -0,0 +1,182 @@ +using MiloLib.Classes; +using MiloLib.Utils; + +namespace MiloLib.Assets.Char +{ + [Name("CharMeshHide"), Description("")] + public class CharMeshHide : Object + { + public class Hide + { + public Symbol draw = new(0, ""); + public int flags; + public bool show; + + public Hide Read(EndianReader reader, uint revision) + { + draw = Symbol.Read(reader); + flags = reader.ReadInt32(); + if (revision > 1) + show = reader.ReadBoolean(); + return this; + } + + public void Write(EndianWriter writer, uint revision) + { + Symbol.Write(writer, draw); + writer.WriteInt32(flags); + if (revision > 1) + writer.WriteBoolean(show); + } + + public override string ToString() + { + return $"{draw} flags: {flags} showing: {show}"; + } + } + + [Flags] + public enum HideOptions + { + None = 0, + HideLongCoat = 1, + HideLongDress = 2, + HideLongSleeve = 4, + HideMidSleeve = 8, + HideFullSleeve = 16, + HideHead = 32, + HideLongGlove = 64, + HideMask = 128, + HideLongBoot = 256, + HideShortSleeve = 512, + HideShortBoot = 1024, + HideLongPants = 2048, + HideGlasses = 4096, + HideVignette = 8192, + HideSocks = 16384 + } + + private void SetFromFlags(int flags) + { + var options = (HideOptions)flags; + + hideLongCoat = options.HasFlag(HideOptions.HideLongCoat); + hideLongDress = options.HasFlag(HideOptions.HideLongDress); + hideLongSleeve = options.HasFlag(HideOptions.HideLongSleeve); + hideMidSleeve = options.HasFlag(HideOptions.HideMidSleeve); + hideFullSleeve = options.HasFlag(HideOptions.HideFullSleeve); + hideHead = options.HasFlag(HideOptions.HideHead); + hideLongGlove = options.HasFlag(HideOptions.HideLongGlove); + hideMask = options.HasFlag(HideOptions.HideMask); + hideLongBoot = options.HasFlag(HideOptions.HideLongBoot); + hideShortSleeve = options.HasFlag(HideOptions.HideShortSleeve); + hideShortBoot = options.HasFlag(HideOptions.HideShortBoot); + hideLongPants = options.HasFlag(HideOptions.HideLongPants); + hideGlasses = options.HasFlag(HideOptions.HideGlasses); + hideVignette = options.HasFlag(HideOptions.HideVignette); + hideSocks = options.HasFlag(HideOptions.HideSocks); + } + + private int GetFlags() + { + var options = HideOptions.None; + + if (hideLongCoat) options |= HideOptions.HideLongCoat; + if (hideLongDress) options |= HideOptions.HideLongDress; + if (hideLongSleeve) options |= HideOptions.HideLongSleeve; + if (hideMidSleeve) options |= HideOptions.HideMidSleeve; + if (hideFullSleeve) options |= HideOptions.HideFullSleeve; + if (hideHead) options |= HideOptions.HideHead; + if (hideLongGlove) options |= HideOptions.HideLongGlove; + if (hideMask) options |= HideOptions.HideMask; + if (hideLongBoot) options |= HideOptions.HideLongBoot; + if (hideShortSleeve) options |= HideOptions.HideShortSleeve; + if (hideShortBoot) options |= HideOptions.HideShortBoot; + if (hideLongPants) options |= HideOptions.HideLongPants; + if (hideGlasses) options |= HideOptions.HideGlasses; + if (hideVignette) options |= HideOptions.HideVignette; + if (hideSocks) options |= HideOptions.HideSocks; + + return (int)options; + } + + + public ushort altRevision; + public ushort revision; + + private uint hidesCount; + public List hides = new(); + + public int flags; + + + [Name("Hide Long Coat")] + public bool hideLongCoat; + [Name("Hide Long Dress")] + public bool hideLongDress; + [Name("Hide Long Sleeve")] + public bool hideLongSleeve; + [Name("Hide Mid Sleeve")] + public bool hideMidSleeve; + [Name("Hide Full Sleeve")] + public bool hideFullSleeve; + [Name("Hide Head"), Description("Means the whole head should be hidden, like for a horse head mask or something crazy")] + public bool hideHead; + [Name("Hide Long Glove")] + public bool hideLongGlove; + [Name("Hide Mask")] + public bool hideMask; + [Name("Hide Long Boot")] + public bool hideLongBoot; + [Name("Hide Short Sleeve")] + public bool hideShortSleeve; + [Name("Hide Short Boot")] + public bool hideShortBoot; + [Name("Hide Long Pants")] + public bool hideLongPants; + [Name("Hide Glasses")] + public bool hideGlasses; + [Name("Hide in Vignette"), Description("Means geometry is too big for vignettes, but closet and game should be fine")] + public bool hideVignette; + [Name("Hide Socks"), Description("Means legs include socks, so show socked foot geometry rather than barefoot geometry")] + public bool hideSocks; + + public CharMeshHide Read(EndianReader reader, bool standalone, DirectoryMeta parent, DirectoryMeta.Entry entry) + { + uint combinedRevision = reader.ReadUInt32(); + if (BitConverter.IsLittleEndian) (revision, altRevision) = ((ushort)(combinedRevision & 0xFFFF), (ushort)(combinedRevision >> 16 & 0xFFFF)); + else (altRevision, revision) = ((ushort)(combinedRevision & 0xFFFF), (ushort)(combinedRevision >> 16 & 0xFFFF)); + + base.Read(reader, false, parent, entry); + + flags = reader.ReadInt32(); + SetFromFlags(flags); + + hidesCount = reader.ReadUInt32(); + for (int i = 0; i < hidesCount; i++) + hides.Add(new Hide().Read(reader, revision)); + + if (standalone) + if ((reader.Endianness == Endian.BigEndian ? 0xADDEADDE : 0xDEADDEAD) != reader.ReadUInt32()) throw new Exception("Got to end of standalone asset but didn't find the expected end bytes, read likely did not succeed"); + + return this; + } + + public override void Write(EndianWriter writer, bool standalone, DirectoryMeta parent, DirectoryMeta.Entry? entry) + { + writer.WriteUInt32(BitConverter.IsLittleEndian ? (uint)(altRevision << 16 | revision) : (uint)(revision << 16 | altRevision)); + + base.Write(writer, false, parent, entry); + + int flags = GetFlags(); + writer.WriteInt32(flags); + writer.WriteUInt32(hidesCount); + foreach (var hide in hides) + hide.Write(writer, revision); + + if (standalone) + writer.WriteBlock(new byte[4] { 0xAD, 0xDE, 0xAD, 0xDE }); + } + + } +} diff --git a/MiloLib/Assets/Char/Character.cs b/MiloLib/Assets/Char/Character.cs index e2868fd..364e0cd 100644 --- a/MiloLib/Assets/Char/Character.cs +++ b/MiloLib/Assets/Char/Character.cs @@ -95,6 +95,11 @@ public void Write(EndianWriter writer, uint revision) } } } + + public override string ToString() + { + return $"{group} {transGroup} opaque: {opaqueCount} translucent: {translucentCount}"; + } } public class CharacterTesting diff --git a/MiloLib/Assets/DirectoryMeta.cs b/MiloLib/Assets/DirectoryMeta.cs index bdc532c..b119045 100644 --- a/MiloLib/Assets/DirectoryMeta.cs +++ b/MiloLib/Assets/DirectoryMeta.cs @@ -466,66 +466,59 @@ public void ReadEntry(EndianReader reader, DirectoryMeta.Entry entry) { switch (entry.type.value) { - // DIRS - // These need special handling, they are different than inlined directories - - case "ObjectDir": - Debug.WriteLine("Reading entry ObjectDir " + entry.name.value); + ////////// + // DIRS // + ////////// + case "BandCharacter": + Debug.WriteLine("Reading entry BandCharacter " + entry.name.value); entry.isEntryInRootDir = true; - entry.obj = new ObjectDir(0).Read(reader, true, this, entry); + entry.obj = new BandCharacter(0).Read(reader, true, this, entry); DirectoryMeta dir = new DirectoryMeta(); dir.platform = platform; dir.Read(reader); entry.dir = dir; break; - case "EndingBonusDir": - case "RndDir": - Debug.WriteLine("Reading entry RndDir " + entry.name.value); + case "BandCrowdMeterDir": + Debug.WriteLine("Reading entry BandCrowdMeterDir " + entry.name.value); entry.isEntryInRootDir = true; - entry.obj = new RndDir(0).Read(reader, true, this, entry); + entry.obj = new BandCrowdMeterDir(0).Read(reader, true, this, entry); - if (((ObjectDir)entry.obj).inlineProxy) - { - dir = new DirectoryMeta(); - dir.platform = platform; - dir.Read(reader); - entry.dir = dir; - } + dir = new DirectoryMeta(); + dir.platform = platform; + dir.Read(reader); + entry.dir = dir; break; - case "OvershellDir": - Debug.WriteLine("Reading entry OvershellDir " + entry.name.value); + case "BandCrowdMeterIcon": + Debug.WriteLine("Reading entry BandCrowdMeterIcon " + entry.name.value); entry.isEntryInRootDir = true; - entry.obj = new OvershellDir(0).Read(reader, true, this, entry); + entry.obj = new BandCrowdMeterIcon(0).Read(reader, true, this, entry); dir = new DirectoryMeta(); dir.platform = platform; dir.Read(reader); entry.dir = dir; break; - case "UIPanel": - case "PanelDir": - Debug.WriteLine("Reading entry PanelDir " + entry.name.value); + case "BandScoreboard": + Debug.WriteLine("Reading entry BandScoreboard " + entry.name.value); entry.isEntryInRootDir = true; - entry.obj = new PanelDir(0).Read(reader, true, this, entry); + entry.obj = new BandScoreboard(0).Read(reader, true, this, entry); dir = new DirectoryMeta(); dir.platform = platform; dir.Read(reader); entry.dir = dir; break; - - case "WorldDir": - Debug.WriteLine("Reading entry WorldDir " + entry.name.value); + case "BandStarDisplay": + Debug.WriteLine("Reading entry BandStarDisplay " + entry.name.value); entry.isEntryInRootDir = true; - entry.obj = new WorldDir(0).Read(reader, true, this, entry); + entry.obj = new BandStarDisplay(0).Read(reader, true, this, entry); dir = new DirectoryMeta(); dir.platform = platform; dir.Read(reader); entry.dir = dir; break; - case "Character": Debug.WriteLine("Reading entry Character " + entry.name.value); entry.isEntryInRootDir = true; @@ -540,18 +533,16 @@ public void ReadEntry(EndianReader reader, DirectoryMeta.Entry entry) } break; - - case "P9Character": - Debug.WriteLine("Reading entry P9Character " + entry.name.value); + case "CharBoneDir": + Debug.WriteLine("Reading entry CharBoneDir " + entry.name.value); entry.isEntryInRootDir = true; - entry.obj = new P9Character(0).Read(reader, true, this, entry); + entry.obj = new CharBoneDir(0).Read(reader, true, this, entry); dir = new DirectoryMeta(); dir.platform = platform; dir.Read(reader); entry.dir = dir; break; - case "CharClipSet": Debug.WriteLine("Reading entry CharClipSet " + entry.name.value); entry.isEntryInRootDir = true; @@ -565,322 +556,309 @@ public void ReadEntry(EndianReader reader, DirectoryMeta.Entry entry) dir.Read(reader); entry.dir = dir; break; - - case "CharBoneDir": - Debug.WriteLine("Reading entry CharBoneDir " + entry.name.value); + case "EndingBonusDir": + case "RndDir": + Debug.WriteLine("Reading entry RndDir " + entry.name.value); entry.isEntryInRootDir = true; - entry.obj = new CharBoneDir(0).Read(reader, true, this, entry); + entry.obj = new RndDir(0).Read(reader, true, this, entry); - dir = new DirectoryMeta(); - dir.platform = platform; - dir.Read(reader); - entry.dir = dir; + if (((ObjectDir)entry.obj).inlineProxy) + { + dir = new DirectoryMeta(); + dir.platform = platform; + dir.Read(reader); + entry.dir = dir; + } break; - - case "UIListDir": - Debug.WriteLine("Reading entry UIListDir " + entry.name.value); + case "GemTrackDir": + Debug.WriteLine("Reading entry GemTrackDir " + entry.name.value); entry.isEntryInRootDir = true; - entry.obj = new UIListDir(0).Read(reader, true, this, entry); + entry.obj = new GemTrackDir(0).Read(reader, true, this, entry); dir = new DirectoryMeta(); dir.platform = platform; dir.Read(reader); entry.dir = dir; break; - - case "UILabelDir": - Debug.WriteLine("Reading entry UILabelDir " + entry.name.value); + case "MoveDir": + Debug.WriteLine("Reading entry MoveDir " + entry.name.value); entry.isEntryInRootDir = true; - entry.obj = new UILabelDir(0).Read(reader, true, this, entry); + entry.obj = new MoveDir(0).Read(reader, true, this, entry); dir = new DirectoryMeta(); dir.platform = platform; dir.Read(reader); entry.dir = dir; break; - - case "BandCrowdMeterDir": - Debug.WriteLine("Reading entry BandCrowdMeterDir " + entry.name.value); + case "ObjectDir": + Debug.WriteLine("Reading entry ObjectDir " + entry.name.value); entry.isEntryInRootDir = true; - entry.obj = new BandCrowdMeterDir(0).Read(reader, true, this, entry); + entry.obj = new ObjectDir(0).Read(reader, true, this, entry); dir = new DirectoryMeta(); dir.platform = platform; dir.Read(reader); entry.dir = dir; break; - - case "BandCrowdMeterIcon": - Debug.WriteLine("Reading entry BandCrowdMeterIcon " + entry.name.value); + case "OverdriveMeterDir": + Debug.WriteLine("Reading entry OverdriveMeterDir " + entry.name.value); entry.isEntryInRootDir = true; - entry.obj = new BandCrowdMeterIcon(0).Read(reader, true, this, entry); + entry.obj = new OverdriveMeterDir(0).Read(reader, true, this, entry); dir = new DirectoryMeta(); dir.platform = platform; dir.Read(reader); entry.dir = dir; break; - - case "BandCharacter": - Debug.WriteLine("Reading entry BandCharacter " + entry.name.value); + case "OvershellDir": + Debug.WriteLine("Reading entry OvershellDir " + entry.name.value); entry.isEntryInRootDir = true; - entry.obj = new BandCharacter(0).Read(reader, true, this, entry); + entry.obj = new OvershellDir(0).Read(reader, true, this, entry); dir = new DirectoryMeta(); dir.platform = platform; dir.Read(reader); entry.dir = dir; break; - - case "WorldInstance": - Debug.WriteLine("Reading entry WorldInstance " + entry.name.value); - entry.isEntryInRootDir = true; - - entry.obj = new WorldInstance(0).Read(reader, false, this, entry); - - // if the world instance has no persistent perObjs, it will have a dir as expected, otherwise it won't - if (!((WorldInstance)entry.obj).hasPersistentObjects) - { - dir = new DirectoryMeta(); - dir.platform = platform; - dir.Read(reader); - entry.dir = dir; - - if (((WorldInstance)dir.directory).hasPersistentObjects) - { - ((WorldInstance)dir.directory).persistentObjects = new WorldInstance.PersistentObjects().Read(reader, this, entry); - } - } - else - { - ((WorldInstance)entry.obj).persistentObjects = new WorldInstance.PersistentObjects().Read(reader, this, entry); - } - - - break; - - case "TrackPanelDir": - Debug.WriteLine("Reading entry TrackPanelDir " + entry.name.value); + case "P9Character": + Debug.WriteLine("Reading entry P9Character " + entry.name.value); entry.isEntryInRootDir = true; - entry.obj = new TrackPanelDir(0).Read(reader, true, this, entry); + entry.obj = new P9Character(0).Read(reader, true, this, entry); dir = new DirectoryMeta(); dir.platform = platform; dir.Read(reader); entry.dir = dir; break; - - case "UnisonIcon": - Debug.WriteLine("Reading entry UnisonIcon " + entry.name.value); + case "PanelDir": + case "UIPanel": + Debug.WriteLine("Reading entry PanelDir " + entry.name.value); entry.isEntryInRootDir = true; - entry.obj = new UnisonIcon(0).Read(reader, true, this, entry); + entry.obj = new PanelDir(0).Read(reader, true, this, entry); dir = new DirectoryMeta(); dir.platform = platform; dir.Read(reader); entry.dir = dir; break; - - case "BandScoreboard": - Debug.WriteLine("Reading entry BandScoreboard " + entry.name.value); + case "SkeletonDir": + Debug.WriteLine("Reading entry SkeletonDir " + entry.name.value); entry.isEntryInRootDir = true; - entry.obj = new BandScoreboard(0).Read(reader, true, this, entry); + entry.obj = new SkeletonDir(0).Read(reader, true, this, entry); dir = new DirectoryMeta(); dir.platform = platform; dir.Read(reader); entry.dir = dir; break; - - case "BandStarDisplay": - Debug.WriteLine("Reading entry BandStarDisplay " + entry.name.value); + case "TrackPanelDir": + Debug.WriteLine("Reading entry TrackPanelDir " + entry.name.value); entry.isEntryInRootDir = true; - entry.obj = new BandStarDisplay(0).Read(reader, true, this, entry); + entry.obj = new TrackPanelDir(0).Read(reader, true, this, entry); dir = new DirectoryMeta(); dir.platform = platform; dir.Read(reader); entry.dir = dir; break; - - case "VocalTrackDir": - Debug.WriteLine("Reading entry VocalTrackDir " + entry.name.value); + case "UILabelDir": + Debug.WriteLine("Reading entry UILabelDir " + entry.name.value); entry.isEntryInRootDir = true; - entry.obj = new VocalTrackDir(0).Read(reader, true, this, entry); + entry.obj = new UILabelDir(0).Read(reader, true, this, entry); dir = new DirectoryMeta(); dir.platform = platform; dir.Read(reader); entry.dir = dir; break; - - case "GemTrackDir": - Debug.WriteLine("Reading entry GemTrackDir " + entry.name.value); + case "UIListDir": + Debug.WriteLine("Reading entry UIListDir " + entry.name.value); entry.isEntryInRootDir = true; - entry.obj = new GemTrackDir(0).Read(reader, true, this, entry); + entry.obj = new UIListDir(0).Read(reader, true, this, entry); dir = new DirectoryMeta(); dir.platform = platform; dir.Read(reader); entry.dir = dir; break; - - case "MoveDir": - Debug.WriteLine("Reading entry MoveDir " + entry.name.value); + case "UnisonIcon": + Debug.WriteLine("Reading entry UnisonIcon " + entry.name.value); entry.isEntryInRootDir = true; - entry.obj = new MoveDir(0).Read(reader, true, this, entry); + entry.obj = new UnisonIcon(0).Read(reader, true, this, entry); dir = new DirectoryMeta(); dir.platform = platform; dir.Read(reader); entry.dir = dir; break; - - case "SkeletonDir": - Debug.WriteLine("Reading entry SkeletonDir " + entry.name.value); + case "VocalTrackDir": + Debug.WriteLine("Reading entry VocalTrackDir " + entry.name.value); entry.isEntryInRootDir = true; - entry.obj = new SkeletonDir(0).Read(reader, true, this, entry); + entry.obj = new VocalTrackDir(0).Read(reader, true, this, entry); dir = new DirectoryMeta(); dir.platform = platform; dir.Read(reader); entry.dir = dir; break; - - case "OverdriveMeterDir": - Debug.WriteLine("Reading entry OverdriveMeterDir " + entry.name.value); + case "WorldDir": + Debug.WriteLine("Reading entry WorldDir " + entry.name.value); entry.isEntryInRootDir = true; - entry.obj = new OverdriveMeterDir(0).Read(reader, true, this, entry); + entry.obj = new WorldDir(0).Read(reader, true, this, entry); dir = new DirectoryMeta(); dir.platform = platform; dir.Read(reader); entry.dir = dir; break; + case "WorldInstance": + Debug.WriteLine("Reading entry WorldInstance " + entry.name.value); + entry.isEntryInRootDir = true; - //case "EndingBonusDir": - // Debug.WriteLine("Reading entry EndingBonusDir " + entry.name.value); - // entry.isEntryInRootDir = true; - // entry.obj = new RndDir(0).Read(reader, true, this, entry); - // - // entry.obj = new DirectoryMeta().Read(reader); - // break; + entry.obj = new WorldInstance(0).Read(reader, false, this, entry); - // OBJECTS + // if the world instance has no persistent perObjs, it will have a dir as expected, otherwise it won't + if (!((WorldInstance)entry.obj).hasPersistentObjects) + { + dir = new DirectoryMeta(); + dir.platform = platform; + dir.Read(reader); + entry.dir = dir; - case "Object": - Debug.WriteLine("Reading entry Object " + entry.name.value); - entry.obj = new Object().Read(reader, true, this, entry); + if (((WorldInstance)dir.directory).hasPersistentObjects) + { + ((WorldInstance)dir.directory).persistentObjects = new WorldInstance.PersistentObjects().Read(reader, this, entry); + } + } + else + { + ((WorldInstance)entry.obj).persistentObjects = new WorldInstance.PersistentObjects().Read(reader, this, entry); + } + break; + + ///////////// + // OBJECTS // + ///////////// + case "AnimFilter": + Debug.WriteLine("Reading entry AnimFilter " + entry.name.value); + entry.obj = new RndAnimFilter().Read(reader, true, this, entry); + break; + case "BandCharDesc": + Debug.WriteLine("Reading entry BandCharDesc " + entry.name.value); + entry.obj = new BandCharDesc().Read(reader, true, this, entry); + break; + case "BandConfiguration": + Debug.WriteLine("Reading entry BandConfiguration " + entry.name.value); + entry.obj = new BandConfiguration().Read(reader, true, this, entry); + break; + case "BandPlacer": + Debug.WriteLine("Reading entry BandPlacer " + entry.name.value); + entry.obj = new BandPlacer().Read(reader, true, this, entry); break; case "BandSongPref": Debug.WriteLine("Reading entry BandSongPref " + entry.name.value); entry.obj = new BandSongPref().Read(reader, true, this, entry); break; - case "Sfx": - Debug.WriteLine("Reading entry Sfx " + entry.name.value); - entry.obj = new Sfx().Read(reader, true, this, entry); + case "Cam": + Debug.WriteLine("Reading entry Cam " + entry.name.value); + entry.obj = new RndCam().Read(reader, true, this, entry); break; - case "Trans": - Debug.WriteLine("Reading entry Trans " + entry.name.value); - entry.obj = new RndTrans().Read(reader, true, this, entry); + case "CharClipGroup": + Debug.WriteLine("Reading entry CharClipGroup " + entry.name.value); + entry.obj = new CharClipGroup().Read(reader, true, this, entry); break; - case "View": - case "Group": - Debug.WriteLine("Reading entry Group " + entry.name.value); - entry.obj = new RndGroup().Read(reader, true, this, entry); - break; - case "P9Director": - Debug.WriteLine("Reading entry P9Director " + entry.name.value); - entry.obj = new P9Director().Read(reader, true, this, entry); - break; - // TODO: figure out how to read textures properly - case "Tex": - Debug.WriteLine("Reading entry Tex " + entry.name.value); - entry.obj = new RndTex().Read(reader, true, this, entry); + case "CharMeshHide": + Debug.WriteLine("Reading entry CharMeshHide " + entry.name.value); + entry.obj = new CharMeshHide().Read(reader, true, this, entry); break; case "ColorPalette": Debug.WriteLine("Reading entry ColorPalette " + entry.name.value); entry.obj = new ColorPalette().Read(reader, true, this, entry); break; - //case "Mat": - // Debug.WriteLine("Reading entry Mat " + entry.name.value); - // entry.obj = new RndMat().Read(reader, true, this); - // break; - case "BandCharDesc": - Debug.WriteLine("Reading entry BandCharDesc " + entry.name.value); - entry.obj = new BandCharDesc().Read(reader, true, this, entry); + case "Environ": + Debug.WriteLine("Reading entry Environ " + entry.name.value); + entry.obj = new RndEnviron().Read(reader, true, this, entry); + break; + case "EventTrigger": + Debug.WriteLine("Reading entry EventTrigger " + entry.name.value); + entry.obj = new EventTrigger().Read(reader, true, this, entry); + break; + case "Group": + case "View": + Debug.WriteLine("Reading entry Group " + entry.name.value); + entry.obj = new RndGroup().Read(reader, true, this, entry); break; case "Light": Debug.WriteLine("Reading entry Light " + entry.name.value); entry.obj = new RndLight().Read(reader, true, this, entry); break; - case "UIColor": - Debug.WriteLine("Reading entry UIColor" + entry.name.value); - entry.obj = new UIColor().Read(reader, true, this, entry); + case "Mat": + if (revision != 28) + goto default; + Debug.WriteLine("Reading entry Mat " + entry.name.value); + entry.obj = new RndMat().Read(reader, true, this, entry); + break; + case "MatAnim": + Debug.WriteLine("Reading entry MatAnim " + entry.name.value); + entry.obj = new RndMatAnim().Read(reader, true, this, entry); + break; + case "Object": + Debug.WriteLine("Reading entry Object " + entry.name.value); + entry.obj = new Object().Read(reader, true, this, entry); + break; + case "OutfitConfig": + if (revision != 28) + goto default; + Debug.WriteLine("Reading entry OutfitConfig " + entry.name.value); + entry.obj = new OutfitConfig().Read(reader, true, this, entry); + break; + case "P9Director": + Debug.WriteLine("Reading entry P9Director " + entry.name.value); + entry.obj = new P9Director().Read(reader, true, this, entry); break; case "ParticleSys": Debug.WriteLine("Reading entry ParticleSys " + entry.name.value); entry.obj = new RndParticleSys().Read(reader, true, this, entry); break; - case "AnimFilter": - Debug.WriteLine("Reading entry AnimFilter " + entry.name.value); - entry.obj = new RndAnimFilter().Read(reader, true, this, entry); - break; - case "BandPlacer": - Debug.WriteLine("Reading entry BandPlacer " + entry.name.value); - entry.obj = new BandPlacer().Read(reader, true, this, entry); - break; case "ScreenMask": Debug.WriteLine("Reading entry ScreenMask " + entry.name.value); entry.obj = new RndScreenMask().Read(reader, true, this, entry); break; - case "TexMovie": - Debug.WriteLine("Reading entry TexMovie " + entry.name.value); - entry.obj = new TexMovie().Read(reader, true, this, entry); - break; - case "Environ": - Debug.WriteLine("Reading entry Environ " + entry.name.value); - entry.obj = new RndEnviron().Read(reader, true, this, entry); - break; - case "SynthSample": - Debug.WriteLine("Reading entry SynthSample " + entry.name.value); - entry.obj = new SynthSample().Read(reader, true, this, entry); - break; - case "Cam": - Debug.WriteLine("Reading entry Cam " + entry.name.value); - entry.obj = new RndCam().Read(reader, true, this, entry); - break; - //case "Mesh": - // Debug.WriteLine("Reading entry Mesh " + entry.name.value); - // entry.obj = new RndMesh().Read(reader, true, this, entry); - // break; case "Set": Debug.WriteLine("Reading entry Set " + entry.name.value); entry.obj = new Set().Read(reader, true, this, entry); break; + case "Sfx": + Debug.WriteLine("Reading entry Sfx " + entry.name.value); + entry.obj = new Sfx().Read(reader, true, this, entry); + break; case "SpotlightDrawer": Debug.WriteLine("Reading entry SpotlightDrawer " + entry.name.value); entry.obj = new SpotlightDrawer().Read(reader, true, this, entry); break; - case "WorldCrowd": - Debug.WriteLine("Reading entry WorldCrowd " + entry.name.value); - entry.obj = new WorldCrowd().Read(reader, true, this, entry); + case "SynthSample": + Debug.WriteLine("Reading entry SynthSample " + entry.name.value); + entry.obj = new SynthSample().Read(reader, true, this, entry); break; - case "CharClipGroup": - Debug.WriteLine("Reading entry CharClipGroup " + entry.name.value); - entry.obj = new CharClipGroup().Read(reader, true, this, entry); + case "Tex": + Debug.WriteLine("Reading entry Tex " + entry.name.value); + entry.obj = new RndTex().Read(reader, true, this, entry); break; - case "MatAnim": - Debug.WriteLine("Reading entry MatAnim " + entry.name.value); - entry.obj = new RndMatAnim().Read(reader, true, this, entry); + case "TexMovie": + Debug.WriteLine("Reading entry TexMovie " + entry.name.value); + entry.obj = new TexMovie().Read(reader, true, this, entry); break; - case "EventTrigger": - Debug.WriteLine("Reading entry EventTrigger " + entry.name.value); - entry.obj = new EventTrigger().Read(reader, true, this, entry); + case "Trans": + Debug.WriteLine("Reading entry Trans " + entry.name.value); + entry.obj = new RndTrans().Read(reader, true, this, entry); break; - case "BandConfiguration": - Debug.WriteLine("Reading entry BandConfiguration " + entry.name.value); - entry.obj = new BandConfiguration().Read(reader, true, this, entry); + case "UIColor": + Debug.WriteLine("Reading entry UIColor" + entry.name.value); + entry.obj = new UIColor().Read(reader, true, this, entry); + break; + case "WorldCrowd": + Debug.WriteLine("Reading entry WorldCrowd " + entry.name.value); + entry.obj = new WorldCrowd().Read(reader, true, this, entry); break; // re-enable when the class is 100% //case "CharClip": @@ -916,8 +894,6 @@ public void ReadEntry(EndianReader reader, DirectoryMeta.Entry entry) } Debug.WriteLine("Found ending of file, new position: " + reader.BaseStream.Position); - - break; } } @@ -935,39 +911,103 @@ public void WriteEntry(EndianWriter writer, DirectoryMeta.Entry entry) Debug.WriteLine("Writing " + entry.type.value + " " + entry.name.value); switch (entry.type.value) { - case "ObjectDir": + ////////// + // DIRS // + ////////// + case "BandCrowdMeterDir": + ((BandCrowdMeterDir)entry.obj).Write(writer, true, this, entry); + entry.isEntryInRootDir = false; + entry.dir.Write(writer); + break; + case "Character": + ((Character)entry.obj).Write(writer, true, this, entry); + if (((Character)entry.obj).proxyPath != String.Empty) + { + entry.isEntryInRootDir = false; + entry.dir.Write(writer); + } + break; + case "CharClipSet": + writer.WriteUInt32(0x18); ((ObjectDir)entry.obj).Write(writer, true, this, entry); entry.isEntryInRootDir = false; entry.dir.Write(writer); break; - case "RndDir": + case "EndingBonusDir": ((RndDir)entry.obj).Write(writer, true, this, entry); entry.isEntryInRootDir = false; entry.dir.Write(writer); break; - case "PanelDir": - ((PanelDir)entry.obj).Write(writer, true, this, entry); + case "GemTrackDir": + ((GemTrackDir)entry.obj).Write(writer, true, this, entry); entry.isEntryInRootDir = false; entry.dir.Write(writer); break; - case "WorldDir": - ((WorldDir)entry.obj).Write(writer, true, this, entry); + case "MoveDir": + ((MoveDir)entry.obj).Write(writer, true, this, entry); entry.isEntryInRootDir = false; entry.dir.Write(writer); break; - case "Character": - ((Character)entry.obj).Write(writer, true, this, entry); - if (((Character)entry.obj).proxyPath != String.Empty) - { - entry.isEntryInRootDir = false; - entry.dir.Write(writer); - } + case "ObjectDir": + ((ObjectDir)entry.obj).Write(writer, true, this, entry); + entry.isEntryInRootDir = false; + entry.dir.Write(writer); + break; + case "OverdriveMeterDir": + ((OverdriveMeterDir)entry.obj).Write(writer, true, this, entry); + entry.isEntryInRootDir = false; + entry.dir.Write(writer); + break; + case "OvershellDir": + ((OvershellDir)entry.obj).Write(writer, true, this, entry); + entry.isEntryInRootDir = false; + entry.dir.Write(writer); break; case "P9Character": ((P9Character)entry.obj).Write(writer, true, this, entry); entry.isEntryInRootDir = false; entry.dir.Write(writer); break; + case "PanelDir": + ((PanelDir)entry.obj).Write(writer, true, this, entry); + entry.isEntryInRootDir = false; + entry.dir.Write(writer); + break; + case "RndDir": + ((RndDir)entry.obj).Write(writer, true, this, entry); + entry.isEntryInRootDir = false; + entry.dir.Write(writer); + break; + case "SkeletonDir": + ((SkeletonDir)entry.obj).Write(writer, true, this, entry); + entry.isEntryInRootDir = false; + entry.dir.Write(writer); + break; + case "TrackPanelDir": + ((TrackPanelDir)entry.obj).Write(writer, true, this, entry); + entry.isEntryInRootDir = false; + entry.dir.Write(writer); + break; + case "UILabelDir": + ((UILabelDir)entry.obj).Write(writer, true, this, entry); + entry.isEntryInRootDir = false; + entry.dir.Write(writer); + break; + case "UIListDir": + ((UIListDir)entry.obj).Write(writer, true, this, entry); + entry.isEntryInRootDir = false; + entry.dir.Write(writer); + break; + case "UnisonIcon": + ((UnisonIcon)entry.obj).Write(writer, true, this, entry); + entry.isEntryInRootDir = false; + entry.dir.Write(writer); + break; + case "WorldDir": + ((WorldDir)entry.obj).Write(writer, true, this, entry); + entry.isEntryInRootDir = false; + entry.dir.Write(writer); + break; case "WorldInstance": // Write the main object ((WorldInstance)entry.obj).Write(writer, false, this, entry); @@ -1019,128 +1059,90 @@ public void WriteEntry(EndianWriter writer, DirectoryMeta.Entry entry) break; - case "CharClipSet": - writer.WriteUInt32(0x18); - ((ObjectDir)entry.obj).Write(writer, true, this, entry); - entry.isEntryInRootDir = false; - entry.dir.Write(writer); - break; - case "UILabelDir": - ((UILabelDir)entry.obj).Write(writer, true, this, entry); - entry.isEntryInRootDir = false; - entry.dir.Write(writer); - break; - case "UIListDir": - ((UIListDir)entry.obj).Write(writer, true, this, entry); - entry.isEntryInRootDir = false; - entry.dir.Write(writer); - break; - case "BandCrowdMeterDir": - ((BandCrowdMeterDir)entry.obj).Write(writer, true, this, entry); - entry.isEntryInRootDir = false; - entry.dir.Write(writer); - break; - case "UnisonIcon": - ((UnisonIcon)entry.obj).Write(writer, true, this, entry); - entry.isEntryInRootDir = false; - entry.dir.Write(writer); - break; - case "EndingBonusDir": - ((RndDir)entry.obj).Write(writer, true, this, entry); - entry.isEntryInRootDir = false; - entry.dir.Write(writer); - break; - case "GemTrackDir": - ((GemTrackDir)entry.obj).Write(writer, true, this, entry); - entry.isEntryInRootDir = false; - entry.dir.Write(writer); - break; - case "MoveDir": - ((MoveDir)entry.obj).Write(writer, true, this, entry); - entry.isEntryInRootDir = false; - entry.dir.Write(writer); + + ///////////// + // OBJECTS // + ///////////// + case "AnimFilter": + ((RndAnimFilter)entry.obj).Write(writer, true, this, entry); break; - case "SkeletonDir": - ((SkeletonDir)entry.obj).Write(writer, true, this, entry); - entry.isEntryInRootDir = false; - entry.dir.Write(writer); + case "BandCharDesc": + ((BandCharDesc)entry.obj).Write(writer, true, this, entry); break; - case "OvershellDir": - ((OvershellDir)entry.obj).Write(writer, true, this, entry); - entry.isEntryInRootDir = false; - entry.dir.Write(writer); + case "BandConfiguration": + ((BandConfiguration)entry.obj).Write(writer, true, this, entry); break; - case "OverdriveMeterDir": - ((OverdriveMeterDir)entry.obj).Write(writer, true, this, entry); - entry.isEntryInRootDir = false; - entry.dir.Write(writer); + case "BandPlacer": + ((BandPlacer)entry.obj).Write(writer, true, this, entry); break; case "BandSongPref": ((BandSongPref)entry.obj).Write(writer, true, this, entry); break; - case "Sfx": - ((Sfx)entry.obj).Write(writer, true, this, entry); + case "Cam": + ((RndCam)entry.obj).Write(writer, true, this, entry); break; - case "BandCharDesc": - ((BandCharDesc)entry.obj).Write(writer, true, this, entry); + case "CharClipGroup": + ((CharClipGroup)entry.obj).Write(writer, true, this, entry); break; - case "Group": - ((RndGroup)entry.obj).Write(writer, true, this, entry); + case "CharMeshHide": + ((CharMeshHide)entry.obj).Write(writer, true, this, entry); break; case "ColorPalette": ((ColorPalette)entry.obj).Write(writer, true, this, entry); break; - case "Tex": - ((RndTex)entry.obj).Write(writer, true, this, entry); + case "Environ": + ((RndEnviron)entry.obj).Write(writer, true, this, entry); break; - case "Trans": - ((RndTrans)entry.obj).Write(writer, true, false); + case "Group": + ((RndGroup)entry.obj).Write(writer, true, this, entry); break; case "Light": ((RndLight)entry.obj).Write(writer, true, this, entry); break; - case "UIColor": - ((UIColor)entry.obj).Write(writer, true, this, entry); + case "Mat": + if (revision != 28) + goto default; + ((RndMat)entry.obj).Write(writer, true, this, entry); + break; + case "MatAnim": + ((RndMatAnim)entry.obj).Write(writer, true, this, entry); break; case "ParticleSys": ((RndParticleSys)entry.obj).Write(writer, true, this, entry); break; - case "AnimFilter": - ((RndAnimFilter)entry.obj).Write(writer, true, this, entry); - break; - case "BandPlacer": - ((BandPlacer)entry.obj).Write(writer, true, this, entry); - break; case "ScreenMask": ((RndScreenMask)entry.obj).Write(writer, true, this, entry); break; - case "TexMovie": - ((TexMovie)entry.obj).Write(writer, true, this, entry); + case "Set": + ((Set)entry.obj).Write(writer, true, this, entry); break; - case "Environ": - ((RndEnviron)entry.obj).Write(writer, true, this, entry); + case "Sfx": + ((Sfx)entry.obj).Write(writer, true, this, entry); + break; + case "SpotlightDrawer": + ((SpotlightDrawer)entry.obj).Write(writer, true, this, entry); break; case "SynthSample": ((SynthSample)entry.obj).Write(writer, true, this, entry); break; - case "Cam": - ((RndCam)entry.obj).Write(writer, true, this, entry); - break; - case "Set": - ((Set)entry.obj).Write(writer, true, this, entry); + case "Tex": + ((RndTex)entry.obj).Write(writer, true, this, entry); break; - case "SpotlightDrawer": - ((SpotlightDrawer)entry.obj).Write(writer, true, this, entry); + case "TexMovie": + ((TexMovie)entry.obj).Write(writer, true, this, entry); break; - case "CharClipGroup": - ((CharClipGroup)entry.obj).Write(writer, true, this, entry); + case "Trans": + ((RndTrans)entry.obj).Write(writer, true, false); break; - case "MatAnim": - ((RndMatAnim)entry.obj).Write(writer, true, this, entry); + case "UIColor": + ((UIColor)entry.obj).Write(writer, true, this, entry); break; - //case "Mat": - // ((RndMat)entry.obj).Write(writer, false); + // re-enable when the class is 100% + //case "CharClip": + // Debug.WriteLine("Reading entry CharClip " + entry.name.value); + // entry.obj = new CharClip().Read(reader, true, this, entry); // break; + default: Debug.WriteLine("Unknown entry type, dumping raw bytes for " + entry.type.value + " of name " + entry.name.value); diff --git a/MiloLib/Assets/EventTrigger.cs b/MiloLib/Assets/EventTrigger.cs index 58aa6b2..42dd870 100644 --- a/MiloLib/Assets/EventTrigger.cs +++ b/MiloLib/Assets/EventTrigger.cs @@ -52,6 +52,11 @@ public void Write(EndianWriter writer) Symbol.Write(writer, type); writer.WriteFloat(unknown); } + + public override string ToString() + { + return $"{anim} {blend} {delay} {wait} {enable} {scale} {start} {end} {period} {type} {unknown}"; + } } public class ProxyCall @@ -289,6 +294,119 @@ public override void Write(EndianWriter writer, bool standalone, DirectoryMeta p base.Write(writer, false, parent, entry); + if (revision > 0xF) + anim.Write(writer); + + if (revision > 9) + { + writer.WriteUInt32((uint)triggerEvents.Count); + foreach (var triggerEvent in triggerEvents) + { + Symbol.Write(writer, triggerEvent); + } + } + else if (revision > 6) + { + Symbol.Write(writer, unkSym1); + } + + if (revision > 6) + { + writer.WriteUInt32((uint)anims.Count); + foreach (var anim in anims) + { + anim.Write(writer); + } + + writer.WriteUInt32((uint)sounds.Count); + foreach (var sound in sounds) + { + Symbol.Write(writer, sound); + } + + writer.WriteUInt32((uint)shows.Count); + foreach (var show in shows) + { + Symbol.Write(writer, show); + } + } + + if (revision > 0xC) + { + writer.WriteUInt32((uint)hideDelays.Count); + foreach (var hideDelay in hideDelays) + { + hideDelay.Write(writer); + } + } + + if (revision > 2) + { + writer.WriteUInt32((uint)enableEvents.Count); + foreach (var enableEvent in enableEvents) + { + Symbol.Write(writer, enableEvent); + } + + writer.WriteUInt32((uint)disableEvents.Count); + foreach (var disableEvent in disableEvents) + { + Symbol.Write(writer, disableEvent); + } + } + + if (revision > 5) + { + writer.WriteUInt32((uint)waitForEvents.Count); + foreach (var waitForEvent in waitForEvents) + { + Symbol.Write(writer, waitForEvent); + } + } + + if (revision > 6) + Symbol.Write(writer, nextLink); + + if (revision > 7) + { + writer.WriteUInt32((uint)proxyCalls.Count); + foreach (var proxyCall in proxyCalls) + { + proxyCall.Write(writer); + } + } + + if (revision > 0xB) + writer.WriteUInt32(triggerOrder); + + if (revision > 0xD) + { + writer.WriteUInt32((uint)resetTriggers.Count); + foreach (var resetTrigger in resetTriggers) + { + Symbol.Write(writer, resetTrigger); + } + + } + + if (revision > 0xE) + writer.WriteBoolean(enabledAtStart); + + if (revision > 0xF) + { + writer.WriteUInt32(animTrigger); + writer.WriteFloat(animFrame); + } + + if (revision > 0x10) + { + writer.WriteUInt32((uint)partLaunchers.Count); + foreach (var partLauncher in partLaunchers) + { + Symbol.Write(writer, partLauncher); + } + } + if (standalone) writer.WriteBlock(new byte[4] { 0xAD, 0xDE, 0xAD, 0xDE }); } diff --git a/MiloLib/Assets/OutfitConfig.cs b/MiloLib/Assets/OutfitConfig.cs index a18b0a8..ce75976 100644 --- a/MiloLib/Assets/OutfitConfig.cs +++ b/MiloLib/Assets/OutfitConfig.cs @@ -1,4 +1,5 @@ -using MiloLib.Classes; +using MiloLib.Assets.Band; +using MiloLib.Classes; using MiloLib.Utils; namespace MiloLib.Assets @@ -6,6 +7,154 @@ namespace MiloLib.Assets [Name("OutfitConfig"), Description("Configurable options for outfits")] public class OutfitConfig : Object { + public class Overlay + { + public int category; + public Symbol texture = new(0, ""); + + public Overlay Read(EndianReader reader) + { + category = reader.ReadInt32(); + texture = Symbol.Read(reader); + return this; + } + + public void Write(EndianWriter writer) + { + writer.WriteInt32(category); + Symbol.Write(writer, texture); + } + } + public class Piercing + { + public class Piece + { + public Symbol attachment = new(0, ""); + public bool highlight; + public int vert; + private uint unkShortCount; + public List unkShorts = new(); + + public int unkInt1; + public int unkInt2; + + public bool unkBool1; + + public Matrix xfm = new(); + + private uint unkUShortCount; + public List unkUShorts = new(); + + public Piece Read(EndianReader reader, uint revision) + { + if (revision > 0xF) + vert = reader.ReadInt32(); + else + { + unkInt1 = reader.ReadInt32(); + unkInt2 = reader.ReadInt32(); + } + + if (revision < 0xF) + unkBool1 = reader.ReadBoolean(); + + if (revision < 0xE) + { + xfm.Read(reader); + unkUShortCount = reader.ReadUInt32(); + for (int i = 0; i < unkUShortCount; i++) + unkUShorts.Add(reader.ReadUInt16()); + } + else + { + attachment = Symbol.Read(reader); + } + + unkShortCount = reader.ReadUInt32(); + for (int i = 0; i < unkShortCount; i++) + unkShorts.Add(reader.ReadUInt16()); + + return this; + } + + public void Write(EndianWriter writer, uint revision) + { + if (revision > 0xF) + writer.WriteInt32(vert); + else + { + writer.WriteInt32(unkInt1); + writer.WriteInt32(unkInt2); + } + + if (revision < 0xF) + writer.WriteBoolean(unkBool1); + + if (revision < 0xE) + { + xfm.Write(writer); + writer.WriteUInt32((uint)unkUShorts.Count); + foreach (ushort unkUShort in unkUShorts) + writer.WriteUInt16(unkUShort); + } + else + { + Symbol.Write(writer, attachment); + } + + writer.WriteUInt32((uint)unkShorts.Count); + foreach (ushort unkShort in unkShorts) + writer.WriteUInt16(unkShort); + } + } + + public Symbol piercing = new(0, ""); + public Matrix transform = new(); + public bool reskin; + private uint pieceCount; + public List pieces = new(); + + public Piercing Read(EndianReader reader, uint revision) + { + piercing = Symbol.Read(reader); + if (revision < 0xD) + { + // TODO: Implement this + } + else + { + transform.Read(reader); + pieceCount = reader.ReadUInt32(); + pieces = new List(); + for (int i = 0; i < pieceCount; i++) + pieces.Add(new Piece().Read(reader, revision)); + + if (revision > 0x1A) + reskin = reader.ReadBoolean(); + } + return this; + } + + public void Write(EndianWriter writer, uint revision) + { + Symbol.Write(writer, piercing); + if (revision < 0xD) + { + // TODO: Implement this + } + else + { + transform.Write(writer); + } + transform.Write(writer); + writer.WriteUInt32((uint)pieces.Count); + foreach (Piece piece in pieces) + piece.Write(writer, revision); + + if (revision > 0x1A) + writer.WriteBoolean(reskin); + } + } public class MeshAO { public class Seam @@ -27,16 +176,22 @@ public void Write(EndianWriter writer) } public Symbol meshName = new(0, ""); - public Symbol unkSym = new(0, ""); private uint coefficientCount; - public List coefficients; + public List coefficients = new(); private uint seamCount; - public List seams; + public List seams = new(); + + public byte[] sha1Digest = new byte[20]; + + public Symbol unkSym = new(0, ""); - public MeshAO Read(EndianReader reader) + public MeshAO Read(EndianReader reader, uint revision) { meshName = Symbol.Read(reader); - unkSym = Symbol.Read(reader); + if (revision == 9 || revision == 10 || revision == 11 || revision == 12 || revision == 13 || revision == 14 || revision == 15 || revision == 16 || revision == 17 || revision == 18 || revision == 19 || revision == 20 || revision == 21 || revision == 22) + { + sha1Digest = reader.ReadBlock(20); + } coefficientCount = reader.ReadUInt32(); coefficients = new List(); for (int i = 0; i < coefficientCount; i++) @@ -45,13 +200,18 @@ public MeshAO Read(EndianReader reader) seams = new List(); for (int i = 0; i < seamCount; i++) seams.Add(new Seam().Read(reader)); + if (revision > 0x18) + unkSym = Symbol.Read(reader); return this; } - public void Write(EndianWriter writer) + public void Write(EndianWriter writer, uint revision) { Symbol.Write(writer, meshName); - Symbol.Write(writer, unkSym); + if (revision == 9 || revision == 10 || revision == 11 || revision == 12 || revision == 13 || revision == 14 || revision == 15 || revision == 16 || revision == 17 || revision == 18 || revision == 19 || revision == 20 || revision == 21 || revision == 22) + { + writer.WriteBlock(sha1Digest); + } writer.WriteUInt32((uint)coefficients.Count); foreach (int coefficient in coefficients) writer.WriteInt32(coefficient); @@ -74,42 +234,64 @@ public class MatSwap int color2Option; private uint texturesCount; public List textures = new(); - bool twoColor; - public MatSwap Read(EndianReader reader) + public MatSwap Read(EndianReader reader, uint revision) { mat = Symbol.Read(reader); resourceMat = Symbol.Read(reader); - twoColorDiffuse = Symbol.Read(reader); - twoColorInterp = Symbol.Read(reader); + if (revision < 5) + { + // TODO: Implement this + } + else + { + twoColorDiffuse = Symbol.Read(reader); + twoColorInterp = Symbol.Read(reader); + } twoColorMask = Symbol.Read(reader); - color1Palette = Symbol.Read(reader); - color1Option = reader.ReadInt32(); - color2Palette = Symbol.Read(reader); - color2Option = reader.ReadInt32(); - texturesCount = reader.ReadUInt32(); - textures = new List(); - for (int i = 0; i < texturesCount; i++) - textures.Add(Symbol.Read(reader)); - twoColor = reader.ReadBoolean(); + if (revision > 4) + { + color1Palette = Symbol.Read(reader); + color1Option = reader.ReadInt32(); + color2Palette = Symbol.Read(reader); + color2Option = reader.ReadInt32(); + texturesCount = reader.ReadUInt32(); + textures = new List(); + for (int i = 0; i < texturesCount; i++) + textures.Add(Symbol.Read(reader)); + } return this; } - public void Write(EndianWriter writer) + public void Write(EndianWriter writer, uint revision) { Symbol.Write(writer, mat); Symbol.Write(writer, resourceMat); - Symbol.Write(writer, twoColorDiffuse); - Symbol.Write(writer, twoColorInterp); + if (revision < 5) + { + // TODO: Implement this + } + else + { + Symbol.Write(writer, twoColorDiffuse); + Symbol.Write(writer, twoColorInterp); + } Symbol.Write(writer, twoColorMask); - Symbol.Write(writer, color1Palette); - writer.WriteInt32(color1Option); - Symbol.Write(writer, color2Palette); - writer.WriteInt32(color2Option); - writer.WriteUInt32((uint)textures.Count); - foreach (Symbol texture in textures) - Symbol.Write(writer, texture); - writer.WriteBoolean(twoColor); + if (revision > 4) + { + Symbol.Write(writer, color1Palette); + writer.WriteInt32(color1Option); + Symbol.Write(writer, color2Palette); + writer.WriteInt32(color2Option); + writer.WriteUInt32((uint)textures.Count); + foreach (Symbol texture in textures) + Symbol.Write(writer, texture); + } + } + + public override string ToString() + { + return $"Mat: {mat} Resource Mat: {resourceMat} {twoColorDiffuse} {twoColorInterp} {twoColorMask} {color1Palette} {color1Option} {color2Palette} {color2Option} {texturesCount}"; } } private ushort altRevision; @@ -119,6 +301,30 @@ public void Write(EndianWriter writer) public bool computeAO; + private uint matSwapCount; + public List matSwaps = new(); + + private uint meshAOCount; + public List meshAOs = new(); + + private uint bandPatchMeshCount; + public List bandPatchMeshes = new(); + + private uint piercingCount; + public List piercings = new(); + + public Symbol texBlender = new(0, ""); + public Symbol wrinkleBlender = new(0, ""); + + public Symbol bandLogo = new(0, ""); + + private uint overlaysCount; + public List overlays = new(); + + public byte[] sha1Digest = new byte[20]; + + + @@ -140,10 +346,34 @@ public OutfitConfig Read(EndianReader reader, bool standalone, DirectoryMeta par if (revision > 3) { - MatSwap matSwap = new MatSwap().Read(reader); + matSwapCount = reader.ReadUInt32(); + for (int i = 0; i < matSwapCount; i++) + matSwaps.Add(new MatSwap().Read(reader, revision)); } + meshAOCount = reader.ReadUInt32(); + for (int i = 0; i < meshAOCount; i++) + meshAOs.Add(new MeshAO().Read(reader, revision)); + computeAO = reader.ReadBoolean(); + bandPatchMeshCount = reader.ReadUInt32(); + for (int i = 0; i < bandPatchMeshCount; i++) + bandPatchMeshes.Add(new BandPatchMesh().Read(reader, false, parent, entry)); + + piercingCount = reader.ReadUInt32(); + for (int i = 0; i < piercingCount; i++) + piercings.Add(new Piercing().Read(reader, revision)); + + texBlender = Symbol.Read(reader); + overlaysCount = reader.ReadUInt32(); + for (int i = 0; i < overlaysCount; i++) + overlays.Add(new Overlay().Read(reader)); + + bandLogo = Symbol.Read(reader); + + sha1Digest = reader.ReadBlock(20); + + wrinkleBlender = Symbol.Read(reader); if (standalone) if ((reader.Endianness == Endian.BigEndian ? 0xADDEADDE : 0xDEADDEAD) != reader.ReadUInt32()) throw new Exception("Got to end of standalone asset but didn't find the expected end bytes, read likely did not succeed"); @@ -157,6 +387,45 @@ public override void Write(EndianWriter writer, bool standalone, DirectoryMeta p base.Write(writer, false, parent, entry); + if (revision > 4) + { + writer.WriteInt32(colors[0]); + writer.WriteInt32(colors[1]); + if (revision > 10) + writer.WriteInt32(colors[2]); + } + + if (revision > 3) + { + writer.WriteUInt32((uint)matSwaps.Count); + foreach (MatSwap matSwap in matSwaps) + matSwap.Write(writer, revision); + } + + writer.WriteUInt32((uint)meshAOs.Count); + foreach (MeshAO meshAO in meshAOs) + meshAO.Write(writer, revision); + writer.WriteBoolean(computeAO); + writer.WriteUInt32((uint)bandPatchMeshes.Count); + foreach (BandPatchMesh bandPatchMesh in bandPatchMeshes) + bandPatchMesh.Write(writer, false, parent, entry); + + writer.WriteUInt32((uint)piercings.Count); + foreach (Piercing piercing in piercings) + piercing.Write(writer, revision); + + Symbol.Write(writer, texBlender); + + writer.WriteUInt32((uint)overlays.Count); + foreach (Overlay overlay in overlays) + overlay.Write(writer); + + Symbol.Write(writer, bandLogo); + + writer.WriteBlock(sha1Digest); + + Symbol.Write(writer, wrinkleBlender); + if (standalone) writer.WriteBlock(new byte[4] { 0xAD, 0xDE, 0xAD, 0xDE }); } diff --git a/MiloLib/Assets/Rnd/RndMat.cs b/MiloLib/Assets/Rnd/RndMat.cs index 1033c50..e4e8633 100644 --- a/MiloLib/Assets/Rnd/RndMat.cs +++ b/MiloLib/Assets/Rnd/RndMat.cs @@ -66,100 +66,27 @@ public struct MatPerfSettings [Name("Force Trilinear Filtering (PS3)"), Description("Force trilinear filtering of diffuse map (PS3 only)")] public bool mPS3ForceTrilinear; - public void Read(EndianReader reader) + public void Read(EndianReader reader, uint revision) { byte flags = reader.ReadByte(); mRecvProjLights = (flags & 0x01) != 0; mPS3ForceTrilinear = (flags & 0x02) != 0; mRecvPointCubeTex = (flags & 0x04) != 0; - - // mRecvPointCubeTex is read later based on rev } - public void Write(EndianWriter writer) + public void Write(EndianWriter writer, uint revision) { byte flags = 0; if (mRecvProjLights) flags |= 0x01; if (mPS3ForceTrilinear) flags |= 0x02; - if (mRecvPointCubeTex) flags |= 0x04; + if (revision > 65) + if (mRecvPointCubeTex) flags |= 0x04; writer.WriteByte(flags); } } - public struct MatShaderOptions - { - public int itop; - public bool mHasAOCalc; - public bool mHasBones; - public int i5; - public int i4; - public int i3; - public int i2; - public int i1; - public int i0; - - [Name("Temporary Material"), Description("If set, is a temporary material")] - public bool mTempMat; - public uint Value - { - get - { - uint result = 0; - result |= (uint)(itop & 0xffffff) << 8; - result |= (mHasAOCalc ? 1u : 0) << 7; - result |= (mHasBones ? 1u : 0) << 6; - result |= (uint)(i5 & 0x01) << 5; - result |= (uint)(i4 & 0x01) << 4; - result |= (uint)(i3 & 0x01) << 3; - result |= (uint)(i2 & 0x01) << 2; - result |= (uint)(i1 & 0x01) << 1; - result |= (uint)(i0 & 0x01); - return result; - } - set - { - itop = (int)((value >> 8) & 0xffffff); - mHasAOCalc = (value & (1 << 7)) != 0; - mHasBones = (value & (1 << 6)) != 0; - i5 = (int)((value >> 5) & 0x01); - i4 = (int)((value >> 4) & 0x01); - i3 = (int)((value >> 3) & 0x01); - i2 = (int)((value >> 2) & 0x01); - i1 = (int)((value >> 1) & 0x01); - i0 = (int)(value & 0x01); - } - } - - public void Read(EndianReader reader) - { - Value = reader.ReadUInt32(); - mTempMat = reader.ReadBoolean(); - } - - public void Write(EndianWriter writer) - { - writer.WriteUInt32(Value); - writer.WriteByte((byte)(mTempMat ? 1 : 0)); - } - - public void SetLast5(int mask) - { - uint value = Value; - value = (value & ~0x1fu) | (uint)(mask & 0x1f); - Value = value; - } - } [Name("Mat"), Description("Material perObjs determine texturing, blending, and the effect of lighting on drawn polys.")] public class RndMat : Object { - public enum ColorModFlags : byte - { - kColorModNone = 0, - kColorModAlphaPack = 1, - kColorModAlphaUnpackModulate = 2, - kColorModModulate = 3, - kColorModNum = 3 - } - private ushort altRevision; private ushort revision; // constant for revision 68 @@ -184,6 +111,12 @@ public enum ColorModFlags : byte [Name("Emissive Map"), Description("Map for self illumination")] public Symbol emissiveMap; + public Symbol normalMap = new Symbol(0, ""); + + public Symbol specularMap = new Symbol(0, ""); + + public Symbol environMap = new Symbol(0, ""); + [Name("Refract Strength"), Description("The scale of the refraction of the screen under the material. Ranges from 0 to 100.")] public float refractStrength; @@ -193,12 +126,6 @@ public enum ColorModFlags : byte [Name("Color Modifiers"), Description("Color modifiers for the material")] public List colorModifiers = new List(); - [Name("Performance Settings"), Description("Performance options for this material")] - public MatPerfSettings performanceSettings; - - [Name("Shader Options"), Description("Options pertaining to the shader capabilities")] - public MatShaderOptions shaderOptions; - [Name("Intensify"), Description("Double the intensity of base map")] public bool intensify; @@ -258,15 +185,12 @@ public enum ColorModFlags : byte [Name("Shader Variation"), Description("Select a variation on the shader to enable a new range of rendering features.")] public ShaderVariation shaderVariation; - [Name("Color Modification Flags"), Description("Flags pertaining to color modifiers")] - public ColorModFlags colorModFlags; - [Name("Dirty Flags"), Description("Dirty flags that denote changes to the material")] public byte dirty; - public HmxColor4 shaderVariationColor = new HmxColor4(1f, 1f, 1f, 1f); + public HmxColor3 specularRGB = new HmxColor3(); - public HmxColor4 locColor = new HmxColor4(1f, 1f, 1f, 1f); + public float specularPower; public HmxColor4 unkColor = new HmxColor4(1f, 1f, 1f, 1f); @@ -274,6 +198,34 @@ public enum ColorModFlags : byte public Symbol unkSym = new Symbol(0, ""); + public Symbol fur = new Symbol(0, ""); + + public float deNormal; + public float anisotropy; + public float normalDetailTiling; + + public float normalDetailStrength; + public Symbol normalDetailMap; + + public HmxColor3 rimRGB = new HmxColor3(); + public float rimPower; + public Symbol rimMap = new Symbol(0, ""); + public bool rimAlwaysShow; + + public HmxColor3 specular2RGB = new HmxColor3(); + + public float specular2Power; + + public float unkFloat; + + public float unkFloat2; + public Symbol alphaMask = new Symbol(0, ""); + + public ushort unkShort; + + + + public RndMat Read(EndianReader reader, bool standalone, DirectoryMeta parent, DirectoryMeta.Entry entry) { uint combinedRevision = reader.ReadUInt32(); @@ -289,8 +241,8 @@ public RndMat Read(EndianReader reader, bool standalone, DirectoryMeta parent, D blend = (Blend)reader.ReadInt32(); color = new HmxColor4().Read(reader); - useEnviron = reader.ReadBoolean(); preLit = reader.ReadBoolean(); + useEnviron = reader.ReadBoolean(); ZMode = (ZMode)reader.ReadInt32(); alphaCut = reader.ReadBoolean(); if (revision > 0x25) @@ -305,80 +257,47 @@ public RndMat Read(EndianReader reader, bool standalone, DirectoryMeta parent, D cull = reader.ReadBoolean(); emissiveMultiplier = reader.ReadFloat(); - locColor = new HmxColor4().Read(reader); - + specularRGB = new HmxColor3().Read(reader); + specularPower = reader.ReadFloat(); + normalMap = Symbol.Read(reader); emissiveMap = Symbol.Read(reader); + specularMap = Symbol.Read(reader); + environMap = Symbol.Read(reader); + unkShort = reader.ReadUInt16(); + perPixelLit = reader.ReadBoolean(); stencilMode = (StencilMode)reader.ReadInt32(); + fur = Symbol.Read(reader); + deNormal = reader.ReadFloat(); + anisotropy = reader.ReadFloat(); + normalDetailTiling = reader.ReadFloat(); + normalDetailStrength = reader.ReadFloat(); + normalDetailMap = Symbol.Read(reader); - Symbol sym = Symbol.Read(reader); + pointLights = reader.ReadBoolean(); + fog = reader.ReadBoolean(); + fadeout = reader.ReadBoolean(); + colorAdjust = reader.ReadBoolean(); - HmxColor4 color2 = new HmxColor4().Read(reader); - //texPtr = Symbol.Read(reader); + rimRGB = new HmxColor3().Read(reader); + rimPower = reader.ReadFloat(); - int i = reader.ReadInt32(); - i = reader.ReadInt32(); + rimMap = Symbol.Read(reader); + rimAlwaysShow = reader.ReadBoolean(); - int i2 = reader.ReadInt32(); - i2 = reader.ReadInt32(); - new HmxColor4().Read(reader); - int b2 = reader.ReadInt32(); - //texPtr = Symbol.Read(reader); - //texPtr = Symbol.Read(reader); + screenAligned = reader.ReadBoolean(); - if (revision > 0x2a) - { - if (revision > 0x2c) - pointLights = reader.ReadBoolean(); - - fog = reader.ReadBoolean(); - fadeout = reader.ReadBoolean(); - if (revision > 0x2E) - colorAdjust = reader.ReadBoolean(); - } + shaderVariation = (ShaderVariation)reader.ReadInt32(); + specular2RGB = new HmxColor3().Read(reader); + specular2Power = reader.ReadFloat(); - if (revision > 0x2F) - { - unkColor = new HmxColor4().Read(reader); - unkSym = Symbol.Read(reader); - byte b = reader.ReadByte(); - } - - if (revision > 0x30) - screenAligned = reader.ReadBoolean(); - - if (revision == 0x32) - unkBool1 = reader.ReadBoolean(); - - if (revision > 0x32) - { - shaderVariation = (ShaderVariation)reader.ReadInt32(); - shaderVariationColor = new HmxColor4().Read(reader); - } - - - colorModifiers = new List(); - for (int x = 0; x < 3; x++) - { - colorModifiers.Add(new HmxColor4(1f, 1f, 1f, 1f)); - } + unkFloat = reader.ReadFloat(); + unkFloat2 = reader.ReadFloat(); - - - Symbol objPtr = Symbol.Read(reader); - - if (revision > 0x3E) - performanceSettings.Read(reader); - - if (revision > 0x3F) - { - refractEnabled = reader.ReadBoolean(); - refractStrength = reader.ReadFloat(); - refractNormalMap = Symbol.Read(reader); - } + alphaMask = Symbol.Read(reader); if (standalone) { @@ -389,78 +308,73 @@ public RndMat Read(EndianReader reader, bool standalone, DirectoryMeta parent, D } public override void Write(EndianWriter writer, bool standalone, DirectoryMeta parent, DirectoryMeta.Entry? entry) { - base.Write(writer, standalone, parent, entry); writer.WriteUInt32(BitConverter.IsLittleEndian ? (uint)((altRevision << 16) | revision) : (uint)((revision << 16) | altRevision)); + + base.Write(writer, false, parent, entry); + writer.WriteInt32((int)blend); color.Write(writer); - writer.WriteByte((byte)(useEnviron ? 1 : 0)); - writer.WriteByte((byte)(preLit ? 1 : 0)); + writer.WriteBoolean(preLit); + writer.WriteBoolean(useEnviron); writer.WriteInt32((int)ZMode); - writer.WriteByte((byte)(alphaCut ? 1 : 0)); - writer.WriteInt32(alphaThreshold); - writer.WriteByte((byte)(alphaWrite ? 1 : 0)); + writer.WriteBoolean(alphaCut); + if (revision > 0x25) + writer.WriteInt32(alphaThreshold); + writer.WriteBoolean(alphaWrite); writer.WriteInt32((int)texGen); writer.WriteInt32((int)texWrap); texXfm.Write(writer); Symbol.Write(writer, diffuseTex); Symbol.Write(writer, nextPass); - writer.WriteByte((byte)(intensify ? 1 : 0)); - writer.WriteByte((byte)(cull ? 1 : 0)); + writer.WriteBoolean(intensify); + + writer.WriteBoolean(cull); writer.WriteFloat(emissiveMultiplier); - new HmxColor4().Write(writer); - Symbol.Write(writer, null); + specularRGB.Write(writer); + writer.WriteFloat(specularPower); + Symbol.Write(writer, normalMap); Symbol.Write(writer, emissiveMap); - Symbol.Write(writer, null); - Symbol.Write(writer, null); + Symbol.Write(writer, specularMap); + Symbol.Write(writer, environMap); + writer.WriteUInt16(unkShort); + writer.WriteBoolean(perPixelLit); writer.WriteInt32((int)stencilMode); + Symbol.Write(writer, fur); + + writer.WriteFloat(deNormal); + writer.WriteFloat(anisotropy); + writer.WriteFloat(normalDetailTiling); + writer.WriteFloat(normalDetailStrength); + Symbol.Write(writer, normalDetailMap); + + writer.WriteBoolean(pointLights); + writer.WriteBoolean(fog); + writer.WriteBoolean(fadeout); + writer.WriteBoolean(colorAdjust); + + rimRGB.Write(writer); + writer.WriteFloat(rimPower); + + Symbol.Write(writer, rimMap); + writer.WriteBoolean(rimAlwaysShow); - Symbol.Write(writer, null); - Symbol.Write(writer, null); - new HmxColor4().Write(writer); - Symbol.Write(writer, null); - writer.WriteInt32(0); - writer.WriteInt32(0); - writer.WriteInt32(0); - writer.WriteInt32(0); - new HmxColor4().Write(writer); - writer.WriteInt32(0); - Symbol.Write(writer, null); - Symbol.Write(writer, null); - - writer.WriteByte((byte)(pointLights ? 1 : 0)); - writer.WriteByte((byte)(fog ? 1 : 0)); - writer.WriteByte((byte)(fadeout ? 1 : 0)); - writer.WriteByte((byte)(colorAdjust ? 1 : 0)); - - new HmxColor4().Write(writer); - Symbol.Write(writer, null); - writer.WriteByte(0); - writer.WriteByte((byte)(screenAligned ? 1 : 0)); + writer.WriteBoolean(screenAligned); writer.WriteInt32((int)shaderVariation); - new HmxColor4().Write(writer); + specular2RGB.Write(writer); + writer.WriteFloat(specular2Power); + + writer.WriteFloat(unkFloat); + writer.WriteFloat(unkFloat2); + + Symbol.Write(writer, alphaMask); - if (colorModifiers == null) - { - for (int i = 0; i < 3; i++) - { - colorModifiers = new List(); - colorModifiers.Add(new HmxColor4(1f, 1f, 1f, 1f)); - } - } - Symbol.Write(writer, null); - writer.WriteByte((byte)(performanceSettings.mPS3ForceTrilinear ? 1 : 0)); - performanceSettings.Write(writer); - writer.WriteByte((byte)(performanceSettings.mRecvPointCubeTex ? 1 : 0)); - writer.WriteByte((byte)(refractEnabled ? 1 : 0)); - writer.WriteFloat(refractStrength); - Symbol.Write(writer, refractNormalMap); if (standalone) { - writer.WriteBlock(new byte[4] { 0xAD, 0xDE, 0xAD, 0xDE }); + writer.WriteUInt32(writer.Endianness == Endian.BigEndian ? 0xADDEADDE : 0xDEADDEAD); } } diff --git a/MiloLib/MiloFile.cs b/MiloLib/MiloFile.cs index 431dcb7..bb50620 100644 --- a/MiloLib/MiloFile.cs +++ b/MiloLib/MiloFile.cs @@ -15,7 +15,7 @@ public class MiloFile { /// /// The maximum size a block can be. - /// TODO: check if there is some "best" value for this + /// TODO: check if there is some "best" value for this, right now we just use the maximum possible block size /// private const int MAX_BLOCK_SIZE = 0xFFFFFF; @@ -372,7 +372,10 @@ public void Save(string? path, Type? type, uint startingOffset = 0x810, Endian h compressedBlocks.Add(compressedBlock); if (type == Type.CompressedZlibAlt) { + Endian origEndian = writer.Endianness; + writer.Endianness = Endian.LittleEndian; writer.WriteUInt32(MAX_BLOCK_SIZE); + writer.Endianness = origEndian; } writer.WriteBlock(compressedBlock); }