From 75274ebd6ba90784f5aa837b7e5ea97fc6bfb720 Mon Sep 17 00:00:00 2001 From: Stijn Buys Date: Sat, 20 Oct 2012 16:35:26 +0000 Subject: Item id based inventory, support for weapon dealers. --- src/core/commandbuffer.cc | 9 +++++-- src/core/entity.cc | 4 +-- src/core/gameserver.cc | 4 +-- src/core/info.cc | 4 +-- src/core/inventory.cc | 48 ++++++++++++++++++++++++++++----- src/core/inventory.h | 29 +++++++++++++++----- src/core/item.cc | 22 ++++++++------- src/core/item.h | 41 +++++++++++++++++++++++++--- src/core/netconnection.cc | 68 ++++++++++++++++++++++++++++++++++++++--------- src/core/netserver.cc | 19 ++++++++++--- 10 files changed, 197 insertions(+), 51 deletions(-) (limited to 'src/core') diff --git a/src/core/commandbuffer.cc b/src/core/commandbuffer.cc index d46cc38..78b76af 100644 --- a/src/core/commandbuffer.cc +++ b/src/core/commandbuffer.cc @@ -49,10 +49,13 @@ void func_list_info(std::string const &args) std::istringstream argstream(args); if (!(argstream >> typestr)) { - // no argument, list all info records - Info::list(); + // no arguments, list info types + InfoType::list(); + con_print << " list_info [type] list all info records for a specified type" << std::endl; return; } + + aux::to_label(typestr); Info *info = 0; InfoType *infotype = InfoType::find(typestr); @@ -87,6 +90,8 @@ void func_list_info(std::string const &args) return; } + aux::to_label(labelstr); + // two arguments info = Info::find(infotype, labelstr); if (info) { diff --git a/src/core/entity.cc b/src/core/entity.cc index 825f9bf..78878f9 100644 --- a/src/core/entity.cc +++ b/src/core/entity.cc @@ -94,11 +94,11 @@ void Entity::list_inventory() const return; } - con_print << " ^Nid type label amount" << std::endl; + con_print << " ^Nitem info infotype amount" << std::endl; for (Inventory::Items::const_iterator it = entity_inventory->items().begin(); it != entity_inventory->items().end(); it++) { Item *item = (*it); con_print << " " - << " ^B" << std::setw(4) << item->info()->id() + << " ^B" << std::setw(4) << item->id() << " ^N" << aux::pad_right((item->info()->type() ? item->info()->type()->label() : "NULL"), 8) << " ^N" << aux::pad_right(item->info()->label(), 24) << std::setw(5) << item->amount() << std::endl; diff --git a/src/core/gameserver.cc b/src/core/gameserver.cc index 579f65d..796b99f 100644 --- a/src/core/gameserver.cc +++ b/src/core/gameserver.cc @@ -717,11 +717,11 @@ void GameServer::frame(const unsigned long timestamp) // send network updates server_network->frame(this->timestamp()); } - + // remove deleted entities and mark remaining entities as updated for (Entity::Registry::iterator it = Entity::registry().begin(); it != Entity::registry().end();) { // remove deleted entities - if ((*it).second->entity_destroyed) { + if ((*it).second->destroyed()) { delete (*it).second; (*it).second = 0; Entity::registry().erase(it++); diff --git a/src/core/info.cc b/src/core/info.cc index 8e286dc..dbe4c76 100644 --- a/src/core/info.cc +++ b/src/core/info.cc @@ -91,9 +91,9 @@ Info::Info(const unsigned int id) info_type = 0; info_registry.push_back(this); - info_price = 0; - info_timestamp = 1; + info_price = 0; + info_volume = 0; add_text("Requesting server information..."); } diff --git a/src/core/inventory.cc b/src/core/inventory.cc index 28327a3..c10e1c6 100644 --- a/src/core/inventory.cc +++ b/src/core/inventory.cc @@ -16,6 +16,7 @@ namespace core Inventory::Inventory(const float capacity) { inventory_timestamp = 0; + inventory_timestamp_erase = 0; inventory_capacity = capacity; inventory_capacity_used = 0; inventory_dirty = false; @@ -25,6 +26,7 @@ Inventory::~Inventory() { clear(); inventory_timestamp = 0; + inventory_timestamp_erase = 0; inventory_capacity = 0; inventory_capacity_used = 0; } @@ -48,24 +50,45 @@ void Inventory::set_dirty(const bool dirty) void Inventory::add(Item *item) { + assert(item != (Item *) 0x81); + + // assign an id + unsigned int id = 0; for (Items::iterator it = inventory_items.begin(); it != inventory_items.end(); it++) { - // check if the item was already added - if ((*it) == item) - return; + if ((*it)->id() > id) { + id = (*it)->id(); + } } + id++; + item->set_id(id); + inventory_items.push_back(item); } -void Inventory::remove(Item *item) +void Inventory::erase(Item *item) { for (Items::iterator it = inventory_items.begin(); it != inventory_items.end(); it++) { if ((*it) == item) { + delete (*it); + (*it) = 0; + inventory_items.erase(it); + inventory_timestamp_erase = (game() ? game()->timestamp() : 1); + return; + } + } +} + +void Inventory::erase(const unsigned int id) +{ + for (Items::iterator it = inventory_items.begin(); it != inventory_items.end(); it++) { + if ((*it)->id() == id) { + delete (*it); + (*it) = 0; inventory_items.erase(it); - delete item; + inventory_timestamp_erase = (game() ? game()->timestamp() : 1); return; } } - // FIXME remove doesn't work over network } Item *Inventory::find(const Info *info) const @@ -81,6 +104,19 @@ Item *Inventory::find(const Info *info) const return 0; } +Item *Inventory::find(const unsigned int id) const +{ + // sarch the inventory for a specified item id + for (Items::const_iterator it = inventory_items.begin(); it != inventory_items.end(); it++) { + Item *item = (*it); + if (item->id() == id) { + return item; + } + } + // not found + return 0; +} + void Inventory::clear() { for (Items::iterator it = inventory_items.begin(); it != inventory_items.end(); it++) { diff --git a/src/core/inventory.h b/src/core/inventory.h index 80dbde1..3c3adfa 100644 --- a/src/core/inventory.h +++ b/src/core/inventory.h @@ -23,7 +23,7 @@ public: /** * @brief type definition for items in the inventory */ - typedef std::vector Items; + typedef std::list Items; /** * @brief default constructor @@ -45,13 +45,20 @@ public: }; /** - * @brief return the timestamp of the last server update - * This is a client-side property and shoul not be used server-side + * @brief return the timestamp of the last client-side update + * This is a client-side property */ inline const unsigned long timestamp() const { return inventory_timestamp; } + /** + * @brief return the timestamp of the last item erase + * */ + inline const unsigned long timestamp_erase() const { + return inventory_timestamp_erase; + } + /** * @brief return the maximal inventory capacity, in cubic meters */ @@ -89,6 +96,11 @@ public: * @brief search the inventory for a specific item type */ Item *find(const Info *info) const; + + /** + * @brief search the inventory for a specific item id + */ + Item *find(const unsigned int id) const; /* ---- mutators --------------------------------------------------- */ @@ -98,9 +110,12 @@ public: void add(Item *item); /** - * @brief remove an item from the inventory and delete it + * @brief erase an item from the inventory + * This will call the Item's destructor */ - void remove(Item *item); + void erase(Item *item); + + void erase(const unsigned int id); /** * @brief removes all items from the inventory and delete them @@ -135,8 +150,10 @@ private: // items in the inventory Items inventory_items; - // timestamp when inventory was last updated + // timestamp, last time the inventory was updated unsigned long inventory_timestamp; + // timestamp, last time there was an item deleted from the inventory + unsigned long inventory_timestamp_erase; // maximum inventory capacity, in cubic meters float inventory_capacity; diff --git a/src/core/item.cc b/src/core/item.cc index f6e0382..b6e5bd8 100644 --- a/src/core/item.cc +++ b/src/core/item.cc @@ -24,27 +24,29 @@ Item::Item(const Info *info) item_info = info; item_amount = 0; item_flags = 0; + item_id = 0; item_price = info->price(); set_timestamp(game() ? game()->timestamp() : 1); } -Item::Item(const Item &other) -{ - item_info = other.info(); - item_amount = other.amount(); - item_flags = other.flags(); - item_price = other.price(); - item_dirty = other.dirty(); - set_timestamp(game() ? game()->timestamp() : 1); -} - Item::~Item() { item_info = 0; item_amount = 0; item_flags = 0; item_price = 0; + item_id = 0; +} + +void Item::set_info(const Info *info) +{ + item_info = info; +} + +void Item::set_id(const unsigned int id) +{ + item_id = id; } void Item::set_amount(const long amount) diff --git a/src/core/item.h b/src/core/item.h index 6c99270..ec0d6be 100644 --- a/src/core/item.h +++ b/src/core/item.h @@ -23,13 +23,15 @@ public: Item(const Info *info); - /// copy constructor - Item(const Item &other); - ~Item(); /* ---- inspectors --------------------------------------------- */ + /** + * @brief returns the item id + * */ + inline unsigned int id() const { return item_id; } + /** * @brief associated amount */ @@ -68,6 +70,13 @@ public: return ((item_flags & (unsigned int) flag) == (unsigned int) flag); } + /** + * @brief returns true if the Unique flag is set + */ + inline const bool unique() const { + return ((item_flags & (unsigned int) Unique) == (unsigned int) Unique); + } + /** * @brief return true if the dirty flag is set * */ @@ -76,6 +85,21 @@ public: } /* ---- mutators ----------------------------------------------- */ + + /** + * @brief set item id + * This should never be called from within the game module, + * it is used by Inventory to keep track of unique items + */ + void set_id(const unsigned int id); + + /** + * @brief set item info + * This should never be called from within the game module, + * it essentially changes the item type and is used by NetConnection + * for inventory householding. + */ + void set_info(const Info *info); /** * @brief set associated amount @@ -97,6 +121,13 @@ public: */ void set_price(const long price); + /** + * @brief set all item flags + */ + inline void set_flags(const unsigned int flags) { + item_flags = flags; + } + /** * @brief set item flag */ @@ -115,7 +146,7 @@ public: * @brief set the dirty flag * */ inline void set_dirty(const bool dirty = true) { - item_dirty = true; + item_dirty = dirty; } /* ---- serializers -------------------------------------------- */ @@ -136,6 +167,8 @@ private: unsigned int item_flags; bool item_dirty; + + unsigned int item_id; }; } // namespace core diff --git a/src/core/netconnection.cc b/src/core/netconnection.cc index 3c68be9..24f6a3d 100644 --- a/src/core/netconnection.cc +++ b/src/core/netconnection.cc @@ -754,7 +754,7 @@ void NetConnection::parse_incoming_message(const std::string & message) oldzone->content().clear(); } - // short "pif" message about a different player + // short "pif" message about a different player } else if (player_id != localplayer()->id()) { // find player @@ -895,49 +895,91 @@ void NetConnection::parse_incoming_message(const std::string & message) } else if (command.compare("inv") == 0) { // received inventory update - unsigned int id = 0; + unsigned int entity_id = 0; unsigned long server_timestamp; - // read id - if (!(msgstream >> id >> server_timestamp)) { + // read entity id and server timestamp + if (!(msgstream >> entity_id >> server_timestamp)) { con_warn << "Received invalid inventory update message!" << std::endl; return; } - Entity *entity = Entity::find(id); + Entity *entity = Entity::find(entity_id); if (!entity) { - con_warn << "Received inventory update for non-existing entity " << id << "!" << std::endl; + con_warn << "Received inventory update for non-existing entity " << entity_id << "!" << std::endl; return; } if (!entity->inventory()) { - con_warn << "Received inventory update for entity " << id << " without inventory!" << std::endl; + con_warn << "Received inventory update for entity " << entity_id << " without inventory!" << std::endl; return; } - //con_debug << "CLIENT received inv message for entity " << id << " client timestamp " << entity->inventory()->timestamp() << " server timestamp " << server_timestamp << std::endl; - if (server_timestamp < entity->inventory()->timestamp()) return; + unsigned int item_id = 0; + unsigned int info_id = 0; + + int full_update = 0; + if (!(msgstream >> full_update)) { + con_warn << "Received inventory update for entity " << entity_id << " without full update marker!" << std::endl; + return; + } + + if (full_update == 1) { + // mark all items dirty + for (Inventory::Items::iterator it = entity->inventory()->items().begin(); it != entity->inventory()->items().end(); ++it) { + (*it)->set_dirty(); + } + } + size_t nbitems = 0; if (!(msgstream >> nbitems)) nbitems = 0; //con_debug << "CLIENT number of items: " << nbitems << std::endl; + // receive item updates for (size_t i = 0; i < nbitems; i++) { - if (!(msgstream >> id)) { - con_warn << "Received inventory update without info id for existing entity " << id << "!" << std::endl; + // read item id + if (!(msgstream >> item_id)) { + con_warn << "Received inventory item update for entity " << entity_id << " without item id!" << std::endl; + return; + } + // read info id + if (!(msgstream >> info_id)) { + con_warn << "Received inventory item update for entity " << entity_id << " without info id!" << std::endl; return; } - Info *info = core::game()->request_info(id); - Item *item = entity->inventory()->find(info); + Info *info = core::game()->request_info(info_id); + Item *item = entity->inventory()->find(item_id); if (!item) { item = new Item(info); entity->inventory()->add(item); + item->set_id(item_id); + } else { + if (item->info() != info) { + item->set_info(info); + } } item->receive_server_update(msgstream); + item->set_dirty(false); } + + if (full_update == 1) { + // remove items for which no update was received + for (Inventory::Items::iterator it = entity->inventory()->items().begin(); it != entity->inventory()->items().end();) { + Item *item = (*it); + if (item->dirty()) { + delete (item); + (*it) = 0; + entity->inventory()->items().erase(it++); + } else { + ++it; + } + } + } + entity->inventory()->recalculate(); entity->inventory()->set_timestamp(server_timestamp); diff --git a/src/core/netserver.cc b/src/core/netserver.cc index 81bd303..9fb5f78 100644 --- a/src/core/netserver.cc +++ b/src/core/netserver.cc @@ -667,16 +667,27 @@ void NetServer::send_inventory_update(NetClient *client, Entity *entity, const u if (!entity || !entity->inventory()) return; + // send message header std::ostringstream msg; msg << "inv " << entity->id() << " " << game()->timestamp() << " "; - size_t nbitems = 0; + // send full update marker + bool send_full_update = false; + if (entity->inventory()->timestamp_erase() >= timestamp) { + send_full_update = true; + msg << "1 "; + } else { + send_full_update = false; + msg << "0 "; + } + // send items + size_t nbitems = 0; std::ostringstream itemstr; for (Inventory::Items::const_iterator it = entity->inventory()->items().begin(); it != entity->inventory()->items().end(); it++) { const Item *item = (*it); - if (item->timestamp() >= timestamp) { - itemstr << item->info()->id() << " "; + if (send_full_update || (item->timestamp() >= timestamp)) { + itemstr << item->id() << " " << item->info()->id() << " "; item->serialize_server_update(itemstr); nbitems++; } @@ -733,7 +744,7 @@ void NetServer::parse_incoming_message(NetClient *client, const std::string & me unsigned int protover; if (msgstream >> protover) { if (protover != PROTOCOLVERSION) { - // set protocol version mismatch notification + // send protocol version mismatch notification std::stringstream netmsgstream(""); netmsgstream << "^WProtocol version mismatch: "; netmsgstream << "client " << protover << " server " << PROTOCOLVERSION << "!\n"; -- cgit v1.2.3