diff --git a/Minecraft.Client/Common/Network/NetworkSocketLayer.cpp b/Minecraft.Client/Common/Network/NetworkSocketLayer.cpp index b76c5716..9536e272 100644 --- a/Minecraft.Client/Common/Network/NetworkSocketLayer.cpp +++ b/Minecraft.Client/Common/Network/NetworkSocketLayer.cpp @@ -143,7 +143,9 @@ bool NetworkSocketLayer::Initialize() s_initialized = true; +#ifndef _DEDICATED_SERVER StartDiscovery(); +#endif return true; } diff --git a/Minecraft.Client/MinecraftServer.cpp b/Minecraft.Client/MinecraftServer.cpp index eae6c64a..67f5e027 100644 --- a/Minecraft.Client/MinecraftServer.cpp +++ b/Minecraft.Client/MinecraftServer.cpp @@ -1634,6 +1634,33 @@ void MinecraftServer::tick() tickCount++; +#ifdef _DEDICATED_SERVER + if (tickCount % 6000 == 0 && !s_bServerHalted) + { + app.DebugPrintf("Auto-saving world...\n"); + if (players != NULL) + { + players->saveAll(NULL); + } + for (unsigned int j = 0; j < levels.length; j++) + { + if (s_bServerHalted) break; + ServerLevel *level = levels[levels.length - 1 - j]; + if (level) level->save(false, NULL, true); + } + if (!s_bServerHalted) + { + saveGameRules(); + levels[0]->saveToDisc(NULL, true); + } + while (StorageManager.GetSaveState() != C4JStorage::ESaveGame_Idle) + { + Sleep(10); + } + app.DebugPrintf("Auto-save complete\n"); + } +#endif + // 4J We need to update client difficulty levels based on the servers Minecraft *pMinecraft = Minecraft::GetInstance(); // 4J-PB - sending this on the host changing the difficulty in the menus diff --git a/Minecraft.Client/MultiPlayerChunkCache.cpp b/Minecraft.Client/MultiPlayerChunkCache.cpp index 46c2a8d7..879ebfd9 100644 --- a/Minecraft.Client/MultiPlayerChunkCache.cpp +++ b/Minecraft.Client/MultiPlayerChunkCache.cpp @@ -175,10 +175,11 @@ LevelChunk *MultiPlayerChunkCache::create(int x, int z) if (MinecraftServer::getInstance()->serverHalted()) return NULL; // If we're the host, then don't create the chunk, share data from the server's copy + int dimId = level->dimension->id; #ifdef _LARGE_WORLDS - LevelChunk *serverChunk = MinecraftServer::getInstance()->getLevel(level->dimension->id)->cache->getChunkLoadedOrUnloaded(x,z); + LevelChunk *serverChunk = MinecraftServer::getInstance()->getLevel(dimId)->cache->getChunkLoadedOrUnloaded(x,z); #else - LevelChunk *serverChunk = MinecraftServer::getInstance()->getLevel(level->dimension->id)->cache->getChunk(x,z); + LevelChunk *serverChunk = MinecraftServer::getInstance()->getLevel(dimId)->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 diff --git a/Minecraft.Client/ServerChunkCache.cpp b/Minecraft.Client/ServerChunkCache.cpp index f26489e8..c8f84836 100644 --- a/Minecraft.Client/ServerChunkCache.cpp +++ b/Minecraft.Client/ServerChunkCache.cpp @@ -151,8 +151,10 @@ LevelChunk *ServerChunkCache::create(int x, int z, bool asyncPostProcess) // 4J if( ( chunk == NULL ) || ( chunk->x != x ) || ( chunk->z != z ) ) { + bool wasLoaded = false; EnterCriticalSection(&m_csLoadCreate); chunk = load(x, z); + wasLoaded = (chunk != NULL); if (chunk == NULL) { if (source == NULL) diff --git a/Minecraft.World/OldChunkStorage.cpp b/Minecraft.World/OldChunkStorage.cpp index bb87e39d..7dbd4a86 100644 --- a/Minecraft.World/OldChunkStorage.cpp +++ b/Minecraft.World/OldChunkStorage.cpp @@ -476,29 +476,28 @@ LevelChunk *OldChunkStorage::load(Level *level, DataInputStream *dis) CompoundTag *tag = NbtIo::read(dis); - loadEntities(levelChunk, level, tag); - - if (tag->contains(L"TileTicks")) + if (tag != NULL) { - PIXBeginNamedEvent(0,"Loading TileTicks"); - ListTag *tileTicks = (ListTag *) tag->getList(L"TileTicks"); + loadEntities(levelChunk, level, tag); - if (tileTicks != NULL) + if (tag->contains(L"TileTicks")) { - for (int i = 0; i < tileTicks->size(); i++) - { - CompoundTag *teTag = tileTicks->get(i); + ListTag *tileTicks = (ListTag *) tag->getList(L"TileTicks"); - level->forceAddTileTick(teTag->getInt(L"x"), teTag->getInt(L"y"), teTag->getInt(L"z"), teTag->getInt(L"i"), teTag->getInt(L"t"), teTag->getInt(L"p")); + if (tileTicks != NULL) + { + for (int i = 0; i < tileTicks->size(); i++) + { + CompoundTag *teTag = tileTicks->get(i); + + level->forceAddTileTick(teTag->getInt(L"x"), teTag->getInt(L"y"), teTag->getInt(L"z"), teTag->getInt(L"i"), teTag->getInt(L"t")); + } } } - PIXEndNamedEvent(); + + delete tag; } - delete tag; - - PIXEndNamedEvent(); - return levelChunk; } diff --git a/Minecraft.World/RandomLevelSource.cpp b/Minecraft.World/RandomLevelSource.cpp index 9c24e4b3..51954be9 100644 --- a/Minecraft.World/RandomLevelSource.cpp +++ b/Minecraft.World/RandomLevelSource.cpp @@ -778,7 +778,7 @@ void RandomLevelSource::postProcess(ChunkSource *parent, int xt, int zt) mineShaftFeature->postProcess(level, pprandom, xt, zt); hasVillage = villageFeature->postProcess(level, pprandom, xt, zt); strongholdFeature->postProcess(level, pprandom, xt, zt); - scatteredFeature->postProcess(level, random, xt, zt); + scatteredFeature->postProcess(level, pprandom, xt, zt); } PIXEndNamedEvent(); diff --git a/Minecraft.World/RegionFile.cpp b/Minecraft.World/RegionFile.cpp index 305337a8..de920fa9 100644 --- a/Minecraft.World/RegionFile.cpp +++ b/Minecraft.World/RegionFile.cpp @@ -38,7 +38,12 @@ RegionFile::RegionFile(ConsoleSaveFile *saveFile, File *path) } */ - fileEntry = m_saveFile->createFile( fileName->getName() ); + wstring saveName = fileName->getPath(); + for (size_t i = 0; i < saveName.size(); i++) + { + if (saveName[i] == L'\\') saveName[i] = L'/'; + } + fileEntry = m_saveFile->createFile( ConsoleSavePath(saveName) ); m_saveFile->setFilePointer( fileEntry, 0, NULL, FILE_END ); if ( fileEntry->getFileSize() < SECTOR_BYTES) diff --git a/Minecraft.World/RegionFileCache.cpp b/Minecraft.World/RegionFileCache.cpp index 6b88f4e0..3b84f773 100644 --- a/Minecraft.World/RegionFileCache.cpp +++ b/Minecraft.World/RegionFileCache.cpp @@ -17,7 +17,7 @@ bool RegionFileCache::useSplitSaves(ESavePlatform platform) }; } -RegionFile *RegionFileCache::_getRegionFile(ConsoleSaveFile *saveFile, const wstring &prefix, int chunkX, int chunkZ) // 4J - TODO was synchronized +RegionFile *RegionFileCache::_getRegionFile(ConsoleSaveFile *saveFile, const wstring &prefix, int chunkX, int chunkZ) // 4J - synchronized restored { // 4J Jev - changed back to use of the File class. //char file[MAX_PATH_SIZE]; @@ -26,6 +26,7 @@ RegionFile *RegionFileCache::_getRegionFile(ConsoleSaveFile *saveFile, const wst //File regionDir(basePath, L"region"); //File file(regionDir, wstring(L"r.") + _toString(chunkX>>5) + L"." + _toString(chunkZ>>5) + L".mcr" ); + EnterCriticalSection(&m_cs); MemSect(31); File file; if(useSplitSaves(saveFile->getSavePlatform())) @@ -46,6 +47,7 @@ RegionFile *RegionFileCache::_getRegionFile(ConsoleSaveFile *saveFile, const wst // 4J Jev, put back in. if (ref != NULL) { + LeaveCriticalSection(&m_cs); return ref; } @@ -63,12 +65,14 @@ RegionFile *RegionFileCache::_getRegionFile(ConsoleSaveFile *saveFile, const wst RegionFile *reg = new RegionFile(saveFile, &file); cache[file] = reg; // 4J - this was originally a softReferenc + LeaveCriticalSection(&m_cs); return reg; } void RegionFileCache::_clear() // 4J - TODO was synchronized { + EnterCriticalSection(&m_cs); AUTO_VAR(itEnd, cache.end()); for( AUTO_VAR(it, cache.begin()); it != itEnd; it++ ) { @@ -85,6 +89,7 @@ void RegionFileCache::_clear() // 4J - TODO was synchronized // } } cache.clear(); + LeaveCriticalSection(&m_cs); } int RegionFileCache::_getSizeDelta(ConsoleSaveFile *saveFile, const wstring &prefix, int chunkX, int chunkZ) @@ -120,9 +125,3 @@ DataOutputStream *RegionFileCache::_getChunkDataOutputStream(ConsoleSaveFile *sa return r->getChunkDataOutputStream(chunkX & 31, chunkZ & 31); } } - - -RegionFileCache::~RegionFileCache() -{ - _clear(); -} diff --git a/Minecraft.World/RegionFileCache.h b/Minecraft.World/RegionFileCache.h index 822e49c9..58af1f03 100644 --- a/Minecraft.World/RegionFileCache.h +++ b/Minecraft.World/RegionFileCache.h @@ -10,13 +10,14 @@ private: static const int MAX_CACHE_SIZE = 256; unordered_map cache; + CRITICAL_SECTION m_cs; static RegionFileCache s_defaultCache; public: // Made public and non-static so we can have a cache for input and output files - RegionFileCache() {} - ~RegionFileCache(); + RegionFileCache() { InitializeCriticalSectionAndSpinCount(&m_cs, 4000); } + ~RegionFileCache() { DeleteCriticalSection(&m_cs); _clear(); } RegionFile *_getRegionFile(ConsoleSaveFile *saveFile, const wstring &prefix, int chunkX, int chunkZ); // 4J - TODO was synchronized void _clear(); // 4J - TODO was synchronized diff --git a/Minecraft.World/SparseDataStorage.cpp b/Minecraft.World/SparseDataStorage.cpp index dc32a431..0e460214 100644 --- a/Minecraft.World/SparseDataStorage.cpp +++ b/Minecraft.World/SparseDataStorage.cpp @@ -602,9 +602,10 @@ bool SparseDataStorage::isCompressed() void SparseDataStorage::write(DataOutputStream *dos) { - int count = ( dataAndCount >> 48 ) & 0xffff; + __int64 snapshot = dataAndCount; + int count = ( snapshot >> 48 ) & 0xffff; dos->writeInt(count); - unsigned char *dataPointer = (unsigned char *)(dataAndCount & 0x0000ffffffffffff); + unsigned char *dataPointer = (unsigned char *)(snapshot & 0x0000ffffffffffff); byteArray wrapper(dataPointer, count * 128 + 128); dos->write(wrapper); } diff --git a/Minecraft.World/SparseLightStorage.cpp b/Minecraft.World/SparseLightStorage.cpp index 8b848520..7257f29d 100644 --- a/Minecraft.World/SparseLightStorage.cpp +++ b/Minecraft.World/SparseLightStorage.cpp @@ -619,9 +619,10 @@ bool SparseLightStorage::isCompressed() void SparseLightStorage::write(DataOutputStream *dos) { - int count = ( dataAndCount >> 48 ) & 0xffff; + __int64 snapshot = dataAndCount; + int count = ( snapshot >> 48 ) & 0xffff; dos->writeInt(count); - unsigned char *dataPointer = (unsigned char *)(dataAndCount & 0x0000ffffffffffff); + unsigned char *dataPointer = (unsigned char *)(snapshot & 0x0000ffffffffffff); byteArray wrapper(dataPointer, count * 128 + 128); dos->write(wrapper); } diff --git a/Minecraft.World/StructureFeature.cpp b/Minecraft.World/StructureFeature.cpp index ab4e37db..ba10ceec 100644 --- a/Minecraft.World/StructureFeature.cpp +++ b/Minecraft.World/StructureFeature.cpp @@ -9,6 +9,7 @@ StructureFeature::StructureFeature() { + InitializeCriticalSectionAndSpinCount(&m_csCachedStructures, 4000); #ifdef ENABLE_STRUCTURE_SAVING savedData = nullptr; #endif @@ -16,10 +17,13 @@ StructureFeature::StructureFeature() StructureFeature::~StructureFeature() { + EnterCriticalSection(&m_csCachedStructures); for( AUTO_VAR(it, cachedStructures.begin()); it != cachedStructures.end(); it++ ) { delete it->second; } + LeaveCriticalSection(&m_csCachedStructures); + DeleteCriticalSection(&m_csCachedStructures); } void StructureFeature::addFeature(Level *level, int x, int z, int xOffs, int zOffs, byteArray blocks) @@ -28,12 +32,16 @@ void StructureFeature::addFeature(Level *level, int x, int z, int xOffs, int zOf // the chunk being generated, but not all chunks are the sources of // structures + EnterCriticalSection(&m_csCachedStructures); + restoreSavedData(level); if (cachedStructures.find(ChunkPos::hashCode(x, z)) != cachedStructures.end()) { + LeaveCriticalSection(&m_csCachedStructures); return; } + LeaveCriticalSection(&m_csCachedStructures); // clear random key random->nextInt(); @@ -41,7 +49,9 @@ void StructureFeature::addFeature(Level *level, int x, int z, int xOffs, int zOf if (isFeatureChunk(x, z,level->getLevelData()->getGenerator() == LevelType::lvl_flat)) { StructureStart *start = createStructureStart(x, z); + EnterCriticalSection(&m_csCachedStructures); cachedStructures[ChunkPos::hashCode(x, z)] = start; + LeaveCriticalSection(&m_csCachedStructures); saveFeature(x, z, start); } } @@ -58,6 +68,7 @@ bool StructureFeature::postProcess(Level *level, Random *random, int chunkX, int int cz = (chunkZ << 4); // + 8; bool intersection = false; + EnterCriticalSection(&m_csCachedStructures); for( AUTO_VAR(it, cachedStructures.begin()); it != cachedStructures.end(); it++ ) { StructureStart *structureStart = it->second; @@ -76,12 +87,14 @@ bool StructureFeature::postProcess(Level *level, Random *random, int chunkX, int } } } + LeaveCriticalSection(&m_csCachedStructures); return intersection; } bool StructureFeature::isIntersection(int cellX, int cellZ) { + EnterCriticalSection(&m_csCachedStructures); restoreSavedData(level); for( AUTO_VAR(it, cachedStructures.begin()); it != cachedStructures.end(); it++ ) @@ -97,12 +110,14 @@ bool StructureFeature::isIntersection(int cellX, int cellZ) StructurePiece *next = *it2++; if (next->getBoundingBox()->intersects(cellX, cellZ, cellX, cellZ)) { + LeaveCriticalSection(&m_csCachedStructures); return true; } } } } } + LeaveCriticalSection(&m_csCachedStructures); return false; } @@ -114,6 +129,7 @@ bool StructureFeature::isInsideFeature(int cellX, int cellY, int cellZ) StructureStart *StructureFeature::getStructureAt(int cellX, int cellY, int cellZ) { + EnterCriticalSection(&m_csCachedStructures); //for (StructureStart structureStart : cachedStructures.values()) for(AUTO_VAR(it, cachedStructures.begin()); it != cachedStructures.end(); ++it) { @@ -138,12 +154,14 @@ StructureStart *StructureFeature::getStructureAt(int cellX, int cellY, int cellZ StructurePiece* piece = *it2; if ( piece->getBoundingBox()->isInside(cellX, cellY, cellZ) ) { + LeaveCriticalSection(&m_csCachedStructures); return pStructureStart; } } } } } + LeaveCriticalSection(&m_csCachedStructures); return NULL; } @@ -151,14 +169,17 @@ bool StructureFeature::isInsideBoundingFeature(int cellX, int cellY, int cellZ) { restoreSavedData(level); + EnterCriticalSection(&m_csCachedStructures); for(AUTO_VAR(it, cachedStructures.begin()); it != cachedStructures.end(); ++it) { StructureStart *structureStart = it->second; if (structureStart->isValid()) { + LeaveCriticalSection(&m_csCachedStructures); return (structureStart->getBoundingBox()->intersects(cellX, cellZ, cellX, cellZ)); } } + LeaveCriticalSection(&m_csCachedStructures); return false; } @@ -182,6 +203,7 @@ TilePos *StructureFeature::getNearestGeneratedFeature(Level *level, int cellX, i double minDistance = DBL_MAX; TilePos *selected = NULL; + EnterCriticalSection(&m_csCachedStructures); for(AUTO_VAR(it, cachedStructures.begin()); it != cachedStructures.end(); ++it) { StructureStart *pStructureStart = it->second; @@ -205,6 +227,7 @@ TilePos *StructureFeature::getNearestGeneratedFeature(Level *level, int cellX, i } } } + LeaveCriticalSection(&m_csCachedStructures); if (selected != NULL) { return selected; diff --git a/Minecraft.World/StructureFeature.h b/Minecraft.World/StructureFeature.h index 5159343a..16e246cb 100644 --- a/Minecraft.World/StructureFeature.h +++ b/Minecraft.World/StructureFeature.h @@ -27,6 +27,7 @@ private: protected: unordered_map<__int64, StructureStart *> cachedStructures; + CRITICAL_SECTION m_csCachedStructures; public: StructureFeature();