# HG changeset patch # User terom # Date 1226176454 0 # Node ID b70d30e1b0fe4f6cf3e3ae6901158ee310528e46 # Parent 32c6cc55256a4b033b99c181f6ffef2d3c217af3 all the network code is now there, although it doesn't quite work diff -r 32c6cc55256a -r b70d30e1b0fe src/proto2/Application.cc --- 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; diff -r 32c6cc55256a -r b70d30e1b0fe src/proto2/Engine.cc --- 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 + 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; +} + diff -r 32c6cc55256a -r b70d30e1b0fe src/proto2/Engine.hh --- 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); diff -r 32c6cc55256a -r b70d30e1b0fe src/proto2/GameState.hh --- 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 +#include 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_list; + std::list 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 diff -r 32c6cc55256a -r b70d30e1b0fe src/proto2/Network.hh --- 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 diff -r 32c6cc55256a -r b70d30e1b0fe src/proto2/NetworkClient.cc --- 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 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); +} diff -r 32c6cc55256a -r b70d30e1b0fe src/proto2/NetworkClient.hh --- 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 diff -r 32c6cc55256a -r b70d30e1b0fe src/proto2/NetworkConfig.hh --- 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 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 */ diff -r 32c6cc55256a -r b70d30e1b0fe src/proto2/NetworkServer.cc --- 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 #include 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::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); +} + diff -r 32c6cc55256a -r b70d30e1b0fe src/proto2/NetworkServer.hh --- 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 // forward-declare -class NetworkServerClient; +class NetworkServerPlayer; class NetworkServer : public NetworkCore { + friend class NetworkServerPlayer; + + private: + uint16_t pid_pool; + + public: + std::map 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 diff -r 32c6cc55256a -r b70d30e1b0fe src/proto2/Protocol.hh --- 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 - -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 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 T read_type (void) { - T val; - - read_into(&val); - - return val; - } - - uint8_t read_uint8 (void) { - return read_type(); - } - - uint16_t read_uint16 (void) { - return htons(read_type()); - } - - 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