--- 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