+ClientConnection::SpawnStatus::SpawnStatus(Entity &e)
+: entity(&e)
+, spawn_pack(-1)
+, despawn_pack(-1) {
+ entity->Ref();
+}
+
+ClientConnection::SpawnStatus::~SpawnStatus() {
+ entity->UnRef();
+}
+
+bool ClientConnection::CanSpawn(const Entity &e) const noexcept {
+ return
+ &e != player &&
+ !e.Dead() &&
+ manhattan_radius(e.ChunkCoords() - Player().ChunkCoords()) < 7;
+}
+
+bool ClientConnection::CanDespawn(const Entity &e) const noexcept {
+ return
+ e.Dead() ||
+ manhattan_radius(e.ChunkCoords() - Player().ChunkCoords()) > 7;
+}
+
+void ClientConnection::SendSpawn(SpawnStatus &status) {
+ // don't double spawn
+ if (status.spawn_pack != -1) return;
+
+ auto pack = Packet::Make<Packet::SpawnEntity>(server.GetPacket());
+ pack.WriteEntity(*status.entity);
+ status.spawn_pack = conn.Send(server.GetPacket(), server.GetSocket());
+ ++confirm_wait;
+}
+
+void ClientConnection::SendDespawn(SpawnStatus &status) {
+ // don't double despawn
+ if (status.despawn_pack != -1) return;
+
+ auto pack = Packet::Make<Packet::DespawnEntity>(server.GetPacket());
+ pack.WriteEntityID(status.entity->ID());
+ status.despawn_pack = conn.Send(server.GetPacket(), server.GetSocket());
+ ++confirm_wait;
+}
+
+void ClientConnection::SendUpdate(SpawnStatus &status) {
+ // don't send updates while spawn not ack'd or despawn sent
+ if (status.spawn_pack != -1 || status.despawn_pack != -1) return;
+
+ // TODO: pack entity updates
+ auto pack = Packet::Make<Packet::EntityUpdate>(server.GetPacket());
+ pack.WriteEntityCount(1);
+ pack.WriteEntity(*status.entity, 0);
+ server.GetPacket().len = Packet::EntityUpdate::GetSize(1);
+ conn.Send(server.GetPacket(), server.GetSocket());
+}
+
+void ClientConnection::CheckPlayerFix() {
+ // check always succeeds for now ;)
+ auto pack = Packet::Make<Packet::PlayerCorrection>(server.GetPacket());
+ pack.WritePacketSeq(player_update_pack);
+ pack.WritePlayer(Player());
+ conn.Send(server.GetPacket(), server.GetSocket());
+}
+