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/core/netserver.cc | 209 +++++++++++++++++++++++++++++--------------------- 1 file changed, 122 insertions(+), 87 deletions(-) (limited to 'src/core/netserver.cc') 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) { -- cgit v1.2.3