public ItemBuffMemory(StashItem stashItem, int endOfSection) { (_stashItem, _endOfSection) = (stashItem, endOfSection); var data = Bytes.AsSpan(Offsets.ItemBuffCount); BuffInstance.ReadList(ref data); // activeBuffs BuffInstance.ReadList(ref data); // inactiveBuffs var selfBuffs = BuffDuration.ReadList(ref data); foreach (var(buffId, _) in selfBuffs) { List.Add(Amalur.GetBuff(buffId)); } }
public Item(GameSave gameSave, int typeIdOffset, int offset, int dataLength, int itemBuffsOffset, int itemBuffsLength, int itemGemsOffset, int itemGemsLength) { (_gameSave, TypeIdOffset, ItemOffset) = (gameSave, typeIdOffset, offset); _levelShiftOffset = (byte)(8 * gameSave.Body[TypeIdOffset + 10]); Bytes = _gameSave.Body.AsSpan(offset, dataLength).ToArray(); ItemSockets = new(gameSave, itemGemsOffset, itemGemsLength); ItemBuffs = new(gameSave, this, itemBuffsOffset, itemBuffsLength); var span = Bytes.AsSpan(Offsets.BuffCount); foreach (var(buffId, _) in BuffDuration.ReadList(ref span)) { PlayerBuffs.Add(Amalur.GetBuff(buffId)); } if (HasCustomName) { ItemName = _gameSave.Encoding.GetString(Bytes, Offsets.Name, NameLength); } }
public StashItem(GameSave gameSave, int offset, int dataLength, Gem[] gems) { ItemOffset = offset; Bytes = gameSave.Body.AsSpan(offset, dataLength).ToArray(); var span = Bytes.AsSpan(Offsets.BuffCount); foreach (var(buffId, _) in BuffDuration.ReadList(ref span)) { PlayerBuffs.Add(Amalur.GetBuff(buffId)); } if (HasCustomName) { ItemName = gameSave.Encoding.GetString(Bytes, Offsets.Name, NameLength); } Gems = gems; // socket section is either FF // or 20 02, followed by int32 count, and int32 handle per gem. int socketsStart = gems.Length == 0 ? Bytes.Length - 1 : gems[0].ItemOffset - offset - (4 * (1 + gems.Length)) - 2; ItemBuffs = Bytes[Offsets.HasItemBuffs] == 0x14 ? new ItemBuffMemory(this, socketsStart) : Definition.ItemBuffs; }
static void Main() { var path = @"C:\Program Files (x86)\Steam\userdata\107335713\102500\remote\9190114save98.sav"; var sw = Stopwatch.StartNew(); Amalur.ReadFile(path); var bytes = Amalur.Bytes; var interest = new[] { "Primal Chakrams", "Mastercrafted Prismere Chakrams" }; var mems = Amalur.Items .Where(x => x.HasCustomName) //&& x.ItemId == 0x19_02_1C) .ToArray(); //Console.Read(); //ReadOnlySpan<byte> itemDesc = new byte[5] { 0x06, 0x2D, 0x75, 0x00, 0x05 }; //var indices = GetAllIndices(bytes, itemDesc).GroupBy(x => bytes[x + 27]).ToDictionary(x => x.Key, x => x.Count()); ReadOnlySpan <byte> donor = new byte[] { 0x06, 0x2D, 0x75, 0x00, 0x05, 0x3B, 0x00, 0x00, 0x00, 0x04, 0x05, 0xDD, 0x02, 0xF1, 0x1D, 0x20, 0x00, 0x83, 0x06, 0x0B, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x99, 0xFB, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0xF1, 0x1D, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; ReadOnlySpan <byte> donor2 = new byte[] { 0x06, 0x2D, 0x75, 0x00, 0x05, 0x3B, 0x00, 0x00, 0x00, 0x59, 0x00, 0x2E, 0x01, 0xFA, 0x78, 0x07, 0x00, 0x24, 0xA0, 0x15, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x99, 0xFB, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0xFA, 0x78, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; var ore = new[] { "Iron", "Steel", "Azurite", "Sylvanite", "Prismere" }; var wood = new[] { "Birch", "Elm", "Oak", "Ash", "Ebony" }; var metal = new[] { "Bronze", "Copper", "Silver", "Gold", "Platinum" }; foreach (var item in mems) { var material = item.Category switch { EquipmentCategory.Talisman => metal, EquipmentCategory.Buckler => wood, EquipmentCategory.Longbow => wood, EquipmentCategory.Staff => wood, EquipmentCategory.Sceptre => wood, _ => ore }; item.ItemName = $"{item.ItemName} [Lvl {item.Level}]"; item.WriteToCsv(); } return; var arrays = new List <byte[]> [mems.Length]; var j = 0; foreach (var chakrams in mems) { arrays[j] = new List <byte[]>(); var foo = chakrams.ItemBytes.AsSpan(0, 4); ReadOnlySpan <byte> marker = new byte[] { 0x06, 0x2D, 0x75, 0x00, 0x05 }; var last = 0; var start = Amalur.Bytes.AsSpan().IndexOf(foo); Console.WriteLine($"{chakrams.Category} {chakrams.ItemName}"); while (start != -1) { int next = -1; start += last; if (Amalur.Bytes[start + 4] == 0x0B) { next = Amalur.Bytes.AsSpan(start + 13).IndexOf(Amalur.Bytes.AsSpan(start + 4, 9)); } var end = arrays[j].Count switch { 0 => 59, _ when next != -1 => next + 9, _ => 150 }; arrays[j].Add(Amalur.Bytes.AsSpan(start + 4, end - 4).ToArray()); last = start + end; start = Amalur.Bytes.AsSpan(last).IndexOf(foo); } j++; } for (int i = 0; i < arrays[0].Count; i++) { var sample = arrays[0][i]; var isEqual = true; foreach (var list in arrays.Skip(1)) { if (!list[i].SequenceEqual(sample)) { isEqual = false; break; } } if (!isEqual) { Console.WriteLine($"Section {i}"); PrintRuler(); foreach (var(list, mem) in arrays.Zip(mems)) { Console.WriteLine($"{mem.Category} {BinaryPrimitives.ReadInt32BigEndian(mem.ItemBytes):X8} {mem.TypeId:X6} {mem.Level}"); PrintByteString(list[i]); Console.WriteLine(); } } else { Console.WriteLine($"Section {i} is identical"); } } Console.WriteLine(sw.Elapsed); //Amalur.SaveFile(path); // var items = mems // .Select(x => (x.ItemName, ItemId:x.ItemBytes.AsSpan(0, 4).ToArray())).OrderBy(x=>x.ItemName).ToArray(); // //var items = new[] { "92 05 FC 00 0B 00 00 00", // // "A2 05 FB 00 0B 00 00 00", // // "91 05 EF 00 0B 00 00 00" }.Select(GetBytesFromText).ToArray(); // var offsets = items.Select(x => GetAllIndices(bytes, x.ItemId)).ToArray(); // var poop = bytes.AsSpan(offsets[0][0] + 8, 5); // for (int i = 0; i < offsets.Length; i++) // { // List<int> offset = (List<int>)offsets[i]; // Debug.Assert(bytes.AsSpan(offset[0] + 8, 5).SequenceEqual(poop),items[i].ItemName); // } // bytes[offsets[0][0] + 4] = 0xF1; // bytes[offsets[0][0] + 5] = 0x1D; // bytes[offsets[0][0] + 6] = 0x20; // bytes[offsets[0][0] + 7] = 0x00; // //offsets[0] = offsets[0].Except( new[]{ // // 144844 // // ,156940 // // ,214472 // // ,233348 // // ,243325 // // ,253623 // // ,266855 // // ,270662 }).ToList(); // bytes[offsets[0][0] + 18] = 0x2a; // //bytes[offsets[0][0] + 34] = 0xf1; // //bytes[offsets[0][0] + 35] = 0x1d; // //bytes[offsets[0][0] + 36] = 0x20; // //bytes[offsets[0][0] + 37] = 0x00; // Amalur.SaveFile(path); // return; // var core = GetBytesFromText("84 60 28 00 00"); // var equipSeq = new byte[] { 0x68, 0xD5, 0x24, 0x00, 0x03 }; // const int magicNumber = 0x00FF00FF; // static string Converter(int x)=> ((x = x >> 16 | x << 16) >> 8 & magicNumber | (x & magicNumber) << 8).ToString("X8"); // for (int i= 0; i <1; i++) // { // Console.WriteLine(new string('-', 120)); // var output = new byte[items.Length][]; // Console.WriteLine(new string('*', 120)); // Console.WriteLine($"Section {i}"); // Console.WriteLine(new string('*', 120)); // Console.WriteLine(string.Join(' ', Enumerable.Range(0, 40).Select(x => x.ToString("D2")))); // Console.WriteLine(new string('-', 120)); // var buffer = new byte[9]; // for (int j = 0; j < offsets.Length; j++) // { // if (offsets[j].Count <= i) continue; // int ix = offsets[j][i]; // bytes[(ix + 4)..(ix + 13)].CopyTo(buffer, 0); // ReadOnlySpan<byte> supportSeq = new byte[] { 0x68, 0xD5, 0x24, 0x00, 0x03 }; // ReadOnlySpan<byte> coreSeq = new byte[] { 0x84, 0x60, 0x28, 0x00, 0x00 }; // if (bytes.AsSpan(ix + 8, 5).SequenceEqual(supportSeq)) // { // var itemMemory = mems[j]; // var offset = new ItemMemoryInfo.Offset(itemMemory.EffectCount); // Console.WriteLine($"--- Item {j}: {items[j].ItemName} Support component sequence"); // Console.WriteLine($"byte13:{bytes[ix + 13]:X2}"); // Console.WriteLine($"Post Effect bytes:{GetBytesString(bytes[(ix + offset.PostEffect)..(ix + offset.CurrentDurability)])}"); // Console.WriteLine($"After Max Durability:{GetBytesString(bytes[(ix + offset.MaxDurability + 4)..(ix + offset.MaxDurability + 8)])}"); // Console.WriteLine($"byte before customName:{bytes[ix+offset.HasCustomName - 1]:X2}"); // continue; // } // else if (bytes.AsSpan(ix + 8, 5).SequenceEqual(coreSeq)) // { // Console.WriteLine($"--- Item {j}: {items[j].ItemName} Core component sequence"); // continue; // } // var nextPos = bytes.AsSpan(ix + 13).IndexOf(buffer); // output[j] = bytes[ix..(ix + 113 + nextPos - 4)]; // Console.WriteLine($"--- Item {j}: {items[j].ItemName} offset {ix} ---"); // Console.WriteLine(string.Join(' ', output[j].Select(x => x.ToString("X2")))); // } // if (output.Any(x => x is null || x.Length == 0)) continue; // var smallest = output.FirstOrDefault(x => x.Length == output.Min(y => y.Length)); // if (output.All(x => x.AsSpan(8, smallest.Length - 8).SequenceEqual(smallest.AsSpan(8, smallest.Length - 8)))) // { // Console.WriteLine($"****Section {i} is identical****"); // } // } // return; // static List<int> GetAllIndices(ReadOnlySpan<byte> data, ReadOnlySpan<byte> sequence) // { // var results = new List<int>(); // int ix = data.IndexOf(sequence); // int start = 0; // while (ix != -1) // { // results.Add(start + ix); // start += ix + sequence.Length; // ix = data.Slice(start).IndexOf(sequence); // } // return results; // } //} } } }