diff --git a/Minecraft.Client/MultiPlayerChunkCache.cpp b/Minecraft.Client/MultiPlayerChunkCache.cpp index cfb32802..302ff119 100644 --- a/Minecraft.Client/MultiPlayerChunkCache.cpp +++ b/Minecraft.Client/MultiPlayerChunkCache.cpp @@ -93,8 +93,8 @@ MultiPlayerChunkCache::MultiPlayerChunkCache(Level *level) this->level = level; - //this->cache = new LevelChunk *[XZSIZE * XZSIZE]; - //memset(this->cache, 0, XZSIZE * XZSIZE * sizeof(LevelChunk *)); + this->cache = new LevelChunk *[XZSIZE * XZSIZE]; + memset(this->cache, 0, XZSIZE * XZSIZE * sizeof(LevelChunk *)); InitializeCriticalSectionAndSpinCount(&m_csLoadCreate,4000); } @@ -102,7 +102,7 @@ MultiPlayerChunkCache::~MultiPlayerChunkCache() { delete emptyChunk; delete waterChunk; - dynamic_cache.clear(); //delete cache; + delete cache; delete hasData; for (auto& it : loadedChunkList) @@ -130,10 +130,12 @@ bool MultiPlayerChunkCache::reallyHasChunk(int x, int z) if( ( ix < 0 ) || ( ix >= XZSIZE ) ) return true; if( ( iz < 0 ) || ( iz >= XZSIZE ) ) return true; int idx = ix * XZSIZE + iz; - auto itor = dynamic_cache.find(idx); - - if (itor == dynamic_cache.end() || itor->second == nullptr) return false; + LevelChunk *chunk = cache[idx]; + if( chunk == nullptr ) + { + return false; + } return hasData[idx]; } @@ -144,18 +146,19 @@ void MultiPlayerChunkCache::drop(const int x, const int z) if ((ix < 0) || (ix >= XZSIZE)) return; if ((iz < 0) || (iz >= XZSIZE)) return; const int idx = ix * XZSIZE + iz; - auto itor = dynamic_cache.find(idx); - - if (itor == dynamic_cache.end() || itor->second == nullptr || itor->second->isEmpty()) return; + LevelChunk* chunk = cache[idx]; - // Drop entities in the chunks, especially for the case when a player is dead - // as they will not get the RemoveEntity packet if an entity is removed. - // Don't delete tile entities, as they won't get recreated unless they've got - // update packets. Tile entities are created on the client by the chunk rebuild. - itor->second->unload(false); + if (chunk != nullptr && !chunk->isEmpty()) + { + // Drop entities in the chunks, especially for the case when a player is dead + // as they will not get the RemoveEntity packet if an entity is removed. + // Don't delete tile entities, as they won't get recreated unless they've got + // update packets. Tile entities are created on the client by the chunk rebuild. + chunk->unload(false); - // Keep chunk in cache with structural data intact. - itor->second->loaded = true; + // Keep chunk in cache with structural data intact. + chunk->loaded = true; + } } LevelChunk *MultiPlayerChunkCache::create(int x, int z) @@ -166,16 +169,11 @@ LevelChunk *MultiPlayerChunkCache::create(int x, int z) if( ( ix < 0 ) || ( ix >= XZSIZE ) ) return ( waterChunk ? waterChunk : emptyChunk ); if( ( iz < 0 ) || ( iz >= XZSIZE ) ) return ( waterChunk ? waterChunk : emptyChunk ); int idx = ix * XZSIZE + iz; - LevelChunk* chunk = nullptr; - LevelChunk* lastChunk = nullptr; - auto itor = dynamic_cache.find(idx); + LevelChunk *chunk = cache[idx]; + LevelChunk *lastChunk = chunk; - if (itor != dynamic_cache.end()) { - chunk = itor->second; - lastChunk = chunk; - } - - if (chunk == nullptr) { + if( chunk == nullptr ) + { EnterCriticalSection(&m_csLoadCreate); //LevelChunk *chunk; @@ -212,9 +210,9 @@ LevelChunk *MultiPlayerChunkCache::create(int x, int z) LeaveCriticalSection(&m_csLoadCreate); #if ( defined _WIN64 || defined __LP64__ ) - if( InterlockedCompareExchangeRelease64((LONG64 *)&dynamic_cache[idx],(LONG64)chunk,(LONG64)lastChunk) == (LONG64)lastChunk ) + if( InterlockedCompareExchangeRelease64((LONG64 *)&cache[idx],(LONG64)chunk,(LONG64)lastChunk) == (LONG64)lastChunk ) #else - if( InterlockedCompareExchangeRelease((LONG *)&dynamic_cache[idx],(LONG)chunk,(LONG)lastChunk) == (LONG)lastChunk ) + if( InterlockedCompareExchangeRelease((LONG *)&cache[idx],(LONG)chunk,(LONG)lastChunk) == (LONG)lastChunk ) #endif // _DURANGO { // If we're sharing with the server, we'll need to calculate our heightmap now, which isn't shared. If we aren't sharing with the server, @@ -234,11 +232,7 @@ LevelChunk *MultiPlayerChunkCache::create(int x, int z) // Something else must have updated the cache. Return that chunk and discard this one. This really shouldn't be happening // in multiplayer delete chunk; - - itor = dynamic_cache.find(idx); - if (itor == dynamic_cache.end()) return nullptr; - - return itor->second; + return cache[idx]; } } @@ -258,11 +252,16 @@ LevelChunk *MultiPlayerChunkCache::getChunk(int x, int z) if( ( ix < 0 ) || ( ix >= XZSIZE ) ) return ( waterChunk ? waterChunk : emptyChunk ); if( ( iz < 0 ) || ( iz >= XZSIZE ) ) return ( waterChunk ? waterChunk : emptyChunk ); int idx = ix * XZSIZE + iz; - auto itor = dynamic_cache.find(idx); - if (itor == dynamic_cache.end() || itor->second == nullptr) return emptyChunk; - - return itor->second; + LevelChunk *chunk = cache[idx]; + if( chunk == nullptr ) + { + return emptyChunk; + } + else + { + return chunk; + } } bool MultiPlayerChunkCache::save(bool force, ProgressListener *progressListener) diff --git a/Minecraft.Client/MultiPlayerChunkCache.h b/Minecraft.Client/MultiPlayerChunkCache.h index 189057e4..77a82101 100644 --- a/Minecraft.Client/MultiPlayerChunkCache.h +++ b/Minecraft.Client/MultiPlayerChunkCache.h @@ -16,7 +16,7 @@ private: vector loadedChunkList; - //LevelChunk **cache; + LevelChunk **cache; // 4J - added for multithreaded support CRITICAL_SECTION m_csLoadCreate; // 4J - size of cache is defined by size of one side - must be even @@ -44,5 +44,5 @@ public: virtual void recreateLogicStructuresForChunk(int chunkX, int chunkZ); virtual void dataReceived(int x, int z); // 4J added - virtual std::unordered_map& getCache() { return dynamic_cache; } // 4J added + virtual std::unordered_map& getCache() { return dynamic_cache; } // 4J added }; \ No newline at end of file diff --git a/Minecraft.Client/MultiPlayerLevel.cpp b/Minecraft.Client/MultiPlayerLevel.cpp index b893fc12..d1161a3e 100644 --- a/Minecraft.Client/MultiPlayerLevel.cpp +++ b/Minecraft.Client/MultiPlayerLevel.cpp @@ -33,7 +33,7 @@ MultiPlayerLevel::MultiPlayerLevel(ClientConnection *connection, LevelSettings * // 4J - this this used to be called in parent ctor via a virtual fn chunkSource = createChunkSource(); // 4J - optimisation - keep direct reference of underlying cache here - dynamic_chunkSourceCache = chunkSource->getCache(); + //dynamic_chunkSourceCache = chunkSource->getCache(); chunkSourceXZSize = chunkSource->m_XZSize; // This also used to be called in parent ctor, but can't be called until chunkSource is created. Call now if required. diff --git a/Minecraft.Client/ServerChunkCache.h b/Minecraft.Client/ServerChunkCache.h index 5446afd9..f446960b 100644 --- a/Minecraft.Client/ServerChunkCache.h +++ b/Minecraft.Client/ServerChunkCache.h @@ -27,7 +27,7 @@ private: #ifdef _LARGE_WORLDS deque m_toDrop; //LevelChunk **m_unloadedCache; - std::unordered_map dynamic_unloadedCache; + std::unordered_map dynamic_unloadedCache; #endif // 4J - added for multithreaded support @@ -53,7 +53,7 @@ public: void updateOverwriteHellChunk(LevelChunk* origChunk, LevelChunk* playerChunk, int xMin, int xMax, int zMin, int zMax); #endif - virtual std::unordered_map& getCache() { return dynamic_cache; } // 4J added + virtual std::unordered_map& getCache() { return dynamic_cache; } // 4J added #ifdef MINECRAFT_SERVER_BUILD void regenerateChunk(int x, int z); #endif diff --git a/Minecraft.World/ChunkSource.h b/Minecraft.World/ChunkSource.h index bd7d8fef..b6f1ffe5 100644 --- a/Minecraft.World/ChunkSource.h +++ b/Minecraft.World/ChunkSource.h @@ -48,6 +48,13 @@ class TilePos; #define END_LEVEL_MIN_WIDTH 18 //#define END_LEVEL_MAX_WIDTH (LEVEL_MAX_WIDTH / END_LEVEL_SCALE) +class ChunkKeyHash { +public: + std::size_t operator()(const uint64_t& k) const noexcept { + return (std::size_t)k; + } +}; + class ChunkSource { public: @@ -60,7 +67,7 @@ public: #endif protected: - std::unordered_map dynamic_cache; + std::unordered_map dynamic_cache; public: virtual ~ChunkSource() {} @@ -76,7 +83,7 @@ public: virtual bool tick() = 0; virtual bool shouldSave() = 0; - virtual std::unordered_map& getCache() { return dynamic_cache; } // 4J added + virtual std::unordered_map& getCache() { return dynamic_cache; } // 4J added virtual void dataReceived(int x, int z) {} // 4J added /** diff --git a/Minecraft.World/Level.h b/Minecraft.World/Level.h index 1b882cd6..7657a662 100644 --- a/Minecraft.World/Level.h +++ b/Minecraft.World/Level.h @@ -524,7 +524,7 @@ public: int getAuxValueForMap(PlayerUID xuid, int dimension, int centreXC, int centreZC, int scale); // 4J - optimisation - keep direct reference of underlying cache here - std::unordered_map dynamic_chunkSourceCache; + std::unordered_map dynamic_chunkSourceCache; int chunkSourceXZSize; // 4J - added for implementation of finite limit to number of item entities, tnt and falling block entities