mirror of
https://github.com/4jcraft/4jcraft.git
synced 2026-04-23 16:24:43 +00:00
159 lines
5.1 KiB
C++
159 lines
5.1 KiB
C++
#include "minecraft/util/Log.h"
|
|
#include "BlockRegionUpdatePacket.h"
|
|
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
|
|
#include "app/linux/LinuxGame.h"
|
|
#include "PacketListener.h"
|
|
#include "minecraft/world/level/storage/ConsoleSaveFileIO/compression.h"
|
|
#include "java/InputOutputStream/DataInputStream.h"
|
|
#include "java/InputOutputStream/DataOutputStream.h"
|
|
#include "minecraft/world/level/Level.h"
|
|
#include "minecraft/world/level/chunk/LevelChunk.h"
|
|
#include "minecraft/world/level/dimension/Dimension.h"
|
|
|
|
#define BLOCK_REGION_UPDATE_FULLCHUNK 0x01
|
|
#define BLOCK_REGION_UPDATE_ZEROHEIGHT \
|
|
0x02 // added so we can still send a byte for ys, which really needs the
|
|
// range 0-256
|
|
|
|
BlockRegionUpdatePacket::~BlockRegionUpdatePacket() {}
|
|
|
|
BlockRegionUpdatePacket::BlockRegionUpdatePacket() {
|
|
shouldDelay = true;
|
|
x = 0;
|
|
y = 0;
|
|
z = 0;
|
|
xs = 0;
|
|
ys = 0;
|
|
zs = 0;
|
|
bIsFullChunk = false;
|
|
}
|
|
|
|
BlockRegionUpdatePacket::BlockRegionUpdatePacket(int x, int y, int z, int xs,
|
|
int ys, int zs, Level* level) {
|
|
shouldDelay = true;
|
|
this->x = x;
|
|
this->y = y;
|
|
this->z = z;
|
|
this->xs = xs;
|
|
this->ys = ys;
|
|
this->zs = zs;
|
|
bIsFullChunk = false;
|
|
levelIdx =
|
|
((level->dimension->id == 0) ? 0
|
|
: ((level->dimension->id == -1) ? 1 : 2));
|
|
|
|
// 4J - if we are compressing a full chunk, re-order the blocks so that they
|
|
// compress better
|
|
// TODO - we should be using compressed data directly here rather than
|
|
// decompressing first and then recompressing...
|
|
std::vector<uint8_t> rawBuffer;
|
|
|
|
if (xs == 16 && ys == Level::maxBuildHeight && zs == 16 &&
|
|
((x & 15) == 0) && (y == 0) && ((z & 15) == 0)) {
|
|
bIsFullChunk = true;
|
|
|
|
LevelChunk* lc = level->getChunkAt(x, z);
|
|
rawBuffer = lc->getReorderedBlocksAndData(x & 0xF, y, z & 0xF, xs,
|
|
this->ys, zs);
|
|
} else {
|
|
rawBuffer = level->getBlocksAndData(x, y, z, xs, ys, zs, false);
|
|
}
|
|
|
|
if (rawBuffer.size() == 0) {
|
|
size = 0;
|
|
buffer = std::vector<uint8_t>();
|
|
} else {
|
|
// 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 char* ucTemp = new unsigned char[(256 * 16 * 16 * 5) / 2];
|
|
unsigned int inputSize = (256 * 16 * 16 * 5) / 2;
|
|
|
|
Compression::getCompression()->CompressLZXRLE(
|
|
ucTemp, &inputSize, rawBuffer.data(),
|
|
(unsigned int)rawBuffer.size());
|
|
// Log::info("Chunk (%d,%d) compressed from %d to size %d\n",
|
|
// x>>4, z>>4, rawBuffer.size(), inputSize);
|
|
unsigned char* ucTemp2 = new unsigned char[inputSize];
|
|
memcpy(ucTemp2, ucTemp, inputSize);
|
|
delete[] ucTemp;
|
|
buffer = std::vector<uint8_t>(ucTemp2, ucTemp2 + inputSize);
|
|
delete[] ucTemp2;
|
|
size = inputSize;
|
|
}
|
|
}
|
|
|
|
void BlockRegionUpdatePacket::read(DataInputStream* dis) // throws IOException
|
|
{
|
|
uint8_t chunkFlags = dis->readByte();
|
|
x = dis->readInt();
|
|
y = dis->readShort();
|
|
z = dis->readInt();
|
|
xs = dis->read() + 1;
|
|
ys = dis->read() + 1;
|
|
zs = dis->read() + 1;
|
|
|
|
bIsFullChunk = (chunkFlags & BLOCK_REGION_UPDATE_FULLCHUNK) ? true : false;
|
|
if (chunkFlags & BLOCK_REGION_UPDATE_ZEROHEIGHT) ys = 0;
|
|
|
|
size = dis->readInt();
|
|
levelIdx = (size >> 30) & 3;
|
|
size &= 0x3fffffff;
|
|
|
|
if (size == 0) {
|
|
buffer = std::vector<uint8_t>();
|
|
} else {
|
|
std::vector<uint8_t> compressedBuffer(size);
|
|
bool success = dis->readFully(compressedBuffer);
|
|
|
|
int bufferSize = xs * ys * zs * 5 / 2;
|
|
// Add the size of the biome data if it's a full chunk
|
|
if (bIsFullChunk) bufferSize += (16 * 16);
|
|
buffer = std::vector<uint8_t>(bufferSize);
|
|
unsigned int outputSize = buffer.size();
|
|
|
|
if (success) {
|
|
Compression::getCompression()->DecompressLZXRLE(
|
|
buffer.data(), &outputSize, compressedBuffer.data(), size);
|
|
} else {
|
|
Log::info(
|
|
"Not decompressing packet that wasn't fully read\n");
|
|
}
|
|
|
|
// printf("Block (%d %d %d), (%d %d %d) coming in decomp from %d to
|
|
//%d\n",x,y,z,xs,ys,zs,size,outputSize);
|
|
|
|
assert(buffer.size() == outputSize);
|
|
}
|
|
}
|
|
|
|
void BlockRegionUpdatePacket::write(
|
|
DataOutputStream* dos) // throws IOException
|
|
{
|
|
uint8_t chunkFlags = 0;
|
|
if (bIsFullChunk) chunkFlags |= BLOCK_REGION_UPDATE_FULLCHUNK;
|
|
if (ys == 0) chunkFlags |= BLOCK_REGION_UPDATE_ZEROHEIGHT;
|
|
|
|
dos->writeByte(chunkFlags);
|
|
dos->writeInt(x);
|
|
dos->writeShort(y);
|
|
dos->writeInt(z);
|
|
dos->write(xs - 1);
|
|
dos->write(ys - 1);
|
|
dos->write(zs - 1);
|
|
|
|
int sizeAndLevel = size;
|
|
sizeAndLevel |= (levelIdx << 30);
|
|
dos->writeInt(sizeAndLevel);
|
|
dos->write(buffer, 0, size);
|
|
}
|
|
|
|
void BlockRegionUpdatePacket::handle(PacketListener* listener) {
|
|
listener->handleBlockRegionUpdate(shared_from_this());
|
|
}
|
|
|
|
int BlockRegionUpdatePacket::getEstimatedSize() { return 17 + size; }
|