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;
|
uuidHi = login.uuidHi;
|
||||||
uuidLo = login.uuidLo;
|
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