X-Git-Url: http://git.localhorst.tv/?a=blobdiff_plain;f=src%2Fserver%2Fnet.cpp;h=f5e974d7e71bcfb9808e08a7d9fc909aa1dbe2d8;hb=b07f3c123fff221edeffb4864bab7db88d0d1f4d;hp=47342ffad130b0a2edc6337797fa458eee9863ec;hpb=56069d41c1553d87a8759713ef391d3a908adc0e;p=blank.git diff --git a/src/server/net.cpp b/src/server/net.cpp index 47342ff..f5e974d 100644 --- a/src/server/net.cpp +++ b/src/server/net.cpp @@ -6,6 +6,7 @@ #include "../geometry/distance.hpp" #include "../io/WorldSave.hpp" #include "../model/Model.hpp" +#include "../shared/CommandService.hpp" #include "../world/ChunkIndex.hpp" #include "../world/Entity.hpp" #include "../world/World.hpp" @@ -355,7 +356,7 @@ void ClientConnection::SendUpdates() { void ClientConnection::CheckPlayerFix() { // player_update_state's position holds the client's most recent prediction glm::vec3 diff = player_update_state.Diff(PlayerEntity().GetState()); - float dist_squared = dot(diff, diff); + float dist_squared = glm::length2(diff); // if client's prediction is off by more than 1cm, send // our (authoritative) state back so it can fix it @@ -401,6 +402,7 @@ void ClientConnection::CheckChunkQueue() { } old_base = PlayerChunks().Base(); sort(chunk_queue.begin(), chunk_queue.end(), QueueCompare(old_base)); + chunk_queue.erase(unique(chunk_queue.begin(), chunk_queue.end()), chunk_queue.end()); } // don't push entity updates and chunk data in the same tick if (chunk_blocks_skipped >= NetStat().SuggestedPacketHold() && !SendingUpdates()) { @@ -438,6 +440,8 @@ void ClientConnection::AttachPlayer(Player &player) { input.reset(new DirectInput(server.GetWorld(), player, server)); PlayerEntity().Ref(); + cli_ctx.reset(new NetworkCLIFeedback(player, *this)); + old_base = PlayerChunks().Base(); ExactLocation::Coarse begin = PlayerChunks().CoordsBegin(); ExactLocation::Coarse end = PlayerChunks().CoordsEnd(); @@ -468,6 +472,7 @@ void ClientConnection::DetachPlayer() { server.GetWorldSave().Write(input->GetPlayer()); PlayerEntity().Kill(); PlayerEntity().UnRef(); + cli_ctx.reset(); input.reset(); transmitter.Abort(); chunk_queue.clear(); @@ -612,6 +617,14 @@ 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; @@ -620,12 +633,43 @@ void ClientConnection::On(const Packet::Message &pack) { pack.ReadReferral(ref); pack.ReadMessage(msg); - if (type == 1 && HasPlayer()) { - server.DispatchMessage(input->GetPlayer(), msg); + if (type == 1 && cli_ctx) { + server.DispatchMessage(*cli_ctx, msg); } } +uint16_t ClientConnection::SendMessage(uint8_t type, uint32_t from, const string &msg) { + auto pack = Prepare(); + pack.WriteType(type); + pack.WriteReferral(from); + pack.WriteMessage(msg); + return Send(Packet::Message::GetSize(msg)); +} + + +NetworkCLIFeedback::NetworkCLIFeedback(Player &p, ClientConnection &c) +: CLIContext(&p) +, conn(c) { + +} + +void NetworkCLIFeedback::Error(const string &msg) { + conn.SendMessage(0, 0, msg); +} + +void NetworkCLIFeedback::Message(const string &msg) { + conn.SendMessage(0, 0, msg); +} + +void NetworkCLIFeedback::Broadcast(const string &msg) { + conn.GetServer().DistributeMessage(0, GetPlayer().GetEntity().ID(), msg); +} + +// relying on {} zero intitialization for UDPpacket, because +// the type and number of fields is not well defined +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" Server::Server( const Config::Network &conf, World &world, @@ -633,28 +677,66 @@ 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) { +, cli(world) +, cmd_srv() { +#pragma GCC diagnostic pop + 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); + + if (conf.cmd_port) { + cmd_srv.reset(new CommandService(cli, conf.cmd_port)); + } } 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); + if (cmd_srv) { + cmd_srv->Wait(0); + } +} + +bool Server::Ready() noexcept { + if (SDLNet_CheckSockets(serv_set, 0) > 0) { + return true; + } + return cmd_srv && cmd_srv->Ready(); +} + void Server::Handle() { int result = SDLNet_UDP_Recv(serv_sock, &serv_pack); while (result > 0) { @@ -665,6 +747,9 @@ void Server::Handle() { // a boo boo happened throw NetError("SDLNet_UDP_Recv"); } + if (cmd_srv) { + cmd_srv->Handle(); + } } void Server::HandlePacket(const UDPpacket &udp_pack) { @@ -704,6 +789,9 @@ void Server::Update(int dt) { ++client; } } + if (cmd_srv) { + cmd_srv->Send(); + } } void Server::SetPlayerModel(const Model &m) noexcept { @@ -753,14 +841,14 @@ void Server::SetBlock(Chunk &chunk, int index, const Block &block) { } } -void Server::DispatchMessage(Player &player, const string &msg) { +void Server::DispatchMessage(CLIContext &ctx, const string &msg) { if (msg.empty()) { return; } if (msg[0] == '/' && msg.size() > 1 && msg[1] != '/') { - cli.Execute(player, msg.substr(1)); + cli.Execute(ctx, msg.substr(1)); } else { - DistributeMessage(1, player.GetEntity().ID(), msg); + DistributeMessage(1, ctx.GetPlayer().GetEntity().ID(), msg); } }