mirror of
https://github.com/smartcmd/MinecraftConsoles.git
synced 2026-04-29 18:35:59 +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]
|
||||
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
|
||||
{
|
||||
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.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
namespace Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
using Minecraft.Server.FourKit.Inventory.Meta;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a stack of items.
|
||||
/// </summary>
|
||||
|
|
@ -8,6 +10,7 @@ public class ItemStack
|
|||
private Material _type;
|
||||
private int _amount;
|
||||
private short _durability;
|
||||
private ItemMeta? _meta;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new ItemStack of the specified material with amount 1.
|
||||
|
|
@ -99,4 +102,31 @@ public class ItemStack
|
|||
/// </summary>
|
||||
/// <param name="durability">Durability of this item.</param>
|
||||
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;
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Minecraft.Server.FourKit.Entity;
|
||||
using Minecraft.Server.FourKit.Inventory.Meta;
|
||||
|
||||
/// <summary>
|
||||
/// 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 aux = buf[i * 3 + 2];
|
||||
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
|
||||
{
|
||||
_items[i] = null;
|
||||
}
|
||||
}
|
||||
_heldItemSlot = buf[120];
|
||||
}
|
||||
|
|
@ -62,6 +72,7 @@ public class PlayerInventory : Inventory
|
|||
int count = item?.getAmount() ?? 0;
|
||||
int aux = item?.getDurability() ?? 0;
|
||||
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.
|
||||
/// </summary>
|
||||
/// <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>
|
||||
/// Gets the slot number of the currently held item.
|
||||
|
|
@ -168,6 +183,8 @@ public class PlayerInventory : Inventory
|
|||
if (slot < 0 || slot >= QUICKBAR_SIZE)
|
||||
throw new ArgumentException($"Slot must be between 0 and {QUICKBAR_SIZE - 1} inclusive.");
|
||||
_heldItemSlot = slot;
|
||||
if (_holder != null)
|
||||
NativeBridge.SetHeldItemSlot?.Invoke(_holder.getEntityId(), slot);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -199,4 +216,128 @@ public class PlayerInventory : Inventory
|
|||
/// </summary>
|
||||
/// <returns>The HumanEntity that owns this inventory.</returns>
|
||||
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)]
|
||||
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 NativeSetHealthDelegate? SetPlayerHealth;
|
||||
|
|
@ -144,6 +153,9 @@ internal static class NativeBridge
|
|||
internal static NativeGetContainerViewerEntityIdsDelegate? GetContainerViewerEntityIds;
|
||||
internal static NativeCloseContainerDelegate? CloseContainer;
|
||||
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)
|
||||
{
|
||||
|
|
@ -184,7 +196,7 @@ internal static class NativeBridge
|
|||
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);
|
||||
SetPlayerInventorySlot = Marshal.GetDelegateForFunctionPointer<NativeSetPlayerInventorySlotDelegate>(setPlayerInventorySlot);
|
||||
|
|
@ -193,5 +205,8 @@ internal static class NativeBridge
|
|||
GetContainerViewerEntityIds = Marshal.GetDelegateForFunctionPointer<NativeGetContainerViewerEntityIdsDelegate>(getContainerViewerEntityIds);
|
||||
CloseContainer = Marshal.GetDelegateForFunctionPointer<NativeCloseContainerDelegate>(closeContainer);
|
||||
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\Player.h"
|
||||
#include "..\Minecraft.World\PlayerAbilitiesPacket.h"
|
||||
#include "..\Minecraft.World\SetCarriedItemPacket.h"
|
||||
#include "..\Minecraft.World\SimpleContainer.h"
|
||||
#include "..\Minecraft.World\Slot.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,
|
||||
int itemId, int itemCount, int itemAux,
|
||||
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,
|
||||
int itemId, int itemCount, int itemAux,
|
||||
int clickedX, int clickedY, int clickedZ,
|
||||
|
|
@ -1069,6 +1070,212 @@ static void __cdecl NativeGetContainerViewerEntityIds(int entityId, int *outIds,
|
|||
*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()
|
||||
{
|
||||
// overengineered
|
||||
|
|
@ -1362,7 +1569,10 @@ void Initialize()
|
|||
(void *)&NativeSetContainerSlot,
|
||||
(void *)&NativeGetContainerViewerEntityIds,
|
||||
(void *)&NativeCloseContainer,
|
||||
(void *)&NativeOpenVirtualContainer);
|
||||
(void *)&NativeOpenVirtualContainer,
|
||||
(void *)&NativeGetItemMeta,
|
||||
(void *)&NativeSetItemMeta,
|
||||
(void *)&NativeSetHeldItemSlot);
|
||||
|
||||
LogInfo("fourkit", "FourKit initialized successfully.");
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue