terom@185: terom@186: #include "Client.hh" terom@187: #include "Protocol.hh" terom@187: #include "Config.hh" terom@186: #include "../Engine.hh" terom@186: #include "../Logger.hh" terom@185: terom@185: #include terom@185: terom@185: NetworkClient::NetworkClient (GameState &state, const NetworkAddress &connect_to) : terom@187: state(state), netsession(NETWORK_MAGIC_ID), server(netsession.connect(connect_to)), netobjs(netsession, NETCHAN_CORE, server) { terom@185: terom@185: // connect slots terom@223: slots.connect(netobjs.sig_create(NETMSG_SERVER_HELLO), this, &NetworkClient::on_server_hello); terom@223: slots.connect(netobjs.sig_create(NETMSG_PLAYER_INFO), this, &NetworkClient::on_player_info); terom@223: slots.connect(netobjs.sig_create(NETMSG_PLAYER_JOIN), this, &NetworkClient::on_player_join); terom@223: slots.connect(netobjs.sig_create(NETMSG_PROJECTILE_CREATE), this, &NetworkClient::on_projectile_create); terom@223: terom@203: slots.connect(netsession.sig_chan_message(NETCHAN_TERRAIN_ARRAY), this, &NetworkClient::on_terrain_array); terom@185: terom@185: // XXX: sig_disconnected terom@185: } terom@185: terom@200: void NetworkClient::on_server_hello (NetworkObject_Client *obj, NetworkPacketInput &pkt) { terom@185: // read the packet terom@185: Vector position = pkt.read_vector(); terom@185: terom@185: Engine::log(INFO, "client.on_server_hello") << "obj=" << obj << ", pos=" << position; terom@185: terom@185: // create the LocalPlayer object terom@185: NetworkClientLocalPlayer *player = new NetworkClientLocalPlayer(*this, obj, position); terom@185: terom@185: // inform state terom@185: state.newLocalPlayer(player); terom@185: } terom@185: terom@200: void NetworkClient::on_player_info (NetworkObject_Client *obj, NetworkPacketInput &pkt) { terom@185: // read the packet terom@185: Vector position = pkt.read_vector(); terom@185: terom@185: Engine::log(INFO, "client.on_player_info") << "obj=" << obj << ", pos=" << position; terom@185: terom@185: // create the LocalPlayer object terom@185: NetworkClientRemotePlayer *player = new NetworkClientRemotePlayer(*this, obj, position); terom@185: terom@185: // inform state terom@209: state.newPlayer(player); terom@185: terom@185: } terom@185: terom@200: void NetworkClient::on_player_join (NetworkObject_Client *obj, NetworkPacketInput &pkt) { terom@185: // read the packet terom@185: Vector position = pkt.read_vector(); terom@185: terom@185: Engine::log(INFO, "client.on_player_join") << "obj=" << obj << ", pos=" << position; terom@185: terom@185: // create the RemotePlayer object terom@185: NetworkClientRemotePlayer *player = new NetworkClientRemotePlayer(*this, obj, position); terom@185: terom@185: // inform state terom@209: state.newPlayer(player); terom@185: } terom@185: terom@223: void NetworkClient::on_projectile_create (NetworkObject_Client *obj, NetworkPacketInput &pkt) { terom@223: // read the packet terom@223: Vector position = pkt.read_vector(); terom@223: Vector velocity = pkt.read_vector(); terom@223: float explosionRadius = pkt.read_float32(); terom@223: terom@223: Engine::log(INFO, "client.on_projectile_create") << "obj=" << obj << ", pos=" << position << ", velocity=" << velocity; terom@223: terom@223: // create the NetworkClientPorjectile object terom@223: new NetworkClientProjectile(*this, obj, position, velocity, explosionRadius); terom@223: } terom@223: terom@203: void NetworkClient::on_terrain_array (NetworkPacketInput &pkt, NetworkNode *node) { terom@203: // ignore if not from server terom@203: if (node != server) terom@203: return; terom@203: terom@203: Terrain &terrain = state.world; terom@203: terom@203: // read map width/height terom@203: uint32_t map_w = pkt.read_uint32(); terom@203: uint32_t map_h = pkt.read_uint32(); terom@203: terom@203: // read map data terom@203: for (int x = 0; x < map_w; x++) { terom@203: for (int y = 0; y < map_h; y++) { terom@203: terrain.terrain[x][y] = (TerrainType) pkt.read_uint8(); terom@203: } terom@203: } terom@203: terom@203: // update the pixbuf terom@203: terrain.generatePixelBuffer(); terom@203: } terom@203: terom@185: void NetworkClient::player_quit (NetworkClientRemotePlayer *player) { terom@185: // inform state terom@185: state.removePlayer(player); terom@185: terom@185: // delete terom@185: // XXX: leak because deleting the slot while it's being called breaks ClanLib terom@185: // delete player; terom@185: } terom@185: terom@223: /* terom@223: * NetworkClientObjectHelper terom@223: */ terom@223: NetworkClientObjectHelper::NetworkClientObjectHelper (NetworkClient &client, NetworkObject_Client *obj) : terom@223: client(client), obj(obj) terom@223: { terom@223: terom@223: } terom@223: terom@223: /* terom@223: * NetworkClientPlayerHelper terom@223: */ terom@209: NetworkClientPlayerHelper::NetworkClientPlayerHelper (NetworkClient &client, Vector position, NetworkObject_Client *obj) : terom@223: NetworkClientObjectHelper(client, obj), Player(client.state, position, true) terom@223: { terom@200: // receive position updates terom@200: slots.connect(obj->sig_message(NETMSG_PLAYER_POSITION), this, &NetworkClientPlayerHelper::on_position); terom@200: slots.connect(obj->sig_message(NETMSG_PLAYER_DIG), this, &NetworkClientPlayerHelper::on_dig); terom@200: } terom@200: terom@200: void NetworkClientPlayerHelper::on_position (NetworkPacketInput &pkt) { terom@200: Vector position = pkt.read_vector(); terom@200: Vector velocity = pkt.read_vector(); terom@200: int flags = pkt.read_uint8(); terom@200: float aim = pkt.read_float32(); terom@200: terom@200: Engine::log(INFO, "client_player.on_position") << "obj=" << obj << ", position=" << position << ", velocity=" << velocity << ", aim=" << aim << ", [" << flags << "]"; terom@200: terom@200: // just update... terom@209: updatePhysics(position, velocity, flags & NETWORK_PHYSICS_INAIR, flags & NETWORK_PHYSICS_FACE_RIGHT, aim); terom@200: } terom@200: terom@200: void NetworkClientPlayerHelper::on_dig (NetworkPacketInput &pkt) { terom@200: Vector position = pkt.read_vector(); terom@200: float radius = pkt.read_float32(); terom@200: terom@200: Engine::log(INFO, "client_player.on_dig") << "obj=" << obj << ", position=" << position << ", radius=" << radius; terom@200: terom@200: // just update... terom@209: handleDig(position, radius); terom@200: } terom@200: terom@185: NetworkClientLocalPlayer::NetworkClientLocalPlayer (NetworkClient &client, NetworkObject_Client *obj, Vector position) : terom@209: Player(client.state, position, true), NetworkClientPlayerHelper(client, position, obj) { terom@185: terom@185: } terom@185: terom@221: void NetworkClientLocalPlayer::handleInput (PlayerInput input) { terom@185: // always send move, in all cases terom@185: NetworkPacket pkt; terom@185: pkt.write_uint16(input); terom@185: terom@223: obj->send(NETMSG_CLIENT_INPUT, pkt, false); terom@185: terom@185: // do not handle locally terom@185: } terom@185: terom@185: NetworkClientRemotePlayer::NetworkClientRemotePlayer (NetworkClient &client, NetworkObject_Client *obj, Vector position) : terom@209: Player(client.state, position, true), NetworkClientPlayerHelper(client, position, obj) { terom@185: terom@185: // receive messages terom@185: slots.connect(obj->sig_message(NETMSG_PLAYER_QUIT), this, &NetworkClientRemotePlayer::on_quit); terom@185: } terom@185: terom@200: void NetworkClientRemotePlayer::on_quit (NetworkPacketInput &pkt) { terom@185: // pkt is empty terom@185: (void) pkt; terom@185: terom@185: Engine::log(INFO, "client_player.on_quit") << "obj=" << obj; terom@185: terom@185: client.player_quit(this); terom@185: } terom@185: terom@223: NetworkClientProjectile::NetworkClientProjectile (NetworkClient &client, NetworkObject_Client *obj, Vector position, terom@223: Vector velocity, float explosionRadius) : terom@223: NetworkClientObjectHelper(client, obj), Projectile(client.state, position, velocity, true, explosionRadius) terom@223: { terom@224: // hook up signals terom@224: slots.connect(obj->sig_message(NETMSG_PROJECTILE_DESTROY), this, &NetworkClientProjectile::on_destroy); terom@223: } terom@200: terom@224: void NetworkClientProjectile::onDestroy (Vector position, bool removeGround) { terom@224: // ignore :> terom@224: } terom@224: terom@224: void NetworkClientProjectile::on_destroy (NetworkPacketInput &pkt) { terom@224: Vector position = pkt.read_vector(); terom@224: uint8_t flags = pkt.read_uint8(); terom@224: terom@224: Engine::log(INFO, "client_projectile.on_destroy") << "obj=" << obj << ", position=" << position << ", flags=" << flags; terom@224: terom@224: // XXX: leak obj, not yet implemented: obj.destory(); terom@224: terom@224: // pass on to super terom@224: Projectile::onDestroy(position, flags & NETWORK_PROJECTILE_REMOVE_GROUND); terom@224: }