1755 lines
51 KiB
Ucode
1755 lines
51 KiB
Ucode
/**
|
|
* The query handler that provides information about the current game. It will
|
|
* also set the start page for the webadmin.
|
|
*
|
|
* Copyright 2008 Epic Games, Inc. All Rights Reserved
|
|
* Copyright (C) 2011,2014 Tripwire Interactive LLC
|
|
*
|
|
* @author Michiel 'elmuerte' Hendriks
|
|
*/
|
|
class QHCurrent extends Object implements(IQueryHandler) config(WebAdmin);
|
|
|
|
`include(WebAdmin.uci)
|
|
|
|
var WebAdmin webadmin;
|
|
|
|
/**
|
|
* Refresh time of the chat console
|
|
*/
|
|
var config int ChatRefresh;
|
|
|
|
/**
|
|
* If true the management console will be available. This will allow users to
|
|
* directly enter console commands on the server. This means that the user will
|
|
* have the ability to shutdown the server or execute commands that change
|
|
* certain core variables.
|
|
*/
|
|
var config bool bConsoleEnabled;
|
|
|
|
/**
|
|
* Options in this list are not allowed to be set in the "change game" page.
|
|
* They will removed from the url.
|
|
*/
|
|
var config array<string> denyUrlOptions;
|
|
|
|
/**
|
|
* Lists of console commands that are not allowed to be executed.
|
|
*/
|
|
var config array<string> denyConsoleCommands;
|
|
|
|
/**
|
|
* if true use the hack to access some special admin commands lick "kickban ...",
|
|
* "restartlevel". If false these commands would not be available
|
|
*/
|
|
var config bool bAdminConsoleCommandsHack;
|
|
|
|
/**
|
|
* The AdminCommandHandler class to use for handling the admin console command hack.
|
|
*/
|
|
var config string AdminCommandHandlerClass;
|
|
|
|
/**
|
|
* if true team chat will be enabled.
|
|
*/
|
|
var config bool bEnableTeamChat;
|
|
|
|
/**
|
|
* Instance that handled "Admin" console command aliases.
|
|
*/
|
|
var AdminCommandHandler adminCmdHandler;
|
|
|
|
/**
|
|
* CSS code to make things visible.
|
|
*/
|
|
var string cssVisible;
|
|
|
|
/**
|
|
* CSS code to make HTML elements hidden.
|
|
*/
|
|
var string cssHidden;
|
|
|
|
/**
|
|
* Will hold a sorted player replication info list.
|
|
*/
|
|
var array<PlayerReplicationInfo> sortedPRI;
|
|
|
|
/**
|
|
* Will hold the url where to switch the game to. Game switching a delayed for
|
|
* a few ms.
|
|
*/
|
|
var private string newUrl;
|
|
|
|
/**
|
|
* if true the news will be shown on the "current" page
|
|
*/
|
|
var config bool hideNews;
|
|
|
|
var NewsDesk newsDesk;
|
|
|
|
/**
|
|
* Notes which an admin can enter if they feel like
|
|
*/
|
|
var config array<string> Notes;
|
|
|
|
//!localization
|
|
var localized string menuCurrent, menuCurrentDesc, menuPlayers, menuPlayersDesc,
|
|
menuChat, menuChatDesc, menuChange, menuChangeDesc, menuConsole, menuConsoleDesc,
|
|
menuBots, menuBotsDesc, NotesSaved, msgPlayerNotFound, msgNoHumanPlayer,
|
|
msgVoiceMuted, msgVoiceUnmuted, msgTextMuted, msgTextUnmuted, msgCantBanAdmin,
|
|
msgSessionBanned, msgCantKickAdmin, msgPlayerRemoved, msgTextMute, msgTextUnmute,
|
|
msgExecDisabled, msgChangingGame, msgAddingBots, msgRemovedBots,
|
|
msgNoMutators, msgAddingBotsTeam, msgYes, msgNo, msgScreenshot, rmRealistic,
|
|
rmStandard, rmCustom, msgOff, pbLow, pbMedium, pbHigh, msgUnknown, msgOn,
|
|
msgSessionBanNoROAC, msgNotAllowed, menuServerInfo, menuServerInfoDesc;
|
|
|
|
var array<string> playerActions;
|
|
|
|
/**
|
|
* If true, spectators are separated from the player list in the current info page.
|
|
*/
|
|
var bool separateSpectators;
|
|
|
|
var array<string> consoleCommandsToGetServerExiled;
|
|
|
|
function init(WebAdmin webapp)
|
|
{
|
|
local class<AdminCommandHandler> achc;
|
|
|
|
if (Len(AdminCommandHandlerClass) == 0)
|
|
{
|
|
AdminCommandHandlerClass = class.getPackageName()$".AdminCommandHandler";
|
|
SaveConfig();
|
|
}
|
|
|
|
webadmin = webapp;
|
|
if (len(webapp.startpage) == 0)
|
|
{
|
|
webapp.startpage = "/current";
|
|
webapp.SaveConfig();
|
|
}
|
|
if (ChatRefresh < 500) ChatRefresh = 5000;
|
|
|
|
if (bAdminConsoleCommandsHack)
|
|
{
|
|
achc = class<AdminCommandHandler>(DynamicLoadObject(AdminCommandHandlerClass, class'class'));
|
|
if (achc != none)
|
|
{
|
|
adminCmdHandler = webadmin.worldinfo.spawn(achc);
|
|
}
|
|
}
|
|
|
|
webadmin.WorldInfo.Game.SetTimer(0.1, false, 'CreateTeamChatProxy', self);
|
|
if (!hideNews)
|
|
{
|
|
newsDesk = new class'NewsDesk';
|
|
newsDesk.getNews();
|
|
}
|
|
}
|
|
|
|
function CreateTeamChatProxy()
|
|
{
|
|
local TeamChatProxy tcp;
|
|
local int i;
|
|
|
|
//KFII-38982 | Adam Massingale | Always spawning team chat proxies even if we're not in a team game like vs
|
|
//this will allow team chat to always take place in case users send team chat messages. the users are all on the same
|
|
//team but we still want to see the messages in webadmin and chat logs.
|
|
//if (bEnableTeamChat) && `isTeamGame(webadmin.WorldInfo.Game))
|
|
if (bEnableTeamChat)
|
|
{
|
|
if (webadmin.WorldInfo.Game.GameReplicationInfo == none)
|
|
{
|
|
webadmin.WorldInfo.Game.SetTimer(0.1, false, 'CreateTeamChatProxy', self);
|
|
return;
|
|
}
|
|
|
|
`log("Creating team chat proxies",,'WebAdmin');
|
|
|
|
for (i = 0; i < webadmin.WorldInfo.Game.GameReplicationInfo.Teams.length; i++)
|
|
{
|
|
if (webadmin.WorldInfo.Game.GameReplicationInfo.Teams[i] == none) continue;
|
|
tcp = webadmin.WorldInfo.Spawn(class'TeamChatProxy',, name("TeamChatProxy__"$i));
|
|
if (tcp != none)
|
|
{
|
|
tcp.PlayerReplicationInfo.Team = webadmin.WorldInfo.Game.GameReplicationInfo.Teams[i];
|
|
}
|
|
else {
|
|
`log("Failed to create TeamChatProxy for team "$i,,'WebAdmin');
|
|
}
|
|
}
|
|
if (WebAdmin.bChatLog)
|
|
{
|
|
WebAdmin.CreateChatLog();
|
|
}
|
|
}
|
|
else if (WebAdmin.bChatLog)
|
|
{
|
|
WebAdmin.CreateChatLog();
|
|
}
|
|
}
|
|
|
|
function cleanup()
|
|
{
|
|
adminCmdHandler = none;
|
|
webadmin = none;
|
|
newsDesk.cleanup();
|
|
newsDesk = none;
|
|
sortedPRI.Remove(0, sortedPRI.Length);
|
|
}
|
|
|
|
function bool producesXhtml()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
function registerMenuItems(WebAdminMenu menu)
|
|
{
|
|
menu.addMenu("/current", menuCurrent, self, menuCurrentDesc, -100);
|
|
menu.addMenu("/current/info", menuServerInfo, self, menuServerInfoDesc, -100);
|
|
menu.addMenu("/current/info+data", "", self);
|
|
menu.addMenu("/current/change", menuChange, self, menuChangeDesc, -90);
|
|
menu.addMenu("/current/change+data", "", self);
|
|
menu.addMenu("/current/change+check", "", self);
|
|
menu.addMenu("/current/players", menuPlayers, self, menuPlayersDesc, -80);
|
|
menu.addMenu("/current/players+data", "", self);;
|
|
menu.addMenu("/current/chat", menuChat, self, menuChatDesc);
|
|
menu.addMenu("/current/chat+data", "", self,,, "/current+chat");
|
|
`if(`WITH_BOTS)
|
|
menu.addMenu("/current/bots", menuBots, self, menuBotsDesc);
|
|
`endif
|
|
if (bConsoleEnabled)
|
|
{
|
|
menu.addMenu("/console", menuConsole, self, menuConsoleDesc);
|
|
}
|
|
}
|
|
|
|
function bool handleQuery(WebAdminQuery q)
|
|
{
|
|
switch (q.request.URI)
|
|
{
|
|
case "/current":
|
|
q.response.Redirect(WebAdmin.Path$"/current/info");
|
|
return true;
|
|
case "/current/info":
|
|
handleCurrent(q);
|
|
return true;
|
|
case "/current/info+data":
|
|
handleCurrentData(q);
|
|
return true;
|
|
case "/current/players":
|
|
handleCurrentPlayers(q);
|
|
return true;
|
|
case "/current/players+data":
|
|
handleCurrentPlayersData(q);
|
|
return true;
|
|
case "/current/chat":
|
|
handleCurrentChat(q);
|
|
return true;
|
|
case "/current/chat+data":
|
|
handleCurrentChatData(q);
|
|
return true;
|
|
case "/console":
|
|
if (bConsoleEnabled)
|
|
{
|
|
handleConsole(q);
|
|
return true;
|
|
}
|
|
return false;
|
|
case "/current/change":
|
|
handleCurrentChange(q);
|
|
return true;
|
|
case "/current/change+data":
|
|
handleCurrentChangeData(q);
|
|
return true;
|
|
case "/current/change+check":
|
|
if (newUrl == "")
|
|
{
|
|
q.response.SendText("ok");
|
|
}
|
|
else {
|
|
q.response.HTTPResponse("HTTP/1.1 503 Service Unavailable");
|
|
}
|
|
return true;
|
|
`if(`WITH_BOTS)
|
|
case "/current/bots":
|
|
handleBots(q);
|
|
return true;
|
|
`endif
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// not used here
|
|
function bool unhandledQuery(WebAdminQuery q);
|
|
|
|
function decoratePage(WebAdminQuery q);
|
|
|
|
function handleCurrentData(WebAdminQuery q)
|
|
{
|
|
local string tmp;
|
|
local int idx;
|
|
|
|
if (q.request.getVariable("action") ~= "save")
|
|
{
|
|
notes.length = 0;
|
|
tmp = q.request.getVariable("notes");
|
|
idx = InStr(tmp, chr(10));
|
|
while (idx != INDEX_NONE)
|
|
{
|
|
notes[notes.length] = `Trim(Left(tmp, idx));
|
|
tmp = Mid(tmp, idx+1);
|
|
idx = InStr(tmp, chr(10));
|
|
}
|
|
tmp = `Trim(tmp);
|
|
if (len(tmp) > 0)
|
|
{
|
|
notes[notes.length] = tmp;
|
|
}
|
|
SaveConfig();
|
|
webadmin.addMessage(q, NotesSaved);
|
|
}
|
|
|
|
if (q.request.getVariable("ajax") == "1")
|
|
{
|
|
q.response.AddHeader("Content-Type: text/xml");
|
|
q.response.SendText("<request>");
|
|
q.response.SendText("<messages><![CDATA[");
|
|
q.response.SendText(webadmin.renderMessages(q));
|
|
q.response.SendText("]]></messages>");
|
|
q.response.SendText("</request>");
|
|
}
|
|
}
|
|
|
|
function handleCurrent(WebAdminQuery q)
|
|
{
|
|
local string players;
|
|
local PlayerReplicationInfo pri;
|
|
local int idx, cnt;
|
|
local string tmp;
|
|
local OnlineGameSettings GameSettings;
|
|
|
|
handleCurrentData(q);
|
|
|
|
if (!hideNews && newsDesk != none && newsDesk.newsIface != none)
|
|
{
|
|
q.response.subst("news", newsDesk.renderNews(webadmin, q));
|
|
}
|
|
else {
|
|
q.response.subst("news", "");
|
|
}
|
|
|
|
tmp = "";
|
|
for (idx = 0; idx < notes.length; idx++)
|
|
{
|
|
tmp $= notes[idx]$chr(10);
|
|
}
|
|
q.response.subst("notes", `HTMLEscape(tmp));
|
|
|
|
substGameInfo(q);
|
|
|
|
GameSettings = webadmin.WorldInfo.Game.GameInterface.GetGameSettings(webadmin.WorldInfo.Game.PlayerReplicationInfoClass.default.SessionName);
|
|
if (GameSettings != None)
|
|
{
|
|
if (GameSettings.bAntiCheatProtected)
|
|
{
|
|
q.response.subst("server.anticheat", msgOn);
|
|
}
|
|
else {
|
|
q.response.subst("server.anticheat", msgOff);
|
|
}
|
|
}
|
|
|
|
q.response.subst("teams", getCurrentTeamInfo(q));
|
|
|
|
q.response.subst("server.name", `HTMLEscape(webadmin.WorldInfo.Game.GameReplicationInfo.ServerName));
|
|
|
|
buildSortedPRI(q.request.getVariable("sortby", "score"), q.request.getVariable("reverse", "true") ~= "true", false);
|
|
cnt = 0;
|
|
foreach sortedPRI(pri, idx)
|
|
{
|
|
if (separateSpectators && pri.bOnlySpectator)
|
|
{
|
|
continue;
|
|
}
|
|
if (`mod(cnt, 2) == 0) q.response.subst("evenodd", "even");
|
|
else q.response.subst("evenodd", "odd");
|
|
substPri(q, pri);
|
|
players $= webadmin.include(q, "current_player_row.inc");
|
|
cnt++;
|
|
}
|
|
if (sortedPRI.Length == 0)
|
|
{
|
|
players = webadmin.include(q, "current_player_empty.inc");
|
|
}
|
|
q.response.subst("sorted."$q.request.getVariable("sortby", "score"), "sorted");
|
|
if (!(q.request.getVariable("reverse", "true") ~= "true"))
|
|
{
|
|
q.response.subst("reverse."$q.request.getVariable("sortby", "score"), "true");
|
|
}
|
|
|
|
q.response.subst("players", players);
|
|
q.response.subst("rules", webadmin.include(q, getGameTypeIncFile(q, "current_rules")));
|
|
|
|
if (separateSpectators) {
|
|
q.response.subst("spectators", getCurrentSpectatorsInfo(q));
|
|
}
|
|
else {
|
|
q.response.subst("spectators", "");
|
|
}
|
|
|
|
webadmin.sendPage(q, "current.html");
|
|
}
|
|
|
|
function string getCurrentSpectatorsInfo(WebAdminQuery q)
|
|
{
|
|
local array<PlayerReplicationInfo> spectators;
|
|
local PlayerReplicationInfo pri;
|
|
local PlayerController pc;
|
|
local bool inserted, cmp;
|
|
local int idx;
|
|
local string tmp;
|
|
|
|
foreach WebAdmin.WorldInfo.AllControllers(class'PlayerController', pc)
|
|
{
|
|
if (pc.PlayerReplicationInfo == none || !pc.PlayerReplicationInfo.bOnlySpectator)
|
|
{
|
|
continue;
|
|
}
|
|
if (MessagingSpectator(PC) != none)
|
|
{
|
|
continue;
|
|
}
|
|
inserted = false;
|
|
foreach spectators(PRI, idx)
|
|
{
|
|
cmp = comparePRI(PRI, PC.PlayerReplicationInfo, "name");
|
|
if (cmp)
|
|
{
|
|
spectators.Insert(idx, 1);
|
|
spectators[idx] = PC.PlayerReplicationInfo;
|
|
inserted = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!inserted)
|
|
{
|
|
spectators.addItem(PC.PlayerReplicationInfo);
|
|
}
|
|
}
|
|
|
|
tmp = "";
|
|
if (spectators.Length == 0) {
|
|
return "";
|
|
}
|
|
|
|
foreach spectators(PRI, idx)
|
|
{
|
|
if (idx > 0) {
|
|
tmp $= ", ";
|
|
}
|
|
tmp $= `HTMLEscape(pri.PlayerName);
|
|
}
|
|
q.response.subst("spectators.names", tmp);
|
|
q.response.subst("spectators.current", spectators.Length);
|
|
q.response.subst("spectators.max", webadmin.WorldInfo.Game.MaxSpectators);
|
|
return webadmin.include(q, "current_spectators.inc");
|
|
}
|
|
|
|
function substGameInfo(WebAdminQuery q)
|
|
{
|
|
local int idx, i;
|
|
local mutator mut;
|
|
local string tmp, tmp2;
|
|
local array<string> activeMuts;
|
|
|
|
q.response.subst("game.name", `HTMLEscape(webadmin.WorldInfo.Game.GameName));
|
|
q.response.subst("game.type", webadmin.WorldInfo.Game.class.getPackageName()$"."$webadmin.WorldInfo.Game.class);
|
|
|
|
q.response.subst("map.title", `HTMLEscape(webadmin.WorldInfo.Title));
|
|
q.response.subst("map.author", `HTMLEscape(webadmin.WorldInfo.Author));
|
|
q.response.subst("map.name", webadmin.WorldInfo.GetPackageName());
|
|
if (len(webadmin.WorldInfo.Title) > 0)
|
|
{
|
|
q.response.subst("map.title.safe", `HTMLEscape(webadmin.WorldInfo.Title));
|
|
}
|
|
else {
|
|
q.response.subst("map.title.safe", webadmin.WorldInfo.GetPackageName());
|
|
}
|
|
|
|
tmp = "/images/maps/"$webadmin.WorldInfo.GetPackageName()$".jpg";
|
|
tmp2 = "/images/maps/"$locs(webadmin.WorldInfo.GetPackageName())$".jpg";
|
|
if (q.response.FileExists(tmp))
|
|
{
|
|
q.response.subst("map.image", tmp);
|
|
}
|
|
else if (q.response.FileExists(tmp2))
|
|
{
|
|
q.response.subst("map.image", tmp2);
|
|
}
|
|
else {
|
|
q.response.subst("map.image", "/images/maps/noimage.png");
|
|
}
|
|
|
|
webadmin.dataStoreCache.loadMutators();
|
|
ParseStringIntoArray(webadmin.WorldInfo.Game.ParseOption(getServerOptions(), "mutator"), activeMuts, ",", true);
|
|
|
|
mut = webadmin.WorldInfo.Game.BaseMutator;
|
|
while (mut != none)
|
|
{
|
|
tmp2 = mut.class.getPackageName()$"."$mut.class;
|
|
if (activeMuts.find(tmp2) == INDEX_none)
|
|
{
|
|
activeMuts.addItem(tmp2);
|
|
}
|
|
mut = mut.NextMutator;
|
|
}
|
|
|
|
tmp = "";
|
|
for (i = 0; i < activeMuts.length; i++)
|
|
{
|
|
if (len(tmp) > 0) tmp $= ", ";
|
|
tmp2 = activeMuts[i];
|
|
for (idx = 0; idx < webadmin.dataStoreCache.mutators.Length; ++idx)
|
|
{
|
|
if (webadmin.dataStoreCache.mutators[idx].ClassName ~= tmp2)
|
|
{
|
|
tmp $= webadmin.dataStoreCache.mutators[idx].FriendlyName;
|
|
break;
|
|
}
|
|
}
|
|
if (idx == webadmin.dataStoreCache.mutators.Length)
|
|
{
|
|
tmp $= tmp2;
|
|
}
|
|
}
|
|
q.response.subst("rules.mutators", tmp);
|
|
|
|
q.response.subst("rules.timelimit", webadmin.WorldInfo.Game.TimeLimit);
|
|
q.response.subst("rules.goalscore", webadmin.WorldInfo.Game.GoalScore);
|
|
q.response.subst("rules.maxlives", webadmin.WorldInfo.Game.MaxLives);
|
|
q.response.subst("rules.difficulty", webadmin.WorldInfo.Game.GameDifficulty);
|
|
|
|
q.response.subst("rules.maxspectators", webadmin.WorldInfo.Game.MaxSpectators);
|
|
q.response.subst("rules.numspectators", webadmin.WorldInfo.Game.NumSpectators);
|
|
q.response.subst("rules.maxplayers", webadmin.WorldInfo.Game.MaxPlayers);
|
|
q.response.subst("rules.numplayers", webadmin.WorldInfo.Game.NumPlayers);
|
|
q.response.subst("rules.numbots", webadmin.WorldInfo.Game.NumBots);
|
|
|
|
q.response.subst("time.timelimit", webadmin.WorldInfo.Game.GameReplicationInfo.TimeLimit);
|
|
q.response.subst("time.elapsed", webadmin.WorldInfo.Game.GameReplicationInfo.ElapsedTime);
|
|
q.response.subst("time.remaining", webadmin.WorldInfo.Game.GameReplicationInfo.RemainingTime);
|
|
}
|
|
|
|
/*
|
|
* Called from #handleCurrent(..)
|
|
*/
|
|
function string getCurrentTeamInfo(WebAdminQuery q)
|
|
{
|
|
local TeamInfo teaminfo;
|
|
local int i;
|
|
local string tmp;
|
|
|
|
if (!`isTeamGame(webadmin.WorldInfo.Game)) return "";
|
|
|
|
tmp = "";
|
|
for (i = 0; i < webadmin.WorldInfo.Game.GameReplicationInfo.teams.length; ++i)
|
|
{
|
|
if (`mod(i, 2) == 0) q.response.subst("evenodd", "even");
|
|
else q.response.subst("evenodd", "odd");
|
|
teaminfo = webadmin.WorldInfo.Game.GameReplicationInfo.teams[i];
|
|
q.response.subst("team.color", class'WebAdminUtils'.static.ColorToHTMLColor(TeamInfo.TeamColor));
|
|
q.response.subst("team.index", teaminfo.TeamIndex);
|
|
q.response.subst("team.name", `HTMLEscape(class'WebAdminUtils'.static.getTeamNameEx(teaminfo)));
|
|
q.response.subst("team.size", teaminfo.Size);
|
|
q.response.subst("team.score", teaminfo.Score);
|
|
q.response.subst("team.score.int", int(teaminfo.Score));
|
|
|
|
tmp $= webadmin.include(q, getGameTypeIncFile(q, "current_team"));
|
|
}
|
|
q.response.subst("teams", tmp);
|
|
return webadmin.include(q, getGameTypeIncFile(q, "current_teams"));
|
|
}
|
|
|
|
function string getGameTypeIncFile(WebAdminQuery q, string base)
|
|
{
|
|
local string incFile;
|
|
incFile = base$"_"$locs(webadmin.WorldInfo.Game.class)$".inc";
|
|
if (webadmin.hasIncludeFile(q, incFile)) return incFile;
|
|
return base$".inc";
|
|
}
|
|
|
|
function buildSortedPRI(string sortkey, optional bool reverse=false, optional bool includeBots=true)
|
|
{
|
|
local Controller P;
|
|
local PlayerReplicationInfo PRI;
|
|
local int idx;
|
|
local bool cmp, inserted;
|
|
|
|
sortedPRI.Remove(0, sortedPRI.Length);
|
|
|
|
foreach WebAdmin.WorldInfo.AllControllers(class'Controller', P)
|
|
{
|
|
if (!P.bDeleteMe && P.PlayerReplicationInfo != None && P.bIsPlayer)
|
|
{
|
|
if (!includeBots && P.PlayerReplicationInfo.bBot)
|
|
{
|
|
continue;
|
|
}
|
|
/*
|
|
if (DemoRecSpectator(P) != none)
|
|
{
|
|
// never mess with this one
|
|
continue;
|
|
}
|
|
*/
|
|
inserted = false;
|
|
foreach sortedPRI(PRI, idx)
|
|
{
|
|
cmp = comparePRI(PRI, P.PlayerReplicationInfo, sortkey);
|
|
if (reverse)
|
|
{
|
|
cmp = !cmp;
|
|
}
|
|
if (cmp)
|
|
{
|
|
sortedPRI.Insert(idx, 1);
|
|
sortedPRI[idx] = P.PlayerReplicationInfo;
|
|
inserted = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!inserted)
|
|
{
|
|
sortedPRI.addItem(P.PlayerReplicationInfo);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function bool comparePRI(PlayerReplicationInfo PRI1, PlayerReplicationInfo PRI2, string key)
|
|
{
|
|
`if(`GAME_UT3)
|
|
local string s1, s2;
|
|
if (key ~= "name")
|
|
{
|
|
if (len(pri1.PlayerName) == 0)
|
|
{
|
|
s1 = pri1.PlayerAlias;
|
|
}
|
|
else {
|
|
s1 = pri1.PlayerName;
|
|
}
|
|
if (len(pri2.PlayerName) == 0)
|
|
{
|
|
s2 = pri2.PlayerAlias;
|
|
}
|
|
else {
|
|
s2 = pri2.PlayerName;
|
|
}
|
|
return caps(s1) > caps(s2);
|
|
}
|
|
else
|
|
`endif
|
|
if (key ~= "playername" `if(`GAME_UT3) `else || key ~= "name" `endif)
|
|
{
|
|
return caps(pri1.PlayerName) > caps(pri2.PlayerName);
|
|
}
|
|
`if(`GAME_UT3)
|
|
else if (key ~= "playeralias")
|
|
{
|
|
return caps(pri1.PlayerAlias) > caps(pri2.PlayerAlias);
|
|
}
|
|
`endif
|
|
else if (key ~= "score")
|
|
{
|
|
return pri1.score > pri2.score;
|
|
}
|
|
else if (key ~= "deaths")
|
|
{
|
|
return pri1.deaths > pri2.deaths;
|
|
}
|
|
else if (key ~= "ping")
|
|
{
|
|
return pri1.ping > pri2.ping;
|
|
}
|
|
else if (key ~= "lives")
|
|
{
|
|
return pri1.NumLives > pri2.numlives;
|
|
}
|
|
`if(`GAME_UT3)
|
|
else if (key ~= "ranking")
|
|
{
|
|
return pri1.playerranking > pri2.playerranking;
|
|
}
|
|
else if (key ~= "teamid")
|
|
{
|
|
return pri1.teamid > pri2.teamid;
|
|
}
|
|
`endif
|
|
else if (key ~= "kills")
|
|
{
|
|
return pri1.kills > pri2.kills;
|
|
}
|
|
else if (key ~= "starttime")
|
|
{
|
|
return pri1.starttime > pri2.starttime;
|
|
}
|
|
}
|
|
|
|
static function string getPlayerKey(PlayerReplicationInfo pri)
|
|
{
|
|
return pri.PlayerID$"_"$class'OnlineSubsystem'.static.UniqueNetIdToString(pri.UniqueId)$"_"$pri.CreationTime;
|
|
}
|
|
|
|
function substPri(WebAdminQuery q, PlayerReplicationInfo pri)
|
|
{
|
|
local PlayerController pc;
|
|
|
|
q.response.subst("player.playerid", pri.PlayerID);
|
|
q.response.subst("player.playerkey", getPlayerKey(pri));
|
|
q.response.subst("player.name", `HTMLEscape(pri.PlayerName));
|
|
q.response.subst("player.playername", `HTMLEscape(pri.PlayerName));
|
|
q.response.subst("player.score", int(pri.score));
|
|
q.response.subst("player.deaths", pri.deaths);
|
|
q.response.subst("player.ping", pri.ping * 4); // this ping value is divided by 4 (250 = 1sec) see bug #40
|
|
q.response.subst("player.exactping", pri.ExactPing);
|
|
q.response.subst("player.lives", pri.numlives);
|
|
if (`isTeamGame(webadmin.WorldInfo.Game) && pri.Team != none)
|
|
{
|
|
q.response.subst("player.teamid", pri.Team.TeamIndex);
|
|
q.response.subst("player.teamcolor", class'WebAdminUtils'.static.ColorToHTMLColor(pri.Team.TeamColor));
|
|
q.response.subst("player.teamname", `HTMLEscape(class'WebAdminUtils'.static.getTeamNameEx(pri.Team)));
|
|
}
|
|
else {
|
|
q.response.subst("player.teamid", "");
|
|
q.response.subst("player.teamcolor", "transparent");
|
|
q.response.subst("player.teamname", "");
|
|
}
|
|
q.response.subst("player.admin", `HTMLEscape(pri.bAdmin?default.msgYes:default.msgNo));
|
|
q.response.subst("player.bot", `HTMLEscape(pri.bBot?default.msgYes:default.msgNo));
|
|
q.response.subst("player.spectator", `HTMLEscape(pri.bIsSpectator?default.msgYes:default.msgNo));
|
|
q.response.subst("player.kills", pri.kills);
|
|
q.response.subst("player.starttime", pri.starttime);
|
|
|
|
pc = PlayerController(pri.Owner);
|
|
if (pc != none)
|
|
{
|
|
if (pc.pawn != none)
|
|
{
|
|
q.response.subst("player.pawn.health", pc.pawn.Health);
|
|
q.response.subst("player.pawn.healthmax", pc.pawn.HealthMax);
|
|
}
|
|
else {
|
|
q.response.subst("player.pawn.health", "");
|
|
q.response.subst("player.pawn.healthmax", "");
|
|
}
|
|
}
|
|
}
|
|
|
|
function int handleCurrentPlayersAction(WebAdminQuery q)
|
|
{
|
|
local PlayerReplicationInfo PRI;
|
|
local int idx;
|
|
local string IP, action, kickMessage;
|
|
local PlayerController PC,otherPC;
|
|
`if(`WITH_TEXT_MUTE)
|
|
local KFPlayerController UTPC;
|
|
`endif
|
|
|
|
action = q.request.getVariable("action");
|
|
if (action != "")
|
|
{
|
|
//PRI = webadmin.WorldInfo.Game.GameReplicationInfo.FindPlayerByID(int(q.request.getVariable("playerid")));
|
|
IP = q.request.getVariable("playerkey");
|
|
PRI = none;
|
|
for (idx = 0; idx < webadmin.WorldInfo.Game.GameReplicationInfo.PRIArray.length; idx++)
|
|
{
|
|
if (getPlayerKey(webadmin.WorldInfo.Game.GameReplicationInfo.PRIArray[idx]) == IP)
|
|
{
|
|
PRI = webadmin.WorldInfo.Game.GameReplicationInfo.PRIArray[idx];
|
|
break;
|
|
}
|
|
}
|
|
if (PRI == none)
|
|
{
|
|
webadmin.addMessage(q, msgPlayerNotFound, MT_Warning);
|
|
}
|
|
else if (q.user.canPerform(webadmin.getAuthURL("/current/players#"$action)))
|
|
{
|
|
PC = PlayerController(PRI.Owner);
|
|
if ( NetConnection(PC.Player) == None )
|
|
{
|
|
PC = none;
|
|
}
|
|
if (PC == none)
|
|
{
|
|
webadmin.addMessage(q, msgNoHumanPlayer, MT_Warning);
|
|
}
|
|
else {
|
|
// Default to just the normal kick message
|
|
kickMessage = "Engine.AccessControl.KickedMsg";
|
|
if (action ~= "mutevoice")
|
|
{
|
|
foreach webadmin.WorldInfo.AllControllers(class'PlayerController', otherPC)
|
|
{
|
|
otherPC.ServerMutePlayer(PC.PlayerReplicationInfo.UniqueId);
|
|
}
|
|
webadmin.addMessage(q, repl(msgVoiceMuted, "%s", PRI.PlayerName));
|
|
return 0;
|
|
}
|
|
else if (action ~= "unmutevoice")
|
|
{
|
|
foreach webadmin.WorldInfo.AllControllers(class'PlayerController', otherPC)
|
|
{
|
|
otherPC.ServerUnMutePlayer(PC.PlayerReplicationInfo.UniqueId);
|
|
}
|
|
webadmin.addMessage(q, repl(msgVoiceUnmuted, "%s", PRI.PlayerName));
|
|
return 0;
|
|
}
|
|
|
|
`if(`WITH_TEXT_MUTE)
|
|
else if (action ~= "toggletext")
|
|
{
|
|
UTPC = KFPlayerController(PC);
|
|
if (UTPC != none)
|
|
{
|
|
UTPC.bServerMutedText = !UTPC.bServerMutedText;
|
|
if (UTPC.bServerMutedText) webadmin.addMessage(q, repl(msgTextMuted, "%s", PRI.PlayerName));
|
|
else webadmin.addMessage(q, repl(msgTextUnmuted, "%s", PRI.PlayerName));
|
|
return (UTPC.bServerMutedText?2:3);
|
|
}
|
|
return 0;
|
|
}
|
|
`endif
|
|
|
|
else if (action ~= "banip" || action ~= "ban ip")
|
|
{
|
|
banByIP(PC);
|
|
kickMessage = "Engine.AccessControl.KickAndPermaBan";
|
|
}
|
|
else if (action ~= "banid" || action ~= "ban unique id")
|
|
{
|
|
banByID(PC);
|
|
kickMessage = "Engine.AccessControl.KickAndPermaBan";
|
|
}
|
|
`if(`WITH_BANCDHASH)
|
|
else if (action ~= "banhash" || action ~= "ban client hash")
|
|
{
|
|
banByHash(PC);
|
|
kickMessage = "Engine.AccessControl.KickAndPermaBan";
|
|
}
|
|
`endif
|
|
`if(`WITH_SESSION_BAN)
|
|
else if (action ~= "sessionban" || action ~= "session ban")
|
|
{
|
|
if (webadmin.WorldInfo.Game.AccessControl.IsAdmin(PC))
|
|
{
|
|
webadmin.addMessage(q, repl(msgCantBanAdmin, "%s", PRI.PlayerName), MT_Error);
|
|
return 0;
|
|
}
|
|
else {
|
|
if (`{AccessControl} (webadmin.WorldInfo.Game.AccessControl) != none)
|
|
{
|
|
`{AccessControl} (webadmin.WorldInfo.Game.AccessControl).KickSessionBanPlayer(PC, PC.PlayerReplicationInfo.UniqueId, "Engine.AccessControl.KickAndSessionBan");
|
|
(webadmin.WorldInfo.Game).ExileServerUsingKickBan();
|
|
webadmin.addMessage(q, repl(msgSessionBanned, "%s", PRI.PlayerName));
|
|
return 1;
|
|
}
|
|
else {
|
|
webadmin.addMessage(q, msgSessionBanNoROAC, MT_Error);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
`endif
|
|
|
|
if (!webadmin.WorldInfo.Game.AccessControl.KickPlayer(PC, kickMessage))
|
|
{
|
|
webadmin.addMessage(q, repl(msgCantKickAdmin, "%s", PRI.PlayerName), MT_Error);
|
|
}
|
|
else {
|
|
(webadmin.WorldInfo.Game).ExileServerUsingKickBan();
|
|
webadmin.addMessage(q, repl(msgPlayerRemoved, "%s", PRI.PlayerName));
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
webadmin.addMessage(q, msgNotAllowed, MT_Error);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
function handleCurrentPlayers(WebAdminQuery q)
|
|
{
|
|
local PlayerReplicationInfo PRI;
|
|
local int idx;
|
|
local string players, IP;
|
|
local PlayerController PC;
|
|
local OnlineSubsystem steamworks;
|
|
local string tmp, playerAct;
|
|
|
|
handleCurrentPlayersAction(q);
|
|
|
|
steamworks = class'GameEngine'.static.GetOnlineSubsystem();
|
|
|
|
playerAct = "";
|
|
for (idx = 0; idx < playerActions.length; ++idx)
|
|
{
|
|
if (!q.user.canPerform(webadmin.getAuthURL(q.request.uri$"#"$playerActions[idx])))
|
|
{
|
|
continue;
|
|
}
|
|
q.response.subst("action.action", `HTMLEscape(playerActions[idx]));
|
|
tmp = Localize("QHCurrent", "PlayerAction_"$playerActions[idx], "WebAdmin");
|
|
if (tmp == "")
|
|
{
|
|
tmp = playerActions[idx];
|
|
}
|
|
q.response.subst("action.text", `HTMLEscape(tmp));
|
|
playerAct $= webadmin.include(q, "current_players_row_action.inc");
|
|
}
|
|
q.response.subst("actions", playerAct);
|
|
|
|
buildSortedPRI(q.request.getVariable("sortby", "name"), q.request.getVariable("reverse", "") ~= "true", false);
|
|
foreach sortedPRI(pri, idx)
|
|
{
|
|
PC = PlayerController(pri.owner);
|
|
if (PC == none)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (`mod(idx, 2) == 0) q.response.subst("evenodd", "even");
|
|
else q.response.subst("evenodd", "odd");
|
|
|
|
substPri(q, pri);
|
|
IP = class'WebAdminUtils'.static.extractIp(PC.GetPlayerNetworkAddress());
|
|
q.response.subst("player.ip", IP);
|
|
q.response.subst("player.uniqueid", class'WebAdminUtils'.static.UniqueNetIdToString(pri.UniqueId));
|
|
if (steamworks != none)
|
|
{
|
|
q.response.subst("player.steamid", steamworks.UniqueNetIdToInt64(pri.UniqueId));
|
|
IP = steamworks.UniqueNetIdToPlayerName(pri.UniqueId);
|
|
q.response.subst("player.steamname", `HTMLEscape(IP));
|
|
}
|
|
else {
|
|
q.response.subst("player.steamname", "");
|
|
q.response.subst("player.steamid", "");
|
|
}
|
|
`if(`WITH_TEXT_MUTE)
|
|
if (KFPlayerController(PC) != none && KFPlayerController(PC).bServerMutedText)
|
|
{
|
|
q.response.subst("player.mutetext", msgTextUnmute);
|
|
}
|
|
else {
|
|
q.response.subst("player.mutetext", msgTextMute);
|
|
}
|
|
`endif
|
|
players $= webadmin.include(q, "current_players_row.inc");
|
|
}
|
|
if (sortedPRI.Length == 0)
|
|
{
|
|
players = webadmin.include(q, "current_players_empty.inc");
|
|
}
|
|
|
|
q.response.subst("sorted."$q.request.getVariable("sortby", "name"), "sorted");
|
|
if (!(q.request.getVariable("reverse", "") ~= "true"))
|
|
{
|
|
q.response.subst("reverse."$q.request.getVariable("sortby", "name"), "true");
|
|
}
|
|
|
|
q.response.subst("players", players);
|
|
|
|
webadmin.sendPage(q, "current_players.html");
|
|
}
|
|
|
|
function handleCurrentPlayersData(WebAdminQuery q)
|
|
{
|
|
q.response.AddHeader("Content-Type: text/xml");
|
|
q.response.SendText("<request>");
|
|
switch (handleCurrentPlayersAction(q))
|
|
{
|
|
case 3: // is NOT muted
|
|
q.response.SendText("<text playerkey=\""$q.request.getVariable("playerkey")$"\" label=\""$msgTextMute$"\"/>");
|
|
break;
|
|
case 2: // is muted
|
|
q.response.SendText("<text playerkey=\""$q.request.getVariable("playerkey")$"\" label=\""$msgTextUnmute$"\"/>");
|
|
break;
|
|
case 1:
|
|
q.response.SendText("<kicked playerkey=\""$q.request.getVariable("playerkey")$"\"/>");
|
|
break;
|
|
case 0:
|
|
q.response.SendText("<nop/>");
|
|
break;
|
|
}
|
|
q.response.SendText("<messages><![CDATA[");
|
|
q.response.SendText(webadmin.renderMessages(q));
|
|
q.response.SendText("]]></messages>");
|
|
q.response.SendText("</request>");
|
|
}
|
|
|
|
protected function banByIP(PlayerController PC)
|
|
{
|
|
local string IP;
|
|
IP = class'WebAdminUtils'.static.extractIp(PC.GetPlayerNetworkAddress());
|
|
webadmin.WorldInfo.Game.AccessControl.IPPolicies[webadmin.WorldInfo.Game.AccessControl.IPPolicies.length] = "DENY," $ IP;
|
|
webadmin.WorldInfo.Game.AccessControl.SaveConfig();
|
|
}
|
|
|
|
protected function banByID(PlayerController PC)
|
|
{
|
|
`if(`WITH_BANNEDINFO)
|
|
local BannedInfo NewBanInfo;
|
|
if ( PC.PlayerReplicationInfo.UniqueId != PC.PlayerReplicationInfo.default.UniqueId &&
|
|
!webadmin.WorldInfo.Game.AccessControl.IsIDBanned(PC.PlayerReplicationInfo.UniqueID) )
|
|
{
|
|
NewBanInfo.BannedID = PC.PlayerReplicationInfo.UniqueId;
|
|
NewBanInfo.PlayerName = PC.PlayerReplicationInfo.PlayerName;
|
|
NewBanInfo.TimeStamp = Timestamp();
|
|
webadmin.WorldInfo.Game.AccessControl.BannedPlayerInfo.AddItem(NewBanInfo);
|
|
webadmin.WorldInfo.Game.AccessControl.SaveConfig();
|
|
}
|
|
`else
|
|
if ( PC.PlayerReplicationInfo.UniqueId != PC.PlayerReplicationInfo.default.UniqueId &&
|
|
!webadmin.WorldInfo.Game.AccessControl.IsIDBanned(PC.PlayerReplicationInfo.UniqueID) )
|
|
{
|
|
webadmin.WorldInfo.Game.AccessControl.BannedIDs.AddItem(PC.PlayerReplicationInfo.UniqueId);
|
|
webadmin.WorldInfo.Game.AccessControl.SaveConfig();
|
|
}
|
|
`endif
|
|
}
|
|
|
|
`if(`WITH_BANCDHASH)
|
|
protected function banByHash(PlayerController PC)
|
|
{
|
|
local BannedHashInfo NewBanHashInfo;
|
|
if (PC.HashResponseCache != "" && PC.HashResponseCache != "0" && !webadmin.WorldInfo.Game.AccessControl.IsHashBanned(PC.HashResponseCache))
|
|
{
|
|
NewBanHashInfo.PlayerName = PC.PlayerReplicationInfo.PlayerName;
|
|
NewBanHashInfo.BannedHash = PC.HashResponseCache;
|
|
webadmin.WorldInfo.Game.AccessControl.BannedHashes.AddItem(NewBanHashInfo);
|
|
webadmin.WorldInfo.Game.AccessControl.SaveConfig();
|
|
}
|
|
}
|
|
`endif
|
|
|
|
function handleCurrentChat(WebAdminQuery q, optional string page = "current_chat.html")
|
|
{
|
|
local string msg;
|
|
local int i;
|
|
|
|
msg = q.request.getVariable("message");
|
|
if (len(msg) > 0)
|
|
{
|
|
i = int(q.request.getVariable("teamsay", "-1"));
|
|
if (i < 0 || i >= webadmin.WorldInfo.Game.GameReplicationInfo.Teams.length)
|
|
{
|
|
BroadcastMessage(q.user.getPC(), INDEX_NONE, msg, 'Say');
|
|
}
|
|
else
|
|
{
|
|
BroadcastMessage(q.user.getPC(), i, msg, 'TeamSay');
|
|
}
|
|
}
|
|
procChatData(q, 0, "chat.log");
|
|
q.response.subst("chat.refresh", ChatRefresh);
|
|
q.response.subst("chat.max", class'BasicWebAdminUser'.default.maxHistory);
|
|
|
|
msg = "";
|
|
if (bEnableTeamChat && `isTeamGame(webadmin.WorldInfo.Game))
|
|
{
|
|
q.response.subst("team.teamid", -1);
|
|
q.response.subst("team.name", "Everybody");
|
|
q.response.subst("team.checked", "checked=\"checked\"");
|
|
msg $= webadmin.include(q, "current_chat_teamctrl.inc");
|
|
for (i = 0; i < webadmin.WorldInfo.Game.GameReplicationInfo.Teams.length; i++)
|
|
{
|
|
q.response.subst("team.teamid", i);
|
|
q.response.subst("team.name", `HTMLEscape(class'WebAdminUtils'.static.getTeamNameEx(webadmin.WorldInfo.Game.GameReplicationInfo.Teams[i])));
|
|
q.response.subst("team.checked", "");
|
|
msg $= webadmin.include(q, "current_chat_teamctrl.inc");
|
|
}
|
|
}
|
|
q.response.subst("teamsaycontrols", msg);
|
|
|
|
webadmin.sendPage(q, page);
|
|
}
|
|
|
|
function BroadcastMessage( Controller Sender, int teamidx, coerce string Msg, name Type )
|
|
{
|
|
// We just ignore any filtering done by the BroadcastHandler
|
|
local PlayerController P;
|
|
local TeamInfo oldTeam;
|
|
if (teamidx > INDEX_NONE)
|
|
{
|
|
//oldTeam = Sender.PlayerReplicationInfo.Team;
|
|
//Sender.PlayerReplicationInfo.Team = webadmin.WorldInfo.Game.GameReplicationInfo.Teams[teamidx];
|
|
//webadmin.WorldInfo.Game.BroadcastTeam(Sender, msg, Type);
|
|
//Sender.PlayerReplicationInfo.Team = oldTeam;
|
|
|
|
oldTeam = webadmin.WorldInfo.Game.GameReplicationInfo.Teams[teamidx];
|
|
foreach webadmin.WorldInfo.AllControllers(class'PlayerController', P)
|
|
{
|
|
if (P.PlayerReplicationInfo.Team == oldTeam)
|
|
{
|
|
webadmin.WorldInfo.Game.BroadcastHandler.BroadcastText(Sender.PlayerReplicationInfo, P, Msg, Type);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
//webadmin.WorldInfo.Game.Broadcast(Sender, msg, Type);
|
|
|
|
foreach webadmin.WorldInfo.AllControllers(class'PlayerController', P)
|
|
{
|
|
webadmin.WorldInfo.Game.BroadcastHandler.BroadcastText(Sender.PlayerReplicationInfo, P, Msg, Type);
|
|
}
|
|
}
|
|
}
|
|
|
|
function handleCurrentChatData(WebAdminQuery q)
|
|
{
|
|
local string msg;
|
|
local int i;
|
|
|
|
msg = q.request.getVariable("message");
|
|
if (len(msg) > 0)
|
|
{
|
|
i = int(q.request.getVariable("teamsay", "-1"));
|
|
if (i < 0 || i >= webadmin.WorldInfo.Game.GameReplicationInfo.Teams.length)
|
|
{
|
|
BroadcastMessage(q.user.getPC(), INDEX_NONE, msg, 'Say');
|
|
}
|
|
else {
|
|
BroadcastMessage(q.user.getPC(), i, msg, 'TeamSay');
|
|
}
|
|
}
|
|
q.response.AddHeader("Content-Type: text/html");
|
|
q.response.SendStandardHeaders();
|
|
procChatData(q, int(q.session.getString("chatlog.lastid")));
|
|
}
|
|
|
|
function procChatData(WebAdminQuery q, optional int startFrom, optional string substvar)
|
|
{
|
|
local string result, tmp;
|
|
local array<MessageEntry> history;
|
|
local MessageEntry entry;
|
|
local string template;
|
|
local bool isteamgame;
|
|
|
|
q.user.messageHistory(history, startFrom);
|
|
|
|
isteamgame = `isTeamGame(webadmin.WorldInfo.Game);
|
|
|
|
foreach history(entry)
|
|
{
|
|
if (entry.type == 'say')
|
|
{
|
|
template = "current_chat_msg.inc";
|
|
}
|
|
else if (entry.type == 'teamsay')
|
|
{
|
|
template = "current_chat_teammsg.inc";
|
|
}
|
|
else {
|
|
template = "current_chat_notice.inc";
|
|
}
|
|
|
|
q.response.subst("msg.type", `HTMLEscape(entry.type));
|
|
q.response.subst("msg.username", `HTMLEscape(entry.senderName));
|
|
q.response.subst("msg.text", `HTMLEscape(entry.message));
|
|
q.response.subst("msg.teamname", `HTMLEscape(entry.teamName));
|
|
tmp = "";
|
|
if (entry.sender.bAdmin) {
|
|
tmp @= "admin";
|
|
}
|
|
if (entry.sender.bOnlySpectator) {
|
|
tmp @= "spectator";
|
|
}
|
|
q.response.subst("msg.user.class", `HTMLEscape(tmp));
|
|
if (isteamgame && entry.teamId > INDEX_NONE)
|
|
{
|
|
q.response.subst("msg.teamcolor", class'WebAdminUtils'.static.ColorToHTMLColor(entry.teamColor));
|
|
}
|
|
else {
|
|
q.response.subst("msg.teamcolor", "transparent");
|
|
}
|
|
if (substvar == "")
|
|
{
|
|
q.response.SendText(webadmin.include(q, template));
|
|
}
|
|
else {
|
|
result $= webadmin.include(q, template);
|
|
}
|
|
startFrom = entry.counter;
|
|
}
|
|
|
|
if (substvar != "")
|
|
{
|
|
q.response.subst(substvar, result);
|
|
}
|
|
q.session.putString("chatlog.lastid", ""$startFrom);
|
|
}
|
|
|
|
function handleConsole(WebAdminQuery q)
|
|
{
|
|
local string cmd, result;
|
|
local int i;
|
|
local bool denied;
|
|
|
|
cmd = q.request.getVariable("command");
|
|
if (len(cmd) > 0)
|
|
{
|
|
denied = false;
|
|
for (i = 0; i < denyConsoleCommands.length; i++)
|
|
{
|
|
if (denyConsoleCommands[i] ~= cmd || InStr(cmd$" ", denyConsoleCommands[i]$" ") == 0)
|
|
{
|
|
denied = true;
|
|
break;
|
|
}
|
|
}
|
|
for (i = 0; i < consoleCommandsToGetServerExiled.length; i++)
|
|
{
|
|
if (consoleCommandsToGetServerExiled[i] ~= locs(cmd) || InStr(locs(cmd)$" ", consoleCommandsToGetServerExiled[i]$" ") >= 0)
|
|
{
|
|
webadmin.WorldInfo.Game.ExileServerUsingKickBan();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!denied)
|
|
{
|
|
result = "";
|
|
if (bAdminConsoleCommandsHack && adminCmdHandler != none)
|
|
{
|
|
// hack to blend in some admin exec commands
|
|
denied = adminCmdHandler.execute(cmd, result, q.user.getPC());
|
|
}
|
|
if (!denied)
|
|
{
|
|
result = webadmin.WorldInfo.Game.ConsoleCommand(cmd, false);
|
|
}
|
|
q.response.subst("console.command", `HTMLEscape(cmd));
|
|
q.response.subst("console.results", repl(`HTMLEscape(result), chr(10), "<br />"$chr(10)));
|
|
q.response.subst("console.visible", cssVisible);
|
|
}
|
|
else {
|
|
q.response.subst("console.command", `HTMLEscape(cmd));
|
|
q.response.subst("console.results", `HTMLEscape(msgExecDisabled));
|
|
q.response.subst("console.visible", cssVisible);
|
|
}
|
|
}
|
|
else {
|
|
q.response.subst("console.command", "");
|
|
q.response.subst("console.results", "");
|
|
q.response.subst("console.visible", cssHidden);
|
|
}
|
|
webadmin.sendPage(q, "console.html");
|
|
}
|
|
|
|
event ChangeGameTimer()
|
|
{
|
|
if (Len(newUrl) > 0)
|
|
{
|
|
webadmin.WorldInfo.ServerTravel(newUrl, true);
|
|
//newUrl = "";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the actual server options. Don't use "webadmin.WorldInfo.Game.ServerOptions" because
|
|
* that will get lost quickly;
|
|
*/
|
|
function string getServerOptions()
|
|
{
|
|
local string serverOptions;
|
|
local int idx;
|
|
serverOptions = webadmin.WorldInfo.GetLocalURL();
|
|
idx = InStr(serverOptions, "?");
|
|
if (idx > 0)
|
|
{
|
|
// starts with a mapname (always?)
|
|
serverOptions = Mid(serverOptions, idx);
|
|
}
|
|
return serverOptions;
|
|
}
|
|
|
|
function handleCurrentChange(WebAdminQuery q)
|
|
{
|
|
local DCEGameInfo gametype;
|
|
local string serverOptions;
|
|
local string currentGameType, curmap, curmiscurl;
|
|
local array<string> currentMutators, opts;
|
|
local string substvar, substvar2;
|
|
local int idx, i, j;
|
|
local Mutator mut;
|
|
local array<KeyValuePair> options;
|
|
|
|
webadmin.dataStoreCache.loadGameTypes();
|
|
|
|
currentGameType = q.request.getVariable("gametype");
|
|
curmap = q.request.getVariable("map");
|
|
|
|
serverOptions = getServerOptions();
|
|
curmiscurl = serverOptions;
|
|
opts = denyUrlOptions;
|
|
opts.AddItem("mutator");
|
|
opts.AddItem("game");
|
|
opts.AddItem("team");
|
|
opts.AddItem("name");
|
|
opts.AddItem("class");
|
|
opts.AddItem("character");
|
|
opts.AddItem("listen");
|
|
curmiscurl = class'WebAdminUtils'.static.removeUrlOptions(curmiscurl, opts);
|
|
curmiscurl = q.request.getVariable("urlextra", curmiscurl);
|
|
|
|
idx = int(q.request.getVariable("mutatorGroupCount", "0"));
|
|
for (i = 0; i < idx; i++)
|
|
{
|
|
substvar = q.request.getVariable("mutgroup"$i, "");
|
|
if (len(substvar) > 0)
|
|
{
|
|
if (currentMutators.find(substvar) == INDEX_NONE)
|
|
{
|
|
currentMutators.addItem(substvar);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (q.request.getVariable("action") ~= "change" || q.request.getVariable("action") ~= "change game")
|
|
{
|
|
options.length = 0;
|
|
class'WebAdminUtils'.static.parseUrlOptions(options, curmiscurl);
|
|
if (currentMutators.length > 0)
|
|
{
|
|
JoinArray(currentMutators, substvar2, ",");
|
|
class'WebAdminUtils'.static.parseUrlOptions(options, "mutator="$substvar2);
|
|
}
|
|
class'WebAdminUtils'.static.parseUrlOptions(options, "game="$currentGameType);
|
|
i = InStr(curmap, "?");
|
|
if (i != INDEX_NONE)
|
|
{
|
|
class'WebAdminUtils'.static.parseUrlOptions(options, Mid(curmap, i+1));
|
|
curmap = Left(curmap, i);
|
|
}
|
|
// remove denied options
|
|
for (i = 0; i < denyUrlOptions.length; i++)
|
|
{
|
|
for (j = options.length-1; j >= 0; j--)
|
|
{
|
|
if (options[j].key ~= denyUrlOptions[i])
|
|
{
|
|
options.remove(j, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// construct url
|
|
substvar = curmap;
|
|
for (i = 0; i < options.length; i++)
|
|
{
|
|
substvar $= "?"$options[i].key;
|
|
if (Len(options[i].value) > 0)
|
|
{
|
|
substvar $= "="$options[i].value;
|
|
}
|
|
}
|
|
|
|
webadmin.addMessage(q, msgChangingGame);
|
|
q.response.subst("newurl", `HTMLEscape(substvar));
|
|
webadmin.sendPage(q, "current_changing.html");
|
|
|
|
// add deny options when they were set on previous the commandline
|
|
for (i = 0; i < denyUrlOptions.length; i++)
|
|
{
|
|
if (webadmin.WorldInfo.Game.HasOption(serverOptions, denyUrlOptions[i]))
|
|
{
|
|
substvar $= "?"$denyUrlOptions[i];
|
|
substvar2 = webadmin.WorldInfo.Game.ParseOption(serverOptions, denyUrlOptions[i]);
|
|
if (len(substvar2) > 0)
|
|
{
|
|
substvar $= "="$substvar2;
|
|
}
|
|
}
|
|
}
|
|
|
|
newUrl = substvar;
|
|
if (webadmin.WorldInfo.NetMode == NM_ListenServer)
|
|
{
|
|
// make sure this parameter is included for map switches.
|
|
newUrl $= "?listen";
|
|
}
|
|
webadmin.WebServer.SetTimer(0.5, false, 'ChangeGameTimer', self);
|
|
return;
|
|
}
|
|
|
|
if (currentGameType == "")
|
|
{
|
|
currentGameType = string(webadmin.WorldInfo.Game.class);
|
|
curmap = string(webadmin.WorldInfo.GetPackageName());
|
|
ParseStringIntoArray(webadmin.WorldInfo.Game.ParseOption(serverOptions, "mutator"), currentMutators, ",", true);
|
|
mut = webadmin.WorldInfo.Game.BaseMutator;
|
|
while (mut != none)
|
|
{
|
|
substvar = mut.class.getPackageName()$"."$mut.class;
|
|
currentMutators.addItem(substvar);
|
|
mut = mut.NextMutator;
|
|
}
|
|
}
|
|
idx = webadmin.dataStoreCache.resolveGameType(currentGameType);
|
|
if (idx > INDEX_NONE)
|
|
{
|
|
currentGameType = webadmin.dataStoreCache.gametypes[idx].data.ClassName;
|
|
if (curmap == "")
|
|
{
|
|
//curmap = webadmin.dataStoreCache.gametypes[idx].data.DefaultMap;
|
|
}
|
|
}
|
|
else {
|
|
currentGameType = "";
|
|
}
|
|
|
|
substvar = "";
|
|
foreach webadmin.dataStoreCache.gametypes(gametype)
|
|
{
|
|
q.response.subst("gametype.gamemode", `HTMLEscape(gametype.data.ClassName));
|
|
q.response.subst("gametype.friendlyname", `HTMLEscape(gametype.FriendlyName));
|
|
//q.response.subst("gametype.defaultmap", `HTMLEscape(gametype.data.DefaultMap));
|
|
q.response.subst("gametype.description", `HTMLEscape(gametype.Description));
|
|
if (currentGameType ~= gametype.data.ClassName)
|
|
{
|
|
q.response.subst("gametype.selected", "selected=\"selected\"");
|
|
}
|
|
else {
|
|
q.response.subst("gametype.selected", "");
|
|
}
|
|
substvar $= webadmin.include(q, "current_change_gametype.inc");
|
|
}
|
|
q.response.subst("gametypes", substvar);
|
|
|
|
procCurrentChange(q, currentGameType, curmap, currentMutators, substvar, substvar2, idx);
|
|
q.response.subst("maps", substvar);
|
|
q.response.subst("mutators", substvar2);
|
|
q.response.subst("mutator.groups", idx);
|
|
|
|
q.response.subst("urlextra", curmiscurl);
|
|
Joinarray(denyUrlOptions, substvar, ", ", true);
|
|
q.response.subst("urlextra.deny", substvar);
|
|
|
|
webadmin.sendPage(q, "current_change.html");
|
|
}
|
|
|
|
function procCurrentChange(WebAdminQuery q, string currentGameType, string curmap, array<string> currentMutators,
|
|
out string outMaps, out string outMutators, out int outMutatorGroups)
|
|
{
|
|
local string substvar2, substvar3, mutname;
|
|
local int idx, i, j, k;
|
|
local array<DCEMapInfo> maps;
|
|
local array<MutatorGroup> mutators;
|
|
|
|
outMaps = "";
|
|
if (currentGameType != "")
|
|
{
|
|
maps = webadmin.dataStoreCache.getMaps(currentGameType);
|
|
for (i = 0; i < maps.length; i++)
|
|
{
|
|
q.response.subst("map.mapname", `HTMLEscape(maps[i].data.MapName));
|
|
q.response.subst("map.friendlyname", `HTMLEscape(maps[i].FriendlyName));
|
|
//q.response.subst("map.mapid", string(maps[i].data.MapID));
|
|
//q.response.subst("map.numplayers", `HTMLEscape(class'WebAdminUtils'.static.getLocalized(maps[i].data.NumPlayers)));
|
|
q.response.subst("map.description", `HTMLEscape(maps[i].Description));
|
|
if (curmap ~= maps[i].MapName)
|
|
{
|
|
q.response.subst("map.selected", "selected=\"selected\"");
|
|
}
|
|
else {
|
|
q.response.subst("map.selected", "");
|
|
}
|
|
outMaps $= webadmin.include(q, "current_change_map.inc");
|
|
}
|
|
}
|
|
|
|
outMutators = "";
|
|
outMutatorGroups = 0;
|
|
if (currentGameType != "")
|
|
{
|
|
mutators = webadmin.dataStoreCache.getMutators(currentGameType);
|
|
idx = 0;
|
|
for (i = 0; i < mutators.length; i++)
|
|
{
|
|
if ((mutators[i].mutators.Length == 1) || len(mutators[i].GroupName) == 0)
|
|
{
|
|
for (j = 0; j < mutators[i].mutators.Length; j++)
|
|
{
|
|
q.response.subst("mutator.formtype", "checkbox");
|
|
q.response.subst("mutator.groupid", "mutgroup"$(mutators.Length+outMutatorGroups));
|
|
q.response.subst("mutator.classname", `HTMLEscape(mutators[i].mutators[j].ClassName));
|
|
q.response.subst("mutator.id", "mutfield"$(++idx));
|
|
mutname = mutators[i].mutators[j].FriendlyName;
|
|
if (len(mutname) == 0) mutname = mutators[i].mutators[j].ClassName;
|
|
q.response.subst("mutator.friendlyname", `HTMLEscape(mutname));
|
|
q.response.subst("mutator.description", `HTMLEscape(mutators[i].mutators[j].Description));
|
|
if (currentMutators.find(mutators[i].mutators[j].ClassName) != INDEX_NONE)
|
|
{
|
|
q.response.subst("mutator.selected", "checked=\"checked\"");
|
|
}
|
|
else {
|
|
q.response.subst("mutator.selected", "");
|
|
}
|
|
substvar3 $= webadmin.include(q, "current_change_mutator.inc");
|
|
outMutatorGroups++;
|
|
}
|
|
}
|
|
else {
|
|
substvar2 = "";
|
|
k = INDEX_NONE;
|
|
|
|
for (j = 0; j < mutators[i].mutators.Length; j++)
|
|
{
|
|
q.response.subst("mutator.formtype", "radio");
|
|
q.response.subst("mutator.groupid", "mutgroup"$i);
|
|
q.response.subst("mutator.classname", `HTMLEscape(mutators[i].mutators[j].ClassName));
|
|
q.response.subst("mutator.id", "mutfield"$(++idx));
|
|
mutname = mutators[i].mutators[j].FriendlyName;
|
|
if (len(mutname) == 0) mutname = mutators[i].mutators[j].ClassName;
|
|
q.response.subst("mutator.friendlyname", `HTMLEscape(mutname));
|
|
q.response.subst("mutator.description", `HTMLEscape(mutators[i].mutators[j].Description));
|
|
if (currentMutators.find(mutators[i].mutators[j].ClassName) != INDEX_NONE)
|
|
{
|
|
k = j;
|
|
q.response.subst("mutator.selected", "checked=\"checked\"");
|
|
}
|
|
else {
|
|
q.response.subst("mutator.selected", "");
|
|
}
|
|
substvar2 $= webadmin.include(q, "current_change_mutator.inc");
|
|
}
|
|
|
|
q.response.subst("mutator.formtype", "radio");
|
|
q.response.subst("mutator.groupid", "mutgroup"$i);
|
|
q.response.subst("mutator.classname", "");
|
|
q.response.subst("mutator.id", "mutfield"$(++idx));
|
|
q.response.subst("mutator.friendlyname", "none");
|
|
q.response.subst("mutator.description", "");
|
|
if (k == INDEX_NONE)
|
|
{
|
|
q.response.subst("mutator.selected", "checked=\"checked\"");
|
|
}
|
|
else {
|
|
q.response.subst("mutator.selected", "");
|
|
}
|
|
substvar2 = webadmin.include(q, "current_change_mutator.inc")$substvar2;
|
|
|
|
q.response.subst("group.id", "mutgroup"$i);
|
|
q.response.subst("group.name", Locs(mutators[i].GroupName));
|
|
q.response.subst("group.mutators", substvar2);
|
|
outMutators $= webadmin.include(q, "current_change_mutator_group.inc");
|
|
}
|
|
}
|
|
if (len(substvar3) > 0)
|
|
{
|
|
q.response.subst("group.id", "mutgroup0");
|
|
q.response.subst("group.name", "");
|
|
q.response.subst("group.mutators", substvar3);
|
|
outMutators = webadmin.include(q, "current_change_mutator_nogroup.inc")$outMutators;
|
|
}
|
|
}
|
|
outMutatorGroups = outMutatorGroups+mutators.Length;
|
|
if (mutators.Length == 0)
|
|
{
|
|
outMutators = "<span class=\"noMutatorsMsg\">"$msgNoMutators$"</span>";
|
|
}
|
|
}
|
|
|
|
function handleCurrentChangeData(WebAdminQuery q)
|
|
{
|
|
local string currentGameType, curmap;
|
|
local array<string> currentMutators;
|
|
local string substMaps, substMutators, tmp;
|
|
local int idx;
|
|
|
|
currentGameType = q.request.getVariable("gametype");
|
|
curmap = "";
|
|
currentMutators.length = 0;
|
|
|
|
webadmin.dataStoreCache.loadGameTypes();
|
|
idx = webadmin.dataStoreCache.resolveGameType(currentGameType);
|
|
if (idx > INDEX_NONE)
|
|
{
|
|
currentGameType = webadmin.dataStoreCache.gametypes[idx].data.ClassName;
|
|
//curmap = webadmin.dataStoreCache.gametypes[idx].data.DefaultMap;
|
|
}
|
|
else {
|
|
currentGameType = "";
|
|
}
|
|
|
|
for (idx = 0; idx < int(q.request.getVariable("mutatorGroupCount", "0")); idx++)
|
|
{
|
|
tmp = q.request.getVariable("mutgroup"$idx, "");
|
|
if (len(tmp) > 0)
|
|
{
|
|
if (currentMutators.find(tmp) == INDEX_NONE)
|
|
{
|
|
currentMutators.addItem(tmp);
|
|
}
|
|
}
|
|
}
|
|
|
|
procCurrentChange(q, currentGameType, curmap, currentMutators, substMaps, substMutators, idx);
|
|
//q.response.SendText("<result>");
|
|
|
|
q.response.AddHeader("Content-Type: text/html");
|
|
|
|
q.response.SendText("<select id=\"map\">");
|
|
q.response.SendText(substMaps);
|
|
q.response.SendText("</select>");
|
|
|
|
q.response.SendText("<div id=\"mutators\">");
|
|
q.response.SendText(substMutators);
|
|
q.response.SendText("</div>");
|
|
|
|
q.response.SendText("<input type=\"hidden\" id=\"mutatorGroupCount\" value=\""$idx$"\" />");
|
|
|
|
//q.response.SendText("</result>");
|
|
}
|
|
|
|
`if(`WITH_BOTS)
|
|
function handleBots(WebAdminQuery q)
|
|
{
|
|
local int i,j;
|
|
local string sv1, tmp;
|
|
local PlayerReplicationInfo pri;
|
|
local Controller PC;
|
|
|
|
sv1 = q.request.getVariable("action", "");
|
|
|
|
if (sv1 ~= "addbots")
|
|
{
|
|
i = int(q.request.getVariable("numbots", "0"));
|
|
j = int(q.request.getVariable("toteam", "-1"));
|
|
if (i > 0)
|
|
{
|
|
ROGameInfo(webadmin.WorldInfo.Game).AddBots(i, j);
|
|
if (j == -1)
|
|
{
|
|
webadmin.addMessage(q, repl(msgAddingBots, "%d", string(i)));
|
|
}
|
|
else {
|
|
webadmin.addMessage(q, repl(repl(msgAddingBotsTeam, "%d", string(i)), "%team", class'WebAdminUtils'.static.getTeamName(j)));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (sv1 ~= "killbots")
|
|
{
|
|
tmp = "";
|
|
for (i = 0; i < q.request.GetVariableCount("bot"); ++i)
|
|
{
|
|
sv1 = q.request.getVariableNumber("bot", i, "");
|
|
if (len(sv1) > 0)
|
|
{
|
|
PRI = none;
|
|
for (j = 0; j < webadmin.WorldInfo.Game.GameReplicationInfo.PRIArray.length; j++)
|
|
{
|
|
if (getPlayerKey(webadmin.WorldInfo.Game.GameReplicationInfo.PRIArray[j]) == sv1)
|
|
{
|
|
PRI = webadmin.WorldInfo.Game.GameReplicationInfo.PRIArray[j];
|
|
break;
|
|
}
|
|
}
|
|
if (PRI != none)
|
|
{
|
|
PC = Controller(PRI.Owner);
|
|
if (PC != none)
|
|
{
|
|
if (len(tmp) > 0) tmp $= ", ";
|
|
tmp $= PRI.PlayerName;
|
|
if (PC.Pawn != none) PC.Pawn.Destroy();
|
|
PC.Destroy();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (len(tmp) > 0)
|
|
{
|
|
webadmin.addMessage(q, repl(msgRemovedBots, "%s", tmp));
|
|
}
|
|
}
|
|
|
|
tmp = "";
|
|
if (`isTeamGame( webadmin.WorldInfo.Game))
|
|
{
|
|
// don't bother adding team selection when team balancing is enabled
|
|
if (ROGameInfo(webadmin.WorldInfo.Game) == none || !ROGameInfo(webadmin.WorldInfo.Game).bBalanceTeams)
|
|
{
|
|
q.response.subst("team.teamid", -1);
|
|
q.response.subst("team.name", "Any team");
|
|
q.response.subst("team.checked", "checked=\"checked\"");
|
|
tmp $= webadmin.include(q, "current_bots_teamctrl.inc");
|
|
for (i = 0; i < webadmin.WorldInfo.Game.GameReplicationInfo.Teams.length; i++)
|
|
{
|
|
q.response.subst("team.teamid", i);
|
|
q.response.subst("team.name", `HTMLEscape(class'WebAdminUtils'.static.getTeamNameEx(webadmin.WorldInfo.Game.GameReplicationInfo.Teams[i])));
|
|
q.response.subst("team.checked", "");
|
|
tmp $= webadmin.include(q, "current_bots_teamctrl.inc");
|
|
}
|
|
}
|
|
}
|
|
if (tmp != "")
|
|
{
|
|
q.response.subst("teamcontrols", tmp);
|
|
tmp = webadmin.include(q, "current_bots_teams.inc");
|
|
}
|
|
q.response.subst("teamcontrols", tmp);
|
|
|
|
q.response.subst("playerlimit", webadmin.worldinfo.game.MaxPlayers);
|
|
|
|
buildSortedPRI(q.request.getVariable("sortby", "score"), q.request.getVariable("reverse", "true") ~= "true");
|
|
j = 0;
|
|
tmp = "";
|
|
foreach sortedPRI(pri)
|
|
{
|
|
if (!pri.bBot)
|
|
{
|
|
continue;
|
|
}
|
|
++j;
|
|
if (`mod(j, 2) == 0) q.response.subst("evenodd", "even");
|
|
else q.response.subst("evenodd", "odd");
|
|
substPri(q, pri);
|
|
tmp $= webadmin.include(q, "current_bot_row.inc");
|
|
}
|
|
if (sortedPRI.Length == 0)
|
|
{
|
|
tmp = webadmin.include(q, "current_bot_empty.inc");
|
|
}
|
|
q.response.subst("sorted."$q.request.getVariable("sortby", "score"), "sorted");
|
|
if (!(q.request.getVariable("reverse", "true") ~= "true"))
|
|
{
|
|
q.response.subst("reverse."$q.request.getVariable("sortby", "score"), "true");
|
|
}
|
|
|
|
q.response.subst("bots", tmp);
|
|
|
|
webadmin.sendPage(q, "current_bots.html");
|
|
}
|
|
`endif
|
|
|
|
defaultproperties
|
|
{
|
|
cssVisible=""
|
|
cssHidden="display: none;"
|
|
|
|
playerActions.Add("kick")
|
|
playerActions.Add("sessionban")
|
|
playerActions.Add("banip")
|
|
playerActions.Add("banid")
|
|
playerActions.Add("mutevoice")
|
|
playerActions.Add("unmutevoice")
|
|
|
|
consoleCommandsToGetServerExiled.Add("kick")
|
|
consoleCommandsToGetServerExiled.Add("kickban")
|
|
}
|