Skip to main content
added 4 characters in body; edited tags
Source Link
Jamal
  • 34.9k
  • 13
  • 133
  • 237

Items are stored in an ItemDatabaseItemDatabase after being read from a JSON file.

Therefore, I want to start returning deep copies as std::unique_ptrsstd::unique_ptrs because each Item is unique and is possessed by only one entity. This avoids dangerous dangling pointers, if the Item is not maintained or destroyed by the caller:

Items are stored in an ItemDatabase after being read from a JSON file.

Therefore, I want to start returning deep copies as std::unique_ptrs because each Item is unique and is possessed by only one entity. This avoids dangerous dangling pointers, if the Item is not maintained or destroyed by the caller:

Items are stored in an ItemDatabase after being read from a JSON file.

Therefore, I want to start returning deep copies as std::unique_ptrs because each Item is unique and is possessed by only one entity. This avoids dangerous dangling pointers, if the Item is not maintained or destroyed by the caller:

Rollback to Revision 1
Source Link
Jamal
  • 34.9k
  • 13
  • 133
  • 237

Edit:

Some of the assumptions made by Yuushi are correct and I wish to state them here:

EntityDatabase is the base class for all Databases such as ItemDatabase. It contains raw pointers to objects created after reading the appropriate Json-File.

template <typename DataType>
class EntityDatabase
{
public:
    typedef std::map<EntityId, DataType*> Container;

Loading happens in the derived Databases, for example the loading of Items including Armor, Weapons, Consumables:

class ItemDatabase : public EntityDatabase<Item>
{
public:
    static void load();

    template <typename ItemType>
    static void load(std::string const& filename)
    {
        PropertyTree propertyTree;
        boost::property_tree::read_json(filename, propertyTree);
    
        for (auto& jsonItem : propertyTree)
        {
            Item *item = new ItemType();
            item->fromJson(jsonItem);

            database_[item->id()] = item;
        }
    }

Further, Weapon, Armor, Consumable are all of type Item:

class Item
{
    Item();
    virtual ~Item();
    //....
}

class Weapon : public Item
{ 
    //...
}

class Armor : public Item
{
    //...
}

ItemDatabase::find() returns a unique_ptr<Item>, a deep copy of the pointer object to be owned by only one person:

static std::unique_ptr<Item> find(EntityId const& id)
{
    auto item = database_.find(id);
    if (item != std::end(database_))
        return std::unique_ptr<Item>(new Item(**item));
    else
        return nullptr;
}

The Inventory class I showed whose weapon_ and armor_ fields must be set looks like this:

class Inventory : public JsonObject
{
public:
    Inventory();
    ~Inventory();

    virtual void fromJson(PropertyTree::value_type const& properties) override;
    virtual void toJson(PropertyTree& propertyTree);

    void equipWeapon(Weapon *weapon);
    void removeWeapon();
    std::shared_ptr<Weapon> weapon() const;

    void equipArmor(Armor *armor);
    void removeArmor();
    std::shared_ptr<Armor> armor() const;

    void pickUpItem(Item *item);
    std::shared_ptr<Item> dropItem(Item *item);
    void destroyItem(Item *item);

    std::shared_ptr<Item> getItem(Item *item);
    std::shared_ptr<Item> findItem(std::string const& name);
    bool hasItem(Item *item);

    void earnMoney(Money amount);
    void spendMoney(Money amount);
    Money money() const;

    size_t size() const;

    friend std::ostream& operator<<(std::ostream& os, Inventory const& inventory);

private:
    bool isBeingUsedAsAWeapon(Item *item) const;
    bool isBeingUsedAsArmor(Item *item) const;

private:
    std::shared_ptr<Weapon> weapon_;
    std::shared_ptr<Armor> armor_;
    std::vector<std::shared_ptr<Item>> inventory_;

    Money money_;
};

Wherein an Item only of type Weapon can be equipped as a weapon, but both Weapon and Armor must be displayed and kept in the inventory.

Edit:

Some of the assumptions made by Yuushi are correct and I wish to state them here:

EntityDatabase is the base class for all Databases such as ItemDatabase. It contains raw pointers to objects created after reading the appropriate Json-File.

template <typename DataType>
class EntityDatabase
{
public:
    typedef std::map<EntityId, DataType*> Container;

Loading happens in the derived Databases, for example the loading of Items including Armor, Weapons, Consumables:

class ItemDatabase : public EntityDatabase<Item>
{
public:
    static void load();

    template <typename ItemType>
    static void load(std::string const& filename)
    {
        PropertyTree propertyTree;
        boost::property_tree::read_json(filename, propertyTree);
    
        for (auto& jsonItem : propertyTree)
        {
            Item *item = new ItemType();
            item->fromJson(jsonItem);

            database_[item->id()] = item;
        }
    }

Further, Weapon, Armor, Consumable are all of type Item:

class Item
{
    Item();
    virtual ~Item();
    //....
}

class Weapon : public Item
{ 
    //...
}

class Armor : public Item
{
    //...
}

ItemDatabase::find() returns a unique_ptr<Item>, a deep copy of the pointer object to be owned by only one person:

static std::unique_ptr<Item> find(EntityId const& id)
{
    auto item = database_.find(id);
    if (item != std::end(database_))
        return std::unique_ptr<Item>(new Item(**item));
    else
        return nullptr;
}

The Inventory class I showed whose weapon_ and armor_ fields must be set looks like this:

class Inventory : public JsonObject
{
public:
    Inventory();
    ~Inventory();

    virtual void fromJson(PropertyTree::value_type const& properties) override;
    virtual void toJson(PropertyTree& propertyTree);

    void equipWeapon(Weapon *weapon);
    void removeWeapon();
    std::shared_ptr<Weapon> weapon() const;

    void equipArmor(Armor *armor);
    void removeArmor();
    std::shared_ptr<Armor> armor() const;

    void pickUpItem(Item *item);
    std::shared_ptr<Item> dropItem(Item *item);
    void destroyItem(Item *item);

    std::shared_ptr<Item> getItem(Item *item);
    std::shared_ptr<Item> findItem(std::string const& name);
    bool hasItem(Item *item);

    void earnMoney(Money amount);
    void spendMoney(Money amount);
    Money money() const;

    size_t size() const;

    friend std::ostream& operator<<(std::ostream& os, Inventory const& inventory);

private:
    bool isBeingUsedAsAWeapon(Item *item) const;
    bool isBeingUsedAsArmor(Item *item) const;

private:
    std::shared_ptr<Weapon> weapon_;
    std::shared_ptr<Armor> armor_;
    std::vector<std::shared_ptr<Item>> inventory_;

    Money money_;
};

Wherein an Item only of type Weapon can be equipped as a weapon, but both Weapon and Armor must be displayed and kept in the inventory.

added 2868 characters in body
Source Link
IAE
  • 765
  • 5
  • 13

Edit:

Some of the assumptions made by Yuushi are correct and I wish to state them here:

EntityDatabase is the base class for all Databases such as ItemDatabase. It contains raw pointers to objects created after reading the appropriate Json-File.

template <typename DataType>
class EntityDatabase
{
public:
    typedef std::map<EntityId, DataType*> Container;

Loading happens in the derived Databases, for example the loading of Items including Armor, Weapons, Consumables:

class ItemDatabase : public EntityDatabase<Item>
{
public:
    static void load();

    template <typename ItemType>
    static void load(std::string const& filename)
    {
        PropertyTree propertyTree;
        boost::property_tree::read_json(filename, propertyTree);
    
        for (auto& jsonItem : propertyTree)
        {
            Item *item = new ItemType();
            item->fromJson(jsonItem);

            database_[item->id()] = item;
        }
    }

Further, Weapon, Armor, Consumable are all of type Item:

class Item
{
    Item();
    virtual ~Item();
    //....
}

class Weapon : public Item
{ 
    //...
}

class Armor : public Item
{
    //...
}

ItemDatabase::find() returns a unique_ptr<Item>, a deep copy of the pointer object to be owned by only one person:

static std::unique_ptr<Item> find(EntityId const& id)
{
    auto item = database_.find(id);
    if (item != std::end(database_))
        return std::unique_ptr<Item>(new Item(**item));
    else
        return nullptr;
}

The Inventory class I showed whose weapon_ and armor_ fields must be set looks like this:

class Inventory : public JsonObject
{
public:
    Inventory();
    ~Inventory();

    virtual void fromJson(PropertyTree::value_type const& properties) override;
    virtual void toJson(PropertyTree& propertyTree);

    void equipWeapon(Weapon *weapon);
    void removeWeapon();
    std::shared_ptr<Weapon> weapon() const;

    void equipArmor(Armor *armor);
    void removeArmor();
    std::shared_ptr<Armor> armor() const;

    void pickUpItem(Item *item);
    std::shared_ptr<Item> dropItem(Item *item);
    void destroyItem(Item *item);

    std::shared_ptr<Item> getItem(Item *item);
    std::shared_ptr<Item> findItem(std::string const& name);
    bool hasItem(Item *item);

    void earnMoney(Money amount);
    void spendMoney(Money amount);
    Money money() const;

    size_t size() const;

    friend std::ostream& operator<<(std::ostream& os, Inventory const& inventory);

private:
    bool isBeingUsedAsAWeapon(Item *item) const;
    bool isBeingUsedAsArmor(Item *item) const;

private:
    std::shared_ptr<Weapon> weapon_;
    std::shared_ptr<Armor> armor_;
    std::vector<std::shared_ptr<Item>> inventory_;

    Money money_;
};

Wherein an Item only of type Weapon can be equipped as a weapon, but both Weapon and Armor must be displayed and kept in the inventory.

Edit:

Some of the assumptions made by Yuushi are correct and I wish to state them here:

EntityDatabase is the base class for all Databases such as ItemDatabase. It contains raw pointers to objects created after reading the appropriate Json-File.

template <typename DataType>
class EntityDatabase
{
public:
    typedef std::map<EntityId, DataType*> Container;

Loading happens in the derived Databases, for example the loading of Items including Armor, Weapons, Consumables:

class ItemDatabase : public EntityDatabase<Item>
{
public:
    static void load();

    template <typename ItemType>
    static void load(std::string const& filename)
    {
        PropertyTree propertyTree;
        boost::property_tree::read_json(filename, propertyTree);
    
        for (auto& jsonItem : propertyTree)
        {
            Item *item = new ItemType();
            item->fromJson(jsonItem);

            database_[item->id()] = item;
        }
    }

Further, Weapon, Armor, Consumable are all of type Item:

class Item
{
    Item();
    virtual ~Item();
    //....
}

class Weapon : public Item
{ 
    //...
}

class Armor : public Item
{
    //...
}

ItemDatabase::find() returns a unique_ptr<Item>, a deep copy of the pointer object to be owned by only one person:

static std::unique_ptr<Item> find(EntityId const& id)
{
    auto item = database_.find(id);
    if (item != std::end(database_))
        return std::unique_ptr<Item>(new Item(**item));
    else
        return nullptr;
}

The Inventory class I showed whose weapon_ and armor_ fields must be set looks like this:

class Inventory : public JsonObject
{
public:
    Inventory();
    ~Inventory();

    virtual void fromJson(PropertyTree::value_type const& properties) override;
    virtual void toJson(PropertyTree& propertyTree);

    void equipWeapon(Weapon *weapon);
    void removeWeapon();
    std::shared_ptr<Weapon> weapon() const;

    void equipArmor(Armor *armor);
    void removeArmor();
    std::shared_ptr<Armor> armor() const;

    void pickUpItem(Item *item);
    std::shared_ptr<Item> dropItem(Item *item);
    void destroyItem(Item *item);

    std::shared_ptr<Item> getItem(Item *item);
    std::shared_ptr<Item> findItem(std::string const& name);
    bool hasItem(Item *item);

    void earnMoney(Money amount);
    void spendMoney(Money amount);
    Money money() const;

    size_t size() const;

    friend std::ostream& operator<<(std::ostream& os, Inventory const& inventory);

private:
    bool isBeingUsedAsAWeapon(Item *item) const;
    bool isBeingUsedAsArmor(Item *item) const;

private:
    std::shared_ptr<Weapon> weapon_;
    std::shared_ptr<Armor> armor_;
    std::vector<std::shared_ptr<Item>> inventory_;

    Money money_;
};

Wherein an Item only of type Weapon can be equipped as a weapon, but both Weapon and Armor must be displayed and kept in the inventory.

Tweeted twitter.com/#!/StackCodeReview/status/318405904074694660
Source Link
IAE
  • 765
  • 5
  • 13
Loading