mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 10:53:44 +00:00
A command may be used when the character's GM level allows it or a grant does: a grant of the command, of every command up to a GM level, or of the dashboard permission the command follows (so accounts_kick covers /kick). A deny of any of those takes it away even when the level allows it, except from GM 9 accounts (also while they play at a lower level). Grants never take anyone below a command's floor above GM 1 (/execute), and commands the client handles keep their fixed level. Expired grants count for nothing. The grants are the account's and the logged-in character's, read from the database the first time a command is used and kept on the User. /help lists the commands a player may use this way. The self and rank rules for commands that act on another player count grants of self_* and manage_equal_rank too. A denied command says it was taken away. Check: grant a GM 0 account /spawn (or "every command up to GM 8") on the dashboard, relog, and /spawn works and shows in /help; deny /spawn from a GM 8 character: "it was taken away"; grant accounts_kick and /kick works (the rank rules still apply to whom). dGameTests SlashCommandGrantsTest. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
119 lines
5.2 KiB
C++
119 lines
5.2 KiB
C++
/*
|
|
* Darkflame Universe
|
|
* Copyright 2018
|
|
*/
|
|
|
|
#ifndef SLASHCOMMANDHANDLER_H
|
|
#define SLASHCOMMANDHANDLER_H
|
|
|
|
#include "RakNetTypes.h"
|
|
#include "eGameMasterLevel.h"
|
|
#include "dCommonVars.h"
|
|
#include "AccountRules.h"
|
|
#include "SlashCommandLevels.h"
|
|
#include "PermissionGrants.h"
|
|
#include <functional>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <vector>
|
|
|
|
class Entity;
|
|
|
|
struct Command {
|
|
std::string help;
|
|
std::string info;
|
|
std::vector<std::string> aliases;
|
|
std::function<void(Entity*, const SystemAddress&,const std::string)> handle;
|
|
// The default level; command_level_<name> in the settings (e.g. from the dashboard) can change it
|
|
eGameMasterLevel requiredLevel = eGameMasterLevel::OPERATOR;
|
|
// The lowest level the settings may give it; unset: GM 1 for staff commands (never players), GM 0 for the rest
|
|
std::optional<eGameMasterLevel> minLevel;
|
|
// Always requiredLevel, whatever the settings say
|
|
bool fixedLevel = false;
|
|
// Set by RegisterCommand for commands the game client acts on by itself (their level is fixed)
|
|
bool clientHandled = false;
|
|
// Why the command has a floor or a fixed level, shown on the dashboard
|
|
std::string levelNote;
|
|
// The dashboard permission (Permissions.cpp key) that does the same thing. The command then needs that permission's
|
|
// level (one setting for both); a command_level_<name> value still overrides it, so older setups don't change silently
|
|
std::string dashboardPermission;
|
|
// Who it may be used on when it acts on another player: the dashboard's self and rank rules (the handler checks them
|
|
// with SlashCommandHandler::MayActOn; this tells the dashboard which rule it follows)
|
|
SlashCommandLevels::eTargetRule targetRule = SlashCommandLevels::eTargetRule::NONE;
|
|
// Set by RegisterCommand: the command's name in the settings, from its first alias
|
|
std::string name;
|
|
};
|
|
|
|
// A player a command acts on, in this world or not
|
|
struct CommandTarget {
|
|
uint32_t accountId{};
|
|
uint8_t gmLevel{}; // the account's GM level (the character's in-game level if that is higher)
|
|
LWOOBJID characterId{};
|
|
std::string name; // the character's name
|
|
Entity* entity{}; // set when the player is in this world
|
|
};
|
|
|
|
namespace SlashCommandHandler {
|
|
void HandleChatCommand(const std::u16string& command, Entity* entity, const SystemAddress& sysAddr);
|
|
void SendAnnouncement(const std::string& title, const std::string& message);
|
|
void RegisterCommand(Command info);
|
|
void Startup();
|
|
|
|
// The command an alias runs (nullptr: none)
|
|
const Command* FindCommand(const std::string& alias);
|
|
|
|
// The level needed to use a command right now: its default unless the settings change it
|
|
eGameMasterLevel GetRequiredLevel(const Command& command);
|
|
|
|
// Store the registered commands in the database for the dashboard (only what changed)
|
|
void ReportCommands();
|
|
|
|
// A player in this world, as a command target
|
|
std::optional<CommandTarget> TargetOf(Entity* player);
|
|
|
|
// The character with this name: in this world if they are here, else from the database. nullopt: no such character
|
|
std::optional<CommandTarget> FindTarget(const std::string& name);
|
|
|
|
/**
|
|
* Pure (apart from the permission levels): whether staff at actorLevel may use a command with this rule on the target
|
|
* account. The same rules as the dashboard's tools: GM 9 may act on anyone; below GM 9 never on a higher GM level, on
|
|
* their own level only with manage_equal_rank, and on themselves only with the self_* permission for the rule
|
|
* (OTHERS: on themselves always, as before).
|
|
*/
|
|
AccountRules::eManageDenial TargetDenial(uint8_t actorLevel, uint32_t actorAccountId, uint8_t targetLevel, uint32_t targetAccountId, SlashCommandLevels::eTargetRule rule,
|
|
const PermissionGrants::Held* actorGrants = nullptr);
|
|
|
|
// Why a command may not be used on someone, for the chat; empty when it may
|
|
std::string TargetRefusal(AccountRules::eManageDenial denial, SlashCommandLevels::eTargetRule rule, std::string_view command);
|
|
|
|
/**
|
|
* Whether the actor may use the command on the target (TargetDenial with the actor's current GM level and account).
|
|
* When not, tells whoever typed the command (sysAddr) why in the chat.
|
|
*/
|
|
bool MayActOn(Entity* actor, const SystemAddress& sysAddr, const CommandTarget& target, SlashCommandLevels::eTargetRule rule, std::string_view command);
|
|
|
|
// The account of the player using a command (0 if unknown)
|
|
uint32_t AccountOf(Entity* player);
|
|
|
|
/**
|
|
* The permission grants of a player's account and logged-in character (PermissionGrants.h), loaded from the database
|
|
* the first time they are needed and kept on the User until the dashboard changes them (DashboardActions). nullptr:
|
|
* not a player.
|
|
*/
|
|
const PermissionGrants::Held* GrantsOf(Entity* player);
|
|
|
|
// Whether a player may use a command now: its level, or a grant for it (the command, a command group, or the
|
|
// dashboard permission it follows), unless a deny takes it away (PermissionGrants::MayUseCommand)
|
|
bool MayUse(Entity* player, const Command& command);
|
|
|
|
// The command as the grant rules see it: its name, level now, floor, and the dashboard permission it follows
|
|
PermissionGrants::Command GrantRules(const Command& command);
|
|
};
|
|
|
|
namespace GMZeroCommands {
|
|
void Help(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
|
}
|
|
|
|
#endif // SLASHCOMMANDHANDLER_H
|