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
}
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()) {
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();
server.GetWorldSave().Write(input->GetPlayer());
PlayerEntity().Kill();
PlayerEntity().UnRef();
+ cli_ctx.reset();
input.reset();
transmitter.Abort();
chunk_queue.clear();
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;
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<Packet::Message>();
+ 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,
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) {
+#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);
}
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) {
}
}
-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);
}
}