1
0
mirror of https://github.com/RaidMax/IW4M-Admin.git synced 2025-06-11 15:52:25 -05:00

Branch for IW4X practically everything refactored

This commit is contained in:
RaidMax
2017-05-26 17:49:27 -05:00
parent 85a658b987
commit 10075b0d3f
107 changed files with 7426 additions and 3995 deletions

View File

@ -1,700 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using SharedLibrary;
namespace IW4MAdmin
{
class Owner : Command
{
public Owner(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
if (E.Owner.clientDB.getOwner() == null)
{
E.Origin.setLevel(Player.Permission.Owner);
E.Origin.Tell("Congratulations, you have claimed ownership of this server!");
E.Owner.owner = E.Origin;
E.Owner.clientDB.updatePlayer(E.Origin);
}
else
E.Origin.Tell("This server already has an owner!");
}
}
class Warn : Command
{
public Warn(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
E.Target.lastOffense = SharedLibrary.Utilities.removeWords(E.Data, 1);
if (E.Origin.Level <= E.Target.Level)
E.Origin.Tell("You cannot warn " + E.Target.Name);
else
{
E.Target.Warn(E.Target.lastOffense, E.Origin);
}
}
}
class WarnClear : Command
{
public WarnClear(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
E.Target.lastOffense = String.Empty;
E.Target.Warnings = 0;
String Message = String.Format("All warning cleared for {0}", E.Target.Name);
E.Owner.Broadcast(Message);
}
}
class Kick : Command
{
public Kick(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
E.Target.lastOffense = SharedLibrary.Utilities.removeWords(E.Data, 1);
if (E.Origin.Level > E.Target.Level)
E.Target.Kick(E.Target.lastOffense, E.Origin);
else
E.Origin.Tell("You cannot kick " + E.Target.Name);
}
}
class Say : Command
{
public Say(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
E.Owner.Broadcast("^1" + E.Origin.Name + " - ^6" + E.Data + "^7");
}
}
class TempBan : Command
{
public TempBan(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
E.Target.lastOffense = SharedLibrary.Utilities.removeWords(E.Data, 1);
String Message = "^1Player Temporarily Banned: ^5" + E.Target.lastOffense + "^7 (1 hour)";
if (E.Origin.Level > E.Target.Level)
E.Target.tempBan(Message, E.Origin);
else
E.Origin.Tell("You cannot temp ban " + E.Target.Name);
}
}
class SBan : Command
{
public SBan(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
E.Target.lastOffense = SharedLibrary.Utilities.removeWords(E.Data, 1);
E.Target.lastEvent = E; // needs to be fixed
String Message;
if (E.Owner.Website == null)
Message = "^1Player Banned: ^5" + E.Target.lastOffense;
else
Message = "^1Player Banned: ^5" + E.Target.lastOffense + "^7 (appeal at" + E.Owner.Website + ")";
if (E.Origin.Level > E.Target.Level)
{
E.Target.Ban(Message, E.Origin);
E.Origin.Tell(String.Format("Sucessfully banned ^5{0} ^7({1})", E.Target.Name, E.Target.npID));
}
else
E.Origin.Tell("You cannot ban " + E.Target.Name);
}
}
class Unban : Command
{
public Unban(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
if (E.Owner.Unban(E.Data.Trim(), E.Target))
E.Origin.Tell("Successfully unbanned " + E.Target.Name);
else
E.Origin.Tell("Unable to find a ban for that GUID");
}
}
class WhoAmI : Command
{
public WhoAmI(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
String You = String.Format("{0} [^3#{1}^7] {2} [^3@{3}^7] [{4}^7] IP: {5}", E.Origin.Name, E.Origin.clientID, E.Origin.npID, E.Origin.databaseID, SharedLibrary.Utilities.levelToColor(E.Origin.Level), E.Origin.IP);
E.Origin.Tell(You);
}
}
class List : Command
{
public List(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
StringBuilder playerList = new StringBuilder();
lock (E.Owner.getPlayers())
{
int count = 0;
foreach (Player P in E.Owner.getPlayers())
{
if (P == null)
continue;
playerList.AppendFormat("[^3{0}^7]{3}[^3{1}^7] {2}", SharedLibrary.Utilities.levelToColor(P.Level), P.clientID, P.Name, SharedLibrary.Utilities.getSpaces(Player.Permission.SeniorAdmin.ToString().Length - P.Level.ToString().Length));
if (count == 2)
{
E.Origin.Tell(playerList.ToString());
count = 0;
playerList = new StringBuilder();
continue;
}
count++;
}
}
}
}
class Help : Command
{
public Help(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
String cmd = E.Data.Trim();
if (cmd.Length > 2)
{
bool found = false;
foreach (Command C in E.Owner.getCommands())
{
if (C.Name.Contains(cmd) || C.Name == cmd)
{
E.Origin.Tell(" [^3" + C.Name + "^7] " + C.Description);
found = true;
}
}
if (!found)
E.Origin.Tell("Could not find that command");
}
else
{
int count = 0;
StringBuilder helpResponse = new StringBuilder();
List<Command> test = E.Owner.getCommands();
foreach (Command C in test)
{
if (E.Origin.Level >= C.Permission)
{
helpResponse.Append(" [^3" + C.Name + "^7] ");
if (count >= 4)
{
E.Origin.Tell(helpResponse.ToString());
helpResponse = new StringBuilder();
count = 0;
}
count++;
}
}
E.Origin.Tell(helpResponse.ToString());
E.Origin.Tell("Type !help <cmd> to get command usage example");
}
}
}
class FastRestart : Command
{
public FastRestart(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
E.Owner.Broadcast("Performing fast restart in 5 seconds...");
E.Owner.fastRestart(5);
}
}
class MapRotate : Command
{
public MapRotate(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
E.Owner.Broadcast("Performing map rotate in 5 seconds...");
E.Owner.mapRotate(5);
}
}
class SetLevel : Command
{
public SetLevel(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
if (E.Target == E.Origin)
{
E.Origin.Tell("You can't set your own level, silly.");
return;
}
Player.Permission newPerm = SharedLibrary.Utilities.matchPermission(SharedLibrary.Utilities.removeWords(E.Data, 1));
if (newPerm > Player.Permission.Banned)
{
E.Target.setLevel(newPerm);
E.Target.Tell("Congratulations! You have been promoted to ^3" + newPerm);
E.Origin.Tell(E.Target.Name + " was successfully promoted!");
//NEEED TO MOVE
E.Owner.clientDB.updatePlayer(E.Target);
}
else
E.Origin.Tell("Invalid group specified.");
}
}
class Usage : Command
{
public Usage(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
E.Origin.Tell("IW4M Admin is using " + Math.Round(((System.Diagnostics.Process.GetCurrentProcess().PrivateMemorySize64 / 2048f) / 1200f), 1) + "MB");
}
}
class Uptime : Command
{
public Uptime(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
TimeSpan uptime = DateTime.Now - System.Diagnostics.Process.GetCurrentProcess().StartTime;
E.Origin.Tell(String.Format("IW4M Admin has been up for {0} days, {1} hours, and {2} minutes", uptime.Days, uptime.Hours, uptime.Minutes));
}
}
class Admins : Command
{
public Admins(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
List<Player> activePlayers = E.Owner.getPlayers();
lock (activePlayers)
{
foreach (Player P in E.Owner.getPlayers())
{
if (P != null && P.Level > Player.Permission.Flagged && !P.Masked)
{
E.Origin.Tell(String.Format("[^3{0}^7] {1}", SharedLibrary.Utilities.levelToColor(P.Level), P.Name));
}
}
}
}
}
class MapCMD : Command
{
public MapCMD(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
string newMap = E.Data.Trim().ToLower();
foreach (Map m in E.Owner.maps)
{
if (m.Name.ToLower() == newMap || m.Alias.ToLower() == newMap)
{
E.Owner.Broadcast("Changing to map ^2" + m.Alias);
SharedLibrary.Utilities.Wait(3);
E.Owner.Map(m.Name);
return;
}
}
E.Owner.Broadcast("Attempting to change to unknown map ^1" + newMap);
SharedLibrary.Utilities.Wait(3);
E.Owner.Map(newMap);
}
}
class Find : Command
{
public Find(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
var db_players = E.Owner.clientDB.findPlayers(E.Data.Trim());
if (db_players == null)
{
E.Origin.Tell("No players found");
return;
}
foreach (Player P in db_players)
{
String mesg = String.Format("[^3{0}^7] [^3@{1}^7] - [{2}^7] - {3} | last seen {4} ago", P.Name, P.databaseID, SharedLibrary.Utilities.levelToColor(P.Level), P.IP, P.getLastConnection());
E.Origin.Tell(mesg);
}
}
}
class FindAll : Command
{
public FindAll(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
E.Data = E.Data.Trim();
if (E.Data.Length < 4)
{
E.Origin.Tell("You must enter at least 4 letters");
return;
}
//var db_players = E.Owner.clientDB.findPlayers(E.Data.Trim());
var db_aliases = E.Owner.aliasDB.findPlayers(E.Data);
if (db_aliases == null)
{
E.Origin.Tell("No players found");
return;
}
foreach (Aliases P in db_aliases)
{
if (P == null)
continue;
String lookingFor = String.Empty;
foreach(String S in P.Names)
{
if (S.Contains(E.Data))
lookingFor = S;
}
Player Current = E.Owner.clientDB.getPlayer(P.Number);
if (Current != null)
{
String mesg = String.Format("^1{0} ^7now goes by ^5{1}^7 [^3{2}^7]", lookingFor, Current.Name, Current.databaseID);
E.Origin.Tell(mesg);
}
}
}
}
class Rules : Command
{
public Rules(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
if (E.Owner.rules.Count < 1)
E.Origin.Tell("This server has not set any rules.");
else
{
foreach (String r in E.Owner.rules)
E.Origin.Tell("- " + r);
}
}
}
class PrivateMessage : Command
{
public PrivateMessage(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
E.Data = SharedLibrary.Utilities.removeWords(E.Data, 1);
E.Target.Alert();
E.Target.Tell("^1" + E.Origin.Name + " ^3[PM]^7 - " + E.Data);
E.Origin.Tell(String.Format("To ^3{0} ^7-> {1}", E.Target.Name, E.Data));
}
}
class Reload : Command
{
public Reload(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
if (E.Owner.Reload())
E.Origin.Tell("Sucessfully reloaded configs!");
else
E.Origin.Tell("Unable to reload configs :(");
}
}
class Balance : Command
{
public Balance(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
E.Origin.currentServer.executeCommand(String.Format("admin_lastevent {0};{1}", "balance", E.Origin.npID)); //Let gsc do the magic
}
}
class GoTo : Command
{
public GoTo(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
E.Origin.currentServer.executeCommand(String.Format("admin_lastevent {0};{1};{2};{3}", "goto", E.Origin.npID, E.Target.Name, E.Data)); //Let gsc do the magic
}
}
class Flag : Command
{
public Flag(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
if (E.Target.Level >= E.Origin.Level)
{
E.Origin.Tell("You cannot flag " + E.Target.Name);
return;
}
if (E.Target.Level == Player.Permission.Flagged)
{
E.Target.setLevel(Player.Permission.User);
E.Origin.Tell("You have ^5unflagged ^7" + E.Target.Name);
}
else
{
E.Target.setLevel(Player.Permission.Flagged);
E.Origin.Tell("You have ^5flagged ^7" + E.Target.Name);
}
E.Owner.clientDB.updatePlayer(E.Target);
}
}
class _Report : Command
{
public _Report(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
if (E.Owner.Reports.Find(x => x.Origin == E.Origin) != null)
{
E.Origin.Tell("You have already reported this player");
return;
}
if (E.Target == E.Origin)
{
E.Origin.Tell("You cannot report yourself, silly.");
return;
}
if (E.Target.Level > E.Origin.Level)
{
E.Origin.Tell("You cannot report " + E.Target.Name);
return;
}
E.Data = SharedLibrary.Utilities.removeWords(E.Data, 1);
E.Owner.Reports.Add(new Report(E.Target, E.Origin, E.Data));
Connection Screenshot = new Connection(String.Format("http://server.nbsclan.org/screen.php?id={0}&name={1}?save=1", SharedLibrary.Utilities.getForumIDFromStr(E.Target.npID), E.Origin.Name));
String Response = Screenshot.Read();
E.Origin.Tell("Successfully reported " + E.Target.Name);
E.Owner.ToAdmins(String.Format("^5{0}^7->^1{1}^7: {2}", E.Origin.Name, E.Target.Name, E.Data));
}
}
class Reports : Command
{
public Reports(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
if (E.Data != null && E.Data.ToLower().Contains("clear"))
{
E.Owner.Reports = new List<Report>();
E.Origin.Tell("Reports successfully cleared!");
return;
}
if (E.Owner.Reports.Count < 1)
{
E.Origin.Tell("No players reported yet.");
return;
}
int count = E.Owner.Reports.Count - 1;
for (int i = 0; i <= count; i++)
{
if (count > 8)
i = count - 8;
Report R = E.Owner.Reports[i];
E.Origin.Tell(String.Format("^5{0}^7->^1{1}^7: {2}", R.Origin.Name, R.Target.Name, R.Reason));
}
}
}
class _Tell : Command
{
public _Tell(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
E.Data = SharedLibrary.Utilities.removeWords(E.Data, 1);
E.Origin.currentServer.executeCommand(String.Format("admin_lastevent tell;{0};{1};{2}", E.Origin.npID, E.Target.npID, E.Data));
}
}
class Mask : Command
{
public Mask(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
if (E.Origin.Masked)
{
E.Origin.Masked = false;
E.Origin.Tell("You are now unmasked");
}
else
{
E.Origin.Masked = true;
E.Origin.Tell("You are now masked");
}
}
}
class BanInfo : Command
{
public BanInfo(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
if (E.Target == null)
{
E.Origin.Tell("No bans for that player.");
return;
}
Penalty B = E.Owner.Bans.Find(b => b.npID.Equals(E.Target.npID));
if (B == null)
{
E.Origin.Tell("No active ban was found for that player.");
return;
}
Player Banner = E.Owner.clientDB.getPlayer(B.bannedByID, -1);
if (Banner == null)
{
E.Origin.Tell("Ban was found for the player, but origin of the ban is unavailable.");
return;
}
E.Origin.Tell(String.Format("^1{0} ^7was banned by ^5{1} ^7for: {2}", E.Target.Name, Banner.Name, B.Reason));
}
}
class Alias : Command
{
public Alias(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
E.Target.Alias = E.Owner.aliasDB.getPlayer(E.Target.databaseID);
if (E.Target.Alias == null)
{
E.Target.Tell("Could not find alias info for that player.");
return;
}
E.Target.Tell("[^3" + E.Target.Name + "^7]");
StringBuilder message = new StringBuilder();
List<Player> playerAliases = E.Owner.getPlayerAliases(E.Target);
message.Append("Aliases: ");
foreach (Player P in playerAliases)
{
foreach (String S in P.Alias.Names)
{
if (S != String.Empty && S != E.Target.Name)
message.Append(S + " | ");
}
}
E.Origin.Tell(message.ToString());
message = new StringBuilder();
if (E.Target.Alias.IPS != null)
{
message.Append("IPs: ");
foreach (Player P2 in playerAliases)
{
foreach (String IP in P2.Alias.IPS)
{
if (IP.Split('.').Length > 3 && IP != String.Empty && !message.ToString().Contains(IP))
message.Append (IP + " | ");
}
}
E.Origin.Tell(message.ToString());
}
}
}
class _RCON : Command
{
public _RCON(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
E.Origin.currentServer.executeCommand(E.Data.Trim());
E.Origin.Tell("Successfuly sent RCON command!");
}
}
class Plugins : Command
{
public Plugins(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override void Execute(Event E)
{
E.Origin.Tell("^5Loaded Plugins:");
foreach (Plugin P in PluginImporter.potentialPlugins)
{
E.Origin.Tell(String.Format("^3{0} ^7[^3{1}^7] by ^5{2}^7", P.Name, P.Version, P.Author));
}
}
}
}

24
Admin/Commands.cs Normal file
View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Text;
using SharedLibrary;
using SharedLibrary.Network;
using System.Threading.Tasks;
namespace IW4MAdmin
{
class Plugins : Command
{
public Plugins(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override async Task ExecuteAsync(Event E)
{
await E.Origin.Tell("^5Loaded Plugins:");
foreach (SharedLibrary.Extensions.IPlugin P in PluginImporter.potentialPlugins)
{
await E.Origin.Tell(String.Format("^3{0} ^7[v^3{1}^7] by ^5{2}^7", P.Name, P.Version, P.Author));
}
}
}
}

73
Admin/Config.cs Normal file
View File

@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using SharedLibrary.Interfaces;
namespace IW4MAdmin
{
public class Config : Serialize<Config>
{
public string IP;
public int Port;
public string Password;
public string FtpPrefix;
public override string Filename()
{
return $"config/servers/{IP}_{Port}.cfg";
}
public static Config Generate()
{
string IP = String.Empty;
int Port = 0;
string Password;
while(IP == String.Empty)
{
try
{
Console.Write("Enter server IP: ");
string input = Console.ReadLine();
IPAddress.Parse(input);
IP = input;
}
catch (Exception)
{
continue;
}
}
while(Port == 0)
{
try
{
Console.Write("Enter server port: ");
Port = Int32.Parse(Console.ReadLine());
}
catch (Exception)
{
continue;
}
}
Console.Write("Enter server RCON password: ");
Password = Console.ReadLine();
var config = new Config() { IP = IP, Password = Password, Port = Port };
config.Write();
Console.WriteLine("Config saved, add another? [y/n]:");
if (Console.ReadLine().ToLower().First() == 'y')
Generate();
return config;
}
}
}

View File

@ -10,16 +10,15 @@ namespace IW4MAdmin
public Heartbeat(Server I)
{
Handle = new Connection("http://raidmax.org/IW4M/Admin");
Instance = I;
}
public void Send()
public void Send(Server S)
{
String URI = String.Format("http://raidmax.org/IW4M/Admin/heartbeat.php?address={0}&name={1}&map={2}&players={3}&version={4}", Instance.getPort().ToString(), Instance.getName(), Instance.getMap(), Instance.getClientNum() + '/' + Instance.getMaxClients().ToString(), IW4MAdmin.Program.Version.ToString());
String URI = String.Format("http://raidmax.org/IW4M/Admin/heartbeat.php?port={0}&name={1}&map={2}&players={3}&version={4}&gametype={5}&servercount={6}", S.getPort(), S.getName(), S.CurrentMap.Name, S.getPlayers().Count, IW4MAdmin.Program.Version.ToString(), S.Gametype, Manager.GetInstance().Servers);
// blind fire
Handle.Request(URI);
}
private Connection Handle;
private Server Instance;
}
}

View File

@ -9,7 +9,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>IW4MAdmin</RootNamespace>
<AssemblyName>IW4MAdmin</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
@ -61,6 +61,8 @@
<Prefer32Bit>false</Prefer32Bit>
<RunCodeAnalysis>false</RunCodeAnalysis>
<CodeAnalysisIgnoreGeneratedCode>false</CodeAnalysisIgnoreGeneratedCode>
<DocumentationFile>
</DocumentationFile>
</PropertyGroup>
<PropertyGroup>
<TargetZone>LocalIntranet</TargetZone>
@ -88,25 +90,29 @@
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<Reference Include="SharedLibrary, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<Reference Include="Kayak, Version=0.7.2.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>lib\SharedLibrary.dll</HintPath>
<HintPath>lib\Kayak.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Data" />
<Reference Include="System.Data.SQLite, Version=1.0.96.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>libs\System.Data.SQLite.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="System.Management" />
<Reference Include="System.Web" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Command.cs" />
<Compile Include="Commands.cs" />
<Compile Include="Config.cs" />
<Compile Include="Connection.cs" />
<Compile Include="Heartbeat.cs" />
<Compile Include="Kayak.cs" />
<Compile Include="Main.cs" />
<Compile Include="Manager.cs" />
<Compile Include="Plugins.cs" />
@ -117,19 +123,15 @@
<DependentUpon>Settings.settings</DependentUpon>
</Compile>
<Compile Include="Server.cs" />
<Compile Include="Utilities.cs" />
<Compile Include="IW4_GameStructs.cs" />
<Compile Include="WebService.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.manifest" />
<None Include="lib\Kayak.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="lib\System.Data.SQLite.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<Content Include="IW4AdminIcon.ico" />
<Content Include="lib\AdminInterface.dll">
<Content Include="lib\Kayak.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="lib\Newtonsoft.Json.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="lib\SharedLibrary.dll">
@ -138,41 +140,47 @@
<Content Include="lib\SQLite.Interop.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="plugins\SimpleStatsPlugin.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="plugins\WebfrontPlugin.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="version.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="webfront\bans.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="webfront\console.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="webfront\error.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="webfront\footer.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="webfront\graph.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="webfront\header.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="webfront\login.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="webfront\main.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="webfront\main.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="webfront\mobile.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="webfront\notfound.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="webfront\player.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<Content Include="webfront\penalties.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="webfront\stats.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<Content Include="webfront\players.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="config\maps.cfg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
@ -186,6 +194,10 @@
<None Include="app.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="config\web.cfg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="IW4MAdmin.exe.config" />
<None Include="m2demo\admin\commands.gsc">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
@ -198,6 +210,7 @@
<None Include="m2demo\settings\main.gsc">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="packages.config" />
<None Include="Properties\app.manifest" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
@ -298,10 +311,24 @@
<FileType>Assembly</FileType>
</PublishFile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SharedLibrary\SharedLibrary.csproj">
<Project>{d51eeceb-438a-47da-870f-7d7b41bc24d6}</Project>
<Name>SharedLibrary</Name>
<Private>False</Private>
</ProjectReference>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>
</PostBuildEvent>
<PostBuildEvent>move "$(TargetDir)Newtonsoft.Json.dll" "$(TargetDir)lib\Newtonsoft.Json.dll"
copy /Y "$(SolutionDir)lib\*.dll" "$(TargetDir)lib"
copy /Y "$(TargetDir)$(TargetName).exe" "$(SolutionDir)BUILD"
copy /Y "$(TargetDir)IW4MAdmin.exe.config" "$(SolutionDir)BUILD"
copy /Y "$(ProjectDir)lib\Kayak.dll" "$(SolutionDir)BUILD\lib"
copy /Y "$(ProjectDir)lib\SQLite.Interop.dll" "$(SolutionDir)BUILD\lib"
</PostBuildEvent>
</PropertyGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

View File

@ -0,0 +1,11 @@
<?xml version="1.0"?>
<configuration>
<startup>
<supportedRuntime version="v4.5" sku=".NETFramework,Version=v4.5"/>
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="lib"/>
</assemblyBinding>
</runtime>
</configuration>

View File

@ -1,109 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace IW4MAdmin
{
[StructLayout(LayoutKind.Explicit)]
public struct netadr_t
{
[FieldOffset(0x0)]
Int32 type;
[FieldOffset(0x4)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public Byte[] ip;
[FieldOffset(0x8)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public Byte[] ipx;
[FieldOffset(0x12)]
public short port;
}
[StructLayout(LayoutKind.Explicit)]
public struct client_s
{
[FieldOffset(0x0)]
public Int32 state;
[FieldOffset(0x28)]
public netadr_t adr;
[FieldOffset(0x65C)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
public String connectInfoString;
[FieldOffset(0x20EA4)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=400)] // doubt this is the correct size
public String lastUserCmd;
[FieldOffset(0x212A4)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public String name;
[FieldOffset(0x212C0)]
public int snapNum;
[FieldOffset(0x212C8)]
public short ping;
[FieldOffset(0x41AF0)]
public int isBot;
[FieldOffset(0x43F00)]
public UInt64 steamid;
};
[StructLayout(LayoutKind.Explicit)]
public struct dvar_t
{
[FieldOffset(0)]
public IntPtr name;
[FieldOffset(4)]
public IntPtr description;
[FieldOffset(8)]
public uint flags;
[FieldOffset(12)]
public Byte type;
[FieldOffset(16)]
public IntPtr current;
[FieldOffset(32)]
public IntPtr latched;
[FieldOffset(48)]
public IntPtr _default;
[FieldOffset(64)]
public IntPtr min;
[FieldOffset(68)]
public IntPtr max;
}
class Helpers
{
public static String NET_AdrToString(netadr_t a)
{
// not worrying about NA_TYPE
StringBuilder s = new StringBuilder(64);
s.AppendFormat("{0}.{1}.{2}.{3}:{4}", a.ip[0], a.ip[1], a.ip[2], a.ip[3], a.port);
return s.ToString();
}
public static unsafe T ReadStruct<T>(byte[] buffer) where T : struct
{
fixed (byte* b = buffer)
return (T)Marshal.PtrToStructure(new IntPtr(b), typeof(T));
}
}
}

109
Admin/Kayak.cs Normal file
View File

@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using Kayak.Http;
using Kayak;
namespace IW4MAdmin
{
class Scheduler: ISchedulerDelegate
{
public void OnException(IScheduler scheduler, Exception e)
{
Manager.GetInstance().Logger.Write("Web service has encountered an error - " + e.StackTrace);
}
public void OnStop(IScheduler scheduler)
{
Manager.GetInstance().Logger.Write("Web service has been stopped...");
}
}
class Request : IHttpRequestDelegate
{
public void OnRequest(HttpRequestHead request, IDataProducer requestBody, IHttpResponseDelegate response)
{
// Manager.GetInstance().mainLog.Write("HTTP request received", SharedLibrary.Log.Level.Debug);
NameValueCollection querySet = new NameValueCollection();
if (request.QueryString != null)
querySet = System.Web.HttpUtility.ParseQueryString(SharedLibrary.Utilities.removeNastyChars(request.QueryString));
querySet.Set("IP", ((DefaultKayakServer)(WebService.webService)).clientAddress.Address.ToString());
SharedLibrary.HttpResponse requestedPage = WebService.getPage(request.Path, querySet, request.Headers);
var headers = new HttpResponseHead()
{
Status = "200 OK",
Headers = new Dictionary<string, string>()
{
{ "Content-Type", requestedPage.contentType },
{ "Content-Length", requestedPage.content.Length.ToString() },
{ "Access-Control-Allow-Origin", "*" },
}
};
foreach (var key in requestedPage.additionalHeaders.Keys)
headers.Headers.Add(key, requestedPage.additionalHeaders[key]);
response.OnResponse(headers, new BufferedProducer(requestedPage.content));
}
}
class BufferedProducer : IDataProducer
{
ArraySegment<byte> data;
public BufferedProducer(string data) : this(data, Encoding.UTF8) { }
public BufferedProducer(string data, Encoding encoding) : this(encoding.GetBytes(data)) { }
public BufferedProducer(byte[] data) : this(new ArraySegment<byte>(data)) { }
public BufferedProducer(ArraySegment<byte> data)
{
this.data = data;
}
public IDisposable Connect(IDataConsumer channel)
{
channel.OnData(data, null);
channel.OnEnd();
return null;
}
}
class BufferedConsumer : IDataConsumer
{
List<ArraySegment<byte>> buffer = new List<ArraySegment<byte>>();
Action<string> resultCallback;
Action<Exception> errorCallback;
public BufferedConsumer(Action<string> resultCallback, Action<Exception> errorCallback)
{
this.resultCallback = resultCallback;
this.errorCallback = errorCallback;
}
public bool OnData(ArraySegment<byte> data, Action continuation)
{
buffer.Add(data);
return false;
}
public void OnError(Exception error)
{
errorCallback(error);
}
public void OnEnd()
{
var str = buffer
.Select(b => Encoding.UTF8.GetString(b.Array, b.Offset, b.Count))
.Aggregate((result, next) => result + next);
resultCallback(str);
}
}
}

View File

@ -1,65 +1,75 @@
#define USINGMEMORY

#define USINGMEMORY
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Runtime.InteropServices;
using SharedLibrary;
using System.Threading.Tasks;
using System.IO;
namespace IW4MAdmin
{
class Program
{
static public double Version { get; private set; }
static private Manager serverManager;
static private Manager ServerManager;
static void Main(string[] args)
{
Version = 1.1;
Version = 1.3;
double latestVersion = 0;
handler = new ConsoleEventDelegate(OnProcessExit);
SetConsoleCtrlHandler(handler, true);
double.TryParse(checkUpdate(), out latestVersion);
double.TryParse(CheckUpdate(), out latestVersion);
Console.WriteLine("=====================================================");
Console.WriteLine(" IW4M ADMIN");
Console.WriteLine(" by RaidMax ");
if (latestVersion != 0)
Console.WriteLine(" Version " + Version + " (latest " + latestVersion + ")");
else
Console.WriteLine(" Version " + Version + " (unable to retrieve latest)");
Console.WriteLine(" Version " + Version + " (unable to retrieve latest)");
Console.WriteLine("=====================================================");
serverManager = new Manager();
Thread serverMGRThread = new Thread(serverManager.Init);
serverMGRThread.Name = "Server Manager thread";
serverMGRThread.Start();
while(!serverManager.isReady())
try
{
SharedLibrary.Utilities.Wait(1);
CheckDirectories();
ServerManager = Manager.GetInstance();
ServerManager.Init();
/*Task.Run(() =>
{
String userInput;
Player Origin = new Player("IW4MAdmin", "", -1, Player.Permission.Console, -1, "", 0, "");
do
{
userInput = Console.ReadLine();
if (userInput.ToLower() == "quit")
ServerManager.Stop();
if (ServerManager.Servers.Count == 0)
return;
Event E = new Event(Event.GType.Say, userInput, Origin, null, ServerManager.Servers[0]);
Origin.lastEvent = E;
ServerManager.Servers[0].ExecuteEvent(E);
Console.Write('>');
} while (userInput != null && ServerManager.Running);
});*/
}
if (serverManager.getServers() != null)
getManager().mainLog.Write("IW4M Now Initialized!", Log.Level.Production);
String userInput;
Server serverToExecuteOn = serverManager.getServers()[0];
Player Origin = new Player("IW4MAdmin", "", -1, Player.Permission.Console, -1, "", 0, "");
do
catch(Exception e)
{
userInput = Console.ReadLine();
Event E = new Event(Event.GType.Say, userInput, Origin, null, serverToExecuteOn);
Origin.lastEvent = E;
serverToExecuteOn.processEvent(E);
Console.Write('>');
Console.WriteLine($"Fatal Error during initialization: {e.Message}");
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
return;
}
} while (userInput != null && serverManager.isRunning());
serverMGRThread.Join();
serverManager.mainLog.Write("Shutting down IW4MAdmin...", Log.Level.Debug);
ServerManager.Start();
}
static ConsoleEventDelegate handler;
@ -68,22 +78,8 @@ namespace IW4MAdmin
{
try
{
foreach (Server S in getServers())
{
if (S == null)
continue;
S.Broadcast("^5IW4MAdmin ^7is going ^1offline^7");
S.isRunning = false;
if (Utilities.shutdownInterface(S.pID()))
getManager().mainLog.Write("Successfully removed IW4MAdmin from server with PID " + S.pID(), Log.Level.Debug);
else
getManager().mainLog.Write("Could not remove IW4MAdmin from server with PID " + S.pID(), Log.Level.Debug);
}
getManager().shutDown();
return false;
ServerManager.Stop();
return true;
}
catch
@ -96,20 +92,31 @@ namespace IW4MAdmin
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetConsoleCtrlHandler(ConsoleEventDelegate callback, bool add);
static private String checkUpdate()
static private String CheckUpdate()
{
Connection Ver = new Connection("http://raidmax.org/IW4M/Admin/version.php");
return Ver.Read();
}
static public Server[] getServers()
static void CheckDirectories()
{
return serverManager.getServers().ToArray();
}
if (!Directory.Exists("Lib"))
throw new Exception("Lib folder does not exist");
static public Manager getManager()
{
return serverManager;
if (!Directory.Exists("Config"))
{
Console.WriteLine("Warning: Config folder does not exist");
Directory.CreateDirectory("Config");
}
if (!Directory.Exists("Config/Servers"))
Directory.CreateDirectory("Config/Servers");
if (!Directory.Exists("Logs"))
Directory.CreateDirectory("Logs");
if (!Directory.Exists("Database"))
Directory.CreateDirectory("Database");
}
}
}

View File

@ -7,238 +7,134 @@ using System.Runtime.InteropServices;
using System.Net;
using System.Threading;
using SharedLibrary;
using System.IO;
using SharedLibrary.Network;
using System.Threading.Tasks;
namespace IW4MAdmin
{
class Manager
class Manager : SharedLibrary.Interfaces.IManager
{
private List<Server> Servers;
private SortedDictionary<int, Thread> ThreadList;
private List<int> activePIDs;
public Log mainLog;
private bool initialized = false;
static Manager Instance;
public List<Server> Servers { get; private set; }
List<Command> Commands;
Kayak.IScheduler webServiceTask;
Thread WebThread;
public bool Running { get; private set; }
#if FTP_LOG
const double UPDATE_FREQUENCY = 15000;
#else
const double UPDATE_FREQUENCY = 300;
#endif
public Manager()
public Log Logger;
private Manager()
{
ThreadList = new SortedDictionary<int, Thread>();
IFile logFile = new IFile("IW4MAdminManager.log", true);
mainLog = new Log(logFile, Log.Level.Production, 0);
IFile logFile = new IFile("Logs/IW4MAdminManager.log", true);
Logger = new Log(logFile, Log.Level.Production, 0);
Servers = new List<Server>();
Commands = new List<Command>();
}
public void Init()
{
while (getCurrentIW4MProcesses().Count == 0)
{
mainLog.Write("No viable IW4M instances detected.", Log.Level.Production);
SharedLibrary.Utilities.Wait(10);
}
PluginImporter.Load();
activePIDs = getCurrentIW4MProcesses();
Servers = loadServers();
foreach (Server S in Servers)
{
Server IW4MServer = S;
Thread IW4MServerThread = new Thread(IW4MServer.Monitor);
IW4MServerThread.Name = "Monitor thread for " + S.pID();
ThreadList.Add(IW4MServer.pID(), IW4MServerThread);
IW4MServerThread.Start();
}
initialized = true;
while (activePIDs.Count > 0)
{
List<Server> defunctServers = new List<Server>();
lock (Servers)
{
foreach (Server S in Servers)
{
if (S == null)
continue;
if (!isIW4MStillRunning(S.pID()))
{
Thread Defunct = ThreadList[S.pID()];
S.isRunning = false;
if (Defunct != null)
{
Defunct.Join();
ThreadList[S.pID()] = null;
}
if (!S.isRunning)
Utilities.shutdownInterface(S.pID());
mainLog.Write("Server with PID #" + S.pID() + " can no longer be monitored.", Log.Level.Production);
activePIDs.Remove(S.pID());
defunctServers.Add(S);
}
}
}
foreach (Server S in defunctServers)
Servers.Remove(S);
defunctServers = null;
scanForNewServers();
SharedLibrary.Utilities.Wait(5);
}
mainLog.Write("Manager shutting down...");
}
public void shutDown()
{
foreach (Server S in Servers)
S.isRunning = false;
activePIDs = new List<int>();
foreach (KeyValuePair<int, Thread> T in ThreadList)
ThreadList[T.Key].Join();
}
public bool isRunning()
{
return activePIDs.Count != 0;
}
public List<Server> getServers()
public List<Server> GetServers()
{
return Servers;
}
private void scanForNewServers()
public List<Command> GetCommands()
{
List<int> newProcesses = getCurrentIW4MProcesses();
return Commands;
}
if (activePIDs == null)
return;
public static Manager GetInstance()
{
return Instance == null ? Instance = new Manager() : Instance;
}
foreach (int pID in newProcesses)
public void Init()
{
var Configs = Directory.EnumerateFiles("config/servers").Where(x => x.Contains(".cfg"));
if (Configs.Count() == 0)
Config.Generate();
PluginImporter.Load();
foreach (var file in Configs)
{
if (pID == 0)
continue;
var Conf = Config.Read(file);
var ServerInstance = new IW4MServer(this, Conf.IP, Conf.Port, Conf.Password);
if (activePIDs.IndexOf(pID) == -1 && !ThreadList.ContainsKey(pID))
Task.Run(async () =>
{
Server S = loadIndividualServer(pID);
if (S == null)
try
{
mainLog.Write("Unable to load new detected server!", Log.Level.Debug);
continue;
await ServerInstance.Initialize();
Servers.Add(ServerInstance);
Logger.Write($"Now monitoring {ServerInstance.Hostname}", Log.Level.Production);
}
Servers.Add(S);
Thread IW4MServerThread = new Thread(S.Monitor);
ThreadList.Add(pID, IW4MServerThread);
mainLog.Write("New server detected on port " + S.getPort(), Log.Level.Production);
IW4MServerThread.Start();
}
}
}
private bool isIW4MStillRunning(int pID)
{
if (pID > 0)
{
try
{
Process P = Process.GetProcessById(pID);
return true;
}
catch (System.ArgumentException)
{
return false;
}
}
return false;
}
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll")]
public static extern bool ReadProcessMemory(int hProcess, int lpBaseAddress, byte[] lpBuffer, int dwSize, ref int lpNumberOfBytesRead);
private List<int> getCurrentIW4MProcesses()
{
List<int> PIDs = new List<int>();
foreach (Process P in Process.GetProcessesByName("iw4m"))
{
IntPtr Handle = OpenProcess(0x10, false, P.Id);
Byte[] isClient = new Byte[1];
int numberRead = 0;
ReadProcessMemory((int)Handle, 0x5DEC04, isClient, 1, ref numberRead);
if (isClient[0] == 0)
PIDs.Add(P.Id);
}
return PIDs;
}
private List<Server> loadServers()
{
List<Server> activeServers = new List<Server>();
foreach (int pID in activePIDs)
{
Server S = loadIndividualServer(pID);
if (S != null)
activeServers.Add(S);
}
return activeServers;
}
private Server loadIndividualServer(int pID)
{
if (pID > 0)
{
IntPtr Handle = OpenProcess(0x10, false, pID);
if (Handle != null)
{
int timeWaiting = 0;
bool sv_running = false;
while(!sv_running) // server is still booting up
catch (SharedLibrary.Exceptions.ServerException e)
{
int sv_runningPtr = Utilities.getIntFromPointer(0x1AD7934, (int)Handle) + 0x10; // where the dvar_t struct is stored + the offset for current value
sv_running = Utilities.getBoolFromPointer(sv_runningPtr, (int)Handle);
SharedLibrary.Utilities.Wait(1);
timeWaiting++;
if (timeWaiting > 30) // don't want to get stuck waiting forever if the server is frozen
return null;
Logger.Write($"Not monitoring server {Conf.IP}:{Conf.Port} due to uncorrectable errors", Log.Level.Production);
if (e.GetType() == typeof(SharedLibrary.Exceptions.DvarException))
Logger.Write($"Could not get the dvar value for {(e as SharedLibrary.Exceptions.DvarException).Data["dvar_name"]} (ensure the server has a map loaded)", Log.Level.Production);
else if (e.GetType() == typeof(SharedLibrary.Exceptions.NetworkException))
Logger.Write("Could not communicate with the server (ensure the configuration is correct)", Log.Level.Production);
}
});
if (timeWaiting > 5)
SharedLibrary.Utilities.Wait(2);
dvar net_ip = Utilities.getDvarOld(0x64A1DF8, (int)Handle);
dvar net_port = Utilities.getDvarOld(0x64A3004, (int)Handle);
return new IW4MServer(net_ip.current, Convert.ToInt32(net_port.current), "", (int)Handle, pID);
}
return null;
}
return null;
SharedLibrary.WebService.Init();
webServiceTask = WebService.getScheduler();
WebThread = new Thread(webServiceTask.Start);
WebThread.Name = "Web Thread";
WebThread.Start();
while (Servers.Count < 1)
Thread.Sleep(500);
Running = true;
}
public void Start()
{
int Processed;
DateTime Start;
while(Running)
{
Processed = 0;
Start = DateTime.Now;
foreach (Server S in Servers)
Processed += S.ProcessUpdatesAsync().Result;
// ideally we don't want to sleep on the thread, but polling
// as much as possible will use unnecessary CPU
int ElapsedTime = (int)(DateTime.Now - Start).TotalMilliseconds;
while ((Processed != Servers.Count || ElapsedTime < UPDATE_FREQUENCY) && Running)
{
Thread.Sleep((int)(UPDATE_FREQUENCY - ElapsedTime));
ElapsedTime = (int)(DateTime.Now - Start).TotalMilliseconds;
}
}
#if !DEBUG
foreach (var S in Servers)
S.Broadcast("^1IW4MAdmin going offline!");
#endif
Servers.Clear();
WebThread.Abort();
webServiceTask.Stop();
}
public bool isReady()
public void Stop()
{
return initialized;
Running = false;
}
}
}

View File

@ -3,17 +3,20 @@ using System.IO;
using System.Collections.Generic;
using System.Reflection;
using SharedLibrary;
using SharedLibrary.Extensions;
namespace IW4MAdmin
{
public class PluginImporter
{
public static List<Command> potentialCommands = new List<Command>();
public static List<Plugin> potentialPlugins = new List<Plugin>();
public static Plugin webFront = null;
public static List<IPlugin> potentialPlugins = new List<IPlugin>();
public static IPlugin webFront = null;
//private static AppDomain pluginDomain;
public static bool Load()
{
//pluginDomain = AppDomain.CreateDomain("Plugins");
string[] dllFileNames = null;
if (Directory.Exists(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + "\\plugins"))
@ -21,13 +24,13 @@ namespace IW4MAdmin
else
{
Program.getManager().mainLog.Write("Plugin folder does not exist!", Log.Level.All);
Manager.GetInstance().Logger.Write("Plugin folder does not exist!", Log.Level.All);
return false;
}
if (dllFileNames == null || dllFileNames.Length == 0)
{
Program.getManager().mainLog.Write("No plugins to load", Log.Level.All);
Manager.GetInstance().Logger.Write("No plugins to load", Log.Level.All);
return true;
}
@ -47,74 +50,67 @@ namespace IW4MAdmin
Type[] types = Plugin.GetTypes();
foreach(Type assemblyType in types)
{
if(assemblyType.IsClass && assemblyType.BaseType.Name == "Plugin")
{
Object notifyObject = Activator.CreateInstance(assemblyType);
Plugin newNotify = (Plugin)notifyObject;
if (potentialPlugins.Find(x => x.Name == newNotify.Name) == null)
{
potentialPlugins.Add(newNotify);
try
{
newNotify.onLoad();
}
catch (Exception E)
{
Program.getManager().mainLog.Write("There was an error starting \"" + newNotify.Name + "\" plugin", Log.Level.Debug);
Program.getManager().mainLog.Write("Error Message: " + E.Message, Log.Level.Debug);
Program.getManager().mainLog.Write("Error Trace: " + E.StackTrace, Log.Level.Debug);
continue;
}
Program.getManager().mainLog.Write("Loaded plugin \"" + newNotify.Name + "\"" + " [" + newNotify.Version + "]", Log.Level.Debug);
totalLoaded++;
}
}
else if (assemblyType.IsClass && assemblyType.BaseType.Name == "Command")
if (assemblyType.IsClass && assemblyType.BaseType.Name == "Command")
{
Object commandObject = Activator.CreateInstance(assemblyType);
Command newCommand = (Command)commandObject;
potentialCommands.Add(newCommand);
Program.getManager().mainLog.Write("Registered command \"" + newCommand.Name + "\"", Log.Level.Debug);
Manager.GetInstance().Logger.Write("Registered command \"" + newCommand.Name + "\"", Log.Level.Debug);
totalLoaded++;
continue;
}
try
{
if (assemblyType.GetInterface("IPlugin", false) == null)
continue;
Object notifyObject = Activator.CreateInstance(assemblyType);
IPlugin newNotify = (IPlugin)notifyObject;
if (potentialPlugins.Find(x => x.Name == newNotify.Name) == null)
{
potentialPlugins.Add(newNotify);
newNotify.OnLoad();
Manager.GetInstance().Logger.Write("Loaded plugin \"" + newNotify.Name + "\"" + " [" + newNotify.Version + "]", Log.Level.Debug);
totalLoaded++;
}
}
catch (Exception E)
{
Manager.GetInstance().Logger.Write("Could not load plugin " + Plugin.Location + " - " + E.Message);
}
}
}
}
Program.getManager().mainLog.Write("Loaded " + totalLoaded + " plugins.", Log.Level.Production);
Manager.GetInstance().Logger.Write("Loaded " + totalLoaded + " plugins.", Log.Level.Production);
return true;
}
/*
public static void Unload()
{
foreach (Plugin P in potentialPlugins)
foreach (IPlugin P in potentialPlugins)
{
try
{
if (P.Name != "Webfront")
P.onUnload();
else
webFront = P;
P.onUnload();
}
catch (Exception E)
{
Program.getManager().mainLog.Write("There was an error unloading \"" + P.Name + "\" plugin", Log.Level.Debug);
Program.getManager().mainLog.Write("Error Message: " + E.Message, Log.Level.Debug);
Program.getManager().mainLog.Write("Error Trace: " + E.StackTrace, Log.Level.Debug);
Manager.GetInstance().mainLog.Write("There was an error unloading \"" + P.Name + "\" plugin", Log.Level.Debug);
Manager.GetInstance().mainLog.Write("Error Message: " + E.Message, Log.Level.Debug);
Manager.GetInstance().mainLog.Write("Error Trace: " + E.StackTrace, Log.Level.Debug);
continue;
}
}
potentialCommands = new List<Command>();
potentialPlugins = new List<Plugin>();
if (webFront != null)
potentialPlugins.Add(webFront);
}
potentialPlugins = new List<IPlugin>();
AppDomain.Unload(pluginDomain);
}*/
}
}

View File

@ -11,7 +11,7 @@ using System.Resources;
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("RaidMax LLC")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("2015")]
[assembly: AssemblyCopyright("2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@ -33,5 +33,5 @@ using System.Resources;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.9.5")]
[assembly: AssemblyVersion("1.2.*")]
[assembly: NeutralResourcesLanguageAttribute("en")]

View File

@ -12,7 +12,7 @@ namespace IW4MAdmin.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.1.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));

File diff suppressed because it is too large Load Diff

View File

@ -1,566 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Text.RegularExpressions;
using System.Runtime.InteropServices;
using System.IO;
using SharedLibrary;
namespace IW4MAdmin
{
class Utilities
{
const int PROCESS_CREATE_THREAD = 0x0002;
const int PROCESS_QUERY_INFORMATION = 0x0400;
const int PROCESS_VM_OPERATION = 0x0008;
const int PROCESS_VM_WRITE = 0x0020;
const int PROCESS_VM_READ = 0x0010;
[Flags]
public enum ProcessAccessFlags : uint
{
Terminate = 0x00000001,
CreateThread = 0x00000002,
VMOperation = 0x00000008,
VMRead = 0x00000010,
VMWrite = 0x00000020,
DupHandle = 0x00000040,
SetInformation = 0x00000200,
QueryInformation = 0x00000400,
Synchronize = 0x00100000,
All = 0x001F0FFF
}
[Flags]
public enum AllocationType
{
Commit = 0x00001000,
Reserve = 0x00002000,
Decommit = 0x00004000,
Release = 0x00008000,
Reset = 0x00080000,
TopDown = 0x00100000,
WriteWatch = 0x00200000,
Physical = 0x00400000,
LargePages = 0x20000000
}
[Flags]
public enum MemoryProtection
{
NoAccess = 0x0001,
ReadOnly = 0x0002,
ReadWrite = 0x0004,
WriteCopy = 0x0008,
Execute = 0x0010,
ExecuteRead = 0x0020,
ExecuteReadWrite = 0x0040,
ExecuteWriteCopy = 0x0080,
GuardModifierflag = 0x0100,
NoCacheModifierflag = 0x0200,
WriteCombineModifierflag = 0x0400
}
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll")]
public static extern bool ReadProcessMemory(int hProcess, int lpBaseAddress, byte[] lpBuffer, int dwSize, ref int lpNumberOfBytesRead);
[DllImport("kernel32.dll")]
public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out UIntPtr lpNumberOfBytesWritten);
[DllImport("kernel32.dll")]
static extern bool TerminateThread(IntPtr hThread, uint dwExitCode);
[DllImport("kernel32.dll")]
public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, AllocationType flAllocationType, MemoryProtection flProtect);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, out uint lpThreadId);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, AllocationType dwFreeType);
[DllImport("kernel32.dll", SetLastError = true)]
static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("kernel32.dll", SetLastError = true)]
static extern int CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll")]
static extern bool GetExitCodeThread(IntPtr hThread, out uint lpExitCode);
[DllImport("ntdll.dll")]
public static extern uint RtlCreateUserThread(
[In] IntPtr Process,
[In] IntPtr ThreadSecurityDescriptor,
[In] bool CreateSuspended,
[In] int StackZeroBits,
uint MaximumStackSize,
[In] [Optional] IntPtr InitialStackSize,
[In] IntPtr StartAddress,
[In] IntPtr Parameter,
[Out] out IntPtr Thread,
[Out] out ClientId ClientId
);
[StructLayout(LayoutKind.Sequential)]
public struct ClientId
{
public ClientId(int processId, int threadId)
{
this.UniqueProcess = new IntPtr(processId);
this.UniqueThread = new IntPtr(threadId);
}
public IntPtr UniqueProcess;
public IntPtr UniqueThread;
public int ProcessId { get { return this.UniqueProcess.ToInt32(); } }
public int ThreadId { get { return this.UniqueThread.ToInt32(); } }
}
public static dvar getDvar(int Location, IntPtr Handle)
{
int numberRead = 0;
Byte[] Buff = new Byte[72];
ReadProcessMemory((int)Handle, Location, Buff, Buff.Length, ref numberRead); // read dvar memory
dvar_t dvar_raw = Helpers.ReadStruct<dvar_t>(Buff); // get the dvar struct
dvar dvar_actual = new dvar(); // gotta convert to something readable
dvar_actual.name = getStringFromPointer((int)dvar_raw.name, (int)Handle);
dvar_actual.description = getStringFromPointer((int)dvar_raw.description, (int)Handle);
if (dvar_raw.type == 7)
{
dvar_actual._default = getStringFromPointer((int)dvar_raw._default, (int)Handle);
dvar_actual.current = getStringFromPointer((int)dvar_raw.current, (int)Handle);
dvar_actual.latched = getStringFromPointer((int)dvar_raw.latched, (int)Handle);
}
else if (dvar_raw.type == 0)
{
dvar_actual._default = ((byte)dvar_raw._default).ToString();
dvar_actual.current = ((byte)dvar_raw.current).ToString();
dvar_actual.latched = ((byte)dvar_raw.latched).ToString();
}
else
{
dvar_actual.current = dvar_raw.current.ToString();
dvar_actual._default = dvar_raw._default.ToString();
dvar_actual.latched = dvar_raw.latched.ToString();
}
dvar_actual.type = dvar_raw.type;
dvar_actual.flags = getIntFromPointer((int)dvar_raw.flags, (int)Handle);
dvar_actual.max = getIntFromPointer((int)dvar_raw.max, (int)Handle);
dvar_actual.min = getIntFromPointer((int)dvar_raw.min, (int)Handle);
// done!
return dvar_actual;
}
public static dvar getDvarOld(int Location, int Handle)
{
int loc = getIntFromPointer(Location, Handle);
return getDvar(loc, (IntPtr)Handle);
}
public static int getDvarCurrentAddress(int Location, int Handle)
{
int numberRead = 0;
Byte[] Buff = new Byte[72];
Byte[] Ptr = new Byte[4];
ReadProcessMemory(Handle, Location, Ptr, Ptr.Length, ref numberRead); // get location of dvar
ReadProcessMemory(Handle, (int)BitConverter.ToUInt32(Ptr, 0), Buff, Buff.Length, ref numberRead); // read dvar memory
dvar_t dvar_raw = Helpers.ReadStruct<dvar_t>(Buff); // get the dvar struct
int current = (int)dvar_raw.current;
return current;
}
public static void setDvar(int Location, int Handle, String Value)
{
UIntPtr bytesWritten = UIntPtr.Zero;
WriteProcessMemory((IntPtr)Handle, (IntPtr)Location, Encoding.ASCII.GetBytes(Value), (uint)Value.Length, out bytesWritten);
}
public static String getStringFromPointer(int Location, int Handle)
{
int numberRead = 0;
Byte[] Buff = new Byte[256];
ReadProcessMemory(Handle, Location, Buff, Buff.Length, ref numberRead);
StringBuilder str = new StringBuilder();
for (int i = 0; i < Buff.Length; i++)
{
if (Buff[i] == 0)
break;
str.Append((char)Buff[i]);
}
return str.ToString();
}
public static int getIntFromPointer(int Location, int Handle)
{
int numberRead = 0;
Byte[] Buff = new Byte[4];
ReadProcessMemory(Handle, Location, Buff, Buff.Length, ref numberRead);
return BitConverter.ToInt32(Buff, 0);
}
public static Boolean getBoolFromPointer(int Location, int Handle)
{
int numberRead = 0;
Byte[] Buff = new Byte[1];
ReadProcessMemory(Handle, Location, Buff, Buff.Length, ref numberRead);
return BitConverter.ToBoolean(Buff, 0);
}
public static IntPtr executeCommand(int pID, String Command, IntPtr lastMemoryLocation)
{
/*IntPtr ProcessHandle = OpenProcess(ProcessAccessFlags.All, false, pID);
IntPtr memoryForCMDName = allocateAndWrite(Encoding.ASCII.GetBytes(Command + "\0"), ProcessHandle);
uint threadID;
if (memoryForCMDName == IntPtr.Zero)
return;
// set the dvar's current value pointer to our desired command
setDvarCurrentPtr((IntPtr)0x2098D9C, memoryForCMDName, ProcessHandle);
// assembly instruction to execute the command we want stored in `surogate` dvar
byte[] executeCMD = {
0x55, 0x8B, 0xEC, 0x51, 0xC7, 0x45, 0xFC, // ---------------------------------------------
0x9C, 0x8D, 0x09, 0x02, 0x8B, 0x45, 0xFC, // dvar_t** dvarWithCMD = (dvar_t**)(0x2098D9C);
0x8B, 0x08, 0x8B, 0x51, 0x10, 0x52, 0x6A,
0x00, 0x6A, 0x00, 0xFF, 0x15, 0x1C, 0x53, // Cmd_ExecuteSingleCommand(0, 0, (*dvarWithCMD)->current.string );
0x11, 0x10, 0x83, 0xC4, 0x0C, 0x8B, 0xE5, // ---------------------------------------------
0x5D, 0xC3
};
// allocate the memory for the assembly command and write it
IntPtr codeAllocation = allocateAndWrite(executeCMD, ProcessHandle);
if (codeAllocation == IntPtr.Zero)
return;
// create our thread that executes command :)
IntPtr ThreadHandle = CreateRemoteThread(ProcessHandle, IntPtr.Zero, 0, codeAllocation, IntPtr.Zero, 0, out threadID);
if (ThreadHandle == null || ThreadHandle == IntPtr.Zero)
return;
WaitForSingleObject(ThreadHandle, Int32.MaxValue); // gg if it doesn't finishe
// cleanup
if (!VirtualFreeEx(ProcessHandle, codeAllocation, 0, AllocationType.Release))
Program.getManager().mainLog.Write(Marshal.GetLastWin32Error());
if (!VirtualFreeEx(ProcessHandle, memoryForCMDName, 0, AllocationType.Release))
Program.getManager().mainLog.Write(Marshal.GetLastWin32Error());*/
IntPtr ProcessHandle = OpenProcess(ProcessAccessFlags.All, false, pID);
if (lastMemoryLocation != IntPtr.Zero)
{
if (!VirtualFreeEx(ProcessHandle, lastMemoryLocation, 0, AllocationType.Release))
{
Program.getManager().mainLog.Write("Virtual Free Failed -- Error #" + Marshal.GetLastWin32Error());
return IntPtr.Zero;
}
}
IntPtr memoryForDvarName = allocateAndWrite(Encoding.ASCII.GetBytes(Command + '\0'), ProcessHandle); // this gets disposed next call
if (memoryForDvarName == IntPtr.Zero)
{
Program.getManager().mainLog.Write("UNABLE TO ALLOCATE MEMORY FOR DVAR NAME");
return IntPtr.Zero;
}
setDvarCurrentPtr(0x2098D9C, memoryForDvarName, ProcessHandle);
CloseHandle(ProcessHandle);
return memoryForDvarName;
}
public static IntPtr allocateAndWrite(Byte[] Data, IntPtr ProcessHandle)
{
UIntPtr bytesWritten;
IntPtr AllocatedMemory = VirtualAllocEx(ProcessHandle, IntPtr.Zero, (uint)Data.Length, AllocationType.Commit, MemoryProtection.ExecuteReadWrite);
if (!WriteProcessMemory(ProcessHandle, AllocatedMemory, Data, (uint)Data.Length, out bytesWritten))
{
Program.getManager().mainLog.Write("Unable to write process memory!");
return IntPtr.Zero;
}
if ((int)bytesWritten != Data.Length)
return IntPtr.Zero;
else
return AllocatedMemory;
}
public static bool setDvarCurrentPtr(int DvarAddress, IntPtr ValueAddress, IntPtr ProcessHandle)
{
int locationOfCurrentPtr = getIntFromPointer(DvarAddress, (int)ProcessHandle) + 0x10;
Byte[] newTextPtr = BitConverter.GetBytes((int)ValueAddress);
UIntPtr bytesWritten;
if (!WriteProcessMemory(ProcessHandle, (IntPtr)locationOfCurrentPtr, newTextPtr, (uint)newTextPtr.Length, out bytesWritten))
return false;
if (newTextPtr.Length != (int)bytesWritten)
return false;
return true;
}
public static bool shutdownInterface(int pID, params IntPtr[] cleanUp)
{
IntPtr threadID;
IntPtr ProcessHandle = OpenProcess(ProcessAccessFlags.All, false, pID);
#if DEBUG
Program.getManager().mainLog.Write("Process handle is: " + ProcessHandle);
#endif
if (ProcessHandle == IntPtr.Zero)
{
Program.getManager().mainLog.Write("Unable to open target process");
return false;
}
List<IntPtr> baseAddresses = new List<IntPtr>();
System.Diagnostics.Process P;
try
{
P = System.Diagnostics.Process.GetProcessById(pID);
}
catch (System.ArgumentException)
{
Program.getManager().mainLog.Write("The server with PID " + pID + " was exited before deinit occured.", Log.Level.Debug);
return false;
}
foreach (System.Diagnostics.ProcessModule M in P.Modules)
{
if (M.ModuleName == "AdminInterface.dll" && M.BaseAddress != IntPtr.Zero)
baseAddresses.Add(M.BaseAddress);
}
IntPtr lpLLAddress = GetProcAddress(GetModuleHandle("kernel32.dll"), "FreeLibraryAndExitThread");
if (lpLLAddress == IntPtr.Zero)
{
Program.getManager().mainLog.Write("Could not obtain address of freelibary");
return false;
}
ClientId clientid = new ClientId();
threadID = new IntPtr();
foreach (IntPtr baseAddress in baseAddresses)
{
RtlCreateUserThread(ProcessHandle, IntPtr.Zero, false, 0, (uint)0, IntPtr.Zero, lpLLAddress, baseAddress, out threadID, out clientid);
if (threadID == IntPtr.Zero)
{
Program.getManager().mainLog.Write("Could not create remote thread");
return false;
}
#if DEBUG
Program.getManager().mainLog.Write("Thread ID is " + threadID);
#endif
uint responseCode = WaitForSingleObject(threadID, 3000);
if (responseCode != 0x00000000L)
{
Program.getManager().mainLog.Write("Thread did not finish in a timely manner!", Log.Level.Debug);
Program.getManager().mainLog.Write("Last error is: " + Marshal.GetLastWin32Error(), Log.Level.Debug);
return false;
}
}
CloseHandle(ProcessHandle);
foreach (IntPtr Pointer in cleanUp)
{
if (Pointer != IntPtr.Zero)
{
if (!VirtualFreeEx(ProcessHandle, Pointer, 0, AllocationType.Release))
Program.getManager().mainLog.Write("Virtual Free Failed During Exit Cleanup -- Error #" + Marshal.GetLastWin32Error());
}
}
#if DEBUG
Program.getManager().mainLog.Write("Shutdown finished -- last error : " + Marshal.GetLastWin32Error());
#endif
return true;
}
/////////////////////////////////////////////////////////////
public static Boolean initalizeInterface(int pID)
{
String Path = AppDomain.CurrentDomain.BaseDirectory + "lib\\AdminInterface.dll";
if (!File.Exists(Path))
{
Program.getManager().mainLog.Write("AdminInterface DLL does not exist!");
return false;
}
UIntPtr bytesWritten;
IntPtr threadID;
IntPtr ProcessHandle = OpenProcess(ProcessAccessFlags.All, false, pID);
#if DEBUG
Program.getManager().mainLog.Write("Process handle is: " + ProcessHandle);
#endif
if (ProcessHandle == IntPtr.Zero)
{
Program.getManager().mainLog.Write("Unable to open target process");
return false;
}
IntPtr lpLLAddress = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
if (lpLLAddress == IntPtr.Zero)
{
Program.getManager().mainLog.Write("Could not obtain address of function address");
return false;
}
#if DEBUG
Program.getManager().mainLog.Write("LoadLibraryA location is 0x" + lpLLAddress.ToString("X8"));
#endif
IntPtr pathAllocation = VirtualAllocEx(ProcessHandle, IntPtr.Zero, (uint)Path.Length + 1, AllocationType.Commit, MemoryProtection.ExecuteReadWrite);
if (pathAllocation == IntPtr.Zero)
{
Program.getManager().mainLog.Write("Could not allocate memory for path location");
return false;
}
#if DEBUG
Program.getManager().mainLog.Write("Allocated DLL path address is 0x" + pathAllocation.ToString("X8"));
#endif
byte[] pathBytes = Encoding.ASCII.GetBytes(Path);
if (!WriteProcessMemory(ProcessHandle, pathAllocation, pathBytes, (uint)pathBytes.Length, out bytesWritten))
{
Program.getManager().mainLog.Write("Could not write process memory");
return false;
}
ClientId clientid = new ClientId();
threadID = new IntPtr();
RtlCreateUserThread(ProcessHandle, IntPtr.Zero, false, 0, (uint)0, IntPtr.Zero, lpLLAddress, pathAllocation, out threadID, out clientid);
if (threadID == IntPtr.Zero)
{
Program.getManager().mainLog.Write("Could not create remote thread");
return false;
}
#if DEBUG
//Program.getManager().mainLog.Write("Thread Status is " + threadStatus);
Program.getManager().mainLog.Write("Thread ID is " + threadID);
#endif
uint responseCode = WaitForSingleObject(threadID, 5000);
if (responseCode != 0x00000000L)
{
Program.getManager().mainLog.Write("Thread did not finish in a timely manner!", Log.Level.Debug);
Program.getManager().mainLog.Write("Last error is: " + Marshal.GetLastWin32Error(), Log.Level.Debug);
return false;
}
CloseHandle(ProcessHandle);
#if DEBUG
Program.getManager().mainLog.Write("Initialization finished -- last error : " + Marshal.GetLastWin32Error());
#endif
return true;
}
public static dvar getDvar(int pID, String DVAR, IntPtr lastMemoryLocation)
{
dvar requestedDvar = new dvar();
IntPtr ProcessHandle = OpenProcess(ProcessAccessFlags.All, false, pID);
if (lastMemoryLocation != IntPtr.Zero)
{
if (!VirtualFreeEx(ProcessHandle, lastMemoryLocation, 0, AllocationType.Release))
Program.getManager().mainLog.Write("Virtual free failed during cleanup-- Error #" + Marshal.GetLastWin32Error(), Log.Level.Debug);
}
IntPtr memoryForDvarName = allocateAndWrite(Encoding.ASCII.GetBytes(DVAR + "\0"), ProcessHandle);
if (memoryForDvarName == IntPtr.Zero)
{
Program.getManager().mainLog.Write("Unable to allocate memory for dvar name", Log.Level.Debug);
return requestedDvar;
}
setDvarCurrentPtr(0x2089E04, memoryForDvarName, ProcessHandle); // sv_allowedclan1
#if ASD
/* byte[] copyDvarValue = {
0x55, 0x8B, 0xEC, 0x83, 0xEC, 0x08, // -----------------------------------------------
0xC7, 0x45, 0xFC, 0x9C, 0x8D, 0x09, // dvar_t** surogateDvar = (dvar_t**)(0x2098D9C);
0x02, 0x8B, 0x45, 0xFC, 0x8B, 0x08, //
0x8B, 0x51, 0x10, 0x52, 0xFF, 0x15, // dvar_t *newDvar = Dvar_FindVar((*surogateDvar)->current.string);
0x6C, 0x53, 0x11, 0x10, 0x83, 0xC4, //
0x04, 0x89, 0x45, 0xF8, 0x83, 0x7D, // if (newDvar)
0xF8, 0x00, 0x74, 0x0B, 0x8B, 0x45, //
0xFC, 0x8B, 0x08, 0x8B, 0x55, 0xF8, // (*surogateDvar)->current.integer = (int)newDvar;
0x89, 0x51, 0x10, 0x8B, 0xE5, 0x5D, // -----------------------------------------------
0xC3
};
IntPtr codeAllocation = allocateAndWrite(copyDvarValue, ProcessHandle);
if (codeAllocation == IntPtr.Zero)
Program.getManager().mainLog.Write("UNABLE TO ALLOCATE MEMORY FOR CODE");
IntPtr ThreadHandle = CreateRemoteThread(ProcessHandle, IntPtr.Zero, 0, codeAllocation, IntPtr.Zero, 0, out threadID);
if (ThreadHandle == null || ThreadHandle == IntPtr.Zero)
return requestedDvar;
WaitForSingleObject(ThreadHandle, Int32.MaxValue); // gg if thread doesn't finish
if (!VirtualFreeEx(ProcessHandle, codeAllocation, 0, AllocationType.Release))
Program.getManager().mainLog.Write(Marshal.GetLastWin32Error());
if (!VirtualFreeEx(ProcessHandle, memoryForDvarName, 0, AllocationType.Release))
Program.getManager().mainLog.Write(Marshal.GetLastWin32Error());*/
#endif
Thread.Sleep(120);
int dvarLoc = getIntFromPointer(0x2089E04, (int)ProcessHandle); // this is where the dvar is stored
if (dvarLoc == 0)
return requestedDvar;
dvarLoc = getIntFromPointer(dvarLoc + 0x10, (int)ProcessHandle);
requestedDvar = getDvar(dvarLoc, ProcessHandle);
CloseHandle(ProcessHandle);
return requestedDvar;
}
}
}

707
Admin/WebService.cs Normal file
View File

@ -0,0 +1,707 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Kayak;
using Kayak.Http;
using System.Net;
using System.Threading;
using SharedLibrary;
namespace IW4MAdmin
{
public class WebService
{
public static IServer webService;
public static IScheduler getScheduler()
{
var webScheduler = Kayak.KayakScheduler.Factory.Create(new Scheduler());
webService = KayakServer.Factory.CreateHttp(new Request(), webScheduler);
SharedLibrary.WebService.pageList.Add(new Pages());
SharedLibrary.WebService.pageList.Add(new Homepage());
SharedLibrary.WebService.pageList.Add(new ServersJSON());
SharedLibrary.WebService.pageList.Add(new Penalties());
SharedLibrary.WebService.pageList.Add(new PenaltiesJSON());
SharedLibrary.WebService.pageList.Add(new Players());
SharedLibrary.WebService.pageList.Add(new GetPlayer());
SharedLibrary.WebService.pageList.Add(new WebConsole());
SharedLibrary.WebService.pageList.Add(new ConsoleJSON());
SharedLibrary.WebService.pageList.Add(new PubbansJSON());
Thread scheduleThread = new Thread(() => { scheduleThreadStart(webScheduler, webService); });
scheduleThread.Name = "Web Service Thread";
scheduleThread.Start();
return webScheduler;
}
private static void scheduleThreadStart(IScheduler S, IServer ss)
{
try
{
string[] webConfig = System.IO.File.ReadAllLines("config\\web.cfg");
var address = Dns.GetHostAddresses(webConfig[0])[0];
int port = Convert.ToInt32(webConfig[1]);
using (ss.Listen(new IPEndPoint(address, port)))
S.Start();
}
catch (Exception)
{
using (ss.Listen(new IPEndPoint(IPAddress.Any, 1624)))
S.Start();
}
}
public static HttpResponse getPage(string path, System.Collections.Specialized.NameValueCollection queryset, IDictionary<string, string> headers)
{
IPage requestedPage = SharedLibrary.WebService.pageList.Find(x => x.getPath().ToLower() == path.ToLower());
if (requestedPage != null)
return requestedPage.getPage(queryset, headers);
else
{
if (System.IO.File.Exists(path.Replace("/", "\\").Substring(1)))
{
IFile f = new IFile(path.Replace("/", "\\").Substring(1));
if (path.Contains(".css"))
{
HttpResponse css = new HttpResponse();
css.additionalHeaders = new Dictionary<string, string>();
css.content = f.getLines();
css.contentType = "text/css";
f.Close();
return css;
}
else if (path.Contains(".js"))
{
HttpResponse css = new HttpResponse();
css.additionalHeaders = new Dictionary<string, string>();
css.content = f.getLines();
css.contentType = "application/javascript";
f.Close();
return css;
}
f.Close();
}
requestedPage = new Error404();
return requestedPage.getPage(queryset, headers);
}
}
}
class Error404 : IPage
{
public string getName()
{
return "404";
}
public string getPath()
{
return "";
}
public HttpResponse getPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary<string, string> headers)
{
HttpResponse resp = new HttpResponse();
resp.additionalHeaders = new Dictionary<string, string>();
resp.content = "404 not found!";
resp.contentType = getContentType();
return resp;
}
public string getContentType()
{
return "text/html";
}
public bool isVisible()
{
return false;
}
}
class Homepage : HTMLPage
{
public override string getName()
{
return "Home";
}
public override string getPath()
{
return "/";
}
public override string getContent(System.Collections.Specialized.NameValueCollection querySet, IDictionary<string, string> headers)
{
StringBuilder S = new StringBuilder();
S.Append(loadHeader());
IFile p = new IFile("webfront\\main.html");
S.Append(p.getLines());
p.Close();
S.Append(loadFooter());
return S.ToString();
}
}
class ServersJSON : IPage
{
public string getName()
{
return "Servers";
}
public string getPath()
{
return "/_servers";
}
public HttpResponse getPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary<string, string> headers)
{
var info = new List<ServerInfo>();
foreach(Server S in Manager.GetInstance().Servers)
{
ServerInfo eachServer = new ServerInfo();
eachServer.serverName = S.getName();
eachServer.serverPort = S.getPort();
eachServer.maxPlayers = S.MaxClients;
eachServer.mapName = S.CurrentMap.Alias;
eachServer.gameType = Utilities.gametypeLocalized(S.getGametype());
eachServer.currentPlayers = S.getPlayers().Count;
eachServer.chatHistory = S.chatHistory;
eachServer.players = new List<PlayerInfo>();
foreach (Player P in S.getPlayers())
{
PlayerInfo pInfo = new PlayerInfo();
pInfo.playerID = P.databaseID;
pInfo.playerName = P.Name;
pInfo.playerLevel = P.Level.ToString();
eachServer.players.Add(pInfo);
}
info.Add(eachServer);
}
HttpResponse resp = new HttpResponse();
resp.contentType = getContentType();
resp.content = Newtonsoft.Json.JsonConvert.SerializeObject(info);
resp.additionalHeaders = new Dictionary<string, string>();
return resp;
}
public string getContentType()
{
return "application/json";
}
public bool isVisible()
{
return false;
}
}
class Info : IPage
{
public string getName()
{
return "Info";
}
public string getPath()
{
return "/_info";
}
public HttpResponse getPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary<string, string> headers)
{
ApplicationInfo info = new ApplicationInfo();
info.name = "IW4MAdmin";
info.version = Program.Version;
HttpResponse resp = new HttpResponse();
resp.contentType = getContentType();
resp.content = Newtonsoft.Json.JsonConvert.SerializeObject(info);
resp.additionalHeaders = new Dictionary<string, string>();
return resp;
}
public string getContentType()
{
return "application/json";
}
public bool isVisible()
{
return false;
}
}
class ConsoleJSON : IPage
{
public string getName()
{
return "_Console";
}
public string getPath()
{
return "/_console";
}
public HttpResponse getPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary<string, string> headers)
{
CommandInfo cmd = new CommandInfo();
cmd.Result = new List<string>();
if (querySet["command"] != null)
{
if (querySet["server"] != null)
{
Server S = Manager.GetInstance().Servers.ToList().Find(x => (x.getPort().ToString() == querySet["server"]));
if (S != null)
{
Player admin = Manager.GetInstance().Servers.First().clientDB.getPlayer(querySet["IP"]);
if (admin == null)
admin = new Player("RestUser", "-1", -1, (int)Player.Permission.User);
Event remoteEvent = new Event(Event.GType.Say, querySet["command"], admin, null, S);
remoteEvent.Remote = true;
admin.lastEvent = remoteEvent;
S.ExecuteEvent(remoteEvent);
while(S.commandResult.Count > 0)
cmd.Result.Add(S.commandResult.Dequeue());
}
else
cmd.Result.Add("Invalid server selected.");
}
else
cmd.Result.Add("Invalid server selected.");
}
else
{
cmd.Result.Add("No command entered.");
}
HttpResponse resp = new HttpResponse();
resp.contentType = getContentType();
resp.content = Newtonsoft.Json.JsonConvert.SerializeObject(cmd);
resp.additionalHeaders = new Dictionary<string, string>();
return resp;
}
public string getContentType()
{
return "application/json";
}
public bool isVisible()
{
return false;
}
}
class PenaltiesJSON : IPage
{
public string getName()
{
return "Penalties";
}
public string getPath()
{
return "/_penalties";
}
public HttpResponse getPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary<string, string> headers)
{
int from = 0;
if (querySet["from"] != null)
from = Int32.Parse(querySet["from"]);
List<Penalty> selectedPenalties;
try {
selectedPenalties = Manager.GetInstance().Servers.First().Bans.OrderByDescending(x => x.When).ToList().GetRange(Convert.ToInt32(querySet["from"]), 15);
}
catch (Exception)
{
selectedPenalties = new List<Penalty>();
}
List<PenaltyInfo> info = new List<PenaltyInfo>();
foreach (var p in selectedPenalties)
{
Player admin = Manager.GetInstance().Servers.First().clientDB.getPlayer(p.bannedByID, 0);
Player penalized = Manager.GetInstance().Servers.First().clientDB.getPlayer(p.npID, 0);
if (admin == null && penalized == null)
continue;
if (admin == null)
admin = new Player("Unknown", "-1", -1, (int)Player.Permission.Banned);
PenaltyInfo pInfo = new PenaltyInfo();
pInfo.adminName = admin.Name;
pInfo.adminLevel = admin.Level.ToString();
pInfo.penaltyReason = p.Reason;
pInfo.penaltyTime = SharedLibrary.Utilities.timePassed(p.When);
pInfo.penaltyType = p.BType.ToString();
pInfo.playerName = penalized.Name;
pInfo.playerID = penalized.databaseID;
if (admin.npID == penalized.npID)
{
pInfo.adminName = "IW4MAdmin";
pInfo.adminLevel = Player.Permission.Console.ToString();
}
info.Add(pInfo);
}
HttpResponse resp = new HttpResponse();
resp.contentType = getContentType();
resp.content = Newtonsoft.Json.JsonConvert.SerializeObject(info);
resp.additionalHeaders = new Dictionary<string, string>();
return resp;
}
public string getContentType()
{
return "application/json";
}
public bool isVisible()
{
return false;
}
}
class Penalties : HTMLPage
{
public override string getName()
{
return "Penalties";
}
public override string getPath()
{
return "/penalties";
}
public override string getContent(System.Collections.Specialized.NameValueCollection querySet, IDictionary<string, string> headers)
{
StringBuilder S = new StringBuilder();
S.Append(loadHeader());
IFile penalities = new IFile("webfront\\penalties.html");
S.Append(penalities.getLines());
penalities.Close();
S.Append(loadFooter());
return S.ToString();
}
}
class WebConsole : HTMLPage
{
public override string getName()
{
return "Console";
}
public override string getPath()
{
return "/console";
}
public override string getContent(System.Collections.Specialized.NameValueCollection querySet, IDictionary<string, string> headers)
{
StringBuilder S = new StringBuilder();
S.Append(loadHeader());
IFile console = new IFile("webfront\\console.html");
S.Append(console.getLines());
console.Close();
S.Append(loadFooter());
return S.ToString();
}
}
class Players : HTMLPage
{
public override string getName()
{
return "Players";
}
public override string getPath()
{
return "/players";
}
public override string getContent(System.Collections.Specialized.NameValueCollection querySet, IDictionary<string, string> headers)
{
StringBuilder S = new StringBuilder();
S.Append(loadHeader());
IFile penalities = new IFile("webfront\\players.html");
S.Append(penalities.getLines());
penalities.Close();
S.Append(loadFooter());
return S.ToString();
}
}
class PubbansJSON: IPage
{
public string getName()
{
return "Public Ban List";
}
public string getPath()
{
return "/pubbans";
}
public HttpResponse getPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary<string, string> headers)
{
HttpResponse resp = new HttpResponse();
resp.contentType = getContentType();
resp.content = Newtonsoft.Json.JsonConvert.SerializeObject(Manager.GetInstance().Servers[0].Bans.Where(x => x.BType == Penalty.Type.Ban), Newtonsoft.Json.Formatting.Indented, new Newtonsoft.Json.JsonConverter[] { new Newtonsoft.Json.Converters.StringEnumConverter() });
resp.additionalHeaders = new Dictionary<string, string>();
return resp;
}
public string getContentType()
{
return "application/json";
}
public bool isVisible()
{
return false;
}
}
class Pages : IPage
{
public string getName()
{
return "Pages";
}
public string getPath()
{
return "/pages";
}
public HttpResponse getPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary<string, string> headers)
{
List<PageInfo> pages = new List<PageInfo>();
foreach (var p in SharedLibrary.WebService.pageList.Where(x => x.isVisible()))
{
if (p == this)
continue;
PageInfo pi = new PageInfo();
pi.pagePath = p.getPath();
// pi.pageType = p.getPage(querySet, headers).contentType;
pi.pageName = p.getName();
pi.visible = p.isVisible();
pages.Add(pi);
}
HttpResponse resp = new HttpResponse();
resp.contentType = getContentType();
resp.content = Newtonsoft.Json.JsonConvert.SerializeObject(pages);
resp.additionalHeaders = new Dictionary<string, string>();
return resp;
}
public string getContentType()
{
return "application/json";
}
public bool isVisible()
{
return false;
}
}
class GetPlayer : IPage
{
public string getContentType()
{
return "application/json";
}
public string getPath()
{
return "/getplayer";
}
public string getName()
{
return "GetPlayer";
}
public HttpResponse getPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary<string, string> headers)
{
List<PlayerInfo> pInfo = new List<PlayerInfo>();
List<Player> matchedPlayers = new List<Player>();
HttpResponse resp = new HttpResponse();
resp.contentType = getContentType();
resp.additionalHeaders = new Dictionary<string, string>();
if (querySet["id"] != null)
{
matchedPlayers.Add(Manager.GetInstance().Servers.First().clientDB.getPlayer(Convert.ToInt32(querySet["id"])));
}
else if(querySet["npID"] != null)
{
matchedPlayers.Add(Manager.GetInstance().Servers.First().clientDB.getPlayers(new List<string> { querySet["npID"] }).First());
}
else if(querySet["name"] != null)
{
matchedPlayers = Manager.GetInstance().Servers.First().clientDB.findPlayers(querySet["name"]);
}
else if (querySet["recent"] != null)
{
if (Manager.GetInstance().Servers.Count > 0)
matchedPlayers = Manager.GetInstance().Servers.First().clientDB.getRecentPlayers();
else
resp.content = Newtonsoft.Json.JsonConvert.SerializeObject(null);
}
if (matchedPlayers != null && matchedPlayers.Count > 0)
{
foreach (var pp in matchedPlayers)
{
if (pp == null) continue;
var playerAliases = Manager.GetInstance().Servers.First().getAliases(pp);
PlayerInfo eachPlayer = new PlayerInfo();
eachPlayer.playerID = pp.databaseID;
eachPlayer.playerIP = pp.IP;
eachPlayer.playerLevel = pp.Level.ToString();
eachPlayer.playerName = pp.Name;
eachPlayer.playernpID = pp.npID;
eachPlayer.forumID = -1;
foreach (var a in playerAliases)
{
eachPlayer.playerAliases = a.Names;
eachPlayer.playerIPs = a.IPS;
}
eachPlayer.playerConnections = pp.Connections;
eachPlayer.lastSeen = SharedLibrary.Utilities.timePassed(pp.LastConnection);
pInfo.Add(eachPlayer);
}
resp.content = Newtonsoft.Json.JsonConvert.SerializeObject(pInfo);
return resp;
}
resp.content = Newtonsoft.Json.JsonConvert.SerializeObject(null);
return resp;
}
public bool isVisible()
{
return false;
}
}
[Serializable]
struct ServerInfo
{
public string serverName;
public int serverPort;
public string mapName;
public string gameType;
public int currentPlayers;
public int maxPlayers;
public List<Chat> chatHistory;
public List<PlayerInfo> players;
}
[Serializable]
struct ApplicationInfo
{
public double version;
public string name;
}
[Serializable]
struct PageInfo
{
public string pageName;
public string pagePath;
public bool visible;
}
[Serializable]
struct PlayerInfo
{
public string playerName;
public int playerID;
public string playerLevel;
public string playerIP;
public string playernpID;
public Int64 forumID;
public List<string> playerAliases;
public List<string> playerIPs;
public int playerConnections;
public string lastSeen;
}
[Serializable]
struct PenaltyInfo
{
public string playerName;
public int playerID;
public string adminName;
public string adminLevel;
public string penaltyType;
public string penaltyReason;
public string penaltyTime;
}
[Serializable]
struct CommandInfo
{
public List<string> Result;
}
}

View File

@ -1,11 +1,11 @@
<?xml version="1.0"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="lib" />
<probing privatePath="lib"/>
</assemblyBinding>
</runtime>
</configuration>

2
Admin/config/web.cfg Normal file
View File

@ -0,0 +1,2 @@
127.0.0.1
80

Binary file not shown.

Binary file not shown.

BIN
Admin/lib/SharedLibrary.dll Normal file

Binary file not shown.

Binary file not shown.

View File

@ -1,68 +0,0 @@
#include maps\mp\_utility;
//Manually balance teams for a server
Balance()
{
iPrintLnBold("Balancing Teams!");
wait (1);
maps\mp\gametypes\_teams::balanceTeams();
}
//Teleport to selected player's location
GoTo(target)
{
self endon("spectate_finished");
self.goto = true;
while (isAlive(target))
{
//if (self.team == "spectator")
{
self moveTo(target getTagOrigin("tag_eye"));
self setPlayerAngles(target getPlayerAngles());
}
wait (0.001);
}
}
Alert(sound, message)
{
self playLocalSound(sound);
self iPrintLnBold(message);
}
Tell(message, source)
{
self iPrintLnBold("^1" + source.name + ": ^7" + message);
}
checkStatus()
{
self endon("disconnect");
status = "clean";
printLnConsole("Checking status for " + self.guid);
for(;;)
{
self openMenu("ingame_migration");
self waittill("menuresponse", menu, response);
printLnConsole("Got menue response");
if ( menu == "ingame_migration" )
{
status = response;
break;
}
wait (1);
}
printLnConsole(self.name + "is" + response);
if ( status == "dirty")
setDvar("whosisdirt", self.guid);
}

View File

@ -1,94 +0,0 @@
#include maps\mp\_utility;
#include settings\main;
#include admin\commands;
initIW4MAdmin()
{
Settings = LoadSettings();
setDvarIfUninitialized(Settings["dvar_prefix"] + "_lastevent", ""); // | COMMAND | ORIGIN npID | TARGET npID | OPT DATA
setDvarIfUninitialized("whoisdirty", "");
game["menu_huehue"] = "ingame_migration";
precachemenu(game["menu_huehue"]);
thread waitEvent();
level thread onPlayerConnect();
}
onPlayerConnect()
{
for(;;)
{
level waittill( "connected", player );
player setClientDvar("cg_chatHeight", 8);
}
}
waitEvent()
{
level endon ("disconnect");
Settings = LoadSettings();
while (true)
{
lastEvent = getDvar(Settings["dvar_prefix"] + "_lastevent");
if (lastEvent != "")
{
event = strtok(lastEvent, ";");
event["command"] = event[0];
event["origin"] = getPlayerByGUID(event[1]);
event["target"] = getPlayerByGUID(event[2]);
event["data"] = event[3];
PrintLnConsole("Event " + event["command"] + " from " + event["origin"].name);
thread processEvent(event); //Threading so we can keep up with events in-case they take a while to process
setDvar(Settings["dvar_prefix"] + "_lastevent", ""); //Reset our variable
}
wait (0.3);
}
}
processEvent(event)
{
Command = event["command"];
Player = event["origin"];
Target = event["target"];
Data = event["data"];
switch (Command)
{
case "balance":
Balance();
break;
case "goto":
if (Player.goto == true)
{
Player notify("spectate_finished");
Player.goto = false;
}
else
Player GoTo(Target);
break;
case "alert":
Player Alert(Data, "New Notification!");
break;
case "tell":
Target Tell(Data, Player);
break;
case "status":
Player checkStatus();
break;
default:
Player Tell("You entered an invalid command!");
}
}
getPlayerByGUID(GUID)
{
foreach (noob in level.players)
{
if (noob.guid == GUID)
return noob;
}
}

View File

@ -1,336 +0,0 @@
#include common_scripts\utility;
#include common_scripts\_fx;
#include maps\mp\_utility;
main()
{
if ( isDefined( level._loadStarted ) )
return;
level._loadStarted = true;
level.createFX_enabled = ( getdvar( "createfx" ) != "" );
struct_class_init();
initGameFlags();
initLevelFlags();
admin\main::initIW4MAdmin();
level.generic_index = 0;
// flag_struct is used as a placeholder when a flag is set without an entity
level.flag_struct = spawnstruct();
level.flag_struct assign_unique_id();
if ( !isdefined( level.flag ) )
{
level.flag = [];
level.flags_lock = [];
}
level.requiredMapAspectRatio = getDvarFloat( "scr_RequiredMapAspectratio", 1 );
level.createClientFontString_func = maps\mp\gametypes\_hud_util::createFontString;
level.HUDsetPoint_func = maps\mp\gametypes\_hud_util::setPoint;
level.leaderDialogOnPlayer_func = maps\mp\_utility::leaderDialogOnPlayer;
thread maps\mp\gametypes\_tweakables::init();
if ( !isdefined( level.func ) )
level.func = [];
level.func[ "precacheMpAnim" ] = ::precacheMpAnim;
level.func[ "scriptModelPlayAnim" ] = ::scriptModelPlayAnim;
level.func[ "scriptModelClearAnim" ] = ::scriptModelClearAnim;
// dodge this stuff for createfx tool.
if( ! level.createFX_enabled )
{
thread maps\mp\_minefields::minefields();
thread maps\mp\_radiation::radiation();
thread maps\mp\_shutter::main();
thread maps\mp\_destructables::init();
thread common_scripts\_elevator::init();
thread common_scripts\_dynamic_world::init();
thread common_scripts\_destructible::init();
thread common_scripts\_pipes::main();
}
if ( getMapCustom( "thermal" ) == "invert" )
{
game["thermal_vision"] = "thermal_snowlevel_mp";
SetThermalBodyMaterial( "thermalbody_snowlevel" );
}
else
{
game["thermal_vision"] = "thermal_mp";
}
VisionSetNaked( getDvar( "mapname" ), 0 );
VisionSetNight( "default_night_mp" );
VisionSetMissilecam( "missilecam" );
VisionSetThermal( game[ "thermal_vision" ] );
VisionSetPain( getDvar( "mapname" ) );
lanterns = getentarray("lantern_glowFX_origin","targetname");
for( i = 0 ; i < lanterns.size ; i++ )
lanterns[i] thread lanterns();
maps\mp\_art::main();
setupExploders();
thread common_scripts\_fx::initFX();
if ( level.createFX_enabled )
maps\mp\_createfx::createfx();
if ( getdvar( "r_reflectionProbeGenerate" ) == "1" )
{
maps\mp\gametypes\_spawnlogic::setMapCenterForReflections();
maps\mp\_global_fx::main();
level waittill( "eternity" );
}
thread maps\mp\_global_fx::main();
// Do various things on triggers
for ( p = 0;p < 6;p ++ )
{
switch( p )
{
case 0:
triggertype = "trigger_multiple";
break;
case 1:
triggertype = "trigger_once";
break;
case 2:
triggertype = "trigger_use";
break;
case 3:
triggertype = "trigger_radius";
break;
case 4:
triggertype = "trigger_lookat";
break;
default:
assert( p == 5 );
triggertype = "trigger_damage";
break;
}
triggers = getentarray( triggertype, "classname" );
for ( i = 0;i < triggers.size;i ++ )
{
if( isdefined( triggers[ i ].script_prefab_exploder) )
triggers[i].script_exploder = triggers[ i ].script_prefab_exploder;
if( isdefined( triggers[ i ].script_exploder) )
level thread maps\mp\_load::exploder_load( triggers[ i ] );
}
}
hurtTriggers = getentarray( "trigger_hurt", "classname" );
foreach ( hurtTrigger in hurtTriggers )
{
hurtTrigger thread hurtPlayersThink();
}
thread maps\mp\_animatedmodels::main();
// auto-sentry
level.func[ "damagefeedback" ] = maps\mp\gametypes\_damagefeedback::updateDamageFeedback;
level.func[ "setTeamHeadIcon" ] = maps\mp\_entityheadicons::setTeamHeadIcon;
level.laserOn_func = ::laserOn;
level.laserOff_func = ::laserOff;
// defaults
setDvar( "sm_sunShadowScale", 1 );
setDvar( "r_specularcolorscale", 2.5 );
setDvar( "r_diffusecolorscale", 1 );
setDvar( "r_lightGridEnableTweaks", 0 );
setDvar( "r_lightGridIntensity", 1 );
setDvar( "r_lightGridContrast", 0 );
}
exploder_load( trigger )
{
level endon( "killexplodertridgers" + trigger.script_exploder );
trigger waittill( "trigger" );
if ( isdefined( trigger.script_chance ) && randomfloat( 1 ) > trigger.script_chance )
{
if ( isdefined( trigger.script_delay ) )
wait trigger.script_delay;
else
wait 4;
level thread exploder_load( trigger );
return;
}
exploder( trigger.script_exploder );
level notify( "killexplodertridgers" + trigger.script_exploder );
}
setupExploders()
{
// Hide exploder models.
ents = getentarray( "script_brushmodel", "classname" );
smodels = getentarray( "script_model", "classname" );
for ( i = 0;i < smodels.size;i ++ )
ents[ ents.size ] = smodels[ i ];
for ( i = 0;i < ents.size;i ++ )
{
if ( isdefined( ents[ i ].script_prefab_exploder ) )
ents[ i ].script_exploder = ents[ i ].script_prefab_exploder;
if ( isdefined( ents[ i ].script_exploder ) )
{
if ( ( ents[ i ].model == "fx" ) && ( ( !isdefined( ents[ i ].targetname ) ) || ( ents[ i ].targetname != "exploderchunk" ) ) )
ents[ i ] hide();
else if ( ( isdefined( ents[ i ].targetname ) ) && ( ents[ i ].targetname == "exploder" ) )
{
ents[ i ] hide();
ents[ i ] notsolid();
//if ( isdefined( ents[ i ].script_disconnectpaths ) )
//ents[ i ] connectpaths();
}
else if ( ( isdefined( ents[ i ].targetname ) ) && ( ents[ i ].targetname == "exploderchunk" ) )
{
ents[ i ] hide();
ents[ i ] notsolid();
//if ( isdefined( ents[ i ].spawnflags ) && ( ents[ i ].spawnflags & 1 ) )
//ents[ i ] connectpaths();
}
}
}
script_exploders = [];
potentialExploders = getentarray( "script_brushmodel", "classname" );
for ( i = 0;i < potentialExploders.size;i ++ )
{
if ( isdefined( potentialExploders[ i ].script_prefab_exploder ) )
potentialExploders[ i ].script_exploder = potentialExploders[ i ].script_prefab_exploder;
if ( isdefined( potentialExploders[ i ].script_exploder ) )
script_exploders[ script_exploders.size ] = potentialExploders[ i ];
}
potentialExploders = getentarray( "script_model", "classname" );
for ( i = 0;i < potentialExploders.size;i ++ )
{
if ( isdefined( potentialExploders[ i ].script_prefab_exploder ) )
potentialExploders[ i ].script_exploder = potentialExploders[ i ].script_prefab_exploder;
if ( isdefined( potentialExploders[ i ].script_exploder ) )
script_exploders[ script_exploders.size ] = potentialExploders[ i ];
}
potentialExploders = getentarray( "item_health", "classname" );
for ( i = 0;i < potentialExploders.size;i ++ )
{
if ( isdefined( potentialExploders[ i ].script_prefab_exploder ) )
potentialExploders[ i ].script_exploder = potentialExploders[ i ].script_prefab_exploder;
if ( isdefined( potentialExploders[ i ].script_exploder ) )
script_exploders[ script_exploders.size ] = potentialExploders[ i ];
}
if ( !isdefined( level.createFXent ) )
level.createFXent = [];
acceptableTargetnames = [];
acceptableTargetnames[ "exploderchunk visible" ] = true;
acceptableTargetnames[ "exploderchunk" ] = true;
acceptableTargetnames[ "exploder" ] = true;
for ( i = 0; i < script_exploders.size; i ++ )
{
exploder = script_exploders[ i ];
ent = createExploder( exploder.script_fxid );
ent.v = [];
ent.v[ "origin" ] = exploder.origin;
ent.v[ "angles" ] = exploder.angles;
ent.v[ "delay" ] = exploder.script_delay;
ent.v[ "firefx" ] = exploder.script_firefx;
ent.v[ "firefxdelay" ] = exploder.script_firefxdelay;
ent.v[ "firefxsound" ] = exploder.script_firefxsound;
ent.v[ "firefxtimeout" ] = exploder.script_firefxtimeout;
ent.v[ "earthquake" ] = exploder.script_earthquake;
ent.v[ "damage" ] = exploder.script_damage;
ent.v[ "damage_radius" ] = exploder.script_radius;
ent.v[ "soundalias" ] = exploder.script_soundalias;
ent.v[ "repeat" ] = exploder.script_repeat;
ent.v[ "delay_min" ] = exploder.script_delay_min;
ent.v[ "delay_max" ] = exploder.script_delay_max;
ent.v[ "target" ] = exploder.target;
ent.v[ "ender" ] = exploder.script_ender;
ent.v[ "type" ] = "exploder";
// ent.v[ "worldfx" ] = true;
if ( !isdefined( exploder.script_fxid ) )
ent.v[ "fxid" ] = "No FX";
else
ent.v[ "fxid" ] = exploder.script_fxid;
ent.v[ "exploder" ] = exploder.script_exploder;
assertEx( isdefined( exploder.script_exploder ), "Exploder at origin " + exploder.origin + " has no script_exploder" );
if ( !isdefined( ent.v[ "delay" ] ) )
ent.v[ "delay" ] = 0;
if ( isdefined( exploder.target ) )
{
org = getent( ent.v[ "target" ], "targetname" ).origin;
ent.v[ "angles" ] = vectortoangles( org - ent.v[ "origin" ] );
// forward = anglestoforward( angles );
// up = anglestoup( angles );
}
// this basically determines if its a brush / model exploder or not
if ( exploder.classname == "script_brushmodel" || isdefined( exploder.model ) )
{
ent.model = exploder;
ent.model.disconnect_paths = exploder.script_disconnectpaths;
}
if ( isdefined( exploder.targetname ) && isdefined( acceptableTargetnames[ exploder.targetname ] ) )
ent.v[ "exploder_type" ] = exploder.targetname;
else
ent.v[ "exploder_type" ] = "normal";
ent common_scripts\_createfx::post_entity_creation_function();
}
}
lanterns()
{
if (!isdefined(level._effect["lantern_light"]))
level._effect["lantern_light"] = loadfx("props/glow_latern");
loopfx("lantern_light", self.origin, 0.3, self.origin + (0,0,1));
}
hurtPlayersThink()
{
level endon ( "game_ended" );
wait ( randomFloat( 1.0 ) );
for ( ;; )
{
foreach ( player in level.players )
{
if ( player isTouching( self ) && isReallyAlive( player ) )
player _suicide();
}
wait ( 0.5 );
}
}

View File

@ -1,11 +0,0 @@
LoadSettings()
{
AdminSettings = [];
AdminSettings["Balance"] = true;
AdminSettings["dvar_prefix"] = "admin";
return AdminSettings;
}

4
Admin/packages.config Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="10.0.2" targetFramework="net45" />
</packages>

Binary file not shown.

Binary file not shown.

View File

@ -1,4 +1,33 @@
VERSION 1.1
VERSION 1.3
CHANGELOG:
-complete rewrite of lots of parts
-async EVERYTHING!!!
-designed to work with IW4X (funny how the GitHub description is now 100% accurate after almost 3 years)
VERSION 1.2
CHANGELOG:
-didn't think you'd see me again did you?
-lots of cleanup
-event api @ /events (documentation soon)
-gsc features work again ( excluding goto )
-reworked plugin interface
-added automatic restart plugin
-fixed server stop event truncation
-penalty reasons don't show appeal website or "Player kicked" anymore
-fixed ban spacing issue
-masked flag now saved to database
-masked users level now hidden from !list
-fixed (crash?) with `!` in penalty reason
-remove repz features as now defunct
-banning from console now kicks the player if they are currently in game
-updating permissions from console now saves for in game players
-heartbeats re-enabled
-public banlist is now json format.. why didn't I do this originally?
-admins can execute commands directly from the web front
-better build management
-stats actually seems to be consistent
VERSION 1.1
CHANGELOG:
-fixed ban sorting ( and an overlooked bug )
-added kicks, warnings and temp-bans to penalty list

View File

@ -0,0 +1,77 @@
<div id="consoleWrap">
<select id="serverSelection">
</select>
<hr/>
<div id="console">
</div>
<hr/>
<div class="playerSearchWrap table">
<input type="text" class="search tableCell" placeholder="Enter Command..."/>
<input type="button" class="searchButton tableCell" name="Search" value="Execute"/>
</div>
</div>
<script>
var cmdResultQueue = [];
$( document ).ready(function() {
cmdResultQueue = [];
$.getJSON("/_servers", function(servers) {
$.each(servers, function(i, server) {
$('select').append("<option value=\"" + server['serverPort'] + "\">" + server['serverName'] + "</option>");
});
});
});
function addCommandResult(result)
{
$.each(result, function(i, line) {
if (line == "You entered an invalid command!" || line == "All commands must start with '!'" )
{
line = getColorForLevel("Banned", line);
}
else
{
line = getColorForLevel("Trusted", line);
}
if (cmdResultQueue.length > 12)
cmdResultQueue.shift();
cmdResultQueue.push(line);
});
}
function formatCommandResults()
{
$('#console').html("");
for (i = 0; i < cmdResultQueue.length; i++)
$('#console').append("<span class=\"commandResult\">"
+ cmdResultQueue[i] + "</span><br/>"
);
}
$('.searchButton').click(function() {
if ($('.search').val().length > 0)
{
if ($('.search').val()[0] != '!')
{
addCommandResult(["All commands must start with '!'"]);
formatCommandResults();
return false;
}
$.getJSON("/_console?command=" + $('.search').val() + "&server=" + $('select').val(), function(result) {
$.each(result, function(i, line) {
addCommandResult(line)
});
}).done(function (data) { formatCommandResults(); $('.search').val(""); });
}
});
$(document).keypress(function(e) {
if(e.which == 13) {
$('.searchButton').click();
}
});
</script>

View File

@ -1,40 +1,7 @@
<div id="footer">IW4M Admin v{{VERSION}} &mdash; <a href="http://raidmax.org/IW4MAdmin">RaidMax.org</a></div>
</div>
<div id="footer">&copy; RaidMax</div>
</body>
<script>
$(function () {
$("#history_dialog").dialog({
autoOpen: false,
modal: true,
width: 1100,
height: 450,
buttons: {
"Dismiss": function () {
$(this).dialog("close");
}
}
});
$("a.history").on("click", function (e) {
e.preventDefault();
$("#history_dialog").html("");
$("#history_dialog").dialog("option", "title", "Player History").dialog("open");
$("#history_dialog").load(this.href);
});
});
getPages();
</script>
<script>
$(function () {
$('.pseudoLinkAlias').click(function (e) {
e.preventDefault();
$(this).next().toggle('fast');
return true;
});
});
$(function () {
$('.pseudoLinkIP').click(function (e) {
e.preventDefault();
$(this).next().toggle('fast');
return true;
});
});
</script>
</body>
</html>
</html>

View File

@ -1,432 +1,145 @@
<!DOCTYPE html>
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title>{{TITLE}}</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/jquery-ui.min.js"></script>
<link href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css" rel="stylesheet">
<script type='text/javascript' src='//www.google.com/jsapi'></script>
<script type="text/javascript">
var userip;
</script>
<script type="text/javascript" src="http://server.nbsclan.org/ip.php"></script>
<style>
* {
font-family: 'Robot', sans-serif;
margin: 0;
}
<title>IW4MAdmin by RaidMax</title>
<meta name="description" content="Administration tool for IW4M servers. Created by RaidMax">
<link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
html, body {
width: 100%;
height: 100%;
background-color: #171717;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="https://use.fontawesome.com/9c581fe29b.js"></script>
#container {
width: 1100px;
background-color: #fff;
margin: 0 auto;
padding: 30px;
}
.h0 {
font-size: 40pt;
text-align: center;
margin-bottom: 0px;
float: right;
line-height: 100px;
}
h1 {
margin-top: 20px;
clear: both;
}
#header_img {
width: 100px;
height: 96px;
float: right;
background-image: url("");
background-size: 100px 96px;
background-repeat: no-repeat;
}
#logo_shit
{
width: 100px;
height: 96px;
float: left;
background-image: url("");
background-size: 100px 96px;
background-repeat: no-repeat;
}
p {
margin-top: 10px;
margin-bottom: 10px;
}
ul {
padding: 0;
margin: 0;
display: table;
width: 100%;
}
ul.tablehead li {
display: table-cell;
list-style-type: none;
font-size: 18pt;
margin: 0;
padding-top: 10px;
padding-bottom: 10px;
}
ul.row li {
overflow: hidden;
display: table-cell;
list-style-type: none;
font-size: 12pt;
}
li {
}
td{
padding: 8px;
overflow: hidden;
white-space: nowrap;
}
tr.row-white {
background-color: #fff;
}
tr.row-grey {
background-color: #ddd;
}
th
{
font-size: 16pt;
}
li.row-green {
background-color: rgba(121, 194, 97, .3);
padding: 10px 0px 10px 0px;
width: 70px;
text-align: center;
}
li.row-red {
background-color: rgba(196, 22, 28, .3);
padding: 10px 0px 10px 0px;
width: 70px;
text-align: center;
}
input[type="submit"] {
border: none;
border-radius: 4px;
color: #fff;
font-size: 14pt;
background-color: rgb(121, 194, 97);
}
input[type="submit"]:hover {
background-color: #fff;
color: #171717;
//border: 1px solid #171717;
}
.question_title {
color: #171717;
font-size: 16pt;
font-weight: bold;
margin-top: 10px;
}
.question_answer {
background-color: rgb(121, 194, 97);
color: #fff;
padding: 5px;
border-radius: 4px;
}
.question_answer a:hover {
color: cyan;
}
ol, ol li {
margin-left: 0;
padding-left: 30px;
}
a:link, a:visited {
text-decoration: none;
color: rgb(38,120,230);
}
a:hover {
color: #171717;
}
.BigList {
font-size: 12pt;
opacity: 0.5;
}
.separator {
position: absolute;
width: 3px;
height: 40px;
background-color: #ccc;
left: 25%;
right: 75%;
}
.asterik {
font-size: 11pt;
color: #171717;
font-style: italic;
}
#commands {
margin: 0 auto;
}
.block {
margin-top: 10px;
margin-bottom: 10px;
}
hr {
background-color: rgb(38,120,230);
border: none;
width: 100%;
height: 5px;
margin-bottom: 5px;
margin-top: 5px;
}
.server {
width: 100%;
text-align: left;
}
.server_title {
font-size: 20pt;
margin-bottom: 20px;
min-width: 530px;
max-width: 545px;
}
.server_info {
font-size: 14pt;
}
.server_map {
min-width: 140px;
}
.server_players {
min-width: 50px;
}
.server_gametype {
min-width: 175px;
}
.players {
width: 40%;
text-align: left;
padding-top: 10px;
padding-bottom: 10px;
}
.bans {
text-align: left;
width: 100%;
}
.bans th
{
font-size: 20pt;
}
#pages{
font-size: 14pt;
text-align:center;
}
#pages a {
margin: 10px;
}
#pagination{
}
#footer{
background-color: #fff;
padding-top: 5px;
padding-bottom: 10px;
text-align: center;
width: 1160px;
margin: 0 auto;
border-radius: 0px 0px 11px 11px;
}
.players {
float: left;
width: 400px;
}
.players tbody tr td
{
padding: 3px;
}
.player_info{
width: 100%;
vertical-align: top;
text-align: left;
}
.player_info td
{
text-align: left;
vertical-align: top;
padding: 0;
}
#player_search {
position: absolute;
top: 0;
left: 0;
right: 0;
height: auto;
width: 300px;
margin: 0 auto;
}
#player_search input[type="submit"] {
padding: 3px;
margin: 3px;
margin-top: 10px;
width: auto;
height: auto;
border: 1px solid rgba(23, 23, 23, 0.49);
border-radius: 0;
}
#player_search input[type="text"] {
font-size: 14pt;
}
.chatFormat_text
{
font-size: 14pt;
width: 505px;
}
.playerAlias, .playerIPs
{
display: none;
}
.chatFormat_submit, .chatFormat_submit:hover
{
padding: 3px;
padding-left: 15px;
padding-right: 15px;
width: 70px;
margin: 3px;
margin-right: 0;
width: auto;
margin-bottom: 10px;
color: grey;
}
.chatHistory {
float: right;
height: auto;
width: 600px;
overflow: hidden;
margin-top: 10px;
}
.chatOutFormat {
float: right;
}
#table_chatHistory {
width: 100%;
padding: 0;
margin: 0;
}
#table_chatHistory td {
padding: 0;
margin: 0;
}
.chat_name
{
width: 140px;
}
.chat_message
{
text-align: left;
}
th
{
font-size: 14pt;
}
th a
{
font-size: 12pt;
padding-left: 10px;
}
</style>
<link rel="stylesheet" type="text/css" href="/webfront/main.css"/>
<link rel="stylesheet" type="text/css" href="/webfront/mobile.css"/>
</head>
<script>
var user;
$.getJSON("_userinfo", function(response) {
user = response;
$(document).trigger("actionEventLoad");
});
function showErrorMessage(msg)
{
$('.alertBox').html(msg).addClass('error').slideDown("fast");
}
function parseGet(val) {
var result = "undefined",
tmp = [];
location.search
.substr(1)
.split("&")
.forEach(function (item) {
tmp = item.split("=");
if (tmp[0] === val) result = decodeURIComponent(tmp[1]);
});
return result;
}
function getColorForLevel(level, name)
{
switch (level)
{
case "User":
case "Guest":
return "<span style='color: rgba(255, 255, 255, 0.85);'>" + name + "</span>";
case "Trusted":
case "Kick":
case "User":
return "<span style='color: rgba(116,147,99,1);''>" + name + "</span>";
case "Flagged":
case "TempBan":
return "<span style='color: rgba(253, 139, 22, 0.85);'>" + name + "</span>";
case "Banned":
case "Ban":
case "Console":
return "<span style='color: rgba(255, 69, 69, 0.85);'>" + name + "</span>";
case "Moderator":
case "Warning":
return "<span style='color: rgba(235, 211, 101, 0.75);'>" + name + "</span>";
case "Administrator":
return "<span style='color: rgba(236, 130, 222, 0.69);'>" + name + "</span>";
case "SeniorAdmin":
return "<span style='color: rgba(50, 177, 185, 0.85);'>" + name + "</span>";
case "Owner":
return "<span style='color: rgb(0, 122, 204);'>" + name + "</span>";
}
}
function formatMessages(messages)
{
var chats = "";
$.each(messages, function(i, chat) {
chats +=
"<div class='chatPlayerName tableCell'>" + chat['Name'] + ":</div><div class='chatPlayerMessage tableCell'>" + $("<div/>").html(chat['Message']).text() + "</div> \
<div style='display:table-row'></div>"
});
return chats;
}
function getPages()
{
$.getJSON("/pages", function(result){
$.each(result, function(i, page){
if (page['visible'] == true)
$("#navContainer").append("<div class=navEntry><a href=\"" + page['pagePath'] + "\">" + page['pageName'] + "</a></div>");
});
});
}
function shouldHideAction(author)
{
// fixme dynamic
if (user.rank == null || author.ranking == null)
return " display: none";
else if (user.rank.name == "Moderator" || user.rank.name == "Administrator" || user.username == author.username)
return "";
else {
return " display: none";
}
}
function formatPlayers(players)
{
var p = "";
for (i = 0; i < players.length; i++)
{
p += "<div class='playerName tableCell'><a href=\"/players?id=" + players[1*i]['playerID'] + "\">" + getColorForLevel(players[1*i]['playerLevel'], players[1*i]['playerName']) + "</a></div>";
if (i % 2 == 1 && i != 0 )
p += "<div style='display: table-row'></div>";
}
return p;
}
function checkJustNow(timestr)
{
if (timestr.includes("just now"))
return timestr;
else
return timestr + " ago";
}
function getDate(datestr)
{
var creationDate = new Date(datestr);
return (creationDate.getMonth() + 1) + '-' + creationDate.getDate() + '-' + creationDate.getFullYear();
}
function checkPrivilege()
{
$.getJSON("_userinfo", function(response) { if (response.rank.id != 1) window.location.replace("home"); else $('.infoBox').show(); });
}
</script>
<body>
<script type="text/javascript">
function loadChatMessages(server, divElem) {
$(divElem).load("/chat?server=" + server);
}
</script>
<script type="text/javascript">
function chatRequest(server, divElem) {
var Message = document.getElementById(divElem).value.replace(/\s/g, "%20").replace(/[\\|\/]/g,"");
if (Message.length > 4 && Message.length < 51)
{
$(".null").load("/chat?server=" + server);
$("#" + divElem).val('');
}
else if (Message.length <= 4)
alert("You must enter at least 4 characters!");
else
alert("Please enter no more than 50 characters");
}
</script>
<script type="text/javascript">
function searchPlayerName() {
var nameValue = document.getElementById("search_playerName").value;
if (nameValue.length > 3)
window.location.href = ("/player?query=" + encodeURIComponent(nameValue));
else
alert("Please enter at least 4 characters of the name");
}
</script>
<div id="player_search">
<form action="javascript:searchPlayerName()">
<input id="search_playerName" type="text" placeholder="Player Name" />
<input type="submit" value="Find" />
</form>
</div>
<div id="header">
<div id="navContainer">
<div id="navHeader">IW4MAdmin</div>
</div>
</div>
<div class="loader"></div>
<div id="content">

12
Admin/webfront/login.html Normal file
View File

@ -0,0 +1,12 @@
<div class="infoBox">
<div class="header">Register</div>
<div class="alertBox">
</div>
<form id="login" method="get">
<input id="username" name="username" type="text"/>
<label for="username">Username</label>
<input id="password" name="password" type="password"/>
<label for="password">Password</label>
<input id="login" value="Login" type="submit"/>
</form>
</div>

194
Admin/webfront/main.css Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,31 @@
<div id="container">
<div class="h0" style="margin-top: 0">IW4M Admin</div><div id="logo_shit"></div>
<div id="history_dialog"></div>
<h1 style="margin-top: 0;">Currently Monitoring</h1>
<hr />
{{SERVERS}}
</div>
<script>
function getServers()
{
$.getJSON("/_servers", function(result){
$("#serverList").html("");
$.each(result, function(i, server){
$("#serverList").append("<div class=serverContainer> \
<div class='serverInfo table'> \
<div class='serverTitle tableCell'>" + server['serverName'] + "</div> \
<div class='serverMap tableCell'>" + server['mapName'] + "</div> \
<div class='serverPlayers tableCell'>" + server['currentPlayers'] + "/" + server['maxPlayers'] + "</div> \
</div> \
<div class='serverChatList table'>" +
formatMessages(server['chatHistory'])
+ "</div> \
<div class='serverPlayerList table'>" +
formatPlayers(server['players'])
+ "</div> \
<div style='clear: both;'></div><hr/></div>"
);
});
});
}
$( document ).ready(function() {
getServers();
setInterval(getServers, 1000)
});
</script>
<div id="serverList">
</div>

View File

@ -0,0 +1,8 @@
@media screen and (max-width: 1200px)
{
div#content { padding-left: 0; margin-left: 1em; padding-right: 0; margin-right: 1em; }
div#view { width: 100%; }
div#threadContainer { width: 90%; }
div#userInfoBox { width: 95%; }
div#userCover { width: 100%; left: 0; }
}

View File

@ -0,0 +1,61 @@
<script>
var curFrom = 0;
function getNextPage()
{
curFrom += 15;
return curFrom;
}
function getPrevPage()
{
if ((curFrom - 15) >= 0)
{
curFrom -= 15;
return (curFrom );
}
else
{
curFrom = 0;
return 0;
}
}
function getPenalties(from)
{
$("#penaltyList").html("");
$(".loader").fadeIn();
$.getJSON("/_penalties?from=" + from, function(result) {
$.each(result, function(i, penalty) {
$("#penaltyList").append(
"<div class=\"playerPenalty table alternate_" + i % 2 + "\"> \
<div class=\"penaltyName tableCell\"><a href=\"/players?id="+ penalty['playerID'] + "\">" + penalty['playerName'] + "</a></div> \
<div class=\"penaltyType tableCell\">"+ getColorForLevel(penalty['penaltyType'], penalty['penaltyType']) + "</div> \
<div class=\"penaltyReason tableCell\">"+ penalty['penaltyReason'] + "</div> \
<div class=\"penaltyOrigin tableCell\">"+ getColorForLevel(penalty['adminLevel'], penalty['adminName']) + "</div> \
<div class=\"penaltyTime tableCell\">"+ penalty['penaltyTime'] + " ago </div> \
</div>"
)
});
}).done(function (data) { $(".loader").fadeOut(); });
}
$( document ).ready(function() {
getPenalties(0);
});
</script>
<div class="penaltyHeader table">
<div class="penaltyName tableCell">Name</div>
<div class="penaltyType tableCell">Type</div>
<div class="penaltyReason tableCell">Reason</div>
<div class="penaltyOrigin tableCell">Admin</div>
<div class="penaltyTime tableCell">Time</div>
</div>
<div id="penaltyList">
</div>
<hr />
<div id="paginationButtons" class="table">
<div id="previousPage" class="tableCell"><a href=# onclick="getPenalties(getPrevPage())"><<</a></div>
<div id="nextPage" class="tableCell"><a href=# onclick="getPenalties(getNextPage())">>></a></div>
</div>

View File

@ -1,7 +0,0 @@
<div id="container">
<div class="h0" style="margin-top: 0; line-height:normal;">PLAYER<br /><a style="padding: 0; margin: 0; font-size: 24px; float: right;" href="/">Back</a></div>
<div id="logo_shit"></div>
<div style="clear:both"></div>
<hr/>
{{PLAYER}}
</div>

110
Admin/webfront/players.html Normal file
View File

@ -0,0 +1,110 @@
<script>
var curFrom = 0;
function getNextPage()
{
curFrom += 15;
return curFrom;
}
function getPrevPage()
{
if ((curFrom - 15) >= 0)
{
curFrom -= 15;
return (curFrom - 15);
}
else
return 0;
}
function formatHidden(data)
{
var p = "<div class=\"hiddenWrapper\">Expand<div class=\"hiddenElements\">";
$.each(data, function(i, dat) {
p += "<span>" + dat + "</span><br/>"
})
p += "</div></div>"
return p;
}
function printPlayer(player, i)
{
$("#playersTable").append(
"<div class=\"playerInfo table alternate_" + i % 2 + "\"> \
<div class=\"tableCell\"><a href=\"/players?id="+ player['playerID'] + "\">" + player['playerName'] + "</a></div> \
<div class=\"tableCell\">"+ formatHidden(player['playerAliases']) + "</div> \
<div class=\"tableCell\">"+ formatHidden(player['playerIPs']) + "</div> \
<div class=\"tableCell\">"+ getColorForLevel(player['playerLevel'], player['playerLevel']) + "</div> \
<div class=\"tableCell\">"+ player['playerConnections'] + "</div> \
<div class=\"tableCell actionButton\" style='width: 2em;'> \
<a target=\"_blank\" href='http://server.nbsclan.org/screen.php?id=" + player.forumID+ "&name=" + player.playerName + "'> \
<i class=\"fa fa-camera\" aria-hidden=\"true\"></i> \
</a> \
<a target=\"_blank\" href='https://v2.mcsebi.ru/memberlist.php?mode=viewprofile&u=" + player.forumID + "'> \
<i class=\"fa fa-user tableCell\" aria-hidden=\"true\"></i> \
</a> \
</div> \
<div class=\"tableCell alignRight\">"+ checkJustNow(player['lastSeen']) + "</div> \
</div>"
)
}
function getPlayer(ident, identValue)
{
$("#playersTable").html("");
$(".loader").fadeIn();
$.getJSON("/getplayer?" + ident + "=" + identValue, function(result) {
$.each(result, function(i, player) {
printPlayer(player, i);
});
}).done(function (data) { $(".loader").fadeOut(); });
}
$( document ).ready(function() {
if (parseGet('id') != "undefined")
getPlayer('id', parseGet('id'));
else if (parseGet('name') != "undefined")
getPlayer('name', parseGet('name'));
else {
getPlayer('recent', '1');
}
});
$('#content').on('click', '.hiddenWrapper', function(){
$(this).find('.hiddenElements').toggle()
});
</script>
<div class="playerSearchWrap">
<input type="button" class="searchButton" name="Search" value="Search"/>
<input type="text" class="search" placeholder="Player Name..."/>
</div>
<div class="contentHeader table">
<div class="contentColumn tableCell">Name</div>
<div class="contentColumn tableCell">Aliases</div>
<div class="contentColumn tableCell">IP</div>
<div class="contentColumn tableCell">Level</div>
<div class="contentColumn tableCell">Connections</div>
<div class="contentColumn tableCell" style="width: 1em;">V2</div>
<div class="contentColumn tableCell alignRight">Last Seen</div>
</div>
<div id="playersTable">
</div>
<hr/>
<script>
$('.searchButton').click(function() {
if ($('.search').val().length > 0)
getPlayer('name', $('.search').val());
});
$(document).keypress(function(e) {
if(e.which == 13) {
$('.searchButton').click();
}
});
</script>

View File

@ -1,5 +0,0 @@
<div id="container">
<div class="h0" style="margin-top: 0; line-height:normal;">STATS<br /><a style="padding: 0; margin: 0; font-size: 24px; float: right;" href="/">Back</a></div>
<div id="logo_shit"></div>
{{STATS}}
</div>