From 50a1e2b2fe3c207c7227df4941f2f66990db0c2c Mon Sep 17 00:00:00 2001 From: Stijn Buys Date: Mon, 4 Aug 2008 18:24:36 +0000 Subject: network protocol version 5, netserver per-client updates, zone change protocol --- src/client/client.cc | 24 ++++++ src/client/client.h | 2 + src/core/application.cc | 6 ++ src/core/application.h | 3 + src/core/entity.cc | 179 ++++++++++++++++++++------------------ src/core/entity.h | 27 ++++-- src/core/gameconnection.cc | 2 +- src/core/gameserver.cc | 73 ++++------------ src/core/net.h | 2 +- src/core/netconnection.cc | 109 ++++++++++++++++------- src/core/netserver.cc | 209 ++++++++++++++++++++++++++------------------- src/core/netserver.h | 45 +++++----- src/core/player.cc | 41 +++------ src/core/player.h | 7 ++ src/core/zone.cc | 1 - 15 files changed, 412 insertions(+), 318 deletions(-) (limited to 'src') diff --git a/src/client/client.cc b/src/client/client.cc index 93d254e..5d060aa 100644 --- a/src/client/client.cc +++ b/src/client/client.cc @@ -222,5 +222,29 @@ void Client::notify_message(std::string const & message) console()->notify(message); } +void Client::notify_zoneclear(core::Zone *zone) +{ + // FIXME unload zone textures + /* + if (!zone) + return; + + for (core::Zone::Content::iterator it = zone->content().begin(); it != zone->content.end(); i++) { + core:: Entity *entity = (*it); + + if (entity->type() == core::Entity::Globe) { + core::EntityGlobe *globe = static_cast(entity); + if (globe->render_texture) + render::Textures::unload(render_texture); + + } + + if (zone->sky_texture()) { + render::Textures::unload(zone->sky_texture()); + zone->set_sky_texture(0); + } + */ +} + } // namespace client diff --git a/src/client/client.h b/src/client/client.h index 9b60671..664bbb4 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -37,6 +37,8 @@ public: /// remove sound source notification virtual void notify_remove_sound(size_t source); + /// clear zone notification + virtual void notify_zoneclear(core::Zone *zone); }; diff --git a/src/core/application.cc b/src/core/application.cc index 5cf4d66..49c61d7 100644 --- a/src/core/application.cc +++ b/src/core/application.cc @@ -461,4 +461,10 @@ void Application::notify_message(std::string const & message) con_print << message << std::endl; } +void Application::notify_zoneclear(Zone *zone) +{ + // the default implementation does nothing. + // The client uses this to clear old zones +} + } diff --git a/src/core/application.h b/src/core/application.h index 0e5c9c0..ef89e70 100644 --- a/src/core/application.h +++ b/src/core/application.h @@ -67,6 +67,9 @@ public: /// remove sound source notification virtual void notify_remove_sound(size_t source); + /// zone clear notification + virtual void notify_zoneclear(Zone *zone); + /*----- static --------------------------------------------------- */ /// a pointer to the current application instance diff --git a/src/core/entity.cc b/src/core/entity.cc index 20e1b05..060ceab 100644 --- a/src/core/entity.cc +++ b/src/core/entity.cc @@ -77,7 +77,7 @@ void Entity::list() con_print << entity_registry.size() << " registered entities" << std::endl; } -/*----- Entity ----------------------------------------------------- */ +/*----- class Entity ----------------------------------------------- */ Entity::Entity(unsigned int flags) : entity_location(0.0f, 0.0f, 0.0f), @@ -109,65 +109,13 @@ Entity::Entity(unsigned int flags) : Entity::Entity(std::istream & is) { + entity_id = 0; entity_zone = 0; - - // type is already determined - unsigned int s; - std::string n; - - is >> entity_id; - is >> entity_moduletypeid; - is >> entity_flags; - is >> s; - - set_zone(Zone::find(s)); - if (entity_zone && !s) { - con_warn << "Received entity " << entity_id << " for unknown zone " << s << "!" << std::endl; - } - - is >> entity_location; - is >> entity_color; - is >> entity_color_second; - - is >> s; // shape - entity_shape = (Shape) s; - - is >> entity_radius; - - is >> entity_axis[0]; - is >> entity_axis[1]; - entity_axis[2] = math::crossproduct(entity_axis.forward(), entity_axis.left()); - - char c; - // read label - while ( (is.get(c)) && (c != '"')); - while ( (is.get(c)) && (c != '"')) - n += c; - entity_label = n; - n.clear(); - - // read name - while ( (is.get(c)) && (c != '"')); - while ( (is.get(c)) && (c != '"')) - n += c; - entity_name = n; - n.clear(); - - // read model name - while ( (is.get(c)) && (c != '"')); - while ( (is.get(c)) && (c != '"')) - n += c; - entity_modelname = n; - entity_model = 0; // this will be resolved later + entity_model = 0; + entity_clientstate = 0; entity_created = true; entity_destroyed = false; - entity_dirty = false; - - // this entity is created clientside - entity_clientstate = 0; - - add(this, entity_id); } Entity::~Entity() @@ -201,11 +149,9 @@ void Entity::set_zone(Zone *zone) entity_zone->add(this); } -void Entity::serialize(std::ostream & os) const +void Entity::serialize_server_create(std::ostream & os) const { - os << type() << " " - << entity_id << " " - << entity_moduletypeid << " " + os << entity_moduletypeid << " " << entity_flags << " " << (entity_zone ? entity_zone->id() : 0) << " " << entity_location << " " @@ -220,6 +166,58 @@ void Entity::serialize(std::ostream & os) const << "\"" << entity_modelname << "\""; } +void Entity::receive_server_create(std::istream &is) +{ + unsigned int s; + unsigned int zo; + std::string n; + + is >> entity_moduletypeid; + is >> entity_flags; + is >> zo; + + set_zone(Zone::find(zo)); + if (entity_zone && !zo) { + con_warn << "Received entity " << entity_id << " for unknown zone " << zo << "!" << std::endl; + } + + is >> entity_location; + is >> entity_color; + is >> entity_color_second; + + is >> s; // shape + entity_shape = (Shape) s; + + is >> entity_radius; + + is >> entity_axis[0]; + is >> entity_axis[1]; + entity_axis[2] = math::crossproduct(entity_axis.forward(), entity_axis.left()); + + char c; + // read label + while ( (is.get(c)) && (c != '"')); + while ( (is.get(c)) && (c != '"')) + n += c; + entity_label = n; + n.clear(); + + // read name + while ( (is.get(c)) && (c != '"')); + while ( (is.get(c)) && (c != '"')) + n += c; + entity_name = n; + n.clear(); + + // read model name + while ( (is.get(c)) && (c != '"')); + while ( (is.get(c)) && (c != '"')) + n += c; + entity_modelname = n; + + entity_dirty = false; +} + void Entity::serialize_client_update(std::ostream & os) const { } @@ -241,7 +239,7 @@ void Entity::frame(float seconds) { } -/* ---- EntityDynamic ---------------------------------------------- */ +/* ---- class EntityDynamic ---------------------------------------- */ EntityDynamic::EntityDynamic(unsigned int flags) : Entity(flags) @@ -252,7 +250,7 @@ EntityDynamic::EntityDynamic(unsigned int flags) : EntityDynamic::EntityDynamic(std::istream & is) : Entity(is) { - is >> entity_speed; + entity_speed = 0.0f; } EntityDynamic::~EntityDynamic() @@ -272,12 +270,18 @@ void EntityDynamic::frame(float seconds) entity_dirty = true; } -void EntityDynamic::serialize(std::ostream & os) const +void EntityDynamic::serialize_server_create(std::ostream & os) const { - Entity::serialize(os); + Entity::serialize_server_create(os); os << " " << entity_speed; } +void EntityDynamic::receive_server_create(std::istream &is) +{ + Entity::receive_server_create(is); + is >> entity_speed; +} + void EntityDynamic::serialize_client_update(std::ostream & os) const { } @@ -340,8 +344,6 @@ EntityControlable::EntityControlable(Player *owner, unsigned int flags) : EntityControlable::EntityControlable(std::istream & is) : EntityDynamic(is) { - unsigned int o; - entity_thrust = 0; entity_autolevel = false; @@ -350,10 +352,6 @@ EntityControlable::EntityControlable(std::istream & is) : target_pitch = 0.0f; target_roll = 0.0f; - is >> entity_thrust; - is >> o; - - // FIXME resolve owner entity_owner = 0; } @@ -364,13 +362,25 @@ EntityControlable::~EntityControlable() entity_owner->remove_asset(this); } -void EntityControlable::serialize(std::ostream & os) const +void EntityControlable::serialize_server_create(std::ostream & os) const { - EntityDynamic::serialize(os); + EntityDynamic::serialize_server_create(os); os << " " << entity_thrust; os << " " << ( entity_owner ? entity_owner->id() : 0); } +void EntityControlable::receive_server_create(std::istream &is) +{ + unsigned int o; + + EntityDynamic::receive_server_create(is); + is >> entity_thrust; + is >> o; + + // FIXME resolve owner + entity_owner = 0; +} + void EntityControlable::serialize_client_update(std::ostream & os) const { EntityDynamic::serialize_client_update(os); @@ -483,6 +493,21 @@ EntityGlobe::EntityGlobe(std::istream & is) : { render_texture = 0; entity_shape = Sphere; +} + +EntityGlobe::~EntityGlobe() +{ +} + +void EntityGlobe::serialize_server_create(std::ostream & os) const +{ + Entity::serialize_server_create(os); + os << " \"" << entity_texture << "\""; +} + +void EntityGlobe::receive_server_create(std::istream &is) +{ + Entity::receive_server_create(is); std::string n; char c; @@ -494,15 +519,5 @@ EntityGlobe::EntityGlobe(std::istream & is) : } -EntityGlobe::~EntityGlobe() -{ -} - -void EntityGlobe::serialize(std::ostream & os) const -{ - Entity::serialize(os); - os << " \"" << entity_texture << "\""; -} - } diff --git a/src/core/entity.h b/src/core/entity.h index 2515796..feb99f7 100644 --- a/src/core/entity.h +++ b/src/core/entity.h @@ -109,7 +109,7 @@ public: inline float radius() const { return entity_radius; } /// serialize the entity to a stream - virtual void serialize(std::ostream & os) const; + virtual void serialize_server_create(std::ostream & os) const; /// serialize a client-to-server update on a stream virtual void serialize_client_update(std::ostream & os) const; @@ -123,6 +123,9 @@ public: /// receive a client-to-server update from a stream virtual void receive_client_update(std::istream &is); + /// receive a server-to-client create from a stream + virtual void receive_server_create(std::istream &is); + /// receive a server-to-client update from a stream virtual void receive_server_update(std::istream &is); @@ -150,6 +153,9 @@ public: /// find an entity in the registry static Entity *find(unsigned int id); + /// add an entity to the registry + static void add(Entity *ent, unsigned int it); + /// erase an entity from the registry and delete it static void erase(unsigned int entity_id); @@ -191,9 +197,6 @@ private: // add an entity to the registry static void add(Entity *ent); - // add an entity to the registry - static void add(Entity *ent, unsigned int it); - // the id is set by add() unsigned int entity_id; @@ -224,7 +227,7 @@ public: inline float speed() const { return entity_speed; } /// serialize the entity to a stream - virtual void serialize(std::ostream & os) const; + virtual void serialize_server_create(std::ostream & os) const; /// serialize a client-to-server update on a stream virtual void serialize_client_update(std::ostream & os) const ; @@ -237,6 +240,9 @@ public: /// receive a client-to-server update from a stream virtual void receive_client_update(std::istream &is); + /// receive a server-to-client create from a stream + virtual void receive_server_create(std::istream &is); + /// receive a server-to-client update from a stream virtual void receive_server_update(std::istream &is); @@ -278,7 +284,7 @@ public: inline float thrust() const { return entity_thrust; } /// serialize the entity to a stream - virtual void serialize(std::ostream & os) const; + virtual void serialize_server_create(std::ostream & os) const; /// serialize a client-to-server update on a stream virtual void serialize_client_update(std::ostream & os) const; @@ -295,6 +301,9 @@ public: /// receive a client-to-server update from a stream virtual void receive_client_update(std::istream &is); + /// receive a server-to-client create from a stream + virtual void receive_server_create(std::istream &is); + /// receive a server-to-client update from a stream virtual void receive_server_update(std::istream &is); @@ -354,7 +363,11 @@ public: ~EntityGlobe(); - virtual void serialize(std::ostream & os) const; + /// serialize the entity to a stream + virtual void serialize_server_create(std::ostream & os) const; + + /// receive a server-to-client create from a stream + virtual void receive_server_create(std::istream &is); inline const std::string &texture() const { return entity_texture; } diff --git a/src/core/gameconnection.cc b/src/core/gameconnection.cc index 2085adb..ef998e6 100644 --- a/src/core/gameconnection.cc +++ b/src/core/gameconnection.cc @@ -23,7 +23,7 @@ GameConnection::GameConnection(std::string const &connectionstr) connection_network = 0; connection_running = false; connection_frametime = 0; - + unsigned int port = DEFAULTPORT; std::string host(connectionstr); size_t found = host.find(':'); diff --git a/src/core/gameserver.cc b/src/core/gameserver.cc index 53698c2..717ce87 100644 --- a/src/core/gameserver.cc +++ b/src/core/gameserver.cc @@ -553,71 +553,28 @@ void GameServer::frame(float seconds) } } - // send updates - if (server_network) { - // FIXME prevent connecting clients from receiving update frames - - // transmit buffered sends - server_network->transmit(); - - // start server frame - server_network->broadcast_frame(server_time, server_previoustime); - - // send changes in the world - for (Entity::Registry::iterator it=Entity::registry().begin(); it != Entity::registry().end(); ) { - - Entity *entity = (*it).second; - - if (entity->entity_destroyed) { - - if (!entity->entity_created) { - server_network->broadcast_entity_delete(entity); - } - - delete entity; - (*it).second = entity = 0; - Entity::registry().erase(it++); - - } else { - if (entity->entity_created) { - - server_network->broadcast_entity_create(entity); - entity->entity_created = false; - entity->entity_dirty = false; - } else if (entity->dirty()) { - - server_network->broadcast_entity_update(entity); - entity->entity_dirty = false; - } - ++it; - } - } + if (server_network) { - // update player info - server_network->broadcast_player_update(); + // send network updates + server_network->frame(server_time, server_previoustime); - // transmit buffered sends - server_network->transmit(); + } - } else { + for (Entity::Registry::iterator it=Entity::registry().begin(); it != Entity::registry().end(); ) { + Entity *entity = (*it).second; - // local update stub - for (Entity::Registry::iterator it=Entity::registry().begin(); it != Entity::registry().end(); ) { - Entity *entity = (*it).second; - - if (entity->entity_destroyed) { - delete entity; - (*it).second = entity = 0; - Entity::registry().erase(it++); - } else { - entity->entity_created = false; - entity->entity_dirty = false; - ++it; - } + if (entity->entity_destroyed) { + delete entity; + (*it).second = entity = 0; + Entity::registry().erase(it++); + } else { + entity->entity_created = false; + entity->entity_dirty = false; + ++it; } } - + if (!Cvar::sv_dedicated->value()) { update_clientstate(0); } diff --git a/src/core/net.h b/src/core/net.h index 04c77a5..6f4a280 100644 --- a/src/core/net.h +++ b/src/core/net.h @@ -11,7 +11,7 @@ namespace core { /// network protocol version -const unsigned int PROTOCOLVERSION = 4; +const unsigned int PROTOCOLVERSION = 5; /// maximum lenght of a (compressed) network message block const unsigned int FRAMESIZE = 1152; diff --git a/src/core/netconnection.cc b/src/core/netconnection.cc index db8e3a2..3b302dd 100644 --- a/src/core/netconnection.cc +++ b/src/core/netconnection.cc @@ -451,7 +451,7 @@ void NetConnection::parse_incoming_message(const std::string & message) } else if (command == "die") { unsigned int id; if (msgstream >> id) { - //con_debug << "Received die entity id " << id << std::endl; + con_debug << "Received die entity id " << id << std::endl; Entity *e = Entity::find(id); if (localcontrol() == e) localplayer()->set_control(0); @@ -460,47 +460,96 @@ void NetConnection::parse_incoming_message(const std::string & message) } } else if (command == "ent") { - unsigned int type; - if (msgstream >> type) { - //con_debug << "Received create entity type " << type << std::endl; - switch (type) - { - case Entity::Default: - game()->update_entity_clientstate(new Entity(msgstream)); - break; - case Entity::Dynamic: - game()->update_entity_clientstate(new EntityDynamic(msgstream)); - break; - case Entity::Controlable: - game()->update_entity_clientstate(new EntityControlable(msgstream)); - break; - case Entity::Globe: - game()->update_entity_clientstate(new EntityGlobe(msgstream)); - break; - default: - con_warn << "Create for unknown entity type " << type << std::endl; - break; + + unsigned int type = 0; + unsigned int id = 0; + + if ((msgstream >> id) && (msgstream >> type)) { + + if (!id) { + con_warn << "Received create for NULL entity!" << std::endl; + return; + } + con_debug << "Received create entity id " << id << " type " << type << std::endl; + + Entity *entity = Entity::find(id); + + if (!entity) { + switch (type) + { + case Entity::Default: + entity = new Entity(msgstream); + break; + case Entity::Dynamic: + entity = new EntityDynamic(msgstream); + break; + case Entity::Controlable: + entity = new EntityControlable(msgstream); + break; + case Entity::Globe: + entity = new EntityGlobe(msgstream); + break; + default: + con_warn << "Received create for unknown entity type " << type << std::endl; + return; + break; + } + + Entity::add(entity, id); } + + entity->receive_server_create(msgstream); + game()->update_entity_clientstate(entity); } + } else if (command.compare("zone") == 0) { + unsigned int id; std::string label; if (msgstream >> id) { - con_debug << "Received create zone " << id << std::endl; - Zone * zone = Zone::find(id); + if (id) { + con_debug << "Received zone " << id << std::endl; + Zone * zone = Zone::find(id); - // create the zone if necessary - if (!zone) { - zone = new Zone(msgstream); - Zone::add(zone, id); - } else { - zone->receive_server_update(msgstream); + // create the zone if necessary + if (!zone) { + zone = new Zone(msgstream); + Zone::add(zone, id); + } else { + zone->receive_server_update(msgstream); + } } + + // control is set to 0 on zone change and is put back by pif + connection()->localplayer()->set_control(0); } } else if (command == "pif") { - //con_debug << "Received update player info" << std::endl; + con_debug << "Received update player info" << std::endl; + + Zone *oldzone = connection()->localplayer()->zone(); connection()->localplayer()->receive_server_update(msgstream); + + con_debug << "zone " << ( connection()->localplayer()->zone() ? connection()->localplayer()->zone()->id() : 0) << std::endl; + + if (connection()->localplayer()->zonechange() && oldzone && (oldzone != connection()->localplayer()->zone())) { + + // notify the applciation to clear none-core zone assets (textures etc) + application()->notify_zoneclear(oldzone); + + // delete all entities in the old zone + for (Entity::Registry::iterator it=Entity::registry().begin(); it != Entity::registry().end(); ) { + Entity *entity = (*it).second; + + if ((entity->zone() == oldzone)) { + delete entity; + Entity::registry().erase(it++); + } else { + ++it; + } + } + oldzone->content().clear(); + } } else if (command == "sup") { if (connection_state == Connected) diff --git a/src/core/netserver.cc b/src/core/netserver.cc index dd5dc38..b674dbd 100644 --- a/src/core/netserver.cc +++ b/src/core/netserver.cc @@ -122,6 +122,17 @@ void NetServer::abort() { netserver_error = true; } +// find the client corresponding to a player +NetClient *NetServer::find_client(Player const *player) +{ + for (Clients::iterator it = clients.begin(); it != clients.end(); it++) { + if ((*it)->player() == player) { + return (*it); + } + } + return 0; +} + // remove disconnected clients void NetServer::reap() { @@ -160,14 +171,6 @@ void NetServer::reap() } } - -void NetServer::transmit() -{ - for (Clients::iterator it = clients.begin(); it != clients.end(); it++) { - (*it)->transmit(fd()); - } -} - void NetServer::receive() { if (error()) @@ -286,11 +289,6 @@ void NetServer::client_initialize(NetClient *client) { send_zone_update(client, (*it).second); } - // send entities - for (Entity::Registry::iterator it = Entity::registry().begin(); it != Entity::registry().end(); it++) { - send_entity_create(client, (*it).second); - } - // send connect completed std::string connect("connect\n"); client->send_raw(connect); @@ -300,21 +298,96 @@ void NetServer::client_initialize(NetClient *client) { client->client_state = NetClient::Pending; } -// find the client corresponding to a player -NetClient *NetServer::find_client(Player const *player) +// send updates to one client +void NetServer::client_frame(NetClient *client, float timestamp, float previoustimestamp) { + if (client->state() != NetClient::Connected) + return; + + Zone *zone = client->player()->zone(); + + if (zone) { + if (client->player()->zonechange()) { + + // send zone info + send_zone_update(client, zone); + + // send entities in zone + if (client->player()->zone()) { + for (Zone::Content::iterator it = zone->content().begin(); it != zone->content().end(); it++) { + Entity *entity = (*it); + + if (!entity->entity_destroyed) { + send_entity_create(client, entity); + } + } + } + + // the actual zone change is send by the "pif" message + + } else { + // send a server frame marker + send_frame_marker(client, timestamp, previoustimestamp); + + // send updates for entities in the zone + for (Zone::Content::iterator it = zone->content().begin(); it != zone->content().end(); it++) { + Entity *entity = (*it); + + if (entity->entity_destroyed) { + if (!entity->entity_created) { + send_entity_delete(client, entity); + } + } else if (entity->entity_created) { + send_entity_create(client, entity); + } else if (entity->dirty() && !(entity->flags() & Entity::Static) ) { + + // FIXME only within visual range + send_entity_update(client, entity); + } + } + } + } +} + +// run a network server frame, send updates to clients +void NetServer::frame(float timestamp, float previoustimestamp) +{ + /* FIXME + This code has to be rewritten to send per-player updates. + Players should only receive updates from their current zone + Fix zonechange events + + Only entities within visual range should send updates (1024 game units?) + Fix reliable messages + It would be nice if players with the highest ping got their updates first + */ + + // send updates to each client for (Clients::iterator it = clients.begin(); it != clients.end(); it++) { - if ((*it)->player() == player) { - return (*it); + NetClient *client = *it; + + client->transmit(fd()); + + if (client->state() == NetClient::Connected) + client_frame(client, timestamp, previoustimestamp); + + // update player info always gets through + if (client->player()->dirty() || client->player()->zonechange()) { + + send_player_update(client); + + client->player()->player_dirty = false; + client->player()->player_zonechange = false; } + + client->transmit(fd()); } - return 0; } // send outgoing messages to clients /** - * The followig messages can be send to a client + * The following messages can be send to a client * * frame * ent @@ -361,7 +434,6 @@ void NetServer::send_message(NetClient *client, const char *channel, std::string client->send_raw(msg); } - // disconnect a client void NetServer::send_disconnect(NetClient *client) { @@ -370,101 +442,64 @@ void NetServer::send_disconnect(NetClient *client) client->abort(); } -// broadcast a "frame" message to all clients -void NetServer::broadcast_frame(float timestamp, float previoustimestamp) +// send a "frame" message to a client +void NetServer::send_frame_marker(NetClient *client, float timestamp, float previoustimestamp) { std::ostringstream msg(""); msg << "frame " << timestamp << " " << previoustimestamp << "\n"; - for (Clients::iterator it = clients.begin(); it != clients.end(); it++) { - if ((*it)->state() == NetClient::Connected) { - (*it)->send_raw(msg.str()); - } + if (client->state() == NetClient::Connected) { + client->send_raw(msg.str()); } + } -// broadcast a "die" delete entity message to all clients -void NetServer::broadcast_entity_delete(Entity *entity) +// send a "ent" create entity message to all clients +void NetServer::send_entity_create(NetClient *client, Entity *entity) { - std::ostringstream msg(""); - msg << "die " << entity->id() << '\n'; - - for (Clients::iterator it = clients.begin(); it != clients.end(); it++) { - if ((*it)->state() == NetClient::Connected) { - (*it)->send_raw(msg.str()); - } + if (client->state() == NetClient::Connected) { + std::ostringstream msg; + msg << "ent " << entity->id() << " " << entity->type() << " "; + entity->serialize_server_create(msg); + msg << '\n'; + client->send_raw(msg.str()); } } -// broadcast a "ent" create entity message to all clients -void NetServer::broadcast_entity_create(Entity *entity) +// send a "die" delete entity message to a client +void NetServer::send_entity_delete(NetClient *client, Entity *entity) { - std::ostringstream msg; - msg << "ent "; - entity->serialize(msg); - msg << '\n'; + std::ostringstream msg(""); + msg << "die " << entity->id() << '\n'; - for (Clients::iterator it = clients.begin(); it != clients.end(); it++) { - if ((*it)->state() == NetClient::Connected) { - (*it)->send_raw(msg.str()); - } + if (client->state() == NetClient::Connected) { + client->send_raw(msg.str()); } } -// send a "ent" create entity message to all clients -void NetServer::send_entity_create(NetClient *client, Entity *entity) +// broadcast a "sup" server update entity message to all clients +void NetServer::send_entity_update(NetClient *client, Entity *entity) { - std::ostringstream msg; - msg << "ent "; - entity->serialize(msg); - msg << '\n'; - client->send_raw(msg.str()); + if (client->state() == NetClient::Connected) { + std::ostringstream msg; + msg << "sup " << entity->id() << " "; + entity->serialize_server_update(msg); + msg << '\n'; + + client->send_raw(msg.str()); + } } // send a "zone" update zone message to a client void NetServer::send_zone_update(NetClient *client, Zone *zone) { std::ostringstream msg; - msg << "zone "; + msg << "zone " << zone->id() << " "; zone->serialize_server_update(msg); msg << '\n'; client->send_raw(msg.str()); } -// broadcast a "sup" server update entity message to all clients -void NetServer::broadcast_entity_update(Entity *entity) -{ - std::ostringstream msg; - msg << "sup " << entity->id() << " "; - entity->serialize_server_update(msg); - msg << '\n'; - - for (Clients::iterator it = clients.begin(); it != clients.end(); it++) { - if ((*it)->state() == NetClient::Connected) { - (*it)->send_raw(msg.str()); - } - } -} - -// broadcast a "pif" update player information if necessary -void NetServer::broadcast_player_update() -{ - for (Clients::iterator it = clients.begin(); it != clients.end(); it++) { - NetClient *client = *it; - - if (client->player()->dirty()) { - // send player data - std::ostringstream msg; - msg << "pif "; - client->player()->serialize_server_update(msg); - msg << '\n'; - client->send_raw(msg.str()); - - client->player()->player_dirty = false; - } - } -} - // send a "pif" update player information to a single player void NetServer::send_player_update(NetClient *client) { diff --git a/src/core/netserver.h b/src/core/netserver.h index 2340a5d..4dcae69 100644 --- a/src/core/netserver.h +++ b/src/core/netserver.h @@ -48,49 +48,43 @@ public: /*----- mutators -------------------------------------------------- */ + /// run a network server frame + void frame(float timestamp, float previoustimestamp); + /// receive data from clients void receive(); - /// transmit data to clients - void transmit(); - /// broadcast a message void broadcast_message(const char *channel, std::string const & message, Player *ignore_player=0); - /// send a message to a single client + /// send a message to a client void send_message(NetClient *client, const char *channel, std::string const & message); - /// disconnect a single client + /// disconnect a client void send_disconnect(NetClient *client); - /// broadcast a server frame message - void broadcast_frame(float timestamp, float previoustimestamp); - - /// broadcast a delete entity event - void broadcast_entity_delete(Entity *entity); + /// find the client corresponding to a player + NetClient *find_client(Player const *player); - /// broadcast a create entity event - void broadcast_entity_create(Entity *entity); +protected: + /// send a server frame marker + void send_frame_marker(NetClient *client, float timestamp, float previoustimestamp); - /// send a create entity event to a single player + /// send a create entity event void send_entity_create(NetClient *client, Entity *entity); - - /// send a zone update event to a single player - void send_zone_update(NetClient *client, Zone *zone); + + /// broadcast a delete entity event + void send_entity_delete(NetClient *client, Entity *entity); /// broadcast a update entity event - void broadcast_entity_update(Entity *entity); + void send_entity_update(NetClient *client, Entity *entity); - /// broadcast updated player information, if necessary - void broadcast_player_update(); + /// send a zone update event + void send_zone_update(NetClient *client, Zone *zone); - /// send an update player information message to a single client + /// send an update player information message void send_player_update(NetClient *client); - /// find the client corresponding to a player - NetClient *find_client(Player const *player); - -protected: /// set the error state void abort(); @@ -106,6 +100,9 @@ protected: /// parse incoming client messages void parse_incoming_message(NetClient *client, const std::string & message); + /// send a server frame to a single client + void client_frame(NetClient *client, float timestamp, float previoustimestamp); + private: bool netserver_error; int netserver_fd; diff --git a/src/core/player.cc b/src/core/player.cc index ba5ffbe..fafb052 100644 --- a/src/core/player.cc +++ b/src/core/player.cc @@ -29,6 +29,7 @@ void Player::clear() player_zone = 0; player_name.clear(); player_dirty = false; + player_zonechange = false; player_rcon = false; player_mute = false; @@ -40,16 +41,17 @@ void Player::set_control(EntityControlable *entitycontrolable) player_control = entitycontrolable; if (entitycontrolable) { - player_zone = entitycontrolable->zone(); + set_zone(entitycontrolable->zone()); } - player_dirty = true; } void Player::set_zone(Zone *zone) { - player_zone = zone; - player_dirty = true; + if (zone != player_zone) { + player_zone = zone; + player_zonechange = true; + } } void Player::update_info() @@ -99,41 +101,26 @@ void Player::receive_client_update(std::istream &is) void Player::serialize_server_update(std::ostream & os) const { - unsigned int zone; - if (player_zone) - zone = player_zone->id(); - else - zone = 0; - - unsigned int co; - if (player_control) - co = player_control->id(); - else - co = 0; - - - os << player_id << " " << zone << " " << co << " " << player_color << " \"" << player_name << "\""; + unsigned int zo = (zone() ? zone()->id() : 0); + unsigned int co = (player_control ? player_control->id() : 0); + + os << player_id << " " << zo << " " << co << " " << player_color << " \"" << player_name << "\""; } void Player::receive_server_update(std::istream &is) { is >> player_id; - unsigned int zone = 0; - is >> zone; - if (zone) { - player_zone = Zone::find(zone); - } else { - player_zone = 0; - } + unsigned int zo = 0; + is >> zo; + set_zone(Zone::find(zo)); unsigned int co = 0; is >> co; if (co) { Entity *e = Entity::find(co); if (e && e->type() == Entity::Controlable) { - player_control = (EntityControlable *) e; - player_zone = player_control->zone(); + player_control = static_cast(e); } else { player_control = 0; con_warn << "control set to unknown entity " << co << "\n"; diff --git a/src/core/player.h b/src/core/player.h index cdcdbd1..7bf533c 100644 --- a/src/core/player.h +++ b/src/core/player.h @@ -56,6 +56,8 @@ public: /// set the zone the player is currently in void set_zone(Zone *zone); + inline bool zonechange() const { return player_zonechange; } + /// player primary color inline math::Color const & color() const { return player_color; } @@ -102,6 +104,9 @@ public: /// dirty state bool player_dirty; + /// player has changed zone + bool player_zonechange; + /// indicates rcon access bool player_rcon; @@ -128,6 +133,8 @@ private: // the zone the player is currently in Zone *player_zone; + + }; } diff --git a/src/core/zone.cc b/src/core/zone.cc index 584f75d..a81736d 100644 --- a/src/core/zone.cc +++ b/src/core/zone.cc @@ -182,7 +182,6 @@ Entity *Zone::find_entity(unsigned int id) void Zone::serialize_server_update(std::ostream & os) const { - os << zone_id << " "; os << zone_label << " "; os << "\"" << zone_name << "\" "; os << "\"" << zone_sky << "\" "; -- cgit v1.2.3