mirror of
https://github.com/Jacobwasbeast/LegacyWeaveLoader.git
synced 2026-07-04 18:14:19 +00:00
feat(pickaxe): implement Hooked_PickaxeItemGetDestroySpeed and Hooked_PickaxeItemCanDestroySpecial
- Add hook implementations for custom pickaxe tier support - Hooked_PickaxeItemGetDestroySpeed: use CustomPickaxeRegistry destroy speed for configured pickaxes when mining effective blocks - Hooked_PickaxeItemCanDestroySpecial: use CustomPickaxeRegistry effective blocks and harvest level (obsidian requires level 3) - Add TryReadItemIdFromPickaxe and TryReadTileId helpers for reading item/tile IDs from native pointers
This commit is contained in:
26
WeaveLoaderRuntime/src/CustomBlockRegistry.cpp
Normal file
26
WeaveLoaderRuntime/src/CustomBlockRegistry.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "CustomBlockRegistry.h"
|
||||
#include <unordered_map>
|
||||
|
||||
namespace
|
||||
{
|
||||
std::unordered_map<int, CustomBlockRegistry::Definition> g_definitions;
|
||||
}
|
||||
|
||||
namespace CustomBlockRegistry
|
||||
{
|
||||
void Register(int blockId, int requiredHarvestLevel, int requiredTool)
|
||||
{
|
||||
Definition def;
|
||||
def.requiredHarvestLevel = requiredHarvestLevel;
|
||||
def.requiredTool = static_cast<ToolType>(requiredTool);
|
||||
g_definitions[blockId] = def;
|
||||
}
|
||||
|
||||
const Definition* Find(int blockId)
|
||||
{
|
||||
const auto it = g_definitions.find(blockId);
|
||||
if (it == g_definitions.end())
|
||||
return nullptr;
|
||||
return &it->second;
|
||||
}
|
||||
}
|
||||
21
WeaveLoaderRuntime/src/CustomBlockRegistry.h
Normal file
21
WeaveLoaderRuntime/src/CustomBlockRegistry.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
namespace CustomBlockRegistry
|
||||
{
|
||||
enum class ToolType : int
|
||||
{
|
||||
None = 0,
|
||||
Pickaxe = 1,
|
||||
Axe = 2,
|
||||
Shovel = 3,
|
||||
};
|
||||
|
||||
struct Definition
|
||||
{
|
||||
int requiredHarvestLevel = -1;
|
||||
ToolType requiredTool = ToolType::None;
|
||||
};
|
||||
|
||||
void Register(int blockId, int requiredHarvestLevel, int requiredTool);
|
||||
const Definition* Find(int blockId);
|
||||
}
|
||||
26
WeaveLoaderRuntime/src/CustomPickaxeRegistry.cpp
Normal file
26
WeaveLoaderRuntime/src/CustomPickaxeRegistry.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "CustomPickaxeRegistry.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
std::unordered_map<int, CustomPickaxeRegistry::Definition> g_definitions;
|
||||
}
|
||||
|
||||
namespace CustomPickaxeRegistry
|
||||
{
|
||||
void Register(int itemId, int harvestLevel, float destroySpeed)
|
||||
{
|
||||
Definition definition;
|
||||
definition.harvestLevel = harvestLevel;
|
||||
definition.destroySpeed = destroySpeed;
|
||||
|
||||
g_definitions[itemId] = std::move(definition);
|
||||
}
|
||||
|
||||
const Definition* Find(int itemId)
|
||||
{
|
||||
const auto it = g_definitions.find(itemId);
|
||||
if (it == g_definitions.end())
|
||||
return nullptr;
|
||||
return &it->second;
|
||||
}
|
||||
}
|
||||
14
WeaveLoaderRuntime/src/CustomPickaxeRegistry.h
Normal file
14
WeaveLoaderRuntime/src/CustomPickaxeRegistry.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
namespace CustomPickaxeRegistry
|
||||
{
|
||||
struct Definition
|
||||
{
|
||||
int harvestLevel = 0;
|
||||
float destroySpeed = 1.0f;
|
||||
};
|
||||
|
||||
void Register(int itemId, int harvestLevel, float destroySpeed);
|
||||
const Definition* Find(int itemId);
|
||||
}
|
||||
27
WeaveLoaderRuntime/src/CustomToolMaterialRegistry.cpp
Normal file
27
WeaveLoaderRuntime/src/CustomToolMaterialRegistry.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#include "CustomToolMaterialRegistry.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
std::unordered_map<int, CustomToolMaterialRegistry::Definition> g_definitions;
|
||||
}
|
||||
|
||||
namespace CustomToolMaterialRegistry
|
||||
{
|
||||
void Register(int itemId, ToolKind toolKind, int harvestLevel, float destroySpeed, float attackDamage)
|
||||
{
|
||||
Definition definition;
|
||||
definition.toolKind = toolKind;
|
||||
definition.harvestLevel = harvestLevel;
|
||||
definition.destroySpeed = destroySpeed;
|
||||
definition.attackDamage = attackDamage;
|
||||
g_definitions[itemId] = definition;
|
||||
}
|
||||
|
||||
const Definition* Find(int itemId)
|
||||
{
|
||||
const auto it = g_definitions.find(itemId);
|
||||
if (it == g_definitions.end())
|
||||
return nullptr;
|
||||
return &it->second;
|
||||
}
|
||||
}
|
||||
26
WeaveLoaderRuntime/src/CustomToolMaterialRegistry.h
Normal file
26
WeaveLoaderRuntime/src/CustomToolMaterialRegistry.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace CustomToolMaterialRegistry
|
||||
{
|
||||
enum class ToolKind : int
|
||||
{
|
||||
Pickaxe = 1,
|
||||
Shovel = 2,
|
||||
Hoe = 3,
|
||||
Sword = 4,
|
||||
Axe = 5,
|
||||
};
|
||||
|
||||
struct Definition
|
||||
{
|
||||
ToolKind toolKind = ToolKind::Pickaxe;
|
||||
int harvestLevel = 0;
|
||||
float destroySpeed = 1.0f;
|
||||
float attackDamage = 0.0f;
|
||||
};
|
||||
|
||||
void Register(int itemId, ToolKind toolKind, int harvestLevel, float destroySpeed, float attackDamage);
|
||||
const Definition* Find(int itemId);
|
||||
}
|
||||
@@ -4,6 +4,9 @@
|
||||
#include "MainMenuOverlay.h"
|
||||
#include "ModStrings.h"
|
||||
#include "ModAtlas.h"
|
||||
#include "CustomPickaxeRegistry.h"
|
||||
#include "CustomToolMaterialRegistry.h"
|
||||
#include "CustomBlockRegistry.h"
|
||||
#include "LogUtil.h"
|
||||
#include <Windows.h>
|
||||
#include <string>
|
||||
@@ -40,6 +43,11 @@ namespace GameHooks
|
||||
ItemInstanceMineBlock_fn Original_ItemInstanceMineBlock = nullptr;
|
||||
ItemMineBlock_fn Original_ItemMineBlock = nullptr;
|
||||
ItemMineBlock_fn Original_DiggerItemMineBlock = nullptr;
|
||||
PickaxeGetDestroySpeed_fn Original_PickaxeItemGetDestroySpeed = nullptr;
|
||||
PickaxeCanDestroySpecial_fn Original_PickaxeItemCanDestroySpecial = nullptr;
|
||||
PickaxeGetDestroySpeed_fn Original_ShovelItemGetDestroySpeed = nullptr;
|
||||
PickaxeCanDestroySpecial_fn Original_ShovelItemCanDestroySpecial = nullptr;
|
||||
PlayerCanDestroy_fn Original_PlayerCanDestroy = nullptr;
|
||||
GameModeUseItem_fn Original_ServerPlayerGameModeUseItem = nullptr;
|
||||
GameModeUseItem_fn Original_MultiPlayerGameModeUseItem = nullptr;
|
||||
MinecraftSetLevel_fn Original_MinecraftSetLevel = nullptr;
|
||||
@@ -66,6 +74,8 @@ namespace GameHooks
|
||||
// Verified from compiled Player::inventory accesses in this game build.
|
||||
static constexpr ptrdiff_t kPlayerInventoryOffset = 0x340;
|
||||
static constexpr ptrdiff_t kLevelIsClientSideOffset = 0x268;
|
||||
static constexpr ptrdiff_t kItemIdOffset = 0x20;
|
||||
static constexpr ptrdiff_t kTileIdOffset = 0x28;
|
||||
static constexpr ptrdiff_t kEntityXOffset = 0x78;
|
||||
static constexpr ptrdiff_t kEntityYOffset = 0x80;
|
||||
static constexpr ptrdiff_t kEntityZOffset = 0x88;
|
||||
@@ -78,6 +88,7 @@ namespace GameHooks
|
||||
static void* s_textureAtlasLocationItems = nullptr;
|
||||
static int s_textureAtlasIdBlocks = -1;
|
||||
static int s_textureAtlasIdItems = -1;
|
||||
static void* s_tileTilesArray = nullptr;
|
||||
static thread_local bool s_inLoadTextureByNameHook = false;
|
||||
static thread_local bool s_hasForcedBillboardRoute = false;
|
||||
static thread_local int s_forcedBillboardAtlas = -1;
|
||||
@@ -758,6 +769,11 @@ namespace GameHooks
|
||||
LogUtil::Log("[WeaveLoader] Atlas IDs: blocks=%d items=%d", s_textureAtlasIdBlocks, s_textureAtlasIdItems);
|
||||
}
|
||||
|
||||
void SetTileTilesArray(void* tilesArray)
|
||||
{
|
||||
s_tileTilesArray = tilesArray;
|
||||
}
|
||||
|
||||
static bool TryReadVec3(void* vecPtr, double& x, double& y, double& z)
|
||||
{
|
||||
if (!IsReadableRange(vecPtr, sizeof(double) * 3))
|
||||
@@ -1207,6 +1223,232 @@ namespace GameHooks
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool TryReadItemIdFromPickaxe(void* pickaxeItemPtr, int& outItemId)
|
||||
{
|
||||
if (!pickaxeItemPtr || !IsReadableRange(pickaxeItemPtr, kItemIdOffset + sizeof(int)))
|
||||
return false;
|
||||
int itemId = *reinterpret_cast<const int*>(static_cast<const char*>(pickaxeItemPtr) + kItemIdOffset);
|
||||
if (itemId >= 0 && itemId < 32000)
|
||||
{
|
||||
outItemId = itemId;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static constexpr int TILE_NUM_COUNT = 4096;
|
||||
|
||||
static bool TryReadTileId(void* tilePtr, int& outTileId)
|
||||
{
|
||||
if (!tilePtr)
|
||||
return false;
|
||||
if (IsReadableRange(tilePtr, kTileIdOffset + sizeof(int)))
|
||||
{
|
||||
int id = *reinterpret_cast<const int*>(static_cast<const char*>(tilePtr) + kTileIdOffset);
|
||||
if (id >= 0 && id < TILE_NUM_COUNT)
|
||||
{
|
||||
outTileId = id;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Fallback: resolve via Tile::tiles (Tile** - pointer to array). Must dereference once.
|
||||
if (s_tileTilesArray && IsReadableRange(s_tileTilesArray, sizeof(void*)))
|
||||
{
|
||||
const void* arrayPtr = *reinterpret_cast<const void* const*>(s_tileTilesArray);
|
||||
if (arrayPtr && IsReadableRange(arrayPtr, TILE_NUM_COUNT * sizeof(void*)))
|
||||
{
|
||||
const void* const* tiles = reinterpret_cast<const void* const*>(arrayPtr);
|
||||
for (int i = 0; i < TILE_NUM_COUNT; i++)
|
||||
{
|
||||
if (tiles[i] == tilePtr)
|
||||
{
|
||||
outTileId = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int GetToolHarvestLevel(void* diggerItemPtr, int itemId)
|
||||
{
|
||||
const CustomToolMaterialRegistry::Definition* def = CustomToolMaterialRegistry::Find(itemId);
|
||||
if (def)
|
||||
return def->harvestLevel;
|
||||
if (!diggerItemPtr || !IsReadableRange(diggerItemPtr, 0xA8 + sizeof(void*)))
|
||||
return -1;
|
||||
const void* tierPtr = *reinterpret_cast<const void* const*>(static_cast<const char*>(diggerItemPtr) + 0xA8);
|
||||
if (!tierPtr || !IsReadableRange(tierPtr, sizeof(int)))
|
||||
return -1;
|
||||
return *reinterpret_cast<const int*>(tierPtr);
|
||||
}
|
||||
|
||||
static float GetToolDestroySpeed(void* diggerItemPtr, int itemId)
|
||||
{
|
||||
const CustomToolMaterialRegistry::Definition* def = CustomToolMaterialRegistry::Find(itemId);
|
||||
if (def)
|
||||
return def->destroySpeed;
|
||||
if (!diggerItemPtr || !IsReadableRange(static_cast<const char*>(diggerItemPtr) + 0xA0, sizeof(float)))
|
||||
return 1.0f;
|
||||
return *reinterpret_cast<const float*>(static_cast<const char*>(diggerItemPtr) + 0xA0);
|
||||
}
|
||||
|
||||
float __fastcall Hooked_PickaxeItemGetDestroySpeed(void* thisPtr, void* itemInstanceSharedPtr, void* tilePtr)
|
||||
{
|
||||
void* itemInstancePtr = DecodeItemInstancePtrFromSharedArg(itemInstanceSharedPtr);
|
||||
int itemId = 0;
|
||||
if (!TryReadItemId(itemInstancePtr, itemId))
|
||||
{
|
||||
if (Original_PickaxeItemGetDestroySpeed)
|
||||
return Original_PickaxeItemGetDestroySpeed(thisPtr, itemInstanceSharedPtr, tilePtr);
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
int tileId = 0;
|
||||
if (tilePtr && TryReadTileId(tilePtr, tileId))
|
||||
{
|
||||
const CustomBlockRegistry::Definition* blockDef = CustomBlockRegistry::Find(tileId);
|
||||
if (blockDef && blockDef->requiredTool == CustomBlockRegistry::ToolType::Pickaxe)
|
||||
{
|
||||
int harvestLevel = GetToolHarvestLevel(thisPtr, itemId);
|
||||
if (harvestLevel >= 0 &&
|
||||
(blockDef->requiredHarvestLevel < 0 || harvestLevel >= blockDef->requiredHarvestLevel))
|
||||
{
|
||||
return GetToolDestroySpeed(thisPtr, itemId);
|
||||
}
|
||||
// Block requires pickaxe but harvest level insufficient - return slow speed
|
||||
return 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (Original_PickaxeItemGetDestroySpeed)
|
||||
return Original_PickaxeItemGetDestroySpeed(thisPtr, itemInstanceSharedPtr, tilePtr);
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
bool __fastcall Hooked_PickaxeItemCanDestroySpecial(void* thisPtr, void* tilePtr)
|
||||
{
|
||||
int itemId = 0;
|
||||
if (!TryReadItemIdFromPickaxe(thisPtr, itemId))
|
||||
{
|
||||
if (Original_PickaxeItemCanDestroySpecial)
|
||||
return Original_PickaxeItemCanDestroySpecial(thisPtr, tilePtr);
|
||||
return false;
|
||||
}
|
||||
|
||||
int tileId = 0;
|
||||
if (tilePtr && TryReadTileId(tilePtr, tileId))
|
||||
{
|
||||
const CustomBlockRegistry::Definition* blockDef = CustomBlockRegistry::Find(tileId);
|
||||
if (blockDef && blockDef->requiredTool == CustomBlockRegistry::ToolType::Pickaxe)
|
||||
{
|
||||
int harvestLevel = GetToolHarvestLevel(thisPtr, itemId);
|
||||
if (harvestLevel >= 0 &&
|
||||
(blockDef->requiredHarvestLevel < 0 || harvestLevel >= blockDef->requiredHarvestLevel))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (Original_PickaxeItemCanDestroySpecial)
|
||||
return Original_PickaxeItemCanDestroySpecial(thisPtr, tilePtr);
|
||||
return false;
|
||||
}
|
||||
|
||||
float __fastcall Hooked_ShovelItemGetDestroySpeed(void* thisPtr, void* itemInstanceSharedPtr, void* tilePtr)
|
||||
{
|
||||
void* itemInstancePtr = DecodeItemInstancePtrFromSharedArg(itemInstanceSharedPtr);
|
||||
int itemId = 0;
|
||||
if (!TryReadItemId(itemInstancePtr, itemId))
|
||||
{
|
||||
if (Original_ShovelItemGetDestroySpeed)
|
||||
return Original_ShovelItemGetDestroySpeed(thisPtr, itemInstanceSharedPtr, tilePtr);
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
int tileId = 0;
|
||||
if (tilePtr && TryReadTileId(tilePtr, tileId))
|
||||
{
|
||||
const CustomBlockRegistry::Definition* blockDef = CustomBlockRegistry::Find(tileId);
|
||||
if (blockDef && blockDef->requiredTool == CustomBlockRegistry::ToolType::Shovel)
|
||||
{
|
||||
int harvestLevel = GetToolHarvestLevel(thisPtr, itemId);
|
||||
if (harvestLevel >= 0 &&
|
||||
(blockDef->requiredHarvestLevel < 0 || harvestLevel >= blockDef->requiredHarvestLevel))
|
||||
{
|
||||
return GetToolDestroySpeed(thisPtr, itemId);
|
||||
}
|
||||
return 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (Original_ShovelItemGetDestroySpeed)
|
||||
return Original_ShovelItemGetDestroySpeed(thisPtr, itemInstanceSharedPtr, tilePtr);
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
bool __fastcall Hooked_ShovelItemCanDestroySpecial(void* thisPtr, void* tilePtr)
|
||||
{
|
||||
int itemId = 0;
|
||||
if (!TryReadItemIdFromPickaxe(thisPtr, itemId))
|
||||
{
|
||||
if (Original_ShovelItemCanDestroySpecial)
|
||||
return Original_ShovelItemCanDestroySpecial(thisPtr, tilePtr);
|
||||
return false;
|
||||
}
|
||||
|
||||
int tileId = 0;
|
||||
if (tilePtr && TryReadTileId(tilePtr, tileId))
|
||||
{
|
||||
const CustomBlockRegistry::Definition* blockDef = CustomBlockRegistry::Find(tileId);
|
||||
if (blockDef && blockDef->requiredTool == CustomBlockRegistry::ToolType::Shovel)
|
||||
{
|
||||
int harvestLevel = GetToolHarvestLevel(thisPtr, itemId);
|
||||
if (harvestLevel >= 0 &&
|
||||
(blockDef->requiredHarvestLevel < 0 || harvestLevel >= blockDef->requiredHarvestLevel))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (Original_ShovelItemCanDestroySpecial)
|
||||
return Original_ShovelItemCanDestroySpecial(thisPtr, tilePtr);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Inventory layout: items.data at +0x8, selected at +0x28. shared_ptr is 16 bytes.
|
||||
static void* GetSelectedItemInstanceFromPlayer(void* playerPtr)
|
||||
{
|
||||
void* inv = FindInventoryPtrFromPlayer(playerPtr);
|
||||
if (!inv || !IsReadableRange(inv, 0x30))
|
||||
return nullptr;
|
||||
void* itemsData = *reinterpret_cast<void* const*>(static_cast<const char*>(inv) + 0x8);
|
||||
int selected = *reinterpret_cast<const int*>(static_cast<const char*>(inv) + 0x28);
|
||||
if (!itemsData || selected < 0 || selected >= 36)
|
||||
return nullptr;
|
||||
// shared_ptr<ItemInstance> at itemsData[selected]; raw ptr is first 8 bytes
|
||||
const char* slotPtr = static_cast<const char*>(itemsData) + selected * 16;
|
||||
if (!IsReadableRange(slotPtr, 8))
|
||||
return nullptr;
|
||||
return *reinterpret_cast<void* const*>(slotPtr);
|
||||
}
|
||||
|
||||
bool __fastcall Hooked_PlayerCanDestroy(void* thisPtr, void* tilePtr)
|
||||
{
|
||||
// For pickaxe harvest rules, Inventory::canDestroy -> ItemInstance::canDestroySpecial
|
||||
// already gives the correct source behavior:
|
||||
// proper tool/tier => normal speed + drops
|
||||
// insufficient tool/tier => slow break + no drops
|
||||
if (Original_PlayerCanDestroy)
|
||||
return Original_PlayerCanDestroy(thisPtr, tilePtr);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool __fastcall Hooked_ServerPlayerGameModeUseItem(void* thisPtr, void* playerSharedPtr, void* level, void* itemInstanceSharedPtr, bool bTestUseOnly)
|
||||
{
|
||||
void* previousLevel = s_activeUseLevel;
|
||||
|
||||
@@ -25,6 +25,9 @@ typedef void (__fastcall *AnimatedTextureCycleFrames_fn)(void* thisPtr);
|
||||
typedef int (__fastcall *TextureGetSourceDim_fn)(void* thisPtr);
|
||||
typedef void (__fastcall *ItemInstanceMineBlock_fn)(void* thisPtr, void* level, int tile, int x, int y, int z, void* ownerSharedPtr);
|
||||
typedef bool (__fastcall *ItemMineBlock_fn)(void* thisPtr, void* itemInstanceSharedPtr, void* level, int tile, int x, int y, int z, void* ownerSharedPtr);
|
||||
typedef float (__fastcall *PickaxeGetDestroySpeed_fn)(void* thisPtr, void* itemInstanceSharedPtr, void* tilePtr);
|
||||
typedef bool (__fastcall *PickaxeCanDestroySpecial_fn)(void* thisPtr, void* tilePtr);
|
||||
typedef bool (__fastcall *PlayerCanDestroy_fn)(void* thisPtr, void* tilePtr);
|
||||
typedef bool (__fastcall *GameModeUseItem_fn)(void* thisPtr, void* playerSharedPtr, void* level, void* itemInstanceSharedPtr, bool bTestUseOnly);
|
||||
typedef void (__fastcall *MinecraftSetLevel_fn)(void* thisPtr, void* level, int message, void* forceInsertPlayerSharedPtr, bool doForceStatsSave, bool bPrimaryPlayerSignedOut);
|
||||
typedef bool (__fastcall *LevelAddEntity_fn)(void* thisPtr, void* entitySharedPtr);
|
||||
@@ -68,6 +71,11 @@ namespace GameHooks
|
||||
extern ItemInstanceMineBlock_fn Original_ItemInstanceMineBlock;
|
||||
extern ItemMineBlock_fn Original_ItemMineBlock;
|
||||
extern ItemMineBlock_fn Original_DiggerItemMineBlock;
|
||||
extern PickaxeGetDestroySpeed_fn Original_PickaxeItemGetDestroySpeed;
|
||||
extern PickaxeCanDestroySpecial_fn Original_PickaxeItemCanDestroySpecial;
|
||||
extern PickaxeGetDestroySpeed_fn Original_ShovelItemGetDestroySpeed;
|
||||
extern PickaxeCanDestroySpecial_fn Original_ShovelItemCanDestroySpecial;
|
||||
extern PlayerCanDestroy_fn Original_PlayerCanDestroy;
|
||||
extern GameModeUseItem_fn Original_ServerPlayerGameModeUseItem;
|
||||
extern GameModeUseItem_fn Original_MultiPlayerGameModeUseItem;
|
||||
extern MinecraftSetLevel_fn Original_MinecraftSetLevel;
|
||||
@@ -103,6 +111,11 @@ namespace GameHooks
|
||||
void __fastcall Hooked_ItemInstanceMineBlock(void* thisPtr, void* level, int tile, int x, int y, int z, void* ownerSharedPtr);
|
||||
bool __fastcall Hooked_ItemMineBlock(void* thisPtr, void* itemInstanceSharedPtr, void* level, int tile, int x, int y, int z, void* ownerSharedPtr);
|
||||
bool __fastcall Hooked_DiggerItemMineBlock(void* thisPtr, void* itemInstanceSharedPtr, void* level, int tile, int x, int y, int z, void* ownerSharedPtr);
|
||||
float __fastcall Hooked_PickaxeItemGetDestroySpeed(void* thisPtr, void* itemInstanceSharedPtr, void* tilePtr);
|
||||
bool __fastcall Hooked_PickaxeItemCanDestroySpecial(void* thisPtr, void* tilePtr);
|
||||
float __fastcall Hooked_ShovelItemGetDestroySpeed(void* thisPtr, void* itemInstanceSharedPtr, void* tilePtr);
|
||||
bool __fastcall Hooked_ShovelItemCanDestroySpecial(void* thisPtr, void* tilePtr);
|
||||
bool __fastcall Hooked_PlayerCanDestroy(void* thisPtr, void* tilePtr);
|
||||
bool __fastcall Hooked_ServerPlayerGameModeUseItem(void* thisPtr, void* playerSharedPtr, void* level, void* itemInstanceSharedPtr, bool bTestUseOnly);
|
||||
bool __fastcall Hooked_MultiPlayerGameModeUseItem(void* thisPtr, void* playerSharedPtr, void* level, void* itemInstanceSharedPtr, bool bTestUseOnly);
|
||||
void __fastcall Hooked_MinecraftSetLevel(void* thisPtr, void* level, int message, void* forceInsertPlayerSharedPtr, bool doForceStatsSave, bool bPrimaryPlayerSignedOut);
|
||||
@@ -114,6 +127,7 @@ namespace GameHooks
|
||||
float __fastcall Hooked_StitchedGetV0(void* thisPtr, bool adjust);
|
||||
float __fastcall Hooked_StitchedGetV1(void* thisPtr, bool adjust);
|
||||
void SetAtlasLocationPointers(void* blocksLocation, void* itemsLocation);
|
||||
void SetTileTilesArray(void* tilesArray);
|
||||
void SetSummonSymbols(void* levelAddEntity,
|
||||
void* entityIoNewById,
|
||||
void* entityMoveTo,
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <Windows.h>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
// Tile::Tile(int id, Material* material, bool isSolidRender) — protected ctor
|
||||
typedef void (__fastcall *TileCtor_fn)(void* thisPtr, int id, void* material, bool isSolidRender);
|
||||
@@ -24,6 +25,10 @@ typedef void (__fastcall *TileItemCtor_fn)(void* thisPtr, int id);
|
||||
typedef void (__fastcall *ItemCtor_fn)(void* thisPtr, int id);
|
||||
// PickaxeItem::PickaxeItem(int id, const Item::Tier* tier)
|
||||
typedef void (__fastcall *PickaxeCtor_fn)(void* thisPtr, int id, const void* tier);
|
||||
typedef void (__fastcall *ShovelCtor_fn)(void* thisPtr, int id, const void* tier);
|
||||
typedef void (__fastcall *HoeCtor_fn)(void* thisPtr, int id, const void* tier);
|
||||
typedef void (__fastcall *HatchetCtor_fn)(void* thisPtr, int id, const void* tier);
|
||||
typedef void (__fastcall *WeaponCtor_fn)(void* thisPtr, int id, const void* tier);
|
||||
// Item* Item::setIconName(const std::wstring&)
|
||||
typedef void* (__fastcall *ItemSetIconName_fn)(void* thisPtr, const std::wstring& name);
|
||||
// Item::getDescriptionId(int) — used to extract the descriptionId field offset
|
||||
@@ -40,6 +45,10 @@ static TileItemCtor_fn fnTileItemCtor = nullptr;
|
||||
|
||||
static ItemCtor_fn fnItemCtor = nullptr;
|
||||
static PickaxeCtor_fn fnPickaxeCtor = nullptr;
|
||||
static ShovelCtor_fn fnShovelCtor = nullptr;
|
||||
static HoeCtor_fn fnHoeCtor = nullptr;
|
||||
static HatchetCtor_fn fnHatchetCtor = nullptr;
|
||||
static WeaponCtor_fn fnWeaponCtor = nullptr;
|
||||
static ItemSetIconName_fn fnItemSetIconName= nullptr;
|
||||
static int s_itemDescIdOffset = -1; // offset of descriptionId field in Item, extracted from getDescriptionId
|
||||
|
||||
@@ -54,6 +63,20 @@ static const int ITEM_ALLOC_SIZE = 1024;
|
||||
static const int TILEITEM_ALLOC_SIZE = 1024;
|
||||
|
||||
static bool s_resolved = false;
|
||||
static std::unordered_map<int, void*> s_createdItems;
|
||||
|
||||
static int MapTierMaterial(int tier)
|
||||
{
|
||||
switch (tier)
|
||||
{
|
||||
case 0: return 1; // wood
|
||||
case 1: return 2; // stone
|
||||
case 2: return 3; // iron
|
||||
case 3: return 5; // diamond
|
||||
case 4: return 4; // gold
|
||||
default: return 5;
|
||||
}
|
||||
}
|
||||
|
||||
static void* GetMaterial(int idx)
|
||||
{
|
||||
@@ -101,6 +124,10 @@ bool ResolveSymbols(SymbolResolver& resolver)
|
||||
// Item constructor — protected (IEAA not QEAA)
|
||||
fnItemCtor = (ItemCtor_fn)resolver.Resolve("??0Item@@IEAA@H@Z");
|
||||
fnPickaxeCtor = (PickaxeCtor_fn)resolver.Resolve("??0PickaxeItem@@QEAA@HPEBVTier@Item@@@Z");
|
||||
fnShovelCtor = (ShovelCtor_fn)resolver.Resolve("??0ShovelItem@@QEAA@HPEBVTier@Item@@@Z");
|
||||
fnHoeCtor = (HoeCtor_fn)resolver.Resolve("??0HoeItem@@QEAA@HPEBVTier@Item@@@Z");
|
||||
fnHatchetCtor = (HatchetCtor_fn)resolver.Resolve("??0HatchetItem@@QEAA@HPEBVTier@Item@@@Z");
|
||||
fnWeaponCtor = (WeaponCtor_fn)resolver.Resolve("??0WeaponItem@@QEAA@HPEBVTier@Item@@@Z");
|
||||
|
||||
// Item::setIconName
|
||||
fnItemSetIconName = (ItemSetIconName_fn)resolver.Resolve(
|
||||
@@ -190,6 +217,10 @@ bool ResolveSymbols(SymbolResolver& resolver)
|
||||
logSym("TileItem::TileItem", (void*)fnTileItemCtor);
|
||||
logSym("Item::Item", (void*)fnItemCtor);
|
||||
logSym("PickaxeItem::PickaxeItem", (void*)fnPickaxeCtor);
|
||||
logSym("ShovelItem::ShovelItem", (void*)fnShovelCtor);
|
||||
logSym("HoeItem::HoeItem", (void*)fnHoeCtor);
|
||||
logSym("HatchetItem::HatchetItem", (void*)fnHatchetCtor);
|
||||
logSym("WeaponItem::WeaponItem", (void*)fnWeaponCtor);
|
||||
logSym("Item::setIconName", (void*)fnItemSetIconName);
|
||||
logSym("Material::stone addr", (void*)s_materialAddrs[1]);
|
||||
logSym("SOUND_STONE addr", (void*)s_soundAddrs[1]);
|
||||
@@ -320,6 +351,7 @@ bool CreateItem(int itemId, int maxStackSize, int maxDamage, const wchar_t* icon
|
||||
itemId, ctorParam, maxStackSize, maxDamage,
|
||||
iconName ? iconName : L"<none>", descriptionId);
|
||||
|
||||
s_createdItems[itemId] = item;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -346,17 +378,7 @@ bool CreatePickaxeItem(int itemId, int tier, int maxDamage, const wchar_t* iconN
|
||||
// Ensure pickaxe category/material for crafting menus:
|
||||
// baseType=pickaxe(3), material depends on tier.
|
||||
*reinterpret_cast<int*>(static_cast<char*>(item) + 0x38) = 3;
|
||||
int material = 5; // diamond default
|
||||
switch (tier)
|
||||
{
|
||||
case 0: material = 1; break; // wood
|
||||
case 1: material = 2; break; // stone
|
||||
case 2: material = 3; break; // iron
|
||||
case 3: material = 5; break; // diamond
|
||||
case 4: material = 4; break; // gold
|
||||
default: break;
|
||||
}
|
||||
*reinterpret_cast<int*>(static_cast<char*>(item) + 0x3C) = material;
|
||||
*reinterpret_cast<int*>(static_cast<char*>(item) + 0x3C) = MapTierMaterial(tier);
|
||||
|
||||
// Tools should always stack to 1.
|
||||
*reinterpret_cast<int*>(static_cast<char*>(item) + 0x24) = 1;
|
||||
@@ -381,7 +403,89 @@ bool CreatePickaxeItem(int itemId, int tier, int maxDamage, const wchar_t* iconN
|
||||
|
||||
LogUtil::Log("[WeaveLoader] Created PickaxeItem id=%d (ctorParam=%d, tier=%d, damage=%d, icon=%ls, descId=%d)",
|
||||
itemId, ctorParam, tier, maxDamage, iconName ? iconName : L"<none>", descriptionId);
|
||||
s_createdItems[itemId] = item;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool CreateTieredItem(
|
||||
const char* typeName,
|
||||
void* ctorRaw,
|
||||
int baseType,
|
||||
int itemId,
|
||||
int tier,
|
||||
int maxDamage,
|
||||
const wchar_t* iconName,
|
||||
int descriptionId)
|
||||
{
|
||||
if (!s_resolved || !ctorRaw)
|
||||
{
|
||||
LogUtil::Log("[WeaveLoader] %s: symbols not resolved", typeName);
|
||||
return false;
|
||||
}
|
||||
|
||||
const void* tierPtr = GetTier(tier);
|
||||
if (!tierPtr)
|
||||
{
|
||||
LogUtil::Log("[WeaveLoader] %s: invalid tier %d", typeName, tier);
|
||||
return false;
|
||||
}
|
||||
|
||||
int ctorParam = itemId - 256;
|
||||
void* item = ::operator new(ITEM_ALLOC_SIZE);
|
||||
memset(item, 0, ITEM_ALLOC_SIZE);
|
||||
reinterpret_cast<PickaxeCtor_fn>(ctorRaw)(item, ctorParam, tierPtr);
|
||||
|
||||
*reinterpret_cast<int*>(static_cast<char*>(item) + 0x38) = baseType;
|
||||
*reinterpret_cast<int*>(static_cast<char*>(item) + 0x3C) = MapTierMaterial(tier);
|
||||
*reinterpret_cast<int*>(static_cast<char*>(item) + 0x24) = 1;
|
||||
|
||||
if (maxDamage > 0)
|
||||
*reinterpret_cast<int*>(static_cast<char*>(item) + 0x28) = maxDamage;
|
||||
|
||||
if (fnItemSetIconName)
|
||||
{
|
||||
std::wstring name = (iconName && iconName[0]) ? iconName : L"MISSING_ICON_ITEM";
|
||||
fnItemSetIconName(item, name);
|
||||
}
|
||||
|
||||
if (s_itemDescIdOffset > 0 && descriptionId >= 0)
|
||||
{
|
||||
*reinterpret_cast<unsigned int*>(static_cast<char*>(item) + s_itemDescIdOffset) =
|
||||
static_cast<unsigned int>(descriptionId);
|
||||
}
|
||||
|
||||
LogUtil::Log("[WeaveLoader] Created %s id=%d (ctorParam=%d, tier=%d, damage=%d, icon=%ls, descId=%d)",
|
||||
typeName, itemId, ctorParam, tier, maxDamage, iconName ? iconName : L"<none>", descriptionId);
|
||||
s_createdItems[itemId] = item;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CreateShovelItem(int itemId, int tier, int maxDamage, const wchar_t* iconName, int descriptionId)
|
||||
{
|
||||
return CreateTieredItem("ShovelItem", fnShovelCtor, 2, itemId, tier, maxDamage, iconName, descriptionId);
|
||||
}
|
||||
|
||||
bool CreateHoeItem(int itemId, int tier, int maxDamage, const wchar_t* iconName, int descriptionId)
|
||||
{
|
||||
return CreateTieredItem("HoeItem", fnHoeCtor, 5, itemId, tier, maxDamage, iconName, descriptionId);
|
||||
}
|
||||
|
||||
bool CreateAxeItem(int itemId, int tier, int maxDamage, const wchar_t* iconName, int descriptionId)
|
||||
{
|
||||
return CreateTieredItem("HatchetItem", fnHatchetCtor, 4, itemId, tier, maxDamage, iconName, descriptionId);
|
||||
}
|
||||
|
||||
bool CreateSwordItem(int itemId, int tier, int maxDamage, const wchar_t* iconName, int descriptionId)
|
||||
{
|
||||
return CreateTieredItem("WeaponItem", fnWeaponCtor, 1, itemId, tier, maxDamage, iconName, descriptionId);
|
||||
}
|
||||
|
||||
void* FindItem(int itemId)
|
||||
{
|
||||
const auto it = s_createdItems.find(itemId);
|
||||
if (it == s_createdItems.end())
|
||||
return nullptr;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
} // namespace GameObjectFactory
|
||||
|
||||
@@ -26,4 +26,13 @@ namespace GameObjectFactory
|
||||
// maxDamage: if > 0, overrides the tier default durability.
|
||||
bool CreatePickaxeItem(int itemId, int tier, int maxDamage,
|
||||
const wchar_t* iconName, int descriptionId = -1);
|
||||
bool CreateShovelItem(int itemId, int tier, int maxDamage,
|
||||
const wchar_t* iconName, int descriptionId = -1);
|
||||
bool CreateHoeItem(int itemId, int tier, int maxDamage,
|
||||
const wchar_t* iconName, int descriptionId = -1);
|
||||
bool CreateAxeItem(int itemId, int tier, int maxDamage,
|
||||
const wchar_t* iconName, int descriptionId = -1);
|
||||
bool CreateSwordItem(int itemId, int tier, int maxDamage,
|
||||
const wchar_t* iconName, int descriptionId = -1);
|
||||
void* FindItem(int itemId);
|
||||
}
|
||||
|
||||
@@ -236,6 +236,76 @@ bool HookManager::Install(const SymbolResolver& symbols)
|
||||
}
|
||||
}
|
||||
|
||||
if (symbols.pPickaxeItemGetDestroySpeed)
|
||||
{
|
||||
if (MH_CreateHook(symbols.pPickaxeItemGetDestroySpeed,
|
||||
reinterpret_cast<void*>(&GameHooks::Hooked_PickaxeItemGetDestroySpeed),
|
||||
reinterpret_cast<void**>(&GameHooks::Original_PickaxeItemGetDestroySpeed)) != MH_OK)
|
||||
{
|
||||
LogUtil::Log("[WeaveLoader] Warning: Failed to hook PickaxeItem::getDestroySpeed");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogUtil::Log("[WeaveLoader] Hooked PickaxeItem::getDestroySpeed (custom pickaxe tiers)");
|
||||
}
|
||||
}
|
||||
|
||||
if (symbols.pPickaxeItemCanDestroySpecial)
|
||||
{
|
||||
if (MH_CreateHook(symbols.pPickaxeItemCanDestroySpecial,
|
||||
reinterpret_cast<void*>(&GameHooks::Hooked_PickaxeItemCanDestroySpecial),
|
||||
reinterpret_cast<void**>(&GameHooks::Original_PickaxeItemCanDestroySpecial)) != MH_OK)
|
||||
{
|
||||
LogUtil::Log("[WeaveLoader] Warning: Failed to hook PickaxeItem::canDestroySpecial");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogUtil::Log("[WeaveLoader] Hooked PickaxeItem::canDestroySpecial (custom pickaxe tiers)");
|
||||
}
|
||||
}
|
||||
|
||||
if (symbols.pShovelItemGetDestroySpeed)
|
||||
{
|
||||
if (MH_CreateHook(symbols.pShovelItemGetDestroySpeed,
|
||||
reinterpret_cast<void*>(&GameHooks::Hooked_ShovelItemGetDestroySpeed),
|
||||
reinterpret_cast<void**>(&GameHooks::Original_ShovelItemGetDestroySpeed)) != MH_OK)
|
||||
{
|
||||
LogUtil::Log("[WeaveLoader] Warning: Failed to hook ShovelItem::getDestroySpeed");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogUtil::Log("[WeaveLoader] Hooked ShovelItem::getDestroySpeed (custom tool materials)");
|
||||
}
|
||||
}
|
||||
|
||||
if (symbols.pShovelItemCanDestroySpecial)
|
||||
{
|
||||
if (MH_CreateHook(symbols.pShovelItemCanDestroySpecial,
|
||||
reinterpret_cast<void*>(&GameHooks::Hooked_ShovelItemCanDestroySpecial),
|
||||
reinterpret_cast<void**>(&GameHooks::Original_ShovelItemCanDestroySpecial)) != MH_OK)
|
||||
{
|
||||
LogUtil::Log("[WeaveLoader] Warning: Failed to hook ShovelItem::canDestroySpecial");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogUtil::Log("[WeaveLoader] Hooked ShovelItem::canDestroySpecial (custom tool materials)");
|
||||
}
|
||||
}
|
||||
|
||||
if (symbols.pPlayerCanDestroy)
|
||||
{
|
||||
if (MH_CreateHook(symbols.pPlayerCanDestroy,
|
||||
reinterpret_cast<void*>(&GameHooks::Hooked_PlayerCanDestroy),
|
||||
reinterpret_cast<void**>(&GameHooks::Original_PlayerCanDestroy)) != MH_OK)
|
||||
{
|
||||
LogUtil::Log("[WeaveLoader] Warning: Failed to hook Player::canDestroy");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogUtil::Log("[WeaveLoader] Hooked Player::canDestroy (block harvest enforcement)");
|
||||
}
|
||||
}
|
||||
|
||||
if (symbols.pServerPlayerGameModeUseItem)
|
||||
{
|
||||
if (MH_CreateHook(symbols.pServerPlayerGameModeUseItem,
|
||||
@@ -265,6 +335,7 @@ bool HookManager::Install(const SymbolResolver& symbols)
|
||||
}
|
||||
|
||||
GameHooks::SetAtlasLocationPointers(symbols.pTextureAtlasLocationBlocks, symbols.pTextureAtlasLocationItems);
|
||||
GameHooks::SetTileTilesArray(symbols.pTileTiles);
|
||||
|
||||
if (symbols.pTexturesBindTextureResource)
|
||||
{
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
#include "GameObjectFactory.h"
|
||||
#include "FurnaceRecipeRegistry.h"
|
||||
#include "GameHooks.h"
|
||||
#include "CustomPickaxeRegistry.h"
|
||||
#include "CustomToolMaterialRegistry.h"
|
||||
#include "CustomBlockRegistry.h"
|
||||
#include "ModStrings.h"
|
||||
#include "LogUtil.h"
|
||||
#include <Windows.h>
|
||||
@@ -45,7 +48,9 @@ int native_register_block(
|
||||
const char* iconName,
|
||||
float lightEmission,
|
||||
int lightBlock,
|
||||
const char* displayName)
|
||||
const char* displayName,
|
||||
int requiredHarvestLevel,
|
||||
int requiredTool)
|
||||
{
|
||||
if (!namespacedId) return -1;
|
||||
|
||||
@@ -75,6 +80,11 @@ int native_register_block(
|
||||
LogUtil::Log("[WeaveLoader] Warning: failed to create game Tile for block '%s' id=%d", namespacedId, id);
|
||||
}
|
||||
|
||||
if (requiredHarvestLevel >= 0 || requiredTool != 0)
|
||||
{
|
||||
CustomBlockRegistry::Register(id, requiredHarvestLevel, requiredTool);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
@@ -154,6 +164,171 @@ int native_register_pickaxe_item(
|
||||
return id;
|
||||
}
|
||||
|
||||
int native_register_shovel_item(
|
||||
const char* namespacedId,
|
||||
int tier,
|
||||
int maxDamage,
|
||||
const char* iconName,
|
||||
const char* displayName)
|
||||
{
|
||||
if (!namespacedId) return -1;
|
||||
|
||||
int id = IdRegistry::Instance().Register(IdRegistry::Type::Item, namespacedId);
|
||||
if (id < 0) return -1;
|
||||
|
||||
std::wstring wIcon = Utf8ToWide(iconName);
|
||||
int descId = -1;
|
||||
if (displayName && displayName[0])
|
||||
{
|
||||
descId = ModStrings::AllocateId();
|
||||
std::wstring wName = Utf8ToWide(displayName);
|
||||
ModStrings::Register(descId, wName.c_str());
|
||||
}
|
||||
|
||||
if (!GameObjectFactory::CreateShovelItem(id, tier, maxDamage, wIcon.empty() ? nullptr : wIcon.c_str(), descId))
|
||||
LogUtil::Log("[WeaveLoader] Warning: failed to create native ShovelItem for '%s' id=%d", namespacedId, id);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
int native_register_hoe_item(
|
||||
const char* namespacedId,
|
||||
int tier,
|
||||
int maxDamage,
|
||||
const char* iconName,
|
||||
const char* displayName)
|
||||
{
|
||||
if (!namespacedId) return -1;
|
||||
|
||||
int id = IdRegistry::Instance().Register(IdRegistry::Type::Item, namespacedId);
|
||||
if (id < 0) return -1;
|
||||
|
||||
std::wstring wIcon = Utf8ToWide(iconName);
|
||||
int descId = -1;
|
||||
if (displayName && displayName[0])
|
||||
{
|
||||
descId = ModStrings::AllocateId();
|
||||
std::wstring wName = Utf8ToWide(displayName);
|
||||
ModStrings::Register(descId, wName.c_str());
|
||||
}
|
||||
|
||||
if (!GameObjectFactory::CreateHoeItem(id, tier, maxDamage, wIcon.empty() ? nullptr : wIcon.c_str(), descId))
|
||||
LogUtil::Log("[WeaveLoader] Warning: failed to create native HoeItem for '%s' id=%d", namespacedId, id);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
int native_register_axe_item(
|
||||
const char* namespacedId,
|
||||
int tier,
|
||||
int maxDamage,
|
||||
const char* iconName,
|
||||
const char* displayName)
|
||||
{
|
||||
if (!namespacedId) return -1;
|
||||
|
||||
int id = IdRegistry::Instance().Register(IdRegistry::Type::Item, namespacedId);
|
||||
if (id < 0) return -1;
|
||||
|
||||
std::wstring wIcon = Utf8ToWide(iconName);
|
||||
int descId = -1;
|
||||
if (displayName && displayName[0])
|
||||
{
|
||||
descId = ModStrings::AllocateId();
|
||||
std::wstring wName = Utf8ToWide(displayName);
|
||||
ModStrings::Register(descId, wName.c_str());
|
||||
}
|
||||
|
||||
if (!GameObjectFactory::CreateAxeItem(id, tier, maxDamage, wIcon.empty() ? nullptr : wIcon.c_str(), descId))
|
||||
LogUtil::Log("[WeaveLoader] Warning: failed to create native HatchetItem for '%s' id=%d", namespacedId, id);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
int native_register_sword_item(
|
||||
const char* namespacedId,
|
||||
int tier,
|
||||
int maxDamage,
|
||||
const char* iconName,
|
||||
const char* displayName)
|
||||
{
|
||||
if (!namespacedId) return -1;
|
||||
|
||||
int id = IdRegistry::Instance().Register(IdRegistry::Type::Item, namespacedId);
|
||||
if (id < 0) return -1;
|
||||
|
||||
std::wstring wIcon = Utf8ToWide(iconName);
|
||||
int descId = -1;
|
||||
if (displayName && displayName[0])
|
||||
{
|
||||
descId = ModStrings::AllocateId();
|
||||
std::wstring wName = Utf8ToWide(displayName);
|
||||
ModStrings::Register(descId, wName.c_str());
|
||||
}
|
||||
|
||||
if (!GameObjectFactory::CreateSwordItem(id, tier, maxDamage, wIcon.empty() ? nullptr : wIcon.c_str(), descId))
|
||||
LogUtil::Log("[WeaveLoader] Warning: failed to create native WeaponItem for '%s' id=%d", namespacedId, id);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
int native_configure_custom_pickaxe_item(
|
||||
int numericItemId,
|
||||
int harvestLevel,
|
||||
float destroySpeed)
|
||||
{
|
||||
return native_configure_custom_tool_item(
|
||||
numericItemId,
|
||||
static_cast<int>(CustomToolMaterialRegistry::ToolKind::Pickaxe),
|
||||
harvestLevel,
|
||||
destroySpeed,
|
||||
0.0f);
|
||||
}
|
||||
|
||||
int native_configure_custom_tool_item(
|
||||
int numericItemId,
|
||||
int toolKind,
|
||||
int harvestLevel,
|
||||
float destroySpeed,
|
||||
float attackDamage)
|
||||
{
|
||||
if (numericItemId < 0 || harvestLevel < 0 || destroySpeed <= 0.0f)
|
||||
return 0;
|
||||
|
||||
const auto kind = static_cast<CustomToolMaterialRegistry::ToolKind>(toolKind);
|
||||
CustomToolMaterialRegistry::Register(numericItemId, kind, harvestLevel, destroySpeed, attackDamage);
|
||||
if (kind == CustomToolMaterialRegistry::ToolKind::Pickaxe)
|
||||
{
|
||||
CustomPickaxeRegistry::Register(numericItemId, harvestLevel, destroySpeed);
|
||||
}
|
||||
|
||||
void* itemPtr = GameObjectFactory::FindItem(numericItemId);
|
||||
if (itemPtr)
|
||||
{
|
||||
switch (kind)
|
||||
{
|
||||
case CustomToolMaterialRegistry::ToolKind::Pickaxe:
|
||||
case CustomToolMaterialRegistry::ToolKind::Shovel:
|
||||
case CustomToolMaterialRegistry::ToolKind::Axe:
|
||||
if (destroySpeed > 0.0f)
|
||||
*reinterpret_cast<float*>(static_cast<char*>(itemPtr) + 0xA0) = destroySpeed;
|
||||
if (attackDamage > 0.0f)
|
||||
*reinterpret_cast<float*>(static_cast<char*>(itemPtr) + 0xA4) = attackDamage;
|
||||
break;
|
||||
case CustomToolMaterialRegistry::ToolKind::Sword:
|
||||
if (attackDamage > 0.0f)
|
||||
*reinterpret_cast<float*>(static_cast<char*>(itemPtr) + 0x98) = attackDamage;
|
||||
break;
|
||||
case CustomToolMaterialRegistry::ToolKind::Hoe:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LogUtil::Log("[WeaveLoader] Configured custom tool item id=%d (kind=%d harvest=%d speed=%.2f attack=%.2f)",
|
||||
numericItemId, toolKind, harvestLevel, destroySpeed, attackDamage);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int native_allocate_description_id()
|
||||
{
|
||||
return ModStrings::AllocateId();
|
||||
|
||||
@@ -14,7 +14,9 @@ extern "C"
|
||||
const char* iconName,
|
||||
float lightEmission,
|
||||
int lightBlock,
|
||||
const char* displayName);
|
||||
const char* displayName,
|
||||
int requiredHarvestLevel,
|
||||
int requiredTool);
|
||||
|
||||
__declspec(dllexport) int native_register_item(
|
||||
const char* namespacedId,
|
||||
@@ -29,6 +31,41 @@ extern "C"
|
||||
int maxDamage,
|
||||
const char* iconName,
|
||||
const char* displayName);
|
||||
__declspec(dllexport) int native_register_shovel_item(
|
||||
const char* namespacedId,
|
||||
int tier,
|
||||
int maxDamage,
|
||||
const char* iconName,
|
||||
const char* displayName);
|
||||
__declspec(dllexport) int native_register_hoe_item(
|
||||
const char* namespacedId,
|
||||
int tier,
|
||||
int maxDamage,
|
||||
const char* iconName,
|
||||
const char* displayName);
|
||||
__declspec(dllexport) int native_register_axe_item(
|
||||
const char* namespacedId,
|
||||
int tier,
|
||||
int maxDamage,
|
||||
const char* iconName,
|
||||
const char* displayName);
|
||||
__declspec(dllexport) int native_register_sword_item(
|
||||
const char* namespacedId,
|
||||
int tier,
|
||||
int maxDamage,
|
||||
const char* iconName,
|
||||
const char* displayName);
|
||||
|
||||
__declspec(dllexport) int native_configure_custom_pickaxe_item(
|
||||
int numericItemId,
|
||||
int harvestLevel,
|
||||
float destroySpeed);
|
||||
__declspec(dllexport) int native_configure_custom_tool_item(
|
||||
int numericItemId,
|
||||
int toolKind,
|
||||
int harvestLevel,
|
||||
float destroySpeed,
|
||||
float attackDamage);
|
||||
|
||||
__declspec(dllexport) int native_allocate_description_id();
|
||||
__declspec(dllexport) void native_register_string(int descriptionId, const char* displayName);
|
||||
|
||||
@@ -30,6 +30,11 @@ static const char* SYM_CLOCK_GETSOURCEHEIGHT = "?getSourceHeight@ClockTexture@@U
|
||||
static const char* SYM_ITEMINSTANCE_MINEBLOCK = "?mineBlock@ItemInstance@@QEAAXPEAVLevel@@HHHHV?$shared_ptr@VPlayer@@@std@@@Z";
|
||||
static const char* SYM_ITEM_MINEBLOCK = "?mineBlock@Item@@UEAA_NV?$shared_ptr@VItemInstance@@@std@@PEAVLevel@@HHHHV?$shared_ptr@VLivingEntity@@@3@@Z";
|
||||
static const char* SYM_DIGGERITEM_MINEBLOCK = "?mineBlock@DiggerItem@@UEAA_NV?$shared_ptr@VItemInstance@@@std@@PEAVLevel@@HHHHV?$shared_ptr@VLivingEntity@@@3@@Z";
|
||||
static const char* SYM_PICKAXEITEM_GETDESTROYSPEED = "?getDestroySpeed@PickaxeItem@@UEAAMV?$shared_ptr@VItemInstance@@@std@@PEAVTile@@@Z";
|
||||
static const char* SYM_PICKAXEITEM_CANDESTROYSPECIAL = "?canDestroySpecial@PickaxeItem@@UEAA_NPEAVTile@@@Z";
|
||||
static const char* SYM_SHOVELITEM_GETDESTROYSPEED = "?getDestroySpeed@ShovelItem@@UEAAMV?$shared_ptr@VItemInstance@@@std@@PEAVTile@@@Z";
|
||||
static const char* SYM_SHOVELITEM_CANDESTROYSPECIAL = "?canDestroySpecial@ShovelItem@@UEAA_NPEAVTile@@@Z";
|
||||
static const char* SYM_PLAYER_CANDESTROY = "?canDestroy@Player@@QEAA_NPEAVTile@@@Z";
|
||||
static const char* SYM_SERVER_PLAYER_GAMEMODE_USEITEM = "?useItem@ServerPlayerGameMode@@QEAA_NV?$shared_ptr@VPlayer@@@std@@PEAVLevel@@V?$shared_ptr@VItemInstance@@@3@_N@Z";
|
||||
static const char* SYM_MULTI_PLAYER_GAMEMODE_USEITEM = "?useItem@MultiPlayerGameMode@@UEAA_NV?$shared_ptr@VPlayer@@@std@@PEAVLevel@@V?$shared_ptr@VItemInstance@@@3@_N@Z";
|
||||
static const char* SYM_TEXTURES_BIND_RESOURCE = "?bindTexture@Textures@@QEAAXPEAVResourceLocation@@@Z";
|
||||
@@ -55,6 +60,7 @@ static const char* SYM_ITEMINSTANCE_HURTANDBREAK = "?hurtAndBreak@ItemInstance@@
|
||||
static const char* SYM_ABSTRACTCONTAINERMENU_BROADCASTCHANGES = "?broadcastChanges@AbstractContainerMenu@@UEAAXXZ";
|
||||
static const char* SYM_TEXATLAS_BLOCKS = "?LOCATION_BLOCKS@TextureAtlas@@2VResourceLocation@@A";
|
||||
static const char* SYM_TEXATLAS_ITEMS = "?LOCATION_ITEMS@TextureAtlas@@2VResourceLocation@@A";
|
||||
static const char* SYM_TILE_TILES = "?tiles@Tile@@2PEAPEAV1@EA";
|
||||
|
||||
bool SymbolResolver::Initialize()
|
||||
{
|
||||
@@ -137,6 +143,11 @@ bool SymbolResolver::ResolveGameFunctions()
|
||||
pItemInstanceMineBlock = Resolve(SYM_ITEMINSTANCE_MINEBLOCK);
|
||||
pItemMineBlock = Resolve(SYM_ITEM_MINEBLOCK);
|
||||
pDiggerItemMineBlock = Resolve(SYM_DIGGERITEM_MINEBLOCK);
|
||||
pPickaxeItemGetDestroySpeed = Resolve(SYM_PICKAXEITEM_GETDESTROYSPEED);
|
||||
pPickaxeItemCanDestroySpecial = Resolve(SYM_PICKAXEITEM_CANDESTROYSPECIAL);
|
||||
pShovelItemGetDestroySpeed = Resolve(SYM_SHOVELITEM_GETDESTROYSPEED);
|
||||
pShovelItemCanDestroySpecial = Resolve(SYM_SHOVELITEM_CANDESTROYSPECIAL);
|
||||
pPlayerCanDestroy = Resolve(SYM_PLAYER_CANDESTROY);
|
||||
pServerPlayerGameModeUseItem = Resolve(SYM_SERVER_PLAYER_GAMEMODE_USEITEM);
|
||||
pMultiPlayerGameModeUseItem = Resolve(SYM_MULTI_PLAYER_GAMEMODE_USEITEM);
|
||||
pTexturesBindTextureResource = Resolve(SYM_TEXTURES_BIND_RESOURCE);
|
||||
@@ -164,6 +175,7 @@ bool SymbolResolver::ResolveGameFunctions()
|
||||
pAbstractContainerMenuBroadcastChanges = Resolve(SYM_ABSTRACTCONTAINERMENU_BROADCASTCHANGES);
|
||||
pTextureAtlasLocationBlocks = Resolve(SYM_TEXATLAS_BLOCKS);
|
||||
pTextureAtlasLocationItems = Resolve(SYM_TEXATLAS_ITEMS);
|
||||
pTileTiles = Resolve(SYM_TILE_TILES);
|
||||
if (!pOperatorNew) pOperatorNew = GetProcAddress(GetModuleHandleA("vcruntime140.dll"), SYM_OPERATOR_NEW);
|
||||
if (!pOperatorNew) pOperatorNew = GetProcAddress(GetModuleHandleA("vcruntime140d.dll"), SYM_OPERATOR_NEW);
|
||||
if (!pOperatorNew) pOperatorNew = GetProcAddress(GetModuleHandle(nullptr), SYM_OPERATOR_NEW);
|
||||
@@ -202,6 +214,11 @@ bool SymbolResolver::ResolveGameFunctions()
|
||||
logSym("ItemInstance::mineBlock", pItemInstanceMineBlock);
|
||||
logSym("Item::mineBlock", pItemMineBlock);
|
||||
logSym("DiggerItem::mineBlock", pDiggerItemMineBlock);
|
||||
logSym("PickaxeItem::getDestroySpeed", pPickaxeItemGetDestroySpeed);
|
||||
logSym("PickaxeItem::canDestroySpecial", pPickaxeItemCanDestroySpecial);
|
||||
logSym("ShovelItem::getDestroySpeed", pShovelItemGetDestroySpeed);
|
||||
logSym("ShovelItem::canDestroySpecial", pShovelItemCanDestroySpecial);
|
||||
logSym("Player::canDestroy", pPlayerCanDestroy);
|
||||
logSym("ServerPlayerGameMode::useItem", pServerPlayerGameModeUseItem);
|
||||
logSym("MultiPlayerGameMode::useItem", pMultiPlayerGameModeUseItem);
|
||||
logSym("Textures::bindTexture(ResourceLocation)", pTexturesBindTextureResource);
|
||||
@@ -225,6 +242,7 @@ bool SymbolResolver::ResolveGameFunctions()
|
||||
logSym("AbstractContainerMenu::broadcastChanges", pAbstractContainerMenuBroadcastChanges);
|
||||
logSym("TextureAtlas::LOCATION_BLOCKS", pTextureAtlasLocationBlocks);
|
||||
logSym("TextureAtlas::LOCATION_ITEMS", pTextureAtlasLocationItems);
|
||||
logSym("Tile::tiles", pTileTiles);
|
||||
|
||||
bool ok = pRunStaticCtors && pMinecraftTick && pMinecraftInit;
|
||||
if (ok)
|
||||
|
||||
@@ -35,6 +35,11 @@ public:
|
||||
void* pItemInstanceMineBlock = nullptr; // ItemInstance::mineBlock(Level*,int,int,int,int,shared_ptr<Player>)
|
||||
void* pItemMineBlock = nullptr; // Item::mineBlock(shared_ptr<ItemInstance>,Level*,int,int,int,int,shared_ptr<LivingEntity>)
|
||||
void* pDiggerItemMineBlock = nullptr; // DiggerItem::mineBlock(shared_ptr<ItemInstance>,Level*,int,int,int,int,shared_ptr<LivingEntity>)
|
||||
void* pPickaxeItemGetDestroySpeed = nullptr; // PickaxeItem::getDestroySpeed(shared_ptr<ItemInstance>,Tile*)
|
||||
void* pPickaxeItemCanDestroySpecial = nullptr; // PickaxeItem::canDestroySpecial(Tile*)
|
||||
void* pShovelItemGetDestroySpeed = nullptr; // ShovelItem::getDestroySpeed(shared_ptr<ItemInstance>,Tile*)
|
||||
void* pShovelItemCanDestroySpecial = nullptr; // ShovelItem::canDestroySpecial(Tile*)
|
||||
void* pPlayerCanDestroy = nullptr; // Player::canDestroy(Tile*)
|
||||
void* pServerPlayerGameModeUseItem = nullptr; // ServerPlayerGameMode::useItem(shared_ptr<Player>,Level*,shared_ptr<ItemInstance>,bool)
|
||||
void* pMultiPlayerGameModeUseItem = nullptr; // MultiPlayerGameMode::useItem(shared_ptr<Player>,Level*,shared_ptr<ItemInstance>,bool)
|
||||
void* pTexturesBindTextureResource = nullptr; // Textures::bindTexture(ResourceLocation*)
|
||||
@@ -58,6 +63,7 @@ public:
|
||||
void* pAbstractContainerMenuBroadcastChanges = nullptr; // AbstractContainerMenu::broadcastChanges()
|
||||
void* pTextureAtlasLocationBlocks = nullptr; // TextureAtlas::LOCATION_BLOCKS
|
||||
void* pTextureAtlasLocationItems = nullptr; // TextureAtlas::LOCATION_ITEMS
|
||||
void* pTileTiles = nullptr; // Tile::tiles (Tile*[]) for tile id lookup
|
||||
|
||||
private:
|
||||
uintptr_t m_moduleBase = 0;
|
||||
|
||||
Reference in New Issue
Block a user