4jcraft/Minecraft.World/Network/Packets/ChunkTilesUpdatePacket.cpp
2026-03-13 17:06:56 -05:00

161 lines
5.1 KiB
C++

#include "../../Platform/stdafx.h"
#include <iostream>
#include "../../IO/Streams/InputOutputStream.h"
#include "../../Headers/net.minecraft.world.level.h"
#include "../../Headers/net.minecraft.world.level.chunk.h"
#include "PacketListener.h"
#include "ChunkTilesUpdatePacket.h"
#include "../../Level/Dimensions/Dimension.h"
ChunkTilesUpdatePacket::~ChunkTilesUpdatePacket() {
delete[] blocks.data;
delete[] data.data;
delete[] positions.data;
}
ChunkTilesUpdatePacket::ChunkTilesUpdatePacket() {
shouldDelay = true;
xc = 0;
zc = 0;
count = (uint8_t)0;
}
ChunkTilesUpdatePacket::ChunkTilesUpdatePacket(int xc, int zc,
shortArray positions,
uint8_t count, Level* level) {
shouldDelay = true;
this->xc = xc;
this->zc = zc;
this->count = count;
this->positions = shortArray((short int)count);
this->blocks = byteArray((unsigned int)count);
this->data = byteArray((unsigned int)count);
LevelChunk* levelChunk = level->getChunk(xc, zc);
for (int i = 0; (uint8_t)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] = (uint8_t)levelChunk->getTile(x, y, z);
data[i] = (uint8_t)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();
// 4jcraft changed shift back and forth to a down cast
xc = (int16_t)xc;
zc = (int16_t)zc;
#else
xc = dis->read();
zc = dis->read();
xc = (xc << 24) >> 24;
zc = (zc << 24) >> 24;
#endif
int countAndFlags = (int)dis->readByte();
bool dataAllZero = ((countAndFlags & 0x80) == 0x80);
levelIdx = (countAndFlags >> 5) & 3;
count = (uint8_t)countAndFlags & (uint8_t)0x1f;
positions = shortArray((short int)count);
blocks = byteArray((unsigned int)count);
data = byteArray((unsigned int)count);
int currentBlockType = -1;
for (int i = 0; (uint8_t)i < count; i++) {
int xzAndFlag = dis->readShort();
int y = (int)dis->readByte();
positions[i] = (xzAndFlag & 0xff00) | (y & 0xff);
if ((xzAndFlag & 0x0080) == 0x0080) {
currentBlockType = dis->read();
}
blocks[i] = (uint8_t)currentBlockType;
if (!dataAllZero) {
data[i] = (uint8_t)dis->read();
} else {
data[i] = (uint8_t)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 < (int)count; i++) {
if ((bool)data[i]) dataAllZero = false;
}
int countAndFlags = (int)count;
if ((bool)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 < (int)count; i++) {
int xzAndFlag = positions[i] & 0xff00;
int y = positions[i] & 0xff;
int thisBlockType = (int)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((unsigned int)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 < (int)count; i++) {
if ((bool)data[i]) dataAllZero = false;
int thisBlockType = (int)blocks[i];
if (thisBlockType != lastBlockType) {
blockTypeChanges++;
lastBlockType = thisBlockType;
}
}
int byteCount = 3 + 2 * (int)count + blockTypeChanges;
if (!dataAllZero) {
byteCount += (unsigned char)count;
}
return byteCount;
}