feat: extend NetSession

This commit is contained in:
dualfroz committed 2026-09-08 18:09:29 +02:00
1 parent 34191ca984
commit 5a8b7da730
1 file changed
+156
+156
View File
@@ -158,3 +158,159 @@ void NetSession::beginHandshake(const std::string& playerName, uint64_t high, ui
login.encode(loginBody); login.encode(loginBody);
enqueue(PacketId::LoginStart, loginBody, true); enqueue(PacketId::LoginStart, loginBody, true);
handshakeStarted = true;
currentPhase = SessionPhase::Login;
}
bool NetSession::legalHere(PacketId id) const {
if (role == Role::Server) {
switch (currentPhase) {
case SessionPhase::Handshake:
return id == PacketId::Handshake;
case SessionPhase::Login:
return id == PacketId::LoginStart;
case SessionPhase::Play:
return id == PacketId::PlayerState || id == PacketId::KeepAlive ||
id == PacketId::BlockChange;
case SessionPhase::Disconnected:
return false;
}
return false;
}
switch (currentPhase) {
case SessionPhase::Handshake:
return false;
case SessionPhase::Login:
return id == PacketId::JoinGame;
case SessionPhase::Play:
return id == PacketId::ChunkData || id == PacketId::BlockChange ||
id == PacketId::MultiBlockChange || id == PacketId::EntityMove ||
id == PacketId::PlayerState || id == PacketId::KeepAlive;
case SessionPhase::Disconnected:
return false;
}
return false;
}
void NetSession::enterPlay(uint64_t tick) {
currentPhase = SessionPhase::Play;
lastKeepAliveHeard = tick;
lastKeepAliveSent = tick;
if (role == Role::Server) recentre(clientView.position);
}
void NetSession::recentre(const Vec3& position) {
clientView.position = position;
Vec3i centre = chunkOf(position);
if (clientView.tracker.hasCentre() && clientView.tracker.centre() == centre) return;
std::vector<Vec3i> entered;
std::vector<Vec3i> left;
clientView.tracker.update(centre, entered, left);
clientView.centreChunk = centre;
for (const Vec3i& coord : entered) clientView.queueChunk(coord);
for (const Vec3i& coord : left) clientView.forget(coord);
}
void NetSession::markChunkDirty(const Vec3i& coord) {
if (!dirtyLookup.insert(coord).second) return;
dirtyChunks.push_back(coord);
}
void NetSession::sendEntityMove(int32_t movedEntityId, const Vec3& position, float yaw, float pitch,
bool onGround) {
if (currentPhase != SessionPhase::Play) return;
EntityMove move;
move.entityId = movedEntityId;
move.x = position.x;
move.y = position.y;
move.z = position.z;
move.yaw = yaw;
move.pitch = pitch;
move.onGround = onGround;
PacketWriter body;
move.encode(body);
enqueue(PacketId::EntityMove, body, false);
++statistics.entityMovesSent;
}
void NetSession::sendPlayerState(const PlayerState& state) {
if (currentPhase != SessionPhase::Play) return;
PacketWriter body;
state.encode(body);
// Upstream position reports age out instantly, an authoritative correction
// from the server must not.
enqueue(PacketId::PlayerState, body, role == Role::Server);
}
void NetSession::requestBlockEdit(int32_t x, int32_t y, int32_t z, Block block) {
if (currentPhase != SessionPhase::Play) return;
BlockChange change;
change.x = x;
change.y = y;
change.z = z;
change.block = block;
PacketWriter body;
change.encode(body);
enqueue(PacketId::BlockChange, body, true);
}
bool NetSession::entityMove(int32_t movedEntityId, EntityMove& out) const {
auto it = entities.find(movedEntityId);
if (it == entities.end()) return false;
out = it->second;
return true;
}
void NetSession::handleMessage(const ByteBuffer& message, uint64_t tick) {
std::vector<Frame> frames;
std::size_t consumed = 0;
splitFrames(message.data(), message.size(), frames, consumed);
for (const Frame& frame : frames) {
if (currentPhase == SessionPhase::Disconnected) return;
handleFrame(frame, tick);
}
}
void NetSession::handleFrame(const Frame& frame, uint64_t tick) {
++statistics.packetsReceived;
if (!legalHere(frame.id)) {
++statistics.packetsRejected;
disconnect("packet out of phase");
return;
}
PacketReader reader(frame.payload.data(), frame.payload.size());
switch (frame.id) {
case PacketId::Handshake: {
Handshake hello;
if (!hello.decode(reader)) {
++statistics.packetsRejected;
disconnect("malformed handshake");
return;
}
if (hello.protocolVersion != config.protocolVersion) {
++statistics.packetsRejected;
disconnect("protocol version mismatch");
return;
}
if (hello.nextState != 2) {
++statistics.packetsRejected;
disconnect("unsupported next state");
return;
}
currentPhase = SessionPhase::Login;
return;
}
case PacketId::LoginStart: {
LoginStart login;
if (!login.decode(reader)) {
++statistics.packetsRejected;
disconnect("malformed login");
return;
}
name = login.name;
uuidHi = login.uuidHi;
uuidLo = login.uuidLo;