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
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
|
#pragma once
#include "StarTileEntity.hpp"
#include "StarInteractionTypes.hpp"
#include "StarCollisionBlock.hpp"
#include "StarForceRegions.hpp"
#include "StarWorldGeometry.hpp"
#include "StarTileModification.hpp"
#include "StarLuaRoot.hpp"
#include "StarRpcPromise.hpp"
namespace Star {
STAR_CLASS(World);
STAR_CLASS(TileEntity);
STAR_CLASS(ScriptedEntity);
typedef function<void(World*)> WorldAction;
class World {
public:
virtual ~World() {}
// Will remain constant throughout the life of the world.
virtual ConnectionId connection() const = 0;
virtual WorldGeometry geometry() const = 0;
// Update frame counter. Returns the frame that is *currently* being
// updated, not the *last* frame, so during the first call to update(), this
// would return 1
virtual uint64_t currentStep() const = 0;
// All methods that take int parameters wrap around or clamp so that all int
// values are valid world indexes.
virtual MaterialId material(Vec2I const& position, TileLayer layer) const = 0;
virtual MaterialHue materialHueShift(Vec2I const& position, TileLayer layer) const = 0;
virtual ModId mod(Vec2I const& position, TileLayer layer) const = 0;
virtual MaterialHue modHueShift(Vec2I const& position, TileLayer layer) const = 0;
virtual MaterialColorVariant colorVariant(Vec2I const& position, TileLayer layer) const = 0;
virtual LiquidLevel liquidLevel(Vec2I const& pos) const = 0;
virtual LiquidLevel liquidLevel(RectF const& region) const = 0;
// Tests a tile modification list and returns the ones that are valid.
virtual TileModificationList validTileModifications(TileModificationList const& modificationList, bool allowEntityOverlap) const = 0;
// Apply a list of tile modifications in the best order to apply as many
// possible, and returns the modifications that could not be applied.
virtual TileModificationList applyTileModifications(TileModificationList const& modificationList, bool allowEntityOverlap) = 0;
// Swap existing tiles for ones defined in the modification list,
// and returns the modifications that could not be applied.
virtual TileModificationList replaceTiles(TileModificationList const& modificationList, TileDamage const& tileDamage, bool applyDamage = false) = 0;
// If an applied damage would destroy a tile
virtual bool damageWouldDestroy(Vec2I const& pos, TileLayer layer, TileDamage const& tileDamage) const = 0;
virtual bool isTileProtected(Vec2I const& pos) const = 0;
virtual EntityPtr entity(EntityId entityId) const = 0;
// *If* the entity is initialized immediately and locally, then will use the
// passed in pointer directly and initialize it, and entity will have a valid
// id in this world and be ready for use. This is always the case on the
// server, but not *always* the case on the client.
virtual void addEntity(EntityPtr const& entity, EntityId entityId = NullEntityId) = 0;
virtual EntityPtr closestEntity(Vec2F const& center, float radius, EntityFilter selector = {}) const = 0;
virtual void forAllEntities(EntityCallback entityCallback) const = 0;
// Query here is a fuzzy query based on metaBoundBox
virtual void forEachEntity(RectF const& boundBox, EntityCallback entityCallback) const = 0;
// Fuzzy metaBoundBox query for intersecting the given line.
virtual void forEachEntityLine(Vec2F const& begin, Vec2F const& end, EntityCallback entityCallback) const = 0;
// Performs action for all entities that occupies the given tile position
// (only entity types laid out in the tile grid).
virtual void forEachEntityAtTile(Vec2I const& pos, EntityCallbackOf<TileEntity> entityCallback) const = 0;
// Like forEachEntity, but stops scanning when entityFilter returns true, and
// returns the EntityPtr found, otherwise returns a null pointer.
virtual EntityPtr findEntity(RectF const& boundBox, EntityFilter entityFilter) const = 0;
virtual EntityPtr findEntityLine(Vec2F const& begin, Vec2F const& end, EntityFilter entityFilter) const = 0;
virtual EntityPtr findEntityAtTile(Vec2I const& pos, EntityFilterOf<TileEntity> entityFilter) const = 0;
// Is the given tile layer and position occupied by an entity or block?
virtual bool tileIsOccupied(Vec2I const& pos, TileLayer layer, bool includeEphemeral = false, bool checkCollision = false) const = 0;
// Returns the collision kind of a tile.
virtual CollisionKind tileCollisionKind(Vec2I const& pos) const = 0;
// Iterate over the collision block for each tile in the region. Collision
// polys for tiles can extend to a maximum of 1 tile outside of the natural
// tile bounds.
virtual void forEachCollisionBlock(RectI const& region, function<void(CollisionBlock const&)> const& iterator) const = 0;
// Is there some connectable tile / tile based entity in this position? If
// tilesOnly is true, only checks to see whether that tile is a connectable
// material.
virtual bool isTileConnectable(Vec2I const& pos, TileLayer layer, bool tilesOnly = false) const = 0;
// Returns whether or not a given point is inside any colliding tile. If
// collisionSet is Dynamic or Static, then does not intersect with platforms.
virtual bool pointTileCollision(Vec2F const& point, CollisionSet const& collisionSet = DefaultCollisionSet) const = 0;
// Returns whether line intersects with any colliding tiles.
virtual bool lineTileCollision(Vec2F const& begin, Vec2F const& end, CollisionSet const& collisionSet = DefaultCollisionSet) const = 0;
virtual Maybe<pair<Vec2F, Vec2I>> lineTileCollisionPoint(Vec2F const& begin, Vec2F const& end, CollisionSet const& collisionSet = DefaultCollisionSet) const = 0;
// Returns a list of all the collidable tiles along the given line.
virtual List<Vec2I> collidingTilesAlongLine(Vec2F const& begin, Vec2F const& end, CollisionSet const& collisionSet = DefaultCollisionSet, int maxSize = -1, bool includeEdges = true) const = 0;
// Returns whether the given rect contains any colliding tiles.
virtual bool rectTileCollision(RectI const& region, CollisionSet const& collisionSet = DefaultCollisionSet) const = 0;
// Damage multiple tiles, avoiding duplication (objects or plants that occupy
// more than one tile
// position are only damaged once)
virtual TileDamageResult damageTiles(List<Vec2I> const& tilePositions, TileLayer layer, Vec2F const& sourcePosition, TileDamage const& tileDamage, Maybe<EntityId> sourceEntity = {}) = 0;
virtual InteractiveEntityPtr getInteractiveInRange(Vec2F const& targetPosition, Vec2F const& sourcePosition, float maxRange) const = 0;
// Can the target entity be reached from the given position within the given radius?
virtual bool canReachEntity(Vec2F const& position, float radius, EntityId targetEntity, bool preferInteractive = true) const = 0;
virtual RpcPromise<InteractAction> interact(InteractRequest const& request) = 0;
virtual float gravity(Vec2F const& pos) const = 0;
virtual float windLevel(Vec2F const& pos) const = 0;
virtual float lightLevel(Vec2F const& pos) const = 0;
virtual bool breathable(Vec2F const& pos) const = 0;
virtual float threatLevel() const = 0;
virtual StringList environmentStatusEffects(Vec2F const& pos) const = 0;
virtual StringList weatherStatusEffects(Vec2F const& pos) const = 0;
virtual bool exposedToWeather(Vec2F const& pos) const = 0;
virtual bool isUnderground(Vec2F const& pos) const = 0;
virtual bool disableDeathDrops() const = 0;
virtual List<PhysicsForceRegion> forceRegions() const = 0;
// Gets / sets world-wide properties
virtual Json getProperty(String const& propertyName, Json const& def = {}) const = 0;
virtual void setProperty(String const& propertyName, Json const& property) = 0;
virtual void timer(float delay, WorldAction worldAction) = 0;
virtual double epochTime() const = 0;
virtual uint32_t day() const = 0;
virtual float dayLength() const = 0;
virtual float timeOfDay() const = 0;
virtual LuaRootPtr luaRoot() = 0;
// Locate a unique entity, if the target is local, the promise will be
// finished before being returned. If the unique entity is not found, the
// promise will fail.
virtual RpcPromise<Vec2F> findUniqueEntity(String const& uniqueEntityId) = 0;
// Send a message to a local or remote scripted entity. If the target is
// local, the promise will be finished before being returned. Entity id can
// either be EntityId or a uniqueId.
virtual RpcPromise<Json> sendEntityMessage(Variant<EntityId, String> const& entity, String const& message, JsonArray const& args = {}) = 0;
// Helper non-virtual methods.
bool isServer() const;
bool isClient() const;
List<EntityPtr> entityQuery(RectF const& boundBox, EntityFilter selector = {}) const;
List<EntityPtr> entityLineQuery(Vec2F const& begin, Vec2F const& end, EntityFilter selector = {}) const;
List<TileEntityPtr> entitiesAtTile(Vec2I const& pos, EntityFilter filter = EntityFilter()) const;
// Find tiles near the given point that are not occupied (according to
// tileIsOccupied)
List<Vec2I> findEmptyTiles(Vec2I pos, unsigned maxDist = 5, size_t maxAmount = 1, bool excludeEphemeral = false) const;
// Do tile modification that only uses a single tile.
bool canModifyTile(Vec2I const& pos, TileModification const& modification, bool allowEntityOverlap) const;
bool modifyTile(Vec2I const& pos, TileModification const& modification, bool allowEntityOverlap);
TileDamageResult damageTile(Vec2I const& tilePosition, TileLayer layer, Vec2F const& sourcePosition, TileDamage const& tileDamage, Maybe<EntityId> sourceEntity = {});
// Returns closest entity for which lineCollision between the given center
// position and the entity position returns false.
EntityPtr closestEntityInSight(Vec2F const& center, float radius, CollisionSet const& collisionSet = DefaultCollisionSet, EntityFilter selector = {}) const;
// Returns whether point collides with any collision geometry.
bool pointCollision(Vec2F const& point, CollisionSet const& collisionSet = DefaultCollisionSet) const;
// Returns first point along line that collides with any collision geometry, along
// with the normal of the intersected line, if any.
Maybe<pair<Vec2F, Maybe<Vec2F>>> lineCollision(Line2F const& line, CollisionSet const& collisionSet = DefaultCollisionSet) const;
// Returns whether poly collides with any collision geometry.
bool polyCollision(PolyF const& poly, CollisionSet const& collisionSet = DefaultCollisionSet) const;
// Helper template methods. Only queries entities of the given template
// type, and casts them to the appropriate pointer type.
template <typename EntityT>
shared_ptr<EntityT> get(EntityId entityId) const;
template <typename EntityT>
List<shared_ptr<EntityT>> query(RectF const& boundBox, EntityFilterOf<EntityT> selector = {}) const;
template <typename EntityT>
shared_ptr<EntityT> closest(Vec2F const& center, float radius, EntityFilterOf<EntityT> selector = {}) const;
template <typename EntityT>
shared_ptr<EntityT> closestInSight(Vec2F const& center, float radius, CollisionSet const& collisionSet, EntityFilterOf<EntityT> selector = {}) const;
template <typename EntityT>
List<shared_ptr<EntityT>> lineQuery(Vec2F const& begin, Vec2F const& end, EntityFilterOf<EntityT> selector = {}) const;
template <typename EntityT>
List<shared_ptr<EntityT>> atTile(Vec2I const& pos) const;
};
template <typename EntityT>
shared_ptr<EntityT> World::get(EntityId entityId) const {
return as<EntityT>(entity(entityId));
}
template <typename EntityT>
List<shared_ptr<EntityT>> World::query(RectF const& boundBox, EntityFilterOf<EntityT> selector) const {
List<shared_ptr<EntityT>> list;
forEachEntity(boundBox, [&](EntityPtr const& entity) {
if (auto e = as<EntityT>(entity)) {
if (!selector || selector(e))
list.append(std::move(e));
}
});
return list;
}
template <typename EntityT>
shared_ptr<EntityT> World::closest(Vec2F const& center, float radius, EntityFilterOf<EntityT> selector) const {
return as<EntityT>(closestEntity(center, radius, entityTypeFilter<EntityT>(selector)));
}
template <typename EntityT>
shared_ptr<EntityT> World::closestInSight(
Vec2F const& center, float radius, CollisionSet const& collisionSet, EntityFilterOf<EntityT> selector) const {
return as<EntityT>(closestEntityInSight(center, radius, collisionSet, entityTypeFilter<EntityT>(selector)));
}
template <typename EntityT>
List<shared_ptr<EntityT>> World::lineQuery(
Vec2F const& begin, Vec2F const& end, EntityFilterOf<EntityT> selector) const {
List<shared_ptr<EntityT>> list;
forEachEntityLine(begin, end, [&](EntityPtr entity) {
if (auto e = as<EntityT>(std::move(entity))) {
if (!selector || selector(e))
list.append(std::move(e));
}
});
return list;
}
template <typename EntityT>
List<shared_ptr<EntityT>> World::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 list;
}
}
|