feat: expand NetSession

This commit is contained in:
dualfroz committed 2026-09-08 18:24:05 +02:00
1 parent 5a8b7da730
commit 48093a8260
1 file changed
+168
+168
View File
@@ -314,3 +314,171 @@ void NetSession::handleFrame(const Frame& frame, uint64_t tick) {
uuidHi = login.uuidHi;
uuidLo = login.uuidLo;
JoinGame join;
join.entityId = ownEntityId;
join.gameMode = config.gameMode;
join.dimension = config.dimension;
join.seedHash = config.seedHash;
join.maxPlayers = config.maxPlayers;
join.levelType = config.levelType;
join.viewDistance = config.viewRadius;
join.reducedDebugInfo = false;
PacketWriter body;
join.encode(body);
enqueue(PacketId::JoinGame, body, true);
enterPlay(tick);
return;
}
case PacketId::JoinGame: {
JoinGame join;
if (!join.decode(reader)) {
++statistics.packetsRejected;
disconnect("malformed join");
return;
}
ownEntityId = join.entityId;
clientView.tracker.setRadius(join.viewDistance);
enterPlay(tick);
return;
}
case PacketId::ChunkData: {
ChunkData snapshot;
if (!snapshot.decode(reader)) {
++statistics.packetsRejected;
disconnect("malformed chunk data");
return;
}
clientSync.applyFull(snapshot, *worldRef);
++statistics.chunksApplied;
return;
}
case PacketId::BlockChange: {
BlockChange change;
if (!change.decode(reader)) {
++statistics.packetsRejected;
disconnect("malformed block change");
return;
}
if (role == Role::Server) {
edits.push_back(change);
return;
}
clientSync.applyBlockChange(change, *worldRef);
++statistics.blockChangesApplied;
return;
}
case PacketId::MultiBlockChange: {
MultiBlockChange delta;
if (!delta.decode(reader)) {
++statistics.packetsRejected;
disconnect("malformed multi block change");
return;
}
clientSync.applyDelta(delta, *worldRef);
++statistics.multiBlockChangesApplied;
return;
}
case PacketId::EntityMove: {
EntityMove move;
if (!move.decode(reader)) {
++statistics.packetsRejected;
disconnect("malformed entity move");
return;
}
entities[move.entityId] = move;
++statistics.entityMovesApplied;
return;
}
case PacketId::PlayerState: {
PlayerState state;
if (!state.decode(reader)) {
++statistics.packetsRejected;
disconnect("malformed player state");
return;
}
if (role == Role::Server) {
recentre(Vec3{state.x, state.y, state.z});
return;
}
latestPlayerState = state;
return;
}
case PacketId::KeepAlive: {
KeepAlive beat;
if (!beat.decode(reader)) {
++statistics.packetsRejected;
disconnect("malformed keep alive");
return;
}
if (role == Role::Server) {
// Only a token this server actually issued, and only the first
// time it comes back, counts as proof the client is alive.
if (beat.token > pendingKeepAliveToken) return;
if (beat.token <= acceptedKeepAliveToken) return;
acceptedKeepAliveToken = beat.token;
lastKeepAliveHeard = tick;
return;
}
lastKeepAliveHeard = tick;
PacketWriter body;
beat.encode(body);
enqueue(PacketId::KeepAlive, body, true);
return;
}
}
}
void NetSession::streamChunks() {
uint32_t budget = config.chunksPerTick;
Vec3i coord;
while (budget > 0 && clientView.takeNextPending(coord)) {
if (!clientView.tracker.contains(coord)) continue;
ChunkData snapshot;
if (!syncRef->buildFull(*worldRef, coord, snapshot)) continue;
PacketWriter body;
snapshot.encode(body);
enqueue(PacketId::ChunkData, body, true);
clientView.sent.insert(coord);
++statistics.chunksSent;
--budget;
}
}
void NetSession::flushBlockChanges() {
for (const Vec3i& coord : dirtyChunks) {
if (!clientView.hasChunk(coord)) {
// Nothing to patch yet: the pending full snapshot already carries
// the current contents, so the delta would be redundant.
if (clientView.tracker.contains(coord)) clientView.queueChunk(coord);
continue;
}
MultiBlockChange delta;
if (!syncRef->buildDelta(*worldRef, coord, delta)) continue;
if (delta.changes.size() > config.multiBlockThreshold) {
PacketWriter body;
delta.encode(body);
enqueue(PacketId::MultiBlockChange, body, true);
++statistics.multiBlockChangesSent;
continue;
}
for (const MultiBlockChange::Change& change : delta.changes) {
int local = change.localIndex;
int lx = local % chunkSize;
int lz = (local / chunkSize) % chunkSize;
int ly = local / (chunkSize * chunkSize);
BlockChange single;
single.x = coord.x * chunkSize + lx;
single.y = coord.y * chunkSize + ly;
single.z = coord.z * chunkSize + lz;
single.block = change.block;
PacketWriter body;
single.encode(body);
enqueue(PacketId::BlockChange, body, true);
++statistics.blockChangesSent;
}
}
dirtyChunks.clear();
dirtyLookup.clear();
}