src/Network/Client.cc
author terom
Sun, 07 Dec 2008 01:18:59 +0000
changeset 241 e95b1602d836
parent 239 550397d9d479
child 255 99431fdb0dc8
permissions -rw-r--r--
implement the ROT (Rope Over TCP) protocol

#include "Client.hh"
#include "Protocol.hh"
#include "Config.hh"
#include "../Engine.hh"
#include "../Logger.hh"

#include <cassert>

NetworkClient::NetworkClient (GameState &state, const NetworkAddress &connect_to) : 
    state(state), netsession(NETWORK_MAGIC_ID), server(netsession.connect(connect_to)), netobjs(netsession, NETCHAN_CORE, server) {
    
    // connect slots
    slots.connect(netobjs.sig_create(NETMSG_SERVER_HELLO), this, &NetworkClient::on_server_hello);
    slots.connect(netobjs.sig_create(NETMSG_PLAYER_INFO), this, &NetworkClient::on_player_info);
    slots.connect(netobjs.sig_create(NETMSG_PLAYER_JOIN), this, &NetworkClient::on_player_join);
    slots.connect(netobjs.sig_create(NETMSG_PROJECTILE_CREATE), this, &NetworkClient::on_projectile_create);

    slots.connect(netsession.sig_chan_message(NETCHAN_TERRAIN_ARRAY), this, &NetworkClient::on_terrain_array);

    // XXX: sig_disconnected
}
        
void NetworkClient::on_server_hello (NetworkObject_Client *obj, NetworkPacketInput &pkt) {
    // read the packet
    Vector position = pkt.read_vector();
    
    Engine::log(INFO, "client.on_server_hello") << "obj=" << obj << ", pos=" << position;

    // create the LocalPlayer object
    NetworkClientLocalPlayer *player = new NetworkClientLocalPlayer(*this, obj, position);

    // inform state
    state.newLocalPlayer(player);
}
        
void NetworkClient::on_player_info (NetworkObject_Client *obj, NetworkPacketInput &pkt) {
    // read the packet
    Vector position = pkt.read_vector();
    
    Engine::log(INFO, "client.on_player_info") << "obj=" << obj << ", pos=" << position;

    // create the LocalPlayer object
    NetworkClientRemotePlayer *player = new NetworkClientRemotePlayer(*this, obj, position);

    // inform state
    state.newPlayer(player);

}
        
void NetworkClient::on_player_join (NetworkObject_Client *obj, NetworkPacketInput &pkt) {
    // read the packet
    Vector position = pkt.read_vector();
    
    Engine::log(INFO, "client.on_player_join") << "obj=" << obj << ", pos=" << position;
    
    // create the RemotePlayer object
    NetworkClientRemotePlayer *player = new NetworkClientRemotePlayer(*this, obj, position);

    // inform state
    state.newPlayer(player);
}
        
void NetworkClient::on_projectile_create (NetworkObject_Client *obj, NetworkPacketInput &pkt) {
    // read the packet
    Vector position = pkt.read_vector();
    Vector velocity = pkt.read_vector();
    float explosionRadius = pkt.read_float32();

    Engine::log(INFO, "client.on_projectile_create") << "obj=" << obj << ", pos=" << position << ", velocity=" << velocity;

    // create the NetworkClientPorjectile object
    new NetworkClientProjectile(*this, obj, position, velocity, explosionRadius);
}
        
void NetworkClient::on_terrain_array (NetworkPacketInput &pkt, NetworkNode *node) {
    // ignore if not from server
    if (node != server)
        return;

    Terrain &terrain = state.world;

    // read map width/height
    uint32_t map_w = pkt.read_uint32();
    uint32_t map_h = pkt.read_uint32();

    // read map data
    for (int x = 0; x < map_w; x++) {
        for (int y = 0; y < map_h; y++) {
            terrain.terrain[x][y] = (TerrainType) pkt.read_uint8();
        }
    }

    // update the pixbuf
    terrain.generatePixelBuffer();
}
        
void NetworkClient::player_quit (NetworkClientRemotePlayer *player) {
    // inform state
    state.removePlayer(player);

    // delete
    // XXX: leak because deleting the slot while it's being called breaks ClanLib
    //  delete player;
}

/*
 * NetworkClientObjectHelper
 */
NetworkClientObjectHelper::NetworkClientObjectHelper (NetworkClient &client, NetworkObject_Client *obj) :
    client(client), obj(obj)
{

}

/*
 * NetworkClientPlayerHelper
 */
NetworkClientPlayerHelper::NetworkClientPlayerHelper (NetworkClient &client, Vector position, NetworkObject_Client *obj) :
    NetworkClientObjectHelper(client, obj), Player(client.state, position, true) 
{
    slots.connect(obj->sig_message(NETMSG_PLAYER_POSITION),         this,   &NetworkClientPlayerHelper::on_position         );
    slots.connect(obj->sig_message(NETMSG_PLAYER_DIG),              this,   &NetworkClientPlayerHelper::on_dig              );
    slots.connect(obj->sig_message(NETMSG_PLAYER_WEAPON_CHANGE),    this,   &NetworkClientPlayerHelper::on_weapon_change    );
    slots.connect(obj->sig_message(NETMSG_PLAYER_ROPE_THROW),       this,   &NetworkClientPlayerHelper::on_rope_throw       );
    slots.connect(obj->sig_message(NETMSG_PLAYER_ROPE_FIXED),       this,   &NetworkClientPlayerHelper::on_rope_fixed       );
    slots.connect(obj->sig_message(NETMSG_PLAYER_ROPE_RELEASED),    this,   &NetworkClientPlayerHelper::on_rope_released    );
    slots.connect(obj->sig_message(NETMSG_PLAYER_ROPE_LENGTH),      this,   &NetworkClientPlayerHelper::on_rope_length      );

}

void NetworkClientPlayerHelper::on_position (NetworkPacketInput &pkt) {
    Vector position = pkt.read_vector();
    Vector velocity = pkt.read_vector();
    int flags = pkt.read_uint8();
    float aim = pkt.read_float32();

    Engine::log(INFO, "client_player.on_position") << "obj=" << obj << ", position=" << position << ", velocity=" << velocity << ", aim=" << aim << ", [" << flags << "]";
    
    // just update... 
    updatePhysics(position, velocity, flags & NETWORK_PHYSICS_INAIR, flags & NETWORK_PHYSICS_FACE_RIGHT, aim);
}

void NetworkClientPlayerHelper::on_dig (NetworkPacketInput &pkt) {
    Vector position = pkt.read_vector();
    float radius = pkt.read_float32();

    Engine::log(INFO, "client_player.on_dig") << "obj=" << obj << ", position=" << position << ", radius=" << radius;
    
    // just update... 
    handleDig(position, radius);
}
        
void NetworkClientPlayerHelper::on_weapon_change (NetworkPacketInput &pkt) {
    uint8_t weapon_index = pkt.read_uint8();

    Engine::log(INFO, "client_player.on_weapon_change") << "obj=" << obj << ", weapon_index=" << weapon_index;

    handleChangeWeapon(weapon_index);
}

void NetworkClientPlayerHelper::on_rope_throw (NetworkPacketInput &pkt) {
    Vector position = pkt.read_vector();
    Vector velocity = pkt.read_vector();
    float length = pkt.read_float32();

    Engine::log(INFO, "client_player.on_rope_throw") << "obj=" << obj << ", position=" << position << ", velocity=" << velocity << ", length=" << length;

    rope.updateState(ROPE_FLYING, position, velocity, length);
}

void NetworkClientPlayerHelper::on_rope_fixed (NetworkPacketInput &pkt) {
    Vector position = pkt.read_vector();
    float length = pkt.read_float32();
    
    Engine::log(INFO, "client_player.on_rope_fixed") << "obj=" << obj << ", position=" << position << ", length=" << length;

    rope.updateState(ROPE_FIXED, position, Vector(0, 0), length);
}

void NetworkClientPlayerHelper::on_rope_released (NetworkPacketInput &pkt) {
    Engine::log(INFO, "client_player.on_rope_released") << "obj=" << obj;
    
    // use rope.getPosition() instead of e.g. Vector(0, 0) because it will collide there...
    rope.updateState(ROPE_FOLDED, rope.getPosition(), Vector(0, 0), 0);
}

void NetworkClientPlayerHelper::on_rope_length (NetworkPacketInput &pkt) {
    float length = pkt.read_float32();
    
    Engine::log(INFO, "client_player.on_rope_length") << "obj=" << obj << ", length=" << length;

    rope.updateLength(length);
}

NetworkClientLocalPlayer::NetworkClientLocalPlayer (NetworkClient &client, NetworkObject_Client *obj, Vector position) :
    Player(client.state, position, true), NetworkClientPlayerHelper(client, position, obj) {
    
}
        
void NetworkClientLocalPlayer::handleInput (PlayerInput input) {
    // always send move, in all cases
    NetworkPacket pkt;
    pkt.write_uint16(input);

    obj->send(NETMSG_CLIENT_INPUT, pkt, false);
    
    // do not handle locally
}
        
NetworkClientRemotePlayer::NetworkClientRemotePlayer (NetworkClient &client, NetworkObject_Client *obj, Vector position) :
    Player(client.state, position, true), NetworkClientPlayerHelper(client, position, obj) {
    
    // receive messages
    slots.connect(obj->sig_message(NETMSG_PLAYER_QUIT), this, &NetworkClientRemotePlayer::on_quit);
}

void NetworkClientRemotePlayer::on_quit (NetworkPacketInput &pkt) {
    // pkt is empty
    (void) pkt;

    Engine::log(INFO, "client_player.on_quit") << "obj=" << obj;

    client.player_quit(this);
}

NetworkClientProjectile::NetworkClientProjectile (NetworkClient &client, NetworkObject_Client *obj, Vector position,
        Vector velocity, float explosionRadius) :
    NetworkClientObjectHelper(client, obj), Projectile(client.state, position, velocity, true, explosionRadius)
{
    // hook up signals
    slots.connect(obj->sig_message(NETMSG_PROJECTILE_DESTROY), this, &NetworkClientProjectile::on_destroy);
}

void NetworkClientProjectile::onDestroy (Vector position, bool removeGround) {
    // ignore :>
}

void NetworkClientProjectile::on_destroy (NetworkPacketInput &pkt) {
    Vector position = pkt.read_vector();
    uint8_t flags = pkt.read_uint8();

    Engine::log(INFO, "client_projectile.on_destroy") << "obj=" << obj << ", position=" << position << ", flags=" << flags;
    
    // XXX: leak obj, not yet implemented:  obj.destory();

    // pass on to super
    Projectile::onDestroy(position, flags & NETWORK_PROJECTILE_REMOVE_GROUND);
}