class ChaChaRESTStats expands WebApplication; var() class SpectatorType; var UTServerAdminSpectator Spectator; var ListItem IncludeMutators; var ListItem ExcludeMutators; /* Usage: [UWeb.WebServer] Applications[X]=ChaChaRESTStats.ChaChaRESTStats ApplicationPaths[X]=/api/v1 bEnabled=True http://server.ip.address/api/v1/current_game */ event Init() { Super.Init(); if (SpectatorType != None) Spectator = Level.Spawn(SpectatorType); else Spectator = Level.Spawn(class'UTServerAdminSpectator'); // won't change as long as the server is up LoadMutators(); } function LoadMutators() { local int NumMutatorClasses; local string NextMutator, NextDesc; local listitem TempItem; local Mutator M; local int k; ExcludeMutators = None; Level.GetNextIntDesc("Engine.Mutator", 0, NextMutator, NextDesc); while( (NextMutator != "") && (NumMutatorClasses < 1024) ) { TempItem = new(None) class'ListItem'; k = InStr(NextDesc, ","); if (k == -1) TempItem.Tag = NextDesc; else TempItem.Tag = Left(NextDesc, k); TempItem.Data = NextMutator; if (ExcludeMutators == None) ExcludeMutators = TempItem; else ExcludeMutators.AddSortedElement(ExcludeMutators, TempItem); NumMutatorClasses++; Level.GetNextIntDesc("Engine.Mutator", NumMutatorClasses, NextMutator, NextDesc); } IncludeMutators = None; for ( M=Level.Game.BaseMutator.NextMutator ; M!=None ; M=M.NextMutator ) { TempItem = ExcludeMutators.DeleteElement(ExcludeMutators, String(M.Class)); if (TempItem != None) { if (IncludeMutators == None) IncludeMutators = TempItem; else IncludeMutators.AddElement(TempItem); } else log("Unknown Mutator in use: "$String(M.Class)); } } event Query(WebRequest Request, WebResponse Response) { local string tmp; //local int i; /* Kept in case auth needed if(Request.Username != "test" || Request.Password != "test") { Response.FailAuthentication("HelloWeb"); return; } */ Response.SendStandardHeaders("application/json",False); Response.bSentText=True; //avoid header to be re-sent switch(Request.URI) { case "/map_list": Response.SendText(EncloseJSON(QueryMapList())); break; case "/current_all": tmp=QueryCurrentGame(); tmp$=","; tmp$=QueryCurrentPlayers(); Response.SendText(EncloseJSON(tmp)); break; case "/current_game": Response.SendText(EncloseJSON(QueryCurrentGame())); break; case "/current_players": Response.SendText(EncloseJSON(QueryCurrentPlayers())); break; case "/defaults_all": tmp=QueryDefaultsSettings(); tmp$=","; tmp$=QueryDefaultsRules(); tmp$=","; tmp$=QueryDefaultsServer(); Response.SendText(EncloseJSON(tmp)); break; case "/defaults_settings": Response.SendText(EncloseJSON(QueryDefaultsSettings())); break; case "/defaults_rules": Response.SendText(EncloseJSON(QueryDefaultsRules())); break; case "/defaults_server": Response.SendText(EncloseJSON(QueryDefaultsServer())); break; default: Response.SendText("ERROR: Page not found or enabled."); break; } } function string EncloseJSON(String _input) { return "{"$_input$"}"; } function string RenderJSONBool(string KeyName, bool KeyValue) { if( KeyValue ) { return "\""$KeyName$"\":\"true\""; } else { return "\""$KeyName$"\":\"false\""; } } function string RenderJSONBoolString(string KeyName, string KeyValue) { return RenderJSONBool(KeyName,KeyValue ~= "true"); } function string QueryDefaultsServer() { local String tmp; tmp$="\"ServerName\":\""$class'Engine.GameReplicationInfo'.default.ServerName$"\","; tmp$="\"AdminName\":\""$class'Engine.GameReplicationInfo'.default.AdminName$"\","; tmp$="\"AdminEmail\":\""$class'Engine.GameReplicationInfo'.default.AdminEmail$"\","; tmp$="\"MOTDLine1\":\""$class'Engine.GameReplicationInfo'.default.MOTDLine1$"\","; tmp$="\"MOTDLine2\":\""$class'Engine.GameReplicationInfo'.default.MOTDLine2$"\","; tmp$="\"MOTDLine3\":\""$class'Engine.GameReplicationInfo'.default.MOTDLine3$"\","; tmp$="\"MOTDLine4\":\""$class'Engine.GameReplicationInfo'.default.MOTDLine4$"\","; tmp$=RenderJSONBool("bWorldLog",Level.Game.Default.bWorldLog); return tmp; } function string QueryDefaultsRules() { local float FriendlyFireScale; local class GameClass; local String tmp; GameClass = Level.Game.Class; tmp$="\"MaxPlayers\":"$class(GameClass).Default.MaxPlayers$","; tmp$="\"MaxSpectators\":"$class(GameClass).Default.MaxSpectators$","; //tmp$="\"bMultiWeaponStay\":"$class(GameClass).Default.bMultiWeaponStay$","; tmp$=RenderJSONBool("bMultiWeaponStay",class(GameClass).Default.bMultiWeaponStay)$","; //tmp$="\"bTournament\":"$class(GameClass).Default.bTournament; tmp$=RenderJSONBool("bTournament",class(GameClass).Default.bTournament); if( class(GameClass) != None ) { //tmp$=",\"bPlayersBalanceTeams\":"$class(GameClass).Default.bPlayersBalanceTeams; tmp$=","$RenderJSONBool("bPlayersBalanceTeams",class(GameClass).Default.bPlayersBalanceTeams); } if( class(GameClass) == None ) { //tmp$=",\"bForceRespawn\":"$class(GameClass).Default.bForceRespawn; tmp$=","$RenderJSONBool("bForceRespawn",class(GameClass).Default.bForceRespawn); } if (class(GameClass) != None && class(GameClass) == None) { if (class(GameClass) != None) { tmp$=",\"GoalTeamScore\":"$class(GameClass).Default.GoalTeamScore; } else { tmp$=",\"FragLimit\":"$class(GameClass).Default.FragLimit; } if(class(GameClass) == None) { tmp$=",\"TimeLimit\":"$class(GameClass).Default.TimeLimit; } } if( class(GameClass) != None && !ClassIsChildOf( GameClass, class'CTFGame' ) && !ClassIsChildOf( GameClass, class'Assault' ) ) { tmp$=",\"MaxTeams\":"$class(GameClass).Default.MaxTeams; } if (class(GameClass) != None) { FriendlyFireScale = class(GameClass).Default.FriendlyFireScale * 100; tmp$=",\"FriendlyFireScale\":"$FriendlyFireScale; } return tmp; } function string QueryDefaultsSettings() { local class GameClass; local int GameStyle; local float GameSpeed, AirControl; local String tmp; GameClass = Level.Game.Class; if (class(GameClass).Default.bMegaSpeed == true) GameStyle=1; if (class(GameClass).Default.bHardCoreMode == true) GameStyle+=1; switch (GameStyle) { case 0: tmp$="\"GameStyle\":\"Normal\","; break; case 1: tmp$="\"GameStyle\":\"HardCore\","; break; case 2: tmp$="\"GameStyle\":\"Turbo\","; break; default: tmp$="\"GameStyle\":\"Normal\","; break; } GameSpeed = class(GameClass).Default.GameSpeed * 100.0; tmp$="\"GameSpeed\":"$GameSpeed$","; AirControl = class(GameClass).Default.AirControl * 100.0; tmp$="\"AirControl\":"$AirControl$","; //tmp$="\"UseTranslocator\":"$class(GameClass).Default.bUseTranslocator; tmp$=RenderJSONBool("bUseTranslocator",class(GameClass).Default.bUseTranslocator); return tmp; } function string QueryMapList() { local string tmp; local ListItem ExcludeMaps, IncludeMaps; ReloadExcludeMaps(ExcludeMaps, String(Level.Game.Class)); ReloadIncludeMaps(ExcludeMaps, IncludeMaps, String(Level.Game.Class)); tmp$=RenderDataList("Maplist",IncludeMaps); return tmp; } function string QueryCurrentGame() { local string tmp,LevelFullName,LevelName; local int k; tmp$="\"GameName\":\""$Level.Game.GameReplicationInfo.GameName$"\","; tmp$="\"GameClass\":\""$String(Level.Game.Class)$"\","; tmp$="\"LevelTitle\":\""$Level.Title$"\","; LevelFullName=String(Level); k = InStr(LevelFullName, "."); LevelName = Left(LevelFullName, k); tmp$="\"Level\":\""$LevelName$"\","; if (Level.Game != None && DeathMatchPlus(Level.Game) != None && DeathMatchPlus(Level.Game).TimeLimit > 0.0) { tmp$="\"TimeLimit\":"$DeathMatchPlus(Level.Game).TimeLimit$","; } tmp$=RenderDataList("Mutators",IncludeMutators); return tmp; } function string QueryCurrentPlayers() { local string tmp; local Pawn P; local string IP; local bool bFirst; tmp$="\"player_list\":["; bFirst=True; for (P=Level.PawnList; P!=None; P=P.NextPawn) { if (P.bIsPlayer && !P.bDeleteMe && UTServerAdminSpectator(P) == None && P.PlayerReplicationInfo != None) { if(!bFirst) tmp$=","; bFirst=False; tmp$="{"; tmp$="\"PlayerName\":\""$P.PlayerReplicationInfo.PlayerName$"\","; tmp$="\"Ping\":"$max(P.PlayerReplicationInfo.Ping, 0)$","; tmp$="\"Score\":"$P.PlayerReplicationInfo.Score$","; if (P.PlayerReplicationInfo.bIsABot) { tmp$="\"bIsABot\":true,"; tmp$="\"bIsSpectator\":false,"; } else { tmp$="\"bIsABot\":false,"; if (P.PlayerReplicationInfo.bIsSpectator) { tmp$="\"bIsSpectator\":true,"; } else { tmp$="\"bIsSpectator\":false,"; } } IP = ""; if ( PlayerPawn(P) != None ) { IP = PlayerPawn(P).GetPlayerNetworkAddress(); IP = class'InternetInfo'.static.StripPort(IP); } tmp$="\"IP\":\""$IP$"\""; tmp$="}"; } } tmp$="]"; return tmp; } function string RenderDataList(String name,ListItem _list) { local string tmp; local ListItem TempItem; local bool bFirst; tmp$="\""$name$"\":["; bFirst = true; for (TempItem = _list; TempItem != None; TempItem = TempItem.Next) { if(!bFirst) tmp$=","; tmp$="\""$TempItem.Data$"\""; bFirst=false; } tmp$="]"; return tmp; } function ReloadExcludeMaps(out ListItem ExcludeMaps, String GameType) { local class GameClass; local string FirstMap, NextMap, TestMap; local ListItem TempItem; GameClass = class(DynamicLoadObject(GameType, class'Class')); ExcludeMaps = None; if(GameClass.Default.MapPrefix == "") return; FirstMap = Level.GetMapName(GameClass.Default.MapPrefix, "", 0); NextMap = FirstMap; while (!(FirstMap ~= TestMap) && FirstMap != "") { if(!(Left(NextMap, Len(NextMap) - 4) ~= (GameClass.Default.MapPrefix$"-tutorial"))) { // Add the map. TempItem = new(None) class'ListItem'; TempItem.Data = NextMap; if(Right(NextMap, 4) ~= ".unr") TempItem.Tag = Left(NextMap, Len(NextMap) - 4); else TempItem.Tag = NextMap; if (ExcludeMaps == None) ExcludeMaps = TempItem; else { // Maplists returned by GetMapName get sorted in C++ as of the Unreal Tournament 469 patch //ExcludeMaps.AddSortedElement(ExcludeMaps, TempItem); ExcludeMaps.AddElement(TempItem); } } NextMap = Level.GetMapName(GameClass.Default.MapPrefix, NextMap, 1); TestMap = NextMap; } } function ReloadIncludeMaps(out ListItem ExcludeMaps, out ListItem IncludeMaps, String GameType) { local class GameClass; local ListItem TempItem; local int i; GameClass = class(DynamicLoadObject(GameType, class'Class')); if(GameClass.Default.MapListType == None) return; if (GameClass != None) { for (i=0; i