#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);
}