From 99345b497912db65204d48348140fc774dcb6989 Mon Sep 17 00:00:00 2001
From: Daniel Karbach <daniel.karbach@localhorst.tv>
Date: Sat, 5 Sep 2015 15:45:11 +0200
Subject: [PATCH] make server aware connected clients' player entity

---
 src/net/ClientConnection.hpp |  44 ++++++++++++
 src/net/Server.hpp           |  17 +++--
 src/net/net.cpp              | 132 ++++++++++++++++++-----------------
 3 files changed, 121 insertions(+), 72 deletions(-)
 create mode 100644 src/net/ClientConnection.hpp

diff --git a/src/net/ClientConnection.hpp b/src/net/ClientConnection.hpp
new file mode 100644
index 0000000..acbee6e
--- /dev/null
+++ b/src/net/ClientConnection.hpp
@@ -0,0 +1,44 @@
+#ifndef BLANK_NET_CLIENTCONNECTION_HPP_
+#define BLANK_NET_CLIENTCONNECTION_HPP_
+
+#include "Connection.hpp"
+#include "ConnectionHandler.hpp"
+
+#include <SDL_net.h>
+
+
+namespace blank {
+
+class Entity;
+class Server;
+
+class ClientConnection
+: public ConnectionHandler {
+
+public:
+	explicit ClientConnection(Server &, const IPaddress &);
+	~ClientConnection();
+
+	bool Matches(const IPaddress &addr) const noexcept { return conn.Matches(addr); }
+
+	void Update(int dt);
+
+	Connection &GetConnection() noexcept { return conn; }
+	bool Disconnected() const noexcept { return conn.Closed(); }
+
+	void AttachPlayer(Entity &);
+	void DetachPlayer();
+
+	void On(const Packet::Login &) override;
+	void On(const Packet::Part &) override;
+
+private:
+	Server &server;
+	Connection conn;
+	Entity *player;
+
+};
+
+}
+
+#endif
diff --git a/src/net/Server.hpp b/src/net/Server.hpp
index a95cd37..a6d509b 100644
--- a/src/net/Server.hpp
+++ b/src/net/Server.hpp
@@ -7,7 +7,7 @@
 
 namespace blank {
 
-class Connection;
+class ClientConnection;
 class World;
 
 class Server {
@@ -25,21 +25,20 @@ public:
 
 	void Update(int dt);
 
-private:
-	void HandlePacket(const UDPpacket &);
+	UDPsocket &GetSocket() noexcept { return serv_sock; }
+	UDPpacket &GetPacket() noexcept { return serv_pack; }
 
-	Connection &GetClient(const IPaddress &);
+	World &GetWorld() noexcept { return world; }
 
-	void OnConnect(Connection &);
-	void OnDisconnect(Connection &);
+private:
+	void HandlePacket(const UDPpacket &);
 
-	void HandleLogin(Connection &client, const UDPpacket &);
-	void HandlePart(Connection &client, const UDPpacket &);
+	ClientConnection &GetClient(const IPaddress &);
 
 private:
 	UDPsocket serv_sock;
 	UDPpacket serv_pack;
-	std::list<Connection> clients;
+	std::list<ClientConnection> clients;
 
 	World &world;
 
diff --git a/src/net/net.cpp b/src/net/net.cpp
index 4d36412..7f12e63 100644
--- a/src/net/net.cpp
+++ b/src/net/net.cpp
@@ -1,4 +1,5 @@
 #include "Client.hpp"
+#include "ClientConnection.hpp"
 #include "Connection.hpp"
 #include "ConnectionHandler.hpp"
 #include "io.hpp"
@@ -101,6 +102,67 @@ uint16_t Client::SendLogin(const string &name) {
 }
 
 
+ClientConnection::ClientConnection(Server &server, const IPaddress &addr)
+: server(server)
+, conn(addr)
+, player(nullptr) {
+	conn.SetHandler(this);
+}
+
+ClientConnection::~ClientConnection() {
+	DetachPlayer();
+}
+
+void ClientConnection::Update(int dt) {
+	conn.Update(dt);
+	if (Disconnected()) {
+		cout << "disconnect from " << conn.Address() << endl;
+	} else if (conn.ShouldPing()) {
+		conn.SendPing(server.GetPacket(), server.GetSocket());
+	}
+}
+
+void ClientConnection::AttachPlayer(Entity &new_player) {
+	DetachPlayer();
+	player = &new_player;
+	player->Ref();
+}
+
+void ClientConnection::DetachPlayer() {
+	if (!player) return;
+	player->Kill();
+	player->UnRef();
+	player = nullptr;
+}
+
+void ClientConnection::On(const Packet::Login &pack) {
+	string name;
+	pack.ReadPlayerName(name);
+
+	Entity *new_player = server.GetWorld().AddPlayer(name);
+
+	if (new_player) {
+		// success!
+		AttachPlayer(*new_player);
+		cout << "accepted login from player \"" << name << '"' << endl;
+		auto response = Packet::Make<Packet::Join>(server.GetPacket());
+		response.WritePlayer(*new_player);
+		response.WriteWorldName(server.GetWorld().Name());
+		conn.Send(server.GetPacket(), server.GetSocket());
+	} else {
+		// aw no :(
+		cout << "rejected login from player \"" << name << '"' << endl;
+		Packet::Make<Packet::Part>(server.GetPacket());
+		conn.Send(server.GetPacket(), server.GetSocket());
+		conn.Close();
+	}
+}
+
+void ClientConnection::On(const Packet::Part &) {
+	conn.Close();
+}
+
+
 Connection::Connection(const IPaddress &addr)
 : handler(nullptr)
 , addr(addr)
@@ -387,85 +449,29 @@ void Server::HandlePacket(const UDPpacket &udp_pack) {
 		return;
 	}
 
-	Connection &client = GetClient(udp_pack.address);
-	client.Received(udp_pack);
-
-	switch (pack.header.type) {
-		case Packet::Login::TYPE:
-			HandleLogin(client, udp_pack);
-			break;
-		case Packet::Part::TYPE:
-			HandlePart(client, udp_pack);
-			break;
-		default:
-			// just drop packets of unknown or unhandled type
-			break;
-	}
+	ClientConnection &client = GetClient(udp_pack.address);
+	client.GetConnection().Received(udp_pack);
 }
 
-Connection &Server::GetClient(const IPaddress &addr) {
-	for (Connection &client : clients) {
+ClientConnection &Server::GetClient(const IPaddress &addr) {
+	for (ClientConnection &client : clients) {
 		if (client.Matches(addr)) {
 			return client;
 		}
 	}
-	clients.emplace_back(addr);
-	OnConnect(clients.back());
+	clients.emplace_back(*this, addr);
 	return clients.back();
 }
 
-void Server::OnConnect(Connection &client) {
-	cout << "new connection from " << client.Address() << endl;
-	// tell it we're alive
-	client.SendPing(serv_pack, serv_sock);
-}
-
 void Server::Update(int dt) {
-	for (list<Connection>::iterator client(clients.begin()), end(clients.end()); client != end;) {
+	for (list<ClientConnection>::iterator client(clients.begin()), end(clients.end()); client != end;) {
 		client->Update(dt);
-		if (client->Closed()) {
-			OnDisconnect(*client);
+		if (client->Disconnected()) {
 			client = clients.erase(client);
 		} else {
-			if (client->ShouldPing()) {
-				client->SendPing(serv_pack, serv_sock);
-			}
 			++client;
 		}
 	}
 }
 
-void Server::OnDisconnect(Connection &client) {
-	cout << "connection timeout from " << client.Address() << endl;
-}
-
-
-void Server::HandleLogin(Connection &client, const UDPpacket &udp_pack) {
-	auto pack = Packet::As<Packet::Login>(udp_pack);
-
-	string name;
-	pack.ReadPlayerName(name);
-
-	Entity *player = world.AddPlayer(name);
-
-	if (player) {
-		// success!
-		cout << "accepted login from player \"" << name << '"' << endl;
-		auto response = Packet::Make<Packet::Join>(serv_pack);
-		response.WritePlayer(*player);
-		response.WriteWorldName(world.Name());
-		client.Send(serv_pack, serv_sock);
-	} else {
-		// aw no :(
-		cout << "rejected login from player \"" << name << '"' << endl;
-		Packet::Make<Packet::Part>(serv_pack);
-		client.Send(serv_pack, serv_sock);
-		client.Close();
-	}
-}
-
-void Server::HandlePart(Connection &client, const UDPpacket &udp_pack) {
-	client.Close();
-}
-
 }
-- 
2.39.5