feat: extend NetSession
This commit is contained in:
1 parent
34191ca984
commit
5a8b7da730
1 file changed
+156
@@ -158,3 +158,159 @@ void NetSession::beginHandshake(const std::string& playerName, uint64_t high, ui
|
||||
login.encode(loginBody);
|
||||
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;
|
||||
|
||||
Reference in new issue
Block a user