feat: expand NetSession
This commit is contained in:
1 parent
5a8b7da730
commit
48093a8260
1 file changed
+168
@@ -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();
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user