Use platform TLS keys for entity small IDs

This commit is contained in:
notmatthewbeshay 2026-03-11 07:51:27 +11:00
parent 4e8d1c9e17
commit a08cb8d190
4 changed files with 110 additions and 30 deletions

View file

@ -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<ThreadStorage *>(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<ThreadStorage *>(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<ThreadStorage *>(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<ThreadStorage *>(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<ThreadStorage *>(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<ThreadStorage *>(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<ThreadStorage *>(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<ThreadStorage *>(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<ThreadStorage *>(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<ThreadStorage *>(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<TileEntity> forceEntity) // 4J added forceData, forceEntity param
{
ThreadStorage *tls = (ThreadStorage *)TlsGetValue(Tile::tlsIdxShape);
ThreadStorage *tls = static_cast<ThreadStorage *>(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<ThreadStorage *>(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<ThreadStorage *>(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<ThreadStorage *>(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<ThreadStorage *>(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<ThreadStorage *>(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<ThreadStorage *>(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

View file

@ -3,6 +3,9 @@
#include "../Util/Vec3.h"
#include "../Util/Definitions.h"
#include "../Util/SoundTypes.h"
#if !defined(_WIN32)
#include <pthread.h>
#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

View file

@ -21,10 +21,48 @@
#include "../../Minecraft.Client/MinecraftServer.h"
#include "../../Minecraft.Client/Level/MultiPlayerLevel.h"
#include "../../Minecraft.Client/Player/MultiPlayerLocalPlayer.h"
#include <cstdint>
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<std::intptr_t>(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<std::intptr_t>(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<std::intptr_t>(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<void *>(static_cast<std::intptr_t>(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<std::intptr_t>(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<std::intptr_t>(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<std::intptr_t>(EntityTlsGetValue(tlsIdx)) != 0 )
{
entityId = getSmallId();
}

View file

@ -5,7 +5,9 @@
#include "../IO/NBT/FloatTag.h"
#include "../Util/Vec3.h"
#include "../Util/Definitions.h"
#if !defined(_WIN32)
#include <pthread.h>
#endif
class Mob;
class LightningBolt;