+ if (pack_diff <= 0 && !overdue) {
+ // drop old packets if we have a fairly recent state
+ return;
+ }
+ glm::vec3 movement(0.0f);
+ uint8_t new_actions;
+ uint8_t slot;
+
+ player_update_pack = pack.Seq();
+ pack.ReadPredictedState(player_update_state);
+ pack.ReadMovement(movement);
+ pack.ReadActions(new_actions);
+ pack.ReadSlot(slot);
+
+ // accept client's orientation as is
+ input->GetPlayer().GetEntity().Orientation(player_update_state.orient);
+ // simulate movement
+ input->SetMovement(movement);
+ // rotate head to match client's "prediction"
+ input->TurnHead(player_update_state.pitch - input->GetPitch(), player_update_state.yaw - input->GetYaw());
+ // select the given inventory slot
+ input->SelectInventory(slot);
+
+ // check if any actions have been started or stopped
+ if ((new_actions & 0x01) && !(old_actions & 0x01)) {
+ input->StartPrimaryAction();
+ } else if (!(new_actions & 0x01) && (old_actions & 0x01)) {
+ input->StopPrimaryAction();
+ }
+ if ((new_actions & 0x02) && !(old_actions & 0x02)) {
+ input->StartSecondaryAction();
+ } else if (!(new_actions & 0x02) && (old_actions & 0x02)) {
+ input->StopSecondaryAction();
+ }
+ if ((new_actions & 0x04) && !(old_actions & 0x04)) {
+ input->StartTertiaryAction();
+ } else if (!(new_actions & 0x04) && (old_actions & 0x04)) {
+ input->StopTertiaryAction();
+ }
+ old_actions = new_actions;
+}
+
+bool ClientConnection::ChunkInRange(const glm::ivec3 &pos) const noexcept {
+ return HasPlayer() && PlayerChunks().InRange(pos);
+}
+
+void ClientConnection::On(const Packet::ChunkBegin &pack) {
+ glm::ivec3 pos;
+ pack.ReadChunkCoords(pos);
+ if (ChunkInRange(pos)) {
+ chunk_queue.push_front(pos);
+ }
+}
+
+void ClientConnection::On(const Packet::Message &pack) {
+ uint8_t type;
+ uint32_t ref;
+ string msg;
+ pack.ReadType(type);
+ pack.ReadReferral(ref);
+ pack.ReadMessage(msg);
+
+ if (type == 1 && cli_ctx) {
+ server.DispatchMessage(*cli_ctx, msg);