Merge pull request #369 from MatthewBeshay/refactor/nuke-critical-sections

Refactor/nuke critical sections
This commit is contained in:
Tropical 2026-03-30 09:37:57 -05:00 committed by GitHub
commit d5cf90c713
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
69 changed files with 3291 additions and 3557 deletions

View file

@ -1,4 +1,5 @@
#include "../Platform/stdafx.h"
#include <mutex>
#include "MultiPlayerLevel.h"
#include "../Player/MultiPlayerLocalPlayer.h"
#include "../Network/ClientConnection.h"
@ -117,14 +118,15 @@ void MultiPlayerLevel::tick() {
PIXEndNamedEvent();
PIXBeginNamedEvent(0, "Entity re-entry");
EnterCriticalSection(&m_entitiesCS);
for (int i = 0; i < 10 && !reEntries.empty(); i++) {
std::shared_ptr<Entity> e = *(reEntries.begin());
{
std::lock_guard<std::recursive_mutex> lock(m_entitiesCS);
for (int i = 0; i < 10 && !reEntries.empty(); i++) {
std::shared_ptr<Entity> e = *(reEntries.begin());
if (find(entities.begin(), entities.end(), e) == entities.end())
addEntity(e);
if (find(entities.begin(), entities.end(), e) == entities.end())
addEntity(e);
}
}
LeaveCriticalSection(&m_entitiesCS);
PIXEndNamedEvent();
PIXBeginNamedEvent(0, "Connection ticking");
@ -808,23 +810,24 @@ void MultiPlayerLevel::setDayTime(int64_t newTime) {
void MultiPlayerLevel::removeAllPendingEntityRemovals() {
// entities.removeAll(entitiesToRemove);
EnterCriticalSection(&m_entitiesCS);
for (auto it = entities.begin(); it != entities.end();) {
bool found = false;
for (auto it2 = entitiesToRemove.begin(); it2 != entitiesToRemove.end();
it2++) {
if ((*it) == (*it2)) {
found = true;
break;
{
std::lock_guard<std::recursive_mutex> lock(m_entitiesCS);
for (auto it = entities.begin(); it != entities.end();) {
bool found = false;
for (auto it2 = entitiesToRemove.begin();
it2 != entitiesToRemove.end(); it2++) {
if ((*it) == (*it2)) {
found = true;
break;
}
}
if (found) {
it = entities.erase(it);
} else {
it++;
}
}
if (found) {
it = entities.erase(it);
} else {
it++;
}
}
LeaveCriticalSection(&m_entitiesCS);
auto endIt = entitiesToRemove.end();
for (auto it = entitiesToRemove.begin(); it != endIt; it++) {
@ -845,36 +848,37 @@ void MultiPlayerLevel::removeAllPendingEntityRemovals() {
entitiesToRemove.clear();
// for (int i = 0; i < entities.size(); i++)
EnterCriticalSection(&m_entitiesCS);
std::vector<std::shared_ptr<Entity> >::iterator it = entities.begin();
while (it != entities.end()) {
std::shared_ptr<Entity> e = *it; // entities.at(i);
{
std::lock_guard<std::recursive_mutex> lock(m_entitiesCS);
std::vector<std::shared_ptr<Entity> >::iterator it = entities.begin();
while (it != entities.end()) {
std::shared_ptr<Entity> e = *it; // entities.at(i);
if (e->riding != nullptr) {
if (e->riding->removed || e->riding->rider.lock() != e) {
e->riding->rider = std::weak_ptr<Entity>();
e->riding = nullptr;
if (e->riding != nullptr) {
if (e->riding->removed || e->riding->rider.lock() != e) {
e->riding->rider = std::weak_ptr<Entity>();
e->riding = nullptr;
} else {
++it;
continue;
}
}
if (e->removed) {
int xc = e->xChunk;
int zc = e->zChunk;
if (e->inChunk && hasChunk(xc, zc)) {
getChunk(xc, zc)->removeEntity(e);
}
// entities.remove(i--);
it = entities.erase(it);
entityRemoved(e);
} else {
++it;
continue;
it++;
}
}
if (e->removed) {
int xc = e->xChunk;
int zc = e->zChunk;
if (e->inChunk && hasChunk(xc, zc)) {
getChunk(xc, zc)->removeEntity(e);
}
// entities.remove(i--);
it = entities.erase(it);
entityRemoved(e);
} else {
it++;
}
}
LeaveCriticalSection(&m_entitiesCS);
}
void MultiPlayerLevel::removeClientConnection(ClientConnection* c,
@ -907,34 +911,34 @@ void MultiPlayerLevel::dataReceivedForChunk(int x, int z) {
void MultiPlayerLevel::removeUnusedTileEntitiesInRegion(int x0, int y0, int z0,
int x1, int y1,
int z1) {
EnterCriticalSection(&m_tileEntityListCS);
{
std::lock_guard<std::recursive_mutex> lock(m_tileEntityListCS);
for (unsigned int i = 0; i < tileEntityList.size();) {
bool removed = false;
std::shared_ptr<TileEntity> te = tileEntityList[i];
if (te->x >= x0 && te->y >= y0 && te->z >= z0 && te->x < x1 &&
te->y < y1 && te->z < z1) {
LevelChunk* lc = getChunk(te->x >> 4, te->z >> 4);
if (lc != nullptr) {
// Only remove tile entities where this is no longer a tile
// entity
int tileId = lc->getTile(te->x & 15, te->y, te->z & 15);
if (Tile::tiles[tileId] == nullptr ||
!Tile::tiles[tileId]->isEntityTile()) {
tileEntityList[i] = tileEntityList.back();
tileEntityList.pop_back();
for (unsigned int i = 0; i < tileEntityList.size();) {
bool removed = false;
std::shared_ptr<TileEntity> te = tileEntityList[i];
if (te->x >= x0 && te->y >= y0 && te->z >= z0 && te->x < x1 &&
te->y < y1 && te->z < z1) {
LevelChunk* lc = getChunk(te->x >> 4, te->z >> 4);
if (lc != nullptr) {
// Only remove tile entities where this is no longer a tile
// entity
int tileId = lc->getTile(te->x & 15, te->y, te->z & 15);
if (Tile::tiles[tileId] == nullptr ||
!Tile::tiles[tileId]->isEntityTile()) {
tileEntityList[i] = tileEntityList.back();
tileEntityList.pop_back();
// 4J Stu - Chests can create new tile entities when being
// removed, so disable this
m_bDisableAddNewTileEntities = true;
lc->removeTileEntity(te->x & 15, te->y, te->z & 15);
m_bDisableAddNewTileEntities = false;
removed = true;
// 4J Stu - Chests can create new tile entities when
// being removed, so disable this
m_bDisableAddNewTileEntities = true;
lc->removeTileEntity(te->x & 15, te->y, te->z & 15);
m_bDisableAddNewTileEntities = false;
removed = true;
}
}
}
if (!removed) i++;
}
if (!removed) i++;
}
LeaveCriticalSection(&m_tileEntityListCS);
}

View file

@ -1,5 +1,6 @@
#include <thread>
#include <chrono>
#include <mutex>
#include "../Platform/stdafx.h"
#include "ServerLevel.h"
@ -45,7 +46,7 @@ WeighedTreasureArray ServerLevel::RANDOM_BONUS_ITEMS;
C4JThread* ServerLevel::m_updateThread = nullptr;
C4JThread::EventArray* ServerLevel::m_updateTrigger;
CRITICAL_SECTION ServerLevel::m_updateCS[3];
std::recursive_mutex ServerLevel::m_updateCS[3];
Level* ServerLevel::m_level[3];
int ServerLevel::m_updateChunkX[3][LEVEL_CHUNKS_TO_UPDATE_MAX];
@ -59,13 +60,10 @@ int ServerLevel::m_randValue[3];
void ServerLevel::staticCtor() {
m_updateTrigger = new C4JThread::EventArray(3);
InitializeCriticalSection(&m_updateCS[0]);
InitializeCriticalSection(&m_updateCS[1]);
InitializeCriticalSection(&m_updateCS[2]);
m_updateThread = new C4JThread(runUpdate, nullptr, "Tile update");
m_updateThread->SetProcessor(CPU_CORE_TILE_UPDATE);
m_updateThread->Run();
m_updateThread->setProcessor(CPU_CORE_TILE_UPDATE);
m_updateThread->run();
RANDOM_BONUS_ITEMS = WeighedTreasureArray(20);
@ -107,9 +105,6 @@ ServerLevel::ServerLevel(MinecraftServer* server,
LevelSettings* levelSettings)
: Level(levelStorage, levelName, levelSettings,
Dimension::getNew(dimension), false) {
InitializeCriticalSection(&m_limiterCS);
InitializeCriticalSection(&m_tickNextTickCS);
InitializeCriticalSection(&m_csQueueSendTileUpdates);
m_fallingTileCount = 0;
m_primedTntCount = 0;
@ -188,31 +183,31 @@ ServerLevel::~ServerLevel() {
delete portalForcer;
delete mobSpawner;
EnterCriticalSection(&m_csQueueSendTileUpdates);
for (auto it = m_queuedSendTileUpdates.begin();
it != m_queuedSendTileUpdates.end(); ++it) {
Pos* p = *it;
delete p;
{
std::lock_guard<std::recursive_mutex> lock(m_csQueueSendTileUpdates);
for (auto it = m_queuedSendTileUpdates.begin();
it != m_queuedSendTileUpdates.end(); ++it) {
Pos* p = *it;
delete p;
}
m_queuedSendTileUpdates.clear();
delete this->tracker; // MGH - added, we were losing about 500K going
// in and out the menus
delete this->chunkMap;
}
m_queuedSendTileUpdates.clear();
delete this->tracker; // MGH - added, we were losing about 500K going in
// and out the menus
delete this->chunkMap;
LeaveCriticalSection(&m_csQueueSendTileUpdates);
DeleteCriticalSection(&m_csQueueSendTileUpdates);
DeleteCriticalSection(&m_limiterCS);
DeleteCriticalSection(&m_tickNextTickCS);
// Make sure that the update thread isn't actually doing any updating
EnterCriticalSection(&m_updateCS[0]);
LeaveCriticalSection(&m_updateCS[0]);
EnterCriticalSection(&m_updateCS[1]);
LeaveCriticalSection(&m_updateCS[1]);
EnterCriticalSection(&m_updateCS[2]);
LeaveCriticalSection(&m_updateCS[2]);
m_updateTrigger->ClearAll();
{
std::lock_guard<std::recursive_mutex> lock(m_updateCS[0]);
}
{
std::lock_guard<std::recursive_mutex> lock(m_updateCS[1]);
}
{
std::lock_guard<std::recursive_mutex> lock(m_updateCS[2]);
}
m_updateTrigger->clearAll();
}
void ServerLevel::tick() {
@ -450,31 +445,35 @@ void ServerLevel::tickTiles() {
unsigned int tickCount = 0;
EnterCriticalSection(&m_updateCS[iLev]);
// This section processes the tiles that need to be ticked, which we worked
// out in the previous tick (or haven't yet, if this is the first frame)
/*int grassTicks = 0;
int lavaTicks = 0;
int otherTicks = 0;*/
for (int i = 0; i < m_updateTileCount[iLev]; i++) {
int x = m_updateTileX[iLev][i];
int y = m_updateTileY[iLev][i];
int z = m_updateTileZ[iLev][i];
if (hasChunkAt(x, y, z)) {
int id = getTile(x, y, z);
if (Tile::tiles[id] != nullptr && Tile::tiles[id]->isTicking()) {
/*if(id == 2) ++grassTicks;
else if(id == 11) ++lavaTicks;
else ++otherTicks;*/
Tile::tiles[id]->tick(this, x, y, z, random);
{
std::lock_guard<std::recursive_mutex> lock(m_updateCS[iLev]);
// This section processes the tiles that need to be ticked, which we
// worked out in the previous tick (or haven't yet, if this is the first
// frame)
/*int grassTicks = 0;
int lavaTicks = 0;
int otherTicks = 0;*/
for (int i = 0; i < m_updateTileCount[iLev]; i++) {
int x = m_updateTileX[iLev][i];
int y = m_updateTileY[iLev][i];
int z = m_updateTileZ[iLev][i];
if (hasChunkAt(x, y, z)) {
int id = getTile(x, y, z);
if (Tile::tiles[id] != nullptr &&
Tile::tiles[id]->isTicking()) {
/*if(id == 2) ++grassTicks;
else if(id == 11) ++lavaTicks;
else ++otherTicks;*/
Tile::tiles[id]->tick(this, x, y, z, random);
}
}
}
// printf("Total ticks - Grass: %d, Lava: %d, Other: %d, Total: %d\n",
// grassTicks, lavaTicks, otherTicks, grassTicks + lavaTicks +
// otherTicks);
m_updateTileCount[iLev] = 0;
m_updateChunkCount[iLev] = 0;
}
// printf("Total ticks - Grass: %d, Lava: %d, Other: %d, Total: %d\n",
// grassTicks, lavaTicks, otherTicks, grassTicks + lavaTicks + otherTicks);
m_updateTileCount[iLev] = 0;
m_updateChunkCount[iLev] = 0;
LeaveCriticalSection(&m_updateCS[iLev]);
Level::tickTiles();
@ -563,7 +562,7 @@ void ServerLevel::tickTiles() {
m_level[iLev] = this;
m_randValue[iLev] = randValue;
// We've set up everything that the udpate thread needs, so kick it off
m_updateTrigger->Set(iLev);
m_updateTrigger->set(iLev);
}
bool ServerLevel::isTileToBeTickedAt(int x, int y, int z, int tileId) {
@ -603,12 +602,13 @@ void ServerLevel::addToTickNextTick(int x, int y, int z, int tileId,
td.delay(tickDelay + levelData->getGameTime());
td.setPriorityTilt(priorityTilt);
}
EnterCriticalSection(&m_tickNextTickCS);
if (tickNextTickSet.find(td) == tickNextTickSet.end()) {
tickNextTickSet.insert(td);
tickNextTickList.insert(td);
{
std::lock_guard<std::recursive_mutex> lock(m_tickNextTickCS);
if (tickNextTickSet.find(td) == tickNextTickSet.end()) {
tickNextTickSet.insert(td);
tickNextTickList.insert(td);
}
}
LeaveCriticalSection(&m_tickNextTickCS);
}
MemSect(0);
}
@ -621,12 +621,13 @@ void ServerLevel::forceAddTileTick(int x, int y, int z, int tileId,
if (tileId > 0) {
td.delay(tickDelay + levelData->getGameTime());
}
EnterCriticalSection(&m_tickNextTickCS);
if (tickNextTickSet.find(td) == tickNextTickSet.end()) {
tickNextTickSet.insert(td);
tickNextTickList.insert(td);
{
std::lock_guard<std::recursive_mutex> lock(m_tickNextTickCS);
if (tickNextTickSet.find(td) == tickNextTickSet.end()) {
tickNextTickSet.insert(td);
tickNextTickList.insert(td);
}
}
LeaveCriticalSection(&m_tickNextTickCS);
}
void ServerLevel::tickEntities() {
@ -644,7 +645,7 @@ void ServerLevel::tickEntities() {
void ServerLevel::resetEmptyTime() { emptyTime = 0; }
bool ServerLevel::tickPendingTicks(bool force) {
EnterCriticalSection(&m_tickNextTickCS);
std::lock_guard<std::recursive_mutex> lock(m_tickNextTickCS);
int count = (int)tickNextTickList.size();
int count2 = (int)tickNextTickSet.size();
if (count != tickNextTickSet.size()) {
@ -687,14 +688,13 @@ bool ServerLevel::tickPendingTicks(bool force) {
int count4 = (int)tickNextTickSet.size();
bool retval = tickNextTickList.size() != 0;
LeaveCriticalSection(&m_tickNextTickCS);
return retval;
}
std::vector<TickNextTickData>* ServerLevel::fetchTicksInChunk(LevelChunk* chunk,
bool remove) {
EnterCriticalSection(&m_tickNextTickCS);
std::lock_guard<std::recursive_mutex> lock(m_tickNextTickCS);
std::vector<TickNextTickData>* results = new std::vector<TickNextTickData>;
ChunkPos* pos = chunk->getPos();
@ -749,7 +749,6 @@ std::vector<TickNextTickData>* ServerLevel::fetchTicksInChunk(LevelChunk* chunk,
}
}
LeaveCriticalSection(&m_tickNextTickCS);
return results;
}
@ -1225,13 +1224,12 @@ void ServerLevel::sendParticles(const std::wstring& name, double x, double y,
// 4J Stu - Sometimes we want to update tiles on the server from the main thread
// (eg SignTileEntity when string verify returns)
void ServerLevel::queueSendTileUpdate(int x, int y, int z) {
EnterCriticalSection(&m_csQueueSendTileUpdates);
std::lock_guard<std::recursive_mutex> lock(m_csQueueSendTileUpdates);
m_queuedSendTileUpdates.push_back(new Pos(x, y, z));
LeaveCriticalSection(&m_csQueueSendTileUpdates);
}
void ServerLevel::runQueuedSendTileUpdates() {
EnterCriticalSection(&m_csQueueSendTileUpdates);
std::lock_guard<std::recursive_mutex> lock(m_csQueueSendTileUpdates);
for (auto it = m_queuedSendTileUpdates.begin();
it != m_queuedSendTileUpdates.end(); ++it) {
Pos* p = *it;
@ -1239,7 +1237,6 @@ void ServerLevel::runQueuedSendTileUpdates() {
delete p;
}
m_queuedSendTileUpdates.clear();
LeaveCriticalSection(&m_csQueueSendTileUpdates);
}
// 4J - added special versions of addEntity and extra processing on entity
@ -1249,53 +1246,48 @@ bool ServerLevel::addEntity(std::shared_ptr<Entity> e) {
if (e->instanceof(eTYPE_ITEMENTITY)) {
// printf("Adding item entity count
//%d\n",m_itemEntities.size());
EnterCriticalSection(&m_limiterCS);
std::lock_guard<std::recursive_mutex> lock(m_limiterCS);
if (m_itemEntities.size() >= MAX_ITEM_ENTITIES) {
// printf("Adding - doing remove\n");
removeEntityImmediately(m_itemEntities.front());
}
LeaveCriticalSection(&m_limiterCS);
}
// If its an hanging entity, and we've got to our capacity, delete the
// oldest
else if (e->instanceof(eTYPE_HANGING_ENTITY)) {
// printf("Adding item entity count
//%d\n",m_itemEntities.size());
EnterCriticalSection(&m_limiterCS);
std::lock_guard<std::recursive_mutex> lock(m_limiterCS);
if (m_hangingEntities.size() >= MAX_HANGING_ENTITIES) {
// printf("Adding - doing remove\n");
// 4J-PB - refuse to add the entity, since we'll be removing one
// already there, and it may be an item frame with something in it.
LeaveCriticalSection(&m_limiterCS);
return false;
// removeEntityImmediately(m_hangingEntities.front());
}
LeaveCriticalSection(&m_limiterCS);
}
// If its an arrow entity, and we've got to our capacity, delete the oldest
else if (e->instanceof(eTYPE_ARROW)) {
// printf("Adding arrow entity count
//%d\n",m_arrowEntities.size());
EnterCriticalSection(&m_limiterCS);
std::lock_guard<std::recursive_mutex> lock(m_limiterCS);
if (m_arrowEntities.size() >= MAX_ARROW_ENTITIES) {
// printf("Adding - doing remove\n");
removeEntityImmediately(m_arrowEntities.front());
}
LeaveCriticalSection(&m_limiterCS);
}
// If its an experience orb entity, and we've got to our capacity, delete
// the oldest
else if (e->instanceof(eTYPE_EXPERIENCEORB)) {
// printf("Adding arrow entity count
//%d\n",m_arrowEntities.size());
EnterCriticalSection(&m_limiterCS);
std::lock_guard<std::recursive_mutex> lock(m_limiterCS);
if (m_experienceOrbEntities.size() >= MAX_EXPERIENCEORB_ENTITIES) {
// printf("Adding - doing remove\n");
removeEntityImmediately(m_experienceOrbEntities.front());
}
LeaveCriticalSection(&m_limiterCS);
}
return Level::addEntity(e);
}
@ -1308,21 +1300,17 @@ bool ServerLevel::atEntityLimit(std::shared_ptr<Entity> e) {
bool atLimit = false;
if (e->instanceof(eTYPE_ITEMENTITY)) {
EnterCriticalSection(&m_limiterCS);
std::lock_guard<std::recursive_mutex> lock(m_limiterCS);
atLimit = m_itemEntities.size() >= MAX_ITEM_ENTITIES;
LeaveCriticalSection(&m_limiterCS);
} else if (e->instanceof(eTYPE_HANGING_ENTITY)) {
EnterCriticalSection(&m_limiterCS);
std::lock_guard<std::recursive_mutex> lock(m_limiterCS);
atLimit = m_hangingEntities.size() >= MAX_HANGING_ENTITIES;
LeaveCriticalSection(&m_limiterCS);
} else if (e->instanceof(eTYPE_ARROW)) {
EnterCriticalSection(&m_limiterCS);
std::lock_guard<std::recursive_mutex> lock(m_limiterCS);
atLimit = m_arrowEntities.size() >= MAX_ARROW_ENTITIES;
LeaveCriticalSection(&m_limiterCS);
} else if (e->instanceof(eTYPE_EXPERIENCEORB)) {
EnterCriticalSection(&m_limiterCS);
std::lock_guard<std::recursive_mutex> lock(m_limiterCS);
atLimit = m_experienceOrbEntities.size() >= MAX_EXPERIENCEORB_ENTITIES;
LeaveCriticalSection(&m_limiterCS);
}
return atLimit;
@ -1331,37 +1319,31 @@ bool ServerLevel::atEntityLimit(std::shared_ptr<Entity> e) {
// Maintain a cound of primed tnt & falling tiles in this level
void ServerLevel::entityAddedExtra(std::shared_ptr<Entity> e) {
if (e->instanceof(eTYPE_ITEMENTITY)) {
EnterCriticalSection(&m_limiterCS);
std::lock_guard<std::recursive_mutex> lock(m_limiterCS);
m_itemEntities.push_back(e);
// printf("entity added: item entity count now
//%d\n",m_itemEntities.size());
LeaveCriticalSection(&m_limiterCS);
} else if (e->instanceof(eTYPE_HANGING_ENTITY)) {
EnterCriticalSection(&m_limiterCS);
std::lock_guard<std::recursive_mutex> lock(m_limiterCS);
m_hangingEntities.push_back(e);
// printf("entity added: item entity count now
//%d\n",m_itemEntities.size());
LeaveCriticalSection(&m_limiterCS);
} else if (e->instanceof(eTYPE_ARROW)) {
EnterCriticalSection(&m_limiterCS);
std::lock_guard<std::recursive_mutex> lock(m_limiterCS);
m_arrowEntities.push_back(e);
// printf("entity added: arrow entity count now
//%d\n",m_arrowEntities.size());
LeaveCriticalSection(&m_limiterCS);
} else if (e->instanceof(eTYPE_EXPERIENCEORB)) {
EnterCriticalSection(&m_limiterCS);
std::lock_guard<std::recursive_mutex> lock(m_limiterCS);
m_experienceOrbEntities.push_back(e);
// printf("entity added: experience orb entity count now
//%d\n",m_arrowEntities.size());
LeaveCriticalSection(&m_limiterCS);
} else if (e->instanceof(eTYPE_PRIMEDTNT)) {
EnterCriticalSection(&m_limiterCS);
std::lock_guard<std::recursive_mutex> lock(m_limiterCS);
m_primedTntCount++;
LeaveCriticalSection(&m_limiterCS);
} else if (e->instanceof(eTYPE_FALLINGTILE)) {
EnterCriticalSection(&m_limiterCS);
std::lock_guard<std::recursive_mutex> lock(m_limiterCS);
m_fallingTileCount++;
LeaveCriticalSection(&m_limiterCS);
}
}
@ -1369,7 +1351,7 @@ void ServerLevel::entityAddedExtra(std::shared_ptr<Entity> e) {
// item entities from our list
void ServerLevel::entityRemovedExtra(std::shared_ptr<Entity> e) {
if (e->instanceof(eTYPE_ITEMENTITY)) {
EnterCriticalSection(&m_limiterCS);
std::lock_guard<std::recursive_mutex> lock(m_limiterCS);
// printf("entity removed: item entity count
//%d\n",m_itemEntities.size());
auto it = find(m_itemEntities.begin(), m_itemEntities.end(), e);
@ -1379,9 +1361,8 @@ void ServerLevel::entityRemovedExtra(std::shared_ptr<Entity> e) {
}
// printf("entity removed: item entity count now
//%d\n",m_itemEntities.size());
LeaveCriticalSection(&m_limiterCS);
} else if (e->instanceof(eTYPE_HANGING_ENTITY)) {
EnterCriticalSection(&m_limiterCS);
std::lock_guard<std::recursive_mutex> lock(m_limiterCS);
// printf("entity removed: item entity count
//%d\n",m_itemEntities.size());
auto it = find(m_hangingEntities.begin(), m_hangingEntities.end(), e);
@ -1391,9 +1372,8 @@ void ServerLevel::entityRemovedExtra(std::shared_ptr<Entity> e) {
}
// printf("entity removed: item entity count now
//%d\n",m_itemEntities.size());
LeaveCriticalSection(&m_limiterCS);
} else if (e->instanceof(eTYPE_ARROW)) {
EnterCriticalSection(&m_limiterCS);
std::lock_guard<std::recursive_mutex> lock(m_limiterCS);
// printf("entity removed: arrow entity count
//%d\n",m_arrowEntities.size());
auto it = find(m_arrowEntities.begin(), m_arrowEntities.end(), e);
@ -1403,9 +1383,8 @@ void ServerLevel::entityRemovedExtra(std::shared_ptr<Entity> e) {
}
// printf("entity removed: arrow entity count now
//%d\n",m_arrowEntities.size());
LeaveCriticalSection(&m_limiterCS);
} else if (e->instanceof(eTYPE_EXPERIENCEORB)) {
EnterCriticalSection(&m_limiterCS);
std::lock_guard<std::recursive_mutex> lock(m_limiterCS);
// printf("entity removed: experience orb entity count
//%d\n",m_arrowEntities.size());
auto it = find(m_experienceOrbEntities.begin(),
@ -1416,29 +1395,24 @@ void ServerLevel::entityRemovedExtra(std::shared_ptr<Entity> e) {
}
// printf("entity removed: experience orb entity count now
//%d\n",m_arrowEntities.size());
LeaveCriticalSection(&m_limiterCS);
} else if (e->instanceof(eTYPE_PRIMEDTNT)) {
EnterCriticalSection(&m_limiterCS);
std::lock_guard<std::recursive_mutex> lock(m_limiterCS);
m_primedTntCount--;
LeaveCriticalSection(&m_limiterCS);
} else if (e->instanceof(eTYPE_FALLINGTILE)) {
EnterCriticalSection(&m_limiterCS);
std::lock_guard<std::recursive_mutex> lock(m_limiterCS);
m_fallingTileCount--;
LeaveCriticalSection(&m_limiterCS);
}
}
bool ServerLevel::newPrimedTntAllowed() {
EnterCriticalSection(&m_limiterCS);
std::lock_guard<std::recursive_mutex> lock(m_limiterCS);
bool retval = m_primedTntCount < MAX_PRIMED_TNT;
LeaveCriticalSection(&m_limiterCS);
return retval;
}
bool ServerLevel::newFallingTileAllowed() {
EnterCriticalSection(&m_limiterCS);
std::lock_guard<std::recursive_mutex> lock(m_limiterCS);
bool retval = m_fallingTileCount < MAX_FALLING_TILE;
LeaveCriticalSection(&m_limiterCS);
return retval;
}
@ -1446,7 +1420,7 @@ int ServerLevel::runUpdate(void* lpParam) {
ShutdownManager::HasStarted(ShutdownManager::eRunUpdateThread,
m_updateTrigger);
while (ShutdownManager::ShouldRun(ShutdownManager::eRunUpdateThread)) {
m_updateTrigger->WaitForAll(INFINITE);
m_updateTrigger->waitForAll(C4JThread::kInfiniteTimeout);
if (!ShutdownManager::ShouldRun(ShutdownManager::eRunUpdateThread))
break;
@ -1457,7 +1431,7 @@ int ServerLevel::runUpdate(void* lpParam) {
int grassTicks = 0;
int lavaTicks = 0;
for (unsigned int iLev = 0; iLev < 3; ++iLev) {
EnterCriticalSection(&m_updateCS[iLev]);
std::lock_guard<std::recursive_mutex> lock(m_updateCS[iLev]);
for (int i = 0; i < m_updateChunkCount[iLev]; i++) {
// 4J - some of these tile ticks will check things in
// neighbouring tiles, causing chunks to load/create that aren't
@ -1547,7 +1521,6 @@ int ServerLevel::runUpdate(void* lpParam) {
}
}
}
LeaveCriticalSection(&m_updateCS[iLev]);
}
PIXEndNamedEvent();
}

View file

@ -1,4 +1,5 @@
#pragma once
#include <mutex>
#include "../../Minecraft.World/Headers/net.minecraft.world.level.h"
#include "../../Minecraft.World/Util/JavaIntHash.h"
class ServerChunkCache;
@ -16,7 +17,7 @@ private:
EntityTracker* tracker;
PlayerChunkMap* chunkMap;
CRITICAL_SECTION m_tickNextTickCS; // 4J added
std::recursive_mutex m_tickNextTickCS; // 4J added
std::set<TickNextTickData, TickNextTickDataKeyCompare>
tickNextTickList; // 4J Was TreeSet
std::unordered_set<TickNextTickData, TickNextTickDataKeyHash,
@ -24,7 +25,7 @@ private:
tickNextTickSet; // 4J Was HashSet
std::vector<Pos*> m_queuedSendTileUpdates; // 4J added
CRITICAL_SECTION m_csQueueSendTileUpdates;
std::recursive_mutex m_csQueueSendTileUpdates;
protected:
int saveInterval;
@ -177,7 +178,7 @@ public:
int m_primedTntCount;
int m_fallingTileCount;
CRITICAL_SECTION m_limiterCS;
std::recursive_mutex m_limiterCS;
std::list<std::shared_ptr<Entity> > m_itemEntities;
std::list<std::shared_ptr<Entity> > m_hangingEntities;
std::list<std::shared_ptr<Entity> > m_arrowEntities;
@ -211,7 +212,7 @@ public:
static int m_randValue[3];
static C4JThread::EventArray* m_updateTrigger;
static CRITICAL_SECTION m_updateCS[3];
static std::recursive_mutex m_updateCS[3];
static C4JThread* m_updateThread;
static int runUpdate(void* lpParam);

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,5 @@
#pragma once
#include <mutex>
class Timer;
class MultiPlayerLevel;
class LevelRenderer;
@ -347,7 +348,7 @@ public:
// 4J Stu
void forceStatsSave(int idx);
CRITICAL_SECTION m_setLevelCS;
std::recursive_mutex m_setLevelCS;
private:
// A bit field that store whether a particular quadrant is in the full

View file

@ -243,38 +243,40 @@ int MinecraftServer::runPostUpdate(void* lpParam) {
// Update lights for both levels until we are signalled to terminate
do {
EnterCriticalSection(&server->m_postProcessCS);
if (server->m_postProcessRequests.size()) {
MinecraftServer::postProcessRequest request =
server->m_postProcessRequests.back();
server->m_postProcessRequests.pop_back();
LeaveCriticalSection(&server->m_postProcessCS);
static int count = 0;
PIXBeginNamedEvent(0, "Post processing %d ", (count++) % 8);
request.chunkSource->postProcess(request.chunkSource, request.x,
request.z);
PIXEndNamedEvent();
} else {
LeaveCriticalSection(&server->m_postProcessCS);
{
std::unique_lock<std::mutex> lock(server->m_postProcessCS);
if (server->m_postProcessRequests.size()) {
MinecraftServer::postProcessRequest request =
server->m_postProcessRequests.back();
server->m_postProcessRequests.pop_back();
lock.unlock();
static int count = 0;
PIXBeginNamedEvent(0, "Post processing %d ", (count++) % 8);
request.chunkSource->postProcess(request.chunkSource, request.x,
request.z);
PIXEndNamedEvent();
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
} while (!server->m_postUpdateTerminate &&
ShutdownManager::ShouldRun(ShutdownManager::ePostProcessThread));
// #ifndef 0
// One final pass through updates to make sure we're done
EnterCriticalSection(&server->m_postProcessCS);
int maxRequests = server->m_postProcessRequests.size();
while (server->m_postProcessRequests.size() &&
ShutdownManager::ShouldRun(ShutdownManager::ePostProcessThread)) {
MinecraftServer::postProcessRequest request =
server->m_postProcessRequests.back();
server->m_postProcessRequests.pop_back();
LeaveCriticalSection(&server->m_postProcessCS);
request.chunkSource->postProcess(request.chunkSource, request.x,
request.z);
EnterCriticalSection(&server->m_postProcessCS);
{
std::unique_lock<std::mutex> lock(server->m_postProcessCS);
int maxRequests = server->m_postProcessRequests.size();
while (
server->m_postProcessRequests.size() &&
ShutdownManager::ShouldRun(ShutdownManager::ePostProcessThread)) {
MinecraftServer::postProcessRequest request =
server->m_postProcessRequests.back();
server->m_postProcessRequests.pop_back();
lock.unlock();
request.chunkSource->postProcess(request.chunkSource, request.x,
request.z);
lock.lock();
}
}
LeaveCriticalSection(&server->m_postProcessCS);
// #endif //0
Tile::ReleaseThreadStorage();
Level::destroyLightingCache();
@ -286,26 +288,30 @@ int MinecraftServer::runPostUpdate(void* lpParam) {
void MinecraftServer::addPostProcessRequest(ChunkSource* chunkSource, int x,
int z) {
EnterCriticalSection(&m_postProcessCS);
m_postProcessRequests.push_back(
MinecraftServer::postProcessRequest(x, z, chunkSource));
LeaveCriticalSection(&m_postProcessCS);
{
std::lock_guard<std::mutex> lock(m_postProcessCS);
m_postProcessRequests.push_back(
MinecraftServer::postProcessRequest(x, z, chunkSource));
}
}
void MinecraftServer::postProcessTerminate(ProgressRenderer* mcprogress) {
std::uint32_t status = 0;
size_t postProcessItemCount = 0;
size_t postProcessItemRemaining = 0;
EnterCriticalSection(&server->m_postProcessCS);
size_t postProcessItemCount = server->m_postProcessRequests.size();
LeaveCriticalSection(&server->m_postProcessCS);
{
std::lock_guard<std::mutex> lock(server->m_postProcessCS);
postProcessItemCount = server->m_postProcessRequests.size();
}
do {
status = m_postUpdateThread->WaitForCompletion(50);
if (status == WAIT_TIMEOUT) {
EnterCriticalSection(&server->m_postProcessCS);
size_t postProcessItemRemaining =
server->m_postProcessRequests.size();
LeaveCriticalSection(&server->m_postProcessCS);
status = m_postUpdateThread->waitForCompletion(50);
if (status == C4JThread::WaitResult::Timeout) {
{
std::lock_guard<std::mutex> lock(server->m_postProcessCS);
postProcessItemRemaining = server->m_postProcessRequests.size();
}
if (postProcessItemCount) {
mcprogress->progressStagePercentage(
@ -316,10 +322,9 @@ void MinecraftServer::postProcessTerminate(ProgressRenderer* mcprogress) {
SparseLightStorage::tick();
SparseDataStorage::tick();
}
} while (status == WAIT_TIMEOUT);
} while (status == C4JThread::WaitResult::Timeout);
delete m_postUpdateThread;
m_postUpdateThread = nullptr;
DeleteCriticalSection(&m_postProcessCS);
}
bool MinecraftServer::loadLevel(LevelStorageSource* storageSource,
@ -481,7 +486,6 @@ bool MinecraftServer::loadLevel(LevelStorageSource* storageSource,
if (s_bServerHalted || !g_NetworkManager.IsInSession()) return false;
// 4J - Make a new thread to do post processing
InitializeCriticalSection(&m_postProcessCS);
// 4J-PB - fix for 108310 - TCR #001 BAS Game Stability: TU12: Code:
// Compliance: Crash after creating world on "journey" seed. Stack gets very
@ -492,9 +496,9 @@ bool MinecraftServer::loadLevel(LevelStorageSource* storageSource,
new C4JThread(runPostUpdate, this, "Post processing", 256 * 1024);
m_postUpdateTerminate = false;
m_postUpdateThread->SetProcessor(CPU_CORE_POST_PROCESSING);
m_postUpdateThread->SetPriority(THREAD_PRIORITY_ABOVE_NORMAL);
m_postUpdateThread->Run();
m_postUpdateThread->setProcessor(CPU_CORE_POST_PROCESSING);
m_postUpdateThread->setPriority(C4JThread::ThreadPriority::AboveNormal);
m_postUpdateThread->run();
int64_t startTime = System::currentTimeMillis();
@ -1175,7 +1179,7 @@ void MinecraftServer::run(int64_t seed, void* lpParameter) {
switch (eAction) {
case eXuiServerAction_AutoSaveGame:
case eXuiServerAction_SaveGame:
app.EnterSaveNotificationSection();
app.lockSaveNotification();
if (players != nullptr) {
players->saveAll(
Minecraft::GetInstance()->progressRenderer);
@ -1210,7 +1214,7 @@ void MinecraftServer::run(int64_t seed, void* lpParameter) {
Minecraft::GetInstance()->progressRenderer,
(eAction == eXuiServerAction_AutoSaveGame));
}
app.LeaveSaveNotificationSection();
app.unlockSaveNotification();
break;
case eXuiServerAction_DropItem:
// Find the player, and drop the id at their feet
@ -1243,7 +1247,7 @@ void MinecraftServer::run(int64_t seed, void* lpParameter) {
case eXuiServerAction_PauseServer:
m_isServerPaused = ((size_t)param == true);
if (m_isServerPaused) {
m_serverPausedEvent->Set();
m_serverPausedEvent->set();
}
break;
case eXuiServerAction_ToggleRain: {
@ -1291,7 +1295,7 @@ void MinecraftServer::run(int64_t seed, void* lpParameter) {
break;
case eXuiServerAction_ExportSchematic:
#if !defined(_CONTENT_PACKAGE)
app.EnterSaveNotificationSection();
app.lockSaveNotification();
// players->broadcastAll(
// shared_ptr<UpdateProgressPacket>( new
@ -1325,7 +1329,7 @@ void MinecraftServer::run(int64_t seed, void* lpParameter) {
delete initData;
}
app.LeaveSaveNotificationSection();
app.unlockSaveNotification();
#endif
break;
case eXuiServerAction_SetCameraLocation:

View file

@ -1,5 +1,6 @@
#pragma once
#include <cstdint>
#include <mutex>
#include "Input/ConsoleInputSource.h"
#include "../Minecraft.World/Util/ArrayWithLength.h"
@ -246,7 +247,7 @@ private:
: x(x), z(z), chunkSource(chunkSource) {}
};
std::vector<postProcessRequest> m_postProcessRequests;
CRITICAL_SECTION m_postProcessCS;
std::mutex m_postProcessCS;
public:
void addPostProcessRequest(ChunkSource* chunkSource, int x, int z);

View file

@ -89,7 +89,6 @@ MultiPlayerChunkCache::MultiPlayerChunkCache(Level* level) {
this->cache = new LevelChunk*[XZSIZE * XZSIZE];
memset(this->cache, 0, XZSIZE * XZSIZE * sizeof(LevelChunk*));
InitializeCriticalSectionAndSpinCount(&m_csLoadCreate, 4000);
}
MultiPlayerChunkCache::~MultiPlayerChunkCache() {
@ -100,8 +99,6 @@ MultiPlayerChunkCache::~MultiPlayerChunkCache() {
auto itEnd = loadedChunkList.end();
for (auto it = loadedChunkList.begin(); it != itEnd; it++) delete *it;
DeleteCriticalSection(&m_csLoadCreate);
}
bool MultiPlayerChunkCache::hasChunk(int x, int z) {
@ -158,50 +155,53 @@ LevelChunk* MultiPlayerChunkCache::create(int x, int z) {
LevelChunk* lastChunk = chunk;
if (chunk == nullptr) {
EnterCriticalSection(&m_csLoadCreate);
// LevelChunk *chunk;
if (g_NetworkManager.IsHost()) // force here to disable sharing of data
{
// 4J-JEV: We are about to use shared data, abort if the server is
// stopped and the data is deleted.
if (MinecraftServer::getInstance()->serverHalted()) return nullptr;
std::unique_lock<std::mutex> lock(m_csLoadCreate);
// If we're the host, then don't create the chunk, share data from
// the server's copy
// LevelChunk *chunk;
if (g_NetworkManager
.IsHost()) // force here to disable sharing of data
{
// 4J-JEV: We are about to use shared data, abort if the server
// is stopped and the data is deleted.
if (MinecraftServer::getInstance()->serverHalted())
return nullptr;
// If we're the host, then don't create the chunk, share data
// from the server's copy
#ifdef _LARGE_WORLDS
LevelChunk* serverChunk =
MinecraftServer::getInstance()
->getLevel(level->dimension->id)
->cache->getChunkLoadedOrUnloaded(x, z);
LevelChunk* serverChunk =
MinecraftServer::getInstance()
->getLevel(level->dimension->id)
->cache->getChunkLoadedOrUnloaded(x, z);
#else
LevelChunk* serverChunk = MinecraftServer::getInstance()
->getLevel(level->dimension->id)
->cache->getChunk(x, z);
LevelChunk* serverChunk = MinecraftServer::getInstance()
->getLevel(level->dimension->id)
->cache->getChunk(x, z);
#endif
chunk = new LevelChunk(level, x, z, serverChunk);
// Let renderer know that this chunk has been created - it might
// have made render data from the EmptyChunk if it got to a chunk
// before the server sent it
level->setTilesDirty(x * 16, 0, z * 16, x * 16 + 15, 127,
z * 16 + 15);
hasData[idx] = true;
} else {
// Passing an empty array into the LevelChunk ctor, which it now
// detects and sets up the chunk as compressed & empty
byteArray bytes;
chunk = new LevelChunk(level, x, z, serverChunk);
// Let renderer know that this chunk has been created - it might
// have made render data from the EmptyChunk if it got to a
// chunk before the server sent it
level->setTilesDirty(x * 16, 0, z * 16, x * 16 + 15, 127,
z * 16 + 15);
hasData[idx] = true;
} else {
// Passing an empty array into the LevelChunk ctor, which it now
// detects and sets up the chunk as compressed & empty
byteArray bytes;
chunk = new LevelChunk(level, bytes, x, z);
chunk = new LevelChunk(level, bytes, x, z);
// 4J - changed to use new methods for lighting
chunk->setSkyLightDataAllBright();
// Arrays::fill(chunk->skyLight->data, (byte) 255);
// 4J - changed to use new methods for lighting
chunk->setSkyLightDataAllBright();
// Arrays::fill(chunk->skyLight->data,
//(byte) 255);
}
chunk->loaded = true;
}
chunk->loaded = true;
LeaveCriticalSection(&m_csLoadCreate);
#if (defined _WIN64 || defined __LP64__)
if (InterlockedCompareExchangeRelease64(
(int64_t*)&cache[idx], (int64_t)chunk, (int64_t)lastChunk) ==
@ -220,9 +220,10 @@ LevelChunk* MultiPlayerChunkCache::create(int x, int z) {
}
// Successfully updated the cache
EnterCriticalSection(&m_csLoadCreate);
loadedChunkList.push_back(chunk);
LeaveCriticalSection(&m_csLoadCreate);
{
std::lock_guard<std::mutex> lock(m_csLoadCreate);
loadedChunkList.push_back(chunk);
}
} else {
// Something else must have updated the cache. Return that chunk and
// discard this one. This really shouldn't be happening in
@ -281,9 +282,11 @@ void MultiPlayerChunkCache::recreateLogicStructuresForChunk(int chunkX,
int chunkZ) {}
std::wstring MultiPlayerChunkCache::gatherStats() {
EnterCriticalSection(&m_csLoadCreate);
int size = (int)loadedChunkList.size();
LeaveCriticalSection(&m_csLoadCreate);
int size;
{
std::lock_guard<std::mutex> lock(m_csLoadCreate);
size = (int)loadedChunkList.size();
}
return L"MultiplayerChunkCache: " + _toString<int>(size);
}

View file

@ -1,4 +1,5 @@
#pragma once
#include <mutex>
#include "../../Minecraft.World/Headers/net.minecraft.world.level.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.level.chunk.h"
#include "../../Minecraft.World/Level/RandomLevelSource.h"
@ -18,7 +19,7 @@ private:
LevelChunk** cache;
// 4J - added for multithreaded support
CRITICAL_SECTION m_csLoadCreate;
std::mutex m_csLoadCreate;
// 4J - size of cache is defined by size of one side - must be even
int XZSIZE;
int XZOFFSET;

View file

@ -57,8 +57,6 @@ PlayerConnection::PlayerConnection(MinecraftServer* server,
this->player = player;
// player->connection = this; // 4J - moved out as we can't
// assign in a ctor
InitializeCriticalSection(&done_cs);
m_bCloseOnTick = false;
m_bWasKicked = false;
@ -71,10 +69,7 @@ PlayerConnection::PlayerConnection(MinecraftServer* server,
app.GetGameHostOption(eGameHostOption_Gamertags) != 0 ? true : false);
}
PlayerConnection::~PlayerConnection() {
delete connection;
DeleteCriticalSection(&done_cs);
}
PlayerConnection::~PlayerConnection() { delete connection; }
void PlayerConnection::tick() {
if (done) return;
@ -106,9 +101,8 @@ void PlayerConnection::tick() {
}
void PlayerConnection::disconnect(DisconnectPacket::eDisconnectReason reason) {
EnterCriticalSection(&done_cs);
std::lock_guard<std::mutex> lock(done_cs);
if (done) {
LeaveCriticalSection(&done_cs);
return;
}
@ -135,7 +129,6 @@ void PlayerConnection::disconnect(DisconnectPacket::eDisconnectReason reason) {
server->getPlayers()->remove(player);
done = true;
LeaveCriticalSection(&done_cs);
}
void PlayerConnection::handlePlayerInput(
@ -551,7 +544,7 @@ void PlayerConnection::handleUseItem(std::shared_ptr<UseItemPacket> packet) {
void PlayerConnection::onDisconnect(DisconnectPacket::eDisconnectReason reason,
void* reasonObjects) {
EnterCriticalSection(&done_cs);
std::lock_guard<std::mutex> lock(done_cs);
if (done) return;
// logger.info(player.name + " lost connection: " + reason);
// 4J-PB - removed, since it needs to be localised in the language the
@ -568,7 +561,6 @@ void PlayerConnection::onDisconnect(DisconnectPacket::eDisconnectReason reason,
}
server->getPlayers()->remove(player);
done = true;
LeaveCriticalSection(&done_cs);
}
void PlayerConnection::onUnhandledPacket(std::shared_ptr<Packet> packet) {

View file

@ -1,4 +1,5 @@
#pragma once
#include <mutex>
#include "../Input/ConsoleInputSource.h"
#include "../../Minecraft.World/Network/Packets/PacketListener.h"
#include "../../Minecraft.World/Util/JavaIntHash.h"
@ -14,7 +15,7 @@ class PlayerConnection : public PacketListener, public ConsoleInputSource {
public:
Connection* connection;
bool done;
CRITICAL_SECTION done_cs;
std::mutex done_cs;
// 4J Stu - Added this so that we can manage UGC privileges
PlayerUID m_offlineXUID, m_onlineXUID;

View file

@ -48,9 +48,6 @@ PlayerList::PlayerList(MinecraftServer* server) {
maxPlayers = server->settings->getInt(L"max-players", 20);
doWhiteList = false;
InitializeCriticalSection(&m_kickPlayersCS);
InitializeCriticalSection(&m_closePlayersCS);
}
PlayerList::~PlayerList() {
@ -61,9 +58,6 @@ PlayerList::~PlayerList() {
// back to this player
(*it)->gameMode = nullptr;
}
DeleteCriticalSection(&m_kickPlayersCS);
DeleteCriticalSection(&m_closePlayersCS);
}
void PlayerList::placeNewPlayer(Connection* connection,
@ -995,73 +989,76 @@ void PlayerList::tick() {
}
}
EnterCriticalSection(&m_closePlayersCS);
while (!m_smallIdsToClose.empty()) {
std::uint8_t smallId = m_smallIdsToClose.front();
m_smallIdsToClose.pop_front();
{
std::lock_guard<std::mutex> lock(m_closePlayersCS);
while (!m_smallIdsToClose.empty()) {
std::uint8_t smallId = m_smallIdsToClose.front();
m_smallIdsToClose.pop_front();
std::shared_ptr<ServerPlayer> player = nullptr;
std::shared_ptr<ServerPlayer> player = nullptr;
for (unsigned int i = 0; i < players.size(); i++) {
std::shared_ptr<ServerPlayer> p = players.at(i);
// 4J Stu - May be being a bit overprotective with all the nullptr
// checks, but adding late in TU7 so want to be safe
if (p != nullptr && p->connection != nullptr &&
p->connection->connection != nullptr &&
p->connection->connection->getSocket() != nullptr &&
p->connection->connection->getSocket()->getSmallId() ==
smallId) {
player = p;
break;
for (unsigned int i = 0; i < players.size(); i++) {
std::shared_ptr<ServerPlayer> p = players.at(i);
// 4J Stu - May be being a bit overprotective with all the
// nullptr checks, but adding late in TU7 so want to be safe
if (p != nullptr && p->connection != nullptr &&
p->connection->connection != nullptr &&
p->connection->connection->getSocket() != nullptr &&
p->connection->connection->getSocket()->getSmallId() ==
smallId) {
player = p;
break;
}
}
if (player != nullptr) {
player->connection->disconnect(
DisconnectPacket::eDisconnect_Closed);
}
}
if (player != nullptr) {
player->connection->disconnect(
DisconnectPacket::eDisconnect_Closed);
}
}
LeaveCriticalSection(&m_closePlayersCS);
EnterCriticalSection(&m_kickPlayersCS);
while (!m_smallIdsToKick.empty()) {
std::uint8_t smallId = m_smallIdsToKick.front();
m_smallIdsToKick.pop_front();
INetworkPlayer* selectedPlayer =
g_NetworkManager.GetPlayerBySmallId(smallId);
if (selectedPlayer != nullptr) {
if (selectedPlayer->IsLocal() != true) {
// #if 0
PlayerUID xuid = selectedPlayer->GetUID();
// Kick this player from the game
std::shared_ptr<ServerPlayer> player = nullptr;
{
std::lock_guard<std::mutex> lock(m_kickPlayersCS);
while (!m_smallIdsToKick.empty()) {
std::uint8_t smallId = m_smallIdsToKick.front();
m_smallIdsToKick.pop_front();
INetworkPlayer* selectedPlayer =
g_NetworkManager.GetPlayerBySmallId(smallId);
if (selectedPlayer != nullptr) {
if (selectedPlayer->IsLocal() != true) {
// #if 0
PlayerUID xuid = selectedPlayer->GetUID();
// Kick this player from the game
std::shared_ptr<ServerPlayer> player = nullptr;
for (unsigned int i = 0; i < players.size(); i++) {
std::shared_ptr<ServerPlayer> p = players.at(i);
PlayerUID playersXuid = p->getOnlineXuid();
if (p != nullptr &&
ProfileManager.AreXUIDSEqual(playersXuid, xuid)) {
player = p;
break;
for (unsigned int i = 0; i < players.size(); i++) {
std::shared_ptr<ServerPlayer> p = players.at(i);
PlayerUID playersXuid = p->getOnlineXuid();
if (p != nullptr &&
ProfileManager.AreXUIDSEqual(playersXuid, xuid)) {
player = p;
break;
}
}
}
if (player != nullptr) {
m_bannedXuids.push_back(player->getOnlineXuid());
// 4J Stu - If we have kicked a player, make sure that they
// have no privileges if they later try to join the world
// when trust players is off
player->enableAllPlayerPrivileges(false);
player->connection->setWasKicked();
player->connection->send(
std::shared_ptr<DisconnectPacket>(new DisconnectPacket(
DisconnectPacket::eDisconnect_Kicked)));
if (player != nullptr) {
m_bannedXuids.push_back(player->getOnlineXuid());
// 4J Stu - If we have kicked a player, make sure that
// they have no privileges if they later try to join the
// world when trust players is off
player->enableAllPlayerPrivileges(false);
player->connection->setWasKicked();
player->connection->send(
std::shared_ptr<DisconnectPacket>(
new DisconnectPacket(
DisconnectPacket::eDisconnect_Kicked)));
}
// #endif
}
// #endif
}
}
}
LeaveCriticalSection(&m_kickPlayersCS);
// Check our receiving players, and if they are dead see if we can replace
// them
@ -1628,15 +1625,17 @@ bool PlayerList::canReceiveAllPackets(std::shared_ptr<ServerPlayer> player) {
}
void PlayerList::kickPlayerByShortId(std::uint8_t networkSmallId) {
EnterCriticalSection(&m_kickPlayersCS);
m_smallIdsToKick.push_back(networkSmallId);
LeaveCriticalSection(&m_kickPlayersCS);
{
std::lock_guard<std::mutex> lock(m_kickPlayersCS);
m_smallIdsToKick.push_back(networkSmallId);
}
}
void PlayerList::closePlayerConnectionBySmallId(std::uint8_t networkSmallId) {
EnterCriticalSection(&m_closePlayersCS);
m_smallIdsToClose.push_back(networkSmallId);
LeaveCriticalSection(&m_closePlayersCS);
{
std::lock_guard<std::mutex> lock(m_closePlayersCS);
m_smallIdsToClose.push_back(networkSmallId);
}
}
bool PlayerList::isXuidBanned(PlayerUID xuid) {

View file

@ -1,6 +1,7 @@
#pragma once
#include <cstdint>
#include <deque>
#include <mutex>
#include "../../Minecraft.World/Util/ArrayWithLength.h"
class ServerPlayer;
@ -31,9 +32,9 @@ private:
// 4J Added
std::vector<PlayerUID> m_bannedXuids;
std::deque<std::uint8_t> m_smallIdsToKick;
CRITICAL_SECTION m_kickPlayersCS;
std::mutex m_kickPlayersCS;
std::deque<std::uint8_t> m_smallIdsToClose;
CRITICAL_SECTION m_closePlayersCS;
std::mutex m_closePlayersCS;
/* 4J - removed
Set<String> bans = new HashSet<String>();
Set<String> ipBans = new HashSet<String>();

View file

@ -38,8 +38,6 @@ ServerChunkCache::ServerChunkCache(ServerLevel* level, ChunkStorage* storage,
m_unloadedCache = new LevelChunk*[XZSIZE * XZSIZE];
memset(m_unloadedCache, 0, XZSIZE * XZSIZE * sizeof(LevelChunk*));
#endif
InitializeCriticalSectionAndSpinCount(&m_csLoadCreate, 4000);
}
// 4J-PB added
@ -58,7 +56,6 @@ ServerChunkCache::~ServerChunkCache() {
auto itEnd = m_loadedChunkList.end();
for (auto it = m_loadedChunkList.begin(); it != itEnd; it++) delete *it;
DeleteCriticalSection(&m_csLoadCreate);
}
bool ServerChunkCache::hasChunk(int x, int z) {
@ -146,20 +143,20 @@ LevelChunk* ServerChunkCache::create(
LevelChunk* lastChunk = chunk;
if ((chunk == nullptr) || (chunk->x != x) || (chunk->z != z)) {
EnterCriticalSection(&m_csLoadCreate);
chunk = load(x, z);
if (chunk == nullptr) {
if (source == nullptr) {
chunk = emptyChunk;
} else {
chunk = source->getChunk(x, z);
{
std::lock_guard<std::recursive_mutex> lock(m_csLoadCreate);
chunk = load(x, z);
if (chunk == nullptr) {
if (source == nullptr) {
chunk = emptyChunk;
} else {
chunk = source->getChunk(x, z);
}
}
if (chunk != nullptr) {
chunk->load();
}
}
if (chunk != nullptr) {
chunk->load();
}
LeaveCriticalSection(&m_csLoadCreate);
#if defined(_WIN64) || defined(__LP64__)
if (InterlockedCompareExchangeRelease64(
@ -172,7 +169,7 @@ LevelChunk* ServerChunkCache::create(
#endif
{
// Successfully updated the cache
EnterCriticalSection(&m_csLoadCreate);
std::lock_guard<std::recursive_mutex> lock(m_csLoadCreate);
// 4J - added - this will run a recalcHeightmap if source is a
// randomlevelsource, which has been split out from source::getChunk
// so that we are doing it after the chunk has been added to the
@ -269,7 +266,6 @@ LevelChunk* ServerChunkCache::create(
hasChunk(x, z - 1) && hasChunk(x, z + 1))
chunk->checkChests(this, x, z);
LeaveCriticalSection(&m_csLoadCreate);
} else {
// Something else must have updated the cache. Return that chunk and
// discard this one
@ -653,12 +649,13 @@ bool ServerChunkCache::saveAllEntities() {
PIXBeginNamedEvent(0, "Save all entities");
PIXBeginNamedEvent(0, "saving to NBT");
EnterCriticalSection(&m_csLoadCreate);
for (auto it = m_loadedChunkList.begin(); it != m_loadedChunkList.end();
++it) {
storage->saveEntities(level, *it);
{
std::lock_guard<std::recursive_mutex> lock(m_csLoadCreate);
for (auto it = m_loadedChunkList.begin(); it != m_loadedChunkList.end();
++it) {
storage->saveEntities(level, *it);
}
}
LeaveCriticalSection(&m_csLoadCreate);
PIXEndNamedEvent();
PIXBeginNamedEvent(0, "Flushing");
@ -670,7 +667,7 @@ bool ServerChunkCache::saveAllEntities() {
}
bool ServerChunkCache::save(bool force, ProgressListener* progressListener) {
EnterCriticalSection(&m_csLoadCreate);
std::lock_guard<std::recursive_mutex> lock(m_csLoadCreate);
int saves = 0;
// 4J - added this to support progressListner
@ -701,7 +698,6 @@ bool ServerChunkCache::save(bool force, ProgressListener* progressListener) {
save(chunk);
chunk->setUnsaved(false);
if (++saves == MAX_SAVES && !force) {
LeaveCriticalSection(&m_csLoadCreate);
return false;
}
@ -751,7 +747,6 @@ bool ServerChunkCache::save(bool force, ProgressListener* progressListener) {
save(chunk);
chunk->setUnsaved(false);
if (++saves == MAX_SAVES && !force) {
LeaveCriticalSection(&m_csLoadCreate);
return false;
}
@ -776,13 +771,11 @@ bool ServerChunkCache::save(bool force, ProgressListener* progressListener) {
if (force) {
if (storage == nullptr) {
LeaveCriticalSection(&m_csLoadCreate);
return true;
}
storage->flush();
}
LeaveCriticalSection(&m_csLoadCreate);
return !maxSavesReached;
}
@ -867,8 +860,9 @@ int ServerChunkCache::runSaveThreadProc(void* lpParam) {
}
// Wait for the producer thread to tell us to start
params->wakeEvent->WaitForSignal(
INFINITE); // WaitForSingleObject(params->wakeEvent,INFINITE);
params->wakeEvent->waitForSignal(
C4JThread::
kInfiniteTimeout); // WaitForSingleObject(params->wakeEvent,INFINITE);
// app.DebugPrintf("Save thread has started\n");
@ -888,14 +882,15 @@ int ServerChunkCache::runSaveThreadProc(void* lpParam) {
// Inform the producer thread that we are done with this chunk
params->notificationEvent
->Set(); // SetEvent(params->notificationEvent);
->set(); // SetEvent(params->notificationEvent);
// app.DebugPrintf("Save thread has alerted producer that it is
// complete\n");
// Wait for the producer thread to tell us to go again
params->wakeEvent->WaitForSignal(
INFINITE); // WaitForSingleObject(params->wakeEvent,INFINITE);
params->wakeEvent->waitForSignal(
C4JThread::
kInfiniteTimeout); // WaitForSingleObject(params->wakeEvent,INFINITE);
PIXEndNamedEvent();
}

View file

@ -1,4 +1,5 @@
#pragma once
#include <mutex>
#include "../../Minecraft.World/Headers/net.minecraft.world.level.h"
#include "../../Minecraft.World/IO/Files/File.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.level.storage.h"
@ -30,7 +31,7 @@ private:
#endif
// 4J - added for multithreaded support
CRITICAL_SECTION m_csLoadCreate;
std::recursive_mutex m_csLoadCreate;
// 4J - size of cache is defined by size of one side - must be even
int XZSIZE;
int XZOFFSET;

View file

@ -12,12 +12,11 @@
ServerConnection::ServerConnection(MinecraftServer* server) {
// 4J - added initialiser
connectionCounter = 0;
InitializeCriticalSection(&pending_cs);
this->server = server;
}
ServerConnection::~ServerConnection() { DeleteCriticalSection(&pending_cs); }
ServerConnection::~ServerConnection() {}
// 4J - added to handle incoming connections, to replace thread that original
// used to have
@ -35,18 +34,20 @@ void ServerConnection::addPlayerConnection(
}
void ServerConnection::handleConnection(std::shared_ptr<PendingConnection> uc) {
EnterCriticalSection(&pending_cs);
pending.push_back(uc);
LeaveCriticalSection(&pending_cs);
{
std::lock_guard<std::mutex> lock(pending_cs);
pending.push_back(uc);
}
}
void ServerConnection::stop() {
EnterCriticalSection(&pending_cs);
for (unsigned int i = 0; i < pending.size(); i++) {
std::shared_ptr<PendingConnection> uc = pending[i];
uc->connection->close(DisconnectPacket::eDisconnect_Closed);
{
std::lock_guard<std::mutex> lock(pending_cs);
for (unsigned int i = 0; i < pending.size(); i++) {
std::shared_ptr<PendingConnection> uc = pending[i];
uc->connection->close(DisconnectPacket::eDisconnect_Closed);
}
}
LeaveCriticalSection(&pending_cs);
for (unsigned int i = 0; i < players.size(); i++) {
std::shared_ptr<PlayerConnection> player = players[i];
@ -58,9 +59,11 @@ void ServerConnection::tick() {
{
// MGH - changed this so that the the CS lock doesn't cover the tick
// (was causing a lockup when 2 players tried to join)
EnterCriticalSection(&pending_cs);
std::vector<std::shared_ptr<PendingConnection> > tempPending = pending;
LeaveCriticalSection(&pending_cs);
std::vector<std::shared_ptr<PendingConnection> > tempPending;
{
std::lock_guard<std::mutex> lock(pending_cs);
tempPending = pending;
}
for (unsigned int i = 0; i < tempPending.size(); i++) {
std::shared_ptr<PendingConnection> uc = tempPending[i];
@ -76,13 +79,14 @@ void ServerConnection::tick() {
}
// now remove from the pending list
EnterCriticalSection(&pending_cs);
for (unsigned int i = 0; i < pending.size(); i++)
if (pending[i]->done) {
pending.erase(pending.begin() + i);
i--;
}
LeaveCriticalSection(&pending_cs);
{
std::lock_guard<std::mutex> lock(pending_cs);
for (unsigned int i = 0; i < pending.size(); i++)
if (pending[i]->done) {
pending.erase(pending.begin() + i);
i--;
}
}
for (unsigned int i = 0; i < players.size(); i++) {
std::shared_ptr<PlayerConnection> player = players[i];

View file

@ -1,4 +1,5 @@
#pragma once
#include <mutex>
class PendingConnection;
class PlayerConnection;
class MinecraftServer;
@ -18,7 +19,7 @@ private:
int connectionCounter;
private:
CRITICAL_SECTION pending_cs; // 4J added
std::mutex pending_cs; // 4J added
std::vector<std::shared_ptr<PendingConnection> > pending;
std::vector<std::shared_ptr<PlayerConnection> > players;

View file

@ -462,7 +462,7 @@ void SoundEngine::playMusicTick() {
SetIsPlayingStreamingCDMusic(isCD);
m_openStreamThread = new C4JThread(
OpenStreamThreadProc, this, "OpenStreamThreadProc");
m_openStreamThread->Run();
m_openStreamThread->run();
m_StreamState = eMusicStreamState_Opening;
} else {
app.DebugPrintf(
@ -1493,7 +1493,7 @@ void SoundEngine::playMusicUpdate() {
// ~300ms.
m_openStreamThread = new C4JThread(OpenStreamThreadProc, this,
"OpenStreamThreadProc");
m_openStreamThread->Run();
m_openStreamThread->run();
m_StreamState = eMusicStreamState_Opening;
}
break;

View file

@ -25,7 +25,6 @@ class C4JMemoryPoolFixed : public C4JMemoryPool {
uchar* m_memStart; // Beginning of memory pool
uchar* m_memEnd; // End of memory pool
uchar* m_next; // Num of next free block
// CRITICAL_SECTION m_CS;
public:
C4JMemoryPoolFixed() {
m_numOfBlocks = 0;
@ -53,7 +52,6 @@ public:
m_memStart = new uchar[m_sizeOfEachBlock * m_numOfBlocks];
m_memEnd = m_memStart + (m_sizeOfEachBlock * m_numOfBlocks);
m_next = m_memStart;
// InitializeCriticalSection(&m_CS);
}
void DestroyPool() {
@ -71,7 +69,6 @@ public:
virtual void* Alloc(size_t size) {
if (size > m_sizeOfEachBlock) return ::malloc(size);
// EnterCriticalSection(&m_CS);
if (m_numInitialized < m_numOfBlocks) {
uint* p = (uint*)AddrFromIndex(m_numInitialized);
*p = m_numInitialized + 1;
@ -87,7 +84,6 @@ public:
m_next = nullptr;
}
}
// LeaveCriticalSection(&m_CS);
return ret;
}
@ -96,7 +92,6 @@ public:
::free(ptr);
return;
}
// EnterCriticalSection(&m_CS);
if (m_next != nullptr) {
(*(uint*)ptr) = IndexFromAddr(m_next);
m_next = (uchar*)ptr;
@ -105,7 +100,6 @@ public:
m_next = (uchar*)ptr;
}
++m_numFreeBlocks;
// LeaveCriticalSection(&m_CS);
}
}; // End pool class

View file

@ -177,17 +177,8 @@ CMinecraftApp::CMinecraftApp() {
m_iDLCOfferC = 0;
m_bAllDLCContentRetrieved = true;
InitializeCriticalSection(&csDLCDownloadQueue);
m_bAllTMSContentRetrieved = true;
m_bTickTMSDLCFiles = true;
InitializeCriticalSection(&csTMSPPDownloadQueue);
InitializeCriticalSection(&csAdditionalModelParts);
InitializeCriticalSection(&csAdditionalSkinBoxes);
InitializeCriticalSection(&csAnimOverrideBitmask);
InitializeCriticalSection(&csMemFilesLock);
InitializeCriticalSection(&csMemTPDLock);
InitializeCriticalSection(&m_saveNotificationCriticalSection);
m_saveNotificationDepth = 0;
m_dwRequiredTexturePackID = 0;
@ -4556,7 +4547,7 @@ bool CMinecraftApp::isXuidDeadmau5(PlayerUID xuid) {
void CMinecraftApp::AddMemoryTextureFile(const std::wstring& wName,
std::uint8_t* pbData,
unsigned int byteCount) {
EnterCriticalSection(&csMemFilesLock);
std::lock_guard<std::mutex> lock(csMemFilesLock);
// check it's not already in
PMEMDATA pData = nullptr;
auto it = m_MEM_Files.find(wName);
@ -4576,7 +4567,6 @@ void CMinecraftApp::AddMemoryTextureFile(const std::wstring& wName,
}
++pData->ucRefCount;
LeaveCriticalSection(&csMemFilesLock);
return;
}
@ -4595,12 +4585,10 @@ void CMinecraftApp::AddMemoryTextureFile(const std::wstring& wName,
// use the xuid to access the skin data
m_MEM_Files[wName] = pData;
LeaveCriticalSection(&csMemFilesLock);
}
void CMinecraftApp::RemoveMemoryTextureFile(const std::wstring& wName) {
EnterCriticalSection(&csMemFilesLock);
std::lock_guard<std::mutex> lock(csMemFilesLock);
auto it = m_MEM_Files.find(wName);
if (it != m_MEM_Files.end()) {
@ -4619,17 +4607,17 @@ void CMinecraftApp::RemoveMemoryTextureFile(const std::wstring& wName) {
m_MEM_Files.erase(wName);
}
}
LeaveCriticalSection(&csMemFilesLock);
}
bool CMinecraftApp::DefaultCapeExists() {
std::wstring wTex = L"Special_Cape.png";
bool val = false;
EnterCriticalSection(&csMemFilesLock);
auto it = m_MEM_Files.find(wTex);
if (it != m_MEM_Files.end()) val = true;
LeaveCriticalSection(&csMemFilesLock);
{
std::lock_guard<std::mutex> lock(csMemFilesLock);
auto it = m_MEM_Files.find(wTex);
if (it != m_MEM_Files.end()) val = true;
}
return val;
}
@ -4637,10 +4625,11 @@ bool CMinecraftApp::DefaultCapeExists() {
bool CMinecraftApp::IsFileInMemoryTextures(const std::wstring& wName) {
bool val = false;
EnterCriticalSection(&csMemFilesLock);
auto it = m_MEM_Files.find(wName);
if (it != m_MEM_Files.end()) val = true;
LeaveCriticalSection(&csMemFilesLock);
{
std::lock_guard<std::mutex> lock(csMemFilesLock);
auto it = m_MEM_Files.find(wName);
if (it != m_MEM_Files.end()) val = true;
}
return val;
}
@ -4648,19 +4637,18 @@ bool CMinecraftApp::IsFileInMemoryTextures(const std::wstring& wName) {
void CMinecraftApp::GetMemFileDetails(const std::wstring& wName,
std::uint8_t** ppbData,
unsigned int* pByteCount) {
EnterCriticalSection(&csMemFilesLock);
std::lock_guard<std::mutex> lock(csMemFilesLock);
auto it = m_MEM_Files.find(wName);
if (it != m_MEM_Files.end()) {
PMEMDATA pData = (*it).second;
*ppbData = pData->pbData;
*pByteCount = pData->byteCount;
}
LeaveCriticalSection(&csMemFilesLock);
}
void CMinecraftApp::AddMemoryTPDFile(int iConfig, std::uint8_t* pbData,
unsigned int byteCount) {
EnterCriticalSection(&csMemTPDLock);
std::lock_guard<std::mutex> lock(csMemTPDLock);
// check it's not already in
PMEMDATA pData = nullptr;
auto it = m_MEM_TPD.find(iConfig);
@ -4672,12 +4660,10 @@ void CMinecraftApp::AddMemoryTPDFile(int iConfig, std::uint8_t* pbData,
m_MEM_TPD[iConfig] = pData;
}
LeaveCriticalSection(&csMemTPDLock);
}
void CMinecraftApp::RemoveMemoryTPDFile(int iConfig) {
EnterCriticalSection(&csMemTPDLock);
std::lock_guard<std::mutex> lock(csMemTPDLock);
// check it's not already in
PMEMDATA pData = nullptr;
auto it = m_MEM_TPD.find(iConfig);
@ -4686,8 +4672,6 @@ void CMinecraftApp::RemoveMemoryTPDFile(int iConfig) {
delete pData;
m_MEM_TPD.erase(iConfig);
}
LeaveCriticalSection(&csMemTPDLock);
}
#if defined(_WINDOWS64)
@ -4696,24 +4680,24 @@ int CMinecraftApp::GetTPConfigVal(wchar_t* pwchDataFile) { return -1; }
bool CMinecraftApp::IsFileInTPD(int iConfig) {
bool val = false;
EnterCriticalSection(&csMemTPDLock);
auto it = m_MEM_TPD.find(iConfig);
if (it != m_MEM_TPD.end()) val = true;
LeaveCriticalSection(&csMemTPDLock);
{
std::lock_guard<std::mutex> lock(csMemTPDLock);
auto it = m_MEM_TPD.find(iConfig);
if (it != m_MEM_TPD.end()) val = true;
}
return val;
}
void CMinecraftApp::GetTPD(int iConfig, std::uint8_t** ppbData,
unsigned int* pByteCount) {
EnterCriticalSection(&csMemTPDLock);
std::lock_guard<std::mutex> lock(csMemTPDLock);
auto it = m_MEM_TPD.find(iConfig);
if (it != m_MEM_TPD.end()) {
PMEMDATA pData = (*it).second;
*ppbData = pData->pbData;
*pByteCount = pData->byteCount;
}
LeaveCriticalSection(&csMemTPDLock);
}
// bool CMinecraftApp::UploadFileToGlobalStorage(int iQuadrant,
@ -5660,8 +5644,8 @@ DLC_INFO* CMinecraftApp::GetDLCInfoForFullOfferID(uint64_t ullOfferID_Full) {
return nullptr;
}
void CMinecraftApp::EnterSaveNotificationSection() {
EnterCriticalSection(&m_saveNotificationCriticalSection);
void CMinecraftApp::lockSaveNotification() {
std::lock_guard<std::mutex> lock(m_saveNotificationMutex);
if (m_saveNotificationDepth++ == 0) {
if (g_NetworkManager
.IsInSession()) // this can be triggered from the front end if
@ -5677,11 +5661,10 @@ void CMinecraftApp::EnterSaveNotificationSection() {
}
}
}
LeaveCriticalSection(&m_saveNotificationCriticalSection);
}
void CMinecraftApp::LeaveSaveNotificationSection() {
EnterCriticalSection(&m_saveNotificationCriticalSection);
void CMinecraftApp::unlockSaveNotification() {
std::lock_guard<std::mutex> lock(m_saveNotificationMutex);
if (--m_saveNotificationDepth == 0) {
if (g_NetworkManager
.IsInSession()) // this can be triggered from the front end if
@ -5697,7 +5680,6 @@ void CMinecraftApp::LeaveSaveNotificationSection() {
}
}
}
LeaveCriticalSection(&m_saveNotificationCriticalSection);
}
int CMinecraftApp::RemoteSaveThreadProc(void* lpParameter) {
@ -6628,45 +6610,44 @@ std::uint32_t CMinecraftApp::m_dwContentTypeA[e_Marketplace_MAX] = {
unsigned int CMinecraftApp::AddDLCRequest(eDLCMarketplaceType eType,
bool bPromote) {
// lock access
EnterCriticalSection(&csDLCDownloadQueue);
{
std::lock_guard<std::mutex> lock(csDLCDownloadQueue);
// If it's already in there, promote it to the top of the list
int iPosition = 0;
for (auto it = m_DLCDownloadQueue.begin(); it != m_DLCDownloadQueue.end();
++it) {
DLCRequest* pCurrent = *it;
// If it's already in there, promote it to the top of the list
int iPosition = 0;
for (auto it = m_DLCDownloadQueue.begin();
it != m_DLCDownloadQueue.end(); ++it) {
DLCRequest* pCurrent = *it;
if (pCurrent->dwType == m_dwContentTypeA[eType]) {
// already got this in the list
if (pCurrent->eState == e_DLC_ContentState_Retrieving ||
pCurrent->eState == e_DLC_ContentState_Retrieved) {
// already retrieved this
LeaveCriticalSection(&csDLCDownloadQueue);
return 0;
} else {
// promote
if (bPromote) {
m_DLCDownloadQueue.erase(m_DLCDownloadQueue.begin() +
iPosition);
m_DLCDownloadQueue.insert(m_DLCDownloadQueue.begin(),
pCurrent);
if (pCurrent->dwType == m_dwContentTypeA[eType]) {
// already got this in the list
if (pCurrent->eState == e_DLC_ContentState_Retrieving ||
pCurrent->eState == e_DLC_ContentState_Retrieved) {
// already retrieved this
return 0;
} else {
// promote
if (bPromote) {
m_DLCDownloadQueue.erase(m_DLCDownloadQueue.begin() +
iPosition);
m_DLCDownloadQueue.insert(m_DLCDownloadQueue.begin(),
pCurrent);
}
return 0;
}
LeaveCriticalSection(&csDLCDownloadQueue);
return 0;
}
iPosition++;
}
iPosition++;
DLCRequest* pDLCreq = new DLCRequest;
pDLCreq->dwType = m_dwContentTypeA[eType];
pDLCreq->eState = e_DLC_ContentState_Idle;
m_DLCDownloadQueue.push_back(pDLCreq);
m_bAllDLCContentRetrieved = false;
}
DLCRequest* pDLCreq = new DLCRequest;
pDLCreq->dwType = m_dwContentTypeA[eType];
pDLCreq->eState = e_DLC_ContentState_Idle;
m_DLCDownloadQueue.push_back(pDLCreq);
m_bAllDLCContentRetrieved = false;
LeaveCriticalSection(&csDLCDownloadQueue);
app.DebugPrintf("[Consoles_App] Added DLC request.\n");
return 1;
}
@ -6674,7 +6655,7 @@ unsigned int CMinecraftApp::AddDLCRequest(eDLCMarketplaceType eType,
unsigned int CMinecraftApp::AddTMSPPFileTypeRequest(eDLCContentType eType,
bool bPromote) {
// lock access
EnterCriticalSection(&csTMSPPDownloadQueue);
std::lock_guard<std::mutex> lock(csTMSPPDownloadQueue);
// If it's already in there, promote it to the top of the list
int iPosition = 0;
@ -6708,7 +6689,6 @@ unsigned int CMinecraftApp::AddTMSPPFileTypeRequest(eDLCContentType eType,
if(bPromoted)
{
// re-ordered the list, so leave now
LeaveCriticalSection(&csTMSPPDownloadQueue);
return 0;
}
*/
@ -6855,22 +6835,19 @@ unsigned int CMinecraftApp::AddTMSPPFileTypeRequest(eDLCContentType eType,
}
}
LeaveCriticalSection(&csTMSPPDownloadQueue);
return 1;
}
bool CMinecraftApp::CheckTMSDLCCanStop() {
EnterCriticalSection(&csTMSPPDownloadQueue);
std::lock_guard<std::mutex> lock(csTMSPPDownloadQueue);
for (auto it = m_TMSPPDownloadQueue.begin();
it != m_TMSPPDownloadQueue.end(); ++it) {
TMSPPRequest* pCurrent = *it;
if (pCurrent->eState == e_TMS_ContentState_Retrieving) {
LeaveCriticalSection(&csTMSPPDownloadQueue);
return false;
}
}
LeaveCriticalSection(&csTMSPPDownloadQueue);
return true;
}
@ -6886,43 +6863,42 @@ bool CMinecraftApp::RetrieveNextDLCContent() {
// online.
}
EnterCriticalSection(&csDLCDownloadQueue);
for (auto it = m_DLCDownloadQueue.begin(); it != m_DLCDownloadQueue.end();
++it) {
DLCRequest* pCurrent = *it;
{
std::lock_guard<std::mutex> lock(csDLCDownloadQueue);
for (auto it = m_DLCDownloadQueue.begin();
it != m_DLCDownloadQueue.end(); ++it) {
DLCRequest* pCurrent = *it;
if (pCurrent->eState == e_DLC_ContentState_Retrieving) {
LeaveCriticalSection(&csDLCDownloadQueue);
return true;
if (pCurrent->eState == e_DLC_ContentState_Retrieving) {
return true;
}
}
}
// Now look for the next retrieval
for (auto it = m_DLCDownloadQueue.begin(); it != m_DLCDownloadQueue.end();
++it) {
DLCRequest* pCurrent = *it;
// Now look for the next retrieval
for (auto it = m_DLCDownloadQueue.begin();
it != m_DLCDownloadQueue.end(); ++it) {
DLCRequest* pCurrent = *it;
if (pCurrent->eState == e_DLC_ContentState_Idle) {
if (pCurrent->eState == e_DLC_ContentState_Idle) {
#if defined(_DEBUG)
app.DebugPrintf("RetrieveNextDLCContent - type = %d\n",
pCurrent->dwType);
app.DebugPrintf("RetrieveNextDLCContent - type = %d\n",
pCurrent->dwType);
#endif
C4JStorage::EDLCStatus status = StorageManager.GetDLCOffers(
ProfileManager.GetPrimaryPad(),
&CMinecraftApp::DLCOffersReturned, this, pCurrent->dwType);
if (status == C4JStorage::EDLC_Pending) {
pCurrent->eState = e_DLC_ContentState_Retrieving;
} else {
// no content of this type, or some other problem
app.DebugPrintf("RetrieveNextDLCContent - PROBLEM\n");
pCurrent->eState = e_DLC_ContentState_Retrieved;
C4JStorage::EDLCStatus status = StorageManager.GetDLCOffers(
ProfileManager.GetPrimaryPad(),
&CMinecraftApp::DLCOffersReturned, this, pCurrent->dwType);
if (status == C4JStorage::EDLC_Pending) {
pCurrent->eState = e_DLC_ContentState_Retrieving;
} else {
// no content of this type, or some other problem
app.DebugPrintf("RetrieveNextDLCContent - PROBLEM\n");
pCurrent->eState = e_DLC_ContentState_Retrieved;
}
return true;
}
LeaveCriticalSection(&csDLCDownloadQueue);
return true;
}
}
LeaveCriticalSection(&csDLCDownloadQueue);
app.DebugPrintf("[Consoles_App] Finished downloading dlc content.\n");
return false;
@ -6934,46 +6910,48 @@ int CMinecraftApp::TMSPPFileReturned(void* pParam, int iPad, int iUserData,
CMinecraftApp* pClass = (CMinecraftApp*)pParam;
// find the right one in the vector
EnterCriticalSection(&pClass->csTMSPPDownloadQueue);
for (auto it = pClass->m_TMSPPDownloadQueue.begin();
it != pClass->m_TMSPPDownloadQueue.end(); ++it) {
TMSPPRequest* pCurrent = *it;
{
std::lock_guard<std::mutex> lock(pClass->csTMSPPDownloadQueue);
for (auto it = pClass->m_TMSPPDownloadQueue.begin();
it != pClass->m_TMSPPDownloadQueue.end(); ++it) {
TMSPPRequest* pCurrent = *it;
#if defined(_WINDOWS64)
char szFile[MAX_TMSFILENAME_SIZE];
wcstombs(szFile, pCurrent->wchFilename, MAX_TMSFILENAME_SIZE);
char szFile[MAX_TMSFILENAME_SIZE];
wcstombs(szFile, pCurrent->wchFilename, MAX_TMSFILENAME_SIZE);
if (strcmp(szFilename, szFile) == 0)
if (strcmp(szFilename, szFile) == 0)
#endif
{
// set this to retrieved whether it found it or not
pCurrent->eState = e_TMS_ContentState_Retrieved;
{
// set this to retrieved whether it found it or not
pCurrent->eState = e_TMS_ContentState_Retrieved;
if (pFileData != nullptr) {
switch (pCurrent->eType) {
case e_DLC_TexturePackData: {
app.DebugPrintf("--- Got texturepack data %ls\n",
pCurrent->wchFilename);
// get the config value for the texture pack
int iConfig = app.GetTPConfigVal(pCurrent->wchFilename);
app.AddMemoryTPDFile(iConfig, pFileData->pbData,
pFileData->size);
} break;
default:
app.DebugPrintf("--- Got image data - %ls\n",
pCurrent->wchFilename);
app.AddMemoryTextureFile(pCurrent->wchFilename,
pFileData->pbData,
if (pFileData != nullptr) {
switch (pCurrent->eType) {
case e_DLC_TexturePackData: {
app.DebugPrintf("--- Got texturepack data %ls\n",
pCurrent->wchFilename);
// get the config value for the texture pack
int iConfig =
app.GetTPConfigVal(pCurrent->wchFilename);
app.AddMemoryTPDFile(iConfig, pFileData->pbData,
pFileData->size);
break;
} break;
default:
app.DebugPrintf("--- Got image data - %ls\n",
pCurrent->wchFilename);
app.AddMemoryTextureFile(pCurrent->wchFilename,
pFileData->pbData,
pFileData->size);
break;
}
} else {
app.DebugPrintf("TMSImageReturned failed (%s)...\n",
szFilename);
}
} else {
app.DebugPrintf("TMSImageReturned failed (%s)...\n",
szFilename);
break;
}
break;
}
}
LeaveCriticalSection(&pClass->csTMSPPDownloadQueue);
return 0;
}
@ -6992,17 +6970,18 @@ void CMinecraftApp::ClearAndResetDLCDownloadQueue() {
app.DebugPrintf("[Consoles_App] Clear and reset download queue.\n");
int iPosition = 0;
EnterCriticalSection(&csTMSPPDownloadQueue);
for (auto it = m_DLCDownloadQueue.begin(); it != m_DLCDownloadQueue.end();
++it) {
DLCRequest* pCurrent = *it;
{
std::lock_guard<std::mutex> lock(csTMSPPDownloadQueue);
for (auto it = m_DLCDownloadQueue.begin();
it != m_DLCDownloadQueue.end(); ++it) {
DLCRequest* pCurrent = *it;
delete pCurrent;
iPosition++;
delete pCurrent;
iPosition++;
}
m_DLCDownloadQueue.clear();
m_bAllDLCContentRetrieved = true;
}
m_DLCDownloadQueue.clear();
m_bAllDLCContentRetrieved = true;
LeaveCriticalSection(&csTMSPPDownloadQueue);
}
void CMinecraftApp::TickTMSPPFilesRetrieved() {
@ -7014,17 +6993,18 @@ void CMinecraftApp::TickTMSPPFilesRetrieved() {
}
void CMinecraftApp::ClearTMSPPFilesRetrieved() {
int iPosition = 0;
EnterCriticalSection(&csTMSPPDownloadQueue);
for (auto it = m_TMSPPDownloadQueue.begin();
it != m_TMSPPDownloadQueue.end(); ++it) {
TMSPPRequest* pCurrent = *it;
{
std::lock_guard<std::mutex> lock(csTMSPPDownloadQueue);
for (auto it = m_TMSPPDownloadQueue.begin();
it != m_TMSPPDownloadQueue.end(); ++it) {
TMSPPRequest* pCurrent = *it;
delete pCurrent;
iPosition++;
delete pCurrent;
iPosition++;
}
m_TMSPPDownloadQueue.clear();
m_bAllTMSContentRetrieved = true;
}
m_TMSPPDownloadQueue.clear();
m_bAllTMSContentRetrieved = true;
LeaveCriticalSection(&csTMSPPDownloadQueue);
}
int CMinecraftApp::DLCOffersReturned(void* pParam, int iOfferC,
@ -7032,24 +7012,25 @@ int CMinecraftApp::DLCOffersReturned(void* pParam, int iOfferC,
CMinecraftApp* pClass = (CMinecraftApp*)pParam;
// find the right one in the vector
EnterCriticalSection(&pClass->csTMSPPDownloadQueue);
for (auto it = pClass->m_DLCDownloadQueue.begin();
it != pClass->m_DLCDownloadQueue.end(); ++it) {
DLCRequest* pCurrent = *it;
{
std::lock_guard<std::mutex> lock(pClass->csTMSPPDownloadQueue);
for (auto it = pClass->m_DLCDownloadQueue.begin();
it != pClass->m_DLCDownloadQueue.end(); ++it) {
DLCRequest* pCurrent = *it;
// avatar items are coming back as type Content, so we can't trust the
// type setting
if (pCurrent->dwType == static_cast<std::uint32_t>(dwType)) {
pClass->m_iDLCOfferC = iOfferC;
app.DebugPrintf(
"DLCOffersReturned - type %u, count %d - setting to "
"retrieved\n",
dwType, iOfferC);
pCurrent->eState = e_DLC_ContentState_Retrieved;
break;
// avatar items are coming back as type Content, so we can't trust
// the type setting
if (pCurrent->dwType == static_cast<std::uint32_t>(dwType)) {
pClass->m_iDLCOfferC = iOfferC;
app.DebugPrintf(
"DLCOffersReturned - type %u, count %d - setting to "
"retrieved\n",
dwType, iOfferC);
pCurrent->eState = e_DLC_ContentState_Retrieved;
break;
}
}
}
LeaveCriticalSection(&pClass->csTMSPPDownloadQueue);
return 0;
}
@ -7064,18 +7045,16 @@ eDLCContentType CMinecraftApp::Find_eDLCContentType(std::uint32_t dwType) {
bool CMinecraftApp::DLCContentRetrieved(eDLCMarketplaceType eType) {
// If there's already a retrieve in progress, quit
// we may have re-ordered the list, so need to check every item
EnterCriticalSection(&csDLCDownloadQueue);
std::lock_guard<std::mutex> lock(csDLCDownloadQueue);
for (auto it = m_DLCDownloadQueue.begin(); it != m_DLCDownloadQueue.end();
++it) {
DLCRequest* pCurrent = *it;
if ((pCurrent->dwType == m_dwContentTypeA[eType]) &&
(pCurrent->eState == e_DLC_ContentState_Retrieved)) {
LeaveCriticalSection(&csDLCDownloadQueue);
return true;
}
}
LeaveCriticalSection(&csDLCDownloadQueue);
return false;
}
@ -7088,32 +7067,33 @@ void CMinecraftApp::SetAdditionalSkinBoxes(std::uint32_t dwSkinID,
std::vector<ModelPart*>* pvModelPart = new std::vector<ModelPart*>;
std::vector<SKIN_BOX*>* pvSkinBoxes = new std::vector<SKIN_BOX*>;
EnterCriticalSection(&csAdditionalModelParts);
EnterCriticalSection(&csAdditionalSkinBoxes);
{
std::lock_guard<std::mutex> lock_mp(csAdditionalModelParts);
std::lock_guard<std::mutex> lock_sb(csAdditionalSkinBoxes);
app.DebugPrintf(
"*** SetAdditionalSkinBoxes - Inserting model parts for skin %d from "
"array of Skin Boxes\n",
dwSkinID & 0x0FFFFFFF);
app.DebugPrintf(
"*** SetAdditionalSkinBoxes - Inserting model parts for skin %d "
"from "
"array of Skin Boxes\n",
dwSkinID & 0x0FFFFFFF);
// convert the skin boxes into model parts, and add to the humanoid model
for (unsigned int i = 0; i < dwSkinBoxC; i++) {
if (pModel) {
ModelPart* pModelPart = pModel->AddOrRetrievePart(&SkinBoxA[i]);
pvModelPart->push_back(pModelPart);
pvSkinBoxes->push_back(&SkinBoxA[i]);
// convert the skin boxes into model parts, and add to the humanoid
// model
for (unsigned int i = 0; i < dwSkinBoxC; i++) {
if (pModel) {
ModelPart* pModelPart = pModel->AddOrRetrievePart(&SkinBoxA[i]);
pvModelPart->push_back(pModelPart);
pvSkinBoxes->push_back(&SkinBoxA[i]);
}
}
m_AdditionalModelParts.insert(
std::pair<std::uint32_t, std::vector<ModelPart*>*>(dwSkinID,
pvModelPart));
m_AdditionalSkinBoxes.insert(
std::pair<std::uint32_t, std::vector<SKIN_BOX*>*>(dwSkinID,
pvSkinBoxes));
}
m_AdditionalModelParts.insert(
std::pair<std::uint32_t, std::vector<ModelPart*>*>(dwSkinID,
pvModelPart));
m_AdditionalSkinBoxes.insert(
std::pair<std::uint32_t, std::vector<SKIN_BOX*>*>(dwSkinID,
pvSkinBoxes));
LeaveCriticalSection(&csAdditionalSkinBoxes);
LeaveCriticalSection(&csAdditionalModelParts);
}
std::vector<ModelPart*>* CMinecraftApp::SetAdditionalSkinBoxes(
@ -7123,36 +7103,37 @@ std::vector<ModelPart*>* CMinecraftApp::SetAdditionalSkinBoxes(
Model* pModel = renderer->getModel();
std::vector<ModelPart*>* pvModelPart = new std::vector<ModelPart*>;
EnterCriticalSection(&csAdditionalModelParts);
EnterCriticalSection(&csAdditionalSkinBoxes);
app.DebugPrintf(
"*** SetAdditionalSkinBoxes - Inserting model parts for skin %d from "
"array of Skin Boxes\n",
dwSkinID & 0x0FFFFFFF);
{
std::lock_guard<std::mutex> lock_mp(csAdditionalModelParts);
std::lock_guard<std::mutex> lock_sb(csAdditionalSkinBoxes);
app.DebugPrintf(
"*** SetAdditionalSkinBoxes - Inserting model parts for skin %d "
"from "
"array of Skin Boxes\n",
dwSkinID & 0x0FFFFFFF);
// convert the skin boxes into model parts, and add to the humanoid model
for (auto it = pvSkinBoxA->begin(); it != pvSkinBoxA->end(); ++it) {
if (pModel) {
ModelPart* pModelPart = pModel->AddOrRetrievePart(*it);
pvModelPart->push_back(pModelPart);
// convert the skin boxes into model parts, and add to the humanoid
// model
for (auto it = pvSkinBoxA->begin(); it != pvSkinBoxA->end(); ++it) {
if (pModel) {
ModelPart* pModelPart = pModel->AddOrRetrievePart(*it);
pvModelPart->push_back(pModelPart);
}
}
m_AdditionalModelParts.insert(
std::pair<std::uint32_t, std::vector<ModelPart*>*>(dwSkinID,
pvModelPart));
m_AdditionalSkinBoxes.insert(
std::pair<std::uint32_t, std::vector<SKIN_BOX*>*>(dwSkinID,
pvSkinBoxA));
}
m_AdditionalModelParts.insert(
std::pair<std::uint32_t, std::vector<ModelPart*>*>(dwSkinID,
pvModelPart));
m_AdditionalSkinBoxes.insert(
std::pair<std::uint32_t, std::vector<SKIN_BOX*>*>(dwSkinID,
pvSkinBoxA));
LeaveCriticalSection(&csAdditionalSkinBoxes);
LeaveCriticalSection(&csAdditionalModelParts);
return pvModelPart;
}
std::vector<ModelPart*>* CMinecraftApp::GetAdditionalModelParts(
std::uint32_t dwSkinID) {
EnterCriticalSection(&csAdditionalModelParts);
std::lock_guard<std::mutex> lock(csAdditionalModelParts);
std::vector<ModelPart*>* pvModelParts = nullptr;
if (m_AdditionalModelParts.size() > 0) {
auto it = m_AdditionalModelParts.find(dwSkinID);
@ -7161,13 +7142,12 @@ std::vector<ModelPart*>* CMinecraftApp::GetAdditionalModelParts(
}
}
LeaveCriticalSection(&csAdditionalModelParts);
return pvModelParts;
}
std::vector<SKIN_BOX*>* CMinecraftApp::GetAdditionalSkinBoxes(
std::uint32_t dwSkinID) {
EnterCriticalSection(&csAdditionalSkinBoxes);
std::lock_guard<std::mutex> lock(csAdditionalSkinBoxes);
std::vector<SKIN_BOX*>* pvSkinBoxes = nullptr;
if (m_AdditionalSkinBoxes.size() > 0) {
auto it = m_AdditionalSkinBoxes.find(dwSkinID);
@ -7176,12 +7156,11 @@ std::vector<SKIN_BOX*>* CMinecraftApp::GetAdditionalSkinBoxes(
}
}
LeaveCriticalSection(&csAdditionalSkinBoxes);
return pvSkinBoxes;
}
unsigned int CMinecraftApp::GetAnimOverrideBitmask(std::uint32_t dwSkinID) {
EnterCriticalSection(&csAnimOverrideBitmask);
std::lock_guard<std::mutex> lock(csAnimOverrideBitmask);
unsigned int uiAnimOverrideBitmask = 0L;
if (m_AnimOverrides.size() > 0) {
@ -7191,25 +7170,22 @@ unsigned int CMinecraftApp::GetAnimOverrideBitmask(std::uint32_t dwSkinID) {
}
}
LeaveCriticalSection(&csAnimOverrideBitmask);
return uiAnimOverrideBitmask;
}
void CMinecraftApp::SetAnimOverrideBitmask(std::uint32_t dwSkinID,
unsigned int uiAnimOverrideBitmask) {
// Make thread safe
EnterCriticalSection(&csAnimOverrideBitmask);
std::lock_guard<std::mutex> lock(csAnimOverrideBitmask);
if (m_AnimOverrides.size() > 0) {
auto it = m_AnimOverrides.find(dwSkinID);
if (it != m_AnimOverrides.end()) {
LeaveCriticalSection(&csAnimOverrideBitmask);
return; // already in here
}
}
m_AnimOverrides.insert(std::pair<std::uint32_t, unsigned int>(
dwSkinID, uiAnimOverrideBitmask));
LeaveCriticalSection(&csAnimOverrideBitmask);
}
std::uint32_t CMinecraftApp::getSkinIdFromPath(const std::wstring& skin) {

View file

@ -1,6 +1,7 @@
#pragma once
#include <cstdint>
#include <mutex>
// using namespace std;
@ -458,8 +459,8 @@ private:
std::unordered_map<std::wstring, PMEMDATA> m_MEM_Files;
// for storing texture pack data files
std::unordered_map<int, PMEMDATA> m_MEM_TPD;
CRITICAL_SECTION csMemFilesLock; // For locking access to the above map
CRITICAL_SECTION csMemTPDLock; // For locking access to the above map
std::mutex csMemFilesLock; // For locking access to the above map
std::mutex csMemTPDLock; // For locking access to the above map
VNOTIFICATIONS m_vNotifications;
@ -879,11 +880,11 @@ public:
void SetCorruptSaveDeleted(bool bVal) { m_bCorruptSaveDeleted = bVal; }
bool GetCorruptSaveDeleted(void) { return m_bCorruptSaveDeleted; }
void EnterSaveNotificationSection();
void LeaveSaveNotificationSection();
void lockSaveNotification();
void unlockSaveNotification();
private:
CRITICAL_SECTION m_saveNotificationCriticalSection;
std::mutex m_saveNotificationMutex;
int m_saveNotificationDepth;
// Download Status
@ -895,11 +896,11 @@ private:
bool m_bAllDLCContentRetrieved;
bool m_bAllTMSContentRetrieved;
bool m_bTickTMSDLCFiles;
CRITICAL_SECTION csDLCDownloadQueue;
CRITICAL_SECTION csTMSPPDownloadQueue;
CRITICAL_SECTION csAdditionalModelParts;
CRITICAL_SECTION csAdditionalSkinBoxes;
CRITICAL_SECTION csAnimOverrideBitmask;
std::mutex csDLCDownloadQueue;
std::mutex csTMSPPDownloadQueue;
std::mutex csAdditionalModelParts;
std::mutex csAdditionalSkinBoxes;
std::mutex csAnimOverrideBitmask;
bool m_bCorruptSaveDeleted;
std::uint32_t m_dwAdditionalModelParts[XUSER_MAX_COUNT];

View file

@ -33,8 +33,6 @@ SonyLeaderboardManager::SonyLeaderboardManager() {
m_openSessions = 0;
InitializeCriticalSection(&m_csViewsLock);
m_running = false;
m_threadScoreboard = nullptr;
}
@ -50,8 +48,6 @@ SonyLeaderboardManager::~SonyLeaderboardManager() {
}
delete m_threadScoreboard;
DeleteCriticalSection(&m_csViewsLock);
}
int SonyLeaderboardManager::scoreboardThreadEntry(void* lpParam) {
@ -68,9 +64,10 @@ int SonyLeaderboardManager::scoreboardThreadEntry(void* lpParam) {
self->scoreboardThreadInternal();
}
EnterCriticalSection(&self->m_csViewsLock);
needsWriting = self->m_views.size() > 0;
LeaveCriticalSection(&self->m_csViewsLock);
{
std::lock_guard<std::mutex> lock(self->m_csViewsLock);
needsWriting = self->m_views.size() > 0;
}
// 4J Stu - We can't write while we aren't signed in to live
if (!ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad())) {
@ -166,9 +163,11 @@ void SonyLeaderboardManager::scoreboardThreadInternal() {
// 4J-JEV: Writing no longer changes the manager state,
// we'll manage the write queue seperately.
EnterCriticalSection(&m_csViewsLock);
bool hasWork = !m_views.empty();
LeaveCriticalSection(&m_csViewsLock);
bool hasWork;
{
std::lock_guard<std::mutex> lock(m_csViewsLock);
hasWork = !m_views.empty();
}
if (hasWork) {
setScore();
@ -493,10 +492,12 @@ bool SonyLeaderboardManager::setScore() {
// Get next job.
EnterCriticalSection(&m_csViewsLock);
RegisterScore rscore = m_views.front();
m_views.pop();
LeaveCriticalSection(&m_csViewsLock);
RegisterScore rscore;
{
std::lock_guard<std::mutex> lock(m_csViewsLock);
rscore = m_views.front();
m_views.pop();
}
if (ProfileManager.IsGuest(rscore.m_iPad)) {
app.DebugPrintf(
@ -519,9 +520,8 @@ bool SonyLeaderboardManager::setScore() {
// Start emptying queue if leaderboards has been closed.
if (ret == SCE_NP_COMMUNITY_ERROR_NOT_INITIALIZED) {
EnterCriticalSection(&m_csViewsLock);
std::lock_guard<std::mutex> lock(m_csViewsLock);
m_views.pop();
LeaveCriticalSection(&m_csViewsLock);
}
// Error handling.
@ -641,9 +641,10 @@ bool SonyLeaderboardManager::OpenSession() {
if (m_threadScoreboard == nullptr) {
m_threadScoreboard =
new C4JThread(&scoreboardThreadEntry, this, "4JScoreboard");
m_threadScoreboard->SetProcessor(CPU_CORE_LEADERBOARDS);
m_threadScoreboard->SetPriority(THREAD_PRIORITY_BELOW_NORMAL);
m_threadScoreboard->Run();
m_threadScoreboard->setProcessor(CPU_CORE_LEADERBOARDS);
m_threadScoreboard->setPriority(
C4JThread::ThreadPriority::BelowNormal);
m_threadScoreboard->run();
}
app.DebugPrintf(
@ -683,17 +684,19 @@ bool SonyLeaderboardManager::WriteStats(unsigned int viewCount, ViewIn views) {
// Write relevant parameters.
// RegisterScore *regScore = reinterpret_cast<RegisterScore *>(views);
EnterCriticalSection(&m_csViewsLock);
for (int i = 0; i < viewCount; i++) {
app.DebugPrintf(
"[SonyLeaderboardManager] WriteStats(), starting. difficulty=%i, "
"statsType=%i, score=%i\n",
views[i].m_difficulty, views[i].m_commentData.m_statsType,
views[i].m_score);
{
std::lock_guard<std::mutex> lock(m_csViewsLock);
for (int i = 0; i < viewCount; i++) {
app.DebugPrintf(
"[SonyLeaderboardManager] WriteStats(), starting. "
"difficulty=%i, "
"statsType=%i, score=%i\n",
views[i].m_difficulty, views[i].m_commentData.m_statsType,
views[i].m_score);
m_views.push(views[i]);
m_views.push(views[i]);
}
}
LeaveCriticalSection(&m_csViewsLock);
delete[] views; //*regScore;

View file

@ -1,4 +1,5 @@
#pragma once
#include <mutex>
#include "Common/Leaderboards/LeaderboardManager.h"
@ -40,7 +41,7 @@ protected:
std::queue<RegisterScore> m_views;
CRITICAL_SECTION m_csViewsLock;
std::mutex m_csViewsLock;
EStatsState m_eStatsState; // State of the stats read
// EFilterMode m_eFilterMode;

View file

@ -213,8 +213,8 @@ bool CGameNetworkManager::StartNetworkGame(Minecraft* minecraft,
new C4JThread(&CGameNetworkManager::ServerThreadProc, lpParameter,
"Server", 256 * 1024);
thread->SetProcessor(CPU_CORE_SERVER);
thread->Run();
thread->setProcessor(CPU_CORE_SERVER);
thread->run();
app.DebugPrintf("[NET] Waiting for server ready...\n");
ServerReadyWait();
@ -916,7 +916,7 @@ int CGameNetworkManager::ChangeSessionTypeThreadProc(void* lpParam) {
eXuiServerAction_PauseServer, (void*)true);
// wait for the server to be in a non-ticking state
pServer->m_serverPausedEvent->WaitForSignal(INFINITE);
pServer->m_serverPausedEvent->waitForSignal(C4JThread::kInfiniteTimeout);
pMinecraft->progressRenderer->progressStartNoAbort(
g_NetworkManager.CorrectErrorIDS(IDS_CONNECTION_LOST_LIVE_NO_EXIT));
@ -1495,7 +1495,7 @@ void CGameNetworkManager::ServerReadyCreate(bool create) {
void CGameNetworkManager::ServerReady() {
if (m_hServerReadyEvent != nullptr) {
m_hServerReadyEvent->Set();
m_hServerReadyEvent->set();
} else {
app.DebugPrintf(
"[NET] Warning: ServerReady() called but m_hServerReadyEvent is "
@ -1505,7 +1505,7 @@ void CGameNetworkManager::ServerReady() {
void CGameNetworkManager::ServerReadyWait() {
if (m_hServerReadyEvent != nullptr) {
m_hServerReadyEvent->WaitForSignal(INFINITE);
m_hServerReadyEvent->waitForSignal(C4JThread::kInfiniteTimeout);
} else {
app.DebugPrintf(
"[NET] Warning: ServerReadyWait() called but m_hServerReadyEvent "
@ -1528,7 +1528,7 @@ void CGameNetworkManager::ServerStoppedCreate(bool create) {
void CGameNetworkManager::ServerStopped() {
if (m_hServerStoppedEvent != nullptr) {
m_hServerStoppedEvent->Set();
m_hServerStoppedEvent->set();
} else {
app.DebugPrintf(
"[NET] Warning: ServerStopped() called but m_hServerStoppedEvent "
@ -1543,10 +1543,10 @@ void CGameNetworkManager::ServerStoppedWait() {
// it might be locked waiting for this to complete itself. Do some ticking
// here then if this is the case.
if (C4JThread::isMainThread()) {
int result = WAIT_TIMEOUT;
int result = C4JThread::WaitResult::Timeout;
do {
RenderManager.StartFrame();
result = m_hServerStoppedEvent->WaitForSignal(20);
result = m_hServerStoppedEvent->waitForSignal(20);
// Tick some simple things
ProfileManager.Tick();
StorageManager.Tick();
@ -1555,10 +1555,10 @@ void CGameNetworkManager::ServerStoppedWait() {
ui.tick();
ui.render();
RenderManager.Present();
} while (result == WAIT_TIMEOUT);
} while (result == C4JThread::WaitResult::Timeout);
} else {
if (m_hServerStoppedEvent != nullptr) {
m_hServerStoppedEvent->WaitForSignal(INFINITE);
m_hServerStoppedEvent->waitForSignal(C4JThread::kInfiniteTimeout);
} else {
app.DebugPrintf(
"[NET] Warning: ServerStoppedWait() called but "

View file

@ -330,7 +330,7 @@ int CPlatformNetworkManagerStub::RemovePlayerOnSocketClosedThreadProc(
if (socket != nullptr) {
// printf("Waiting for socket closed event\n");
socket->m_socketClosedEvent->WaitForSignal(INFINITE);
socket->m_socketClosedEvent->waitForSignal(C4JThread::kInfiniteTimeout);
// printf("Socket closed event has fired\n");
// 4J Stu - Clear our reference to this socket

View file

@ -5,6 +5,7 @@
#include "../../Minecraft.Client/Level/MultiPlayerLevel.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.level.dimension.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.level.storage.h"
#include <mutex>
UIComponent_Panorama::UIComponent_Panorama(int iPad, void* initData,
UILayer* parentLayer)
@ -42,25 +43,26 @@ void UIComponent_Panorama::tick() {
if (!hasMovie()) return;
Minecraft* pMinecraft = Minecraft::GetInstance();
EnterCriticalSection(&pMinecraft->m_setLevelCS);
if (pMinecraft->level != nullptr) {
int64_t i64TimeOfDay = 0;
// are we in the Nether? - Leave the time as 0 if we are, so we show
// daylight
if (pMinecraft->level->dimension->id == 0) {
i64TimeOfDay =
pMinecraft->level->getLevelData()->getGameTime() % 24000;
}
{
std::lock_guard<std::recursive_mutex> lock(pMinecraft->m_setLevelCS);
if (pMinecraft->level != nullptr) {
int64_t i64TimeOfDay = 0;
// are we in the Nether? - Leave the time as 0 if we are, so we show
// daylight
if (pMinecraft->level->dimension->id == 0) {
i64TimeOfDay =
pMinecraft->level->getLevelData()->getGameTime() % 24000;
}
if (i64TimeOfDay > 14000) {
setPanorama(false);
if (i64TimeOfDay > 14000) {
setPanorama(false);
} else {
setPanorama(true);
}
} else {
setPanorama(true);
}
} else {
setPanorama(true);
}
LeaveCriticalSection(&pMinecraft->m_setLevelCS);
UIScene::tick();
}

View file

@ -34,7 +34,7 @@
#endif
CRITICAL_SECTION UIController::ms_reloadSkinCS;
std::mutex UIController::ms_reloadSkinCS;
bool UIController::ms_bReloadSkinCSInitialised = false;
std::uint32_t UIController::m_dwTrialTimerLimitSecs =
@ -126,7 +126,7 @@ static void* RADLINK AllocateFunction(void* alloc_callback_user_data,
size_t size_requested,
size_t* size_returned) {
UIController* controller = (UIController*)alloc_callback_user_data;
EnterCriticalSection(&controller->m_Allocatorlock);
std::lock_guard<std::mutex> lock(controller->m_Allocatorlock);
#if defined(EXCLUDE_IGGY_ALLOCATIONS_FROM_HEAP_INSPECTOR)
void* alloc = __real_malloc(size_requested);
#else
@ -137,14 +137,13 @@ static void* RADLINK AllocateFunction(void* alloc_callback_user_data,
allocations[alloc] = size_requested;
app.DebugPrintf(app.USER_SR, "Allocating %d, new total: %d\n",
size_requested, UIController::iggyAllocCount);
LeaveCriticalSection(&controller->m_Allocatorlock);
return alloc;
}
static void RADLINK DeallocateFunction(void* alloc_callback_user_data,
void* ptr) {
UIController* controller = (UIController*)alloc_callback_user_data;
EnterCriticalSection(&controller->m_Allocatorlock);
std::lock_guard<std::mutex> lock(controller->m_Allocatorlock);
size_t size = allocations[ptr];
UIController::iggyAllocCount -= size;
allocations.erase(ptr);
@ -155,7 +154,6 @@ static void RADLINK DeallocateFunction(void* alloc_callback_user_data,
#else
free(ptr);
#endif
LeaveCriticalSection(&controller->m_Allocatorlock);
}
UIController::UIController() {
@ -174,7 +172,7 @@ UIController::UIController() {
m_eCurrentFont = m_eTargetFont = eFont_NotLoaded;
#if defined(ENABLE_IGGY_ALLOCATOR)
InitializeCriticalSection(&m_Allocatorlock);
// std::mutex is default-constructed, no initialization needed
#endif
// 4J Stu - This is a bit of a hack until we change the Minecraft
@ -215,15 +213,12 @@ UIController::UIController() {
m_accumulatedTicks = 0;
m_lastUiSfx = 0;
InitializeCriticalSection(&m_navigationLock);
InitializeCriticalSection(&m_registeredCallbackScenesCS);
// m_bSysUIShowing=false;
m_bSystemUIShowing = false;
if (!ms_bReloadSkinCSInitialised) {
// MGH - added to prevent crash loading Iggy movies while the skins were
// being reloaded
InitializeCriticalSection(&ms_reloadSkinCS);
ms_bReloadSkinCSInitialised = true;
}
}
@ -593,13 +588,13 @@ void UIController::ReloadSkin() {
m_reloadSkinThread =
new C4JThread(reloadSkinThreadProc, (void*)this, "Reload skin thread");
m_reloadSkinThread->SetProcessor(CPU_CORE_UI_SCENE);
m_reloadSkinThread->setProcessor(CPU_CORE_UI_SCENE);
// Navigate to the timer scene so that we can display something while the
// loading is happening
ui.NavigateToScene(0, eUIScene_Timer, (void*)1, eUILayer_Tooltips,
eUIGroup_Fullscreen);
// m_reloadSkinThread->Run();
// m_reloadSkinThread->run();
//// Load new skin
// loadSkins();
@ -616,31 +611,32 @@ void UIController::ReloadSkin() {
}
void UIController::StartReloadSkinThread() {
if (m_reloadSkinThread) m_reloadSkinThread->Run();
if (m_reloadSkinThread) m_reloadSkinThread->run();
}
int UIController::reloadSkinThreadProc(void* lpParam) {
EnterCriticalSection(
&ms_reloadSkinCS); // MGH - added to prevent crash loading Iggy movies
// while the skins were being reloaded
UIController* controller = (UIController*)lpParam;
// Load new skin
controller->loadSkins();
{
std::lock_guard<std::mutex> lock(
ms_reloadSkinCS); // MGH - added to prevent crash loading Iggy
// movies while the skins were being reloaded
UIController* controller = (UIController*)lpParam;
// Load new skin
controller->loadSkins();
// Reload all scene swf
for (int i = eUIGroup_Player1; i < eUIGroup_COUNT; ++i) {
controller->m_groups[i]->ReloadAll();
}
// Reload all scene swf
for (int i = eUIGroup_Player1; i < eUIGroup_COUNT; ++i) {
controller->m_groups[i]->ReloadAll();
}
// Always reload the fullscreen group
controller->m_groups[eUIGroup_Fullscreen]->ReloadAll();
// Always reload the fullscreen group
controller->m_groups[eUIGroup_Fullscreen]->ReloadAll();
// 4J Stu - Don't do this on windows, as we never navigated forwards to
// start with
// 4J Stu - Don't do this on windows, as we never navigated forwards to
// start with
#if !(defined(_WINDOWS64) || defined(__linux__))
controller->NavigateBack(0, false, eUIScene_COUNT, eUILayer_Tooltips);
controller->NavigateBack(0, false, eUIScene_COUNT, eUILayer_Tooltips);
#endif
LeaveCriticalSection(&ms_reloadSkinCS);
}
return 0;
}
@ -1252,13 +1248,15 @@ bool UIController::NavigateToScene(int iPad, EUIScene scene, void* initData,
PerformanceTimer timer;
EnterCriticalSection(&m_navigationLock);
SetMenuDisplayed(menuDisplayedPad, true);
bool success =
m_groups[(int)group]->NavigateToScene(iPad, scene, initData, layer);
if (success && group == eUIGroup_Fullscreen)
setFullscreenMenuDisplayed(true);
LeaveCriticalSection(&m_navigationLock);
bool success;
{
std::lock_guard<std::mutex> lock(m_navigationLock);
SetMenuDisplayed(menuDisplayedPad, true);
success =
m_groups[(int)group]->NavigateToScene(iPad, scene, initData, layer);
if (success && group == eUIGroup_Fullscreen)
setFullscreenMenuDisplayed(true);
}
timer.PrintElapsedTime(L"Navigate to scene");
@ -1376,24 +1374,22 @@ UIScene* UIController::GetTopScene(int iPad, EUILayer layer, EUIGroup group) {
}
size_t UIController::RegisterForCallbackId(UIScene* scene) {
EnterCriticalSection(&m_registeredCallbackScenesCS);
std::lock_guard<std::mutex> lock(m_registeredCallbackScenesCS);
size_t newId = GetTickCount();
newId &= 0xFFFFFF; // Chop off the top byte, we don't need any more
// accuracy than that
newId |= (scene->getSceneType()
<< 24); // Add in the scene's type to help keep this unique
m_registeredCallbackScenes[newId] = scene;
LeaveCriticalSection(&m_registeredCallbackScenesCS);
return newId;
}
void UIController::UnregisterCallbackId(size_t id) {
EnterCriticalSection(&m_registeredCallbackScenesCS);
std::lock_guard<std::mutex> lock(m_registeredCallbackScenesCS);
auto it = m_registeredCallbackScenes.find(id);
if (it != m_registeredCallbackScenes.end()) {
m_registeredCallbackScenes.erase(it);
}
LeaveCriticalSection(&m_registeredCallbackScenesCS);
}
UIScene* UIController::GetSceneFromCallbackId(size_t id) {
@ -1405,12 +1401,10 @@ UIScene* UIController::GetSceneFromCallbackId(size_t id) {
return scene;
}
void UIController::EnterCallbackIdCriticalSection() {
EnterCriticalSection(&m_registeredCallbackScenesCS);
}
void UIController::lockCallbackScenes() { m_registeredCallbackScenesCS.lock(); }
void UIController::LeaveCallbackIdCriticalSection() {
LeaveCriticalSection(&m_registeredCallbackScenesCS);
void UIController::unlockCallbackScenes() {
m_registeredCallbackScenesCS.unlock();
}
void UIController::CloseAllPlayersScenes() {

View file

@ -1,6 +1,7 @@
#pragma once
// using namespace std;
#include <cstdint>
#include <mutex>
#include "IUIController.h"
#include "UIEnums.h"
@ -20,7 +21,7 @@ public:
// MGH - added to prevent crash loading Iggy movies while the skins were
// being reloaded
static CRITICAL_SECTION ms_reloadSkinCS;
static std::mutex ms_reloadSkinCS;
static bool ms_bReloadSkinCSInitialised;
protected:
@ -28,7 +29,7 @@ protected:
UIComponent_DebugUIMarketingGuide* m_uiDebugMarketingGuide;
private:
CRITICAL_SECTION m_navigationLock;
std::mutex m_navigationLock;
static const int UI_REPEAT_KEY_DELAY_MS =
300; // How long from press until the first repeat
@ -165,7 +166,7 @@ private:
// that are used in async callbacks so we
// can safely handle when they get
// destroyed
CRITICAL_SECTION m_registeredCallbackScenesCS;
std::mutex m_registeredCallbackScenesCS;
;
public:
@ -190,7 +191,7 @@ protected:
void postInit();
public:
CRITICAL_SECTION m_Allocatorlock;
std::mutex m_Allocatorlock;
void SetupFont();
bool PendingFontChange();
bool UsingBitmapFont();
@ -311,8 +312,8 @@ public:
size_t RegisterForCallbackId(UIScene* scene);
void UnregisterCallbackId(size_t id);
UIScene* GetSceneFromCallbackId(size_t id);
void EnterCallbackIdCriticalSection();
void LeaveCallbackIdCriticalSection();
void lockCallbackScenes();
void unlockCallbackScenes();
private:
void setFullscreenMenuDisplayed(bool displayed);

View file

@ -1,4 +1,5 @@
#include "../../Minecraft.World/Platform/stdafx.h"
#include <mutex>
#include "UI.h"
#include "UIScene.h"
@ -243,12 +244,11 @@ bool UIScene::mapElementsAndNames() {
return true;
}
extern CRITICAL_SECTION s_loadSkinCS;
extern std::mutex s_loadSkinCS;
void UIScene::loadMovie() {
EnterCriticalSection(
&UIController::ms_reloadSkinCS); // MGH - added to prevent crash
// loading Iggy movies while the skins
// were being reloaded
UIController::ms_reloadSkinCS.lock(); // MGH - added to prevent crash
// loading Iggy movies while the
// skins were being reloaded
std::wstring moviePath = getMoviePath();
#if defined(_WINDOWS64)
@ -318,7 +318,7 @@ void UIScene::loadMovie() {
IggyPlayerSetUserdata(swf, this);
// #ifdef _DEBUG
LeaveCriticalSection(&UIController::ms_reloadSkinCS);
UIController::ms_reloadSkinCS.unlock();
}
void UIScene::getDebugMemoryUseRecursive(const std::wstring& moviePath,

View file

@ -63,11 +63,11 @@ UIScene_FullscreenProgress::UIScene_FullscreenProgress(int iPad, void* initData,
m_labelTip.setVisible(m_CompletionData->bShowTips);
thread = new C4JThread(params->func, params->lpParam, "FullscreenProgress");
thread->SetProcessor(CPU_CORE_UI_SCENE); // TODO 4J Stu - Make sure this is
thread->setProcessor(CPU_CORE_UI_SCENE); // TODO 4J Stu - Make sure this is
// a good thread/core to use
m_threadCompleted = false;
thread->Run();
thread->run();
threadStarted = true;
}
@ -92,12 +92,12 @@ void UIScene_FullscreenProgress::updateTooltips() {
}
void UIScene_FullscreenProgress::handleDestroy() {
int code = thread->GetExitCode();
int code = thread->getExitCode();
const unsigned int exitcode = static_cast<unsigned int>(code);
// If we're active, have a cancel func, and haven't already cancelled, call
// cancel func
if (exitcode == STILL_ACTIVE && m_cancelFunc != nullptr &&
if (exitcode == C4JThread::kStillActive && m_cancelFunc != nullptr &&
!m_bWasCancelled) {
m_bWasCancelled = true;
m_cancelFunc(m_cancelFuncParam);
@ -140,12 +140,12 @@ void UIScene_FullscreenProgress::tick() {
m_progressBar.setLabel(wstrText.c_str());
}
int code = thread->GetExitCode();
int code = thread->getExitCode();
uint32_t exitcode = *((uint32_t*)&code);
// app.DebugPrintf("CScene_FullscreenProgress Timer %d\n",pTimer->nId);
if (exitcode != STILL_ACTIVE) {
if (exitcode != C4JThread::kStillActive) {
// If we failed (currently used by network connection thread), navigate
// back
if (exitcode != S_OK) {

View file

@ -95,7 +95,7 @@ UIScene_InGameSaveManagementMenu::~UIScene_InGameSaveManagementMenu() {
}
delete[] m_saveDetails;
}
app.LeaveSaveNotificationSection();
app.unlockSaveNotification();
StorageManager.SetSaveDisabled(false);
StorageManager.ContinueIncompleteOperation();
}

View file

@ -1442,7 +1442,7 @@ int UIScene_LoadOrJoinMenu::DeleteSaveDialogReturned(
}
int UIScene_LoadOrJoinMenu::DeleteSaveDataReturned(void* lpParam, bool bRes) {
ui.EnterCallbackIdCriticalSection();
ui.lockCallbackScenes();
UIScene_LoadOrJoinMenu* pClass =
(UIScene_LoadOrJoinMenu*)ui.GetSceneFromCallbackId((size_t)lpParam);
@ -1455,7 +1455,7 @@ int UIScene_LoadOrJoinMenu::DeleteSaveDataReturned(void* lpParam, bool bRes) {
pClass->updateTooltips();
}
ui.LeaveCallbackIdCriticalSection();
ui.unlockCallbackScenes();
return 0;
}

View file

@ -115,7 +115,7 @@ void CConsoleMinecraftApp::TemporaryCreateGameStart() {
C4JThread* thread = new C4JThread(loadingParams->func,
loadingParams->lpParam, "RunNetworkGame");
thread->Run();
thread->run();
}
int CConsoleMinecraftApp::GetLocalTMSFileIndex(wchar_t* wchTMSFile,

View file

@ -4,6 +4,7 @@
#include "../../../Minecraft.World/Platform/stdafx.h"
#include <assert.h>
#include <mutex>
// #include <system_service.h>
#if defined(__linux__) && defined(__GLIBC__)
#include <signal.h>
@ -1042,7 +1043,7 @@ bool trackStarted = false;
volatile size_t sizeCheckMin = 1160;
volatile size_t sizeCheckMax = 1160;
volatile int sectCheck = 48;
CRITICAL_SECTION memCS;
std::mutex memCS;
uint32_t tlsIdx;
void* XMemAlloc(size_t dwSize, uint32_t dwAllocAttributes) {
@ -1053,33 +1054,34 @@ void* XMemAlloc(size_t dwSize, uint32_t dwAllocAttributes) {
return p;
}
EnterCriticalSection(&memCS);
void* p;
{
std::lock_guard<std::mutex> lock(memCS);
void* p = XMemAllocDefault(dwSize + 16, dwAllocAttributes);
size_t realSize = XMemSizeDefault(p, dwAllocAttributes) - 16;
p = XMemAllocDefault(dwSize + 16, dwAllocAttributes);
size_t realSize = XMemSizeDefault(p, dwAllocAttributes) - 16;
if (trackEnable) {
int sect = ((int)TlsGetValue(tlsIdx)) & 0x3f;
*(((unsigned char*)p) + realSize) = sect;
if (trackEnable) {
int sect = ((int)TlsGetValue(tlsIdx)) & 0x3f;
*(((unsigned char*)p) + realSize) = sect;
if ((realSize >= sizeCheckMin) && (realSize <= sizeCheckMax) &&
((sect == sectCheck) || (sectCheck == -1))) {
app.DebugPrintf("Found one\n");
}
if ((realSize >= sizeCheckMin) && (realSize <= sizeCheckMax) &&
((sect == sectCheck) || (sectCheck == -1))) {
app.DebugPrintf("Found one\n");
}
if (p) {
totalAllocGen += realSize;
trackEnable = false;
int key = (sect << 26) | realSize;
int oldCount = allocCounts[key];
allocCounts[key] = oldCount + 1;
if (p) {
totalAllocGen += realSize;
trackEnable = false;
int key = (sect << 26) | realSize;
int oldCount = allocCounts[key];
allocCounts[key] = oldCount + 1;
trackEnable = true;
trackEnable = true;
}
}
}
LeaveCriticalSection(&memCS);
return p;
}
@ -1110,22 +1112,23 @@ void WINAPI XMemFree(void* pAddress, uint32_t dwAllocAttributes) {
totalAllocGen -= realSize;
return;
}
EnterCriticalSection(&memCS);
if (pAddress) {
size_t realSize = XMemSizeDefault(pAddress, dwAllocAttributes) - 16;
{
std::lock_guard<std::mutex> lock(memCS);
if (pAddress) {
size_t realSize = XMemSizeDefault(pAddress, dwAllocAttributes) - 16;
if (trackEnable) {
int sect = *(((unsigned char*)pAddress) + realSize);
totalAllocGen -= realSize;
trackEnable = false;
int key = (sect << 26) | realSize;
int oldCount = allocCounts[key];
allocCounts[key] = oldCount - 1;
trackEnable = true;
if (trackEnable) {
int sect = *(((unsigned char*)pAddress) + realSize);
totalAllocGen -= realSize;
trackEnable = false;
int key = (sect << 26) | realSize;
int oldCount = allocCounts[key];
allocCounts[key] = oldCount - 1;
trackEnable = true;
}
XMemFreeDefault(pAddress, dwAllocAttributes);
}
XMemFreeDefault(pAddress, dwAllocAttributes);
}
LeaveCriticalSection(&memCS);
}
size_t WINAPI XMemSize(void* pAddress, uint32_t dwAllocAttributes) {
@ -1154,14 +1157,14 @@ void ResetMem() {
trackEnable = true;
trackStarted = true;
totalAllocGen = 0;
InitializeCriticalSection(&memCS);
tlsIdx = TlsAlloc();
}
EnterCriticalSection(&memCS);
trackEnable = false;
allocCounts.clear();
trackEnable = true;
LeaveCriticalSection(&memCS);
{
std::lock_guard<std::mutex> lock(memCS);
trackEnable = false;
allocCounts.clear();
trackEnable = true;
}
}
void MemSect(int section) {

View file

@ -249,46 +249,6 @@ typedef HINSTANCE HMODULE;
#define E_ABORT _HRESULT_TYPEDEF_(0x80004004L)
#define E_NOINTERFACE _HRESULT_TYPEDEF_(0x80004002L)
typedef pthread_mutex_t RTL_CRITICAL_SECTION;
typedef pthread_mutex_t* PRTL_CRITICAL_SECTION;
typedef RTL_CRITICAL_SECTION CRITICAL_SECTION;
typedef PRTL_CRITICAL_SECTION PCRITICAL_SECTION;
typedef PRTL_CRITICAL_SECTION LPCRITICAL_SECTION;
static inline void InitializeCriticalSection(
PRTL_CRITICAL_SECTION CriticalSection) {
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(CriticalSection, &attr);
pthread_mutexattr_destroy(&attr);
}
static inline void InitializeCriticalSectionAndSpinCount(
PRTL_CRITICAL_SECTION CriticalSection, ULONG SpinCount) {
// no spin count required because we use a recursive mutex
InitializeCriticalSection(CriticalSection);
}
static inline void DeleteCriticalSection(
PRTL_CRITICAL_SECTION CriticalSection) {
pthread_mutex_destroy(CriticalSection);
}
static inline void EnterCriticalSection(PRTL_CRITICAL_SECTION CriticalSection) {
pthread_mutex_lock(CriticalSection);
}
static inline void LeaveCriticalSection(PRTL_CRITICAL_SECTION CriticalSection) {
pthread_mutex_unlock(CriticalSection);
}
static inline ULONG TryEnterCriticalSection(
PRTL_CRITICAL_SECTION CriticalSection) {
return pthread_mutex_trylock(CriticalSection) == 0;
}
// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-globalmemorystatus
static inline void GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer) {
// TODO: Parse /proc/meminfo and set lpBuffer based on that. Probably will

View file

@ -108,7 +108,7 @@ void CConsoleMinecraftApp::TemporaryCreateGameStart() {
C4JThread* thread = new C4JThread(loadingParams->func,
loadingParams->lpParam, "RunNetworkGame");
thread->Run();
thread->run();
}
int CConsoleMinecraftApp::GetLocalTMSFileIndex(wchar_t* wchTMSFile,

View file

@ -4,6 +4,7 @@
#include "../../../Minecraft.World/Platform/stdafx.h"
#include <assert.h>
#include <mutex>
#include "GameConfig/Minecraft.spa.h"
#include "../../MinecraftServer.h"
#include "../../Player/LocalPlayer.h"
@ -930,7 +931,7 @@ bool trackStarted = false;
volatile size_t sizeCheckMin = 1160;
volatile size_t sizeCheckMax = 1160;
volatile int sectCheck = 48;
CRITICAL_SECTION memCS;
std::mutex memCS;
uint32_t tlsIdx;
void* XMemAlloc(size_t dwSize, uint32_t dwAllocAttributes) {
@ -941,33 +942,34 @@ void* XMemAlloc(size_t dwSize, uint32_t dwAllocAttributes) {
return p;
}
EnterCriticalSection(&memCS);
void* p;
{
std::lock_guard<std::mutex> lock(memCS);
void* p = XMemAllocDefault(dwSize + 16, dwAllocAttributes);
size_t realSize = XMemSizeDefault(p, dwAllocAttributes) - 16;
p = XMemAllocDefault(dwSize + 16, dwAllocAttributes);
size_t realSize = XMemSizeDefault(p, dwAllocAttributes) - 16;
if (trackEnable) {
int sect = ((int)TlsGetValue(tlsIdx)) & 0x3f;
*(((unsigned char*)p) + realSize) = sect;
if (trackEnable) {
int sect = ((int)TlsGetValue(tlsIdx)) & 0x3f;
*(((unsigned char*)p) + realSize) = sect;
if ((realSize >= sizeCheckMin) && (realSize <= sizeCheckMax) &&
((sect == sectCheck) || (sectCheck == -1))) {
app.DebugPrintf("Found one\n");
}
if ((realSize >= sizeCheckMin) && (realSize <= sizeCheckMax) &&
((sect == sectCheck) || (sectCheck == -1))) {
app.DebugPrintf("Found one\n");
}
if (p) {
totalAllocGen += realSize;
trackEnable = false;
int key = (sect << 26) | realSize;
int oldCount = allocCounts[key];
allocCounts[key] = oldCount + 1;
if (p) {
totalAllocGen += realSize;
trackEnable = false;
int key = (sect << 26) | realSize;
int oldCount = allocCounts[key];
allocCounts[key] = oldCount + 1;
trackEnable = true;
trackEnable = true;
}
}
}
LeaveCriticalSection(&memCS);
return p;
}
@ -998,22 +1000,23 @@ void WINAPI XMemFree(void* pAddress, uint32_t dwAllocAttributes) {
totalAllocGen -= realSize;
return;
}
EnterCriticalSection(&memCS);
if (pAddress) {
size_t realSize = XMemSizeDefault(pAddress, dwAllocAttributes) - 16;
{
std::lock_guard<std::mutex> lock(memCS);
if (pAddress) {
size_t realSize = XMemSizeDefault(pAddress, dwAllocAttributes) - 16;
if (trackEnable) {
int sect = *(((unsigned char*)pAddress) + realSize);
totalAllocGen -= realSize;
trackEnable = false;
int key = (sect << 26) | realSize;
int oldCount = allocCounts[key];
allocCounts[key] = oldCount - 1;
trackEnable = true;
if (trackEnable) {
int sect = *(((unsigned char*)pAddress) + realSize);
totalAllocGen -= realSize;
trackEnable = false;
int key = (sect << 26) | realSize;
int oldCount = allocCounts[key];
allocCounts[key] = oldCount - 1;
trackEnable = true;
}
XMemFreeDefault(pAddress, dwAllocAttributes);
}
XMemFreeDefault(pAddress, dwAllocAttributes);
}
LeaveCriticalSection(&memCS);
}
size_t WINAPI XMemSize(void* pAddress, uint32_t dwAllocAttributes) {
@ -1042,14 +1045,14 @@ void ResetMem() {
trackEnable = true;
trackStarted = true;
totalAllocGen = 0;
InitializeCriticalSection(&memCS);
tlsIdx = TlsAlloc();
}
EnterCriticalSection(&memCS);
trackEnable = false;
allocCounts.clear();
trackEnable = true;
LeaveCriticalSection(&memCS);
{
std::lock_guard<std::mutex> lock(memCS);
trackEnable = false;
allocCounts.clear();
trackEnable = true;
}
}
void MemSect(int section) {

View file

@ -9,6 +9,7 @@
#include "LevelRenderer.h"
#include "../Utils/FrameProfiler.h"
#include <unordered_set>
#include <mutex>
int Chunk::updates = 0;
@ -92,8 +93,8 @@ void Chunk::reconcileRenderableTileEntities(
// TODO - 4J see how input entity vector is set up and decide what way is best
// to pass this to the function
Chunk::Chunk(Level* level, LevelRenderer::rteMap& globalRenderableTileEntities,
CRITICAL_SECTION& globalRenderableTileEntities_cs, int x, int y,
int z, ClipChunk* clipChunk)
std::mutex& globalRenderableTileEntities_cs, int x, int y, int z,
ClipChunk* clipChunk)
: globalRenderableTileEntities(&globalRenderableTileEntities),
globalRenderableTileEntities_cs(&globalRenderableTileEntities_cs) {
clipChunk->visible = false;
@ -149,31 +150,33 @@ void Chunk::setPos(int x, int y, int z) {
assigned = true;
EnterCriticalSection(&levelRenderer->m_csDirtyChunks);
unsigned char refCount =
levelRenderer->incGlobalChunkRefCount(x, y, z, level);
// printf("\t\t [inc] refcount %d at %d, %d, %d\n",refCount,x,y,z);
{
std::lock_guard<std::recursive_mutex> lock(
levelRenderer->m_csDirtyChunks);
unsigned char refCount =
levelRenderer->incGlobalChunkRefCount(x, y, z, level);
// printf("\t\t [inc] refcount %d at %d, %d, %d\n",refCount,x,y,z);
// int idx = levelRenderer->getGlobalIndexForChunk(x, y, z, level);
// int idx = levelRenderer->getGlobalIndexForChunk(x, y, z, level);
// If we're the first thing to be referencing this, mark it up as dirty to
// get rebuilt
if (refCount == 1) {
// printf("Setting %d %d %d dirty [%d]\n",x,y,z, idx);
// Chunks being made dirty in this way can be very numerous (eg the full
// visible area of the world at start up, or a whole edge of the world
// when moving). On account of this, don't want to stick them into our
// lock free queue that we would normally use for letting the render
// update thread know about this chunk. Instead, just set the flag to
// say this is dirty, and then pass a special value of 1 through to the
// lock free stack which lets that thread know that at least one chunk
// other than the ones in the stack itself have been made dirty.
levelRenderer->setGlobalChunkFlag(x, y, z, level,
LevelRenderer::CHUNK_FLAG_DIRTY);
PIXSetMarkerDeprecated(0, "Non-stack event pushed");
// If we're the first thing to be referencing this, mark it up as dirty
// to get rebuilt
if (refCount == 1) {
// printf("Setting %d %d %d dirty [%d]\n",x,y,z, idx);
// Chunks being made dirty in this way can be very numerous (eg the
// full visible area of the world at start up, or a whole edge of
// the world when moving). On account of this, don't want to stick
// them into our lock free queue that we would normally use for
// letting the render update thread know about this chunk. Instead,
// just set the flag to say this is dirty, and then pass a special
// value of 1 through to the lock free stack which lets that thread
// know that at least one chunk other than the ones in the stack
// itself have been made dirty.
levelRenderer->setGlobalChunkFlag(x, y, z, level,
LevelRenderer::CHUNK_FLAG_DIRTY);
PIXSetMarkerDeprecated(0, "Non-stack event pushed");
}
}
LeaveCriticalSection(&levelRenderer->m_csDirtyChunks);
}
void Chunk::translateToPos() {
@ -543,9 +546,10 @@ void Chunk::rebuild() {
// globally in the levelrenderer, in a hashmap with a special key made up
// from the dimension and chunk position (using same index as is used for
// global flags)
EnterCriticalSection(globalRenderableTileEntities_cs);
reconcileRenderableTileEntities(renderableTileEntities);
LeaveCriticalSection(globalRenderableTileEntities_cs);
{
std::lock_guard<std::mutex> lock(*globalRenderableTileEntities_cs);
reconcileRenderableTileEntities(renderableTileEntities);
}
PIXEndNamedEvent();
// 4J - These removed items are now also removed from
@ -719,27 +723,29 @@ void Chunk::reset() {
int oldKey = -1;
bool retireRenderableTileEntities = false;
EnterCriticalSection(&levelRenderer->m_csDirtyChunks);
oldKey = levelRenderer->getGlobalIndexForChunk(x, y, z, level);
unsigned char refCount =
levelRenderer->decGlobalChunkRefCount(x, y, z, level);
assigned = false;
// printf("\t\t [dec] refcount %d at %d, %d,
//%d\n",refCount,x,y,z);
if (refCount == 0 && oldKey != -1) {
retireRenderableTileEntities = true;
int lists = oldKey * 2;
if (lists >= 0) {
lists += levelRenderer->chunkLists;
for (int i = 0; i < 2; i++) {
// 4J - added - clear any renderer data associated with this
// unused list
RenderManager.CBuffClear(lists + i);
{
std::lock_guard<std::recursive_mutex> lock(
levelRenderer->m_csDirtyChunks);
oldKey = levelRenderer->getGlobalIndexForChunk(x, y, z, level);
unsigned char refCount =
levelRenderer->decGlobalChunkRefCount(x, y, z, level);
assigned = false;
// printf("\t\t [dec] refcount %d at %d, %d,
//%d\n",refCount,x,y,z);
if (refCount == 0 && oldKey != -1) {
retireRenderableTileEntities = true;
int lists = oldKey * 2;
if (lists >= 0) {
lists += levelRenderer->chunkLists;
for (int i = 0; i < 2; i++) {
// 4J - added - clear any renderer data associated with
// this unused list
RenderManager.CBuffClear(lists + i);
}
levelRenderer->setGlobalChunkFlags(x, y, z, level, 0);
}
levelRenderer->setGlobalChunkFlags(x, y, z, level, 0);
}
}
LeaveCriticalSection(&levelRenderer->m_csDirtyChunks);
if (retireRenderableTileEntities) {
levelRenderer->retireRenderableTileEntitiesForChunkKey(oldKey);

View file

@ -56,13 +56,13 @@ public:
private:
LevelRenderer::rteMap* globalRenderableTileEntities;
CRITICAL_SECTION* globalRenderableTileEntities_cs;
std::mutex* globalRenderableTileEntities_cs;
bool assigned;
public:
Chunk(Level* level, LevelRenderer::rteMap& globalRenderableTileEntities,
CRITICAL_SECTION& globalRenderableTileEntities_cs, int x, int y,
int z, ClipChunk* clipChunk);
std::mutex& globalRenderableTileEntities_cs, int x, int y, int z,
ClipChunk* clipChunk);
Chunk();
void setPos(int x, int y, int z);

View file

@ -4,7 +4,7 @@
#include "ProgressRenderer.h"
#include "../../../Minecraft.World/Platform/System.h"
CRITICAL_SECTION ProgressRenderer::s_progress;
std::recursive_mutex ProgressRenderer::s_progress;
ProgressRenderer::ProgressRenderer(Minecraft* minecraft) {
status = -1;
@ -33,10 +33,12 @@ void ProgressRenderer::_progressStart(int title) {
// throw new StopGameException(); // 4J - removed
}
EnterCriticalSection(&ProgressRenderer::s_progress);
lastPercent = 0;
this->title = title;
LeaveCriticalSection(&ProgressRenderer::s_progress);
{
std::lock_guard<std::recursive_mutex> lock(
ProgressRenderer::s_progress);
lastPercent = 0;
this->title = title;
}
}
void ProgressRenderer::progressStage(int status) {
@ -46,10 +48,12 @@ void ProgressRenderer::progressStage(int status) {
}
lastTime = 0;
EnterCriticalSection(&ProgressRenderer::s_progress);
setType(eProgressStringType_ID);
this->status = status;
LeaveCriticalSection(&ProgressRenderer::s_progress);
{
std::lock_guard<std::recursive_mutex> lock(
ProgressRenderer::s_progress);
m_eType = eProgressStringType_ID;
this->status = status;
}
progressStagePercentage(-1);
lastTime = 0;
}
@ -57,56 +61,66 @@ void ProgressRenderer::progressStage(int status) {
void ProgressRenderer::progressStagePercentage(int i) {
// 4J Stu - Removing all progressRenderer rendering. This will be replaced
// on the xbox
EnterCriticalSection(&ProgressRenderer::s_progress);
lastPercent = i;
LeaveCriticalSection(&ProgressRenderer::s_progress);
{
std::lock_guard<std::recursive_mutex> lock(
ProgressRenderer::s_progress);
lastPercent = i;
}
}
int ProgressRenderer::getCurrentPercent() {
int returnValue = 0;
EnterCriticalSection(&ProgressRenderer::s_progress);
returnValue = lastPercent;
LeaveCriticalSection(&ProgressRenderer::s_progress);
{
std::lock_guard<std::recursive_mutex> lock(
ProgressRenderer::s_progress);
returnValue = lastPercent;
}
return returnValue;
}
int ProgressRenderer::getCurrentTitle() {
EnterCriticalSection(&ProgressRenderer::s_progress);
int returnValue = title;
LeaveCriticalSection(&ProgressRenderer::s_progress);
int returnValue;
{
std::lock_guard<std::recursive_mutex> lock(
ProgressRenderer::s_progress);
returnValue = title;
}
return returnValue;
}
int ProgressRenderer::getCurrentStatus() {
EnterCriticalSection(&ProgressRenderer::s_progress);
int returnValue = status;
LeaveCriticalSection(&ProgressRenderer::s_progress);
int returnValue;
{
std::lock_guard<std::recursive_mutex> lock(
ProgressRenderer::s_progress);
returnValue = status;
}
return returnValue;
}
ProgressRenderer::eProgressStringType ProgressRenderer::getType() {
EnterCriticalSection(&ProgressRenderer::s_progress);
eProgressStringType returnValue = m_eType;
LeaveCriticalSection(&ProgressRenderer::s_progress);
eProgressStringType returnValue;
{
std::lock_guard<std::recursive_mutex> lock(
ProgressRenderer::s_progress);
returnValue = m_eType;
}
return returnValue;
}
void ProgressRenderer::setType(eProgressStringType eType) {
EnterCriticalSection(&ProgressRenderer::s_progress);
std::lock_guard<std::recursive_mutex> lock(ProgressRenderer::s_progress);
m_eType = eType;
LeaveCriticalSection(&ProgressRenderer::s_progress);
}
void ProgressRenderer::progressStage(std::wstring& wstrText) {
EnterCriticalSection(&ProgressRenderer::s_progress);
std::lock_guard<std::recursive_mutex> lock(ProgressRenderer::s_progress);
m_wstrText = wstrText;
setType(eProgressStringType_String);
LeaveCriticalSection(&ProgressRenderer::s_progress);
m_eType = eProgressStringType_String;
}
std::wstring& ProgressRenderer::getProgressString(void) {
EnterCriticalSection(&ProgressRenderer::s_progress);
std::lock_guard<std::recursive_mutex> lock(ProgressRenderer::s_progress);
std::wstring& temp = m_wstrText;
LeaveCriticalSection(&ProgressRenderer::s_progress);
return temp;
}

View file

@ -1,4 +1,5 @@
#pragma once
#include <mutex>
#include "../../../Minecraft.World/Util/ProgressListener.h"
class ProgressRenderer : public ProgressListener {
@ -9,7 +10,7 @@ public:
// on a save transfer
};
static CRITICAL_SECTION s_progress;
static std::recursive_mutex s_progress;
int getCurrentPercent();
int getCurrentTitle();

View file

@ -66,7 +66,7 @@ std::vector<CompressedTileStorage*>
GameRenderer::m_deleteStackCompressedTileStorage;
std::vector<SparseDataStorage*> GameRenderer::m_deleteStackSparseDataStorage;
#endif
CRITICAL_SECTION GameRenderer::m_csDeleteStack;
std::mutex GameRenderer::m_csDeleteStack;
ResourceLocation GameRenderer::RAIN_LOCATION =
ResourceLocation(TN_ENVIRONMENT_RAIN);
@ -167,13 +167,12 @@ GameRenderer::GameRenderer(Minecraft* mc) {
#if defined(MULTITHREAD_ENABLE)
m_updateEvents = new C4JThread::EventArray(
eUpdateEventCount, C4JThread::EventArray::e_modeAutoClear);
m_updateEvents->Set(eUpdateEventIsFinished);
eUpdateEventCount, C4JThread::EventArray::Mode::AutoClear);
m_updateEvents->set(eUpdateEventIsFinished);
InitializeCriticalSection(&m_csDeleteStack);
m_updateThread = new C4JThread(runUpdate, nullptr, "Chunk update");
m_updateThread->SetProcessor(CPU_CORE_CHUNK_UPDATE);
m_updateThread->Run();
m_updateThread->setProcessor(CPU_CORE_CHUNK_UPDATE);
m_updateThread->run();
#endif
}
@ -1044,28 +1043,26 @@ void GameRenderer::renderLevel(float a) { renderLevel(a, 0); }
#if defined(MULTITHREAD_ENABLE)
// Request that an item be deleted, when it is safe to do so
void GameRenderer::AddForDelete(uint8_t* deleteThis) {
EnterCriticalSection(&m_csDeleteStack);
m_csDeleteStack.lock();
m_deleteStackByte.push_back(deleteThis);
}
void GameRenderer::AddForDelete(SparseLightStorage* deleteThis) {
EnterCriticalSection(&m_csDeleteStack);
m_csDeleteStack.lock();
m_deleteStackSparseLightStorage.push_back(deleteThis);
}
void GameRenderer::AddForDelete(CompressedTileStorage* deleteThis) {
EnterCriticalSection(&m_csDeleteStack);
m_csDeleteStack.lock();
m_deleteStackCompressedTileStorage.push_back(deleteThis);
}
void GameRenderer::AddForDelete(SparseDataStorage* deleteThis) {
EnterCriticalSection(&m_csDeleteStack);
m_csDeleteStack.lock();
m_deleteStackSparseDataStorage.push_back(deleteThis);
}
void GameRenderer::FinishedReassigning() {
LeaveCriticalSection(&m_csDeleteStack);
}
void GameRenderer::FinishedReassigning() { m_csDeleteStack.unlock(); }
int GameRenderer::runUpdate(void* lpParam) {
Minecraft* minecraft = Minecraft::GetInstance();
@ -1081,17 +1078,17 @@ int GameRenderer::runUpdate(void* lpParam) {
m_updateEvents);
while (
ShutdownManager::ShouldRun(ShutdownManager::eRenderChunkUpdateThread)) {
// m_updateEvents->Clear(eUpdateEventIsFinished);
// m_updateEvents->WaitForSingle(eUpdateCanRun,INFINITE);
// m_updateEvents->clear(eUpdateEventIsFinished);
// m_updateEvents->waitForSingle(eUpdateCanRun,C4JThread::kInfiniteTimeout);
// 4J Stu - We Need to have this happen atomically to avoid deadlocks
m_updateEvents->WaitForAll(INFINITE);
m_updateEvents->waitForAll(C4JThread::kInfiniteTimeout);
if (!ShutdownManager::ShouldRun(
ShutdownManager::eRenderChunkUpdateThread)) {
break;
}
m_updateEvents->Set(eUpdateCanRun);
m_updateEvents->set(eUpdateCanRun);
// PIXBeginNamedEvent(0,"Updating dirty chunks
//%d",(count++)&7);
@ -1123,26 +1120,28 @@ int GameRenderer::runUpdate(void* lpParam) {
// We've got stacks for things that can only safely be deleted whilst
// this thread isn't updating things - delete those things now
EnterCriticalSection(&m_csDeleteStack);
for (unsigned int i = 0; i < m_deleteStackByte.size(); i++)
delete m_deleteStackByte[i];
m_deleteStackByte.clear();
for (unsigned int i = 0; i < m_deleteStackSparseLightStorage.size();
i++)
delete m_deleteStackSparseLightStorage[i];
m_deleteStackSparseLightStorage.clear();
for (unsigned int i = 0; i < m_deleteStackCompressedTileStorage.size();
i++)
delete m_deleteStackCompressedTileStorage[i];
m_deleteStackCompressedTileStorage.clear();
for (unsigned int i = 0; i < m_deleteStackSparseDataStorage.size(); i++)
delete m_deleteStackSparseDataStorage[i];
m_deleteStackSparseDataStorage.clear();
LeaveCriticalSection(&m_csDeleteStack);
{
std::lock_guard<std::mutex> lock(m_csDeleteStack);
for (unsigned int i = 0; i < m_deleteStackByte.size(); i++)
delete m_deleteStackByte[i];
m_deleteStackByte.clear();
for (unsigned int i = 0; i < m_deleteStackSparseLightStorage.size();
i++)
delete m_deleteStackSparseLightStorage[i];
m_deleteStackSparseLightStorage.clear();
for (unsigned int i = 0;
i < m_deleteStackCompressedTileStorage.size(); i++)
delete m_deleteStackCompressedTileStorage[i];
m_deleteStackCompressedTileStorage.clear();
for (unsigned int i = 0; i < m_deleteStackSparseDataStorage.size();
i++)
delete m_deleteStackSparseDataStorage[i];
m_deleteStackSparseDataStorage.clear();
}
// PIXEndNamedEvent();
m_updateEvents->Set(eUpdateEventIsFinished);
m_updateEvents->set(eUpdateEventIsFinished);
}
ShutdownManager::HasFinished(ShutdownManager::eRenderChunkUpdateThread);
@ -1159,8 +1158,8 @@ void GameRenderer::EnableUpdateThread() {
app.DebugPrintf(
"------------------EnableUpdateThread--------------------\n");
updateRunning = true;
m_updateEvents->Set(eUpdateCanRun);
m_updateEvents->Set(eUpdateEventIsFinished);
m_updateEvents->set(eUpdateCanRun);
m_updateEvents->set(eUpdateEventIsFinished);
#endif
}
@ -1173,8 +1172,9 @@ void GameRenderer::DisableUpdateThread() {
app.DebugPrintf(
"------------------DisableUpdateThread--------------------\n");
updateRunning = false;
m_updateEvents->Clear(eUpdateCanRun);
m_updateEvents->WaitForSingle(eUpdateEventIsFinished, INFINITE);
m_updateEvents->clear(eUpdateCanRun);
m_updateEvents->waitForSingle(eUpdateEventIsFinished,
C4JThread::kInfiniteTimeout);
#endif
}

View file

@ -9,6 +9,7 @@ class SparseLightStorage;
class CompressedTileStorage;
class SparseDataStorage;
#include <mutex>
#include "../../Minecraft.World/Util/SmoothFloat.h"
#include "../../Minecraft.World/Util/C4JThread.h"
#include "../Textures/ResourceLocation.h"
@ -191,7 +192,7 @@ public:
static std::vector<CompressedTileStorage*>
m_deleteStackCompressedTileStorage;
static std::vector<SparseDataStorage*> m_deleteStackSparseDataStorage;
static CRITICAL_SECTION m_csDeleteStack;
static std::mutex m_csDeleteStack;
static void AddForDelete(uint8_t* deleteThis);
static void AddForDelete(SparseLightStorage* deleteThis);
static void AddForDelete(CompressedTileStorage* deleteThis);

View file

@ -1,6 +1,7 @@
#include <thread>
#include <chrono>
#include <array>
#include <mutex>
#include "../Platform/stdafx.h"
#include "LevelRenderer.h"
@ -163,11 +164,7 @@ LevelRenderer::LevelRenderer(Minecraft* mc, Textures* textures) {
lastPlayerCount[i] = 0;
}
InitializeCriticalSection(&m_csDirtyChunks);
InitializeCriticalSection(&m_csRenderableTileEntities);
#if defined(_LARGE_WORLDS)
InitializeCriticalSection(&m_csChunkFlags);
#endif
// std::mutex members are default-constructed
dirtyChunkPresent = false;
lastDirtyChunkFound = 0;
@ -395,10 +392,11 @@ void LevelRenderer::setLevel(int playerIndex, MultiPlayerLevel* level) {
// actually exiting the game, so only when the primary player sets there
// level to nullptr
if (playerIndex == ProfileManager.GetPrimaryPad()) {
EnterCriticalSection(&m_csRenderableTileEntities);
renderableTileEntities.clear();
m_renderableTileEntitiesPendingRemoval.clear();
LeaveCriticalSection(&m_csRenderableTileEntities);
{
std::lock_guard<std::mutex> lock(m_csRenderableTileEntities);
renderableTileEntities.clear();
m_renderableTileEntitiesPendingRemoval.clear();
}
}
}
}
@ -428,7 +426,6 @@ void LevelRenderer::allChanged(int playerIndex) {
// to add it back then: If this CS is entered before DisableUpdateThread is
// called then (on 360 at least) we can get a deadlock when starting a game
// in splitscreen.
// EnterCriticalSection(&m_csDirtyChunks);
if (level[playerIndex] == nullptr) {
return;
}
@ -516,9 +513,6 @@ void LevelRenderer::allChanged(int playerIndex) {
noEntityRenderFrames = 2;
Minecraft::GetInstance()->gameRenderer->EnableUpdateThread();
// 4J Stu - Remove. See comment above.
// LeaveCriticalSection(&m_csDirtyChunks);
}
void LevelRenderer::renderEntities(Vec3* cam, Culler* culler, float a) {
@ -619,21 +613,22 @@ void LevelRenderer::renderEntities(Vec3* cam, Culler* culler, float a) {
// 4J - have restructed this so that the tile entities are stored within a
// hashmap by chunk/dimension index. The index is calculated in the same way
// as the global flags.
EnterCriticalSection(&m_csRenderableTileEntities);
for (auto it = renderableTileEntities.begin();
it != renderableTileEntities.end(); it++) {
int idx = it->first;
// Don't render if it isn't in the same dimension as this player
if (!isGlobalIndexInSameDimension(idx, level[playerIndex])) continue;
{
std::lock_guard<std::mutex> lock(m_csRenderableTileEntities);
for (auto it = renderableTileEntities.begin();
it != renderableTileEntities.end(); it++) {
int idx = it->first;
// Don't render if it isn't in the same dimension as this player
if (!isGlobalIndexInSameDimension(idx, level[playerIndex]))
continue;
for (auto it2 = it->second.tiles.begin(); it2 != it->second.tiles.end();
it2++) {
TileEntityRenderDispatcher::instance->render(*it2, a);
for (auto it2 = it->second.tiles.begin();
it2 != it->second.tiles.end(); it2++) {
TileEntityRenderDispatcher::instance->render(*it2, a);
}
}
}
LeaveCriticalSection(&m_csRenderableTileEntities);
mc->gameRenderer->turnOffLightLayer(a); // 4J - brought forward from 1.8.2
}
@ -653,7 +648,7 @@ std::wstring LevelRenderer::gatherStats2() {
}
void LevelRenderer::resortChunks(int xc, int yc, int zc) {
EnterCriticalSection(&m_csDirtyChunks);
std::lock_guard<std::recursive_mutex> lock(m_csDirtyChunks);
xc -= CHUNK_XZSIZE / 2;
yc -= CHUNK_SIZE / 2;
zc -= CHUNK_XZSIZE / 2;
@ -702,7 +697,6 @@ void LevelRenderer::resortChunks(int xc, int yc, int zc) {
}
}
nonStackDirtyChunksAdded();
LeaveCriticalSection(&m_csDirtyChunks);
}
int LevelRenderer::render(std::shared_ptr<LivingEntity> player, int layer,
@ -1704,6 +1698,7 @@ bool LevelRenderer::updateDirtyChunks() {
ClipChunk* nearChunk = nullptr; // Nearest chunk that is dirty
int veryNearCount = 0;
int minDistSq = 0x7fffffff; // Distances to this chunk
std::unique_lock<std::recursive_mutex> dirtyChunksLock(m_csDirtyChunks);
// Set a flag if we should only rebuild existing chunks, not create anything
// new
@ -1722,7 +1717,6 @@ bool LevelRenderer::updateDirtyChunks() {
PIXAddNamedCounter(((float)memAlloc) / (1024.0f * 1024.0f),
"Command buffer allocations");
bool onlyRebuild = (memAlloc >= MAX_COMMANDBUFFER_ALLOCATIONS);
EnterCriticalSection(&m_csDirtyChunks);
// Move any dirty chunks stored in the lock free stack into global flags
int index = 0;
@ -1936,22 +1930,22 @@ bool LevelRenderer::updateDirtyChunks() {
chunk->clearDirty();
// Take a copy of the details that are required for chunk
// rebuilding, and rebuild That instead of the original chunk
// data. This is done within the m_csDirtyChunks critical
// section, which means that any chunks can't be repositioned
// data. This is done within the m_csDirtyChunks lock,
// which means that any chunks can't be repositioned
// whilst we are doing this copy. The copy will then be
// guaranteed to be consistent whilst rebuilding takes place
// outside of that critical section.
// outside of that lock.
permaChunk[index].makeCopyForRebuild(chunk);
++index;
}
LeaveCriticalSection(&m_csDirtyChunks);
dirtyChunksLock.unlock();
--index; // Bring it back into 0 counted range
for (int i = MAX_CHUNK_REBUILD_THREADS - 1; i >= 0; --i) {
// Set the events that won't run
if ((i + 1) > index)
s_rebuildCompleteEvents->Set(i);
s_rebuildCompleteEvents->set(i);
else
break;
}
@ -1980,7 +1974,7 @@ bool LevelRenderer::updateDirtyChunks() {
if (index != 0) {
FRAME_PROFILE_SCOPE(ChunkRebuildSchedule);
s_rebuildCompleteEvents->Set(
s_rebuildCompleteEvents->set(
index - 1); // MGH - this rebuild happening on the main
// thread instead, mark the thread it
// should have been running on as complete
@ -1996,14 +1990,14 @@ bool LevelRenderer::updateDirtyChunks() {
else {
// Activate thread to rebuild this chunk
FRAME_PROFILE_SCOPE(ChunkRebuildSchedule);
s_activationEventA[index - 1]->Set();
s_activationEventA[index - 1]->set();
}
}
// Wait for the other threads to be done as well
{
FRAME_PROFILE_SCOPE(ChunkRebuildSchedule);
s_rebuildCompleteEvents->WaitForAll(INFINITE);
s_rebuildCompleteEvents->waitForAll(C4JThread::kInfiniteTimeout);
}
}
#else
@ -2030,12 +2024,12 @@ bool LevelRenderer::updateDirtyChunks() {
chunk->clearDirty();
// Take a copy of the details that are required for chunk
// rebuilding, and rebuild That instead of the original chunk data.
// This is done within the m_csDirtyChunks critical section, which
// This is done within the m_csDirtyChunks lock, which
// means that any chunks can't be repositioned whilst we are doing
// this copy. The copy will then be guaranteed to be consistent
// whilst rebuilding takes place outside of that critical section.
// whilst rebuilding takes place outside of that lock.
permaChunk.makeCopyForRebuild(chunk);
LeaveCriticalSection(&m_csDirtyChunks);
dirtyChunksLock.unlock();
}
// static int64_t totalTime = 0;
// static int64_t countTime = 0;
@ -2062,7 +2056,7 @@ bool LevelRenderer::updateDirtyChunks() {
} else {
dirtyChunkPresent = false;
}
LeaveCriticalSection(&m_csDirtyChunks);
dirtyChunksLock.unlock();
return false;
}
@ -2287,7 +2281,6 @@ void LevelRenderer::setDirty(int x0, int y0, int z0, int x1, int y1, int z1,
// come from when connection is being ticked outside of normal level tick,
// and player won't be set up
if (level == nullptr) level = this->level[mc->player->GetXboxPad()];
// EnterCriticalSection(&m_csDirtyChunks);
int _x0 = Mth::intFloorDiv(x0, CHUNK_XZSIZE);
int _y0 = Mth::intFloorDiv(y0, CHUNK_SIZE);
int _z0 = Mth::intFloorDiv(z0, CHUNK_XZSIZE);
@ -2377,7 +2370,6 @@ void LevelRenderer::setDirty(int x0, int y0, int z0, int x1, int y1, int z1,
}
}
}
// LeaveCriticalSection(&m_csDirtyChunks);
}
void LevelRenderer::tileChanged(int x, int y, int z) {
@ -3678,12 +3670,9 @@ void LevelRenderer::setGlobalChunkFlags(int x, int y, int z, Level* level,
int index = getGlobalIndexForChunk(x, y, z, level);
if (index != -1) {
#if defined(_LARGE_WORLDS)
EnterCriticalSection(&m_csChunkFlags);
std::lock_guard<std::mutex> lock(m_csChunkFlags);
#endif
globalChunkFlags[index] = flags;
#if defined(_LARGE_WORLDS)
LeaveCriticalSection(&m_csChunkFlags);
#endif
}
}
@ -3693,12 +3682,9 @@ void LevelRenderer::setGlobalChunkFlag(int index, unsigned char flag,
if (index != -1) {
#if defined(_LARGE_WORLDS)
EnterCriticalSection(&m_csChunkFlags);
std::lock_guard<std::mutex> lock(m_csChunkFlags);
#endif
globalChunkFlags[index] |= sflag;
#if defined(_LARGE_WORLDS)
LeaveCriticalSection(&m_csChunkFlags);
#endif
}
}
@ -3709,12 +3695,9 @@ void LevelRenderer::setGlobalChunkFlag(int x, int y, int z, Level* level,
int index = getGlobalIndexForChunk(x, y, z, level);
if (index != -1) {
#if defined(_LARGE_WORLDS)
EnterCriticalSection(&m_csChunkFlags);
std::lock_guard<std::mutex> lock(m_csChunkFlags);
#endif
globalChunkFlags[index] |= sflag;
#if defined(_LARGE_WORLDS)
LeaveCriticalSection(&m_csChunkFlags);
#endif
}
}
@ -3738,12 +3721,9 @@ void LevelRenderer::clearGlobalChunkFlag(int x, int y, int z, Level* level,
int index = getGlobalIndexForChunk(x, y, z, level);
if (index != -1) {
#if defined(_LARGE_WORLDS)
EnterCriticalSection(&m_csChunkFlags);
std::lock_guard<std::mutex> lock(m_csChunkFlags);
#endif
globalChunkFlags[index] &= ~sflag;
#if defined(_LARGE_WORLDS)
LeaveCriticalSection(&m_csChunkFlags);
#endif
}
}
@ -3835,19 +3815,19 @@ void LevelRenderer::eraseRenderableTileEntity_Locked(
void LevelRenderer::retireRenderableTileEntitiesForChunkKey(int key) {
if (key == -1) return;
EnterCriticalSection(&m_csRenderableTileEntities);
renderableTileEntities.erase(key);
m_renderableTileEntitiesPendingRemoval.erase(key);
LeaveCriticalSection(&m_csRenderableTileEntities);
{
std::lock_guard<std::mutex> lock(m_csRenderableTileEntities);
renderableTileEntities.erase(key);
m_renderableTileEntitiesPendingRemoval.erase(key);
}
}
// 4J added
void LevelRenderer::fullyFlagRenderableTileEntitiesToBeRemoved() {
FRAME_PROFILE_SCOPE(RenderableTileEntityCleanup);
EnterCriticalSection(&m_csRenderableTileEntities);
std::lock_guard<std::mutex> lock(m_csRenderableTileEntities);
if (m_renderableTileEntitiesPendingRemoval.empty()) {
LeaveCriticalSection(&m_csRenderableTileEntities);
return;
}
@ -3877,7 +3857,6 @@ void LevelRenderer::fullyFlagRenderableTileEntitiesToBeRemoved() {
}
}
m_renderableTileEntitiesPendingRemoval.clear();
LeaveCriticalSection(&m_csRenderableTileEntities);
}
LevelRenderer::DestroyedTileManager::RecentTile::RecentTile(int x, int y, int z,
@ -3888,11 +3867,10 @@ LevelRenderer::DestroyedTileManager::RecentTile::RecentTile(int x, int y, int z,
}
LevelRenderer::DestroyedTileManager::DestroyedTileManager() {
InitializeCriticalSection(&m_csDestroyedTiles);
// std::mutex is default-constructed
}
LevelRenderer::DestroyedTileManager::~DestroyedTileManager() {
DeleteCriticalSection(&m_csDestroyedTiles);
for (unsigned int i = 0; i < m_destroyedTiles.size(); i++) {
delete m_destroyedTiles[i];
}
@ -3902,7 +3880,7 @@ LevelRenderer::DestroyedTileManager::~DestroyedTileManager() {
// be called before it actually is)
void LevelRenderer::DestroyedTileManager::destroyingTileAt(Level* level, int x,
int y, int z) {
EnterCriticalSection(&m_csDestroyedTiles);
std::lock_guard<std::mutex> lock(m_csDestroyedTiles);
// Store a list of AABBs that the tile to be destroyed would have made,
// before we go and destroy it. This is made slightly more complicated as
@ -3919,8 +3897,6 @@ void LevelRenderer::DestroyedTileManager::destroyingTileAt(Level* level, int x,
}
m_destroyedTiles.push_back(recentTile);
LeaveCriticalSection(&m_csDestroyedTiles);
}
// For chunk rebuilding to inform the manager that a chunk (a 16x16x16 tile
@ -3928,7 +3904,7 @@ void LevelRenderer::DestroyedTileManager::destroyingTileAt(Level* level, int x,
void LevelRenderer::DestroyedTileManager::updatedChunkAt(Level* level, int x,
int y, int z,
int veryNearCount) {
EnterCriticalSection(&m_csDestroyedTiles);
std::lock_guard<std::mutex> lock(m_csDestroyedTiles);
// There's 2 stages to this. This function is called when a renderer chunk
// has been rebuilt, but that chunk's render data might be grouped
@ -3970,15 +3946,13 @@ void LevelRenderer::DestroyedTileManager::updatedChunkAt(Level* level, int x,
}
}
}
LeaveCriticalSection(&m_csDestroyedTiles);
}
// For game to get any AABBs that the user should be colliding with as render
// data has not yet been updated
void LevelRenderer::DestroyedTileManager::addAABBs(Level* level, AABB* box,
AABBList* boxes) {
EnterCriticalSection(&m_csDestroyedTiles);
std::lock_guard<std::mutex> lock(m_csDestroyedTiles);
for (unsigned int i = 0; i < m_destroyedTiles.size(); i++) {
if (m_destroyedTiles[i]->level == level) {
@ -3999,12 +3973,10 @@ void LevelRenderer::DestroyedTileManager::addAABBs(Level* level, AABB* box,
}
}
}
LeaveCriticalSection(&m_csDestroyedTiles);
}
void LevelRenderer::DestroyedTileManager::tick() {
EnterCriticalSection(&m_csDestroyedTiles);
std::lock_guard<std::mutex> lock(m_csDestroyedTiles);
// Remove any tiles that have timed out
for (unsigned int i = 0; i < m_destroyedTiles.size();) {
@ -4016,8 +3988,6 @@ void LevelRenderer::DestroyedTileManager::tick() {
i++;
}
}
LeaveCriticalSection(&m_csDestroyedTiles);
}
#if defined(_LARGE_WORLDS)
@ -4034,14 +4004,14 @@ void LevelRenderer::staticCtor() {
// Threads 1,3 and 5 are generally idle so use them
if ((i % 3) == 0)
rebuildThreads[i]->SetProcessor(CPU_CORE_CHUNK_REBUILD_A);
rebuildThreads[i]->setProcessor(CPU_CORE_CHUNK_REBUILD_A);
else if ((i % 3) == 1) {
rebuildThreads[i]->SetProcessor(CPU_CORE_CHUNK_REBUILD_B);
rebuildThreads[i]->setProcessor(CPU_CORE_CHUNK_REBUILD_B);
} else if ((i % 3) == 2)
rebuildThreads[i]->SetProcessor(CPU_CORE_CHUNK_REBUILD_C);
rebuildThreads[i]->setProcessor(CPU_CORE_CHUNK_REBUILD_C);
// ResumeThread( saveThreads[j] );
rebuildThreads[i]->Run();
rebuildThreads[i]->run();
}
}
@ -4054,7 +4024,7 @@ int LevelRenderer::rebuildChunkThreadProc(void* lpParam) {
int index = (int)(uintptr_t)lpParam;
while (true) {
s_activationEventA[index]->WaitForSignal(INFINITE);
s_activationEventA[index]->waitForSignal(C4JThread::kInfiniteTimeout);
// app.DebugPrintf("Rebuilding permaChunk %d\n", index + 1);
{
@ -4063,7 +4033,7 @@ int LevelRenderer::rebuildChunkThreadProc(void* lpParam) {
}
// Inform the producer thread that we are done with this chunk
s_rebuildCompleteEvents->Set(index);
s_rebuildCompleteEvents->set(index);
}
return 0;

View file

@ -8,6 +8,7 @@
#include <xmcore.h>
#endif
#include <unordered_set>
#include <mutex>
class MultiPlayerLevel;
class Textures;
class Chunk;
@ -164,7 +165,7 @@ private:
typedef std::unordered_map<int, rtePendingRemovalSet, IntKeyHash, IntKeyEq>
rtePendingRemovalMap;
rtePendingRemovalMap m_renderableTileEntitiesPendingRemoval;
CRITICAL_SECTION m_csRenderableTileEntities;
std::mutex m_csRenderableTileEntities;
MultiPlayerLevel* level[4]; // 4J - now one per player
Textures* textures;
// std::vector<Chunk *> *sortedChunks[4]; // 4J - removed - not
@ -215,7 +216,7 @@ private:
public:
void fullyFlagRenderableTileEntitiesToBeRemoved(); // 4J added
CRITICAL_SECTION m_csDirtyChunks;
std::recursive_mutex m_csDirtyChunks;
bool m_nearDirtyChunk;
// 4J - Destroyed Tile Management - these things added so we can track tiles
@ -235,7 +236,7 @@ public:
RecentTile(int x, int y, int z, Level* level);
~RecentTile() = default;
};
CRITICAL_SECTION m_csDestroyedTiles;
std::mutex m_csDestroyedTiles;
std::vector<RecentTile*> m_destroyedTiles;
public:
@ -343,7 +344,7 @@ public:
static void staticCtor();
static int rebuildChunkThreadProc(void* lpParam);
CRITICAL_SECTION m_csChunkFlags;
std::mutex m_csChunkFlags;
#endif
void nonStackDirtyChunksAdded();

View file

@ -774,13 +774,9 @@ int ConsoleSaveFileOriginal::getOriginalSaveVersion() {
return header.getOriginalSaveVersion();
}
void ConsoleSaveFileOriginal::LockSaveAccess() {
EnterCriticalSection(&m_lock);
}
void ConsoleSaveFileOriginal::LockSaveAccess() { m_lock.lock(); }
void ConsoleSaveFileOriginal::ReleaseSaveAccess() {
LeaveCriticalSection(&m_lock);
}
void ConsoleSaveFileOriginal::ReleaseSaveAccess() { m_lock.unlock(); }
ESavePlatform ConsoleSaveFileOriginal::getSavePlatform() {
return header.getSavePlatform();

View file

@ -1,4 +1,5 @@
#pragma once
#include <mutex>
#include "FileHeader.h"
#include "ConsoleSavePath.h"
@ -23,7 +24,7 @@ private:
#endif
void* pvSaveMem;
CRITICAL_SECTION m_lock;
std::recursive_mutex m_lock;
void PrepareForWrite(FileEntry* file, unsigned int nNumberOfBytesToWrite);
void MoveDataBeyond(FileEntry* file, unsigned int nNumberOfBytesToWrite);

View file

@ -396,8 +396,6 @@ ConsoleSaveFileSplit::ConsoleSaveFileSplit(ConsoleSaveFile* sourceSave,
void ConsoleSaveFileSplit::_init(const std::wstring& fileName, void* pvSaveData,
unsigned int fileSize, ESavePlatform plat) {
InitializeCriticalSectionAndSpinCount(&m_lock, 5120);
m_lastTickTime = 0;
// One time initialise of static stuff required for our storage
@ -549,7 +547,6 @@ ConsoleSaveFileSplit::~ConsoleSaveFileSplit() {
}
StorageManager.ResetSubfiles();
DeleteCriticalSection(&m_lock);
}
// Add the file to our table of internal files if not already there
@ -1504,11 +1501,9 @@ int ConsoleSaveFileSplit::getOriginalSaveVersion() {
return header.getOriginalSaveVersion();
}
void ConsoleSaveFileSplit::LockSaveAccess() { EnterCriticalSection(&m_lock); }
void ConsoleSaveFileSplit::LockSaveAccess() { m_lock.lock(); }
void ConsoleSaveFileSplit::ReleaseSaveAccess() {
LeaveCriticalSection(&m_lock);
}
void ConsoleSaveFileSplit::ReleaseSaveAccess() { m_lock.unlock(); }
ESavePlatform ConsoleSaveFileSplit::getSavePlatform() {
return header.getSavePlatform();

View file

@ -1,4 +1,5 @@
#pragma once
#include <mutex>
#include "FileHeader.h"
#include "ConsoleSavePath.h"
@ -79,7 +80,7 @@ private:
#endif
void* pvSaveMem;
CRITICAL_SECTION m_lock;
std::recursive_mutex m_lock;
void PrepareForWrite(FileEntry* file, unsigned int nNumberOfBytesToWrite);
void MoveDataBeyond(FileEntry* file, unsigned int nNumberOfBytesToWrite);

View file

@ -42,7 +42,7 @@ Compression* Compression::getCompression() {
int32_t Compression::CompressLZXRLE(void* pDestination, unsigned int* pDestSize,
void* pSource, unsigned int SrcSize) {
EnterCriticalSection(&rleCompressLock);
std::lock_guard<std::mutex> lock(rleCompressLock);
// static unsigned char rleBuf[1024*100];
unsigned char* pucIn = (unsigned char*)pSource;
@ -84,7 +84,6 @@ int32_t Compression::CompressLZXRLE(void* pDestination, unsigned int* pDestSize,
PIXBeginNamedEvent(0, "Secondary compression");
Compress(pDestination, pDestSize, rleCompressBuf, rleSize);
PIXEndNamedEvent();
LeaveCriticalSection(&rleCompressLock);
// printf("Compressed from %d to %d to %d\n",SrcSize,rleSize,*pDestSize);
return S_OK;
@ -92,45 +91,48 @@ int32_t Compression::CompressLZXRLE(void* pDestination, unsigned int* pDestSize,
int32_t Compression::CompressRLE(void* pDestination, unsigned int* pDestSize,
void* pSource, unsigned int SrcSize) {
EnterCriticalSection(&rleCompressLock);
// static unsigned char rleBuf[1024*100];
unsigned int rleSize;
{
std::lock_guard<std::mutex> lock(rleCompressLock);
// static unsigned char rleBuf[1024*100];
unsigned char* pucIn = (unsigned char*)pSource;
unsigned char* pucEnd = pucIn + SrcSize;
unsigned char* pucOut = (unsigned char*)rleCompressBuf;
unsigned char* pucIn = (unsigned char*)pSource;
unsigned char* pucEnd = pucIn + SrcSize;
unsigned char* pucOut = (unsigned char*)rleCompressBuf;
// Compress with RLE first:
// 0 - 254 - encodes a single byte
// 255 followed by 0, 1, 2 - encodes a 1, 2, or 3 255s
// 255 followed by 3-255, followed by a byte - encodes a run of n + 1 bytes
PIXBeginNamedEvent(0, "RLE compression");
do {
unsigned char thisOne = *pucIn++;
// Compress with RLE first:
// 0 - 254 - encodes a single byte
// 255 followed by 0, 1, 2 - encodes a 1, 2, or 3 255s
// 255 followed by 3-255, followed by a byte - encodes a run of n + 1
// bytes
PIXBeginNamedEvent(0, "RLE compression");
do {
unsigned char thisOne = *pucIn++;
unsigned int count = 1;
while ((pucIn != pucEnd) && (*pucIn == thisOne) && (count < 256)) {
pucIn++;
count++;
}
unsigned int count = 1;
while ((pucIn != pucEnd) && (*pucIn == thisOne) && (count < 256)) {
pucIn++;
count++;
}
if (count <= 3) {
if (thisOne == 255) {
if (count <= 3) {
if (thisOne == 255) {
*pucOut++ = 255;
*pucOut++ = count - 1;
} else {
for (unsigned int i = 0; i < count; i++) {
*pucOut++ = thisOne;
}
}
} else {
*pucOut++ = 255;
*pucOut++ = count - 1;
} else {
for (unsigned int i = 0; i < count; i++) {
*pucOut++ = thisOne;
}
*pucOut++ = thisOne;
}
} else {
*pucOut++ = 255;
*pucOut++ = count - 1;
*pucOut++ = thisOne;
}
} while (pucIn != pucEnd);
unsigned int rleSize = (unsigned int)(pucOut - rleCompressBuf);
PIXEndNamedEvent();
LeaveCriticalSection(&rleCompressLock);
} while (pucIn != pucEnd);
rleSize = (unsigned int)(pucOut - rleCompressBuf);
PIXEndNamedEvent();
}
// Return
if (rleSize <= *pDestSize) {
@ -148,7 +150,7 @@ int32_t Compression::CompressRLE(void* pDestination, unsigned int* pDestSize,
int32_t Compression::DecompressLZXRLE(void* pDestination,
unsigned int* pDestSize, void* pSource,
unsigned int SrcSize) {
EnterCriticalSection(&rleDecompressLock);
std::lock_guard<std::mutex> lock(rleDecompressLock);
// 4J Stu - Fix for #13676 - Crash: Crash while attempting to load a world
// after updating TU Some saves can have chunks that decompress into very
// large sizes, so I have doubled the size of this buffer Ideally we should
@ -204,13 +206,12 @@ int32_t Compression::DecompressLZXRLE(void* pDestination,
if (dynamicRleBuf != nullptr) delete[] dynamicRleBuf;
LeaveCriticalSection(&rleDecompressLock);
return S_OK;
}
int32_t Compression::DecompressRLE(void* pDestination, unsigned int* pDestSize,
void* pSource, unsigned int SrcSize) {
EnterCriticalSection(&rleDecompressLock);
std::lock_guard<std::mutex> lock(rleDecompressLock);
// unsigned char *pucIn = (unsigned char *)rleDecompressBuf;
unsigned char* pucIn = (unsigned char*)pSource;
@ -239,7 +240,6 @@ int32_t Compression::DecompressRLE(void* pDestination, unsigned int* pDestSize,
}
*pDestSize = (unsigned int)(pucOut - (unsigned char*)pDestination);
LeaveCriticalSection(&rleDecompressLock);
return S_OK;
}
@ -440,16 +440,11 @@ Compression::Compression() {
m_localDecompressType = eCompressionType_ZLIBRLE;
m_decompressType = m_localDecompressType;
InitializeCriticalSection(&rleCompressLock);
InitializeCriticalSection(&rleDecompressLock);
}
Compression::~Compression() {
XMemDestroyCompressionContext(compressionContext);
XMemDestroyDecompressionContext(decompressionContext);
DeleteCriticalSection(&rleCompressLock);
DeleteCriticalSection(&rleDecompressLock);
}
void Compression::SetDecompressionType(ESavePlatform platform) {

View file

@ -1,4 +1,5 @@
#pragma once
#include <mutex>
#include "../Files/FileHeader.h"
class Compression {
@ -67,8 +68,8 @@ private:
XMEMCOMPRESSION_CONTEXT compressionContext;
XMEMDECOMPRESSION_CONTEXT decompressionContext;
CRITICAL_SECTION rleCompressLock;
CRITICAL_SECTION rleDecompressLock;
std::mutex rleCompressLock;
std::mutex rleDecompressLock;
unsigned char rleCompressBuf[1024 * 100];
static const unsigned int staticRleSize = 1024 * 200;

File diff suppressed because it is too large Load diff

View file

@ -10,6 +10,7 @@
#include "../WorldGen/Biomes/Biome.h"
#include "../Util/C4JThread.h"
#include <cstdint>
#include <mutex>
#include <unordered_set>
// 4J Stu - This value should be big enough that we don't get any crashes causes
@ -100,7 +101,7 @@ public:
static const int TICKS_PER_DAY = 20 * 60 * 20; // ORG:20*60*20
public:
CRITICAL_SECTION m_entitiesCS; // 4J added
std::recursive_mutex m_entitiesCS; // 4J added
std::vector<std::shared_ptr<Entity> > entities;
@ -108,9 +109,9 @@ protected:
std::vector<std::shared_ptr<Entity> > entitiesToRemove;
public:
bool hasEntitiesToRemove(); // 4J added
bool m_bDisableAddNewTileEntities; // 4J Added
CRITICAL_SECTION m_tileEntityListCS; // 4J added
bool hasEntitiesToRemove(); // 4J added
bool m_bDisableAddNewTileEntities; // 4J Added
std::recursive_mutex m_tileEntityListCS; // 4J added
std::vector<std::shared_ptr<TileEntity> > tileEntityList;
private:
@ -631,7 +632,7 @@ public:
virtual bool newFallingTileAllowed() { return true; }
// 4J - added for new lighting from 1.8.2
CRITICAL_SECTION m_checkLightCS;
std::recursive_mutex m_checkLightCS;
private:
int m_iHighestY; // 4J-PB - for the end portal in The End

View file

@ -19,48 +19,27 @@
#include "../Entities/ItemEntity.h"
#include "../Entities/Mobs/Minecart.h"
#include <mutex>
#if defined(SHARING_ENABLED)
CRITICAL_SECTION LevelChunk::m_csSharing;
std::recursive_mutex LevelChunk::m_csSharing;
#endif
#if defined(_ENTITIES_RW_SECTION)
// AP - use a RW critical section so we can have multiple threads reading the
// same data to avoid a clash
CRITICAL_RW_SECTION LevelChunk::m_csEntities;
#else
CRITICAL_SECTION LevelChunk::m_csEntities;
#endif
CRITICAL_SECTION LevelChunk::m_csTileEntities;
std::recursive_mutex LevelChunk::m_csEntities;
std::recursive_mutex LevelChunk::m_csTileEntities;
bool LevelChunk::touchedSky = false;
void LevelChunk::staticCtor() {
#if defined(SHARING_ENABLED)
InitializeCriticalSection(&m_csSharing);
#endif
#if defined(_ENTITIES_RW_SECTION)
InitializeCriticalRWSection(&m_csEntities);
#else
InitializeCriticalSection(&m_csEntities);
#endif
InitializeCriticalSection(&m_csTileEntities);
}
void LevelChunk::staticCtor() {}
void LevelChunk::init(Level* level, int x, int z) {
biomes = byteArray(16 * 16);
for (int i = 0; i < 16 * 16; i++) {
biomes[i] = 0xff;
}
#if defined(_ENTITIES_RW_SECTION)
EnterCriticalRWSection(&m_csEntities, true);
#else
EnterCriticalSection(&m_csEntities);
#endif
entityBlocks =
new std::vector<std::shared_ptr<Entity> >*[ENTITY_BLOCKS_LENGTH];
#if defined(_ENTITIES_RW_SECTION)
LeaveCriticalRWSection(&m_csEntities, true);
#else
LeaveCriticalSection(&m_csEntities);
#endif
{
std::lock_guard<std::recursive_mutex> lock(m_csEntities);
entityBlocks =
new std::vector<std::shared_ptr<Entity> >*[ENTITY_BLOCKS_LENGTH];
}
terrainPopulated = 0;
m_unsaved = false;
@ -80,19 +59,12 @@ void LevelChunk::init(Level* level, int x, int z) {
this->z = z;
MemSect(1);
heightmap = byteArray(16 * 16);
#if defined(_ENTITIES_RW_SECTION)
EnterCriticalRWSection(&m_csEntities, true);
#else
EnterCriticalSection(&m_csEntities);
#endif
for (int i = 0; i < ENTITY_BLOCKS_LENGTH; i++) {
entityBlocks[i] = new std::vector<std::shared_ptr<Entity> >();
{
std::lock_guard<std::recursive_mutex> lock(m_csEntities);
for (int i = 0; i < ENTITY_BLOCKS_LENGTH; i++) {
entityBlocks[i] = new std::vector<std::shared_ptr<Entity> >();
}
}
#if defined(_ENTITIES_RW_SECTION)
LeaveCriticalRWSection(&m_csEntities, true);
#else
LeaveCriticalSection(&m_csEntities);
#endif
MemSect(0);
@ -253,65 +225,64 @@ void LevelChunk::setUnsaved(bool unsaved) {
void LevelChunk::stopSharingTilesAndData() {
#if defined(SHARING_ENABLED)
EnterCriticalSection(&m_csSharing);
lastUnsharedTime = System::currentTimeMillis();
if (!sharingTilesAndData) {
LeaveCriticalSection(&m_csSharing);
return;
{
std::lock_guard<std::recursive_mutex> lock(m_csSharing);
lastUnsharedTime = System::currentTimeMillis();
if (!sharingTilesAndData) {
return;
}
// If we've got a reference to a server chunk's terrainPopulated flag
// that this LevelChunk is sharing with, then don't consider unsharing
// if it hasn't been set. This is because post-processing things that
// update the server chunks won't actually cause the server to send any
// updates to the tiles that they alter, so they completely depend on
// the data not being shared for it to get from the server to here
if ((serverTerrainPopulated) &&
(((*serverTerrainPopulated) & sTerrainPopulatedAllAffecting) !=
sTerrainPopulatedAllAffecting)) {
return;
}
// If this is the empty chunk, then it will have a x & z of 0,0 - if we
// don't drop out here we'll end up unsharing the chunk at this location
// for no reason
if (isEmpty()) {
return;
}
MemSect(47);
// Changed to used compressed storage - these CTORs make deep copies of
// the storage passed as a parameter
lowerBlocks = new CompressedTileStorage(lowerBlocks);
// Changed to use new sparse data storage - this CTOR makes a deep copy
// of the storage passed as a parameter
lowerData = new SparseDataStorage(lowerData);
if (Level::maxBuildHeight > Level::COMPRESSED_CHUNK_SECTION_HEIGHT) {
upperBlocks = new CompressedTileStorage(upperBlocks);
upperData = new SparseDataStorage(upperData);
} else {
upperBlocks = nullptr;
upperData = nullptr;
}
/*
newDataLayer = new DataLayer(skyLight->data.length*2, level->depthBits);
XMemCpy(newDataLayer->data.data, skyLight->data.data,
skyLight->data.length); skyLight = newDataLayer;
newDataLayer = new DataLayer(blockLight->data.length*2,
level->depthBits); XMemCpy(newDataLayer->data.data,
blockLight->data.data, blockLight->data.length); blockLight =
newDataLayer;
*/
sharingTilesAndData = false;
MemSect(0);
}
// If we've got a reference to a server chunk's terrainPopulated flag that
// this LevelChunk is sharing with, then don't consider unsharing if it
// hasn't been set. This is because post-processing things that update the
// server chunks won't actually cause the server to send any updates to the
// tiles that they alter, so they completely depend on the data not being
// shared for it to get from the server to here
if ((serverTerrainPopulated) &&
(((*serverTerrainPopulated) & sTerrainPopulatedAllAffecting) !=
sTerrainPopulatedAllAffecting)) {
LeaveCriticalSection(&m_csSharing);
return;
}
// If this is the empty chunk, then it will have a x & z of 0,0 - if we
// don't drop out here we'll end up unsharing the chunk at this location for
// no reason
if (isEmpty()) {
LeaveCriticalSection(&m_csSharing);
return;
}
MemSect(47);
// Changed to used compressed storage - these CTORs make deep copies of the
// storage passed as a parameter
lowerBlocks = new CompressedTileStorage(lowerBlocks);
// Changed to use new sparse data storage - this CTOR makes a deep copy of
// the storage passed as a parameter
lowerData = new SparseDataStorage(lowerData);
if (Level::maxBuildHeight > Level::COMPRESSED_CHUNK_SECTION_HEIGHT) {
upperBlocks = new CompressedTileStorage(upperBlocks);
upperData = new SparseDataStorage(upperData);
} else {
upperBlocks = nullptr;
upperData = nullptr;
}
/*
newDataLayer = new DataLayer(skyLight->data.length*2, level->depthBits);
XMemCpy(newDataLayer->data.data, skyLight->data.data,
skyLight->data.length); skyLight = newDataLayer;
newDataLayer = new DataLayer(blockLight->data.length*2, level->depthBits);
XMemCpy(newDataLayer->data.data, blockLight->data.data,
blockLight->data.length); blockLight = newDataLayer;
*/
sharingTilesAndData = false;
MemSect(0);
LeaveCriticalSection(&m_csSharing);
#endif
}
@ -322,114 +293,111 @@ void LevelChunk::stopSharingTilesAndData() {
// not sharing
void LevelChunk::reSyncLighting() {
#if defined(SHARING_ENABLED)
EnterCriticalSection(&m_csSharing);
{
std::lock_guard<std::recursive_mutex> lock(m_csSharing);
if (isEmpty()) {
LeaveCriticalSection(&m_csSharing);
return;
}
if (isEmpty()) {
return;
}
#if defined(_LARGE_WORLDS)
LevelChunk* lc = MinecraftServer::getInstance()
->getLevel(level->dimension->id)
->cache->getChunkLoadedOrUnloaded(x, z);
LevelChunk* lc = MinecraftServer::getInstance()
->getLevel(level->dimension->id)
->cache->getChunkLoadedOrUnloaded(x, z);
#else
LevelChunk* lc = MinecraftServer::getInstance()
->getLevel(level->dimension->id)
->cache->getChunk(x, z);
LevelChunk* lc = MinecraftServer::getInstance()
->getLevel(level->dimension->id)
->cache->getChunk(x, z);
#endif
GameRenderer::AddForDelete(lowerSkyLight);
lowerSkyLight = new SparseLightStorage(lc->lowerSkyLight);
GameRenderer::FinishedReassigning();
GameRenderer::AddForDelete(lowerBlockLight);
lowerBlockLight = new SparseLightStorage(lc->lowerBlockLight);
GameRenderer::FinishedReassigning();
GameRenderer::AddForDelete(lowerSkyLight);
lowerSkyLight = new SparseLightStorage(lc->lowerSkyLight);
GameRenderer::FinishedReassigning();
GameRenderer::AddForDelete(lowerBlockLight);
lowerBlockLight = new SparseLightStorage(lc->lowerBlockLight);
GameRenderer::FinishedReassigning();
if (Level::maxBuildHeight > Level::COMPRESSED_CHUNK_SECTION_HEIGHT) {
GameRenderer::AddForDelete(upperSkyLight);
upperSkyLight = new SparseLightStorage(lc->upperSkyLight);
GameRenderer::FinishedReassigning();
GameRenderer::AddForDelete(upperBlockLight);
upperBlockLight = new SparseLightStorage(lc->upperBlockLight);
GameRenderer::FinishedReassigning();
if (Level::maxBuildHeight > Level::COMPRESSED_CHUNK_SECTION_HEIGHT) {
GameRenderer::AddForDelete(upperSkyLight);
upperSkyLight = new SparseLightStorage(lc->upperSkyLight);
GameRenderer::FinishedReassigning();
GameRenderer::AddForDelete(upperBlockLight);
upperBlockLight = new SparseLightStorage(lc->upperBlockLight);
GameRenderer::FinishedReassigning();
}
}
LeaveCriticalSection(&m_csSharing);
#endif
}
void LevelChunk::startSharingTilesAndData(int forceMs) {
#if defined(SHARING_ENABLED)
EnterCriticalSection(&m_csSharing);
if (sharingTilesAndData) {
LeaveCriticalSection(&m_csSharing);
return;
}
{
std::lock_guard<std::recursive_mutex> lock(m_csSharing);
if (sharingTilesAndData) {
return;
}
// If this is the empty chunk, then it will have a x & z of 0,0 - we'll end
// up potentially loading the 0,0 block if we proceed. And it obviously
// doesn't make sense to go resharing the 0,0 block on behalf of an empty
// chunk either
if (isEmpty()) {
LeaveCriticalSection(&m_csSharing);
return;
}
// If this is the empty chunk, then it will have a x & z of 0,0 - we'll
// end up potentially loading the 0,0 block if we proceed. And it
// obviously doesn't make sense to go resharing the 0,0 block on behalf
// of an empty chunk either
if (isEmpty()) {
return;
}
#if defined(_LARGE_WORLDS)
LevelChunk* lc = MinecraftServer::getInstance()
->getLevel(level->dimension->id)
->cache->getChunkLoadedOrUnloaded(x, z);
LevelChunk* lc = MinecraftServer::getInstance()
->getLevel(level->dimension->id)
->cache->getChunkLoadedOrUnloaded(x, z);
#else
LevelChunk* lc = MinecraftServer::getInstance()
->getLevel(level->dimension->id)
->cache->getChunk(x, z);
LevelChunk* lc = MinecraftServer::getInstance()
->getLevel(level->dimension->id)
->cache->getChunk(x, z);
#endif
// In normal usage, chunks should only reshare if their local data matched
// that on the server. The forceMs parameter though can be used to force a
// share if resharing hasn't happened after a period of time
if (forceMs == 0) {
// Normal behaviour - just check that the data matches, and don't start
// sharing data if it doesn't (yet)
if (!lowerBlocks->isSameAs(lc->lowerBlocks) ||
(upperBlocks && lc->upperBlocks &&
!upperBlocks->isSameAs(lc->upperBlocks))) {
LeaveCriticalSection(&m_csSharing);
return;
// In normal usage, chunks should only reshare if their local data
// matched that on the server. The forceMs parameter though can be used
// to force a share if resharing hasn't happened after a period of time
if (forceMs == 0) {
// Normal behaviour - just check that the data matches, and don't
// start sharing data if it doesn't (yet)
if (!lowerBlocks->isSameAs(lc->lowerBlocks) ||
(upperBlocks && lc->upperBlocks &&
!upperBlocks->isSameAs(lc->upperBlocks))) {
return;
}
} else {
// Only force if it has been more than forceMs milliseconds since we
// last wanted to unshare this chunk
int64_t timenow = System::currentTimeMillis();
if ((timenow - lastUnsharedTime) < forceMs) {
return;
}
}
} else {
// Only force if it has been more than forceMs milliseconds since we
// last wanted to unshare this chunk
int64_t timenow = System::currentTimeMillis();
if ((timenow - lastUnsharedTime) < forceMs) {
LeaveCriticalSection(&m_csSharing);
return;
}
}
// Note - data that was shared isn't directly deleted here, as it might
// still be in use in the game render update thread. Let that thread delete
// it when it is safe to do so instead.
GameRenderer::AddForDelete(lowerBlocks);
lowerBlocks = lc->lowerBlocks;
GameRenderer::FinishedReassigning();
GameRenderer::AddForDelete(lowerData);
lowerData = lc->lowerData;
GameRenderer::FinishedReassigning();
if (Level::maxBuildHeight > Level::COMPRESSED_CHUNK_SECTION_HEIGHT) {
GameRenderer::AddForDelete(upperBlocks);
upperBlocks = lc->upperBlocks;
// Note - data that was shared isn't directly deleted here, as it might
// still be in use in the game render update thread. Let that thread
// delete it when it is safe to do so instead.
GameRenderer::AddForDelete(lowerBlocks);
lowerBlocks = lc->lowerBlocks;
GameRenderer::FinishedReassigning();
GameRenderer::AddForDelete(upperData);
upperData = lc->upperData;
GameRenderer::AddForDelete(lowerData);
lowerData = lc->lowerData;
GameRenderer::FinishedReassigning();
}
sharingTilesAndData = true;
LeaveCriticalSection(&m_csSharing);
if (Level::maxBuildHeight > Level::COMPRESSED_CHUNK_SECTION_HEIGHT) {
GameRenderer::AddForDelete(upperBlocks);
upperBlocks = lc->upperBlocks;
GameRenderer::FinishedReassigning();
GameRenderer::AddForDelete(upperData);
upperData = lc->upperData;
GameRenderer::FinishedReassigning();
}
sharingTilesAndData = true;
}
#endif
}
@ -1187,17 +1155,10 @@ void LevelChunk::addEntity(std::shared_ptr<Entity> e) {
e->yChunk = yc;
e->zChunk = z;
#if defined(_ENTITIES_RW_SECTION)
EnterCriticalRWSection(&m_csEntities, true);
#else
EnterCriticalSection(&m_csEntities);
#endif
entityBlocks[yc]->push_back(e);
#if defined(_ENTITIES_RW_SECTION)
LeaveCriticalRWSection(&m_csEntities, true);
#else
LeaveCriticalSection(&m_csEntities);
#endif
{
std::lock_guard<std::recursive_mutex> lock(m_csEntities);
entityBlocks[yc]->push_back(e);
}
}
void LevelChunk::removeEntity(std::shared_ptr<Entity> e) {
@ -1208,28 +1169,20 @@ void LevelChunk::removeEntity(std::shared_ptr<Entity> e, int yc) {
if (yc < 0) yc = 0;
if (yc >= ENTITY_BLOCKS_LENGTH) yc = ENTITY_BLOCKS_LENGTH - 1;
#if defined(_ENTITIES_RW_SECTION)
EnterCriticalRWSection(&m_csEntities, true);
#else
EnterCriticalSection(&m_csEntities);
#endif
{
std::lock_guard<std::recursive_mutex> lock(m_csEntities);
// 4J - was entityBlocks[yc]->remove(e);
auto it = find(entityBlocks[yc]->begin(), entityBlocks[yc]->end(), e);
if (it != entityBlocks[yc]->end()) {
entityBlocks[yc]->erase(it);
// 4J - we don't want storage creeping up here as thinkgs move round the
// world accumulating up spare space
MemSect(31);
entityBlocks[yc]->shrink_to_fit();
MemSect(0);
// 4J - was entityBlocks[yc]->remove(e);
auto it = find(entityBlocks[yc]->begin(), entityBlocks[yc]->end(), e);
if (it != entityBlocks[yc]->end()) {
entityBlocks[yc]->erase(it);
// 4J - we don't want storage creeping up here as thinkgs move round
// the world accumulating up spare space
MemSect(31);
entityBlocks[yc]->shrink_to_fit();
MemSect(0);
}
}
#if defined(_ENTITIES_RW_SECTION)
LeaveCriticalRWSection(&m_csEntities, true);
#else
LeaveCriticalSection(&m_csEntities);
#endif
}
bool LevelChunk::isSkyLit(int x, int y, int z) {
@ -1253,53 +1206,58 @@ std::shared_ptr<TileEntity> LevelChunk::getTileEntity(int x, int y, int z) {
// 4J Stu - Changed as we should not be using the [] accessor (causes an
// insert when we don't want one)
// shared_ptr<TileEntity> tileEntity = tileEntities[pos];
EnterCriticalSection(&m_csTileEntities);
std::shared_ptr<TileEntity> tileEntity = nullptr;
auto it = tileEntities.find(pos);
{
std::unique_lock<std::recursive_mutex> lock(m_csTileEntities);
auto it = tileEntities.find(pos);
if (it == tileEntities.end()) {
LeaveCriticalSection(
&m_csTileEntities); // Note: don't assume iterator is valid for
// tileEntities after this point
if (it == tileEntities.end()) {
lock.unlock(); // Note: don't assume iterator is valid for
// tileEntities after this point
// Fix for #48450 - All: Code Defect: Hang: Game hangs in tutorial, when
// player arrive at the particular coordinate 4J Stu - Chests try to get
// their neighbours when being destroyed, which then causes new tile
// entities to be created if the neighbour has already been destroyed
if (level->m_bDisableAddNewTileEntities) return nullptr;
// Fix for #48450 - All: Code Defect: Hang: Game hangs in tutorial,
// when player arrive at the particular coordinate 4J Stu - Chests
// try to get their neighbours when being destroyed, which then
// causes new tile entities to be created if the neighbour has
// already been destroyed
if (level->m_bDisableAddNewTileEntities) return nullptr;
int t = getTile(x, y, z);
if (t <= 0 || !Tile::tiles[t]->isEntityTile()) return nullptr;
int t = getTile(x, y, z);
if (t <= 0 || !Tile::tiles[t]->isEntityTile()) return nullptr;
// 4J-PB changed from this in 1.7.3
// EntityTile *et = (EntityTile *) Tile::tiles[t];
// et->onPlace(level, this->x * 16 + x, y, this->z * 16 + z);
// 4J-PB changed from this in 1.7.3
// EntityTile *et = (EntityTile *) Tile::tiles[t];
// et->onPlace(level, this->x * 16 + x, y, this->z * 16 + z);
// if (tileEntity == nullptr)
//{
tileEntity =
dynamic_cast<EntityTile*>(Tile::tiles[t])->newTileEntity(level);
level->setTileEntity(this->x * 16 + x, y, this->z * 16 + z, tileEntity);
//}
// if (tileEntity == nullptr)
//{
tileEntity =
dynamic_cast<EntityTile*>(Tile::tiles[t])->newTileEntity(level);
level->setTileEntity(this->x * 16 + x, y, this->z * 16 + z,
tileEntity);
//}
// tileEntity = tileEntities[pos]; // 4J - TODO - this
// doesn't seem right - assignment wrong way? Check
// tileEntity = tileEntities[pos]; // 4J - TODO - this
// doesn't seem right - assignment wrong way? Check
// 4J Stu - It should have been inserted by now, but check to be sure
EnterCriticalSection(&m_csTileEntities);
auto newIt = tileEntities.find(pos);
if (newIt != tileEntities.end()) {
tileEntity = newIt->second;
// 4J Stu - It should have been inserted by now, but check to be
// sure
{
std::lock_guard<std::recursive_mutex> lock2(m_csTileEntities);
auto newIt = tileEntities.find(pos);
if (newIt != tileEntities.end()) {
tileEntity = newIt->second;
}
}
} else {
tileEntity = it->second;
}
LeaveCriticalSection(&m_csTileEntities);
} else {
tileEntity = it->second;
LeaveCriticalSection(&m_csTileEntities);
}
if (tileEntity != nullptr && tileEntity->isRemoved()) {
EnterCriticalSection(&m_csTileEntities);
tileEntities.erase(pos);
LeaveCriticalSection(&m_csTileEntities);
{
std::lock_guard<std::recursive_mutex> lock(m_csTileEntities);
tileEntities.erase(pos);
}
return nullptr;
}
@ -1312,9 +1270,11 @@ void LevelChunk::addTileEntity(std::shared_ptr<TileEntity> te) {
int zz = (int)(te->z - this->z * 16);
setTileEntity(xx, yy, zz, te);
if (loaded) {
EnterCriticalSection(&level->m_tileEntityListCS);
level->tileEntityList.push_back(te);
LeaveCriticalSection(&level->m_tileEntityListCS);
{
std::lock_guard<std::recursive_mutex> lock(
level->m_tileEntityListCS);
level->tileEntityList.push_back(te);
}
}
}
@ -1342,9 +1302,10 @@ void LevelChunk::setTileEntity(int x, int y, int z,
tileEntity->clearRemoved();
EnterCriticalSection(&m_csTileEntities);
tileEntities[pos] = tileEntity;
LeaveCriticalSection(&m_csTileEntities);
{
std::lock_guard<std::recursive_mutex> lock(m_csTileEntities);
tileEntities[pos] = tileEntity;
}
}
void LevelChunk::removeTileEntity(int x, int y, int z) {
@ -1356,20 +1317,21 @@ void LevelChunk::removeTileEntity(int x, int y, int z) {
// if (removeThis != null) {
// removeThis.setRemoved();
// }
EnterCriticalSection(&m_csTileEntities);
auto it = tileEntities.find(pos);
if (it != tileEntities.end()) {
std::shared_ptr<TileEntity> te = tileEntities[pos];
tileEntities.erase(pos);
if (te != nullptr) {
if (level->isClientSide) {
app.DebugPrintf("Removing tile entity of type %d\n",
te->GetType());
{
std::lock_guard<std::recursive_mutex> lock(m_csTileEntities);
auto it = tileEntities.find(pos);
if (it != tileEntities.end()) {
std::shared_ptr<TileEntity> te = tileEntities[pos];
tileEntities.erase(pos);
if (te != nullptr) {
if (level->isClientSide) {
app.DebugPrintf("Removing tile entity of type %d\n",
te->GetType());
}
te->setRemoved();
}
te->setRemoved();
}
}
LeaveCriticalSection(&m_csTileEntities);
}
}
@ -1414,26 +1376,21 @@ void LevelChunk::load() {
#endif
std::vector<std::shared_ptr<TileEntity> > values;
EnterCriticalSection(&m_csTileEntities);
for (auto it = tileEntities.begin(); it != tileEntities.end(); it++) {
values.push_back(it->second);
{
std::lock_guard<std::recursive_mutex> lock(m_csTileEntities);
for (auto it = tileEntities.begin(); it != tileEntities.end();
it++) {
values.push_back(it->second);
}
}
LeaveCriticalSection(&m_csTileEntities);
level->addAllPendingTileEntities(values);
#if defined(_ENTITIES_RW_SECTION)
EnterCriticalRWSection(&m_csEntities, true);
#else
EnterCriticalSection(&m_csEntities);
#endif
for (int i = 0; i < ENTITY_BLOCKS_LENGTH; i++) {
level->addEntities(entityBlocks[i]);
{
std::lock_guard<std::recursive_mutex> lock(m_csEntities);
for (int i = 0; i < ENTITY_BLOCKS_LENGTH; i++) {
level->addEntities(entityBlocks[i]);
}
}
#if defined(_ENTITIES_RW_SECTION)
LeaveCriticalRWSection(&m_csEntities, true);
#else
LeaveCriticalSection(&m_csEntities);
#endif
} else {
#if defined(_LARGE_WORLDS)
m_bUnloaded = false;
@ -1446,11 +1403,13 @@ void LevelChunk::unload(bool unloadTileEntities) // 4J - added parameter
loaded = false;
if (unloadTileEntities) {
std::vector<std::shared_ptr<TileEntity> > tileEntitiesToRemove;
EnterCriticalSection(&m_csTileEntities);
for (auto it = tileEntities.begin(); it != tileEntities.end(); it++) {
tileEntitiesToRemove.push_back(it->second);
{
std::lock_guard<std::recursive_mutex> lock(m_csTileEntities);
for (auto it = tileEntities.begin(); it != tileEntities.end();
it++) {
tileEntitiesToRemove.push_back(it->second);
}
}
LeaveCriticalSection(&m_csTileEntities);
auto itEnd = tileEntitiesToRemove.end();
for (auto it = tileEntitiesToRemove.begin(); it != itEnd; it++) {
@ -1459,19 +1418,12 @@ void LevelChunk::unload(bool unloadTileEntities) // 4J - added parameter
}
}
#if defined(_ENTITIES_RW_SECTION)
EnterCriticalRWSection(&m_csEntities, true);
#else
EnterCriticalSection(&m_csEntities);
#endif
for (int i = 0; i < ENTITY_BLOCKS_LENGTH; i++) {
level->removeEntities(entityBlocks[i]);
{
std::lock_guard<std::recursive_mutex> lock(m_csEntities);
for (int i = 0; i < ENTITY_BLOCKS_LENGTH; i++) {
level->removeEntities(entityBlocks[i]);
}
}
#if defined(_ENTITIES_RW_SECTION)
LeaveCriticalRWSection(&m_csEntities, true);
#else
LeaveCriticalSection(&m_csEntities);
#endif
// app.DebugPrintf("Unloaded chunk %d, %d\n", x, z);
#if defined(_LARGE_WORLDS)
@ -1487,23 +1439,24 @@ void LevelChunk::unload(bool unloadTileEntities) // 4J - added parameter
PIXBeginNamedEvent(0, "Saving entities");
ListTag<CompoundTag>* entityTags = new ListTag<CompoundTag>();
EnterCriticalSection(&m_csEntities);
for (int i = 0; i < ENTITY_BLOCKS_LENGTH; i++) {
auto itEnd = entityBlocks[i]->end();
for (std::vector<std::shared_ptr<Entity> >::iterator it =
entityBlocks[i]->begin();
it != itEnd; it++) {
std::shared_ptr<Entity> e = *it;
CompoundTag* teTag = new CompoundTag();
if (e->save(teTag)) {
entityTags->add(teTag);
{
std::lock_guard<std::recursive_mutex> lock(m_csEntities);
for (int i = 0; i < ENTITY_BLOCKS_LENGTH; i++) {
auto itEnd = entityBlocks[i]->end();
for (std::vector<std::shared_ptr<Entity> >::iterator it =
entityBlocks[i]->begin();
it != itEnd; it++) {
std::shared_ptr<Entity> e = *it;
CompoundTag* teTag = new CompoundTag();
if (e->save(teTag)) {
entityTags->add(teTag);
}
}
}
// Clear out this list
entityBlocks[i]->clear();
// Clear out this list
entityBlocks[i]->clear();
}
}
LeaveCriticalSection(&m_csEntities);
m_unloadedEntitiesTag->put(L"Entities", entityTags);
PIXEndNamedEvent();
@ -1532,29 +1485,17 @@ void LevelChunk::unload(bool unloadTileEntities) // 4J - added parameter
}
bool LevelChunk::containsPlayer() {
#if defined(_ENTITIES_RW_SECTION)
EnterCriticalRWSection(&m_csEntities, true);
#else
EnterCriticalSection(&m_csEntities);
#endif
for (int i = 0; i < ENTITY_BLOCKS_LENGTH; i++) {
std::vector<std::shared_ptr<Entity> >* vecEntity = entityBlocks[i];
for (int j = 0; j < vecEntity->size(); j++) {
if (vecEntity->at(j)->GetType() == eTYPE_SERVERPLAYER) {
#if defined(_ENTITIES_RW_SECTION)
LeaveCriticalRWSection(&m_csEntities, true);
#else
LeaveCriticalSection(&m_csEntities);
#endif
return true;
{
std::lock_guard<std::recursive_mutex> lock(m_csEntities);
for (int i = 0; i < ENTITY_BLOCKS_LENGTH; i++) {
std::vector<std::shared_ptr<Entity> >* vecEntity = entityBlocks[i];
for (int j = 0; j < vecEntity->size(); j++) {
if (vecEntity->at(j)->GetType() == eTYPE_SERVERPLAYER) {
return true;
}
}
}
}
#if defined(_ENTITIES_RW_SECTION)
LeaveCriticalRWSection(&m_csEntities, true);
#else
LeaveCriticalSection(&m_csEntities);
#endif
return false;
}
@ -1572,33 +1513,34 @@ void LevelChunk::getEntities(std::shared_ptr<Entity> except, AABB* bb,
if (yc0 < 0) yc0 = 0;
if (yc1 >= ENTITY_BLOCKS_LENGTH) yc1 = ENTITY_BLOCKS_LENGTH - 1;
// AP - RW critical sections are expensive so enter once in
// AP - locking is expensive so enter once in
// Level::getEntities
EnterCriticalSection(&m_csEntities);
for (int yc = yc0; yc <= yc1; yc++) {
std::vector<std::shared_ptr<Entity> >* entities = entityBlocks[yc];
{
std::lock_guard<std::recursive_mutex> lock(m_csEntities);
for (int yc = yc0; yc <= yc1; yc++) {
std::vector<std::shared_ptr<Entity> >* entities = entityBlocks[yc];
auto itEnd = entities->end();
for (auto it = entities->begin(); it != itEnd; it++) {
std::shared_ptr<Entity> e = *it; // entities->at(i);
if (e != except && e->bb.intersects(*bb) &&
(selector == nullptr || selector->matches(e))) {
es.push_back(e);
std::vector<std::shared_ptr<Entity> >* subs =
e->getSubEntities();
if (subs != nullptr) {
for (int j = 0; j < subs->size(); j++) {
e = subs->at(j);
if (e != except && e->bb.intersects(*bb) &&
(selector == nullptr || selector->matches(e))) {
es.push_back(e);
auto itEnd = entities->end();
for (auto it = entities->begin(); it != itEnd; it++) {
std::shared_ptr<Entity> e = *it; // entities->at(i);
if (e != except && e->bb.intersects(*bb) &&
(selector == nullptr || selector->matches(e))) {
es.push_back(e);
std::vector<std::shared_ptr<Entity> >* subs =
e->getSubEntities();
if (subs != nullptr) {
for (int j = 0; j < subs->size(); j++) {
e = subs->at(j);
if (e != except && e->bb.intersects(*bb) &&
(selector == nullptr || selector->matches(e))) {
es.push_back(e);
}
}
}
}
}
}
}
LeaveCriticalSection(&m_csEntities);
}
void LevelChunk::getEntitiesOfClass(const std::type_info& ec, AABB* bb,
@ -1618,66 +1560,60 @@ void LevelChunk::getEntitiesOfClass(const std::type_info& ec, AABB* bb,
yc1 = 0;
}
// AP - RW critical sections are expensive so enter once in
// AP - locking is expensive so enter once in
// Level::getEntitiesOfClass
EnterCriticalSection(&m_csEntities);
for (int yc = yc0; yc <= yc1; yc++) {
std::vector<std::shared_ptr<Entity> >* entities = entityBlocks[yc];
{
std::lock_guard<std::recursive_mutex> lock(m_csEntities);
for (int yc = yc0; yc <= yc1; yc++) {
std::vector<std::shared_ptr<Entity> >* entities = entityBlocks[yc];
auto itEnd = entities->end();
for (auto it = entities->begin(); it != itEnd; it++) {
std::shared_ptr<Entity> e = *it; // entities->at(i);
auto itEnd = entities->end();
for (auto it = entities->begin(); it != itEnd; it++) {
std::shared_ptr<Entity> e = *it; // entities->at(i);
bool isAssignableFrom = false;
// Some special cases where the base class is a general type that
// our class may be derived from, otherwise do a direct comparison
// of type_info
if (ec == typeid(Player))
isAssignableFrom = e->instanceof(eTYPE_PLAYER);
else if (ec == typeid(Entity))
isAssignableFrom = e->instanceof(eTYPE_ENTITY);
else if (ec == typeid(Mob))
isAssignableFrom = e->instanceof(eTYPE_MOB);
else if (ec == typeid(LivingEntity))
isAssignableFrom = e->instanceof(eTYPE_LIVINGENTITY);
else if (ec == typeid(ItemEntity))
isAssignableFrom = e->instanceof(eTYPE_ITEMENTITY);
else if (ec == typeid(Minecart))
isAssignableFrom = e->instanceof(eTYPE_MINECART);
else if (ec == typeid(Monster))
isAssignableFrom = e->instanceof(eTYPE_MONSTER);
else if (ec == typeid(Zombie))
isAssignableFrom = e->instanceof(eTYPE_ZOMBIE);
else if (Entity* entity = e.get();
entity != nullptr && ec == typeid(*entity))
isAssignableFrom = true;
if (isAssignableFrom && e->bb.intersects(*bb)) {
if (selector == nullptr || selector->matches(e)) {
es.push_back(e);
bool isAssignableFrom = false;
// Some special cases where the base class is a general type
// that our class may be derived from, otherwise do a direct
// comparison of type_info
if (ec == typeid(Player))
isAssignableFrom = e->instanceof(eTYPE_PLAYER);
else if (ec == typeid(Entity))
isAssignableFrom = e->instanceof(eTYPE_ENTITY);
else if (ec == typeid(Mob))
isAssignableFrom = e->instanceof(eTYPE_MOB);
else if (ec == typeid(LivingEntity))
isAssignableFrom = e->instanceof(eTYPE_LIVINGENTITY);
else if (ec == typeid(ItemEntity))
isAssignableFrom = e->instanceof(eTYPE_ITEMENTITY);
else if (ec == typeid(Minecart))
isAssignableFrom = e->instanceof(eTYPE_MINECART);
else if (ec == typeid(Monster))
isAssignableFrom = e->instanceof(eTYPE_MONSTER);
else if (ec == typeid(Zombie))
isAssignableFrom = e->instanceof(eTYPE_ZOMBIE);
else if (Entity* entity = e.get();
entity != nullptr && ec == typeid(*entity))
isAssignableFrom = true;
if (isAssignableFrom && e->bb.intersects(*bb)) {
if (selector == nullptr || selector->matches(e)) {
es.push_back(e);
}
}
// 4J - note needs to be equivalent to
// baseClass.isAssignableFrom(e.getClass())
}
// 4J - note needs to be equivalent to
// baseClass.isAssignableFrom(e.getClass())
}
}
LeaveCriticalSection(&m_csEntities);
}
int LevelChunk::countEntities() {
int entityCount = 0;
#if defined(_ENTITIES_RW_SECTION)
EnterCriticalRWSection(&m_csEntities, false);
#else
EnterCriticalSection(&m_csEntities);
#endif
for (int yc = 0; yc < ENTITY_BLOCKS_LENGTH; yc++) {
entityCount += (int)entityBlocks[yc]->size();
{
std::lock_guard<std::recursive_mutex> lock(m_csEntities);
for (int yc = 0; yc < ENTITY_BLOCKS_LENGTH; yc++) {
entityCount += (int)entityBlocks[yc]->size();
}
}
#if defined(_ENTITIES_RW_SECTION)
LeaveCriticalRWSection(&m_csEntities, false);
#else
LeaveCriticalSection(&m_csEntities);
#endif
return entityCount;
}
@ -2219,14 +2155,15 @@ void LevelChunk::compressBlocks() {
// server again.
if (level->isClientSide && g_NetworkManager.IsHost()) {
// Note - only the extraction of the pointers needs to be done in the
// critical section, since even if the data is unshared whilst we are
// lock, since even if the data is unshared whilst we are
// processing this data is still valid (for the server)
EnterCriticalSection(&m_csSharing);
if (sharingTilesAndData) {
blocksToCompressLower = lowerBlocks;
blocksToCompressUpper = upperBlocks;
{
std::lock_guard<std::recursive_mutex> lock(m_csSharing);
if (sharingTilesAndData) {
blocksToCompressLower = lowerBlocks;
blocksToCompressUpper = upperBlocks;
}
}
LeaveCriticalSection(&m_csSharing);
} else {
// Not the host, simple case
blocksToCompressLower = lowerBlocks;
@ -2318,14 +2255,15 @@ void LevelChunk::compressData() {
// server again.
if (level->isClientSide && g_NetworkManager.IsHost()) {
// Note - only the extraction of the pointers needs to be done in the
// critical section, since even if the data is unshared whilst we are
// lock, since even if the data is unshared whilst we are
// processing this data is still valid (for the server)
EnterCriticalSection(&m_csSharing);
if (sharingTilesAndData) {
dataToCompressLower = lowerData;
dataToCompressUpper = upperData;
{
std::lock_guard<std::recursive_mutex> lock(m_csSharing);
if (sharingTilesAndData) {
dataToCompressLower = lowerData;
dataToCompressUpper = upperData;
}
}
LeaveCriticalSection(&m_csSharing);
} else {
// Not the host, simple case
dataToCompressLower = lowerData;

View file

@ -1,5 +1,7 @@
#pragma once
#include <mutex>
class DataLayer;
class TileEntity;
class Random;
@ -268,17 +270,11 @@ public:
virtual void attemptCompression();
#if defined(SHARING_ENABLED)
static CRITICAL_SECTION m_csSharing; // 4J added
static std::recursive_mutex m_csSharing; // 4J added
#endif
// 4J added
#if defined(_ENTITIES_RW_SECTION)
static CRITICAL_RW_SECTION
m_csEntities; // AP - we're using a RW critical so we can do multiple
// reads without contention
#else
static CRITICAL_SECTION m_csEntities;
#endif
static CRITICAL_SECTION m_csTileEntities; // 4J added
static std::recursive_mutex m_csEntities;
static std::recursive_mutex m_csTileEntities; // 4J added
static void staticCtor();
void checkPostProcess(ChunkSource* source, ChunkSource* parent, int x,
int z);

View file

@ -6,7 +6,7 @@
int CompressedTileStorage::deleteQueueIndex;
XLockFreeStack<unsigned char> CompressedTileStorage::deleteQueue[3];
CRITICAL_SECTION CompressedTileStorage::cs_write;
std::recursive_mutex CompressedTileStorage::cs_write;
#if defined(PSVITA_PRECOMPUTED_TABLE)
// AP - this will create a precomputed table to speed up getData
@ -33,17 +33,18 @@ CompressedTileStorage::CompressedTileStorage() {
}
CompressedTileStorage::CompressedTileStorage(CompressedTileStorage* copyFrom) {
EnterCriticalSection(&cs_write);
allocatedSize = copyFrom->allocatedSize;
if (allocatedSize > 0) {
indicesAndData = (unsigned char*)XPhysicalAlloc(
allocatedSize, MAXULONG_PTR, 4096,
PAGE_READWRITE); //(unsigned char *)malloc(allocatedSize);
XMemCpy(indicesAndData, copyFrom->indicesAndData, allocatedSize);
} else {
indicesAndData = nullptr;
{
std::lock_guard<std::recursive_mutex> lock(cs_write);
allocatedSize = copyFrom->allocatedSize;
if (allocatedSize > 0) {
indicesAndData = (unsigned char*)XPhysicalAlloc(
allocatedSize, MAXULONG_PTR, 4096,
PAGE_READWRITE); //(unsigned char *)malloc(allocatedSize);
XMemCpy(indicesAndData, copyFrom->indicesAndData, allocatedSize);
} else {
indicesAndData = nullptr;
}
}
LeaveCriticalSection(&cs_write);
#if defined(PSVITA_PRECOMPUTED_TABLE)
CompressedTileStorage_InitTable();
@ -139,9 +140,8 @@ bool CompressedTileStorage::isRenderChunkEmpty(
}
bool CompressedTileStorage::isSameAs(CompressedTileStorage* other) {
EnterCriticalSection(&cs_write);
std::lock_guard<std::recursive_mutex> lock(cs_write);
if (allocatedSize != other->allocatedSize) {
LeaveCriticalSection(&cs_write);
return false;
}
@ -166,7 +166,6 @@ bool CompressedTileStorage::isSameAs(CompressedTileStorage* other) {
d0 |= d2;
d4 |= d6;
if (d0 | d4) {
LeaveCriticalSection(&cs_write);
return false;
}
pOld += 8;
@ -178,12 +177,10 @@ bool CompressedTileStorage::isSameAs(CompressedTileStorage* other) {
unsigned char* pucNew = (unsigned char*)pNew;
for (int i = 0; i < allocatedSize - (quickCount * 64); i++) {
if (*pucOld++ != *pucNew++) {
LeaveCriticalSection(&cs_write);
return false;
}
}
LeaveCriticalSection(&cs_write);
return true;
}
@ -242,7 +239,7 @@ inline void CompressedTileStorage::getBlock(int* block, int x, int y, int z) {
void CompressedTileStorage::setData(byteArray dataIn, unsigned int inOffset) {
unsigned short _blockIndices[512];
EnterCriticalSection(&cs_write);
std::lock_guard<std::recursive_mutex> lock(cs_write);
unsigned char* data = dataIn.data + inOffset;
// Is the destination fully uncompressed? If so just write our data in -
@ -257,7 +254,6 @@ void CompressedTileStorage::setData(byteArray dataIn, unsigned int inOffset) {
*dataOut++ = data[getIndex(i, j)];
}
}
LeaveCriticalSection(&cs_write);
return;
}
@ -404,7 +400,6 @@ void CompressedTileStorage::setData(byteArray dataIn, unsigned int inOffset) {
}
indicesAndData = newIndicesAndData;
allocatedSize = memToAlloc;
LeaveCriticalSection(&cs_write);
}
#if defined(PSVITA_PRECOMPUTED_TABLE)
@ -596,7 +591,7 @@ int CompressedTileStorage::get(int x, int y, int z) {
// Set an individual tile value
void CompressedTileStorage::set(int x, int y, int z, int val) {
EnterCriticalSection(&cs_write);
std::lock_guard<std::recursive_mutex> lock(cs_write);
assert(val != 255);
int block, tile;
getBlockAndTile(&block, &tile, x, y, z);
@ -616,7 +611,6 @@ void CompressedTileStorage::set(int x, int y, int z, int val) {
// continue on to upgrade storage
if (val == ((blockIndices[block] >> INDEX_TILE_SHIFT) &
INDEX_TILE_MASK)) {
LeaveCriticalSection(&cs_write);
return;
}
} else {
@ -625,7 +619,6 @@ void CompressedTileStorage::set(int x, int y, int z, int val) {
data + ((blockIndices[block] >> INDEX_OFFSET_SHIFT) &
INDEX_OFFSET_MASK);
packed[tile] = val;
LeaveCriticalSection(&cs_write);
return;
}
} else {
@ -658,7 +651,6 @@ void CompressedTileStorage::set(int x, int y, int z, int val) {
int bit = (tile & indexmask_bits) * bitspertile;
packed[idx] &= ~(tiletypemask << bit);
packed[idx] |= i << bit;
LeaveCriticalSection(&cs_write);
return;
}
}
@ -667,7 +659,6 @@ void CompressedTileStorage::set(int x, int y, int z, int val) {
compress(block);
}
};
LeaveCriticalSection(&cs_write);
}
// Sets a region of tile values with the data at offset position in the array
@ -741,7 +732,6 @@ int CompressedTileStorage::getDataRegion(byteArray dataInOut, int x0, int y0,
}
void CompressedTileStorage::staticCtor() {
InitializeCriticalSectionAndSpinCount(&cs_write, 5120);
for (int i = 0; i < 3; i++) {
deleteQueue[i].Initialize();
}
@ -789,7 +779,7 @@ void CompressedTileStorage::compress(int upgradeBlock /*=-1*/) {
(upgradeBlock > -1); // If an upgrade block is specified, we'll always
// need to recompress - otherwise default to false
EnterCriticalSection(&cs_write);
std::lock_guard<std::recursive_mutex> lock(cs_write);
unsigned short* blockIndices = (unsigned short*)indicesAndData;
unsigned char* data = indicesAndData + 1024;
@ -1126,7 +1116,6 @@ void CompressedTileStorage::compress(int upgradeBlock /*=-1*/) {
indicesAndData = newIndicesAndData;
allocatedSize = memToAlloc;
}
LeaveCriticalSection(&cs_write);
}
int CompressedTileStorage::getAllocatedSize(int* count0, int* count1,

View file

@ -1,4 +1,5 @@
#pragma once
#include <mutex>
#if !defined(__linux__)
#include "../../Platform/x64headers/xmcore.h"
#endif
@ -157,7 +158,7 @@ public:
static unsigned char compressBuffer[32768 + 256];
static CRITICAL_SECTION cs_write;
static std::recursive_mutex cs_write;
int getAllocatedSize(int* count0, int* count1, int* count2, int* count4,
int* count8);

View file

@ -1,3 +1,4 @@
#include <mutex>
#include <thread>
#include <chrono>
@ -8,7 +9,7 @@
#include "../LevelData.h"
#include "McRegionChunkStorage.h"
CRITICAL_SECTION McRegionChunkStorage::cs_memory;
std::mutex McRegionChunkStorage::cs_memory;
std::deque<DataOutputStream*> McRegionChunkStorage::s_chunkDataQueue;
int McRegionChunkStorage::s_runningThreadCount = 0;
@ -181,11 +182,11 @@ void McRegionChunkStorage::save(Level* level, LevelChunk* levelChunk) {
// 4J - removed try/catch
// try {
// Note - have added use of a critical section round sections of code that
// Note - have added use of a mutex round sections of code that
// do a lot of memory alloc/free operations. This is because when we are
// running saves on multiple threads these sections have a lot of contention
// and thrash the memory system's critical sections Better to let each
// thread have its turn at a higher level of granularity.
// running saves on multiple threads these sections have a lot of
// contention. Better to let each thread have its turn at a higher level of
// granularity.
MemSect(30);
PIXBeginNamedEvent(0, "Getting output stream\n");
DataOutputStream* output = RegionFileCache::getChunkDataOutputStream(
@ -199,22 +200,25 @@ void McRegionChunkStorage::save(Level* level, LevelChunk* levelChunk) {
PIXEndNamedEvent();
PIXBeginNamedEvent(0, "Updating chunk queue");
EnterCriticalSection(&cs_memory);
s_chunkDataQueue.push_back(output);
LeaveCriticalSection(&cs_memory);
{
std::lock_guard<std::mutex> lock(cs_memory);
s_chunkDataQueue.push_back(output);
}
PIXEndNamedEvent();
} else {
EnterCriticalSection(&cs_memory);
PIXBeginNamedEvent(0, "Creating tags\n");
CompoundTag* tag = new CompoundTag();
CompoundTag* levelData = new CompoundTag();
tag->put(L"Level", levelData);
OldChunkStorage::save(levelChunk, level, levelData);
PIXEndNamedEvent();
PIXBeginNamedEvent(0, "NbtIo writing\n");
NbtIo::write(tag, output);
PIXEndNamedEvent();
LeaveCriticalSection(&cs_memory);
CompoundTag* tag;
{
std::lock_guard<std::mutex> lock(cs_memory);
PIXBeginNamedEvent(0, "Creating tags\n");
tag = new CompoundTag();
CompoundTag* levelData = new CompoundTag();
tag->put(L"Level", levelData);
OldChunkStorage::save(levelChunk, level, levelData);
PIXEndNamedEvent();
PIXBeginNamedEvent(0, "NbtIo writing\n");
NbtIo::write(tag, output);
PIXEndNamedEvent();
}
PIXBeginNamedEvent(0, "Output closing\n");
output->close();
PIXEndNamedEvent();
@ -222,12 +226,13 @@ void McRegionChunkStorage::save(Level* level, LevelChunk* levelChunk) {
// 4J Stu - getChunkDataOutputStream makes a new DataOutputStream that
// points to a new ChunkBuffer( ByteArrayOutputStream ) We should clean
// these up when we are done
EnterCriticalSection(&cs_memory);
PIXBeginNamedEvent(0, "Cleaning up\n");
output->deleteChildStream();
delete output;
delete tag;
LeaveCriticalSection(&cs_memory);
{
std::lock_guard<std::mutex> lock(cs_memory);
PIXBeginNamedEvent(0, "Cleaning up\n");
output->deleteChildStream();
delete output;
delete tag;
}
PIXEndNamedEvent();
}
MemSect(0);
@ -321,8 +326,6 @@ void McRegionChunkStorage::flush() {
}
void McRegionChunkStorage::staticCtor() {
InitializeCriticalSectionAndSpinCount(&cs_memory, 5120);
for (unsigned int i = 0; i < 3; ++i) {
char threadName[256];
sprintf(threadName, "McRegion Save thread %d\n", i);
@ -337,14 +340,14 @@ void McRegionChunkStorage::staticCtor() {
// Threads 1,3 and 5 are generally idle so use them
if (i == 0)
s_saveThreads[i]->SetProcessor(CPU_CORE_SAVE_THREAD_A);
s_saveThreads[i]->setProcessor(CPU_CORE_SAVE_THREAD_A);
else if (i == 1) {
s_saveThreads[i]->SetProcessor(CPU_CORE_SAVE_THREAD_B);
s_saveThreads[i]->setProcessor(CPU_CORE_SAVE_THREAD_B);
} else if (i == 2)
s_saveThreads[i]->SetProcessor(CPU_CORE_SAVE_THREAD_C);
s_saveThreads[i]->setProcessor(CPU_CORE_SAVE_THREAD_C);
// ResumeThread( saveThreads[j] );
s_saveThreads[i]->Run();
s_saveThreads[i]->run();
}
}
@ -356,29 +359,33 @@ int McRegionChunkStorage::runSaveThreadProc(void* lpParam) {
DataOutputStream* dos = nullptr;
while (running) {
if (TryEnterCriticalSection(&cs_memory)) {
lastQueueSize = s_chunkDataQueue.size();
if (lastQueueSize > 0) {
dos = s_chunkDataQueue.front();
s_chunkDataQueue.pop_front();
}
s_runningThreadCount++;
LeaveCriticalSection(&cs_memory);
{
std::unique_lock<std::mutex> lock(cs_memory, std::try_to_lock);
if (lock.owns_lock()) {
lastQueueSize = s_chunkDataQueue.size();
if (lastQueueSize > 0) {
dos = s_chunkDataQueue.front();
s_chunkDataQueue.pop_front();
}
s_runningThreadCount++;
lock.unlock();
if (dos) {
PIXBeginNamedEvent(0, "Saving chunk");
// app.DebugPrintf("Compressing chunk data (%d left)\n",
// lastQueueSize - 1);
dos->close();
dos->deleteChildStream();
PIXEndNamedEvent();
}
delete dos;
dos = nullptr;
if (dos) {
PIXBeginNamedEvent(0, "Saving chunk");
// app.DebugPrintf("Compressing chunk data (%d left)\n",
// lastQueueSize - 1);
dos->close();
dos->deleteChildStream();
PIXEndNamedEvent();
}
delete dos;
dos = nullptr;
EnterCriticalSection(&cs_memory);
s_runningThreadCount--;
LeaveCriticalSection(&cs_memory);
{
std::lock_guard<std::mutex> lock2(cs_memory);
s_runningThreadCount--;
}
}
}
// If there was more than one thing in the queue last time we checked,
@ -402,30 +409,36 @@ void McRegionChunkStorage::WaitIfTooManyQueuedChunks() { WaitForSaves(); }
// Static
void McRegionChunkStorage::WaitForAllSaves() {
// Wait for there to be no more tasks to be processed...
EnterCriticalSection(&cs_memory);
size_t queueSize = s_chunkDataQueue.size();
LeaveCriticalSection(&cs_memory);
size_t queueSize;
{
std::lock_guard<std::mutex> lock(cs_memory);
queueSize = s_chunkDataQueue.size();
}
while (queueSize > 0) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
EnterCriticalSection(&cs_memory);
queueSize = s_chunkDataQueue.size();
LeaveCriticalSection(&cs_memory);
{
std::lock_guard<std::mutex> lock(cs_memory);
queueSize = s_chunkDataQueue.size();
}
}
// And then wait for there to be no running threads that are processing
// these tasks
EnterCriticalSection(&cs_memory);
int runningThreadCount = s_runningThreadCount;
LeaveCriticalSection(&cs_memory);
int runningThreadCount;
{
std::lock_guard<std::mutex> lock(cs_memory);
runningThreadCount = s_runningThreadCount;
}
while (runningThreadCount > 0) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
EnterCriticalSection(&cs_memory);
runningThreadCount = s_runningThreadCount;
LeaveCriticalSection(&cs_memory);
{
std::lock_guard<std::mutex> lock(cs_memory);
runningThreadCount = s_runningThreadCount;
}
}
}
@ -435,17 +448,20 @@ void McRegionChunkStorage::WaitForSaves() {
static const int DESIRED_QUEUE_SIZE = 6;
// Wait for the queue to reduce to a level where we should add more elements
EnterCriticalSection(&cs_memory);
size_t queueSize = s_chunkDataQueue.size();
LeaveCriticalSection(&cs_memory);
size_t queueSize;
{
std::lock_guard<std::mutex> lock(cs_memory);
queueSize = s_chunkDataQueue.size();
}
if (queueSize > MAX_QUEUE_SIZE) {
while (queueSize > DESIRED_QUEUE_SIZE) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
EnterCriticalSection(&cs_memory);
queueSize = s_chunkDataQueue.size();
LeaveCriticalSection(&cs_memory);
{
std::lock_guard<std::mutex> lock(cs_memory);
queueSize = s_chunkDataQueue.size();
}
}
}
}

View file

@ -1,5 +1,7 @@
#pragma once
#include <mutex>
#include "ChunkStorage.h"
#include "../LevelChunk.h"
#include "RegionFileCache.h"
@ -12,7 +14,7 @@ class McRegionChunkStorage : public ChunkStorage {
private:
const std::wstring m_prefix;
ConsoleSaveFile* m_saveFile;
static CRITICAL_SECTION cs_memory;
static std::mutex cs_memory;
std::unordered_map<int64_t, byteArray> m_entityData;

View file

@ -1,4 +1,5 @@
#include "../../Platform/stdafx.h"
#include <mutex>
#include "../../IO/Files/File.h"
#include "../../IO/Streams/InputOutputStream.h"
#include "../../Headers/net.minecraft.world.entity.h"
@ -196,29 +197,22 @@ bool OldChunkStorage::saveEntities(LevelChunk* lc, Level* level,
lc->lastSaveHadEntities = false;
ListTag<CompoundTag>* entityTags = new ListTag<CompoundTag>();
#if defined(_ENTITIES_RW_SECTION)
EnterCriticalRWSection(&lc->m_csEntities, true);
#else
EnterCriticalSection(&lc->m_csEntities);
#endif
for (int i = 0; i < lc->ENTITY_BLOCKS_LENGTH; i++) {
auto itEnd = lc->entityBlocks[i]->end();
for (std::vector<std::shared_ptr<Entity> >::iterator it =
lc->entityBlocks[i]->begin();
it != itEnd; it++) {
std::shared_ptr<Entity> e = *it;
lc->lastSaveHadEntities = true;
CompoundTag* teTag = new CompoundTag();
if (e->save(teTag)) {
entityTags->add(teTag);
{
std::lock_guard<std::recursive_mutex> lock(lc->m_csEntities);
for (int i = 0; i < lc->ENTITY_BLOCKS_LENGTH; i++) {
auto itEnd = lc->entityBlocks[i]->end();
for (std::vector<std::shared_ptr<Entity> >::iterator it =
lc->entityBlocks[i]->begin();
it != itEnd; it++) {
std::shared_ptr<Entity> e = *it;
lc->lastSaveHadEntities = true;
CompoundTag* teTag = new CompoundTag();
if (e->save(teTag)) {
entityTags->add(teTag);
}
}
}
}
#if defined(_ENTITIES_RW_SECTION)
LeaveCriticalRWSection(&lc->m_csEntities, true);
#else
LeaveCriticalSection(&lc->m_csEntities);
#endif
tag->put(L"Entities", entityTags);

View file

@ -1,4 +1,5 @@
#include "../../Platform/stdafx.h"
#include <mutex>
#include "../../IO/Files/File.h"
#include "../../IO/Streams/ByteBuffer.h"
#include "../../Headers/net.minecraft.world.entity.h"
@ -214,28 +215,22 @@ void ZonedChunkStorage::saveEntities(Level* level, LevelChunk* lc) {
std::vector<CompoundTag*> tags;
#ifdef _ENTITIES_RW_SECTION
EnterCriticalRWSection(&lc->m_csEntities, true);
#else
EnterCriticalSection(&lc->m_csEntities);
#endif
for (int i = 0; i < LevelChunk::ENTITY_BLOCKS_LENGTH; i++) {
std::vector<std::shared_ptr<Entity> >* entities = lc->entityBlocks[i];
{
std::lock_guard<std::mutex> lock(lc->m_csEntities);
for (int i = 0; i < LevelChunk::ENTITY_BLOCKS_LENGTH; i++) {
std::vector<std::shared_ptr<Entity> >* entities =
lc->entityBlocks[i];
auto itEndTags = entities->end();
for (auto it = entities->begin(); it != itEndTags; it++) {
std::shared_ptr<Entity> e = *it; // entities->at(j);
CompoundTag* cp = new CompoundTag();
cp->putInt(L"_TYPE", 0);
e->save(cp);
tags.push_back(cp);
auto itEndTags = entities->end();
for (auto it = entities->begin(); it != itEndTags; it++) {
std::shared_ptr<Entity> e = *it; // entities->at(j);
CompoundTag* cp = new CompoundTag();
cp->putInt(L"_TYPE", 0);
e->save(cp);
tags.push_back(cp);
}
}
}
#ifdef _ENTITIES_RW_SECTION
LeaveCriticalRWSection(&lc->m_csEntities, true);
#else
LeaveCriticalSection(&lc->m_csEntities);
#endif
for (std::unordered_map<TilePos, std::shared_ptr<TileEntity>,
TilePosKeyHash, TilePosKeyEq>::iterator it =

View file

@ -22,10 +22,6 @@ int Connection::writeSizes[256];
void Connection::_init() {
// printf("Con:0x%x init\n",this);
InitializeCriticalSection(&writeLock);
InitializeCriticalSection(&threadCounterLock);
InitializeCriticalSection(&incoming_cs);
running = true;
quitting = false;
disconnected = false;
@ -42,7 +38,6 @@ void Connection::_init() {
tickCount = 0;
}
// 4J Jev, need to delete the critical section.
Connection::~Connection() {
// 4J Stu - Just to be sure, make sure the read and write threads terminate
// themselves before the connection object is destroyed
@ -51,12 +46,8 @@ Connection::~Connection() {
dis->close(); // The input stream needs closed before the readThread,
// or the readThread may get stuck whilst blocking
// waiting on a read
readThread->WaitForCompletion(INFINITE);
writeThread->WaitForCompletion(INFINITE);
DeleteCriticalSection(&writeLock);
DeleteCriticalSection(&threadCounterLock);
DeleteCriticalSection(&incoming_cs);
readThread->waitForCompletion(C4JThread::kInfiniteTimeout);
writeThread->waitForCompletion(C4JThread::kInfiniteTimeout);
delete m_hWakeReadThread;
delete m_hWakeWriteThread;
@ -120,11 +111,11 @@ Connection::Connection(Socket* socket, const std::wstring& id,
new C4JThread(runRead, (void*)this, readThreadName, READ_STACK_SIZE);
writeThread =
new C4JThread(runWrite, this, writeThreadName, WRITE_STACK_SIZE);
readThread->SetProcessor(CPU_CORE_CONNECTIONS);
writeThread->SetProcessor(CPU_CORE_CONNECTIONS);
readThread->setProcessor(CPU_CORE_CONNECTIONS);
writeThread->setProcessor(CPU_CORE_CONNECTIONS);
readThread->Run();
writeThread->Run();
readThread->run();
writeThread->run();
/* 4J JEV, java:
new Thread(wstring(id).append(L" read thread")) {
@ -150,29 +141,31 @@ void Connection::send(std::shared_ptr<Packet> packet) {
MemSect(15);
// 4J Jev, synchronized (&writeLock)
EnterCriticalSection(&writeLock);
{
std::lock_guard<std::mutex> lock(writeLock);
estimatedRemaining += packet->getEstimatedSize() + 1;
if (packet->shouldDelay) {
// 4J We have delayed it enough by putting it in the slow queue, so
// don't delay when we actually send it
packet->shouldDelay = false;
outgoing_slow.push(packet);
} else {
outgoing.push(packet);
estimatedRemaining += packet->getEstimatedSize() + 1;
if (packet->shouldDelay) {
// 4J We have delayed it enough by putting it in the slow queue, so
// don't delay when we actually send it
packet->shouldDelay = false;
outgoing_slow.push(packet);
} else {
outgoing.push(packet);
}
}
// 4J Jev, end synchronized.
LeaveCriticalSection(&writeLock);
MemSect(0);
}
void Connection::queueSend(std::shared_ptr<Packet> packet) {
if (quitting) return;
EnterCriticalSection(&writeLock);
estimatedRemaining += packet->getEstimatedSize() + 1;
outgoing_slow.push(packet);
LeaveCriticalSection(&writeLock);
{
std::lock_guard<std::mutex> lock(writeLock);
estimatedRemaining += packet->getEstimatedSize() + 1;
outgoing_slow.push(packet);
}
}
bool Connection::writeTick() {
@ -189,13 +182,13 @@ bool Connection::writeTick() {
fakeLag)) {
std::shared_ptr<Packet> packet;
EnterCriticalSection(&writeLock);
{
std::lock_guard<std::mutex> lock(writeLock);
packet = outgoing.front();
outgoing.pop();
estimatedRemaining -= packet->getEstimatedSize() + 1;
LeaveCriticalSection(&writeLock);
packet = outgoing.front();
outgoing.pop();
estimatedRemaining -= packet->getEstimatedSize() + 1;
}
Packet::writePacket(packet, bufferedDos);
#if defined(__linux__)
@ -238,13 +231,13 @@ bool Connection::writeTick() {
// synchronized (writeLock) {
EnterCriticalSection(&writeLock);
{
std::lock_guard<std::mutex> lock(writeLock);
packet = outgoing_slow.front();
outgoing_slow.pop();
estimatedRemaining -= packet->getEstimatedSize() + 1;
LeaveCriticalSection(&writeLock);
packet = outgoing_slow.front();
outgoing_slow.pop();
estimatedRemaining -= packet->getEstimatedSize() + 1;
}
// If the shouldDelay flag is still set at this point then we want to
// write it to QNet as a single packet with priority flags Otherwise
@ -311,8 +304,8 @@ void Connection::flush() {
// multithreaded functions a bit more
// readThread.interrupt();
// writeThread.interrupt();
m_hWakeReadThread->Set();
m_hWakeWriteThread->Set();
m_hWakeReadThread->set();
m_hWakeWriteThread->set();
}
bool Connection::readTick() {
@ -329,11 +322,12 @@ bool Connection::readTick() {
if (packet != nullptr) {
readSizes[packet->getId()] += packet->getEstimatedSize() + 1;
EnterCriticalSection(&incoming_cs);
if (!quitting) {
incoming.push(packet);
{
std::lock_guard<std::mutex> lock(incoming_cs);
if (!quitting) {
incoming.push(packet);
}
}
LeaveCriticalSection(&incoming_cs);
didSomething = true;
} else {
// printf("Con:0x%x readTick close EOS\n",this);
@ -394,8 +388,8 @@ void Connection::close(DisconnectPacket::eDisconnectReason reason) {
// Make sure that the read & write threads are dead before we go and kill
// the streams that they depend on
readThread->WaitForCompletion(INFINITE);
writeThread->WaitForCompletion(INFINITE);
readThread->waitForCompletion(C4JThread::kInfiniteTimeout);
writeThread->waitForCompletion(C4JThread::kInfiniteTimeout);
delete dis;
dis = nullptr;
@ -420,9 +414,11 @@ void Connection::tick() {
if (estimatedRemaining > 1 * 1024 * 1024) {
close(DisconnectPacket::eDisconnect_Overflow);
}
EnterCriticalSection(&incoming_cs);
bool empty = incoming.empty();
LeaveCriticalSection(&incoming_cs);
bool empty;
{
std::lock_guard<std::mutex> lock(incoming_cs);
empty = incoming.empty();
}
if (empty) {
#if CONNECTION_ENABLE_TIMEOUT_DISCONNECT
if (noInputTicks++ == MAX_TICKS_WITHOUT_INPUT) {
@ -461,16 +457,18 @@ void Connection::tick() {
// changed to use a eAppAction_ExitPlayerPreLogin which will run in the main
// loop, so the connection will not be ticked at that point
EnterCriticalSection(&incoming_cs);
// 4J Stu - If disconnected, then we shouldn't process incoming packets
std::vector<std::shared_ptr<Packet> > packetsToHandle;
while (!disconnected && !g_NetworkManager.IsLeavingGame() &&
g_NetworkManager.IsInSession() && !incoming.empty() && max-- >= 0) {
std::shared_ptr<Packet> packet = incoming.front();
packetsToHandle.push_back(packet);
incoming.pop();
{
std::lock_guard<std::mutex> lock(incoming_cs);
while (!disconnected && !g_NetworkManager.IsLeavingGame() &&
g_NetworkManager.IsInSession() && !incoming.empty() &&
max-- >= 0) {
std::shared_ptr<Packet> packet = incoming.front();
packetsToHandle.push_back(packet);
incoming.pop();
}
}
LeaveCriticalSection(&incoming_cs);
// MGH - moved the packet handling outside of the incoming_cs block, as it
// was locking up sometimes when disconnecting
@ -490,11 +488,13 @@ void Connection::tick() {
}
// 4J - split the following condition (used to be disconnect &&
// iscoming.empty()) so we can wrap the access in a critical section
// iscoming.empty()) so we can wrap the access in a mutex
if (disconnected) {
EnterCriticalSection(&incoming_cs);
bool empty = incoming.empty();
LeaveCriticalSection(&incoming_cs);
bool empty;
{
std::lock_guard<std::mutex> lock(incoming_cs);
empty = incoming.empty();
}
if (empty) {
packetListener->onDisconnect(disconnectReason,
disconnectReasonObjects);
@ -540,11 +540,12 @@ int Connection::runRead(void* lpParam) {
Compression::UseDefaultThreadStorage();
CRITICAL_SECTION* cs = &con->threadCounterLock;
std::mutex* cs = &con->threadCounterLock;
EnterCriticalSection(cs);
con->readThreads++;
LeaveCriticalSection(cs);
{
std::lock_guard<std::mutex> lock(*cs);
con->readThreads++;
}
// try {
@ -558,7 +559,7 @@ int Connection::runRead(void* lpParam) {
// std::this_thread::sleep_for(std::chrono::milliseconds(100L));
// TODO - 4J Stu - 1.8.2 changes these sleeps to 2L, but not sure
// whether we should do that as well
con->m_hWakeReadThread->WaitForSignal(100L);
con->m_hWakeReadThread->waitForSignal(100L);
}
MemSect(0);
@ -587,36 +588,38 @@ int Connection::runWrite(void* lpParam) {
Compression::UseDefaultThreadStorage();
CRITICAL_SECTION* cs = &con->threadCounterLock;
std::mutex* cs = &con->threadCounterLock;
EnterCriticalSection(cs);
con->writeThreads++;
LeaveCriticalSection(cs);
{
std::lock_guard<std::mutex> lock(*cs);
con->writeThreads++;
}
// 4J Stu - Adding this to force us to run through the writeTick at least
// once after the event is fired Otherwise there is a race between the
// calling thread setting the running flag and this loop checking the
// condition
unsigned int waitResult = WAIT_TIMEOUT;
unsigned int waitResult = C4JThread::WaitResult::Timeout;
while (
(con->running || waitResult == WAIT_OBJECT_0) &&
(con->running || waitResult == C4JThread::WaitResult::Signaled) &&
ShutdownManager::ShouldRun(ShutdownManager::eConnectionWriteThreads)) {
while (con->writeTick());
// std::this_thread::sleep_for(std::chrono::milliseconds(100L));
// TODO - 4J Stu - 1.8.2 changes these sleeps to 2L, but not sure
// whether we should do that as well
waitResult = con->m_hWakeWriteThread->WaitForSignal(100L);
waitResult = con->m_hWakeWriteThread->waitForSignal(100L);
if (con->bufferedDos != nullptr) con->bufferedDos->flush();
// if (con->byteArrayDos != nullptr) con->byteArrayDos->flush();
}
// 4J was in a finally block.
EnterCriticalSection(cs);
con->writeThreads--;
LeaveCriticalSection(cs);
{
std::lock_guard<std::mutex> lock(*cs);
con->writeThreads--;
}
ShutdownManager::HasFinished(ShutdownManager::eConnectionWriteThreads);
return 0;

View file

@ -8,6 +8,8 @@
#include "../Headers/net.minecraft.network.packet.h"
#include "../Util/C4JThread.h"
#include <mutex>
#include "Socket.h"
// 4J JEV, size of the threads (bytes).
@ -53,15 +55,14 @@ private:
bool running;
std::queue<std::shared_ptr<Packet> >
incoming; // 4J - was using synchronizedList...
CRITICAL_SECTION incoming_cs; // ... now has this critical section
incoming; // 4J - was using synchronizedList...
std::mutex incoming_cs; // ... now has this mutex
std::queue<std::shared_ptr<Packet> >
outgoing; // 4J - was using synchronizedList - but don't think it is
// required as usage is wrapped in writeLock critical section
// required as usage is wrapped in writeLock
std::queue<std::shared_ptr<Packet> >
outgoing_slow; // 4J - was using synchronizedList - but don't think it
// is required as usage is wrapped in writeLock critical
// section
// is required as usage is wrapped in writeLock
PacketListener* packetListener;
bool quitting;
@ -93,11 +94,10 @@ private:
void _init();
// 4J Jev, these might be better of as private
CRITICAL_SECTION threadCounterLock;
CRITICAL_SECTION writeLock;
std::mutex threadCounterLock;
std::mutex writeLock;
public:
// 4J Jev, need to delete the critical section.
~Connection();
Connection(Socket* socket, const std::wstring& id,
PacketListener* packetListener); // throws IOException

View file

@ -14,7 +14,7 @@
// link. 2 sockets can be created, one for either end of this local link, the
// end (0 or 1) is passed as a parameter to the ctor.
CRITICAL_SECTION Socket::s_hostQueueLock[2];
std::mutex Socket::s_hostQueueLock[2];
std::queue<std::uint8_t> Socket::s_hostQueue[2];
Socket::SocketOutputStreamLocal* Socket::s_hostOutStream[2];
Socket::SocketInputStreamLocal* Socket::s_hostInStream[2];
@ -26,7 +26,6 @@ void Socket::EnsureStreamsInitialised() {
// concurrently.
static bool initialized = []() -> bool {
for (int i = 0; i < 2; i++) {
InitializeCriticalSection(&Socket::s_hostQueueLock[i]);
s_hostOutStream[i] = new SocketOutputStreamLocal(i);
s_hostInStream[i] = new SocketInputStreamLocal(i);
}
@ -47,11 +46,14 @@ void Socket::Initialise(ServerConnection* serverConnection) {
if (init) {
// Streams already exist just reset queue state and re-open streams.
for (int i = 0; i < 2; i++) {
if (TryEnterCriticalSection(&s_hostQueueLock[i])) {
// Clear the queue
std::queue<std::uint8_t> empty;
std::swap(s_hostQueue[i], empty);
LeaveCriticalSection(&s_hostQueueLock[i]);
{
std::unique_lock<std::mutex> lock(s_hostQueueLock[i],
std::try_to_lock);
if (lock.owns_lock()) {
// Clear the queue
std::queue<std::uint8_t> empty;
std::swap(s_hostQueue[i], empty);
}
}
s_hostOutStream[i]->m_streamOpen = true;
s_hostInStream[i]->m_streamOpen = true;
@ -94,7 +96,6 @@ Socket::Socket(INetworkPlayer* player, bool response /* = false*/,
m_hostLocal = hostLocal;
for (int i = 0; i < 2; i++) {
InitializeCriticalSection(&m_queueLockNetwork[i]);
m_inputStream[i] = nullptr;
m_outputStream[i] = nullptr;
m_endClosed[i] = false;
@ -143,11 +144,12 @@ void Socket::pushDataToQueue(const std::uint8_t* pbData, std::size_t dataSize,
return;
}
EnterCriticalSection(&m_queueLockNetwork[queueIdx]);
for (std::size_t i = 0; i < dataSize; ++i) {
m_queueNetwork[queueIdx].push(*pbData++);
{
std::lock_guard<std::mutex> lock(m_queueLockNetwork[queueIdx]);
for (std::size_t i = 0; i < dataSize; ++i) {
m_queueNetwork[queueIdx].push(*pbData++);
}
}
LeaveCriticalSection(&m_queueLockNetwork[queueIdx]);
}
void Socket::addIncomingSocket(Socket* socket) {
@ -226,7 +228,7 @@ bool Socket::close(bool isServerConnection) {
m_endClosed[m_end] = true;
}
if (allClosed && m_socketClosedEvent != nullptr) {
m_socketClosedEvent->Set();
m_socketClosedEvent->set();
}
if (allClosed) createdOk = false;
return allClosed;
@ -244,14 +246,16 @@ Socket::SocketInputStreamLocal::SocketInputStreamLocal(int queueIdx) {
int Socket::SocketInputStreamLocal::read() {
while (m_streamOpen && ShutdownManager::ShouldRun(
ShutdownManager::eConnectionReadThreads)) {
if (TryEnterCriticalSection(&s_hostQueueLock[m_queueIdx])) {
if (s_hostQueue[m_queueIdx].size()) {
std::uint8_t retval = s_hostQueue[m_queueIdx].front();
s_hostQueue[m_queueIdx].pop();
LeaveCriticalSection(&s_hostQueueLock[m_queueIdx]);
return retval;
{
std::unique_lock<std::mutex> lock(s_hostQueueLock[m_queueIdx],
std::try_to_lock);
if (lock.owns_lock()) {
if (s_hostQueue[m_queueIdx].size()) {
std::uint8_t retval = s_hostQueue[m_queueIdx].front();
s_hostQueue[m_queueIdx].pop();
return retval;
}
}
LeaveCriticalSection(&s_hostQueueLock[m_queueIdx]);
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
@ -269,16 +273,18 @@ int Socket::SocketInputStreamLocal::read(byteArray b) {
int Socket::SocketInputStreamLocal::read(byteArray b, unsigned int offset,
unsigned int length) {
while (m_streamOpen) {
if (TryEnterCriticalSection(&s_hostQueueLock[m_queueIdx])) {
if (s_hostQueue[m_queueIdx].size() >= length) {
for (unsigned int i = 0; i < length; i++) {
b[i + offset] = s_hostQueue[m_queueIdx].front();
s_hostQueue[m_queueIdx].pop();
{
std::unique_lock<std::mutex> lock(s_hostQueueLock[m_queueIdx],
std::try_to_lock);
if (lock.owns_lock()) {
if (s_hostQueue[m_queueIdx].size() >= length) {
for (unsigned int i = 0; i < length; i++) {
b[i + offset] = s_hostQueue[m_queueIdx].front();
s_hostQueue[m_queueIdx].pop();
}
return length;
}
LeaveCriticalSection(&s_hostQueueLock[m_queueIdx]);
return length;
}
LeaveCriticalSection(&s_hostQueueLock[m_queueIdx]);
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
@ -287,9 +293,10 @@ int Socket::SocketInputStreamLocal::read(byteArray b, unsigned int offset,
void Socket::SocketInputStreamLocal::close() {
m_streamOpen = false;
EnterCriticalSection(&s_hostQueueLock[m_queueIdx]);
std::queue<std::uint8_t>().swap(s_hostQueue[m_queueIdx]);
LeaveCriticalSection(&s_hostQueueLock[m_queueIdx]);
{
std::lock_guard<std::mutex> lock(s_hostQueueLock[m_queueIdx]);
std::queue<std::uint8_t>().swap(s_hostQueue[m_queueIdx]);
}
}
/////////////////////////////////// Socket for output, on local connection
@ -304,9 +311,10 @@ void Socket::SocketOutputStreamLocal::write(unsigned int b) {
if (m_streamOpen != true) {
return;
}
EnterCriticalSection(&s_hostQueueLock[m_queueIdx]);
s_hostQueue[m_queueIdx].push((std::uint8_t)b);
LeaveCriticalSection(&s_hostQueueLock[m_queueIdx]);
{
std::lock_guard<std::mutex> lock(s_hostQueueLock[m_queueIdx]);
s_hostQueue[m_queueIdx].push((std::uint8_t)b);
}
}
void Socket::SocketOutputStreamLocal::write(byteArray b) {
@ -319,19 +327,21 @@ void Socket::SocketOutputStreamLocal::write(byteArray b, unsigned int offset,
return;
}
MemSect(12);
EnterCriticalSection(&s_hostQueueLock[m_queueIdx]);
for (unsigned int i = 0; i < length; i++) {
s_hostQueue[m_queueIdx].push(b[offset + i]);
{
std::lock_guard<std::mutex> lock(s_hostQueueLock[m_queueIdx]);
for (unsigned int i = 0; i < length; i++) {
s_hostQueue[m_queueIdx].push(b[offset + i]);
}
}
LeaveCriticalSection(&s_hostQueueLock[m_queueIdx]);
MemSect(0);
}
void Socket::SocketOutputStreamLocal::close() {
m_streamOpen = false;
EnterCriticalSection(&s_hostQueueLock[m_queueIdx]);
std::queue<std::uint8_t>().swap(s_hostQueue[m_queueIdx]);
LeaveCriticalSection(&s_hostQueueLock[m_queueIdx]);
{
std::lock_guard<std::mutex> lock(s_hostQueueLock[m_queueIdx]);
std::queue<std::uint8_t>().swap(s_hostQueue[m_queueIdx]);
}
}
/////////////////////////////////// Socket for input, on network connection
@ -348,16 +358,17 @@ Socket::SocketInputStreamNetwork::SocketInputStreamNetwork(Socket* socket,
int Socket::SocketInputStreamNetwork::read() {
while (m_streamOpen && ShutdownManager::ShouldRun(
ShutdownManager::eConnectionReadThreads)) {
if (TryEnterCriticalSection(
&m_socket->m_queueLockNetwork[m_queueIdx])) {
if (m_socket->m_queueNetwork[m_queueIdx].size()) {
std::uint8_t retval =
m_socket->m_queueNetwork[m_queueIdx].front();
m_socket->m_queueNetwork[m_queueIdx].pop();
LeaveCriticalSection(&m_socket->m_queueLockNetwork[m_queueIdx]);
return retval;
{
std::unique_lock<std::mutex> lock(
m_socket->m_queueLockNetwork[m_queueIdx], std::try_to_lock);
if (lock.owns_lock()) {
if (m_socket->m_queueNetwork[m_queueIdx].size()) {
std::uint8_t retval =
m_socket->m_queueNetwork[m_queueIdx].front();
m_socket->m_queueNetwork[m_queueIdx].pop();
return retval;
}
}
LeaveCriticalSection(&m_socket->m_queueLockNetwork[m_queueIdx]);
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
@ -375,18 +386,19 @@ int Socket::SocketInputStreamNetwork::read(byteArray b) {
int Socket::SocketInputStreamNetwork::read(byteArray b, unsigned int offset,
unsigned int length) {
while (m_streamOpen) {
if (TryEnterCriticalSection(
&m_socket->m_queueLockNetwork[m_queueIdx])) {
if (m_socket->m_queueNetwork[m_queueIdx].size() >= length) {
for (unsigned int i = 0; i < length; i++) {
b[i + offset] =
m_socket->m_queueNetwork[m_queueIdx].front();
m_socket->m_queueNetwork[m_queueIdx].pop();
{
std::unique_lock<std::mutex> lock(
m_socket->m_queueLockNetwork[m_queueIdx], std::try_to_lock);
if (lock.owns_lock()) {
if (m_socket->m_queueNetwork[m_queueIdx].size() >= length) {
for (unsigned int i = 0; i < length; i++) {
b[i + offset] =
m_socket->m_queueNetwork[m_queueIdx].front();
m_socket->m_queueNetwork[m_queueIdx].pop();
}
return length;
}
LeaveCriticalSection(&m_socket->m_queueLockNetwork[m_queueIdx]);
return length;
}
LeaveCriticalSection(&m_socket->m_queueLockNetwork[m_queueIdx]);
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
@ -441,11 +453,13 @@ void Socket::SocketOutputStreamNetwork::writeWithFlags(byteArray b,
else
queueIdx = SOCKET_CLIENT_END;
EnterCriticalSection(&m_socket->m_queueLockNetwork[queueIdx]);
for (unsigned int i = 0; i < length; i++) {
m_socket->m_queueNetwork[queueIdx].push(b[offset + i]);
{
std::lock_guard<std::mutex> lock(
m_socket->m_queueLockNetwork[queueIdx]);
for (unsigned int i = 0; i < length; i++) {
m_socket->m_queueNetwork[queueIdx].push(b[offset + i]);
}
}
LeaveCriticalSection(&m_socket->m_queueLockNetwork[queueIdx]);
} else {
XRNM_SEND_BUFFER buffer;
buffer.pbyData = &b[offset];

View file

@ -5,6 +5,7 @@
#include <xrnm.h>
#include <qnet.h>
#endif
#include <mutex>
#include <queue>
#include "../IO/Streams/InputStream.h"
#include "../IO/Streams/OutputStream.h"
@ -107,14 +108,14 @@ private:
int m_end; // 0 for client side or 1 for host side
// For local connections between the host player and the server
static CRITICAL_SECTION s_hostQueueLock[2];
static std::mutex s_hostQueueLock[2];
static std::queue<std::uint8_t> s_hostQueue[2];
static SocketOutputStreamLocal* s_hostOutStream[2];
static SocketInputStreamLocal* s_hostInStream[2];
// For network connections
std::queue<std::uint8_t> m_queueNetwork[2]; // For input data
CRITICAL_SECTION m_queueLockNetwork[2]; // For input data
std::mutex m_queueLockNetwork[2]; // For input data
SocketInputStreamNetwork* m_inputStream[2];
SocketOutputStreamNetwork* m_outputStream[2];
bool m_endClosed[2];

File diff suppressed because it is too large Load diff

View file

@ -3,7 +3,6 @@
#include <atomic>
#include <condition_variable>
#include <cstdint>
#include <limits>
#include <memory>
#include <mutex>
#include <queue>
@ -37,19 +36,37 @@ inline constexpr int CPU_CORE_LEADERBOARDS = 5;
class C4JThread {
public:
struct WaitResult {
static constexpr std::uint32_t Signaled = 0;
static constexpr std::uint32_t Timeout = 258;
};
enum class ThreadPriority : int {
Idle = -15,
Lowest = -2,
BelowNormal = -1,
Normal = 0,
AboveNormal = 1,
Highest = 2,
TimeCritical = 15
};
static constexpr int kInfiniteTimeout = -1;
static constexpr int kStillActive = 259;
class Event {
public:
enum EMode { e_modeAutoClear, e_modeManualClear };
enum class Mode { AutoClear, ManualClear };
explicit Event(EMode mode = e_modeAutoClear);
explicit Event(Mode mode = Mode::AutoClear);
~Event() = default;
void Set();
void Clear();
std::uint32_t WaitForSignal(int timeoutMs);
void set();
void clear();
std::uint32_t waitForSignal(int timeoutMs);
private:
EMode m_mode;
Mode m_mode;
std::mutex m_mutex;
std::condition_variable m_condition;
bool m_signaled;
@ -57,21 +74,21 @@ public:
class EventArray {
public:
enum EMode { e_modeAutoClear, e_modeManualClear };
enum class Mode { AutoClear, ManualClear };
explicit EventArray(int size, EMode mode = e_modeAutoClear);
explicit EventArray(int size, Mode mode = Mode::AutoClear);
void Set(int index);
void Clear(int index);
void SetAll();
void ClearAll();
std::uint32_t WaitForAll(int timeoutMs);
std::uint32_t WaitForAny(int timeoutMs);
std::uint32_t WaitForSingle(int index, int timeoutMs);
void set(int index);
void clear(int index);
void setAll();
void clearAll();
std::uint32_t waitForAll(int timeoutMs);
std::uint32_t waitForAny(int timeoutMs);
std::uint32_t waitForSingle(int index, int timeoutMs);
private:
int m_size;
EMode m_mode;
Mode m_mode;
std::mutex m_mutex;
std::condition_variable m_condition;
std::uint32_t m_signaledMask;
@ -90,7 +107,7 @@ public:
EventQueue& operator=(const EventQueue&) = delete;
void setProcessor(int proc);
void setPriority(int priority);
void setPriority(ThreadPriority priority);
void sendEvent(Level* pLevel);
void waitForFinish();
@ -108,7 +125,7 @@ public:
ThreadInitFunc* m_threadInitFunc;
std::string m_threadName;
int m_processor;
int m_priority;
ThreadPriority m_priority;
bool m_busy;
std::once_flag m_initOnce;
std::atomic<bool> m_stopRequested;
@ -122,24 +139,25 @@ public:
C4JThread(const C4JThread&) = delete;
C4JThread& operator=(const C4JThread&) = delete;
void Run();
void run();
[[nodiscard]] bool isRunning() const noexcept { return m_isRunning.load(); }
[[nodiscard]] bool isRunning() const noexcept {
return m_isRunning.load(std::memory_order_acquire);
}
[[nodiscard]] bool hasStarted() const noexcept {
return m_hasStarted.load();
return m_hasStarted.load(std::memory_order_acquire);
}
void SetProcessor(int proc);
void SetPriority(int priority);
void setProcessor(int proc);
void setPriority(ThreadPriority priority);
std::uint32_t WaitForCompletion(int timeoutMs);
[[nodiscard]] int GetExitCode() const noexcept;
std::uint32_t waitForCompletion(int timeoutMs);
[[nodiscard]] int getExitCode() const noexcept;
[[nodiscard]] const char* getName() const noexcept {
return m_threadName.c_str();
}
static void Sleep(int millisecs);
static C4JThread* getCurrentThread() noexcept;
static bool isMainThread() noexcept;
@ -148,11 +166,16 @@ public:
return pThread ? pThread->getName() : "(4J) Unknown thread";
}
static void SetThreadName(std::uint32_t threadId, const char* threadName);
static void SetCurrentThreadName(const char* threadName);
static void setThreadName(std::uint32_t threadId, const char* threadName);
static void setCurrentThreadName(const char* threadName);
static void PushAffinityAllCores();
static void PopAffinity();
static void pushAffinityAllCores();
static void popAffinity();
// TODO(C++26): When we switch to C++26, replace EventQueue with
// std::execution (senders/receivers) for structured concurrency.
// TODO(C++26): When we switch to C++26, use std::hazard_pointer / std::rcu
// for lock-free data structure reclamation.
private:
static void entryPoint(C4JThread* pThread);
@ -171,8 +194,8 @@ private:
std::unique_ptr<Event> m_completionFlag;
std::atomic<int> m_requestedProcessor;
std::atomic<int> m_requestedPriority;
std::atomic<ThreadPriority> m_requestedPriority;
std::atomic<std::int64_t> m_nativeTid;
static thread_local C4JThread* ms_currentThread;
};
};

View file

@ -67,8 +67,6 @@ BiomeCache::BiomeCache(BiomeSource* source) {
lastUpdateTime = 0;
this->source = source;
InitializeCriticalSection(&m_CS);
}
BiomeCache::~BiomeCache() {
@ -78,11 +76,10 @@ BiomeCache::~BiomeCache() {
for (auto it = all.begin(); it != all.end(); ++it) {
delete (*it);
}
DeleteCriticalSection(&m_CS);
}
BiomeCache::Block* BiomeCache::getBlockAt(int x, int z) {
EnterCriticalSection(&m_CS);
std::lock_guard<std::mutex> lock(m_CS);
x >>= ZONE_SIZE_BITS;
z >>= ZONE_SIZE_BITS;
int64_t slot =
@ -99,7 +96,6 @@ BiomeCache::Block* BiomeCache::getBlockAt(int x, int z) {
block = it->second;
}
block->lastUse = app.getAppTime();
LeaveCriticalSection(&m_CS);
return block;
}
@ -116,7 +112,7 @@ float BiomeCache::getDownfall(int x, int z) {
}
void BiomeCache::update() {
EnterCriticalSection(&m_CS);
std::lock_guard<std::mutex> lock(m_CS);
int64_t now = app.getAppTime();
int64_t utime = now - lastUpdateTime;
if (utime > DECAY_TIME / 4 || utime < 0) {
@ -136,7 +132,6 @@ void BiomeCache::update() {
}
}
}
LeaveCriticalSection(&m_CS);
}
BiomeArray BiomeCache::getBiomeBlockAt(int x, int z) {

View file

@ -1,4 +1,5 @@
#pragma once
#include <mutex>
#include "../Minecraft.World/Util/JavaIntHash.h"
class BiomeCache {
@ -48,5 +49,5 @@ public:
byteArray getBiomeIndexBlockAt(int x, int z);
private:
CRITICAL_SECTION m_CS;
std::mutex m_CS;
};