File Entity.hpp
File List > core > Entity.hpp
Go to the documentation of this file
#pragma once
#include <algorithm>
#include <cassert>
#include <istream>
#include <memory>
#include <ostream>
#include <string>
#include <unordered_map>
#include <vector>
#include "CoreObject.hpp"
#include "Data.hpp"
#include "GridPosition.hpp"
#include "Property.hpp"
namespace cse491 {
class WorldBase;
class Entity : public CoreObject {
private:
WorldBase *world_ptr = nullptr;
protected:
size_t id = 0;
std::string name = "";
size_t grid_id = 0;
GridPosition position;
std::vector<size_t> inventory;
using property_map_t = std::unordered_map<std::string, std::unique_ptr<PropertyBase>>;
property_map_t property_map;
// -- Helper Functions --
template <typename T>
Property<T> &AsProperty(const std::string &name) const {
assert(HasProperty(name));
PropertyBase *raw_ptr = property_map.at(name).get();
assert(dynamic_cast<Property<T> *>(raw_ptr));
auto property_ptr = static_cast<Property<T> *>(raw_ptr);
return *property_ptr;
}
public:
Entity(size_t id, const std::string &name) : id(id), name(name) {}
Entity(const Entity &) = delete; // Entities must be unique and shouldn't be copied.
Entity(Entity &&) = default;
virtual ~Entity() = default;
Entity &operator=(const Entity &) = delete; // Entities must be unique and shouldn't be copied.
Entity &operator=(Entity &&) = delete; // Entities should never have IDs change.
// -- Accessors --
[[nodiscard]] size_t GetID() const { return id; }
[[nodiscard]] const std::string &GetName() const { return name; }
[[nodiscard]] GridPosition GetPosition() const { return position; }
[[nodiscard]] WorldBase &GetWorld() const {
assert(world_ptr);
return *world_ptr;
}
[[nodiscard]] size_t GetGridID() const { return grid_id; }
[[nodiscard]] bool IsOnGrid(size_t in_grid_id) const { return grid_id == in_grid_id; }
[[nodiscard]] bool HasWorld() const { return world_ptr != nullptr; }
Entity &SetName(const std::string in_name) {
name = in_name;
return *this;
}
Entity &SetPosition(GridPosition in_pos, size_t grid_id = 0);
Entity &SetPosition(double x, double y) {
position = GridPosition{x, y};
return *this;
}
virtual Entity &SetWorld(WorldBase &in_world) {
world_ptr = &in_world;
return *this;
}
virtual bool IsAgent() const { return false; }
virtual bool IsItem() const { return false; }
virtual bool IsInterface() const { return false; }
// -- Property Management --
[[nodiscard]] bool HasProperty(const std::string &name) const { return property_map.count(name); }
[[nodiscard]] size_t GetNumProperties() const { return property_map.size(); }
template <typename T = double>
[[nodiscard]] const T &GetProperty(const std::string &name) const {
assert(HasProperty(name)); // Break if property does not already exist.
return AsProperty<T>(name).value;
}
[[nodiscard]] PropertyType GetPropertyType(const std::string &name) const {
auto it = property_map.find(name);
if (it == property_map.end()) return PropertyType::t_other;
return it->second->GetType();
}
template <typename T>
Entity &SetProperty(const std::string &name, const T &value) {
if (HasProperty(name)) {
AsProperty<T>(name).value = value;
} else {
property_map[name] = std::make_unique<Property<T>>(value);
}
return *this;
}
Entity &SetProperties() { return *this; }
template <typename VALUE_T, typename... EXTRA_Ts>
Entity &SetProperties(const std::string &name, VALUE_T &&value, EXTRA_Ts &&...extras) {
SetProperty(name, std::forward<VALUE_T>(value)); // Set the first property...
return SetProperties(std::forward<EXTRA_Ts>(extras)...); // And any additional properties...
}
Entity &RemoveProperty(const std::string &name) {
property_map.erase(name);
return *this;
}
property_map_t &GetPropertyMap() {
return property_map;
}
bool HasItem(size_t id) const {
return std::find(inventory.begin(), inventory.end(), id) != inventory.end();
}
Entity &AddItem(size_t id);
Entity &AddItem(Entity &item) { return AddItem(item.GetID()); }
Entity &RemoveItem(size_t id);
Entity &RemoveItem(Entity &item) { return RemoveItem(item.GetID()); }
void Serialize_impl(std::ostream &os) const override {
SerializeValue(os, id);
SerializeValue(os, name);
SerializeValue(os, grid_id);
SerializeValue(os, position);
SerializeValue(os, inventory);
SerializeValue(os, property_map.size());
for (const auto & [name, ptr] : property_map) {
SerializeValue(os, name);
SerializeValue(os, ptr->GetType());
SerializeValue(os, ptr->ToString());
}
}
void Deserialize_impl(std::istream &is) override {
DeserializeValue(is, id);
DeserializeValue(is, name);
DeserializeValue(is, grid_id);
DeserializeValue(is, position);
DeserializeValue(is, inventory);
size_t num_properties = 0;
property_map.clear();
std::string name;
PropertyType type;
DeserializeValue(is, num_properties);
for (size_t i = 0; i < num_properties; ++i) {
DeserializeValue(is, name);
DeserializeValue(is, type);
switch (type) {
using enum PropertyType;
case t_char: SetProperty(name, DeserializeAs<char>(is)); break;
case t_double: SetProperty(name, DeserializeAs<double>(is)); break;
case t_int: SetProperty(name, DeserializeAs<int>(is)); break;
case t_bool: SetProperty(name, DeserializeAs<bool>(is)); break;
case t_string: SetProperty(name, DeserializeAs<std::string>(is)); break;
case t_position: SetProperty(name, DeserializeAs<GridPosition>(is)); break;
case t_other:
std::cerr << "Warning: Cannot deserialize property'" << name << "'." << std::endl;
std::string tmp_str;
std::getline(is, tmp_str, '\n');
std::cerr << " Data for that property: \"" << tmp_str << "\"." << std::endl;
}
}
}
[[nodiscard]] std::vector<size_t> GetInventory() const { return inventory; }
};
} // End of namespace cse491