]> git.localhorst.tv Git - blank.git/blobdiff - src/net/net.cpp
tag packets withsequence numbers
[blank.git] / src / net / net.cpp
index 73ed73c2d006b06480bdef3c53310dd8501d4698..314410ebbdb66fee6bb053f43a7dac6d02762dd6 100644 (file)
@@ -5,6 +5,7 @@
 #include "Server.hpp"
 
 #include "../app/init.hpp"
+#include "../world/World.hpp"
 
 #include <cstring>
 #include <iostream>
@@ -42,7 +43,7 @@ Client::Client(const Config &conf, World &world)
        client_pack.data = new Uint8[sizeof(Packet)];
        client_pack.maxlen = sizeof(Packet);
        // establish connection
-       conn.SendPing(client_pack, client_sock);
+       SendPing();
 }
 
 Client::~Client() {
@@ -74,7 +75,7 @@ void Client::HandlePacket(const UDPpacket &udp_pack) {
                return;
        }
 
-       conn.FlagRecv();
+       conn.Received(udp_pack);
        cout << "I got something!" << endl;
 }
 
@@ -83,15 +84,26 @@ void Client::Update(int dt) {
        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();
 }
@@ -122,14 +134,53 @@ void Connection::Update(int dt) {
 }
 
 
-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();
@@ -160,6 +211,20 @@ size_t Packet::Ping() noexcept {
        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)
@@ -205,7 +270,19 @@ void Server::HandlePacket(const UDPpacket &udp_pack) {
        }
 
        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) {
@@ -244,4 +321,25 @@ void Server::OnDisconnect(Connection &client) {
        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;
+       }
+}
+
 }