X-Git-Url: http://git.localhorst.tv/?a=blobdiff_plain;f=src%2Fserver%2Fnet.cpp;h=7947c221beb13d803a9b6c6a0c9d14a56f190e8d;hb=e2355b50a0d31f675e16593299256334c2baa2c4;hp=cd4f2003c359b1896adbf435430eae8b68fd3562;hpb=b9462143d9b2fd1f54aa3b4ec32eecb62c01615f;p=blank.git diff --git a/src/server/net.cpp b/src/server/net.cpp index cd4f200..7947c22 100644 --- a/src/server/net.cpp +++ b/src/server/net.cpp @@ -3,6 +3,7 @@ #include "Server.hpp" #include "../app/init.hpp" +#include "../geometry/distance.hpp" #include "../io/WorldSave.hpp" #include "../model/Model.hpp" #include "../world/ChunkIndex.hpp" @@ -161,7 +162,7 @@ void ChunkTransmitter::SendData(size_t i) { if (data_packets[i] == -1) { ++confirm_wait; } - data_packets[i] = conn.Send(); + data_packets[i] = conn.Send(Packet::ChunkData::GetSize(len)); } void ChunkTransmitter::Release() { @@ -187,7 +188,8 @@ ClientConnection::ClientConnection(Server &server, const IPaddress &addr) , old_actions(0) , transmitter(*this) , chunk_queue() -, old_base() { +, old_base() +, chunk_blocks_skipped(0) { conn.SetHandler(this); } @@ -201,58 +203,60 @@ void ClientConnection::Update(int dt) { return; } if (HasPlayer()) { - // sync entities - auto global_iter = server.GetWorld().Entities().begin(); - auto global_end = server.GetWorld().Entities().end(); - auto local_iter = spawns.begin(); - auto local_end = spawns.end(); - - while (global_iter != global_end && local_iter != local_end) { - if (global_iter->ID() == local_iter->entity->ID()) { - // they're the same - if (CanDespawn(*global_iter)) { - SendDespawn(*local_iter); - } else if (SendingUpdates()) { - // update - QueueUpdate(*local_iter); - } - ++global_iter; - ++local_iter; - } else if (global_iter->ID() < local_iter->entity->ID()) { - // global entity was inserted - if (CanSpawn(*global_iter)) { - auto spawned = spawns.emplace(local_iter, *global_iter); - SendSpawn(*spawned); - } - ++global_iter; - } else { - // global entity was removed + CheckPlayerFix(); + CheckChunkQueue(); + CheckEntities(); + SendUpdates(); + } + if (conn.ShouldPing()) { + conn.SendPing(server.GetPacket(), server.GetSocket()); + } +} + +void ClientConnection::CheckEntities() { + auto global_iter = server.GetWorld().Entities().begin(); + auto global_end = server.GetWorld().Entities().end(); + auto local_iter = spawns.begin(); + auto local_end = spawns.end(); + + while (global_iter != global_end && local_iter != local_end) { + if (global_iter->ID() == local_iter->entity->ID()) { + // they're the same + if (CanDespawn(*global_iter)) { SendDespawn(*local_iter); - ++local_iter; + } else if (SendingUpdates()) { + // update + QueueUpdate(*local_iter); } - } - - // leftover spawns - while (global_iter != global_end) { + ++global_iter; + ++local_iter; + } else if (global_iter->ID() < local_iter->entity->ID()) { + // global entity was inserted if (CanSpawn(*global_iter)) { - spawns.emplace_back(*global_iter); - SendSpawn(spawns.back()); + auto spawned = spawns.emplace(local_iter, *global_iter); + SendSpawn(*spawned); } ++global_iter; - } - - // leftover despawns - while (local_iter != local_end) { + } else { + // global entity was removed SendDespawn(*local_iter); ++local_iter; } - SendUpdates(); + } - CheckPlayerFix(); - CheckChunkQueue(); + // leftover spawns + while (global_iter != global_end) { + if (CanSpawn(*global_iter)) { + spawns.emplace_back(*global_iter); + SendSpawn(spawns.back()); + } + ++global_iter; } - if (conn.ShouldPing()) { - conn.SendPing(server.GetPacket(), server.GetSocket()); + + // leftover despawns + while (local_iter != local_end) { + SendDespawn(*local_iter); + ++local_iter; } } @@ -310,7 +314,7 @@ void ClientConnection::SendDespawn(SpawnStatus &status) { } bool ClientConnection::SendingUpdates() const noexcept { - return entity_updates_skipped >= NetStat().SuggestedPacketSkip(); + return entity_updates_skipped >= NetStat().SuggestedPacketHold(); } void ClientConnection::QueueUpdate(SpawnStatus &status) { @@ -384,9 +388,9 @@ struct QueueCompare { void ClientConnection::CheckChunkQueue() { if (PlayerChunks().Base() != old_base) { - Chunk::Pos begin = PlayerChunks().CoordsBegin(); - Chunk::Pos end = PlayerChunks().CoordsEnd(); - for (Chunk::Pos pos = begin; pos.z < end.z; ++pos.z) { + ExactLocation::Coarse begin = PlayerChunks().CoordsBegin(); + ExactLocation::Coarse end = PlayerChunks().CoordsEnd(); + for (ExactLocation::Coarse pos = begin; pos.z < end.z; ++pos.z) { for (pos.y = begin.y; pos.y < end.y; ++pos.y) { for (pos.x = begin.x; pos.x < end.x; ++pos.x) { if (manhattan_radius(pos - old_base) > PlayerChunks().Extent()) { @@ -398,20 +402,27 @@ void ClientConnection::CheckChunkQueue() { old_base = PlayerChunks().Base(); sort(chunk_queue.begin(), chunk_queue.end(), QueueCompare(old_base)); } + // don't push entity updates and chunk data in the same tick + if (chunk_blocks_skipped >= NetStat().SuggestedPacketHold() && !SendingUpdates()) { + ++chunk_blocks_skipped; + return; + } if (transmitter.Transmitting()) { transmitter.Transmit(); + chunk_blocks_skipped = 0; return; } if (transmitter.Idle()) { int count = 0; constexpr int max = 64; while (count < max && !chunk_queue.empty()) { - Chunk::Pos pos = chunk_queue.front(); + ExactLocation::Coarse pos = chunk_queue.front(); chunk_queue.pop_front(); if (PlayerChunks().InRange(pos)) { Chunk *chunk = PlayerChunks().Get(pos); if (chunk) { transmitter.Send(*chunk); + chunk_blocks_skipped = 0; return; } else { chunk_queue.push_back(pos); @@ -428,9 +439,9 @@ void ClientConnection::AttachPlayer(Player &player) { PlayerEntity().Ref(); old_base = PlayerChunks().Base(); - Chunk::Pos begin = PlayerChunks().CoordsBegin(); - Chunk::Pos end = PlayerChunks().CoordsEnd(); - for (Chunk::Pos pos = begin; pos.z < end.z; ++pos.z) { + ExactLocation::Coarse begin = PlayerChunks().CoordsBegin(); + ExactLocation::Coarse end = PlayerChunks().CoordsEnd(); + for (ExactLocation::Coarse pos = begin; pos.z < end.z; ++pos.z) { for (pos.y = begin.y; pos.y < end.y; ++pos.y) { for (pos.x = begin.x; pos.x < end.x; ++pos.x) { chunk_queue.push_back(pos); @@ -569,10 +580,16 @@ void ClientConnection::On(const Packet::PlayerUpdate &pack) { 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)) { @@ -616,28 +633,54 @@ Server::Server( const WorldSave &save) : serv_sock(nullptr) , serv_pack{ -1, nullptr, 0 } +, serv_set(SDLNet_AllocSocketSet(1)) , clients() , world(world) , spawn_index(world.Chunks().MakeIndex(wc.spawn, 3)) , save(save) , player_model(nullptr) , cli(world) { + if (!serv_set) { + throw NetError("SDLNet_AllocSocketSet"); + } + serv_sock = SDLNet_UDP_Open(conf.port); if (!serv_sock) { + SDLNet_FreeSocketSet(serv_set); throw NetError("SDLNet_UDP_Open"); } + if (SDLNet_UDP_AddSocket(serv_set, serv_sock) == -1) { + SDLNet_UDP_Close(serv_sock); + SDLNet_FreeSocketSet(serv_set); + throw NetError("SDLNet_UDP_AddSocket"); + } + serv_pack.data = new Uint8[sizeof(Packet)]; serv_pack.maxlen = sizeof(Packet); } Server::~Server() { + for (ClientConnection &client : clients) { + client.Disconnected(); + } + clients.clear(); world.Chunks().UnregisterIndex(spawn_index); delete[] serv_pack.data; + SDLNet_UDP_DelSocket(serv_set, serv_sock); SDLNet_UDP_Close(serv_sock); + SDLNet_FreeSocketSet(serv_set); } +void Server::Wait(int dt) noexcept { + SDLNet_CheckSockets(serv_set, dt); +} + +bool Server::Ready() noexcept { + return SDLNet_CheckSockets(serv_set, 0) > 0; +} + void Server::Handle() { int result = SDLNet_UDP_Recv(serv_sock, &serv_pack); while (result > 0) {