the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at main 310 lines 9.1 kB view raw
1#include "stdafx.h" 2#include "MultiPlayerChunkCache.h" 3#include "ServerChunkCache.h" 4#include "..\Minecraft.World\net.minecraft.world.level.chunk.h" 5#include "..\Minecraft.World\net.minecraft.world.level.dimension.h" 6#include "..\Minecraft.World\Arrays.h" 7#include "..\Minecraft.World\StringHelpers.h" 8#include "MinecraftServer.h" 9#include "ServerLevel.h" 10#include "..\Minecraft.World\Tile.h" 11#include "..\Minecraft.World\WaterLevelChunk.h" 12 13MultiPlayerChunkCache::MultiPlayerChunkCache(Level *level) 14{ 15 XZSIZE = level->dimension->getXZSize(); // 4J Added 16 XZOFFSET = XZSIZE/2; // 4J Added 17 m_XZSize = XZSIZE; 18 hasData = new bool[XZSIZE * XZSIZE]; 19 memset(hasData, 0, sizeof(bool) * XZSIZE * XZSIZE); 20 21 emptyChunk = new EmptyLevelChunk(level, byteArray(16 * 16 * Level::maxBuildHeight), 0, 0); 22 23 // For normal world dimension, create a chunk that can be used to create the illusion of infinite water at the edge of the world 24 if( level->dimension->id == 0 ) 25 { 26 byteArray bytes = byteArray(16 * 16 * 128); 27 28 // Superflat.... make grass, not water... 29 if(level->getLevelData()->getGenerator() == LevelType::lvl_flat) 30 { 31 for( int x = 0; x < 16; x++ ) 32 for( int y = 0; y < 128; y++ ) 33 for( int z = 0; z < 16; z++ ) 34 { 35 unsigned char tileId = 0; 36 if( y == 3 ) tileId = Tile::grass_Id; 37 else if( y <= 2 ) tileId = Tile::dirt_Id; 38 39 bytes[x << 11 | z << 7 | y] = tileId; 40 } 41 } 42 else 43 { 44 for( int x = 0; x < 16; x++ ) 45 for( int y = 0; y < 128; y++ ) 46 for( int z = 0; z < 16; z++ ) 47 { 48 unsigned char tileId = 0; 49 if( y <= ( level->getSeaLevel() - 10 ) ) tileId = Tile::stone_Id; 50 else if( y < level->getSeaLevel() ) tileId = Tile::calmWater_Id; 51 52 bytes[x << 11 | z << 7 | y] = tileId; 53 } 54 } 55 56 waterChunk = new WaterLevelChunk(level, bytes, 0, 0); 57 58 delete[] bytes.data; 59 60 if(level->getLevelData()->getGenerator() == LevelType::lvl_flat) 61 { 62 for( int x = 0; x < 16; x++ ) 63 for( int y = 0; y < 128; y++ ) 64 for( int z = 0; z < 16; z++ ) 65 { 66 if( y >= 3 ) 67 { 68 ((WaterLevelChunk *)waterChunk)->setLevelChunkBrightness(LightLayer::Sky,x,y,z,15); 69 } 70 } 71 } 72 else 73 { 74 for( int x = 0; x < 16; x++ ) 75 for( int y = 0; y < 128; y++ ) 76 for( int z = 0; z < 16; z++ ) 77 { 78 if( y >= ( level->getSeaLevel() - 1 ) ) 79 { 80 ((WaterLevelChunk *)waterChunk)->setLevelChunkBrightness(LightLayer::Sky,x,y,z,15); 81 } 82 else 83 { 84 ((WaterLevelChunk *)waterChunk)->setLevelChunkBrightness(LightLayer::Sky,x,y,z,2); 85 } 86 } 87 } 88 } 89 else 90 { 91 waterChunk = NULL; 92 } 93 94 this->level = level; 95 96 this->cache = new LevelChunk *[XZSIZE * XZSIZE]; 97 memset(this->cache, 0, XZSIZE * XZSIZE * sizeof(LevelChunk *)); 98 InitializeCriticalSectionAndSpinCount(&m_csLoadCreate,4000); 99} 100 101MultiPlayerChunkCache::~MultiPlayerChunkCache() 102{ 103 delete emptyChunk; 104 delete waterChunk; 105 delete cache; 106 delete hasData; 107 108 AUTO_VAR(itEnd, loadedChunkList.end()); 109 for (AUTO_VAR(it, loadedChunkList.begin()); it != itEnd; it++) 110 delete *it; 111 112 DeleteCriticalSection(&m_csLoadCreate); 113} 114 115 116bool MultiPlayerChunkCache::hasChunk(int x, int z) 117{ 118 // This cache always claims to have chunks, although it might actually just return empty data if it doesn't have anything 119 return true; 120} 121 122// 4J added - find out if we actually really do have a chunk in our cache 123bool MultiPlayerChunkCache::reallyHasChunk(int x, int z) 124{ 125 int ix = x + XZOFFSET; 126 int iz = z + XZOFFSET; 127 // Check we're in range of the stored level - if we aren't, then consider that we do have that chunk as we'll be able to use the water chunk there 128 if( ( ix < 0 ) || ( ix >= XZSIZE ) ) return true; 129 if( ( iz < 0 ) || ( iz >= XZSIZE ) ) return true; 130 int idx = ix * XZSIZE + iz; 131 132 LevelChunk *chunk = cache[idx]; 133 if( chunk == NULL ) 134 { 135 return false; 136 } 137 return hasData[idx]; 138} 139 140void MultiPlayerChunkCache::drop(int x, int z) 141{ 142 // 4J Stu - We do want to drop any entities in the chunks, especially for the case when a player is dead as they will 143 // not get the RemoveEntity packet if an entity is removed. 144 LevelChunk *chunk = getChunk(x, z); 145 if (!chunk->isEmpty()) 146 { 147 // Added parameter here specifies that we don't want to delete tile entities, as they won't get recreated unless they've got update packets 148 // The tile entities are in general only created on the client by virtue of the chunk rebuild 149 chunk->unload(false); 150 151 // 4J - We just want to clear out the entities in the chunk, but everything else should be valid 152 chunk->loaded = true; 153 } 154} 155 156LevelChunk *MultiPlayerChunkCache::create(int x, int z) 157{ 158 int ix = x + XZOFFSET; 159 int iz = z + XZOFFSET; 160 // Check we're in range of the stored level 161 if( ( ix < 0 ) || ( ix >= XZSIZE ) ) return ( waterChunk ? waterChunk : emptyChunk ); 162 if( ( iz < 0 ) || ( iz >= XZSIZE ) ) return ( waterChunk ? waterChunk : emptyChunk ); 163 int idx = ix * XZSIZE + iz; 164 LevelChunk *chunk = cache[idx]; 165 LevelChunk *lastChunk = chunk; 166 167 if( chunk == NULL ) 168 { 169 EnterCriticalSection(&m_csLoadCreate); 170 171 //LevelChunk *chunk; 172 if( g_NetworkManager.IsHost() ) // force here to disable sharing of data 173 { 174 // 4J-JEV: We are about to use shared data, abort if the server is stopped and the data is deleted. 175 if (MinecraftServer::getInstance()->serverHalted()) return NULL; 176 177 // If we're the host, then don't create the chunk, share data from the server's copy 178#ifdef _LARGE_WORLDS 179 LevelChunk *serverChunk = MinecraftServer::getInstance()->getLevel(level->dimension->id)->cache->getChunkLoadedOrUnloaded(x,z); 180#else 181 LevelChunk *serverChunk = MinecraftServer::getInstance()->getLevel(level->dimension->id)->cache->getChunk(x,z); 182#endif 183 chunk = new LevelChunk(level, x, z, serverChunk); 184 // 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 185 level->setTilesDirty( x * 16 , 0 , z * 16 , x * 16 + 15, 127, z * 16 + 15); 186 hasData[idx] = true; 187 } 188 else 189 { 190 // Passing an empty array into the LevelChunk ctor, which it now detects and sets up the chunk as compressed & empty 191 byteArray bytes; 192 193 chunk = new LevelChunk(level, bytes, x, z); 194 195 // 4J - changed to use new methods for lighting 196 chunk->setSkyLightDataAllBright(); 197 // Arrays::fill(chunk->skyLight->data, (byte) 255); 198 } 199 200 chunk->loaded = true; 201 202 LeaveCriticalSection(&m_csLoadCreate); 203 204#if ( defined _WIN64 || defined __LP64__ ) 205 if( InterlockedCompareExchangeRelease64((LONG64 *)&cache[idx],(LONG64)chunk,(LONG64)lastChunk) == (LONG64)lastChunk ) 206#else 207 if( InterlockedCompareExchangeRelease((LONG *)&cache[idx],(LONG)chunk,(LONG)lastChunk) == (LONG)lastChunk ) 208#endif // _DURANGO 209 { 210 // 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, 211 // then this will be calculated when the chunk data arrives. 212 if( g_NetworkManager.IsHost() ) 213 { 214 chunk->recalcHeightmapOnly(); 215 } 216 217 // Successfully updated the cache 218 EnterCriticalSection(&m_csLoadCreate); 219 loadedChunkList.push_back(chunk); 220 LeaveCriticalSection(&m_csLoadCreate); 221 } 222 else 223 { 224 // Something else must have updated the cache. Return that chunk and discard this one. This really shouldn't be happening 225 // in multiplayer 226 delete chunk; 227 return cache[idx]; 228 } 229 230 } 231 else 232 { 233 chunk->load(); 234 } 235 236 return chunk; 237} 238 239LevelChunk *MultiPlayerChunkCache::getChunk(int x, int z) 240{ 241 int ix = x + XZOFFSET; 242 int iz = z + XZOFFSET; 243 // Check we're in range of the stored level 244 if( ( ix < 0 ) || ( ix >= XZSIZE ) ) return ( waterChunk ? waterChunk : emptyChunk ); 245 if( ( iz < 0 ) || ( iz >= XZSIZE ) ) return ( waterChunk ? waterChunk : emptyChunk ); 246 int idx = ix * XZSIZE + iz; 247 248 LevelChunk *chunk = cache[idx]; 249 if( chunk == NULL ) 250 { 251 return emptyChunk; 252 } 253 else 254 { 255 return chunk; 256 } 257} 258 259bool MultiPlayerChunkCache::save(bool force, ProgressListener *progressListener) 260{ 261 return true; 262} 263 264bool MultiPlayerChunkCache::tick() 265{ 266 return false; 267} 268 269bool MultiPlayerChunkCache::shouldSave() 270{ 271 return false; 272} 273 274void MultiPlayerChunkCache::postProcess(ChunkSource *parent, int x, int z) 275{ 276} 277 278vector<Biome::MobSpawnerData *> *MultiPlayerChunkCache::getMobsAt(MobCategory *mobCategory, int x, int y, int z) 279{ 280 return NULL; 281} 282 283TilePos *MultiPlayerChunkCache::findNearestMapFeature(Level *level, const wstring &featureName, int x, int y, int z) 284{ 285 return NULL; 286} 287 288void MultiPlayerChunkCache::recreateLogicStructuresForChunk(int chunkX, int chunkZ) 289{ 290} 291 292wstring MultiPlayerChunkCache::gatherStats() 293{ 294 EnterCriticalSection(&m_csLoadCreate); 295 int size = (int)loadedChunkList.size(); 296 LeaveCriticalSection(&m_csLoadCreate); 297 return L"MultiplayerChunkCache: " + _toString<int>(size); 298 299} 300 301void MultiPlayerChunkCache::dataReceived(int x, int z) 302{ 303 int ix = x + XZOFFSET; 304 int iz = z + XZOFFSET; 305 // Check we're in range of the stored level 306 if( ( ix < 0 ) || ( ix >= XZSIZE ) ) return; 307 if( ( iz < 0 ) || ( iz >= XZSIZE ) ) return; 308 int idx = ix * XZSIZE + iz; 309 hasData[idx] = true; 310}