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

summaryrefslogtreecommitdiff
path: root/source/game/StarEntityMap.hpp
blob: f428fea6fbb7f8b468d0fb8a7f4643287b7123f0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#pragma once

#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();
  // Or a specific one, can fail.
  Maybe<EntityId> maybeReserveEntityId(EntityId entityId);
  // If it doesn't matter that we don't get the one want
  EntityId reserveEntityId(EntityId entityId);

  // 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(std::move(e));
      return false;
    });
  return list;
}

}