From 625ce973857562c0e5383327974aac6fbefdf44f Mon Sep 17 00:00:00 2001 From: Tropical <42101043+tropicaaal@users.noreply.github.com> Date: Wed, 25 Mar 2026 14:13:00 -0500 Subject: [PATCH] refactor: use thread_local in OldChunkStorage, FireworksRecipe, Level, Entity --- Minecraft.Client/Rendering/Tesselator.cpp | 4 +- Minecraft.World/Core/BehaviorRegistry.h | 2 +- Minecraft.World/Entities/Entity.cpp | 48 +++------------ Minecraft.World/Entities/Entity.h | 6 +- Minecraft.World/Level/Level.cpp | 51 +++------------- Minecraft.World/Level/Level.h | 15 ++--- .../Level/Storage/OldChunkStorage.cpp | 58 +++++-------------- .../Level/Storage/OldChunkStorage.h | 4 +- Minecraft.World/Recipes/FireworksRecipe.cpp | 6 +- 9 files changed, 44 insertions(+), 150 deletions(-) diff --git a/Minecraft.Client/Rendering/Tesselator.cpp b/Minecraft.Client/Rendering/Tesselator.cpp index aac70dfaf..661eb121b 100644 --- a/Minecraft.Client/Rendering/Tesselator.cpp +++ b/Minecraft.Client/Rendering/Tesselator.cpp @@ -27,11 +27,11 @@ int normal; thread_local Tesselator* Tesselator::m_threadInstance = nullptr; Tesselator* Tesselator::getInstance() { - return m_threadinstance; + return m_threadInstance; } void Tesselator::CreateNewThreadStorage(int bytes) { - Tesselator::m_threadinstance = new Tesselator(bytes / 4); + Tesselator::m_threadInstance = new Tesselator(bytes / 4); } // she tessalate my vertices till i render diff --git a/Minecraft.World/Core/BehaviorRegistry.h b/Minecraft.World/Core/BehaviorRegistry.h index f49d924f1..23b0161bc 100644 --- a/Minecraft.World/Core/BehaviorRegistry.h +++ b/Minecraft.World/Core/BehaviorRegistry.h @@ -1,6 +1,6 @@ #pragma once -class DispenseItemBehavior; +#include "DispenseItemBehavior.h" class BehaviorRegistry { private: diff --git a/Minecraft.World/Entities/Entity.cpp b/Minecraft.World/Entities/Entity.cpp index c0f4412ed..872e0c23c 100644 --- a/Minecraft.World/Entities/Entity.cpp +++ b/Minecraft.World/Entities/Entity.cpp @@ -26,40 +26,12 @@ #include "../../Minecraft.Client/Level/ServerLevel.h" #include "../../Minecraft.Client/Network/PlayerList.h" -namespace { -#if defined(_WIN32) -inline void* EntityTlsGetValue(Entity::TlsKey key) { return TlsGetValue(key); } - -inline void EntityTlsSetValue(Entity::TlsKey key, void* value) { - TlsSetValue(key, value); -} -#else -pthread_key_t CreateEntityTlsKey() { - pthread_key_t key; - const int result = pthread_key_create(&key, nullptr); - assert(result == 0); - return key; -} - -inline void* EntityTlsGetValue(pthread_key_t key) { - return pthread_getspecific(key); -} - -inline void EntityTlsSetValue(pthread_key_t key, void* value) { - pthread_setspecific(key, value); -} -#endif -} // namespace +thread_local bool Entity::m_threadUseSmallIds = false; const std::wstring Entity::RIDING_TAG = L"Riding"; int Entity::entityCounter = 2048; // 4J - changed initialiser to 2048, as we are using range 0 - 2047 // as special unique smaller ids for things that need network tracked -#if defined(_WIN32) -Entity::TlsKey Entity::tlsIdx = TlsAlloc(); -#else -Entity::TlsKey Entity::tlsIdx = CreateEntityTlsKey(); -#endif // 4J - added getSmallId & freeSmallId methods unsigned int Entity::entityIdUsedFlags[2048 / 32] = {0}; @@ -82,7 +54,7 @@ int Entity::getSmallId() { // telling the client that the entity has been removed After we have already // re-used its Id and created a new entity. This ends up with newly created // client-side entities being removed by accident, causing invisible mobs. - if (reinterpret_cast(EntityTlsGetValue(tlsIdx)) != 0) { + if (m_threadUseSmallIds) { MinecraftServer* server = MinecraftServer::getInstance(); if (server) { // In some attempt to optimise this, flagEntitiesToBeRemoved most of @@ -157,13 +129,13 @@ void Entity::countFlagsForPIX() { void Entity::resetSmallId() { freeSmallId(entityId); - if (reinterpret_cast(EntityTlsGetValue(tlsIdx)) != 0) { + if (m_threadUseSmallIds) { entityId = getSmallId(); } } void Entity::freeSmallId(int index) { - if (reinterpret_cast(EntityTlsGetValue(tlsIdx)) == 0) + if (!m_threadUseSmallIds) return; // Don't do anything with small ids if this isn't the server // thread if (index >= 2048) return; // Don't do anything if this isn't a short id @@ -176,10 +148,7 @@ void Entity::freeSmallId(int index) { entityIdWanderFlags[i] &= uiMask; } -void Entity::useSmallIds() { - EntityTlsSetValue(tlsIdx, - reinterpret_cast(static_cast(1))); -} +void Entity::useSmallIds() { m_threadUseSmallIds = true; } // Things also added here to be able to manage the concept of a number of extra // "wandering" entities - normally path finding entities aren't allowed to @@ -192,7 +161,7 @@ void Entity::useSmallIds() { // Let the management system here know whether or not to consider this // particular entity for some extra wandering void Entity::considerForExtraWandering(bool enable) { - if (reinterpret_cast(EntityTlsGetValue(tlsIdx)) == 0) + if (!m_threadUseSmallIds) return; // Don't do anything with small ids if this isn't the server // thread if (entityId >= 2048) return; // Don't do anything if this isn't a short id @@ -211,7 +180,7 @@ void Entity::considerForExtraWandering(bool enable) { // Should this entity do wandering in addition to what the java code would have // done? bool Entity::isExtraWanderingEnabled() { - if (reinterpret_cast(EntityTlsGetValue(tlsIdx)) == 0) + if (!m_threadUseSmallIds) return false; // Don't do anything with small ids if this isn't the // server thread if (entityId >= 2048) @@ -278,8 +247,7 @@ void Entity::_init(bool useSmallId, Level* level) { // rest of the range is used for anything we don't need to track like this, // currently particles. We only ever want to allocate this type of id from // the server thread, so using thread local storage to isolate this. - if (useSmallId && - reinterpret_cast(EntityTlsGetValue(tlsIdx)) != 0) { + if (useSmallId && m_threadUseSmallIds) { entityId = getSmallId(); } else { entityId = Entity::entityCounter++; diff --git a/Minecraft.World/Entities/Entity.h b/Minecraft.World/Entities/Entity.h index 3fceb64b6..9374fea4e 100644 --- a/Minecraft.World/Entities/Entity.h +++ b/Minecraft.World/Entities/Entity.h @@ -6,9 +6,6 @@ #include "../Util/Vec3.h" #include "../Util/Definitions.h" #include -#if !defined(_WIN32) -#include -#endif class LivingEntity; class LightningBolt; @@ -431,7 +428,8 @@ private: static int extraWanderIds[EXTRA_WANDER_MAX]; static int extraWanderCount; static int extraWanderTicks; - static TlsKey tlsIdx; + + static thread_local bool m_threadUseSmallIds; public: static void tickExtraWandering(); static void countFlagsForPIX(); diff --git a/Minecraft.World/Level/Level.cpp b/Minecraft.World/Level/Level.cpp index a4b36f98e..75c0a6c6d 100644 --- a/Minecraft.World/Level/Level.cpp +++ b/Minecraft.World/Level/Level.cpp @@ -41,38 +41,6 @@ #include "../../Minecraft.Client/MinecraftServer.h" #include -namespace { -#if defined(_WIN32) -inline void* LevelTlsGetValue(Level::TlsKey key) { return TlsGetValue(key); } - -inline void LevelTlsSetValue(Level::TlsKey key, void* value) { - TlsSetValue(key, value); -} -#else -pthread_key_t CreateLevelTlsKey() { - pthread_key_t key; - pthread_key_create(&key, NULL); - return key; -} - -inline void* LevelTlsGetValue(pthread_key_t key) { - return pthread_getspecific(key); -} - -inline void LevelTlsSetValue(pthread_key_t key, void* value) { - pthread_setspecific(key, value); -} -#endif -} // namespace - -#if defined(_WIN32) -Level::TlsKey Level::tlsIdx = TlsAlloc(); -Level::TlsKey Level::tlsIdxLightCache = TlsAlloc(); -#else -Level::TlsKey Level::tlsIdx = CreateLevelTlsKey(); -Level::TlsKey Level::tlsIdxLightCache = CreateLevelTlsKey(); -#endif - // 4J : WESTY : Added for time played stats. #include "../Headers/net.minecraft.stats.h" @@ -122,20 +90,20 @@ Level::TlsKey Level::tlsIdxLightCache = CreateLevelTlsKey(); // W - lighting value requires write #endif +thread_local bool Level::m_threadInstaTick = false; +thread_local Level::lightCache_t* Level::m_threadLightCache = nullptr; + void Level::enableLightingCache() { // Allocate 16K (needs 32K for large worlds) for a 16x16x16x4 byte cache of // results, plus 128K required for toCheck array. Rounding up to 256 to keep // as multiple of alignement - aligning to 128K boundary for possible cache // locking. - void* cache = (unsigned char*)XPhysicalAlloc( + m_threadLightCache = (lightCache_t*)XPhysicalAlloc( 256 * 1024, MAXULONG_PTR, 128 * 1024, PAGE_READWRITE | MEM_LARGE_PAGES); - LevelTlsSetValue(tlsIdxLightCache, cache); } void Level::destroyLightingCache() { - lightCache_t* cache = - static_cast(LevelTlsGetValue(tlsIdxLightCache)); - XPhysicalFree(cache); + delete m_threadLightCache; } inline int GetIndex(int x, int y, int z) { @@ -524,13 +492,11 @@ void Level::flushCache(lightCache_t* cache, uint64_t cacheUse, // 4J - added following 2 functions to move instaBuild flag from being a class // member, to TLS bool Level::getInstaTick() { - return reinterpret_cast(LevelTlsGetValue(tlsIdx)) != 0; + return m_threadInstaTick; } void Level::setInstaTick(bool enable) { - void* value = 0; - if (enable) value = (void*)1; - LevelTlsSetValue(tlsIdx, value); + m_threadInstaTick = enable; } // 4J - added @@ -3177,8 +3143,7 @@ int Level::getExpectedLight(lightCache_t* cache, int x, int y, int z, // this thread void Level::checkLight(LightLayer::variety layer, int xc, int yc, int zc, bool force, bool rootOnlyEmissive) { - lightCache_t* cache = - static_cast(LevelTlsGetValue(tlsIdxLightCache)); + lightCache_t* cache = m_threadLightCache; uint64_t cacheUse = 0; if (force) { diff --git a/Minecraft.World/Level/Level.h b/Minecraft.World/Level/Level.h index 2819d09f2..63c61b88e 100644 --- a/Minecraft.World/Level/Level.h +++ b/Minecraft.World/Level/Level.h @@ -54,10 +54,10 @@ class GameRules; class Level : public LevelSource { public: -#if defined(_WIN32) - using TlsKey = std::uint32_t; +#ifdef _LARGE_WORLDS + using lightCache_t = uint64_t; #else - using TlsKey = pthread_key_t; + using lightCache_t = unsigned int; #endif static const int MAX_TICK_TILES_PER_TICK = 1000; @@ -93,8 +93,8 @@ public: // 4J - added, making instaTick flag use TLS so we can set it in the chunk // rebuilding thread without upsetting the main game thread - static TlsKey tlsIdx; - static TlsKey tlsIdxLightCache; + static thread_local bool m_threadInstaTick; + static thread_local lightCache_t* m_threadLightCache; static void enableLightingCache(); static void destroyLightingCache(); static bool getCacheTestEnabled(); @@ -277,11 +277,6 @@ public: void setBrightnessNoUpdateOnClient(LightLayer::variety layer, int x, int y, int z, int brightness); // 4J added -#ifdef _LARGE_WORLDS - typedef uint64_t lightCache_t; -#else - typedef unsigned int lightCache_t; -#endif inline void setBrightnessCached(lightCache_t* cache, uint64_t* cacheUse, LightLayer::variety layer, int x, int y, int z, int brightness); diff --git a/Minecraft.World/Level/Storage/OldChunkStorage.cpp b/Minecraft.World/Level/Storage/OldChunkStorage.cpp index ea8539b85..f13ad45a5 100644 --- a/Minecraft.World/Level/Storage/OldChunkStorage.cpp +++ b/Minecraft.World/Level/Storage/OldChunkStorage.cpp @@ -8,40 +8,11 @@ #include "../../Headers/net.minecraft.world.level.storage.h" #include "../../IO/Files/FileHeader.h" #include "OldChunkStorage.h" -#if defined(_WIN32) -namespace { -inline void* OldChunkStorageTlsGetValue(OldChunkStorage::TlsKey key) { - return TlsGetValue(key); -} -inline void OldChunkStorageTlsSetValue(OldChunkStorage::TlsKey key, - void* value) { - TlsSetValue(key, value); -} -} // namespace - -OldChunkStorage::TlsKey OldChunkStorage::tlsIdx = TlsAlloc(); -#else -namespace { -pthread_key_t CreateOldChunkStorageTlsKey() { - pthread_key_t key; - const int result = pthread_key_create(&key, nullptr); - assert(result == 0); - return key; -} - -inline void* OldChunkStorageTlsGetValue(pthread_key_t key) { - return pthread_getspecific(key); -} - -inline void OldChunkStorageTlsSetValue(pthread_key_t key, void* value) { - pthread_setspecific(key, value); -} -} // namespace - -OldChunkStorage::TlsKey OldChunkStorage::tlsIdx = CreateOldChunkStorageTlsKey(); -#endif -OldChunkStorage::ThreadStorage* OldChunkStorage::tlsDefault = NULL; +thread_local OldChunkStorage::ThreadStorage* OldChunkStorage::m_threadStorage = + nullptr; +OldChunkStorage::ThreadStorage* OldChunkStorage::m_defaultThreadStorage = + nullptr; OldChunkStorage::ThreadStorage::ThreadStorage() { blockData = byteArray(Level::CHUNK_TILE_COUNT); @@ -59,22 +30,22 @@ OldChunkStorage::ThreadStorage::~ThreadStorage() { void OldChunkStorage::CreateNewThreadStorage() { ThreadStorage* tls = new ThreadStorage(); - if (tlsDefault == NULL) { - tlsDefault = tls; + + if (m_defaultThreadStorage == nullptr) { + m_defaultThreadStorage = tls; } - OldChunkStorageTlsSetValue(tlsIdx, tls); + + m_threadStorage = tls; } void OldChunkStorage::UseDefaultThreadStorage() { - OldChunkStorageTlsSetValue(tlsIdx, tlsDefault); + m_threadStorage = m_defaultThreadStorage; } void OldChunkStorage::ReleaseThreadStorage() { - ThreadStorage* tls = - static_cast(OldChunkStorageTlsGetValue(tlsIdx)); - if (tls == tlsDefault) return; - - delete tls; + if (m_threadStorage != m_defaultThreadStorage) { + delete m_threadStorage; + } } OldChunkStorage::OldChunkStorage(File dir, bool create) { @@ -348,8 +319,7 @@ void OldChunkStorage::save(LevelChunk* lc, Level* level, CompoundTag* tag) { // 4J Stu - As we now save on multiple threads, the static data has been // moved to TLS - ThreadStorage* tls = - static_cast(OldChunkStorageTlsGetValue(tlsIdx)); + ThreadStorage* tls = m_threadStorage; PIXBeginNamedEvent(0, "Getting block data"); // static byteArray blockData = byteArray(32768); diff --git a/Minecraft.World/Level/Storage/OldChunkStorage.h b/Minecraft.World/Level/Storage/OldChunkStorage.h index eb1a3cb7f..16e77ef2e 100644 --- a/Minecraft.World/Level/Storage/OldChunkStorage.h +++ b/Minecraft.World/Level/Storage/OldChunkStorage.h @@ -31,8 +31,8 @@ private: ThreadStorage(); ~ThreadStorage(); }; - static TlsKey tlsIdx; - static ThreadStorage* tlsDefault; + static thread_local ThreadStorage* m_threadStorage; + static ThreadStorage* m_defaultThreadStorage; public: // Each new thread that needs to use Compression will need to call one of diff --git a/Minecraft.World/Recipes/FireworksRecipe.cpp b/Minecraft.World/Recipes/FireworksRecipe.cpp index 21a4d8a8a..e7db4cc52 100644 --- a/Minecraft.World/Recipes/FireworksRecipe.cpp +++ b/Minecraft.World/Recipes/FireworksRecipe.cpp @@ -216,16 +216,14 @@ bool FireworksRecipe::matches(std::shared_ptr craftSlots, std::shared_ptr FireworksRecipe::assemble( std::shared_ptr craftSlots) { - ThreadStorage* tls = (ThreadStorage*)TlsGetValue(tlsIdx); - return tls->resultItem->copy(); + return m_threadStorage->resultItem->copy(); // return resultItem->copy(); } int FireworksRecipe::size() { return 10; } const ItemInstance* FireworksRecipe::getResultItem() { - ThreadStorage* tls = (ThreadStorage*)TlsGetValue(tlsIdx); - return tls->resultItem.get(); + return m_threadStorage->resultItem.get(); // return resultItem.get(); }