Skip to content

Commit

Permalink
Better handling of stash gems (#60)
Browse files Browse the repository at this point in the history
Now, the item in question includes the sockets, so the delete removes it and it's gem.
  • Loading branch information
mburbea authored Sep 16, 2020
1 parent 5b351c8 commit 161ec80
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 33 deletions.
2 changes: 1 addition & 1 deletion KoAR.Core/Item.cs
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ public IEnumerable<Socket> GetSockets()
{
0 => Definition.GetSockets(),
1 when Definition.SocketTypes.Length == 1 => new[] { new Socket(Definition.SocketTypes[0], ItemSockets.Gems[0]) }, // trivial case.
_ => Inner(Definition.SocketTypes, ItemSockets.Gems.AsSpan().ToArray())
_ => Inner(Definition.SocketTypes, ItemSockets.Gems.ToArray())
};

static IEnumerable<Socket> Inner(string sockets, Gem[] gems)
Expand Down
4 changes: 2 additions & 2 deletions KoAR.Core/RemasterStashItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ namespace KoAR.Core
{
public class RemasterStashItem : StashItem
{
public RemasterStashItem(GameSave gameSave, int offset, int dataLength) : base(gameSave, offset, dataLength)
public RemasterStashItem(GameSave gameSave, int offset, int dataLength, Gem[] gems) : base(gameSave, offset, dataLength, gems)
{
}

private ref InventoryState State => ref Unsafe.As<byte, InventoryState>(ref Bytes[Offsets.IsStolen]);

public override bool HasCustomName => (Bytes[Offsets.HasCustomName] & 16) != 0;
public override bool HasCustomName => (Bytes[Offsets.HasCustomName] & 16) == 16;

public override bool IsStolen => (State & InventoryState.Stolen) == InventoryState.Stolen;
}
Expand Down
39 changes: 26 additions & 13 deletions KoAR.Core/Stash.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,30 +46,43 @@ public Stash(GameSave gameSave, int offset)
{
if (Amalur.ItemDefinitions.ContainsKey(MemoryUtilities.Read<uint>(_gameSave.Body, _offset + indices[i])))
{
var item = CreateStashItem(gameSave, _offset + indices[i], indices[i + 1] - indices[i]);
Items.Add(item);
for(uint j = 0; j < item.GemCount; j++)
var itemStart = indices[i];
var gems = Array.Empty<Gem>();
if (_gameSave.Body[_offset + indices[i + 1] - 1] != 0xFF)
{
i++;
if (Amalur.GemDefinitions.ContainsKey(MemoryUtilities.Read<uint>(_gameSave.Body, _offset + indices[i])))
var gemList = new List<Gem>();
var ix = _offset + indices[i + 1] - 4;
uint handle;
while ((handle = MemoryUtilities.Read<uint>(_gameSave.Body, ix)) > 4u)
{
ix -= 4;
}
for (uint j = 0; j < handle; j++)
{
item.Gems.Add(new Gem(_gameSave, _offset + indices[i]));
i++;
if (Amalur.GemDefinitions.ContainsKey(MemoryUtilities.Read<uint>(_gameSave.Body, _offset + indices[i])))
{
gemList.Add(new Gem(_gameSave, _offset + indices[i]));
}
}
gems = gemList.ToArray();
}
var item = CreateStashItem(gameSave, _offset + itemStart, (i + 1 == indices.Count ? DataLength : indices[i + 1]) - itemStart, gems);
Items.Add(item);
}

}
// ok we might read this twice, who cares.
if (Amalur.ItemDefinitions.ContainsKey(MemoryUtilities.Read<uint>(_gameSave.Body, _offset + indices[^1])))
{
Items.Add(CreateStashItem(gameSave, _offset + indices[^1], DataLength - indices[^1]));
Items.Add(CreateStashItem(gameSave, _offset + indices[^1], DataLength - indices[^1], Array.Empty<Gem>()));
}
}
}

static StashItem CreateStashItem(GameSave gameSave, int offset, int datalength) => gameSave.IsRemaster
? new RemasterStashItem(gameSave, offset, datalength)
: new StashItem(gameSave, offset, datalength);
static StashItem CreateStashItem(GameSave gameSave, int offset, int datalength, Gem[] gems) => gameSave.IsRemaster
? new RemasterStashItem(gameSave, offset, datalength, gems)
: new StashItem(gameSave, offset, datalength, gems);

public int DataLength
{
Expand All @@ -96,7 +109,7 @@ public StashItem AddItem(ItemDefinition type)
// 2. We blow away everything when we do this operation anyway.
// 3. We rely on the fact that the game will regenerate the ItemBuff section when the stash spawns the item. (Primarily to avoid thinking about instanceIds...)
Span<byte> temp = stackalloc byte[25 + type.PlayerBuffs.Length * 8];
var sectionHeader = _gameSave.IsRemaster ? 0x04_0Aul : 0x03_0Aul;
var sectionHeader = _gameSave.IsRemaster ? 0x04_0Aul : 0x03_0Aul;
MemoryUtilities.Write(temp, 0, type.TypeId | sectionHeader << 32);
MemoryUtilities.Write(temp, 10, type.MaxDurability);
temp[14] = 1;
Expand All @@ -117,7 +130,7 @@ public StashItem AddItem(ItemDefinition type)
_gameSave.Body = MemoryUtilities.ReplaceBytes(_gameSave.Body, offset, 0, temp);
DataLength += temp.Length;
Count++;
Items.Add(CreateStashItem(_gameSave, offset, temp.Length));
Items.Add(CreateStashItem(_gameSave, offset, temp.Length, Array.Empty<Gem>()));
_gameSave.UpdateOffsets(offset, temp.Length);
_gameSave.UpdateDataLengths(offset, temp.Length);
return Items[^1];
Expand Down
2 changes: 1 addition & 1 deletion KoAR.Core/StashItem.ItemBuffMemory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public ItemBuffMemory(StashItem stashItem, int endOfSection)
(_stashItem, _endOfSection) = (stashItem, endOfSection);
int count = Count;
var firstBuff = Offsets.FirstItemBuff;
for(int i = 0; i < count; i++)
for (int i = 0; i < count; i++)
{
var buffId = MemoryUtilities.Read<uint>(Bytes, firstBuff + (i * 16) + 4);
List.Add(Amalur.GetBuff(buffId));
Expand Down
25 changes: 9 additions & 16 deletions KoAR.Core/StashItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@ public partial class StashItem : IItem
protected byte[] Bytes { get; }
public List<Buff> PlayerBuffs { get; } = new List<Buff>();

public uint GemCount { get; }
public List<Gem> Gems { get; } = new List<Gem>();
public Gem[] Gems { get; }

public StashItem(GameSave gameSave, int offset, int dataLength)
public StashItem(GameSave gameSave, int offset, int dataLength, Gem[] gems)
{
ItemOffset = offset;
Bytes = gameSave.Body.AsSpan(offset, dataLength).ToArray();
Expand All @@ -27,18 +26,12 @@ public StashItem(GameSave gameSave, int offset, int dataLength)
{
ItemName = Encoding.Default.GetString(Bytes, Offsets.Name, NameLength);
}
int socketsStart = Bytes.Length - 1;
if (Bytes[^1] != 0xFF)
{
int i = Bytes.Length - 4;
uint handle;
while ((handle = MemoryUtilities.Read<uint>(Bytes, i)) > 4)
{
i -= 4;
}
GemCount = handle;
socketsStart = i - 2;
}
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;
}
Expand Down Expand Up @@ -78,7 +71,7 @@ public StashItem(GameSave gameSave, int offset, int dataLength)

public IEnumerable<Socket> GetSockets()
{
return GemCount switch
return Gems.Length switch
{
0 => Definition.GetSockets(),
1 when Definition.SocketTypes.Length == 1 => new[] { new Socket(Definition.SocketTypes[0], Gems[0]) }, // trivial case.
Expand Down

0 comments on commit 161ec80

Please sign in to comment.