diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..064b3f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +################################################################################ +# This .gitignore file was automatically created by Microsoft(R) Visual Studio. +################################################################################ + +/MoveTool/obj +/.vs +*/obj +*/bin +*.user +*.config +/packages/* \ No newline at end of file diff --git a/MoveLib/BAC.cs b/MoveLib/BAC.cs index a0162d0..7ecfe29 100644 --- a/MoveLib/BAC.cs +++ b/MoveLib/BAC.cs @@ -3,13 +3,21 @@ using System.Diagnostics; using System.IO; using System.Linq; -using System.Text; using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Linq; + +// TODO: Update footer location in header bytes when writing to uasset. namespace MoveLib.BAC { public static class BAC { + /// + /// Converts a BAC Uasset into a JSON file. + /// + /// Path of BAC_***.uasset file to be converted to JSON. + /// Desired name/path for converted file. public static void BacToJson(string inFile, string outFile) { BACFile bac; @@ -24,9 +32,7 @@ public static void BacToJson(string inFile, string outFile) throw; } - Formatting format = Formatting.Indented; - - var json = JsonConvert.SerializeObject(bac, format, new Newtonsoft.Json.Converters.StringEnumConverter()); + var json = JsonConvert.SerializeObject(bac, Formatting.Indented, new StringEnumConverter()); File.WriteAllText(outFile, json); } @@ -37,7 +43,7 @@ public static bool JsonToBac(string inFile, string outFile) try { - bac = JsonConvert.DeserializeObject(File.ReadAllText(inFile)); + bac = JsonConvert.DeserializeObject(File.ReadAllText(inFile), new ForceEnumConverter(), new StringEnumConverter()); } catch (Exception ex) { @@ -49,10 +55,12 @@ public static bool JsonToBac(string inFile, string outFile) { ToUassetFile(bac, outFile); } - catch (Exception) + catch (Exception ex) { + Console.WriteLine($"Error converting to UAsset: \n{ex.Message} \n{ex.InnerException}"); return false; } + return true; } @@ -106,16 +114,18 @@ public static BACFile FromUassetFile(string fileName) baseMoveAddresses.Add(inFile.ReadInt32()); } - BACFile file = new BACFile(); - file.RawUassetHeaderDontTouch = UassetHeaderBytes; - file.MoveLists = new MoveList[MoveListCount]; - file.BACVER = BACVER; + BACFile file = new BACFile + { + RawUassetHeaderDontTouch = UassetHeaderBytes, + MoveLists = new MoveList[MoveListCount], + BACVER = BACVER + }; for (int i = 0; i < baseMoveAddresses.Count; i++) { int thisAddress = baseMoveAddresses[i]; - Debug.WriteLine("Unknown1 at pos: " + thisAddress.ToString("X") + " - Index:" + i); + Debug.WriteLine("ScriptStartTime at pos: " + thisAddress.ToString("X") + " - Index:" + i); inFile.BaseStream.Seek(thisAddress, SeekOrigin.Begin); @@ -138,9 +148,11 @@ public static BACFile FromUassetFile(string fileName) List MoveAddresses = new List(); List NameAddresses = new List(); - file.MoveLists[i] = new MoveList(); - file.MoveLists[i].Unknown1 = unknown1; - file.MoveLists[i].Moves = new Move[MoveCount]; + file.MoveLists[i] = new MoveList + { + Unknown1 = unknown1, + Moves = new Move[MoveCount] + }; for (int j = 0; j < MoveCount; j++) { @@ -180,11 +192,11 @@ public static BACFile FromUassetFile(string fileName) #region DebuggingPurposes - int Size = 0; + int size; if (j == MoveAddresses.Count - 1) { - Size = 0; + size = 0; } else { @@ -194,15 +206,15 @@ public static BACFile FromUassetFile(string fileName) nextAddress++; } - Size = (MoveAddresses[j + nextAddress] - thisMoveAddress); + size = (MoveAddresses[j + nextAddress] - thisMoveAddress); - if (Size < 0) + if (size < 0) { Debug.WriteLine("Size was smaller than 0?? Next address:" + MoveAddresses[j+nextAddress].ToString("X") + " This Address: " + thisMoveAddress.ToString("X") ); } } - Debug.WriteLine("Size: " + Size); + Debug.WriteLine("Size: " + size); #endregion @@ -216,12 +228,12 @@ public static BACFile FromUassetFile(string fileName) TotalTicks = inFile.ReadInt32(), ReturnToOriginalPosition = inFile.ReadInt32(), - Slide = inFile.ReadSingle(), - unk3 = inFile.ReadSingle(), - unk4 = inFile.ReadSingle(), - unk5 = inFile.ReadSingle(), - unk6 = inFile.ReadSingle(), - unk7 = inFile.ReadSingle(), + XSpeedMultiplier = inFile.ReadSingle(), + YSpeedMultiplier = inFile.ReadSingle(), + ZSpeedMultiplier = inFile.ReadSingle(), + XAcceleration = inFile.ReadSingle(), + YAcceleration = inFile.ReadSingle(), + ZAcceleration = inFile.ReadSingle(), Flag = inFile.ReadInt32(), unk9 = inFile.ReadInt32(), @@ -349,16 +361,18 @@ public static BACFile FromUassetFile(string fileName) inFile.BaseStream.Seek(thisType0Address, SeekOrigin.Begin); - AutoCancel thisType0 = new AutoCancel(); - thisType0.TickStart = tickStarts[l]; - thisType0.TickEnd = tickEnds[l]; - thisType0.Condition = (AutoCancelCondition) inFile.ReadInt16(); - thisType0.MoveIndex = inFile.ReadInt16(); - thisType0.Unknown1 = inFile.ReadInt16(); - thisType0.NumberOfInts = inFile.ReadInt16(); - thisType0.Unknown2 = inFile.ReadInt32(); + AutoCancel thisType0 = new AutoCancel + { + TickStart = tickStarts[l], + TickEnd = tickEnds[l], + Condition = (AutoCancelCondition) inFile.ReadInt16(), + MoveIndex = inFile.ReadInt16(), + ScriptStartTime = inFile.ReadInt16(), + NumberOfInts = inFile.ReadInt16(), + Unknown2 = inFile.ReadInt32() + }; - switch (BACVER) + switch (BACVER) { case 1: { @@ -383,9 +397,9 @@ public static BACFile FromUassetFile(string fileName) } Debug.WriteLine( - "thisType0 - TickStart: {0}, TickEnd: {1}, Condition: {2}, MoveIndex: {3}, Unknown1: {4}, NumberOfInts: {5}, Unknown2: {6} Offset: {7} Unknown3: {8} Unknown4: {9}", + "thisType0 - TickStart: {0}, TickEnd: {1}, Condition: {2}, MoveIndex: {3}, ScriptStartTime: {4}, NumberOfInts: {5}, Unknown2: {6} Offset: {7} Unknown3: {8} Unknown4: {9}", thisType0.TickStart, thisType0.TickEnd, thisType0.Condition, - thisType0.MoveIndex, thisType0.Unknown1, thisType0.NumberOfInts, + thisType0.MoveIndex, thisType0.ScriptStartTime, thisType0.NumberOfInts, thisType0.Unknown2, thisType0.Offset.ToString("X"), thisType0.Unknown3, thisType0.Unknown4); @@ -435,7 +449,7 @@ public static BACFile FromUassetFile(string fileName) thisForce.TickStart = tickStarts[l]; thisForce.TickEnd = tickEnds[l]; thisForce.Amount = inFile.ReadSingle(); - thisForce.Flag = (ForceEnum) inFile.ReadInt32(); + thisForce.Flag = inFile.ReadInt32(); Debug.WriteLine( "thisForce - TickStart: {0}, TickEnd: {1}, Amount: {2}, Flag: {3}", @@ -776,7 +790,7 @@ public static BACFile FromUassetFile(string fileName) thisType11.Unknown2 = inFile.ReadInt16(); thisType11.Unknown3 = inFile.ReadInt16(); - thisType11.Type = inFile.ReadInt16(); + thisType11.EffectId = inFile.ReadInt16(); thisType11.Unknown5 = inFile.ReadInt16(); thisType11.AttachPoint = inFile.ReadInt16(); @@ -791,7 +805,7 @@ public static BACFile FromUassetFile(string fileName) Debug.WriteLine( "thisType11 - TickStart: {0}, TickEnd: {1}, Unknown1: {2}, Unknown2: {3}, Unknown3:{4}, Type: {5}, Unknown5: {6}, AttachPoint: {7}, X: {8}, Y: {9}, Z: {10}, Unknown10: {11}, Size: {12}, Unknown12:{13}, filePos: {14}", thisType11.TickStart, thisType11.TickEnd, thisType11.Unknown1, - thisType11.Unknown2, thisType11.Unknown3, thisType11.Type, + thisType11.Unknown2, thisType11.Unknown3, thisType11.EffectId, thisType11.Unknown5, thisType11.AttachPoint, thisType11.X, thisType11.Y, thisType11.Z, thisType11.Unknown10, thisType11.Size, thisType11.Unknown12, thisPosition.ToString("X")); @@ -838,7 +852,7 @@ public static BACFile FromUassetFile(string fileName) { if (inFile.BaseStream.Position > BACVERintAddresses[0]) { - Debug.WriteLine("WE're At the WRONG POSITION, TOO FAR!"); + Debug.WriteLine("We're At the WRONG POSITION, TOO FAR!"); throw new Exception("WE WENT TOO FAR! (Position > BACVERintAddresses[0])"); } @@ -986,17 +1000,14 @@ public static BACFile FromUassetFile(string fileName) } break; } - } - - } foreach (var typeInfo in TypeInfoList) { Debug.WriteLine("Type:"); Debug.WriteLine("TickOffset: {0} DataOffset: {1} TypeNumber: {2} NumberOfType: {3}, TickAddress: {4}, DataAddress {5}", typeInfo.TickOffset.ToString("X"), typeInfo.DataOffset.ToString("X"), typeInfo.TypeNumber, typeInfo.NumberOfType, typeInfo.TickAddress.ToString("X"), typeInfo.DataAddress.ToString("X")); - if (typeInfo.DataOffset > Size && Size > 0) + if (typeInfo.DataOffset > size && size > 0) { Debug.WriteLine("DataOffset BIGGER THAN Size????"); } @@ -1235,8 +1246,6 @@ public static BACFile FromUassetFile(string fileName) } } - - public static void ToUassetFile(BACFile file, string OutPutFileName) { byte[] outPutFileBytes; @@ -1311,7 +1320,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) Debug.WriteLine("MoveCount: " + file.MoveLists[i].Moves.Length); - foreach (var Move in file.MoveLists[i].Moves) + foreach (var move in file.MoveLists[i].Moves) { outFile.Write(0); } @@ -1322,7 +1331,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) Debug.WriteLine("Names: " + StartOfMovesNamesOffset.ToString("X")); - foreach (var Move in file.MoveLists[i].Moves) + foreach (var move in file.MoveLists[i].Moves) { outFile.Write(0); } @@ -1330,9 +1339,9 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) int j = 0; - foreach (var Move in file.MoveLists[i].Moves) + foreach (var move in file.MoveLists[i].Moves) { - if (Move == null) + if (move == null) { Common.WriteInt32ToPosition(outFile, StartOfMovesOffset +(j*4), 0); j++; @@ -1341,38 +1350,38 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) Common.WriteInt32ToPosition(outFile, StartOfMovesOffset +(j*4), (int)(outFile.BaseStream.Position - MoveTableBaseAddress)); - outFile.Write(Move.FirstHitboxFrame); - outFile.Write(Move.LastHitboxFrame); - outFile.Write(Move.InterruptFrame); - outFile.Write(Move.TotalTicks); - outFile.Write(Move.ReturnToOriginalPosition); - outFile.Write(Move.Slide); - outFile.Write(Move.unk3); - outFile.Write(Move.unk4); - outFile.Write(Move.unk5); - outFile.Write(Move.unk6); - outFile.Write(Move.unk7); - outFile.Write(Move.Flag); - outFile.Write(Move.unk9); - - outFile.Write(Move.numberOfTypes); - - outFile.Write(Move.unk13); - outFile.Write(Move.HeaderSize); - - if (Move.HeaderSize == 0x58) + outFile.Write(move.FirstHitboxFrame); + outFile.Write(move.LastHitboxFrame); + outFile.Write(move.InterruptFrame); + outFile.Write(move.TotalTicks); + outFile.Write(move.ReturnToOriginalPosition); + outFile.Write(move.XSpeedMultiplier); + outFile.Write(move.YSpeedMultiplier); + outFile.Write(move.ZSpeedMultiplier); + outFile.Write(move.XAcceleration); + outFile.Write(move.YAcceleration); + outFile.Write(move.ZAcceleration); + outFile.Write(move.Flag); + outFile.Write(move.unk9); + + outFile.Write(move.numberOfTypes); + + outFile.Write(move.unk13); + outFile.Write(move.HeaderSize); + + if (move.HeaderSize == 0x58) { - outFile.Write(Move.Unknown12); - outFile.Write(Move.Unknown13); - outFile.Write(Move.Unknown14); - outFile.Write(Move.Unknown15); - outFile.Write(Move.Unknown16); - outFile.Write(Move.Unknown17); - outFile.Write(Move.Unknown18); - outFile.Write(Move.Unknown19); - outFile.Write(Move.Unknown20); - outFile.Write(Move.Unknown21); - outFile.Write(Move.Unknown22); + outFile.Write(move.Unknown12); + outFile.Write(move.Unknown13); + outFile.Write(move.Unknown14); + outFile.Write(move.Unknown15); + outFile.Write(move.Unknown16); + outFile.Write(move.Unknown17); + outFile.Write(move.Unknown18); + outFile.Write(move.Unknown19); + outFile.Write(move.Unknown20); + outFile.Write(move.Unknown21); + outFile.Write(move.Unknown22); } long type0TickOffsetAddress = 0; @@ -1389,125 +1398,125 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) long type11TickOffsetAddress = 0; long PositionTickOffsetAddress = 0; - if (Move.AutoCancels != null && Move.AutoCancels.Length > 0) + if (move.AutoCancels != null && move.AutoCancels.Length > 0) { outFile.Write((short) 0); - outFile.Write((short)Move.AutoCancels.Length); + outFile.Write((short)move.AutoCancels.Length); type0TickOffsetAddress = outFile.BaseStream.Position; outFile.Write(0); outFile.Write(0); AddBytesDependingOnBACVER(file.BACVER, outFile); } - if (Move.Type1s != null && Move.Type1s.Length > 0) + if (move.Type1s != null && move.Type1s.Length > 0) { outFile.Write((short)1); - outFile.Write((short)Move.Type1s.Length); + outFile.Write((short)move.Type1s.Length); type1TickOffsetAddress = outFile.BaseStream.Position; outFile.Write(0); outFile.Write(0); AddBytesDependingOnBACVER(file.BACVER, outFile); } - if (Move.Forces != null && Move.Forces.Length > 0) + if (move.Forces != null && move.Forces.Length > 0) { outFile.Write((short)2); - outFile.Write((short)Move.Forces.Length); + outFile.Write((short)move.Forces.Length); ForceTickOffsetAddress = outFile.BaseStream.Position; outFile.Write(0); outFile.Write(0); AddBytesDependingOnBACVER(file.BACVER, outFile); } - if (Move.Cancels != null && Move.Cancels.Length > 0) + if (move.Cancels != null && move.Cancels.Length > 0) { outFile.Write((short)3); - outFile.Write((short)Move.Cancels.Length); + outFile.Write((short)move.Cancels.Length); type3TickOffsetAddress = outFile.BaseStream.Position; outFile.Write(0); outFile.Write(0); AddBytesDependingOnBACVER(file.BACVER, outFile); } - if (Move.Others != null && Move.Others.Length > 0) + if (move.Others != null && move.Others.Length > 0) { outFile.Write((short)4); - outFile.Write((short)Move.Others.Length); + outFile.Write((short)move.Others.Length); type4TickOffsetAddress = outFile.BaseStream.Position; outFile.Write(0); outFile.Write(0); AddBytesDependingOnBACVER(file.BACVER, outFile); } - if (Move.Hitboxes != null && Move.Hitboxes.Length > 0) + if (move.Hitboxes != null && move.Hitboxes.Length > 0) { outFile.Write((short)5); - outFile.Write((short)Move.Hitboxes.Length); + outFile.Write((short)move.Hitboxes.Length); HitboxTickOffsetAddress = outFile.BaseStream.Position; outFile.Write(0); outFile.Write(0); AddBytesDependingOnBACVER(file.BACVER, outFile); } - if (Move.Hurtboxes != null && Move.Hurtboxes.Length > 0) + if (move.Hurtboxes != null && move.Hurtboxes.Length > 0) { outFile.Write((short)6); - outFile.Write((short)Move.Hurtboxes.Length); + outFile.Write((short)move.Hurtboxes.Length); HurtboxTickOffsetAddress = outFile.BaseStream.Position; outFile.Write(0); outFile.Write(0); AddBytesDependingOnBACVER(file.BACVER, outFile); } - if (Move.PhysicsBoxes != null && Move.PhysicsBoxes.Length > 0) + if (move.PhysicsBoxes != null && move.PhysicsBoxes.Length > 0) { outFile.Write((short)7); - outFile.Write((short)Move.PhysicsBoxes.Length); + outFile.Write((short)move.PhysicsBoxes.Length); type7TickOffsetAddress = outFile.BaseStream.Position; outFile.Write(0); outFile.Write(0); AddBytesDependingOnBACVER(file.BACVER, outFile); } - if (Move.Animations != null && Move.Animations.Length > 0) + if (move.Animations != null && move.Animations.Length > 0) { outFile.Write((short)8); - outFile.Write((short)Move.Animations.Length); + outFile.Write((short)move.Animations.Length); type8TickOffsetAddress = outFile.BaseStream.Position; outFile.Write(0); outFile.Write(0); AddBytesDependingOnBACVER(file.BACVER, outFile); } - if (Move.Type9s != null && Move.Type9s.Length > 0) + if (move.Type9s != null && move.Type9s.Length > 0) { outFile.Write((short)9); - outFile.Write((short)Move.Type9s.Length); + outFile.Write((short)move.Type9s.Length); type9TickOffsetAddress = outFile.BaseStream.Position; outFile.Write(0); outFile.Write(0); AddBytesDependingOnBACVER(file.BACVER, outFile); } - if (Move.SoundEffects != null && Move.SoundEffects.Length > 0) + if (move.SoundEffects != null && move.SoundEffects.Length > 0) { outFile.Write((short)10); - outFile.Write((short)Move.SoundEffects.Length); + outFile.Write((short)move.SoundEffects.Length); type10TickOffsetAddress = outFile.BaseStream.Position; outFile.Write(0); outFile.Write(0); AddBytesDependingOnBACVER(file.BACVER, outFile); } - if (Move.VisualEffects != null && Move.VisualEffects.Length > 0) + if (move.VisualEffects != null && move.VisualEffects.Length > 0) { outFile.Write((short)11); - outFile.Write((short)Move.VisualEffects.Length); + outFile.Write((short)move.VisualEffects.Length); type11TickOffsetAddress = outFile.BaseStream.Position; outFile.Write(0); outFile.Write(0); AddBytesDependingOnBACVER(file.BACVER, outFile); } - if (Move.Positions != null && Move.Positions.Length > 0) + if (move.Positions != null && move.Positions.Length > 0) { outFile.Write((short)12); - outFile.Write((short)Move.Positions.Length); + outFile.Write((short)move.Positions.Length); PositionTickOffsetAddress = outFile.BaseStream.Position; outFile.Write(0); outFile.Write(0); AddBytesDependingOnBACVER(file.BACVER, outFile); } - if (Move.AutoCancels != null && Move.AutoCancels.Length > 0) + if (move.AutoCancels != null && move.AutoCancels.Length > 0) { List type0Offsets = new List(); List IntOffsets = new List(); @@ -1515,7 +1524,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) Common.WriteInt32ToPosition(outFile, type0TickOffsetAddress, (int)(outFile.BaseStream.Position - (type0TickOffsetAddress - 4))); - foreach (var type0 in Move.AutoCancels) + foreach (var type0 in move.AutoCancels) { outFile.Write(type0.TickStart); outFile.Write(type0.TickEnd); @@ -1523,7 +1532,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) Common.WriteInt32ToPosition(outFile, type0TickOffsetAddress + 4, (int)(outFile.BaseStream.Position - (type0TickOffsetAddress - 4))); - foreach (var type0 in Move.AutoCancels) + foreach (var type0 in move.AutoCancels) { if (type0.Ints.Length != 0) { @@ -1531,7 +1540,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) } outFile.Write((short)type0.Condition); outFile.Write(type0.MoveIndex); - outFile.Write(type0.Unknown1); + outFile.Write(type0.ScriptStartTime); outFile.Write(type0.NumberOfInts); outFile.Write(type0.Unknown2); @@ -1552,7 +1561,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) outFile.Write(0); } - foreach (var type0 in Move.AutoCancels) + foreach (var type0 in move.AutoCancels) { if (type0.Ints.Length != 0) { @@ -1576,7 +1585,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) //TheBACunknownoffsetthingie Common.WriteInt32ToPosition(outFile, type0TickOffsetAddress + 8, (int)(outFile.BaseStream.Position - (type0TickOffsetAddress - 4))); - foreach (var type0 in Move.AutoCancels) + foreach (var type0 in move.AutoCancels) { outFile.Write(type0.BACVERint1); outFile.Write(type0.BACVERint2); @@ -1589,11 +1598,11 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) } } - if (Move.Type1s != null && Move.Type1s.Length > 0) + if (move.Type1s != null && move.Type1s.Length > 0) { Common.WriteInt32ToPosition(outFile, type1TickOffsetAddress, (int)(outFile.BaseStream.Position - (type1TickOffsetAddress - 4))); - foreach (var type1 in Move.Type1s) + foreach (var type1 in move.Type1s) { outFile.Write(type1.TickStart); outFile.Write(type1.TickEnd); @@ -1601,7 +1610,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) Common.WriteInt32ToPosition(outFile, type1TickOffsetAddress + 4, (int)(outFile.BaseStream.Position - (type1TickOffsetAddress - 4))); - foreach (var type1 in Move.Type1s) + foreach (var type1 in move.Type1s) { outFile.Write(type1.Flag1); outFile.Write(type1.Flag2); @@ -1614,7 +1623,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) //TheBACunknownoffsetthingie Common.WriteInt32ToPosition(outFile, type1TickOffsetAddress + 8, (int)(outFile.BaseStream.Position - (type1TickOffsetAddress - 4))); - foreach (var type1 in Move.Type1s) + foreach (var type1 in move.Type1s) { outFile.Write(type1.BACVERint1); outFile.Write(type1.BACVERint2); @@ -1627,11 +1636,11 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) } } - if (Move.Forces != null && Move.Forces.Length > 0) + if (move.Forces != null && move.Forces.Length > 0) { Common.WriteInt32ToPosition(outFile, ForceTickOffsetAddress, (int)(outFile.BaseStream.Position - (ForceTickOffsetAddress - 4))); - foreach (var Force in Move.Forces) + foreach (var Force in move.Forces) { outFile.Write(Force.TickStart); outFile.Write(Force.TickEnd); @@ -1639,7 +1648,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) Common.WriteInt32ToPosition(outFile, ForceTickOffsetAddress + 4, (int)(outFile.BaseStream.Position - (ForceTickOffsetAddress - 4))); - foreach (var Force in Move.Forces) + foreach (var Force in move.Forces) { outFile.Write(Force.Amount); outFile.Write((int)Force.Flag); @@ -1653,7 +1662,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) //TheBACunknownoffsetthingie Common.WriteInt32ToPosition(outFile, ForceTickOffsetAddress + 8, (int)(outFile.BaseStream.Position - (ForceTickOffsetAddress - 4))); - foreach (var Force in Move.Forces) + foreach (var Force in move.Forces) { outFile.Write(Force.BACVERint1); outFile.Write(Force.BACVERint2); @@ -1666,11 +1675,11 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) } } - if (Move.Cancels != null && Move.Cancels.Length > 0) + if (move.Cancels != null && move.Cancels.Length > 0) { Common.WriteInt32ToPosition(outFile, type3TickOffsetAddress, (int)(outFile.BaseStream.Position - (type3TickOffsetAddress - 4))); - foreach (var type3 in Move.Cancels) + foreach (var type3 in move.Cancels) { outFile.Write(type3.TickStart); outFile.Write(type3.TickEnd); @@ -1678,7 +1687,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) Common.WriteInt32ToPosition(outFile, type3TickOffsetAddress + 4, (int)(outFile.BaseStream.Position - (type3TickOffsetAddress - 4))); - foreach (var type3 in Move.Cancels) + foreach (var type3 in move.Cancels) { outFile.Write(type3.CancelList); outFile.Write(type3.Type); @@ -1691,7 +1700,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) //TheBACunknownoffsetthingie Common.WriteInt32ToPosition(outFile, type3TickOffsetAddress + 8, (int)(outFile.BaseStream.Position - (type3TickOffsetAddress - 4))); - foreach (var type3 in Move.Cancels) + foreach (var type3 in move.Cancels) { outFile.Write(type3.BACVERint1); outFile.Write(type3.BACVERint2); @@ -1704,7 +1713,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) } } - if (Move.Others != null && Move.Others.Length > 0) + if (move.Others != null && move.Others.Length > 0) { List type4Offsets = new List(); List IntOffsets = new List(); @@ -1712,7 +1721,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) Common.WriteInt32ToPosition(outFile, type4TickOffsetAddress, (int)(outFile.BaseStream.Position - (type4TickOffsetAddress - 4))); - foreach (var type4 in Move.Others) + foreach (var type4 in move.Others) { outFile.Write(type4.TickStart); outFile.Write(type4.TickEnd); @@ -1720,7 +1729,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) Common.WriteInt32ToPosition(outFile, type4TickOffsetAddress + 4, (int)(outFile.BaseStream.Position - (type4TickOffsetAddress - 4))); - foreach (var type4 in Move.Others) + foreach (var type4 in move.Others) { if (type4.Ints.Length != 0) { @@ -1736,7 +1745,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) outFile.Write(0); } - foreach (var type4 in Move.Others) + foreach (var type4 in move.Others) { if (type4.Ints.Length != 0) { @@ -1760,7 +1769,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) //TheBACunknownoffsetthingie Common.WriteInt32ToPosition(outFile, type4TickOffsetAddress + 8, (int)(outFile.BaseStream.Position - (type4TickOffsetAddress - 4))); - foreach (var type4 in Move.Others) + foreach (var type4 in move.Others) { outFile.Write(type4.BACVERint1); outFile.Write(type4.BACVERint2); @@ -1773,11 +1782,11 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) } } - if (Move.Hitboxes != null && Move.Hitboxes.Length > 0) + if (move.Hitboxes != null && move.Hitboxes.Length > 0) { Common.WriteInt32ToPosition(outFile, HitboxTickOffsetAddress, (int)(outFile.BaseStream.Position - (HitboxTickOffsetAddress - 4))); - foreach (var Hitbox in Move.Hitboxes) + foreach (var Hitbox in move.Hitboxes) { outFile.Write(Hitbox.TickStart); outFile.Write(Hitbox.TickEnd); @@ -1785,7 +1794,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) Common.WriteInt32ToPosition(outFile, HitboxTickOffsetAddress + 4, (int)(outFile.BaseStream.Position - (HitboxTickOffsetAddress - 4))); - foreach (var Hitbox in Move.Hitboxes) + foreach (var Hitbox in move.Hitboxes) { outFile.Write(Hitbox.X); outFile.Write(Hitbox.Y); @@ -1831,7 +1840,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) //TheBACunknownoffsetthingie Common.WriteInt32ToPosition(outFile, HitboxTickOffsetAddress + 8, (int)(outFile.BaseStream.Position - (HitboxTickOffsetAddress - 4))); - foreach (var Hitbox in Move.Hitboxes) + foreach (var Hitbox in move.Hitboxes) { outFile.Write(Hitbox.BACVERint1); outFile.Write(Hitbox.BACVERint2); @@ -1844,11 +1853,11 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) } } - if (Move.Hurtboxes != null && Move.Hurtboxes.Length > 0) + if (move.Hurtboxes != null && move.Hurtboxes.Length > 0) { Common.WriteInt32ToPosition(outFile, HurtboxTickOffsetAddress, (int)(outFile.BaseStream.Position - (HurtboxTickOffsetAddress - 4))); - foreach (var Hurtbox in Move.Hurtboxes) + foreach (var Hurtbox in move.Hurtboxes) { outFile.Write(Hurtbox.TickStart); outFile.Write(Hurtbox.TickEnd); @@ -1856,7 +1865,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) Common.WriteInt32ToPosition(outFile, HurtboxTickOffsetAddress + 4, (int)(outFile.BaseStream.Position - (HurtboxTickOffsetAddress - 4))); - foreach (var Hurtbox in Move.Hurtboxes) + foreach (var Hurtbox in move.Hurtboxes) { outFile.Write(Hurtbox.X); outFile.Write(Hurtbox.Y); @@ -1905,7 +1914,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) Common.WriteInt32ToPosition(outFile, HurtboxTickOffsetAddress + 8, (int)(outFile.BaseStream.Position - (HurtboxTickOffsetAddress - 4))); - foreach (var Hurtbox in Move.Hurtboxes) + foreach (var Hurtbox in move.Hurtboxes) { outFile.Write(Hurtbox.BACVERint1); outFile.Write(Hurtbox.BACVERint2); @@ -1918,11 +1927,11 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) } } - if (Move.PhysicsBoxes != null && Move.PhysicsBoxes.Length > 0) + if (move.PhysicsBoxes != null && move.PhysicsBoxes.Length > 0) { Common.WriteInt32ToPosition(outFile, type7TickOffsetAddress, (int)(outFile.BaseStream.Position - (type7TickOffsetAddress - 4))); - foreach (var type7 in Move.PhysicsBoxes) + foreach (var type7 in move.PhysicsBoxes) { outFile.Write(type7.TickStart); outFile.Write(type7.TickEnd); @@ -1930,7 +1939,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) Common.WriteInt32ToPosition(outFile, type7TickOffsetAddress + 4, (int)(outFile.BaseStream.Position - (type7TickOffsetAddress - 4))); - foreach (var type7 in Move.PhysicsBoxes) + foreach (var type7 in move.PhysicsBoxes) { outFile.Write(type7.X); outFile.Write(type7.Y); @@ -1955,7 +1964,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) //TheBACunknownoffsetthingie Common.WriteInt32ToPosition(outFile, type7TickOffsetAddress + 8, (int)(outFile.BaseStream.Position - (type7TickOffsetAddress - 4))); - foreach (var type7 in Move.PhysicsBoxes) + foreach (var type7 in move.PhysicsBoxes) { outFile.Write(type7.BACVERint1); outFile.Write(type7.BACVERint2); @@ -1968,11 +1977,11 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) } } - if (Move.Animations != null && Move.Animations.Length > 0) + if (move.Animations != null && move.Animations.Length > 0) { Common.WriteInt32ToPosition(outFile, type8TickOffsetAddress, (int)(outFile.BaseStream.Position - (type8TickOffsetAddress - 4))); - foreach (var type8 in Move.Animations) + foreach (var type8 in move.Animations) { outFile.Write(type8.TickStart); outFile.Write(type8.TickEnd); @@ -1980,7 +1989,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) Common.WriteInt32ToPosition(outFile, type8TickOffsetAddress + 4, (int)(outFile.BaseStream.Position - (type8TickOffsetAddress - 4))); - foreach (var type8 in Move.Animations) + foreach (var type8 in move.Animations) { outFile.Write(type8.Index); outFile.Write((short)type8.Type); @@ -1998,7 +2007,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) Common.WriteInt32ToPosition(outFile, type8TickOffsetAddress + 8, (int)(outFile.BaseStream.Position - (type8TickOffsetAddress - 4))); - foreach (var type8 in Move.Animations) + foreach (var type8 in move.Animations) { outFile.Write(type8.BACVERint1); outFile.Write(type8.BACVERint2); @@ -2011,11 +2020,11 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) } } - if (Move.Type9s != null && Move.Type9s.Length > 0) + if (move.Type9s != null && move.Type9s.Length > 0) { Common.WriteInt32ToPosition(outFile, type9TickOffsetAddress, (int)(outFile.BaseStream.Position - (type9TickOffsetAddress - 4))); - foreach (var type9 in Move.Type9s) + foreach (var type9 in move.Type9s) { outFile.Write(type9.TickStart); outFile.Write(type9.TickEnd); @@ -2023,7 +2032,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) Common.WriteInt32ToPosition(outFile, type9TickOffsetAddress + 4, (int)(outFile.BaseStream.Position - (type9TickOffsetAddress - 4))); - foreach (var type9 in Move.Type9s) + foreach (var type9 in move.Type9s) { outFile.Write(type9.Unknown1); outFile.Write(type9.Unknown2); @@ -2037,7 +2046,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) //TheBACunknownoffsetthingie Common.WriteInt32ToPosition(outFile, type9TickOffsetAddress + 8, (int)(outFile.BaseStream.Position - (type9TickOffsetAddress - 4))); - foreach (var type9 in Move.Type9s) + foreach (var type9 in move.Type9s) { outFile.Write(type9.BACVERint1); outFile.Write(type9.BACVERint2); @@ -2050,11 +2059,11 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) } } - if (Move.SoundEffects != null && Move.SoundEffects.Length > 0) + if (move.SoundEffects != null && move.SoundEffects.Length > 0) { Common.WriteInt32ToPosition(outFile, type10TickOffsetAddress, (int)(outFile.BaseStream.Position - (type10TickOffsetAddress - 4))); - foreach (var type10 in Move.SoundEffects) + foreach (var type10 in move.SoundEffects) { outFile.Write(type10.TickStart); outFile.Write(type10.TickEnd); @@ -2062,7 +2071,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) Common.WriteInt32ToPosition(outFile, type10TickOffsetAddress + 4, (int)(outFile.BaseStream.Position - (type10TickOffsetAddress - 4))); - foreach (var type10 in Move.SoundEffects) + foreach (var type10 in move.SoundEffects) { outFile.Write(type10.Unknown1); outFile.Write(type10.Unknown2); @@ -2080,7 +2089,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) //TheBACunknownoffsetthingie Common.WriteInt32ToPosition(outFile, type10TickOffsetAddress + 8, (int)(outFile.BaseStream.Position - (type10TickOffsetAddress - 4))); - foreach (var type10 in Move.SoundEffects) + foreach (var type10 in move.SoundEffects) { outFile.Write(type10.BACVERint1); outFile.Write(type10.BACVERint2); @@ -2093,11 +2102,11 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) } } - if (Move.VisualEffects != null && Move.VisualEffects.Length > 0) + if (move.VisualEffects != null && move.VisualEffects.Length > 0) { Common.WriteInt32ToPosition(outFile, type11TickOffsetAddress, (int)(outFile.BaseStream.Position - (type11TickOffsetAddress - 4))); - foreach (var type11 in Move.VisualEffects) + foreach (var type11 in move.VisualEffects) { outFile.Write(type11.TickStart); outFile.Write(type11.TickEnd); @@ -2105,13 +2114,13 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) Common.WriteInt32ToPosition(outFile, type11TickOffsetAddress + 4, (int)(outFile.BaseStream.Position - (type11TickOffsetAddress - 4))); - foreach (var type11 in Move.VisualEffects) + foreach (var type11 in move.VisualEffects) { outFile.Write(type11.Unknown1); outFile.Write(type11.Unknown2); outFile.Write(type11.Unknown3); - outFile.Write(type11.Type); + outFile.Write(type11.EffectId); outFile.Write(type11.Unknown5); outFile.Write(type11.AttachPoint); @@ -2131,7 +2140,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) //TheBACunknownoffsetthingie Common.WriteInt32ToPosition(outFile, type11TickOffsetAddress + 8, (int)(outFile.BaseStream.Position - (type11TickOffsetAddress - 4))); - foreach (var type11 in Move.VisualEffects) + foreach (var type11 in move.VisualEffects) { outFile.Write(type11.BACVERint1); outFile.Write(type11.BACVERint2); @@ -2144,11 +2153,11 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) } } - if (Move.Positions != null && Move.Positions.Length > 0) + if (move.Positions != null && move.Positions.Length > 0) { Common.WriteInt32ToPosition(outFile, PositionTickOffsetAddress, (int)(outFile.BaseStream.Position - (PositionTickOffsetAddress - 4))); - foreach (var Position in Move.Positions) + foreach (var Position in move.Positions) { outFile.Write(Position.TickStart); outFile.Write(Position.TickEnd); @@ -2156,7 +2165,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) Common.WriteInt32ToPosition(outFile, PositionTickOffsetAddress + 4, (int)(outFile.BaseStream.Position - (PositionTickOffsetAddress - 4))); - foreach (var Position in Move.Positions) + foreach (var Position in move.Positions) { outFile.Write(Position.Movement); outFile.Write(Position.Flag); @@ -2169,7 +2178,7 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) //TheBACunknownoffsetthingie Common.WriteInt32ToPosition(outFile, PositionTickOffsetAddress + 8, (int)(outFile.BaseStream.Position - (PositionTickOffsetAddress - 4))); - foreach (var Position in Move.Positions) + foreach (var Position in move.Positions) { outFile.Write(Position.BACVERint1); outFile.Write(Position.BACVERint2); @@ -2251,21 +2260,18 @@ public static void ToUassetFile(BACFile file, string OutPutFileName) Debug.WriteLine("Done with HitboxEffects! Now doing Names... CurrentPos: " + outFile.BaseStream.Position.ToString("X")); for (int i = 0; i < file.MoveLists.Length; i++) - { + { List NamePositions = new List(); for (int j = 0; j < file.MoveLists[i].Moves.Length; j++) - { - if (file.MoveLists[i].Moves[j] == null) - { - continue; - } - + { + if (file.MoveLists[i].Moves[j] == null) continue; + NamePositions.Add(outFile.BaseStream.Position); outFile.Write(file.MoveLists[i].Moves[j].Name.ToCharArray()); - outFile.Write((byte)0x00); - } + outFile.Write((byte)0x00); + } for (int k = 0; k < file.MoveLists[i].Moves.Length; k++) { @@ -2408,6 +2414,50 @@ private static void WriteUnknownBytesDependingOnBACVER(dynamic type, int BACVER, } } + public class ForceEnumConverter : JsonConverter + { + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + serializer.Serialize(writer, value); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + try + { + switch (reader.TokenType) + { + case JsonToken.String: + + Debug.WriteLine($"\"{reader.Value}\" of type \"{reader.TokenType}\" found. Attempting conversion..."); + + var enumText = reader.Value.ToString(); + var convertedStr = (int)Enum.Parse(typeof(ForceEnum), enumText); + + Debug.WriteLine($"\tConverted \"{reader.Value}\" to {convertedStr}"); + + return convertedStr; + + case JsonToken.Integer: + var convertedInt = Convert.ChangeType(reader.Value, objectType); + + return convertedInt; + } + } + catch (Exception ex) + { + throw new JsonSerializationException($"Error converting value {reader.Value} to type '{objectType}'.", ex); + } + + throw new JsonReaderException($"{nameof(Force.Flag)} was not of type {JTokenType.String} nor {JTokenType.Integer}!"); + } + + public override bool CanConvert(Type objectType) + { + return objectType == typeof(ForceEnum); + } + } + public class BACFile { public MoveList[] MoveLists { get; set; } @@ -2432,12 +2482,24 @@ public class Move public int TotalTicks { get; set; } public int ReturnToOriginalPosition { get; set; } - public float Slide { get; set; } - public float unk3 { get; set; } - public float unk4 { get; set; } - public float unk5 { get; set; } - public float unk6 { get; set; } - public float unk7 { get; set; } + + public float XSpeedMultiplier { get; set; } + private float Slide { set => XSpeedMultiplier = value; } + + public float YSpeedMultiplier { get; set; } + private float unk3 { set => YSpeedMultiplier = value; } + + public float ZSpeedMultiplier { get; set; } + private float unk4 { set => ZSpeedMultiplier = value; } + + public float XAcceleration { get; set; } + public float YAcceleration { get; set; } + public float ZAcceleration { get; set; } + + private float unk5 { set => XAcceleration = value; } + private float unk6 { set => YAcceleration = value; } + private float unk7 { set => ZAcceleration = value; } + public int Flag { get; set; } public int unk9 { get; set; } @@ -2447,20 +2509,23 @@ public class Move public int HeaderSize { get; set; } - public short Unknown12 { get; set; } - public short Unknown13 { get; set; } + public short Unknown12 { get; set; } // Projectile GFX 1 + public short Unknown13 { get; set; } // Projectile GFX 2 - public short Unknown14 { get; set; } - public short Unknown15 { get; set; } - public short Unknown16 { get; set; } - public short Unknown17 { get; set; } - public float Unknown18 { get; set; } - public short Unknown19 { get; set; } + public short Unknown14 { get; set; } // ??? - public short Unknown20 { get; set; } + public short Unknown15 { get; set; } // Projectile Hit Ground GFX 1 + public short Unknown16 { get; set; } // Projectile Hit Ground GFX 2 - public short Unknown21 { get; set; } - public short Unknown22 { get; set; } + public short Unknown17 { get; set; } // ??? + + public float Unknown18 { get; set; } // Projectile Size + public short Unknown19 { get; set; } // Projectile Hit Ground SFX + + public short Unknown20 { get; set; } // ??? + + public short Unknown21 { get; set; } // ??? + public short Unknown22 { get; set; } // ??? public AutoCancel[] AutoCancels { get; set; } @@ -2579,11 +2644,14 @@ public class AutoCancel public short MoveIndex { get; set; } public string MoveIndexName { get; set; } - public short Unknown1 { get; set; } + public short ScriptStartTime { get; set; } + private short Unknown1 { set => ScriptStartTime = value; } + public short NumberOfInts { get; set; } - public int Unknown2 { get; set; } - public int Unknown3 { get; set; } + public int Unknown2 { get; set; } // Something to do with SkillID + public int Unknown3 { get; set; } // if Unknown2 is 24, this value is the Skill ID used for trials + public int Unknown4 { get; set; } public int Offset { get; set; } @@ -2620,7 +2688,9 @@ public class Force public int BACVERint4 { get; set; } public float Amount { get; set; } - public ForceEnum Flag { get; set; } + [JsonProperty("Flag")] + [JsonConverter(typeof(ForceEnumConverter))] + public int Flag { get; set; } } public enum ForceEnum @@ -2832,7 +2902,10 @@ public class VisualEffect public short Unknown1 { get; set; } public short Unknown2 { get; set; } public short Unknown3 { get; set; } - public short Type { get; set; } + + public short EffectId { get; set; } + private short Type { set => EffectId = value; } + public short Unknown5 { get; set; } public short AttachPoint { get; set; } diff --git a/MoveLib/BCM.cs b/MoveLib/BCM.cs index d0fc56d..87c44ee 100644 --- a/MoveLib/BCM.cs +++ b/MoveLib/BCM.cs @@ -1,1050 +1,1083 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Text; -using Newtonsoft.Json; - -namespace MoveLib.BCM -{ - public static class BCM - { - public static void BcmToJson(string inFile, string outFile) - { - BCMFile bcm; - - try - { - bcm = FromUassetFile(inFile); - } - catch (Exception ex) - { - Console.WriteLine("Something went wrong. Couldn't create JSON.\n" + ex.Message + " - " + ex.Data); - throw; - } - - Formatting format = Formatting.Indented; - - var json = JsonConvert.SerializeObject(bcm, format, new Newtonsoft.Json.Converters.StringEnumConverter()); - - File.WriteAllText(outFile, json); - } - - public static bool JsonToBcm(string inFile, string outFile) - { - BCMFile bcm; - - try - { - bcm = JsonConvert.DeserializeObject(File.ReadAllText(inFile)); - } - catch (Exception ex) - { - Console.WriteLine("Error parsing JSON: " + ex.Message + " - " + ex.Data); - return false; - } - - try - { - ToUassetFile(bcm, outFile); - } - catch (Exception ex) - { - Console.WriteLine("Something went wrong. Couldn't create BCM.\n" + ex.Message + " - " + ex.Data); - return false; - } - - return true; - } - - public static BCMFile FromUassetFile(string fileName) - { - byte[] fileBytes = File.ReadAllBytes(fileName); - - byte[] UassetHeaderBytes = Common.GetUassetHeader(fileBytes); - fileBytes = Common.RemoveUassetHeader(fileBytes); - - List MoveList = new List(); - List CancelLists = new List(); - List InputList = new List(); - List ChargeList = new List(); - - Debug.WriteLine("READING"); - using (var ms = new MemoryStream(fileBytes)) - using (var inFile = new BinaryReader(ms)) - { - string bcmString = new string(inFile.ReadChars(4)); - - if (bcmString != "#BCM") - { - throw new Exception("Error: Not a valid KWBCM file!"); - } - - Debug.WriteLine(bcmString); - - inFile.BaseStream.Seek(0xA, SeekOrigin.Begin); - short BCMVER = inFile.ReadInt16(); - Debug.WriteLine("BCMVER: " + BCMVER); - short ChargeCount = inFile.ReadInt16(); - Debug.WriteLine("ChargeCount: " + ChargeCount); - short InputCount = inFile.ReadInt16(); - Debug.WriteLine("InputCount: " + InputCount); - short MoveCount = inFile.ReadInt16(); - Debug.WriteLine("Movecount: " + MoveCount); - short CancelCount = inFile.ReadInt16(); //last cancel index - Debug.WriteLine("Cancelcount: " + CancelCount); - - int startOfCharges = inFile.ReadInt32(); - int startOfInputs = inFile.ReadInt32(); - int startOfMoves = inFile.ReadInt32(); - int startOfNames = inFile.ReadInt32(); - int startOfCancelLists = inFile.ReadInt32(); - Debug.WriteLine("StartOfCharges: " + startOfCharges); - Debug.WriteLine("StartOfInputs: " + startOfInputs); - - Debug.WriteLine("StartOfMoves: " + startOfMoves); - Debug.WriteLine("StartOfNames: " + startOfNames); - - Debug.WriteLine("StartOfCancelLists: " + startOfCancelLists); - - Debug.WriteLine("Current pos: " + inFile.BaseStream.Position.ToString("X")); - Debug.WriteLine("\n\n"); - - inFile.BaseStream.Seek(startOfCharges, SeekOrigin.Begin); - - List ChargeAddresses = new List(); - - for (int i = 0; i < ChargeCount; i++) - { - ChargeAddresses.Add(inFile.ReadInt32()); - } - - for (int i = 0; i < ChargeAddresses.Count; i++) - { - Charge thisCharge = new Charge(); - int thisChargeAddress = ChargeAddresses[i]; - inFile.BaseStream.Seek(thisChargeAddress, SeekOrigin.Begin); - Debug.WriteLine("ChargeAddress: " + thisChargeAddress.ToString("X")); - - thisCharge.ChargeDirection = inFile.ReadInt16(); - thisCharge.Unknown1 = inFile.ReadInt16(); - thisCharge.Unknown2 = inFile.ReadInt16(); - thisCharge.Unknown3 = inFile.ReadInt16(); - thisCharge.ChargeFrames = inFile.ReadInt16(); - thisCharge.Flags = inFile.ReadInt16(); - thisCharge.ChargeIndex = inFile.ReadInt16(); - thisCharge.Unknown4 = inFile.ReadInt16(); - - thisCharge.Index = i; - ChargeList.Add(thisCharge); - } - - inFile.BaseStream.Seek(startOfInputs, SeekOrigin.Begin); - - List InputAddresses = new List(); - - for (int i = 0; i < InputCount; i++) - { - InputAddresses.Add(inFile.ReadInt32()); - } - - for (int i = 0; i < InputAddresses.Count; i++) - { - Input thisInput = new Input(); - int thisInputAddress = InputAddresses[i]; - inFile.BaseStream.Seek(thisInputAddress, SeekOrigin.Begin); - Debug.WriteLine("InputAddress: " + thisInputAddress.ToString("X")); - - List moveEntryOffsets = new List(); - - moveEntryOffsets.Add(inFile.ReadInt32()); - moveEntryOffsets.Add(inFile.ReadInt32()); - moveEntryOffsets.Add(inFile.ReadInt32()); - moveEntryOffsets.Add(inFile.ReadInt32()); - - var entries = new List(); - - foreach (var entryOffset in moveEntryOffsets) - { - if (entryOffset == 0) - { - entries.Add(new InputEntry()); - continue; - } - - inFile.BaseStream.Seek(entryOffset + thisInputAddress, SeekOrigin.Begin); - var partCount = inFile.ReadInt32(); - - InputEntry thisInputEntry = new InputEntry(); - List parts = new List(); - - for (int j = 0; j < partCount; j++) - { - InputPart thisPart = new InputPart() - { - InputType = (InputType)inFile.ReadInt16(), - Buffer = inFile.ReadInt16(), - InputDirection = (InputDirection)inFile.ReadInt16(), - Unknown1 = inFile.ReadInt16(), - Unknown2 = inFile.ReadInt16(), - Unknown3 = inFile.ReadInt16(), - Unknown4 = inFile.ReadInt16(), - Unknown5 = inFile.ReadInt16(), - }; - - parts.Add(thisPart); - } - - for (int j = 0; j < 16-partCount; j++) //There can be up to 16 parts, but even if they are empty they are still there, only filled with 0x00 - { - var unused = inFile.ReadBytes(16); - foreach (var b in unused) - { - if (b != 0) - { - Debug.WriteLine("Read unexpected byte in what was thought to be an empty part of an input."); - } - } - } - - thisInputEntry.InputParts = parts.ToArray(); - entries.Add(thisInputEntry); - } - - thisInput.InputEntries = entries.ToArray(); - - thisInput.Index = i; - InputList.Add(thisInput); - Debug.WriteLine("Created input with index: " + i); - } - - for (int i = 0; i < MoveCount*4; i+=0x4) - { - long thisMovePosition = startOfMoves + i; - long thisNamePosition = startOfNames + i; - - inFile.BaseStream.Seek(thisNamePosition, SeekOrigin.Begin); - int NameAddress = inFile.ReadInt32(); - string Name = GetName(NameAddress, inFile); - - inFile.BaseStream.Seek(thisMovePosition, SeekOrigin.Begin); - int offset = inFile.ReadInt32(); - Debug.WriteLine("Adding move at: " + offset.ToString("X")); - - inFile.BaseStream.Seek(offset, SeekOrigin.Begin); - - short input = inFile.ReadInt16(); - short inputFlags = inFile.ReadInt16(); - int restrict = inFile.ReadInt32(); - int restrict2 = inFile.ReadInt32(); - float restrictDistance = inFile.ReadSingle(); - int unknown4 = (BCMVER > 0) ? inFile.ReadInt32() : 0; - int projectileRestrict = inFile.ReadInt32(); - int unknown6 = inFile.ReadInt16(); - int unknown7 = inFile.ReadInt16(); - short unknown8 = inFile.ReadInt16(); - short unknown9 = inFile.ReadInt16(); - - short MeterRequirement = inFile.ReadInt16(); - short MeterUsed = inFile.ReadInt16(); - short unknown10 = inFile.ReadInt16(); - short unknown11 = inFile.ReadInt16(); - int VtriggerRequirement = inFile.ReadInt16(); - int VtriggerUsed = inFile.ReadInt16(); - int Unknown16 = inFile.ReadInt32(); - int InputMotionIndex = inFile.ReadInt16(); - int ScriptIndex = inFile.ReadInt16(); - - Move thisMove = new Move() - { - Name = Name, - Index = (short)(i == 0 ? 0 : (i / 4)), - Input = input, - InputFlags = inputFlags, - PositionRestriction = restrict, - Unknown3 = restrict2, - RestrictionDistance = restrictDistance, - Unknown4 = unknown4, - ProjectileLimit = projectileRestrict, - Unknown6 = (short)unknown6, - Unknown7 = (short)unknown7, - Unknown8 = unknown8, - Unknown9 = unknown9, - Unknown10 = unknown10, - Unknown11 = unknown11, - MeterRequirement = (short)MeterRequirement, - MeterUsed = (short)MeterUsed, - VtriggerRequirement = (short)VtriggerRequirement, - VtriggerUsed = (short)VtriggerUsed, - Unknown16 = Unknown16, - InputMotionIndex = (short)InputMotionIndex, - ScriptIndex = (short)ScriptIndex, - Unknown17 = inFile.ReadInt32(), - Unknown18 = inFile.ReadInt32(), - Unknown19 = (BCMVER == 0) ? inFile.ReadInt32() : 0, - Unknown20 = inFile.ReadSingle(), - Unknown21 = inFile.ReadSingle(), - Unknown22 = inFile.ReadInt32(), - Unknown23 = inFile.ReadInt32(), - Unknown24 = inFile.ReadInt32(), - Unknown25 = inFile.ReadInt32(), - Unknown26 = inFile.ReadInt16(), - NormalOrVtrigger = inFile.ReadInt16(), - Unknown28 = inFile.ReadInt32() - }; - - if (thisMove.InputMotionIndex != -1) //Just for debugging... - { - InputList.Where(x => x.Index == thisMove.InputMotionIndex).ToList()[0].Name += thisMove.Name + ", "; - } - - MoveList.Add(thisMove); - - Debug.WriteLine("MOVE: " + "Index: " + (i == 0 ? 0 : (i/4)) + - "\nName: " + Name + - "\nOffset: " + offset.ToString("X") + - "\nNameOffet: " + NameAddress.ToString("X") + - "\nInput: " + input + - "\nflags: " + inputFlags - + "\nRestrict: " + restrict - + "\nRestrict2: " + restrict2 - + "\nRestrictDistance: " + restrictDistance - + "\nUnknown4: " + unknown4 - + "\nProjectileRestrict: " + projectileRestrict - + "\nUnknown6: " + unknown6 - + "\nUnknown7: " + unknown7 - + "\nUnknown8: " + unknown8 - + "\nUnknown9: " + unknown9 - + "\nUnknown10: " + unknown10 - + "\nUnknown11: " + unknown11 - + "\nMeterReq: " + MeterRequirement - + "\nMeterUsed: " + MeterUsed - + "\nVtriggerReq: " + VtriggerRequirement - + "\nVtriggerUsed: " + VtriggerUsed - + "\nUnknown16: " + Unknown16 - + "\nInputMotionIndex: " + InputMotionIndex - + "\nScriptIndex: " + ScriptIndex - +"\nUnknown17: " + thisMove.Unknown17 - + "\nUnknown18: " + thisMove.Unknown18 - + "\nUnknown19: " + thisMove.Unknown19 - + "\nUnknown20: " + thisMove.Unknown20 - + "\nUnknown21: " + thisMove.Unknown21 - + "\nUnknown22: " + thisMove.Unknown22 - + "\nUnknown23: " + thisMove.Unknown23 - + "\nUnknown24: " + thisMove.Unknown24 - + "\nUnknown25: " + thisMove.Unknown25 - + "\nUnknown26: " + thisMove.Unknown26 - + "\nUnknown27: " + thisMove.NormalOrVtrigger - + "\nUnknown28: " + thisMove.Unknown28 - + "\n\n"); - } - - inFile.BaseStream.Seek(startOfCancelLists, SeekOrigin.Begin); - List CancelAddresses = new List(); - for (int i = 0; i < CancelCount; i++) - { - int thisCancelAddress = inFile.ReadInt32(); - Debug.WriteLine("Cancel " + (i) + ": " + thisCancelAddress.ToString("X")); - CancelAddresses.Add(thisCancelAddress); - } - - for (int i = 0; i < CancelAddresses.Count; i++) - { - CancelList thisCancelList = new CancelList(); - int thisAddress = CancelAddresses[i]; - - if (thisAddress == 0) - { - CancelLists.Add(new CancelList()); - continue; - } - - inFile.BaseStream.Seek(thisAddress, SeekOrigin.Begin); - - thisCancelList.Unknown1 = inFile.ReadInt32(); - int MovesInList = inFile.ReadInt32(); - int LastIndex = inFile.ReadInt32(); //last move index in list -1... - int StartOffset = inFile.ReadInt32(); //offset until real list FROM START OF CANCEL!!! - int StartOfCancelInts = inFile.ReadInt32(); - int StartOfCancelBytes = inFile.ReadInt32(); - - Debug.WriteLine("ThisCancelAddress: " + thisAddress.ToString("X")); - Debug.WriteLine("Cancel {6}:\nCU1: {0}\nMovesInList: {1}\nNumberOfSomethingInList: {2}\nStartOffset: {3}\nCU5: {4}\nEndOffset: {5}\n", thisCancelList.Unknown1, MovesInList, LastIndex, StartOffset.ToString("X"), StartOfCancelInts.ToString("X"), StartOfCancelBytes.ToString("X"), i); - - inFile.BaseStream.Seek(thisAddress + StartOffset, SeekOrigin.Begin); - Debug.WriteLine("ListAddress: " + (thisAddress + StartOffset).ToString("X")); - Debug.WriteLine("ListAddressEnd: " + (thisAddress + StartOfCancelBytes).ToString("X")); - - List cancels = new List(); - thisCancelList.Index = i; - - for (int j = 0; j < MovesInList; j++) - { - int thisMoveInList = inFile.ReadInt16(); - Debug.WriteLine("Move: " + thisMoveInList); - - Move cancelMove = MoveList.Where(x => x.Index == thisMoveInList).ToList()[0]; - - Cancel thisCancel = new Cancel(); - thisCancel.Index = (short)thisMoveInList; - thisCancel.Name = cancelMove.Name; - thisCancel.ScriptIndex = cancelMove.ScriptIndex; - - cancels.Add(thisCancel); - } - - thisCancelList.Cancels = cancels.ToArray(); - - //All lists should have Moves divisible by 2. If it doesn't, simply add an empty one (0x00, 0x00) - if (MovesInList % 2 != 0) - { - Debug.WriteLine("READING EMPTY MOVE"); - inFile.ReadInt16(); - } - - if (StartOfCancelInts != 0) - { - Debug.WriteLine("We got something!!!" + inFile.BaseStream.Position.ToString("X") + " - Should be: " + (thisAddress + StartOfCancelInts).ToString("X")); - Debug.WriteLine(((thisAddress + StartOfCancelBytes) - (thisAddress + StartOfCancelInts)) / MovesInList); - - for (int j = 0; j < MovesInList; j++) - { - int value1 = inFile.ReadInt32(); - int value2 = inFile.ReadInt32(); - - thisCancelList.Cancels[j].CancelInts = new CancelInts() - { - Unknown1 = value1, - Unknown2 = value2 - }; - } - } - - Debug.WriteLine("Position is " + inFile.BaseStream.Position.ToString("X") + " - Should be: " + (thisAddress + StartOfCancelBytes).ToString("X")); - - if (inFile.BaseStream.Position != thisAddress + StartOfCancelBytes) //NOT a good idea - { - Debug.WriteLine("We are not where we're supposed to be, reading bytes until we are..."); - - while (inFile.BaseStream.Position != thisAddress + StartOfCancelBytes) - { - Debug.WriteLine(inFile.ReadByte()); - } - - Debug.WriteLine("Position is " + inFile.BaseStream.Position.ToString("X") + " - Should be: " + (thisAddress + StartOfCancelBytes).ToString("X")); - } - - for (int j = 0; j < LastIndex; j++) - { - inFile.BaseStream.Seek((thisAddress + StartOfCancelBytes) + (j * 4), SeekOrigin.Begin); - - var offset = inFile.ReadInt32(); - - if (offset == 0) - { - continue; - } - - Debug.WriteLine("SomethingElseInCancelList(offsets?): " + offset.ToString("X") + " Pos: " + (inFile.BaseStream.Position - 4).ToString("X") + " - Index: " + j + " added offset:" + (offset+thisAddress).ToString("X")); - - var address = offset + thisAddress; - - inFile.BaseStream.Seek(address, SeekOrigin.Begin); - - var cancelBytesBelongsTo = thisCancelList.Cancels.First(x => x.Index == j); - - cancelBytesBelongsTo.UnknownBytes = inFile.ReadBytes(0x24); - } - - CancelLists.Add(thisCancelList); - Debug.WriteLine("\n"); - } - - foreach (var cancelList in CancelLists) - { - if (cancelList.Cancels == null) - { - continue; - } - - foreach (var cancel in cancelList.Cancels) - { - if (cancel == null) - { - continue; - } - Debug.WriteLine("Cancel: " + cancel.Index + " ScriptIndex:" + cancel.ScriptIndex); - foreach (var unknownByte in cancel.UnknownBytes) - { - Debug.Write(unknownByte.ToString("X") + " "); - } - Debug.WriteLine(""); - } - } - - Debug.WriteLine("\nCharges\n"); - - foreach (var charge in ChargeList) - { - Debug.WriteLine("CHARGE: " + charge.Index); - Debug.WriteLine("Dir: " + charge.ChargeDirection); - Debug.WriteLine("u1: " + charge.Unknown1); - Debug.WriteLine("u2: " + charge.Unknown2); - Debug.WriteLine("u3: " + charge.Unknown3); - Debug.WriteLine("ChargeFrames: " + charge.ChargeFrames); - Debug.WriteLine("Flags: " + charge.Flags); - Debug.WriteLine("CINDEX: " + charge.ChargeIndex); - Debug.WriteLine("u4: " + charge.Unknown4); - Debug.WriteLine("\n"); - } - - foreach (var input in InputList) - { - Debug.WriteLine("Input: " + input.Index); - Debug.WriteLine("Name: " + input.Name); - Debug.WriteLine("Entries: " + input.InputEntries.Length); - - WriteInputToDebug(input); - - Debug.WriteLine("\n"); - } - } - - Debug.WriteLine("Done"); - - BCMFile bcm = new BCMFile() - { - Inputs = InputList.ToArray(), - CancelLists = CancelLists.ToArray(), - Charges = ChargeList.ToArray(), - Moves = MoveList.ToArray(), - RawUassetHeaderDontTouch = UassetHeaderBytes - }; - - return bcm; - } - - private static void WriteInt32ToPosition(BinaryWriter outFile, long position, int Value) - { - long oldPosition = outFile.BaseStream.Position; - outFile.BaseStream.Seek(position, SeekOrigin.Begin); - outFile.Write(Value); - outFile.BaseStream.Seek(oldPosition, SeekOrigin.Begin); - } - - public static void ToUassetFile(BCMFile file, string fileName) - { - byte[] outPutFileBytes; - - using (var ms = new MemoryStream()) - { - using (var outFile = new BinaryWriter(ms)) - { - byte[] headerBytes = - { - 0x23, 0x42, 0x43, 0x4D, 0xFE, 0xFF, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - - outFile.Write(headerBytes); - - outFile.Write((short) file.Charges.Length); - outFile.Write((short) file.Inputs.Length); - outFile.Write((short) file.Moves.Length); - outFile.Write((short) file.CancelLists.Length); - - var StartOfStartOfChargeOffsets = outFile.BaseStream.Position; - outFile.Write(0); - - var StartOfStartOfInputOffsets = outFile.BaseStream.Position; - outFile.Write(0); - - var StartOfStartOfMoveOffsets = outFile.BaseStream.Position; - outFile.Write(0); - - var StartOfStartOfNameOffsets = outFile.BaseStream.Position; - outFile.Write(0); - - var StartOfStartOfCancelListOffsets = outFile.BaseStream.Position; - outFile.Write(0); - - outFile.Write(0); //Unused? - - var StartOfChargeOffsets = outFile.BaseStream.Position; - if (file.Charges.Length > 0) - { - WriteInt32ToPosition(outFile, StartOfStartOfChargeOffsets, (int) outFile.BaseStream.Position); - } - for (int i = 0; i < file.Charges.Length; i++) - { - outFile.Write(0); - } - - var StartOfInputOffsets = outFile.BaseStream.Position; - if (file.Inputs.Length > 0) - { - WriteInt32ToPosition(outFile, StartOfStartOfInputOffsets, (int)outFile.BaseStream.Position); - } - for (int i = 0; i < file.Inputs.Length; i++) - { - outFile.Write(0); - } - - var StartOfMoveOffsets = outFile.BaseStream.Position; - if (file.Moves.Length > 0) - { - WriteInt32ToPosition(outFile, StartOfStartOfMoveOffsets, (int)outFile.BaseStream.Position); - } - for (int i = 0; i < file.Moves.Length; i++) - { - outFile.Write(0); - } - - var StartOfNameOffsets = outFile.BaseStream.Position; - if (file.Moves.Length > 0) - { - WriteInt32ToPosition(outFile, StartOfStartOfNameOffsets, (int)outFile.BaseStream.Position); - } - for (int i = 0; i < file.Moves.Length; i++) - { - outFile.Write(0); - } - - var StartOfCancelListOffsets = outFile.BaseStream.Position; - if (file.CancelLists.Length > 0) - { - WriteInt32ToPosition(outFile, StartOfStartOfCancelListOffsets, (int)outFile.BaseStream.Position); - } - for (int i = 0; i < file.CancelLists.Length; i++) - { - outFile.Write(0); - } - - Debug.WriteLine("Done writing temp offsets, now at: " + outFile.BaseStream.Position.ToString("X")); - - for (int i = 0; i < file.Charges.Length; i++) - { - WriteInt32ToPosition(outFile, StartOfChargeOffsets + (i*4), (int)outFile.BaseStream.Position); - - outFile.Write(file.Charges[i].ChargeDirection); - outFile.Write(file.Charges[i].Unknown1); - outFile.Write(file.Charges[i].Unknown2); - outFile.Write(file.Charges[i].Unknown3); - outFile.Write(file.Charges[i].ChargeFrames); - outFile.Write(file.Charges[i].Flags); - outFile.Write(file.Charges[i].ChargeIndex); - outFile.Write(file.Charges[i].Unknown4); - } - - Debug.WriteLine("Done writing charges, now at: " + outFile.BaseStream.Position.ToString("X")); - - for (int i = 0; i < file.Inputs.Length; i++) - { - WriteInt32ToPosition(outFile, StartOfInputOffsets + (i * 4), (int)outFile.BaseStream.Position); - var entryOffsetPosition = outFile.BaseStream.Position; - - outFile.Write(0); - outFile.Write(0); - outFile.Write(0); - outFile.Write(0); - - for (int j = 0; j < file.Inputs[i].InputEntries.Length; j++) - { - if (file.Inputs[i].InputEntries[j].InputParts == null) - { - continue; - } - - WriteInt32ToPosition(outFile, entryOffsetPosition + (j*4), (int)(outFile.BaseStream.Position- entryOffsetPosition)); - - outFile.Write(file.Inputs[i].InputEntries[j].InputParts.Length); - - for (int k = 0; k < file.Inputs[i].InputEntries[j].InputParts.Length; k++) - { - outFile.Write((short)file.Inputs[i].InputEntries[j].InputParts[k].InputType); - outFile.Write(file.Inputs[i].InputEntries[j].InputParts[k].Buffer); - outFile.Write((short)file.Inputs[i].InputEntries[j].InputParts[k].InputDirection); - outFile.Write(file.Inputs[i].InputEntries[j].InputParts[k].Unknown1); - outFile.Write(file.Inputs[i].InputEntries[j].InputParts[k].Unknown2); - outFile.Write(file.Inputs[i].InputEntries[j].InputParts[k].Unknown3); - outFile.Write(file.Inputs[i].InputEntries[j].InputParts[k].Unknown4); - outFile.Write(file.Inputs[i].InputEntries[j].InputParts[k].Unknown5); - } - - for (int k = 0; k < 16 - file.Inputs[i].InputEntries[j].InputParts.Length; k++) - { - for (int l = 0; l < 16; l++) - { - outFile.Write((byte)0x00); - } - } - } - } - - Debug.WriteLine("Done writing Inputs, now at: " + outFile.BaseStream.Position.ToString("X")); - - for (int i = 0; i < file.Moves.Length; i++) - { - WriteInt32ToPosition(outFile,StartOfMoveOffsets + (i*4), (int)outFile.BaseStream.Position); - - outFile.Write(file.Moves[i].Input); - outFile.Write(file.Moves[i].InputFlags); - outFile.Write(file.Moves[i].PositionRestriction); - outFile.Write(file.Moves[i].Unknown3); - outFile.Write(file.Moves[i].RestrictionDistance); - outFile.Write(file.Moves[i].ProjectileLimit); - outFile.Write(file.Moves[i].Unknown6); - outFile.Write(file.Moves[i].Unknown7); - outFile.Write(file.Moves[i].Unknown8); - outFile.Write(file.Moves[i].Unknown9); - - outFile.Write(file.Moves[i].MeterRequirement); - outFile.Write(file.Moves[i].MeterUsed); - - outFile.Write(file.Moves[i].Unknown10); - outFile.Write(file.Moves[i].Unknown11); - - outFile.Write(file.Moves[i].VtriggerRequirement); - outFile.Write(file.Moves[i].VtriggerUsed); - - outFile.Write(file.Moves[i].Unknown16); - outFile.Write(file.Moves[i].InputMotionIndex); - outFile.Write(file.Moves[i].ScriptIndex); - - outFile.Write(file.Moves[i].Unknown17); - outFile.Write(file.Moves[i].Unknown18); - outFile.Write(file.Moves[i].Unknown19); - outFile.Write(file.Moves[i].Unknown20); - outFile.Write(file.Moves[i].Unknown21); - outFile.Write(file.Moves[i].Unknown22); - outFile.Write(file.Moves[i].Unknown23); - outFile.Write(file.Moves[i].Unknown24); - outFile.Write(file.Moves[i].Unknown25); - outFile.Write(file.Moves[i].Unknown26); - outFile.Write(file.Moves[i].NormalOrVtrigger); - outFile.Write(file.Moves[i].Unknown28); - } - - Debug.WriteLine("Done writing Moves, now at: " + outFile.BaseStream.Position.ToString("X")); - - List CancelListOffsets = new List(); - List StartOfCancelListsList = new List(); - - for (int i = 0; i < file.CancelLists.Length; i++) - { - StartOfCancelListsList.Add(outFile.BaseStream.Position); - if (file.CancelLists[i].Cancels == null) - { - WriteInt32ToPosition(outFile, StartOfCancelListOffsets + (i*4), 0); - CancelListOffsets.Add(-1); - continue; - } - - WriteInt32ToPosition(outFile, StartOfCancelListOffsets + (i*4), - (int) outFile.BaseStream.Position); - - outFile.Write(file.CancelLists[i].Unknown1); - outFile.Write(file.CancelLists[i].Cancels.Length); - outFile.Write(file.CancelLists[i].Cancels[file.CancelLists[i].Cancels.Length - 1].Index + 1); - - CancelListOffsets.Add(outFile.BaseStream.Position); - - outFile.Write(0); - outFile.Write(0); - outFile.Write(0); - } - - for (int i = 0; i < file.CancelLists.Length; i++) - { - if (file.CancelLists[i].Cancels == null) - { - continue; - } - - Debug.WriteLine("CancelListAtAddress: " + outFile.BaseStream.Position.ToString("X")); - if (CancelListOffsets[i] != -1) - { - WriteInt32ToPosition(outFile, CancelListOffsets[i], (int)(outFile.BaseStream.Position - StartOfCancelListsList[i])); - } - - for (int j = 0; j < file.CancelLists[i].Cancels.Length; j++) - { - outFile.Write(file.CancelLists[i].Cancels[j].Index); - } - - if (file.CancelLists[i].Cancels.Length%2 != 0) - { - Debug.WriteLine("Writing empty move: " + outFile.BaseStream.Position.ToString("X")); - outFile.Write((short)0); - } - - bool shouldWrite = false; - var CancelIntsPosition = outFile.BaseStream.Position; - - foreach (var cancel in file.CancelLists[i].Cancels) - { - if (cancel.CancelInts != null) - { - outFile.Write(cancel.CancelInts.Unknown1); - outFile.Write(cancel.CancelInts.Unknown2); - shouldWrite = true; - } - } - - if (shouldWrite) - { - if (CancelListOffsets[i] != -1) - { - WriteInt32ToPosition(outFile, CancelListOffsets[i] + 4, - (int) (CancelIntsPosition - StartOfCancelListsList[i])); - } - } - - Debug.WriteLine("Startofunknownbytes: " + outFile.BaseStream.Position.ToString("X")); - - if (CancelListOffsets[i] != -1) - { - WriteInt32ToPosition(outFile, CancelListOffsets[i]+8, (int)(outFile.BaseStream.Position - StartOfCancelListsList[i])); - } - - var numberOfOffsets = - file.CancelLists[i].Cancels[file.CancelLists[i].Cancels.Length - 1].Index + 1; //???? +1 only when not dividable by 2?? - - var UnknownBytesOffsetPosition = outFile.BaseStream.Position; - - for (int j = 0; j < numberOfOffsets; j++) - { - outFile.Write(0); - } - - for (int j = 0; j < file.CancelLists[i].Cancels.Length; j++) - { - if (file.CancelLists[i].Cancels[j].UnknownBytes != null) - { - WriteInt32ToPosition(outFile, UnknownBytesOffsetPosition + (file.CancelLists[i].Cancels[j].Index*4), (int)(outFile.BaseStream.Position- StartOfCancelListsList[i])); - outFile.Write(file.CancelLists[i].Cancels[j].UnknownBytes); - } - } - } - - Debug.WriteLine("Done writing Cancels, now at: " + outFile.BaseStream.Position.ToString("X")); - - for (int i = 0; i < file.Moves.Length; i++) - { - WriteInt32ToPosition(outFile, StartOfNameOffsets + (i*4), (int)outFile.BaseStream.Position); - - outFile.Write(file.Moves[i].Name.ToCharArray()); - outFile.Write((byte)0x00); - } - - Debug.WriteLine("Done writing names, now at: " + outFile.BaseStream.Position.ToString("X")); - - outPutFileBytes = ms.ToArray(); - - Debug.WriteLine("Done."); - } - } - - var outPut = outPutFileBytes.ToList(); - outPut.InsertRange(0, BitConverter.GetBytes(outPutFileBytes.Length)); - - outPut.InsertRange(0, new byte[] - { - 0x00, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 - }); - - outPut.InsertRange(0, BitConverter.GetBytes(outPutFileBytes.Length + 4)); - - outPut.InsertRange(0, new byte[] - { - 0x07, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 - }); - - outPut = Common.CreateUassetFile(outPut, file.RawUassetHeaderDontTouch); - - Debug.WriteLine("Done."); - - File.WriteAllBytes(fileName, outPut.ToArray()); - } - - private static void WriteInputToDebug(Input input) - { - foreach (var entry in input.InputEntries) - { - if (entry == null) - { - continue; - } - - string output = "Entry:\n"; - - if (entry.InputParts != null) - { - foreach (var inputPart in entry.InputParts) - { - - output += inputPart.InputType + ", Buffer: " + inputPart.Buffer + ", Direction: " + - inputPart.InputDirection + ", U1:" - + inputPart.Unknown1 - + ", U2:" + inputPart.Unknown2 - + ", U3:" + inputPart.Unknown3 - + ", U4:" + inputPart.Unknown4 - + ", U5:" + inputPart.Unknown5 + "\n"; - - } - } - Debug.WriteLine(output); - - } - } - - private static string GetName(int address, BinaryReader reader) - { - StringBuilder sb = new StringBuilder(); - - reader.BaseStream.Seek(address, SeekOrigin.Begin); - - var c = reader.ReadChar(); - - while (c != 0) - { - sb.Append(c); - c = reader.ReadChar(); - } - - return sb.ToString(); - } - } - - public class BCMFile - { - public Charge[] Charges { get; set; } - public Input[] Inputs { get; set; } - public Move[] Moves { get; set; } - public CancelList[] CancelLists { get; set; } - public byte[] RawUassetHeaderDontTouch { get; set; } - } - - public class CancelList - { - public int Index { get; set; } - public int Unknown1 { get; set; } - public Cancel[] Cancels { get; set; } - } - - public class Cancel - { - public string Name { get; set; } - public short Index { get; set; } - public int ScriptIndex { get; set; } - public CancelInts CancelInts { get; set; } - public byte[] UnknownBytes { get; set; } - } - - public class CancelInts - { - public int Unknown1 { get; set; } - public int Unknown2 { get; set; } - } - - public class Move - { - public byte Offset { get; set; } - public short Index { get; set; } - public string Name { get; set; } - public short Input { get; set; } - public short InputFlags { get; set; } - public int PositionRestriction { get; set; } - public int Unknown3 { get; set; } - public float RestrictionDistance { get; set; } - public int Unknown4 { get; set; } - public int ProjectileLimit { get; set; } - public short Unknown6 { get; set; } - public short Unknown7 { get; set; } - public short Unknown8 { get; set; } - public short Unknown9 { get; set; } - public short MeterRequirement { get; set; } - public short MeterUsed { get; set; } - public short Unknown10 { get; set; } - public short Unknown11 { get; set; } - public short VtriggerRequirement { get; set; } - public short VtriggerUsed { get; set; } - public int Unknown16 { get; set; } - public short InputMotionIndex { get; set; } - public short ScriptIndex { get; set; } - - public int Unknown17 { get; set; } - public int Unknown18 { get; set; } - public int Unknown19 { get; set; } - public float Unknown20 { get; set; } - public float Unknown21 { get; set; } - - public int Unknown22 { get; set; } - public int Unknown23 { get; set; } - public int Unknown24 { get; set; } - public int Unknown25 { get; set; } - - public short Unknown26 { get; set; } - public short NormalOrVtrigger { get; set; } - - public int Unknown28 { get; set; } - } - - public class Charge - { - public int Index { get; set; } - public short ChargeDirection { get; set; } - public short ChargeFrames { get; set; } - public short Unknown1 { get; set; } - public short Unknown2 { get; set; } - public short Unknown3 { get; set; } - public short Flags { get; set; } - public short ChargeIndex { get; set; } - public short Unknown4 { get; set; } - } - - public class Input - { - public int Index { get; set; } - public InputEntry[] InputEntries { get; set; } - public string Name { get; set; } - } - - public class InputEntry - { - public InputPart[] InputParts { get; set; } - } - - public class InputPart - { - public short Buffer { get; set; } - public InputType InputType { get; set; } - public InputDirection InputDirection { get; set; } - public short Unknown1 { get; set; } - public short Unknown2 { get; set; } - public short Unknown3 { get; set; } - public short Unknown4 { get; set; } - public short Unknown5 { get; set; } - } - - public enum InputType - { - Normal = 0, - Charge = 1 - } - - [Flags] - public enum InputDirection - { - Neutral = 0, //??? - Up = 1, - Down = 2, - Back = 4, - Forward = 8, - } -} +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using Newtonsoft.Json; + +namespace MoveLib.BCM +{ + public static class BCM + { + public static void BcmToJson(string inFile, string outFile) + { + BCMFile bcm; + + try + { + bcm = FromUassetFile(inFile); + } + catch (Exception ex) + { + Console.WriteLine("Something went wrong. Couldn't create JSON.\n" + ex.Message + " - " + ex.Data); + throw; + } + + Formatting format = Formatting.Indented; + + var json = JsonConvert.SerializeObject(bcm, format, new Newtonsoft.Json.Converters.StringEnumConverter()); + + File.WriteAllText(outFile, json); + } + + public static bool JsonToBcm(string inFile, string outFile) + { + BCMFile bcm; + + try + { + bcm = JsonConvert.DeserializeObject(File.ReadAllText(inFile)); + } + catch (Exception ex) + { + Console.WriteLine("Error parsing JSON: " + ex.Message + " - " + ex.Data); + return false; + } + + try + { + ToUassetFile(bcm, outFile); + } + catch (Exception ex) + { + Console.WriteLine("Something went wrong. Couldn't create BCM.\n" + ex.Message + " - " + ex.Data); + return false; + } + + return true; + } + + public static BCMFile FromUassetFile(string fileName) + { + byte[] fileBytes = File.ReadAllBytes(fileName); + + byte[] UassetHeaderBytes = Common.GetUassetHeader(fileBytes); + fileBytes = Common.RemoveUassetHeader(fileBytes); + + List MoveList = new List(); + List CancelLists = new List(); + List InputList = new List(); + List ChargeList = new List(); + + Debug.WriteLine("READING"); + using (var ms = new MemoryStream(fileBytes)) + using (var inFile = new BinaryReader(ms)) + { + string bcmString = new string(inFile.ReadChars(4)); + + if (bcmString != "#BCM") + { + throw new Exception("Error: Not a valid KWBCM file!"); + } + + Debug.WriteLine(bcmString); + + inFile.BaseStream.Seek(0xA, SeekOrigin.Begin); + short BCMVER = inFile.ReadInt16(); + Debug.WriteLine("BCMVER: " + BCMVER); + short ChargeCount = inFile.ReadInt16(); + Debug.WriteLine("ChargeCount: " + ChargeCount); + short InputCount = inFile.ReadInt16(); + Debug.WriteLine("InputCount: " + InputCount); + short MoveCount = inFile.ReadInt16(); + Debug.WriteLine("Movecount: " + MoveCount); + short CancelCount = inFile.ReadInt16(); //last cancel index + Debug.WriteLine("Cancelcount: " + CancelCount); + + int startOfCharges = inFile.ReadInt32(); + int startOfInputs = inFile.ReadInt32(); + int startOfMoves = inFile.ReadInt32(); + int startOfNames = inFile.ReadInt32(); + int startOfCancelLists = inFile.ReadInt32(); + Debug.WriteLine("StartOfCharges: " + startOfCharges); + Debug.WriteLine("StartOfInputs: " + startOfInputs); + + Debug.WriteLine("StartOfMoves: " + startOfMoves); + Debug.WriteLine("StartOfNames: " + startOfNames); + + Debug.WriteLine("StartOfCancelLists: " + startOfCancelLists); + + Debug.WriteLine("Current pos: " + inFile.BaseStream.Position.ToString("X")); + Debug.WriteLine("\n\n"); + + inFile.BaseStream.Seek(startOfCharges, SeekOrigin.Begin); + + List ChargeAddresses = new List(); + + for (int i = 0; i < ChargeCount; i++) + { + ChargeAddresses.Add(inFile.ReadInt32()); + } + + for (int i = 0; i < ChargeAddresses.Count; i++) + { + Charge thisCharge = new Charge(); + int thisChargeAddress = ChargeAddresses[i]; + inFile.BaseStream.Seek(thisChargeAddress, SeekOrigin.Begin); + Debug.WriteLine("ChargeAddress: " + thisChargeAddress.ToString("X")); + + thisCharge.ChargeDirection = inFile.ReadInt16(); + thisCharge.Unknown1 = inFile.ReadInt16(); + thisCharge.Unknown2 = inFile.ReadInt16(); + thisCharge.Unknown3 = inFile.ReadInt16(); + thisCharge.ChargeFrames = inFile.ReadInt16(); + thisCharge.Flags = inFile.ReadInt16(); + thisCharge.ChargeIndex = inFile.ReadInt16(); + thisCharge.Unknown4 = inFile.ReadInt16(); + + thisCharge.Index = i; + ChargeList.Add(thisCharge); + } + + inFile.BaseStream.Seek(startOfInputs, SeekOrigin.Begin); + + List InputAddresses = new List(); + + for (int i = 0; i < InputCount; i++) + { + InputAddresses.Add(inFile.ReadInt32()); + } + + for (int i = 0; i < InputAddresses.Count; i++) + { + Input thisInput = new Input(); + int thisInputAddress = InputAddresses[i]; + inFile.BaseStream.Seek(thisInputAddress, SeekOrigin.Begin); + Debug.WriteLine("InputAddress: " + thisInputAddress.ToString("X")); + + List moveEntryOffsets = new List(); + + moveEntryOffsets.Add(inFile.ReadInt32()); + moveEntryOffsets.Add(inFile.ReadInt32()); + moveEntryOffsets.Add(inFile.ReadInt32()); + moveEntryOffsets.Add(inFile.ReadInt32()); + + var entries = new List(); + + foreach (var entryOffset in moveEntryOffsets) + { + if (entryOffset == 0) + { + entries.Add(new InputEntry()); + continue; + } + + inFile.BaseStream.Seek(entryOffset + thisInputAddress, SeekOrigin.Begin); + var partCount = inFile.ReadInt32(); + + InputEntry thisInputEntry = new InputEntry(); + List parts = new List(); + + for (int j = 0; j < partCount; j++) + { + InputPart thisPart = new InputPart() + { + InputType = (InputType)inFile.ReadInt16(), + Buffer = inFile.ReadInt16(), + InputDirection = (InputDirection)inFile.ReadInt16(), + Unknown1 = inFile.ReadInt16(), + Unknown2 = inFile.ReadInt16(), + Unknown3 = inFile.ReadInt16(), + Unknown4 = inFile.ReadInt16(), + Unknown5 = inFile.ReadInt16(), + }; + + parts.Add(thisPart); + } + + for (int j = 0; j < 16-partCount; j++) //There can be up to 16 parts, but even if they are empty they are still there, only filled with 0x00 + { + var unused = inFile.ReadBytes(16); + foreach (var b in unused) + { + if (b != 0) + { + Debug.WriteLine("Read unexpected byte in what was thought to be an empty part of an input."); + } + } + } + + thisInputEntry.InputParts = parts.ToArray(); + entries.Add(thisInputEntry); + } + + thisInput.InputEntries = entries.ToArray(); + + thisInput.Index = i; + InputList.Add(thisInput); + Debug.WriteLine("Created input with index: " + i); + } + + for (int i = 0; i < MoveCount*4; i+=0x4) + { + long thisMovePosition = startOfMoves + i; + long thisNamePosition = startOfNames + i; + + inFile.BaseStream.Seek(thisNamePosition, SeekOrigin.Begin); + int NameAddress = inFile.ReadInt32(); + string Name = GetName(NameAddress, inFile); + + inFile.BaseStream.Seek(thisMovePosition, SeekOrigin.Begin); + int offset = inFile.ReadInt32(); + Debug.WriteLine("Adding move at: " + offset.ToString("X")); + + inFile.BaseStream.Seek(offset, SeekOrigin.Begin); + + short input = inFile.ReadInt16(); + short inputFlags = inFile.ReadInt16(); + int restrict = inFile.ReadInt32(); + int restrict2 = inFile.ReadInt32(); + float restrictDistance = inFile.ReadSingle(); + int unknown4 = (BCMVER > 0) ? inFile.ReadInt32() : 0; + // CHANGED: split projectileRestrict into 2 16bit properties. + var projectileGroup = inFile.ReadInt16(); + var projectileMaxCount = inFile.ReadInt16(); + int unknown6 = inFile.ReadInt16(); + int unknown7 = inFile.ReadInt16(); + short unknown8 = inFile.ReadInt16(); + short unknown9 = inFile.ReadInt16(); + + short MeterRequirement = inFile.ReadInt16(); + short MeterUsed = inFile.ReadInt16(); + short unknown10 = inFile.ReadInt16(); + short unknown11 = inFile.ReadInt16(); + int VtriggerRequirement = inFile.ReadInt16(); + int VtriggerUsed = inFile.ReadInt16(); + int Unknown16 = inFile.ReadInt32(); + int InputMotionIndex = inFile.ReadInt16(); + int ScriptIndex = inFile.ReadInt16(); + + Move thisMove = new Move() + { + Name = Name, + Index = (short)(i == 0 ? 0 : (i / 4)), + Input = input, + InputFlags = inputFlags, + PositionRestriction = restrict, + Unknown3 = restrict2, + RestrictionDistance = restrictDistance, + Unknown4 = unknown4, + ProjectileGroup = projectileGroup, + ProjectileMaxCount = projectileMaxCount, + Unknown6 = (short)unknown6, + Unknown7 = (short)unknown7, + Unknown8 = unknown8, + Unknown9 = unknown9, + Unknown10 = unknown10, + Unknown11 = unknown11, + MeterRequirement = (short)MeterRequirement, + MeterUsed = (short)MeterUsed, + VtriggerRequirement = (short)VtriggerRequirement, + VtriggerUsed = (short)VtriggerUsed, + Unknown16 = Unknown16, + InputMotionIndex = (short)InputMotionIndex, + ScriptIndex = (short)ScriptIndex, + Unknown17 = inFile.ReadInt32(), + Unknown18 = inFile.ReadInt32(), + Unknown19 = (BCMVER == 0) ? inFile.ReadInt32() : 0, + Unknown20 = inFile.ReadSingle(), + Unknown21 = inFile.ReadSingle(), + Unknown22 = inFile.ReadInt32(), + Unknown23 = inFile.ReadInt32(), + Unknown24 = inFile.ReadInt32(), + Unknown25 = inFile.ReadInt32(), + Unknown26 = inFile.ReadInt16(), + NormalOrVtrigger = inFile.ReadInt16(), + Unknown28 = inFile.ReadInt32() + }; + + if (thisMove.InputMotionIndex != -1) //Just for debugging... + { + InputList.Where(x => x.Index == thisMove.InputMotionIndex).ToList()[0].Name += thisMove.Name + ", "; + } + + MoveList.Add(thisMove); + + Debug.WriteLine("MOVE: " + "Index: " + (i == 0 ? 0 : (i/4)) + + "\nName: " + Name + + "\nOffset: " + offset.ToString("X") + + "\nNameOffet: " + NameAddress.ToString("X") + + "\nInput: " + input + + "\nflags: " + inputFlags + + "\nRestrict: " + restrict + + "\nRestrict2: " + restrict2 + + "\nRestrictDistance: " + restrictDistance + + "\nUnknown4: " + unknown4 + + "\nProjectileGroup: " + projectileGroup + + "\nProjectileMaxCount: " + projectileMaxCount + + "\nUnknown6: " + unknown6 + + "\nUnknown7: " + unknown7 + + "\nUnknown8: " + unknown8 + + "\nUnknown9: " + unknown9 + + "\nUnknown10: " + unknown10 + + "\nUnknown11: " + unknown11 + + "\nMeterReq: " + MeterRequirement + + "\nMeterUsed: " + MeterUsed + + "\nVtriggerReq: " + VtriggerRequirement + + "\nVtriggerUsed: " + VtriggerUsed + + "\nUnknown16: " + Unknown16 + + "\nInputMotionIndex: " + InputMotionIndex + + "\nScriptIndex: " + ScriptIndex + +"\nUnknown17: " + thisMove.Unknown17 + + "\nUnknown18: " + thisMove.Unknown18 + + "\nUnknown19: " + thisMove.Unknown19 + + "\nUnknown20: " + thisMove.Unknown20 + + "\nUnknown21: " + thisMove.Unknown21 + + "\nUnknown22: " + thisMove.Unknown22 + + "\nUnknown23: " + thisMove.Unknown23 + + "\nUnknown24: " + thisMove.Unknown24 + + "\nUnknown25: " + thisMove.Unknown25 + + "\nUnknown26: " + thisMove.Unknown26 + + "\nUnknown27: " + thisMove.NormalOrVtrigger + + "\nUnknown28: " + thisMove.Unknown28 + + "\n\n"); + } + + inFile.BaseStream.Seek(startOfCancelLists, SeekOrigin.Begin); + List CancelAddresses = new List(); + for (int i = 0; i < CancelCount; i++) + { + int thisCancelAddress = inFile.ReadInt32(); + Debug.WriteLine("Cancel " + (i) + ": " + thisCancelAddress.ToString("X")); + CancelAddresses.Add(thisCancelAddress); + } + + for (int i = 0; i < CancelAddresses.Count; i++) + { + CancelList thisCancelList = new CancelList(); + int thisAddress = CancelAddresses[i]; + + if (thisAddress == 0) + { + CancelLists.Add(thisCancelList); + continue; + } + + inFile.BaseStream.Seek(thisAddress, SeekOrigin.Begin); + + thisCancelList.Unknown1 = inFile.ReadInt32(); + int MovesInList = inFile.ReadInt32(); + int LastIndex = inFile.ReadInt32(); //last move index in list -1... + int StartOffset = inFile.ReadInt32(); //offset until real list FROM START OF CANCEL!!! + int StartOfCancelInts = inFile.ReadInt32(); + int StartOfCancelBytes = inFile.ReadInt32(); + + Debug.WriteLine("ThisCancelAddress: " + thisAddress.ToString("X")); + Debug.WriteLine($"Cancel {i}:\nCU1: {thisCancelList.Unknown1}\nMovesInList: {MovesInList}\nNumberOfSomethingInList: {LastIndex}\nStartOffset: {StartOffset.ToString("X")}\nCU5: {StartOfCancelInts.ToString("X")}\nEndOffset: {StartOfCancelBytes.ToString("X")}\n"); + + inFile.BaseStream.Seek(thisAddress + StartOffset, SeekOrigin.Begin); + Debug.WriteLine("ListAddress: " + (thisAddress + StartOffset).ToString("X")); + Debug.WriteLine("ListAddressEnd: " + (thisAddress + StartOfCancelBytes).ToString("X")); + + List cancels = new List(); + thisCancelList.Index = i; + + for (int j = 0; j < MovesInList; j++) + { + int thisMoveInList = inFile.ReadInt16(); + Debug.WriteLine("Move: " + thisMoveInList); + + Move cancelMove = MoveList.Where(x => x.Index == thisMoveInList).ToList()[0]; + + Cancel thisCancel = new Cancel(); + thisCancel.Index = (short)thisMoveInList; + thisCancel.Name = cancelMove.Name; + thisCancel.ScriptIndex = cancelMove.ScriptIndex; + + cancels.Add(thisCancel); + } + + thisCancelList.Cancels = cancels.ToArray(); + + //All lists should have Moves divisible by 2. If it doesn't, simply add an empty one (0x00, 0x00) + if (MovesInList % 2 != 0) + { + Debug.WriteLine("READING EMPTY MOVE"); + inFile.ReadInt16(); + } + + if (StartOfCancelInts != 0) + { + Debug.WriteLine("We got something!!!" + inFile.BaseStream.Position.ToString("X") + " - Should be: " + (thisAddress + StartOfCancelInts).ToString("X")); + Debug.WriteLine(((thisAddress + StartOfCancelBytes) - (thisAddress + StartOfCancelInts)) / MovesInList); + + for (int j = 0; j < MovesInList; j++) + { + int value1 = inFile.ReadInt32(); + int value2 = inFile.ReadInt32(); + + thisCancelList.Cancels[j].CancelInts = new CancelInts() + { + Unknown1 = value1, + Unknown2 = value2 + }; + } + } + + Debug.WriteLine("Position is " + inFile.BaseStream.Position.ToString("X") + " - Should be: " + (thisAddress + StartOfCancelBytes).ToString("X")); + + if (inFile.BaseStream.Position != thisAddress + StartOfCancelBytes) //NOT a good idea + { + Debug.WriteLine("We are not where we're supposed to be, reading bytes until we are..."); + + while (inFile.BaseStream.Position != thisAddress + StartOfCancelBytes) + { + Debug.WriteLine(inFile.ReadByte()); + } + + Debug.WriteLine("Position is " + inFile.BaseStream.Position.ToString("X") + " - Should be: " + (thisAddress + StartOfCancelBytes).ToString("X")); + } + + for (int j = 0; j < LastIndex; j++) + { + inFile.BaseStream.Seek((thisAddress + StartOfCancelBytes) + (j * 4), SeekOrigin.Begin); + + var offset = inFile.ReadInt32(); + + if (offset == 0) + { + continue; + } + + Debug.WriteLine("SomethingElseInCancelList(offsets?): " + offset.ToString("X") + " Pos: " + (inFile.BaseStream.Position - 4).ToString("X") + " - Index: " + j + " added offset:" + (offset+thisAddress).ToString("X")); + + var address = offset + thisAddress; + + inFile.BaseStream.Seek(address, SeekOrigin.Begin); + + var cancelBytesBelongsTo = thisCancelList.Cancels.First(x => x.Index == j); + + var unkBytes = inFile.ReadBytes(0x24); + + cancelBytesBelongsTo.UnknownBytes = unkBytes; + } + + CancelLists.Add(thisCancelList); + Debug.WriteLine("\n"); + } + + try + { + foreach (var cancelList in CancelLists) + { + if (cancelList?.Cancels == null) + { + continue; + } + + Debug.WriteLine($"\nCancelList Index: {cancelList.Index}\n"); + + foreach (var cancel in cancelList.Cancels) + { + if (cancel == null) + { + continue; + } + + Debug.WriteLine("Cancel: " + cancel.Index + " ScriptIndex:" + cancel.ScriptIndex); + + foreach (var unknownByte in cancel.UnknownBytes) + { + Debug.Write(unknownByte.ToString("X") + " "); + } + + Debug.WriteLine(""); + } + } + } + catch (Exception) + { + Debug.WriteLine("Are the Cancel indices of the CancelList in order?"); + } + + Debug.WriteLine("\nCharges\n"); + + foreach (var charge in ChargeList) + { + Debug.WriteLine("CHARGE: " + charge.Index); + Debug.WriteLine("Dir: " + charge.ChargeDirection); + Debug.WriteLine("u1: " + charge.Unknown1); + Debug.WriteLine("u2: " + charge.Unknown2); + Debug.WriteLine("u3: " + charge.Unknown3); + Debug.WriteLine("ChargeFrames: " + charge.ChargeFrames); + Debug.WriteLine("Flags: " + charge.Flags); + Debug.WriteLine("CINDEX: " + charge.ChargeIndex); + Debug.WriteLine("u4: " + charge.Unknown4); + Debug.WriteLine("\n"); + } + + foreach (var input in InputList) + { + Debug.WriteLine("Input: " + input.Index); + Debug.WriteLine("Name: " + input.Name); + Debug.WriteLine("Entries: " + input.InputEntries.Length); + + WriteInputToDebug(input); + + Debug.WriteLine("\n"); + } + } + + Debug.WriteLine("Done"); + + BCMFile bcm = new BCMFile() + { + Inputs = InputList.ToArray(), + CancelLists = CancelLists.ToArray(), + Charges = ChargeList.ToArray(), + Moves = MoveList.ToArray(), + RawUassetHeaderDontTouch = UassetHeaderBytes + }; + + return bcm; + } + + private static void WriteInt32ToPosition(BinaryWriter outFile, long position, int Value) + { + long oldPosition = outFile.BaseStream.Position; + outFile.BaseStream.Seek(position, SeekOrigin.Begin); + outFile.Write(Value); + outFile.BaseStream.Seek(oldPosition, SeekOrigin.Begin); + } + + public static void ToUassetFile(BCMFile file, string fileName) + { + byte[] outPutFileBytes; + + using (var ms = new MemoryStream()) + { + using (var outFile = new BinaryWriter(ms)) + { + byte[] headerBytes = + { + 0x23, 0x42, 0x43, 0x4D, 0xFE, 0xFF, 0x2c, 0x00, 0x00, 0x00, 0x01, 0x00 + }; + + outFile.Write(headerBytes); + + outFile.Write((short) file.Charges.Length); + outFile.Write((short) file.Inputs.Length); + outFile.Write((short) file.Moves.Length); + outFile.Write((short) file.CancelLists.Length); + + var StartOfStartOfChargeOffsets = outFile.BaseStream.Position; + outFile.Write(0); + + var StartOfStartOfInputOffsets = outFile.BaseStream.Position; + outFile.Write(0); + + var StartOfStartOfMoveOffsets = outFile.BaseStream.Position; + outFile.Write(0); + + var StartOfStartOfNameOffsets = outFile.BaseStream.Position; + outFile.Write(0); + + var StartOfStartOfCancelListOffsets = outFile.BaseStream.Position; + outFile.Write(0); + + outFile.Write(0); //Unused? + + var StartOfChargeOffsets = outFile.BaseStream.Position; + if (file.Charges.Length > 0) + { + WriteInt32ToPosition(outFile, StartOfStartOfChargeOffsets, (int) outFile.BaseStream.Position); + } + for (int i = 0; i < file.Charges.Length; i++) + { + outFile.Write(0); + } + + var StartOfInputOffsets = outFile.BaseStream.Position; + if (file.Inputs.Length > 0) + { + WriteInt32ToPosition(outFile, StartOfStartOfInputOffsets, (int)outFile.BaseStream.Position); + } + for (int i = 0; i < file.Inputs.Length; i++) + { + outFile.Write(0); + } + + var StartOfMoveOffsets = outFile.BaseStream.Position; + if (file.Moves.Length > 0) + { + WriteInt32ToPosition(outFile, StartOfStartOfMoveOffsets, (int)outFile.BaseStream.Position); + } + for (int i = 0; i < file.Moves.Length; i++) + { + outFile.Write(0); + } + + var StartOfNameOffsets = outFile.BaseStream.Position; + if (file.Moves.Length > 0) + { + WriteInt32ToPosition(outFile, StartOfStartOfNameOffsets, (int)outFile.BaseStream.Position); + } + for (int i = 0; i < file.Moves.Length; i++) + { + outFile.Write(0); + } + + var StartOfCancelListOffsets = outFile.BaseStream.Position; + if (file.CancelLists.Length > 0) + { + WriteInt32ToPosition(outFile, StartOfStartOfCancelListOffsets, (int)outFile.BaseStream.Position); + } + for (int i = 0; i < file.CancelLists.Length; i++) + { + outFile.Write(0); + } + + Debug.WriteLine("Done writing temp offsets, now at: " + outFile.BaseStream.Position.ToString("X")); + + for (int i = 0; i < file.Charges.Length; i++) + { + WriteInt32ToPosition(outFile, StartOfChargeOffsets + (i*4), (int)outFile.BaseStream.Position); + + outFile.Write(file.Charges[i].ChargeDirection); + outFile.Write(file.Charges[i].Unknown1); + outFile.Write(file.Charges[i].Unknown2); + outFile.Write(file.Charges[i].Unknown3); + outFile.Write(file.Charges[i].ChargeFrames); + outFile.Write(file.Charges[i].Flags); + outFile.Write(file.Charges[i].ChargeIndex); + outFile.Write(file.Charges[i].Unknown4); + } + + Debug.WriteLine("Done writing charges, now at: " + outFile.BaseStream.Position.ToString("X")); + + for (int i = 0; i < file.Inputs.Length; i++) + { + WriteInt32ToPosition(outFile, StartOfInputOffsets + (i * 4), (int)outFile.BaseStream.Position); + var entryOffsetPosition = outFile.BaseStream.Position; + + outFile.Write(0); + outFile.Write(0); + outFile.Write(0); + outFile.Write(0); + + for (int j = 0; j < file.Inputs[i].InputEntries.Length; j++) + { + if (file.Inputs[i].InputEntries[j].InputParts == null) + { + continue; + } + + WriteInt32ToPosition(outFile, entryOffsetPosition + (j*4), (int)(outFile.BaseStream.Position- entryOffsetPosition)); + + outFile.Write(file.Inputs[i].InputEntries[j].InputParts.Length); + + for (int k = 0; k < file.Inputs[i].InputEntries[j].InputParts.Length; k++) + { + outFile.Write((short)file.Inputs[i].InputEntries[j].InputParts[k].InputType); + outFile.Write(file.Inputs[i].InputEntries[j].InputParts[k].Buffer); + outFile.Write((short)file.Inputs[i].InputEntries[j].InputParts[k].InputDirection); + outFile.Write(file.Inputs[i].InputEntries[j].InputParts[k].Unknown1); + outFile.Write(file.Inputs[i].InputEntries[j].InputParts[k].Unknown2); + outFile.Write(file.Inputs[i].InputEntries[j].InputParts[k].Unknown3); + outFile.Write(file.Inputs[i].InputEntries[j].InputParts[k].Unknown4); + outFile.Write(file.Inputs[i].InputEntries[j].InputParts[k].Unknown5); + } + + for (int k = 0; k < 16 - file.Inputs[i].InputEntries[j].InputParts.Length; k++) + { + for (int l = 0; l < 16; l++) + { + outFile.Write((byte)0x00); + } + } + } + } + + Debug.WriteLine("Done writing Inputs, now at: " + outFile.BaseStream.Position.ToString("X")); + + for (int i = 0; i < file.Moves.Length; i++) + { + WriteInt32ToPosition(outFile,StartOfMoveOffsets + (i*4), (int)outFile.BaseStream.Position); + + outFile.Write(file.Moves[i].Input); + outFile.Write(file.Moves[i].InputFlags); + outFile.Write(file.Moves[i].PositionRestriction); + outFile.Write(file.Moves[i].Unknown3); + outFile.Write(file.Moves[i].RestrictionDistance); + outFile.Write(file.Moves[i].Unknown4); + outFile.Write(file.Moves[i].ProjectileGroup); + outFile.Write(file.Moves[i].ProjectileMaxCount); + outFile.Write(file.Moves[i].Unknown6); + outFile.Write(file.Moves[i].Unknown7); + outFile.Write(file.Moves[i].Unknown8); + outFile.Write(file.Moves[i].Unknown9); + + outFile.Write(file.Moves[i].MeterRequirement); + outFile.Write(file.Moves[i].MeterUsed); + + outFile.Write(file.Moves[i].Unknown10); + outFile.Write(file.Moves[i].Unknown11); + + outFile.Write(file.Moves[i].VtriggerRequirement); + outFile.Write(file.Moves[i].VtriggerUsed); + + outFile.Write(file.Moves[i].Unknown16); + outFile.Write(file.Moves[i].InputMotionIndex); + outFile.Write(file.Moves[i].ScriptIndex); + + outFile.Write(file.Moves[i].Unknown17); + outFile.Write(file.Moves[i].Unknown18); + outFile.Write(file.Moves[i].Unknown19); // TODO: Why is this omitted? + outFile.Write(file.Moves[i].Unknown20); + outFile.Write(file.Moves[i].Unknown21); + outFile.Write(file.Moves[i].Unknown22); + outFile.Write(file.Moves[i].Unknown23); + outFile.Write(file.Moves[i].Unknown24); + outFile.Write(file.Moves[i].Unknown25); + outFile.Write(file.Moves[i].Unknown26); + outFile.Write(file.Moves[i].NormalOrVtrigger); + outFile.Write(file.Moves[i].Unknown28); + } + + Debug.WriteLine("Done writing Moves, now at: " + outFile.BaseStream.Position.ToString("X")); + + List CancelListOffsets = new List(); + List StartOfCancelListsList = new List(); + + for (int i = 0; i < file.CancelLists.Length; i++) + { + StartOfCancelListsList.Add(outFile.BaseStream.Position); + if (file.CancelLists[i].Cancels == null) + { + WriteInt32ToPosition(outFile, StartOfCancelListOffsets + (i*4), 0); + CancelListOffsets.Add(-1); + continue; + } + + WriteInt32ToPosition(outFile, StartOfCancelListOffsets + (i*4), + (int) outFile.BaseStream.Position); + + outFile.Write(file.CancelLists[i].Unknown1); + outFile.Write(file.CancelLists[i].Cancels.Length); + outFile.Write(file.CancelLists[i].Cancels[file.CancelLists[i].Cancels.Length - 1].Index + 1); + + CancelListOffsets.Add(outFile.BaseStream.Position); + + outFile.Write(0); + outFile.Write(0); + outFile.Write(0); + } + + for (int i = 0; i < file.CancelLists.Length; i++) + { + if (file.CancelLists[i].Cancels == null) + { + continue; + } + + Debug.WriteLine("CancelListAtAddress: " + outFile.BaseStream.Position.ToString("X")); + if (CancelListOffsets[i] != -1) + { + WriteInt32ToPosition(outFile, CancelListOffsets[i], (int)(outFile.BaseStream.Position - StartOfCancelListsList[i])); + } + + for (int j = 0; j < file.CancelLists[i].Cancels.Length; j++) + { + outFile.Write(file.CancelLists[i].Cancels[j].Index); + } + + if (file.CancelLists[i].Cancels.Length%2 != 0) + { + Debug.WriteLine("Writing empty move: " + outFile.BaseStream.Position.ToString("X")); + outFile.Write((short)0); + } + + bool shouldWrite = false; + var CancelIntsPosition = outFile.BaseStream.Position; + + foreach (var cancel in file.CancelLists[i].Cancels) + { + if (cancel.CancelInts != null) + { + outFile.Write(cancel.CancelInts.Unknown1); + outFile.Write(cancel.CancelInts.Unknown2); + shouldWrite = true; + } + } + + if (shouldWrite) + { + if (CancelListOffsets[i] != -1) + { + WriteInt32ToPosition(outFile, CancelListOffsets[i] + 4, + (int) (CancelIntsPosition - StartOfCancelListsList[i])); + } + } + + Debug.WriteLine("Startofunknownbytes: " + outFile.BaseStream.Position.ToString("X")); + + if (CancelListOffsets[i] != -1) + { + WriteInt32ToPosition(outFile, CancelListOffsets[i]+8, (int)(outFile.BaseStream.Position - StartOfCancelListsList[i])); + } + + var numberOfOffsets = + file.CancelLists[i].Cancels[file.CancelLists[i].Cancels.Length - 1].Index + 1; //???? +1 only when not dividable by 2?? + + var UnknownBytesOffsetPosition = outFile.BaseStream.Position; + + for (int j = 0; j < numberOfOffsets; j++) + { + outFile.Write(0); + } + + for (int j = 0; j < file.CancelLists[i].Cancels.Length; j++) + { + if (file.CancelLists[i].Cancels[j].UnknownBytes != null) + { + WriteInt32ToPosition(outFile, UnknownBytesOffsetPosition + (file.CancelLists[i].Cancels[j].Index*4), (int)(outFile.BaseStream.Position- StartOfCancelListsList[i])); + outFile.Write(file.CancelLists[i].Cancels[j].UnknownBytes); + } + } + } + + Debug.WriteLine("Done writing Cancels, now at: " + outFile.BaseStream.Position.ToString("X")); + + for (int i = 0; i < file.Moves.Length; i++) + { + WriteInt32ToPosition(outFile, StartOfNameOffsets + (i*4), (int)outFile.BaseStream.Position); + + outFile.Write(file.Moves[i].Name.ToCharArray()); + outFile.Write((byte)0x00); + } + + Debug.WriteLine("Done writing names, now at: " + outFile.BaseStream.Position.ToString("X")); + + outPutFileBytes = ms.ToArray(); + + Debug.WriteLine("Done."); + } + } + + var outPut = outPutFileBytes.ToList(); + outPut.InsertRange(0, BitConverter.GetBytes(outPutFileBytes.Length)); + + outPut.InsertRange(0, new byte[] + { + 0x00, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 + }); + + outPut.InsertRange(0, BitConverter.GetBytes(outPutFileBytes.Length + 4)); + + outPut.InsertRange(0, new byte[] + { + 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 + }); + + outPut = Common.CreateUassetFile(outPut, file.RawUassetHeaderDontTouch); + + Debug.WriteLine("Done."); + + File.WriteAllBytes(fileName, outPut.ToArray()); + } + + private static void WriteInputToDebug(Input input) + { + foreach (var entry in input.InputEntries) + { + if (entry == null) + { + continue; + } + + string output = "Entry:\n"; + + if (entry.InputParts != null) + { + foreach (var inputPart in entry.InputParts) + { + + output += inputPart.InputType + ", Buffer: " + inputPart.Buffer + ", Direction: " + + inputPart.InputDirection + ", U1:" + + inputPart.Unknown1 + + ", U2:" + inputPart.Unknown2 + + ", U3:" + inputPart.Unknown3 + + ", U4:" + inputPart.Unknown4 + + ", U5:" + inputPart.Unknown5 + "\n"; + + } + } + Debug.WriteLine(output); + + } + } + + private static string GetName(int address, BinaryReader reader) + { + StringBuilder sb = new StringBuilder(); + + reader.BaseStream.Seek(address, SeekOrigin.Begin); + + var c = reader.ReadChar(); + + while (c != 0) + { + sb.Append(c); + c = reader.ReadChar(); + } + + return sb.ToString(); + } + } + + public class BCMFile + { + public Charge[] Charges { get; set; } + public Input[] Inputs { get; set; } + public Move[] Moves { get; set; } + public CancelList[] CancelLists { get; set; } + public byte[] RawUassetHeaderDontTouch { get; set; } + } + + public class CancelList + { + public int Index { get; set; } + public int Unknown1 { get; set; } + public Cancel[] Cancels { get; set; } + } + + public class Cancel + { + public string Name { get; set; } + public short Index { get; set; } + public int ScriptIndex { get; set; } + public CancelInts CancelInts { get; set; } + public byte[] UnknownBytes { get; set; } + } + + public class CancelInts + { + public int Unknown1 { get; set; } + public int Unknown2 { get; set; } + } + + public class Move + { + public byte Offset { get; set; } + public short Index { get; set; } + public string Name { get; set; } + public short Input { get; set; } + public short InputFlags { get; set; } + public int PositionRestriction { get; set; } + public int Unknown3 { get; set; } + public float RestrictionDistance { get; set; } + public int Unknown4 { get; set; } + // CHANGED: ProjectileLimit split into 2 parts + public short ProjectileGroup { get; set; } + public short ProjectileMaxCount { get; set; } + + private int ProjectileLimit + { + set + { + ProjectileGroup = (short)(value & 0x00FF >> 0); + ProjectileMaxCount = (short)(value & 0xFF00 >> 8); + } + } + + // --- + public short Unknown6 { get; set; } + public short Unknown7 { get; set; } + public short Unknown8 { get; set; } + public short Unknown9 { get; set; } + public short MeterRequirement { get; set; } + public short MeterUsed { get; set; } + public short Unknown10 { get; set; } + public short Unknown11 { get; set; } + public short VtriggerRequirement { get; set; } + public short VtriggerUsed { get; set; } + public int Unknown16 { get; set; } + public short InputMotionIndex { get; set; } + public short ScriptIndex { get; set; } + + public int Unknown17 { get; set; } + public int Unknown18 { get; set; } + public int Unknown19 { get; set; } + public float Unknown20 { get; set; } + public float Unknown21 { get; set; } + + public int Unknown22 { get; set; } + public int Unknown23 { get; set; } + public int Unknown24 { get; set; } + public int Unknown25 { get; set; } + + public short Unknown26 { get; set; } + public short NormalOrVtrigger { get; set; } + + public int Unknown28 { get; set; } + } + + public class Charge + { + public int Index { get; set; } + public short ChargeDirection { get; set; } + public short ChargeFrames { get; set; } + public short Unknown1 { get; set; } + public short Unknown2 { get; set; } + public short Unknown3 { get; set; } + public short Flags { get; set; } + public short ChargeIndex { get; set; } + public short Unknown4 { get; set; } + } + + public class Input + { + public int Index { get; set; } + public InputEntry[] InputEntries { get; set; } + public string Name { get; set; } + } + + public class InputEntry + { + public InputPart[] InputParts { get; set; } + } + + public class InputPart + { + public short Buffer { get; set; } + public InputType InputType { get; set; } + public InputDirection InputDirection { get; set; } + public short Unknown1 { get; set; } + public short Unknown2 { get; set; } + public short Unknown3 { get; set; } + public short Unknown4 { get; set; } + public short Unknown5 { get; set; } + } + + public enum InputType + { + Normal = 0, + Charge = 1 + } + + [Flags] + public enum InputDirection + { + Neutral = 0, //??? + Up = 1, + Down = 2, + Back = 4, + Forward = 8, + } +} diff --git a/MoveLib/Common.cs b/MoveLib/Common.cs index d0c3a21..3e6fa5a 100644 --- a/MoveLib/Common.cs +++ b/MoveLib/Common.cs @@ -6,13 +6,24 @@ namespace MoveLib { + /// + /// Common functions used by multiple MoveLib classes. + /// public static class Common { + public const int ADDRESS_CONTENT_PTR = 0x18; // Address of pointer to content OR size of metadata, depending on how you look at it. + public const int ADDRESS_FOOTER_PTR = 0x93; + + /// + /// Removes the Uasset's metadata section (header) and returns the remainder. + /// + /// + /// The main content/data of the Uasset. public static byte[] RemoveUassetHeader(byte[] fileBytes) { var tempList = fileBytes.ToList(); - int sizeOfHeader = BitConverter.ToInt32(fileBytes, 0x18); + int sizeOfHeader = BitConverter.ToInt32(fileBytes, ADDRESS_CONTENT_PTR); tempList.RemoveRange(0, sizeOfHeader + 36); return tempList.ToArray(); @@ -20,14 +31,12 @@ public static byte[] RemoveUassetHeader(byte[] fileBytes) public static byte[] GetUassetHeader(byte[] fileBytes) { - var tempList = fileBytes.ToList(); - - int sizeOfHeader = BitConverter.ToInt32(fileBytes, 0x18); + int sizeOfHeader = BitConverter.ToInt32(fileBytes, ADDRESS_CONTENT_PTR); // get the value @18 - the size of the header (or pointer to the end of the header) - byte[] array = new byte[sizeOfHeader]; - tempList.CopyTo(0, array, 0, sizeOfHeader); + byte[] headerBytes = new byte[sizeOfHeader]; + Array.Copy(fileBytes, headerBytes, sizeOfHeader); - return array; + return headerBytes; } public static List CreateUassetFile(List fileBytes, byte[] uassetHeader) @@ -37,7 +46,7 @@ public static List CreateUassetFile(List fileBytes, byte[] uassetHea 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }); + }); // "None" bytes (+ 4 extra zeros?) var tempLengthBytes = BitConverter.GetBytes(fileBytes.Count); diff --git a/MoveLib/MoveLib.csproj b/MoveLib/MoveLib.csproj index d5f8c6a..5327a16 100644 --- a/MoveLib/MoveLib.csproj +++ b/MoveLib/MoveLib.csproj @@ -30,9 +30,8 @@ 4 - - False - ..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll + + ..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll diff --git a/MoveLib/packages.config b/MoveLib/packages.config index 8c83d75..508c490 100644 --- a/MoveLib/packages.config +++ b/MoveLib/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/MoveTool/MoveTool.csproj b/MoveTool/MoveTool.csproj index 95954f4..1780256 100644 --- a/MoveTool/MoveTool.csproj +++ b/MoveTool/MoveTool.csproj @@ -47,6 +47,7 @@ + @@ -55,11 +56,11 @@ - \ No newline at end of file diff --git a/MoveTool/Program.cs b/MoveTool/Program.cs index 9b7754d..fdc8328 100644 --- a/MoveTool/Program.cs +++ b/MoveTool/Program.cs @@ -1,206 +1,273 @@ using System; using System.IO; +using System.Reflection; using MoveLib; using MoveLib.BAC; using MoveLib.BCM; namespace MoveTool { - class Program + public class Program { - static void Main(string[] args) + private static readonly char Separator = Path.DirectorySeparatorChar; + + [STAThread] + public static void Main(string[] args) { - if (args.Length == 0) - { - Console.WriteLine("\n"); - Console.WriteLine("BAC/BCM/BCH to JSON: MoveTool.exe InFile.uasset OutFile.json"); - Console.WriteLine("JSON to BAC/BCM/BCH: MoveTool.exe InFile.json OutFile.uasset"); - Console.WriteLine("\n"); - Console.WriteLine("You can also drag and drop files onto this tool and it will\nautomatically create the JSON or BAC/BCM/BCH file with the same\nname in the same directory as the original file."); - Console.WriteLine("\n"); - Console.WriteLine(("Back up your files, this tool will overwrite any file with the\nsame name as the output file!").ToUpper()); - } + AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssembly; - if (args.Length == 1) + Start(args); + } + + private static void Start(string[] args) + { + switch (args.Length) { - Console.WriteLine(Path.GetDirectoryName(args[0]) + @"\" + Path.GetFileNameWithoutExtension(args[0])); + case 0: + { + Console.WriteLine("\nBAC/BCM/BCH to JSON: MoveTool.exe InFile.uasset OutFile.json" + + "\nJSON to BAC/BCM/BCH: MoveTool.exe InFile.json OutFile.uasset" + + "\n\nYou can also drag and drop files onto this tool and it will" + + "\nautomatically create the JSON or BAC/BCM/BCH file with the " + + "\nsame name in the same directory as the original file." + + ("\n\nBack up your files, this tool will overwrite any file with the" + + "\nsame name as the output file!").ToUpper() ); + + break; + } - if (File.Exists(args[0])) + case 1: { - if (args[0].ToLower().EndsWith("uasset")) + var path = args[0]; + var directory = Path.GetDirectoryName(path) + Separator; + var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path); + + Console.WriteLine(directory + fileNameWithoutExtension); + + // Check if file exists + if (!File.Exists(path)) { - var type = FileTypeDecider.Decide(args[0]); + Console.WriteLine("File does not exist: " + path); + break; + } - if (type == FileType.BAC) - { - Console.WriteLine("BAC file detected. Trying to do BAC to JSON."); - try - { - BAC.BacToJson(args[0], - Path.GetDirectoryName(args[0]) + @"\" + Path.GetFileNameWithoutExtension(args[0]) + - ".json"); - Console.WriteLine("Done writing file: " + Path.GetDirectoryName(args[0]) + @"\" + - Path.GetFileNameWithoutExtension(args[0]) + ".json"); - } - catch (Exception ex) - { - Console.WriteLine("Something went wrong: " + ex.Message + " - " + ex.Data); - Console.Read(); - } - } - else if (type == FileType.BCM) - { - try - { - Console.WriteLine("BCM file detected. Trying to do BCM to JSON."); - BCM.BcmToJson(args[0], - Path.GetDirectoryName(args[0]) + @"\" + Path.GetFileNameWithoutExtension(args[0]) + - ".json"); - Console.WriteLine("Done writing file: " + Path.GetDirectoryName(args[0]) + @"\" + Path.GetFileNameWithoutExtension(args[0]) + ".json"); - } - catch (Exception ex) - { - Console.WriteLine("Something went wrong: " + ex.Message + " - " + ex.Data); - Console.Read(); - } + #region Handle .UASSET files - } - else if (type == FileType.BCH) - { - try - { - Console.WriteLine("BCH file detected. Trying to do BCH to JSON."); - BCH.BchToJson(args[0], - Path.GetDirectoryName(args[0]) + @"\" + Path.GetFileNameWithoutExtension(args[0]) + - ".json"); - Console.WriteLine("Done writing file: " + Path.GetDirectoryName(args[0]) + @"\" + Path.GetFileNameWithoutExtension(args[0]) + ".json"); - } - catch (Exception ex) - { - Console.WriteLine("Something went wrong: " + ex.Message + " - " + ex.Data); - Console.Read(); - } + if (path.ToLower().EndsWith("uasset")) + { + var type = FileTypeDecider.Decide(path); - } - else if (type == FileType.Unknown) + switch (type) { - Console.WriteLine("Unsupported format."); - Console.Read(); + case FileType.BAC: + Console.WriteLine("BAC file detected. Trying to do BAC to JSON."); + try + { + BAC.BacToJson(path, directory + fileNameWithoutExtension + ".json"); + + Console.WriteLine("Done writing file: " + + directory + fileNameWithoutExtension + ".json"); + } + catch (Exception ex) + { + Console.WriteLine("Something went wrong: " + ex.Message + " - " + ex.Data); + } + + break; + + case FileType.BCM: + try + { + Console.WriteLine("BCM file detected. Trying to do BCM to JSON."); + + BCM.BcmToJson(path, + directory + fileNameWithoutExtension + ".json"); + + Console.WriteLine("Done writing file: " + + directory + fileNameWithoutExtension + ".json"); + } + catch (Exception ex) + { + Console.WriteLine("Something went wrong: " + ex.Message + " - " + ex.Data); + } + + break; + + case FileType.BCH: + try + { + Console.WriteLine("BCH file detected. Trying to do BCH to JSON."); + BCH.BchToJson(path, + directory + fileNameWithoutExtension + ".json"); + Console.WriteLine("Done writing file: " + + directory + fileNameWithoutExtension + ".json"); + } + catch (Exception ex) + { + Console.WriteLine("Something went wrong: " + ex.Message + " - " + ex.Data); + } + + break; + + case FileType.Unknown: + default: + Console.WriteLine("Unsupported format."); + break; } } + #endregion + + #region Handle .JSON files + if (args[0].ToLower().EndsWith("json")) { Console.WriteLine("File is json."); - var success = BAC.JsonToBac(args[0], - Path.GetDirectoryName(args[0]) + @"\" + Path.GetFileNameWithoutExtension(args[0]) + ".uasset"); + var success = BAC.JsonToBac( + args[0], + Path.GetDirectoryName(args[0]) + Separator + + Path.GetFileNameWithoutExtension(args[0]) + ".uasset"); if (!success) { success = BCM.JsonToBcm(args[0], - Path.GetDirectoryName(args[0]) + @"\" + Path.GetFileNameWithoutExtension(args[0]) + ".uasset"); + Path.GetDirectoryName(args[0]) + Separator + + Path.GetFileNameWithoutExtension(args[0]) + ".uasset"); } if (!success) { success = BCH.JsonToBch(args[0], - Path.GetDirectoryName(args[0]) + @"\" + Path.GetFileNameWithoutExtension(args[0]) + ".uasset"); + Path.GetDirectoryName(args[0]) + Separator + + Path.GetFileNameWithoutExtension(args[0]) + ".uasset"); } if (!success) { Console.WriteLine("Something went wrong while parsing json."); - Console.Read(); } else { - Console.WriteLine("Done writing file: " + Path.GetDirectoryName(args[0]) + @"\" + Path.GetFileNameWithoutExtension(args[0]) + ".uasset"); + Console.WriteLine("Done writing file: " + Path.GetDirectoryName(args[0]) + + Separator + Path.GetFileNameWithoutExtension(args[0]) + + ".uasset"); } } - } - else - { - Console.WriteLine("File does not exist: " + args[0]); - Console.Read(); - } - } - if (args.Length == 2) - { - string inFile = args[0]; - string outFile = args[1]; + #endregion + + break; + } - if (inFile.ToLower().EndsWith("uasset")) + case 2: { - if (!outFile.ToLower().EndsWith("json")) + var inFile = args[0]; + var outFile = args[1]; + + if (inFile.ToLower().EndsWith("uasset")) { - outFile += ".json"; - } + if (!outFile.ToLower().EndsWith("json")) + { + outFile += ".json"; + } - var type = FileTypeDecider.Decide(inFile); + var type = FileTypeDecider.Decide(inFile); - if (type == FileType.BAC) - { - Console.WriteLine("BAC file detected. Trying to do BAC to JSON."); - BAC.BacToJson(inFile, outFile); - Console.WriteLine("Done writing file: " + outFile); - } - else if (type == FileType.BCM) - { - Console.WriteLine("BCM file detected. Trying to do BCM to JSON."); - BCM.BcmToJson(inFile,outFile); - Console.WriteLine("Done writing file: " + outFile); - } - else if (type == FileType.BCH) - { - Console.WriteLine("BCH file detected. Trying to do BCH to JSON."); - BCH.BchToJson(inFile, outFile); - Console.WriteLine("Done writing file: " + outFile); + switch (type) + { + case FileType.BAC: + Console.WriteLine("BAC file detected. Trying to do BAC to JSON."); + BAC.BacToJson(inFile, outFile); + Console.WriteLine("Done writing file: " + outFile); + break; + + case FileType.BCM: + Console.WriteLine("BCM file detected. Trying to do BCM to JSON."); + BCM.BcmToJson(inFile, outFile); + Console.WriteLine("Done writing file: " + outFile); + break; + + case FileType.BCH: + Console.WriteLine("BCH file detected. Trying to do BCH to JSON."); + BCH.BchToJson(inFile, outFile); + Console.WriteLine("Done writing file: " + outFile); + break; + + case FileType.Unknown: + default: + Console.WriteLine("Unsupported format."); + break; + } } - else if (type == FileType.Unknown) + else if (inFile.ToLower().EndsWith("json")) { - Console.WriteLine("Unsupported format."); - Console.Read(); - } - } + if (!outFile.ToLower().EndsWith("uasset")) + { + outFile += ".uasset"; + } - if (inFile.ToLower().EndsWith("json")) - { - if (!outFile.ToLower().EndsWith("uasset")) - { - outFile += ".uasset"; - } + Console.WriteLine("File is json."); - Console.WriteLine("File is json."); + var success = BAC.JsonToBac(inFile, outFile); - var success = BAC.JsonToBac(inFile, outFile); + if (!success) + { + success = BCM.JsonToBcm(inFile, outFile); + } - if (!success) - { - success = BCM.JsonToBcm(inFile, outFile); - } + if (!success) + { + success = BCH.JsonToBch(inFile, outFile); + } - if (!success) - { - success = BCH.JsonToBch(inFile, outFile); + if (!success) + Console.WriteLine("Something went wrong while parsing json."); + else + Console.WriteLine("Done writing file: " + outFile); } - if (!success) - { - Console.WriteLine("Something went wrong while parsing json."); - Console.Read(); - } - else - { - Console.WriteLine("Done writing file: " + outFile); - } + break; + } + + default: + { + Console.WriteLine("MoveTool can not understand more than 2 arguments. \n" + + @"If the paths contain spaces, try wrapping the paths in double quotes ("")."); + break; } } - if (args.Length > 2) + Pause(); + } + + private static void Pause() + { + Console.Write("\n\nPress any key to continue..."); + Console.ReadKey(true); + Console.WriteLine("\n"); + } + + // Part of enabling a single .exe file + private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args) + { + var executingAssembly = Assembly.GetExecutingAssembly(); + var assemblyName = new AssemblyName(args.Name); + + var path = assemblyName.Name + ".dll"; + if (assemblyName.CultureInfo.Equals(System.Globalization.CultureInfo.InvariantCulture) == false) { - Console.WriteLine("MoveTool can not understand more than 2 arguments. If you have spaces\n" + @"in the paths, try adding "" around them."); + path = $@"{assemblyName.CultureInfo}\{path}"; + } + + using (var stream = executingAssembly.GetManifestResourceStream(path)) + { + if (stream == null) + return null; + + var assemblyRawBytes = new byte[stream.Length]; + stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length); + return Assembly.Load(assemblyRawBytes); } } } diff --git a/README.md b/README.md index 21ae534..4ffdc3b 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,11 @@ A tool that outputs JSON files from Street Fighter 5's BCM, BAC and BCH (uasset) ## How to use Drag Uasset or JSON files on top of MoveTool.exe +NOTE: If you are having issues with RTE on Windows 10, set it to Windows 7 compatibility mode. + ## Todo -Find out what all the values means and fix remaining BAC files. Se Bugs below. -Many values are probably read in the wrong format (short/int etc). +Find out what all the values mean and fix remaining BAC files. See Bugs below. +Many values are probably read in the wrong format (short/int/etc). ## Bugs Unit test shows that MoveTool is not able to recreate these files: diff --git a/RealtimeEditor/MainForm.Designer.cs b/RealtimeEditor/MainForm.Designer.cs index 894447e..6656fdc 100644 --- a/RealtimeEditor/MainForm.Designer.cs +++ b/RealtimeEditor/MainForm.Designer.cs @@ -28,6 +28,8 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); this.lbOutput = new System.Windows.Forms.ListBox(); this.bScan = new System.Windows.Forms.Button(); this.cbBAC = new System.Windows.Forms.ComboBox(); @@ -39,6 +41,8 @@ private void InitializeComponent() this.bRestore = new System.Windows.Forms.Button(); this.gbBAC = new System.Windows.Forms.GroupBox(); this.gbBCM = new System.Windows.Forms.GroupBox(); + this.toolTip1 = new System.Windows.Forms.ToolTip(this.components); + this.toolTip2 = new System.Windows.Forms.ToolTip(this.components); this.gbBAC.SuspendLayout(); this.gbBCM.SuspendLayout(); this.SuspendLayout(); @@ -53,21 +57,22 @@ private void InitializeComponent() // // bScan // - this.bScan.Location = new System.Drawing.Point(200, 33); + this.bScan.Location = new System.Drawing.Point(200, 29); this.bScan.Name = "bScan"; this.bScan.Size = new System.Drawing.Size(101, 23); this.bScan.TabIndex = 3; this.bScan.Text = "Scan"; + this.toolTip2.SetToolTip(this.bScan, resources.GetString("bScan.ToolTip")); this.bScan.UseVisualStyleBackColor = true; - this.bScan.Click += new System.EventHandler(this.bTest_Click); + this.bScan.Click += new System.EventHandler(this.OnClick_ScanButton); // // cbBAC // this.cbBAC.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.cbBAC.FormattingEnabled = true; - this.cbBAC.Location = new System.Drawing.Point(9, 21); + this.cbBAC.Location = new System.Drawing.Point(6, 19); this.cbBAC.Name = "cbBAC"; - this.cbBAC.Size = new System.Drawing.Size(167, 21); + this.cbBAC.Size = new System.Drawing.Size(170, 21); this.cbBAC.TabIndex = 4; this.cbBAC.SelectedIndexChanged += new System.EventHandler(this.cbBAC_SelectedIndexChanged); // @@ -75,9 +80,9 @@ private void InitializeComponent() // this.cbBCM.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.cbBCM.FormattingEnabled = true; - this.cbBCM.Location = new System.Drawing.Point(9, 21); + this.cbBCM.Location = new System.Drawing.Point(6, 19); this.cbBCM.Name = "cbBCM"; - this.cbBCM.Size = new System.Drawing.Size(164, 21); + this.cbBCM.Size = new System.Drawing.Size(169, 21); this.cbBCM.TabIndex = 5; this.cbBCM.SelectedIndexChanged += new System.EventHandler(this.cbBCM_SelectedIndexChanged); // @@ -99,31 +104,35 @@ private void InitializeComponent() // // bSelectBACJson // - this.bSelectBACJson.Location = new System.Drawing.Point(6, 48); + this.bSelectBACJson.Location = new System.Drawing.Point(6, 46); this.bSelectBACJson.Name = "bSelectBACJson"; this.bSelectBACJson.Size = new System.Drawing.Size(170, 23); this.bSelectBACJson.TabIndex = 8; this.bSelectBACJson.Text = "Select Json"; + this.toolTip1.SetToolTip(this.bSelectBACJson, resources.GetString("SelectJson_ToolTipText")); this.bSelectBACJson.UseVisualStyleBackColor = true; this.bSelectBACJson.Click += new System.EventHandler(this.bSelectBACJson_Click); // // bSelectBCMJson // - this.bSelectBCMJson.Location = new System.Drawing.Point(9, 48); + this.bSelectBCMJson.Location = new System.Drawing.Point(6, 46); this.bSelectBCMJson.Name = "bSelectBCMJson"; - this.bSelectBCMJson.Size = new System.Drawing.Size(164, 23); + this.bSelectBCMJson.Size = new System.Drawing.Size(169, 23); this.bSelectBCMJson.TabIndex = 9; this.bSelectBCMJson.Text = "Select Json"; + this.toolTip1.SetToolTip(this.bSelectBCMJson, resources.GetString("SelectJson_ToolTipText")); this.bSelectBCMJson.UseVisualStyleBackColor = true; this.bSelectBCMJson.Click += new System.EventHandler(this.bSelectBCMJson_Click); // // bRestore // - this.bRestore.Location = new System.Drawing.Point(200, 60); + this.bRestore.Location = new System.Drawing.Point(200, 58); this.bRestore.Name = "bRestore"; this.bRestore.Size = new System.Drawing.Size(101, 23); this.bRestore.TabIndex = 10; this.bRestore.Text = "Restore Game"; + this.toolTip1.SetToolTip(this.bRestore, "Revert to using the files you started the game with.\r\n(Does not affect your JSONs" + + ".)"); this.bRestore.UseVisualStyleBackColor = true; this.bRestore.Click += new System.EventHandler(this.bRestore_Click); // @@ -151,6 +160,12 @@ private void InitializeComponent() this.gbBCM.TabStop = false; this.gbBCM.Text = "BCM"; // + // toolTip2 + // + this.toolTip2.AutoPopDelay = 15000; + this.toolTip2.InitialDelay = 500; + this.toolTip2.ReshowDelay = 100; + // // MainForm // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -167,7 +182,6 @@ private void InitializeComponent() this.ShowIcon = false; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; this.Text = "Real-time editor"; - this.Load += new System.EventHandler(this.MainForm_Load); this.gbBAC.ResumeLayout(false); this.gbBCM.ResumeLayout(false); this.ResumeLayout(false); @@ -187,6 +201,8 @@ private void InitializeComponent() private System.Windows.Forms.Button bRestore; private System.Windows.Forms.GroupBox gbBAC; private System.Windows.Forms.GroupBox gbBCM; + private System.Windows.Forms.ToolTip toolTip1; + private System.Windows.Forms.ToolTip toolTip2; } } diff --git a/RealtimeEditor/MainForm.cs b/RealtimeEditor/MainForm.cs index 6529f8c..3adc423 100644 --- a/RealtimeEditor/MainForm.cs +++ b/RealtimeEditor/MainForm.cs @@ -28,7 +28,7 @@ public Memory Memory var success = _memory.OpenProcess("StreetFighterV"); if (!success) { - writeToOutput("Game process not found!"); + WriteToOutput("Game process not found!"); return null; } } @@ -41,7 +41,7 @@ public MainForm() InitializeComponent(); } - private void writeToOutput(string output) + private void WriteToOutput(string output) { Invoke((MethodInvoker)delegate { @@ -50,13 +50,20 @@ private void writeToOutput(string output) }); } - private void bTest_Click(object sender, EventArgs e) + private void OnClick_ScanButton(object sender, EventArgs e) { + if (Memory == null) + { + // SFV process was not found. Don't scan. + return; + } + + // Reset combo boxes and file list. cbBAC.Items.Clear(); cbBCM.Items.Clear(); MemoryFileList = new List(); - writeToOutput("Scanning game for BAC/BCM files..."); + WriteToOutput("Scanning game for BAC/BCM files..."); Application.DoEvents(); BACAddresses = Memory.MemoryScan(Encoding.UTF8.GetBytes("#BAC")); @@ -64,19 +71,28 @@ private void bTest_Click(object sender, EventArgs e) foreach (var bacAddress in BACAddresses) { - Console.WriteLine("BAC at: " + bacAddress.ToString("X")); + Console.WriteLine($@"BAC at: {bacAddress:X}"); } foreach (var bcmAddress in BCMAddresses) { - Console.WriteLine("BCM at: " + bcmAddress.ToString("X")); + Console.WriteLine($@"BCM at: {bcmAddress:X}"); } + //CHANGED: Checks if Originals exists, and creates it if not. If it does exist, checks for empty folder. + if (!Directory.Exists("Originals")) Directory.CreateDirectory("Originals"); + if (!Directory.EnumerateFiles("Originals").Any()) + { + WriteToOutput("No files in Originals folder. Please add the uasset files for the current character to the \"Originals\" folder."); + return; + } + // --- + foreach (var file in Directory.GetFiles("Originals")) { if (!file.ToLower().EndsWith(".uasset")) { - continue; + continue; // Skip to next file if it's not a .uasset } var fileBytes = File.ReadAllBytes(file); @@ -95,7 +111,7 @@ private void bTest_Click(object sender, EventArgs e) MemoryFileList.Add(new MemoryFile() { OriginalAddress = bacAddress, - Name = Path.GetFileName(file), + UassetFileName = Path.GetFileName(file), Type = MemoryFileType.BAC }); found = true; @@ -105,7 +121,7 @@ private void bTest_Click(object sender, EventArgs e) if (found) { - continue; + continue; // BAC was found. Skip to next file. } foreach (var bcmAddress in BCMAddresses) @@ -117,7 +133,7 @@ private void bTest_Click(object sender, EventArgs e) MemoryFileList.Add(new MemoryFile() { OriginalAddress = bcmAddress, - Name = Path.GetFileName(file), + UassetFileName = Path.GetFileName(file), Type = MemoryFileType.BCM }); break; @@ -134,7 +150,7 @@ private void bTest_Click(object sender, EventArgs e) MemoryFileList.Add(new MemoryFile() { OriginalAddress = bacAddress, - Name = "Unknown" + counter, + UassetFileName = "Unknown" + counter, Type = MemoryFileType.BAC }); } @@ -150,7 +166,7 @@ private void bTest_Click(object sender, EventArgs e) MemoryFileList.Add(new MemoryFile() { OriginalAddress = bcmAddress, - Name = "Unknown" + counter, + UassetFileName = "Unknown" + counter, Type = MemoryFileType.BCM }); } @@ -159,24 +175,30 @@ private void bTest_Click(object sender, EventArgs e) foreach (var memoryFile in MemoryFileList) { memoryFile.Pointers = Memory.MemoryScan(BitConverter.GetBytes(memoryFile.OriginalAddress)); - Console.WriteLine("\nFile:\nOriginalAddress: " + memoryFile.OriginalAddress.ToString("X") + "\nName: " + memoryFile.Name); + + Console.WriteLine("\nFile:\n" + + $"OriginalAddress: {memoryFile.OriginalAddress:X}\n" + + $@"Name: {memoryFile.UassetFileName}"); + foreach (var pointer in memoryFile.Pointers) - { - Console.WriteLine("Pointer: " + pointer.ToString("X")); - } + Console.WriteLine($@"Pointer: {pointer:X}"); } foreach (var memoryFile in MemoryFileList) { + var uassetName = memoryFile.UassetFileName; + + if (uassetName == null) continue; + if (memoryFile.Type == MemoryFileType.BAC) { - cbBAC.Items.Add(Path.GetFileName(memoryFile.Name)); + cbBAC.Items.Add(uassetName); } else { - cbBCM.Items.Add(Path.GetFileName(memoryFile.Name)); + cbBCM.Items.Add(uassetName); } - writeToOutput("File: " + memoryFile.Name + " at: " + memoryFile.OriginalAddress.ToString("X")); + WriteToOutput($"File: {uassetName} at: {memoryFile.OriginalAddress:X}"); } if (cbBAC.Items.Count > 0) @@ -190,49 +212,23 @@ private void bTest_Click(object sender, EventArgs e) } Console.WriteLine("Done."); - writeToOutput("Ready to load JSON."); + WriteToOutput("Ready to load JSON."); } private void bSelectBACJson_Click(object sender, EventArgs e) { - FileDialog dialog = new OpenFileDialog(); - dialog.Filter = "JSON-file | *.json"; - var result = dialog.ShowDialog(); - - if (result != DialogResult.OK) - { - return; - } - - MemoryFileList.First(m => m.Name == cbBAC.SelectedItem.ToString()).JsonFile = dialog.FileName; - - foreach (var memoryFile in MemoryFileList) - { - Console.WriteLine("File:\nOriginalAddress: " + memoryFile.OriginalAddress.ToString("X") + "\nName: " + memoryFile.Name + "\nJSON: " + memoryFile.JsonFile ); - } - - lBAC.Text = dialog.FileName; - - var path = Path.GetDirectoryName(dialog.FileName); - - if (!fileSystemWatchers.ContainsKey(path)) - { - fileSystemWatchers.Add(path, new FileSystemWatcher(path)); - } - - foreach (var fileSystemWatcher in fileSystemWatchers) - { - fileSystemWatcher.Value.EnableRaisingEvents = true; - fileSystemWatcher.Value.Changed -= FileModified; - fileSystemWatcher.Value.Changed += FileModified; - } - - UpdateFileInMemory(dialog.FileName); - writeToOutput("Loaded: " + Path.GetFileName(dialog.FileName)); + SelectJson(sender, e); } private void bSelectBCMJson_Click(object sender, EventArgs e) { + SelectJson(sender, e); + } + + private void SelectJson(object sender, EventArgs e) + { + #region Show "Open File" dialog + FileDialog dialog = new OpenFileDialog(); dialog.Filter = "JSON-file | *.json"; var result = dialog.ShowDialog(); @@ -242,17 +238,31 @@ private void bSelectBCMJson_Click(object sender, EventArgs e) return; } - MemoryFileList.First(m => m.Name == cbBCM.SelectedItem.ToString()).JsonFile = dialog.FileName; + #endregion + + bool isBAC = ((Button)sender).Name.Contains("BAC"); + + var cb = isBAC ? cbBAC : cbBCM; + + var fileName = dialog.FileName; + + MemoryFileList.First(m => m.UassetFileName == cb.SelectedItem.ToString()).JsonFilePath = fileName; foreach (var memoryFile in MemoryFileList) { - Console.WriteLine("File:\nOriginalAddress: " + memoryFile.OriginalAddress.ToString("X") + "\nName: " + memoryFile.Name + "\nJSON: " + memoryFile.JsonFile); + Console.WriteLine($"File:\nOriginalAddress: {memoryFile.OriginalAddress:X}\n" + + $"Name: {memoryFile.UassetFileName}\n" + + $"JSON: {memoryFile.JsonFilePath}"); } - lBCM.Text = dialog.FileName; - var path = Path.GetDirectoryName(dialog.FileName); + var label = isBAC ? lBAC : lBCM; + label.Text = fileName; - if (!fileSystemWatchers.ContainsKey(path)) + var path = Path.GetDirectoryName(fileName); + var shortFileName = Path.GetFileName(fileName); + + // if no Watcher exists for the directory, add one + if (shortFileName != null && path != null && !fileSystemWatchers.ContainsKey(path)) { fileSystemWatchers.Add(path, new FileSystemWatcher(path)); } @@ -264,19 +274,24 @@ private void bSelectBCMJson_Click(object sender, EventArgs e) fileSystemWatcher.Value.Changed += FileModified; } - UpdateFileInMemory(dialog.FileName); - writeToOutput("Loaded: " + Path.GetFileName(dialog.FileName)); + UpdateFileInMemory(fileName); + WriteToOutput("Loaded: " + shortFileName); } - void FileModified(object sender, FileSystemEventArgs e) + private void FileModified(object sender, FileSystemEventArgs e) { + // Check if we care about the modified file... + // TODO + if (!MemoryFileList.Exists(m => m.JsonFilePath == e.FullPath)) return; + Console.WriteLine("File modified: " + e.FullPath); Console.WriteLine("Updating file in memory"); - writeToOutput("File modified: " + e.Name); + WriteToOutput("File modified: " + e.Name); WaitReady(e.FullPath); UpdateFileInMemory(e.FullPath); } + // Wait until the file is ready to be accessed public static void WaitReady(string fileName) { while (true) @@ -285,24 +300,24 @@ public static void WaitReady(string fileName) { using (Stream stream = File.Open(fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.Read)) { - if (stream != null) + if (stream != Stream.Null) { - Trace.WriteLine(string.Format("Output file {0} ready.", fileName)); + Trace.WriteLine($"Output file {fileName} ready."); break; } } } catch (FileNotFoundException ex) { - Trace.WriteLine(string.Format("Output file {0} not yet ready ({1})", fileName, ex.Message)); + Trace.WriteLine($"Output file {fileName} not found: ({ex.Message})"); } catch (IOException ex) { - Trace.WriteLine(string.Format("Output file {0} not yet ready ({1})", fileName, ex.Message)); + Trace.WriteLine($"Output file {fileName} not yet ready ({ex.Message})"); } catch (UnauthorizedAccessException ex) { - Trace.WriteLine(string.Format("Output file {0} not yet ready ({1})", fileName, ex.Message)); + Trace.WriteLine($"Output file {fileName} not yet ready ({ex.Message})"); } Thread.Sleep(500); } @@ -310,55 +325,54 @@ public static void WaitReady(string fileName) private void UpdateFileInMemory(string fileName) { - if (MemoryFileList.Exists(m => m.JsonFile == fileName)) + if (!MemoryFileList.Exists(m => m.JsonFilePath == fileName)) return; + + var tempFileName = "temp_" + Path.GetFileName(fileName); + var success = BAC.JsonToBac(fileName, tempFileName); + + if (!success) { - var tempFileName = "temp_" + Path.GetFileName(fileName); - var success = BAC.JsonToBac(fileName, tempFileName); + success = BCM.JsonToBcm(fileName, + tempFileName); + } - if (!success) - { - success = BCM.JsonToBcm(fileName, - tempFileName); - } + if (!success) + { + lbOutput.Items.Add("Couldn't parse JSON"); + return; + } - if (!success) - { - lbOutput.Items.Add("Couldn't parse JSON"); - return; - } + var memFile = MemoryFileList.First(m => m.JsonFilePath == fileName); - var memFile = MemoryFileList.First(m => m.JsonFile == fileName); + var fileBytes = File.ReadAllBytes(tempFileName).ToList(); + fileBytes.RemoveRange(0, BitConverter.ToInt32(fileBytes.ToArray(), 0x18) + 36); - var fileBytes = File.ReadAllBytes(tempFileName).ToList(); - fileBytes.RemoveRange(0, BitConverter.ToInt32(fileBytes.ToArray(), 0x18) + 36); + if (memFile.NewAddress == 0) + { + Console.WriteLine("Allocating memory space..."); + var newAddress = Memory.AllocAndWriteFileToMemory(fileBytes.ToArray()); + Console.WriteLine("Got some space at: " + newAddress.ToString("X")); + memFile.NewAddress = newAddress; + Console.WriteLine("Wrote file to: " + newAddress.ToString("X")); - if (memFile.NewAddress == 0) + foreach (var pointer in memFile.Pointers) { - Console.WriteLine("Allocating memory space..."); - var newAddress = Memory.AllocAndWriteFileToMemory(fileBytes.ToArray()); - Console.WriteLine("Got some space at: " + newAddress.ToString("X")); - memFile.NewAddress = newAddress; - Console.WriteLine("Wrote file to: " + newAddress.ToString("X")); - - foreach (var pointer in memFile.Pointers) - { - Memory.Write(pointer, BitConverter.GetBytes(memFile.NewAddress)); - Console.WriteLine("Updated pointer at: " + pointer.ToString("X")); - } + Memory.Write(pointer, BitConverter.GetBytes(memFile.NewAddress)); + Console.WriteLine("Updated pointer at: " + pointer.ToString("X")); } - - Memory.Write(memFile.NewAddress, fileBytes.ToArray()); - Console.WriteLine("Wrote file to: " + memFile.NewAddress.ToString("X")); - writeToOutput("Wrote: " + Path.GetFileName(fileName) + " to " + memFile.Name + " - " + - memFile.NewAddress.ToString("X")); } + + Memory.Write(memFile.NewAddress, fileBytes.ToArray()); + Console.WriteLine("Wrote file to: " + memFile.NewAddress.ToString("X")); + WriteToOutput("Wrote: " + Path.GetFileName(fileName) + " to " + memFile.UassetFileName + " - " + + memFile.NewAddress.ToString("X")); } private void cbBAC_SelectedIndexChanged(object sender, EventArgs e) { - if (MemoryFileList.Exists(m => m.Name == cbBAC.SelectedItem.ToString())) + if (MemoryFileList.Exists(m => m.UassetFileName == cbBAC.SelectedItem.ToString())) { - lBAC.Text = MemoryFileList.First(m => m.Name == cbBAC.SelectedItem.ToString()).JsonFile; + lBAC.Text = MemoryFileList.First(m => m.UassetFileName == cbBAC.SelectedItem.ToString()).JsonFilePath; } if (lBAC.Text == "") @@ -369,9 +383,9 @@ private void cbBAC_SelectedIndexChanged(object sender, EventArgs e) private void cbBCM_SelectedIndexChanged(object sender, EventArgs e) { - if (MemoryFileList.Exists(m => m.Name == cbBCM.SelectedItem.ToString())) + if (MemoryFileList.Exists(m => m.UassetFileName == cbBCM.SelectedItem.ToString())) { - lBCM.Text = MemoryFileList.First(m => m.Name == cbBCM.SelectedItem.ToString()).JsonFile; + lBCM.Text = MemoryFileList.First(m => m.UassetFileName == cbBCM.SelectedItem.ToString()).JsonFilePath; } if (lBCM.Text == "") @@ -398,11 +412,8 @@ private void bRestore_Click(object sender, EventArgs e) cbBAC.Items.Clear(); cbBCM.Items.Clear(); MemoryFileList = new List(); - writeToOutput("Game restored"); - } - - private void MainForm_Load(object sender, EventArgs e) - { + WriteToOutput("Game restored"); + lBAC.Text = lBCM.Text = "No JSON-file set."; } } @@ -410,8 +421,8 @@ public class MemoryFile { public long OriginalAddress { get; set; } public long NewAddress { get; set; } - public string Name { get; set; } - public string JsonFile { get; set; } + public string UassetFileName { get; set; } + public string JsonFilePath { get; set; } public MemoryFileType Type { get; set; } public List Pointers { get; set; } } diff --git a/RealtimeEditor/MainForm.resx b/RealtimeEditor/MainForm.resx index 1af7de1..f607686 100644 --- a/RealtimeEditor/MainForm.resx +++ b/RealtimeEditor/MainForm.resx @@ -117,4 +117,20 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 114, 17 + + + When in Training Mode, click this to find character scripts (files in Originals folder) in the game's memory. +NOTE: If it only finds Unknowns, then you might have the wrong JSON files or you might not have the .uasset files in the Originals folder. +(Be sure that you have the same version that the game is using!) + + + + 17, 17 + + + Select the associated JSON file for the uasset indicated in the ComboBox above. + \ No newline at end of file diff --git a/RealtimeEditor/Memory/Memory.cs b/RealtimeEditor/Memory/Memory.cs index b789f2e..29b4ca3 100644 --- a/RealtimeEditor/Memory/Memory.cs +++ b/RealtimeEditor/Memory/Memory.cs @@ -230,7 +230,7 @@ public List MemoryScan(byte[] bytesToFind) Parallel.ForEach(regions, memoryRegion => { - if (memoryRegion.Size < 2000000) + if (memoryRegion.Size < 4000000) { foundAddresses.AddRange( MemoryScan(bytesToFind, diff --git a/RealtimeEditor/Program.cs b/RealtimeEditor/Program.cs index 4d8c9d4..ad84ae5 100644 --- a/RealtimeEditor/Program.cs +++ b/RealtimeEditor/Program.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Threading.Tasks; using System.Windows.Forms; @@ -14,9 +15,32 @@ static class Program [STAThread] static void Main() { + AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssembly; Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new MainForm()); } + + private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args) + { + var executingAssembly = Assembly.GetExecutingAssembly(); + var assemblyName = new AssemblyName(args.Name); + + var path = assemblyName.Name + ".dll"; + if (assemblyName.CultureInfo.Equals(System.Globalization.CultureInfo.InvariantCulture) == false) + { + path = $@"{assemblyName.CultureInfo}\{path}"; + } + + using (var stream = executingAssembly.GetManifestResourceStream(path)) + { + if (stream == null) + return null; + + var assemblyRawBytes = new byte[stream.Length]; + stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length); + return Assembly.Load(assemblyRawBytes); + } + } } } diff --git a/RealtimeEditor/RealtimeEditor.csproj b/RealtimeEditor/RealtimeEditor.csproj index 20a7aeb..d81be1d 100644 --- a/RealtimeEditor/RealtimeEditor.csproj +++ b/RealtimeEditor/RealtimeEditor.csproj @@ -22,6 +22,7 @@ DEBUG;TRACE prompt 4 + bin\Debug\RealtimeEditorDocs.xml AnyCPU @@ -91,11 +92,11 @@ - \ No newline at end of file diff --git a/UnitTest/UnitTest.cs b/UnitTest/UnitTest.cs index 3f26ac4..aa76bdd 100644 --- a/UnitTest/UnitTest.cs +++ b/UnitTest/UnitTest.cs @@ -18,6 +18,23 @@ public class UnitTest BAC/BCM/BCH (uasset) files in the correct folder (UnitTest/Bin/Debug/Originals/...) */ + [TestMethod] + public void OldModifiedBACJson_ShouldReadOldNames() + { + var filePath = "Test Files/BAC_RYU.json"; + + try + { + var isBacSuccessful = BAC.JsonToBac(filePath, "fileOutput (unused in test)"); + + Assert.IsTrue(isBacSuccessful); + } + catch (System.Exception e) + { + Debug.WriteLine("Caught exception:\n" + e.Message); + } + } + [TestMethod] public void TestBAC() { @@ -29,7 +46,7 @@ public void TestBAC() List exceptions = new List(); - foreach (var file in Directory.GetFiles(@"Originals\BAC")) + foreach (var file in Directory.GetFiles(@"Originals", @"BAC_???.uasset")) { var originalBytes = File.ReadAllBytes(file); var bac = BAC.FromUassetFile(file); @@ -78,9 +95,9 @@ public void TestBAC() } [TestMethod] - public void TestBCMeff() + public void TestBACeff() { - foreach (var file in Directory.GetFiles(@"Originals\BACeff")) + foreach (var file in Directory.GetFiles(@"Originals", @"BAC_???_eff.uasset")) { var originalBytes = File.ReadAllBytes(file); var bac = BAC.FromUassetFile(file); @@ -101,7 +118,7 @@ public void TestBCMeff() [TestMethod] public void TestBCM() { - foreach (var file in Directory.GetFiles(@"Originals\BCM")) + foreach (var file in Directory.GetFiles(@"Originals", @"BCM*")) { var originalBytes = File.ReadAllBytes(file); var bcm = BCM.FromUassetFile(file);