From 75c6db097b990e58b4b2585580a89561c838d923 Mon Sep 17 00:00:00 2001 From: Stijn Buys Date: Tue, 26 Oct 2010 21:08:12 +0000 Subject: updated network protocol version to 20, implemented invemtory depletion, unified depletion with keepalive --- src/core/application.cc | 8 ++-- src/core/cvar.cc | 3 +- src/core/cvar.h | 4 +- src/core/entity.cc | 30 ++++--------- src/core/entity.h | 85 ++++++++++++++++++------------------ src/core/gameserver.cc | 107 ++++++++++++++++++++++++++++++---------------- src/core/item.cc | 8 +++- src/core/item.h | 27 +++++++++++- src/core/net.h | 4 +- src/game/base/cargopod.cc | 7 ++- src/game/base/cargopod.h | 2 + src/game/base/game.cc | 12 +++--- src/game/base/game.h | 10 ++--- src/game/base/station.cc | 24 +++++++++++ src/game/base/station.h | 2 + 15 files changed, 208 insertions(+), 125 deletions(-) (limited to 'src') diff --git a/src/core/application.cc b/src/core/application.cc index 1d7ded2..f21dcad 100644 --- a/src/core/application.cc +++ b/src/core/application.cc @@ -110,9 +110,6 @@ void Application::init(int count, char **arguments) Cvar::sv_private = Cvar::get("sv_private", "0"); Cvar::sv_private->set_info("[bool] enable or disable network server for a client"); - Cvar::cl_prediction = Cvar::get("cl_prediction", "0", Cvar::Archive); - Cvar::cl_prediction->set_info("[bool] enable or disable client prediction"); - // load configuration load_config(); load_autoexec(); @@ -133,10 +130,13 @@ void Application::init(int count, char **arguments) Cvar::sv_password = Cvar::get("sv_password", "", Cvar::Archive); Cvar::sv_password->set_info("[string] server rcon password"); + + Cvar::sv_keepalive = Cvar::get("sv_keepalive", "120", core::Cvar::Archive); + Cvar::sv_keepalive->set_info("[int] number of seconds to keep dynamic objects alive"); // network settings Cvar::net_host = Cvar::get("net_host", "0.0.0.0", Cvar::Archive); - Cvar::net_host->set_info("[ip] IP address the network server binds to"); + Cvar::net_host->set_info("[address] IP address the network server binds to"); Cvar::net_port = Cvar::get("net_port", "8042", Cvar::Archive); Cvar::net_port->set_info("[int] default network port"); diff --git a/src/core/cvar.cc b/src/core/cvar.cc index a47b72e..bbdf395 100644 --- a/src/core/cvar.cc +++ b/src/core/cvar.cc @@ -25,8 +25,7 @@ Cvar *Cvar::sv_name = 0; Cvar *Cvar::sv_description = 0; Cvar *Cvar::sv_password = 0; Cvar *Cvar::sv_arraysize = 0; - -Cvar *Cvar::cl_prediction = 0; +Cvar *Cvar::sv_keepalive = 0; Cvar *Cvar::net_host = 0; Cvar *Cvar::net_port = 0; diff --git a/src/core/cvar.h b/src/core/cvar.h index 21491fd..2487adc 100644 --- a/src/core/cvar.h +++ b/src/core/cvar.h @@ -156,10 +156,10 @@ public: static Cvar *sv_description; // server description static Cvar *sv_password; // server rcon password static Cvar *sv_arraysize; // vertex array size in MegaBytes - + static Cvar *sv_keepalive; // entity keepalive timeout + static Cvar *con_ansi; // console ANSI colors - static Cvar *cl_prediction; // client prediction static Cvar *net_host; // network server ip (default binds to all interfaces) static Cvar *net_port; // network port diff --git a/src/core/entity.cc b/src/core/entity.cc index c99c186..4f13efa 100644 --- a/src/core/entity.cc +++ b/src/core/entity.cc @@ -160,6 +160,7 @@ Entity::Entity() : entity_created = true; entity_destroyed = false; entity_dirty = false; + entity_keepalive = 0; entity_zone = 0; entity_oldzone = 0; @@ -182,6 +183,7 @@ Entity::Entity(std::istream & is) entity_zone = 0; entity_oldzone = 0; entity_visible = true; + entity_keepalive = 0; entity_model = 0; @@ -471,6 +473,10 @@ void Entity::frame(float seconds) { } +void Entity::upkeep(const unsigned long timestamp) +{ +} + void Entity::add_menu(MenuDescription *menu) { entity_menus.push_back(menu); @@ -544,16 +550,12 @@ EntityDynamic::EntityDynamic() : Entity() { entity_state = Normal; entity_timer = 0; - entity_keepalive_time = 0.0f; - entity_keepalive_timeout = 0.0f; } EntityDynamic::EntityDynamic(std::istream & is) : Entity(is) { entity_state = Normal; entity_timer = 0; - entity_keepalive_time = 0.0f; - entity_keepalive_timeout = 0.0f; } EntityDynamic::~EntityDynamic() @@ -568,16 +570,6 @@ void EntityDynamic::set_state(int state) } } -void EntityDynamic::set_keepalive_time(float time) -{ - entity_keepalive_time = time; -} - -void EntityDynamic::set_keepalive_timeout(float timeout) -{ - entity_keepalive_timeout = timeout; -} - void EntityDynamic::reset() { Entity::reset(); @@ -596,13 +588,7 @@ void EntityDynamic::frame(float seconds) if (entity_state == Docked) { return; } - - if (flag_is_set(KeepAlive)) { - if ((keepalive_time() > 0.0f) && (keepalive_time() < server()->time())) { - die(); - } - } - + // transfer bullet state to entity state if (entity_body) { // this makes sure an update is sent if speed goes to 0 in the next step @@ -822,6 +808,7 @@ void EntityControlable::serialize_client_update(std::ostream & os) const os << target_thrust << " "; os << target_roll << " "; os << target_strafe << " "; + os << target_vstrafe << " "; os << target_afterburner << " "; } @@ -833,6 +820,7 @@ void EntityControlable::receive_client_update(std::istream &is) is >> target_thrust; is >> target_roll; is >> target_strafe; + is >> target_vstrafe; is >> target_afterburner; } diff --git a/src/core/entity.h b/src/core/entity.h index 8dd5644..954b261 100644 --- a/src/core/entity.h +++ b/src/core/entity.h @@ -216,6 +216,11 @@ public: return entity_destroyed; } + /// time when the entity was last alive + inline unsigned long keepalive() const { + return entity_keepalive; + } + /// list inventory, if available, to console void list_inventory() const; @@ -254,6 +259,15 @@ public: */ virtual void frame(float seconds); + /** + * @brief runs one upkeep frame for the entity + * The upkeep frame will be executed by the engine if the entity has the KeepAlive flag set + * and the keepalive timeout has been elapsed. + * The default implementation does nothing + * @param timestamp game timestamp for the current upkeep frame + */ + virtual void upkeep(const unsigned long timestamp); + /** * @brief set the zone the entity is currently in * this fuction removes the entity from its previous zone @@ -282,18 +296,42 @@ public: entity_radius = radius; } - /* ---- actors ---------------------------------------------------- */ + + /// set location + inline void set_location(const math::Vector3f &location) { + entity_location.assign(location); + } + + /// set location + inline void set_axis(const math::Axis &axis) { + entity_axis.assign(axis); + } - /// set flags + /// set flag inline void set_flag(Flags flag) { entity_flags |= flag; } - /// unset flags + /// unset flag inline void unset_flag(Flags flag) { entity_flags &= ~flag; } + /** + * @brief add an inventory to this entity + * Entity takes ownership over the inventory pointer + */ + void set_inventory(Inventory *inventory); + + void set_info(Info *info); + + /// set the timestamp when the entity was last alive + void set_keepalive(unsigned long timestamp) { + entity_keepalive = timestamp; + } + + /* ---- actors ---------------------------------------------------- */ + /** * @brief reset the physics state */ @@ -307,16 +345,6 @@ public: /// clear all update flags virtual void clear_updates(); - - /// set location - inline void set_location(const math::Vector3f &location) { - entity_location.assign(location); - } - - /// set location - inline void set_axis(const math::Axis &axis) { - entity_axis.assign(axis); - } /** * @brief mutable reference to the location @@ -345,15 +373,7 @@ public: inline math::Color& get_color_second() { return entity_color_second; } - - /** - * @brief add an inventory to this entity - * Entity takes ownership over the inventory pointer - */ - void set_inventory(Inventory *inventory); - - void set_info(Info *info); - + /* ---- deserializers -------------------------------------- */ /// receive a client-to-server update from a stream @@ -376,7 +396,6 @@ public: /// serialize a server-to-client update on a stream virtual void serialize_server_update(std::ostream & os) const; - /* ---- static --------------------------------------------- */ /// type definition for the entity registry @@ -459,6 +478,8 @@ private: Extension* entity_extension[4]; + unsigned long entity_keepalive; + static Registry entity_registry; static size_t entity_nextid; @@ -494,16 +515,6 @@ public: return entity_timer; } - /// time when the entity was last alive - inline const float keepalive_time() const { - return entity_keepalive_time; - } - - /// keepalive timeout - inline const float keepalive_timeout() const { - return entity_keepalive_timeout; - } - /*----- mutators -------------------------------------------------- */ /// mass of the entity @@ -540,12 +551,6 @@ public: /// set event state virtual void set_state(int state); - - /// set the time when the entity was last alive, in game time seconds - void set_keepalive_time(float time); - - /// set the timeout after which the entitie is deleted, in seconds - void set_keepalive_timeout(float timeout); /// runs one game frame for the entity /** @@ -560,8 +565,6 @@ public: virtual void reset(); protected: - float entity_keepalive_time; - float entity_keepalive_timeout; float entity_timer; int entity_state; }; diff --git a/src/core/gameserver.cc b/src/core/gameserver.cc index 344c069..f84e228 100644 --- a/src/core/gameserver.cc +++ b/src/core/gameserver.cc @@ -509,19 +509,77 @@ void GameServer::frame(unsigned long timestamp) server_previoustime = server_timestamp; server_timestamp = timestamp - server_startup; - float elapsed = (float)(server_timestamp - server_previoustime) / 1000.0f; + const float elapsed = (float)(server_timestamp - server_previoustime) / 1000.0f; + const unsigned long keepalive_timeout = (Cvar::sv_keepalive ? 1000 * (unsigned long) Cvar::sv_keepalive->value() : (unsigned long) 0 ); - // copy the previous entity state to the client state - /*if (!Cvar::sv_dedicated->value()) { - reset_clientstate(); - }*/ - - // run a time frame on each entity - for (Entity::Registry::iterator it = Entity::registry().begin(); it != Entity::registry().end(); it++) { - Entity *entity = (*it).second; + for (Zone::Registry::iterator zit = Zone::registry().begin(); zit != Zone::registry().end(); zit++) { + Zone *zone= (*zit).second; + + bool keepalive_run = false; + math::Vector3f keepalive_maxbox; + math::Vector3f keepalive_minbox; - if ((entity->type() == Entity::Controlable) || (entity->type() == Entity::Dynamic)) { - entity->frame(elapsed); + // run a game frame on all dynamic and controlable entities + for (Zone::Content::iterator it = zone->content().begin(); it != zone->content().end(); it++) { + Entity *entity = (*it); + + if (entity->type() == Entity::Dynamic) { + entity->frame(elapsed); + + } else if (entity->type() == Entity::Controlable) { + EntityControlable *controlable = static_cast(entity); + controlable->frame(elapsed); + + if (controlable->owner() && (controlable->owner()->control() == controlable)) { + // add player controlable to keepalive bounding box + if (!keepalive_run) { + keepalive_maxbox.assign(controlable->location()); + keepalive_minbox.assign(controlable->location()); + keepalive_run = true; + } else { + for (size_t i = 0; i < 3; i++) { + if (keepalive_maxbox[i] < controlable->location()[i]) + keepalive_maxbox[i] = controlable->location()[i]; + if (keepalive_minbox[i] > controlable->location()[i]) + keepalive_minbox[i] = controlable->location()[i]; + } + } + } + } + } + + // expand keepalive bounding box + for (size_t i = 0; i < 3; i++) { + keepalive_maxbox[i] += range::fxdistance * 0.5f; + keepalive_minbox[i] -= range::fxdistance * 0.5f; + } + + // run an upkeep frame on entities that require it + for (Zone::Content::iterator it = zone->content().begin(); it != zone->content().end(); it++) { + Entity *entity = (*it); + + // if entity is inside the keepalive bounding box, the keepalive timestamp will be set to the current game timestamp + if (entity->flag_is_set(Entity::KeepAlive)) { + if (keepalive_run) { + bool alive = true; + + // bounding box test + for (size_t i = 0; alive && (i < 3); i++) { + if ((entity->location()[i] > keepalive_maxbox[i]) || (entity->location()[i] < keepalive_minbox[i])) { + alive = false; + } + } + + if (alive) { + entity->set_keepalive(server_timestamp); + } + } + + // run upkeep if the keepalive timeout has elapsed + if (entity->keepalive() + keepalive_timeout < server_timestamp) { + entity->upkeep(server_timestamp); + } + } } } @@ -543,7 +601,7 @@ void GameServer::frame(unsigned long timestamp) EntityControlable *control = player->control(); // the player is viewing an entity - if (view) { + if (view) { // the view has changed zone if (view->zone() != player->zone()) { if (control) { @@ -589,31 +647,6 @@ void GameServer::frame(unsigned long timestamp) server_network->frame(server_timestamp); } - const float keepalive_distance_squared = range::fxdistance * range::fxdistance; - - // FIXME KeepAlive sweep has to be done in linear order, O(n^2) is extremely slow with a large number of entities - - for (Entity::Registry::const_iterator it = Entity::registry().begin(); it != Entity::registry().end(); it++) { - - // set keepalive timeout - if ((*it).second->type() == Entity::Controlable) { - const EntityControlable *controlable = static_cast((*it).second); - - if ( (controlable->state() != Entity::Docked) && controlable->owner() && controlable->zone() ) { - for (Zone::Content::iterator zit = controlable->zone()->content().begin(); zit != controlable->zone()->content().end(); zit++) { - - if ( ((*zit)->flag_is_set(Entity::KeepAlive)) && ((*zit)->type() == Entity::Dynamic) && ((*zit) != controlable) ) { - EntityDynamic *dynamic = static_cast(*zit); - if (math::distancesquared(controlable->location(), dynamic->location()) < keepalive_distance_squared) { - dynamic->set_keepalive_time(time() + dynamic->keepalive_timeout()); - } - } - } - } - - } - } - // remove deleted entities and mark remaining entities as updated for (Entity::Registry::iterator it = Entity::registry().begin(); it != Entity::registry().end();) { // remove deleted entities diff --git a/src/core/item.cc b/src/core/item.cc index df12885..3768afa 100644 --- a/src/core/item.cc +++ b/src/core/item.cc @@ -23,6 +23,7 @@ Item::Item(const Info *info) { item_info = info; item_amount = 0; + item_flags = 0; item_price = info->price(); set_timestamp(game() ? game()->timestamp() : 1); } @@ -31,6 +32,7 @@ Item::Item(const Item &other) { item_info = other.info(); item_amount = other.amount(); + item_flags = other.flags(); item_price = other.price(); set_timestamp(game() ? game()->timestamp() : 1); } @@ -39,7 +41,8 @@ Item::~Item() { item_info = 0; item_amount = 0; - item_amount = 0; + item_flags = 0; + item_price = 0; } void Item::set_amount(const long amount) @@ -73,13 +76,14 @@ void Item::set_timestamp(const unsigned long timestamp) void Item::serialize_server_update(std::ostream & os) const { - os << amount() << " " << price() << " "; + os << amount() << " " << price() << " " << flags() << " "; } void Item::receive_server_update(std::istream &is) { is >> item_amount; is >> item_price; + is >> item_flags; } } // namespace core diff --git a/src/core/item.h b/src/core/item.h index 0e9e167..ac3188d 100644 --- a/src/core/item.h +++ b/src/core/item.h @@ -19,6 +19,8 @@ namespace core class Item { public: + enum Flags {Tradeable = 1}; + Item(const Info *info); /// copy constructor @@ -46,7 +48,17 @@ public: inline const unsigned long timestamp() const { return item_timestamp; } - + + /// item flags + inline const unsigned int flags() const { + return item_flags; + } + + /// returns true of a flag is set + inline const bool flag_is_set(const Flags flag) const { + return ((item_flags & (unsigned int)flag) == (unsigned int)flag); + } + /* ---- mutators ----------------------------------------------- */ /** @@ -59,7 +71,16 @@ public: void dec_amount(const long amount); void set_price(const long price); - + + /// set flag + inline void set_flag(Flags flag) { + item_flags |= flag; + } + + /// unset flag + inline void unset_flag(Flags flag) { + item_flags &= ~flag; + } void set_dirty(); /* ---- serializers -------------------------------------------- */ @@ -76,6 +97,8 @@ private: long item_amount; unsigned long item_timestamp; + + unsigned int item_flags; }; } // namespace core diff --git a/src/core/net.h b/src/core/net.h index 39dfdf6..31fc6d7 100644 --- a/src/core/net.h +++ b/src/core/net.h @@ -11,7 +11,7 @@ namespace core { /// network protocol version -const unsigned int PROTOCOLVERSION = 19; +const unsigned int PROTOCOLVERSION = 20; /// maximum lenght of a (compressed) network message block const unsigned int FRAMESIZE = 1152; @@ -24,7 +24,7 @@ const unsigned int MAXPENDINGCONNECTIONS = 32; const unsigned int DEFAULTPORT = 8042; /// network timeout in seconds -const float NETTIMEOUT = 20; +const float NETTIMEOUT = 15; } diff --git a/src/game/base/cargopod.cc b/src/game/base/cargopod.cc index 5ea4105..7406d3a 100644 --- a/src/game/base/cargopod.cc +++ b/src/game/base/cargopod.cc @@ -17,7 +17,6 @@ CargoPod::CargoPod() : EntityDynamic() set_label("cargopod"); set_flag(core::Entity::KeepAlive); - set_keepalive_timeout(Game::g_keepalive ? Game::g_keepalive->value() : 0); if (Default::podmodel) set_modelname(Default::podmodel->name()); @@ -35,5 +34,11 @@ CargoPod::~CargoPod() } +void CargoPod::upkeep(const unsigned long timestamp) +{ + // cargo pods dissapear on upkeep + die(); +} + } // namespace game diff --git a/src/game/base/cargopod.h b/src/game/base/cargopod.h index daeb9bc..7bce9a4 100644 --- a/src/game/base/cargopod.h +++ b/src/game/base/cargopod.h @@ -17,6 +17,8 @@ class CargoPod : public core::EntityDynamic public: CargoPod(); virtual ~CargoPod(); + + virtual void upkeep(const unsigned long timestamp); }; } // namespace game diff --git a/src/game/base/game.cc b/src/game/base/game.cc index 7aa1081..40c7c28 100644 --- a/src/game/base/game.cc +++ b/src/game/base/game.cc @@ -54,7 +54,7 @@ core::Cvar *Game::g_impulsespeed = 0; core::Cvar *Game::g_jumppointrange = 0; core::Cvar *Game::g_devel = 0; core::Cvar *Game::g_damping = 0; -core::Cvar *Game::g_keepalive; +core::Cvar *Game::g_deplete = 0; core::Module *factory() { @@ -905,8 +905,8 @@ Game::Game() : core::Module("Project::OSiRiON", true) g_damping = core::Cvar::get("g_damping", "0.1", core::Cvar::Archive); g_damping->set_info("[float] physics damping factor (0-1)"); - g_keepalive = core::Cvar::get("g_keepalive", "300", core::Cvar::Archive); - g_keepalive->set_info("[float] amount of time dynamic objects are kept alive, in seconds"); + g_deplete = core::Cvar::get("g_deplete", "60", core::Cvar::Archive); + g_deplete->set_info("[int] number of seconds to deplete 1 unit of cargo from inventories"); } Game::~Game() @@ -915,7 +915,6 @@ Game::~Game() g_jumppointrange = 0; g_devel = 0; g_damping = 0; - g_keepalive = 0; // game functions are automaticly removed // FIXME move cleanup sequence to core:: @@ -1025,7 +1024,7 @@ bool Game::load_zone(core::Zone *zone) bool b; long l; - + std::string strval; while (zoneini.getline()) { @@ -1307,7 +1306,7 @@ bool Game::validate_zone(core::Zone *zone) JumpGate *jumpgate = static_cast(entity); jumpgate->validate(); } else { - if ((entity->flags() & core::Entity::Dockable) == core::Entity::Dockable) { + if (entity->flag_is_set(core::Entity::Dockable)) { generate_entity_menus(entity); } } @@ -1351,6 +1350,7 @@ bool Game::generate_entity_menus(core::Entity *entity) // add trade menus if (entity->inventory()) { + entity->set_flag(core::Entity::KeepAlive); size_t nbcargo = 0; size_t nbships = 0; diff --git a/src/game/base/game.h b/src/game/base/game.h index d879a30..dd47cef 100644 --- a/src/game/base/game.h +++ b/src/game/base/game.h @@ -36,7 +36,7 @@ const unsigned int station_enttype = 262; const unsigned int cargopod_enttype = 263; // planet docking distance -const float planet_safe_distance = 150.0f; +const float planet_safe_distance = 50.0f; const float jump_timer_delay = 5.0f; const float impulse_timer_delay = 3.0f; @@ -85,12 +85,12 @@ public: /// game variable: enable or disable development mode (cheat mode) static core::Cvar *g_devel; + /// game variable: number of seconds it takes for 1 unit of cargo to deplete from station inventories + static core::Cvar *g_deplete; + /// physics variable: default damping factor of space - static core::Cvar *g_damping; + static core::Cvar *g_damping; - /// game variable: amount of time dynamic objects are kept alive when there are no players - static core::Cvar *g_keepalive; - private: bool load_world(); diff --git a/src/game/base/station.cc b/src/game/base/station.cc index 0d992bd..6493348 100644 --- a/src/game/base/station.cc +++ b/src/game/base/station.cc @@ -20,6 +20,30 @@ Station::Station() : Entity() Station::~Station() { + +} + +void Station::upkeep(const unsigned long timestamp) +{ + if (!inventory()) + return; + + const unsigned long deplete = (Game::g_deplete ? 1000 * (unsigned long) Game::g_deplete->value() : 0); + + if (deplete > 0) { + bool dirty = false; + for (core::Inventory::Items::iterator it = inventory()->items().begin(); it != inventory()->items().end(); it++) { + core::Item *item = (*it); + if ((item->amount() > 0) && (item->timestamp() + deplete < timestamp)) { + item->dec_amount(1); + dirty = true; + } + } + + if (dirty) { + inventory()->set_dirty(); + } + } } } diff --git a/src/game/base/station.h b/src/game/base/station.h index 2aa8a95..5f833c4 100644 --- a/src/game/base/station.h +++ b/src/game/base/station.h @@ -15,6 +15,8 @@ class Station : public core::Entity public: Station(); virtual ~Station(); + + virtual void upkeep(const unsigned long timestamp); }; } -- cgit v1.2.3