mirror of
https://github.com/smartcmd/MinecraftConsoles.git
synced 2026-08-20 09:57:09 +00:00
Add itemmeta, fix some bugs regarding inventory syncing and missing impl (oops)
This commit is contained in:
parent
aca05bad7b
commit
91b189e1bd
|
|
@ -581,11 +581,11 @@ public static class FourKitHost
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
public static void SetInventoryCallbacks(IntPtr getPlayerInventory, IntPtr setPlayerInventorySlot, IntPtr getContainerContents, IntPtr setContainerSlot, IntPtr getContainerViewerEntityIds, IntPtr closeContainer, IntPtr openVirtualContainer)
|
public static void SetInventoryCallbacks(IntPtr getPlayerInventory, IntPtr setPlayerInventorySlot, IntPtr getContainerContents, IntPtr setContainerSlot, IntPtr getContainerViewerEntityIds, IntPtr closeContainer, IntPtr openVirtualContainer, IntPtr getItemMeta, IntPtr setItemMeta, IntPtr setHeldItemSlot)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
NativeBridge.SetInventoryCallbacks(getPlayerInventory, setPlayerInventorySlot, getContainerContents, setContainerSlot, getContainerViewerEntityIds, closeContainer, openVirtualContainer);
|
NativeBridge.SetInventoryCallbacks(getPlayerInventory, setPlayerInventorySlot, getContainerContents, setContainerSlot, getContainerViewerEntityIds, closeContainer, openVirtualContainer, getItemMeta, setItemMeta, setHeldItemSlot);
|
||||||
//ServerLog.Info("fourkit", "Inventory native callbacks registered.");
|
//ServerLog.Info("fourkit", "Inventory native callbacks registered.");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
namespace Minecraft.Server.FourKit.Inventory;
|
namespace Minecraft.Server.FourKit.Inventory;
|
||||||
|
|
||||||
|
using Minecraft.Server.FourKit.Inventory.Meta;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a stack of items.
|
/// Represents a stack of items.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -8,6 +10,7 @@ public class ItemStack
|
||||||
private Material _type;
|
private Material _type;
|
||||||
private int _amount;
|
private int _amount;
|
||||||
private short _durability;
|
private short _durability;
|
||||||
|
private ItemMeta? _meta;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new ItemStack of the specified material with amount 1.
|
/// Creates a new ItemStack of the specified material with amount 1.
|
||||||
|
|
@ -99,4 +102,31 @@ public class ItemStack
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="durability">Durability of this item.</param>
|
/// <param name="durability">Durability of this item.</param>
|
||||||
public void setDurability(short durability) => _durability = durability;
|
public void setDurability(short durability) => _durability = durability;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a copy of this ItemStack's ItemMeta.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A copy of the current ItemStack's ItemMeta.</returns>
|
||||||
|
public ItemMeta getItemMeta() => _meta?.clone() ?? new ItemMeta();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks to see if any meta data has been defined.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Returns true if some meta data has been set for this item.</returns>
|
||||||
|
public bool hasItemMeta() => _meta != null && !_meta.isEmpty();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the ItemMeta of this ItemStack.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="itemMeta">New ItemMeta, or null to indicate meta data be cleared.</param>
|
||||||
|
/// <returns>True if successfully applied ItemMeta.</returns>
|
||||||
|
public bool setItemMeta(ItemMeta? itemMeta)
|
||||||
|
{
|
||||||
|
_meta = itemMeta?.clone();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal ItemMeta? getItemMetaInternal() => _meta;
|
||||||
|
|
||||||
|
internal void setItemMetaInternal(ItemMeta? meta) => _meta = meta;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
64
Minecraft.Server.FourKit/Inventory/Meta/ItemMeta.cs
Normal file
64
Minecraft.Server.FourKit/Inventory/Meta/ItemMeta.cs
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
namespace Minecraft.Server.FourKit.Inventory.Meta;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the metadata of an <see cref="ItemStack"/>, including display name and lore.
|
||||||
|
/// </summary>
|
||||||
|
public class ItemMeta
|
||||||
|
{
|
||||||
|
private string? _displayName;
|
||||||
|
private List<string>? _lore;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks for existence of a display name.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>true if this has a display name.</returns>
|
||||||
|
public bool hasDisplayName() => _displayName != null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the display name that is set.
|
||||||
|
/// Plugins should check that hasDisplayName() returns true before calling this method.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The display name that is set.</returns>
|
||||||
|
public string getDisplayName() => _displayName ?? string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the display name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name to set.</param>
|
||||||
|
public void setDisplayName(string? name) => _displayName = name;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks for existence of lore.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>true if this has lore.</returns>
|
||||||
|
public bool hasLore() => _lore != null && _lore.Count > 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the lore that is set.
|
||||||
|
/// Plugins should check if hasLore() returns true before calling this method.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A list of lore that is set.</returns>
|
||||||
|
public List<string> getLore() => _lore != null ? new List<string>(_lore) : new List<string>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the lore for this item. Removes lore when given null.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lore">The lore that will be set.</param>
|
||||||
|
public void setLore(List<string>? lore)
|
||||||
|
{
|
||||||
|
_lore = lore != null ? new List<string>(lore) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemMeta clone()
|
||||||
|
{
|
||||||
|
var copy = new ItemMeta();
|
||||||
|
copy._displayName = _displayName;
|
||||||
|
copy._lore = _lore != null ? new List<string>(_lore) : null;
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool isEmpty()
|
||||||
|
{
|
||||||
|
return _displayName == null && (_lore == null || _lore.Count == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
namespace Minecraft.Server.FourKit.Inventory;
|
namespace Minecraft.Server.FourKit.Inventory;
|
||||||
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
using Minecraft.Server.FourKit.Entity;
|
using Minecraft.Server.FourKit.Entity;
|
||||||
|
using Minecraft.Server.FourKit.Inventory.Meta;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a player's inventory, including armor slots and the held item.
|
/// Represents a player's inventory, including armor slots and the held item.
|
||||||
|
|
@ -43,9 +45,17 @@ public class PlayerInventory : Inventory
|
||||||
int count = buf[i * 3 + 1];
|
int count = buf[i * 3 + 1];
|
||||||
int aux = buf[i * 3 + 2];
|
int aux = buf[i * 3 + 2];
|
||||||
if (id > 0 && count > 0)
|
if (id > 0 && count > 0)
|
||||||
_items[i] = new ItemStack(id, count, (short)aux);
|
{
|
||||||
|
var stack = new ItemStack(id, count, (short)aux);
|
||||||
|
var meta = ReadMetaFromNative(entityId, i);
|
||||||
|
if (meta != null)
|
||||||
|
stack.setItemMetaInternal(meta);
|
||||||
|
_items[i] = stack;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
_items[i] = null;
|
_items[i] = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_heldItemSlot = buf[120];
|
_heldItemSlot = buf[120];
|
||||||
}
|
}
|
||||||
|
|
@ -62,6 +72,7 @@ public class PlayerInventory : Inventory
|
||||||
int count = item?.getAmount() ?? 0;
|
int count = item?.getAmount() ?? 0;
|
||||||
int aux = item?.getDurability() ?? 0;
|
int aux = item?.getDurability() ?? 0;
|
||||||
NativeBridge.SetPlayerInventorySlot(_holder.getEntityId(), index, id, count, aux);
|
NativeBridge.SetPlayerInventorySlot(_holder.getEntityId(), index, id, count, aux);
|
||||||
|
WriteMetaToNative(_holder.getEntityId(), index, item?.getItemMetaInternal());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -147,7 +158,11 @@ public class PlayerInventory : Inventory
|
||||||
/// Sets the item in the player's hand.
|
/// Sets the item in the player's hand.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="stack">The ItemStack to set.</param>
|
/// <param name="stack">The ItemStack to set.</param>
|
||||||
public void setItemInHand(ItemStack? stack) => setItem(_heldItemSlot, stack);
|
public void setItemInHand(ItemStack? stack)
|
||||||
|
{
|
||||||
|
EnsureSynced();
|
||||||
|
setItem(_heldItemSlot, stack);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the slot number of the currently held item.
|
/// Gets the slot number of the currently held item.
|
||||||
|
|
@ -168,6 +183,8 @@ public class PlayerInventory : Inventory
|
||||||
if (slot < 0 || slot >= QUICKBAR_SIZE)
|
if (slot < 0 || slot >= QUICKBAR_SIZE)
|
||||||
throw new ArgumentException($"Slot must be between 0 and {QUICKBAR_SIZE - 1} inclusive.");
|
throw new ArgumentException($"Slot must be between 0 and {QUICKBAR_SIZE - 1} inclusive.");
|
||||||
_heldItemSlot = slot;
|
_heldItemSlot = slot;
|
||||||
|
if (_holder != null)
|
||||||
|
NativeBridge.SetHeldItemSlot?.Invoke(_holder.getEntityId(), slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -199,4 +216,128 @@ public class PlayerInventory : Inventory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The HumanEntity that owns this inventory.</returns>
|
/// <returns>The HumanEntity that owns this inventory.</returns>
|
||||||
public HumanEntity? getHolder() => _holder;
|
public HumanEntity? getHolder() => _holder;
|
||||||
|
|
||||||
|
private static ItemMeta? ReadMetaFromNative(int entityId, int slot)
|
||||||
|
{
|
||||||
|
if (NativeBridge.GetItemMeta == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
byte[] buf = new byte[4096];
|
||||||
|
int bytesWritten;
|
||||||
|
var gh = GCHandle.Alloc(buf, GCHandleType.Pinned);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
bytesWritten = NativeBridge.GetItemMeta(entityId, slot, gh.AddrOfPinnedObject(), buf.Length);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
gh.Free();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytesWritten <= 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
int nameLen = BitConverter.ToInt32(buf, offset);
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
string? displayName = null;
|
||||||
|
if (nameLen > 0)
|
||||||
|
{
|
||||||
|
displayName = Encoding.UTF8.GetString(buf, offset, nameLen);
|
||||||
|
offset += nameLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
int loreCount = 0;
|
||||||
|
if (offset + 4 <= bytesWritten)
|
||||||
|
{
|
||||||
|
loreCount = BitConverter.ToInt32(buf, offset);
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<string>? lore = null;
|
||||||
|
if (loreCount > 0)
|
||||||
|
{
|
||||||
|
lore = new List<string>(loreCount);
|
||||||
|
for (int i = 0; i < loreCount; i++)
|
||||||
|
{
|
||||||
|
if (offset + 4 > bytesWritten) break;
|
||||||
|
int lineLen = BitConverter.ToInt32(buf, offset);
|
||||||
|
offset += 4;
|
||||||
|
if (lineLen > 0 && offset + lineLen <= bytesWritten)
|
||||||
|
{
|
||||||
|
lore.Add(Encoding.UTF8.GetString(buf, offset, lineLen));
|
||||||
|
offset += lineLen;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lore.Add(string.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (displayName == null && (lore == null || lore.Count == 0))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var meta = new ItemMeta();
|
||||||
|
if (displayName != null)
|
||||||
|
meta.setDisplayName(displayName);
|
||||||
|
if (lore != null && lore.Count > 0)
|
||||||
|
meta.setLore(lore);
|
||||||
|
return meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void WriteMetaToNative(int entityId, int slot, ItemMeta? meta)
|
||||||
|
{
|
||||||
|
if (NativeBridge.SetItemMeta == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (meta == null || meta.isEmpty())
|
||||||
|
{
|
||||||
|
NativeBridge.SetItemMeta(entityId, slot, IntPtr.Zero, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
using var ms = new System.IO.MemoryStream(512);
|
||||||
|
using var bw = new System.IO.BinaryWriter(ms);
|
||||||
|
|
||||||
|
if (meta.hasDisplayName())
|
||||||
|
{
|
||||||
|
byte[] nameBytes = Encoding.UTF8.GetBytes(meta.getDisplayName());
|
||||||
|
bw.Write(nameBytes.Length);
|
||||||
|
bw.Write(nameBytes);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bw.Write(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (meta.hasLore())
|
||||||
|
{
|
||||||
|
var lore = meta.getLore();
|
||||||
|
bw.Write(lore.Count);
|
||||||
|
foreach (var line in lore)
|
||||||
|
{
|
||||||
|
byte[] lineBytes = Encoding.UTF8.GetBytes(line ?? string.Empty);
|
||||||
|
bw.Write(lineBytes.Length);
|
||||||
|
bw.Write(lineBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bw.Write(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bw.Flush();
|
||||||
|
byte[] data = ms.ToArray();
|
||||||
|
var gh = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
NativeBridge.SetItemMeta(entityId, slot, gh.AddrOfPinnedObject(), data.Length);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
gh.Free();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,15 @@ internal static class NativeBridge
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
internal delegate void NativeOpenVirtualContainerDelegate(int entityId, int nativeType, IntPtr titleUtf8, int titleByteLen, int slotCount, IntPtr itemsBuf);
|
internal delegate void NativeOpenVirtualContainerDelegate(int entityId, int nativeType, IntPtr titleUtf8, int titleByteLen, int slotCount, IntPtr itemsBuf);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
internal delegate int NativeGetItemMetaDelegate(int entityId, int slot, IntPtr outBuf, int bufSize);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
internal delegate void NativeSetItemMetaDelegate(int entityId, int slot, IntPtr inBuf, int bufSize);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
internal delegate void NativeSetHeldItemSlotDelegate(int entityId, int slot);
|
||||||
|
|
||||||
|
|
||||||
internal static NativeDamageDelegate? DamagePlayer;
|
internal static NativeDamageDelegate? DamagePlayer;
|
||||||
internal static NativeSetHealthDelegate? SetPlayerHealth;
|
internal static NativeSetHealthDelegate? SetPlayerHealth;
|
||||||
|
|
@ -144,6 +153,9 @@ internal static class NativeBridge
|
||||||
internal static NativeGetContainerViewerEntityIdsDelegate? GetContainerViewerEntityIds;
|
internal static NativeGetContainerViewerEntityIdsDelegate? GetContainerViewerEntityIds;
|
||||||
internal static NativeCloseContainerDelegate? CloseContainer;
|
internal static NativeCloseContainerDelegate? CloseContainer;
|
||||||
internal static NativeOpenVirtualContainerDelegate? OpenVirtualContainer;
|
internal static NativeOpenVirtualContainerDelegate? OpenVirtualContainer;
|
||||||
|
internal static NativeGetItemMetaDelegate? GetItemMeta;
|
||||||
|
internal static NativeSetItemMetaDelegate? SetItemMeta;
|
||||||
|
internal static NativeSetHeldItemSlotDelegate? SetHeldItemSlot;
|
||||||
|
|
||||||
internal static void SetCallbacks(IntPtr damage, IntPtr setHealth, IntPtr teleport, IntPtr setGameMode, IntPtr broadcastMessage, IntPtr setFallDistance, IntPtr getPlayerSnapshot, IntPtr sendMessage, IntPtr setWalkSpeed, IntPtr teleportEntity)
|
internal static void SetCallbacks(IntPtr damage, IntPtr setHealth, IntPtr teleport, IntPtr setGameMode, IntPtr broadcastMessage, IntPtr setFallDistance, IntPtr getPlayerSnapshot, IntPtr sendMessage, IntPtr setWalkSpeed, IntPtr teleportEntity)
|
||||||
{
|
{
|
||||||
|
|
@ -184,7 +196,7 @@ internal static class NativeBridge
|
||||||
GetPlayerAddress = Marshal.GetDelegateForFunctionPointer<NativeGetPlayerAddressDelegate>(getPlayerAddress);
|
GetPlayerAddress = Marshal.GetDelegateForFunctionPointer<NativeGetPlayerAddressDelegate>(getPlayerAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void SetInventoryCallbacks(IntPtr getPlayerInventory, IntPtr setPlayerInventorySlot, IntPtr getContainerContents, IntPtr setContainerSlot, IntPtr getContainerViewerEntityIds, IntPtr closeContainer, IntPtr openVirtualContainer)
|
internal static void SetInventoryCallbacks(IntPtr getPlayerInventory, IntPtr setPlayerInventorySlot, IntPtr getContainerContents, IntPtr setContainerSlot, IntPtr getContainerViewerEntityIds, IntPtr closeContainer, IntPtr openVirtualContainer, IntPtr getItemMeta, IntPtr setItemMeta, IntPtr setHeldItemSlot)
|
||||||
{
|
{
|
||||||
GetPlayerInventory = Marshal.GetDelegateForFunctionPointer<NativeGetPlayerInventoryDelegate>(getPlayerInventory);
|
GetPlayerInventory = Marshal.GetDelegateForFunctionPointer<NativeGetPlayerInventoryDelegate>(getPlayerInventory);
|
||||||
SetPlayerInventorySlot = Marshal.GetDelegateForFunctionPointer<NativeSetPlayerInventorySlotDelegate>(setPlayerInventorySlot);
|
SetPlayerInventorySlot = Marshal.GetDelegateForFunctionPointer<NativeSetPlayerInventorySlotDelegate>(setPlayerInventorySlot);
|
||||||
|
|
@ -193,5 +205,8 @@ internal static class NativeBridge
|
||||||
GetContainerViewerEntityIds = Marshal.GetDelegateForFunctionPointer<NativeGetContainerViewerEntityIdsDelegate>(getContainerViewerEntityIds);
|
GetContainerViewerEntityIds = Marshal.GetDelegateForFunctionPointer<NativeGetContainerViewerEntityIdsDelegate>(getContainerViewerEntityIds);
|
||||||
CloseContainer = Marshal.GetDelegateForFunctionPointer<NativeCloseContainerDelegate>(closeContainer);
|
CloseContainer = Marshal.GetDelegateForFunctionPointer<NativeCloseContainerDelegate>(closeContainer);
|
||||||
OpenVirtualContainer = Marshal.GetDelegateForFunctionPointer<NativeOpenVirtualContainerDelegate>(openVirtualContainer);
|
OpenVirtualContainer = Marshal.GetDelegateForFunctionPointer<NativeOpenVirtualContainerDelegate>(openVirtualContainer);
|
||||||
|
GetItemMeta = Marshal.GetDelegateForFunctionPointer<NativeGetItemMetaDelegate>(getItemMeta);
|
||||||
|
SetItemMeta = Marshal.GetDelegateForFunctionPointer<NativeSetItemMetaDelegate>(setItemMeta);
|
||||||
|
SetHeldItemSlot = Marshal.GetDelegateForFunctionPointer<NativeSetHeldItemSlotDelegate>(setHeldItemSlot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@
|
||||||
#include "..\Minecraft.World\LightningBolt.h"
|
#include "..\Minecraft.World\LightningBolt.h"
|
||||||
#include "..\Minecraft.World\Player.h"
|
#include "..\Minecraft.World\Player.h"
|
||||||
#include "..\Minecraft.World\PlayerAbilitiesPacket.h"
|
#include "..\Minecraft.World\PlayerAbilitiesPacket.h"
|
||||||
|
#include "..\Minecraft.World\SetCarriedItemPacket.h"
|
||||||
#include "..\Minecraft.World\SimpleContainer.h"
|
#include "..\Minecraft.World\SimpleContainer.h"
|
||||||
#include "..\Minecraft.World\Slot.h"
|
#include "..\Minecraft.World\Slot.h"
|
||||||
#include "..\Minecraft.World\Tile.h"
|
#include "..\Minecraft.World\Tile.h"
|
||||||
|
|
@ -141,7 +142,7 @@ typedef void(__stdcall *fn_set_player_callbacks)(void *kickPlayer, void *banPlay
|
||||||
typedef long long(__stdcall *fn_fire_player_drop_item)(int entityId,
|
typedef long long(__stdcall *fn_fire_player_drop_item)(int entityId,
|
||||||
int itemId, int itemCount, int itemAux,
|
int itemId, int itemCount, int itemAux,
|
||||||
int *outItemId, int *outItemCount, int *outItemAux);
|
int *outItemId, int *outItemCount, int *outItemAux);
|
||||||
typedef void(__stdcall *fn_set_inventory_callbacks)(void *getPlayerInventory, void *setPlayerInventorySlot, void *getContainerContents, void *setContainerSlot, void *getContainerViewerEntityIds, void *closeContainer, void *openVirtualContainer);
|
typedef void(__stdcall *fn_set_inventory_callbacks)(void *getPlayerInventory, void *setPlayerInventorySlot, void *getContainerContents, void *setContainerSlot, void *getContainerViewerEntityIds, void *closeContainer, void *openVirtualContainer, void *getItemMeta, void *setItemMeta, void *setHeldItemSlot);
|
||||||
typedef int(__stdcall *fn_fire_player_interact)(int entityId, int action,
|
typedef int(__stdcall *fn_fire_player_interact)(int entityId, int action,
|
||||||
int itemId, int itemCount, int itemAux,
|
int itemId, int itemCount, int itemAux,
|
||||||
int clickedX, int clickedY, int clickedZ,
|
int clickedX, int clickedY, int clickedZ,
|
||||||
|
|
@ -1069,6 +1070,212 @@ static void __cdecl NativeGetContainerViewerEntityIds(int entityId, int *outIds,
|
||||||
*outCount = count;
|
*outCount = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// [nameLen:int32][nameUTF8:bytes][loreCount:int32][lore0Len:int32][lore0UTF8:bytes]
|
||||||
|
// todo: des muass i no a bissl überarwatn
|
||||||
|
static int __cdecl NativeGetItemMeta(int entityId, int slot, char *outBuf, int bufSize)
|
||||||
|
{
|
||||||
|
auto player = FindPlayer(entityId);
|
||||||
|
if (!player || !player->inventory)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int size = player->inventory->getContainerSize();
|
||||||
|
if (slot < 0 || slot >= (int)size)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto item = player->inventory->getItem(slot);
|
||||||
|
if (!item || !item->hasTag())
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CompoundTag *tag = item->getTag();
|
||||||
|
if (!tag || !tag->contains(L"display"))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CompoundTag *display = tag->getCompound(L"display");
|
||||||
|
bool hasName = display->contains(L"Name");
|
||||||
|
bool hasLore = display->contains(L"Lore");
|
||||||
|
|
||||||
|
if (!hasName && !hasLore)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
if (hasName)
|
||||||
|
{
|
||||||
|
std::wstring wname = display->getString(L"Name");
|
||||||
|
std::string nameUtf8 = ServerRuntime::StringUtils::WideToUtf8(wname);
|
||||||
|
int nameLen = (int)nameUtf8.size();
|
||||||
|
if (offset + 4 + nameLen > bufSize) return 0;
|
||||||
|
memcpy(outBuf + offset, &nameLen, 4);
|
||||||
|
offset += 4;
|
||||||
|
memcpy(outBuf + offset, nameUtf8.data(), nameLen);
|
||||||
|
offset += nameLen;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int zero = 0;
|
||||||
|
if (offset + 4 > bufSize) return 0;
|
||||||
|
memcpy(outBuf + offset, &zero, 4);
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasLore)
|
||||||
|
{
|
||||||
|
ListTag<StringTag> *lore = (ListTag<StringTag> *)display->getList(L"Lore");
|
||||||
|
int loreCount = lore->size();
|
||||||
|
if (offset + 4 > bufSize) return 0;
|
||||||
|
memcpy(outBuf + offset, &loreCount, 4);
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
for (int i = 0; i < loreCount; i++)
|
||||||
|
{
|
||||||
|
std::wstring wline = lore->get(i)->data;
|
||||||
|
std::string lineUtf8 = ServerRuntime::StringUtils::WideToUtf8(wline);
|
||||||
|
int lineLen = (int)lineUtf8.size();
|
||||||
|
if (offset + 4 + lineLen > bufSize) return 0;
|
||||||
|
memcpy(outBuf + offset, &lineLen, 4);
|
||||||
|
offset += 4;
|
||||||
|
memcpy(outBuf + offset, lineUtf8.data(), lineLen);
|
||||||
|
offset += lineLen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int zero = 0;
|
||||||
|
if (offset + 4 > bufSize) return 0;
|
||||||
|
memcpy(outBuf + offset, &zero, 4);
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __cdecl NativeSetItemMeta(int entityId, int slot, const char *inBuf, int bufSize)
|
||||||
|
{
|
||||||
|
auto player = FindPlayer(entityId);
|
||||||
|
if (!player || !player->inventory)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int size = player->inventory->getContainerSize();
|
||||||
|
if (slot < 0 || slot >= (int)size)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto item = player->inventory->getItem(slot);
|
||||||
|
if (!item)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inBuf == nullptr || bufSize <= 0)
|
||||||
|
{
|
||||||
|
item->resetHoverName();
|
||||||
|
if (item->hasTag())
|
||||||
|
{
|
||||||
|
CompoundTag *tag = item->getTag();
|
||||||
|
if (tag && tag->contains(L"display"))
|
||||||
|
{
|
||||||
|
CompoundTag *display = tag->getCompound(L"display");
|
||||||
|
display->remove(L"Lore");
|
||||||
|
if (display->isEmpty())
|
||||||
|
{
|
||||||
|
tag->remove(L"display");
|
||||||
|
if (tag->isEmpty())
|
||||||
|
{
|
||||||
|
item->setTag(nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
if (offset + 4 > bufSize) return;
|
||||||
|
int nameLen = 0;
|
||||||
|
memcpy(&nameLen, inBuf + offset, 4);
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
if (nameLen > 0)
|
||||||
|
{
|
||||||
|
if (offset + nameLen > bufSize) return;
|
||||||
|
std::string nameUtf8(inBuf + offset, nameLen);
|
||||||
|
offset += nameLen;
|
||||||
|
std::wstring wname = ServerRuntime::StringUtils::Utf8ToWide(nameUtf8);
|
||||||
|
item->setHoverName(wname);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item->resetHoverName();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset + 4 > bufSize) return;
|
||||||
|
int loreCount = 0;
|
||||||
|
memcpy(&loreCount, inBuf + offset, 4);
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
if (loreCount > 0)
|
||||||
|
{
|
||||||
|
if (!item->hasTag()) item->setTag(new CompoundTag());
|
||||||
|
CompoundTag *tag = item->getTag();
|
||||||
|
if (!tag->contains(L"display")) tag->putCompound(L"display", new CompoundTag());
|
||||||
|
CompoundTag *display = tag->getCompound(L"display");
|
||||||
|
|
||||||
|
auto *loreList = new ListTag<StringTag>(L"Lore");
|
||||||
|
for (int i = 0; i < loreCount; i++)
|
||||||
|
{
|
||||||
|
if (offset + 4 > bufSize) break;
|
||||||
|
int lineLen = 0;
|
||||||
|
memcpy(&lineLen, inBuf + offset, 4);
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
std::wstring wline;
|
||||||
|
if (lineLen > 0 && offset + lineLen <= bufSize)
|
||||||
|
{
|
||||||
|
std::string lineUtf8(inBuf + offset, lineLen);
|
||||||
|
offset += lineLen;
|
||||||
|
wline = ServerRuntime::StringUtils::Utf8ToWide(lineUtf8);
|
||||||
|
}
|
||||||
|
loreList->add(new StringTag(L"", wline));
|
||||||
|
}
|
||||||
|
display->put(L"Lore", loreList);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (item->hasTag())
|
||||||
|
{
|
||||||
|
CompoundTag *tag = item->getTag();
|
||||||
|
if (tag && tag->contains(L"display"))
|
||||||
|
{
|
||||||
|
tag->getCompound(L"display")->remove(L"Lore");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __cdecl NativeSetHeldItemSlot(int entityId, int slot)
|
||||||
|
{
|
||||||
|
auto player = FindPlayer(entityId);
|
||||||
|
if (!player || !player->inventory) return;
|
||||||
|
if (slot < 0 || slot >= Inventory::getSelectionSize()) return;
|
||||||
|
player->inventory->selected = slot;
|
||||||
|
if (player->connection)
|
||||||
|
player->connection->queueSend(std::make_shared<SetCarriedItemPacket>(slot));
|
||||||
|
}
|
||||||
|
|
||||||
static std::wstring FindNet10SystemRoot()
|
static std::wstring FindNet10SystemRoot()
|
||||||
{
|
{
|
||||||
// overengineered
|
// overengineered
|
||||||
|
|
@ -1362,7 +1569,10 @@ void Initialize()
|
||||||
(void *)&NativeSetContainerSlot,
|
(void *)&NativeSetContainerSlot,
|
||||||
(void *)&NativeGetContainerViewerEntityIds,
|
(void *)&NativeGetContainerViewerEntityIds,
|
||||||
(void *)&NativeCloseContainer,
|
(void *)&NativeCloseContainer,
|
||||||
(void *)&NativeOpenVirtualContainer);
|
(void *)&NativeOpenVirtualContainer,
|
||||||
|
(void *)&NativeGetItemMeta,
|
||||||
|
(void *)&NativeSetItemMeta,
|
||||||
|
(void *)&NativeSetHeldItemSlot);
|
||||||
|
|
||||||
LogInfo("fourkit", "FourKit initialized successfully.");
|
LogInfo("fourkit", "FourKit initialized successfully.");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue