diff options
| author | daoge_cmd <3523206925@qq.com> | 2026-03-01 12:16:08 +0800 |
|---|---|---|
| committer | daoge_cmd <3523206925@qq.com> | 2026-03-01 12:16:08 +0800 |
| commit | b691c43c44ff180d10e7d4a9afc83b98551ff586 (patch) | |
| tree | 3e9849222cbc6ba49f2f1fc6e5fe7179632c7390 /Minecraft.World/OldChunkStorage.cpp | |
| parent | def8cb415354ac390b7e89052a50605285f1aca9 (diff) | |
Initial commit
Diffstat (limited to 'Minecraft.World/OldChunkStorage.cpp')
| -rw-r--r-- | Minecraft.World/OldChunkStorage.cpp | 594 |
1 files changed, 594 insertions, 0 deletions
diff --git a/Minecraft.World/OldChunkStorage.cpp b/Minecraft.World/OldChunkStorage.cpp new file mode 100644 index 00000000..50c29a96 --- /dev/null +++ b/Minecraft.World/OldChunkStorage.cpp @@ -0,0 +1,594 @@ +#include "stdafx.h" +#include "File.h" +#include "InputOutputStream.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.chunk.h" +#include "net.minecraft.world.level.tile.entity.h" +#include "net.minecraft.world.level.storage.h" +#include "FileHeader.h" +#include "OldChunkStorage.h" +DWORD OldChunkStorage::tlsIdx = 0; +OldChunkStorage::ThreadStorage *OldChunkStorage::tlsDefault = NULL; + +OldChunkStorage::ThreadStorage::ThreadStorage() +{ + blockData = byteArray(Level::CHUNK_TILE_COUNT); + dataData = byteArray(Level::HALF_CHUNK_TILE_COUNT); + skyLightData = byteArray(Level::HALF_CHUNK_TILE_COUNT); + blockLightData = byteArray(Level::HALF_CHUNK_TILE_COUNT); +} + +OldChunkStorage::ThreadStorage::~ThreadStorage() +{ + delete [] blockData.data; + delete [] dataData.data; + delete [] skyLightData.data; + delete [] blockLightData.data; +} + +void OldChunkStorage::CreateNewThreadStorage() +{ + ThreadStorage *tls = new ThreadStorage(); + if(tlsDefault == NULL ) + { + tlsIdx = TlsAlloc(); + tlsDefault = tls; + } + TlsSetValue(tlsIdx, tls); +} + +void OldChunkStorage::UseDefaultThreadStorage() +{ + TlsSetValue(tlsIdx, tlsDefault); +} + +void OldChunkStorage::ReleaseThreadStorage() +{ + ThreadStorage *tls = (ThreadStorage *)TlsGetValue(tlsIdx); + if( tls == tlsDefault ) return; + + delete tls; +} + +OldChunkStorage::OldChunkStorage(File dir, bool create) +{ + this->dir = dir; + this->create = create; +} + +File OldChunkStorage::getFile(int x, int z) +{ + wchar_t name[MAX_PATH_SIZE]; + wchar_t path1[MAX_PATH_SIZE]; + wchar_t path2[MAX_PATH_SIZE]; + + wchar_t xRadix36[64]; + wchar_t zRadix36[64]; +#if ( defined __PS3__ || defined __ORBIS__ || defined __PSVITA__ ) + assert(0); // need a gcc verison of _itow ? +#else + _itow(x,xRadix36,36); + _itow(z,zRadix36,36); + swprintf(name,MAX_PATH_SIZE,L"c.%ls.%ls.dat",xRadix36,zRadix36); + _itow(x & 63,path1,36); + _itow(z & 63,path2,36); +#endif + //sprintf(file,"%s\\%s",dir,path1); + File file( dir, wstring( path1 ) ); + if( !file.exists() ) + { + if(create) file.mkdir(); + else + { + return File(L""); + } + } + + //strcat(file,"\\"); + //strcat(file,path2); + file = File( file, wstring( path2 ) ); + if( !file.exists() ) + { + if(create) file.mkdir(); + else + { + return File(L""); + } + } + + //strcat(file,"\\"); + //strcat(file,name); + //sprintf(file,"%s\\%s",file,name); + file = File( file, wstring( name ) ); + if ( !file.exists() ) + { + if (!create) + { + return File(L""); + } + } + return file; +} + +LevelChunk *OldChunkStorage::load(Level *level, int x, int z) +{ + File file = getFile(x, z); + if (!file.getPath().empty() && file.exists()) + { + // 4J - removed try/catch + // try { + // System.out.println("Loading chunk "+x+", "+z); + FileInputStream fis = FileInputStream(file); + CompoundTag *tag = NbtIo::readCompressed(&fis); + if (!tag->contains(L"Level")) + { + char buf[256]; + sprintf(buf,"Chunk file at %d, %d is missing level data, skipping\n",x,z); + app.DebugPrintf(buf); + return NULL; + } + if (!tag->getCompound(L"Level")->contains(L"Blocks")) + { + char buf[256]; + sprintf(buf,"Chunk file at %d, %d is missing block data, skipping\n",x,z); + app.DebugPrintf(buf); + return NULL; + } + LevelChunk *levelChunk = OldChunkStorage::load(level, tag->getCompound(L"Level")); + if (!levelChunk->isAt(x, z)) + { + char buf[256]; + sprintf(buf,"Chunk fileat %d, %d is in the wrong location; relocating. Expected %d, %d, got %d, %d\n", + x, z, x, z, levelChunk->x, levelChunk->z); + app.DebugPrintf(buf); + tag->putInt(L"xPos", x); + tag->putInt(L"zPos", z); + levelChunk = OldChunkStorage::load(level, tag->getCompound(L"Level")); + } + + return levelChunk; + // } catch (Exception e) { + // e.printStackTrace(); + // } + } + return NULL; +} + +void OldChunkStorage::save(Level *level, LevelChunk *levelChunk) +{ + level->checkSession(); + File file = getFile(levelChunk->x, levelChunk->z); + if (file.exists()) + { + LevelData *levelData = level->getLevelData(); + levelData->setSizeOnDisk( levelData->getSizeOnDisk() - file.length() ); + } + + // 4J - removed try/catch + // try { + //char tmpFileName[MAX_PATH_SIZE]; + //sprintf(tmpFileName,"%s\\%s",dir,"tmp_chunk.dat"); + File tmpFile( dir, L"tmp_chunk.dat" ); + // System.out.println("Saving chunk "+levelChunk.x+", "+levelChunk.z); + + FileOutputStream fos = FileOutputStream(tmpFile); + CompoundTag *tag = new CompoundTag(); + CompoundTag *levelData = new CompoundTag(); + tag->put(L"Level", levelData); + OldChunkStorage::save(levelChunk, level, levelData); + NbtIo::writeCompressed(tag, &fos); + fos.close(); + + if (file.exists()) + { + //DeleteFile(file); + file._delete(); + } + //MoveFile(tmpFile,file); + tmpFile.renameTo( file ); + + LevelData *levelInfo = level->getLevelData(); + levelInfo->setSizeOnDisk(levelInfo->getSizeOnDisk() + file.length() ); + // } catch (Exception e) { + // e.printStackTrace(); + // } +} + +bool OldChunkStorage::saveEntities(LevelChunk *lc, Level *level, CompoundTag *tag) +{ + // If we saved and it had no entities, and nothing has been added since skip this one + if(!lc->lastSaveHadEntities) return false; + + lc->lastSaveHadEntities = false; + ListTag<CompoundTag> *entityTags = new ListTag<CompoundTag>(); + +#ifdef _ENTITIES_RW_SECTION + EnterCriticalRWSection(&lc->m_csEntities, true); +#else + EnterCriticalSection(&lc->m_csEntities); +#endif + for (int i = 0; i < lc->ENTITY_BLOCKS_LENGTH; i++) + { + AUTO_VAR(itEnd, lc->entityBlocks[i]->end()); + for( vector<shared_ptr<Entity> >::iterator it = lc->entityBlocks[i]->begin(); it != itEnd; it++ ) + { + shared_ptr<Entity> e = *it; + lc->lastSaveHadEntities = true; + CompoundTag *teTag = new CompoundTag(); + if (e->save(teTag)) + { + entityTags->add(teTag); + } + + } + } +#ifdef _ENTITIES_RW_SECTION + LeaveCriticalRWSection(&lc->m_csEntities, true); +#else + LeaveCriticalSection(&lc->m_csEntities); +#endif + + tag->put(L"Entities", entityTags); + + return lc->lastSaveHadEntities; +} + +void OldChunkStorage::save(LevelChunk *lc, Level *level, DataOutputStream *dos) +{ + dos->writeShort(SAVE_FILE_VERSION_NUMBER); + dos->writeInt(lc->x); + dos->writeInt(lc->z); + dos->writeLong(level->getTime()); + + PIXBeginNamedEvent(0,"Getting block data"); + lc->writeCompressedBlockData(dos); + PIXEndNamedEvent(); + + PIXBeginNamedEvent(0,"Getting data data"); + lc->writeCompressedDataData(dos); + PIXEndNamedEvent(); + + PIXBeginNamedEvent(0,"Getting sky and block light data"); + lc->writeCompressedSkyLightData(dos); + lc->writeCompressedBlockLightData(dos); + PIXEndNamedEvent(); + + dos->write(lc->heightmap); + dos->writeShort(lc->terrainPopulated); + dos->write(lc->getBiomes()); + + PIXBeginNamedEvent(0,"Saving entities"); + CompoundTag *tag = new CompoundTag(); +#ifndef SPLIT_SAVES + saveEntities(lc, level, tag); +#endif + + PIXBeginNamedEvent(0,"Saving tile entities"); + ListTag<CompoundTag> *tileEntityTags = new ListTag<CompoundTag>(); + + AUTO_VAR(itEnd, lc->tileEntities.end()); + for( unordered_map<TilePos, shared_ptr<TileEntity>, TilePosKeyHash, TilePosKeyEq>::iterator it = lc->tileEntities.begin(); + it != itEnd; it++) + { + shared_ptr<TileEntity> te = it->second; + CompoundTag *teTag = new CompoundTag(); + te->save(teTag); + tileEntityTags->add(teTag); + } + tag->put(L"TileEntities", tileEntityTags); + PIXEndNamedEvent(); + + PIXBeginNamedEvent(0,"Saving tile tick data"); + vector<TickNextTickData > *ticksInChunk = level->fetchTicksInChunk(lc, false); + if (ticksInChunk != NULL) + { + __int64 levelTime = level->getTime(); + + ListTag<CompoundTag> *tickTags = new ListTag<CompoundTag>(); + for( int i = 0; i < ticksInChunk->size(); i++ ) + { + TickNextTickData td = ticksInChunk->at(i); + CompoundTag *teTag = new CompoundTag(); + teTag->putInt(L"i", td.tileId); + teTag->putInt(L"x", td.x); + teTag->putInt(L"y", td.y); + teTag->putInt(L"z", td.z); + teTag->putInt(L"t", (int) (td.m_delay - levelTime)); + + tickTags->add(teTag); + } + tag->put(L"TileTicks", tickTags); + } + delete ticksInChunk; + PIXEndNamedEvent(); + + NbtIo::write(tag,dos); + delete tag; + PIXEndNamedEvent(); +} + +void OldChunkStorage::save(LevelChunk *lc, Level *level, CompoundTag *tag) +{ + level->checkSession(); + tag->putInt(L"xPos", lc->x); + tag->putInt(L"zPos", lc->z); + tag->putLong(L"LastUpdate", level->getTime()); + // 4J - changes here for new storage. Now have static storage for getting lighting data for block, data, and sky & block lighting. This + // wasn't required in the original version as we could just reference the information in the level itself, but with our new storage system + // the full data doesn't normally exist & so getSkyLightData/getBlockLightData etc. need somewhere to output this data. Making this static so + // that we aren't dynamically allocating memory in the server thread when writing chunks as this causes serious stalling on the main thread. + // Will be fine so long as we only actually create tags for once chunk at a time. + + // 4J Stu - As we now save on multiple threads, the static data has been moved to TLS + ThreadStorage *tls = (ThreadStorage *)TlsGetValue(tlsIdx); + + PIXBeginNamedEvent(0,"Getting block data"); + //static byteArray blockData = byteArray(32768); + lc->getBlockData(tls->blockData); + tag->putByteArray(L"Blocks", tls->blockData); + PIXEndNamedEvent(); + + PIXBeginNamedEvent(0,"Getting data data"); + //static byteArray dataData = byteArray(16384); + lc->getDataData(tls->dataData); + tag->putByteArray(L"Data", tls->dataData); + PIXEndNamedEvent(); + + PIXBeginNamedEvent(0,"Getting sky and block light data"); + //static byteArray skyLightData = byteArray(16384); + //static byteArray blockLightData = byteArray(16384); + lc->getSkyLightData(tls->skyLightData); + lc->getBlockLightData(tls->blockLightData); + tag->putByteArray(L"SkyLight", tls->skyLightData); + tag->putByteArray(L"BlockLight", tls->blockLightData); + PIXEndNamedEvent(); + + tag->putByteArray(L"HeightMap", lc->heightmap); + tag->putShort(L"TerrainPopulatedFlags", lc->terrainPopulated); // 4J - changed from "TerrainPopulated" to "TerrainPopulatedFlags" as now stores a bitfield, java stores a bool + tag->putByteArray(L"Biomes", lc->getBiomes()); + + PIXBeginNamedEvent(0,"Saving entities"); +#ifndef SPLIT_SAVES + saveEntities(lc, level, tag); +#endif + + PIXBeginNamedEvent(0,"Saving tile entities"); + ListTag<CompoundTag> *tileEntityTags = new ListTag<CompoundTag>(); + + AUTO_VAR(itEnd, lc->tileEntities.end()); + for( unordered_map<TilePos, shared_ptr<TileEntity>, TilePosKeyHash, TilePosKeyEq>::iterator it = lc->tileEntities.begin(); + it != itEnd; it++) + { + shared_ptr<TileEntity> te = it->second; + CompoundTag *teTag = new CompoundTag(); + te->save(teTag); + tileEntityTags->add(teTag); + } + tag->put(L"TileEntities", tileEntityTags); + PIXEndNamedEvent(); + + PIXBeginNamedEvent(0,"Saving tile tick data"); + vector<TickNextTickData > *ticksInChunk = level->fetchTicksInChunk(lc, false); + if (ticksInChunk != NULL) + { + __int64 levelTime = level->getTime(); + + ListTag<CompoundTag> *tickTags = new ListTag<CompoundTag>(); + for( int i = 0; i < ticksInChunk->size(); i++ ) + { + TickNextTickData td = ticksInChunk->at(i); + CompoundTag *teTag = new CompoundTag(); + teTag->putInt(L"i", td.tileId); + teTag->putInt(L"x", td.x); + teTag->putInt(L"y", td.y); + teTag->putInt(L"z", td.z); + teTag->putInt(L"t", (int) (td.m_delay - levelTime)); + + tickTags->add(teTag); + } + tag->put(L"TileTicks", tickTags); + } + delete ticksInChunk; + PIXEndNamedEvent(); + PIXEndNamedEvent(); +} + +void OldChunkStorage::loadEntities(LevelChunk *lc, Level *level, CompoundTag *tag) +{ + ListTag<CompoundTag> *entityTags = (ListTag<CompoundTag> *) tag->getList(L"Entities"); + if (entityTags != NULL) + { + for (int i = 0; i < entityTags->size(); i++) + { + CompoundTag *teTag = entityTags->get(i); + shared_ptr<Entity> te = EntityIO::loadStatic(teTag, level); + lc->lastSaveHadEntities = true; + if (te != NULL) + { + lc->addEntity(te); + } + } + } + + ListTag<CompoundTag> *tileEntityTags = (ListTag<CompoundTag> *) tag->getList(L"TileEntities"); + if (tileEntityTags != NULL) + { + for (int i = 0; i < tileEntityTags->size(); i++) + { + CompoundTag *teTag = tileEntityTags->get(i); + shared_ptr<TileEntity> te = TileEntity::loadStatic(teTag); + if (te != NULL) + { + lc->addTileEntity(te); + } + } + } +} + +LevelChunk *OldChunkStorage::load(Level *level, DataInputStream *dis) +{ + short version = dis->readShort(); + int x = dis->readInt(); + int z = dis->readInt(); + int time = dis->readLong(); + + LevelChunk *levelChunk = new LevelChunk(level, x, z); + + levelChunk->readCompressedBlockData(dis); + levelChunk->readCompressedDataData(dis); + levelChunk->readCompressedSkyLightData(dis); + levelChunk->readCompressedBlockLightData(dis); + + dis->readFully(levelChunk->heightmap); + + levelChunk->terrainPopulated = dis->readShort(); + // If all neighbours have been post-processed, then we should have done the post-post-processing now. Check that this is set as if it isn't then we won't be able + // to send network data for chunks, and we won't ever try and set it again as all the directional flags are now already set - should only be an issue for old maps + // before this flag was added. + if( ( levelChunk->terrainPopulated & LevelChunk::sTerrainPopulatedAllNeighbours ) == LevelChunk::sTerrainPopulatedAllNeighbours ) + { + levelChunk->terrainPopulated |= LevelChunk::sTerrainPostPostProcessed; + } + + dis->readFully(levelChunk->biomes); + + CompoundTag *tag = NbtIo::read(dis); + + loadEntities(levelChunk, level, tag); + + if (tag->contains(L"TileTicks")) + { + ListTag<CompoundTag> *tileTicks = (ListTag<CompoundTag> *) tag->getList(L"TileTicks"); + + 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; + + return levelChunk; +} + +LevelChunk *OldChunkStorage::load(Level *level, CompoundTag *tag) +{ + int x = tag->getInt(L"xPos"); + int z = tag->getInt(L"zPos"); + + LevelChunk *levelChunk = new LevelChunk(level, x, z); + // 4J - the original code uses the data in the tag directly, but this is now just used as a source when creating the compressed data, so + // we need to free up the data in the tag once we are done + levelChunk->setBlockData(tag->getByteArray(L"Blocks")); + delete [] tag->getByteArray(L"Blocks").data; + // levelChunk->blocks = tag->getByteArray(L"Blocks"); + + // 4J - the original code uses the data in the tag directly, but this is now just used as a source when creating the compressed data, so + // we need to free up the data in the tag once we are done + levelChunk->setDataData(tag->getByteArray(L"Data")); + delete [] tag->getByteArray(L"Data").data; + + // 4J - changed to use our new methods for accessing lighting + levelChunk->setSkyLightData(tag->getByteArray(L"SkyLight")); + levelChunk->setBlockLightData(tag->getByteArray(L"BlockLight")); + + // In the original code (commented out below) constructing DataLayers from these arrays uses the data directly and so it doesn't need deleted. The new + // setSkyLightData/setBlockLightData take a copy of the data so we need to delete the local one now + delete [] tag->getByteArray(L"SkyLight").data; + delete [] tag->getByteArray(L"BlockLight").data; + + // levelChunk->skyLight = new DataLayer(tag->getByteArray(L"SkyLight"), level->depthBits); + // levelChunk->blockLight = new DataLayer(tag->getByteArray(L"BlockLight"), level->depthBits); + + delete [] levelChunk->heightmap.data; + levelChunk->heightmap = tag->getByteArray(L"HeightMap"); + // 4J - TerrainPopulated was a bool (java), then changed to be a byte bitfield, then replaced with TerrainPopulatedShort to store a wider bitfield + if( tag->get(L"TerrainPopulated") ) + { + // Java bool type or byte bitfield + levelChunk->terrainPopulated = tag->getByte(L"TerrainPopulated"); + if( levelChunk->terrainPopulated >= 1 ) levelChunk->terrainPopulated = LevelChunk::sTerrainPopulatedAllNeighbours | LevelChunk::sTerrainPostPostProcessed; // Convert from old bool type to new bitfield + } + else + { + // New style short + levelChunk->terrainPopulated = tag->getShort(L"TerrainPopulatedFlags"); + // If all neighbours have been post-processed, then we should have done the post-post-processing now. Check that this is set as if it isn't then we won't be able + // to send network data for chunks, and we won't ever try and set it again as all the directional flags are now already set - should only be an issue for old maps + // before this flag was added. + if( ( levelChunk->terrainPopulated & LevelChunk::sTerrainPopulatedAllNeighbours ) == LevelChunk::sTerrainPopulatedAllNeighbours ) + { + levelChunk->terrainPopulated |= LevelChunk::sTerrainPostPostProcessed; + } + } + +#if 0 + // 4J - removed - we shouldn't need this any more + if (!levelChunk->data->isValid()) + { + levelChunk->data = new DataLayer(LevelChunk::BLOCKS_LENGTH, level->depthBits); // 4J - BLOCKS_LENGTH was levelChunk->blocks.length + } +#endif + + // 4J removed - we shouldn't need this any more +#if 0 + if (levelChunk->heightmap.data == NULL || !levelChunk->skyLight->isValid()) + { + static int chunksUpdated = 0; + delete [] levelChunk->heightmap.data; + levelChunk->heightmap = byteArray(16 * 16); + delete levelChunk->skyLight; + levelChunk->skyLight = new DataLayer(levelChunk->blocks.length, level->depthBits); + levelChunk->recalcHeightmap(); + } + + if (!levelChunk->blockLight->isValid()) + { + delete levelChunk->blockLight; + levelChunk->blockLight = new DataLayer(levelChunk->blocks.length, level->depthBits); + levelChunk->recalcBlockLights(); + } +#endif + + if (tag->contains(L"Biomes")) + { + levelChunk->setBiomes(tag->getByteArray(L"Biomes")); + } + + loadEntities(levelChunk, level, tag); + + if (tag->contains(L"TileTicks")) + { + ListTag<CompoundTag> *tileTicks = (ListTag<CompoundTag> *) tag->getList(L"TileTicks"); + + 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")); + } + } + } + + return levelChunk; +} + +void OldChunkStorage::tick() +{ +} + +void OldChunkStorage::flush() +{ +} + +void OldChunkStorage::saveEntities(Level *level, LevelChunk *levelChunk) +{ +} |
