From 3a0ab052712769bf1a638c54b5db4b93cc563386 Mon Sep 17 00:00:00 2001 From: dreamsyntax Date: Tue, 2 Jan 2024 18:01:49 -0700 Subject: [PATCH] AirWing spline conversion impl --- ShadowRando/MainForm.Designer.cs | 26 +++ ShadowRando/MainForm.cs | 27 ++- ShadowRando/ShadowRando.csproj | 1 + ShadowRando/ShadowSpline.cs | 364 +++++++++++++++++++++++++++++++ 4 files changed, 414 insertions(+), 4 deletions(-) create mode 100644 ShadowRando/ShadowSpline.cs diff --git a/ShadowRando/MainForm.Designer.cs b/ShadowRando/MainForm.Designer.cs index 030032c..e35f27d 100644 --- a/ShadowRando/MainForm.Designer.cs +++ b/ShadowRando/MainForm.Designer.cs @@ -398,6 +398,7 @@ private void InitializeComponent() this.toolTip1.SetToolTip(this.FNTCheckBox_SpecificCharacters, "Only characters specified are used"); this.FNTCheckBox_SpecificCharacters.UseVisualStyleBackColor = true; this.FNTCheckBox_SpecificCharacters.CheckedChanged += new System.EventHandler(this.FNTCheckBox_SpecificCharacters_CheckedChanged); + this.FNTCheckBox_SpecificCharacters.MouseDown += new System.Windows.Forms.MouseEventHandler(this.SharedMouseDown_Chkchk); // // FNTCheckBox_OnlyLinkedAudio // @@ -411,6 +412,7 @@ private void InitializeComponent() this.toolTip1.SetToolTip(this.FNTCheckBox_OnlyLinkedAudio, "Only subtitles that have a matching voiceline are used in the random pool"); this.FNTCheckBox_OnlyLinkedAudio.UseVisualStyleBackColor = true; this.FNTCheckBox_OnlyLinkedAudio.CheckedChanged += new System.EventHandler(this.FNTCheckBox_OnlyLinkedAudio_CheckedChanged); + this.FNTCheckBox_OnlyLinkedAudio.MouseDown += new System.Windows.Forms.MouseEventHandler(this.SharedMouseDown_Chkchk); // // FNTCheckBox_NoSystemMessages // @@ -423,6 +425,7 @@ private void InitializeComponent() this.FNTCheckBox_NoSystemMessages.Text = "No System Messages In Pool"; this.toolTip1.SetToolTip(this.FNTCheckBox_NoSystemMessages, "No system messages will be used in the random pool"); this.FNTCheckBox_NoSystemMessages.UseVisualStyleBackColor = true; + this.FNTCheckBox_NoSystemMessages.MouseDown += new System.Windows.Forms.MouseEventHandler(this.SharedMouseDown_Chkchk); // // FNTCheckBox_NoDuplicatesPreRandomization // @@ -436,6 +439,7 @@ private void InitializeComponent() this.toolTip1.SetToolTip(this.FNTCheckBox_NoDuplicatesPreRandomization, "Every unique subtitle entry is only considered once in the pool. It is still poss" + "ible to get the same entry multiple times."); this.FNTCheckBox_NoDuplicatesPreRandomization.UseVisualStyleBackColor = true; + this.FNTCheckBox_NoDuplicatesPreRandomization.MouseDown += new System.Windows.Forms.MouseEventHandler(this.SharedMouseDown_Chkchk); // // FNTCheckBox_GiveAudioToNoLinkedAudio // @@ -449,6 +453,7 @@ private void InitializeComponent() this.toolTip1.SetToolTip(this.FNTCheckBox_GiveAudioToNoLinkedAudio, "Subtitles with no associated audio will be given random audio"); this.FNTCheckBox_GiveAudioToNoLinkedAudio.UseVisualStyleBackColor = true; this.FNTCheckBox_GiveAudioToNoLinkedAudio.CheckedChanged += new System.EventHandler(this.FNTCheckBox_GiveAudioToNoLinkedAudio_CheckedChanged); + this.FNTCheckBox_GiveAudioToNoLinkedAudio.MouseDown += new System.Windows.Forms.MouseEventHandler(this.SharedMouseDown_Chkchk); // // seedTextBox // @@ -553,6 +558,7 @@ private void InitializeComponent() this.toolTip1.SetToolTip(this.setLayout_keepType, "Example: A flying enemy (GUN Beetle) will be restricted to become another flying " + "enemy type."); this.setLayout_keepType.UseVisualStyleBackColor = true; + this.setLayout_keepType.MouseDown += new System.Windows.Forms.MouseEventHandler(this.SharedMouseDown_Chkchk); // // setLayout_haveShieldBlockProb // @@ -605,10 +611,12 @@ private void InitializeComponent() this.setLayout_adjustMissionCounts.Text = "Adjust Mission Counts"; this.toolTip1.SetToolTip(this.setLayout_adjustMissionCounts, "Missions counts are adjusted if enemy counts of affiliation are modified"); this.setLayout_adjustMissionCounts.UseVisualStyleBackColor = true; + this.setLayout_adjustMissionCounts.MouseDown += new System.Windows.Forms.MouseEventHandler(this.SharedMouseDown_Chkchk); // // setLayout_makeCCSplinesAWRidable // this.setLayout_makeCCSplinesAWRidable.AutoSize = true; + this.setLayout_makeCCSplinesAWRidable.Enabled = false; this.setLayout_makeCCSplinesAWRidable.Location = new System.Drawing.Point(247, 156); this.setLayout_makeCCSplinesAWRidable.Name = "setLayout_makeCCSplinesAWRidable"; this.setLayout_makeCCSplinesAWRidable.Size = new System.Drawing.Size(200, 17); @@ -617,6 +625,7 @@ private void InitializeComponent() this.toolTip1.SetToolTip(this.setLayout_makeCCSplinesAWRidable, "Allows Black Hawk/Volt to attach to Chaos Control splines. May have side effects." + ""); this.setLayout_makeCCSplinesAWRidable.UseVisualStyleBackColor = true; + this.setLayout_makeCCSplinesAWRidable.MouseDown += new System.Windows.Forms.MouseEventHandler(this.SharedMouseDown_Chkchk); // // tabControl1 // @@ -783,6 +792,7 @@ private void InitializeComponent() this.FNTCheckBox_Chars_GUNSoldier.TabIndex = 16; this.FNTCheckBox_Chars_GUNSoldier.Text = "GUN Soldier"; this.FNTCheckBox_Chars_GUNSoldier.UseVisualStyleBackColor = true; + this.FNTCheckBox_Chars_GUNSoldier.MouseDown += new System.Windows.Forms.MouseEventHandler(this.SharedMouseDown_Chkchk); // // FNTCheckBox_Chars_GUNCommander // @@ -794,6 +804,7 @@ private void InitializeComponent() this.FNTCheckBox_Chars_GUNCommander.TabIndex = 15; this.FNTCheckBox_Chars_GUNCommander.Text = "GUN Commander"; this.FNTCheckBox_Chars_GUNCommander.UseVisualStyleBackColor = true; + this.FNTCheckBox_Chars_GUNCommander.MouseDown += new System.Windows.Forms.MouseEventHandler(this.SharedMouseDown_Chkchk); // // FNTCheckBox_Chars_BlackDoom // @@ -805,6 +816,7 @@ private void InitializeComponent() this.FNTCheckBox_Chars_BlackDoom.TabIndex = 14; this.FNTCheckBox_Chars_BlackDoom.Text = "Black Doom"; this.FNTCheckBox_Chars_BlackDoom.UseVisualStyleBackColor = true; + this.FNTCheckBox_Chars_BlackDoom.MouseDown += new System.Windows.Forms.MouseEventHandler(this.SharedMouseDown_Chkchk); // // FNTCheckBox_Chars_Cheese // @@ -816,6 +828,7 @@ private void InitializeComponent() this.FNTCheckBox_Chars_Cheese.TabIndex = 13; this.FNTCheckBox_Chars_Cheese.Text = "Cheese"; this.FNTCheckBox_Chars_Cheese.UseVisualStyleBackColor = true; + this.FNTCheckBox_Chars_Cheese.MouseDown += new System.Windows.Forms.MouseEventHandler(this.SharedMouseDown_Chkchk); // // FNTCheckBox_Chars_Maria // @@ -827,6 +840,7 @@ private void InitializeComponent() this.FNTCheckBox_Chars_Maria.TabIndex = 9; this.FNTCheckBox_Chars_Maria.Text = "Maria"; this.FNTCheckBox_Chars_Maria.UseVisualStyleBackColor = true; + this.FNTCheckBox_Chars_Maria.MouseDown += new System.Windows.Forms.MouseEventHandler(this.SharedMouseDown_Chkchk); // // FNTCheckBox_Chars_Cream // @@ -838,6 +852,7 @@ private void InitializeComponent() this.FNTCheckBox_Chars_Cream.TabIndex = 12; this.FNTCheckBox_Chars_Cream.Text = "Cream"; this.FNTCheckBox_Chars_Cream.UseVisualStyleBackColor = true; + this.FNTCheckBox_Chars_Cream.MouseDown += new System.Windows.Forms.MouseEventHandler(this.SharedMouseDown_Chkchk); // // FNTCheckBox_Chars_Eggman // @@ -849,6 +864,7 @@ private void InitializeComponent() this.FNTCheckBox_Chars_Eggman.TabIndex = 11; this.FNTCheckBox_Chars_Eggman.Text = "Eggman"; this.FNTCheckBox_Chars_Eggman.UseVisualStyleBackColor = true; + this.FNTCheckBox_Chars_Eggman.MouseDown += new System.Windows.Forms.MouseEventHandler(this.SharedMouseDown_Chkchk); // // FNTCheckBox_Chars_Charmy // @@ -860,6 +876,7 @@ private void InitializeComponent() this.FNTCheckBox_Chars_Charmy.TabIndex = 10; this.FNTCheckBox_Chars_Charmy.Text = "Charmy"; this.FNTCheckBox_Chars_Charmy.UseVisualStyleBackColor = true; + this.FNTCheckBox_Chars_Charmy.MouseDown += new System.Windows.Forms.MouseEventHandler(this.SharedMouseDown_Chkchk); // // FNTCheckBox_Chars_Espio // @@ -871,6 +888,7 @@ private void InitializeComponent() this.FNTCheckBox_Chars_Espio.TabIndex = 8; this.FNTCheckBox_Chars_Espio.Text = "Espio"; this.FNTCheckBox_Chars_Espio.UseVisualStyleBackColor = true; + this.FNTCheckBox_Chars_Espio.MouseDown += new System.Windows.Forms.MouseEventHandler(this.SharedMouseDown_Chkchk); // // FNTCheckBox_Chars_Vector // @@ -882,6 +900,7 @@ private void InitializeComponent() this.FNTCheckBox_Chars_Vector.TabIndex = 7; this.FNTCheckBox_Chars_Vector.Text = "Vector"; this.FNTCheckBox_Chars_Vector.UseVisualStyleBackColor = true; + this.FNTCheckBox_Chars_Vector.MouseDown += new System.Windows.Forms.MouseEventHandler(this.SharedMouseDown_Chkchk); // // FNTCheckBox_Chars_Omega // @@ -893,6 +912,7 @@ private void InitializeComponent() this.FNTCheckBox_Chars_Omega.TabIndex = 6; this.FNTCheckBox_Chars_Omega.Text = "Omega"; this.FNTCheckBox_Chars_Omega.UseVisualStyleBackColor = true; + this.FNTCheckBox_Chars_Omega.MouseDown += new System.Windows.Forms.MouseEventHandler(this.SharedMouseDown_Chkchk); // // FNTCheckBox_Chars_Rouge // @@ -904,6 +924,7 @@ private void InitializeComponent() this.FNTCheckBox_Chars_Rouge.TabIndex = 5; this.FNTCheckBox_Chars_Rouge.Text = "Rouge"; this.FNTCheckBox_Chars_Rouge.UseVisualStyleBackColor = true; + this.FNTCheckBox_Chars_Rouge.MouseDown += new System.Windows.Forms.MouseEventHandler(this.SharedMouseDown_Chkchk); // // FNTCheckBox_Chars_Amy // @@ -915,6 +936,7 @@ private void InitializeComponent() this.FNTCheckBox_Chars_Amy.TabIndex = 4; this.FNTCheckBox_Chars_Amy.Text = "Amy"; this.FNTCheckBox_Chars_Amy.UseVisualStyleBackColor = true; + this.FNTCheckBox_Chars_Amy.MouseDown += new System.Windows.Forms.MouseEventHandler(this.SharedMouseDown_Chkchk); // // FNTCheckBox_Chars_Knuckles // @@ -926,6 +948,7 @@ private void InitializeComponent() this.FNTCheckBox_Chars_Knuckles.TabIndex = 3; this.FNTCheckBox_Chars_Knuckles.Text = "Knuckles"; this.FNTCheckBox_Chars_Knuckles.UseVisualStyleBackColor = true; + this.FNTCheckBox_Chars_Knuckles.MouseDown += new System.Windows.Forms.MouseEventHandler(this.SharedMouseDown_Chkchk); // // FNTCheckBox_Chars_Tails // @@ -937,6 +960,7 @@ private void InitializeComponent() this.FNTCheckBox_Chars_Tails.TabIndex = 2; this.FNTCheckBox_Chars_Tails.Text = "Tails"; this.FNTCheckBox_Chars_Tails.UseVisualStyleBackColor = true; + this.FNTCheckBox_Chars_Tails.MouseDown += new System.Windows.Forms.MouseEventHandler(this.SharedMouseDown_Chkchk); // // FNTCheckBox_Chars_Sonic // @@ -948,6 +972,7 @@ private void InitializeComponent() this.FNTCheckBox_Chars_Sonic.TabIndex = 1; this.FNTCheckBox_Chars_Sonic.Text = "Sonic"; this.FNTCheckBox_Chars_Sonic.UseVisualStyleBackColor = true; + this.FNTCheckBox_Chars_Sonic.MouseDown += new System.Windows.Forms.MouseEventHandler(this.SharedMouseDown_Chkchk); // // FNTCheckBox_Chars_Shadow // @@ -959,6 +984,7 @@ private void InitializeComponent() this.FNTCheckBox_Chars_Shadow.TabIndex = 0; this.FNTCheckBox_Chars_Shadow.Text = "Shadow"; this.FNTCheckBox_Chars_Shadow.UseVisualStyleBackColor = true; + this.FNTCheckBox_Chars_Shadow.MouseDown += new System.Windows.Forms.MouseEventHandler(this.SharedMouseDown_Chkchk); // // subtitleAndVoicelineConfigurationGroupBox // diff --git a/ShadowRando/MainForm.cs b/ShadowRando/MainForm.cs index fdee402..260b7ea 100644 --- a/ShadowRando/MainForm.cs +++ b/ShadowRando/MainForm.cs @@ -1,5 +1,7 @@ using AFSLib; using HeroesONE_R.Structures; +using HeroesONE_R.Structures.Common; +using HeroesONE_R.Structures.SonicHeroes; using IniFile; using NAudio.Wave; using ShadowFNT; @@ -182,7 +184,7 @@ public MainForm() InitializeComponent(); } - const string programVersion = "0.4.0-preview-2024-01-01"; + const string programVersion = "0.4.0-preview-2024-01-02"; private static string hoverSoundPath = AppDomain.CurrentDomain.BaseDirectory + "res/hover.wav"; private static string selectSoundPath = AppDomain.CurrentDomain.BaseDirectory + "res/select.wav"; Settings settings; @@ -210,13 +212,14 @@ private void MainForm_Load(object sender, EventArgs e) setLayout_keepType.Checked = settings.SETEnemyKeepType; setLayout_randomPartners.Checked = settings.SETRandomPartners; setLayout_randomWeaponsInBoxes.Checked = settings.SETRandomWeaponsInBoxes; + setLayout_adjustMissionCounts.Checked = settings.SETRandomAdjustMissionCounts; + setLayout_makeCCSplinesAWRidable.Checked = settings.SETRandomMakeCCSplinesAWRidable; // FNT Configuration FNTCheckBox_NoDuplicatesPreRandomization.Checked = settings.FNTNoDuplicatesPreRandomization; FNTCheckBox_NoSystemMessages.Checked = settings.FNTNoSystemMessages; FNTCheckBox_OnlyLinkedAudio.Checked = settings.FNTOnlyLinkedAudio; FNTCheckBox_SpecificCharacters.Checked = settings.FNTSpecificCharacters; FNTCheckBox_GiveAudioToNoLinkedAudio.Checked = settings.FNTGiveAudioToNoLinkedAudio; - // FNT Configuration Specific Characters FNTCheckBox_Chars_Shadow.Checked = settings.FNTShadowSelected; FNTCheckBox_Chars_Sonic.Checked = settings.FNTSonicSelected; @@ -338,6 +341,8 @@ private void MainForm_FormClosing(object sender, FormClosingEventArgs e) settings.SETEnemyKeepType = setLayout_keepType.Checked; settings.SETRandomPartners = setLayout_randomPartners.Checked; settings.SETRandomWeaponsInBoxes = setLayout_randomWeaponsInBoxes.Checked; + settings.SETRandomAdjustMissionCounts = setLayout_adjustMissionCounts.Checked; + settings.SETRandomMakeCCSplinesAWRidable = setLayout_makeCCSplinesAWRidable.Checked; // FNT Configuration settings.FNTNoDuplicatesPreRandomization = FNTCheckBox_NoDuplicatesPreRandomization.Checked; settings.FNTNoSystemMessages = FNTCheckBox_NoSystemMessages.Checked; @@ -1221,11 +1226,20 @@ all same weapon type or random { var datOneFile = stageDataIdentifier + "_dat.one"; var datOneData = File.ReadAllBytes(Path.Combine("backup", "sets", stageDataIdentifier, datOneFile)); + ONEArchiveType archiveType = ONEArchiveTester.GetArchiveType(ref datOneData); var datOneDataContent = Archive.FromONEFile(ref datOneData); if (datOneDataContent.Files[0].Name == "PATH.PTP") { - var splineData = datOneDataContent.Files[0].DecompressThis(); - // TODO: Spline parsing and manipulation of AW ridable byte per spline + var splines = SplineReader.ReadShadowSplineFile(datOneDataContent.Files[0]); + foreach (var spline in splines) + { + if (spline.SplineType == 32) + spline.Setting2 = 1; + } + var updatedPATHPTP = SplineReader.ShadowSplinesToByteArray(stageDataIdentifier, splines); + datOneDataContent.Files[0].CompressedData = Prs.Compress(ref updatedPATHPTP); + var updatedDatOneData = datOneDataContent.BuildShadowONEArchive(archiveType == ONEArchiveType.Shadow060); + File.WriteAllBytes(Path.Combine(settings.GamePath, "files", stageDataIdentifier, datOneFile), updatedDatOneData.ToArray()); } } } // end - layout operations @@ -2529,6 +2543,7 @@ private void randomSET_CheckedChanged(object sender, EventArgs e) setLayout_randomWeaponsInBoxes.Enabled = randomSET.Checked; setLayout_randomPartners.Enabled = randomSET.Checked; setLayout_adjustMissionCounts.Enabled = randomSET.Checked; + setLayout_makeCCSplinesAWRidable.Enabled = randomSET.Checked; } } @@ -2786,6 +2801,10 @@ class Settings public bool SETRandomPartners { get; set; } [IniAlwaysInclude] public bool SETRandomWeaponsInBoxes { get; set; } + [IniAlwaysInclude] + public bool SETRandomMakeCCSplinesAWRidable { get; set; } + [IniAlwaysInclude] + public bool SETRandomAdjustMissionCounts { get; set; } // FNT [IniAlwaysInclude] public bool FNTNoDuplicatesPreRandomization; diff --git a/ShadowRando/ShadowRando.csproj b/ShadowRando/ShadowRando.csproj index 516ecea..f5a1edf 100644 --- a/ShadowRando/ShadowRando.csproj +++ b/ShadowRando/ShadowRando.csproj @@ -106,6 +106,7 @@ + PreserveNewest diff --git a/ShadowRando/ShadowSpline.cs b/ShadowRando/ShadowSpline.cs new file mode 100644 index 0000000..8fcf58b --- /dev/null +++ b/ShadowRando/ShadowSpline.cs @@ -0,0 +1,364 @@ +using ShadowSET.Utilities; +using System.Collections.Generic; +using System.IO; +using System.Numerics; +using System; +using System.Linq; +using HeroesONE_R.Structures.Substructures; + +// Hacky file for lazy spline editing; Uses the inaccurate save version from HPP; Only good for editing core attributes! + +namespace ShadowRando +{ + public class ShadowSplineSec5Bytes + { + public byte slot1 { get; set; } + public byte slot2 { get; set; } + public bool noSlot2 { get; set; } + } + public class ShadowSplineVertex + { + public Vector3 Position; + public float PositionX + { + get => Position.X; + set => Position.X = value; + } + public float PositionY + { + get => Position.Y; + set => Position.Y = value; + } + public float PositionZ + { + get => Position.Z; + set => Position.Z = value; + } + public Vector3 Rotation; + public float RotationX + { + get => RadiansToDegrees(Rotation.X); + set => Rotation.X = DegreesToRadians(value); + } + public float RotationY + { + get => RadiansToDegrees(Rotation.Y); + set => Rotation.Y = DegreesToRadians(value); + } + public float RotationZ + { + get => RadiansToDegrees(Rotation.Z); + set => Rotation.Z = DegreesToRadians(value); + } + public int AngularAttachmentToleranceInt { get; set; } + + public override string ToString() + { + return $"X:{PositionX} Y:{PositionY} Z:{PositionZ} AAT:{AngularAttachmentToleranceInt}"; + } + + public static float DegreesToRadians(float degree) + { + return degree * ((float)Math.PI / 180f); + } + + public static float RadiansToDegrees(float radian) + { + return radian * (180f / (float)Math.PI); + } + } + public class ShadowSpline + { + public byte Setting1 { get; set; } + public byte Setting2 { get; set; } + public byte SplineType { get; set; } + public byte Setting4 { get; set; } + public int SettingInt { get; set; } + public string Name { get; set; } + public ShadowSplineSec5Bytes[] UnknownSec5Bytes { get; set; } + public ShadowSplineVertex[] Vertices { get; set; } + public ShadowSpline() + { + Vertices = new ShadowSplineVertex[0]; + UnknownSec5Bytes = new ShadowSplineSec5Bytes[0]; + Name = "NewSpline"; + } + public IEnumerable ToByteArray(int startOffset) + { + List vertexBytes = new List(0x20 * Vertices.Length); + + float totalLength = 0; + Vector3 Max = Vertices[0].Position; + Vector3 Min = Vertices[0].Position; + + for (int i = 0; i < Vertices.Length; i++) + { + float distance = i == Vertices.Length - 1 ? 0 : Vector3.Distance(Vertices[i].Position, Vertices[i + 1].Position); + totalLength += distance; + + if (Vertices[i].PositionX > Max.X) + Max.X = Vertices[i].Position.X; + if (Vertices[i].PositionY > Max.Y) + Max.Y = Vertices[i].PositionY; + if (Vertices[i].PositionZ > Max.Z) + Max.Z = Vertices[i].PositionZ; + if (Vertices[i].PositionX < Min.X) + Min.X = Vertices[i].PositionX; + if (Vertices[i].PositionY < Min.Y) + Min.Y = Vertices[i].PositionY; + if (Vertices[i].PositionZ < Min.Z) + Min.Z = Vertices[i].PositionZ; + + vertexBytes.AddRange(BitConverter.GetBytes(Vertices[i].PositionX).Reverse()); + vertexBytes.AddRange(BitConverter.GetBytes(Vertices[i].PositionY).Reverse()); + vertexBytes.AddRange(BitConverter.GetBytes(Vertices[i].PositionZ).Reverse()); + vertexBytes.AddRange(BitConverter.GetBytes(Vertices[i].Rotation.X).Reverse()); + vertexBytes.AddRange(BitConverter.GetBytes(Vertices[i].Rotation.Y).Reverse()); + vertexBytes.AddRange(BitConverter.GetBytes(Vertices[i].Rotation.Z).Reverse()); + vertexBytes.AddRange(BitConverter.GetBytes(distance).Reverse()); + vertexBytes.AddRange(BitConverter.GetBytes(Vertices[i].AngularAttachmentToleranceInt).Reverse()); + } + + List bytes = new List(0x30 + 0x20 * Vertices.Length); + + bytes.AddRange(BitConverter.GetBytes(Vertices.Length).Reverse()); + bytes.AddRange(BitConverter.GetBytes(totalLength).Reverse()); + bytes.AddRange(BitConverter.GetBytes(startOffset + 0x30).Reverse()); + bytes.Add(Setting1); + bytes.Add(Setting2); + bytes.Add(SplineType); + bytes.Add(Setting4); + bytes.AddRange(BitConverter.GetBytes(Max.X).Reverse()); + bytes.AddRange(BitConverter.GetBytes(Max.Y).Reverse()); + bytes.AddRange(BitConverter.GetBytes(Max.Z).Reverse()); + bytes.AddRange(BitConverter.GetBytes(SettingInt).Reverse()); + bytes.AddRange(BitConverter.GetBytes(Min.X).Reverse()); + bytes.AddRange(BitConverter.GetBytes(Min.Y).Reverse()); + bytes.AddRange(BitConverter.GetBytes(Min.Z).Reverse()); + bytes.AddRange(BitConverter.GetBytes(0)); + + bytes.AddRange(vertexBytes); + + return bytes; + } + } + + public class SplineReader + { + private static string ReadString(BinaryReader binaryReader) + { + List list = new List(); + + while (binaryReader.PeekChar() != '\0') + list.Add(binaryReader.ReadChar()); + + binaryReader.BaseStream.Position += 1; + + return new string(list.ToArray()); + } + public static List ReadShadowSplineFile(ArchiveFile pathPTP) + { + var splineReader = new EndianBinaryReader(new MemoryStream(pathPTP.DecompressThis()), Endianness.Big); + + List splineList = new List(); + + splineReader.BaseStream.Position = 0x4; + int sec5offset = splineReader.ReadInt32(); + int sec5length = splineReader.ReadInt32(); + + splineReader.BaseStream.Position = 0x20; + List offsetList = new List(); + + int a = splineReader.ReadInt32(); + + while (a != 0) + { + offsetList.Add(a + 0x20); + a = splineReader.ReadInt32(); + } + + foreach (int i in offsetList) + { + if (i >= splineReader.BaseStream.Length) + throw new Exception(); + + splineReader.BaseStream.Position = i; + + ShadowSpline spline = new ShadowSpline(); + int amountOfPoints = splineReader.ReadInt32(); + + splineReader.BaseStream.Position += 8; + + spline.Setting1 = splineReader.ReadByte(); + spline.Setting2 = splineReader.ReadByte(); + spline.SplineType = splineReader.ReadByte(); + spline.Setting4 = splineReader.ReadByte(); + + splineReader.BaseStream.Position += 0xC; + + spline.SettingInt = splineReader.ReadInt32(); + + splineReader.BaseStream.Position += 0xC; + + int nameOffset = splineReader.ReadInt32(); + + spline.Vertices = new ShadowSplineVertex[amountOfPoints]; + + for (int j = 0; j < amountOfPoints; j++) + { + ShadowSplineVertex vertex = new ShadowSplineVertex + { + Position = new Vector3(splineReader.ReadSingle(), splineReader.ReadSingle(), splineReader.ReadSingle()), + Rotation = new Vector3(splineReader.ReadSingle(), splineReader.ReadSingle(), splineReader.ReadSingle()) + }; + splineReader.BaseStream.Position += 0x4; + vertex.AngularAttachmentToleranceInt = splineReader.ReadInt32(); + + spline.Vertices[j] = vertex; + } + + splineReader.BaseStream.Position = nameOffset + 0x20; + spline.Name = ReadString(splineReader); + + splineList.Add(spline); + } + + splineReader.BaseStream.Position = sec5offset + 0x20 + splineList.Count; + + for (int i = 0; i < splineList.Count; i++) + { + byte byte0 = splineReader.ReadByte(); + + if (byte0 >= 0x80) + { + byte byte1 = splineReader.ReadByte(); + splineList[i].UnknownSec5Bytes = new ShadowSplineSec5Bytes[1] { new ShadowSplineSec5Bytes { slot1 = byte0, slot2 = byte1, noSlot2 = false } }; + } + else + splineList[i].UnknownSec5Bytes = new ShadowSplineSec5Bytes[1] { new ShadowSplineSec5Bytes { slot1 = byte0, noSlot2 = true } }; + + splineReader.ReadByte(); + } + + splineReader.Close(); + + return splineList; + } + + public static byte[] ShadowSplinesToByteArray(string shadowFolderNamePrefix, List Splines) + { + List bytes = new List(); + + bytes.AddRange(BitConverter.GetBytes(0)); + bytes.AddRange(BitConverter.GetBytes(0)); + bytes.AddRange(BitConverter.GetBytes(0)); + bytes.AddRange(BitConverter.GetBytes(1).Reverse()); + bytes.AddRange(BitConverter.GetBytes(0)); + bytes.AddRange(BitConverter.GetBytes(12610).Reverse()); + bytes.AddRange(BitConverter.GetBytes(0)); + bytes.AddRange(BitConverter.GetBytes(0)); + + // add 0x10 offset (breaks without this on stg0412) + // with this added offset, breaks stg0504, so for now just hardcode for 0412 + if (shadowFolderNamePrefix == "stg0412") + { + for (int i = 0; i < 10; i++) + bytes.Add(0); + } + + foreach (ShadowSpline s in Splines) + bytes.AddRange(BitConverter.GetBytes(0)); + + while (bytes.Count % 0x10 != 0) + bytes.Add(0); + + List offsets = new List(); + + for (int i = 0; i < Splines.Count; i++) + { + offsets.Add(bytes.Count - 0x20); + bytes.AddRange(Splines[i].ToByteArray(bytes.Count - 0x20)); + } + + for (int i = 0; i < Splines.Count; i++) + { + byte[] offsetBytes = BitConverter.GetBytes(offsets[i]); + + bytes[0x20 + 4 * i + 0] = offsetBytes[3]; + bytes[0x20 + 4 * i + 1] = offsetBytes[2]; + bytes[0x20 + 4 * i + 2] = offsetBytes[1]; + bytes[0x20 + 4 * i + 3] = offsetBytes[0]; + + byte[] nameOffset = BitConverter.GetBytes(bytes.Count - 0x20); + + bytes[offsets[i] + 0x20 + 0x2C] = nameOffset[3]; + bytes[offsets[i] + 0x20 + 0x2D] = nameOffset[2]; + bytes[offsets[i] + 0x20 + 0x2E] = nameOffset[1]; + bytes[offsets[i] + 0x20 + 0x2F] = nameOffset[0]; + + foreach (char c in Splines[i].Name) + bytes.Add((byte)c); + + bytes.Add(0); + } + + while (bytes.Count % 0x4 != 0) + bytes.Add(0); + + int section5startOffset = bytes.Count - 0x20; + + bytes.Add(0x40); + + for (int i = 1; i < Splines.Count; i++) + bytes.Add(0x41); + + for (int i = 0; i < Splines.Count; i++) + { + bytes.Add(Splines[i].UnknownSec5Bytes[0].slot1); + if (!Splines[i].UnknownSec5Bytes[0].noSlot2) + bytes.Add(Splines[i].UnknownSec5Bytes[0].slot2); + bytes.Add(0x49); + } + + while (bytes.Count % 0x4 != 0) + bytes.Add(0); + + int section5length = bytes.Count - section5startOffset - 0x20; + + for (int i = 0; i < 8; i++) + bytes.Add(0); + + foreach (char c in ("o:\\PJS\\PJSart\\exportdata\\stage\\" + shadowFolderNamePrefix + "\\path")) + bytes.Add((byte)c); + bytes.Add(0); + + // Inspect byte % 0x10 + + while (bytes.Count % 0x4 != 0) + bytes.Add(0); + + byte[] aux = BitConverter.GetBytes(bytes.Count); + + bytes[0] = aux[3]; + bytes[1] = aux[2]; + bytes[2] = aux[1]; + bytes[3] = aux[0]; + + aux = BitConverter.GetBytes(section5startOffset); + + bytes[4] = aux[3]; + bytes[5] = aux[2]; + bytes[6] = aux[1]; + bytes[7] = aux[0]; + + aux = BitConverter.GetBytes(section5length); + + bytes[8] = aux[3]; + bytes[9] = aux[2]; + bytes[10] = aux[1]; + bytes[11] = aux[0]; + + return bytes.ToArray(); + } + } +}