- added topmenus extension to build
- basecommands is slowly getting split into multiple source files now - added experimental api of a potential admin menu design - added experimental admin menu entry to basecommands to kick things off --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401516
This commit is contained in:
parent
2c5cd63552
commit
602b0aa6a5
176
plugins/adminmenu.sp
Normal file
176
plugins/adminmenu.sp
Normal file
@ -0,0 +1,176 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod Anti-Flood Plugin
|
||||
* Protects against chat flooding.
|
||||
*
|
||||
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#pragma semicolon 1
|
||||
|
||||
#include <sourcemod>
|
||||
#include <topmenus>
|
||||
|
||||
public Plugin:myinfo =
|
||||
{
|
||||
name = "Admin Menu",
|
||||
author = "AlliedModders LLC",
|
||||
description = "Administration Menu",
|
||||
version = SOURCEMOD_VERSION,
|
||||
url = "http://www.sourcemod.net/"
|
||||
};
|
||||
|
||||
/* Forwards */
|
||||
new Handle:hOnAdminMenuReady = INVALID_HANDLE;
|
||||
new Handle:hOnAdminMenuCreated = INVALID_HANDLE;
|
||||
|
||||
/* Menus */
|
||||
new Handle:hAdminMenu = INVALID_HANDLE;
|
||||
|
||||
/* Top menu objects */
|
||||
new TopMenuObject:obj_playercmds = INVALID_TOPMENUOBJECT;
|
||||
|
||||
public bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max)
|
||||
{
|
||||
CreateNative("GetAdminTopMenu", __GetAdminTopMenu);
|
||||
CreateNative("AddTargetsToMenu", __AddTargetsToMenu);
|
||||
RegPluginLibrary("adminmenu");
|
||||
return true;
|
||||
}
|
||||
|
||||
public OnPluginStart()
|
||||
{
|
||||
LoadTranslations("common.phrases");
|
||||
|
||||
hOnAdminMenuCreated = CreateGlobalForward("OnAdminMenuCreated", ET_Ignore, Param_Cell);
|
||||
hOnAdminMenuReady = CreateGlobalForward("OnAdminMenuReady", ET_Ignore, Param_Cell);
|
||||
|
||||
RegAdminCmd("sm_admin", Command_DisplayMenu, ADMFLAG_GENERIC, "sm_admin");
|
||||
}
|
||||
|
||||
public OnAllPluginsLoaded()
|
||||
{
|
||||
hAdminMenu = CreateTopMenu(CategoryHandler);
|
||||
|
||||
obj_playercmds = AddToTopMenu(hAdminMenu,
|
||||
"PlayerCommands",
|
||||
TopMenuObject_Category,
|
||||
CategoryHandler,
|
||||
INVALID_TOPMENUOBJECT);
|
||||
|
||||
Call_StartForward(hOnAdminMenuCreated);
|
||||
Call_PushCell(hAdminMenu);
|
||||
Call_Finish();
|
||||
|
||||
Call_StartForward(hOnAdminMenuReady);
|
||||
Call_PushCell(hAdminMenu);
|
||||
Call_Finish();
|
||||
}
|
||||
|
||||
public CategoryHandler(Handle:topmenu,
|
||||
TopMenuAction:action,
|
||||
TopMenuObject:object_id,
|
||||
param,
|
||||
String:buffer[],
|
||||
maxlength)
|
||||
{
|
||||
if (action == TopMenuAction_DrawTitle)
|
||||
{
|
||||
if (object_id == INVALID_TOPMENUOBJECT)
|
||||
{
|
||||
Format(buffer, maxlength, "%T:", "Admin Menu", param);
|
||||
}
|
||||
else if (object_id == obj_playercmds)
|
||||
{
|
||||
Format(buffer, maxlength, "%T:", "Player Commands", param);
|
||||
}
|
||||
}
|
||||
else if (action == TopMenuAction_DrawOption)
|
||||
{
|
||||
if (object_id == obj_playercmds)
|
||||
{
|
||||
Format(buffer, maxlength, "%T", "Player Commands", param);
|
||||
}
|
||||
return ITEMDRAW_DEFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public __GetAdminTopMenu(Handle:plugin, numParams)
|
||||
{
|
||||
return _:hAdminMenu;
|
||||
}
|
||||
|
||||
public __AddTargetsToMenu(Handle:plugin, numParams)
|
||||
{
|
||||
return UTIL_AddTargetsToMenu(GetNativeCell(1), GetNativeCell(2), GetNativeCell(3));
|
||||
}
|
||||
|
||||
public Action:Command_DisplayMenu(client, args)
|
||||
{
|
||||
DisplayTopMenu(hAdminMenu, client, TopMenuPosition_Start);
|
||||
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
stock UTIL_AddTargetsToMenu(Handle:menu, source_client, bool:in_game_only)
|
||||
{
|
||||
new max_clients = GetMaxClients();
|
||||
decl String:user_id[12];
|
||||
decl String:name[MAX_NAME_LENGTH];
|
||||
decl String:display[MAX_NAME_LENGTH+12];
|
||||
|
||||
new num_clients;
|
||||
|
||||
for (new i = 1; i <= max_clients; i++)
|
||||
{
|
||||
if (!IsClientConnected(i) || IsClientInKickQueue(i))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (in_game_only && !IsClientInGame(i))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (source_client && !CanUserTarget(source_client, i))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
IntToString(GetClientUserId(i), user_id, sizeof(user_id));
|
||||
GetClientName(i, name, sizeof(name));
|
||||
Format(display, sizeof(display), "%s (%s)", name, user_id);
|
||||
AddMenuItem(menu, user_id, display);
|
||||
num_clients++;
|
||||
}
|
||||
|
||||
return num_clients;
|
||||
}
|
@ -34,6 +34,8 @@
|
||||
#pragma semicolon 1
|
||||
|
||||
#include <sourcemod>
|
||||
#undef REQUIRE_PLUGIN
|
||||
#include <adminmenu>
|
||||
|
||||
public Plugin:myinfo =
|
||||
{
|
||||
@ -44,6 +46,10 @@ public Plugin:myinfo =
|
||||
url = "http://www.sourcemod.net/"
|
||||
};
|
||||
|
||||
new Handle:hTopMenu = INVALID_HANDLE;
|
||||
|
||||
#include "basecommands/kick.sp"
|
||||
|
||||
public OnPluginStart()
|
||||
{
|
||||
LoadTranslations("common.phrases");
|
||||
@ -56,6 +62,47 @@ public OnPluginStart()
|
||||
RegAdminCmd("sm_who", Command_Who, ADMFLAG_GENERIC, "sm_who [#userid|name]");
|
||||
RegAdminCmd("sm_reloadadmins", Command_ReloadAdmins, ADMFLAG_BAN, "sm_reloadadmins");
|
||||
RegAdminCmd("sm_cancelvote", Command_CancelVote, ADMFLAG_VOTE, "sm_cancelvote");
|
||||
|
||||
/* Account for late loading */
|
||||
new Handle:topmenu;
|
||||
if (LibraryExists("adminmenu") && ((topmenu = GetAdminTopMenu()) != INVALID_HANDLE))
|
||||
{
|
||||
OnAdminMenuReady(topmenu);
|
||||
}
|
||||
}
|
||||
|
||||
public OnAdminMenuReady(Handle:topmenu)
|
||||
{
|
||||
/* Block us from being called twice */
|
||||
if (topmenu == hTopMenu)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Save the Handle */
|
||||
hTopMenu = topmenu;
|
||||
|
||||
/* Build the "Player Commands" category */
|
||||
new TopMenuObject:player_commands = FindTopMenuCategory(hTopMenu, ADMINMENU_PLAYERCOMMANDS);
|
||||
|
||||
if (player_commands != INVALID_TOPMENUOBJECT)
|
||||
{
|
||||
AddToTopMenu(hTopMenu,
|
||||
"Kick",
|
||||
TopMenuObject_Item,
|
||||
AdminMenu_Kick,
|
||||
player_commands,
|
||||
"sm_kick",
|
||||
ADMFLAG_KICK);
|
||||
}
|
||||
}
|
||||
|
||||
public OnLibraryRemoved(const String:name[])
|
||||
{
|
||||
if (strcmp(name, "adminmenu") == 0)
|
||||
{
|
||||
hTopMenu = INVALID_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
public Action:Command_ReloadAdmins(client, args)
|
||||
@ -365,51 +412,6 @@ public Action:Timer_ChangeMap(Handle:timer, Handle:dp)
|
||||
return Plugin_Stop;
|
||||
}
|
||||
|
||||
public Action:Command_Kick(client, args)
|
||||
{
|
||||
if (args < 1)
|
||||
{
|
||||
ReplyToCommand(client, "[SM] Usage: sm_kick <#userid|name> [reason]");
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
|
||||
decl String:Arguments[256];
|
||||
GetCmdArgString(Arguments, sizeof(Arguments));
|
||||
|
||||
decl String:arg[65];
|
||||
new len = BreakString(Arguments, arg, sizeof(arg));
|
||||
|
||||
new target = FindTarget(client, arg);
|
||||
if (target == -1)
|
||||
{
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
GetClientName(target, arg, sizeof(arg));
|
||||
|
||||
if (len == -1)
|
||||
{
|
||||
/* Safely null terminate */
|
||||
len = 0;
|
||||
Arguments[0] = '\0';
|
||||
}
|
||||
|
||||
ShowActivity(client, "%t", "Kicked player", arg);
|
||||
LogAction(client, target, "\"%L\" kicked \"%L\" (reason \"%s\")", client, target, Arguments[len]);
|
||||
|
||||
if (Arguments[0] == '\0')
|
||||
{
|
||||
KickClient(target, "%t", "Kicked by admin");
|
||||
}
|
||||
else
|
||||
{
|
||||
KickClient(target, "%s", Arguments[len]);
|
||||
}
|
||||
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
public Action:Command_CancelVote(client, args)
|
||||
{
|
||||
if (!IsVoteInProgress())
|
||||
@ -424,3 +426,4 @@ public Action:Command_CancelVote(client, args)
|
||||
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
|
124
plugins/basecommands/kick.sp
Normal file
124
plugins/basecommands/kick.sp
Normal file
@ -0,0 +1,124 @@
|
||||
|
||||
PerformKick(client, target, const String:reason[])
|
||||
{
|
||||
decl String:name[MAX_NAME_LENGTH];
|
||||
|
||||
GetClientName(target, name, sizeof(name));
|
||||
|
||||
ShowActivity(client, "%t", "Kicked player", name);
|
||||
LogAction(client, target, "\"%L\" kicked \"%L\" (reason \"%s\")", client, target, reason);
|
||||
|
||||
if (reason[0] == '\0')
|
||||
{
|
||||
KickClient(target, "%t", "Kicked by admin");
|
||||
}
|
||||
else
|
||||
{
|
||||
KickClient(target, "%s", reason);
|
||||
}
|
||||
}
|
||||
|
||||
DisplayKickMenu(client)
|
||||
{
|
||||
new Handle:menu = CreateMenu(MenuHandler_Kick);
|
||||
|
||||
decl String:title[100];
|
||||
Format(title, sizeof(title), "%T:", "Kick player", client);
|
||||
SetMenuTitle(menu, title);
|
||||
SetMenuExitBackButton(menu, true);
|
||||
|
||||
AddTargetsToMenu(menu, client, false);
|
||||
|
||||
DisplayMenu(menu, client, MENU_TIME_FOREVER);
|
||||
}
|
||||
|
||||
public AdminMenu_Kick(Handle:topmenu,
|
||||
TopMenuAction:action,
|
||||
TopMenuObject:object_id,
|
||||
param,
|
||||
String:buffer[],
|
||||
maxlength)
|
||||
{
|
||||
if (action == TopMenuAction_DrawOption)
|
||||
{
|
||||
Format(buffer, maxlength, "%T", "Kick player", param);
|
||||
}
|
||||
else if (action == TopMenuAction_SelectOption)
|
||||
{
|
||||
DisplayKickMenu(param);
|
||||
}
|
||||
}
|
||||
|
||||
public MenuHandler_Kick(Handle:menu, MenuAction:action, param1, param2)
|
||||
{
|
||||
if (action == MenuAction_End)
|
||||
{
|
||||
CloseHandle(menu);
|
||||
}
|
||||
else if (action == MenuAction_Cancel)
|
||||
{
|
||||
if (param2 == MenuCancel_ExitBack && hTopMenu != INVALID_HANDLE)
|
||||
{
|
||||
DisplayTopMenu(hTopMenu, param1, TopMenuPosition_LastCategory);
|
||||
}
|
||||
}
|
||||
else if (action == MenuAction_Select)
|
||||
{
|
||||
decl String:info[32];
|
||||
new userid, target;
|
||||
|
||||
GetMenuItem(menu, param2, info, sizeof(info));
|
||||
userid = StringToInt(info);
|
||||
|
||||
if ((target = GetClientOfUserId(userid)) == 0)
|
||||
{
|
||||
PrintToChat(param1, "[SM] %t", "Player no longer available");
|
||||
}
|
||||
else if (!CanUserTarget(param1, target))
|
||||
{
|
||||
PrintToChat(param1, "[SM] %t", "Unable to target");
|
||||
}
|
||||
else
|
||||
{
|
||||
PerformKick(param1, target, "");
|
||||
}
|
||||
|
||||
/* Re-draw the menu if they're still valid */
|
||||
if (IsClientInGame(param1) && !IsClientInKickQueue(param1))
|
||||
{
|
||||
DisplayKickMenu(param1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Action:Command_Kick(client, args)
|
||||
{
|
||||
if (args < 1)
|
||||
{
|
||||
ReplyToCommand(client, "[SM] Usage: sm_kick <#userid|name> [reason]");
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
decl String:Arguments[256];
|
||||
GetCmdArgString(Arguments, sizeof(Arguments));
|
||||
|
||||
decl String:arg[65];
|
||||
new len = BreakString(Arguments, arg, sizeof(arg));
|
||||
|
||||
new target = FindTarget(client, arg);
|
||||
if (target == -1)
|
||||
{
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
if (len == -1)
|
||||
{
|
||||
/* Safely null terminate */
|
||||
len = 0;
|
||||
Arguments[0] = '\0';
|
||||
}
|
||||
|
||||
PerformKick(client, target, Arguments[len]);
|
||||
|
||||
return Plugin_Handled;
|
||||
}
|
110
plugins/include/adminmenu.inc
Normal file
110
plugins/include/adminmenu.inc
Normal file
@ -0,0 +1,110 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This file is part of the SourceMod/SourcePawn SDK.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#if defined _adminmenu_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _adminmenu_included
|
||||
|
||||
/* Decide whether topmenus should be required */
|
||||
#if !defined REQUIRE_PLUGIN
|
||||
#if defined REQUIRE_EXTENSIONS
|
||||
#define TEMP_REQUIRE_EXTENSIONS
|
||||
#undef REQUIRE_EXTENSIONS
|
||||
#endif
|
||||
|
||||
#include <topmenus>
|
||||
|
||||
/* Restore old REQUIRE_EXTENSIONS value if necessary */
|
||||
#if defined TEMP_REQUIRE_EXTENSIONS
|
||||
#define REQUIRE_EXTENSIONS
|
||||
#undef TEMP_REQUIRE_EXTENSIONS
|
||||
#endif
|
||||
|
||||
/** Category for player commands. */
|
||||
#define ADMINMENU_PLAYERCOMMANDS "PlayerCommands"
|
||||
|
||||
/**
|
||||
* Called when the admin menu is created and 3rd party plugins can grab
|
||||
* the Handle or add categories.
|
||||
*
|
||||
* @param topmenu Handle to the admin menu's TopMenu.
|
||||
* @noreturn
|
||||
*/
|
||||
forward OnAdminMenuCreated(Handle:topmenu);
|
||||
|
||||
/**
|
||||
* Called when the admin menu is ready to have items added.
|
||||
*
|
||||
* @param topmenu Handle to the admin menu's TopMenu.
|
||||
* @noreturn
|
||||
*/
|
||||
forward OnAdminMenuReady(Handle:topmenu);
|
||||
|
||||
/**
|
||||
* Retrieves the Handle to the admin top menu.
|
||||
*
|
||||
* @return Handle to the admin menu's TopMenu,
|
||||
* or INVALID_HANDLE if not created yet.
|
||||
*/
|
||||
native Handle:GetAdminTopMenu();
|
||||
|
||||
/**
|
||||
* Adds targets to an admin menu.
|
||||
*
|
||||
* Each client is displayed as: name (userid)
|
||||
* Each item contains the userid as a string for its info.
|
||||
*
|
||||
* @param menu Menu Handle.
|
||||
* @param source_client Source client, or 0 to ignore immunity.
|
||||
* @param in_game_only True to only select in-game players.
|
||||
* @return Number of clients added.
|
||||
*/
|
||||
native AddTargetsToMenu(Handle:menu, source_client, bool:in_game_only=true);
|
||||
|
||||
/* DO NOT EDIT BELOW THIS LINE */
|
||||
|
||||
public SharedPlugin:__pl_adminmenu =
|
||||
{
|
||||
name = "adminmenu",
|
||||
file = "adminmenu.smx",
|
||||
#if defined REQUIRE_PLUGIN
|
||||
required = 1,
|
||||
#else
|
||||
required = 0,
|
||||
#endif
|
||||
};
|
||||
|
||||
public __pl_adminmenu_SetNTVOptional()
|
||||
{
|
||||
MarkNativeAsOptional("GetAdminTopMenu");
|
||||
}
|
@ -29,7 +29,7 @@ namespace builder
|
||||
*/
|
||||
public override string [] GetFolders()
|
||||
{
|
||||
string [] folders = new string[16];
|
||||
string [] folders = new string[17];
|
||||
|
||||
folders[0] = "addons/sourcemod/bin";
|
||||
folders[1] = "addons/sourcemod/plugins/disabled";
|
||||
@ -47,6 +47,7 @@ namespace builder
|
||||
folders[13] = "addons/sourcemod/configs/sql-init-scripts/mysql";
|
||||
folders[14] = "addons/sourcemod/configs/sql-init-scripts/sqlite";
|
||||
folders[15] = "addons/sourcemod/extensions/games";
|
||||
folders[16] = "addons/sourcemod/scripting/basecommands";
|
||||
|
||||
return folders;
|
||||
}
|
||||
@ -93,6 +94,7 @@ namespace builder
|
||||
builder.CopyFolder(this, "public/licenses", "addons/sourcemod", null);
|
||||
builder.CopyFolder(this, "plugins/admin-flatfile", "addons/sourcemod/scripting/admin-flatfile", null);
|
||||
builder.CopyFolder(this, "plugins/testsuite", "addons/sourcemod/scripting/testsuite", null);
|
||||
builder.CopyFolder(this, "plugins/basecommands", "addons/sourcemod/scripting/basecommands", null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -100,7 +102,7 @@ namespace builder
|
||||
*/
|
||||
public override Library [] GetLibraries()
|
||||
{
|
||||
Library [] libs = new Library[9];
|
||||
Library [] libs = new Library[10];
|
||||
|
||||
for (int i=0; i<libs.Length; i++)
|
||||
{
|
||||
@ -152,6 +154,11 @@ namespace builder
|
||||
libs[8].Name = "game.cstrike.ext";
|
||||
libs[8].ProjectFile = "cstrike";
|
||||
|
||||
libs[9].Destination = "addons/sourcemod/extenions";
|
||||
libs[9].LocalPath = "extensions/topmenus";
|
||||
libs[9].Name = "topmenus.ext";
|
||||
libs[9].ProjectFile = "topmenus";
|
||||
|
||||
return libs;
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,16 @@
|
||||
"en" "More than one client matches the pattern \"{1}\""
|
||||
}
|
||||
|
||||
"Player no longer available"
|
||||
{
|
||||
"en" "The player you selected is no longer available."
|
||||
}
|
||||
|
||||
"Kick player"
|
||||
{
|
||||
"en" "Kick player"
|
||||
}
|
||||
|
||||
"Kicked player"
|
||||
{
|
||||
"#format" "{1:s}"
|
||||
@ -236,5 +246,15 @@
|
||||
{
|
||||
"en" "You have specified an invalid Steam ID (must start with 'STEAM_0:')."
|
||||
}
|
||||
|
||||
"Admin Menu"
|
||||
{
|
||||
"en" "Admin Menu"
|
||||
}
|
||||
|
||||
"Player Commands"
|
||||
{
|
||||
"en" "Player Commands"
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user