}
/// true if an interval boundary was passed by the last call to Update()
bool Hit() const noexcept {
- return Running() && mod(value, intv) < last_dt;
+ return Running() && IntervalElapsed() < last_dt;
}
bool HitOnce() const noexcept {
return Running() && value >= intv;
Time Interval() const noexcept {
return intv;
}
+ Time IntervalElapsed() const noexcept {
+ return mod(value, intv);
+ }
+ Time IntervalRemain() const noexcept {
+ return intv - IntervalElapsed();
+ }
int Iteration() const noexcept {
return value / intv;
}
Server(const Config::Network &, World &, const World::Config &, const WorldSave &);
~Server();
+ // wait for data to arrive for at most dt milliseconds
+ void Wait(int dt) noexcept;
+ // true if there's data waiting to be handled
+ bool Ready() noexcept;
void Handle();
void Update(int dt);
private:
UDPsocket serv_sock;
UDPpacket serv_pack;
+ SDLNet_SocketSet serv_set;
std::list<ClientConnection> clients;
World &world;
void ServerState::Update(int dt) {
loop_timer.Update(dt);
+ if (!loop_timer.HitOnce() && loop_timer.IntervalRemain() > 1) {
+ server.Wait(loop_timer.IntervalRemain() - 1);
+ return;
+ }
+ if (dt == 0 && !server.Ready()) {
+ // effectively wait in a spin loop
+ return;
+ }
+
server.Handle();
int world_dt = 0;
while (loop_timer.HitOnce()) {
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) {