Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/game/StarEntityMap.hpp
diff options
context:
space:
mode:
authorKae <80987908+Novaenia@users.noreply.github.com>2023-06-20 14:33:09 +1000
committerKae <80987908+Novaenia@users.noreply.github.com>2023-06-20 14:33:09 +1000
commit6352e8e3196f78388b6c771073f9e03eaa612673 (patch)
treee23772f79a7fbc41bc9108951e9e136857484bf4 /source/game/StarEntityMap.hpp
parent6741a057e5639280d85d0f88ba26f000baa58f61 (diff)
everything everywhere
all at once
Diffstat (limited to 'source/game/StarEntityMap.hpp')
-rw-r--r--source/game/StarEntityMap.hpp189
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