diff --git a/Minecraft.Server.FourKit/Inventory/Inventory.cs b/Minecraft.Server.FourKit/Inventory/Inventory.cs index f98cafbd..52fda5fc 100644 --- a/Minecraft.Server.FourKit/Inventory/Inventory.cs +++ b/Minecraft.Server.FourKit/Inventory/Inventory.cs @@ -60,8 +60,17 @@ public class Inventory : IEnumerable _items[i]?.UnbindFromInventory(); if (id > 0 && count > 0) { - _items[i] = new ItemStack(id, count, (short)aux); - _items[i]!.BindToInventory(this, i); + if (_items[i] == null) + { + _items[i] = new ItemStack(id, count, (short)aux); + } + else + { + _items[i]!.setTypeId(id); + _items[i]!.setAmount(count); + _items[i]!.setDurability((short)aux); + } + _items[i]!.BindToInventory(this, i); //should we unbind and rebind or just keep the bind? } else { diff --git a/Minecraft.Server.FourKit/Inventory/PlayerInventory.cs b/Minecraft.Server.FourKit/Inventory/PlayerInventory.cs index 065b1926..e5941146 100644 --- a/Minecraft.Server.FourKit/Inventory/PlayerInventory.cs +++ b/Minecraft.Server.FourKit/Inventory/PlayerInventory.cs @@ -19,9 +19,14 @@ public class PlayerInventory : Inventory private int _heldItemSlot; internal HumanEntity? _holder; + private int[] syncBuffer; + private GCHandle syncBufferHandle; + internal PlayerInventory() : base("Player", InventoryType.PLAYER, INVENTORY_SIZE) { + this.syncBuffer = new int[121]; + this.syncBufferHandle = GCHandle.Alloc(this.syncBuffer, GCHandleType.Pinned); } protected internal override void EnsureSynced() @@ -30,22 +35,17 @@ public class PlayerInventory : Inventory return; int entityId = _holder.getEntityId(); - int[] buf = new int[121]; - var gh = GCHandle.Alloc(buf, GCHandleType.Pinned); - try - { - NativeBridge.GetPlayerInventory(entityId, gh.AddrOfPinnedObject()); - } - finally - { - gh.Free(); - } + + NativeBridge.GetPlayerInventory(entityId, this.syncBufferHandle.AddrOfPinnedObject()); + + byte[]? metadataBuffer = null; + GCHandle? metadataBufferHandle = null; for (int i = 0; i < INVENTORY_SIZE; i++) { - int id = buf[i * 3 + 0]; - int aux = buf[i * 3 + 1]; - int packed = buf[i * 3 + 2]; + int id = this.syncBuffer[i * 3 + 0]; + int aux = this.syncBuffer[i * 3 + 1]; + int packed = this.syncBuffer[i * 3 + 2]; ushort count = (ushort)((packed >> 8) & 0xFFFF); @@ -55,22 +55,37 @@ public class PlayerInventory : Inventory _items[i]?.UnbindFromInventory(); if (id > 0 && count > 0) { - var stack = new ItemStack(id, count, (short)aux); + if (_items[i] == null) + { + _items[i] = new ItemStack(id, count, (short)aux); + } + else + { + _items[i]!.setTypeId(id); + _items[i]!.setAmount(count); + _items[i]!.setDurability((short)aux); + } + if (hasMetadata) { - var meta = ReadMetaFromNative(entityId, i); + var meta = ReadMetaFromNative(entityId, i, metadataBuffer, metadataBufferHandle); if (meta != null) - stack.setItemMetaInternal(meta); + { + _items[i]!.setItemMetaInternal(meta); + } + } - _items[i] = stack; - stack.BindToInventory(this, i); + _items[i]!.BindToInventory(this, i); } else { _items[i] = null; } } - _heldItemSlot = buf[120]; + _heldItemSlot = this.syncBuffer[120]; + + if (metadataBufferHandle.HasValue) + metadataBufferHandle.Value.Free(); } /// @@ -176,7 +191,7 @@ public class PlayerInventory : Inventory /// The ItemStack to set. public void setItemInHand(ItemStack? stack) { - EnsureSynced(); + EnsureSynced(); //we need to sync the current held slot, hate doing this here during a set call setItem(_heldItemSlot, stack); } @@ -233,41 +248,37 @@ public class PlayerInventory : Inventory /// The HumanEntity that owns this inventory. public HumanEntity? getHolder() => _holder; - private static ItemMeta? ReadMetaFromNative(int entityId, int slot) + private static ItemMeta? ReadMetaFromNative(int entityId, int slot, byte[]? buffer, GCHandle? bufferHandle) { if (NativeBridge.GetItemMeta == null) return null; - byte[] buf = new byte[4096]; - int bytesWritten; - var gh = GCHandle.Alloc(buf, GCHandleType.Pinned); - try + if (buffer == null) { - bytesWritten = NativeBridge.GetItemMeta(entityId, slot, gh.AddrOfPinnedObject(), buf.Length); - } - finally - { - gh.Free(); + buffer = new byte[4096]; + bufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned); } + int bytesWritten = NativeBridge.GetItemMeta(entityId, slot, bufferHandle.GetValueOrDefault().AddrOfPinnedObject(), buffer!.Length); + if (bytesWritten <= 0) return null; int offset = 0; - int nameLen = BitConverter.ToInt32(buf, offset); + int nameLen = BitConverter.ToInt32(buffer, offset); offset += 4; string? displayName = null; if (nameLen > 0) { - displayName = Encoding.UTF8.GetString(buf, offset, nameLen); + displayName = Encoding.UTF8.GetString(buffer, offset, nameLen); offset += nameLen; } int loreCount = 0; if (offset + 4 <= bytesWritten) { - loreCount = BitConverter.ToInt32(buf, offset); + loreCount = BitConverter.ToInt32(buffer, offset); offset += 4; } @@ -278,11 +289,11 @@ public class PlayerInventory : Inventory for (int i = 0; i < loreCount; i++) { if (offset + 4 > bytesWritten) break; - int lineLen = BitConverter.ToInt32(buf, offset); + int lineLen = BitConverter.ToInt32(buffer, offset); offset += 4; if (lineLen > 0 && offset + lineLen <= bytesWritten) { - lore.Add(Encoding.UTF8.GetString(buf, offset, lineLen)); + lore.Add(Encoding.UTF8.GetString(buffer, offset, lineLen)); offset += lineLen; } else @@ -295,7 +306,7 @@ public class PlayerInventory : Inventory int enchantCount = 0; if (offset + 4 <= bytesWritten) { - enchantCount = BitConverter.ToInt32(buf, offset); + enchantCount = BitConverter.ToInt32(buffer, offset); offset += 4; } @@ -308,10 +319,10 @@ public class PlayerInventory : Inventory if (offset + (4 + 4) > bytesWritten) break; - int type = BitConverter.ToInt32(buf, offset); + int type = BitConverter.ToInt32(buffer, offset); offset += 4; - int level = BitConverter.ToInt32(buf, offset); + int level = BitConverter.ToInt32(buffer, offset); offset += 4; enchants.Add((EnchantmentType)type, level);