Merge pull request #309 from 4jcraft/refactor/thread_local
Some checks are pending
Publish Documentation / build (push) Waiting to run
Build (Linux, x86_64) / build-linux (push) Waiting to run
Build (Linux, x86_64) / build-linux-debug (push) Waiting to run
Clang Format / clang-format (push) Waiting to run

refactor: replace usage of Win32 `TlsAlloc`/`TlsFree` with C++11 thread_locals
This commit is contained in:
ffqq 2026-03-26 00:09:25 +03:00 committed by GitHub
commit f4a2db1252
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
29 changed files with 141 additions and 440 deletions

View file

@ -20,22 +20,15 @@
int Chunk::updates = 0;
#ifdef _LARGE_WORLDS
unsigned int Chunk::tlsIdx = TlsAlloc();
thread_local uint8_t* Chunk::m_tlsTileIds = nullptr;
void Chunk::CreateNewThreadStorage() {
unsigned char* tileIds = new unsigned char[16 * 16 * Level::maxBuildHeight];
TlsSetValue(tlsIdx, tileIds);
m_tlsTileIds = new unsigned char[16 * 16 * Level::maxBuildHeight];
}
void Chunk::ReleaseThreadStorage() {
unsigned char* tileIds = (unsigned char*)TlsGetValue(tlsIdx);
delete tileIds;
}
void Chunk::ReleaseThreadStorage() { delete m_tlsTileIds; }
unsigned char* Chunk::GetTileIdsStorage() {
unsigned char* tileIds = (unsigned char*)TlsGetValue(tlsIdx);
return tileIds;
}
uint8_t* Chunk::GetTileIdsStorage() { return m_tlsTileIds; }
#else
// 4J Stu - Don't want this when multi-threaded
Tesselator* Chunk::t = Tesselator::getInstance();

View file

@ -30,12 +30,12 @@ private:
#ifndef _LARGE_WORLDS
static Tesselator* t;
#else
static unsigned int tlsIdx;
static thread_local uint8_t* m_tlsTileIds;
public:
static void CreateNewThreadStorage();
static void ReleaseThreadStorage();
static unsigned char* GetTileIdsStorage();
static uint8_t* GetTileIdsStorage();
#endif
public:

View file

@ -24,15 +24,12 @@ int normal;
*/
unsigned int Tesselator::tlsIdx = TlsAlloc();
thread_local Tesselator* Tesselator::m_tlsInstance = nullptr;
Tesselator* Tesselator::getInstance() {
return (Tesselator*)TlsGetValue(tlsIdx);
}
Tesselator* Tesselator::getInstance() { return m_tlsInstance; }
void Tesselator::CreateNewThreadStorage(int bytes) {
Tesselator* instance = new Tesselator(bytes / 4);
TlsSetValue(tlsIdx, instance);
Tesselator::m_tlsInstance = new Tesselator(bytes / 4);
}
// she tessalate my vertices till i render
@ -350,7 +347,7 @@ void Tesselator::vertexUV(float x, float y, float z, float u, float v) {
// where: cccc is a 15-bit (5 bits per x/y/z) origin position / offset
// for the whole quad. Each
// component is unsigned, and offset by 16
//so has a range 0 to 31 actually representing -16 to 15
// so has a range 0 to 31 actually representing -16 to 15
// xx,yy,zz are 8-bit deltas from this origin to each vertex. These are
// unsigned 1.7 fixed point, ie
// representing a range of 0 to 1.9921875
@ -359,14 +356,16 @@ void Tesselator::vertexUV(float x, float y, float z, float u, float v) {
// v required by the quad ud,vd are 8-bit unsigned fixed pont
// UV deltas, which can be added to umin/vmin to get umax, vmax
// and therefore define the 4 corners of
//an axis aligned UV mapping
// an axis aligned UV mapping
// i is a code per vertex that indicates which of umin/umax
// should be used for u, and which
// of vmin/vmax should be used for v for
//this vertex. The coding is: 0 - u = umin, v = vmin 1 - u = umin, v = vmax 2 -
//u = umax, v = vmin 3 - u = umax, v = vmax 4 - not axis aligned, use uv stored
//in the vertex data 4 on from this one ll is an 8-bit (4 bit per
//u/v) index into the current lighting texture
// this vertex. The coding is: 0 - u =
// umin, v = vmin 1 - u = umin, v
// = vmax 2 - u = umax, v = vmin
// 3 - u = umax, v = vmax 4 - not
// axis aligned, use uv stored in the vertex data 4 on from this one ll
// is an 8-bit (4 bit per u/v) index into the current lighting texture
//
// For quads that don't have axis aligned UVs (ie have a code for 4 in i as
// described above) the 8 byte vertex is followed by a further 8 bytes which
@ -748,7 +747,8 @@ void packLinuxLightmapCoords(int tex2, std::int16_t& u, std::int16_t& v) {
v = static_cast<std::int16_t>((tex2 >> 16) & 0xffff);
// Linux 4jlibs consumes packed UV2 values by dividing them by 256 directly
// for chunk and other non-scaleLight draws, so offset to texel centers here.
// for chunk and other non-scaleLight draws, so offset to texel centers
// here.
u += 8;
v += 8;
}
@ -854,8 +854,7 @@ void Tesselator::vertex(float x, float y, float z) {
pShortData[4] = (((int)(uu * 8192.0f)) & 0xffff);
pShortData[5] = (((int)(v * 8192.0f)) & 0xffff);
std::int16_t u2 = static_cast<std::int16_t>(_tex2 & 0xffff);
std::int16_t v2 =
static_cast<std::int16_t>((_tex2 >> 16) & 0xffff);
std::int16_t v2 = static_cast<std::int16_t>((_tex2 >> 16) & 0xffff);
#ifdef __linux__
packLinuxLightmapCoords(_tex2, u2, v2);
logLinuxPackedLightmapCoords("compact", _tex2, u2, v2);

View file

@ -41,7 +41,7 @@ public:
static void CreateNewThreadStorage(int bytes);
private:
static unsigned int tlsIdx;
static thread_local Tesselator* m_tlsInstance;
public:
static Tesselator* getInstance();

View file

@ -260,8 +260,7 @@ void ButtonTile::checkPressed(Level* level, int x, int y, int z) {
bool shouldBePressed;
updateShape(data);
Tile::ThreadStorage* tls =
(Tile::ThreadStorage*)TlsGetValue(Tile::tlsIdxShape);
Tile::ThreadStorage* tls = m_tlsShape;
std::vector<std::shared_ptr<Entity> >* entities = level->getEntitiesOfClass(
typeid(Arrow), AABB::newTemp(x + tls->xx0, y + tls->yy0, z + tls->zz0,
x + tls->xx1, y + tls->yy1, z + tls->zz1));

View file

@ -13,8 +13,7 @@ const std::wstring LiquidTile::TEXTURE_WATER_STILL = L"water";
const std::wstring LiquidTile::TEXTURE_WATER_FLOW = L"water_flow";
const std::wstring LiquidTile::TEXTURE_LAVA_FLOW = L"lava_flow";
LiquidTile::LiquidTile(int id, Material* material)
: Tile(id, material, false) {
LiquidTile::LiquidTile(int id, Material* material) : Tile(id, material, false) {
float yo = 0;
float e = 0;
@ -267,8 +266,7 @@ void LiquidTile::animateTick(Level* level, int x, int y, int z,
if (level->getMaterial(x, y + 1, z) == Material::air &&
!level->isSolidRenderTile(x, y + 1, z)) {
if (random->nextInt(100) == 0) {
ThreadStorage* tls =
(ThreadStorage*)TlsGetValue(Tile::tlsIdxShape);
ThreadStorage* tls = m_tlsShape;
double xx = x + random->nextFloat();
double yy = y + tls->yy1;
double zz = z + random->nextFloat();

View file

@ -20,37 +20,7 @@ const std::wstring PistonBaseTile::INSIDE_TEX = L"piston_inner_top";
const float PistonBaseTile::PLATFORM_THICKNESS = 4.0f;
namespace {
#if defined(_WIN32)
inline void* PistonTlsGetValue(PistonBaseTile::TlsKey key) {
return TlsGetValue(key);
}
inline void PistonTlsSetValue(PistonBaseTile::TlsKey key, void* value) {
TlsSetValue(key, value);
}
#else
pthread_key_t CreatePistonTlsKey() {
pthread_key_t key;
pthread_key_create(&key, NULL);
return key;
}
inline void* PistonTlsGetValue(pthread_key_t key) {
return pthread_getspecific(key);
}
inline void PistonTlsSetValue(pthread_key_t key, void* value) {
pthread_setspecific(key, value);
}
#endif
} // namespace
#if defined(_WIN32)
PistonBaseTile::TlsKey PistonBaseTile::tlsIdx = TlsAlloc();
#else
PistonBaseTile::TlsKey PistonBaseTile::tlsIdx = CreatePistonTlsKey();
#endif
thread_local bool PistonBaseTile::m_tlsIgnoreUpdate = false;
// 4J - NOTE - this ignoreUpdate stuff has been removed from the java version,
// but I'm not currently sure how the java version does without it... there must
@ -61,14 +31,9 @@ PistonBaseTile::TlsKey PistonBaseTile::tlsIdx = CreatePistonTlsKey();
// leaving the piston in a bad (simultaneously extended & not extended) state.
// 4J - ignoreUpdate is a static in java, implementing as TLS here to make
// thread safe
bool PistonBaseTile::ignoreUpdate() {
return PistonTlsGetValue(tlsIdx) != NULL;
}
bool PistonBaseTile::ignoreUpdate() { return m_tlsIgnoreUpdate; }
void PistonBaseTile::ignoreUpdate(bool set) {
PistonTlsSetValue(
tlsIdx, reinterpret_cast<void*>(static_cast<intptr_t>(set ? 1 : 0)));
}
void PistonBaseTile::ignoreUpdate(bool set) { m_tlsIgnoreUpdate = set; }
PistonBaseTile::PistonBaseTile(int id, bool isSticky)
: Tile(id, Material::piston, false) {
@ -103,7 +68,7 @@ Icon* PistonBaseTile::getTexture(int face, int data) {
// when the piston is extended, either normally
// or because a piston arm animation, the top
// texture is the furnace bottom
ThreadStorage* tls = (ThreadStorage*)TlsGetValue(Tile::tlsIdxShape);
ThreadStorage* tls = m_tlsShape;
if (isExtended(data) || tls->xx0 > 0 || tls->yy0 > 0 || tls->zz0 > 0 ||
tls->xx1 < 1 || tls->yy1 < 1 || tls->zz1 < 1) {
return iconInside;

View file

@ -2,18 +2,8 @@
#include "Tile.h"
#include <cstdint>
#if !defined(_WIN32)
#include <pthread.h>
#endif
class PistonBaseTile : public Tile {
public:
#if defined(_WIN32)
using TlsKey = std::uint32_t;
#else
using TlsKey = pthread_key_t;
#endif
static const int EXTENDED_BIT = 8;
static const int UNDEFINED_FACING = 7;
@ -35,7 +25,8 @@ private:
Icon* iconBack;
Icon* iconPlatform;
static TlsKey tlsIdx;
static thread_local bool m_tlsIgnoreUpdate;
// 4J - was just a static but implemented with TLS for our version
static bool ignoreUpdate();
static void ignoreUpdate(bool set);

View file

@ -126,7 +126,7 @@ void PistonMovingPiece::updateShape(
progress = 1.0f - progress;
}
int facing = entity->getFacing();
ThreadStorage* tls = (ThreadStorage*)TlsGetValue(Tile::tlsIdxShape);
ThreadStorage* tls = m_tlsShape;
tls->xx0 = tile->getShapeX0() - Facing::STEP_X[facing] * progress;
tls->yy0 = tile->getShapeY0() - Facing::STEP_Y[facing] * progress;
tls->zz0 = tile->getShapeZ0() - Facing::STEP_Z[facing] * progress;

View file

@ -145,7 +145,7 @@ void StemTile::updateShape(
std::shared_ptr<TileEntity>
forceEntity) // 4J added forceData, forceEntity param
{
ThreadStorage* tls = (ThreadStorage*)TlsGetValue(Tile::tlsIdxShape);
ThreadStorage* tls = m_tlsShape;
tls->yy1 = (level->getData(x, y, z) * 2 + 2) / 16.0f;
float ss = 0.125f;
setShape(0.5f - ss, 0, 0.5f - ss, 0.5f + ss, (float)tls->yy1, 0.5f + ss);

View file

@ -9,48 +9,13 @@
#include "../Headers/net.minecraft.world.h"
#include <cstdint>
namespace {
#if defined(_WIN32)
inline void* TheEndPortalTlsGetValue(TheEndPortal::TlsKey key) {
return TlsGetValue(key);
}
inline void TheEndPortalTlsSetValue(TheEndPortal::TlsKey key, void* value) {
TlsSetValue(key, value);
}
#else
pthread_key_t CreateTheEndPortalTlsKey() {
pthread_key_t key;
pthread_key_create(&key, NULL);
return key;
}
inline void* TheEndPortalTlsGetValue(pthread_key_t key) {
return pthread_getspecific(key);
}
inline void TheEndPortalTlsSetValue(pthread_key_t key, void* value) {
pthread_setspecific(key, value);
}
#endif
} // namespace
#if defined(_WIN32)
TheEndPortal::TlsKey TheEndPortal::tlsIdx = TlsAlloc();
#else
TheEndPortal::TlsKey TheEndPortal::tlsIdx = CreateTheEndPortalTlsKey();
#endif
thread_local bool TheEndPortal::m_tlsAllowAnywhere = false;
// 4J - allowAnywhere is a static in java, implementing as TLS here to make
// thread safe
bool TheEndPortal::allowAnywhere() {
return TheEndPortalTlsGetValue(tlsIdx) != NULL;
}
bool TheEndPortal::allowAnywhere() { return m_tlsAllowAnywhere; }
void TheEndPortal::allowAnywhere(bool set) {
TheEndPortalTlsSetValue(
tlsIdx, reinterpret_cast<void*>(static_cast<intptr_t>(set ? 1 : 0)));
}
void TheEndPortal::allowAnywhere(bool set) { m_tlsAllowAnywhere = set; }
TheEndPortal::TheEndPortal(int id, Material* material)
: BaseEntityTile(id, material, false) {

View file

@ -3,20 +3,10 @@
#include "BaseEntityTile.h"
#include <cstdint>
#if !defined(_WIN32)
#include <pthread.h>
#endif
class IconRegister;
class TheEndPortal : public BaseEntityTile {
public:
#if defined(_WIN32)
using TlsKey = std::uint32_t;
#else
using TlsKey = pthread_key_t;
#endif
static TlsKey tlsIdx;
// 4J - was just a static but implemented with TLS for our version
static bool allowAnywhere();
static void allowAnywhere(bool set);
@ -43,4 +33,7 @@ public:
virtual void onPlace(Level* level, int x, int y, int z);
virtual int cloneTileId(Level* level, int x, int y, int z);
void registerIcons(IconRegister* iconRegister);
private:
static thread_local bool m_tlsAllowAnywhere;
};

View file

@ -17,31 +17,6 @@
#include "../Headers/net.minecraft.h"
#include "Tile.h"
namespace {
#if defined(_WIN32)
inline void* TileTlsGetValue(Tile::TlsKey key) { return TlsGetValue(key); }
inline void TileTlsSetValue(Tile::TlsKey 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
} // namespace
std::wstring Tile::TILE_DESCRIPTION_PREFIX = L"Tile.";
const float Tile::INDESTRUCTIBLE_DESTROY_TIME = -1.0f;
@ -247,27 +222,16 @@ Tile* Tile::woolCarpet = NULL;
Tile* Tile::clayHardened = NULL;
Tile* Tile::coalBlock = NULL;
#if defined(_WIN32)
Tile::TlsKey Tile::tlsIdxShape = TlsAlloc();
#else
Tile::TlsKey Tile::tlsIdxShape = CreateTileTlsKey();
#endif
thread_local Tile::ThreadStorage* Tile::m_tlsShape = nullptr;
Tile::ThreadStorage::ThreadStorage() {
xx0 = yy0 = zz0 = xx1 = yy1 = zz1 = 0.0;
tileId = 0;
}
void Tile::CreateNewThreadStorage() {
ThreadStorage* tls = new ThreadStorage();
TileTlsSetValue(Tile::tlsIdxShape, tls);
}
void Tile::CreateNewThreadStorage() { m_tlsShape = new ThreadStorage(); }
void Tile::ReleaseThreadStorage() {
ThreadStorage* tls =
static_cast<ThreadStorage*>(TileTlsGetValue(Tile::tlsIdxShape));
delete tls;
}
void Tile::ReleaseThreadStorage() { delete m_tlsShape; }
void Tile::staticCtor() {
Tile::SOUND_NORMAL = new Tile::SoundType(eMaterialSoundType_STONE, 1, 1);
@ -1900,8 +1864,7 @@ Tile* Tile::disableMipmap() {
void Tile::setShape(float x0, float y0, float z0, float x1, float y1,
float z1) {
ThreadStorage* tls =
static_cast<ThreadStorage*>(TileTlsGetValue(Tile::tlsIdxShape));
ThreadStorage* tls = m_tlsShape;
tls->xx0 = x0;
tls->yy0 = y0;
tls->zz0 = z0;
@ -1951,8 +1914,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 =
static_cast<ThreadStorage*>(TileTlsGetValue(Tile::tlsIdxShape));
ThreadStorage* tls = m_tlsShape;
// 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;
@ -1969,8 +1931,7 @@ bool Tile::shouldRenderFace(LevelSource* level, int x, int y, int z, int face) {
int Tile::getFaceFlags(LevelSource* level, int x, int y, int z) {
int faceFlags = 0;
ThreadStorage* tls =
static_cast<ThreadStorage*>(TileTlsGetValue(Tile::tlsIdxShape));
ThreadStorage* tls = m_tlsShape;
// 4J Stu - Added this so that the TLS shape is correct for this tile
if (tls->tileId != this->id) updateDefaultShape();
@ -2043,8 +2004,7 @@ Icon* Tile::getTexture(int face, int data) { return icon; }
Icon* Tile::getTexture(int face) { return getTexture(face, 0); }
AABB* Tile::getTileAABB(Level* level, int x, int y, int z) {
ThreadStorage* tls =
static_cast<ThreadStorage*>(TileTlsGetValue(Tile::tlsIdxShape));
ThreadStorage* tls = m_tlsShape;
// 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,
@ -2058,8 +2018,7 @@ void Tile::addAABBs(Level* level, int x, int y, int z, AABB* box,
}
AABB* Tile::getAABB(Level* level, int x, int y, int z) {
ThreadStorage* tls =
static_cast<ThreadStorage*>(TileTlsGetValue(Tile::tlsIdxShape));
ThreadStorage* tls = m_tlsShape;
// 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,
@ -2164,8 +2123,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 =
static_cast<ThreadStorage*>(TileTlsGetValue(Tile::tlsIdxShape));
ThreadStorage* tls = m_tlsShape;
Vec3* xh0 = a->clipX(b, tls->xx0);
Vec3* xh1 = a->clipX(b, tls->xx1);
@ -2213,8 +2171,7 @@ HitResult* Tile::clip(Level* level, int xt, int yt, int zt, Vec3* a, Vec3* b) {
bool Tile::containsX(Vec3* v) {
if (v == NULL) return false;
ThreadStorage* tls =
static_cast<ThreadStorage*>(TileTlsGetValue(Tile::tlsIdxShape));
ThreadStorage* tls = m_tlsShape;
// 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 &&
@ -2224,8 +2181,7 @@ bool Tile::containsX(Vec3* v) {
bool Tile::containsY(Vec3* v) {
if (v == NULL) return false;
ThreadStorage* tls =
static_cast<ThreadStorage*>(TileTlsGetValue(Tile::tlsIdxShape));
ThreadStorage* tls = m_tlsShape;
// 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 &&
@ -2235,8 +2191,7 @@ bool Tile::containsY(Vec3* v) {
bool Tile::containsZ(Vec3* v) {
if (v == NULL) return false;
ThreadStorage* tls =
static_cast<ThreadStorage*>(TileTlsGetValue(Tile::tlsIdxShape));
ThreadStorage* tls = m_tlsShape;
// 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 &&
@ -2300,55 +2255,48 @@ void Tile::updateShape(
std::shared_ptr<TileEntity>
forceEntity) // 4J added forceData, forceEntity param
{
ThreadStorage* tls =
static_cast<ThreadStorage*>(TileTlsGetValue(Tile::tlsIdxShape));
ThreadStorage* tls = m_tlsShape;
// 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 =
static_cast<ThreadStorage*>(TileTlsGetValue(Tile::tlsIdxShape));
ThreadStorage* tls = m_tlsShape;
// 4J Stu - Added this so that the TLS shape is correct for this tile
if (tls->tileId != this->id) updateDefaultShape();
return tls->xx0;
}
double Tile::getShapeX1() {
ThreadStorage* tls =
static_cast<ThreadStorage*>(TileTlsGetValue(Tile::tlsIdxShape));
ThreadStorage* tls = m_tlsShape;
// 4J Stu - Added this so that the TLS shape is correct for this tile
if (tls->tileId != this->id) updateDefaultShape();
return tls->xx1;
}
double Tile::getShapeY0() {
ThreadStorage* tls =
static_cast<ThreadStorage*>(TileTlsGetValue(Tile::tlsIdxShape));
ThreadStorage* tls = m_tlsShape;
// 4J Stu - Added this so that the TLS shape is correct for this tile
if (tls->tileId != this->id) updateDefaultShape();
return tls->yy0;
}
double Tile::getShapeY1() {
ThreadStorage* tls =
static_cast<ThreadStorage*>(TileTlsGetValue(Tile::tlsIdxShape));
ThreadStorage* tls = m_tlsShape;
// 4J Stu - Added this so that the TLS shape is correct for this tile
if (tls->tileId != this->id) updateDefaultShape();
return tls->yy1;
}
double Tile::getShapeZ0() {
ThreadStorage* tls =
static_cast<ThreadStorage*>(TileTlsGetValue(Tile::tlsIdxShape));
ThreadStorage* tls = m_tlsShape;
// 4J Stu - Added this so that the TLS shape is correct for this tile
if (tls->tileId != this->id) updateDefaultShape();
return tls->zz0;
}
double Tile::getShapeZ1() {
ThreadStorage* tls =
static_cast<ThreadStorage*>(TileTlsGetValue(Tile::tlsIdxShape));
ThreadStorage* tls = m_tlsShape;
// 4J Stu - Added this so that the TLS shape is correct for this tile
if (tls->tileId != this->id) updateDefaultShape();
return tls->zz1;
@ -2642,7 +2590,8 @@ int Tile::SoundType::getPlaceSound() const { return iPlaceSound; }
4J: These are necessary on the PS3.
(and 4 and Vita).
*/
#if (defined __PS3__ || defined __ORBIS__ || defined __PSVITA__ || defined __linux__)
#if (defined __PS3__ || defined __ORBIS__ || defined __PSVITA__ || \
defined __linux__)
const int Tile::stone_Id;
const int Tile::grass_Id;
const int Tile::dirt_Id;

View file

@ -4,9 +4,6 @@
#include "../Util/Definitions.h"
#include "../Util/SoundTypes.h"
#include <cstdint>
#if !defined(_WIN32)
#include <pthread.h>
#endif
class GrassTile;
class LeafTile;
@ -53,12 +50,6 @@ class Tile {
friend class WallTile;
protected:
#if defined(_WIN32)
using TlsKey = std::uint32_t;
#else
using TlsKey = pthread_key_t;
#endif
// 4J added so we can have separate shapes for different threads
class ThreadStorage {
public:
@ -66,7 +57,7 @@ protected:
int tileId;
ThreadStorage();
};
static TlsKey tlsIdxShape;
static thread_local ThreadStorage* m_tlsShape;
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

View file

@ -11,8 +11,7 @@
const int TopSnowTile::MAX_HEIGHT = 6;
const int TopSnowTile::HEIGHT_MASK = 7; // max 8 steps
TopSnowTile::TopSnowTile(int id)
: Tile(id, Material::topSnow, false) {
TopSnowTile::TopSnowTile(int id) : Tile(id, Material::topSnow, false) {
setShape(0, 0, 0, 1, 2 / 16.0f, 1);
setTicking(true);
updateShape(0);
@ -25,7 +24,7 @@ void TopSnowTile::registerIcons(IconRegister* iconRegister) {
AABB* TopSnowTile::getAABB(Level* level, int x, int y, int z) {
int height = level->getData(x, y, z) & HEIGHT_MASK;
float offset = 2.0f / SharedConstants::WORLD_RESOLUTION;
ThreadStorage* tls = (ThreadStorage*)TlsGetValue(Tile::tlsIdxShape);
ThreadStorage* tls = m_tlsShape;
return AABB::newTemp(x + tls->xx0, y + tls->yy0, z + tls->zz0, x + tls->xx1,
y + (height * offset), z + tls->zz1);
}

View file

@ -5,8 +5,7 @@
#include "../Headers/net.minecraft.world.phys.h"
#include "TripWireTile.h"
TripWireTile::TripWireTile(int id)
: Tile(id, Material::decoration, false) {
TripWireTile::TripWireTile(int id) : Tile(id, Material::decoration, false) {
setShape(0, 0, 0, 1, 2.5f / 16.0f, 1);
this->setTicking(true);
}
@ -132,7 +131,7 @@ void TripWireTile::checkPressed(Level* level, int x, int y, int z) {
bool wasPressed = (data & MASK_POWERED) == MASK_POWERED;
bool shouldBePressed = false;
ThreadStorage* tls = (ThreadStorage*)TlsGetValue(Tile::tlsIdxShape);
ThreadStorage* tls = m_tlsShape;
std::vector<std::shared_ptr<Entity> >* entities = level->getEntities(
nullptr, AABB::newTemp(x + tls->xx0, y + tls->yy0, z + tls->zz0,
x + tls->xx1, y + tls->yy1, z + tls->zz1));

View file

@ -24,7 +24,7 @@ void WaterlilyTile::addAABBs(Level* level, int x, int y, int z, AABB* box,
}
AABB* WaterlilyTile::getAABB(Level* level, int x, int y, int z) {
ThreadStorage* tls = (ThreadStorage*)TlsGetValue(Tile::tlsIdxShape);
ThreadStorage* tls = m_tlsShape;
// 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,

View file

@ -18,7 +18,7 @@ Icon* WoolCarpetTile::getTexture(int face, int data) {
AABB* WoolCarpetTile::getAABB(Level* level, int x, int y, int z) {
int height = 0;
float offset = 1.0f / SharedConstants::WORLD_RESOLUTION;
ThreadStorage* tls = (ThreadStorage*)TlsGetValue(Tile::tlsIdxShape);
ThreadStorage* tls = m_tlsShape;
// 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,

View file

@ -1,6 +1,6 @@
#pragma once
class DispenseItemBehavior;
#include "DispenseItemBehavior.h"
class BehaviorRegistry {
private:

View file

@ -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_tlsUseSmallIds = 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<std::intptr_t>(EntityTlsGetValue(tlsIdx)) != 0) {
if (m_tlsUseSmallIds) {
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<std::intptr_t>(EntityTlsGetValue(tlsIdx)) != 0) {
if (m_tlsUseSmallIds) {
entityId = getSmallId();
}
}
void Entity::freeSmallId(int index) {
if (reinterpret_cast<std::intptr_t>(EntityTlsGetValue(tlsIdx)) == 0)
if (!m_tlsUseSmallIds)
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<void*>(static_cast<std::intptr_t>(1)));
}
void Entity::useSmallIds() { m_tlsUseSmallIds = 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<std::intptr_t>(EntityTlsGetValue(tlsIdx)) == 0)
if (!m_tlsUseSmallIds)
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<std::intptr_t>(EntityTlsGetValue(tlsIdx)) == 0)
if (!m_tlsUseSmallIds)
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<std::intptr_t>(EntityTlsGetValue(tlsIdx)) != 0) {
if (useSmallId && m_tlsUseSmallIds) {
entityId = getSmallId();
} else {
entityId = Entity::entityCounter++;

View file

@ -6,9 +6,6 @@
#include "../Util/Vec3.h"
#include "../Util/Definitions.h"
#include <cstdint>
#if !defined(_WIN32)
#include <pthread.h>
#endif
class LivingEntity;
class LightningBolt;
@ -40,12 +37,6 @@ class Entity : public std::enable_shared_from_this<Entity> {
// functions and constants, without making them publicly
// available to everything
public:
#if defined(_WIN32)
using TlsKey = std::uint32_t;
#else
using TlsKey = pthread_key_t;
#endif
// 4J-PB - added to replace (e instanceof Type), avoiding dynamic casts
virtual eINSTANCEOF GetType() = 0;
@ -431,7 +422,8 @@ private:
static int extraWanderIds[EXTRA_WANDER_MAX];
static int extraWanderCount;
static int extraWanderTicks;
static TlsKey tlsIdx;
static thread_local bool m_tlsUseSmallIds;
public:
static void tickExtraWandering();
static void countFlagsForPIX();

View file

@ -17,8 +17,8 @@
#include "../../../Minecraft.Client/Platform/PS3/PS3Extras/EdgeZLib.h"
#endif //__PS3__
unsigned int Compression::tlsIdx = 0;
Compression::ThreadStorage* Compression::tlsDefault = NULL;
thread_local Compression::ThreadStorage* Compression::m_tlsCompression = nullptr;
Compression::ThreadStorage* Compression::m_tlsCompressionDefault = nullptr;
Compression::ThreadStorage::ThreadStorage() { compression = new Compression(); }
@ -26,28 +26,24 @@ Compression::ThreadStorage::~ThreadStorage() { delete compression; }
void Compression::CreateNewThreadStorage() {
ThreadStorage* tls = new ThreadStorage();
if (tlsDefault == nullptr) {
pthread_key_create(&tlsIdx, nullptr);
tlsDefault = tls;
if (m_tlsCompressionDefault == nullptr) {
m_tlsCompressionDefault = tls;
}
pthread_setspecific(tlsIdx, tls);
m_tlsCompression = tls;
}
void Compression::UseDefaultThreadStorage() {
pthread_setspecific(tlsIdx, tlsDefault);
m_tlsCompression = m_tlsCompressionDefault;
}
void Compression::ReleaseThreadStorage() {
ThreadStorage* tls =
(ThreadStorage*)pthread_getspecific(tlsIdx); // POSIX equivalent
if (tls != tlsDefault) {
delete tls;
if (m_tlsCompression != m_tlsCompressionDefault) {
delete m_tlsCompression;
}
}
Compression* Compression::getCompression() {
ThreadStorage* tls = (ThreadStorage*)pthread_getspecific(tlsIdx);
return tls->compression;
return m_tlsCompression->compression;
}
HRESULT Compression::CompressLZXRLE(void* pDestination, unsigned int* pDestSize,

View file

@ -25,8 +25,8 @@ private:
ThreadStorage();
~ThreadStorage();
};
static unsigned int tlsIdx;
static ThreadStorage* tlsDefault;
static thread_local ThreadStorage* m_tlsCompression;
static ThreadStorage* m_tlsCompressionDefault;
public:
// Each new thread that needs to use Compression will need to call one of

View file

@ -41,38 +41,6 @@
#include "../../Minecraft.Client/MinecraftServer.h"
#include <cstdint>
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,21 +90,19 @@ Level::TlsKey Level::tlsIdxLightCache = CreateLevelTlsKey();
// W - lighting value requires write
#endif
thread_local bool Level::m_tlsInstaTick = false;
thread_local Level::lightCache_t* Level::m_tlsLightCache = 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_tlsLightCache = (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<lightCache_t*>(LevelTlsGetValue(tlsIdxLightCache));
XPhysicalFree(cache);
}
void Level::destroyLightingCache() { delete m_tlsLightCache; }
inline int GetIndex(int x, int y, int z) {
return ((x & 15) << 8) | ((y & 15) << 4) | (z & 15);
@ -523,15 +489,9 @@ 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<std::intptr_t>(LevelTlsGetValue(tlsIdx)) != 0;
}
bool Level::getInstaTick() { return m_tlsInstaTick; }
void Level::setInstaTick(bool enable) {
void* value = 0;
if (enable) value = (void*)1;
LevelTlsSetValue(tlsIdx, value);
}
void Level::setInstaTick(bool enable) { m_tlsInstaTick = enable; }
// 4J - added
bool Level::hasEntitiesToRemove() { return !entitiesToRemove.empty(); }
@ -1603,8 +1563,8 @@ void Level::playStreamingMusic(const std::wstring& name, int x, int y, int z) {
}
}
void Level::playMusic(double x, double y, double z,
const std::wstring& string, float volume) {}
void Level::playMusic(double x, double y, double z, const std::wstring& string,
float volume) {}
// 4J removed -
/*
@ -3177,8 +3137,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<lightCache_t*>(LevelTlsGetValue(tlsIdxLightCache));
lightCache_t* cache = m_tlsLightCache;
uint64_t cacheUse = 0;
if (force) {

View file

@ -10,9 +10,6 @@
#include "../WorldGen/Biomes/Biome.h"
#include "../Util/C4JThread.h"
#include <cstdint>
#if !defined(_WIN32)
#include <pthread.h>
#endif
#ifdef __PSVITA__
#include "../../Minecraft.Client/Platform/PSVita/PSVitaExtras/CustomSet.h"
@ -54,10 +51,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 +90,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_tlsInstaTick;
static thread_local lightCache_t* m_tlsLightCache;
static void enableLightingCache();
static void destroyLightingCache();
static bool getCacheTestEnabled();
@ -277,11 +274,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);
@ -340,8 +332,8 @@ public:
float fClipSoundDist = 16.0f);
void playStreamingMusic(const std::wstring& name, int x, int y, int z);
void playMusic(double x, double y, double z,
const std::wstring& string, float volume);
void playMusic(double x, double y, double z, const std::wstring& string,
float volume);
// 4J removed - void addParticle(const std::wstring& id, double x, double y,
// double z, double xd, double yd, double zd);
void addParticle(ePARTICLE_TYPE id, double x, double y, double z, double xd,

View file

@ -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_tlsStorage =
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_tlsStorage = tls;
}
void OldChunkStorage::UseDefaultThreadStorage() {
OldChunkStorageTlsSetValue(tlsIdx, tlsDefault);
m_tlsStorage = m_defaultThreadStorage;
}
void OldChunkStorage::ReleaseThreadStorage() {
ThreadStorage* tls =
static_cast<ThreadStorage*>(OldChunkStorageTlsGetValue(tlsIdx));
if (tls == tlsDefault) return;
delete tls;
if (m_tlsStorage != m_defaultThreadStorage) {
delete m_tlsStorage;
}
}
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<ThreadStorage*>(OldChunkStorageTlsGetValue(tlsIdx));
ThreadStorage* tls = m_tlsStorage;
PIXBeginNamedEvent(0, "Getting block data");
// static byteArray blockData = byteArray(32768);

View file

@ -5,20 +5,10 @@
#include "../../IO/NBT/CompoundTag.h"
#include "../../Headers/com.mojang.nbt.h"
#include <cstdint>
#if !defined(_WIN32)
#include <pthread.h>
#endif
class Level;
class OldChunkStorage : public ChunkStorage {
public:
#if defined(_WIN32)
using TlsKey = std::uint32_t;
#else
using TlsKey = pthread_key_t;
#endif
private:
// 4J added so we can have separate storage arrays for different threads
class ThreadStorage {
@ -31,8 +21,8 @@ private:
ThreadStorage();
~ThreadStorage();
};
static TlsKey tlsIdx;
static ThreadStorage* tlsDefault;
static thread_local ThreadStorage* m_tlsStorage;
static ThreadStorage* m_defaultThreadStorage;
public:
// Each new thread that needs to use Compression will need to call one of

View file

@ -2,34 +2,35 @@
#include "../Headers/net.minecraft.world.item.h"
#include "FireworksRecipe.h"
DWORD FireworksRecipe::tlsIdx = 0;
FireworksRecipe::ThreadStorage* FireworksRecipe::tlsDefault = NULL;
thread_local FireworksRecipe::ThreadStorage* FireworksRecipe::m_tlsStorage =
nullptr;
FireworksRecipe::ThreadStorage* FireworksRecipe::m_defaultThreadStorage =
nullptr;
FireworksRecipe::ThreadStorage::ThreadStorage() { resultItem = nullptr; }
void FireworksRecipe::CreateNewThreadStorage() {
ThreadStorage* tls = new ThreadStorage();
if (tlsDefault == NULL) {
tlsIdx = TlsAlloc();
tlsDefault = tls;
if (m_defaultThreadStorage == nullptr) {
m_defaultThreadStorage = tls;
}
TlsSetValue(tlsIdx, tls);
m_tlsStorage = tls;
}
void FireworksRecipe::UseDefaultThreadStorage() {
TlsSetValue(tlsIdx, tlsDefault);
m_tlsStorage = m_defaultThreadStorage;
}
void FireworksRecipe::ReleaseThreadStorage() {
ThreadStorage* tls = (ThreadStorage*)TlsGetValue(tlsIdx);
if (tls == tlsDefault) return;
delete tls;
if (m_tlsStorage != m_defaultThreadStorage) {
delete m_tlsStorage;
}
}
void FireworksRecipe::setResultItem(std::shared_ptr<ItemInstance> item) {
ThreadStorage* tls = (ThreadStorage*)TlsGetValue(tlsIdx);
tls->resultItem = item;
m_tlsStorage->resultItem = item;
}
FireworksRecipe::FireworksRecipe() {
@ -215,16 +216,14 @@ bool FireworksRecipe::matches(std::shared_ptr<CraftingContainer> craftSlots,
std::shared_ptr<ItemInstance> FireworksRecipe::assemble(
std::shared_ptr<CraftingContainer> craftSlots) {
ThreadStorage* tls = (ThreadStorage*)TlsGetValue(tlsIdx);
return tls->resultItem->copy();
return m_tlsStorage->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_tlsStorage->resultItem.get();
// return resultItem.get();
}

View file

@ -13,8 +13,8 @@ private:
std::shared_ptr<ItemInstance> resultItem;
ThreadStorage();
};
static DWORD tlsIdx;
static ThreadStorage* tlsDefault;
static thread_local ThreadStorage* m_tlsStorage;
static ThreadStorage* m_defaultThreadStorage;
void setResultItem(std::shared_ptr<ItemInstance> item);
@ -38,14 +38,8 @@ public:
virtual const int getGroup() { return 0; }
// 4J-PB
virtual bool
requiresRecipe(int iRecipe)
{
return false;
};
virtual void
collectRequirements(INGREDIENTS_REQUIRED* pIngReq)
{};
virtual bool requiresRecipe(int iRecipe) { return false; };
virtual void collectRequirements(INGREDIENTS_REQUIRED* pIngReq) {};
// 4J Added
static void updatePossibleRecipes(