diff --git a/Minecraft.Client/MinecraftServer.cpp b/Minecraft.Client/MinecraftServer.cpp index ce9669c..454272d 100644 --- a/Minecraft.Client/MinecraftServer.cpp +++ b/Minecraft.Client/MinecraftServer.cpp @@ -1474,6 +1474,33 @@ void MinecraftServer::tick() tickCount++; +#ifdef WITH_SERVER_CODE + 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 8c6c90e..ca52cba 100644 --- a/Minecraft.Client/MultiPlayerChunkCache.cpp +++ b/Minecraft.Client/MultiPlayerChunkCache.cpp @@ -174,11 +174,12 @@ LevelChunk *MultiPlayerChunkCache::create(int x, int z) // 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 NULL; - // If we're the host, then don't create the chunk, share data from the server's copy + // 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 1fe1a86..538461f 100644 --- a/Minecraft.Client/ServerChunkCache.cpp +++ b/Minecraft.Client/ServerChunkCache.cpp @@ -149,8 +149,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) @@ -470,7 +472,7 @@ void ServerChunkCache::postProcess(ChunkSource *parent, int x, int z ) { LevelChunk *chunk = getChunk(x, z); if ( (chunk->terrainPopulated & LevelChunk::sTerrainPopulatedFromHere) == 0 ) - { + { if (source != NULL) { PIXBeginNamedEvent(0,"Main post processing"); @@ -478,7 +480,7 @@ void ServerChunkCache::postProcess(ChunkSource *parent, int x, int z ) PIXEndNamedEvent(); chunk->markUnsaved(); - } + } // Flag not only this chunk as being post-processed, but also all the chunks that this post-processing might affect. We can guarantee that these // chunks exist as that's determined before post-processing can even run diff --git a/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp b/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp index 2eee625..acfa1d2 100644 --- a/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp +++ b/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp @@ -89,7 +89,9 @@ bool WinsockNetLayer::Initialize() s_initialized = true; +#ifndef WITH_SERVER_CODE StartDiscovery(); +#endif return true; } diff --git a/Minecraft.World/OldChunkStorage.cpp b/Minecraft.World/OldChunkStorage.cpp index 50c29a9..3494bf6 100644 --- a/Minecraft.World/OldChunkStorage.cpp +++ b/Minecraft.World/OldChunkStorage.cpp @@ -455,24 +455,27 @@ LevelChunk *OldChunkStorage::load(Level *level, DataInputStream *dis) CompoundTag *tag = NbtIo::read(dis); - loadEntities(levelChunk, level, tag); - - if (tag->contains(L"TileTicks")) + if (tag != NULL) { - 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")); + 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")); + } } } - } - delete tag; + delete tag; + } return levelChunk; } diff --git a/Minecraft.World/RandomLevelSource.cpp b/Minecraft.World/RandomLevelSource.cpp index 4e26134..3a07a2e 100644 --- a/Minecraft.World/RandomLevelSource.cpp +++ b/Minecraft.World/RandomLevelSource.cpp @@ -664,7 +664,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(); @@ -674,7 +674,7 @@ void RandomLevelSource::postProcess(ChunkSource *parent, int xt, int zt) int x = xo + pprandom->nextInt(16) + 8; int y = pprandom->nextInt(Level::genDepth); int z = zo + pprandom->nextInt(16) + 8; - + LakeFeature *calmWater = new LakeFeature(Tile::calmWater_Id); calmWater->place(level, pprandom, x, y, z); delete calmWater; diff --git a/Minecraft.World/RegionFile.cpp b/Minecraft.World/RegionFile.cpp index 2cfd907..d8f7710 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 c21a625..cdb44d3 100644 --- a/Minecraft.World/RegionFileCache.cpp +++ b/Minecraft.World/RegionFileCache.cpp @@ -17,15 +17,11 @@ 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 { + EnterCriticalSection(&m_cs); + // 4J Jev - changed back to use of the File class. - //char file[MAX_PATH_SIZE]; - //sprintf(file,"%s\\region\\r.%d.%d.mcr",basePath,chunkX >> 5,chunkZ >> 5); - - //File regionDir(basePath, L"region"); - - //File file(regionDir, wstring(L"r.") + _toString(chunkX>>5) + L"." + _toString(chunkZ>>5) + L".mcr" ); MemSect(31); File file; if(useSplitSaves(saveFile->getSavePlatform())) @@ -46,45 +42,37 @@ RegionFile *RegionFileCache::_getRegionFile(ConsoleSaveFile *saveFile, const wst // 4J Jev, put back in. if (ref != NULL) { + LeaveCriticalSection(&m_cs); return ref; } - // 4J Stu - Remove for new save files - /* - if (!regionDir.exists()) - { - regionDir.mkdirs(); - } - */ if (cache.size() >= MAX_CACHE_SIZE) { _clear(); } RegionFile *reg = new RegionFile(saveFile, &file); - cache[file] = reg; // 4J - this was originally a softReferenc + cache[file] = reg; // 4J - this was originally a softReference + LeaveCriticalSection(&m_cs); return reg; } -void RegionFileCache::_clear() // 4J - TODO was synchronized +void RegionFileCache::_clear() // 4J - synchronized (recursive CS is safe here) { + EnterCriticalSection(&m_cs); AUTO_VAR(itEnd, cache.end()); for( AUTO_VAR(it, cache.begin()); it != itEnd; it++ ) { - // 4J - removed try/catch -// try { RegionFile *regionFile = it->second; if (regionFile != NULL) { regionFile->close(); } delete regionFile; -// } catch (IOException e) { -// e.printStackTrace(); -// } } cache.clear(); + LeaveCriticalSection(&m_cs); } int RegionFileCache::_getSizeDelta(ConsoleSaveFile *saveFile, const wstring &prefix, int chunkX, int chunkZ) diff --git a/Minecraft.World/RegionFileCache.h b/Minecraft.World/RegionFileCache.h index 03e576c..d22fb11 100644 --- a/Minecraft.World/RegionFileCache.h +++ b/Minecraft.World/RegionFileCache.h @@ -10,12 +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() { InitializeCriticalSectionAndSpinCount(&m_cs, 4000); } + ~RegionFileCache() { DeleteCriticalSection(&m_cs); } 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 6db131e..925aabe 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 f9a2f0c..a161709 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 5e8489f..65f19db 100644 --- a/Minecraft.World/StructureFeature.cpp +++ b/Minecraft.World/StructureFeature.cpp @@ -7,12 +7,20 @@ #include "net.minecraft.world.level.h" #include "LevelData.h" +StructureFeature::StructureFeature() +{ + InitializeCriticalSectionAndSpinCount(&m_csCachedStructures, 4000); +} + 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) @@ -21,10 +29,13 @@ 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); if (cachedStructures.find(ChunkPos::hashCode(x, z)) != cachedStructures.end()) { + LeaveCriticalSection(&m_csCachedStructures); return; } + LeaveCriticalSection(&m_csCachedStructures); // clear random key random->nextInt(); @@ -32,7 +43,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); } } @@ -46,6 +59,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; @@ -61,12 +75,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); for( AUTO_VAR(it, cachedStructures.begin()); it != cachedStructures.end(); it++ ) { StructureStart *structureStart = it->second; @@ -80,12 +96,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; } @@ -94,7 +112,7 @@ bool StructureFeature::isIntersection(int cellX, int cellZ) /////////////////////////////////////////// bool StructureFeature::isInsideFeature(int cellX, int cellY, int cellZ) { - //for (StructureStart structureStart : cachedStructures.values()) + EnterCriticalSection(&m_csCachedStructures); for(AUTO_VAR(it, cachedStructures.begin()); it != cachedStructures.end(); ++it) { StructureStart *pStructureStart = it->second; @@ -103,14 +121,6 @@ bool StructureFeature::isInsideFeature(int cellX, int cellY, int cellZ) { if (pStructureStart->getBoundingBox()->intersects(cellX, cellZ, cellX, cellZ)) { - /* - Iterator it = structureStart.getPieces().iterator(); - while (it.hasNext()) { - StructurePiece next = it.next(); - if (next.getBoundingBox().isInside(cellX, cellY, cellZ)) { - return true; - } - */ list *pieces=pStructureStart->getPieces(); for ( AUTO_VAR(it2, pieces->begin()); it2 != pieces->end(); it2++ ) @@ -118,12 +128,14 @@ bool StructureFeature::isInsideFeature(int cellX, int cellY, int cellZ) StructurePiece* piece = *it2; if ( piece->getBoundingBox()->isInside(cellX, cellY, cellZ) ) { + LeaveCriticalSection(&m_csCachedStructures); return true; } } } } } + LeaveCriticalSection(&m_csCachedStructures); return false; } @@ -146,6 +158,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; @@ -169,6 +182,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 642e6aa..a0efb91 100644 --- a/Minecraft.World/StructureFeature.h +++ b/Minecraft.World/StructureFeature.h @@ -17,8 +17,10 @@ public: protected: unordered_map<__int64, StructureStart *> cachedStructures; + CRITICAL_SECTION m_csCachedStructures; public: + StructureFeature(); ~StructureFeature(); virtual void addFeature(Level *level, int x, int z, int xOffs, int zOffs, byteArray blocks);