From b11a41fd30ab426c7cd934abd9219f3eb8b63a5d Mon Sep 17 00:00:00 2001 From: David Markowitz Date: Sun, 31 Mar 2024 04:36:53 -0700 Subject: [PATCH] move all commands to functions --- dGame/dUtilities/SlashCommandHandler.cpp | 3906 +++++++++++----------- dGame/dUtilities/SlashCommandHandler.h | 193 +- 2 files changed, 2062 insertions(+), 2037 deletions(-) diff --git a/dGame/dUtilities/SlashCommandHandler.cpp b/dGame/dUtilities/SlashCommandHandler.cpp index 48cd5b60..877b32be 100644 --- a/dGame/dUtilities/SlashCommandHandler.cpp +++ b/dGame/dUtilities/SlashCommandHandler.cpp @@ -1,6 +1,6 @@ /* * Darkflame Universe - * Copyright 2018 + * Copyright 2024 */ #include "SlashCommandHandler.h" @@ -11,15 +11,6 @@ #include #include "dZoneManager.h" -#include /* defines FILENAME_MAX */ -#ifdef _WIN32 -#include -#define GetCurrentDir _getcwd -#else -#include -#define GetCurrentDir getcwd -#endif - #include "Metrics.hpp" #include "User.h" @@ -100,7 +91,7 @@ void SlashCommandHandler::RegisterCommand(Command command) { }; // DEV Commands -void DEVGMCommands::SetGMLevel(Entity* entity, const std::string args) { +void DEVGMCommands::SetGMLevel(Entity* entity, const SystemAddress& sysAddr, const std::string args) { User* user = UserManager::Instance()->GetUser(entity->GetSystemAddress()); const auto level_intermed = GeneralUtils::TryParse(args); @@ -141,7 +132,7 @@ void DEVGMCommands::SetGMLevel(Entity* entity, const std::string args) { #endif } -void DEVGMCommands::ToggleNameplate(Entity* entity, const std::string args) { +void DEVGMCommands::ToggleNameplate(Entity* entity, const SystemAddress& sysAddr, const std::string args) { if ((Game::config->GetValue("allow_nameplate_off") != "1" && entity->GetGMLevel() < eGameMasterLevel::DEVELOPER)) return; auto* character = entity->GetCharacter(); @@ -154,34 +145,34 @@ void DEVGMCommands::ToggleNameplate(Entity* entity, const std::string args) { } } -void DEVGMCommands::ToggleSkipCinematics(Entity* entity, const std::string args) { - if (Game::config->GetValue("allow_players_to_skip_cinematics") != "1" && entity->GetGMLevel() < eGameMasterLevel::DEVELOPER) return; - auto* character = entity->GetCharacter(); - if (!character) return; - bool current = character->GetPlayerFlag(ePlayerFlag::DLU_SKIP_CINEMATICS); - character->SetPlayerFlag(ePlayerFlag::DLU_SKIP_CINEMATICS, !current); - if (!current) { - GameMessages::SendSlashCommandFeedbackText(entity, u"You have elected to skip cinematics. Note that not all cinematics can be skipped, but most will be skipped now."); - } else { - GameMessages::SendSlashCommandFeedbackText(entity, u"Cinematics will no longer be skipped."); - } +void DEVGMCommands::ToggleSkipCinematics(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + if (Game::config->GetValue("allow_players_to_skip_cinematics") != "1" && entity->GetGMLevel() < eGameMasterLevel::DEVELOPER) return; + auto* character = entity->GetCharacter(); + if (!character) return; + bool current = character->GetPlayerFlag(ePlayerFlag::DLU_SKIP_CINEMATICS); + character->SetPlayerFlag(ePlayerFlag::DLU_SKIP_CINEMATICS, !current); + if (!current) { + GameMessages::SendSlashCommandFeedbackText(entity, u"You have elected to skip cinematics. Note that not all cinematics can be skipped, but most will be skipped now."); + } else { + GameMessages::SendSlashCommandFeedbackText(entity, u"Cinematics will no longer be skipped."); + } } // Greater Than Zero Commands // GM Zero Commands -void GMZeroCommands::Help(Entity* entity, const std::string args) { +void GMZeroCommands::Help(Entity* entity, const SystemAddress& sysAddr, const std::string args) { if (args.empty()) { std::ostringstream helpMessage; helpMessage << "Commands:\n*"; - for (auto& command: RegisteredCommands) { + for (auto& command : RegisteredCommands) { // TODO: Limit displaying commands based on GM level they require // if (RegisteredCommands[args].requiredLevel > entity->GetGMLevel()) continue; helpMessage << "\t" << command.aliases[0] << ": " << command.info << "\n*"; } GameMessages::SendSlashCommandFeedbackText(entity, GeneralUtils::ASCIIToUTF16(helpMessage.str().substr(0, helpMessage.str().size() - 3))); } else { - for (auto& command: RegisteredCommands) { + for (auto& command : RegisteredCommands) { if (std::find(command.aliases.begin(), command.aliases.end(), args) != command.aliases.end()) { if (entity->GetGMLevel() >= command.requiredLevel) { command.help; @@ -201,43 +192,43 @@ void GMZeroCommands::Help(Entity* entity, const std::string args) { void SlashCommandHandler::Startup() { // Register Dev Commands - Command SetGMLevelCommand( - "", - "", - {"setgmlevel", "makegm", "gmlevel"}, - DEVGMCommands::SetGMLevel, - eGameMasterLevel::CIVILIAN - ); + Command SetGMLevelCommand{ + .help = "", + .info = "", + .aliases = { "setgmlevel", "makegm", "gmlevel" }, + .handle = DEVGMCommands::SetGMLevel, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; RegisterCommand(SetGMLevelCommand); - - Command ToggleNameplateCommand( - "", - "", - {"togglenameplate", "tnp"}, - DEVGMCommands::ToggleNameplate, - eGameMasterLevel::CIVILIAN - ); + + Command ToggleNameplateCommand{ + .help = "", + .info = "", + .aliases = { "togglenameplate", "tnp" }, + .handle = DEVGMCommands::ToggleNameplate, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; RegisterCommand(ToggleNameplateCommand); - Command ToggleSkipCinematicsCommand( - "", - "", - {"toggleskipcinematics", "tsc"}, - DEVGMCommands::ToggleSkipCinematics, - eGameMasterLevel::CIVILIAN - ); + Command ToggleSkipCinematicsCommand{ + .help = "", + .info = "", + .aliases = { "toggleskipcinematics", "tsc" }, + .handle = DEVGMCommands::ToggleSkipCinematics, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; RegisterCommand(ToggleSkipCinematicsCommand); // Register Greater Than Zero Commands // Register GM Zero Commands - Command HelpCommand( - "Display command info", - "If a command is given, display detailed info on that command. Otherwise display a list of commands with short desctiptions.", - {"help", "h"}, - GMZeroCommands::Help, - eGameMasterLevel::CIVILIAN - ); + Command HelpCommand{ + .help = "Display command info", + .info = "If a command is given, display detailed info on that command. Otherwise display a list of commands with short desctiptions.", + .aliases = { "help", "h" }, + .handle = GMZeroCommands::Help, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; RegisterCommand(HelpCommand); } @@ -253,7 +244,8 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& chat, Entity* for (auto& registeredCommand : RegisteredCommands) { if (std::find(registeredCommand.aliases.begin(), registeredCommand.aliases.end(), args) != registeredCommand.aliases.end()) { if (entity->GetGMLevel() >= registeredCommand.requiredLevel) { - registeredCommand.handle(entity, args); + // Database::Get()->InsertSlashCommandUsage(entity->GetObjectID(), chatCommand); + registeredCommand.handle(entity, sysAddr, args); } else { // We don't need to tell normies they aren't high enough level if (entity->GetGMLevel() == eGameMasterLevel::CIVILIAN) return; @@ -270,1889 +262,1929 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& chat, Entity* GameMessages::SendSlashCommandFeedbackText(entity, GeneralUtils::ASCIIToUTF16(feedback.str())); } } - - return; - - - // //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - // //HANDLE ALL NON GM SLASH COMMANDS RIGHT HERE! - // //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - // if (chatCommand == "pvp") { - // auto* character = entity->GetComponent(); - - // if (character == nullptr) { - // LOG("Failed to find character component!"); - // return; - // } - - // character->SetPvpEnabled(!character->GetPvpEnabled()); - // Game::entityManager->SerializeEntity(entity); - - // std::stringstream message; - // message << character->GetName() << " changed their PVP flag to " << std::to_string(character->GetPvpEnabled()) << "!"; - - // ChatPackets::SendSystemMessage(UNASSIGNED_SYSTEM_ADDRESS, GeneralUtils::UTF8ToUTF16(message.str()), true); - - // return; - // } - - // if (chatCommand == "who") { - // ChatPackets::SendSystemMessage( - // sysAddr, - // u"Players in this instance: (" + GeneralUtils::to_u16string(PlayerManager::GetAllPlayers().size()) + u")" - // ); - - // for (auto* player : PlayerManager::GetAllPlayers()) { - // const auto& name = player->GetCharacter()->GetName(); - - // ChatPackets::SendSystemMessage( - // sysAddr, - // GeneralUtils::UTF8ToUTF16(player == entity ? name + " (you)" : name) - // ); - // } - // } - - // if (chatCommand == "ping") { - // if (!args.empty() && args[0] == "-l") { - // std::stringstream message; - // message << "Your latest ping: " << std::to_string(Game::server->GetLatestPing(sysAddr)) << "ms"; - - // ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(message.str())); - // } else { - // std::stringstream message; - // message << "Your average ping: " << std::to_string(Game::server->GetPing(sysAddr)) << "ms"; - - // ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(message.str())); - // } - // return; - // } - - // if (chatCommand == "fix-stats") { - // // Reset skill component and buff component - // auto* skillComponent = entity->GetComponent(); - // auto* buffComponent = entity->GetComponent(); - // auto* destroyableComponent = entity->GetComponent(); - - // // If any of the components are nullptr, return - // if (skillComponent == nullptr || buffComponent == nullptr || destroyableComponent == nullptr) { - // return; - // } - - // // Reset skill component - // skillComponent->Reset(); - - // // Reset buff component - // buffComponent->Reset(); - - // // Fix the destroyable component - // destroyableComponent->FixStats(); - // } - - // if (chatCommand == "credits" || chatCommand == "info") { - // const auto& customText = chatCommand == "credits" ? VanityUtilities::ParseMarkdown((BinaryPathFinder::GetBinaryDir() / "vanity/CREDITS.md").string()) : VanityUtilities::ParseMarkdown((BinaryPathFinder::GetBinaryDir() / "vanity/INFO.md").string()); - - // { - // AMFArrayValue args; - - // args.Insert("state", "Story"); - - // GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "pushGameState", args); - // } - - // entity->AddCallbackTimer(0.5f, [customText, entity]() { - // AMFArrayValue args; - - // args.Insert("visible", true); - // args.Insert("text", customText); - - // LOG("Sending %s", customText.c_str()); - - // GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "ToggleStoryBox", args); - // }); - - // return; - // } - - // if (chatCommand == "leave-zone" || chatCommand == "leavezone") { - // const auto currentZone = Game::zoneManager->GetZone()->GetZoneID().GetMapID(); - // LWOMAPID newZone = 0; - - // if (currentZone == 1001 || currentZone % 100 == 0) { - // ChatPackets::SendSystemMessage(sysAddr, u"You are not in an instanced zone."); - // return; - // } else { - // newZone = (currentZone / 100) * 100; - // } - // // If new zone would be inaccessible, then default to Avant Gardens. - // if (!Game::zoneManager->CheckIfAccessibleZone(newZone)) newZone = 1100; - - // ChatPackets::SendSystemMessage(sysAddr, u"Leaving zone..."); - - // const auto objid = entity->GetObjectID(); - - // ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, newZone, 0, false, [objid](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { - // auto* entity = Game::entityManager->GetEntity(objid); - - // if (entity == nullptr) { - // return; - // } - - // const auto sysAddr = entity->GetSystemAddress(); - - // LOG("Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", entity->GetCharacter()->GetName().c_str(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); - - // if (entity->GetCharacter()) { - // entity->GetCharacter()->SetZoneID(zoneID); - // entity->GetCharacter()->SetZoneInstance(zoneInstance); - // entity->GetCharacter()->SetZoneClone(zoneClone); - // } - - // entity->GetCharacter()->SaveXMLToDatabase(); - - // WorldPackets::SendTransferToWorld(sysAddr, serverIP, serverPort, mythranShift); - // }); - // } - - // if (chatCommand == "join" && !args.empty()) { - // ChatPackets::SendSystemMessage(sysAddr, u"Requesting private map..."); - // const auto& password = args[0]; - - // ZoneInstanceManager::Instance()->RequestPrivateZone(Game::server, false, password, [=](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { - // LOG("Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", sysAddr.ToString(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); - - // if (entity->GetCharacter()) { - // entity->GetCharacter()->SetZoneID(zoneID); - // entity->GetCharacter()->SetZoneInstance(zoneInstance); - // entity->GetCharacter()->SetZoneClone(zoneClone); - // } - - // entity->GetCharacter()->SaveXMLToDatabase(); - - // WorldPackets::SendTransferToWorld(sysAddr, serverIP, serverPort, mythranShift); - // }); - // } - - // if (user->GetMaxGMLevel() == eGameMasterLevel::CIVILIAN || entity->GetGMLevel() >= eGameMasterLevel::CIVILIAN) { - // if (chatCommand == "die") { - // entity->Smash(entity->GetObjectID()); - // } - - // if (chatCommand == "resurrect") { - // ScriptedActivityComponent* scriptedActivityComponent = Game::zoneManager->GetZoneControlObject()->GetComponent(); - - // if (scriptedActivityComponent) { // check if user is in activity world and if so, they can't resurrect - // ChatPackets::SendSystemMessage(sysAddr, u"You cannot resurrect in an activity world."); - // return; - // } - - // GameMessages::SendResurrect(entity); - // } - - // if (chatCommand == "requestmailcount") { - // Mail::HandleNotificationRequest(entity->GetSystemAddress(), entity->GetObjectID()); - // } - - // if (chatCommand == "instanceinfo") { - // const auto zoneId = Game::zoneManager->GetZone()->GetZoneID(); - - // 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() == eGameMasterLevel::CIVILIAN) return; - // } - - // if (chatCommand == "resetmission" && args.size() >= 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // const auto missionId = GeneralUtils::TryParse(args[0]); - // if (!missionId) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid mission ID."); - // return; - // } - - // auto* missionComponent = entity->GetComponent(); - // if (!missionComponent) return; - // missionComponent->ResetMission(missionId.value()); - // } - - // // Log command to database - // Database::Get()->InsertSlashCommandUsage(entity->GetObjectID(), chatCommand); - - // if (chatCommand == "setminifig" && args.size() == 2 && entity->GetGMLevel() >= eGameMasterLevel::FORUM_MODERATOR) { // could break characters so only allow if GM > 0 - // const auto minifigItemIdExists = GeneralUtils::TryParse(args[1]); - // if (!minifigItemIdExists) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid Minifig Item Id ID."); - // return; - // } - // const int32_t minifigItemId = minifigItemIdExists.value(); - // Game::entityManager->DestructEntity(entity, sysAddr); - // auto* charComp = entity->GetComponent(); - // std::string lowerName = args[0]; - // if (lowerName.empty()) return; - // std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), ::tolower); - // if (lowerName == "eyebrows") { - // charComp->m_Character->SetEyebrows(minifigItemId); - // } else if (lowerName == "eyes") { - // charComp->m_Character->SetEyes(minifigItemId); - // } else if (lowerName == "haircolor") { - // charComp->m_Character->SetHairColor(minifigItemId); - // } else if (lowerName == "hairstyle") { - // charComp->m_Character->SetHairStyle(minifigItemId); - // } else if (lowerName == "pants") { - // charComp->m_Character->SetPantsColor(minifigItemId); - // } else if (lowerName == "lefthand") { - // charComp->m_Character->SetLeftHand(minifigItemId); - // } else if (lowerName == "mouth") { - // charComp->m_Character->SetMouth(minifigItemId); - // } else if (lowerName == "righthand") { - // charComp->m_Character->SetRightHand(minifigItemId); - // } else if (lowerName == "shirtcolor") { - // charComp->m_Character->SetShirtColor(minifigItemId); - // } else if (lowerName == "hands") { - // charComp->m_Character->SetLeftHand(minifigItemId); - // charComp->m_Character->SetRightHand(minifigItemId); - // } else { - // Game::entityManager->ConstructEntity(entity); - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid Minifig item to change, try one of the following: Eyebrows, Eyes, HairColor, HairStyle, Pants, LeftHand, Mouth, RightHand, Shirt, Hands"); - // return; - // } - - // Game::entityManager->ConstructEntity(entity); - // ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(lowerName) + u" set to " + (GeneralUtils::to_u16string(minifigItemId))); - - // 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() >= eGameMasterLevel::DEVELOPER) { - // std::u16string anim = GeneralUtils::ASCIIToUTF16(args[0], args[0].size()); - // RenderComponent::PlayAnimation(entity, anim); - // auto* possessorComponent = entity->GetComponent(); - // if (possessorComponent) { - // auto* possessedComponent = Game::entityManager->GetEntity(possessorComponent->GetPossessable()); - // if (possessedComponent) RenderComponent::PlayAnimation(possessedComponent, anim); - // } - // } - - // if (chatCommand == "list-spawns" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // for (const auto& pair : Game::entityManager->GetSpawnPointEntities()) { - // ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(pair.first)); - // } - - // ChatPackets::SendSystemMessage(sysAddr, u"Current: " + GeneralUtils::ASCIIToUTF16(entity->GetCharacter()->GetTargetScene())); - - // return; - // } - - // if (chatCommand == "unlock-emote" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // const auto emoteID = GeneralUtils::TryParse(args.at(0)); - - // if (!emoteID) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid emote ID."); - // return; - // } - - // entity->GetCharacter()->UnlockEmote(emoteID.value()); - // } - - // if (chatCommand == "force-save" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // entity->GetCharacter()->SaveXMLToDatabase(); - // } - - // if (chatCommand == "kill" && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // ChatPackets::SendSystemMessage(sysAddr, u"Brutally murdering that player, if online on this server."); - - // auto* player = PlayerManager::GetPlayer(args[0]); - // if (player) { - // player->Smash(entity->GetObjectID()); - // ChatPackets::SendSystemMessage(sysAddr, u"It has been done, do you feel good about yourself now?"); - // return; - // } - - // ChatPackets::SendSystemMessage(sysAddr, u"They were saved from your carnage."); - // return; - // } - - // if (chatCommand == "speedboost" && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // const auto boostOptional = GeneralUtils::TryParse(args[0]); - // if (!boostOptional) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid boost."); - // return; - // } - // const float boost = boostOptional.value(); - - // auto* controllablePhysicsComponent = entity->GetComponent(); - - // if (!controllablePhysicsComponent) return; - // controllablePhysicsComponent->SetSpeedMultiplier(boost); - - // // speedboost possessables - // auto possessor = entity->GetComponent(); - // if (possessor) { - // auto possessedID = possessor->GetPossessable(); - // if (possessedID != LWOOBJID_EMPTY) { - // auto possessable = Game::entityManager->GetEntity(possessedID); - // if (possessable) { - // auto* possessControllablePhysicsComponent = possessable->GetComponent(); - // if (possessControllablePhysicsComponent) { - // possessControllablePhysicsComponent->SetSpeedMultiplier(boost); - // } - // } - // } - // } - - // Game::entityManager->SerializeEntity(entity); - // } - - // if (chatCommand == "freecam" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // const auto state = !entity->GetVar(u"freecam"); - // entity->SetVar(u"freecam", state); - - // GameMessages::SendSetPlayerControlScheme(entity, static_cast(state ? 9 : 1)); - - // ChatPackets::SendSystemMessage(sysAddr, u"Toggled freecam."); - // return; - // } - - // if (chatCommand == "setcontrolscheme" && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // const auto scheme = GeneralUtils::TryParse(args[0]); - - // if (!scheme) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid control scheme."); - // return; - // } - - // GameMessages::SendSetPlayerControlScheme(entity, static_cast(scheme.value())); - - // ChatPackets::SendSystemMessage(sysAddr, u"Switched control scheme."); - // return; - // } - - // if (chatCommand == "approveproperty" && entity->GetGMLevel() >= eGameMasterLevel::LEAD_MODERATOR) { - - // if (PropertyManagementComponent::Instance() != nullptr) { - // PropertyManagementComponent::Instance()->UpdateApprovedStatus(true); - // } - - // return; - // } - - // if (chatCommand == "setuistate" && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // AMFArrayValue uiState; - - // uiState.Insert("state", args.at(0)); - - // GameMessages::SendUIMessageServerToSingleClient(entity, sysAddr, "pushGameState", uiState); - - // ChatPackets::SendSystemMessage(sysAddr, u"Switched UI state."); - - // return; - // } - - // if (chatCommand == "toggle" && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // AMFArrayValue amfArgs; - - // amfArgs.Insert("visible", true); - - // GameMessages::SendUIMessageServerToSingleClient(entity, sysAddr, args[0], amfArgs); - - // ChatPackets::SendSystemMessage(sysAddr, u"Toggled UI state."); - - // return; - // } - - // if ((chatCommand == "setinventorysize" || chatCommand == "setinvsize") && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { - // const auto sizeOptional = GeneralUtils::TryParse(args[0]); - // if (!sizeOptional) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid size."); - // return; - // } - // const uint32_t size = sizeOptional.value(); - - // eInventoryType selectedInventory = eInventoryType::ITEMS; - - // // a possible inventory was provided if we got more than 1 argument - // if (args.size() >= 2) { - // selectedInventory = GeneralUtils::TryParse(args.at(1)).value_or(eInventoryType::INVALID); - // if (selectedInventory == eInventoryType::INVALID) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid inventory."); - // return; - // } else { - // // In this case, we treat the input as a string and try to find it in the reflection list - // std::transform(args.at(1).begin(), args.at(1).end(), args.at(1).begin(), ::toupper); - // for (uint32_t index = 0; index < NUMBER_OF_INVENTORIES; index++) { - // if (std::string_view(args.at(1)) == std::string_view(InventoryType::InventoryTypeToString(static_cast(index)))) selectedInventory = static_cast(index); - // } - // } - - // ChatPackets::SendSystemMessage(sysAddr, u"Setting inventory " + - // GeneralUtils::ASCIIToUTF16(args.at(1)) + - // u" to size " + - // GeneralUtils::to_u16string(size)); - // } else ChatPackets::SendSystemMessage(sysAddr, u"Setting inventory ITEMS to size " + GeneralUtils::to_u16string(size)); - - // auto* inventoryComponent = entity->GetComponent(); - // if (inventoryComponent) { - // auto* inventory = inventoryComponent->GetInventory(selectedInventory); - - // inventory->SetSize(size); - // } - - // return; - // } - - // if (chatCommand == "runmacro" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // if (args.size() != 1) return; - - // // Only process if input does not contain separator charaters - // if (args[0].find("/") != std::string::npos) return; - // if (args[0].find("\\") != std::string::npos) return; - - // auto infile = Game::assetManager->GetFile(("macros/" + args[0] + ".scm").c_str()); - - // if (!infile) { - // ChatPackets::SendSystemMessage(sysAddr, u"Unknown macro! Is the filename right?"); - // return; - // } - - // if (infile.good()) { - // std::string line; - // while (std::getline(infile, line)) { - // // Do this in two separate calls to catch both \n and \r\n - // line.erase(std::remove(line.begin(), line.end(), '\n'), line.end()); - // line.erase(std::remove(line.begin(), line.end(), '\r'), line.end()); - // SlashCommandHandler::HandleChatCommand(GeneralUtils::ASCIIToUTF16(line), entity, sysAddr); - // } - // } else { - // ChatPackets::SendSystemMessage(sysAddr, u"Unknown macro! Is the filename right?"); - // } - - // return; - // } - - // if (chatCommand == "addmission" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // if (args.size() == 0) return; - - // const auto missionID = GeneralUtils::TryParse(args.at(0)); - - // if (!missionID) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid mission id."); - // return; - // } - - // auto comp = static_cast(entity->GetComponent(eReplicaComponentType::MISSION)); - // if (comp) comp->AcceptMission(missionID.value(), true); - // return; - // } - - // if (chatCommand == "completemission" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // if (args.size() == 0) return; - - // const auto missionID = GeneralUtils::TryParse(args.at(0)); - - // if (!missionID) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid mission id."); - // return; - // } - - // auto comp = static_cast(entity->GetComponent(eReplicaComponentType::MISSION)); - // if (comp) comp->CompleteMission(missionID.value(), true); - // return; - // } - - // if (chatCommand == "setflag" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() == 1) { - // const auto flagId = GeneralUtils::TryParse(args.at(0)); - - // if (!flagId) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid flag id."); - // return; - // } - - // entity->GetCharacter()->SetPlayerFlag(flagId.value(), true); - // } - - // if (chatCommand == "setflag" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() == 2) { - // const auto flagId = GeneralUtils::TryParse(args.at(1)); - // std::string onOffFlag = args.at(0); - // if (!flagId) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid flag id."); - // return; - // } - // if (onOffFlag != "off" && onOffFlag != "on") { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid flag type."); - // return; - // } - // entity->GetCharacter()->SetPlayerFlag(flagId.value(), onOffFlag == "on"); - // } - // if (chatCommand == "clearflag" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() == 1) { - // const auto flagId = GeneralUtils::TryParse(args.at(0)); - - // if (!flagId) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid flag id."); - // return; - // } - - // entity->GetCharacter()->SetPlayerFlag(flagId.value(), false); - // } - - // if (chatCommand == "playeffect" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 3) { - // const auto effectID = GeneralUtils::TryParse(args.at(0)); - - // if (!effectID) return; - - // // FIXME: use fallible ASCIIToUTF16 conversion, because non-ascii isn't valid anyway - // GameMessages::SendPlayFXEffect(entity->GetObjectID(), effectID.value(), GeneralUtils::ASCIIToUTF16(args.at(1)), args.at(2)); - // } - - // if (chatCommand == "stopeffect" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { - // GameMessages::SendStopFXEffect(entity, true, args[0]); - // } - - // if (chatCommand == "setanntitle" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // if (args.size() < 0) return; - - // std::stringstream ss; - // for (auto string : args) - // ss << string << " "; - - // entity->GetCharacter()->SetAnnouncementTitle(ss.str()); - // return; - // } - - // if (chatCommand == "setannmsg" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // if (args.size() < 0) return; - - // std::stringstream ss; - // for (auto string : args) - // ss << string << " "; - - // entity->GetCharacter()->SetAnnouncementMessage(ss.str()); - // return; - // } - - // 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; - // } - - // SendAnnouncement(entity->GetCharacter()->GetAnnouncementTitle(), entity->GetCharacter()->GetAnnouncementMessage()); - // return; - // } - - // if (chatCommand == "shutdownuniverse" && entity->GetGMLevel() == eGameMasterLevel::OPERATOR) { - // //Tell the master server that we're going to be shutting down whole "universe": - // CBITSTREAM; - // BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::SHUTDOWN_UNIVERSE); - // Game::server->SendToMaster(bitStream); - // ChatPackets::SendSystemMessage(sysAddr, u"Sent universe shutdown notification to master."); - - // //Tell chat to send an announcement to all servers - // SendAnnouncement("Servers Closing Soon!", "DLU servers will close for maintenance in 10 minutes from now."); - // return; - // } - - // if (chatCommand == "getnavmeshheight" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // auto control = static_cast<ControllablePhysicsComponent*>(entity->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS)); - // if (!control) return; - - // float y = dpWorld::GetNavMesh()->GetHeightAtPoint(control->GetPosition()); - // std::u16string msg = u"Navmesh height: " + (GeneralUtils::to_u16string(y)); - // ChatPackets::SendSystemMessage(sysAddr, msg); - // } - - // if (chatCommand == "gmadditem" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // if (args.size() == 1) { - // const auto itemLOT = GeneralUtils::TryParse<uint32_t>(args.at(0)); - - // if (!itemLOT) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid item LOT."); - // return; - // } - - // InventoryComponent* inventory = static_cast<InventoryComponent*>(entity->GetComponent(eReplicaComponentType::INVENTORY)); - - // inventory->AddItem(itemLOT.value(), 1, eLootSourceType::MODERATION); - // } else if (args.size() == 2) { - // const auto itemLOT = GeneralUtils::TryParse<uint32_t>(args.at(0)); - // if (!itemLOT) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid item LOT."); - // return; - // } - - // const auto count = GeneralUtils::TryParse<uint32_t>(args.at(1)); - // if (!count) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid item count."); - // return; - // } - - // InventoryComponent* inventory = static_cast<InventoryComponent*>(entity->GetComponent(eReplicaComponentType::INVENTORY)); - - // inventory->AddItem(itemLOT.value(), count.value(), eLootSourceType::MODERATION); - // } else { - // ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /gmadditem <lot>"); - // } - // } - - // if (chatCommand == "mailitem" && entity->GetGMLevel() >= eGameMasterLevel::MODERATOR && args.size() >= 2) { - // const auto& playerName = args[0]; - - // auto playerInfo = Database::Get()->GetCharacterInfo(playerName); - - // uint32_t receiverID = 0; - // if (!playerInfo) { - // ChatPackets::SendSystemMessage(sysAddr, u"Failed to find that player"); - - // return; - // } - - // receiverID = playerInfo->id; - - // const auto lot = GeneralUtils::TryParse<LOT>(args.at(1)); - - // if (!lot) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid item lot."); - // return; - // } - - // IMail::MailInfo mailInsert; - // mailInsert.senderId = entity->GetObjectID(); - // mailInsert.senderUsername = "Darkflame Universe"; - // mailInsert.receiverId = receiverID; - // mailInsert.recipient = playerName; - // mailInsert.subject = "Lost item"; - // mailInsert.body = "This is a replacement item for one you lost."; - // mailInsert.itemID = LWOOBJID_EMPTY; - // mailInsert.itemLOT = lot.value(); - // mailInsert.itemSubkey = LWOOBJID_EMPTY; - // mailInsert.itemCount = 1; - // Database::Get()->InsertNewMail(mailInsert); - - // ChatPackets::SendSystemMessage(sysAddr, u"Mail sent"); - - // return; - // } - - // if (chatCommand == "setname" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // std::string name = ""; - - // for (const auto& arg : args) { - // name += arg + " "; - // } - - // GameMessages::SendSetName(entity->GetObjectID(), GeneralUtils::UTF8ToUTF16(name), UNASSIGNED_SYSTEM_ADDRESS); - // } - - // if (chatCommand == "title" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // std::string name = entity->GetCharacter()->GetName() + " - "; - - // for (const auto& arg : args) { - // name += arg + " "; - // } - - // GameMessages::SendSetName(entity->GetObjectID(), GeneralUtils::UTF8ToUTF16(name), UNASSIGNED_SYSTEM_ADDRESS); - // } - - // if ((chatCommand == "teleport" || chatCommand == "tele") && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_MODERATOR) { - // NiPoint3 pos{}; - // if (args.size() == 3) { - - // const auto x = GeneralUtils::TryParse<float>(args.at(0)); - // if (!x) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid x."); - // return; - // } - - // const auto y = GeneralUtils::TryParse<float>(args.at(1)); - // if (!y) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid y."); - // return; - // } - - // const auto z = GeneralUtils::TryParse<float>(args.at(2)); - // if (!z) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid z."); - // return; - // } - - // pos.SetX(x.value()); - // pos.SetY(y.value()); - // pos.SetZ(z.value()); - - // LOG("Teleporting objectID: %llu to %f, %f, %f", entity->GetObjectID(), pos.x, pos.y, pos.z); - // GameMessages::SendTeleport(entity->GetObjectID(), pos, NiQuaternion(), sysAddr); - // } else if (args.size() == 2) { - - // const auto x = GeneralUtils::TryParse<float>(args.at(0)); - // if (!x) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid x."); - // return; - // } - - // const auto z = GeneralUtils::TryParse<float>(args.at(1)); - // if (!z) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid z."); - // return; - // } - - // pos.SetX(x.value()); - // pos.SetY(0.0f); - // pos.SetZ(z.value()); - - // LOG("Teleporting objectID: %llu to X: %f, Z: %f", entity->GetObjectID(), pos.x, pos.z); - // GameMessages::SendTeleport(entity->GetObjectID(), pos, NiQuaternion(), sysAddr); - // } else { - // ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /teleport <x> (<y>) <z> - if no Y given, will teleport to the height of the terrain (or any physics object)."); - // } - - - // auto* possessorComponent = entity->GetComponent<PossessorComponent>(); - // if (possessorComponent) { - // auto* possassableEntity = Game::entityManager->GetEntity(possessorComponent->GetPossessable()); - - // if (possassableEntity != nullptr) { - // auto* havokVehiclePhysicsComponent = possassableEntity->GetComponent<HavokVehiclePhysicsComponent>(); - // if (havokVehiclePhysicsComponent) { - // havokVehiclePhysicsComponent->SetPosition(pos); - // Game::entityManager->SerializeEntity(possassableEntity); - // } else GameMessages::SendTeleport(possassableEntity->GetObjectID(), pos, NiQuaternion(), sysAddr); - // } - // } - // } - - // if (chatCommand == "tpall" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // const auto pos = entity->GetPosition(); - - // const auto characters = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::CHARACTER); - - // for (auto* character : characters) { - // GameMessages::SendTeleport(character->GetObjectID(), pos, NiQuaternion(), character->GetSystemAddress()); - // } - - // return; - // } - - // if (chatCommand == "dismount" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // auto* possessorComponent = entity->GetComponent<PossessorComponent>(); - // if (possessorComponent) { - // auto possessableId = possessorComponent->GetPossessable(); - // if (possessableId != LWOOBJID_EMPTY) { - // auto* possessableEntity = Game::entityManager->GetEntity(possessableId); - // if (possessableEntity) possessorComponent->Dismount(possessableEntity, true); - // } - // } - // } - - // if (chatCommand == "fly" && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_DEVELOPER) { - // auto* character = entity->GetCharacter(); - - // if (character) { - // bool isFlying = character->GetIsFlying(); - - // if (isFlying) { - // GameMessages::SendSetJetPackMode(entity, false); - - // character->SetIsFlying(false); - // } else { - // float speedScale = 1.0f; - - // if (args.size() >= 1) { - // const auto tempScaleStore = GeneralUtils::TryParse<float>(args.at(0)); - - // if (tempScaleStore) { - // speedScale = tempScaleStore.value(); - // } else { - // ChatPackets::SendSystemMessage(sysAddr, u"Failed to parse speed scale argument."); - // } - // } - - // float airSpeed = 20 * speedScale; - // float maxAirSpeed = 30 * speedScale; - // float verticalVelocity = 1.5 * speedScale; - - // GameMessages::SendSetJetPackMode(entity, true, true, false, 167, airSpeed, maxAirSpeed, verticalVelocity); - - // character->SetIsFlying(true); - // } - // } - // } - - // //------- GM COMMANDS TO ACTUALLY MODERATE -------- - - // if (chatCommand == "mute" && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_DEVELOPER) { - // if (args.size() >= 1) { - // auto* player = PlayerManager::GetPlayer(args[0]); - - // uint32_t accountId = 0; - // LWOOBJID characterId = 0; - - // if (player == nullptr) { - // auto characterInfo = Database::Get()->GetCharacterInfo(args[0]); - - // if (characterInfo) { - // accountId = characterInfo->accountId; - // characterId = characterInfo->id; - - // GeneralUtils::SetBit(characterId, eObjectBits::CHARACTER); - // GeneralUtils::SetBit(characterId, eObjectBits::PERSISTENT); - // } - - // if (accountId == 0) { - // ChatPackets::SendSystemMessage(sysAddr, u"Count not find player of name: " + GeneralUtils::UTF8ToUTF16(args[0])); - - // return; - // } - // } else { - // auto* character = player->GetCharacter(); - // auto* user = character != nullptr ? character->GetParentUser() : nullptr; - // if (user) accountId = user->GetAccountID(); - // characterId = player->GetObjectID(); - // } - - // time_t expire = 1; // Default to indefinate mute - - // if (args.size() >= 2) { - // const auto days = GeneralUtils::TryParse<uint32_t>(args[1]); - // if (!days) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid days."); - - // return; - // } - - // std::optional<uint32_t> hours; - // if (args.size() >= 3) { - // hours = GeneralUtils::TryParse<uint32_t>(args[2]); - // if (!hours) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid hours."); - - // return; - // } - // } - - // expire = time(NULL); - // expire += 24 * 60 * 60 * days.value(); - // expire += 60 * 60 * hours.value_or(0); - // } - - // if (accountId != 0) Database::Get()->UpdateAccountUnmuteTime(accountId, expire); - - // char buffer[32] = "brought up for review.\0"; - - // if (expire != 1) { - // std::tm* ptm = std::localtime(&expire); - // // Format: Mo, 15.06.2009 20:20:00 - // std::strftime(buffer, 32, "%a, %d.%m.%Y %H:%M:%S", ptm); - // } - - // const auto timeStr = GeneralUtils::ASCIIToUTF16(std::string(buffer)); - - // ChatPackets::SendSystemMessage(sysAddr, u"Muted: " + GeneralUtils::UTF8ToUTF16(args[0]) + u" until " + timeStr); - - // //Notify chat about it - // CBITSTREAM; - // BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::MUTE_UPDATE); - - // bitStream.Write(characterId); - // bitStream.Write(expire); - - // Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false); - // } else { - // ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /mute <username> <days (optional)> <hours (optional)>"); - // } - // } - - // if (chatCommand == "kick" && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_MODERATOR) { - // if (args.size() == 1) { - // auto* player = PlayerManager::GetPlayer(args[0]); - - // std::u16string username = GeneralUtils::UTF8ToUTF16(args[0]); - // if (player == nullptr) { - // ChatPackets::SendSystemMessage(sysAddr, u"Count not find player of name: " + username); - // return; - // } - - // Game::server->Disconnect(player->GetSystemAddress(), eServerDisconnectIdentifiers::KICK); - - // ChatPackets::SendSystemMessage(sysAddr, u"Kicked: " + username); - // } else { - // ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /kick <username>"); - // } - // } - - // if (chatCommand == "ban" && entity->GetGMLevel() >= eGameMasterLevel::SENIOR_MODERATOR) { - // if (args.size() == 1) { - // auto* player = PlayerManager::GetPlayer(args[0]); - - // uint32_t accountId = 0; - - // if (player == nullptr) { - // auto characterInfo = Database::Get()->GetCharacterInfo(args[0]); - - // if (characterInfo) { - // accountId = characterInfo->accountId; - // } - - // if (accountId == 0) { - // ChatPackets::SendSystemMessage(sysAddr, u"Count not find player of name: " + GeneralUtils::UTF8ToUTF16(args[0])); - - // return; - // } - // } else { - // auto* character = player->GetCharacter(); - // auto* user = character != nullptr ? character->GetParentUser() : nullptr; - // if (user) accountId = user->GetAccountID(); - // } - - // if (accountId != 0) Database::Get()->UpdateAccountBan(accountId, true); - - // if (player != nullptr) { - // Game::server->Disconnect(player->GetSystemAddress(), eServerDisconnectIdentifiers::FREE_TRIAL_EXPIRED); - // } - - // ChatPackets::SendSystemMessage(sysAddr, u"Banned: " + GeneralUtils::ASCIIToUTF16(args[0])); - // } else { - // ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /ban <username>"); - // } - // } - - // //------------------------------------------------- - - // if (chatCommand == "buffme" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // auto dest = static_cast<DestroyableComponent*>(entity->GetComponent(eReplicaComponentType::DESTROYABLE)); - // if (dest) { - // dest->SetHealth(999); - // dest->SetMaxHealth(999.0f); - // dest->SetArmor(999); - // dest->SetMaxArmor(999.0f); - // dest->SetImagination(999); - // dest->SetMaxImagination(999.0f); - // } - // Game::entityManager->SerializeEntity(entity); - // } - - // if (chatCommand == "startcelebration" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() == 1) { - // const auto celebration = GeneralUtils::TryParse<int32_t>(args.at(0)); - - // if (!celebration) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid celebration."); - // return; - // } - - // GameMessages::SendStartCelebrationEffect(entity, entity->GetSystemAddress(), celebration.value()); - // } - - // if (chatCommand == "buffmed" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // auto dest = static_cast<DestroyableComponent*>(entity->GetComponent(eReplicaComponentType::DESTROYABLE)); - // if (dest) { - // dest->SetHealth(9); - // dest->SetMaxHealth(9.0f); - // dest->SetArmor(9); - // dest->SetMaxArmor(9.0f); - // dest->SetImagination(9); - // dest->SetMaxImagination(9.0f); - // } - // Game::entityManager->SerializeEntity(entity); - // } - - // if (chatCommand == "refillstats" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - - // auto dest = static_cast<DestroyableComponent*>(entity->GetComponent(eReplicaComponentType::DESTROYABLE)); - // if (dest) { - // dest->SetHealth(static_cast<int32_t>(dest->GetMaxHealth())); - // dest->SetArmor(static_cast<int32_t>(dest->GetMaxArmor())); - // dest->SetImagination(static_cast<int32_t>(dest->GetMaxImagination())); - // } - - // Game::entityManager->SerializeEntity(entity); - // } - - // 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. - // std::string conditional = args[0]; - // args.erase(args.begin()); - // for (auto& argument : args) { - // conditional += ' ' + argument; - // } - - // const std::string query_text = "%" + conditional + "%"; - // query.bind(1, query_text.c_str()); - - // auto tables = query.execQuery(); - - // while (!tables.eof()) { - // std::string message = std::to_string(tables.getIntField(0)) + " - " + tables.getStringField(1); - // ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::UTF8ToUTF16(message, message.size())); - // tables.nextRow(); - // } - // } - - // if (chatCommand == "spawn" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { - // ControllablePhysicsComponent* comp = static_cast<ControllablePhysicsComponent*>(entity->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS)); - // if (!comp) return; - - // const auto lot = GeneralUtils::TryParse<uint32_t>(args[0]); - - // if (!lot) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid lot."); - // return; - // } - - // EntityInfo info; - // info.lot = lot.value(); - // info.pos = comp->GetPosition(); - // info.rot = comp->GetRotation(); - // info.spawner = nullptr; - // info.spawnerID = entity->GetObjectID(); - // info.spawnerNodeID = 0; - - // Entity* newEntity = Game::entityManager->CreateEntity(info, nullptr); - - // if (newEntity == nullptr) { - // ChatPackets::SendSystemMessage(sysAddr, u"Failed to spawn entity."); - // return; - // } - - // Game::entityManager->ConstructEntity(newEntity); - // } - - // if (chatCommand == "spawngroup" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 3) { - // auto controllablePhysicsComponent = entity->GetComponent<ControllablePhysicsComponent>(); - // if (!controllablePhysicsComponent) return; - - // const auto lot = GeneralUtils::TryParse<LOT>(args[0]); - // if (!lot) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid lot."); - // return; - // } - - // const auto numberToSpawnOptional = GeneralUtils::TryParse<uint32_t>(args[1]); - // if (!numberToSpawnOptional && numberToSpawnOptional.value() > 0) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid number of enemies to spawn."); - // return; - // } - // uint32_t numberToSpawn = numberToSpawnOptional.value(); - - // // Must spawn within a radius of at least 0.0f - // const auto radiusToSpawnWithinOptional = GeneralUtils::TryParse<float>(args[2]); - // if (!radiusToSpawnWithinOptional && radiusToSpawnWithinOptional.value() < 0.0f) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid radius to spawn within."); - // return; - // } - // const float radiusToSpawnWithin = radiusToSpawnWithinOptional.value(); - - // EntityInfo info; - // info.lot = lot.value(); - // info.spawner = nullptr; - // info.spawnerID = entity->GetObjectID(); - // info.spawnerNodeID = 0; - - // auto playerPosition = controllablePhysicsComponent->GetPosition(); - // while (numberToSpawn > 0) { - // auto randomAngle = GeneralUtils::GenerateRandomNumber<float>(0.0f, 2 * PI); - // auto randomRadius = GeneralUtils::GenerateRandomNumber<float>(0.0f, radiusToSpawnWithin); - - // // Set the position to the generated random position plus the player position. This will - // // spawn the entity in a circle around the player. As you get further from the player, the angle chosen will get less accurate. - // info.pos = playerPosition + NiPoint3(cos(randomAngle) * randomRadius, 0.0f, sin(randomAngle) * randomRadius); - // info.rot = NiQuaternion(); - - // auto newEntity = Game::entityManager->CreateEntity(info); - // if (newEntity == nullptr) { - // ChatPackets::SendSystemMessage(sysAddr, u"Failed to spawn entity."); - // return; - // } - - // Game::entityManager->ConstructEntity(newEntity); - // numberToSpawn--; - // } - // } - - // if ((chatCommand == "giveuscore") && args.size() >= 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // const auto uscoreOptional = GeneralUtils::TryParse<int32_t>(args[0]); - // if (!uscoreOptional) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid uscore."); - // return; - // } - // const int32_t uscore = uscoreOptional.value(); - - // CharacterComponent* character = entity->GetComponent<CharacterComponent>(); - // if (character) character->SetUScore(character->GetUScore() + uscore); - // // MODERATION should work but it doesn't. Relog to see uscore changes - - // eLootSourceType lootType = eLootSourceType::MODERATION; - - // if (args.size() >= 2) { - // const auto type = GeneralUtils::TryParse<eLootSourceType>(args[1]); - // lootType = type.value_or(lootType); - // } - - // GameMessages::SendModifyLEGOScore(entity, entity->GetSystemAddress(), uscore, lootType); - // } - - // 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) { - // requestedPlayerToSetLevelOf = args[1]; - - // auto requestedPlayer = PlayerManager::GetPlayer(requestedPlayerToSetLevelOf); - - // if (!requestedPlayer) { - // ChatPackets::SendSystemMessage(sysAddr, u"No player found with username: (" + GeneralUtils::UTF8ToUTF16(requestedPlayerToSetLevelOf) + u")."); - // return; - // } - - // if (!requestedPlayer->GetOwner()) { - // ChatPackets::SendSystemMessage(sysAddr, u"No entity found with username: (" + GeneralUtils::UTF8ToUTF16(requestedPlayerToSetLevelOf) + u")."); - // return; - // } - - // entity = requestedPlayer->GetOwner(); - // } - // const auto requestedLevelOptional = GeneralUtils::TryParse<uint32_t>(args[0]); - // uint32_t oldLevel; - - // // first check the level is valid - // if (!requestedLevelOptional) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid level."); - // return; - // } - // uint32_t requestedLevel = requestedLevelOptional.value(); - // // query to set our uscore to the correct value for this level - - // auto characterComponent = entity->GetComponent<CharacterComponent>(); - // if (!characterComponent) return; - // auto levelComponent = entity->GetComponent<LevelProgressionComponent>(); - // auto query = CDClientDatabase::CreatePreppedStmt("SELECT requiredUScore from LevelProgressionLookup WHERE id = ?;"); - // query.bind(1, static_cast<int>(requestedLevel)); - // auto result = query.execQuery(); - - // if (result.eof()) return; - - // // Set the UScore first - // oldLevel = levelComponent->GetLevel(); - // characterComponent->SetUScore(result.getIntField(0, characterComponent->GetUScore())); - - // // handle level up for each level we have passed if we set our level to be higher than the current one. - // if (oldLevel < requestedLevel) { - // while (oldLevel < requestedLevel) { - // oldLevel += 1; - // levelComponent->SetLevel(oldLevel); - // levelComponent->HandleLevelUp(); - // } - // } else { - // levelComponent->SetLevel(requestedLevel); - // } - - // if (requestedPlayerToSetLevelOf != "") { - // ChatPackets::SendSystemMessage( - // sysAddr, u"Set " + GeneralUtils::UTF8ToUTF16(requestedPlayerToSetLevelOf) + u"'s level to " + GeneralUtils::to_u16string(requestedLevel) + - // u" and UScore to " + GeneralUtils::to_u16string(characterComponent->GetUScore()) + - // u". Relog to see changes."); - // } else { - // ChatPackets::SendSystemMessage( - // sysAddr, u"Set your level to " + GeneralUtils::to_u16string(requestedLevel) + - // u" and UScore to " + GeneralUtils::to_u16string(characterComponent->GetUScore()) + - // u". Relog to see changes."); - // } - // return; - // } - - // 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">"); - - // LOG("Position: %f, %f, %f", position.x, position.y, position.z); - // } - - // 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">"); - - // LOG("Rotation: %f, %f, %f, %f", rotation.w, rotation.x, rotation.y, rotation.z); - // } - - // if (chatCommand == "locrow" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // const auto position = entity->GetPosition(); - // const auto rotation = entity->GetRotation(); - - // LOG("<location x=\"%f\" y=\"%f\" z=\"%f\" rw=\"%f\" rx=\"%f\" ry=\"%f\" rz=\"%f\" />", position.x, position.y, position.z, rotation.w, rotation.x, rotation.y, rotation.z); - // } - - // 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() >= eGameMasterLevel::DEVELOPER) { - // GameMessages::SendPlayFXEffect(entity, 230, u"rebuild", "230", LWOOBJID_EMPTY, 1.0f, 1.0f, true); - // } - - // if ((chatCommand == "freemoney" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) && args.size() == 1) { - // const auto money = GeneralUtils::TryParse<int64_t>(args[0]); - - // if (!money) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid money."); - // return; - // } - - // auto* ch = entity->GetCharacter(); - // ch->SetCoins(ch->GetCoins() + money.value(), eLootSourceType::MODERATION); - // } - - // if ((chatCommand == "setcurrency") && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // const auto money = GeneralUtils::TryParse<int64_t>(args[0]); - - // if (!money) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid money."); - // return; - // } - - // auto* ch = entity->GetCharacter(); - // ch->SetCoins(money.value(), eLootSourceType::MODERATION); - // } - - // // Allow for this on even while not a GM, as it sometimes toggles incorrrectly. - // if (chatCommand == "gminvis" && entity->GetCharacter()->GetParentUser()->GetMaxGMLevel() >= eGameMasterLevel::DEVELOPER) { - // GameMessages::SendToggleGMInvis(entity->GetObjectID(), true, UNASSIGNED_SYSTEM_ADDRESS); - - // return; - // } - - // if (chatCommand == "gmimmune" && args.size() >= 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // auto* destroyableComponent = entity->GetComponent<DestroyableComponent>(); - - // const auto state = GeneralUtils::TryParse<int32_t>(args[0]); - - // if (!state) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid state."); - // return; - // } - - // if (destroyableComponent) destroyableComponent->SetIsGMImmune(state.value()); - // return; - // } - - // //Testing basic attack immunity - // if (chatCommand == "attackimmune" && args.size() >= 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // auto* destroyableComponent = entity->GetComponent<DestroyableComponent>(); - - // const auto state = GeneralUtils::TryParse<int32_t>(args[0]); - - // if (!state) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid state."); - // return; - // } - - // if (destroyableComponent) destroyableComponent->SetIsImmune(state.value()); - // return; - // } - - // if (chatCommand == "buff" && args.size() >= 2 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // auto* buffComponent = entity->GetComponent<BuffComponent>(); - - // const auto id = GeneralUtils::TryParse<int32_t>(args[0]); - // if (!id) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid buff id."); - // return; - // } - - // const auto duration = GeneralUtils::TryParse<int32_t>(args[1]); - // if (!duration) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid buff duration."); - // return; - // } - - // if (buffComponent) buffComponent->ApplyBuff(id.value(), duration.value(), entity->GetObjectID()); - // return; - // } - - // if ((chatCommand == "testmap" && args.size() >= 1) && entity->GetGMLevel() >= eGameMasterLevel::FORUM_MODERATOR) { - // ChatPackets::SendSystemMessage(sysAddr, u"Requesting map change..."); - // LWOCLONEID cloneId = 0; - // bool force = false; - - // const auto reqZoneOptional = GeneralUtils::TryParse<LWOMAPID>(args[0]); - // if (!reqZoneOptional) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid zone."); - // return; - // } - // const LWOMAPID reqZone = reqZoneOptional.value(); - - // if (args.size() > 1) { - // auto index = 1; - - // if (args[index] == "force") { - // index++; - - // force = true; - // } - - // if (args.size() > index) { - // const auto cloneIdOptional = GeneralUtils::TryParse<LWOCLONEID>(args[index]); - // if (!cloneIdOptional) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid clone id."); - // return; - // } - // cloneId = cloneIdOptional.value(); - // } - // } - - // const auto objid = entity->GetObjectID(); - - // if (force || Game::zoneManager->CheckIfAccessibleZone(reqZone)) { // to prevent tomfoolery - - // ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, reqZone, cloneId, false, [objid](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { - - // auto* entity = Game::entityManager->GetEntity(objid); - // if (!entity) return; - - // const auto sysAddr = entity->GetSystemAddress(); - - // ChatPackets::SendSystemMessage(sysAddr, u"Transfering map..."); - - // LOG("Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", sysAddr.ToString(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); - // if (entity->GetCharacter()) { - // entity->GetCharacter()->SetZoneID(zoneID); - // entity->GetCharacter()->SetZoneInstance(zoneInstance); - // entity->GetCharacter()->SetZoneClone(zoneClone); - // entity->GetComponent<CharacterComponent>()->SetLastRocketConfig(u""); - // } - - // entity->GetCharacter()->SaveXMLToDatabase(); - - // WorldPackets::SendTransferToWorld(sysAddr, serverIP, serverPort, mythranShift); - // return; - // }); - // } else { - // std::string msg = "ZoneID not found or allowed: "; - // msg.append(args[0]); // FIXME: unnecessary utf16 re-encoding just for error - // ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::UTF8ToUTF16(msg, msg.size())); - // } - // } - - // if (chatCommand == "createprivate" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 3) { - // const auto zone = GeneralUtils::TryParse<uint32_t>(args[0]); - // if (!zone) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid zone."); - // return; - // } - - // const auto clone = GeneralUtils::TryParse<uint32_t>(args[1]); - // if (!clone) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid clone."); - // return; - // } - - // const auto& password = args[2]; - - // ZoneInstanceManager::Instance()->CreatePrivateZone(Game::server, zone.value(), clone.value(), password); - - // ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16("Sent request for private zone with password: " + password)); - - // return; - // } - - // if ((chatCommand == "debugui") && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // ChatPackets::SendSystemMessage(sysAddr, u"Opening UIDebugger..."); - // AMFArrayValue args; - // GameMessages::SendUIMessageServerToSingleClient(entity, sysAddr, "ToggleUIDebugger;", args); - // } - - // if ((chatCommand == "boost") && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // auto* possessorComponent = entity->GetComponent<PossessorComponent>(); - - // if (possessorComponent == nullptr) { - // return; - // } - - // auto* vehicle = Game::entityManager->GetEntity(possessorComponent->GetPossessable()); - - // if (vehicle == nullptr) { - // return; - // } - - // if (args.size() >= 1) { - // const auto time = GeneralUtils::TryParse<float>(args[0]); - - // if (!time) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid boost time."); - // return; - // } else { - // GameMessages::SendVehicleAddPassiveBoostAction(vehicle->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); - // entity->AddCallbackTimer(time.value(), [vehicle]() { - // if (!vehicle) return; - // GameMessages::SendVehicleRemovePassiveBoostAction(vehicle->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); - // }); - // } - // } else { - // GameMessages::SendVehicleAddPassiveBoostAction(vehicle->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); - // } - - // } - - // if ((chatCommand == "unboost") && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // auto* possessorComponent = entity->GetComponent<PossessorComponent>(); - - // if (possessorComponent == nullptr) return; - // auto* vehicle = Game::entityManager->GetEntity(possessorComponent->GetPossessable()); - - // if (vehicle == nullptr) return; - // GameMessages::SendVehicleRemovePassiveBoostAction(vehicle->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); - // } - - // if (chatCommand == "activatespawner" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { - // auto spawners = Game::zoneManager->GetSpawnersByName(args[0]); - - // for (auto* spawner : spawners) { - // spawner->Activate(); - // } - - // spawners = Game::zoneManager->GetSpawnersInGroup(args[0]); - - // for (auto* spawner : spawners) { - // spawner->Activate(); - // } - // } - - // if (chatCommand == "spawnphysicsverts" && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_DEVELOPER) { - // //Go tell physics to spawn all the vertices: - // auto entities = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::PHANTOM_PHYSICS); - // for (auto en : entities) { - // auto phys = static_cast<PhantomPhysicsComponent*>(en->GetComponent(eReplicaComponentType::PHANTOM_PHYSICS)); - // if (phys) - // phys->SpawnVertices(); - // } - // } - - // if (chatCommand == "reportproxphys" && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_DEVELOPER) { - // auto entities = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::PROXIMITY_MONITOR); - // for (auto en : entities) { - // auto phys = static_cast<ProximityMonitorComponent*>(en->GetComponent(eReplicaComponentType::PROXIMITY_MONITOR)); - // if (phys) { - // for (auto prox : phys->GetProximitiesData()) { - // if (!prox.second) continue; - - // auto sphere = static_cast<dpShapeSphere*>(prox.second->GetShape()); - // auto pos = prox.second->GetPosition(); - // LOG("Proximity: %s, r: %f, pos: %f, %f, %f", prox.first.c_str(), sphere->GetRadius(), pos.x, pos.y, pos.z); - // } - // } - // } - // } - - // if (chatCommand == "triggerspawner" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { - // auto spawners = Game::zoneManager->GetSpawnersByName(args[0]); - - // for (auto* spawner : spawners) { - // spawner->Spawn(); - // } - - // spawners = Game::zoneManager->GetSpawnersInGroup(args[0]); - - // for (auto* spawner : spawners) { - // spawner->Spawn(); - // } - // } - - // if (chatCommand == "reforge" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 2) { - // const auto baseItem = GeneralUtils::TryParse<LOT>(args[0]); - // if (!baseItem) return; - - // const auto reforgedItem = GeneralUtils::TryParse<LOT>(args[1]); - // if (!reforgedItem) return; - - // auto* inventoryComponent = entity->GetComponent<InventoryComponent>(); - // if (!inventoryComponent) return; - - // std::vector<LDFBaseData*> data{}; - // data.push_back(new LDFData<int32_t>(u"reforgedLOT", reforgedItem.value())); - - // inventoryComponent->AddItem(baseItem.value(), 1, eLootSourceType::MODERATION, eInventoryType::INVALID, data); - // } - - // if (chatCommand == "crash" && entity->GetGMLevel() >= eGameMasterLevel::OPERATOR) { - // ChatPackets::SendSystemMessage(sysAddr, u"Crashing..."); - - // int* badPtr = nullptr; - // *badPtr = 0; - - // return; - // } - - // if (chatCommand == "metrics" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // for (const auto variable : Metrics::GetAllMetrics()) { - // auto* metric = Metrics::GetMetric(variable); - - // if (metric == nullptr) { - // continue; - // } - - // ChatPackets::SendSystemMessage( - // sysAddr, - // GeneralUtils::ASCIIToUTF16(Metrics::MetricVariableToString(variable)) + - // u": " + - // GeneralUtils::to_u16string(Metrics::ToMiliseconds(metric->average)) + - // u"ms" - // ); - // } - - // ChatPackets::SendSystemMessage( - // sysAddr, - // u"Peak RSS: " + GeneralUtils::to_u16string(static_cast<float>(static_cast<double>(Metrics::GetPeakRSS()) / 1.024e6)) + - // u"MB" - // ); - - // ChatPackets::SendSystemMessage( - // sysAddr, - // u"Current RSS: " + GeneralUtils::to_u16string(static_cast<float>(static_cast<double>(Metrics::GetCurrentRSS()) / 1.024e6)) + - // u"MB" - // ); - - // ChatPackets::SendSystemMessage( - // sysAddr, - // u"Process ID: " + GeneralUtils::to_u16string(Metrics::GetProcessID()) - // ); - - // return; - // } - - // if (chatCommand == "reloadconfig" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // Game::config->ReloadConfig(); - // VanityUtilities::SpawnVanity(); - // dpWorld::Reload(); - // auto entities = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY); - // for (const auto* const entity : entities) { - // auto* const scriptedActivityComponent = entity->GetComponent<ScriptedActivityComponent>(); - // if (!scriptedActivityComponent) continue; - - // scriptedActivityComponent->ReloadConfig(); - // } - // Game::server->UpdateMaximumMtuSize(); - // Game::server->UpdateBandwidthLimit(); - // ChatPackets::SendSystemMessage(sysAddr, u"Successfully reloaded config for world!"); - // } - - // if (chatCommand == "rollloot" && entity->GetGMLevel() >= eGameMasterLevel::OPERATOR && args.size() >= 3) { - // const auto lootMatrixIndex = GeneralUtils::TryParse<uint32_t>(args[0]); - // if (!lootMatrixIndex) return; - - // const auto targetLot = GeneralUtils::TryParse<uint32_t>(args[1]); - // if (!targetLot) return; - - // const auto loops = GeneralUtils::TryParse<uint32_t>(args[2]); - // if (!loops) return; - - // uint64_t totalRuns = 0; - - // for (uint32_t i = 0; i < loops; i++) { - // while (true) { - // auto lootRoll = Loot::RollLootMatrix(lootMatrixIndex.value()); - // totalRuns += 1; - // bool doBreak = false; - // for (const auto& kv : lootRoll) { - // if (static_cast<uint32_t>(kv.first) == targetLot) { - // doBreak = true; - // } - // } - // if (doBreak) break; - // } - // } - - // std::u16string message = u"Ran loot drops looking for " - // + GeneralUtils::to_u16string(targetLot.value()) - // + u", " - // + GeneralUtils::to_u16string(loops.value()) - // + u" times. It ran " - // + GeneralUtils::to_u16string(totalRuns) - // + u" times. Averaging out at " - // + GeneralUtils::to_u16string(static_cast<float>(totalRuns) / loops.value()); - - // ChatPackets::SendSystemMessage(sysAddr, message); - // } - - // if (chatCommand == "deleteinven" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { - // eInventoryType inventoryType = eInventoryType::INVALID; - - // const auto inventoryTypeOptional = GeneralUtils::TryParse<eInventoryType>(args[0]); - // if (!inventoryTypeOptional) { - // // In this case, we treat the input as a string and try to find it in the reflection list - // std::transform(args[0].begin(), args[0].end(), args[0].begin(), ::toupper); - // LOG("looking for inventory %s", args[0].c_str()); - // for (uint32_t index = 0; index < NUMBER_OF_INVENTORIES; index++) { - // if (std::string_view(args[0]) == std::string_view(InventoryType::InventoryTypeToString(static_cast<eInventoryType>(index)))) inventoryType = static_cast<eInventoryType>(index); - // } - // } else { - // inventoryType = inventoryTypeOptional.value(); - // } - - // if (inventoryType == eInventoryType::INVALID || inventoryType >= NUMBER_OF_INVENTORIES) { - // ChatPackets::SendSystemMessage(sysAddr, u"Invalid inventory provided."); - // return; - // } - - // auto* inventoryComponent = entity->GetComponent<InventoryComponent>(); - // if (!inventoryComponent) return; - - // auto* inventoryToDelete = inventoryComponent->GetInventory(inventoryType); - // if (!inventoryToDelete) return; - - // inventoryToDelete->DeleteAllItems(); - // LOG("Deleted inventory %s for user %llu", args[0].c_str(), entity->GetObjectID()); - // ChatPackets::SendSystemMessage(sysAddr, u"Deleted inventory " + GeneralUtils::UTF8ToUTF16(args[0])); - // } - - // if (chatCommand == "castskill" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { - // auto* skillComponent = entity->GetComponent<SkillComponent>(); - // if (skillComponent) { - // const auto skillId = GeneralUtils::TryParse<uint32_t>(args[0]); - - // if (!skillId) { - // ChatPackets::SendSystemMessage(sysAddr, u"Error getting skill ID."); - // return; - // } else { - // skillComponent->CastSkill(skillId.value(), entity->GetObjectID(), entity->GetObjectID()); - // ChatPackets::SendSystemMessage(sysAddr, u"Cast skill"); - // } - // } - // } - - // if (chatCommand == "setskillslot" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 2) { - // auto* const inventoryComponent = entity->GetComponent<InventoryComponent>(); - // if (inventoryComponent) { - // const auto slot = GeneralUtils::TryParse<BehaviorSlot>(args[0]); - // if (!slot) { - // ChatPackets::SendSystemMessage(sysAddr, u"Error getting slot."); - // return; - // } else { - // const auto skillId = GeneralUtils::TryParse<uint32_t>(args[1]); - // if (!skillId) { - // ChatPackets::SendSystemMessage(sysAddr, u"Error getting skill."); - // return; - // } else { - // if (inventoryComponent->SetSkill(slot.value(), skillId.value())) ChatPackets::SendSystemMessage(sysAddr, u"Set skill to slot successfully"); - // else ChatPackets::SendSystemMessage(sysAddr, u"Set skill to slot failed"); - // } - // } - // } - // } - - // if (chatCommand == "setfaction" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { - // auto* destroyableComponent = entity->GetComponent<DestroyableComponent>(); - // if (destroyableComponent) { - // const auto faction = GeneralUtils::TryParse<int32_t>(args[0]); - - // if (!faction) { - // ChatPackets::SendSystemMessage(sysAddr, u"Error getting faction."); - // return; - // } else { - // destroyableComponent->SetFaction(faction.value()); - // ChatPackets::SendSystemMessage(sysAddr, u"Set faction and updated enemies list"); - // } - // } - // } - - // if (chatCommand == "addfaction" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { - // auto* destroyableComponent = entity->GetComponent<DestroyableComponent>(); - // if (destroyableComponent) { - // const auto faction = GeneralUtils::TryParse<int32_t>(args[0]); - - // if (!faction) { - // ChatPackets::SendSystemMessage(sysAddr, u"Error getting faction."); - // return; - // } else { - // destroyableComponent->AddFaction(faction.value()); - // ChatPackets::SendSystemMessage(sysAddr, u"Added faction and updated enemies list"); - // } - // } - // } - - // if (chatCommand == "getfactions" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // auto* destroyableComponent = entity->GetComponent<DestroyableComponent>(); - // if (destroyableComponent) { - // ChatPackets::SendSystemMessage(sysAddr, u"Friendly factions:"); - // for (const auto entry : destroyableComponent->GetFactionIDs()) { - // ChatPackets::SendSystemMessage(sysAddr, (GeneralUtils::to_u16string(entry))); - // } - - // ChatPackets::SendSystemMessage(sysAddr, u"Enemy factions:"); - // for (const auto entry : destroyableComponent->GetEnemyFactionsIDs()) { - // ChatPackets::SendSystemMessage(sysAddr, (GeneralUtils::to_u16string(entry))); - // } - // } - // } - - // if (chatCommand == "setrewardcode" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() == 1) { - // auto* cdrewardCodes = CDClientManager::GetTable<CDRewardCodesTable>(); - - // auto id = cdrewardCodes->GetCodeID(args[0]); - // if (id != -1) Database::Get()->InsertRewardCode(user->GetAccountID(), id); - // } - - // if (chatCommand == "inspect" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { - // Entity* closest = nullptr; - - // std::u16string ldf; - - // bool isLDF = false; - - // auto component = GeneralUtils::TryParse<eReplicaComponentType>(args[0]); - // if (!component) { - // component = eReplicaComponentType::INVALID; - - // ldf = GeneralUtils::UTF8ToUTF16(args[0]); - - // isLDF = true; - // } - - // auto reference = entity->GetPosition(); - - // auto closestDistance = 0.0f; - - // const auto candidates = Game::entityManager->GetEntitiesByComponent(component.value()); - - // for (auto* candidate : candidates) { - // if (candidate->GetLOT() == 1 || candidate->GetLOT() == 8092) { - // continue; - // } - - // if (isLDF && !candidate->HasVar(ldf)) { - // continue; - // } - - // if (!closest) { - // closest = candidate; - - // closestDistance = NiPoint3::Distance(candidate->GetPosition(), reference); - - // continue; - // } - - // const auto distance = NiPoint3::Distance(candidate->GetPosition(), reference); - - // if (distance < closestDistance) { - // closest = candidate; - - // closestDistance = distance; - // } - // } - - // if (!closest) return; - - // Game::entityManager->SerializeEntity(closest); - - // auto* table = CDClientManager::GetTable<CDObjectsTable>(); - - // const auto& info = table->GetByID(closest->GetLOT()); - - // std::stringstream header; - - // header << info.name << " [" << std::to_string(info.id) << "]" << " " << std::to_string(closestDistance) << " " << std::to_string(closest->IsSleeping()); - - // ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(header.str())); - - // for (const auto& pair : closest->GetComponents()) { - // auto id = pair.first; - - // std::stringstream stream; - - // stream << "Component [" << std::to_string(static_cast<uint32_t>(id)) << "]"; - - // ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(stream.str())); - // } - - // if (args.size() >= 2) { - // if (args[1] == "-m" && args.size() >= 3) { - // auto* const movingPlatformComponent = closest->GetComponent<MovingPlatformComponent>(); - - // const auto mValue = GeneralUtils::TryParse<int32_t>(args[2]); - - // if (!movingPlatformComponent || !mValue) return; - - // movingPlatformComponent->SetSerialized(true); - - // if (mValue == -1) { - // movingPlatformComponent->StopPathing(); - // } else { - // movingPlatformComponent->GotoWaypoint(mValue.value()); - // } - - // Game::entityManager->SerializeEntity(closest); - // } else if (args[1] == "-a" && args.size() >= 3) { - // RenderComponent::PlayAnimation(closest, args.at(2)); - // } else if (args[1] == "-s") { - // for (auto* entry : closest->GetSettings()) { - // ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::UTF8ToUTF16(entry->GetString())); - // } - - // ChatPackets::SendSystemMessage(sysAddr, u"------"); - // ChatPackets::SendSystemMessage(sysAddr, u"Spawner ID: " + GeneralUtils::to_u16string(closest->GetSpawnerID())); - // } else if (args[1] == "-p") { - // const auto postion = closest->GetPosition(); - - // ChatPackets::SendSystemMessage( - // sysAddr, - // GeneralUtils::ASCIIToUTF16("< " + std::to_string(postion.x) + ", " + std::to_string(postion.y) + ", " + std::to_string(postion.z) + " >") - // ); - // } else if (args[1] == "-f") { - // auto* destuctable = closest->GetComponent<DestroyableComponent>(); - - // if (destuctable == nullptr) { - // ChatPackets::SendSystemMessage(sysAddr, u"No destroyable component on this entity!"); - // return; - // } - - // ChatPackets::SendSystemMessage(sysAddr, u"Smashable: " + (GeneralUtils::to_u16string(destuctable->GetIsSmashable()))); - - // ChatPackets::SendSystemMessage(sysAddr, u"Friendly factions:"); - // for (const auto entry : destuctable->GetFactionIDs()) { - // ChatPackets::SendSystemMessage(sysAddr, (GeneralUtils::to_u16string(entry))); - // } - - // ChatPackets::SendSystemMessage(sysAddr, u"Enemy factions:"); - // for (const auto entry : destuctable->GetEnemyFactionsIDs()) { - // ChatPackets::SendSystemMessage(sysAddr, (GeneralUtils::to_u16string(entry))); - // } - - // if (args.size() >= 3) { - // const auto faction = GeneralUtils::TryParse<int32_t>(args[2]); - // if (!faction) return; - - // destuctable->SetFaction(-1); - // destuctable->AddFaction(faction.value(), true); - // } - // } else if (args[1] == "-cf") { - // auto* destuctable = entity->GetComponent<DestroyableComponent>(); - // if (!destuctable) { - // ChatPackets::SendSystemMessage(sysAddr, u"No destroyable component on this entity!"); - // return; - // } - // if (destuctable->IsEnemy(closest)) ChatPackets::SendSystemMessage(sysAddr, u"They are our enemy"); - // else ChatPackets::SendSystemMessage(sysAddr, u"They are NOT our enemy"); - // } else if (args[1] == "-t") { - // auto* phantomPhysicsComponent = closest->GetComponent<PhantomPhysicsComponent>(); - - // if (phantomPhysicsComponent != nullptr) { - // 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()))); - // ChatPackets::SendSystemMessage(sysAddr, u"Active: " + (GeneralUtils::to_u16string(phantomPhysicsComponent->GetPhysicsEffectActive()))); - // } - - // auto* triggerComponent = closest->GetComponent<TriggerComponent>(); - // if (triggerComponent) { - // auto trigger = triggerComponent->GetTrigger(); - // if (trigger) { - // ChatPackets::SendSystemMessage(sysAddr, u"Trigger: " + (GeneralUtils::to_u16string(trigger->id))); - // } - // } - // } - // } - // } } +namespace GMZeroCommands { + void Pvp(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + auto* character = entity->GetComponent<CharacterComponent>(); + + if (character == nullptr) { + LOG("Failed to find character component!"); + return; + } + + character->SetPvpEnabled(!character->GetPvpEnabled()); + Game::entityManager->SerializeEntity(entity); + + std::stringstream message; + message << character->GetName() << " changed their PVP flag to " << std::to_string(character->GetPvpEnabled()) << "!"; + + ChatPackets::SendSystemMessage(UNASSIGNED_SYSTEM_ADDRESS, GeneralUtils::UTF8ToUTF16(message.str()), true); + } + + void Who(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + ChatPackets::SendSystemMessage( + sysAddr, + u"Players in this instance: (" + GeneralUtils::to_u16string(PlayerManager::GetAllPlayers().size()) + u")" + ); + + for (auto* player : PlayerManager::GetAllPlayers()) { + const auto& name = player->GetCharacter()->GetName(); + + ChatPackets::SendSystemMessage( + sysAddr, + GeneralUtils::UTF8ToUTF16(player == entity ? name + " (you)" : name) + ); + } + } + + void Ping(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + if (!args.empty() && args.starts_with("-l")) { + std::stringstream message; + message << "Your latest ping: " << std::to_string(Game::server->GetLatestPing(sysAddr)) << "ms"; + + ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(message.str())); + } else { + std::stringstream message; + message << "Your average ping: " << std::to_string(Game::server->GetPing(sysAddr)) << "ms"; + + ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(message.str())); + } + } + + void FixStats(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + // Reset skill component and buff component + auto* skillComponent = entity->GetComponent<SkillComponent>(); + auto* buffComponent = entity->GetComponent<BuffComponent>(); + auto* destroyableComponent = entity->GetComponent<DestroyableComponent>(); + + // If any of the components are nullptr, return + if (skillComponent == nullptr || buffComponent == nullptr || destroyableComponent == nullptr) { + return; + } + + // Reset skill component + skillComponent->Reset(); + + // Reset buff component + buffComponent->Reset(); + + // Fix the destroyable component + destroyableComponent->FixStats(); + } + + void Credits(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto& customText = VanityUtilities::ParseMarkdown((BinaryPathFinder::GetBinaryDir() / "vanity/CREDITS.md").string()); + + { + AMFArrayValue args; + + args.Insert("state", "Story"); + + GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "pushGameState", args); + } + + entity->AddCallbackTimer(0.5f, [customText, entity]() { + AMFArrayValue args; + + args.Insert("visible", true); + args.Insert("text", customText); + + LOG("Sending %s", customText.c_str()); + + GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "ToggleStoryBox", args); + }); + } + + void Info(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto& customText = VanityUtilities::ParseMarkdown((BinaryPathFinder::GetBinaryDir() / "vanity/INFO.md").string()); + + { + AMFArrayValue args; + + args.Insert("state", "Story"); + + GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "pushGameState", args); + } + + entity->AddCallbackTimer(0.5f, [customText, entity]() { + AMFArrayValue args; + + args.Insert("visible", true); + args.Insert("text", customText); + + LOG("Sending %s", customText.c_str()); + + GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "ToggleStoryBox", args); + }); + } + + void LeaveZone(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto currentZone = Game::zoneManager->GetZone()->GetZoneID().GetMapID(); + LWOMAPID newZone = 0; + + if (currentZone == 1001 || currentZone % 100 == 0) { + ChatPackets::SendSystemMessage(sysAddr, u"You are not in an instanced zone."); + return; + } else { + newZone = (currentZone / 100) * 100; + } + // If new zone would be inaccessible, then default to Avant Gardens. + if (!Game::zoneManager->CheckIfAccessibleZone(newZone)) newZone = 1100; + + ChatPackets::SendSystemMessage(sysAddr, u"Leaving zone..."); + + const auto objid = entity->GetObjectID(); + + ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, newZone, 0, false, [objid](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { + auto* entity = Game::entityManager->GetEntity(objid); + + if (entity == nullptr) { + return; + } + + const auto sysAddr = entity->GetSystemAddress(); + + LOG("Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", entity->GetCharacter()->GetName().c_str(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); + + if (entity->GetCharacter()) { + entity->GetCharacter()->SetZoneID(zoneID); + entity->GetCharacter()->SetZoneInstance(zoneInstance); + entity->GetCharacter()->SetZoneClone(zoneClone); + } + + entity->GetCharacter()->SaveXMLToDatabase(); + + WorldPackets::SendTransferToWorld(sysAddr, serverIP, serverPort, mythranShift); + }); + } + + void Join(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + ChatPackets::SendSystemMessage(sysAddr, u"Requesting private map..."); + const auto& password = splitArgs[0]; + + ZoneInstanceManager::Instance()->RequestPrivateZone(Game::server, false, password, [=](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { + LOG("Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", sysAddr.ToString(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); + + if (entity->GetCharacter()) { + entity->GetCharacter()->SetZoneID(zoneID); + entity->GetCharacter()->SetZoneInstance(zoneInstance); + entity->GetCharacter()->SetZoneClone(zoneClone); + } + + entity->GetCharacter()->SaveXMLToDatabase(); + + WorldPackets::SendTransferToWorld(sysAddr, serverIP, serverPort, mythranShift); + }); + } + + void Die(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + entity->Smash(entity->GetObjectID()); + } + + void Resurrect(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + ScriptedActivityComponent* scriptedActivityComponent = Game::zoneManager->GetZoneControlObject()->GetComponent<ScriptedActivityComponent>(); + + if (scriptedActivityComponent) { // check if user is in activity world and if so, they can't resurrect + ChatPackets::SendSystemMessage(sysAddr, u"You cannot resurrect in an activity world."); + return; + } + + GameMessages::SendResurrect(entity); + } + + void RequestMailCount(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + Mail::HandleNotificationRequest(entity->GetSystemAddress(), entity->GetObjectID()); + } + + void InstanceInfo(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto zoneId = Game::zoneManager->GetZone()->GetZoneID(); + + ChatPackets::SendSystemMessage(sysAddr, u"Map: " + (GeneralUtils::to_u16string(zoneId.GetMapID())) + u"\nClone: " + (GeneralUtils::to_u16string(zoneId.GetCloneID())) + u"\nInstance: " + (GeneralUtils::to_u16string(zoneId.GetInstanceID()))); + } +}; + +namespace DEVGMCommands { + void ResetMission(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + const auto missionId = GeneralUtils::TryParse<uint32_t>(splitArgs[0]); + if (!missionId) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid mission ID."); + return; + } + + auto* missionComponent = entity->GetComponent<MissionComponent>(); + if (!missionComponent) return; + missionComponent->ResetMission(missionId.value()); + } + + void SetMinifig(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.size() < 2) return; + + const auto minifigItemIdExists = GeneralUtils::TryParse<int32_t>(splitArgs[1]); + if (!minifigItemIdExists) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid Minifig Item Id ID."); + return; + } + const int32_t minifigItemId = minifigItemIdExists.value(); + Game::entityManager->DestructEntity(entity, sysAddr); + auto* charComp = entity->GetComponent<CharacterComponent>(); + std::string lowerName = splitArgs[0]; + if (lowerName.empty()) return; + std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), ::tolower); + if (lowerName == "eyebrows") { + charComp->m_Character->SetEyebrows(minifigItemId); + } else if (lowerName == "eyes") { + charComp->m_Character->SetEyes(minifigItemId); + } else if (lowerName == "haircolor") { + charComp->m_Character->SetHairColor(minifigItemId); + } else if (lowerName == "hairstyle") { + charComp->m_Character->SetHairStyle(minifigItemId); + } else if (lowerName == "pants") { + charComp->m_Character->SetPantsColor(minifigItemId); + } else if (lowerName == "lefthand") { + charComp->m_Character->SetLeftHand(minifigItemId); + } else if (lowerName == "mouth") { + charComp->m_Character->SetMouth(minifigItemId); + } else if (lowerName == "righthand") { + charComp->m_Character->SetRightHand(minifigItemId); + } else if (lowerName == "shirtcolor") { + charComp->m_Character->SetShirtColor(minifigItemId); + } else if (lowerName == "hands") { + charComp->m_Character->SetLeftHand(minifigItemId); + charComp->m_Character->SetRightHand(minifigItemId); + } else { + Game::entityManager->ConstructEntity(entity); + ChatPackets::SendSystemMessage(sysAddr, u"Invalid Minifig item to change, try one of the following: Eyebrows, Eyes, HairColor, HairStyle, Pants, LeftHand, Mouth, RightHand, Shirt, Hands"); + return; + } + + Game::entityManager->ConstructEntity(entity); + ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(lowerName) + u" set to " + (GeneralUtils::to_u16string(minifigItemId))); + + GameMessages::SendToggleGMInvis(entity->GetObjectID(), false, UNASSIGNED_SYSTEM_ADDRESS); // need to retoggle because it gets reenabled on creation of new character + } + + void PlayAnimation(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + std::u16string anim = GeneralUtils::ASCIIToUTF16(splitArgs[0], splitArgs[0].size()); + RenderComponent::PlayAnimation(entity, anim); + auto* possessorComponent = entity->GetComponent<PossessorComponent>(); + if (possessorComponent) { + auto* possessedComponent = Game::entityManager->GetEntity(possessorComponent->GetPossessable()); + if (possessedComponent) RenderComponent::PlayAnimation(possessedComponent, anim); + } + } + + void ListSpawns(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + for (const auto& pair : Game::entityManager->GetSpawnPointEntities()) { + ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(pair.first)); + } + + ChatPackets::SendSystemMessage(sysAddr, u"Current: " + GeneralUtils::ASCIIToUTF16(entity->GetCharacter()->GetTargetScene())); + } + + void UnlockEmote(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + const auto emoteID = GeneralUtils::TryParse<int32_t>(splitArgs[0]); + + if (!emoteID) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid emote ID."); + return; + } + + entity->GetCharacter()->UnlockEmote(emoteID.value()); + } + + void ForceSave(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + entity->GetCharacter()->SaveXMLToDatabase(); + } + + void Kill(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + ChatPackets::SendSystemMessage(sysAddr, u"Brutally murdering that player, if online on this server."); + + auto* player = PlayerManager::GetPlayer(splitArgs[0]); + if (player) { + player->Smash(entity->GetObjectID()); + ChatPackets::SendSystemMessage(sysAddr, u"It has been done, do you feel good about yourself now?"); + return; + } + + ChatPackets::SendSystemMessage(sysAddr, u"They were saved from your carnage."); + return; + } + + void SpeedBoost(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + const auto boostOptional = GeneralUtils::TryParse<float>(splitArgs[0]); + if (!boostOptional) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid boost."); + return; + } + const float boost = boostOptional.value(); + + auto* controllablePhysicsComponent = entity->GetComponent<ControllablePhysicsComponent>(); + + if (!controllablePhysicsComponent) return; + controllablePhysicsComponent->SetSpeedMultiplier(boost); + + // speedboost possessables + auto possessor = entity->GetComponent<PossessorComponent>(); + if (possessor) { + auto possessedID = possessor->GetPossessable(); + if (possessedID != LWOOBJID_EMPTY) { + auto possessable = Game::entityManager->GetEntity(possessedID); + if (possessable) { + auto* possessControllablePhysicsComponent = possessable->GetComponent<ControllablePhysicsComponent>(); + if (possessControllablePhysicsComponent) { + possessControllablePhysicsComponent->SetSpeedMultiplier(boost); + } + } + } + } + + Game::entityManager->SerializeEntity(entity); + } + + void Freecam(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto state = !entity->GetVar<bool>(u"freecam"); + entity->SetVar<bool>(u"freecam", state); + + GameMessages::SendSetPlayerControlScheme(entity, static_cast<eControlScheme>(state ? 9 : 1)); + + ChatPackets::SendSystemMessage(sysAddr, u"Toggled freecam."); + } + + void SetControlScheme(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + const auto scheme = GeneralUtils::TryParse<uint32_t>(splitArgs[0]); + + if (!scheme) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid control scheme."); + return; + } + + GameMessages::SendSetPlayerControlScheme(entity, static_cast<eControlScheme>(scheme.value())); + + ChatPackets::SendSystemMessage(sysAddr, u"Switched control scheme."); + } + + void ApproveProperty(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + if (PropertyManagementComponent::Instance() != nullptr) { + PropertyManagementComponent::Instance()->UpdateApprovedStatus(true); + } + } + + void SetUiState(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + AMFArrayValue uiState; + + uiState.Insert("state", splitArgs[0]); + + GameMessages::SendUIMessageServerToSingleClient(entity, sysAddr, "pushGameState", uiState); + + ChatPackets::SendSystemMessage(sysAddr, u"Switched UI state."); + } + + void Toggle(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + AMFArrayValue amfArgs; + + amfArgs.Insert("visible", true); + + GameMessages::SendUIMessageServerToSingleClient(entity, sysAddr, splitArgs[0], amfArgs); + + ChatPackets::SendSystemMessage(sysAddr, u"Toggled UI state."); + } + + void SetInventorySize(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + const auto sizeOptional = GeneralUtils::TryParse<uint32_t>(splitArgs[0]); + if (!sizeOptional) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid size."); + return; + } + const uint32_t size = sizeOptional.value(); + + eInventoryType selectedInventory = eInventoryType::ITEMS; + + // a possible inventory was provided if we got more than 1 argument + if (splitArgs.size() >= 2) { + selectedInventory = GeneralUtils::TryParse<eInventoryType>(splitArgs.at(1)).value_or(eInventoryType::INVALID); + if (selectedInventory == eInventoryType::INVALID) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid inventory."); + return; + } else { + // In this case, we treat the input as a string and try to find it in the reflection list + std::transform(splitArgs.at(1).begin(), splitArgs.at(1).end(), splitArgs.at(1).begin(), ::toupper); + for (uint32_t index = 0; index < NUMBER_OF_INVENTORIES; index++) { + if (std::string_view(splitArgs.at(1)) == std::string_view(InventoryType::InventoryTypeToString(static_cast<eInventoryType>(index)))) selectedInventory = static_cast<eInventoryType>(index); + } + } + + ChatPackets::SendSystemMessage(sysAddr, u"Setting inventory " + + GeneralUtils::ASCIIToUTF16(splitArgs.at(1)) + + u" to size " + + GeneralUtils::to_u16string(size)); + } else ChatPackets::SendSystemMessage(sysAddr, u"Setting inventory ITEMS to size " + GeneralUtils::to_u16string(size)); + + auto* inventoryComponent = entity->GetComponent<InventoryComponent>(); + if (inventoryComponent) { + auto* inventory = inventoryComponent->GetInventory(selectedInventory); + + inventory->SetSize(size); + } + } + + void RunMacro(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + // Only process if input does not contain separator charaters + if (splitArgs[0].find("/") != std::string::npos) return; + if (splitArgs[0].find("\\") != std::string::npos) return; + + auto infile = Game::assetManager->GetFile(("macros/" + splitArgs[0] + ".scm").c_str()); + + if (!infile) { + ChatPackets::SendSystemMessage(sysAddr, u"Unknown macro! Is the filename right?"); + return; + } + + if (infile.good()) { + std::string line; + while (std::getline(infile, line)) { + // Do this in two separate calls to catch both \n and \r\n + line.erase(std::remove(line.begin(), line.end(), '\n'), line.end()); + line.erase(std::remove(line.begin(), line.end(), '\r'), line.end()); + SlashCommandHandler::HandleChatCommand(GeneralUtils::ASCIIToUTF16(line), entity, sysAddr); + } + } else { + ChatPackets::SendSystemMessage(sysAddr, u"Unknown macro! Is the filename right?"); + } + } + + void AddMission(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + const auto missionID = GeneralUtils::TryParse<uint32_t>(splitArgs.at(0)); + + if (!missionID) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid mission id."); + return; + } + + auto comp = static_cast<MissionComponent*>(entity->GetComponent(eReplicaComponentType::MISSION)); + if (comp) comp->AcceptMission(missionID.value(), true); + } + + void CompleteMission(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + const auto missionID = GeneralUtils::TryParse<uint32_t>(splitArgs.at(0)); + + if (!missionID) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid mission id."); + return; + } + + auto comp = static_cast<MissionComponent*>(entity->GetComponent(eReplicaComponentType::MISSION)); + if (comp) comp->CompleteMission(missionID.value(), true); + } + + void SetFlag(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.size() == 1) { + const auto flagId = GeneralUtils::TryParse<int32_t>(splitArgs.at(0)); + + if (!flagId) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid flag id."); + return; + } + + entity->GetCharacter()->SetPlayerFlag(flagId.value(), true); + } else if (splitArgs.size() >= 2) { + const auto flagId = GeneralUtils::TryParse<int32_t>(splitArgs.at(1)); + std::string onOffFlag = splitArgs.at(0); + if (!flagId) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid flag id."); + return; + } + + if (onOffFlag != "off" && onOffFlag != "on") { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid flag type."); + return; + } + + entity->GetCharacter()->SetPlayerFlag(flagId.value(), onOffFlag == "on"); + } + } + + void ClearFlag(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + const auto flagId = GeneralUtils::TryParse<int32_t>(splitArgs.at(0)); + + if (!flagId) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid flag id."); + return; + } + + entity->GetCharacter()->SetPlayerFlag(flagId.value(), false); + } + + void PlayEffect(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.size() < 3) return; + + const auto effectID = GeneralUtils::TryParse<int32_t>(splitArgs.at(0)); + + if (!effectID) return; + + // FIXME: use fallible ASCIIToUTF16 conversion, because non-ascii isn't valid anyway + GameMessages::SendPlayFXEffect(entity->GetObjectID(), effectID.value(), GeneralUtils::ASCIIToUTF16(splitArgs.at(1)), splitArgs.at(2)); + } + + void StopEffect(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + GameMessages::SendStopFXEffect(entity, true, splitArgs[0]); + } + + void SetAnnTitle(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + entity->GetCharacter()->SetAnnouncementTitle(args); + } + + void SetAnnMsg(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + entity->GetCharacter()->SetAnnouncementMessage(args); + } + + void Announce(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + if (entity->GetCharacter()->GetAnnouncementTitle().empty() || entity->GetCharacter()->GetAnnouncementMessage().empty()) { + ChatPackets::SendSystemMessage(sysAddr, u"Use /setanntitle <title> & /setannmsg <msg> first!"); + return; + } + + SlashCommandHandler::SendAnnouncement(entity->GetCharacter()->GetAnnouncementTitle(), entity->GetCharacter()->GetAnnouncementMessage()); + } + + void ShutdownUniverse(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + //Tell the master server that we're going to be shutting down whole "universe": + CBITSTREAM; + BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::SHUTDOWN_UNIVERSE); + Game::server->SendToMaster(bitStream); + ChatPackets::SendSystemMessage(sysAddr, u"Sent universe shutdown notification to master."); + + //Tell chat to send an announcement to all servers + SlashCommandHandler::SendAnnouncement("Servers Closing Soon!", "DLU servers will close for maintenance in 10 minutes from now."); + } + + void GetNavmeshHeight(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + auto control = static_cast<ControllablePhysicsComponent*>(entity->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS)); + if (!control) return; + + float y = dpWorld::GetNavMesh()->GetHeightAtPoint(control->GetPosition()); + std::u16string msg = u"Navmesh height: " + (GeneralUtils::to_u16string(y)); + ChatPackets::SendSystemMessage(sysAddr, msg); + } + + void GmAddItem(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + + if (splitArgs.size() == 1) { + const auto itemLOT = GeneralUtils::TryParse<uint32_t>(splitArgs.at(0)); + + if (!itemLOT) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid item LOT."); + return; + } + + InventoryComponent* inventory = static_cast<InventoryComponent*>(entity->GetComponent(eReplicaComponentType::INVENTORY)); + + inventory->AddItem(itemLOT.value(), 1, eLootSourceType::MODERATION); + } else if (splitArgs.size() == 2) { + const auto itemLOT = GeneralUtils::TryParse<uint32_t>(splitArgs.at(0)); + if (!itemLOT) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid item LOT."); + return; + } + + const auto count = GeneralUtils::TryParse<uint32_t>(splitArgs.at(1)); + if (!count) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid item count."); + return; + } + + InventoryComponent* inventory = static_cast<InventoryComponent*>(entity->GetComponent(eReplicaComponentType::INVENTORY)); + + inventory->AddItem(itemLOT.value(), count.value(), eLootSourceType::MODERATION); + } else { + ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /gmadditem <lot>"); + } + } + + void MailItem(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.size() < 2) return; + + const auto& playerName = splitArgs[0]; + + auto playerInfo = Database::Get()->GetCharacterInfo(playerName); + + uint32_t receiverID = 0; + if (!playerInfo) { + ChatPackets::SendSystemMessage(sysAddr, u"Failed to find that player"); + + return; + } + + receiverID = playerInfo->id; + + const auto lot = GeneralUtils::TryParse<LOT>(splitArgs.at(1)); + + if (!lot) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid item lot."); + return; + } + + IMail::MailInfo mailInsert; + mailInsert.senderId = entity->GetObjectID(); + mailInsert.senderUsername = "Darkflame Universe"; + mailInsert.receiverId = receiverID; + mailInsert.recipient = playerName; + mailInsert.subject = "Lost item"; + mailInsert.body = "This is a replacement item for one you lost."; + mailInsert.itemID = LWOOBJID_EMPTY; + mailInsert.itemLOT = lot.value(); + mailInsert.itemSubkey = LWOOBJID_EMPTY; + mailInsert.itemCount = 1; + Database::Get()->InsertNewMail(mailInsert); + + ChatPackets::SendSystemMessage(sysAddr, u"Mail sent"); + } + + void SetName(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + GameMessages::SendSetName(entity->GetObjectID(), GeneralUtils::UTF8ToUTF16(args), UNASSIGNED_SYSTEM_ADDRESS); + } + + void Title(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + std::string name = entity->GetCharacter()->GetName() + " - " + args; + GameMessages::SendSetName(entity->GetObjectID(), GeneralUtils::UTF8ToUTF16(name), UNASSIGNED_SYSTEM_ADDRESS); + } + + void Teleport(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + + NiPoint3 pos{}; + if (splitArgs.size() == 3) { + + const auto x = GeneralUtils::TryParse<float>(splitArgs.at(0)); + if (!x) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid x."); + return; + } + + const auto y = GeneralUtils::TryParse<float>(splitArgs.at(1)); + if (!y) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid y."); + return; + } + + const auto z = GeneralUtils::TryParse<float>(splitArgs.at(2)); + if (!z) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid z."); + return; + } + + pos.SetX(x.value()); + pos.SetY(y.value()); + pos.SetZ(z.value()); + + LOG("Teleporting objectID: %llu to %f, %f, %f", entity->GetObjectID(), pos.x, pos.y, pos.z); + GameMessages::SendTeleport(entity->GetObjectID(), pos, NiQuaternion(), sysAddr); + } else if (splitArgs.size() == 2) { + + const auto x = GeneralUtils::TryParse<float>(splitArgs.at(0)); + if (!x) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid x."); + return; + } + + const auto z = GeneralUtils::TryParse<float>(splitArgs.at(1)); + if (!z) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid z."); + return; + } + + pos.SetX(x.value()); + pos.SetY(0.0f); + pos.SetZ(z.value()); + + LOG("Teleporting objectID: %llu to X: %f, Z: %f", entity->GetObjectID(), pos.x, pos.z); + GameMessages::SendTeleport(entity->GetObjectID(), pos, NiQuaternion(), sysAddr); + } else { + ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /teleport <x> (<y>) <z> - if no Y given, will teleport to the height of the terrain (or any physics object)."); + } + + auto* possessorComponent = entity->GetComponent<PossessorComponent>(); + if (possessorComponent) { + auto* possassableEntity = Game::entityManager->GetEntity(possessorComponent->GetPossessable()); + + if (possassableEntity != nullptr) { + auto* havokVehiclePhysicsComponent = possassableEntity->GetComponent<HavokVehiclePhysicsComponent>(); + if (havokVehiclePhysicsComponent) { + havokVehiclePhysicsComponent->SetPosition(pos); + Game::entityManager->SerializeEntity(possassableEntity); + } else GameMessages::SendTeleport(possassableEntity->GetObjectID(), pos, NiQuaternion(), sysAddr); + } + } + } + + void TpAll(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto pos = entity->GetPosition(); + + const auto characters = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::CHARACTER); + + for (auto* character : characters) { + GameMessages::SendTeleport(character->GetObjectID(), pos, NiQuaternion(), character->GetSystemAddress()); + } + } + + void Dismount(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + auto* possessorComponent = entity->GetComponent<PossessorComponent>(); + if (possessorComponent) { + auto possessableId = possessorComponent->GetPossessable(); + if (possessableId != LWOOBJID_EMPTY) { + auto* possessableEntity = Game::entityManager->GetEntity(possessableId); + if (possessableEntity) possessorComponent->Dismount(possessableEntity, true); + } + } + } + + void Fly(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + auto* character = entity->GetCharacter(); + + if (character) { + bool isFlying = character->GetIsFlying(); + + if (isFlying) { + GameMessages::SendSetJetPackMode(entity, false); + + character->SetIsFlying(false); + } else { + float speedScale = 1.0f; + + if (splitArgs.size() >= 1) { + const auto tempScaleStore = GeneralUtils::TryParse<float>(splitArgs.at(0)); + + if (tempScaleStore) { + speedScale = tempScaleStore.value(); + } else { + ChatPackets::SendSystemMessage(sysAddr, u"Failed to parse speed scale argument."); + } + } + + float airSpeed = 20 * speedScale; + float maxAirSpeed = 30 * speedScale; + float verticalVelocity = 1.5 * speedScale; + + GameMessages::SendSetJetPackMode(entity, true, true, false, 167, airSpeed, maxAirSpeed, verticalVelocity); + + character->SetIsFlying(true); + } + } + } + + void Mute(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + + if (splitArgs.size() >= 1) { + auto* player = PlayerManager::GetPlayer(splitArgs[0]); + + uint32_t accountId = 0; + LWOOBJID characterId = 0; + + if (player == nullptr) { + auto characterInfo = Database::Get()->GetCharacterInfo(splitArgs[0]); + + if (characterInfo) { + accountId = characterInfo->accountId; + characterId = characterInfo->id; + + GeneralUtils::SetBit(characterId, eObjectBits::CHARACTER); + GeneralUtils::SetBit(characterId, eObjectBits::PERSISTENT); + } + + if (accountId == 0) { + ChatPackets::SendSystemMessage(sysAddr, u"Count not find player of name: " + GeneralUtils::UTF8ToUTF16(splitArgs[0])); + + return; + } + } else { + auto* character = player->GetCharacter(); + auto* user = character != nullptr ? character->GetParentUser() : nullptr; + if (user) accountId = user->GetAccountID(); + characterId = player->GetObjectID(); + } + + time_t expire = 1; // Default to indefinate mute + + if (splitArgs.size() >= 2) { + const auto days = GeneralUtils::TryParse<uint32_t>(splitArgs[1]); + if (!days) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid days."); + + return; + } + + std::optional<uint32_t> hours; + if (splitArgs.size() >= 3) { + hours = GeneralUtils::TryParse<uint32_t>(splitArgs[2]); + if (!hours) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid hours."); + + return; + } + } + + expire = time(NULL); + expire += 24 * 60 * 60 * days.value(); + expire += 60 * 60 * hours.value_or(0); + } + + if (accountId != 0) Database::Get()->UpdateAccountUnmuteTime(accountId, expire); + + char buffer[32] = "brought up for review.\0"; + + if (expire != 1) { + std::tm* ptm = std::localtime(&expire); + // Format: Mo, 15.06.2009 20:20:00 + std::strftime(buffer, 32, "%a, %d.%m.%Y %H:%M:%S", ptm); + } + + const auto timeStr = GeneralUtils::ASCIIToUTF16(std::string(buffer)); + + ChatPackets::SendSystemMessage(sysAddr, u"Muted: " + GeneralUtils::UTF8ToUTF16(splitArgs[0]) + u" until " + timeStr); + + //Notify chat about it + CBITSTREAM; + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::MUTE_UPDATE); + + bitStream.Write(characterId); + bitStream.Write(expire); + + Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false); + } else { + ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /mute <username> <days (optional)> <hours (optional)>"); + } + } + + void Kick(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.size() == 1) { + auto* player = PlayerManager::GetPlayer(splitArgs[0]); + + std::u16string username = GeneralUtils::UTF8ToUTF16(splitArgs[0]); + if (player == nullptr) { + ChatPackets::SendSystemMessage(sysAddr, u"Count not find player of name: " + username); + return; + } + + Game::server->Disconnect(player->GetSystemAddress(), eServerDisconnectIdentifiers::KICK); + + ChatPackets::SendSystemMessage(sysAddr, u"Kicked: " + username); + } else { + ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /kick <username>"); + } + } + + void Ban(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + + if (splitArgs.size() == 1) { + auto* player = PlayerManager::GetPlayer(splitArgs[0]); + + uint32_t accountId = 0; + + if (player == nullptr) { + auto characterInfo = Database::Get()->GetCharacterInfo(splitArgs[0]); + + if (characterInfo) { + accountId = characterInfo->accountId; + } + + if (accountId == 0) { + ChatPackets::SendSystemMessage(sysAddr, u"Count not find player of name: " + GeneralUtils::UTF8ToUTF16(splitArgs[0])); + + return; + } + } else { + auto* character = player->GetCharacter(); + auto* user = character != nullptr ? character->GetParentUser() : nullptr; + if (user) accountId = user->GetAccountID(); + } + + if (accountId != 0) Database::Get()->UpdateAccountBan(accountId, true); + + if (player != nullptr) { + Game::server->Disconnect(player->GetSystemAddress(), eServerDisconnectIdentifiers::FREE_TRIAL_EXPIRED); + } + + ChatPackets::SendSystemMessage(sysAddr, u"Banned: " + GeneralUtils::ASCIIToUTF16(splitArgs[0])); + } else { + ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /ban <username>"); + } + } + + void BuffMe(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + auto dest = static_cast<DestroyableComponent*>(entity->GetComponent(eReplicaComponentType::DESTROYABLE)); + if (dest) { + dest->SetHealth(999); + dest->SetMaxHealth(999.0f); + dest->SetArmor(999); + dest->SetMaxArmor(999.0f); + dest->SetImagination(999); + dest->SetMaxImagination(999.0f); + } + Game::entityManager->SerializeEntity(entity); + } + + void StartCelebration(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + const auto celebration = GeneralUtils::TryParse<int32_t>(splitArgs.at(0)); + + if (!celebration) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid celebration."); + return; + } + + GameMessages::SendStartCelebrationEffect(entity, entity->GetSystemAddress(), celebration.value()); + } + + void BuffMed(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + auto dest = static_cast<DestroyableComponent*>(entity->GetComponent(eReplicaComponentType::DESTROYABLE)); + if (dest) { + dest->SetHealth(9); + dest->SetMaxHealth(9.0f); + dest->SetArmor(9); + dest->SetMaxArmor(9.0f); + dest->SetImagination(9); + dest->SetMaxImagination(9.0f); + } + Game::entityManager->SerializeEntity(entity); + } + + void RefillStats(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + auto dest = static_cast<DestroyableComponent*>(entity->GetComponent(eReplicaComponentType::DESTROYABLE)); + if (dest) { + dest->SetHealth(static_cast<int32_t>(dest->GetMaxHealth())); + dest->SetArmor(static_cast<int32_t>(dest->GetMaxArmor())); + dest->SetImagination(static_cast<int32_t>(dest->GetMaxImagination())); + } + + Game::entityManager->SerializeEntity(entity); + } + + void Lookup(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + auto query = CDClientDatabase::CreatePreppedStmt( + "SELECT `id`, `name` FROM `Objects` WHERE `displayName` LIKE ?1 OR `name` LIKE ?1 OR `description` LIKE ?1 LIMIT 50"); + + const std::string query_text = "%" + args + "%"; + query.bind(1, query_text.c_str()); + + auto tables = query.execQuery(); + + while (!tables.eof()) { + std::string message = std::to_string(tables.getIntField(0)) + " - " + tables.getStringField(1); + ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::UTF8ToUTF16(message, message.size())); + tables.nextRow(); + } + } + + void Spawn(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + ControllablePhysicsComponent* comp = static_cast<ControllablePhysicsComponent*>(entity->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS)); + if (!comp) return; + + const auto lot = GeneralUtils::TryParse<uint32_t>(splitArgs[0]); + + if (!lot) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid lot."); + return; + } + + EntityInfo info; + info.lot = lot.value(); + info.pos = comp->GetPosition(); + info.rot = comp->GetRotation(); + info.spawner = nullptr; + info.spawnerID = entity->GetObjectID(); + info.spawnerNodeID = 0; + + Entity* newEntity = Game::entityManager->CreateEntity(info, nullptr); + + if (newEntity == nullptr) { + ChatPackets::SendSystemMessage(sysAddr, u"Failed to spawn entity."); + return; + } + + Game::entityManager->ConstructEntity(newEntity); + } + + void SpawnGroup(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.size() < 3) return; + + const auto lot = GeneralUtils::TryParse<uint32_t>(splitArgs[0]); + if (!lot) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid lot."); + return; + } + + const auto numberToSpawnOptional = GeneralUtils::TryParse<uint32_t>(splitArgs[1]); + if (!numberToSpawnOptional && numberToSpawnOptional.value() > 0) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid number of enemies to spawn."); + return; + } + uint32_t numberToSpawn = numberToSpawnOptional.value(); + + // Must spawn within a radius of at least 0.0f + const auto radiusToSpawnWithinOptional = GeneralUtils::TryParse<float>(splitArgs[2]); + if (!radiusToSpawnWithinOptional && radiusToSpawnWithinOptional.value() < 0.0f) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid radius to spawn within."); + return; + } + const float radiusToSpawnWithin = radiusToSpawnWithinOptional.value(); + + EntityInfo info; + info.lot = lot.value(); + info.spawner = nullptr; + info.spawnerID = entity->GetObjectID(); + info.spawnerNodeID = 0; + + auto playerPosition = entity->GetPosition(); + while (numberToSpawn > 0) { + auto randomAngle = GeneralUtils::GenerateRandomNumber<float>(0.0f, 2 * PI); + auto randomRadius = GeneralUtils::GenerateRandomNumber<float>(0.0f, radiusToSpawnWithin); + + // Set the position to the generated random position plus the player position. This will + // spawn the entity in a circle around the player. As you get further from the player, the angle chosen will get less accurate. + info.pos = playerPosition + NiPoint3(cos(randomAngle) * randomRadius, 0.0f, sin(randomAngle) * randomRadius); + info.rot = NiQuaternion(); + + auto newEntity = Game::entityManager->CreateEntity(info); + if (newEntity == nullptr) { + } + } + } + + void GiveUScore(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + const auto uscoreOptional = GeneralUtils::TryParse<int32_t>(splitArgs[0]); + if (!uscoreOptional) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid uscore."); + return; + } + const int32_t uscore = uscoreOptional.value(); + + CharacterComponent* character = entity->GetComponent<CharacterComponent>(); + if (character) character->SetUScore(character->GetUScore() + uscore); + // MODERATION should work but it doesn't. Relog to see uscore changes + + eLootSourceType lootType = eLootSourceType::MODERATION; + + if (splitArgs.size() >= 2) { + const auto type = GeneralUtils::TryParse<eLootSourceType>(splitArgs[1]); + lootType = type.value_or(lootType); + } + + GameMessages::SendModifyLEGOScore(entity, entity->GetSystemAddress(), uscore, lootType); + } + + void SetLevel(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + // 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 (splitArgs.size() > 1) { + requestedPlayerToSetLevelOf = splitArgs[1]; + + auto requestedPlayer = PlayerManager::GetPlayer(requestedPlayerToSetLevelOf); + + if (!requestedPlayer) { + ChatPackets::SendSystemMessage(sysAddr, u"No player found with username: (" + GeneralUtils::UTF8ToUTF16(requestedPlayerToSetLevelOf) + u")."); + return; + } + + if (!requestedPlayer->GetOwner()) { + ChatPackets::SendSystemMessage(sysAddr, u"No entity found with username: (" + GeneralUtils::UTF8ToUTF16(requestedPlayerToSetLevelOf) + u")."); + return; + } + + entity = requestedPlayer->GetOwner(); + } + const auto requestedLevelOptional = GeneralUtils::TryParse<uint32_t>(splitArgs[0]); + uint32_t oldLevel; + + // first check the level is valid + if (!requestedLevelOptional) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid level."); + return; + } + uint32_t requestedLevel = requestedLevelOptional.value(); + // query to set our uscore to the correct value for this level + + auto characterComponent = entity->GetComponent<CharacterComponent>(); + if (!characterComponent) return; + auto levelComponent = entity->GetComponent<LevelProgressionComponent>(); + auto query = CDClientDatabase::CreatePreppedStmt("SELECT requiredUScore from LevelProgressionLookup WHERE id = ?;"); + query.bind(1, static_cast<int>(requestedLevel)); + auto result = query.execQuery(); + + if (result.eof()) return; + + // Set the UScore first + oldLevel = levelComponent->GetLevel(); + characterComponent->SetUScore(result.getIntField(0, characterComponent->GetUScore())); + + // handle level up for each level we have passed if we set our level to be higher than the current one. + if (oldLevel < requestedLevel) { + while (oldLevel < requestedLevel) { + oldLevel += 1; + levelComponent->SetLevel(oldLevel); + levelComponent->HandleLevelUp(); + } + } else { + levelComponent->SetLevel(requestedLevel); + } + + if (requestedPlayerToSetLevelOf != "") { + ChatPackets::SendSystemMessage( + sysAddr, u"Set " + GeneralUtils::UTF8ToUTF16(requestedPlayerToSetLevelOf) + u"'s level to " + GeneralUtils::to_u16string(requestedLevel) + + u" and UScore to " + GeneralUtils::to_u16string(characterComponent->GetUScore()) + + u". Relog to see changes."); + } else { + ChatPackets::SendSystemMessage( + sysAddr, u"Set your level to " + GeneralUtils::to_u16string(requestedLevel) + + u" and UScore to " + GeneralUtils::to_u16string(characterComponent->GetUScore()) + + u". Relog to see changes."); + } + } + + void Pos(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + 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">"); + + LOG("Position: %f, %f, %f", position.x, position.y, position.z); + } + + void Rot(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + 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">"); + + LOG("Rotation: %f, %f, %f, %f", rotation.w, rotation.x, rotation.y, rotation.z); + } + + void LocRow(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto position = entity->GetPosition(); + const auto rotation = entity->GetRotation(); + + LOG("<location x=\"%f\" y=\"%f\" z=\"%f\" rw=\"%f\" rx=\"%f\" ry=\"%f\" rz=\"%f\" />", position.x, position.y, position.z, rotation.w, rotation.x, rotation.y, rotation.z); + } + + void PlayLvlFx(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + GameMessages::SendPlayFXEffect(entity, 7074, u"create", "7074", LWOOBJID_EMPTY, 1.0f, 1.0f, true); + } + + void PlayRebuildFx(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + GameMessages::SendPlayFXEffect(entity, 230, u"rebuild", "230", LWOOBJID_EMPTY, 1.0f, 1.0f, true); + } + + void FreeMoney(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + const auto money = GeneralUtils::TryParse<int64_t>(splitArgs[0]); + + if (!money) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid money."); + return; + } + + auto* ch = entity->GetCharacter(); + ch->SetCoins(ch->GetCoins() + money.value(), eLootSourceType::MODERATION); + } + + void SetCurrency(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + const auto money = GeneralUtils::TryParse<int64_t>(splitArgs[0]); + + if (!money) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid money."); + return; + } + + auto* ch = entity->GetCharacter(); + ch->SetCoins(money.value(), eLootSourceType::MODERATION); + } + + void GmInvis(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + GameMessages::SendToggleGMInvis(entity->GetObjectID(), true, UNASSIGNED_SYSTEM_ADDRESS); + } + + void GmImmune(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + auto* destroyableComponent = entity->GetComponent<DestroyableComponent>(); + + const auto state = GeneralUtils::TryParse<int32_t>(splitArgs[0]); + + if (!state) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid state."); + return; + } + + if (destroyableComponent) destroyableComponent->SetIsGMImmune(state.value()); + } + + void AttackImmune(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + auto* destroyableComponent = entity->GetComponent<DestroyableComponent>(); + + const auto state = GeneralUtils::TryParse<int32_t>(splitArgs[0]); + + if (!state) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid state."); + return; + } + + if (destroyableComponent) destroyableComponent->SetIsImmune(state.value()); + } + + void Buff(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.size() < 2) return; + + auto* buffComponent = entity->GetComponent<BuffComponent>(); + + const auto id = GeneralUtils::TryParse<int32_t>(splitArgs[0]); + if (!id) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid buff id."); + return; + } + + const auto duration = GeneralUtils::TryParse<int32_t>(splitArgs[1]); + if (!duration) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid buff duration."); + return; + } + + if (buffComponent) buffComponent->ApplyBuff(id.value(), duration.value(), entity->GetObjectID()); + } + + void TestMap(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + ChatPackets::SendSystemMessage(sysAddr, u"Requesting map change..."); + LWOCLONEID cloneId = 0; + bool force = false; + + const auto reqZoneOptional = GeneralUtils::TryParse<LWOMAPID>(splitArgs[0]); + if (!reqZoneOptional) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid zone."); + return; + } + const LWOMAPID reqZone = reqZoneOptional.value(); + + if (splitArgs.size() > 1) { + auto index = 1; + + if (splitArgs[index] == "force") { + index++; + + force = true; + } + + if (splitArgs.size() > index) { + const auto cloneIdOptional = GeneralUtils::TryParse<LWOCLONEID>(splitArgs[index]); + if (!cloneIdOptional) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid clone id."); + return; + } + cloneId = cloneIdOptional.value(); + } + } + + const auto objid = entity->GetObjectID(); + + if (force || Game::zoneManager->CheckIfAccessibleZone(reqZone)) { // to prevent tomfoolery + + ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, reqZone, cloneId, false, [objid](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { + + auto* entity = Game::entityManager->GetEntity(objid); + if (!entity) return; + + const auto sysAddr = entity->GetSystemAddress(); + + ChatPackets::SendSystemMessage(sysAddr, u"Transfering map..."); + + LOG("Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", sysAddr.ToString(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); + if (entity->GetCharacter()) { + entity->GetCharacter()->SetZoneID(zoneID); + entity->GetCharacter()->SetZoneInstance(zoneInstance); + entity->GetCharacter()->SetZoneClone(zoneClone); + entity->GetComponent<CharacterComponent>()->SetLastRocketConfig(u""); + } + + entity->GetCharacter()->SaveXMLToDatabase(); + + WorldPackets::SendTransferToWorld(sysAddr, serverIP, serverPort, mythranShift); + return; + }); + } else { + std::string msg = "ZoneID not found or allowed: "; + msg.append(splitArgs[0]); // FIXME: unnecessary utf16 re-encoding just for error + ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::UTF8ToUTF16(msg, msg.size())); + } + } + + void CreatePrivate(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.size() < 3) return; + + const auto zone = GeneralUtils::TryParse<uint32_t>(splitArgs[0]); + if (!zone) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid zone."); + return; + } + + const auto clone = GeneralUtils::TryParse<uint32_t>(splitArgs[1]); + if (!clone) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid clone."); + return; + } + + const auto& password = splitArgs[2]; + + ZoneInstanceManager::Instance()->CreatePrivateZone(Game::server, zone.value(), clone.value(), password); + + ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16("Sent request for private zone with password: " + password)); + } + + void DebugUi(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + ChatPackets::SendSystemMessage(sysAddr, u"Opening UIDebugger..."); + } + + void Boost(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + + auto* possessorComponent = entity->GetComponent<PossessorComponent>(); + + if (possessorComponent == nullptr) { + return; + } + + auto* vehicle = Game::entityManager->GetEntity(possessorComponent->GetPossessable()); + + if (vehicle == nullptr) { + return; + } + + if (splitArgs.size() >= 1) { + const auto time = GeneralUtils::TryParse<float>(splitArgs[0]); + + if (!time) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid boost time."); + return; + } else { + GameMessages::SendVehicleAddPassiveBoostAction(vehicle->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); + entity->AddCallbackTimer(time.value(), [vehicle]() { + if (!vehicle) return; + GameMessages::SendVehicleRemovePassiveBoostAction(vehicle->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); + }); + } + } else { + GameMessages::SendVehicleAddPassiveBoostAction(vehicle->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); + } + } + + void Unboost(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + auto* possessorComponent = entity->GetComponent<PossessorComponent>(); + + if (possessorComponent == nullptr) return; + auto* vehicle = Game::entityManager->GetEntity(possessorComponent->GetPossessable()); + + if (vehicle == nullptr) return; + GameMessages::SendVehicleRemovePassiveBoostAction(vehicle->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); + } + + void ActivateSpawner(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + auto spawners = Game::zoneManager->GetSpawnersByName(splitArgs[0]); + + for (auto* spawner : spawners) { + spawner->Activate(); + } + + spawners = Game::zoneManager->GetSpawnersInGroup(splitArgs[0]); + + for (auto* spawner : spawners) { + spawner->Activate(); + } + } + + void SpawnPhysicsVerts(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + //Go tell physics to spawn all the vertices: + auto entities = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::PHANTOM_PHYSICS); + for (auto en : entities) { + auto phys = static_cast<PhantomPhysicsComponent*>(en->GetComponent(eReplicaComponentType::PHANTOM_PHYSICS)); + if (phys) + phys->SpawnVertices(); + } + } + + void ReportProxPhys(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + auto entities = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::PROXIMITY_MONITOR); + for (auto en : entities) { + auto phys = static_cast<ProximityMonitorComponent*>(en->GetComponent(eReplicaComponentType::PROXIMITY_MONITOR)); + if (phys) { + for (auto prox : phys->GetProximitiesData()) { + if (!prox.second) continue; + + auto sphere = static_cast<dpShapeSphere*>(prox.second->GetShape()); + auto pos = prox.second->GetPosition(); + LOG("Proximity: %s, r: %f, pos: %f, %f, %f", prox.first.c_str(), sphere->GetRadius(), pos.x, pos.y, pos.z); + } + } + } + } + + void TriggerSpawner(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + auto spawners = Game::zoneManager->GetSpawnersByName(splitArgs[0]); + + for (auto* spawner : spawners) { + spawner->Spawn(); + } + + spawners = Game::zoneManager->GetSpawnersInGroup(splitArgs[0]); + + for (auto* spawner : spawners) { + spawner->Spawn(); + } + } + + void Reforge(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.size() < 2) return; + + const auto baseItem = GeneralUtils::TryParse<LOT>(splitArgs[0]); + if (!baseItem) return; + + const auto reforgedItem = GeneralUtils::TryParse<LOT>(splitArgs[1]); + if (!reforgedItem) return; + + auto* inventoryComponent = entity->GetComponent<InventoryComponent>(); + if (!inventoryComponent) return; + + std::vector<LDFBaseData*> data{}; + data.push_back(new LDFData<int32_t>(u"reforgedLOT", reforgedItem.value())); + + inventoryComponent->AddItem(baseItem.value(), 1, eLootSourceType::MODERATION, eInventoryType::INVALID, data); + } + + void Crash(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + ChatPackets::SendSystemMessage(sysAddr, u"Crashing..."); + + int* badPtr = nullptr; + *badPtr = 0; + } + + void Metrics(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + for (const auto variable : Metrics::GetAllMetrics()) { + auto* metric = Metrics::GetMetric(variable); + + if (metric == nullptr) { + continue; + } + + ChatPackets::SendSystemMessage( + sysAddr, + GeneralUtils::ASCIIToUTF16(Metrics::MetricVariableToString(variable)) + + u": " + + GeneralUtils::to_u16string(Metrics::ToMiliseconds(metric->average)) + + u"ms" + ); + } + + ChatPackets::SendSystemMessage( + sysAddr, + u"Peak RSS: " + GeneralUtils::to_u16string(static_cast<float>(static_cast<double>(Metrics::GetPeakRSS()) / 1.024e6)) + + u"MB" + ); + + ChatPackets::SendSystemMessage( + sysAddr, + u"Current RSS: " + GeneralUtils::to_u16string(static_cast<float>(static_cast<double>(Metrics::GetCurrentRSS()) / 1.024e6)) + + u"MB" + ); + + ChatPackets::SendSystemMessage( + sysAddr, + u"Process ID: " + GeneralUtils::to_u16string(Metrics::GetProcessID()) + ); + } + + void ReloadConfig(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + Game::config->ReloadConfig(); + VanityUtilities::SpawnVanity(); + dpWorld::Reload(); + auto entities = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY); + for (const auto* const entity : entities) { + auto* const scriptedActivityComponent = entity->GetComponent<ScriptedActivityComponent>(); + if (!scriptedActivityComponent) continue; + + scriptedActivityComponent->ReloadConfig(); + } + Game::server->UpdateMaximumMtuSize(); + Game::server->UpdateBandwidthLimit(); + ChatPackets::SendSystemMessage(sysAddr, u"Successfully reloaded config for world!"); + } + + void RollLoot(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.size() < 3) return; + + const auto lootMatrixIndex = GeneralUtils::TryParse<uint32_t>(splitArgs[0]); + if (!lootMatrixIndex) return; + + const auto targetLot = GeneralUtils::TryParse<uint32_t>(splitArgs[1]); + if (!targetLot) return; + + const auto loops = GeneralUtils::TryParse<uint32_t>(splitArgs[2]); + if (!loops) return; + + uint64_t totalRuns = 0; + + for (uint32_t i = 0; i < loops; i++) { + while (true) { + auto lootRoll = Loot::RollLootMatrix(lootMatrixIndex.value()); + totalRuns += 1; + bool doBreak = false; + for (const auto& kv : lootRoll) { + if (static_cast<uint32_t>(kv.first) == targetLot) { + doBreak = true; + } + } + if (doBreak) break; + } + } + + std::u16string message = u"Ran loot drops looking for " + + GeneralUtils::to_u16string(targetLot.value()) + + u", " + + GeneralUtils::to_u16string(loops.value()) + + u" times. It ran " + + GeneralUtils::to_u16string(totalRuns) + + u" times. Averaging out at " + + GeneralUtils::to_u16string(static_cast<float>(totalRuns) / loops.value()); + + ChatPackets::SendSystemMessage(sysAddr, message); + } + + void DeleteInven(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + eInventoryType inventoryType = eInventoryType::INVALID; + + const auto inventoryTypeOptional = GeneralUtils::TryParse<eInventoryType>(splitArgs[0]); + if (!inventoryTypeOptional) { + // In this case, we treat the input as a string and try to find it in the reflection list + std::transform(splitArgs[0].begin(), splitArgs[0].end(), splitArgs[0].begin(), ::toupper); + LOG("looking for inventory %s", splitArgs[0].c_str()); + for (uint32_t index = 0; index < NUMBER_OF_INVENTORIES; index++) { + if (std::string_view(splitArgs[0]) == std::string_view(InventoryType::InventoryTypeToString(static_cast<eInventoryType>(index)))) inventoryType = static_cast<eInventoryType>(index); + } + } else { + inventoryType = inventoryTypeOptional.value(); + } + + if (inventoryType == eInventoryType::INVALID || inventoryType >= NUMBER_OF_INVENTORIES) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid inventory provided."); + return; + } + + auto* inventoryComponent = entity->GetComponent<InventoryComponent>(); + if (!inventoryComponent) return; + + auto* inventoryToDelete = inventoryComponent->GetInventory(inventoryType); + if (!inventoryToDelete) return; + + inventoryToDelete->DeleteAllItems(); + LOG("Deleted inventory %s for user %llu", splitArgs[0].c_str(), entity->GetObjectID()); + ChatPackets::SendSystemMessage(sysAddr, u"Deleted inventory " + GeneralUtils::UTF8ToUTF16(splitArgs[0])); + } + + void SetSkillSlot(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.size() < 2) return; + + auto* const inventoryComponent = entity->GetComponent<InventoryComponent>(); + if (inventoryComponent) { + const auto slot = GeneralUtils::TryParse<BehaviorSlot>(splitArgs[0]); + if (!slot) { + ChatPackets::SendSystemMessage(sysAddr, u"Error getting slot."); + return; + } else { + const auto skillId = GeneralUtils::TryParse<uint32_t>(splitArgs[1]); + if (!skillId) { + ChatPackets::SendSystemMessage(sysAddr, u"Error getting skill."); + return; + } else { + if (inventoryComponent->SetSkill(slot.value(), skillId.value())) ChatPackets::SendSystemMessage(sysAddr, u"Set skill to slot successfully"); + else ChatPackets::SendSystemMessage(sysAddr, u"Set skill to slot failed"); + } + } + } + } + + void SetFaction(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + auto* destroyableComponent = entity->GetComponent<DestroyableComponent>(); + if (destroyableComponent) { + const auto faction = GeneralUtils::TryParse<int32_t>(splitArgs[0]); + + if (!faction) { + ChatPackets::SendSystemMessage(sysAddr, u"Error getting faction."); + return; + } else { + destroyableComponent->SetFaction(faction.value()); + ChatPackets::SendSystemMessage(sysAddr, u"Set faction and updated enemies list"); + } + } + } + + void AddFaction(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + auto* destroyableComponent = entity->GetComponent<DestroyableComponent>(); + if (destroyableComponent) { + const auto faction = GeneralUtils::TryParse<int32_t>(splitArgs[0]); + + if (!faction) { + ChatPackets::SendSystemMessage(sysAddr, u"Error getting faction."); + return; + } else { + destroyableComponent->AddFaction(faction.value()); + ChatPackets::SendSystemMessage(sysAddr, u"Added faction and updated enemies list"); + } + } + } + + void GetFactions(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + auto* destroyableComponent = entity->GetComponent<DestroyableComponent>(); + if (destroyableComponent) { + ChatPackets::SendSystemMessage(sysAddr, u"Friendly factions:"); + for (const auto entry : destroyableComponent->GetFactionIDs()) { + ChatPackets::SendSystemMessage(sysAddr, (GeneralUtils::to_u16string(entry))); + } + + ChatPackets::SendSystemMessage(sysAddr, u"Enemy factions:"); + for (const auto entry : destroyableComponent->GetEnemyFactionsIDs()) { + ChatPackets::SendSystemMessage(sysAddr, (GeneralUtils::to_u16string(entry))); + } + } + } + + void SetRewardCode(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + auto* character = entity->GetCharacter(); + if (!character) return; + auto* user = character->GetParentUser(); + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + auto* cdrewardCodes = CDClientManager::GetTable<CDRewardCodesTable>(); + + auto id = cdrewardCodes->GetCodeID(splitArgs[0]); + if (id != -1) Database::Get()->InsertRewardCode(user->GetAccountID(), id); + } + + void Inspect(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + Entity* closest = nullptr; + + std::u16string ldf; + + bool isLDF = false; + + auto component = GeneralUtils::TryParse<eReplicaComponentType>(splitArgs[0]); + if (!component) { + component = eReplicaComponentType::INVALID; + + ldf = GeneralUtils::UTF8ToUTF16(splitArgs[0]); + + isLDF = true; + } + + auto reference = entity->GetPosition(); + + auto closestDistance = 0.0f; + + const auto candidates = Game::entityManager->GetEntitiesByComponent(component.value()); + + for (auto* candidate : candidates) { + if (candidate->GetLOT() == 1 || candidate->GetLOT() == 8092) { + continue; + } + + if (isLDF && !candidate->HasVar(ldf)) { + continue; + } + + if (!closest) { + closest = candidate; + + closestDistance = NiPoint3::Distance(candidate->GetPosition(), reference); + + continue; + } + + const auto distance = NiPoint3::Distance(candidate->GetPosition(), reference); + + if (distance < closestDistance) { + closest = candidate; + + closestDistance = distance; + } + } + + if (!closest) return; + + Game::entityManager->SerializeEntity(closest); + + auto* table = CDClientManager::GetTable<CDObjectsTable>(); + + const auto& info = table->GetByID(closest->GetLOT()); + + std::stringstream header; + + header << info.name << " [" << std::to_string(info.id) << "]" << " " << std::to_string(closestDistance) << " " << std::to_string(closest->IsSleeping()); + + ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(header.str())); + + for (const auto& pair : closest->GetComponents()) { + auto id = pair.first; + + std::stringstream stream; + + stream << "Component [" << std::to_string(static_cast<uint32_t>(id)) << "]"; + + ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(stream.str())); + } + + if (splitArgs.size() >= 2) { + if (splitArgs[1] == "-m" && splitArgs.size() >= 3) { + auto* const movingPlatformComponent = closest->GetComponent<MovingPlatformComponent>(); + + const auto mValue = GeneralUtils::TryParse<int32_t>(splitArgs[2]); + + if (!movingPlatformComponent || !mValue) return; + + movingPlatformComponent->SetSerialized(true); + + if (mValue == -1) { + movingPlatformComponent->StopPathing(); + } else { + movingPlatformComponent->GotoWaypoint(mValue.value()); + } + + Game::entityManager->SerializeEntity(closest); + } else if (splitArgs[1] == "-a" && splitArgs.size() >= 3) { + RenderComponent::PlayAnimation(closest, splitArgs.at(2)); + } else if (splitArgs[1] == "-s") { + for (auto* entry : closest->GetSettings()) { + ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::UTF8ToUTF16(entry->GetString())); + } + + ChatPackets::SendSystemMessage(sysAddr, u"------"); + ChatPackets::SendSystemMessage(sysAddr, u"Spawner ID: " + GeneralUtils::to_u16string(closest->GetSpawnerID())); + } else if (splitArgs[1] == "-p") { + const auto postion = closest->GetPosition(); + + ChatPackets::SendSystemMessage( + sysAddr, + GeneralUtils::ASCIIToUTF16("< " + std::to_string(postion.x) + ", " + std::to_string(postion.y) + ", " + std::to_string(postion.z) + " >") + ); + } else if (splitArgs[1] == "-f") { + auto* destuctable = closest->GetComponent<DestroyableComponent>(); + + if (destuctable == nullptr) { + ChatPackets::SendSystemMessage(sysAddr, u"No destroyable component on this entity!"); + return; + } + + ChatPackets::SendSystemMessage(sysAddr, u"Smashable: " + (GeneralUtils::to_u16string(destuctable->GetIsSmashable()))); + + ChatPackets::SendSystemMessage(sysAddr, u"Friendly factions:"); + for (const auto entry : destuctable->GetFactionIDs()) { + ChatPackets::SendSystemMessage(sysAddr, (GeneralUtils::to_u16string(entry))); + } + + ChatPackets::SendSystemMessage(sysAddr, u"Enemy factions:"); + for (const auto entry : destuctable->GetEnemyFactionsIDs()) { + ChatPackets::SendSystemMessage(sysAddr, (GeneralUtils::to_u16string(entry))); + } + + if (splitArgs.size() >= 3) { + const auto faction = GeneralUtils::TryParse<int32_t>(splitArgs[2]); + if (!faction) return; + + destuctable->SetFaction(-1); + destuctable->AddFaction(faction.value(), true); + } + } else if (splitArgs[1] == "-cf") { + auto* destuctable = entity->GetComponent<DestroyableComponent>(); + if (!destuctable) { + ChatPackets::SendSystemMessage(sysAddr, u"No destroyable component on this entity!"); + return; + } + if (destuctable->IsEnemy(closest)) ChatPackets::SendSystemMessage(sysAddr, u"They are our enemy"); + else ChatPackets::SendSystemMessage(sysAddr, u"They are NOT our enemy"); + } else if (splitArgs[1] == "-t") { + auto* phantomPhysicsComponent = closest->GetComponent<PhantomPhysicsComponent>(); + + if (phantomPhysicsComponent != nullptr) { + 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()))); + ChatPackets::SendSystemMessage(sysAddr, u"Active: " + (GeneralUtils::to_u16string(phantomPhysicsComponent->GetPhysicsEffectActive()))); + } + + auto* triggerComponent = closest->GetComponent<TriggerComponent>(); + if (triggerComponent) { + auto trigger = triggerComponent->GetTrigger(); + if (trigger) { + ChatPackets::SendSystemMessage(sysAddr, u"Trigger: " + (GeneralUtils::to_u16string(trigger->id))); + } + } + } + } + } +}; + void SlashCommandHandler::SendAnnouncement(const std::string& title, const std::string& message) { AMFArrayValue args; diff --git a/dGame/dUtilities/SlashCommandHandler.h b/dGame/dUtilities/SlashCommandHandler.h index d280be06..da36d636 100644 --- a/dGame/dUtilities/SlashCommandHandler.h +++ b/dGame/dUtilities/SlashCommandHandler.h @@ -13,17 +13,10 @@ class Entity; struct Command { - Command(std::string help, std::string info, std::vector<std::string> aliases, std::function<void(Entity*,const std::string)> handle, eGameMasterLevel requiredLevel = eGameMasterLevel::DEVELOPER) { - this->help = help; - this->info = info; - this->aliases = aliases; - this->handle = handle; - this->requiredLevel = requiredLevel; - } std::string help; std::string info; std::vector<std::string> aliases; - std::function<void(Entity*,const std::string)> handle; + std::function<void(Entity*, const SystemAddress&,const std::string)> handle; eGameMasterLevel requiredLevel = eGameMasterLevel::DEVELOPER; }; @@ -35,105 +28,105 @@ namespace SlashCommandHandler { }; namespace DEVGMCommands { - void SetGMLevel(Entity* entity, const std::string args); - void ToggleNameplate(Entity* entity, const std::string args); - void ToggleSkipCinematics(Entity* entity, const std::string args); - void Kill(Entity* entity, const std::string args); - void Metrics(Entity* entity, const std::string args); - void Announce(Entity* entity, const std::string args); - void SetAnnouncementTitle(Entity* entity, const std::string args); - void SetAnnouncementMessage(Entity* entity, const std::string args); - void ShutdownUniverse(Entity* entity, const std::string args); - void SetMinifig(Entity* entity, const std::string args); - void TestMap(Entity* entity, const std::string args); - void ReportProximityPhysics(Entity* entity, const std::string args); - void SpawnPhysicsVerts(Entity* entity, const std::string args); - void Teleport(Entity* entity, const std::string args); - void ActivateSpawner(Entity* entity, const std::string args); - void AddMission(Entity* entity, const std::string args); - void Boost(Entity* entity, const std::string args); - void Unboost(Entity* entity, const std::string args); - void Buff(Entity* entity, const std::string args); - void BuffMe(Entity* entity, const std::string args); - void BuffMedium(Entity* entity, const std::string args); - void ClearFlag(Entity* entity, const std::string args); - void CompleteMission(Entity* entity, const std::string args); - void CreatePrivateInstance(Entity* entity, const std::string args); - void DebugUI(Entity* entity, const std::string args); - void Dismount(Entity* entity, const std::string args); - void ReloadConfig(Entity* entity, const std::string args); - void ForceSave(Entity* entity, const std::string args); - void Freecam(Entity* entity, const std::string args); - void FreeMoney(Entity* entity, const std::string args); - void GetNavmeshHeight(Entity* entity, const std::string args); - void GiveUScore(Entity* entity, const std::string args); - void GMAddItem(Entity* entity, const std::string args); - void Inspect(Entity* entity, const std::string args); - void ListSpawns(Entity* entity, const std::string args); - void LocationRotation(Entity* entity, const std::string args); - void Lookup(Entity* entity, const std::string args); - void PlayAnimation(Entity* entity, const std::string args); - void PlayEffect(Entity* entity, const std::string args); - void PlayLevelFX(Entity* entity, const std::string args); - void PlayRebuildFX(Entity* entity, const std::string args); - void Position(Entity* entity, const std::string args); - void RefilStats(Entity* entity, const std::string args); - void Reforge(Entity* entity, const std::string args); - void ResetMission(Entity* entity, const std::string args); - void Rotation(Entity* entity, const std::string args); - void RunMacro(Entity* entity, const std::string args); - void SetControlScheme(Entity* entity, const std::string args); - void SetCurrency(Entity* entity, const std::string args); - void SetFlag(Entity* entity, const std::string args); - void SetInventorySize(Entity* entity, const std::string args); - void SetUIState(Entity* entity, const std::string args); - void Spawn(Entity* entity, const std::string args); - void SpawnGroup(Entity* entity, const std::string args); - void SpeedBoost(Entity* entity, const std::string args); - void StartCelebration(Entity* entity, const std::string args); - void StopEffect(Entity* entity, const std::string args); - void Toggle(Entity* entity, const std::string args); - void TeleportAll(Entity* entity, const std::string args); - void TriggerSpawner(Entity* entity, const std::string args); - void UnlockEmote(Entity* entity, const std::string args); - void SetLevel(Entity* entity, const std::string args); - void SetSkillSlot(Entity* entity, const std::string args); - void SetFaction(Entity* entity, const std::string args); - void AddFaction(Entity* entity, const std::string args); - void GetFactions(Entity* entity, const std::string args); - void SetRewardCode(Entity* entity, const std::string args); + void SetGMLevel(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void ToggleNameplate(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void ToggleSkipCinematics(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Kill(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Metrics(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Announce(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SetAnnouncementTitle(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SetAnnouncementMessage(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void ShutdownUniverse(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SetMinifig(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void TestMap(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void ReportProximityPhysics(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SpawnPhysicsVerts(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Teleport(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void ActivateSpawner(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void AddMission(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Boost(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Unboost(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Buff(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void BuffMe(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void BuffMedium(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void ClearFlag(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void CompleteMission(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void CreatePrivateInstance(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void DebugUI(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Dismount(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void ReloadConfig(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void ForceSave(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Freecam(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void FreeMoney(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void GetNavmeshHeight(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void GiveUScore(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void GMAddItem(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Inspect(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void ListSpawns(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void LocationRotation(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Lookup(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void PlayAnimation(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void PlayEffect(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void PlayLevelFX(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void PlayRebuildFX(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Position(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void RefilStats(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Reforge(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void ResetMission(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Rotation(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void RunMacro(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SetControlScheme(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SetCurrency(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SetFlag(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SetInventorySize(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SetUIState(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Spawn(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SpawnGroup(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SpeedBoost(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void StartCelebration(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void StopEffect(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Toggle(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void TeleportAll(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void TriggerSpawner(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void UnlockEmote(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SetLevel(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SetSkillSlot(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SetFaction(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void AddFaction(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void GetFactions(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SetRewardCode(Entity* entity, const SystemAddress& sysAddr, const std::string args); - void Crash(Entity* entity, const std::string args); - void RollLoot(Entity* entity, const std::string args); - void CastSkill(Entity* entity, const std::string args); + void Crash(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void RollLoot(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void CastSkill(Entity* entity, const SystemAddress& sysAddr, const std::string args); } namespace GMZeroCommands { - void Help(Entity* entity, const std::string args); - void Credits(Entity* entity, const std::string args); - void Info(Entity* entity, const std::string args); - void Die(Entity* entity, const std::string args); - void Ping(Entity* entity, const std::string args); - void PVP(Entity* entity, const std::string args); - void RequestMailCount(Entity* entity, const std::string args); - void Who(Entity* entity, const std::string args); - void FixStats(Entity* entity, const std::string args); - void JoinPrivateInstance(Entity* entity, const std::string args); - void LeaveZone(Entity* entity, const std::string args); + void Help(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Credits(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Info(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Die(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Ping(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void PVP(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void RequestMailCount(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Who(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void FixStats(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void JoinPrivateInstance(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void LeaveZone(Entity* entity, const SystemAddress& sysAddr, const std::string args); } namespace GreaterThanZeroCommands { - void Kick(Entity* entity, const std::string args); - void MailItem(Entity* entity, const std::string args); - void Ban(Entity* entity, const std::string args); - void ApproveProperty(Entity* entity, const std::string args); - void Mute(Entity* entity, const std::string args); - void Fly(Entity* entity, const std::string args); - void AttackImmune(Entity* entity, const std::string args); - void GMImmune(Entity* entity, const std::string args); - void GMInvis(Entity* entity, const std::string args); - void SetName(Entity* entity, const std::string args); - void Title(Entity* entity, const std::string args); + void Kick(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void MailItem(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Ban(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void ApproveProperty(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Mute(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Fly(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void AttackImmune(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void GMImmune(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void GMInvis(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SetName(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Title(Entity* entity, const SystemAddress& sysAddr, const std::string args); } #endif // SLASHCOMMANDHANDLER_H