/* core/entity.cc This file is part of the Osirion project and is distributed under the terms of the GNU General Public License version 2. */ #include #include #include #include "auxiliary/functions.h" #include "sys/sys.h" #include "core/entity.h" #include "core/cvar.h" #include "core/application.h" namespace core { // maximal number of entities const size_t MAX_ENTITY = 1048574; using math::Color; using math::Vector3f; /* ---- Static functions for the Entity registry ------------------- */ Entity::Registry Entity::entity_registry; size_t Entity::entity_nextid = 0; void Entity::add(Entity *ent) { Registry::iterator it; entity_nextid = (entity_nextid % MAX_ENTITY) + 1; // lowest entity-id is 1 unsigned int id = entity_nextid; for (it = entity_registry.begin(); it != entity_registry.end() && id == (*it).second->id(); it++) { id++; } ent->entity_id = id; entity_registry[id] = ent; } void Entity::add(Entity *ent, unsigned int id) { if (find(id)) { con_warn << "Duplicate entity " << id << "!\n"; return; } ent->entity_id = id; entity_registry[id] = ent; } Entity *Entity::find(unsigned int id) { Registry::iterator it = entity_registry.find(id); if (it == entity_registry.end()) return 0; else return (*it).second; } void Entity::erase(unsigned int id) { Registry::iterator it = entity_registry.find(id); if (it != entity_registry.end()) { delete((*it).second); (*it).second = 0; entity_registry.erase(it); } else { con_warn << "Could not erase entity " << id << "!\n"; } } void Entity::list() { Registry::iterator it; for (it = entity_registry.begin(); it != entity_registry.end(); it++) { std::string typeindicator; Entity *entity = (*it).second; con_print << " id " << std::setw(4) << entity->id() << " type " << std::setw(4) << entity->type() << ":" << std::setw(4) << entity->moduletype() << " " << entity->label() << std::endl; } con_print << entity_registry.size() << " registered entities" << std::endl; } /* ---- class Entity ----------------------------------------------- */ Entity::Entity(const unsigned int flags) : entity_location(0.0f, 0.0f, 0.0f), entity_color(1.0f, 1.0f, 1.0f, 1.0f), entity_color_second(1.0f, 1.0f, 1.0f, 1.0f) { entity_id = 0; entity_flags = flags; entity_moduletypeid = 0; entity_speed = 0.0f; entity_radius = 0.5f; entity_shape = Diamond; entity_created = true; entity_destroyed = false; entity_dirty = false; entity_model = 0; entity_label.clear(); entity_name.clear(); entity_zone = 0; entity_oldzone = 0; entity_visible = true; entity_serverside = false; memset(entity_extension, 0, sizeof(entity_extension)); add(this); } Entity::Entity(std::istream & is) { entity_serverside = false; entity_id = 0; entity_zone = 0; entity_oldzone = 0; entity_visible = true; entity_model = 0; entity_speed = 0.0f; entity_created = true; entity_destroyed = false; memset(entity_extension, 0, sizeof(entity_extension)); } Entity::~Entity() { // delete extensions for (size_t i = 0; i < 4; i++) { if (entity_extension[i]) delete entity_extension[i]; entity_extension[i] = 0; } // delete entity menus for (Menus::iterator it = menus().begin(); it != menus().end(); it++) { delete(*it); } menus().clear(); if (entity_zone) entity_zone->remove(this); } void Entity::die() { entity_destroyed = true; } void Entity::clear_updates() { entity_created = false; entity_dirty = false; entity_oldzone = 0; } void Entity::set_zone(Zone *zone) { if (entity_zone == zone) return; if (entity_zone) entity_zone->remove(this); if (!entity_oldzone) entity_oldzone = entity_zone; entity_zone = zone; entity_dirty = true; if (entity_zone) entity_zone->add(this); } void Entity::set_label(const char *label) { entity_label.assign(label); aux::to_label(entity_label); } void Entity::set_label(const std::string &label) { entity_label.assign(label); aux::to_label(entity_label); } void Entity::set_name(const char *name) { entity_name.assign(name); aux::strip_quotes(entity_name); } void Entity::set_name(const std::string &name) { entity_name.assign(name); aux::strip_quotes(entity_name); } void Entity::set_model(model::Model *model) { entity_model = model; if (entity_model) { entity_radius = entity_model->radius(); entity_modelname = entity_model->name(); } } void Entity::set_modelname(const std::string &modelname) { if (!modelname.size()) { set_model(0); } else { set_model(model::Model::load(modelname)); } if (!entity_model) entity_modelname.clear(); } void Entity::serialize_server_create(std::ostream & os) const { os << moduletype() << " " << flags() << " " << (visible() ? 1 : 0) << " " << (zone() ? zone()->id() : 0) << " " << std::setprecision(8) << entity_location << " " << color() << " " << color_second() << " " << shape() << " " << radius() << " " << std::setprecision(8) << entity_axis.forward() << " " << std::setprecision(8) << entity_axis.left() << " " << "\"" << entity_label << "\" " << "\"" << entity_name << "\" " << "\"" << (entity_model ? entity_model->name() : "") << "\" "; } void Entity::receive_server_create(std::istream &is) { unsigned int s; unsigned int zo; unsigned int o = 0; std::string n; is >> entity_moduletypeid; is >> entity_flags; is >> o; if (o) entity_visible = true; else entity_visible = false; 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; if (entity_model) entity_radius = model()->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; set_modelname(n); entity_dirty = false; } void Entity::serialize_client_update(std::ostream & os) const { } void Entity::receive_client_update(std::istream &is) { } void Entity::serialize_server_update(std::ostream & os) const { } void Entity::receive_server_update(std::istream &is) { } void Entity::dock(core::Entity *entity) { } void Entity::frame(float seconds) { } void Entity::add_menu(MenuDescription *menu) { entity_menus.push_back(menu); } MenuDescription *Entity::find_menu(std::string const &label) { for (Menus::iterator it = menus().begin(); it != menus().end(); it++) { if (label.compare((*it)->label()) == 0) return (*it); } return 0; } void Entity::remove_menu(std::string const &label) { for (Menus::iterator it = menus().begin(); it != menus().end(); it++) { if (label.compare((*it)->label()) == 0) menus().erase(it); return; } } /* ---- class EntityDynamic ---------------------------------------- */ EntityDynamic::EntityDynamic(unsigned int flags) : Entity(flags) { entity_state = Normal; entity_timer = 0; } EntityDynamic::EntityDynamic(std::istream & is) : Entity(is) { entity_state = Normal; entity_timer = 0; } EntityDynamic::~EntityDynamic() { } void EntityDynamic::set_state(int state) { if (this->state() != state) { entity_state = state; set_dirty(); } } void EntityDynamic::frame(float seconds) { if ((flags() & Static) == Static) return; if (entity_speed == 0) return; get_location() += axis().forward() * entity_speed * seconds; set_dirty(); } void EntityDynamic::serialize_server_create(std::ostream & os) const { Entity::serialize_server_create(os); os << roundf(entity_speed * 100.0f) << " " << entity_state << " "; if (entity_state != Normal) { os << entity_timer << " "; } } void EntityDynamic::receive_server_create(std::istream &is) { Entity::receive_server_create(is); is >> entity_speed; entity_speed /= 100.0f; is >> entity_state; if (entity_state != Normal) { is >> entity_timer; } else { entity_timer = 0; } } void EntityDynamic::serialize_client_update(std::ostream & os) const { } void EntityDynamic::receive_client_update(std::istream &is) { } void EntityDynamic::serialize_server_update(std::ostream & os) const { os << (visible() ? 1 : 0) << " "; if (visible()) { os << std::setprecision(8) << location() << " " << axis().forward() << " " << axis().left() << " " << roundf(entity_speed * 100.0f) << " " << entity_state << " "; if (entity_state != Normal) { os << entity_timer << " "; } } } void EntityDynamic::receive_server_update(std::istream &is) { unsigned int o = 0; is >> o; // visibility if (o) { set_visible(); is >> get_location(); // axis up vector is the crossproduct of forward and left is >> get_axis()[0]; is >> get_axis()[1]; get_axis()[2] = math::crossproduct(axis().forward(), axis().left()); is >> entity_speed; entity_speed /= 100.0f; is >> entity_state; if (entity_state != Normal) { is >> entity_timer; } else { entity_timer = 0; } } else { set_visible(false); } } /*----- EntityControlable ------------------------------------------ */ EntityControlable::EntityControlable(Player *owner, unsigned int flags) : EntityDynamic(flags) { entity_thrust = 0; entity_movement = 0; target_direction = 0.0f; target_thrust = 0.0f; target_pitch = 0.0f; target_roll = 0.0f; target_strafe = 0.0f; target_afterburner = 0.0f; entity_owner = 0; if (owner) owner->add_asset(this); } EntityControlable::EntityControlable(std::istream & is) : EntityDynamic(is) { entity_thrust = 0; entity_movement = 0; target_direction = 0.0f; target_thrust = 0.0f; target_pitch = 0.0f; target_roll = 0.0f; target_strafe = 0.0f; target_afterburner = 0.0f; entity_owner = 0; } EntityControlable::~EntityControlable() { if (entity_owner) entity_owner->remove_asset(this); } void EntityControlable::serialize_server_create(std::ostream & os) const { EntityDynamic::serialize_server_create(os); os << roundf(entity_thrust*100.0f) << " " << (entity_owner ? entity_owner->id() : 0) << " "; } void EntityControlable::receive_server_create(std::istream &is) { EntityDynamic::receive_server_create(is); is >> entity_thrust; entity_thrust /= 100.0f; entity_owner = 0; int owner_id = 0; is >> owner_id; if (owner_id) { for (GameInterface::Players::iterator pit = game()->players().begin(); pit != game()->players().end(); pit++) { Player *player = (*pit); if (player->id() == owner_id) { player->add_asset(this); entity_owner = player; } } if (!entity_owner) { con_warn << "could not find owner " << owner_id << " for entity " << id() << "\n"; } } } void EntityControlable::serialize_client_update(std::ostream & os) const { EntityDynamic::serialize_client_update(os); os << target_direction << " "; os << target_pitch << " "; os << target_thrust << " "; os << target_roll << " "; os << target_strafe << " "; os << target_afterburner << " "; } void EntityControlable::receive_client_update(std::istream &is) { EntityDynamic::receive_client_update(is); is >> target_direction; is >> target_pitch; is >> target_thrust; is >> target_roll; is >> target_strafe; is >> target_afterburner; } void EntityControlable::serialize_server_update(std::ostream & os) const { EntityDynamic::serialize_server_update(os); os << roundf(entity_thrust*100.0f) << " "; os << roundf(entity_movement * 100.0f) << " "; } void EntityControlable::receive_server_update(std::istream &is) { EntityDynamic::receive_server_update(is); is >> entity_thrust; entity_thrust /= 100.0f; is >> entity_movement; entity_movement /= 100.0f; } void EntityControlable::frame(float seconds) { //entity_direction = target_direction; //entity_thrust = target_thrust; //entity_dirty = true; EntityDynamic::frame(seconds); } void EntityControlable::set_thrust(float thrust) { if ((flags() & Static) == Static) return; if (thrust != target_thrust) { target_thrust = thrust; set_dirty(); } } void EntityControlable::set_direction(float direction) { if ((flags() & Static) == Static) return; if (target_direction != direction) { target_direction = direction; set_dirty(); } } void EntityControlable::set_pitch(float pitch) { if ((flags() & Static) == Static) return; if (target_pitch != pitch) { target_pitch = pitch; set_dirty(); } } void EntityControlable::set_roll(float roll) { if ((flags() & Static) == Static) return; if (target_roll != roll) { target_roll = roll; set_dirty(); } } void EntityControlable::set_strafe(float strafe) { if ((flags() & Static) == Static) return; if (target_strafe != strafe) { target_strafe = strafe; set_dirty(); } } void EntityControlable::set_afterburner(float afterburner) { if ((flags() & Static) == Static) return; if (target_afterburner != afterburner) { target_afterburner = afterburner; set_dirty(); } } /*----- EntityGlobe ------------------------------------------------ */ EntityGlobe::EntityGlobe(unsigned int flags) : Entity(flags) { render_texture = 0; entity_rotationspeed = 0; entity_shape = Sphere; } EntityGlobe::EntityGlobe(std::istream & is) : Entity(is) { render_texture = 0; entity_rotationspeed = 0; entity_shape = Sphere; } EntityGlobe::~EntityGlobe() { } void EntityGlobe::serialize_server_create(std::ostream & os) const { Entity::serialize_server_create(os); os << entity_rotationspeed << " \"" << entity_texture << "\" "; } void EntityGlobe::receive_server_create(std::istream &is) { Entity::receive_server_create(is); is >> entity_rotationspeed; std::string n; char c; while ((is.get(c)) && (c != '"')); while ((is.get(c)) && (c != '"')) n += c; entity_texture = n; n.clear(); } }