#include "Server.hpp"
#include "../app/init.hpp"
+#include "../world/World.hpp"
#include <cstring>
#include <iostream>
client_pack.data = new Uint8[sizeof(Packet)];
client_pack.maxlen = sizeof(Packet);
// establish connection
- conn.SendPing(client_pack, client_sock);
+ SendPing();
}
Client::~Client() {
return;
}
- conn.FlagRecv();
+ conn.Received(udp_pack);
cout << "I got something!" << endl;
}
if (conn.TimedOut()) {
cout << "connection timed out :(" << endl;
} else if (conn.ShouldPing()) {
- conn.SendPing(client_pack, client_sock);
+ SendPing();
}
}
+void Client::SendPing() {
+ conn.SendPing(client_pack, client_sock);
+}
+
+void Client::SendLogin(const string &name) {
+ Packet &pack = *reinterpret_cast<Packet *>(client_pack.data);
+ client_pack.len = pack.Login(name);
+ conn.Send(client_pack, client_sock);
+}
+
Connection::Connection(const IPaddress &addr)
: addr(addr)
, send_timer(5000)
-, recv_timer(10000) {
+, recv_timer(10000)
+, ctrl{ 0, 0xFFFF, 0xFFFF } {
send_timer.Start();
recv_timer.Start();
}
}
-void Connection::Send(UDPpacket &pack, UDPsocket sock) {
- pack.address = addr;
- if (SDLNet_UDP_Send(sock, -1, &pack) == 0) {
+void Connection::Send(UDPpacket &udp_pack, UDPsocket sock) {
+ Packet &pack = *reinterpret_cast<Packet *>(udp_pack.data);
+ pack.header.ctrl = ctrl;
+
+ udp_pack.address = addr;
+ if (SDLNet_UDP_Send(sock, -1, &udp_pack) == 0) {
throw NetError("SDLNet_UDP_Send");
}
+
FlagSend();
}
+void Connection::Received(const UDPpacket &udp_pack) {
+ Packet &pack = *reinterpret_cast<Packet *>(udp_pack.data);
+
+ int diff = std::int16_t(pack.header.ctrl.seq) - std::int16_t(ctrl.ack);
+
+ if (diff > 0) {
+ // incoming more recent than last acked
+
+ // TODO: packets considered lost are detected here
+ // this should have ones for all of them:
+ // ~hist & ((1 << dist) - 1) if dist is < 32
+
+ if (diff >= 32) {
+ // missed more than the last 32 oO
+ ctrl.hist = 0;
+ } else {
+ ctrl.hist >>= diff;
+ ctrl.hist |= 1 << (32 - diff);
+ }
+ } else if (diff < 0) {
+ // incoming older than acked
+ if (diff > -32) {
+ // too late :/
+ } else {
+ ctrl.hist |= 1 << (32 + diff);
+ }
+ } else {
+ // incoming the same as last acked oO
+ }
+
+ ctrl.ack = pack.header.ctrl.seq;
+
+ FlagRecv();
+}
+
void Connection::SendPing(UDPpacket &udp_pack, UDPsocket sock) {
Packet &pack = *reinterpret_cast<Packet *>(udp_pack.data);
udp_pack.len = pack.Ping();
return sizeof(Header);
}
+size_t Packet::Login(const string &name) noexcept {
+ constexpr size_t maxname = 32;
+
+ Tag();
+ header.type = LOGIN;
+ if (name.size() < maxname) {
+ memset(payload, '\0', maxname);
+ memcpy(payload, name.c_str(), name.size());
+ } else {
+ memcpy(payload, name.c_str(), maxname);
+ }
+ return sizeof(Header) + maxname;
+}
+
Server::Server(const Config &conf, World &world)
: serv_sock(nullptr)
}
Connection &client = GetClient(udp_pack.address);
- client.FlagRecv();
+ client.Received(udp_pack);
+
+ switch (pack.header.type) {
+ case Packet::PING:
+ // already done all that's supposed to do
+ break;
+ case Packet::LOGIN:
+ HandleLogin(client, udp_pack);
+ break;
+ default:
+ // just drop packets of unknown type
+ break;
+ }
}
Connection &Server::GetClient(const IPaddress &addr) {
cout << "connection timeout from " << client.Address() << endl;
}
+
+void Server::HandleLogin(Connection &client, const UDPpacket &udp_pack) {
+ const Packet &pack = *reinterpret_cast<const Packet *>(udp_pack.data);
+ size_t maxlen = min(udp_pack.len - int(sizeof(Packet::Header)), 32);
+ string name;
+ name.reserve(maxlen);
+ for (size_t i = 0; i < maxlen && pack.payload[i] != '\0'; ++i) {
+ name.push_back(pack.payload[i]);
+ }
+ cout << "got login request from player \"" << name << '"' << endl;
+
+ Entity *player = world.AddPlayer(name);
+ if (player) {
+ // success!
+ cout << "\taccepted" << endl;
+ } else {
+ // aw no :(
+ cout << "\trejected" << endl;
+ }
+}
+
}