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.
33 kB · 1024 lines
C++
at main
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025#include "stdafx.h"#include <vector>#include "..\..\..\Minecraft.World\com.mojang.nbt.h"#include "..\..\..\Minecraft.World\System.h"#include "ConsoleSchematicFile.h"#include "..\..\..\Minecraft.World\InputOutputStream.h"#include "..\..\..\Minecraft.World\net.minecraft.world.level.h"#include "..\..\..\Minecraft.World\net.minecraft.world.level.chunk.h"#include "..\..\..\Minecraft.World\net.minecraft.world.level.tile.entity.h"#include "..\..\..\Minecraft.World\net.minecraft.world.entity.h"#include "..\..\..\Minecraft.World\net.minecraft.world.entity.item.h"#include "..\..\..\Minecraft.World\net.minecraft.world.phys.h"#include "..\..\..\Minecraft.World\compression.h"
ConsoleSchematicFile::ConsoleSchematicFile(){ m_xSize = m_ySize = m_zSize = 0; m_refCount = 1; m_data.data = NULL;}
ConsoleSchematicFile::~ConsoleSchematicFile(){ app.DebugPrintf("Deleting schematic file\n"); if(m_data.data != NULL) delete [] m_data.data;}
void ConsoleSchematicFile::save(DataOutputStream *dos){ if(dos != NULL) { dos->writeInt(XBOX_SCHEMATIC_CURRENT_VERSION);
dos->writeByte(APPROPRIATE_COMPRESSION_TYPE);
dos->writeInt(m_xSize); dos->writeInt(m_ySize); dos->writeInt(m_zSize);
byteArray ba(new BYTE[ m_data.length ], m_data.length); Compression::getCompression()->CompressLZXRLE( ba.data, &ba.length, m_data.data, m_data.length);
dos->writeInt(ba.length); dos->write(ba);
save_tags(dos);
delete [] ba.data; }}
void ConsoleSchematicFile::load(DataInputStream *dis){ if(dis != NULL) { // VERSION CHECK // int version = dis->readInt();
Compression::ECompressionTypes compressionType = Compression::eCompressionType_LZXRLE;
if (version > XBOX_SCHEMATIC_ORIGINAL_VERSION) // Or later versions { compressionType = (Compression::ECompressionTypes)dis->readByte(); }
if (version > XBOX_SCHEMATIC_CURRENT_VERSION) assert(false && "Unrecognised schematic version!!");
m_xSize = dis->readInt(); m_ySize = dis->readInt(); m_zSize = dis->readInt();
int compressedSize = dis->readInt(); byteArray compressedBuffer(compressedSize); dis->readFully(compressedBuffer);
if(m_data.data != NULL) { delete [] m_data.data; m_data.data = NULL; }
if(compressionType == Compression::eCompressionType_None) { m_data = compressedBuffer; } else { unsigned int outputSize = m_xSize * m_ySize * m_zSize * 3/2; m_data = byteArray(outputSize);
switch(compressionType) { case Compression::eCompressionType_RLE: Compression::getCompression()->DecompressRLE( m_data.data, &m_data.length, compressedBuffer.data, compressedSize); break; case APPROPRIATE_COMPRESSION_TYPE: Compression::getCompression()->DecompressLZXRLE( m_data.data, &m_data.length, compressedBuffer.data, compressedSize); break; default: app.DebugPrintf("Unrecognized compression type for Schematic file (%d)\n", (int)compressionType); Compression::getCompression()->SetDecompressionType( (Compression::ECompressionTypes)compressionType ); Compression::getCompression()->DecompressLZXRLE( m_data.data, &m_data.length, compressedBuffer.data, compressedSize); Compression::getCompression()->SetDecompressionType( APPROPRIATE_COMPRESSION_TYPE ); };
delete [] compressedBuffer.data; }
// READ TAGS // CompoundTag *tag = NbtIo::read(dis); 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) {#ifndef _CONTENT_PACKAGE app.DebugPrintf("ConsoleSchematicFile has read a NULL tile entity\n"); __debugbreak();#endif } else { m_tileEntities.push_back(te); } } } ListTag<CompoundTag> *entityTags = (ListTag<CompoundTag> *) tag->getList(L"Entities"); if (entityTags != NULL) { for (int i = 0; i < entityTags->size(); i++) { CompoundTag *eTag = entityTags->get(i); eINSTANCEOF type = EntityIO::getType(eTag->getString(L"id")); ListTag<DoubleTag> *pos = (ListTag<DoubleTag> *) eTag->getList(L"Pos");
double x = pos->get(0)->data; double y = pos->get(1)->data; double z = pos->get(2)->data;
if( type == eTYPE_PAINTING || type == eTYPE_ITEM_FRAME ) { x = ((IntTag *) eTag->get(L"TileX") )->data; y = ((IntTag *) eTag->get(L"TileY") )->data; z = ((IntTag *) eTag->get(L"TileZ") )->data; }#ifdef _DEBUG //app.DebugPrintf(1,"Loaded entity type %d at (%f,%f,%f)\n",(int)type,x,y,z);#endif m_entities.push_back( pair<Vec3 *, CompoundTag *>(Vec3::newPermanent(x,y,z),(CompoundTag *)eTag->copy())); } } delete tag; }}
void ConsoleSchematicFile::save_tags(DataOutputStream *dos){ CompoundTag *tag = new CompoundTag();
ListTag<CompoundTag> *tileEntityTags = new ListTag<CompoundTag>(); tag->put(L"TileEntities", tileEntityTags);
for (AUTO_VAR(it, m_tileEntities.begin()); it != m_tileEntities.end(); it++) { CompoundTag *cTag = new CompoundTag(); (*it)->save(cTag); tileEntityTags->add(cTag); }
ListTag<CompoundTag> *entityTags = new ListTag<CompoundTag>(); tag->put(L"Entities", entityTags);
for (AUTO_VAR(it, m_entities.begin()); it != m_entities.end(); it++) entityTags->add( (CompoundTag *)(*it).second->copy() );
NbtIo::write(tag,dos); delete tag;}
__int64 ConsoleSchematicFile::applyBlocksAndData(LevelChunk *chunk, AABB *chunkBox, AABB *destinationBox, ESchematicRotation rot){ int xStart = max(destinationBox->x0, (double)chunk->x*16); int xEnd = min(destinationBox->x1, (double)((xStart>>4)<<4) + 16);
int yStart = destinationBox->y0; int yEnd = destinationBox->y1; if(yEnd > Level::maxBuildHeight) yEnd = Level::maxBuildHeight;
int zStart = max(destinationBox->z0, (double)chunk->z*16); int zEnd = min(destinationBox->z1, (double)((zStart>>4)<<4) + 16);
#ifdef _DEBUG app.DebugPrintf("Range is (%d,%d,%d) to (%d,%d,%d)\n",xStart,yStart,zStart,xEnd-1,yEnd-1,zEnd-1);#endif
int rowBlocksIncluded = (yEnd-yStart)*(zEnd-zStart); int blocksIncluded = (xEnd-xStart)*rowBlocksIncluded;
int rowBlockCount = getYSize() * getZSize(); int totalBlockCount = getXSize() * rowBlockCount;
byteArray blockData = byteArray(Level::CHUNK_TILE_COUNT); PIXBeginNamedEvent(0,"Getting block data"); chunk->getBlockData(blockData); PIXEndNamedEvent(); byteArray dataData = byteArray(Level::HALF_CHUNK_TILE_COUNT); PIXBeginNamedEvent(0,"Getting Data data"); chunk->getDataData(dataData); PIXEndNamedEvent();
// Ignore light data int blockLightP = -1; int skyLightP = -1; if( rot == eSchematicRot_90 || rot == eSchematicRot_180 || rot == eSchematicRot_270 ) { int schematicXRow = 0; int schematicZRow = 0; int blocksP = 0; int dataP = 0;
for(int x = xStart; x < xEnd; ++x) { int x0 = x - chunk->x*16; int x1 = x0 + 1;
for(int z = zStart; z < zEnd; ++z) { int z0 = z - chunk->z*16; int z1 = z0 + 1;
chunkCoordToSchematicCoord(destinationBox, x, z, rot, schematicXRow, schematicZRow); blocksP = (schematicXRow*rowBlockCount) + (schematicZRow*getYSize()); dataP = totalBlockCount + (blocksP)/2;
ConsoleSchematicFile::setBlocksAndData(chunk,blockData,dataData,m_data, x0, yStart, z0, x1, yEnd, z1, blocksP, dataP, blockLightP, skyLightP); } } } else if( rot == eSchematicRot_0 ) { // The initial pointer offsets for the different data types int schematicXRow = xStart - destinationBox->x0; int schematicZRow = zStart - destinationBox->z0; int blocksP = (schematicXRow*rowBlockCount) + (schematicZRow*getYSize()); int dataP = totalBlockCount + (schematicXRow*rowBlockCount + (schematicZRow*getYSize()))/2;
for(int x = xStart; x < xEnd; ++x) { int x0 = x - chunk->x*16; int x1 = x0 + 1;
int z0 = zStart - chunk->z*16; int z1 = zEnd - chunk->z*16;
ConsoleSchematicFile::setBlocksAndData(chunk,blockData,dataData,m_data, x0, yStart, z0, x1, yEnd, z1, blocksP, dataP, blockLightP, skyLightP); // update all pointer positions // For z start to z end // Set blocks and data // increment z by the right amount blocksP += (rowBlockCount-rowBlocksIncluded); dataP += (rowBlockCount-rowBlocksIncluded)/2; } } else { app.DebugPrintf("ERROR: Rotation of block and data not implemented!!\n"); }
// 4J Stu - Hack for ME pack to replace sand with end stone in schematics //for(int i = 0; i < blockData.length; ++i) //{ // if(blockData[i] == Tile::sand_Id || blockData[i] == Tile::sandStone_Id) // { // blockData[i] = Tile::endStone_Id; // } //} PIXBeginNamedEvent(0,"Setting Block data"); chunk->setBlockData(blockData); PIXEndNamedEvent(); delete blockData.data; chunk->recalcHeightmapOnly(); PIXBeginNamedEvent(0,"Setting Data data"); chunk->setDataData(dataData); PIXEndNamedEvent(); delete dataData.data;
// A basic pass through to roughly do the lighting. At this point of post-processing, we don't have all the neighbouring chunks loaded in, // so any lighting here should be things that won't propagate out of this chunk. for( int xx = xStart ; xx < xEnd; xx++ ) for( int y = yStart ; y < yEnd; y++ ) for( int zz = zStart ; zz < zEnd; zz++ ) { int x = xx - chunk->x * 16; int z = zz - chunk->z * 16; chunk->setBrightness(LightLayer::Block,x,y,z,0); if( chunk->getTile(x,y,z) ) { chunk->setBrightness(LightLayer::Sky,x,y,z,0); } else { if( chunk->isSkyLit(x,y,z) ) { chunk->setBrightness(LightLayer::Sky,x,y,z,15); } else { chunk->setBrightness(LightLayer::Sky,x,y,z,0); } } }
return blocksIncluded;}
// At the point that this is called, we have all the neighbouring chunks loaded in (and generally post-processed, apart from this lighting pass), so// we can do the sort of lighting that might propagate out of the chunk.__int64 ConsoleSchematicFile::applyLighting(LevelChunk *chunk, AABB *chunkBox, AABB *destinationBox, ESchematicRotation rot){ int xStart = max(destinationBox->x0, (double)chunk->x*16); int xEnd = min(destinationBox->x1, (double)((xStart>>4)<<4) + 16);
int yStart = destinationBox->y0; int yEnd = destinationBox->y1; if(yEnd > Level::maxBuildHeight) yEnd = Level::maxBuildHeight;
int zStart = max(destinationBox->z0, (double)chunk->z*16); int zEnd = min(destinationBox->z1, (double)((zStart>>4)<<4) + 16);
int rowBlocksIncluded = (yEnd-yStart)*(zEnd-zStart); int blocksIncluded = (xEnd-xStart)*rowBlocksIncluded;
// Now actually do a checkLight on blocks that might need it, which should more accurately put everything in place for( int xx = xStart ; xx < xEnd; xx++ ) for( int y = yStart ; y < yEnd; y++ ) for( int zz = zStart ; zz < zEnd; zz++ ) { int x = xx - chunk->x * 16; int z = zz - chunk->z * 16;
if( y <= chunk->getHeightmap( x, z ) ) { chunk->level->checkLight(LightLayer::Sky, xx, y, zz, true); } if( Tile::lightEmission[chunk->getTile(x,y,z)] ) { // Note that this lighting passes a rootOnlyEmissive flag of true, which means that only the location xx/y/zz is considered // as possibly being a source of emissive light, not other tiles that we might encounter whilst propagating the light from // the start location. If we don't do this, and Do encounter another emissive source in the radius of influence that the first // light source had, then we'll start also lighting from that tile but won't actually be able to progatate that second light // fully since checkLight only has a finite radius of 17 from the start position that it can light. Then when we do a checkLight // on the second light later, it won't bother doing anything because the light level at the location of the tile itself will be correct. chunk->level->checkLight(LightLayer::Block, xx, y, zz, true, true); } }
return blocksIncluded;}
void ConsoleSchematicFile::chunkCoordToSchematicCoord(AABB *destinationBox, int chunkX, int chunkZ, ESchematicRotation rot, int &schematicX, int &schematicZ){ switch(rot) { case eSchematicRot_90: // schematicX decreases as chunkZ increases // schematicZ increases as chunkX increases schematicX = chunkZ - destinationBox->z0; schematicZ = (destinationBox->x1 - 1 - destinationBox->x0) - (chunkX - destinationBox->x0); break; case eSchematicRot_180: // schematicX decreases as chunkX increases // schematicZ decreases as chunkZ increases schematicX = (destinationBox->x1 - 1 - destinationBox->x0) - (chunkX - destinationBox->x0); schematicZ = (destinationBox->z1 - 1 - destinationBox->z0) - (chunkZ - destinationBox->z0); break; case eSchematicRot_270: // schematicX increases as chunkZ increases // shcematicZ decreases as chunkX increases schematicX = (destinationBox->z1 - 1 - destinationBox->z0) - (chunkZ - destinationBox->z0); schematicZ = chunkX - destinationBox->x0; break; case eSchematicRot_0: default: // schematicX increases as chunkX increases // schematicZ increases as chunkZ increases schematicX = chunkX - destinationBox->x0; schematicZ = chunkZ - destinationBox->z0; break; };}
void ConsoleSchematicFile::schematicCoordToChunkCoord(AABB *destinationBox, double schematicX, double schematicZ, ESchematicRotation rot, double &chunkX, double &chunkZ){ switch(rot) { case eSchematicRot_90: // schematicX decreases as chunkZ increases // schematicZ increases as chunkX increases chunkX = (destinationBox->x1 - 1 - schematicZ); chunkZ = schematicX + destinationBox->z0; break; case eSchematicRot_180: // schematicX decreases as chunkX increases // schematicZ decreases as chunkZ increases chunkX = (destinationBox->x1 - 1 - schematicX); chunkZ = (destinationBox->z1 - 1 - schematicZ); break; case eSchematicRot_270: // schematicX increases as chunkZ increases // shcematicZ decreases as chunkX increases chunkX = schematicZ + destinationBox->x0; chunkZ = (destinationBox->z1 - 1 - schematicX); break; case eSchematicRot_0: default: // schematicX increases as chunkX increases // schematicZ increases as chunkZ increases chunkX = schematicX + destinationBox->x0; chunkZ = schematicZ + destinationBox->z0; break; };}
void ConsoleSchematicFile::applyTileEntities(LevelChunk *chunk, AABB *chunkBox, AABB *destinationBox, ESchematicRotation rot){ for(AUTO_VAR(it, m_tileEntities.begin()); it != m_tileEntities.end();++it) { shared_ptr<TileEntity> te = *it;
double targetX = te->x; double targetY = te->y + destinationBox->y0; double targetZ = te->z;
schematicCoordToChunkCoord(destinationBox, te->x, te->z, rot, targetX, targetZ);
Vec3 *pos = Vec3::newTemp(targetX,targetY,targetZ); if( chunkBox->containsIncludingLowerBound(pos) ) { shared_ptr<TileEntity> teCopy = chunk->getTileEntity( (int)targetX & 15, (int)targetY & 15, (int)targetZ & 15 );
if ( teCopy != NULL ) { CompoundTag *teData = new CompoundTag(); te->save(teData);
teCopy->load(teData);
delete teData;
// Adjust the tileEntity position to world coords from schematic co-ords teCopy->x = targetX; teCopy->y = targetY; teCopy->z = targetZ;
// Remove the current tile entity //chunk->removeTileEntity( (int)targetX & 15, (int)targetY & 15, (int)targetZ & 15 ); } else { teCopy = te->clone();
// Adjust the tileEntity position to world coords from schematic co-ords teCopy->x = targetX; teCopy->y = targetY; teCopy->z = targetZ; chunk->addTileEntity(teCopy); }
teCopy->setChanged(); } } for(AUTO_VAR(it, m_entities.begin()); it != m_entities.end();) { Vec3 *source = it->first; double targetX = source->x; double targetY = source->y + destinationBox->y0; double targetZ = source->z; schematicCoordToChunkCoord(destinationBox, source->x, source->z, rot, targetX, targetZ);
// Add 0.01 as the AABB::contains function returns false if a value is <= the lower bound Vec3 *pos = Vec3::newTemp(targetX+0.01,targetY+0.01,targetZ+0.01); if( !chunkBox->containsIncludingLowerBound(pos) ) { ++it; continue; }
CompoundTag *eTag = it->second; shared_ptr<Entity> e = EntityIO::loadStatic(eTag, NULL);
if( e->GetType() == eTYPE_PAINTING ) { shared_ptr<Painting> painting = dynamic_pointer_cast<Painting>(e); double tileX = painting->xTile; double tileZ = painting->zTile; schematicCoordToChunkCoord(destinationBox, painting->xTile, painting->zTile, rot, tileX, tileZ);
painting->yTile += destinationBox->y0; painting->xTile = tileX; painting->zTile = tileZ; painting->setDir(painting->dir); } else if( e->GetType() == eTYPE_ITEM_FRAME ) { shared_ptr<ItemFrame> frame = dynamic_pointer_cast<ItemFrame>(e); double tileX = frame->xTile; double tileZ = frame->zTile; schematicCoordToChunkCoord(destinationBox, frame->xTile, frame->zTile, rot, tileX, tileZ);
frame->yTile += destinationBox->y0; frame->xTile = tileX; frame->zTile = tileZ; frame->setDir(frame->dir); } else { e->absMoveTo(targetX, targetY, targetZ,e->yRot,e->xRot); }#ifdef _DEBUG app.DebugPrintf("Adding entity type %d at (%f,%f,%f)\n",e->GetType(),e->x,e->y,e->z);#endif e->setLevel(chunk->level); e->resetSmallId(); e->setDespawnProtected(); // default to being protected against despawning chunk->level->addEntity(e);
// 4J Stu - Until we can copy every type of entity, remove them from this vector // This means that the entities will only exist in the first use of the schematic that is processed //it = m_entities.erase(it); ++it; }}
void ConsoleSchematicFile::generateSchematicFile(DataOutputStream *dos, Level *level, int xStart, int yStart, int zStart, int xEnd, int yEnd, int zEnd, bool bSaveMobs, Compression::ECompressionTypes compressionType){ assert(xEnd > xStart); assert(yEnd > yStart); assert(zEnd > zStart); // 4J Stu - Enforce even numbered positions to start with to avoid problems with half-bytes in data
// We want the start to be even if(xStart > 0 && xStart%2 != 0) xStart-=1; else if(xStart < 0 && xStart%2 !=0) xStart-=1; if(yStart < 0) yStart = 0; else if(yStart > 0 && yStart%2 != 0) yStart-=1; if(zStart > 0 && zStart%2 != 0) zStart-=1; else if(zStart < 0 && zStart%2 !=0) zStart-=1; // We want the end to be odd to have a total size that is even if(xEnd > 0 && xEnd%2 == 0) xEnd+=1; else if(xEnd < 0 && xEnd%2 ==0) xEnd+=1; if(yEnd > Level::maxBuildHeight) yEnd = Level::maxBuildHeight; else if(yEnd > 0 && yEnd%2 == 0) yEnd+=1; else if(yEnd < 0 && yEnd%2 ==0) yEnd+=1; if(zEnd > 0 && zEnd%2 == 0) zEnd+=1; else if(zEnd < 0 && zEnd%2 ==0) zEnd+=1;
int xSize = xEnd - xStart + 1; int ySize = yEnd - yStart + 1; int zSize = zEnd - zStart + 1;
app.DebugPrintf("Generating schematic file for area (%d,%d,%d) to (%d,%d,%d), %dx%dx%d\n",xStart,yStart,zStart,xEnd,yEnd,zEnd,xSize,ySize,zSize);
if(dos != NULL) dos->writeInt(XBOX_SCHEMATIC_CURRENT_VERSION);
if(dos != NULL) dos->writeByte(compressionType);
//Write xSize if(dos != NULL) dos->writeInt(xSize);
//Write ySize if(dos != NULL) dos->writeInt(ySize);
//Write zSize if(dos != NULL) dos->writeInt(zSize);
//byteArray rawBuffer = level->getBlocksAndData(xStart, yStart, zStart, xSize, ySize, zSize, false); int xRowSize = ySize * zSize; int blockCount = xSize * xRowSize; byteArray result( blockCount * 3 / 2 );
// Position pointers into the data when not ordered by chunk int p = 0; int dataP = blockCount; int blockLightP = -1; int skyLightP = -1;
int y0 = yStart; int y1 = yStart + ySize; if (y0 < 0) y0 = 0; if (y1 > Level::maxBuildHeight) y1 = Level::maxBuildHeight;
// Every x is a whole row for(int xPos = xStart; xPos < xStart + xSize; ++xPos) { int xc = xPos >> 4;
int x0 = xPos - xc * 16; if (x0 < 0) x0 = 0; int x1 = x0 + 1; if (x1 > 16) x1 = 16;
for(int zPos = zStart; zPos < zStart + zSize;) { int zc = zPos >> 4;
int z0 = zStart - zc * 16; int z1 = zStart + zSize - zc * 16; if (z0 < 0) z0 = 0; if (z1 > 16) z1 = 16; getBlocksAndData(level->getChunk(xc, zc), &result, x0, y0, z0, x1, y1, z1, p, dataP, blockLightP, skyLightP); zPos += (z1-z0); } }
#ifndef _CONTENT_PACKAGE if(p!=blockCount) __debugbreak();#endif
// We don't know how this will compress - just make a fixed length buffer to initially decompress into // Some small sets of blocks can end up compressing into something bigger than their source unsigned int inputSize = blockCount * 3 / 2; unsigned char *ucTemp = new unsigned char[inputSize];
switch(compressionType) { case Compression::eCompressionType_LZXRLE: Compression::getCompression()->CompressLZXRLE( ucTemp, &inputSize, result.data, (unsigned int) result.length ); break; case Compression::eCompressionType_RLE: Compression::getCompression()->CompressRLE( ucTemp, &inputSize, result.data, (unsigned int) result.length ); break; case Compression::eCompressionType_None: default: memcpy( ucTemp, result.data, inputSize ); break; };
delete [] result.data; byteArray buffer = byteArray(ucTemp,inputSize);
if(dos != NULL) dos->writeInt(inputSize); if(dos != NULL) dos->write(buffer); delete [] buffer.data;
CompoundTag tag; ListTag<CompoundTag> *tileEntitiesTag = new ListTag<CompoundTag>(L"tileEntities");
int xc0 = xStart >> 4; int zc0 = zStart >> 4; int xc1 = (xStart + xSize - 1) >> 4; int zc1 = (zStart + zSize - 1) >> 4;
for (int xc = xc0; xc <= xc1; xc++) { for (int zc = zc0; zc <= zc1; zc++) { vector<shared_ptr<TileEntity> > *tileEntities = getTileEntitiesInRegion(level->getChunk(xc, zc), xStart, yStart, zStart, xStart + xSize, yStart + ySize, zStart + zSize); for(AUTO_VAR(it, tileEntities->begin()); it != tileEntities->end(); ++it) { shared_ptr<TileEntity> te = *it; CompoundTag *teTag = new CompoundTag(); shared_ptr<TileEntity> teCopy = te->clone();
// Adjust the tileEntity position to schematic coords from world co-ords teCopy->x -= xStart; teCopy->y -= yStart; teCopy->z -= zStart; teCopy->save(teTag); tileEntitiesTag->add(teTag); } delete tileEntities; } } tag.put(L"TileEntities", tileEntitiesTag);
AABB *bb = AABB::newTemp(xStart,yStart,zStart,xEnd,yEnd,zEnd); vector<shared_ptr<Entity> > *entities = level->getEntities(nullptr, bb); ListTag<CompoundTag> *entitiesTag = new ListTag<CompoundTag>(L"entities");
for(AUTO_VAR(it, entities->begin()); it != entities->end(); ++it) { shared_ptr<Entity> e = *it;
bool mobCanBeSaved = false; if (bSaveMobs) { if ( e->instanceof(eTYPE_MONSTER) || e->instanceof(eTYPE_WATERANIMAL) || e->instanceof(eTYPE_ANIMAL) || (e->GetType() == eTYPE_VILLAGER) )
// 4J-JEV: All these are derived from eTYPE_ANIMAL and true implicitly. //|| ( e->GetType() == eTYPE_CHICKEN ) || ( e->GetType() == eTYPE_WOLF ) || ( e->GetType() == eTYPE_MUSHROOMCOW ) ) { mobCanBeSaved = true; } }
// 4J-JEV: Changed to check for instances of minecarts and hangingEntities instead of just eTYPE_PAINTING, eTYPE_ITEM_FRAME and eTYPE_MINECART if (mobCanBeSaved || e->instanceof(eTYPE_MINECART) || e->GetType() == eTYPE_BOAT || e->instanceof(eTYPE_HANGING_ENTITY)) { CompoundTag *eTag = new CompoundTag(); if( e->save(eTag) ) { ListTag<DoubleTag> *pos = (ListTag<DoubleTag> *) eTag->getList(L"Pos");
pos->get(0)->data -= xStart; pos->get(1)->data -= yStart; pos->get(2)->data -= zStart;
if( e->instanceof(eTYPE_HANGING_ENTITY) ) { ((IntTag *) eTag->get(L"TileX") )->data -= xStart; ((IntTag *) eTag->get(L"TileY") )->data -= yStart; ((IntTag *) eTag->get(L"TileZ") )->data -= zStart; }
entitiesTag->add(eTag); } } }
tag.put(L"Entities", entitiesTag);
if(dos != NULL) NbtIo::write(&tag,dos);}
void ConsoleSchematicFile::getBlocksAndData(LevelChunk *chunk, byteArray *data, int x0, int y0, int z0, int x1, int y1, int z1, int &blocksP, int &dataP, int &blockLightP, int &skyLightP){ // 4J Stu - Needs updated to work with higher worlds, should still work with non-optimised version below //int xs = x1 - x0; //int ys = y1 - y0; //int zs = z1 - z0; //if (xs * ys * zs == LevelChunk::BLOCKS_LENGTH) //{ // byteArray blockData = byteArray(data->data + blocksP, Level::CHUNK_TILE_COUNT); // chunk->getBlockData(blockData); // blocksP += blockData.length;
// byteArray dataData = byteArray(data->data + dataP, 16384); // chunk->getBlockLightData(dataData); // dataP += dataData.length;
// byteArray blockLightData = byteArray(data->data + blockLightP, 16384); // chunk->getBlockLightData(blockLightData); // blockLightP += blockLightData.length;
// byteArray skyLightData = byteArray(data->data + skyLightP, 16384); // chunk->getSkyLightData(skyLightData); // skyLightP += skyLightData.length; // return; //} bool bHasLower, bHasUpper; bHasLower = bHasUpper = false; int lowerY0, lowerY1, upperY0, upperY1; lowerY0 = upperY0 = y0; lowerY1 = upperY1 = y1;
int compressedHeight = Level::COMPRESSED_CHUNK_SECTION_HEIGHT; if(y0 < Level::COMPRESSED_CHUNK_SECTION_HEIGHT) { lowerY0 = y0; lowerY1 = min(y1, compressedHeight); bHasLower = true; } if(y1 >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT) { upperY0 = max(y0, compressedHeight) - Level::COMPRESSED_CHUNK_SECTION_HEIGHT; upperY1 = y1 - Level::COMPRESSED_CHUNK_SECTION_HEIGHT; bHasUpper = true; }
byteArray blockData = byteArray(Level::CHUNK_TILE_COUNT); chunk->getBlockData(blockData); for (int x = x0; x < x1; x++) for (int z = z0; z < z1; z++) { if(bHasLower) { int slot = x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | lowerY0; int len = lowerY1 - lowerY0; System::arraycopy(blockData, slot, data, blocksP, len); blocksP += len; } if(bHasUpper) { int slot = (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | upperY0) + Level::COMPRESSED_CHUNK_SECTION_TILES; int len = upperY1 - upperY0; System::arraycopy(blockData, slot, data, blocksP, len); blocksP += len; } } delete blockData.data;
byteArray dataData = byteArray(Level::CHUNK_TILE_COUNT); chunk->getDataData(dataData); for (int x = x0; x < x1; x++) for (int z = z0; z < z1; z++) { if(bHasLower) { int slot = (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | lowerY0) >> 1; int len = (lowerY1 - lowerY0) / 2; System::arraycopy(dataData, slot, data, dataP, len); dataP += len; } if(bHasUpper) { int slot = ((x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | upperY0) + Level::COMPRESSED_CHUNK_SECTION_TILES) >> 1; int len = (upperY1 - upperY0) / 2; System::arraycopy(dataData, slot, data, dataP, len); dataP += len; } } delete dataData.data;
// 4J Stu - Allow ignoring light data if(blockLightP > -1) { byteArray blockLightData = byteArray(Level::HALF_CHUNK_TILE_COUNT); chunk->getBlockLightData(blockLightData); for (int x = x0; x < x1; x++) for (int z = z0; z < z1; z++) { if(bHasLower) { int slot = (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | lowerY0) >> 1; int len = (lowerY1 - lowerY0) / 2; System::arraycopy(blockLightData, slot, data, blockLightP, len); blockLightP += len; } if(bHasUpper) { int slot = ((x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | upperY0) >> 1) + (Level::COMPRESSED_CHUNK_SECTION_TILES/2); int len = (upperY1 - upperY0) / 2; System::arraycopy(blockLightData, slot, data, blockLightP, len); blockLightP += len; } } delete blockLightData.data; }
// 4J Stu - Allow ignoring light data if(skyLightP > -1) { byteArray skyLightData = byteArray(Level::HALF_CHUNK_TILE_COUNT); chunk->getSkyLightData(skyLightData); for (int x = x0; x < x1; x++) for (int z = z0; z < z1; z++) { if(bHasLower) { int slot = (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | lowerY0) >> 1; int len = (lowerY1 - lowerY0) / 2; System::arraycopy(skyLightData, slot, data, skyLightP, len); skyLightP += len; } if(bHasUpper) { int slot = ((x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | upperY0) >> 1) + (Level::COMPRESSED_CHUNK_SECTION_TILES/2); int len = (upperY1 - upperY0) / 2; System::arraycopy(skyLightData, slot, data, skyLightP, len); skyLightP += len; } } delete skyLightData.data; }
return;}
void ConsoleSchematicFile::setBlocksAndData(LevelChunk *chunk, byteArray blockData, byteArray dataData, byteArray inputData, int x0, int y0, int z0, int x1, int y1, int z1, int &blocksP, int &dataP, int &blockLightP, int &skyLightP){ bool bHasLower, bHasUpper; bHasLower = bHasUpper = false; int lowerY0, lowerY1, upperY0, upperY1; lowerY0 = upperY0 = y0; lowerY1 = upperY1 = y1;
int compressedHeight = Level::COMPRESSED_CHUNK_SECTION_HEIGHT; if(y0 < Level::COMPRESSED_CHUNK_SECTION_HEIGHT) { lowerY0 = y0; lowerY1 = min(y1, compressedHeight); bHasLower = true; } if(y1 >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT) { upperY0 = max(y0, compressedHeight) - Level::COMPRESSED_CHUNK_SECTION_HEIGHT; upperY1 = y1 - Level::COMPRESSED_CHUNK_SECTION_HEIGHT; bHasUpper = true; } PIXBeginNamedEvent(0,"Applying block data"); for (int x = x0; x < x1; x++) for (int z = z0; z < z1; z++) { if(bHasLower) { int slot = x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | lowerY0; int len = lowerY1 - lowerY0; System::arraycopy(inputData, blocksP, &blockData, slot, len); blocksP += len; } if(bHasUpper) { int slot = (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | upperY0) + Level::COMPRESSED_CHUNK_SECTION_TILES; int len = upperY1 - upperY0; System::arraycopy(inputData, blocksP, &blockData, slot, len); blocksP += len; } } PIXEndNamedEvent();
PIXBeginNamedEvent(0,"Applying Data data"); for (int x = x0; x < x1; x++) for (int z = z0; z < z1; z++) { if(bHasLower) { int slot = (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | lowerY0) >> 1; int len = (lowerY1 - lowerY0) / 2; System::arraycopy(inputData, dataP, &dataData, slot, len); dataP += len; } if(bHasUpper) { int slot = ((x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | upperY0) + Level::COMPRESSED_CHUNK_SECTION_TILES) >> 1; int len = (upperY1 - upperY0) / 2; System::arraycopy(inputData, dataP, &dataData, slot, len); dataP += len; } } PIXEndNamedEvent(); // 4J Stu - Allow ignoring light data if(blockLightP > -1) { byteArray blockLightData = byteArray(Level::HALF_CHUNK_TILE_COUNT); chunk->getBlockLightData(blockLightData); for (int x = x0; x < x1; x++) for (int z = z0; z < z1; z++) { if(bHasLower) { int slot = (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | lowerY0) >> 1; int len = (lowerY1 - lowerY0) / 2; System::arraycopy(inputData, blockLightP, &blockLightData, slot, len); blockLightP += len; } if(bHasUpper) { int slot = ( (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | upperY0) >> 1) + (Level::COMPRESSED_CHUNK_SECTION_TILES/2); int len = (upperY1 - upperY0) / 2; System::arraycopy(inputData, blockLightP, &blockLightData, slot, len); blockLightP += len; } } chunk->setBlockLightData(blockLightData); delete blockLightData.data; }
// 4J Stu - Allow ignoring light data if(skyLightP > -1) { byteArray skyLightData = byteArray(Level::HALF_CHUNK_TILE_COUNT); chunk->getSkyLightData(skyLightData); for (int x = x0; x < x1; x++) for (int z = z0; z < z1; z++) { if(bHasLower) { int slot = (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | lowerY0) >> 1; int len = (lowerY1 - lowerY0) / 2; System::arraycopy(inputData, skyLightP, &skyLightData, slot, len); skyLightP += len; } if(bHasUpper) { int slot = (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | upperY0) + (Level::COMPRESSED_CHUNK_SECTION_TILES/2); int len = (upperY1 - upperY0) / 2; System::arraycopy(inputData, skyLightP, &skyLightData, slot, len); skyLightP += len; } } chunk->setSkyLightData(skyLightData); delete skyLightData.data; }}
vector<shared_ptr<TileEntity> > *ConsoleSchematicFile::getTileEntitiesInRegion(LevelChunk *chunk, int x0, int y0, int z0, int x1, int y1, int z1){ vector<shared_ptr<TileEntity> > *result = new vector<shared_ptr<TileEntity> >; for (AUTO_VAR(it, chunk->tileEntities.begin()); it != chunk->tileEntities.end(); ++it) { shared_ptr<TileEntity> te = it->second; if (te->x >= x0 && te->y >= y0 && te->z >= z0 && te->x < x1 && te->y < y1 && te->z < z1) { result->push_back(te); } } return result;}