From b967cc57d17c47bc35374a004bbcdb133e55399c Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Thu, 23 Mar 2023 07:49:31 -0700 Subject: [PATCH 1/3] Allow name billboards to be toggled (#1026) * Allow name billboards to be toggled * Allow name billboards to be toggled * Add comments * Move logic to Character * Use Entity in Character instead --- dCommon/dEnums/dMessageIdentifiers.h | 2 ++ dGame/Character.cpp | 18 +++++++++++++++ dGame/Character.h | 9 ++++++++ dGame/dGameMessages/GameMessages.cpp | 29 ++++++++++++++++++++++++ dGame/dGameMessages/GameMessages.h | 2 ++ dGame/dUtilities/SlashCommandHandler.cpp | 13 +++++++++++ docs/Commands.md | 1 + resources/worldconfig.ini | 3 +++ 8 files changed, 77 insertions(+) diff --git a/dCommon/dEnums/dMessageIdentifiers.h b/dCommon/dEnums/dMessageIdentifiers.h index e11f9e7f..63d7044e 100644 --- a/dCommon/dEnums/dMessageIdentifiers.h +++ b/dCommon/dEnums/dMessageIdentifiers.h @@ -484,6 +484,7 @@ enum GAME_MSG : unsigned short { GAME_MSG_LOCK_NODE_ROTATION = 1260, GAME_MSG_VEHICLE_SET_WHEEL_LOCK_STATE = 1273, GAME_MSG_NOTIFY_VEHICLE_OF_RACING_OBJECT = 1276, + GAME_MSG_SET_NAME_BILLBOARD_STATE = 1284, GAME_MSG_PLAYER_REACHED_RESPAWN_CHECKPOINT = 1296, GAME_MSG_HANDLE_UGC_EQUIP_POST_DELETE_BASED_ON_EDIT_MODE = 1300, GAME_MSG_HANDLE_UGC_EQUIP_PRE_CREATE_BASED_ON_EDIT_MODE = 1301, @@ -494,6 +495,7 @@ enum GAME_MSG : unsigned short { GAME_MSG_MATCH_UPDATE = 1310, GAME_MSG_MODULE_ASSEMBLY_DB_DATA_FOR_CLIENT = 1131, GAME_MSG_MODULE_ASSEMBLY_QUERY_DATA = 1132, + GAME_MSG_SHOW_BILLBOARD_INTERACT_ICON = 1337, GAME_MSG_CHANGE_IDLE_FLAGS = 1338, GAME_MSG_VEHICLE_ADD_PASSIVE_BOOST_ACTION = 1340, GAME_MSG_VEHICLE_REMOVE_PASSIVE_BOOST_ACTION = 1341, diff --git a/dGame/Character.cpp b/dGame/Character.cpp index 572a3e9e..16497fc3 100644 --- a/dGame/Character.cpp +++ b/dGame/Character.cpp @@ -621,3 +621,21 @@ void Character::SendMuteNotice() const { ChatPackets::SendSystemMessage(GetEntity()->GetSystemAddress(), u"You are muted until " + timeStr); } + +void Character::SetBillboardVisible(bool visible) { + if (m_BillboardVisible == visible) return; + m_BillboardVisible = visible; + + GameMessages::SendSetNamebillboardState(UNASSIGNED_SYSTEM_ADDRESS, m_OurEntity->GetObjectID()); + + if (!visible) return; + + // The GameMessage we send for turning the nameplate off just deletes the BillboardSubcomponent from the parent component. + // Because that same message does not allow for custom parameters, we need to create the BillboardSubcomponent a different way + // This workaround involves sending an unrelated GameMessage that does not apply to player entites, + // but forces the client to create the necessary SubComponent that controls the billboard. + GameMessages::SendShowBillboardInteractIcon(UNASSIGNED_SYSTEM_ADDRESS, m_OurEntity->GetObjectID()); + + // Now turn off the billboard for the owner. + GameMessages::SendSetNamebillboardState(m_OurEntity->GetSystemAddress(), m_OurEntity->GetObjectID()); +} diff --git a/dGame/Character.h b/dGame/Character.h index abded1b3..d77dd022 100644 --- a/dGame/Character.h +++ b/dGame/Character.h @@ -451,6 +451,10 @@ public: */ void SetIsFlying(bool isFlying) { m_IsFlying = isFlying; } + bool GetBillboardVisible() { return m_BillboardVisible; } + + void SetBillboardVisible(bool visible); + private: /** * The ID of this character. First 32 bits of the ObjectID. @@ -652,6 +656,11 @@ private: */ bool m_IsFlying = false; + /** + * True if billboard (referred to as nameplate for end users) is visible, false otherwise + */ + bool m_BillboardVisible = true; + /** * Queries the character XML and updates all the fields of this object * NOTE: quick as there's no DB lookups diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index 33a7f104..8604d136 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -6154,3 +6154,32 @@ void GameMessages::SendDeactivateBubbleBuffFromServer(LWOOBJID objectId, const S if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; } + +void GameMessages::SendSetNamebillboardState(const SystemAddress& sysAddr, LWOOBJID objectId) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(GAME_MSG::GAME_MSG_SET_NAME_BILLBOARD_STATE); + + // Technically these bits would be written, however the client does not + // contain a deserialize method to actually deserialize, so we are leaving it out. + // As such this GM only turns the billboard off. + + // bitStream.Write(overrideDefault); + // bitStream.Write(state); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST + else SEND_PACKET +} + +void GameMessages::SendShowBillboardInteractIcon(const SystemAddress& sysAddr, LWOOBJID objectId) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(GAME_MSG::GAME_MSG_SHOW_BILLBOARD_INTERACT_ICON); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST + else SEND_PACKET +} diff --git a/dGame/dGameMessages/GameMessages.h b/dGame/dGameMessages/GameMessages.h index 5d199995..7305e429 100644 --- a/dGame/dGameMessages/GameMessages.h +++ b/dGame/dGameMessages/GameMessages.h @@ -574,6 +574,8 @@ namespace GameMessages { void HandleToggleGhostReferenceOverride(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); void HandleSetGhostReferencePosition(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void SendSetNamebillboardState(const SystemAddress& sysAddr, LWOOBJID objectId); + void SendShowBillboardInteractIcon(const SystemAddress& sysAddr, LWOOBJID objectId); void HandleBuyFromVendor(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); void HandleSellToVendor(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); void HandleBuybackFromVendor(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); diff --git a/dGame/dUtilities/SlashCommandHandler.cpp b/dGame/dUtilities/SlashCommandHandler.cpp index 0278136b..1f3da6c7 100644 --- a/dGame/dUtilities/SlashCommandHandler.cpp +++ b/dGame/dUtilities/SlashCommandHandler.cpp @@ -171,6 +171,19 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } #endif + if (chatCommand == "togglenameplate" && (Game::config->GetValue("allownameplateoff") == "1" || entity->GetGMLevel() > GAME_MASTER_LEVEL_DEVELOPER)) { + auto* character = entity->GetCharacter(); + + if (character && character->GetBillboardVisible()) { + character->SetBillboardVisible(false); + ChatPackets::SendSystemMessage(sysAddr, u"Your nameplate has been turned off and is not visible to players currently in this zone."); + } else { + character->SetBillboardVisible(true); + ChatPackets::SendSystemMessage(sysAddr, u"Your nameplate is now on and visible to all players."); + } + return; + } + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //HANDLE ALL NON GM SLASH COMMANDS RIGHT HERE! //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! diff --git a/docs/Commands.md b/docs/Commands.md index a9cd3e7c..725a03a0 100644 --- a/docs/Commands.md +++ b/docs/Commands.md @@ -48,6 +48,7 @@ These commands are primarily for development and testing. The usage of many of t |Command|Usage|Description|Admin Level Requirement| |--- |--- |--- |--- | +|togglenameplate|`/togglenameplate`|Turns the nameplate above your head that is visible to other players off and on.|8 or if `allow_nameplate_off` is set to exactly `1` in the settings| |fix-stats|`/fix-stats`|Resets skills, buffs, and destroyables.|| |join|`/join `|Joins a private zone with given password.|| |leave-zone|`/leave-zone`|If you are in an instanced zone, transfers you to the closest main world. For example, if you are in an instance of Avant Gardens Survival or the Spider Queen Battle, you are sent to Avant Gardens. If you are in the Battle of Nimbus Station, you are sent to Nimbus Station.|| diff --git a/resources/worldconfig.ini b/resources/worldconfig.ini index 64b4fb40..b05614b4 100644 --- a/resources/worldconfig.ini +++ b/resources/worldconfig.ini @@ -58,3 +58,6 @@ hardcore_uscore_enemies_multiplier=2 # Percentage of u-score to lose on player death hardcore_lose_uscore_on_death_percent=10 + +# Allow civilian players the ability to turn the nameplate above their head off. Must be exactly 1 to be enabled for civilians. +allow_nameplate_off=0 From 72ca0f13ff0f09137a05784ea1fe062d19e4e58f Mon Sep 17 00:00:00 2001 From: Aaron Kimbrell Date: Fri, 24 Mar 2023 18:16:45 -0500 Subject: [PATCH 2/3] breakout gmlevel into a scoped enum (#996) * breakout gmlevel enum and make it a class tested that things still work slash command, chat restrictions, packets and serializations * fix GM level for some slash commands * fix new use of this enum --- dChatFilter/dChatFilter.cpp | 5 +- dChatFilter/dChatFilter.h | 3 +- dCommon/dEnums/dCommonVars.h | 15 -- dCommon/dEnums/eGameMasterLevel.h | 20 ++ dGame/Character.cpp | 9 +- dGame/Character.h | 7 +- dGame/Entity.cpp | 7 +- dGame/Entity.h | 7 +- dGame/EntityManager.cpp | 3 +- dGame/User.cpp | 5 +- dGame/User.h | 5 +- dGame/UserManager.cpp | 3 +- dGame/dComponents/CharacterComponent.cpp | 7 +- dGame/dComponents/CharacterComponent.h | 6 +- dGame/dComponents/PetComponent.cpp | 6 +- .../dComponents/PropertyEntranceComponent.cpp | 3 +- .../dComponents/ScriptedActivityComponent.cpp | 2 +- dGame/dGameMessages/GameMessages.cpp | 4 +- dGame/dGameMessages/GameMessages.h | 7 +- dGame/dUtilities/SlashCommandHandler.cpp | 176 +++++++++--------- dNet/ClientPackets.cpp | 3 +- dNet/WorldPackets.cpp | 15 +- dNet/WorldPackets.h | 5 +- docs/Commands.md | 20 +- 24 files changed, 184 insertions(+), 159 deletions(-) create mode 100644 dCommon/dEnums/eGameMasterLevel.h diff --git a/dChatFilter/dChatFilter.cpp b/dChatFilter/dChatFilter.cpp index ea38f8cd..92da9556 100644 --- a/dChatFilter/dChatFilter.cpp +++ b/dChatFilter/dChatFilter.cpp @@ -12,6 +12,7 @@ #include "dConfig.h" #include "Database.h" #include "Game.h" +#include "eGameMasterLevel.h" using namespace dChatFilterDCF; @@ -108,8 +109,8 @@ void dChatFilter::ExportWordlistToDCF(const std::string& filepath, bool whiteLis } } -std::vector> dChatFilter::IsSentenceOkay(const std::string& message, int gmLevel, bool whiteList) { - if (gmLevel > GAME_MASTER_LEVEL_FORUM_MODERATOR) return { }; //If anything but a forum mod, return true. +std::vector> dChatFilter::IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool whiteList) { + if (gmLevel > eGameMasterLevel::FORUM_MODERATOR) return { }; //If anything but a forum mod, return true. if (message.empty()) return { }; if (!whiteList && m_DeniedWords.empty()) return { { 0, message.length() } }; diff --git a/dChatFilter/dChatFilter.h b/dChatFilter/dChatFilter.h index 7e7dd859..d00525ce 100644 --- a/dChatFilter/dChatFilter.h +++ b/dChatFilter/dChatFilter.h @@ -4,6 +4,7 @@ #include "dCommonVars.h" +enum class eGameMasterLevel : uint8_t; namespace dChatFilterDCF { static const uint32_t header = ('D' + ('C' << 8) + ('F' << 16) + ('B' << 24)); static const uint32_t formatVersion = 2; @@ -23,7 +24,7 @@ public: void ReadWordlistPlaintext(const std::string& filepath, bool whiteList); bool ReadWordlistDCF(const std::string& filepath, bool whiteList); void ExportWordlistToDCF(const std::string& filepath, bool whiteList); - std::vector> IsSentenceOkay(const std::string& message, int gmLevel, bool whiteList = true); + std::vector> IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool whiteList = true); private: bool m_DontGenerateDCF; diff --git a/dCommon/dEnums/dCommonVars.h b/dCommon/dEnums/dCommonVars.h index 2b7f63dc..16cae3c9 100644 --- a/dCommon/dEnums/dCommonVars.h +++ b/dCommon/dEnums/dCommonVars.h @@ -175,21 +175,6 @@ union suchar { char svalue; }; -//=========== DLU ENUMS ============ - -enum eGameMasterLevel : int32_t { - GAME_MASTER_LEVEL_CIVILIAN = 0, // Normal player. - GAME_MASTER_LEVEL_FORUM_MODERATOR = 1, // No permissions on live servers. - GAME_MASTER_LEVEL_JUNIOR_MODERATOR = 2, // Can kick/mute and pull chat logs. - GAME_MASTER_LEVEL_MODERATOR = 3, // Can return lost items. - GAME_MASTER_LEVEL_SENIOR_MODERATOR = 4, // Can ban. - GAME_MASTER_LEVEL_LEAD_MODERATOR = 5, // Can approve properties. - GAME_MASTER_LEVEL_JUNIOR_DEVELOPER = 6, // Junior developer & future content team. Civilan on live. - GAME_MASTER_LEVEL_INACTIVE_DEVELOPER = 7, // Inactive developer, limited permissions. - GAME_MASTER_LEVEL_DEVELOPER = 8, // Active developer, full permissions on live. - GAME_MASTER_LEVEL_OPERATOR = 9 // Can shutdown server for restarts & updates. -}; - //=========== LU ENUMS ============ //! An enum for object ID bits diff --git a/dCommon/dEnums/eGameMasterLevel.h b/dCommon/dEnums/eGameMasterLevel.h new file mode 100644 index 00000000..a63c1caf --- /dev/null +++ b/dCommon/dEnums/eGameMasterLevel.h @@ -0,0 +1,20 @@ +#ifndef __EGAMEMASTERLEVEL__H__ +#define __EGAMEMASTERLEVEL__H__ + +#include + +enum class eGameMasterLevel : uint8_t { + CIVILIAN = 0, // Normal player. + FORUM_MODERATOR = 1, // No permissions on live servers. + JUNIOR_MODERATOR = 2, // Can kick/mute and pull chat logs. + MODERATOR = 3, // Can return lost items. + SENIOR_MODERATOR = 4, // Can ban. + LEAD_MODERATOR = 5, // Can approve properties. + JUNIOR_DEVELOPER = 6, // Junior developer & future content team. Civilan on live. + INACTIVE_DEVELOPER = 7, // Inactive developer, limited permissions. + DEVELOPER = 8, // Active developer, full permissions on live. + OPERATOR = 9 // Can shutdown server for restarts & updates. +}; + + +#endif //!__EGAMEMASTERLEVEL__H__ diff --git a/dGame/Character.cpp b/dGame/Character.cpp index 16497fc3..b8d08854 100644 --- a/dGame/Character.cpp +++ b/dGame/Character.cpp @@ -18,6 +18,7 @@ #include "InventoryComponent.h" #include "eMissionTaskType.h" #include "eMissionState.h" +#include "eGameMasterLevel.h" Character::Character(uint32_t id, User* parentUser) { //First load the name, etc: @@ -204,7 +205,9 @@ void Character::DoQuickXMLDataParse() { tinyxml2::XMLElement* character = m_Doc->FirstChildElement("obj")->FirstChildElement("char"); if (character) { character->QueryAttribute("cc", &m_Coins); - character->QueryAttribute("gm", &m_GMLevel); + int32_t gm_level = 0; + character->QueryAttribute("gm", &gm_level); + m_GMLevel = static_cast(gm_level); uint64_t lzidConcat = 0; if (character->FindAttribute("lzid")) { @@ -304,7 +307,7 @@ void Character::SaveXMLToDatabase() { tinyxml2::XMLElement* character = m_Doc->FirstChildElement("obj")->FirstChildElement("char"); if (character) { - character->SetAttribute("gm", m_GMLevel); + character->SetAttribute("gm", static_cast(m_GMLevel)); character->SetAttribute("cc", m_Coins); auto zoneInfo = dZoneManager::Instance()->GetZone()->GetZoneID(); @@ -545,7 +548,7 @@ void Character::OnZoneLoad() { const auto maxGMLevel = m_ParentUser->GetMaxGMLevel(); // This does not apply to the GMs - if (maxGMLevel > GAME_MASTER_LEVEL_CIVILIAN) { + if (maxGMLevel > eGameMasterLevel::CIVILIAN) { return; } diff --git a/dGame/Character.h b/dGame/Character.h index d77dd022..2f0abba5 100644 --- a/dGame/Character.h +++ b/dGame/Character.h @@ -15,6 +15,7 @@ class User; struct Packet; class Entity; enum class ePermissionMap : uint64_t; +enum class eGameMasterLevel : uint8_t; /** * Meta information about a character, like their name and style @@ -308,13 +309,13 @@ public: * Gets the GM level of the character * @return the GM level */ - int32_t GetGMLevel() const { return m_GMLevel; } + eGameMasterLevel GetGMLevel() const { return m_GMLevel; } /** * Sets the GM level of the character * @param value the GM level to set */ - void SetGMLevel(uint8_t value) { m_GMLevel = value; } + void SetGMLevel(eGameMasterLevel value) { m_GMLevel = value; } /** * Gets the current amount of coins of the character @@ -481,7 +482,7 @@ private: * * @see eGameMasterLevel */ - int32_t m_GMLevel; + eGameMasterLevel m_GMLevel; /** * Bitmap of permission attributes this character has. diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index 13507527..c33a7247 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -70,6 +70,7 @@ #include "RailActivatorComponent.h" #include "LUPExhibitComponent.h" #include "TriggerComponent.h" +#include "eGameMasterLevel.h" #include "eReplicaComponentType.h" // Table includes @@ -89,7 +90,7 @@ Entity::Entity(const LWOOBJID& objectID, EntityInfo info, Entity* parentEntity) m_TemplateID = info.lot; m_ParentEntity = parentEntity; m_Character = nullptr; - m_GMLevel = 0; + m_GMLevel = eGameMasterLevel::CIVILIAN; m_CollectibleID = 0; m_NetworkID = 0; m_Groups = {}; @@ -857,7 +858,7 @@ void Entity::SetProximityRadius(dpEntity* entity, std::string name) { proxMon->SetProximityRadius(entity, name); } -void Entity::SetGMLevel(uint8_t value) { +void Entity::SetGMLevel(eGameMasterLevel value) { m_GMLevel = value; if (GetParentUser()) { Character* character = GetParentUser()->GetLastUsedChar(); @@ -969,7 +970,7 @@ void Entity::WriteBaseReplicaData(RakNet::BitStream* outBitStream, eReplicaPacke outBitStream->Write0(); //ObjectWorldState - if (m_GMLevel != 0) { + if (m_GMLevel != eGameMasterLevel::CIVILIAN) { outBitStream->Write1(); outBitStream->Write(m_GMLevel); } else outBitStream->Write0(); //No GM Level diff --git a/dGame/Entity.h b/dGame/Entity.h index ae16fb82..f8abff31 100644 --- a/dGame/Entity.h +++ b/dGame/Entity.h @@ -31,6 +31,7 @@ class Item; class Character; class EntityCallbackTimer; enum class eTriggerEventType; +enum class eGameMasterLevel : uint8_t; enum class eReplicaComponentType : uint32_t; namespace CppScripts { @@ -60,7 +61,7 @@ public: Character* GetCharacter() const { return m_Character; } - uint8_t GetGMLevel() const { return m_GMLevel; } + eGameMasterLevel GetGMLevel() const { return m_GMLevel; } uint8_t GetCollectibleID() const { return uint8_t(m_CollectibleID); } @@ -108,7 +109,7 @@ public: void SetCharacter(Character* value) { m_Character = value; } - void SetGMLevel(uint8_t value); + void SetGMLevel(eGameMasterLevel value); void SetOwnerOverride(LWOOBJID value); @@ -308,7 +309,7 @@ protected: Entity* m_ParentEntity; //For spawners and the like std::vector m_ChildEntities; - uint8_t m_GMLevel; + eGameMasterLevel m_GMLevel; uint16_t m_CollectibleID; std::vector m_Groups; uint16_t m_NetworkID; diff --git a/dGame/EntityManager.cpp b/dGame/EntityManager.cpp index e79ada25..31b755fe 100644 --- a/dGame/EntityManager.cpp +++ b/dGame/EntityManager.cpp @@ -20,6 +20,7 @@ #include "MessageIdentifiers.h" #include "dConfig.h" #include "eTriggerEventType.h" +#include "eGameMasterLevel.h" #include "eReplicaComponentType.h" EntityManager* EntityManager::m_Address = nullptr; @@ -370,7 +371,7 @@ void EntityManager::ConstructEntity(Entity* entity, const SystemAddress& sysAddr // PacketUtils::SavePacket("[24]_"+std::to_string(entity->GetObjectID()) + "_" + std::to_string(m_SerializationCounter) + ".bin", (char*)stream.GetData(), stream.GetNumberOfBytesUsed()); if (entity->IsPlayer()) { - if (entity->GetGMLevel() > GAME_MASTER_LEVEL_CIVILIAN) { + if (entity->GetGMLevel() > eGameMasterLevel::CIVILIAN) { GameMessages::SendToggleGMInvis(entity->GetObjectID(), true, sysAddr); } } diff --git a/dGame/User.cpp b/dGame/User.cpp index dc607cd0..55bbcc09 100644 --- a/dGame/User.cpp +++ b/dGame/User.cpp @@ -6,13 +6,14 @@ #include "Game.h" #include "dZoneManager.h" #include "eServerDisconnectIdentifiers.h" +#include "eGameMasterLevel.h" User::User(const SystemAddress& sysAddr, const std::string& username, const std::string& sessionKey) { m_AccountID = 0; m_Username = ""; m_SessionKey = ""; - m_MaxGMLevel = 0; //The max GM level this account can assign to it's characters + m_MaxGMLevel = eGameMasterLevel::CIVILIAN; //The max GM level this account can assign to it's characters m_LastCharID = 0; m_SessionKey = sessionKey; @@ -33,7 +34,7 @@ User::User(const SystemAddress& sysAddr, const std::string& username, const std: sql::ResultSet* res = stmt->executeQuery(); while (res->next()) { m_AccountID = res->getUInt(1); - m_MaxGMLevel = res->getInt(2); + m_MaxGMLevel = static_cast(res->getInt(2)); m_MuteExpire = 0; //res->getUInt64(3); } diff --git a/dGame/User.h b/dGame/User.h index 59416c4c..3201538e 100644 --- a/dGame/User.h +++ b/dGame/User.h @@ -9,6 +9,7 @@ #include class Character; +enum class eGameMasterLevel : uint8_t; struct BehaviorParams { uint32_t behavior; @@ -29,7 +30,7 @@ public: std::string& GetSessionKey() { return m_SessionKey; } SystemAddress& GetSystemAddress() { return m_SystemAddress; } - uint32_t GetMaxGMLevel() { return m_MaxGMLevel; } + eGameMasterLevel GetMaxGMLevel() { return m_MaxGMLevel; } uint32_t GetLastCharID() { return m_LastCharID; } void SetLastCharID(uint32_t newCharID) { m_LastCharID = newCharID; } @@ -61,7 +62,7 @@ private: std::string m_SessionKey; SystemAddress m_SystemAddress; - uint32_t m_MaxGMLevel; //The max GM level this account can assign to it's characters + eGameMasterLevel m_MaxGMLevel; //The max GM level this account can assign to it's characters uint32_t m_LastCharID; std::vector m_Characters; LWOOBJID m_LoggedInCharID; diff --git a/dGame/UserManager.cpp b/dGame/UserManager.cpp index 93469daa..4f0c456d 100644 --- a/dGame/UserManager.cpp +++ b/dGame/UserManager.cpp @@ -23,6 +23,7 @@ #include "AssetManager.h" #include "CDClientDatabase.h" #include "dMessageIdentifiers.h" +#include "eGameMasterLevel.h" UserManager* UserManager::m_Address = nullptr; @@ -330,7 +331,7 @@ void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet) //Check to see if our name was pre-approved: bool nameOk = IsNamePreapproved(name); - if (!nameOk && u->GetMaxGMLevel() > 1) nameOk = true; + if (!nameOk && u->GetMaxGMLevel() > eGameMasterLevel::FORUM_MODERATOR) nameOk = true; if (name != "") { sql::PreparedStatement* stmt = Database::CreatePreppedStmt("INSERT INTO `charinfo`(`id`, `account_id`, `name`, `pending_name`, `needs_rename`, `last_login`) VALUES (?,?,?,?,?,?)"); diff --git a/dGame/dComponents/CharacterComponent.cpp b/dGame/dComponents/CharacterComponent.cpp index 98540bd0..6394cc32 100644 --- a/dGame/dComponents/CharacterComponent.cpp +++ b/dGame/dComponents/CharacterComponent.cpp @@ -14,6 +14,7 @@ #include "GameMessages.h" #include "Item.h" #include "AMFFormat.h" +#include "eGameMasterLevel.h" CharacterComponent::CharacterComponent(Entity* parent, Character* character) : Component(parent) { m_Character = character; @@ -165,9 +166,9 @@ void CharacterComponent::SetPvpEnabled(const bool value) { m_PvpEnabled = value; } -void CharacterComponent::SetGMLevel(int gmlevel) { +void CharacterComponent::SetGMLevel(eGameMasterLevel gmlevel) { m_DirtyGMInfo = true; - if (gmlevel > 0) m_IsGM = true; + if (gmlevel > eGameMasterLevel::CIVILIAN) m_IsGM = true; else m_IsGM = false; m_GMLevel = gmlevel; } @@ -239,7 +240,7 @@ void CharacterComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { // End custom attributes // - if (m_GMLevel > 0) { + if (m_GMLevel > eGameMasterLevel::CIVILIAN) { m_IsGM = true; m_DirtyGMInfo = true; m_EditorLevel = m_GMLevel; diff --git a/dGame/dComponents/CharacterComponent.h b/dGame/dComponents/CharacterComponent.h index 613f2322..0e047494 100644 --- a/dGame/dComponents/CharacterComponent.h +++ b/dGame/dComponents/CharacterComponent.h @@ -178,7 +178,7 @@ public: * Sets the GM level of the character, should be called in the entity. Here it's set for serialization * @param gmlevel the gm level to set */ - void SetGMLevel(int gmlevel); + void SetGMLevel(eGameMasterLevel gmlevel); /** * Initializes the player statistics from the string stored in the XML @@ -333,7 +333,7 @@ private: /** * The current GM level of this character (anything > 0 counts as a GM) */ - unsigned char m_GMLevel; + eGameMasterLevel m_GMLevel; /** * Whether the character has HF enabled @@ -343,7 +343,7 @@ private: /** * The level of the character in HF */ - unsigned char m_EditorLevel; + eGameMasterLevel m_EditorLevel; /** * Whether the currently active activity has been changed diff --git a/dGame/dComponents/PetComponent.cpp b/dGame/dComponents/PetComponent.cpp index 5549f952..090e5791 100644 --- a/dGame/dComponents/PetComponent.cpp +++ b/dGame/dComponents/PetComponent.cpp @@ -22,7 +22,7 @@ #include "Database.h" #include "EntityInfo.h" #include "eMissionTaskType.h" - +#include "eGameMasterLevel.h" std::unordered_map PetComponent::buildCache{}; std::unordered_map PetComponent::currentActivities{}; @@ -988,7 +988,7 @@ void PetComponent::Command(NiPoint3 position, LWOOBJID source, int32_t commandTy // TODO: Go to player } - if (owner->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (owner->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { ChatPackets::SendSystemMessage(owner->GetSystemAddress(), u"Commmand Type: " + (GeneralUtils::to_u16string(commandType)) + u" - Type Id: " + (GeneralUtils::to_u16string(typeId))); } } @@ -1080,7 +1080,7 @@ void PetComponent::SetPetNameForModeration(const std::string& petName) { int approved = 1; //default, in mod //Make sure that the name isn't already auto-approved: - if (Game::chatFilter->IsSentenceOkay(petName, 0).empty()) { + if (Game::chatFilter->IsSentenceOkay(petName, eGameMasterLevel::CIVILIAN).empty()) { approved = 2; //approved } diff --git a/dGame/dComponents/PropertyEntranceComponent.cpp b/dGame/dComponents/PropertyEntranceComponent.cpp index fa838ed7..c251dc96 100644 --- a/dGame/dComponents/PropertyEntranceComponent.cpp +++ b/dGame/dComponents/PropertyEntranceComponent.cpp @@ -12,6 +12,7 @@ #include "UserManager.h" #include "dLogger.h" #include "AMFFormat.h" +#include "eGameMasterLevel.h" PropertyEntranceComponent::PropertyEntranceComponent(uint32_t componentID, Entity* parent) : Component(parent) { this->propertyQueries = {}; @@ -271,7 +272,7 @@ void PropertyEntranceComponent::OnPropertyEntranceSync(Entity* entity, bool incl bool isModeratorApproved = propertyEntry->getBoolean(10); - if (!isModeratorApproved && entity->GetGMLevel() >= GAME_MASTER_LEVEL_LEAD_MODERATOR) { + if (!isModeratorApproved && entity->GetGMLevel() >= eGameMasterLevel::LEAD_MODERATOR) { propertyName = "[AWAITING APPROVAL]"; propertyDescription = "[AWAITING APPROVAL]"; isModeratorApproved = true; diff --git a/dGame/dComponents/ScriptedActivityComponent.cpp b/dGame/dComponents/ScriptedActivityComponent.cpp index bafa1faa..1bc8c01f 100644 --- a/dGame/dComponents/ScriptedActivityComponent.cpp +++ b/dGame/dComponents/ScriptedActivityComponent.cpp @@ -303,7 +303,7 @@ bool ScriptedActivityComponent::HasLobby() const { bool ScriptedActivityComponent::IsValidActivity(Entity* player) { // Makes it so that scripted activities with an unimplemented map cannot be joined - /*if (player->GetGMLevel() < GAME_MASTER_LEVEL_DEVELOPER && (m_ActivityInfo.instanceMapID == 1302 || m_ActivityInfo.instanceMapID == 1301)) { + /*if (player->GetGMLevel() < eGameMasterLevel::DEVELOPER && (m_ActivityInfo.instanceMapID == 1302 || m_ActivityInfo.instanceMapID == 1301)) { if (m_Parent->GetLOT() == 4860) { auto* missionComponent = player->GetComponent(); missionComponent->CompleteMission(229); diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index 8604d136..2941a0f9 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -409,7 +409,7 @@ void GameMessages::SendServerDoneLoadingAllObjects(Entity* entity, const SystemA SEND_PACKET; } -void GameMessages::SendChatModeUpdate(const LWOOBJID& objectID, uint8_t level) { +void GameMessages::SendChatModeUpdate(const LWOOBJID& objectID, eGameMasterLevel level) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectID); @@ -418,7 +418,7 @@ void GameMessages::SendChatModeUpdate(const LWOOBJID& objectID, uint8_t level) { SEND_PACKET_BROADCAST; } -void GameMessages::SendGMLevelBroadcast(const LWOOBJID& objectID, uint8_t level) { +void GameMessages::SendGMLevelBroadcast(const LWOOBJID& objectID, eGameMasterLevel level) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectID); diff --git a/dGame/dGameMessages/GameMessages.h b/dGame/dGameMessages/GameMessages.h index 7305e429..1372003e 100644 --- a/dGame/dGameMessages/GameMessages.h +++ b/dGame/dGameMessages/GameMessages.h @@ -21,6 +21,7 @@ enum class eAnimationFlags : uint32_t; enum class eUnequippableActiveType; enum eInventoryType : uint32_t; +enum class eGameMasterLevel : uint8_t; namespace GameMessages { class PropertyDataMessage; @@ -61,8 +62,8 @@ namespace GameMessages { void SendRestoreToPostLoadStats(Entity* entity, const SystemAddress& sysAddr); void SendServerDoneLoadingAllObjects(Entity* entity, const SystemAddress& sysAddr); - void SendGMLevelBroadcast(const LWOOBJID& objectID, uint8_t level); - void SendChatModeUpdate(const LWOOBJID& objectID, uint8_t level); + void SendGMLevelBroadcast(const LWOOBJID& objectID, eGameMasterLevel level); + void SendChatModeUpdate(const LWOOBJID& objectID, eGameMasterLevel level); void SendAddItemToInventoryClientSync(Entity* entity, const SystemAddress& sysAddr, Item* item, const LWOOBJID& objectID, bool showFlyingLoot, int itemCount, LWOOBJID subKey = LWOOBJID_EMPTY, eLootSourceType lootSourceType = eLootSourceType::LOOT_SOURCE_NONE); void SendNotifyClientFlagChange(const LWOOBJID& objectID, int iFlagID, bool bFlag, const SystemAddress& sysAddr); @@ -623,7 +624,7 @@ namespace GameMessages { void HandleReportBug(RakNet::BitStream* inStream, Entity* entity); void SendRemoveBuff(Entity* entity, bool fromUnEquip, bool removeImmunity, uint32_t buffId); - + // bubble void HandleDeactivateBubbleBuff(RakNet::BitStream* inStream, Entity* entity); diff --git a/dGame/dUtilities/SlashCommandHandler.cpp b/dGame/dUtilities/SlashCommandHandler.cpp index 1f3da6c7..f9bf4884 100644 --- a/dGame/dUtilities/SlashCommandHandler.cpp +++ b/dGame/dUtilities/SlashCommandHandler.cpp @@ -75,6 +75,7 @@ #include "eMissionState.h" #include "TriggerComponent.h" #include "eServerDisconnectIdentifiers.h" +#include "eGameMasterLevel.h" #include "eReplicaComponentType.h" #include "CDObjectsTable.h" @@ -121,19 +122,20 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit //Game::logger->Log("SlashCommandHandler", "Received chat command \"%s\"", GeneralUtils::UTF16ToWTF8(command).c_str()); User* user = UserManager::Instance()->GetUser(sysAddr); - if ((chatCommand == "setgmlevel" || chatCommand == "makegm" || chatCommand == "gmlevel") && user->GetMaxGMLevel() > GAME_MASTER_LEVEL_CIVILIAN) { + if ((chatCommand == "setgmlevel" || chatCommand == "makegm" || chatCommand == "gmlevel") && user->GetMaxGMLevel() > eGameMasterLevel::CIVILIAN) { if (args.size() != 1) return; - uint32_t level; + uint32_t level_intermed = 0; - if (!GeneralUtils::TryParse(args[0], level)) { + if (!GeneralUtils::TryParse(args[0], level_intermed)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid gm level."); return; } + eGameMasterLevel level = static_cast(level_intermed); #ifndef DEVELOPER_SERVER - if (user->GetMaxGMLevel() == GAME_MASTER_LEVEL_JUNIOR_DEVELOPER) { - level = GAME_MASTER_LEVEL_CIVILIAN; + if (user->GetMaxGMLevel() == eGameMasterLevel::JUNIOR_DEVELOPER) { + level = eGameMasterLevel::CIVILIAN; } #endif @@ -146,9 +148,9 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit if (success) { - if (entity->GetGMLevel() > GAME_MASTER_LEVEL_CIVILIAN && level == GAME_MASTER_LEVEL_CIVILIAN) { + if (entity->GetGMLevel() > eGameMasterLevel::CIVILIAN && level == eGameMasterLevel::CIVILIAN) { GameMessages::SendToggleGMInvis(entity->GetObjectID(), false, UNASSIGNED_SYSTEM_ADDRESS); - } else if (entity->GetGMLevel() == GAME_MASTER_LEVEL_CIVILIAN && level > GAME_MASTER_LEVEL_CIVILIAN) { + } else if (entity->GetGMLevel() == eGameMasterLevel::CIVILIAN && level > eGameMasterLevel::CIVILIAN) { GameMessages::SendToggleGMInvis(entity->GetObjectID(), true, UNASSIGNED_SYSTEM_ADDRESS); } @@ -160,10 +162,10 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } #ifndef DEVELOPER_SERVER - if ((entity->GetGMLevel() > user->GetMaxGMLevel()) || (entity->GetGMLevel() > GAME_MASTER_LEVEL_CIVILIAN && user->GetMaxGMLevel() == GAME_MASTER_LEVEL_JUNIOR_DEVELOPER)) { - WorldPackets::SendGMLevelChange(sysAddr, true, user->GetMaxGMLevel(), entity->GetGMLevel(), GAME_MASTER_LEVEL_CIVILIAN); - GameMessages::SendChatModeUpdate(entity->GetObjectID(), GAME_MASTER_LEVEL_CIVILIAN); - entity->SetGMLevel(GAME_MASTER_LEVEL_CIVILIAN); + if ((entity->GetGMLevel() > user->GetMaxGMLevel()) || (entity->GetGMLevel() > eGameMasterLevel::CIVILIAN && user->GetMaxGMLevel() == eGameMasterLevel::JUNIOR_DEVELOPER)) { + WorldPackets::SendGMLevelChange(sysAddr, true, user->GetMaxGMLevel(), entity->GetGMLevel(), eGameMasterLevel::CIVILIAN); + GameMessages::SendChatModeUpdate(entity->GetObjectID(), eGameMasterLevel::CIVILIAN); + entity->SetGMLevel(eGameMasterLevel::CIVILIAN); GameMessages::SendToggleGMInvis(entity->GetObjectID(), false, UNASSIGNED_SYSTEM_ADDRESS); @@ -171,7 +173,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } #endif - if (chatCommand == "togglenameplate" && (Game::config->GetValue("allownameplateoff") == "1" || entity->GetGMLevel() > GAME_MASTER_LEVEL_DEVELOPER)) { + if (chatCommand == "togglenameplate" && (Game::config->GetValue("allownameplateoff") == "1" || entity->GetGMLevel() > eGameMasterLevel::DEVELOPER)) { auto* character = entity->GetCharacter(); if (character && character->GetBillboardVisible()) { @@ -349,7 +351,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit }); } - if (user->GetMaxGMLevel() == 0 || entity->GetGMLevel() >= 0) { + if (user->GetMaxGMLevel() == eGameMasterLevel::CIVILIAN || entity->GetGMLevel() >= eGameMasterLevel::CIVILIAN) { if (chatCommand == "die") { entity->Smash(entity->GetObjectID()); } @@ -375,7 +377,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit ChatPackets::SendSystemMessage(sysAddr, u"Map: " + (GeneralUtils::to_u16string(zoneId.GetMapID())) + u"\nClone: " + (GeneralUtils::to_u16string(zoneId.GetCloneID())) + u"\nInstance: " + (GeneralUtils::to_u16string(zoneId.GetInstanceID()))); } - if (entity->GetGMLevel() == 0) return; + if (entity->GetGMLevel() == eGameMasterLevel::CIVILIAN) return; } // Log command to database @@ -385,7 +387,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit stmt->execute(); delete stmt; - if (chatCommand == "setminifig" && args.size() == 2 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_FORUM_MODERATOR) { // could break characters so only allow if GM > 0 + if (chatCommand == "setminifig" && args.size() == 2 && entity->GetGMLevel() >= eGameMasterLevel::FORUM_MODERATOR) { // could break characters so only allow if GM > 0 int32_t minifigItemId; if (!GeneralUtils::TryParse(args[1], minifigItemId)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid Minifig Item Id ID."); @@ -429,7 +431,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit GameMessages::SendToggleGMInvis(entity->GetObjectID(), false, UNASSIGNED_SYSTEM_ADDRESS); // need to retoggle because it gets reenabled on creation of new character } - if ((chatCommand == "playanimation" || chatCommand == "playanim") && args.size() == 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if ((chatCommand == "playanimation" || chatCommand == "playanim") && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { std::u16string anim = GeneralUtils::ASCIIToUTF16(args[0], args[0].size()); GameMessages::SendPlayAnimation(entity, anim); auto* possessorComponent = entity->GetComponent(); @@ -439,7 +441,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } } - if (chatCommand == "list-spawns" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "list-spawns" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { for (const auto& pair : EntityManager::Instance()->GetSpawnPointEntities()) { ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(pair.first)); } @@ -449,7 +451,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "unlock-emote" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "unlock-emote" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { int32_t emoteID; if (!GeneralUtils::TryParse(args[0], emoteID)) { @@ -460,11 +462,11 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit entity->GetCharacter()->UnlockEmote(emoteID); } - if (chatCommand == "force-save" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "force-save" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { entity->GetCharacter()->SaveXMLToDatabase(); } - if (chatCommand == "kill" && args.size() == 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "kill" && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { ChatPackets::SendSystemMessage(sysAddr, u"Brutally murdering that player, if online on this server."); auto* user = UserManager::Instance()->GetUser(args[0]); @@ -479,7 +481,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "speedboost" && args.size() == 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "speedboost" && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { float boost; if (!GeneralUtils::TryParse(args[0], boost)) { @@ -510,7 +512,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit EntityManager::Instance()->SerializeEntity(entity); } - if (chatCommand == "freecam" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "freecam" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { const auto state = !entity->GetVar(u"freecam"); entity->SetVar(u"freecam", state); @@ -520,7 +522,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "setcontrolscheme" && args.size() == 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "setcontrolscheme" && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { uint32_t scheme; if (!GeneralUtils::TryParse(args[0], scheme)) { @@ -534,7 +536,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "approveproperty" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_LEAD_MODERATOR) { + if (chatCommand == "approveproperty" && entity->GetGMLevel() >= eGameMasterLevel::LEAD_MODERATOR) { if (PropertyManagementComponent::Instance() != nullptr) { PropertyManagementComponent::Instance()->UpdateApprovedStatus(true); @@ -543,7 +545,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "setuistate" && args.size() == 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "setuistate" && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { AMFStringValue* value = new AMFStringValue(); value->SetStringValue(args[0]); @@ -556,7 +558,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "toggle" && args.size() == 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "toggle" && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { AMFTrueValue* value = new AMFTrueValue(); AMFArrayValue amfArgs; @@ -568,7 +570,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if ((chatCommand == "setinventorysize" || chatCommand == "setinvsize") && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 1) { + if ((chatCommand == "setinventorysize" || chatCommand == "setinvsize") && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { uint32_t size; if (!GeneralUtils::TryParse(args.at(0), size)) { @@ -609,7 +611,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "runmacro" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "runmacro" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { if (args.size() != 1) return; // Only process if input does not contain separator charaters @@ -639,7 +641,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "addmission" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "addmission" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { if (args.size() == 0) return; uint32_t missionID; @@ -654,7 +656,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "completemission" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "completemission" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { if (args.size() == 0) return; uint32_t missionID; @@ -669,7 +671,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "setflag" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() == 1) { + if (chatCommand == "setflag" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() == 1) { uint32_t flagId; if (!GeneralUtils::TryParse(args[0], flagId)) { @@ -680,7 +682,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit entity->GetCharacter()->SetPlayerFlag(flagId, true); } - if (chatCommand == "setflag" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() == 2) { + if (chatCommand == "setflag" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() == 2) { uint32_t flagId; std::string onOffFlag = args[0]; if (!GeneralUtils::TryParse(args[1], flagId)) { @@ -693,7 +695,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } entity->GetCharacter()->SetPlayerFlag(flagId, onOffFlag == "on"); } - if (chatCommand == "clearflag" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() == 1) { + if (chatCommand == "clearflag" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() == 1) { uint32_t flagId; if (!GeneralUtils::TryParse(args[0], flagId)) { @@ -704,7 +706,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit entity->GetCharacter()->SetPlayerFlag(flagId, false); } - if (chatCommand == "resetmission" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "resetmission" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { if (args.size() == 0) return; uint32_t missionID; @@ -731,7 +733,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "playeffect" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 3) { + if (chatCommand == "playeffect" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 3) { int32_t effectID = 0; if (!GeneralUtils::TryParse(args[0], effectID)) { @@ -742,11 +744,11 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit GameMessages::SendPlayFXEffect(entity->GetObjectID(), effectID, GeneralUtils::ASCIIToUTF16(args[1]), args[2]); } - if (chatCommand == "stopeffect" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 1) { + if (chatCommand == "stopeffect" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { GameMessages::SendStopFXEffect(entity, true, args[0]); } - if (chatCommand == "setanntitle" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "setanntitle" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { if (args.size() < 0) return; std::stringstream ss; @@ -757,7 +759,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "setannmsg" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "setannmsg" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { if (args.size() < 0) return; std::stringstream ss; @@ -768,7 +770,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "announce" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "announce" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { if (entity->GetCharacter()->GetAnnouncementTitle().size() == 0 || entity->GetCharacter()->GetAnnouncementMessage().size() == 0) { ChatPackets::SendSystemMessage(sysAddr, u"Use /setanntitle & /setannmsg <msg> first!"); return; @@ -778,7 +780,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "shutdownuniverse" && entity->GetGMLevel() == GAME_MASTER_LEVEL_OPERATOR) { + if (chatCommand == "shutdownuniverse" && entity->GetGMLevel() == eGameMasterLevel::OPERATOR) { //Tell the master server that we're going to be shutting down whole "universe": CBITSTREAM; PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_SHUTDOWN_UNIVERSE); @@ -790,7 +792,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "getnavmeshheight" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "getnavmeshheight" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { auto control = static_cast<ControllablePhysicsComponent*>(entity->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS)); if (!control) return; @@ -799,7 +801,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit ChatPackets::SendSystemMessage(sysAddr, msg); } - if (chatCommand == "gmadditem" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "gmadditem" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { if (args.size() == 1) { uint32_t itemLOT; @@ -834,7 +836,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } } - if (chatCommand == "mailitem" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_MODERATOR && args.size() >= 2) { + if (chatCommand == "mailitem" && entity->GetGMLevel() >= eGameMasterLevel::MODERATOR && args.size() >= 2) { const auto& playerName = args[0]; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT id from charinfo WHERE name=? LIMIT 1;"); @@ -883,7 +885,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "setname" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "setname" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { std::string name = ""; for (const auto& arg : args) { @@ -893,7 +895,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit GameMessages::SendSetName(entity->GetObjectID(), GeneralUtils::UTF8ToUTF16(name), UNASSIGNED_SYSTEM_ADDRESS); } - if (chatCommand == "title" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "title" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { std::string name = entity->GetCharacter()->GetName() + " - "; for (const auto& arg : args) { @@ -903,7 +905,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit GameMessages::SendSetName(entity->GetObjectID(), GeneralUtils::UTF8ToUTF16(name), UNASSIGNED_SYSTEM_ADDRESS); } - if ((chatCommand == "teleport" || chatCommand == "tele") && entity->GetGMLevel() >= GAME_MASTER_LEVEL_JUNIOR_MODERATOR) { + if ((chatCommand == "teleport" || chatCommand == "tele") && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_MODERATOR) { NiPoint3 pos{}; if (args.size() == 3) { @@ -969,7 +971,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } } - if (chatCommand == "tpall" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "tpall" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { const auto pos = entity->GetPosition(); const auto characters = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::CHARACTER); @@ -981,7 +983,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "dismount" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "dismount" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { auto* possessorComponent = entity->GetComponent<PossessorComponent>(); if (possessorComponent) { auto possessableId = possessorComponent->GetPossessable(); @@ -992,7 +994,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } } - if (chatCommand == "fly" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_JUNIOR_DEVELOPER) { + if (chatCommand == "fly" && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_DEVELOPER) { auto* character = entity->GetCharacter(); if (character) { @@ -1028,7 +1030,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit //------- GM COMMANDS TO ACTUALLY MODERATE -------- - if (chatCommand == "mute" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_JUNIOR_DEVELOPER) { + if (chatCommand == "mute" && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_DEVELOPER) { if (args.size() >= 1) { auto* player = Player::GetPlayer(args[0]); @@ -1123,7 +1125,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } } - if (chatCommand == "kick" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_JUNIOR_MODERATOR) { + if (chatCommand == "kick" && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_MODERATOR) { if (args.size() == 1) { auto* player = Player::GetPlayer(args[0]); @@ -1141,7 +1143,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } } - if (chatCommand == "ban" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_SENIOR_MODERATOR) { + if (chatCommand == "ban" && entity->GetGMLevel() >= eGameMasterLevel::SENIOR_MODERATOR) { if (args.size() == 1) { auto* player = Player::GetPlayer(args[0]); @@ -1190,7 +1192,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit //------------------------------------------------- - if (chatCommand == "buffme" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "buffme" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { auto dest = static_cast<DestroyableComponent*>(entity->GetComponent(eReplicaComponentType::DESTROYABLE)); if (dest) { dest->SetHealth(999); @@ -1203,7 +1205,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit EntityManager::Instance()->SerializeEntity(entity); } - if (chatCommand == "startcelebration" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() == 1) { + if (chatCommand == "startcelebration" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() == 1) { int32_t celebration; if (!GeneralUtils::TryParse(args[0], celebration)) { @@ -1214,7 +1216,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit GameMessages::SendStartCelebrationEffect(entity, entity->GetSystemAddress(), celebration); } - if (chatCommand == "buffmed" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "buffmed" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { auto dest = static_cast<DestroyableComponent*>(entity->GetComponent(eReplicaComponentType::DESTROYABLE)); if (dest) { dest->SetHealth(9); @@ -1227,7 +1229,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit EntityManager::Instance()->SerializeEntity(entity); } - if (chatCommand == "refillstats" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "refillstats" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { auto dest = static_cast<DestroyableComponent*>(entity->GetComponent(eReplicaComponentType::DESTROYABLE)); if (dest) { @@ -1239,7 +1241,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit EntityManager::Instance()->SerializeEntity(entity); } - if (chatCommand == "lookup" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 1) { + if (chatCommand == "lookup" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { auto query = CDClientDatabase::CreatePreppedStmt( "SELECT `id`, `name` FROM `Objects` WHERE `displayName` LIKE ?1 OR `name` LIKE ?1 OR `description` LIKE ?1 LIMIT 50"); // Concatenate all of the arguments into a single query so a multi word query can be used properly. @@ -1261,7 +1263,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } } - if (chatCommand == "spawn" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 1) { + if (chatCommand == "spawn" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { ControllablePhysicsComponent* comp = static_cast<ControllablePhysicsComponent*>(entity->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS)); if (!comp) return; @@ -1302,7 +1304,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit EntityManager::Instance()->ConstructEntity(newEntity); } - if (chatCommand == "spawngroup" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 3) { + if (chatCommand == "spawngroup" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 3) { auto controllablePhysicsComponent = entity->GetComponent<ControllablePhysicsComponent>(); if (!controllablePhysicsComponent) return; @@ -1353,7 +1355,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } } - if ((chatCommand == "giveuscore") && args.size() >= 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if ((chatCommand == "giveuscore") && args.size() >= 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { int32_t uscore; if (!GeneralUtils::TryParse(args[0], uscore)) { @@ -1375,7 +1377,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit GameMessages::SendModifyLEGOScore(entity, entity->GetSystemAddress(), uscore, lootType); } - if ((chatCommand == "setlevel") && args.size() >= 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if ((chatCommand == "setlevel") && args.size() >= 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { // We may be trying to set a specific players level to a level. If so override the entity with the requested players. std::string requestedPlayerToSetLevelOf = ""; if (args.size() > 1) { @@ -1443,7 +1445,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "pos" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "pos" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { const auto position = entity->GetPosition(); ChatPackets::SendSystemMessage(sysAddr, u"<" + (GeneralUtils::to_u16string(position.x)) + u", " + (GeneralUtils::to_u16string(position.y)) + u", " + (GeneralUtils::to_u16string(position.z)) + u">"); @@ -1451,7 +1453,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit std::cout << position.x << ", " << position.y << ", " << position.z << std::endl; } - if (chatCommand == "rot" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "rot" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { const auto rotation = entity->GetRotation(); ChatPackets::SendSystemMessage(sysAddr, u"<" + (GeneralUtils::to_u16string(rotation.w)) + u", " + (GeneralUtils::to_u16string(rotation.x)) + u", " + (GeneralUtils::to_u16string(rotation.y)) + u", " + (GeneralUtils::to_u16string(rotation.z)) + u">"); @@ -1459,22 +1461,22 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit std::cout << rotation.w << ", " << rotation.x << ", " << rotation.y << ", " << rotation.z << std::endl; } - if (chatCommand == "locrow" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "locrow" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { const auto position = entity->GetPosition(); const auto rotation = entity->GetRotation(); std::cout << "<location x=\"" << position.x << "\" y=\"" << position.y << "\" z=\"" << position.z << "\" rw=\"" << rotation.w << "\" rx=\"" << rotation.x << "\" ry=\"" << rotation.y << "\" rz=\"" << rotation.z << "\" />" << std::endl; } - if (chatCommand == "playlvlfx" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "playlvlfx" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { GameMessages::SendPlayFXEffect(entity, 7074, u"create", "7074", LWOOBJID_EMPTY, 1.0f, 1.0f, true); } - if (chatCommand == "playrebuildfx" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "playrebuildfx" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { GameMessages::SendPlayFXEffect(entity, 230, u"rebuild", "230", LWOOBJID_EMPTY, 1.0f, 1.0f, true); } - if ((chatCommand == "freemoney" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) && args.size() == 1) { + if ((chatCommand == "freemoney" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) && args.size() == 1) { int32_t money; if (!GeneralUtils::TryParse(args[0], money)) { @@ -1486,7 +1488,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit ch->SetCoins(ch->GetCoins() + money, eLootSourceType::LOOT_SOURCE_MODERATION); } - if ((chatCommand == "setcurrency") && args.size() == 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if ((chatCommand == "setcurrency") && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { int32_t money; if (!GeneralUtils::TryParse(args[0], money)) { @@ -1499,13 +1501,13 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } // Allow for this on even while not a GM, as it sometimes toggles incorrrectly. - if (chatCommand == "gminvis" && entity->GetParentUser()->GetMaxGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "gminvis" && entity->GetParentUser()->GetMaxGMLevel() >= eGameMasterLevel::DEVELOPER) { GameMessages::SendToggleGMInvis(entity->GetObjectID(), true, UNASSIGNED_SYSTEM_ADDRESS); return; } - if (chatCommand == "gmimmune" && args.size() >= 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "gmimmune" && args.size() >= 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { auto* destroyableComponent = entity->GetComponent<DestroyableComponent>(); int32_t state = false; @@ -1522,7 +1524,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "buff" && args.size() >= 2 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "buff" && args.size() >= 2 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { auto* buffComponent = entity->GetComponent<BuffComponent>(); int32_t id = 0; @@ -1545,7 +1547,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if ((chatCommand == "testmap" && args.size() >= 1) && entity->GetGMLevel() >= GAME_MASTER_LEVEL_FORUM_MODERATOR) { + if ((chatCommand == "testmap" && args.size() >= 1) && entity->GetGMLevel() >= eGameMasterLevel::FORUM_MODERATOR) { ChatPackets::SendSystemMessage(sysAddr, u"Requesting map change..."); uint32_t reqZone; LWOCLONEID cloneId = 0; @@ -1604,7 +1606,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } } - if (chatCommand == "createprivate" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 3) { + if (chatCommand == "createprivate" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 3) { uint32_t zone; if (!GeneralUtils::TryParse(args[0], zone)) { @@ -1628,13 +1630,13 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if ((chatCommand == "debugui") && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if ((chatCommand == "debugui") && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { ChatPackets::SendSystemMessage(sysAddr, u"Opening UIDebugger..."); AMFArrayValue args; GameMessages::SendUIMessageServerToSingleClient(entity, sysAddr, "ToggleUIDebugger;", nullptr); } - if ((chatCommand == "boost") && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if ((chatCommand == "boost") && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { auto* possessorComponent = entity->GetComponent<PossessorComponent>(); if (possessorComponent == nullptr) { @@ -1666,7 +1668,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } - if ((chatCommand == "unboost") && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if ((chatCommand == "unboost") && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { auto* possessorComponent = entity->GetComponent<PossessorComponent>(); if (possessorComponent == nullptr) return; @@ -1676,7 +1678,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit GameMessages::SendVehicleRemovePassiveBoostAction(vehicle->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); } - if (chatCommand == "activatespawner" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 1) { + if (chatCommand == "activatespawner" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { auto spawners = dZoneManager::Instance()->GetSpawnersByName(args[0]); for (auto* spawner : spawners) { @@ -1690,7 +1692,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } } - if (chatCommand == "spawnphysicsverts" && entity->GetGMLevel() >= 6) { + if (chatCommand == "spawnphysicsverts" && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_DEVELOPER) { //Go tell physics to spawn all the vertices: auto entities = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::PHANTOM_PHYSICS); for (auto en : entities) { @@ -1700,7 +1702,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } } - if (chatCommand == "reportproxphys" && entity->GetGMLevel() >= 6) { + if (chatCommand == "reportproxphys" && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_DEVELOPER) { auto entities = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::PROXIMITY_MONITOR); for (auto en : entities) { auto phys = static_cast<ProximityMonitorComponent*>(en->GetComponent(eReplicaComponentType::PROXIMITY_MONITOR)); @@ -1716,7 +1718,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } } - if (chatCommand == "triggerspawner" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 1) { + if (chatCommand == "triggerspawner" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { auto spawners = dZoneManager::Instance()->GetSpawnersByName(args[0]); for (auto* spawner : spawners) { @@ -1730,7 +1732,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } } - if (chatCommand == "reforge" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 2) { + if (chatCommand == "reforge" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 2) { LOT baseItem; LOT reforgedItem; @@ -1747,7 +1749,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit inventoryComponent->AddItem(baseItem, 1, eLootSourceType::LOOT_SOURCE_MODERATION, eInventoryType::INVALID, data); } - if (chatCommand == "crash" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_OPERATOR) { + if (chatCommand == "crash" && entity->GetGMLevel() >= eGameMasterLevel::OPERATOR) { ChatPackets::SendSystemMessage(sysAddr, u"Crashing..."); int* badPtr = nullptr; @@ -1756,7 +1758,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "metrics" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "metrics" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { for (const auto variable : Metrics::GetAllMetrics()) { auto* metric = Metrics::GetMetric(variable); @@ -1793,7 +1795,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "reloadconfig" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "reloadconfig" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { Game::config->ReloadConfig(); VanityUtilities::SpawnVanity(); dpWorld::Instance().Reload(); @@ -1809,7 +1811,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit ChatPackets::SendSystemMessage(sysAddr, u"Successfully reloaded config for world!"); } - if (chatCommand == "rollloot" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_OPERATOR && args.size() >= 3) { + if (chatCommand == "rollloot" && entity->GetGMLevel() >= eGameMasterLevel::OPERATOR && args.size() >= 3) { uint32_t lootMatrixIndex = 0; uint32_t targetLot = 0; uint32_t loops = 1; @@ -1846,7 +1848,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit ChatPackets::SendSystemMessage(sysAddr, message); } - if (chatCommand == "deleteinven" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 1) { + if (chatCommand == "deleteinven" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { eInventoryType inventoryType = eInventoryType::INVALID; if (!GeneralUtils::TryParse(args[0], inventoryType)) { // In this case, we treat the input as a string and try to find it in the reflection list @@ -1873,7 +1875,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit ChatPackets::SendSystemMessage(sysAddr, u"Deleted inventory " + GeneralUtils::UTF8ToUTF16(args[0])); } - if (chatCommand == "inspect" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 1) { + if (chatCommand == "inspect" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { Entity* closest = nullptr; eReplicaComponentType component; diff --git a/dNet/ClientPackets.cpp b/dNet/ClientPackets.cpp index 100efac5..a1c08938 100644 --- a/dNet/ClientPackets.cpp +++ b/dNet/ClientPackets.cpp @@ -32,6 +32,7 @@ #include "CharacterComponent.h" #include "Database.h" #include "dMessageIdentifiers.h" +#include "eGameMasterLevel.h" #include "eReplicaComponentType.h" void ClientPackets::HandleChatMessage(const SystemAddress& sysAddr, Packet* packet) { @@ -66,7 +67,7 @@ void ClientPackets::HandleChatMessage(const SystemAddress& sysAddr, Packet* pack } std::string playerName = user->GetLastUsedChar()->GetName(); - bool isMythran = user->GetLastUsedChar()->GetGMLevel() > 0; + bool isMythran = user->GetLastUsedChar()->GetGMLevel() > eGameMasterLevel::CIVILIAN; if (!user->GetLastChatMessageApproved() && !isMythran) return; diff --git a/dNet/WorldPackets.cpp b/dNet/WorldPackets.cpp index f6a8f558..febb6bc1 100644 --- a/dNet/WorldPackets.cpp +++ b/dNet/WorldPackets.cpp @@ -15,6 +15,7 @@ #include "CharacterComponent.h" #include "ZCompression.h" + void WorldPackets::SendLoadStaticZone(const SystemAddress& sysAddr, float x, float y, float z, uint32_t checksum) { RakNet::BitStream bitStream; PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_LOAD_STATIC_ZONE); @@ -127,7 +128,7 @@ void WorldPackets::SendServerState(const SystemAddress& sysAddr) { SEND_PACKET; } -void WorldPackets::SendCreateCharacter(const SystemAddress& sysAddr, Entity* entity, const std::string& xmlData, const std::u16string& username, int32_t gm) { +void WorldPackets::SendCreateCharacter(const SystemAddress& sysAddr, Entity* entity, const std::string& xmlData, const std::u16string& username, eGameMasterLevel gm) { RakNet::BitStream bitStream; PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_CREATE_CHARACTER); @@ -144,8 +145,8 @@ void WorldPackets::SendCreateCharacter(const SystemAddress& sysAddr, Entity* ent LDFData<LOT>* lot = new LDFData<LOT>(u"template", 1); LDFData<std::string>* xmlConfigData = new LDFData<std::string>(u"xmlData", xmlData); LDFData<std::u16string>* name = new LDFData<std::u16string>(u"name", username); - LDFData<int32_t>* gmlevel = new LDFData<int32_t>(u"gmlevel", gm); - LDFData<int32_t>* chatmode = new LDFData<int32_t>(u"chatmode", gm); + LDFData<int32_t>* gmlevel = new LDFData<int32_t>(u"gmlevel", static_cast<int32_t>(gm)); + LDFData<int32_t>* chatmode = new LDFData<int32_t>(u"chatmode", static_cast<int32_t>(gm)); LDFData<int64_t>* reputation = new LDFData<int64_t>(u"reputation", character->GetReputation()); objid->WriteToPacket(&data); @@ -220,14 +221,14 @@ void WorldPackets::SendChatModerationResponse(const SystemAddress& sysAddr, bool SEND_PACKET; } -void WorldPackets::SendGMLevelChange(const SystemAddress& sysAddr, bool success, uint8_t highestLevel, uint8_t prevLevel, uint8_t newLevel) { +void WorldPackets::SendGMLevelChange(const SystemAddress& sysAddr, bool success, eGameMasterLevel highestLevel, eGameMasterLevel prevLevel, eGameMasterLevel newLevel) { CBITSTREAM; PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_MAKE_GM_RESPONSE); bitStream.Write<uint8_t>(success); - bitStream.Write<uint16_t>(highestLevel); - bitStream.Write<uint16_t>(prevLevel); - bitStream.Write<uint16_t>(newLevel); + bitStream.Write(static_cast<uint16_t>(highestLevel)); + bitStream.Write(static_cast<uint16_t>(prevLevel)); + bitStream.Write(static_cast<uint16_t>(newLevel)); SEND_PACKET; } diff --git a/dNet/WorldPackets.h b/dNet/WorldPackets.h index d9951941..ec20ac22 100644 --- a/dNet/WorldPackets.h +++ b/dNet/WorldPackets.h @@ -8,6 +8,7 @@ class User; struct SystemAddress; +enum class eGameMasterLevel : uint8_t; namespace WorldPackets { void SendLoadStaticZone(const SystemAddress& sysAddr, float x, float y, float z, uint32_t checksum); @@ -17,9 +18,9 @@ namespace WorldPackets { void SendCharacterDeleteResponse(const SystemAddress& sysAddr, bool response); void SendTransferToWorld(const SystemAddress& sysAddr, const std::string& serverIP, uint32_t serverPort, bool mythranShift); void SendServerState(const SystemAddress& sysAddr); - void SendCreateCharacter(const SystemAddress& sysAddr, Entity* entity, const std::string& xmlData, const std::u16string& username, int32_t gm); + void SendCreateCharacter(const SystemAddress& sysAddr, Entity* entity, const std::string& xmlData, const std::u16string& username, eGameMasterLevel gm); void SendChatModerationResponse(const SystemAddress& sysAddr, bool requestAccepted, uint32_t requestID, const std::string& receiver, std::vector<std::pair<uint8_t, uint8_t>> unacceptedItems); - void SendGMLevelChange(const SystemAddress& sysAddr, bool success, uint8_t highestLevel, uint8_t prevLevel, uint8_t newLevel); + void SendGMLevelChange(const SystemAddress& sysAddr, bool success, eGameMasterLevel highestLevel, eGameMasterLevel prevLevel, eGameMasterLevel newLevel); } #endif // WORLDPACKETS_H diff --git a/docs/Commands.md b/docs/Commands.md index 725a03a0..c997c3c4 100644 --- a/docs/Commands.md +++ b/docs/Commands.md @@ -128,13 +128,13 @@ There are 9 Game master levels |Level|Variable Name|Description| |--- |--- |--- | -|0|GAME_MASTER_LEVEL_CIVILIAN|Normal player| -|1|GAME_MASTER_LEVEL_FORUM_MODERATOR|Forum moderator. No permissions on live servers.| -|2|GAME_MASTER_LEVEL_JUNIOR_MODERATOR|Can kick/mute and pull chat logs| -|3|GAME_MASTER_LEVEL_MODERATOR|Can return lost items| -|4|GAME_MASTER_LEVEL_SENIOR_MODERATOR|Can ban| -|5|GAME_MASTER_LEVEL_LEAD_MODERATOR|Can approve properties| -|6|GAME_MASTER_LEVEL_JUNIOR_DEVELOPER|Junior developer & future content team. Civilan on live.| -|7|GAME_MASTER_LEVEL_INACTIVE_DEVELOPER|Inactive developer, limited permissions.| -|8|GAME_MASTER_LEVEL_DEVELOPER|Active developer, full permissions on live.| -|9|GAME_MASTER_LEVEL_OPERATOR|Can shutdown server for restarts & updates.| +|0|CIVILIAN|Normal player| +|1|FORUM_MODERATOR|Forum moderator. No permissions on live servers.| +|2|JUNIOR_MODERATOR|Can kick/mute and pull chat logs| +|3|MODERATOR|Can return lost items| +|4|SENIOR_MODERATOR|Can ban| +|5|LEAD_MODERATOR|Can approve properties| +|6|JUNIOR_DEVELOPER|Junior developer & future content team. Civilan on live.| +|7|INACTIVE_DEVELOPER|Inactive developer, limited permissions.| +|8|DEVELOPER|Active developer, full permissions on live.| +|9|OPERATOR|Can shutdown server for restarts & updates.| From c415d0520afe442827046ce53ae538703e58f0e0 Mon Sep 17 00:00:00 2001 From: Aaron Kimbrell <aronwk.aaron@gmail.com> Date: Sat, 25 Mar 2023 05:26:39 -0500 Subject: [PATCH 3/3] Implement some more trigger event calls and command handlers (#989) * Implement some trigger event calls and command handlers * add zone summary dimissed GM * break and remove log * some cleanup in Gather Targets and blocking out * fix default value of unlock for play cinematic * Log on errors add enum for physics effect type simplify nipoint3 logic check arg count add enum for End behavior * tryparse for nipoint3 * totally didn't forget to include it * bleh c++ is blah * ??? * address feedback * Fix for #1028 --- dCommon/GeneralUtils.cpp | 4 + dCommon/GeneralUtils.h | 3 + dCommon/NiPoint3.cpp | 6 + dCommon/NiPoint3.h | 3 + dCommon/dEnums/dMessageIdentifiers.h | 1 + dCommon/dEnums/eEndBehavior.h | 11 + dCommon/dEnums/ePhysicsEffectType.h | 15 + dCommon/dEnums/eTriggerEventType.h | 2 +- dGame/Entity.cpp | 5 +- dGame/EntityManager.cpp | 4 +- dGame/dComponents/BouncerComponent.cpp | 3 + dGame/dComponents/PhantomPhysicsComponent.cpp | 5 +- dGame/dComponents/PhantomPhysicsComponent.h | 7 +- dGame/dComponents/RebuildComponent.cpp | 3 + dGame/dComponents/SwitchComponent.cpp | 4 +- dGame/dComponents/TriggerComponent.cpp | 409 ++++++++++++++---- dGame/dComponents/TriggerComponent.h | 31 +- dGame/dGameMessages/GameMessageHandler.cpp | 3 + dGame/dGameMessages/GameMessages.cpp | 14 +- dGame/dGameMessages/GameMessages.h | 5 +- dGame/dUtilities/SlashCommandHandler.cpp | 2 +- .../02_server/Map/AG/AgLaserSensorServer.cpp | 3 +- dScripts/02_server/Map/GF/MastTeleport.cpp | 3 +- .../Map/General/ForceVolumeServer.cpp | 3 +- .../02_server/Map/NT/NtAssemblyTubeServer.cpp | 3 +- .../Map/NT/NtSentinelWalkwayServer.cpp | 3 +- .../Map/NT/NtVentureCannonServer.cpp | 3 +- dScripts/BasePropertyServer.cpp | 14 +- dScripts/ai/FV/ActParadoxPipeFix.cpp | 3 +- dZoneManager/Spawner.cpp | 25 +- dZoneManager/Spawner.h | 1 + dZoneManager/dZoneManager.cpp | 12 +- 32 files changed, 461 insertions(+), 152 deletions(-) create mode 100644 dCommon/dEnums/eEndBehavior.h create mode 100644 dCommon/dEnums/ePhysicsEffectType.h diff --git a/dCommon/GeneralUtils.cpp b/dCommon/GeneralUtils.cpp index 54ef5661..df641a1b 100644 --- a/dCommon/GeneralUtils.cpp +++ b/dCommon/GeneralUtils.cpp @@ -319,3 +319,7 @@ std::vector<std::string> GeneralUtils::GetSqlFileNamesFromFolder(const std::stri return sortedFiles; } + +bool GeneralUtils::TryParse(const std::string& x, const std::string& y, const std::string& z, NiPoint3& dst) { + return TryParse<float>(x.c_str(), dst.x) && TryParse<float>(y.c_str(), dst.y) && TryParse<float>(z.c_str(), dst.z); +} diff --git a/dCommon/GeneralUtils.h b/dCommon/GeneralUtils.h index a2a52b45..25aac783 100644 --- a/dCommon/GeneralUtils.h +++ b/dCommon/GeneralUtils.h @@ -10,6 +10,7 @@ #include <type_traits> #include <stdexcept> #include <BitStream.h> +#include "NiPoint3.h" #include "Game.h" #include "dLogger.h" @@ -208,6 +209,8 @@ namespace GeneralUtils { return TryParse<T>(value.c_str(), dst); } + bool TryParse(const std::string& x, const std::string& y, const std::string& z, NiPoint3& dst); + template<typename T> std::u16string to_u16string(T value) { return GeneralUtils::ASCIIToUTF16(std::to_string(value)); diff --git a/dCommon/NiPoint3.cpp b/dCommon/NiPoint3.cpp index a539c4df..b2ffa0d1 100644 --- a/dCommon/NiPoint3.cpp +++ b/dCommon/NiPoint3.cpp @@ -128,6 +128,12 @@ NiPoint3 NiPoint3::operator+(const NiPoint3& point) const { return NiPoint3(this->x + point.x, this->y + point.y, this->z + point.z); } +//! Operator for addition of vectors +NiPoint3 NiPoint3::operator+=(const NiPoint3& point) const { + return NiPoint3(this->x + point.x, this->y + point.y, this->z + point.z); +} + + //! Operator for subtraction of vectors NiPoint3 NiPoint3::operator-(const NiPoint3& point) const { return NiPoint3(this->x - point.x, this->y - point.y, this->z - point.z); diff --git a/dCommon/NiPoint3.h b/dCommon/NiPoint3.h index 6c0b9d3d..f76b9269 100644 --- a/dCommon/NiPoint3.h +++ b/dCommon/NiPoint3.h @@ -135,6 +135,9 @@ public: //! Operator for addition of vectors NiPoint3 operator+(const NiPoint3& point) const; + //! Operator for addition of vectors + NiPoint3 operator+=(const NiPoint3& point) const; + //! Operator for subtraction of vectors NiPoint3 operator-(const NiPoint3& point) const; diff --git a/dCommon/dEnums/dMessageIdentifiers.h b/dCommon/dEnums/dMessageIdentifiers.h index 63d7044e..7c810a2d 100644 --- a/dCommon/dEnums/dMessageIdentifiers.h +++ b/dCommon/dEnums/dMessageIdentifiers.h @@ -445,6 +445,7 @@ enum GAME_MSG : unsigned short { GAME_MSG_BBB_SAVE_RESPONSE = 1006, GAME_MSG_NOTIFY_CLIENT_OBJECT = 1042, GAME_MSG_DISPLAY_ZONE_SUMMARY = 1043, + GAME_MSG_ZONE_SUMMARY_DISMISSED = 1044, GAME_MSG_ACTIVITY_STATE_CHANGE_REQUEST = 1053, GAME_MSG_MODIFY_PLAYER_ZONE_STATISTIC = 1046, GAME_MSG_START_BUILDING_WITH_ITEM = 1057, diff --git a/dCommon/dEnums/eEndBehavior.h b/dCommon/dEnums/eEndBehavior.h new file mode 100644 index 00000000..77afaab4 --- /dev/null +++ b/dCommon/dEnums/eEndBehavior.h @@ -0,0 +1,11 @@ +#ifndef __EENDBEHAVIOR__H__ +#define __EENDBEHAVIOR__H__ + +#include <cstdint> + +enum class eEndBehavior : uint32_t { + RETURN, + WAIT +}; + +#endif //!__EENDBEHAVIOR__H__ diff --git a/dCommon/dEnums/ePhysicsEffectType.h b/dCommon/dEnums/ePhysicsEffectType.h new file mode 100644 index 00000000..1aa68b34 --- /dev/null +++ b/dCommon/dEnums/ePhysicsEffectType.h @@ -0,0 +1,15 @@ +#ifndef __EPHYSICSEFFECTTYPE__H__ +#define __EPHYSICSEFFECTTYPE__H__ + + +#include <cstdint> + +enum class ePhysicsEffectType : uint32_t { + PUSH, + ATTRACT, + REPULSE, + GRAVITY_SCALE, + FRICTION +}; + +#endif //!__EPHYSICSEFFECTTYPE__H__ diff --git a/dCommon/dEnums/eTriggerEventType.h b/dCommon/dEnums/eTriggerEventType.h index 1705ce22..a2daa256 100644 --- a/dCommon/dEnums/eTriggerEventType.h +++ b/dCommon/dEnums/eTriggerEventType.h @@ -35,7 +35,7 @@ public: {"OnTimerDone", eTriggerEventType::TIMER_DONE}, {"OnRebuildComplete", eTriggerEventType::REBUILD_COMPLETE}, {"OnActivated", eTriggerEventType::ACTIVATED}, - {"OnDeactivated", eTriggerEventType::DEACTIVATED}, + {"OnDectivated", eTriggerEventType::DEACTIVATED}, // Dectivated vs Deactivated {"OnArrived", eTriggerEventType::ARRIVED}, {"OnArrivedAtEndOfPath", eTriggerEventType::ARRIVED_AT_END_OF_PATH}, {"OnZoneSummaryDismissed", eTriggerEventType::ZONE_SUMMARY_DISMISSED}, diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index c33a7247..95a550a6 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -763,7 +763,7 @@ void Entity::Initialize() { no_ghosting: - TriggerEvent(eTriggerEventType::CREATE); + TriggerEvent(eTriggerEventType::CREATE, this); if (m_Character) { auto* controllablePhysicsComponent = GetComponent<ControllablePhysicsComponent>(); @@ -1390,7 +1390,7 @@ void Entity::OnEmoteReceived(const int32_t emote, Entity* target) { } void Entity::OnUse(Entity* originator) { - TriggerEvent(eTriggerEventType::INTERACT); + TriggerEvent(eTriggerEventType::INTERACT, originator); for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { script->OnUse(this, originator); @@ -1412,6 +1412,7 @@ void Entity::OnHitOrHealResult(Entity* attacker, int32_t damage) { } void Entity::OnHit(Entity* attacker) { + TriggerEvent(eTriggerEventType::HIT, attacker); for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { script->OnHit(this, attacker); } diff --git a/dGame/EntityManager.cpp b/dGame/EntityManager.cpp index 31b755fe..d547cdb1 100644 --- a/dGame/EntityManager.cpp +++ b/dGame/EntityManager.cpp @@ -163,6 +163,8 @@ void EntityManager::DestroyEntity(Entity* entity) { return; } + entity->TriggerEvent(eTriggerEventType::DESTROY, entity); + const auto id = entity->GetObjectID(); if (std::count(m_EntitiesToDelete.begin(), m_EntitiesToDelete.end(), id)) { @@ -588,7 +590,7 @@ void EntityManager::ScheduleForKill(Entity* entity) { SwitchComponent* switchComp = entity->GetComponent<SwitchComponent>(); if (switchComp) { - entity->TriggerEvent(eTriggerEventType::DEACTIVATED); + entity->TriggerEvent(eTriggerEventType::DEACTIVATED, entity); } const auto objectId = entity->GetObjectID(); diff --git a/dGame/dComponents/BouncerComponent.cpp b/dGame/dComponents/BouncerComponent.cpp index 1f32d6e5..f6a53261 100644 --- a/dGame/dComponents/BouncerComponent.cpp +++ b/dGame/dComponents/BouncerComponent.cpp @@ -7,6 +7,7 @@ #include "dLogger.h" #include "GameMessages.h" #include <BitStream.h> +#include "eTriggerEventType.h" BouncerComponent::BouncerComponent(Entity* parent) : Component(parent) { m_PetEnabled = false; @@ -46,8 +47,10 @@ void BouncerComponent::SetPetBouncerEnabled(bool value) { EntityManager::Instance()->SerializeEntity(m_Parent); if (value) { + m_Parent->TriggerEvent(eTriggerEventType::PET_ON_SWITCH, m_Parent); GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), 1513, u"create", "PetOnSwitch", LWOOBJID_EMPTY, 1, 1, true); } else { + m_Parent->TriggerEvent(eTriggerEventType::PET_OFF_SWITCH, m_Parent); GameMessages::SendStopFXEffect(m_Parent, true, "PetOnSwitch"); } diff --git a/dGame/dComponents/PhantomPhysicsComponent.cpp b/dGame/dComponents/PhantomPhysicsComponent.cpp index 75cef4fb..ce205826 100644 --- a/dGame/dComponents/PhantomPhysicsComponent.cpp +++ b/dGame/dComponents/PhantomPhysicsComponent.cpp @@ -14,6 +14,7 @@ #include "EntityManager.h" #include "ControllablePhysicsComponent.h" #include "GameMessages.h" +#include "ePhysicsEffectType.h" #include "CDClientManager.h" #include "CDComponentsRegistryTable.h" @@ -36,7 +37,7 @@ PhantomPhysicsComponent::PhantomPhysicsComponent(Entity* parent) : Component(par m_PositionInfoDirty = false; m_IsPhysicsEffectActive = false; - m_EffectType = 0; + m_EffectType = ePhysicsEffectType::PUSH; m_DirectionalMultiplier = 0.0f; m_MinMax = false; @@ -405,7 +406,7 @@ void PhantomPhysicsComponent::SetDirectionalMultiplier(float mul) { m_EffectInfoDirty = true; } -void PhantomPhysicsComponent::SetEffectType(uint32_t type) { +void PhantomPhysicsComponent::SetEffectType(ePhysicsEffectType type) { m_EffectType = type; m_EffectInfoDirty = true; } diff --git a/dGame/dComponents/PhantomPhysicsComponent.h b/dGame/dComponents/PhantomPhysicsComponent.h index 0b27db05..cc0d1844 100644 --- a/dGame/dComponents/PhantomPhysicsComponent.h +++ b/dGame/dComponents/PhantomPhysicsComponent.h @@ -17,6 +17,7 @@ class LDFBaseData; class Entity; class dpEntity; +enum class ePhysicsEffectType : uint32_t ; /** * Allows the creation of phantom physics for an entity: a physics object that is generally invisible but can be @@ -103,13 +104,13 @@ public: * Returns the effect that's currently active, defaults to 0 * @return the effect that's currently active */ - uint32_t GetEffectType() const { return m_EffectType; } + ePhysicsEffectType GetEffectType() const { return m_EffectType; } /** * Sets the effect that's currently active * @param type the effect to set */ - void SetEffectType(uint32_t type); + void SetEffectType(ePhysicsEffectType type); /** * Returns the Physics entity for the component @@ -168,7 +169,7 @@ private: /** * The physics effect that's currently active, defaults to 0 */ - uint32_t m_EffectType; + ePhysicsEffectType m_EffectType; /** * A scaling multiplier to add to the directional vector diff --git a/dGame/dComponents/RebuildComponent.cpp b/dGame/dComponents/RebuildComponent.cpp index abd21873..2562b313 100644 --- a/dGame/dComponents/RebuildComponent.cpp +++ b/dGame/dComponents/RebuildComponent.cpp @@ -8,6 +8,7 @@ #include "CharacterComponent.h" #include "MissionComponent.h" #include "eMissionTaskType.h" +#include "eTriggerEventType.h" #include "dServer.h" #include "PacketUtils.h" @@ -495,6 +496,8 @@ void RebuildComponent::CompleteRebuild(Entity* user) { for (const auto& callback : m_RebuildCompleteCallbacks) callback(user); + m_Parent->TriggerEvent(eTriggerEventType::REBUILD_COMPLETE, user); + auto* movingPlatform = m_Parent->GetComponent<MovingPlatformComponent>(); if (movingPlatform != nullptr) { movingPlatform->OnCompleteRebuild(); diff --git a/dGame/dComponents/SwitchComponent.cpp b/dGame/dComponents/SwitchComponent.cpp index dbdf37a9..392d885a 100644 --- a/dGame/dComponents/SwitchComponent.cpp +++ b/dGame/dComponents/SwitchComponent.cpp @@ -43,7 +43,7 @@ void SwitchComponent::EntityEnter(Entity* entity) { } m_Active = true; if (!m_Parent) return; - m_Parent->TriggerEvent(eTriggerEventType::ACTIVATED); + m_Parent->TriggerEvent(eTriggerEventType::ACTIVATED, entity); const auto grpName = m_Parent->GetVarAsString(u"grp_name"); @@ -79,7 +79,7 @@ void SwitchComponent::Update(float deltaTime) { if (m_Timer <= 0.0f) { m_Active = false; if (!m_Parent) return; - m_Parent->TriggerEvent(eTriggerEventType::DEACTIVATED); + m_Parent->TriggerEvent(eTriggerEventType::DEACTIVATED, m_Parent); const auto grpName = m_Parent->GetVarAsString(u"grp_name"); diff --git a/dGame/dComponents/TriggerComponent.cpp b/dGame/dComponents/TriggerComponent.cpp index d98b2eea..0f241116 100644 --- a/dGame/dComponents/TriggerComponent.cpp +++ b/dGame/dComponents/TriggerComponent.cpp @@ -1,10 +1,19 @@ #include "TriggerComponent.h" #include "dZoneManager.h" -#include "LUTriggers.h" +#include "TeamManager.h" #include "eTriggerCommandType.h" +#include "eMissionTaskType.h" +#include "ePhysicsEffectType.h" + +#include "CharacterComponent.h" +#include "ControllablePhysicsComponent.h" #include "MissionComponent.h" #include "PhantomPhysicsComponent.h" -#include "CDMissionTasksTable.h" +#include "Player.h" +#include "RebuildComponent.h" +#include "SkillComponent.h" +#include "eEndBehavior.h" + TriggerComponent::TriggerComponent(Entity* parent, const std::string triggerInfo): Component(parent) { m_Parent = parent; @@ -51,19 +60,37 @@ void TriggerComponent::HandleTriggerCommand(LUTriggers::Command* command, Entity case eTriggerCommandType::FIRE_EVENT: HandleFireEvent(targetEntity, command->args); break; - case eTriggerCommandType::DESTROY_OBJ: break; - case eTriggerCommandType::TOGGLE_TRIGGER: break; - case eTriggerCommandType::RESET_REBUILD: break; + case eTriggerCommandType::DESTROY_OBJ: + HandleDestroyObject(targetEntity, command->args); + break; + case eTriggerCommandType::TOGGLE_TRIGGER: + HandleToggleTrigger(targetEntity, command->args); + break; + case eTriggerCommandType::RESET_REBUILD: + HandleResetRebuild(targetEntity, command->args); + break; case eTriggerCommandType::SET_PATH: break; case eTriggerCommandType::SET_PICK_TYPE: break; - case eTriggerCommandType::MOVE_OBJECT: break; - case eTriggerCommandType::ROTATE_OBJECT: break; - case eTriggerCommandType::PUSH_OBJECT: break; - case eTriggerCommandType::REPEL_OBJECT: break; + case eTriggerCommandType::MOVE_OBJECT: + HandleMoveObject(targetEntity, argArray); + break; + case eTriggerCommandType::ROTATE_OBJECT: + HandleRotateObject(targetEntity, argArray); + break; + case eTriggerCommandType::PUSH_OBJECT: + HandlePushObject(targetEntity, argArray); + break; + case eTriggerCommandType::REPEL_OBJECT: + HandleRepelObject(targetEntity, command->args); + break; case eTriggerCommandType::SET_TIMER: break; case eTriggerCommandType::CANCEL_TIMER: break; - case eTriggerCommandType::PLAY_CINEMATIC: break; - case eTriggerCommandType::TOGGLE_BBB: break; + case eTriggerCommandType::PLAY_CINEMATIC: + HandlePlayCinematic(targetEntity, argArray); + break; + case eTriggerCommandType::TOGGLE_BBB: + HandleToggleBBB(targetEntity, command->args); + break; case eTriggerCommandType::UPDATE_MISSION: HandleUpdateMission(targetEntity, argArray); break; @@ -75,8 +102,43 @@ void TriggerComponent::HandleTriggerCommand(LUTriggers::Command* command, Entity case eTriggerCommandType::STOP_PATHING: break; case eTriggerCommandType::START_PATHING: break; case eTriggerCommandType::LOCK_OR_UNLOCK_CONTROLS: break; - case eTriggerCommandType::PLAY_EFFECT: break; - case eTriggerCommandType::STOP_EFFECT: break; + case eTriggerCommandType::PLAY_EFFECT: + HandlePlayEffect(targetEntity, argArray); + break; + case eTriggerCommandType::STOP_EFFECT: + GameMessages::SendStopFXEffect(targetEntity, true, command->args); + break; + case eTriggerCommandType::CAST_SKILL: + HandleCastSkill(targetEntity, command->args); + break; + case eTriggerCommandType::DISPLAY_ZONE_SUMMARY: + GameMessages::SendDisplayZoneSummary(targetEntity->GetObjectID(), targetEntity->GetSystemAddress(), false, command->args == "1", m_Parent->GetObjectID()); + break; + case eTriggerCommandType::SET_PHYSICS_VOLUME_EFFECT: + HandleSetPhysicsVolumeEffect(targetEntity, argArray); + break; + case eTriggerCommandType::SET_PHYSICS_VOLUME_STATUS: + HandleSetPhysicsVolumeStatus(targetEntity, command->args); + break; + case eTriggerCommandType::SET_MODEL_TO_BUILD: break; + case eTriggerCommandType::SPAWN_MODEL_BRICKS: break; + case eTriggerCommandType::ACTIVATE_SPAWNER_NETWORK: + HandleActivateSpawnerNetwork(command->args); + break; + case eTriggerCommandType::DEACTIVATE_SPAWNER_NETWORK: + HandleDeactivateSpawnerNetwork(command->args); + break; + case eTriggerCommandType::RESET_SPAWNER_NETWORK: + HandleResetSpawnerNetwork(command->args); + break; + case eTriggerCommandType::DESTROY_SPAWNER_NETWORK_OBJECTS: + HandleDestroySpawnerNetworkObjects(command->args); + break; + case eTriggerCommandType::GO_TO_WAYPOINT: break; + case eTriggerCommandType::ACTIVATE_PHYSICS: + HandleActivatePhysics(targetEntity, command->args); + break; + // DEPRECATED BLOCK START case eTriggerCommandType::ACTIVATE_MUSIC_CUE: break; case eTriggerCommandType::DEACTIVATE_MUSIC_CUE: break; case eTriggerCommandType::FLASH_MUSIC_CUE: break; @@ -87,20 +149,7 @@ void TriggerComponent::HandleTriggerCommand(LUTriggers::Command* command, Entity case eTriggerCommandType::STOP_3D_AMBIENT_SOUND: break; case eTriggerCommandType::ACTIVATE_MIXER_PROGRAM: break; case eTriggerCommandType::DEACTIVATE_MIXER_PROGRAM: break; - case eTriggerCommandType::CAST_SKILL: break; - case eTriggerCommandType::DISPLAY_ZONE_SUMMARY: break; - case eTriggerCommandType::SET_PHYSICS_VOLUME_EFFECT: - HandleSetPhysicsVolume(targetEntity, argArray, command->target); - break; - case eTriggerCommandType::SET_PHYSICS_VOLUME_STATUS: break; - case eTriggerCommandType::SET_MODEL_TO_BUILD: break; - case eTriggerCommandType::SPAWN_MODEL_BRICKS: break; - case eTriggerCommandType::ACTIVATE_SPAWNER_NETWORK: break; - case eTriggerCommandType::DEACTIVATE_SPAWNER_NETWORK: break; - case eTriggerCommandType::RESET_SPAWNER_NETWORK: break; - case eTriggerCommandType::DESTROY_SPAWNER_NETWORK_OBJECTS: break; - case eTriggerCommandType::GO_TO_WAYPOINT: break; - case eTriggerCommandType::ACTIVATE_PHYSICS: break; + // DEPRECATED BLOCK END default: Game::logger->LogDebug("TriggerComponent", "Event %i was not handled!", command->id); break; @@ -113,70 +162,262 @@ std::vector<Entity*> TriggerComponent::GatherTargets(LUTriggers::Command* comman if (command->target == "self") entities.push_back(m_Parent); else if (command->target == "zone") { /*TODO*/ } - else if (command->target == "target") { /*TODO*/ } - else if (command->target == "targetTeam") { /*TODO*/ } - else if (command->target == "objGroup") entities = EntityManager::Instance()->GetEntitiesInGroup(command->targetName); - else if (command->target == "allPlayers") { /*TODO*/ } - else if (command->target == "allNPCs") { /*TODO*/ } - - if (optionalTarget) entities.push_back(optionalTarget); + else if (command->target == "target" && optionalTarget) entities.push_back(optionalTarget); + else if (command->target == "targetTeam" && optionalTarget) { + auto* team = TeamManager::Instance()->GetTeam(optionalTarget->GetObjectID()); + for (const auto memberId : team->members) { + auto* member = EntityManager::Instance()->GetEntity(memberId); + if (member) entities.push_back(member); + } + } else if (command->target == "objGroup") entities = EntityManager::Instance()->GetEntitiesInGroup(command->targetName); + else if (command->target == "allPlayers") { + for (auto* player : Player::GetAllPlayers()) { + entities.push_back(player); + } + } else if (command->target == "allNPCs") { /*UNUSED*/ } return entities; } -void TriggerComponent::HandleSetPhysicsVolume(Entity* targetEntity, std::vector<std::string> argArray, std::string target) { - PhantomPhysicsComponent* phanPhys = m_Parent->GetComponent<PhantomPhysicsComponent>(); - if (!phanPhys) return; - - phanPhys->SetPhysicsEffectActive(true); - uint32_t effectType = 0; - std::transform(argArray.at(0).begin(), argArray.at(0).end(), argArray.at(0).begin(), ::tolower); //Transform to lowercase - if (argArray.at(0) == "push") effectType = 0; - else if (argArray.at(0) == "attract") effectType = 1; - else if (argArray.at(0) == "repulse") effectType = 2; - else if (argArray.at(0) == "gravity") effectType = 3; - else if (argArray.at(0) == "friction") effectType = 4; - - phanPhys->SetEffectType(effectType); - phanPhys->SetDirectionalMultiplier(std::stof(argArray.at(1))); - if (argArray.size() > 4) { - NiPoint3 direction = NiPoint3::ZERO; - GeneralUtils::TryParse<float>(argArray.at(2), direction.x); - GeneralUtils::TryParse<float>(argArray.at(3), direction.y); - GeneralUtils::TryParse<float>(argArray.at(4), direction.z); - phanPhys->SetDirection(direction); - } - if (argArray.size() > 5) { - uint32_t min; - GeneralUtils::TryParse<uint32_t>(argArray.at(6), min); - phanPhys->SetMin(min); - - uint32_t max; - GeneralUtils::TryParse<uint32_t>(argArray.at(7), max); - phanPhys->SetMax(max); - } - - // TODO: why is this contruct and not serialize? - if (target == "self") EntityManager::Instance()->ConstructEntity(m_Parent); -} - -void TriggerComponent::HandleUpdateMission(Entity* targetEntity, std::vector<std::string> argArray) { - CDMissionTasksTable* missionTasksTable = CDClientManager::Instance().GetTable<CDMissionTasksTable>(); - std::vector<CDMissionTasks> missionTasks = missionTasksTable->Query([=](CDMissionTasks entry) { - return (entry.targetGroup == argArray.at(4)); - }); - - for (const CDMissionTasks& task : missionTasks) { - MissionComponent* missionComponent = targetEntity->GetComponent<MissionComponent>(); - if (!missionComponent) continue; - - missionComponent->ForceProgress(task.id, task.uid, std::stoi(argArray.at(2))); - } -} - void TriggerComponent::HandleFireEvent(Entity* targetEntity, std::string args) { for (CppScripts::Script* script : CppScripts::GetEntityScripts(targetEntity)) { script->OnFireEventServerSide(targetEntity, m_Parent, args, 0, 0, 0); } } +void TriggerComponent::HandleDestroyObject(Entity* targetEntity, std::string args){ + uint32_t killType; + GeneralUtils::TryParse<uint32_t>(args, killType); + targetEntity->Smash(m_Parent->GetObjectID(), static_cast<eKillType>(killType)); +} + +void TriggerComponent::HandleToggleTrigger(Entity* targetEntity, std::string args){ + auto* triggerComponent = targetEntity->GetComponent<TriggerComponent>(); + if (!triggerComponent) { + Game::logger->Log("TriggerComponent::HandleToggleTrigger", "Trigger component not found!"); + return; + } + triggerComponent->SetTriggerEnabled(args == "1"); +} + +void TriggerComponent::HandleResetRebuild(Entity* targetEntity, std::string args){ + auto* rebuildComponent = targetEntity->GetComponent<RebuildComponent>(); + if (!rebuildComponent) { + Game::logger->Log("TriggerComponent::HandleResetRebuild", "Rebuild component not found!"); + return; + } + rebuildComponent->ResetRebuild(args == "1"); +} + +void TriggerComponent::HandleMoveObject(Entity* targetEntity, std::vector<std::string> argArray){ + if (argArray.size() <= 2) return; + + auto position = targetEntity->GetPosition(); + NiPoint3 offset = NiPoint3::ZERO; + GeneralUtils::TryParse(argArray.at(0), argArray.at(1), argArray.at(2), offset); + + position += offset; + targetEntity->SetPosition(position); +} + +void TriggerComponent::HandleRotateObject(Entity* targetEntity, std::vector<std::string> argArray){ + if (argArray.size() <= 2) return; + + NiPoint3 vector = NiPoint3::ZERO; + GeneralUtils::TryParse(argArray.at(0), argArray.at(1), argArray.at(2), vector); + + NiQuaternion rotation = NiQuaternion::FromEulerAngles(vector); + targetEntity->SetRotation(rotation); +} + +void TriggerComponent::HandlePushObject(Entity* targetEntity, std::vector<std::string> argArray){ + auto* phantomPhysicsComponent = m_Parent->GetComponent<PhantomPhysicsComponent>(); + if (!phantomPhysicsComponent) { + Game::logger->Log("TriggerComponent::HandlePushObject", "Phantom Physics component not found!"); + return; + } + phantomPhysicsComponent->SetPhysicsEffectActive(true); + phantomPhysicsComponent->SetEffectType(ePhysicsEffectType::PUSH); + phantomPhysicsComponent->SetDirectionalMultiplier(1); + NiPoint3 direction = NiPoint3::ZERO; + GeneralUtils::TryParse(argArray.at(0), argArray.at(1), argArray.at(2), direction); + phantomPhysicsComponent->SetDirection(direction); + + EntityManager::Instance()->SerializeEntity(m_Parent); +} + + +void TriggerComponent::HandleRepelObject(Entity* targetEntity, std::string args){ + auto* phantomPhysicsComponent = m_Parent->GetComponent<PhantomPhysicsComponent>(); + if (!phantomPhysicsComponent) { + Game::logger->Log("TriggerComponent::HandleRepelObject", "Phantom Physics component not found!"); + return; + } + float forceMultiplier; + GeneralUtils::TryParse<float>(args, forceMultiplier); + phantomPhysicsComponent->SetPhysicsEffectActive(true); + phantomPhysicsComponent->SetEffectType(ePhysicsEffectType::REPULSE); + phantomPhysicsComponent->SetDirectionalMultiplier(forceMultiplier); + + auto triggerPos = m_Parent->GetPosition(); + auto targetPos = targetEntity->GetPosition(); + + // normalize the vectors to get the direction + auto delta = targetPos - triggerPos; + auto length = delta.Length(); + NiPoint3 direction = delta / length; + phantomPhysicsComponent->SetDirection(direction); + + EntityManager::Instance()->SerializeEntity(m_Parent); +} + +void TriggerComponent::HandlePlayCinematic(Entity* targetEntity, std::vector<std::string> argArray) { + float leadIn = -1.0; + auto wait = eEndBehavior::RETURN; + bool unlock = true; + bool leaveLocked = false; + bool hidePlayer = false; + + if (argArray.size() >= 2) { + GeneralUtils::TryParse<float>(argArray.at(1), leadIn); + if (argArray.size() >= 3 && argArray.at(2) == "wait") { + wait = eEndBehavior::WAIT; + if (argArray.size() >= 4 && argArray.at(3) == "unlock") { + unlock = false; + if (argArray.size() >= 5 && argArray.at(4) == "leavelocked") { + leaveLocked = true; + if (argArray.size() >= 6 && argArray.at(5) == "hideplayer") { + hidePlayer = true; + } + } + } + } + } + + GameMessages::SendPlayCinematic(targetEntity->GetObjectID(), GeneralUtils::UTF8ToUTF16(argArray.at(0)), targetEntity->GetSystemAddress(), true, true, false, false, wait, hidePlayer, leadIn, leaveLocked, unlock); +} + +void TriggerComponent::HandleToggleBBB(Entity* targetEntity, std::string args) { + auto* character = targetEntity->GetCharacter(); + if (!character) { + Game::logger->Log("TriggerComponent::HandleToggleBBB", "Character was not found!"); + return; + } + bool buildMode = !(character->GetBuildMode()); + if (args == "enter") buildMode = true; + else if (args == "exit") buildMode = false; + character->SetBuildMode(buildMode); +} + +void TriggerComponent::HandleUpdateMission(Entity* targetEntity, std::vector<std::string> argArray) { + // there are only explore tasks used + // If others need to be implemented for modding + // then we need a good way to convert this from a string to that enum + if (argArray.at(0) != "exploretask") return; + MissionComponent* missionComponent = targetEntity->GetComponent<MissionComponent>(); + if (!missionComponent){ + Game::logger->Log("TriggerComponent::HandleUpdateMission", "Mission component not found!"); + return; + } + missionComponent->Progress(eMissionTaskType::EXPLORE, 0, 0, argArray.at(4)); +} + +void TriggerComponent::HandlePlayEffect(Entity* targetEntity, std::vector<std::string> argArray) { + if (argArray.size() < 3) return; + int32_t effectID = 0; + if (!GeneralUtils::TryParse<int32_t>(argArray.at(1), effectID)) return; + std::u16string effectType = GeneralUtils::UTF8ToUTF16(argArray.at(2)); + float priority = 1; + if (argArray.size() == 4) GeneralUtils::TryParse<float>(argArray.at(3), priority); + GameMessages::SendPlayFXEffect(targetEntity, effectID, effectType, argArray.at(0), LWOOBJID_EMPTY, priority); +} + +void TriggerComponent::HandleCastSkill(Entity* targetEntity, std::string args){ + auto* skillComponent = targetEntity->GetComponent<SkillComponent>(); + if (!skillComponent) { + Game::logger->Log("TriggerComponent::HandleCastSkill", "Skill component not found!"); + return; + } + uint32_t skillId; + GeneralUtils::TryParse<uint32_t>(args, skillId); + skillComponent->CastSkill(skillId, targetEntity->GetObjectID()); +} + +void TriggerComponent::HandleSetPhysicsVolumeEffect(Entity* targetEntity, std::vector<std::string> argArray) { + auto* phantomPhysicsComponent = targetEntity->GetComponent<PhantomPhysicsComponent>(); + if (!phantomPhysicsComponent) { + Game::logger->Log("TriggerComponent::HandleSetPhysicsVolumeEffect", "Phantom Physics component not found!"); + return; + } + phantomPhysicsComponent->SetPhysicsEffectActive(true); + ePhysicsEffectType effectType = ePhysicsEffectType::PUSH; + std::transform(argArray.at(0).begin(), argArray.at(0).end(), argArray.at(0).begin(), ::tolower); //Transform to lowercase + if (argArray.at(0) == "push") effectType = ePhysicsEffectType::PUSH; + else if (argArray.at(0) == "attract") effectType = ePhysicsEffectType::ATTRACT; + else if (argArray.at(0) == "repulse") effectType = ePhysicsEffectType::REPULSE; + else if (argArray.at(0) == "gravity") effectType = ePhysicsEffectType::GRAVITY_SCALE; + else if (argArray.at(0) == "friction") effectType = ePhysicsEffectType::FRICTION; + + phantomPhysicsComponent->SetEffectType(effectType); + phantomPhysicsComponent->SetDirectionalMultiplier(std::stof(argArray.at(1))); + if (argArray.size() > 4) { + NiPoint3 direction = NiPoint3::ZERO; + GeneralUtils::TryParse(argArray.at(2), argArray.at(3), argArray.at(4), direction); + phantomPhysicsComponent->SetDirection(direction); + } + if (argArray.size() > 5) { + uint32_t min; + GeneralUtils::TryParse<uint32_t>(argArray.at(6), min); + phantomPhysicsComponent->SetMin(min); + + uint32_t max; + GeneralUtils::TryParse<uint32_t>(argArray.at(7), max); + phantomPhysicsComponent->SetMax(max); + } + + EntityManager::Instance()->SerializeEntity(targetEntity); +} + +void TriggerComponent::HandleSetPhysicsVolumeStatus(Entity* targetEntity, std::string args) { + auto* phantomPhysicsComponent = targetEntity->GetComponent<PhantomPhysicsComponent>(); + if (!phantomPhysicsComponent) { + Game::logger->Log("TriggerComponent::HandleSetPhysicsVolumeEffect", "Phantom Physics component not found!"); + return; + } + phantomPhysicsComponent->SetPhysicsEffectActive(args == "On"); + EntityManager::Instance()->SerializeEntity(targetEntity); +} + +void TriggerComponent::HandleActivateSpawnerNetwork(std::string args){ + for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(args)) { + if (spawner) spawner->Activate(); + } +} + +void TriggerComponent::HandleDeactivateSpawnerNetwork(std::string args){ + for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(args)) { + if (spawner) spawner->Deactivate(); + } +} + +void TriggerComponent::HandleResetSpawnerNetwork(std::string args){ + for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(args)) { + if (spawner) spawner->Reset(); + } +} + +void TriggerComponent::HandleDestroySpawnerNetworkObjects(std::string args){ + for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(args)) { + if (spawner) spawner->DestroyAllEntities(); + } +} + +void TriggerComponent::HandleActivatePhysics(Entity* targetEntity, std::string args) { + if (args == "true") { + // TODO add physics entity if there isn't one + } else if (args == "false"){ + // TODO remove Phsyics entity if there is one + } else { + Game::logger->LogDebug("TriggerComponent", "Invalid argument for ActivatePhysics Trigger: %s", args.c_str()); + } +} diff --git a/dGame/dComponents/TriggerComponent.h b/dGame/dComponents/TriggerComponent.h index 492b0449..317da00e 100644 --- a/dGame/dComponents/TriggerComponent.h +++ b/dGame/dComponents/TriggerComponent.h @@ -2,13 +2,9 @@ #define __TRIGGERCOMPONENT__H__ #include "Component.h" +#include "LUTriggers.h" #include "eReplicaComponentType.h" -namespace LUTriggers { - struct Trigger; - struct Command; -}; - class TriggerComponent : public Component { public: static const eReplicaComponentType ComponentType = eReplicaComponentType::TRIGGER; @@ -17,18 +13,35 @@ public: void TriggerEvent(eTriggerEventType event, Entity* optionalTarget = nullptr); LUTriggers::Trigger* GetTrigger() const { return m_Trigger; } + void SetTriggerEnabled(bool enabled){ m_Trigger->enabled = enabled; }; + private: void HandleTriggerCommand(LUTriggers::Command* command, Entity* optionalTarget); - std::vector<std::string> ParseArgs(std::string args); std::vector<Entity*> GatherTargets(LUTriggers::Command* command, Entity* optionalTarget); // Trigger Event Handlers - void HandleSetPhysicsVolume(Entity* targetEntity, std::vector<std::string> argArray, std::string target); - void HandleUpdateMission(Entity* targetEntity, std::vector<std::string> argArray); void HandleFireEvent(Entity* targetEntity, std::string args); - void HandleCastSkill(Entity* targetEntity, uint32_t skillID); + void HandleDestroyObject(Entity* targetEntity, std::string args); + void HandleToggleTrigger(Entity* targetEntity, std::string args); + void HandleResetRebuild(Entity* targetEntity, std::string args); + void HandleMoveObject(Entity* targetEntity, std::vector<std::string> argArray); + void HandleRotateObject(Entity* targetEntity, std::vector<std::string> argArray); + void HandlePushObject(Entity* targetEntity, std::vector<std::string> argArray); + void HandleRepelObject(Entity* targetEntity, std::string args); + void HandlePlayCinematic(Entity* targetEntity, std::vector<std::string> argArray); + void HandleToggleBBB(Entity* targetEntity, std::string args); + void HandleUpdateMission(Entity* targetEntity, std::vector<std::string> argArray); + void HandlePlayEffect(Entity* targetEntity, std::vector<std::string> argArray); + void HandleCastSkill(Entity* targetEntity, std::string args); + void HandleSetPhysicsVolumeEffect(Entity* targetEntity, std::vector<std::string> argArray); + void HandleSetPhysicsVolumeStatus(Entity* targetEntity, std::string args); + void HandleActivateSpawnerNetwork(std::string args); + void HandleDeactivateSpawnerNetwork(std::string args); + void HandleResetSpawnerNetwork(std::string args); + void HandleDestroySpawnerNetworkObjects(std::string args); + void HandleActivatePhysics(Entity* targetEntity, std::string args); LUTriggers::Trigger* m_Trigger; }; diff --git a/dGame/dGameMessages/GameMessageHandler.cpp b/dGame/dGameMessages/GameMessageHandler.cpp index 5c05c28d..c0893a09 100644 --- a/dGame/dGameMessages/GameMessageHandler.cpp +++ b/dGame/dGameMessages/GameMessageHandler.cpp @@ -673,6 +673,9 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System case GAME_MSG_ACTIVATE_BUBBLE_BUFF: GameMessages::HandleActivateBubbleBuff(inStream, entity); break; + case GAME_MSG_ZONE_SUMMARY_DISMISSED: + GameMessages::HandleZoneSummaryDismissed(inStream, entity); + break; default: // Game::logger->Log("GameMessageHandler", "Unknown game message ID: %i", messageID); break; diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index 2941a0f9..bf7476e9 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -34,6 +34,7 @@ #include "eRacingTaskParam.h" #include "eMissionTaskType.h" #include "eMissionState.h" +#include "eTriggerEventType.h" #include <sstream> #include <future> @@ -2813,7 +2814,7 @@ void GameMessages::HandleSetConsumableItem(RakNet::BitStream* inStream, Entity* void GameMessages::SendPlayCinematic(LWOOBJID objectId, std::u16string pathName, const SystemAddress& sysAddr, bool allowGhostUpdates, bool bCloseMultiInteract, bool bSendServerNotify, bool bUseControlledObjectForAudioListener, - int endBehavior, bool hidePlayerDuringCine, float leadIn, bool leavePlayerLockedWhenFinished, + eEndBehavior endBehavior, bool hidePlayerDuringCine, float leadIn, bool leavePlayerLockedWhenFinished, bool lockPlayer, bool result, bool skipIfSamePath, float startTimeAdvance) { CBITSTREAM; CMSGHEADER; @@ -2826,8 +2827,8 @@ void GameMessages::SendPlayCinematic(LWOOBJID objectId, std::u16string pathName, bitStream.Write(bSendServerNotify); bitStream.Write(bUseControlledObjectForAudioListener); - bitStream.Write(endBehavior != 0); - if (endBehavior != 0) bitStream.Write(endBehavior); + bitStream.Write(endBehavior != eEndBehavior::RETURN); + if (endBehavior != eEndBehavior::RETURN) bitStream.Write(endBehavior); bitStream.Write(hidePlayerDuringCine); @@ -6155,6 +6156,13 @@ void GameMessages::SendDeactivateBubbleBuffFromServer(LWOOBJID objectId, const S SEND_PACKET; } +void GameMessages::HandleZoneSummaryDismissed(RakNet::BitStream* inStream, Entity* entity) { + LWOOBJID player_id; + inStream->Read<LWOOBJID>(player_id); + auto target = EntityManager::Instance()->GetEntity(player_id); + entity->TriggerEvent(eTriggerEventType::ZONE_SUMMARY_DISMISSED, target); +}; + void GameMessages::SendSetNamebillboardState(const SystemAddress& sysAddr, LWOOBJID objectId) { CBITSTREAM; CMSGHEADER; diff --git a/dGame/dGameMessages/GameMessages.h b/dGame/dGameMessages/GameMessages.h index 1372003e..68f4542f 100644 --- a/dGame/dGameMessages/GameMessages.h +++ b/dGame/dGameMessages/GameMessages.h @@ -7,6 +7,7 @@ #include <vector> #include "eMovementPlatformState.h" #include "NiPoint3.h" +#include "eEndBehavior.h" class AMFValue; class Entity; @@ -266,7 +267,7 @@ namespace GameMessages { void SendPlayCinematic(LWOOBJID objectId, std::u16string pathName, const SystemAddress& sysAddr, bool allowGhostUpdates = true, bool bCloseMultiInteract = true, bool bSendServerNotify = false, bool bUseControlledObjectForAudioListener = false, - int endBehavior = 0, bool hidePlayerDuringCine = false, float leadIn = -1, bool leavePlayerLockedWhenFinished = false, + eEndBehavior endBehavior = eEndBehavior::RETURN, bool hidePlayerDuringCine = false, float leadIn = -1, bool leavePlayerLockedWhenFinished = false, bool lockPlayer = true, bool result = false, bool skipIfSamePath = false, float startTimeAdvance = 0); void SendEndCinematic(LWOOBJID objectID, std::u16string pathName, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS, @@ -633,6 +634,8 @@ namespace GameMessages { void SendActivateBubbleBuffFromServer(LWOOBJID objectId, const SystemAddress& sysAddr); void SendDeactivateBubbleBuffFromServer(LWOOBJID objectId, const SystemAddress& sysAddr); + + void HandleZoneSummaryDismissed(RakNet::BitStream* inStream, Entity* entity); }; #endif // GAMEMESSAGES_H diff --git a/dGame/dUtilities/SlashCommandHandler.cpp b/dGame/dUtilities/SlashCommandHandler.cpp index f9bf4884..7383d51c 100644 --- a/dGame/dUtilities/SlashCommandHandler.cpp +++ b/dGame/dUtilities/SlashCommandHandler.cpp @@ -2018,7 +2018,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit auto* phantomPhysicsComponent = closest->GetComponent<PhantomPhysicsComponent>(); if (phantomPhysicsComponent != nullptr) { - ChatPackets::SendSystemMessage(sysAddr, u"Type: " + (GeneralUtils::to_u16string(phantomPhysicsComponent->GetEffectType()))); + ChatPackets::SendSystemMessage(sysAddr, u"Type: " + (GeneralUtils::to_u16string(static_cast<uint32_t>(phantomPhysicsComponent->GetEffectType())))); const auto dir = phantomPhysicsComponent->GetDirection(); ChatPackets::SendSystemMessage(sysAddr, u"Direction: <" + (GeneralUtils::to_u16string(dir.x)) + u", " + (GeneralUtils::to_u16string(dir.y)) + u", " + (GeneralUtils::to_u16string(dir.z)) + u">"); ChatPackets::SendSystemMessage(sysAddr, u"Multiplier: " + (GeneralUtils::to_u16string(phantomPhysicsComponent->GetDirectionalMultiplier()))); diff --git a/dScripts/02_server/Map/AG/AgLaserSensorServer.cpp b/dScripts/02_server/Map/AG/AgLaserSensorServer.cpp index c09000be..703625d2 100644 --- a/dScripts/02_server/Map/AG/AgLaserSensorServer.cpp +++ b/dScripts/02_server/Map/AG/AgLaserSensorServer.cpp @@ -5,13 +5,14 @@ #include "EntityManager.h" #include "AgMonumentLaserServer.h" #include "EntityManager.h" +#include "ePhysicsEffectType.h" #include "eReplicaComponentType.h" void AgLaserSensorServer::OnStartup(Entity* self) { PhantomPhysicsComponent* physComp = static_cast<PhantomPhysicsComponent*>(self->GetComponent(eReplicaComponentType::PHANTOM_PHYSICS)); physComp->SetPhysicsEffectActive(true); - physComp->SetEffectType(2); // repulse (prolly should make definitions of these are in Entity.cpp) + physComp->SetEffectType(ePhysicsEffectType::REPULSE); physComp->SetDirectionalMultiplier(static_cast<float>(m_RepelForce)); physComp->SetDirection(NiPoint3::UNIT_Y); diff --git a/dScripts/02_server/Map/GF/MastTeleport.cpp b/dScripts/02_server/Map/GF/MastTeleport.cpp index 6e50c6ec..8b8453b9 100644 --- a/dScripts/02_server/Map/GF/MastTeleport.cpp +++ b/dScripts/02_server/Map/GF/MastTeleport.cpp @@ -2,6 +2,7 @@ #include "EntityManager.h" #include "GameMessages.h" #include "Preconditions.h" +#include "eEndBehavior.h" #include "DestroyableComponent.h" #ifdef _WIN32 @@ -52,7 +53,7 @@ void MastTeleport::OnTimerDone(Entity* self, std::string timerName) { if (!cinematic.empty()) { GameMessages::SendPlayCinematic(playerId, GeneralUtils::ASCIIToUTF16(cinematic), player->GetSystemAddress(), - true, true, false, false, 0, false, leanIn + true, true, false, false, eEndBehavior::RETURN, false, leanIn ); } diff --git a/dScripts/02_server/Map/General/ForceVolumeServer.cpp b/dScripts/02_server/Map/General/ForceVolumeServer.cpp index fbaad6ee..ed9024c1 100644 --- a/dScripts/02_server/Map/General/ForceVolumeServer.cpp +++ b/dScripts/02_server/Map/General/ForceVolumeServer.cpp @@ -1,6 +1,7 @@ #include "ForceVolumeServer.h" #include "PhantomPhysicsComponent.h" #include "EntityManager.h" +#include "ePhysicsEffectType.h" void ForceVolumeServer::OnStartup(Entity* self) { auto* phantomPhysicsComponent = self->GetComponent<PhantomPhysicsComponent>(); @@ -12,7 +13,7 @@ void ForceVolumeServer::OnStartup(Entity* self) { const auto forceY = self->GetVar<float>(u"ForceY"); const auto forceZ = self->GetVar<float>(u"ForceZ"); - phantomPhysicsComponent->SetEffectType(0); // PUSH + phantomPhysicsComponent->SetEffectType(ePhysicsEffectType::PUSH); phantomPhysicsComponent->SetDirectionalMultiplier(forceAmount); phantomPhysicsComponent->SetDirection({ forceX, forceY, forceZ }); phantomPhysicsComponent->SetPhysicsEffectActive(true); diff --git a/dScripts/02_server/Map/NT/NtAssemblyTubeServer.cpp b/dScripts/02_server/Map/NT/NtAssemblyTubeServer.cpp index b4d75296..74f9bd16 100644 --- a/dScripts/02_server/Map/NT/NtAssemblyTubeServer.cpp +++ b/dScripts/02_server/Map/NT/NtAssemblyTubeServer.cpp @@ -4,6 +4,7 @@ #include "MissionComponent.h" #include "eMissionTaskType.h" #include "eMissionState.h" +#include "eEndBehavior.h" void NtAssemblyTubeServer::OnStartup(Entity* self) { self->SetProximityRadius(5, "teleport"); @@ -45,7 +46,7 @@ void NtAssemblyTubeServer::RunAssemblyTube(Entity* self, Entity* player) { if (!teleCinematic.empty()) { const auto teleCinematicUname = teleCinematic; GameMessages::SendPlayCinematic(player->GetObjectID(), teleCinematicUname, player->GetSystemAddress(), - true, true, true, false, 0, false, -1, false, true + true, true, true, false, eEndBehavior::RETURN, false, -1, false, true ); } diff --git a/dScripts/02_server/Map/NT/NtSentinelWalkwayServer.cpp b/dScripts/02_server/Map/NT/NtSentinelWalkwayServer.cpp index 66bfe46f..257bf6da 100644 --- a/dScripts/02_server/Map/NT/NtSentinelWalkwayServer.cpp +++ b/dScripts/02_server/Map/NT/NtSentinelWalkwayServer.cpp @@ -3,6 +3,7 @@ #include "EntityManager.h" #include "MissionComponent.h" #include "eMissionTaskType.h" +#include "ePhysicsEffectType.h" void NtSentinelWalkwayServer::OnStartup(Entity* self) { auto* phantomPhysicsComponent = self->GetComponent<PhantomPhysicsComponent>(); @@ -19,7 +20,7 @@ void NtSentinelWalkwayServer::OnStartup(Entity* self) { const auto forward = self->GetRotation().GetRightVector() * -1; - phantomPhysicsComponent->SetEffectType(0); // PUSH + phantomPhysicsComponent->SetEffectType(ePhysicsEffectType::PUSH); phantomPhysicsComponent->SetDirectionalMultiplier(force); phantomPhysicsComponent->SetDirection(forward); phantomPhysicsComponent->SetPhysicsEffectActive(true); diff --git a/dScripts/02_server/Map/NT/NtVentureCannonServer.cpp b/dScripts/02_server/Map/NT/NtVentureCannonServer.cpp index e6cd2df6..874d8aa1 100644 --- a/dScripts/02_server/Map/NT/NtVentureCannonServer.cpp +++ b/dScripts/02_server/Map/NT/NtVentureCannonServer.cpp @@ -1,6 +1,7 @@ #include "NtVentureCannonServer.h" #include "GameMessages.h" #include "EntityManager.h" +#include "eEndBehavior.h" void NtVentureCannonServer::OnUse(Entity* self, Entity* user) { auto* player = user; @@ -73,7 +74,7 @@ void NtVentureCannonServer::EnterCannonEnded(Entity* self, Entity* player) { const auto exitCinematicUname = exitCinematic; GameMessages::SendPlayCinematic(player->GetObjectID(), exitCinematicUname, player->GetSystemAddress(), - true, true, true, false, 0, false, 0, false, false + true, true, true, false, eEndBehavior::RETURN, false, 0, false, false ); self->AddCallbackTimer(1.5f, [this, self, playerID]() { diff --git a/dScripts/BasePropertyServer.cpp b/dScripts/BasePropertyServer.cpp index 7552eeca..a9f35e25 100644 --- a/dScripts/BasePropertyServer.cpp +++ b/dScripts/BasePropertyServer.cpp @@ -303,18 +303,8 @@ void BasePropertyServer::ResetSpawner(const std::string& spawnerName) { void BasePropertyServer::DestroySpawner(const std::string& spawnerName) { for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(spawnerName)) { - for (auto* node : spawner->m_Info.nodes) { - for (const auto& element : node->entities) { - auto* entity = EntityManager::Instance()->GetEntity(element); - if (entity == nullptr) - continue; - - entity->Kill(); - } - - node->entities.clear(); - } - + if (!spawner) return; + spawner->DestroyAllEntities(); spawner->Deactivate(); } } diff --git a/dScripts/ai/FV/ActParadoxPipeFix.cpp b/dScripts/ai/FV/ActParadoxPipeFix.cpp index 1dddde64..517474a9 100644 --- a/dScripts/ai/FV/ActParadoxPipeFix.cpp +++ b/dScripts/ai/FV/ActParadoxPipeFix.cpp @@ -3,6 +3,7 @@ #include "RebuildComponent.h" #include "GameMessages.h" #include "MissionComponent.h" +#include "eEndBehavior.h" void ActParadoxPipeFix::OnRebuildComplete(Entity* self, Entity* target) { const auto myGroup = "AllPipes"; @@ -42,7 +43,7 @@ void ActParadoxPipeFix::OnRebuildComplete(Entity* self, Entity* target) { missionComponent->ForceProgressTaskType(769, 1, 1, false); } - GameMessages::SendPlayCinematic(player->GetObjectID(), u"ParadoxPipeFinish", player->GetSystemAddress(), true, true, false, false, 0, false, 2.0f); + GameMessages::SendPlayCinematic(player->GetObjectID(), u"ParadoxPipeFinish", player->GetSystemAddress(), true, true, false, false, eEndBehavior::RETURN, false, 2.0f); } object->SetVar(u"PlayerID", LWOOBJID_EMPTY); diff --git a/dZoneManager/Spawner.cpp b/dZoneManager/Spawner.cpp index 57b4e988..28f77fea 100644 --- a/dZoneManager/Spawner.cpp +++ b/dZoneManager/Spawner.cpp @@ -134,24 +134,23 @@ void Spawner::AddEntitySpawnedCallback(std::function<void(Entity*)> callback) { void Spawner::Reset() { m_Start = true; - - for (auto* node : m_Info.nodes) { - for (const auto& spawned : node->entities) { - auto* entity = EntityManager::Instance()->GetEntity(spawned); - - if (entity == nullptr) continue; - - entity->Kill(); - } - - node->entities.clear(); - } - + DestroyAllEntities(); m_Entities.clear(); m_AmountSpawned = 0; m_NeedsUpdate = true; } +void Spawner::DestroyAllEntities(){ + for (auto* node : m_Info.nodes) { + for (const auto& element : node->entities) { + auto* entity = EntityManager::Instance()->GetEntity(element); + if (entity == nullptr) continue; + entity->Kill(); + } + node->entities.clear(); + } +} + void Spawner::SoftReset() { m_Start = true; m_AmountSpawned = 0; diff --git a/dZoneManager/Spawner.h b/dZoneManager/Spawner.h index a42c8a65..1f610b71 100644 --- a/dZoneManager/Spawner.h +++ b/dZoneManager/Spawner.h @@ -61,6 +61,7 @@ public: void AddEntitySpawnedCallback(std::function<void(Entity*)> callback); void SetSpawnLot(LOT lot); void Reset(); + void DestroyAllEntities(); void SoftReset(); void SetRespawnTime(float time); void SetNumToMaintain(int32_t value); diff --git a/dZoneManager/dZoneManager.cpp b/dZoneManager/dZoneManager.cpp index 52008b5d..ac3a7008 100644 --- a/dZoneManager/dZoneManager.cpp +++ b/dZoneManager/dZoneManager.cpp @@ -182,17 +182,7 @@ void dZoneManager::RemoveSpawner(const LWOOBJID id) { Game::logger->Log("dZoneManager", "Failed to find spawner entity (%llu)", id); } - for (auto* node : spawner->m_Info.nodes) { - for (const auto& element : node->entities) { - auto* nodeEntity = EntityManager::Instance()->GetEntity(element); - - if (nodeEntity == nullptr) continue; - - nodeEntity->Kill(); - } - - node->entities.clear(); - } + spawner->DestroyAllEntities(); spawner->Deactivate();