private static unsafe void CPE_Part56(byte *part5ptr_t, byte *part6ptr_t, Database.Underground2 db) { int len5 = *(int *)(part5ptr_t + 4); // size of part5 int len6 = *(int *)(part6ptr_t + 4); // size of part6 if (len5 + 8 < Assert.CPPart5_AssertSize) { throw new FileLoadException("Detected corrupted GlobalB.lzc CarParts block. Unable to load database."); } if (len6 + 8 < Assert.CPPart6_AssertSize) { throw new FileLoadException("Detected corrupted GlobalB.lzc CarParts block. Unable to load database."); } // Exclude padding while (*(int *)(part5ptr_t + len5 + 4) == 0) { len5 -= 4; } while (*(int *)(part6ptr_t + len6 + 4) == 0) { len6 -= 4; } len6 = len6 / 0xE * 0xE + 8; int off5 = 8; // offset in part5 int off6 = 8; // offset in part6 int size = 0; // size of one part in part6 // Validation check int check = *(part6ptr_t + len6 - 7) + 1; int total = len5 / 4; if (check < total) { len5 = check * 4 + 8; } db.SlotTypes.Part56 = new List <Part56>(); var CarCNames = new List <uint>(); foreach (var car in db.CarTypeInfos.Collections) { CarCNames.Add(car.BinKey); } while (off5 < len5 + 8 && db.SlotTypes.Part56.Count < 75) { uint ckey = *(uint *)(part5ptr_t + off5); if (ckey == 0) { break; // padding means end } bool IsCar = false; byte current = 0; byte index = *(part6ptr_t + off6 + 7); while (true) { if (off6 + size + 7 >= len6) { break; } current = *(part6ptr_t + off6 + size + 7); if (current != index) { break; } else { size += 0xE; } } if (CarCNames.Contains(ckey)) { IsCar = true; } var Part = new Part56(ckey, part6ptr_t + off6, size, IsCar); db.SlotTypes.Part56.Add(Part); off5 += 4; off6 += size; size = 0; } }
/// <summary> /// Writes all car parts into the Global data. /// </summary> /// <param name="db">Database with classes.</param> /// <param name="bw">BinaryWriter for writing data.</param> private static void I_CarParts(Database.Carbon db, BinaryWriter bw) { bw.Write(Global.CarParts); bw.Write(0xFFFFFFFF); // temp size int initial_size = (int)bw.BaseStream.Position; int CarIDOffset = initial_size + 0x30; int PartNumOffset = initial_size + 0x40; int padding = 0; var keylists = new List <uint>(); var Intermid56 = new List <Part56>(); var UsedPart56 = new List <Part56>(); // Copy for processing for (int a1 = 0; a1 < db.SlotTypes.Part56.Count; ++a1) { Intermid56.Add(db.SlotTypes.Part56[a1].MemoryCast()); } // Go through all cartypeinfo, set correct usagetype and keys foreach (var car in db.CarTypeInfos.Collections) { bool CarDoesExist = false; int index = 0; uint ckey = car.BinKey; uint okey = Bin.Hash(car.OriginalName); keylists.Add(ckey); for (index = 0; index < Intermid56.Count; ++index) { if (okey == Intermid56[index].Key) { CarDoesExist = true; break; } } if (CarDoesExist) { if (ckey != okey) { Intermid56[index].Key = ckey; } if (car.Modified && car.UsageType != Intermid56[index].Usage) { Intermid56[index].SetUsage(car.UsageType); } } else { var Class = new Part56(car.CollectionName, (byte)index, car.UsageType); Intermid56.Add(Class); } } // Make new list of only used Part56 to write byte curlength = 0; for (int a1 = 0; a1 < Intermid56.Count; ++a1) { if (Intermid56[a1].IsCar && !keylists.Contains(Intermid56[a1].Key)) { continue; } Intermid56[a1].SetIndex(curlength++); UsedPart56.Add(Intermid56[a1]); } // Write parts 1-4 bw.Write(db.SlotTypes.Part0.Data); bw.Write(db.SlotTypes.Part1.Data); bw.Write(db.SlotTypes.Part2.Data); bw.Write(db.SlotTypes.Part3.Data); bw.Write(db.SlotTypes.Part4.Data); // Write part 5 int part5size = UsedPart56.Count * 4; padding = 0x10 - ((part5size + 8) % 0x10); if (padding == 0x10) { padding = 0; } part5size += padding; bw.Write(CarParts.Part5); bw.Write(part5size); for (int a1 = 0; a1 < UsedPart56.Count; ++a1) { bw.Write(UsedPart56[a1].Key); } for (int a1 = 0; a1 < padding; ++a1) { bw.Write((byte)0); } // Write part 6 int part6size = 0; bw.Write(CarParts.Part6); int size6off = (int)bw.BaseStream.Position; bw.Write(0xFFFFFFFF); // temp size for (int a1 = 0; a1 < UsedPart56.Count; ++a1) { bw.Write(UsedPart56[a1].Data); part6size += UsedPart56[a1].Data.Length; } padding = 0x10 - ((part6size + 8) % 0x10); if (padding == 0x10) { padding = 0; } for (int a1 = 0; a1 < padding; ++a1) { bw.Write((byte)0); } part6size += padding; bw.BaseStream.Position = size6off; bw.Write(part6size); // Quick editing bw.BaseStream.Position = CarIDOffset; bw.Write(UsedPart56.Count); bw.BaseStream.Position = PartNumOffset; bw.Write(part6size / 4); bw.BaseStream.Position = initial_size - 4; bw.Write((int)bw.BaseStream.Length - initial_size); bw.BaseStream.Position = bw.BaseStream.Length; }
private static unsafe void CPE_Part56(byte *part5ptr_t, byte *part6ptr_t, Database.MostWanted db) { int len5 = *(int *)(part5ptr_t + 4) + 8; // size of part5 int len6 = *(int *)(part6ptr_t + 4); // size of part6 // Exclude padding while (*(int *)(part5ptr_t + len5 - 4) == 0) { len5 -= 4; } while (*(int *)(part6ptr_t + len6 + 4) == 0) { len6 -= 4; } len6 = len6 / 0xE * 0xE + 8; int off5 = 8; // offset in part5 int off6 = 8; // offset in part6 int size = 0; // size of one part in part6 // Validation check int check = *(part6ptr_t + len6 - 7) + 1; int total = (len5 - 8) / 4; if (check < total) { len5 = check * 4 + 8; } db.SlotTypes.Part56 = new List <Part56>(); var CarCNames = new List <uint>(); foreach (var car in db.CarTypeInfos.Collections) { CarCNames.Add(car.BinKey); } while (off5 < len5) { uint ckey = *(uint *)(part5ptr_t + off5); if (ckey == 0) { break; // padding means end } bool IsCar = false; byte current = 0; byte index = *(part6ptr_t + off6 + 7); while (true) { if (off6 + size + 7 >= len6) { break; } current = *(part6ptr_t + off6 + size + 7); if (current != index) { break; } else { size += 0xE; } } if (CarCNames.Contains(ckey)) { IsCar = true; } var Part = new Part56(ckey, part6ptr_t + off6, size, IsCar); db.SlotTypes.Part56.Add(Part); off5 += 4; off6 += size; size = 0; } }