#include "stdafx.h" #include #include "InputOutputStream.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.level.chunk.h" #include "PacketListener.h" #include "ChunkTilesUpdatePacket.h" #include "Dimension.h" ChunkTilesUpdatePacket::~ChunkTilesUpdatePacket() { delete [] blocks.data; delete [] data.data; delete [] positions.data; } ChunkTilesUpdatePacket::ChunkTilesUpdatePacket() { shouldDelay = true; xc = 0; zc = 0; count = 0; } ChunkTilesUpdatePacket::ChunkTilesUpdatePacket(int xc, int zc, shortArray positions, byte count, Level *level) { shouldDelay = true; this->xc = xc; this->zc = zc; this->count = count; this->positions = shortArray(count); this->blocks = byteArray(count); this->data = byteArray(count); LevelChunk *levelChunk = level->getChunk(xc, zc); for (int i = 0; i < count; i++) { int x = (positions[i] >> 12) & 15; int z = (positions[i] >> 8) & 15; int y = (positions[i]) & 255; this->positions[i] = positions[i]; blocks[i] = (byte) levelChunk->getTile(x, y, z); data[i] = (byte) levelChunk->getData(x, y, z); } levelIdx = ( ( level->dimension->id == 0 ) ? 0 : ( (level->dimension->id == -1) ? 1 : 2 ) ); } void ChunkTilesUpdatePacket::read(DataInputStream *dis) //throws IOException { // 4J - changed format. See comments in write method. #ifdef _LARGE_WORLDS xc = dis->readShort(); zc = dis->readShort(); xc = ( xc << 16 ) >> 16; zc = ( zc << 16 ) >> 16; #else xc = dis->read(); zc = dis->read(); xc = ( xc << 24 ) >> 24; zc = ( zc << 24 ) >> 24; #endif int countAndFlags = dis->readByte(); bool dataAllZero = (( countAndFlags & 0x80 ) == 0x80 ); levelIdx = ( countAndFlags >> 5 ) & 3; count = countAndFlags & 0x1f; positions = shortArray(count); blocks = byteArray(count); data = byteArray(count); int currentBlockType = -1; for( int i = 0; i < count; i++ ) { int xzAndFlag = dis->readShort(); int y = dis->readByte(); positions[i] = (xzAndFlag & 0xff00) | (y & 0xff); if( ( xzAndFlag & 0x0080 ) == 0x0080 ) { currentBlockType = dis->read(); } blocks[i] = currentBlockType; if( !dataAllZero) { data[i] = dis->read(); } else { data[i] = 0; } } } void ChunkTilesUpdatePacket::write(DataOutputStream *dos) //throws IOException { // 4J - changed format to reduce size of these packets. #ifdef _LARGE_WORLDS dos->writeShort(xc); dos->writeShort(zc); #else dos->write(xc); dos->write(zc); #endif // Determine if we've got any data elements that are non-zero - a large % of these packets set all data to zero, so we don't // bother sending all those zeros in that case. bool dataAllZero = true; for( int i = 0; i < count; i++ ) { if( data[i] ) dataAllZero = false; } int countAndFlags = count; if( dataAllZero ) countAndFlags |= 0x80; countAndFlags |= ( levelIdx << 5 ); dos->write(countAndFlags); int lastBlockType = -1; // Each block is represented by 15 bits of position, a flag to say whether the current block type is to change, and a possible data value. // A large % of these packets set the same block type to a several positions, so no point resending the block type when not necessary. for( int i = 0; i < count; i++ ) { int xzAndFlag = positions[i] &0xff00; int y = positions[i] & 0xff; int thisBlockType = blocks[i]; if( thisBlockType != lastBlockType ) { xzAndFlag |= 0x0080; // Use top bit of y as a flag, we only need 7 bits for that dos->writeShort(xzAndFlag); dos->write(y); dos->write(thisBlockType); lastBlockType = thisBlockType; } else { dos->writeShort(xzAndFlag); dos->write(y); } if( !dataAllZero ) { dos->write(data[i]); } } } void ChunkTilesUpdatePacket::handle(PacketListener *listener) { listener->handleChunkTilesUpdate(shared_from_this()); } int ChunkTilesUpdatePacket::getEstimatedSize() { bool dataAllZero = true; int lastBlockType = -1; int blockTypeChanges = 0; for( int i = 0; i < count; i++ ) { if( data[i] ) dataAllZero = false; int thisBlockType = blocks[i]; if( thisBlockType != lastBlockType ) { blockTypeChanges++; lastBlockType = thisBlockType; } } int byteCount = 3 + 2 * count + blockTypeChanges; if( !dataAllZero ) { byteCount += count; } return byteCount; }