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:
700
Admin/Command.cs
700
Admin/Command.cs
@ -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
24
Admin/Commands.cs
Normal 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
73
Admin/Config.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
11
Admin/IW4MAdmin.exe.config
Normal file
11
Admin/IW4MAdmin.exe.config
Normal 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>
|
@ -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
109
Admin/Kayak.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
119
Admin/Main.cs
119
Admin/Main.cs
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
304
Admin/Manager.cs
304
Admin/Manager.cs
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
@ -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")]
|
||||
|
2
Admin/Properties/Settings.Designer.cs
generated
2
Admin/Properties/Settings.Designer.cs
generated
@ -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())));
|
||||
|
809
Admin/Server.cs
809
Admin/Server.cs
File diff suppressed because it is too large
Load Diff
@ -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
707
Admin/WebService.cs
Normal 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;
|
||||
}
|
||||
}
|
@ -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
2
Admin/config/web.cfg
Normal file
@ -0,0 +1,2 @@
|
||||
127.0.0.1
|
||||
80
|
Binary file not shown.
BIN
Admin/lib/Newtonsoft.Json.dll
Normal file
BIN
Admin/lib/Newtonsoft.Json.dll
Normal file
Binary file not shown.
BIN
Admin/lib/SharedLibrary.dll
Normal file
BIN
Admin/lib/SharedLibrary.dll
Normal file
Binary file not shown.
Binary file not shown.
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 );
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
LoadSettings()
|
||||
{
|
||||
|
||||
AdminSettings = [];
|
||||
|
||||
AdminSettings["Balance"] = true;
|
||||
|
||||
AdminSettings["dvar_prefix"] = "admin";
|
||||
|
||||
return AdminSettings;
|
||||
}
|
4
Admin/packages.config
Normal file
4
Admin/packages.config
Normal 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.
@ -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
|
||||
|
77
Admin/webfront/console.html
Normal file
77
Admin/webfront/console.html
Normal 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>
|
@ -1,40 +1,7 @@
|
||||
<div id="footer">IW4M Admin v{{VERSION}} — <a href="http://raidmax.org/IW4MAdmin">RaidMax.org</a></div>
|
||||
</div>
|
||||
<div id="footer">© 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>
|
||||
|
@ -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
12
Admin/webfront/login.html
Normal 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
194
Admin/webfront/main.css
Normal file
File diff suppressed because one or more lines are too long
@ -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>
|
||||
|
8
Admin/webfront/mobile.css
Normal file
8
Admin/webfront/mobile.css
Normal 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; }
|
||||
}
|
61
Admin/webfront/penalties.html
Normal file
61
Admin/webfront/penalties.html
Normal 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>
|
@ -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
110
Admin/webfront/players.html
Normal 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>
|
@ -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>
|
Reference in New Issue
Block a user