all the network code is now there, although it doesn't quite work
authorterom
Sat, 08 Nov 2008 20:34:14 +0000
changeset 22 b70d30e1b0fe
parent 21 32c6cc55256a
child 23 8d802b573cf0
all the network code is now there, although it doesn't quite work
src/proto2/Application.cc
src/proto2/Engine.cc
src/proto2/Engine.hh
src/proto2/GameState.hh
src/proto2/Network.hh
src/proto2/NetworkClient.cc
src/proto2/NetworkClient.hh
src/proto2/NetworkConfig.hh
src/proto2/NetworkServer.cc
src/proto2/NetworkServer.hh
src/proto2/Protocol.hh
--- a/src/proto2/Application.cc	Sat Nov 08 18:02:58 2008 +0000
+++ b/src/proto2/Application.cc	Sat Nov 08 20:34:14 2008 +0000
@@ -104,6 +104,7 @@
 				args.print_help();
 
 				// XXX: handle --help
+				return 1;
 
 			} catch (std::exception &e) {
 				std::cerr << e.what() << std::endl;
--- a/src/proto2/Engine.cc	Sat Nov 08 18:02:58 2008 +0000
+++ b/src/proto2/Engine.cc	Sat Nov 08 20:34:14 2008 +0000
@@ -4,6 +4,8 @@
 #include "NetworkServer.hh"
 #include "NetworkClient.hh"
 
+#include <iostream>
+
 Engine::Engine (void) : is_running(true) {
 
 }
@@ -66,3 +68,8 @@
 
 	}
 }
+
+void Engine::log (const std::string &level, const std::string &type, const std::string &message) {
+	std::cout << level << " [" << type << "] " << message << std::endl;
+}
+
--- a/src/proto2/Engine.hh	Sat Nov 08 18:02:58 2008 +0000
+++ b/src/proto2/Engine.hh	Sat Nov 08 20:34:14 2008 +0000
@@ -20,7 +20,9 @@
 	public:
 		static void runNetworkServer (const std::string &listen_port);
 		static void runNetworkClient (const std::string &connect_host, const std::string &connect_port);
-	
+		
+		static void log (const std::string &level, const std::string &type, const std::string &message);
+
 	private:
 		void main_loop (void);
 
--- a/src/proto2/GameState.hh	Sat Nov 08 18:02:58 2008 +0000
+++ b/src/proto2/GameState.hh	Sat Nov 08 20:34:14 2008 +0000
@@ -4,57 +4,92 @@
 #include "Dimension.hh"
 
 #include <list>
+#include <stdexcept>
 
 enum PlayerType {
-	PLAYER_LOCAL = 0x01,
-	PLAYER_REMOTE = 0x02
+	PLAYER_LOCAL,
+	PLAYER_REMOTE
 };
 
+#define PLAYER_DIM_W 10
+#define PLAYER_DIM_H 10
+#define MAP_DIM_W 800
+#define MAP_DIM_H 640
+
 class Player {
 	protected:
 		Coordinate position;
 
 	public:
 
-		Player(Coordinate c) : position(c), dimensions(10, 10) {}
+		Player(Coordinate c, bool visible) : position(c), dimensions(PLAYER_DIM_W, PLAYER_DIM_H), visible(visible) {}
 
 		PlayerType type;
 		Dimension dimensions;
+		bool visible;
 
 		Coordinate getPosition (void) const {
 			return this->position;
 		}
+	
+	protected:
+		void updatePosition (Coordinate p) {
+			this->position = p;
+		}
+
 };
 
 class LocalPlayer : public Player {
+	protected:
+		LocalPlayer (Coordinate c, bool visible) : Player(c, visible) { }
+	
 	public:
-		void doMovement (PositionDelta d) {
+		virtual void move (PositionDelta d) {
 			this->position += d;
-
-			// XXX: notify server
 		}
 };
 
 class RemotePlayer : public Player {
-	public:
-		void updatePosition (Coordinate p) {
-			this->position = p;
-		}
+	protected:
+		RemotePlayer (Coordinate c, bool visible) : Player(c, visible) { }
+
 };
 
 class GameState {
 	public:
 		Dimension map_dimensions;
-		std::list<Player> player_list;
+		std::list<Player*> player_list;
 
-		GameState (void) : map_dimensions(800, 640) {
+		// only one local player is supported
+		LocalPlayer *local_player;
+
+		GameState (void) : map_dimensions(MAP_DIM_W, MAP_DIM_H), local_player(NULL) {
 
 		}
 
 		LocalPlayer &getLocalPlayer (void) {
-			// XXX: jotain
+			if (!local_player)
+				throw std::logic_error("getLocalPlayer called with no local player");
+			
+			return *local_player;
+		}
+		
+		void newLocalPlayer (LocalPlayer *player) {
+			if (local_player)
+				throw std::logic_error("newLocalPlayer called even though we already have a local player");
+
+			player_list.push_back(player);
+
+			local_player = player;
+		}
+
+		void newRemotePlayer (RemotePlayer *player) {
+			player_list.push_back(player);
+		}
+
+		void removePlayer (Player *player) {
+			player_list.remove(player);
 		}
 };
 
-
 #endif
--- a/src/proto2/Network.hh	Sat Nov 08 18:02:58 2008 +0000
+++ b/src/proto2/Network.hh	Sat Nov 08 20:34:14 2008 +0000
@@ -13,9 +13,61 @@
 		CL_SlotContainer slots;
 
 		CL_NetSession netsession;
+
+		CL_NetObject_Controller netobjs;
 		
 		// constructor
-		NetworkCore (GameState &state) : state(state), netsession(NETWORK_APP_NAME) { }
+		NetworkCore (GameState &state) : state(state), netsession(NETWORK_APP_NAME), netobjs(&netsession, NETWORK_NETOBJ_CHAN) { }
+};
+
+enum NetworkMessage {
+	NETMSG_PACKET_INVALID	= 0x00,
+
+	/*
+	 * You have joined the game:
+	 *
+	 * 	uint32_t x
+	 * 	uint32_t y
+	 */
+	NETMSG_SERVER_HELLO	= 0x0100,
+
+	/*
+	 * New client has connected to server:
+	 *
+	 * 	uint32_t x
+	 * 	uint32_t y
+	 */
+	NETMSG_PLAYER_JOIN	= 0x0101,
+
+	/*
+	 * Client has left server:
+	 *
+	 */
+	NETMSG_PLAYER_QUIT	= 0x0102,
+
+	/*
+	 * Client has moved
+	 *
+	 * 	uint32_t dx
+	 * 	uint32_t dy
+	 */
+	NETMSG_CLIENT_MOVE	= 0x0201,
+	
+	/*
+	 * Initial player info
+	 *
+	 * 	uint32_t x
+	 * 	uint32_t y
+	 */
+	NETMSG_PLAYER_INFO	= 0x0300,
+
+	/*
+	 * Player position update
+	 *
+	 * 	uint32_t x
+	 * 	uint32_t y
+	 */
+	NETMSG_PLAYER_POSITION	= 0x0301,
 };
 
 #endif
--- a/src/proto2/NetworkClient.cc	Sat Nov 08 18:02:58 2008 +0000
+++ b/src/proto2/NetworkClient.cc	Sat Nov 08 20:34:14 2008 +0000
@@ -1,9 +1,137 @@
 
 #include "NetworkClient.hh"
 
+// XXX: replace logging
+#include <iostream>
 
 NetworkClient::NetworkClient (GameState &state, const CL_IPAddress &connect_to) : 
 	NetworkCore(state), server(netsession.connect(connect_to)) {
 	
 	// connect slots
+	slots.connect(netobjs.sig_create_object(), this, &NetworkClient::on_create_object);
+
+	// XXX: sig_disconnected
 }
+
+void NetworkClient::on_create_object (CL_NetObject_Client &obj, int msg_type, CL_NetPacket &pkt) {
+	switch (msg_type) {
+		case NETMSG_SERVER_HELLO:
+			std::cout << "INFO [client.on_create_object] NETMSG_SERVER_HELLO" << std::endl;
+
+			on_server_hello(obj, pkt);
+
+			break;
+		
+		case NETMSG_PLAYER_INFO:
+			std::cout << "INFO [client.on_create_object] NETMSG_PLAYER_INFO" << std::endl;
+
+			on_player_info(obj, pkt);
+
+			break;
+		
+		case NETMSG_PLAYER_JOIN:
+			std::cout << "INFO [client.on_create_object] NETMSG_PLAYER_JOIN" << std::endl;
+
+			on_player_join(obj, pkt);
+
+			break;
+
+		default:
+			std::cerr << "WARN [client.on_create_object] unknown msg_type=" << msg_type << std::endl; 
+	}
+}
+		
+void NetworkClient::on_server_hello (CL_NetObject_Client &obj, CL_NetPacket &pkt) {
+	// read the packet
+	uint32_t x = pkt.input.read_uint32();
+	uint32_t y = pkt.input.read_uint32();
+	
+	Coordinate initial_position(x, y);
+
+	// create the LocalPlayer object
+	NetworkClientLocalPlayer *player = new NetworkClientLocalPlayer(*this, obj, initial_position);
+
+	// inform state
+	state.newLocalPlayer(player);
+}
+		
+void NetworkClient::on_player_info (CL_NetObject_Client &obj, CL_NetPacket &pkt) {
+	// read the packet
+	uint32_t x = pkt.input.read_uint32();
+	uint32_t y = pkt.input.read_uint32();
+
+	Coordinate initial_position(x, y);
+
+	// create the LocalPlayer object
+	NetworkClientRemotePlayer *player = new NetworkClientRemotePlayer(*this, obj, initial_position);
+
+	// inform state
+	state.newRemotePlayer(player);
+
+}
+		
+void NetworkClient::on_player_join (CL_NetObject_Client &obj, CL_NetPacket &pkt) {
+	// read the packet
+	uint32_t x = pkt.input.read_uint32();
+	uint32_t y = pkt.input.read_uint32();
+	
+	Coordinate initial_position(x, y);
+	
+	// create the RemotePlayer object
+	NetworkClientRemotePlayer *player = new NetworkClientRemotePlayer(*this, obj, initial_position);
+
+	// inform state
+	state.newRemotePlayer(player);
+}
+		
+void NetworkClient::player_quit (NetworkClientRemotePlayer *player) {
+	// inform state
+	state.removePlayer(player);
+
+	// delete
+	delete player;
+}
+
+NetworkClientLocalPlayer::NetworkClientLocalPlayer (NetworkClient &client, CL_NetObject_Client &obj, Coordinate initial_position) :
+	LocalPlayer(initial_position, true), client(client), obj(obj) {
+	
+	// receive messages
+	slots.connect(obj.sig_received_message(NETMSG_PLAYER_POSITION), this, &NetworkClientLocalPlayer::on_position);
+
+}
+		
+void NetworkClientLocalPlayer::move (PositionDelta d) {
+	CL_NetPacket pkt;
+	pkt.output.write_uint32(d.dx);
+	pkt.output.write_uint32(d.dy);
+
+	obj.send(NETMSG_CLIENT_MOVE, pkt, false);
+}
+		
+void NetworkClientLocalPlayer::on_position (CL_NetPacket &pkt) {
+	uint32_t x = pkt.input.read_uint32();
+	uint32_t y = pkt.input.read_uint32();
+	
+	updatePosition(Coordinate(x, y));
+}
+		
+NetworkClientRemotePlayer::NetworkClientRemotePlayer (NetworkClient &client, CL_NetObject_Client &obj, Coordinate initial_position) :
+	RemotePlayer(initial_position, true), client(client), obj(obj) {
+	
+	// receive messages
+	slots.connect(obj.sig_received_message(NETMSG_PLAYER_POSITION), this, &NetworkClientRemotePlayer::on_position);
+}
+
+void NetworkClientRemotePlayer::on_position (CL_NetPacket &pkt) {
+	uint32_t x = pkt.input.read_uint32();
+	uint32_t y = pkt.input.read_uint32();
+	
+	updatePosition(Coordinate(x, y));
+}
+
+void NetworkClientRemotePlayer::on_quit (CL_NetPacket &pkt) {
+	// pkt is empty
+	(void) pkt;
+
+	client.player_quit(this);
+}
--- a/src/proto2/NetworkClient.hh	Sat Nov 08 18:02:58 2008 +0000
+++ b/src/proto2/NetworkClient.hh	Sat Nov 08 20:34:14 2008 +0000
@@ -4,12 +4,59 @@
 #include "Network.hh"
 #include "GameState.hh"
 
+// forward-declare
+class NetworkClientRemotePlayer;
+
 class NetworkClient : public NetworkCore {
 	private:
 		CL_NetComputer server;
+		
+	public:
+		NetworkClient (GameState &state, const CL_IPAddress &connect_to);
+
+	private:
+		void on_create_object (CL_NetObject_Client &obj, int msg_type, CL_NetPacket &pkt);
+
+		void on_server_hello (CL_NetObject_Client &obj, CL_NetPacket &pkt);
+		void on_player_info (CL_NetObject_Client &obj, CL_NetPacket &pkt);
+		void on_player_join (CL_NetObject_Client &obj, CL_NetPacket &pkt);
+	
+	public:
+		void player_quit (NetworkClientRemotePlayer *player);
+};
+
+class NetworkClientLocalPlayer : public LocalPlayer {
+	private:
+		NetworkClient &client;
+
+		CL_SlotContainer slots;
+
+		CL_NetObject_Client &obj;
 
 	public:
-		NetworkClient (GameState &state, const CL_IPAddress &connect_to);
+		NetworkClientLocalPlayer (NetworkClient &client, CL_NetObject_Client &obj, Coordinate initial_position);
+		
+		virtual void move (PositionDelta d);
+	
+	private:
+		void on_position (CL_NetPacket &pkt);
+};
+
+class NetworkClientRemotePlayer : public RemotePlayer {
+	private:
+		NetworkClient &client;
+		
+		CL_SlotContainer slots;
+
+		CL_NetObject_Client &obj;
+
+	public:
+		NetworkClientRemotePlayer (NetworkClient &client, CL_NetObject_Client &obj, Coordinate initial_position);
+	
+	private:
+		void on_position (CL_NetPacket &pkt);
+
+		void on_quit (CL_NetPacket &pkt);
 };
 
 #endif
--- a/src/proto2/NetworkConfig.hh	Sat Nov 08 18:02:58 2008 +0000
+++ b/src/proto2/NetworkConfig.hh	Sat Nov 08 20:34:14 2008 +0000
@@ -19,7 +19,9 @@
 #include <string>
 
 const std::string NETWORK_APP_NAME = "KisnaGlista";
+
 const std::string NETWORK_PORT_STR = "9338";
-const uint16_t NETWORK_PACKET_MAX = 1280;
+
+const std::string NETWORK_NETOBJ_CHAN = "_netobj";
 
 #endif /* NETWORK_CONFIG_HH */
--- a/src/proto2/NetworkServer.cc	Sat Nov 08 18:02:58 2008 +0000
+++ b/src/proto2/NetworkServer.cc	Sat Nov 08 20:34:14 2008 +0000
@@ -1,11 +1,11 @@
 #include "NetworkServer.hh"
-#include "Protocol.hh"
+#include "Engine.hh"
 
 #include <iostream>
 #include <cassert>
 
 NetworkServer::NetworkServer (GameState &state, const std::string &listen_port) : 
-	NetworkCore(state) {
+	NetworkCore(state), pid_pool(0) {
 	
 	// connect slots
 	slots.connect(netsession.sig_computer_connected(), this, &NetworkServer::on_connect);
@@ -16,14 +16,103 @@
 }
 
 void NetworkServer::on_connect (CL_NetComputer &computer) {
-	std::cout << "NetworkServer.on_connect: " << computer.get_address().get_address() << std::endl;
+	// assign a pid
+	uint16_t pid = ++pid_pool;
+	
+	// log
+	std::cout << "[server.on_connect] INFO: " << computer.get_address().get_address() << " -> #" << pid << std::endl;
+
+	// create the player object
+	NetworkServerPlayer *player = new NetworkServerPlayer(*this, computer, pid);
+	
+	// map computer to it
+	players[computer] = player;
+
+	// add to GameState
+	state.newRemotePlayer(player);
 }
 
 void NetworkServer::on_disconnect (CL_NetComputer &computer) {
 	std::cout << "NetworkServer.on_disconnect: " << computer.get_address().get_address() << std::endl;
+
+	// XXX: remove the player
+	NetworkServerPlayer *player = players[computer];
+	
+	// remove from players
+	players.erase(computer);
+
+	// remove from state
+	state.removePlayer(player);
+
+	// remove from game
+	player->disconnected();
+
+	// delete
+	delete player;
 }
 		
-NetworkServerClient::NetworkServerClient (NetworkServer &server) : server(server) {
+NetworkServerPlayer::NetworkServerPlayer (NetworkServer &server, CL_NetComputer &computer, uint16_t pid) : 
+	RemotePlayer(Coordinate(0, 0), true), server(server), computer(computer), netobj(&server.netobjs), pid(pid) {
 	
+	// messages
+	slots.connect(netobj.sig_received_message(NETMSG_CLIENT_MOVE), this, &NetworkServerPlayer::on_move);	
+
+	// the initial NETMSG_PLAYER_HELLO
+	CL_NetPacket hello_pkt;
+	hello_pkt.output.write_uint32(position.x);
+	hello_pkt.output.write_uint32(position.y);
+
+	netobj.send(computer, NETMSG_SERVER_HELLO, hello_pkt, true);
+
+	// send other player objects
+	for (std::map<CL_NetComputer, NetworkServerPlayer*>::iterator it = server.players.begin(); it != server.players.end(); it++) {
+		NetworkServerPlayer *player = it->second;
+		CL_NetPacket player_pkt;
+		
+		// player is not in players list yet
+		assert(player != this);
+
+		player_pkt.output.write_uint32(player->position.x);
+		player_pkt.output.write_uint32(player->position.y);
+
+		player->netobj.send(computer, NETMSG_PLAYER_INFO, player_pkt, true);
+	}
+
+
+	// broadcast NETMSG_PLAYER_JOIN to all clients
+	netobj.send(server.netsession.get_all(), NETMSG_PLAYER_JOIN, hello_pkt, true);
 }
 
+void NetworkServerPlayer::disconnected (void) {
+	CL_NetPacket pkt;
+
+	netobj.send(server.netsession.get_all(), NETMSG_PLAYER_QUIT, pkt, true);
+}
+
+void NetworkServerPlayer::on_move (CL_NetComputer &from, CL_NetPacket &pkt) {
+	// sanity-check
+	if (!(from == computer))
+		return;
+	
+	// read packet
+	uint32_t dx = pkt.input.read_uint32();
+	uint32_t dy = pkt.input.read_uint32();
+
+	// movement delta
+	PositionDelta delta(dx, dy);
+
+	// apply movement
+	position += delta;
+
+	// send position update
+	send_position_update();
+}
+		
+void NetworkServerPlayer::send_position_update (void) {
+	CL_NetPacket pkt;
+	pkt.output.write_uint32(position.x);
+	pkt.output.write_uint32(position.y);
+
+	netobj.send(server.netsession.get_all(), NETMSG_PLAYER_POSITION, pkt, false);
+}
+
--- a/src/proto2/NetworkServer.hh	Sat Nov 08 18:02:58 2008 +0000
+++ b/src/proto2/NetworkServer.hh	Sat Nov 08 20:34:14 2008 +0000
@@ -9,23 +9,46 @@
 #include <ClanLib/core.h>
 
 // forward-declare
-class NetworkServerClient;
+class NetworkServerPlayer;
 
 class NetworkServer : public NetworkCore {
+	friend class NetworkServerPlayer;
+
+	private:
+		uint16_t pid_pool;
+	
+	public:
+		std::map<CL_NetComputer, NetworkServerPlayer*> players;
+
 	public:
 		NetworkServer (GameState &state, const std::string &listen_port);
 
 	private:
 		void on_connect (CL_NetComputer &computer);
 		void on_disconnect (CL_NetComputer &computer);
+
+	
 };
 
-class NetworkServerClient {
+class NetworkServerPlayer : public RemotePlayer {
 	private:
 		NetworkServer &server;
+		CL_NetComputer &computer;
+		CL_NetObject_Server netobj;
+
+		CL_SlotContainer slots;
+
+		uint16_t pid;
 		
+	public:
+		NetworkServerPlayer (NetworkServer &server, CL_NetComputer &computer, uint16_t pid);
+
+		void disconnected (void);
+
 	private:
-		NetworkServerClient (NetworkServer &server);
+		void on_move (CL_NetComputer &from, CL_NetPacket &pkt);
+
+		void send_position_update (void);
 };
 
 #endif
--- a/src/proto2/Protocol.hh	Sat Nov 08 18:02:58 2008 +0000
+++ b/src/proto2/Protocol.hh	Sat Nov 08 20:34:14 2008 +0000
@@ -1,74 +1,4 @@
 #ifndef PROTOCOL_HH
 #define PROTOCOL_HH
 
-#include "NetworkConfig.hh"
-#include "Network.hh"
-
-#include <stdexcept>
-
-enum packet_type {
-    PKT_INVALID,
-    PKT_HELLO
-};
-
-class NetworkPacket {
-    private:
-        char buf[NETWORK_PACKET_MAX];
-        size_t size;
-        size_t offset;
-    public:
-        CL_IPAddress src;
-
-    public:
-        NetworkPacket () : size(0), offset(0) { }
-
-        void recvFromSocket (CL_Socket &sock) {
-            size = sock.recv((void *) buf, NETWORK_PACKET_MAX, src);
-
-            offset = 0;
-        }
-    
-        template <typename T> void read_into (T* val_ptr) {
-            if (offset + sizeof(T) > size)
-                throw std::logic_error("short packet");
-
-            *val_ptr = *((T*) (buf + offset));
-
-            offset += sizeof(T);
-        }
-
-        template <typename T> T read_type (void) {
-            T val;
-
-            read_into(&val);
-
-            return val;
-        }
-        
-        uint8_t read_uint8 (void) {
-            return read_type<uint8_t>();
-        }
-
-        uint16_t read_uint16 (void) {
-            return htons(read_type<uint16_t>());
-        }
-
-        enum packet_type read_pkt_type (void) {
-            return (enum packet_type) read_uint8();
-        }
-};
-
-struct pkt_base {
-    NetworkPacket &packet;
-    
-    pkt_base (NetworkPacket &packet) : packet(packet) { }
-};
-
-struct pkt_Hello : public pkt_base {
-    uint16_t player_id;
-
-    pkt_Hello (NetworkPacket &packet) : pkt_base(packet), 
-        player_id(packet.read_uint16()) { }
-};
-
 #endif