#include "GMGreaterThanZeroCommands.h" #include "ChatServerLink.h" #include "DashboardNotify.h" #include "SlashCommandHandler.h" // Classes #include "Character.h" #include "ChatPackets.h" #include "dServer.h" #include "PlayerManager.h" #include "User.h" // Database #include "Database.h" // Components #include "DestroyableComponent.h" #include "PropertyManagementComponent.h" // Enums #include "MessageType/Chat.h" #include "eServerDisconnectIdentifiers.h" #include "eObjectBits.h" #include "EffectsMessages.h" #include "MovementMessages.h" #include "ObjectMessages.h" #include "PlayerMessages.h" namespace GMGreaterThanZeroCommands { 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; } const auto target = SlashCommandHandler::TargetOf(player); if (!target || !SlashCommandHandler::MayActOn(entity, sysAddr, *target, SlashCommandLevels::eTargetRule::TOOLS, "kick")) return; Game::server->Disconnect(player->GetSystemAddress(), eServerDisconnectIdentifiers::KICK); ChatPackets::SendSystemMessage(sysAddr, u"Kicked: " + username); } else { ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /kick "); } } void Ban(Entity* entity, const SystemAddress& sysAddr, const std::string args) { const auto splitArgs = GeneralUtils::SplitString(args, ' '); if (splitArgs.size() == 1) { const auto target = SlashCommandHandler::FindTarget(splitArgs[0]); if (!target) { ChatPackets::SendSystemMessage(sysAddr, u"Count not find player of name: " + GeneralUtils::UTF8ToUTF16(splitArgs[0])); return; } if (!SlashCommandHandler::MayActOn(entity, sysAddr, *target, SlashCommandLevels::eTargetRule::MODERATION, "ban")) return; // The server always keeps a GM 9 account that can sign in if (target->gmLevel >= AccountRules::OPERATOR_LEVEL && AccountRules::RemovesLastOperator(target->gmLevel, Database::Get()->CountActiveAccountsAtGmLevel(AccountRules::OPERATOR_LEVEL, target->accountId))) { ChatPackets::SendSystemMessage(sysAddr, u"/ban: " + GeneralUtils::UTF8ToUTF16(AccountRules::LastOperatorMessage("banned"))); return; } const auto accountId = target->accountId; if (accountId != 0) Database::Get()->UpdateAccountBan(accountId, true); if (accountId != 0) DashboardNotify::Changed("account_banned", accountId); if (target->entity != nullptr) { Game::server->Disconnect(target->entity->GetSystemAddress(), eServerDisconnectIdentifiers::FREE_TRIAL_EXPIRED); } ChatPackets::SendSystemMessage(sysAddr, u"Banned: " + GeneralUtils::ASCIIToUTF16(splitArgs[0])); } else { ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /ban "); } } 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 target = SlashCommandHandler::FindTarget(playerName); if (!target || !SlashCommandHandler::MayActOn(entity, sysAddr, *target, SlashCommandLevels::eTargetRule::ITEMS, "mailitem")) return; const auto lot = GeneralUtils::TryParse(splitArgs.at(1)); if (!lot) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid item lot."); return; } 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); DashboardNotify::Changed("mail", mailInsert.receiverId); ChatPackets::SendSystemMessage(sysAddr, u"Mail sent"); } void ApproveProperty(Entity* entity, const SystemAddress& sysAddr, const std::string args) { if (PropertyManagementComponent::Instance() != nullptr) { PropertyManagementComponent::Instance()->UpdateApprovedStatus(true); } } void Mute(Entity* entity, const SystemAddress& sysAddr, const std::string args) { const auto splitArgs = GeneralUtils::SplitString(args, ' '); if (splitArgs.size() >= 1) { const auto target = SlashCommandHandler::FindTarget(splitArgs[0]); if (!target) { ChatPackets::SendSystemMessage(sysAddr, u"Count not find player of name: " + GeneralUtils::UTF8ToUTF16(splitArgs[0])); return; } if (!SlashCommandHandler::MayActOn(entity, sysAddr, *target, SlashCommandLevels::eTargetRule::MODERATION, "mute")) return; const uint32_t accountId = target->accountId; const LWOOBJID characterId = target->characterId; time_t expire = 1; // Default to indefinate mute if (splitArgs.size() >= 2) { const auto days = GeneralUtils::TryParse(splitArgs[1]); if (!days) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid days."); return; } std::optional hours; if (splitArgs.size() >= 3) { hours = GeneralUtils::TryParse(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); if (accountId != 0) DashboardNotify::Changed("account_muted", accountId); 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 ChatPackets::GMMute mute; mute.playerID = characterId; mute.expire = expire; ChatServerLink::Send(mute); } else { ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /mute "); } } 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::SetJetPackMode jetPackMode; jetPackMode.target = entity->GetObjectID(); jetPackMode.bUse = false; jetPackMode.Send(UNASSIGNED_SYSTEM_ADDRESS); character->SetIsFlying(false); } else { float speedScale = 1.0f; if (splitArgs.size() >= 1) { const auto tempScaleStore = GeneralUtils::TryParse(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::SetJetPackMode jetPackMode; jetPackMode.target = entity->GetObjectID(); jetPackMode.bUse = true; jetPackMode.bBypassChecks = true; jetPackMode.bDoHover = false; jetPackMode.effectID = 167; jetPackMode.fAirspeed = airSpeed; jetPackMode.fMaxAirspeed = maxAirSpeed; jetPackMode.fVertVel = verticalVelocity; jetPackMode.Send(UNASSIGNED_SYSTEM_ADDRESS); character->SetIsFlying(true); } } } 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(); const auto state = GeneralUtils::TryParse(splitArgs[0]); if (!state) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid state."); return; } if (destroyableComponent) destroyableComponent->SetIsImmune(state.value()); } 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(); const auto state = GeneralUtils::TryParse(splitArgs[0]); if (!state) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid state."); return; } if (destroyableComponent) destroyableComponent->SetIsGMImmune(state.value()); } void GmInvis(Entity* entity, const SystemAddress& sysAddr, const std::string args) { GameMessages::ToggleGMInvisEvent msg; msg.Send(entity->GetObjectID()); } void SetName(Entity* entity, const SystemAddress& sysAddr, const std::string args) { GameMessages::SetName setName; setName.target = entity->GetObjectID(); setName.name = GeneralUtils::UTF8ToUTF16(args); setName.Send(UNASSIGNED_SYSTEM_ADDRESS); } void Title(Entity* entity, const SystemAddress& sysAddr, const std::string args) { std::string name = entity->GetCharacter()->GetName() + " - " + args; GameMessages::SetName setName; setName.target = entity->GetObjectID(); setName.name = GeneralUtils::UTF8ToUTF16(name); setName.Send(UNASSIGNED_SYSTEM_ADDRESS); } void ShowAll(Entity* entity, const SystemAddress& sysAddr, const std::string args) { bool displayZoneData = true; bool displayIndividualPlayers = true; const auto splitArgs = GeneralUtils::SplitString(args, ' '); if (!splitArgs.empty() && !splitArgs.at(0).empty()) displayZoneData = splitArgs.at(0) == "1"; if (splitArgs.size() > 1) displayIndividualPlayers = splitArgs.at(1) == "1"; ChatPackets::ShowAllRequest request; request.requestor = entity->GetObjectID(); request.displayZoneData = displayZoneData; request.displayIndividualPlayers = displayIndividualPlayers; ChatServerLink::Send(request); } void FindPlayer(Entity* entity, const SystemAddress& sysAddr, const std::string args) { if (args.empty()) { GameMessages::SlashCommandTextFeedback(entity->GetObjectID(), u"No player Given").SendToClient(entity->GetSystemAddress()); return; } ChatPackets::FindPlayerRequest request; request.requestor = entity->GetObjectID(); request.playerName = LUWString(args); ChatServerLink::Send(request); } void Spectate(Entity* entity, const SystemAddress& sysAddr, const std::string args) { if (args.empty()) { GameMessages::ForceCameraTargetCycle cameraCycle; cameraCycle.target = entity->GetObjectID(); cameraCycle.bForceCycling = false; cameraCycle.cyclingMode = eCameraTargetCyclingMode::DISALLOW_CYCLING; cameraCycle.optionalTargetID = entity->GetObjectID(); cameraCycle.SendToClient(entity->GetSystemAddress()); return; } auto player = PlayerManager::GetPlayer(args); if (!player) { GameMessages::SlashCommandTextFeedback(entity->GetObjectID(), u"Player not found").SendToClient(entity->GetSystemAddress()); return; } GameMessages::SlashCommandTextFeedback(entity->GetObjectID(), u"Spectating Player").SendToClient(entity->GetSystemAddress()); GameMessages::ForceCameraTargetCycle cameraCycle; cameraCycle.target = entity->GetObjectID(); cameraCycle.bForceCycling = false; cameraCycle.cyclingMode = eCameraTargetCyclingMode::DISALLOW_CYCLING; cameraCycle.optionalTargetID = player->GetObjectID(); cameraCycle.SendToClient(entity->GetSystemAddress()); } }