diff --git a/WeaveLoaderRuntime/src/GameHooks.cpp b/WeaveLoaderRuntime/src/GameHooks.cpp index 8d573e4..0d55dd4 100644 --- a/WeaveLoaderRuntime/src/GameHooks.cpp +++ b/WeaveLoaderRuntime/src/GameHooks.cpp @@ -576,6 +576,8 @@ namespace GameHooks static bool TryGetModelForState(int blockId, int data, void* levelPtr, int x, int y, int z, const std::vector*& outBoxes) { + if (!ModelRegistry::HasModel(blockId)) + return false; if (data < 0) data = 0; const int profile = ModelRegistry::GetRotationProfile(blockId); @@ -3427,7 +3429,7 @@ namespace GameHooks { const std::vector* boxes = nullptr; int tileId = GetTileId(tilePtr); - if (tileId >= 0) + if (tileId >= 0 && ModelRegistry::HasModel(tileId)) { int data = forceData; void* levelPtr = nullptr; @@ -3456,7 +3458,8 @@ namespace GameHooks { const std::vector* boxes = nullptr; int tileId = GetTileId(tilePtr); - if (tileId >= 0 && TryGetModelForState(tileId, data, nullptr, 0, 0, 0, boxes) && boxes && !boxes->empty()) + if (tileId >= 0 && ModelRegistry::HasModel(tileId) && + TryGetModelForState(tileId, data, nullptr, 0, 0, 0, boxes) && boxes && !boxes->empty()) { if (Original_TileRendererRenderTile && Tile_SetShape) { @@ -3483,7 +3486,8 @@ namespace GameHooks const std::vector* boxes = nullptr; int tileId = GetTileId(thisPtr); int data = Level_GetData && levelPtr ? Level_GetData(levelPtr, x, y, z) : 0; - if (tileId >= 0 && TryGetModelForState(tileId, data, levelPtr, x, y, z, boxes) && boxes && !boxes->empty() && AABB_NewTemp && boxesPtr && boxPtr) + if (tileId >= 0 && ModelRegistry::HasModel(tileId) && + TryGetModelForState(tileId, data, levelPtr, x, y, z, boxes) && boxes && !boxes->empty() && AABB_NewTemp && boxesPtr && boxPtr) { auto list = reinterpret_cast*>(boxesPtr); const AABBRaw* clipBox = reinterpret_cast(boxPtr); @@ -3535,7 +3539,8 @@ namespace GameHooks const std::vector* boxes = nullptr; int tileId = GetTileId(thisPtr); - if (tileId >= 0 && ModelRegistry::TryGetModel(tileId, boxes) && boxes && !boxes->empty() && Tile_SetShape) + if (tileId >= 0 && ModelRegistry::HasModel(tileId) && + ModelRegistry::TryGetModel(tileId, boxes) && boxes && !boxes->empty() && Tile_SetShape) { float minX = 0.0f, minY = 0.0f, minZ = 0.0f; float maxX = 0.0f, maxY = 0.0f, maxZ = 0.0f; @@ -3581,7 +3586,8 @@ namespace GameHooks { const std::vector* boxes = nullptr; int tileId = GetTileId(thisPtr); - if (tileId >= 0 && ModelRegistry::TryGetModel(tileId, boxes) && boxes && !boxes->empty()) + if (tileId >= 0 && ModelRegistry::HasModel(tileId) && + ModelRegistry::TryGetModel(tileId, boxes) && boxes && !boxes->empty()) { if (IsFullCubeModel(*boxes)) return Original_TileIsSolidRender ? Original_TileIsSolidRender(thisPtr, isServerLevel) : true; @@ -3595,7 +3601,8 @@ namespace GameHooks { const std::vector* boxes = nullptr; int tileId = GetTileId(thisPtr); - if (tileId >= 0 && ModelRegistry::TryGetModel(tileId, boxes) && boxes && !boxes->empty()) + if (tileId >= 0 && ModelRegistry::HasModel(tileId) && + ModelRegistry::TryGetModel(tileId, boxes) && boxes && !boxes->empty()) { if (IsFullCubeModel(*boxes)) return Original_TileIsCubeShaped ? Original_TileIsCubeShaped(thisPtr) : true; @@ -3613,7 +3620,8 @@ namespace GameHooks const std::vector* boxes = nullptr; int tileId = GetTileId(thisPtr); int data = Level_GetData && levelPtr ? Level_GetData(levelPtr, x, y, z) : 0; - if (tileId < 0 || !TryGetModelForState(tileId, data, levelPtr, x, y, z, boxes) || !boxes || boxes->empty()) + if (tileId < 0 || !ModelRegistry::HasModel(tileId) || + !TryGetModelForState(tileId, data, levelPtr, x, y, z, boxes) || !boxes || boxes->empty()) { return Original_TileClip ? Original_TileClip(thisPtr, levelPtr, x, y, z, aPtr, bPtr) : nullptr; } @@ -3697,7 +3705,8 @@ namespace GameHooks const std::vector* boxes = nullptr; int data = Level_GetData ? Level_GetData(thisPtr, x, y, z) : 0; - if (!TryGetModelForState(tileId, data, thisPtr, x, y, z, boxes) || !boxes || boxes->empty()) + if (!ModelRegistry::HasModel(tileId) || + !TryGetModelForState(tileId, data, thisPtr, x, y, z, boxes) || !boxes || boxes->empty()) continue; for (const auto& box : *boxes) diff --git a/WeaveLoaderRuntime/src/ModelRegistry.cpp b/WeaveLoaderRuntime/src/ModelRegistry.cpp index ea0a39a..a6ae02e 100644 --- a/WeaveLoaderRuntime/src/ModelRegistry.cpp +++ b/WeaveLoaderRuntime/src/ModelRegistry.cpp @@ -3,9 +3,13 @@ #include #include #include +#include +#include namespace { + constexpr int kFastModelLimit = 4096; + struct BlockModelEntry { std::vector base; @@ -15,6 +19,13 @@ namespace std::unordered_map g_models; std::mutex g_mutex; + std::array, kFastModelLimit> g_hasModel{}; + std::array, kFastModelLimit> g_rotationProfile{}; + + inline bool IsFastIndex(int blockId) + { + return blockId >= 0 && blockId < kFastModelLimit; + } } void ModelRegistry::RegisterBlockModel(int blockId, const ModelBox* boxes, int count) @@ -32,6 +43,9 @@ void ModelRegistry::RegisterBlockModel(int blockId, const ModelBox* boxes, int c g_models[blockId].base = std::move(data); } + if (IsFastIndex(blockId)) + g_hasModel[blockId].store(1, std::memory_order_release); + LogUtil::Log("[WeaveLoader] ModelRegistry: registered %d box(es) for block %d", count, blockId); } @@ -50,6 +64,9 @@ void ModelRegistry::RegisterBlockModelVariant(int blockId, const char* key, cons g_models[blockId].variants[std::string(key)] = std::move(data); } + if (IsFastIndex(blockId)) + g_hasModel[blockId].store(1, std::memory_order_release); + LogUtil::Log("[WeaveLoader] ModelRegistry: registered variant '%s' (%d box(es)) for block %d", key, count, blockId); } @@ -57,12 +74,33 @@ void ModelRegistry::SetRotationProfile(int blockId, int profile) { if (blockId < 0) return; + if (IsFastIndex(blockId)) + g_rotationProfile[blockId].store(profile, std::memory_order_release); std::lock_guard guard(g_mutex); g_models[blockId].rotationProfile = profile; } +bool ModelRegistry::HasModel(int blockId) +{ + if (blockId < 0) + return false; + if (IsFastIndex(blockId)) + return g_hasModel[blockId].load(std::memory_order_acquire) != 0; + + std::lock_guard guard(g_mutex); + auto it = g_models.find(blockId); + if (it == g_models.end()) + return false; + return !it->second.base.empty() || !it->second.variants.empty(); +} + int ModelRegistry::GetRotationProfile(int blockId) { + if (blockId < 0) + return 0; + if (IsFastIndex(blockId)) + return g_rotationProfile[blockId].load(std::memory_order_acquire); + std::lock_guard guard(g_mutex); auto it = g_models.find(blockId); if (it == g_models.end()) @@ -72,6 +110,8 @@ int ModelRegistry::GetRotationProfile(int blockId) bool ModelRegistry::TryGetModel(int blockId, const std::vector*& outBoxes) { + if (!HasModel(blockId)) + return false; std::lock_guard guard(g_mutex); auto it = g_models.find(blockId); if (it == g_models.end()) @@ -86,6 +126,8 @@ bool ModelRegistry::TryGetModelVariant(int blockId, const char* key, const std:: { if (!key) return false; + if (!HasModel(blockId)) + return false; std::lock_guard guard(g_mutex); auto it = g_models.find(blockId); if (it == g_models.end()) diff --git a/WeaveLoaderRuntime/src/ModelRegistry.h b/WeaveLoaderRuntime/src/ModelRegistry.h index 8745b77..87eb134 100644 --- a/WeaveLoaderRuntime/src/ModelRegistry.h +++ b/WeaveLoaderRuntime/src/ModelRegistry.h @@ -17,6 +17,7 @@ namespace ModelRegistry void RegisterBlockModel(int blockId, const ModelBox* boxes, int count); void RegisterBlockModelVariant(int blockId, const char* key, const ModelBox* boxes, int count); void SetRotationProfile(int blockId, int profile); + bool HasModel(int blockId); int GetRotationProfile(int blockId); bool TryGetModel(int blockId, const std::vector*& outBoxes); bool TryGetModelVariant(int blockId, const char* key, const std::vector*& outBoxes);