public static BCMFile FromUassetFile(string fileName) { byte[] fileBytes = File.ReadAllBytes(fileName); byte[] UassetHeaderBytes = GetUassetHeader(fileBytes); fileBytes = CreateGameBCMFromFile(fileBytes); List<Move> MoveList = new List<Move>(); List<CancelList> CancelLists = new List<CancelList>(); List<Input> InputList = new List<Input>(); List<Charge> ChargeList = new List<Charge>(); 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(0xC, SeekOrigin.Begin); 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<int> ChargeAddresses = new List<int>(); 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<int> InputAddresses = new List<int>(); 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<int> moveEntryOffsets = new List<int>(); moveEntryOffsets.Add(inFile.ReadInt32()); moveEntryOffsets.Add(inFile.ReadInt32()); moveEntryOffsets.Add(inFile.ReadInt32()); moveEntryOffsets.Add(inFile.ReadInt32()); var entries = new List<InputEntry>(); 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<InputPart> parts = new List<InputPart>(); 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 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, 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 = inFile.ReadInt32(), Unknown20 = inFile.ReadSingle(), Unknown21 = inFile.ReadSingle(), Unknown22 = inFile.ReadInt32(), Unknown23 = inFile.ReadInt32(), Unknown24 = inFile.ReadInt32(), Unknown25 = inFile.ReadInt32(), Unknown26 = inFile.ReadInt16(), Unknown27 = 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 + "\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.Unknown27 + "\nUnknown28: " + thisMove.Unknown28 + "\n\n"); } inFile.BaseStream.Seek(startOfCancelLists, SeekOrigin.Begin); List<int> CancelAddresses = new List<int>(); 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<Cancel> cancels = new List<Cancel>(); 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; }