Something went wrong. Try again.
the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
Something went wrong. Try again.
9.1 kB · 310 lines
C++
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310#include "stdafx.h"#include "MultiPlayerChunkCache.h"#include "ServerChunkCache.h"#include "..\Minecraft.World\net.minecraft.world.level.chunk.h"#include "..\Minecraft.World\net.minecraft.world.level.dimension.h"#include "..\Minecraft.World\Arrays.h"#include "..\Minecraft.World\StringHelpers.h"#include "MinecraftServer.h"#include "ServerLevel.h"#include "..\Minecraft.World\Tile.h"#include "..\Minecraft.World\WaterLevelChunk.h"
MultiPlayerChunkCache::MultiPlayerChunkCache(Level *level){ XZSIZE = level->dimension->getXZSize(); // 4J Added XZOFFSET = XZSIZE/2; // 4J Added m_XZSize = XZSIZE; hasData = new bool[XZSIZE * XZSIZE]; memset(hasData, 0, sizeof(bool) * XZSIZE * XZSIZE);
emptyChunk = new EmptyLevelChunk(level, byteArray(16 * 16 * Level::maxBuildHeight), 0, 0);
// For normal world dimension, create a chunk that can be used to create the illusion of infinite water at the edge of the world if( level->dimension->id == 0 ) { byteArray bytes = byteArray(16 * 16 * 128);
// Superflat.... make grass, not water... if(level->getLevelData()->getGenerator() == LevelType::lvl_flat) { for( int x = 0; x < 16; x++ ) for( int y = 0; y < 128; y++ ) for( int z = 0; z < 16; z++ ) { unsigned char tileId = 0; if( y == 3 ) tileId = Tile::grass_Id; else if( y <= 2 ) tileId = Tile::dirt_Id;
bytes[x << 11 | z << 7 | y] = tileId; } } else { for( int x = 0; x < 16; x++ ) for( int y = 0; y < 128; y++ ) for( int z = 0; z < 16; z++ ) { unsigned char tileId = 0; if( y <= ( level->getSeaLevel() - 10 ) ) tileId = Tile::stone_Id; else if( y < level->getSeaLevel() ) tileId = Tile::calmWater_Id;
bytes[x << 11 | z << 7 | y] = tileId; } }
waterChunk = new WaterLevelChunk(level, bytes, 0, 0);
delete[] bytes.data;
if(level->getLevelData()->getGenerator() == LevelType::lvl_flat) { for( int x = 0; x < 16; x++ ) for( int y = 0; y < 128; y++ ) for( int z = 0; z < 16; z++ ) { if( y >= 3 ) { ((WaterLevelChunk *)waterChunk)->setLevelChunkBrightness(LightLayer::Sky,x,y,z,15); } } } else { for( int x = 0; x < 16; x++ ) for( int y = 0; y < 128; y++ ) for( int z = 0; z < 16; z++ ) { if( y >= ( level->getSeaLevel() - 1 ) ) { ((WaterLevelChunk *)waterChunk)->setLevelChunkBrightness(LightLayer::Sky,x,y,z,15); } else { ((WaterLevelChunk *)waterChunk)->setLevelChunkBrightness(LightLayer::Sky,x,y,z,2); } } } } else { waterChunk = NULL; }
this->level = level;
this->cache = new LevelChunk *[XZSIZE * XZSIZE]; memset(this->cache, 0, XZSIZE * XZSIZE * sizeof(LevelChunk *)); InitializeCriticalSectionAndSpinCount(&m_csLoadCreate,4000);}
MultiPlayerChunkCache::~MultiPlayerChunkCache(){ delete emptyChunk; delete waterChunk; delete cache; delete hasData;
AUTO_VAR(itEnd, loadedChunkList.end()); for (AUTO_VAR(it, loadedChunkList.begin()); it != itEnd; it++) delete *it;
DeleteCriticalSection(&m_csLoadCreate);}
bool MultiPlayerChunkCache::hasChunk(int x, int z){ // This cache always claims to have chunks, although it might actually just return empty data if it doesn't have anything return true;}
// 4J added - find out if we actually really do have a chunk in our cachebool MultiPlayerChunkCache::reallyHasChunk(int x, int z){ int ix = x + XZOFFSET; int iz = z + XZOFFSET; // 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 if( ( ix < 0 ) || ( ix >= XZSIZE ) ) return true; if( ( iz < 0 ) || ( iz >= XZSIZE ) ) return true; int idx = ix * XZSIZE + iz;
LevelChunk *chunk = cache[idx]; if( chunk == NULL ) { return false; } return hasData[idx];}
void MultiPlayerChunkCache::drop(int x, int z){ // 4J Stu - We do want to drop any 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. LevelChunk *chunk = getChunk(x, z); if (!chunk->isEmpty()) { // 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 // The tile entities are in general only created on the client by virtue of the chunk rebuild chunk->unload(false);
// 4J - We just want to clear out the entities in the chunk, but everything else should be valid chunk->loaded = true; }}
LevelChunk *MultiPlayerChunkCache::create(int x, int z){ int ix = x + XZOFFSET; int iz = z + XZOFFSET; // Check we're in range of the stored level 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 = cache[idx]; LevelChunk *lastChunk = chunk;
if( chunk == NULL ) { 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 NULL;
// 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);#else 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, bytes, x, z);
// 4J - changed to use new methods for lighting chunk->setSkyLightDataAllBright(); // Arrays::fill(chunk->skyLight->data, (byte) 255); }
chunk->loaded = true;
LeaveCriticalSection(&m_csLoadCreate);
#if ( defined _WIN64 || defined __LP64__ ) if( InterlockedCompareExchangeRelease64((LONG64 *)&cache[idx],(LONG64)chunk,(LONG64)lastChunk) == (LONG64)lastChunk )#else 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, // then this will be calculated when the chunk data arrives. if( g_NetworkManager.IsHost() ) { chunk->recalcHeightmapOnly(); }
// Successfully updated the cache EnterCriticalSection(&m_csLoadCreate); loadedChunkList.push_back(chunk); LeaveCriticalSection(&m_csLoadCreate); } else { // Something else must have updated the cache. Return that chunk and discard this one. This really shouldn't be happening // in multiplayer delete chunk; return cache[idx]; }
} else { chunk->load(); }
return chunk;}
LevelChunk *MultiPlayerChunkCache::getChunk(int x, int z){ int ix = x + XZOFFSET; int iz = z + XZOFFSET; // Check we're in range of the stored level 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 = cache[idx]; if( chunk == NULL ) { return emptyChunk; } else { return chunk; }}
bool MultiPlayerChunkCache::save(bool force, ProgressListener *progressListener){ return true;}
bool MultiPlayerChunkCache::tick(){ return false;}
bool MultiPlayerChunkCache::shouldSave(){ return false;}
void MultiPlayerChunkCache::postProcess(ChunkSource *parent, int x, int z){}
vector<Biome::MobSpawnerData *> *MultiPlayerChunkCache::getMobsAt(MobCategory *mobCategory, int x, int y, int z){ return NULL;}
TilePos *MultiPlayerChunkCache::findNearestMapFeature(Level *level, const wstring &featureName, int x, int y, int z){ return NULL;}
void MultiPlayerChunkCache::recreateLogicStructuresForChunk(int chunkX, int chunkZ){}
wstring MultiPlayerChunkCache::gatherStats(){ EnterCriticalSection(&m_csLoadCreate); int size = (int)loadedChunkList.size(); LeaveCriticalSection(&m_csLoadCreate); return L"MultiplayerChunkCache: " + _toString<int>(size);
}
void MultiPlayerChunkCache::dataReceived(int x, int z){ int ix = x + XZOFFSET; int iz = z + XZOFFSET; // Check we're in range of the stored level if( ( ix < 0 ) || ( ix >= XZSIZE ) ) return; if( ( iz < 0 ) || ( iz >= XZSIZE ) ) return; int idx = ix * XZSIZE + iz; hasData[idx] = true;}