#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; 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; } }