diff options
author | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-06-20 14:33:09 +1000 |
---|---|---|
committer | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-06-20 14:33:09 +1000 |
commit | 6352e8e3196f78388b6c771073f9e03eaa612673 (patch) | |
tree | e23772f79a7fbc41bc9108951e9e136857484bf4 /source/game/StarEntityMap.hpp | |
parent | 6741a057e5639280d85d0f88ba26f000baa58f61 (diff) |
everything everywhere
all at once
Diffstat (limited to 'source/game/StarEntityMap.hpp')
-rw-r--r-- | source/game/StarEntityMap.hpp | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/source/game/StarEntityMap.hpp b/source/game/StarEntityMap.hpp new file mode 100644 index 0000000..d1adc49 --- /dev/null +++ b/source/game/StarEntityMap.hpp @@ -0,0 +1,189 @@ +#ifndef STAR_ENTITY_MAP_HPP +#define STAR_ENTITY_MAP_HPP + +#include "StarSpatialHash2D.hpp" +#include "StarEntity.hpp" + +namespace Star { + +STAR_CLASS(EntityMap); +STAR_CLASS(TileEntity); +STAR_CLASS(InteractiveEntity); + +STAR_EXCEPTION(EntityMapException, StarException); + +// Class used by WorldServer and WorldClient to store entites organized in a +// spatial hash. Provides convenient ways of querying entities based on +// different selection criteria. +// +// Several of the methods in EntityMap take callbacks or filters that will be +// called while iterating over internal structures. They are all designed so +// that adding new entities is safe to do from the callback, but removing +// entities is never safe to do from any callback function. +class EntityMap { +public: + static float const SpatialHashSectorSize; + static int const MaximumEntityBoundBox; + + // beginIdSpace and endIdSpace is the *inclusive* range for new enittyIds. + EntityMap(Vec2U const& worldSize, EntityId beginIdSpace, EntityId endIdSpace); + + // Get the next free id in the entity id space. + EntityId reserveEntityId(); + + // Add an entity to this EntityMap. The entity must already be initialized + // and have a unique EntityId returned by reserveEntityId. + void addEntity(EntityPtr entity); + EntityPtr removeEntity(EntityId entityId); + + size_t size() const; + List<EntityId> entityIds() const; + + // Iterates through the entity map optionally in the given order, updating + // the spatial information for each entity along the way. + void updateAllEntities(EntityCallback const& callback = {}, function<bool(EntityPtr const&, EntityPtr const&)> sortOrder = {}); + + // If the given unique entity is in this map, then return its entity id + EntityId uniqueEntityId(String const& uniqueId) const; + + EntityPtr entity(EntityId entityId) const; + EntityPtr uniqueEntity(String const& uniqueId) const; + + // Queries entities based on metaBoundBox + List<EntityPtr> entityQuery(RectF const& boundBox, EntityFilter const& filter = {}) const; + + // A fuzzy query of the entities at this position, sorted by closeness. + List<EntityPtr> entitiesAt(Vec2F const& pos, EntityFilter const& filter = {}) const; + + List<TileEntityPtr> entitiesAtTile(Vec2I const& pos, EntityFilterOf<TileEntity> const& filter = {}) const; + + // Sort of a fuzzy line intersection test. Tests if a given line intersects + // the bounding box of any entities, and returns them. + List<EntityPtr> entityLineQuery(Vec2F const& begin, Vec2F const& end, EntityFilter const& filter = {}) const; + + // Callback versions of query functions. + void forEachEntity(RectF const& boundBox, EntityCallback const& callback) const; + void forEachEntityLine(Vec2F const& begin, Vec2F const& end, EntityCallback const& callback) const; + // Returns tile-based entities that occupy the given tile position. + void forEachEntityAtTile(Vec2I const& pos, EntityCallbackOf<TileEntity> const& callback) const; + + // Iterate through all the entities, optionally in the given sort order. + void forAllEntities(EntityCallback const& callback, function<bool(EntityPtr const&, EntityPtr const&)> sortOrder = {}) const; + + // Stops searching when filter returns true, and returns the entity which + // caused it. + EntityPtr findEntity(RectF const& boundBox, EntityFilter const& filter) const; + EntityPtr findEntityLine(Vec2F const& begin, Vec2F const& end, EntityFilter const& filter) const; + EntityPtr findEntityAtTile(Vec2I const& pos, EntityFilterOf<TileEntity> const& filter) const; + + // Closest entity that satisfies the given selector, if given. + EntityPtr closestEntity(Vec2F const& center, float radius, EntityFilter const& filter = {}) const; + + // Returns interactive entity that is near the given world position + InteractiveEntityPtr interactiveEntityNear(Vec2F const& pos, float maxRadius = 1.5f) const; + + // Whether or not any tile entity occupies this tile + bool tileIsOccupied(Vec2I const& pos, bool includeEphemeral = false) const; + + // Intersects any entity's collision area + bool spaceIsOccupied(RectF const& rect, bool includeEphemeral = false) const; + + // Convenience template methods that filter based on dynamic cast and deal + // with pointers to a derived entity type. + + template <typename EntityT> + shared_ptr<EntityT> get(EntityId entityId) const; + + template <typename EntityT> + shared_ptr<EntityT> getUnique(String const& uniqueId) const; + + template <typename EntityT> + List<shared_ptr<EntityT>> query(RectF const& boundBox, EntityFilterOf<EntityT> const& filter = {}) const; + + template <typename EntityT> + List<shared_ptr<EntityT>> all(EntityFilterOf<EntityT> const& filter = {}) const; + + template <typename EntityT> + List<shared_ptr<EntityT>> lineQuery(Vec2F const& begin, Vec2F const& end, EntityFilterOf<EntityT> const& filter = {}) const; + + template <typename EntityT> + shared_ptr<EntityT> closest(Vec2F const& center, float radius, EntityFilterOf<EntityT> const& filter = {}) const; + + template <typename EntityT> + List<shared_ptr<EntityT>> atTile(Vec2I const& pos) const; + +private: + typedef SpatialHash2D<EntityId, float, EntityPtr> SpatialMap; + + WorldGeometry m_geometry; + + SpatialMap m_spatialMap; + BiHashMap<String, EntityId> m_uniqueMap; + + EntityId m_nextId; + EntityId m_beginIdSpace; + EntityId m_endIdSpace; + + List<SpatialMap::Entry const*> m_entrySortBuffer; +}; + +template <typename EntityT> +shared_ptr<EntityT> EntityMap::get(EntityId entityId) const { + return as<EntityT>(entity(entityId)); +} + +template <typename EntityT> +shared_ptr<EntityT> EntityMap::getUnique(String const& uniqueId) const { + return as<EntityT>(uniqueEntity(uniqueId)); +} + +template <typename EntityT> +List<shared_ptr<EntityT>> EntityMap::query(RectF const& boundBox, EntityFilterOf<EntityT> const& filter) const { + List<shared_ptr<EntityT>> entities; + for (auto const& entity : entityQuery(boundBox, entityTypeFilter(filter))) + entities.append(as<EntityT>(entity)); + + return entities; +} + +template <typename EntityT> +List<shared_ptr<EntityT>> EntityMap::all(EntityFilterOf<EntityT> const& filter) const { + List<shared_ptr<EntityT>> entities; + forAllEntities([&](EntityPtr const& entity) { + if (auto e = as<EntityT>(entity)) { + if (!filter || filter(e)) + entities.append(e); + } + }); + + return entities; +} + +template <typename EntityT> +List<shared_ptr<EntityT>> EntityMap::lineQuery(Vec2F const& begin, Vec2F const& end, EntityFilterOf<EntityT> const& filter) const { + List<shared_ptr<EntityT>> entities; + for (auto const& entity : entityLineQuery(begin, end, entityTypeFilter(filter))) + entities.append(as<EntityT>(entity)); + + return entities; +} + +template <typename EntityT> +shared_ptr<EntityT> EntityMap::closest(Vec2F const& center, float radius, EntityFilterOf<EntityT> const& filter) const { + return as<EntityT>(closestEntity(center, radius, entityTypeFilter(filter))); +} + +template <typename EntityT> +List<shared_ptr<EntityT>> EntityMap::atTile(Vec2I const& pos) const { + List<shared_ptr<EntityT>> list; + forEachEntityAtTile(pos, [&](TileEntityPtr const& entity) { + if (auto e = as<EntityT>(entity)) + list.append(move(e)); + return false; + }); + return list; +} + +} + +#endif |