#ifndef __ENTITY__H__ #define __ENTITY__H__ #include #include #include #include #include "dCommonVars.h" #include "NiPoint3.h" #include "NiQuaternion.h" #include "eKillType.h" namespace Loot { class Info; }; namespace tinyxml2 { class XMLDocument; }; namespace CppScripts { class Script; }; class Player; class EntityInfo; class User; class Spawner; class ScriptComponent; class dpEntity; class EntityTimer; class Component; class Item; class Character; class EntityCallbackTimer; class LDFBaseData; class BoxDimensions; enum class eTriggerEventType; enum class eGameMasterLevel : uint8_t; enum class eReplicaComponentType : uint32_t; enum class eReplicaPacketType : uint8_t; enum class eCinematicEvent : uint32_t; /** * An entity in the world. * Entities are composed of components which define their behavior. */ using ComponentPtr = std::unique_ptr; using ComponentWhitelist = std::vector; using TemplateComponents = std::vector>; class Entity { public: explicit Entity(const LWOOBJID& objectID, EntityInfo info, Entity* parentEntity = nullptr); virtual ~Entity(); void ApplyComponentWhitelist(TemplateComponents& components) const; static const std::vector& GetComponentWhitelists() { return m_ComponentWhitelists; } /** * Functions used for creating and setting up an Entity. */ void Initialize(); /** * There are some very very edge cases we need to take care of with what components * are kept and removed. Here is where we take care of those cases. */ void ApplyComponentBlacklist(TemplateComponents& components) const; // For adding and removing components based on LDF keys void ApplyComponentConfig(TemplateComponents& components) const; // Paths have several components they could add. This function will add them. void AddPathComponent(TemplateComponents& components) const; /** * Determines if we should ghost an Entity or not. * Ghosting means we no longer serialize it to a specific player because it is out of range. */ void IsGhosted(); bool operator==(const Entity& other) const; bool operator!=(const Entity& other) const; // General Entity info const LWOOBJID GetObjectID() const { return m_ObjectID; } const LOT GetLOT() const { return m_TemplateID; } Entity* GetParentEntity() const { return m_ParentEntity; } const bool GetIsGhostingCandidate() const { return m_IsGhostingCandidate; } const float GetDefaultScale() const { return m_Scale; } Entity* GetOwner() const; void SetOwnerOverride(const LWOOBJID& value) { m_OwnerOverride = value; }; Entity* GetScheduledKiller() { return m_ScheduleKiller; } std::vector& GetTargetsInPhantom(); const std::unordered_map& GetComponents() { return m_Components; } // Position related info const NiPoint3& GetDefaultPosition() const { return m_DefaultPosition; }; const NiQuaternion& GetDefaultRotation() const { return m_DefaultRotation; }; const NiPoint3& GetPosition() const; void SetPosition(const NiPoint3& position); const NiQuaternion& GetRotation() const; void SetRotation(const NiQuaternion& rotation); virtual NiPoint3 GetRespawnPosition() const { return NiPoint3::ZERO; } virtual NiQuaternion GetRespawnRotation() const { return NiQuaternion::IDENTITY; } // Spawner related info Spawner* GetSpawner() const { return m_Spawner; } LWOOBJID GetSpawnerID() const { return m_SpawnerID; } const std::vector& GetGroups() { return m_Groups; }; void SetGroups(const std::vector& value) { m_Groups = value; } void AddGroup(const std::string& group); // LDF related into const std::vector& GetSettings() const { return m_Settings; } const std::vector& GetNetworkSettings() const { return m_NetworkSettings; } // Networking related info const int8_t GetObservers() const { return m_Observers; } void SetObservers(const int8_t value); const uint16_t GetNetworkId() const { return m_NetworkID; } void SetNetworkId(const uint16_t id) { m_NetworkID = id; } // Player extended info virtual User* GetParentUser() const { return nullptr; }; virtual const SystemAddress GetSystemAddress() const { return UNASSIGNED_SYSTEM_ADDRESS; }; virtual void SetRespawnPosition(const NiPoint3& position) {}; virtual void SetRespawnRotation(const NiQuaternion& rotation) {}; virtual void SetSystemAddress(const SystemAddress& value) {}; eGameMasterLevel GetGMLevel() const { return m_GMLevel; } void SetGMLevel(const eGameMasterLevel value); bool GetPlayerReadyForUpdates() const { return m_PlayerIsReadyForUpdates; } void SetPlayerReadyForUpdates() { m_PlayerIsReadyForUpdates = true; } Character* GetCharacter() const { return m_Character; } void SetCharacter(Character* value) { m_Character = value; } // End info // If you are calling this, then calling GetComponent, just call GetComponent and check for nullptr. bool HasComponent(const eReplicaComponentType componentId) const; // Event management /** * Call these when you want to observe events. Observed events should follow the following naming convention * in scripts Notify. For example, if you want to observe the "OnDeath" event, you would call * entity->Subscribe(script, "OnDeath"). Then in your script, you would have a function called NotifyOnDeath. */ void Subscribe(CppScripts::Script* scriptToAdd, const std::string& notificationName); /** * Call this when you want to stop observing an event. The scriptToRemove will * no longer be notified of notificationName events */ void Unsubscribe(CppScripts::Script* scriptToRemove, const std::string& notificationName); // Proximity radius management void AddProximityRadius(const float proxRadius, const std::string& name); void AddProximityRadius(const BoxDimensions& dimensions, const std::string& name); // Technically this is the live accrate API, however what it does is not setting the proximity radius, but rather // adding a new one to the list of proximity radii. For that reason we will have the old API just call AddProximityRadius. inline void SetProximityRadius(const float proxRadius, const std::string& name) { this->AddProximityRadius(proxRadius, name); } inline void SetProximityRadius(const BoxDimensions& dimensions, const std::string& name) { this->AddProximityRadius(dimensions, name); } void AddRebuildCompleteCallback(const std::function& callback) const; void AddCollisionPhantomCallback(const std::function& callback) { m_PhantomCollisionCallbacks.push_back(callback); }; void AddDieCallback(const std::function& callback) { m_DieCallbacks.push_back(callback); }; void TriggerEvent(const eTriggerEventType event, Entity* optionalTarget = nullptr); void NotifyObject(Entity* sender, const std::u16string& name, const int32_t param1 = 0, const int32_t param2 = 0); // Parent Child management void AddChild(Entity* child); void RemoveChild(Entity* child); void RemoveParent(); // Timer management void AddTimer(const std::string& name, const float time); void AddCallbackTimer(const float time, const std::function& callback); bool HasTimer(const std::string& name); void CancelCallbackTimers(); void CancelAllTimers(); void CancelTimer(const std::string& name); // Serialization void WriteBaseReplicaData(RakNet::BitStream* outBitStream, const eReplicaPacketType packetType); void WriteComponents(RakNet::BitStream* outBitStream, const eReplicaPacketType packetType); // Scripting // Get the script attached to this entity. Will never return nullptr. CppScripts::Script* GetScript() const; void OnCollisionProximity(const LWOOBJID otherEntity, const std::string& proxName, const std::string& status); void OnCollisionPhantom(const LWOOBJID otherEntity); void OnCollisionLeavePhantom(const LWOOBJID otherEntity); void OnFireEventServerSide(Entity* sender, const std::string args, const int32_t param1 = -1, const int32_t param2 = -1, const int32_t param3 = -1); void OnActivityStateChangeRequest(const LWOOBJID senderID, const int32_t value1, const int32_t value2, const std::u16string& stringValue); void OnCinematicUpdate(Entity* self, Entity* sender, const eCinematicEvent event, const std::u16string& pathName, const float pathTime, const float totalTime, const int32_t waypoint); void OnEmoteReceived(const int32_t emote, Entity* target); void OnUse(Entity* originator); void OnHitOrHealResult(Entity* attacker, const int32_t damage); void OnHit(Entity* attacker); void OnZonePropertyEditBegin(); void OnZonePropertyEditEnd(); void OnZonePropertyModelEquipped(); void OnZonePropertyModelPlaced(Entity* player); void OnZonePropertyModelPickedUp(Entity* player); void OnZonePropertyModelRemoved(Entity* player); void OnZonePropertyModelRemovedWhileEquipped(Entity* player); void OnZonePropertyModelRotated(Entity* player); void OnMessageBoxResponse(Entity* sender, const int32_t button, const std::u16string& identifier, const std::u16string& userData); void OnChoiceBoxResponse(Entity* sender, const int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier); void RequestActivityExit(Entity* sender, const LWOOBJID& player, const bool canceled); // End scripting // Cleanup functions void Smash(const LWOOBJID source = LWOOBJID_EMPTY, const eKillType killType = eKillType::VIOLENT, const std::u16string& deathType = u""); // Odds are you do not need to call this. Call Smash instead. void Kill(Entity* murderer = nullptr); void ScheduleKillAfterUpdate(Entity* murderer = nullptr); void ScheduleDestructionAfterUpdate() { m_ShouldDestroyAfterUpdate = true; } void Resurrect(); // Loot management (should be moved to Player. Not every Entity needs this.) void AddLootItem(const Loot::Info& info); void PickupItem(const LWOOBJID& objectID); bool CanPickupCoins(const uint64_t& count) const; void PickupCoins(const uint64_t& count); void RegisterCoinDrop(const uint64_t& count); // State checkers void Sleep(); void Wake(); bool IsSleeping() const; bool IsDead() const; bool IsPlayer() const; // Update void UpdateXMLDoc(tinyxml2::XMLDocument* doc); void Update(float deltaTime); //Retroactively corrects the model vault size due to incorrect initialization in a previous patch. void RetroactiveVaultSize(); void ResetFlags(); // LDF Setting accessors bool GetBoolean(const std::u16string& name) const { return GetVar(name); }; int32_t GetI32(const std::u16string& name) const { return GetVar(name); }; int64_t GetI64(const std::u16string& name) const { return GetVar(name); }; bool HasVar(const std::u16string& name) const; LDFBaseData* GetVarData(const std::u16string& name) const; /** * Get the LDF value and convert it to a string. */ std::string GetVarAsString(const std::u16string& name) const; // LDF Setting assignment shorthands void SetBoolean(const std::u16string& name, bool value) { SetVar(name, value); } void SetI32(const std::u16string& name, int32_t value) { SetVar(name, value); }; void SetI64(const std::u16string& name, int64_t value) { SetVar(name, value); }; // Template declarations template const T& GetVar(const std::u16string& name) const; template T GetVarAs(const std::u16string& name) const; template void SetVar(const std::u16string& name, const T& value); template T GetNetworkVar(const std::u16string& name); void SendNetworkVar(const std::string& data, const SystemAddress& sysAddr); template void SetNetworkVar(const std::u16string& name, const T& value, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS); template void SetNetworkVar(const std::u16string& name, const std::vector& value, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS); /** * @brief Get a non-owning reference to a component * * @tparam Cmpt The component to get a non-owning reference of * @return Cmpt* The non-owning pointer to the component */ template Cmpt* GetComponent() const; /** * @brief Adds a component to this Entity. * * @tparam Cmpt The component to create * @tparam ConstructorValues The constructor values to forward to the component * @param arguments The constructor values to forward to the component * @return Cmpt* A non-owning pointer to the created component, * or a non-owning pointer to the existing component if the component already existed. */ template Cmpt* AddComponent(ConstructorValues... arguments); /** * @brief Removes a component from this Entity. */ template void RemoveComponent(); protected: LWOOBJID m_ObjectID; LWOOBJID m_SpawnerID; LWOOBJID m_OwnerOverride; uint32_t m_SpawnerNodeID; LOT m_TemplateID; NiPoint3 m_DefaultPosition; NiQuaternion m_DefaultRotation; float m_Scale; int8_t m_Observers; eGameMasterLevel m_GMLevel; Entity* m_ParentEntity; //For spawners and the like Entity* m_ScheduleKiller; Spawner* m_Spawner; Character* m_Character; bool m_HasSpawnerNodeID; bool m_ShouldDestroyAfterUpdate; bool m_PlayerIsReadyForUpdates; bool m_IsGhostingCandidate; bool m_IsParentChildDirty; uint16_t m_NetworkID; std::unordered_map m_Components; std::vector> m_Timers; std::vector> m_PendingTimers; std::vector> m_CallbackTimers; std::vector m_Settings; std::vector m_NetworkSettings; std::vector m_ChildEntities; std::vector m_Groups; std::vector> m_DieCallbacks; std::vector> m_PhantomCollisionCallbacks; std::vector m_TargetsInPhantom; static const std::vector m_ComponentWhitelists; bool m_HasModelBehaviors = false; bool m_HasPhysicsComponent = false; uint32_t m_PhysicsComponentID = -1; }; #include "Entity.tcc" #endif //!__ENTITY__H__