4b0bc220e4
Context-specific (like per-world) timescales can also be added later
232 lines
8.2 KiB
C++
232 lines
8.2 KiB
C++
#ifndef STAR_ENTITY_HPP
|
|
#define STAR_ENTITY_HPP
|
|
|
|
#include "StarCasting.hpp"
|
|
#include "StarDamage.hpp"
|
|
#include "StarLightSource.hpp"
|
|
|
|
namespace Star {
|
|
|
|
STAR_CLASS(RenderCallback);
|
|
STAR_CLASS(World);
|
|
STAR_STRUCT(DamageNotification);
|
|
STAR_CLASS(Entity);
|
|
|
|
STAR_EXCEPTION(EntityException, StarException);
|
|
|
|
// Specifies how the client should treat an entity created on the client,
|
|
// whether it should always be sent to the server and be a slave on the client,
|
|
// whether it is allowed to be master on the client, and whether client master
|
|
// entities should contribute to client presence.
|
|
enum class ClientEntityMode {
|
|
// Always a slave on the client
|
|
ClientSlaveOnly,
|
|
// Can be a master on the client
|
|
ClientMasterAllowed,
|
|
// Can be a master on the client, and when it is contributes to client
|
|
// presence.
|
|
ClientPresenceMaster
|
|
};
|
|
extern EnumMap<ClientEntityMode> const ClientEntityModeNames;
|
|
|
|
// The top-level entity type. The enum order is intended to be in the order in
|
|
// which entities should be updated every tick
|
|
enum class EntityType : uint8_t {
|
|
Plant,
|
|
Object,
|
|
Vehicle,
|
|
ItemDrop,
|
|
PlantDrop,
|
|
Projectile,
|
|
Stagehand,
|
|
Monster,
|
|
Npc,
|
|
Player
|
|
};
|
|
extern EnumMap<EntityType> const EntityTypeNames;
|
|
|
|
class Entity {
|
|
public:
|
|
virtual ~Entity();
|
|
|
|
virtual EntityType entityType() const = 0;
|
|
|
|
// Called when an entity is first inserted into a World. Calling base class
|
|
// init sets the world pointer, entityId, and entityMode.
|
|
virtual void init(World* world, EntityId entityId, EntityMode mode);
|
|
|
|
// Should do whatever steps necessary to take an entity out of a world,
|
|
// default implementation clears the world pointer, entityMode, and entityId.
|
|
virtual void uninit();
|
|
|
|
// Write state data that changes over time, and is used to keep slaves in
|
|
// sync. Can return empty and this is the default. May be called
|
|
// uninitalized. Should return the delta to be written to the slave, along
|
|
// with the version to pass into writeDeltaState on the next call. The first
|
|
// delta written to a slave entity will always be the delta starting with 0.
|
|
virtual pair<ByteArray, uint64_t> writeNetState(uint64_t fromVersion = 0);
|
|
// Will be called with deltas written by writeDeltaState, including if the
|
|
// delta is empty. interpolationTime will be provided if interpolation is
|
|
// enabled.
|
|
virtual void readNetState(ByteArray data, float interpolationTime = 0.0);
|
|
|
|
virtual void enableInterpolation(float extrapolationHint);
|
|
virtual void disableInterpolation();
|
|
|
|
// Base position of this entity, bound boxes, drawables, and other entity
|
|
// positions are relative to this.
|
|
virtual Vec2F position() const = 0;
|
|
|
|
// Largest bounding-box of this entity. Any damage boxes / drawables / light
|
|
// or sound *sources* must be contained within this bounding box. Used for
|
|
// all top-level spatial queries.
|
|
virtual RectF metaBoundBox() const = 0;
|
|
|
|
// By default returns a null rect, if non-null, it defines the area around
|
|
// this entity where it is likely for the entity to physically collide with
|
|
// collision geometry.
|
|
virtual RectF collisionArea() const;
|
|
|
|
// Should this entity allow object / block placement over it, and can the
|
|
// entity immediately be despawned without terribly bad effects?
|
|
virtual bool ephemeral() const;
|
|
|
|
// How should this entity be treated if created on the client? Defaults to
|
|
// ClientSlave.
|
|
virtual ClientEntityMode clientEntityMode() const;
|
|
// Should this entity only exist on the master side?
|
|
virtual bool masterOnly() const;
|
|
|
|
virtual String description() const;
|
|
|
|
// Gameplay affecting light sources (separate from light sources added during
|
|
// rendering)
|
|
virtual List<LightSource> lightSources() const;
|
|
|
|
// All damage sources for this frame.
|
|
virtual List<DamageSource> damageSources() const;
|
|
|
|
// Return the damage that would result from being hit by the given damage
|
|
// source. Will be called on master and slave entities. Culling based on
|
|
// team damage and self damage will be done outside of this query.
|
|
virtual Maybe<HitType> queryHit(DamageSource const& source) const;
|
|
|
|
// Return the polygonal area in which the entity can be hit. Not used for
|
|
// actual hit computation, only for determining more precisely where a
|
|
// hit intersection occurred (e.g. by projectiles)
|
|
virtual Maybe<PolyF> hitPoly() const;
|
|
|
|
// Apply a request to damage this entity. Will only be called on Master
|
|
// entities. DamageRequest might be adjusted based on protection and other
|
|
// effects
|
|
virtual List<DamageNotification> applyDamage(DamageRequest const& damage);
|
|
|
|
// Pull any pending damage notifications applied internally, only called on
|
|
// Master entities.
|
|
virtual List<DamageNotification> selfDamageNotifications();
|
|
|
|
// Called on master entities when a DamageRequest has been generated due to a
|
|
// DamageSource from this entity being applied to another entity. Will be
|
|
// called on the *causing* entity of the damage.
|
|
virtual void hitOther(EntityId targetEntityId, DamageRequest const& damageRequest);
|
|
|
|
// Called on master entities when this entity has damaged another entity.
|
|
// Only called on the *source entity* of the damage, which may be different
|
|
// than the causing entity.
|
|
virtual void damagedOther(DamageNotification const& damage);
|
|
|
|
// Returning true here indicates that this entity should be removed from the
|
|
// world, default returns false.
|
|
virtual bool shouldDestroy() const;
|
|
// Will be called once before removing the entity from the World on both
|
|
// master and slave entities.
|
|
virtual void destroy(RenderCallback* renderCallback);
|
|
|
|
// Entities can send other entities potentially remote messages and get
|
|
// responses back from them, and should implement this to receive and respond
|
|
// to messages. If the message is NOT handled, should return Nothing,
|
|
// otherwise should return some Json value.
|
|
// This will only ever be called on master entities.
|
|
virtual Maybe<Json> receiveMessage(ConnectionId sendingConnection, String const& message, JsonArray const& args);
|
|
|
|
virtual void update(float dt, uint64_t currentStep);
|
|
|
|
virtual void render(RenderCallback* renderer);
|
|
|
|
virtual void renderLightSources(RenderCallback* renderer);
|
|
|
|
EntityId entityId() const;
|
|
|
|
EntityDamageTeam getTeam() const;
|
|
|
|
// Returns true if an entity is initialized in a world, and thus has a valid
|
|
// world pointer, entity id, and entity mode.
|
|
bool inWorld() const;
|
|
|
|
// Throws an exception if not currently in a world.
|
|
World* world() const;
|
|
// Returns nullptr if not currently in a world.
|
|
World* worldPtr() const;
|
|
|
|
// Specifies if the entity is to be saved to disk alongside the sector or
|
|
// despawned.
|
|
bool persistent() const;
|
|
|
|
// Entity should keep any sector it is in alive. Default implementation
|
|
// returns false.
|
|
bool keepAlive() const;
|
|
|
|
// If set, then the entity will be discoverable by its unique id and will be
|
|
// indexed in the stored world. Unique ids must be different across all
|
|
// entities in a single world.
|
|
Maybe<String> uniqueId() const;
|
|
|
|
// EntityMode will only be set if the entity is initialized, if the entity is
|
|
// uninitialized then isMaster and isSlave will both return false.
|
|
Maybe<EntityMode> entityMode() const;
|
|
bool isMaster() const;
|
|
bool isSlave() const;
|
|
|
|
protected:
|
|
Entity();
|
|
|
|
void setPersistent(bool persistent);
|
|
void setKeepAlive(bool keepAlive);
|
|
void setUniqueId(Maybe<String> uniqueId);
|
|
void setTeam(EntityDamageTeam newTeam);
|
|
|
|
private:
|
|
EntityId m_entityId;
|
|
Maybe<EntityMode> m_entityMode;
|
|
bool m_persistent;
|
|
bool m_keepAlive;
|
|
Maybe<String> m_uniqueId;
|
|
World* m_world;
|
|
EntityDamageTeam m_team;
|
|
};
|
|
|
|
template <typename EntityT>
|
|
using EntityCallbackOf = function<void(shared_ptr<EntityT> const&)>;
|
|
|
|
template <typename EntityT>
|
|
using EntityFilterOf = function<bool(shared_ptr<EntityT> const&)>;
|
|
|
|
typedef EntityCallbackOf<Entity> EntityCallback;
|
|
typedef EntityFilterOf<Entity> EntityFilter;
|
|
|
|
// Filters based first on dynamic casting to the given type, then optionally on
|
|
// the given derived type filter.
|
|
template <typename EntityT>
|
|
EntityFilter entityTypeFilter(function<bool(shared_ptr<EntityT> const&)> filter = {}) {
|
|
return [filter](EntityPtr const& e) -> bool {
|
|
if (auto entity = as<EntityT>(e)) {
|
|
return !filter || filter(entity);
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
}
|
|
}
|
|
|
|
#endif
|