From a08cb8d190a9e7de127d1e85db5be9146fa0dd0a Mon Sep 17 00:00:00 2001 From: notmatthewbeshay <92357869+NotMachow@users.noreply.github.com> Date: Wed, 11 Mar 2026 07:51:27 +1100 Subject: [PATCH] Use platform TLS keys for entity small IDs --- Minecraft.World/Blocks/Tile.cpp | 74 ++++++++++++++++++++++------- Minecraft.World/Blocks/Tile.h | 7 +++ Minecraft.World/Entities/Entity.cpp | 57 +++++++++++++++++----- Minecraft.World/Entities/Entity.h | 2 + 4 files changed, 110 insertions(+), 30 deletions(-) diff --git a/Minecraft.World/Blocks/Tile.cpp b/Minecraft.World/Blocks/Tile.cpp index adc7cb714..209b76272 100644 --- a/Minecraft.World/Blocks/Tile.cpp +++ b/Minecraft.World/Blocks/Tile.cpp @@ -16,6 +16,39 @@ #include "../Headers/net.minecraft.h" #include "Tile.h" +namespace +{ +#if defined(_WIN32) + inline void *TileTlsGetValue(DWORD key) + { + return TlsGetValue(key); + } + + inline void TileTlsSetValue(DWORD key, void *value) + { + TlsSetValue(key, value); + } +#else + pthread_key_t CreateTileTlsKey() + { + pthread_key_t key; + const int result = pthread_key_create(&key, nullptr); + assert(result == 0); + return key; + } + + inline void *TileTlsGetValue(pthread_key_t key) + { + return pthread_getspecific(key); + } + + inline void TileTlsSetValue(pthread_key_t key, void *value) + { + pthread_setspecific(key, value); + } +#endif +} + std::wstring Tile::TILE_DESCRIPTION_PREFIX = L"Tile."; const float Tile::INDESTRUCTIBLE_DESTROY_TIME = -1.0f; @@ -201,7 +234,11 @@ Tile *Tile::stairs_quartz = NULL; Tile *Tile::woolCarpet = NULL; +#if defined(_WIN32) DWORD Tile::tlsIdxShape = TlsAlloc(); +#else +pthread_key_t Tile::tlsIdxShape = CreateTileTlsKey(); +#endif Tile::ThreadStorage::ThreadStorage() { @@ -212,12 +249,12 @@ Tile::ThreadStorage::ThreadStorage() void Tile::CreateNewThreadStorage() { ThreadStorage *tls = new ThreadStorage(); - TlsSetValue(Tile::tlsIdxShape, tls); + TileTlsSetValue(Tile::tlsIdxShape, tls); } void Tile::ReleaseThreadStorage() { - ThreadStorage *tls = (ThreadStorage *)TlsGetValue(Tile::tlsIdxShape); + ThreadStorage *tls = static_cast(TileTlsGetValue(Tile::tlsIdxShape)); delete tls; } @@ -650,7 +687,7 @@ Tile *Tile::disableMipmap() void Tile::setShape(float x0, float y0, float z0, float x1, float y1, float z1) { - ThreadStorage *tls = (ThreadStorage *)TlsGetValue(Tile::tlsIdxShape); + ThreadStorage *tls = static_cast(TileTlsGetValue(Tile::tlsIdxShape)); tls->xx0 = x0; tls->yy0 = y0; tls->zz0 = z0; @@ -700,7 +737,7 @@ bool Tile::isFaceVisible(Level *level, int x, int y, int z, int f) bool Tile::shouldRenderFace(LevelSource *level, int x, int y, int z, int face) { - ThreadStorage *tls = (ThreadStorage *)TlsGetValue(Tile::tlsIdxShape); + ThreadStorage *tls = static_cast(TileTlsGetValue(Tile::tlsIdxShape)); // 4J Stu - Added this so that the TLS shape is correct for this tile if(tls->tileId != this->id) updateDefaultShape(); if (face == 0 && tls->yy0 > 0) return true; @@ -717,7 +754,7 @@ int Tile::getFaceFlags(LevelSource *level, int x, int y, int z) { int faceFlags = 0; - ThreadStorage *tls = (ThreadStorage *)TlsGetValue(Tile::tlsIdxShape); + ThreadStorage *tls = static_cast(TileTlsGetValue(Tile::tlsIdxShape)); // 4J Stu - Added this so that the TLS shape is correct for this tile if(tls->tileId != this->id) updateDefaultShape(); @@ -792,7 +829,7 @@ Icon *Tile::getTexture(int face) AABB *Tile::getTileAABB(Level *level, int x, int y, int z) { - ThreadStorage *tls = (ThreadStorage *)TlsGetValue(Tile::tlsIdxShape); + ThreadStorage *tls = static_cast(TileTlsGetValue(Tile::tlsIdxShape)); // 4J Stu - Added this so that the TLS shape is correct for this tile if(tls->tileId != this->id) updateDefaultShape(); return AABB::newTemp(x + tls->xx0, y + tls->yy0, z + tls->zz0, x + tls->xx1, y + tls->yy1, z + tls->zz1); @@ -806,7 +843,7 @@ void Tile::addAABBs(Level *level, int x, int y, int z, AABB *box, AABBList *boxe AABB *Tile::getAABB(Level *level, int x, int y, int z) { - ThreadStorage *tls = (ThreadStorage *)TlsGetValue(Tile::tlsIdxShape); + ThreadStorage *tls = static_cast(TileTlsGetValue(Tile::tlsIdxShape)); // 4J Stu - Added this so that the TLS shape is correct for this tile if(tls->tileId != this->id) updateDefaultShape(); return AABB::newTemp(x + tls->xx0, y + tls->yy0, z + tls->zz0, x + tls->xx1, y + tls->yy1, z + tls->zz1); @@ -941,7 +978,7 @@ HitResult *Tile::clip(Level *level, int xt, int yt, int zt, Vec3 *a, Vec3 *b) a = a->add(-xt, -yt, -zt); b = b->add(-xt, -yt, -zt); - ThreadStorage *tls = (ThreadStorage *)TlsGetValue(Tile::tlsIdxShape); + ThreadStorage *tls = static_cast(TileTlsGetValue(Tile::tlsIdxShape)); Vec3 *xh0 = a->clipX(b, tls->xx0); Vec3 *xh1 = a->clipX(b, tls->xx1); @@ -978,7 +1015,7 @@ bool Tile::containsX(Vec3 *v) { if( v == NULL) return false; - ThreadStorage *tls = (ThreadStorage *)TlsGetValue(Tile::tlsIdxShape); + ThreadStorage *tls = static_cast(TileTlsGetValue(Tile::tlsIdxShape)); // 4J Stu - Added this so that the TLS shape is correct for this tile if(tls->tileId != this->id) updateDefaultShape(); return v->y >= tls->yy0 && v->y <= tls->yy1 && v->z >= tls->zz0 && v->z <= tls->zz1; @@ -988,7 +1025,7 @@ bool Tile::containsY(Vec3 *v) { if( v == NULL) return false; - ThreadStorage *tls = (ThreadStorage *)TlsGetValue(Tile::tlsIdxShape); + ThreadStorage *tls = static_cast(TileTlsGetValue(Tile::tlsIdxShape)); // 4J Stu - Added this so that the TLS shape is correct for this tile if(tls->tileId != this->id) updateDefaultShape(); return v->x >= tls->xx0 && v->x <= tls->xx1 && v->z >= tls->zz0 && v->z <= tls->zz1; @@ -998,7 +1035,7 @@ bool Tile::containsZ(Vec3 *v) { if( v == NULL) return false; - ThreadStorage *tls = (ThreadStorage *)TlsGetValue(Tile::tlsIdxShape); + ThreadStorage *tls = static_cast(TileTlsGetValue(Tile::tlsIdxShape)); // 4J Stu - Added this so that the TLS shape is correct for this tile if(tls->tileId != this->id) updateDefaultShape(); return v->x >= tls->xx0 && v->x <= tls->xx1 && v->y >= tls->yy0 && v->y <= tls->yy1; @@ -1063,14 +1100,14 @@ void Tile::handleEntityInside(Level *level, int x, int y, int z, std::shared_ptr void Tile::updateShape(LevelSource *level, int x, int y, int z, int forceData, std::shared_ptr forceEntity) // 4J added forceData, forceEntity param { - ThreadStorage *tls = (ThreadStorage *)TlsGetValue(Tile::tlsIdxShape); + ThreadStorage *tls = static_cast(TileTlsGetValue(Tile::tlsIdxShape)); // 4J Stu - Added this so that the TLS shape is correct for this tile if(tls->tileId != this->id) updateDefaultShape(); } double Tile::getShapeX0() { - ThreadStorage *tls = (ThreadStorage *)TlsGetValue(Tile::tlsIdxShape); + ThreadStorage *tls = static_cast(TileTlsGetValue(Tile::tlsIdxShape)); // 4J Stu - Added this so that the TLS shape is correct for this tile if(tls->tileId != this->id) updateDefaultShape(); return tls->xx0; @@ -1078,7 +1115,7 @@ double Tile::getShapeX0() double Tile::getShapeX1() { - ThreadStorage *tls = (ThreadStorage *)TlsGetValue(Tile::tlsIdxShape); + ThreadStorage *tls = static_cast(TileTlsGetValue(Tile::tlsIdxShape)); // 4J Stu - Added this so that the TLS shape is correct for this tile if(tls->tileId != this->id) updateDefaultShape(); return tls->xx1; @@ -1086,7 +1123,7 @@ double Tile::getShapeX1() double Tile::getShapeY0() { - ThreadStorage *tls = (ThreadStorage *)TlsGetValue(Tile::tlsIdxShape); + ThreadStorage *tls = static_cast(TileTlsGetValue(Tile::tlsIdxShape)); // 4J Stu - Added this so that the TLS shape is correct for this tile if(tls->tileId != this->id) updateDefaultShape(); return tls->yy0; @@ -1094,7 +1131,7 @@ double Tile::getShapeY0() double Tile::getShapeY1() { - ThreadStorage *tls = (ThreadStorage *)TlsGetValue(Tile::tlsIdxShape); + ThreadStorage *tls = static_cast(TileTlsGetValue(Tile::tlsIdxShape)); // 4J Stu - Added this so that the TLS shape is correct for this tile if(tls->tileId != this->id) updateDefaultShape(); return tls->yy1; @@ -1102,7 +1139,7 @@ double Tile::getShapeY1() double Tile::getShapeZ0() { - ThreadStorage *tls = (ThreadStorage *)TlsGetValue(Tile::tlsIdxShape); + ThreadStorage *tls = static_cast(TileTlsGetValue(Tile::tlsIdxShape)); // 4J Stu - Added this so that the TLS shape is correct for this tile if(tls->tileId != this->id) updateDefaultShape(); return tls->zz0; @@ -1110,7 +1147,7 @@ double Tile::getShapeZ0() double Tile::getShapeZ1() { - ThreadStorage *tls = (ThreadStorage *)TlsGetValue(Tile::tlsIdxShape); + ThreadStorage *tls = static_cast(TileTlsGetValue(Tile::tlsIdxShape)); // 4J Stu - Added this so that the TLS shape is correct for this tile if(tls->tileId != this->id) updateDefaultShape(); return tls->zz1; @@ -1630,3 +1667,4 @@ const int Tile::quartzBlock_Id; const int Tile::stairs_quartz_Id; const int Tile::woolCarpet_Id; #endif + diff --git a/Minecraft.World/Blocks/Tile.h b/Minecraft.World/Blocks/Tile.h index de71490c4..ea4421fc0 100644 --- a/Minecraft.World/Blocks/Tile.h +++ b/Minecraft.World/Blocks/Tile.h @@ -3,6 +3,9 @@ #include "../Util/Vec3.h" #include "../Util/Definitions.h" #include "../Util/SoundTypes.h" +#if !defined(_WIN32) +#include +#endif class GrassTile; @@ -55,7 +58,11 @@ protected: int tileId; ThreadStorage(); }; +#if defined(_WIN32) static DWORD tlsIdxShape; +#else + static pthread_key_t tlsIdxShape; +#endif public: // Each new thread that needs to use Vec3 pools will need to call one of the following 2 functions, to either create its own // local storage, or share the default storage already allocated by the main thread diff --git a/Minecraft.World/Entities/Entity.cpp b/Minecraft.World/Entities/Entity.cpp index 9c88a00e2..8a238dcf6 100644 --- a/Minecraft.World/Entities/Entity.cpp +++ b/Minecraft.World/Entities/Entity.cpp @@ -21,10 +21,48 @@ #include "../../Minecraft.Client/MinecraftServer.h" #include "../../Minecraft.Client/Level/MultiPlayerLevel.h" #include "../../Minecraft.Client/Player/MultiPlayerLocalPlayer.h" +#include + +namespace +{ +#if defined(_WIN32) + inline void *EntityTlsGetValue(DWORD key) + { + return TlsGetValue(key); + } + + inline void EntityTlsSetValue(DWORD 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 +} 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) DWORD Entity::tlsIdx = TlsAlloc(); +#else +pthread_key_t Entity::tlsIdx = CreateEntityTlsKey(); +#endif // 4J - added getSmallId & freeSmallId methods unsigned int Entity::entityIdUsedFlags[2048/32] = {0}; @@ -44,12 +82,7 @@ int Entity::getSmallId() // for final notification to the client that the entities are removed. We can't go re-using these small Ids yet, as otherwise we will // potentially end up 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. -#ifdef _WIN32 - if( ((size_t)TlsGetValue(tlsIdx) != 0 ) ) -#else - pthread_key_create(&tlsIdx, nullptr); - if ( ((size_t)pthread_getspecific(tlsIdx) != 0) ) -#endif + if( reinterpret_cast(EntityTlsGetValue(tlsIdx)) != 0 ) { MinecraftServer *server = MinecraftServer::getInstance(); if( server ) @@ -130,7 +163,7 @@ void Entity::countFlagsForPIX() void Entity::resetSmallId() { freeSmallId(entityId); - if( ((size_t)pthread_getspecific(tlsIdx) != 0 ) ) + if( reinterpret_cast(EntityTlsGetValue(tlsIdx)) != 0 ) { entityId = getSmallId(); } @@ -138,7 +171,7 @@ void Entity::resetSmallId() void Entity::freeSmallId(int index) { - if( ( (size_t)pthread_getspecific(tlsIdx) ) == 0 ) return; // Don't do anything with small ids if this isn't the server thread + if( reinterpret_cast(EntityTlsGetValue(tlsIdx)) == 0 ) 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 unsigned int i = index / 32; @@ -151,7 +184,7 @@ void Entity::freeSmallId(int index) void Entity::useSmallIds() { - pthread_setspecific(tlsIdx,(LPVOID)1); + EntityTlsSetValue(tlsIdx, reinterpret_cast(static_cast(1))); } // 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 @@ -161,7 +194,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( ( (size_t)pthread_getspecific(tlsIdx) ) == 0 ) return; // Don't do anything with small ids if this isn't the server thread + if( reinterpret_cast(EntityTlsGetValue(tlsIdx)) == 0 ) 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 unsigned int i = entityId / 32; @@ -181,7 +214,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( ( (size_t)pthread_getspecific(tlsIdx) ) == 0 ) return false; // Don't do anything with small ids if this isn't the server thread + if( reinterpret_cast(EntityTlsGetValue(tlsIdx)) == 0 ) return false; // Don't do anything with small ids if this isn't the server thread if( entityId >= 2048 ) return false; // Don't do anything if this isn't a short id for( int i = 0; i < extraWanderCount; i++ ) @@ -244,7 +277,7 @@ void Entity::_init(bool useSmallId) // 4J - changed to assign two different types of ids. A range from 0-2047 is used for things that we'll be wanting to identify over the network, // so we should only need 11 bits rather than 32 to uniquely identify them. The 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 && ((size_t)pthread_getspecific(tlsIdx) != 0 ) ) + if( useSmallId && reinterpret_cast(EntityTlsGetValue(tlsIdx)) != 0 ) { entityId = getSmallId(); } diff --git a/Minecraft.World/Entities/Entity.h b/Minecraft.World/Entities/Entity.h index bb64e3b79..10cc1553c 100644 --- a/Minecraft.World/Entities/Entity.h +++ b/Minecraft.World/Entities/Entity.h @@ -5,7 +5,9 @@ #include "../IO/NBT/FloatTag.h" #include "../Util/Vec3.h" #include "../Util/Definitions.h" +#if !defined(_WIN32) #include +#endif class Mob; class LightningBolt;