Branch for IW4X practically everything refactored
This commit is contained in:
parent
85a658b987
commit
10075b0d3f
5
.gitignore
vendored
5
.gitignore
vendored
@ -186,4 +186,7 @@ FakesAssemblies/
|
||||
# LightSwitch generated files
|
||||
GeneratedArtifacts/
|
||||
_Pvt_Extensions/
|
||||
ModelManifest.xml
|
||||
ModelManifest.xml
|
||||
/.vs/IW4M Admin/v15
|
||||
/.vs/IW4M Admin/v15/Browse.VC.db
|
||||
/.vs/IW4M Admin/v15
|
||||
|
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));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,63 +1,55 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Kayak;
|
||||
using Kayak.Http;
|
||||
using System.Net;
|
||||
using Kayak;
|
||||
|
||||
namespace Webfront_Plugin
|
||||
|
||||
namespace IW4MAdmin
|
||||
{
|
||||
static class Manager
|
||||
{
|
||||
public static IScheduler webScheduler { get; private set; }
|
||||
public static Framework webFront { get; private set; }
|
||||
public static IPAddress lastIP;
|
||||
public static IServer webServer;
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
webScheduler = KayakScheduler.Factory.Create(new SchedulerDelegate());
|
||||
webServer = KayakServer.Factory.CreateHttp(new RequestDelegate(), webScheduler);
|
||||
webFront = new Framework();
|
||||
|
||||
using (webServer.Listen(new IPEndPoint(IPAddress.Any, 1624)))
|
||||
webScheduler.Start();
|
||||
}
|
||||
}
|
||||
|
||||
class SchedulerDelegate : ISchedulerDelegate
|
||||
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 RequestDelegate : IHttpRequestDelegate
|
||||
class Request : IHttpRequestDelegate
|
||||
{
|
||||
public void OnRequest(HttpRequestHead request, IDataProducer requestBody, IHttpResponseDelegate response)
|
||||
{
|
||||
DefaultKayakServer castCrap = (DefaultKayakServer)Manager.webServer;
|
||||
Manager.lastIP = castCrap.clientAddress.Address;
|
||||
|
||||
string body = Manager.webFront.processRequest(request);
|
||||
// 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>()
|
||||
Headers = new Dictionary<string, string>()
|
||||
{
|
||||
{ "Content-Type", "text/html" },
|
||||
{ "Content-Length", body.Length.ToString() },
|
||||
{ "Content-Type", requestedPage.contentType },
|
||||
{ "Content-Length", requestedPage.content.Length.ToString() },
|
||||
{ "Access-Control-Allow-Origin", "*" },
|
||||
}
|
||||
};
|
||||
|
||||
response.OnResponse(headers, new BufferedProducer(body));
|
||||
foreach (var key in requestedPage.additionalHeaders.Keys)
|
||||
headers.Headers.Add(key, requestedPage.additionalHeaders[key]);
|
||||
|
||||
response.OnResponse(headers, new BufferedProducer(requestedPage.content));
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,6 +60,7 @@ namespace Webfront_Plugin
|
||||
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;
|
||||
@ -113,4 +106,4 @@ namespace Webfront_Plugin
|
||||
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>
|
70
Auto Restart Plugin/Auto Restart Plugin.csproj
Normal file
70
Auto Restart Plugin/Auto Restart Plugin.csproj
Normal file
@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{2321A25F-7871-47C3-8440-02551918D6A1}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Auto_Restart_Plugin</RootNamespace>
|
||||
<AssemblyName>AutorestartPlugin</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Management" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Main.cs" />
|
||||
<Compile Include="Monitoring.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SharedLibrary\SharedLibrary.csproj">
|
||||
<Project>{d51eeceb-438a-47da-870f-7d7b41bc24d6}</Project>
|
||||
<Name>SharedLibrary</Name>
|
||||
<Private>False</Private>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)Admin\bin\$(ConfigurationName)\plugins\AutoRestartPlugin.dll"
|
||||
|
||||
|
||||
|
||||
|
||||
copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)BUILD\plugins\"</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.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
72
Auto Restart Plugin/Main.cs
Normal file
72
Auto Restart Plugin/Main.cs
Normal file
@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using SharedLibrary;
|
||||
using SharedLibrary.Extensions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Auto_Restart_Plugin
|
||||
{
|
||||
public class Main : IPlugin
|
||||
{
|
||||
public string Author
|
||||
{
|
||||
get
|
||||
{
|
||||
return "RaidMax";
|
||||
}
|
||||
}
|
||||
|
||||
public float Version
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Auto Restart Plugin";
|
||||
}
|
||||
}
|
||||
|
||||
public async Task OnLoad()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public async Task OnUnload()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public async Task OnTick(Server S)
|
||||
{
|
||||
switch (Monitoring.shouldRestart())
|
||||
{
|
||||
case 300:
|
||||
await S.Broadcast("^1Server will be performing an ^5AUTOMATIC ^1restart in ^55 ^1minutes.");
|
||||
break;
|
||||
case 120:
|
||||
await S.Broadcast("^1Server will be performing an ^5AUTOMATIC ^1restart in ^52 ^1minutes.");
|
||||
break;
|
||||
case 60:
|
||||
await S.Broadcast("^1Server will be performing an ^5AUTOMATIC ^1restart in ^51 ^1minute.");
|
||||
break;
|
||||
case 30:
|
||||
await S.Broadcast("^1Server will be performing an ^5AUTOMATIC ^1restart in ^530 ^1seconds.");
|
||||
break;
|
||||
case 0:
|
||||
await S.Broadcast("^1Server now performing an ^5AUTOMATIC ^1restart ^5NOW ^1please reconnect.");
|
||||
Monitoring.Restart(S);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task OnEvent(Event E, Server S)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
127
Auto Restart Plugin/Monitoring.cs
Normal file
127
Auto Restart Plugin/Monitoring.cs
Normal file
@ -0,0 +1,127 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Management;
|
||||
using SharedLibrary;
|
||||
|
||||
namespace Auto_Restart_Plugin
|
||||
{
|
||||
static class Monitoring
|
||||
{
|
||||
[DllImport("kernel32")]
|
||||
public static extern bool DeleteFile(string name);
|
||||
|
||||
public static void Restart(Server goodBye)
|
||||
{
|
||||
_Restart(goodBye);
|
||||
}
|
||||
|
||||
private static void _Restart(Server goodBye)
|
||||
{
|
||||
try
|
||||
{
|
||||
string cmdLine = GetCommandLine(Process.GetProcessById(goodBye.pID()));
|
||||
var info = new ProcessStartInfo();
|
||||
|
||||
// if we don't delete this, we get a prompt..
|
||||
DeleteFile(Process.GetProcessById(goodBye.pID()).MainModule.FileName + ":Zone.Identifier");
|
||||
|
||||
//info.WorkingDirectory = goodBye.Basepath;
|
||||
info.Arguments = cmdLine;
|
||||
info.FileName = Process.GetProcessById(goodBye.pID()).MainModule.FileName;
|
||||
// goodBye.executeCommand("killserver");
|
||||
|
||||
Process.GetProcessById(Process.GetProcessById(goodBye.pID()).Parent().Id).Kill();
|
||||
Process.GetProcessById(goodBye.pID()).Kill();
|
||||
|
||||
Process.Start(info);
|
||||
}
|
||||
|
||||
catch (Exception E)
|
||||
{
|
||||
goodBye.Log.Write("SOMETHING FUCKED UP BEYOND ALL REPAIR " + E.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public static int shouldRestart()
|
||||
{
|
||||
var curTime = DateTime.Now;
|
||||
DateTime restartTime = new DateTime(curTime.Year, curTime.Month, curTime.Day, 4, 0, 0);
|
||||
var a = Math.Floor((restartTime - curTime).TotalMilliseconds / 1000);
|
||||
if (a > 0 && a < 2) // just in case of precision
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
switch((int)a)
|
||||
{
|
||||
case 300:
|
||||
return 300;
|
||||
case 120:
|
||||
return 120;
|
||||
case 60:
|
||||
return 60;
|
||||
case 30:
|
||||
return 30;
|
||||
default:
|
||||
return 1337;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//http://stackoverflow.com/questions/2633628/can-i-get-command-line-arguments-of-other-processes-from-net-c
|
||||
private static string GetCommandLine(this Process process)
|
||||
{
|
||||
var commandLine = new StringBuilder();
|
||||
commandLine.Append(" ");
|
||||
using (var searcher = new ManagementObjectSearcher("SELECT CommandLine FROM Win32_Process WHERE ProcessId = " + process.Id))
|
||||
{
|
||||
foreach (var @object in searcher.Get())
|
||||
{
|
||||
if (@object["CommandLine"].ToString().Contains("iw4m"))
|
||||
commandLine.Append(@object["CommandLine"].ToString().Substring(4));
|
||||
else
|
||||
commandLine.Append(@object["CommandLine"]);
|
||||
commandLine.Append(" ");
|
||||
}
|
||||
}
|
||||
|
||||
return commandLine.ToString().Trim();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class ProcessExtensions
|
||||
{
|
||||
private static string FindIndexedProcessName(int pid)
|
||||
{
|
||||
var processName = Process.GetProcessById(pid).ProcessName;
|
||||
var processesByName = Process.GetProcessesByName(processName);
|
||||
string processIndexdName = null;
|
||||
|
||||
for (var index = 0; index < processesByName.Length; index++)
|
||||
{
|
||||
processIndexdName = index == 0 ? processName : processName + "#" + index;
|
||||
var processId = new PerformanceCounter("Process", "ID Process", processIndexdName);
|
||||
if ((int)processId.NextValue() == pid)
|
||||
{
|
||||
return processIndexdName;
|
||||
}
|
||||
}
|
||||
|
||||
return processIndexdName;
|
||||
}
|
||||
|
||||
private static Process FindPidFromIndexedProcessName(string indexedProcessName)
|
||||
{
|
||||
var parentId = new PerformanceCounter("Process", "Creating Process ID", indexedProcessName);
|
||||
return Process.GetProcessById((int)parentId.NextValue());
|
||||
}
|
||||
|
||||
public static Process Parent(this Process process)
|
||||
{
|
||||
return FindPidFromIndexedProcessName(FindIndexedProcessName(process.Id));
|
||||
}
|
||||
}
|
||||
}
|
@ -4,15 +4,16 @@
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{99E36EBD-1FA1-494C-8A66-BECE64EFF378}</ProjectGuid>
|
||||
<ProjectGuid>{79406C5E-A8AD-4A50-A7F0-53CE56792A31}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Webfront_Plugin</RootNamespace>
|
||||
<AssemblyName>Webfront Plugin</AssemblyName>
|
||||
<RootNamespace>ChatMonitor</RootNamespace>
|
||||
<AssemblyName>ChatMonitor</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
@ -22,6 +23,7 @@
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
@ -29,31 +31,28 @@
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<StartupObject />
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Kayak">
|
||||
<HintPath>..\Admin\bin\Release\lib\Kayak.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SharedLibrary, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\SharedLibrary\bin\Release\SharedLibrary.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Compile Include="Main.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Framework.cs" />
|
||||
<Compile Include="Main.cs" />
|
||||
<Compile Include="Manager.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Reference Include="System" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SharedLibrary\SharedLibrary.csproj">
|
||||
<Project>{d51eeceb-438a-47da-870f-7d7b41bc24d6}</Project>
|
||||
<Name>SharedLibrary</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Webfront Plugin\Webfront Plugin.csproj">
|
||||
<Project>{99e36ebd-1fa1-494c-8a66-bece64eff378}</Project>
|
||||
<Name>Webfront Plugin</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)Admin\plugins\WebfrontPlugin.dll"</PostBuildEvent>
|
||||
<PostBuildEvent>copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)Admin\plugins\ChatMonitorPlugin.dll"</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.
|
59
Chat Monitor Plugin/Main.cs
Normal file
59
Chat Monitor Plugin/Main.cs
Normal file
@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using SharedLibrary;
|
||||
|
||||
|
||||
namespace ChatMonitor
|
||||
{
|
||||
public class Main : IPlugin
|
||||
{
|
||||
|
||||
|
||||
public string Author
|
||||
{
|
||||
get
|
||||
{
|
||||
return "RaidMax";
|
||||
}
|
||||
}
|
||||
|
||||
public float Version
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Chat Monitor Plugin";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void onLoad()
|
||||
{
|
||||
lastClear = DateTime.Now;
|
||||
flaggedMessages = 0;
|
||||
flaggedMessagesText = new List<string>();
|
||||
}
|
||||
|
||||
public void onUnload()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public void onTick(Server S)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public void onEvent(Event E, Server S)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
73
EventAPI/EventAPI.csproj
Normal file
73
EventAPI/EventAPI.csproj
Normal file
@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{C9E821BF-23AD-4CB5-B7F9-B3B99B606650}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>EventAPI</RootNamespace>
|
||||
<AssemblyName>EventAPI</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<StartupObject />
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SharedLibrary\SharedLibrary.csproj">
|
||||
<Project>{d51eeceb-438a-47da-870f-7d7b41bc24d6}</Project>
|
||||
<Name>SharedLibrary</Name>
|
||||
<Private>False</Private>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Plugin.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net40\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)Admin\bin\$(ConfigurationName)\plugins\EventAPI.dll"
|
||||
|
||||
copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)BUILD\plugins\"</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.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
183
EventAPI/Plugin.cs
Normal file
183
EventAPI/Plugin.cs
Normal file
@ -0,0 +1,183 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using SharedLibrary;
|
||||
using SharedLibrary.Extensions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace EventAPI
|
||||
{
|
||||
class EventsJSON : IPage
|
||||
{
|
||||
private struct EventResponse
|
||||
{
|
||||
public int eventCount;
|
||||
public RestEvent Event;
|
||||
}
|
||||
|
||||
public string getName()
|
||||
{
|
||||
return "Events";
|
||||
}
|
||||
|
||||
public string getPath()
|
||||
{
|
||||
return "/api/events";
|
||||
}
|
||||
|
||||
public HttpResponse getPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary<string, string> headers)
|
||||
{
|
||||
bool shouldQuery = querySet.Get("status") != null;
|
||||
EventResponse requestedEvent = new EventResponse();
|
||||
HttpResponse resp = new HttpResponse();
|
||||
|
||||
if (shouldQuery)
|
||||
{
|
||||
StringBuilder s = new StringBuilder();
|
||||
foreach (var S in Events.activeServers)
|
||||
s.Append(String.Format("{0} has {1}/{4} players playing {2} on {3}\n", S.getName(), S.getPlayers().Count, Utilities.gametypeLocalized(S.getGametype()), S.CurrentMap.Name, S.MaxClients));
|
||||
requestedEvent.Event = new RestEvent(RestEvent.eType.STATUS, RestEvent.eVersion.IW4MAdmin, s.ToString(), "Status", "", "");
|
||||
requestedEvent.eventCount = 1;
|
||||
}
|
||||
|
||||
else if (Events.apiEvents.Count > 0)
|
||||
{
|
||||
requestedEvent.Event = Events.apiEvents.Dequeue();
|
||||
requestedEvent.eventCount = 1;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
requestedEvent.eventCount = 0;
|
||||
}
|
||||
|
||||
resp.content = Newtonsoft.Json.JsonConvert.SerializeObject(requestedEvent);
|
||||
resp.contentType = getContentType();
|
||||
resp.additionalHeaders = new Dictionary<string, string>();
|
||||
return resp;
|
||||
}
|
||||
|
||||
public string getContentType()
|
||||
{
|
||||
return "application/json";
|
||||
}
|
||||
|
||||
public bool isVisible()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class Events : IPlugin
|
||||
{
|
||||
public static Queue<RestEvent> apiEvents { get; private set; }
|
||||
public static List<Server> activeServers;
|
||||
|
||||
DateTime lastClear;
|
||||
int flaggedMessages;
|
||||
List<string> flaggedMessagesText;
|
||||
|
||||
public String Name
|
||||
{
|
||||
get { return "Event API Plugin"; }
|
||||
}
|
||||
|
||||
public float Version
|
||||
{
|
||||
get { return 1.0f; }
|
||||
}
|
||||
|
||||
public string Author
|
||||
{
|
||||
get
|
||||
{
|
||||
return "RaidMax";
|
||||
}
|
||||
}
|
||||
|
||||
public async Task OnLoad()
|
||||
{
|
||||
apiEvents = new Queue<RestEvent>();
|
||||
flaggedMessagesText = new List<string>();
|
||||
activeServers = new List<Server>();
|
||||
WebService.pageList.Add(new EventsJSON());
|
||||
}
|
||||
|
||||
public async Task OnUnload()
|
||||
{
|
||||
apiEvents.Clear();
|
||||
activeServers.Clear();
|
||||
}
|
||||
|
||||
public async Task OnTick(Server S)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public async Task OnEvent(Event E, Server S)
|
||||
{
|
||||
if (E.Type == Event.GType.Start)
|
||||
{
|
||||
activeServers.Add(S);
|
||||
S.Log.Write("Event API now running on " + S.getName(), Log.Level.Production);
|
||||
}
|
||||
|
||||
if (E.Type == Event.GType.Stop)
|
||||
{
|
||||
activeServers.RemoveAll(s => s.getPort() == S.getPort());
|
||||
S.Log.Write("Event API no longer running on " + S.getName(), Log.Level.Production);
|
||||
}
|
||||
|
||||
if (E.Type == Event.GType.Connect)
|
||||
{
|
||||
addRestEvent(new RestEvent(RestEvent.eType.NOTIFICATION, RestEvent.eVersion.IW4MAdmin, E.Origin.Name + " has joined " + S.getName(), E.Type.ToString(), S.getName(), E.Origin.Name));
|
||||
}
|
||||
|
||||
if (E.Type == Event.GType.Disconnect)
|
||||
{
|
||||
addRestEvent(new RestEvent(RestEvent.eType.NOTIFICATION, RestEvent.eVersion.IW4MAdmin, E.Origin.Name + " has left " + S.getName(), E.Type.ToString(), S.getName(), E.Origin.Name));
|
||||
}
|
||||
|
||||
if (E.Type == Event.GType.Say)
|
||||
{
|
||||
if (E.Data.Length != 0 && E.Data[0] != '!')
|
||||
addRestEvent(new RestEvent(RestEvent.eType.NOTIFICATION, RestEvent.eVersion.IW4MAdmin, E.Data, "Chat", E.Origin.Name, ""));
|
||||
}
|
||||
|
||||
if (E.Type == Event.GType.Say && E.Origin.Level < Player.Permission.Moderator)
|
||||
{
|
||||
string message = E.Data.ToLower();
|
||||
bool flagged = message.Contains(" wh ") || message.Contains("hax") || message.Contains("cheat") || message.Contains("hack") || message.Contains("aim") || message.Contains("wall") || message.Contains("cheto") || message.Contains("hak");
|
||||
|
||||
if (flagged)
|
||||
{
|
||||
flaggedMessages++;
|
||||
flaggedMessagesText.Add(String.Format("{0}: {1}", E.Origin.Name, E.Data));
|
||||
}
|
||||
|
||||
if (flaggedMessages > 3)
|
||||
{
|
||||
await E.Owner.Broadcast("If you suspect someone of ^5CHEATING ^7use the ^5!report ^7command");
|
||||
|
||||
addRestEvent(new RestEvent(RestEvent.eType.ALERT, RestEvent.eVersion.IW4MAdmin, "Chat indicates there may be a cheater", "Alert", E.Owner.getName(), ""));
|
||||
addRestEvent(new RestEvent(RestEvent.eType.NOTIFICATION, RestEvent.eVersion.IW4MAdmin, String.Join("\n", flaggedMessagesText), "Chat Monitor", E.Owner.getName(), ""));
|
||||
flaggedMessages = 0;
|
||||
}
|
||||
|
||||
else if ((DateTime.Now - lastClear).TotalMinutes >= 3)
|
||||
{
|
||||
flaggedMessages = 0;
|
||||
flaggedMessagesText.Clear();
|
||||
lastClear = DateTime.Now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void addRestEvent(RestEvent E)
|
||||
{
|
||||
if (apiEvents.Count > 10)
|
||||
apiEvents.Dequeue();
|
||||
apiEvents.Enqueue(E);
|
||||
}
|
||||
}
|
||||
}
|
4
EventAPI/packages.config
Normal file
4
EventAPI/packages.config
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net40" requireReinstallation="true" />
|
||||
</packages>
|
151
IW4M Admin.sln
151
IW4M Admin.sln
@ -1,17 +1,16 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.24720.0
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26403.7
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IW4M ADMIN", "Admin\IW4M ADMIN.csproj", "{DD5DCDA2-51DB-4B1A-922F-5705546E6115}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{2321A25F-7871-47C3-8440-02551918D6A1} = {2321A25F-7871-47C3-8440-02551918D6A1}
|
||||
{AF097E6B-48D5-4452-9CCF-0A81A21F341D} = {AF097E6B-48D5-4452-9CCF-0A81A21F341D}
|
||||
{4785AB75-66F3-4391-985D-63A5A049A0FA} = {4785AB75-66F3-4391-985D-63A5A049A0FA}
|
||||
{99E36EBD-1FA1-494C-8A66-BECE64EFF378} = {99E36EBD-1FA1-494C-8A66-BECE64EFF378}
|
||||
{D51EECEB-438A-47DA-870F-7D7B41BC24D6} = {D51EECEB-438A-47DA-870F-7D7B41BC24D6}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Webfront Plugin", "Webfront Plugin\Webfront Plugin.csproj", "{99E36EBD-1FA1-494C-8A66-BECE64EFF378}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{428D8EB9-ECA3-4A66-AA59-3A944378C33F} = {428D8EB9-ECA3-4A66-AA59-3A944378C33F}
|
||||
{E46C85BD-A99C-484E-BCCE-0F1831C5925E} = {E46C85BD-A99C-484E-BCCE-0F1831C5925E}
|
||||
{C9E821BF-23AD-4CB5-B7F9-B3B99B606650} = {C9E821BF-23AD-4CB5-B7F9-B3B99B606650}
|
||||
{D51EECEB-438A-47DA-870F-7D7B41BC24D6} = {D51EECEB-438A-47DA-870F-7D7B41BC24D6}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
@ -27,34 +26,162 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Welcome Plugin", "Welcome P
|
||||
{D51EECEB-438A-47DA-870F-7D7B41BC24D6} = {D51EECEB-438A-47DA-870F-7D7B41BC24D6}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Auto Restart Plugin", "Auto Restart Plugin\Auto Restart Plugin.csproj", "{2321A25F-7871-47C3-8440-02551918D6A1}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Votemap Plugin", "Votemap Plugin\Votemap Plugin.csproj", "{428D8EB9-ECA3-4A66-AA59-3A944378C33F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MessageboardPlugin", "MessageboardPlugin\MessageboardPlugin.csproj", "{E46C85BD-A99C-484E-BCCE-0F1831C5925E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventAPI", "EventAPI\EventAPI.csproj", "{C9E821BF-23AD-4CB5-B7F9-B3B99B606650}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugins", "Plugins", "{26E8B310-269E-46D4-A612-24601F16065F}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|Mixed Platforms = Debug|Mixed Platforms
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|Mixed Platforms = Release|Mixed Platforms
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{99E36EBD-1FA1-494C-8A66-BECE64EFF378}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{99E36EBD-1FA1-494C-8A66-BECE64EFF378}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{99E36EBD-1FA1-494C-8A66-BECE64EFF378}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{99E36EBD-1FA1-494C-8A66-BECE64EFF378}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release|x64.Build.0 = Release|Any CPU
|
||||
{DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release|x86.Build.0 = Release|Any CPU
|
||||
{4785AB75-66F3-4391-985D-63A5A049A0FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4785AB75-66F3-4391-985D-63A5A049A0FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4785AB75-66F3-4391-985D-63A5A049A0FA}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{4785AB75-66F3-4391-985D-63A5A049A0FA}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{4785AB75-66F3-4391-985D-63A5A049A0FA}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{4785AB75-66F3-4391-985D-63A5A049A0FA}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{4785AB75-66F3-4391-985D-63A5A049A0FA}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{4785AB75-66F3-4391-985D-63A5A049A0FA}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{4785AB75-66F3-4391-985D-63A5A049A0FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4785AB75-66F3-4391-985D-63A5A049A0FA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4785AB75-66F3-4391-985D-63A5A049A0FA}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{4785AB75-66F3-4391-985D-63A5A049A0FA}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{4785AB75-66F3-4391-985D-63A5A049A0FA}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{4785AB75-66F3-4391-985D-63A5A049A0FA}.Release|x64.Build.0 = Release|Any CPU
|
||||
{4785AB75-66F3-4391-985D-63A5A049A0FA}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{4785AB75-66F3-4391-985D-63A5A049A0FA}.Release|x86.Build.0 = Release|Any CPU
|
||||
{D51EECEB-438A-47DA-870F-7D7B41BC24D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D51EECEB-438A-47DA-870F-7D7B41BC24D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D51EECEB-438A-47DA-870F-7D7B41BC24D6}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{D51EECEB-438A-47DA-870F-7D7B41BC24D6}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{D51EECEB-438A-47DA-870F-7D7B41BC24D6}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{D51EECEB-438A-47DA-870F-7D7B41BC24D6}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{D51EECEB-438A-47DA-870F-7D7B41BC24D6}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{D51EECEB-438A-47DA-870F-7D7B41BC24D6}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{D51EECEB-438A-47DA-870F-7D7B41BC24D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D51EECEB-438A-47DA-870F-7D7B41BC24D6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D51EECEB-438A-47DA-870F-7D7B41BC24D6}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{D51EECEB-438A-47DA-870F-7D7B41BC24D6}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{D51EECEB-438A-47DA-870F-7D7B41BC24D6}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{D51EECEB-438A-47DA-870F-7D7B41BC24D6}.Release|x64.Build.0 = Release|Any CPU
|
||||
{D51EECEB-438A-47DA-870F-7D7B41BC24D6}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{D51EECEB-438A-47DA-870F-7D7B41BC24D6}.Release|x86.Build.0 = Release|Any CPU
|
||||
{AF097E6B-48D5-4452-9CCF-0A81A21F341D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AF097E6B-48D5-4452-9CCF-0A81A21F341D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AF097E6B-48D5-4452-9CCF-0A81A21F341D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{AF097E6B-48D5-4452-9CCF-0A81A21F341D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{AF097E6B-48D5-4452-9CCF-0A81A21F341D}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{AF097E6B-48D5-4452-9CCF-0A81A21F341D}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{AF097E6B-48D5-4452-9CCF-0A81A21F341D}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{AF097E6B-48D5-4452-9CCF-0A81A21F341D}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{AF097E6B-48D5-4452-9CCF-0A81A21F341D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AF097E6B-48D5-4452-9CCF-0A81A21F341D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AF097E6B-48D5-4452-9CCF-0A81A21F341D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{AF097E6B-48D5-4452-9CCF-0A81A21F341D}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{AF097E6B-48D5-4452-9CCF-0A81A21F341D}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{AF097E6B-48D5-4452-9CCF-0A81A21F341D}.Release|x64.Build.0 = Release|Any CPU
|
||||
{AF097E6B-48D5-4452-9CCF-0A81A21F341D}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{AF097E6B-48D5-4452-9CCF-0A81A21F341D}.Release|x86.Build.0 = Release|Any CPU
|
||||
{2321A25F-7871-47C3-8440-02551918D6A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2321A25F-7871-47C3-8440-02551918D6A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2321A25F-7871-47C3-8440-02551918D6A1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{2321A25F-7871-47C3-8440-02551918D6A1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{2321A25F-7871-47C3-8440-02551918D6A1}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{2321A25F-7871-47C3-8440-02551918D6A1}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{2321A25F-7871-47C3-8440-02551918D6A1}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{2321A25F-7871-47C3-8440-02551918D6A1}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{2321A25F-7871-47C3-8440-02551918D6A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2321A25F-7871-47C3-8440-02551918D6A1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2321A25F-7871-47C3-8440-02551918D6A1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{2321A25F-7871-47C3-8440-02551918D6A1}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{2321A25F-7871-47C3-8440-02551918D6A1}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{2321A25F-7871-47C3-8440-02551918D6A1}.Release|x64.Build.0 = Release|Any CPU
|
||||
{2321A25F-7871-47C3-8440-02551918D6A1}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{2321A25F-7871-47C3-8440-02551918D6A1}.Release|x86.Build.0 = Release|Any CPU
|
||||
{428D8EB9-ECA3-4A66-AA59-3A944378C33F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{428D8EB9-ECA3-4A66-AA59-3A944378C33F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{428D8EB9-ECA3-4A66-AA59-3A944378C33F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{428D8EB9-ECA3-4A66-AA59-3A944378C33F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{428D8EB9-ECA3-4A66-AA59-3A944378C33F}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{428D8EB9-ECA3-4A66-AA59-3A944378C33F}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{428D8EB9-ECA3-4A66-AA59-3A944378C33F}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{428D8EB9-ECA3-4A66-AA59-3A944378C33F}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{428D8EB9-ECA3-4A66-AA59-3A944378C33F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{428D8EB9-ECA3-4A66-AA59-3A944378C33F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{428D8EB9-ECA3-4A66-AA59-3A944378C33F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{428D8EB9-ECA3-4A66-AA59-3A944378C33F}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{428D8EB9-ECA3-4A66-AA59-3A944378C33F}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{428D8EB9-ECA3-4A66-AA59-3A944378C33F}.Release|x64.Build.0 = Release|Any CPU
|
||||
{428D8EB9-ECA3-4A66-AA59-3A944378C33F}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{428D8EB9-ECA3-4A66-AA59-3A944378C33F}.Release|x86.Build.0 = Release|Any CPU
|
||||
{E46C85BD-A99C-484E-BCCE-0F1831C5925E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E46C85BD-A99C-484E-BCCE-0F1831C5925E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E46C85BD-A99C-484E-BCCE-0F1831C5925E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{E46C85BD-A99C-484E-BCCE-0F1831C5925E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{E46C85BD-A99C-484E-BCCE-0F1831C5925E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{E46C85BD-A99C-484E-BCCE-0F1831C5925E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{E46C85BD-A99C-484E-BCCE-0F1831C5925E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E46C85BD-A99C-484E-BCCE-0F1831C5925E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E46C85BD-A99C-484E-BCCE-0F1831C5925E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{E46C85BD-A99C-484E-BCCE-0F1831C5925E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{E46C85BD-A99C-484E-BCCE-0F1831C5925E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{E46C85BD-A99C-484E-BCCE-0F1831C5925E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{C9E821BF-23AD-4CB5-B7F9-B3B99B606650}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C9E821BF-23AD-4CB5-B7F9-B3B99B606650}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C9E821BF-23AD-4CB5-B7F9-B3B99B606650}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{C9E821BF-23AD-4CB5-B7F9-B3B99B606650}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{C9E821BF-23AD-4CB5-B7F9-B3B99B606650}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{C9E821BF-23AD-4CB5-B7F9-B3B99B606650}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{C9E821BF-23AD-4CB5-B7F9-B3B99B606650}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{C9E821BF-23AD-4CB5-B7F9-B3B99B606650}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{C9E821BF-23AD-4CB5-B7F9-B3B99B606650}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C9E821BF-23AD-4CB5-B7F9-B3B99B606650}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C9E821BF-23AD-4CB5-B7F9-B3B99B606650}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{C9E821BF-23AD-4CB5-B7F9-B3B99B606650}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{C9E821BF-23AD-4CB5-B7F9-B3B99B606650}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{C9E821BF-23AD-4CB5-B7F9-B3B99B606650}.Release|x64.Build.0 = Release|Any CPU
|
||||
{C9E821BF-23AD-4CB5-B7F9-B3B99B606650}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{C9E821BF-23AD-4CB5-B7F9-B3B99B606650}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{4785AB75-66F3-4391-985D-63A5A049A0FA} = {26E8B310-269E-46D4-A612-24601F16065F}
|
||||
{AF097E6B-48D5-4452-9CCF-0A81A21F341D} = {26E8B310-269E-46D4-A612-24601F16065F}
|
||||
{2321A25F-7871-47C3-8440-02551918D6A1} = {26E8B310-269E-46D4-A612-24601F16065F}
|
||||
{428D8EB9-ECA3-4A66-AA59-3A944378C33F} = {26E8B310-269E-46D4-A612-24601F16065F}
|
||||
{E46C85BD-A99C-484E-BCCE-0F1831C5925E} = {26E8B310-269E-46D4-A612-24601F16065F}
|
||||
{C9E821BF-23AD-4CB5-B7F9-B3B99B606650} = {26E8B310-269E-46D4-A612-24601F16065F}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
43
MessageboardPlugin/Encryption.cs
Normal file
43
MessageboardPlugin/Encryption.cs
Normal file
@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
//http://codereview.stackexchange.com/questions/96494/user-password-encryption-in-c + SCrypt
|
||||
namespace MessageBoard.Encryption
|
||||
{
|
||||
|
||||
public static class PasswordHasher
|
||||
{
|
||||
public static byte[] ComputeHash(string password, byte[] salt)
|
||||
{
|
||||
byte[] pwBytes = Encoding.UTF8.GetBytes(password);
|
||||
byte[] hashBytes = new byte[64];
|
||||
CryptSharp.Utility.SCrypt.ComputeKey(pwBytes, salt, 16384, 8, 1, null, hashBytes);
|
||||
return hashBytes;
|
||||
}
|
||||
|
||||
public static byte[] GenerateSalt(int saltByteSize = 24)
|
||||
{
|
||||
RNGCryptoServiceProvider saltGenerator = new RNGCryptoServiceProvider();
|
||||
byte[] salt = new byte[saltByteSize];
|
||||
saltGenerator.GetBytes(salt);
|
||||
return salt;
|
||||
}
|
||||
|
||||
public static bool VerifyPassword(String password, byte[] passwordSalt, byte[] passwordHash)
|
||||
{
|
||||
byte[] computedHash = ComputeHash(password, passwordSalt);
|
||||
return AreHashesEqual(computedHash, passwordHash);
|
||||
}
|
||||
|
||||
//Length constant verification - prevents timing attack
|
||||
private static bool AreHashesEqual(byte[] firstHash, byte[] secondHash)
|
||||
{
|
||||
int minHashLength = firstHash.Length <= secondHash.Length ? firstHash.Length : secondHash.Length;
|
||||
var xor = firstHash.Length ^ secondHash.Length;
|
||||
for (int i = 0; i < minHashLength; i++)
|
||||
xor |= firstHash[i] ^ secondHash[i];
|
||||
return 0 == xor;
|
||||
}
|
||||
}
|
||||
}
|
9
MessageboardPlugin/Events.cs
Normal file
9
MessageboardPlugin/Events.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MessageBoard.Events
|
||||
{
|
||||
public delegate void ActionEventHandler(User origin, EventArgs e);
|
||||
}
|
33
MessageboardPlugin/Exceptions.cs
Normal file
33
MessageboardPlugin/Exceptions.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MessageBoard.Exceptions
|
||||
{
|
||||
public class ThreadException : Exception
|
||||
{
|
||||
public ThreadException(string msg) : base(msg) { }
|
||||
}
|
||||
|
||||
public class UserException : Exception
|
||||
{
|
||||
public UserException(string msg) : base(msg) { }
|
||||
}
|
||||
|
||||
public class SessionException : Exception
|
||||
{
|
||||
public SessionException(string msg) : base(msg) { }
|
||||
}
|
||||
|
||||
public class CategoryException : Exception
|
||||
{
|
||||
public CategoryException(string msg) : base(msg) { }
|
||||
}
|
||||
|
||||
public class PermissionException: Exception
|
||||
{
|
||||
public PermissionException(string msg) : base(msg) { }
|
||||
}
|
||||
}
|
||||
|
1160
MessageboardPlugin/Forum.cs
Normal file
1160
MessageboardPlugin/Forum.cs
Normal file
File diff suppressed because it is too large
Load Diff
12
MessageboardPlugin/Identifiable.cs
Normal file
12
MessageboardPlugin/Identifiable.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MessageBoard
|
||||
{
|
||||
interface Identifiable
|
||||
{
|
||||
int getID();
|
||||
}
|
||||
}
|
120
MessageboardPlugin/MessageboardPlugin.csproj
Normal file
120
MessageboardPlugin/MessageboardPlugin.csproj
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{E46C85BD-A99C-484E-BCCE-0F1831C5925E}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>MessageBoard</RootNamespace>
|
||||
<AssemblyName>MessageboardPlugin</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<StartupObject />
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SharedLibrary\SharedLibrary.csproj">
|
||||
<Project>{d51eeceb-438a-47da-870f-7d7b41bc24d6}</Project>
|
||||
<Name>SharedLibrary</Name>
|
||||
<Private>False</Private>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Encryption.cs" />
|
||||
<Compile Include="Events.cs" />
|
||||
<Compile Include="Exceptions.cs" />
|
||||
<Compile Include="Forum.cs" />
|
||||
<Compile Include="Identifiable.cs" />
|
||||
<Compile Include="Plugin.cs" />
|
||||
<Compile Include="Rank.cs" />
|
||||
<Compile Include="Session.cs" />
|
||||
<Compile Include="Storage.cs" />
|
||||
<Compile Include="Thread.cs" />
|
||||
<Compile Include="User.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="CryptSharp">
|
||||
<HintPath>..\packages\CryptSharp.1.2.0.1\lib\net35\CryptSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MarkdownDeep, Version=1.5.4615.26275, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MarkdownDeep.NET.1.5\lib\.NetFramework 3.5\MarkdownDeep.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net40\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Security" />
|
||||
<Reference Include="System.XML" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="forum\category.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="forum\home.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="forum\login.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="forum\postthread.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="forum\register.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="forum\thread.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="forum\user.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>mkdir "$(SolutionDir)Admin\bin\$(ConfigurationName)\forum"
|
||||
copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)Admin\bin\$(ConfigurationName)\plugins\MessageBoardPlugin.dll"
|
||||
xcopy /E /Y "$(TargetDir)forum" "$(SolutionDir)Admin\bin\$(ConfigurationName)\forum"
|
||||
|
||||
copy /Y "$(TargetDir)MarkdownDeep.dll" "$(SolutionDir)Admin\bin\$(ConfigurationName)\lib\MarkdownDeep.dll"
|
||||
copy /Y "$(TargetDir)CryptSharp.dll" "$(SolutionDir)Admin\bin\$(ConfigurationName)\lib\CryptSharp.dll"
|
||||
copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)BUILD\plugins\"</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.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
65
MessageboardPlugin/Plugin.cs
Normal file
65
MessageboardPlugin/Plugin.cs
Normal file
@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using SharedLibrary;
|
||||
using SharedLibrary.Extensions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MessageBoard.Plugin
|
||||
{
|
||||
public class Main : IPlugin
|
||||
{
|
||||
public static Forum.Manager forum { get; private set; }
|
||||
public static Server stupidServer { get; private set; }
|
||||
|
||||
public string Author
|
||||
{
|
||||
get
|
||||
{
|
||||
return "RaidMax";
|
||||
}
|
||||
}
|
||||
|
||||
public float Version
|
||||
{
|
||||
get
|
||||
{
|
||||
return 0.1f;
|
||||
}
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Message Board Plugin";
|
||||
}
|
||||
}
|
||||
|
||||
public async Task OnLoad()
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
forum = new Forum.Manager();
|
||||
forum.Start();
|
||||
});
|
||||
}
|
||||
|
||||
public async Task OnUnload()
|
||||
{
|
||||
forum.Stop();
|
||||
}
|
||||
|
||||
public async Task OnTick(Server S)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public async Task OnEvent(Event E, Server S)
|
||||
{
|
||||
if (E.Type == Event.GType.Start)
|
||||
{
|
||||
if (stupidServer == null)
|
||||
stupidServer = S;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
61
MessageboardPlugin/Rank.cs
Normal file
61
MessageboardPlugin/Rank.cs
Normal file
@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MessageBoard
|
||||
{
|
||||
public class Rank : Identifiable
|
||||
{
|
||||
public string name;
|
||||
public SharedLibrary.Player.Permission equivalentRank;
|
||||
public int id;
|
||||
|
||||
/// <summary>
|
||||
/// Initial creation
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="equivalentRank"></param>
|
||||
/// <param name="permissions"></param>
|
||||
public Rank(string name, SharedLibrary.Player.Permission equivalentRank)
|
||||
{
|
||||
this.name = name;
|
||||
this.equivalentRank = equivalentRank;
|
||||
id = 0;
|
||||
}
|
||||
|
||||
public Rank(int id, string name, SharedLibrary.Player.Permission equivalentRank)
|
||||
{
|
||||
this.name = name;
|
||||
this.equivalentRank = equivalentRank;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getID()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
public class Permission
|
||||
{
|
||||
[Flags]
|
||||
public enum Action
|
||||
{
|
||||
NONE = 0x0,
|
||||
READ = 0x1,
|
||||
WRITE = 0x2,
|
||||
MODIFY = 0x4,
|
||||
DELETE = 0x8
|
||||
}
|
||||
|
||||
public int rankID;
|
||||
public Action actionable;
|
||||
|
||||
public Permission(int rankID, Action actionable)
|
||||
{
|
||||
this.rankID = rankID;
|
||||
this.actionable = actionable;
|
||||
}
|
||||
}
|
||||
}
|
22
MessageboardPlugin/Session.cs
Normal file
22
MessageboardPlugin/Session.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MessageBoard
|
||||
{
|
||||
public class Session
|
||||
{
|
||||
public User sessionUser;
|
||||
public string sessionID { get; private set; }
|
||||
public DateTime sessionStartTime;
|
||||
|
||||
public Session(User sessionUser, string sessionID)
|
||||
{
|
||||
this.sessionUser = sessionUser;
|
||||
this.sessionID = sessionID;
|
||||
sessionStartTime = DateTime.Now;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
554
MessageboardPlugin/Storage.cs
Normal file
554
MessageboardPlugin/Storage.cs
Normal file
@ -0,0 +1,554 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Data;
|
||||
|
||||
namespace MessageBoard.Storage
|
||||
{
|
||||
class Database : SharedLibrary.Database
|
||||
{
|
||||
public Database(String FN) : base(FN) { }
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
if (!System.IO.File.Exists(FileName))
|
||||
{
|
||||
string createClientTable = @"CREATE TABLE [USERS] (
|
||||
[id] INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
[ranking] INTEGER DEFAULT 0,
|
||||
[username] TEXT NOT NULL,
|
||||
[email] TEXT NOT NULL,
|
||||
[passwordhash] TEXT NOT NULL,
|
||||
[passwordsalt] TEXT NOT NULL,
|
||||
[lastlogin] TEXT NOT NULL,
|
||||
[creationdate] TEXT NOT NULL,
|
||||
[subscribedthreads] TEXT DEFAULT 0,
|
||||
[avatarurl] TEXT
|
||||
);";
|
||||
|
||||
string createSessionTable = @"CREATE TABLE [SESSIONS] (
|
||||
[sessionid] TEXT NOT NULL,
|
||||
[sessionuserid] INTEGER NOT NULL,
|
||||
FOREIGN KEY(sessionuserid) REFERENCES USERS(id)
|
||||
);";
|
||||
|
||||
string createRankingTable = @"CREATE TABLE [RANKS] (
|
||||
[id] INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
[name] TEXT UNIQUE NOT NULL,
|
||||
[equivalentrank] INTEGER DEFAULT 0
|
||||
);";
|
||||
|
||||
string createCategoryTable = @"CREATE TABLE [CATEGORIES] (
|
||||
[id] INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
[title] TEXT NOT NULL,
|
||||
[description] TEXT NOT NULL,
|
||||
[permissions] BLOB
|
||||
);";
|
||||
|
||||
string createThreadTable = @"CREATE TABLE [THREADS] (
|
||||
[id] INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
[title] TEXT NOT NULL,
|
||||
[categoryid] INTEGER NOT NULL,
|
||||
[replies] INTEGER DEFAULT 0,
|
||||
[authorid] INTEGER NOT NULL,
|
||||
[creationdate] TEXT NOT NULL,
|
||||
[updateddate] TEXT NOT NULL,
|
||||
[content] TEXT NOT NULL,
|
||||
[visible] INTEGER DEFAULT 1,
|
||||
FOREIGN KEY(authorid) REFERENCES USERS(id),
|
||||
FOREIGN KEY(categoryid) REFERENCES CATEGORIES(id)
|
||||
);";
|
||||
|
||||
string createReplyTable = @"CREATE TABLE [REPLIES] (
|
||||
[id] INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
[title] TEXT NOT NULL,
|
||||
[authorid] INT NOT NULL,
|
||||
[threadid] INT NOT NULL,
|
||||
[creationdate] TEXT NOT NULL,
|
||||
[updateddate] TEXT NOT NULL,
|
||||
[content] TEXT NOT NULL,
|
||||
[visible] INTEGER DEFAULT 1,
|
||||
FOREIGN KEY(authorid) REFERENCES USERS(id),
|
||||
FOREIGN KEY(threadid) REFERENCES THREADS(id)
|
||||
);";
|
||||
|
||||
|
||||
ExecuteNonQuery(createClientTable);
|
||||
ExecuteNonQuery(createSessionTable);
|
||||
ExecuteNonQuery(createRankingTable);
|
||||
ExecuteNonQuery(createCategoryTable);
|
||||
ExecuteNonQuery(createThreadTable);
|
||||
ExecuteNonQuery(createReplyTable);
|
||||
|
||||
Rank guestRank = new Rank(1, "Guest", SharedLibrary.Player.Permission.User);
|
||||
Rank userRank = new Rank(2, "User", SharedLibrary.Player.Permission.Trusted);
|
||||
Rank modRank = new Rank(3, "Moderator", SharedLibrary.Player.Permission.Moderator);
|
||||
Rank adminRank = new Rank(4, "Administrator", SharedLibrary.Player.Permission.Owner);
|
||||
|
||||
addRank(guestRank);
|
||||
addRank(userRank);
|
||||
addRank(modRank);
|
||||
addRank(adminRank);
|
||||
|
||||
List<Permission> defaultCatPerms = new List<Permission> {
|
||||
new Permission(guestRank.getID(), Permission.Action.READ),
|
||||
new Permission(userRank.getID(), Permission.Action.READ | Permission.Action.WRITE),
|
||||
new Permission(modRank.getID(), Permission.Action.READ | Permission.Action.WRITE | Permission.Action.MODIFY),
|
||||
new Permission(adminRank.getID(), Permission.Action.READ | Permission.Action.WRITE | Permission.Action.MODIFY | Permission.Action.DELETE)
|
||||
};
|
||||
|
||||
Category defaultCat = new Category(1, "Default Category", "This is the default category.", defaultCatPerms);
|
||||
addCategory(defaultCat);
|
||||
}
|
||||
}
|
||||
|
||||
#region SESSIONS
|
||||
public Session getSession(string sessionID)
|
||||
{
|
||||
DataTable Result = GetDataTable("SESSIONS", new KeyValuePair<string, object>("sessionid", sessionID));
|
||||
|
||||
if (Result != null && Result.Rows.Count > 0)
|
||||
{
|
||||
DataRow ResponseRow = Result.Rows[0];
|
||||
int userID = Int32.Parse(ResponseRow["sessionuserid"].ToString());
|
||||
User sessionUser = getUser(userID);
|
||||
|
||||
// this shouldn't happen.. but it might :c
|
||||
if (sessionUser == null)
|
||||
return null;
|
||||
|
||||
Session foundSession = new Session(sessionUser, sessionID);
|
||||
return foundSession;
|
||||
}
|
||||
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public Session setSession(int userID, string sessionID)
|
||||
{
|
||||
// prevent duplicated tuples
|
||||
if (getSession(sessionID) != null)
|
||||
{
|
||||
updateSession(sessionID, userID);
|
||||
return getSession(sessionID);
|
||||
}
|
||||
|
||||
Dictionary<String, object> newSession = new Dictionary<String, object>();
|
||||
|
||||
newSession.Add("sessionid", sessionID);
|
||||
newSession.Add("sessionuserid", userID);
|
||||
|
||||
Insert("SESSIONS", newSession);
|
||||
|
||||
return getSession(sessionID);
|
||||
}
|
||||
|
||||
public bool updateSession(string sessionID, int userID)
|
||||
{
|
||||
if (getSession(sessionID) == null)
|
||||
return false;
|
||||
|
||||
Dictionary<string, object> updatedSession = new Dictionary<string, object>();
|
||||
updatedSession.Add("sessionuserid", userID);
|
||||
|
||||
Update("SESSIONS", updatedSession, new KeyValuePair<string, object>("sessionid", sessionID));
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region USERS
|
||||
private User getUserFromDataTable(DataTable Result)
|
||||
{
|
||||
if (Result != null && Result.Rows.Count > 0)
|
||||
{
|
||||
DataRow ResponseRow = Result.Rows[0];
|
||||
int id = Convert.ToInt32(ResponseRow["id"].ToString());
|
||||
string passwordHash = ResponseRow["passwordhash"].ToString();
|
||||
string passwordSalt = ResponseRow["passwordsalt"].ToString();
|
||||
string username = ResponseRow["username"].ToString();
|
||||
string email = ResponseRow["email"].ToString();
|
||||
DateTime lastLogon = DateTime.Parse(ResponseRow["lastlogin"].ToString());
|
||||
DateTime creationDate = DateTime.Parse(ResponseRow["creationdate"].ToString());
|
||||
Rank ranking = getRank(Convert.ToInt32(ResponseRow["ranking"]));
|
||||
string avatarURL = ResponseRow["avatarurl"].ToString();
|
||||
string posts = GetDataTable(String.Format("select (select count(*) from THREADS where authorid = {0}) + (select count(*) from REPLIES where authorid = {0}) as posts;", id)).Rows[0]["posts"].ToString();
|
||||
|
||||
User foundUser = new User(id, passwordHash, passwordSalt, username, email, Convert.ToInt32(posts), lastLogon, creationDate, ranking, avatarURL);
|
||||
return foundUser;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Dictionary<string, object> getDataTableFromUser(User addedUser)
|
||||
{
|
||||
Dictionary<String, object> newUser = new Dictionary<String, object>();
|
||||
|
||||
newUser.Add("username", addedUser.username);
|
||||
newUser.Add("email", addedUser.email);
|
||||
newUser.Add("passwordhash", addedUser.getPasswordHash());
|
||||
newUser.Add("passwordsalt", addedUser.getPasswordSalt());
|
||||
newUser.Add("lastlogin", SharedLibrary.Utilities.DateTimeSQLite(addedUser.lastLogin));
|
||||
newUser.Add("creationdate", SharedLibrary.Utilities.DateTimeSQLite(addedUser.creationDate));
|
||||
//newUser.Add("subscribedthreads", String.Join<int>(",", addedUser.subscribedThreads));
|
||||
newUser.Add("ranking", addedUser.ranking.getID());
|
||||
newUser.Add("avatarurl", addedUser.avatarURL);
|
||||
|
||||
return newUser;
|
||||
}
|
||||
|
||||
public User getUser(int userid)
|
||||
{
|
||||
DataTable Result = GetDataTable("USERS", new KeyValuePair<string, object>("id", userid));
|
||||
|
||||
return getUserFromDataTable(Result);
|
||||
}
|
||||
|
||||
public User getUser(string username)
|
||||
{
|
||||
DataTable Result = GetDataTable("USERS", new KeyValuePair<string, object>("username", username));
|
||||
|
||||
return getUserFromDataTable(Result);
|
||||
}
|
||||
|
||||
public bool userExists(string username, string email)
|
||||
{
|
||||
String Query = String.Format("SELECT * FROM USERS WHERE username = '{0}' or email = '{1}'", username, email);
|
||||
DataTable Result = GetDataTable(Query);
|
||||
|
||||
return Result.Rows.Count > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns ID of added user
|
||||
/// </summary>
|
||||
/// <param name="addedUser"></param>
|
||||
/// <param name="userSession"></param>
|
||||
/// <returns></returns>
|
||||
public User addUser(User addedUser, Session userSession)
|
||||
{
|
||||
var newUser = getDataTableFromUser(addedUser);
|
||||
Insert("USERS", newUser);
|
||||
|
||||
// fixme
|
||||
User createdUser = getUser(addedUser.username);
|
||||
return createdUser;
|
||||
}
|
||||
|
||||
public bool updateUser(User updatedUser)
|
||||
{
|
||||
var user = getDataTableFromUser(updatedUser);
|
||||
Update("USERS", user, new KeyValuePair<string, object>("id", updatedUser.getID()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getNumUsers()
|
||||
{
|
||||
var Result = GetDataTable("SELECT COUNT(id) AS userCount FROM `USERS`;");
|
||||
return Convert.ToInt32(Result.Rows[0]["userCount"]);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region CATEGORIES
|
||||
private Category getCategoryFromDataTable(DataTable Result)
|
||||
{
|
||||
if (Result != null && Result.Rows.Count > 0)
|
||||
{
|
||||
DataRow ResponseRow = Result.Rows[0];
|
||||
|
||||
int id = Convert.ToInt32(ResponseRow["id"]);
|
||||
string title = ResponseRow["title"].ToString();
|
||||
string description = ResponseRow["description"].ToString();
|
||||
string permissions = Encoding.UTF8.GetString((byte[])ResponseRow["permissions"]);
|
||||
List<Permission> perms = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Permission>>(permissions);
|
||||
|
||||
Category requestedCategory = new Category(id, title, description, perms);
|
||||
return requestedCategory;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void addCategory(Category addingCategory)
|
||||
{
|
||||
Dictionary<String, object> newCategory = new Dictionary<string, object>();
|
||||
|
||||
newCategory.Add("title", addingCategory.title);
|
||||
newCategory.Add("description", addingCategory.description);
|
||||
newCategory.Add("permissions", Newtonsoft.Json.JsonConvert.SerializeObject(addingCategory.permissions));
|
||||
|
||||
Insert("CATEGORIES", newCategory);
|
||||
}
|
||||
|
||||
public Category getCategory(int id)
|
||||
{
|
||||
string Query = String.Format("SELECT * FROM CATEGORIES WHERE id = {0}", id);
|
||||
DataTable Result = GetDataTable(Query);
|
||||
|
||||
return getCategoryFromDataTable(Result);
|
||||
}
|
||||
|
||||
public List<Category> getAllCategories()
|
||||
{
|
||||
string Query = String.Format("SELECT id FROM CATEGORIES");
|
||||
List<Category> cats = new List<Category>();
|
||||
DataTable Result = GetDataTable(Query);
|
||||
|
||||
if (Result != null && Result.Rows.Count > 0)
|
||||
{
|
||||
for (int i = 0; i < Result.Rows.Count; i++)
|
||||
cats.Add(getCategory(Convert.ToInt32(Result.Rows[i]["id"])));
|
||||
}
|
||||
|
||||
return cats;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region THREADS
|
||||
|
||||
public Dictionary<string, object> getDataTableFromThread(ForumThread Thread)
|
||||
{
|
||||
Dictionary<string, object> newThread = new Dictionary<string, object>();
|
||||
newThread.Add("title", Thread.title);
|
||||
newThread.Add("categoryid", Thread.threadCategory.getID());
|
||||
newThread.Add("replies", Thread.replies);
|
||||
newThread.Add("authorid", Thread.author.getID());
|
||||
newThread.Add("creationdate", SharedLibrary.Utilities.DateTimeSQLite(Thread.creationDate));
|
||||
newThread.Add("updateddate", SharedLibrary.Utilities.DateTimeSQLite(Thread.updatedDate));
|
||||
newThread.Add("content", Thread.content);
|
||||
newThread.Add("visible", Convert.ToInt32(Thread.visible));
|
||||
|
||||
return newThread;
|
||||
}
|
||||
|
||||
public int addThread(ForumThread Thread)
|
||||
{
|
||||
Insert("THREADS", getDataTableFromThread(Thread));
|
||||
return getThreadID(Thread.creationDate);
|
||||
}
|
||||
|
||||
|
||||
public bool updateThread(ForumThread updatedThread)
|
||||
{
|
||||
var user = getDataTableFromThread(updatedThread);
|
||||
Update("THREADS", user, new KeyValuePair<string, object>("id", updatedThread.getID()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public ForumThread getThread(int id)
|
||||
{
|
||||
DataTable Result = GetDataTable("THREADS", new KeyValuePair<string, object>("id", id));
|
||||
|
||||
return getThreadFromDataTable(Result);
|
||||
}
|
||||
|
||||
private ForumThread getThreadFromDataTable(DataTable Result)
|
||||
{
|
||||
if (Result != null && Result.Rows.Count > 0)
|
||||
{
|
||||
DataRow ResponseRow = Result.Rows[0];
|
||||
int id = Convert.ToInt32(ResponseRow["id"].ToString());
|
||||
int categoryid = Convert.ToInt32(ResponseRow["categoryid"].ToString());
|
||||
int authorid = Convert.ToInt32(ResponseRow["authorid"].ToString());
|
||||
int replies = Convert.ToInt32(ResponseRow["replies"].ToString());
|
||||
string title = ResponseRow["title"].ToString();
|
||||
|
||||
var category = getCategory(categoryid);
|
||||
var author = getUser(authorid);
|
||||
|
||||
bool visible = Convert.ToBoolean((Convert.ToInt32(ResponseRow["visible"])));
|
||||
|
||||
DateTime creationDate = DateTime.Parse(ResponseRow["creationdate"].ToString());
|
||||
DateTime updatedDate = DateTime.Parse(ResponseRow["updateddate"].ToString());
|
||||
string content = ResponseRow["content"].ToString();
|
||||
|
||||
ForumThread retrievedThread = new ForumThread(id, title, visible, content, replies, author, category, creationDate, updatedDate);
|
||||
return retrievedThread;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// we have no other unique id yet
|
||||
private int getThreadID(DateTime creationDate)
|
||||
{
|
||||
string Query = String.Format("SELECT * FROM THREADS WHERE creationdate = \"{0}\"", SharedLibrary.Utilities.DateTimeSQLite(creationDate));
|
||||
DataTable Result = GetDataTable(Query);
|
||||
|
||||
if (Result != null && Result.Rows.Count > 0)
|
||||
return Convert.ToInt32(Result.Rows[0]["id"].ToString());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public List<ForumThread> getRecentThreads(int categoryID)
|
||||
{
|
||||
List<ForumThread> threads = new List<ForumThread>();
|
||||
string Query = String.Format("SELECT id FROM THREADS WHERE categoryid = {0} AND visible = 1 ORDER BY `updateddate` DESC LIMIT 3", categoryID);
|
||||
DataTable Result = GetDataTable(Query);
|
||||
|
||||
if (Result != null && Result.Rows.Count > 0)
|
||||
{
|
||||
for (int i = 0; i < Result.Rows.Count; i++)
|
||||
threads.Add(getThread(Convert.ToInt32(Result.Rows[i]["id"])));
|
||||
}
|
||||
|
||||
return threads;
|
||||
}
|
||||
|
||||
public List<ForumThread> getCategoryThreads(int categoryID)
|
||||
{
|
||||
List<ForumThread> threads = new List<ForumThread>();
|
||||
string Query = String.Format("SELECT id FROM THREADS WHERE categoryid = {0} and visible = 1 ORDER BY `updateddate` DESC", categoryID);
|
||||
DataTable Result = GetDataTable(Query);
|
||||
|
||||
if (Result != null && Result.Rows.Count > 0)
|
||||
{
|
||||
for (int i = 0; i < Result.Rows.Count; i++)
|
||||
threads.Add(getThread(Convert.ToInt32(Result.Rows[i]["id"])));
|
||||
}
|
||||
|
||||
return threads;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region RANKING
|
||||
public int addRank(Rank newRank)
|
||||
{
|
||||
Dictionary<string, object> rank = new Dictionary<string, object>();
|
||||
rank.Add("name", newRank.name);
|
||||
rank.Add("equivalentrank", (int)newRank.equivalentRank);
|
||||
|
||||
Insert("RANKS", rank);
|
||||
|
||||
Rank r = getRank(newRank.name);
|
||||
|
||||
if (r == null)
|
||||
return 0;
|
||||
|
||||
return r.getID();
|
||||
}
|
||||
|
||||
public Rank getRank(string rankName)
|
||||
{
|
||||
DataTable Result = GetDataTable("RANKS", new KeyValuePair<string, object>("name", rankName));
|
||||
|
||||
if (Result != null && Result.Rows.Count > 0)
|
||||
{
|
||||
DataRow ResponseRow = Result.Rows[0];
|
||||
string name = ResponseRow["name"].ToString();
|
||||
int equivRank = Convert.ToInt32(ResponseRow["equivalentrank"].ToString());
|
||||
int id = Convert.ToInt32(ResponseRow["id"].ToString());
|
||||
|
||||
Rank retrievedRank = new Rank(id, name, (SharedLibrary.Player.Permission)equivRank);
|
||||
return retrievedRank;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Rank getRank(int rankID)
|
||||
{
|
||||
DataTable Result = GetDataTable("RANKS", new KeyValuePair<string, object>("id", rankID));
|
||||
|
||||
if (Result != null && Result.Rows.Count > 0)
|
||||
{
|
||||
DataRow ResponseRow = Result.Rows[0];
|
||||
string name = ResponseRow["name"].ToString();
|
||||
int equivRank = Convert.ToInt32(ResponseRow["equivalentrank"].ToString());
|
||||
|
||||
Rank retrievedRank = new Rank(rankID, name, (SharedLibrary.Player.Permission)equivRank);
|
||||
return retrievedRank;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region REPLIES
|
||||
public int addReply(Post reply)
|
||||
{
|
||||
Insert("REPLIES", getDataTableFromReply(reply));
|
||||
return getReplyID(reply.creationDate);
|
||||
}
|
||||
|
||||
public bool updateReply(Post reply)
|
||||
{
|
||||
return Update("REPLIES", getDataTableFromReply(reply), new KeyValuePair<string, object>("id", reply.id));
|
||||
}
|
||||
|
||||
public Post getReply(int id)
|
||||
{
|
||||
DataTable Result = GetDataTable("REPLIES", new KeyValuePair<string, object>("id", id));
|
||||
|
||||
return getReplyFromDataTable(Result);
|
||||
}
|
||||
|
||||
public List<Post> getRepliesFromThreadID(int threadID)
|
||||
{
|
||||
List<Post> replies = new List<Post>();
|
||||
//var Result = GetDataTable("REPLIES", new KeyValuePair<string, object>("threadid", threadID));
|
||||
var Result = GetDataTable("SELECT * FROM REPLIES WHERE threadid = " + threadID + " AND visible = 1");
|
||||
|
||||
foreach (DataRow row in Result.Rows)
|
||||
{
|
||||
replies.Add(getReply(Convert.ToInt32(row["id"].ToString())));
|
||||
}
|
||||
|
||||
return replies;
|
||||
}
|
||||
|
||||
private Dictionary<string, object> getDataTableFromReply(Post reply)
|
||||
{
|
||||
Dictionary<string, object> newReply = new Dictionary<string, object>();
|
||||
newReply.Add("title", reply.title);
|
||||
newReply.Add("authorid", reply.author.getID());
|
||||
newReply.Add("threadid", reply.threadid);
|
||||
newReply.Add("creationdate", SharedLibrary.Utilities.DateTimeSQLite(reply.creationDate));
|
||||
newReply.Add("updateddate", SharedLibrary.Utilities.DateTimeSQLite(reply.updatedDate));
|
||||
newReply.Add("content", reply.content);
|
||||
newReply.Add("visible", Convert.ToInt32(reply.visible));
|
||||
|
||||
return newReply;
|
||||
}
|
||||
|
||||
private Post getReplyFromDataTable(DataTable Result)
|
||||
{
|
||||
if (Result != null && Result.Rows.Count > 0)
|
||||
{
|
||||
DataRow ResponseRow = Result.Rows[0];
|
||||
int id = Convert.ToInt32(ResponseRow["id"].ToString());
|
||||
int threadid = Convert.ToInt32(ResponseRow["threadid"].ToString());
|
||||
int authorid = Convert.ToInt32(ResponseRow["authorid"].ToString());
|
||||
string title = ResponseRow["title"].ToString();
|
||||
var author = getUser(authorid);
|
||||
|
||||
DateTime creationDate = DateTime.Parse(ResponseRow["creationdate"].ToString());
|
||||
DateTime updatedDate = DateTime.Parse(ResponseRow["updateddate"].ToString());
|
||||
string content = ResponseRow["content"].ToString();
|
||||
|
||||
bool visible = Convert.ToBoolean((Convert.ToInt32(ResponseRow["visible"])));
|
||||
|
||||
Post retrievedPost = new Post(id, threadid, visible, title, content, author, creationDate, updatedDate);
|
||||
return retrievedPost;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// we have no other unique id yet
|
||||
private int getReplyID(DateTime creationDate)
|
||||
{
|
||||
DataTable Result = GetDataTable("REPLIES", new KeyValuePair<string, object>("creationdate", SharedLibrary.Utilities.DateTimeSQLite(creationDate)));
|
||||
|
||||
if (Result != null && Result.Rows.Count > 0)
|
||||
return Convert.ToInt32(Result.Rows[0]["id"].ToString());
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
152
MessageboardPlugin/Thread.cs
Normal file
152
MessageboardPlugin/Thread.cs
Normal file
@ -0,0 +1,152 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MessageBoard
|
||||
{
|
||||
|
||||
public class Post : ForumThread
|
||||
{
|
||||
/// <summary>
|
||||
/// Initial creation
|
||||
/// </summary>
|
||||
/// <param name="title"></param>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="author"></param>
|
||||
/// <param name="parentThread"></param>
|
||||
///
|
||||
|
||||
public int threadid;
|
||||
|
||||
public Post(string title, int threadid, string content, User author) : base (title, content, author, null)
|
||||
{
|
||||
this.threadid = threadid;
|
||||
}
|
||||
|
||||
public Post(int id, int threadid, bool visible, string title, string content, User author, DateTime creationDate, DateTime updatedDate) : base(id, title, visible, content, 0, author, null, creationDate, updatedDate)
|
||||
{
|
||||
this.lastModificationString = SharedLibrary.Utilities.timePassed(creationDate);
|
||||
this.threadid = threadid;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class Category : Identifiable
|
||||
{
|
||||
public int id { get; private set; }
|
||||
public string title { get; private set; }
|
||||
public string description { get; private set; }
|
||||
public List<Permission> permissions { get; private set; }
|
||||
|
||||
public Category(string title, string description)
|
||||
{
|
||||
this.title = title;
|
||||
this.description = description;
|
||||
this.permissions = new List<Permission>();
|
||||
id = 0;
|
||||
}
|
||||
|
||||
public Category(int id, string title, string description, List<Permission> permissions)
|
||||
{
|
||||
this.title = title;
|
||||
this.description = description;
|
||||
this.id = id;
|
||||
this.permissions = permissions;
|
||||
}
|
||||
|
||||
public int getID()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
public class ForumThread : Identifiable
|
||||
{
|
||||
public string title { get; private set; }
|
||||
public string content { get; private set; }
|
||||
public User author { get; private set; }
|
||||
public Category threadCategory { get; private set; }
|
||||
public DateTime creationDate { get; private set; }
|
||||
public DateTime updatedDate;
|
||||
public string lastModificationString { get; protected set; }
|
||||
public int id { get; private set; }
|
||||
public int replies;
|
||||
public bool visible = true;
|
||||
|
||||
/// <summary>
|
||||
/// Initial creation
|
||||
/// </summary>
|
||||
/// <param name="title"></param>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="author"></param>
|
||||
public ForumThread(string title, string content, User author, Category threadCategory)
|
||||
{
|
||||
if (content.Length == 0)
|
||||
throw new Exceptions.ThreadException("Post is empty");
|
||||
if (author == null)
|
||||
throw new Exceptions.ThreadException("No author of post");
|
||||
if (title.Length == 0)
|
||||
throw new Exceptions.ThreadException("Title is empty");
|
||||
|
||||
this.title = title;
|
||||
this.content = content;
|
||||
this.author = author;
|
||||
this.threadCategory = threadCategory;
|
||||
creationDate = DateTime.Now;
|
||||
updatedDate = DateTime.Now;
|
||||
replies = 0;
|
||||
id = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loading from database
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="title"></param>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="author"></param>
|
||||
/// <param name="creationDate"></param>
|
||||
public ForumThread(int id, string title, bool visible, string content, int replies, User author, Category threadCategory, DateTime creationDate, DateTime updatedDate)
|
||||
{
|
||||
this.id = id;
|
||||
this.replies = replies;
|
||||
this.title = title;
|
||||
this.content = content;
|
||||
this.author = author;
|
||||
this.threadCategory = threadCategory;
|
||||
this.creationDate = creationDate;
|
||||
this.updatedDate = updatedDate;
|
||||
this.lastModificationString = SharedLibrary.Utilities.timePassed(updatedDate);
|
||||
this.visible = visible;
|
||||
}
|
||||
|
||||
public int getID()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
public bool updateContent(string content)
|
||||
{
|
||||
if (content != null && content.Length > 0)
|
||||
{
|
||||
this.content = content;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool updateTitle(string title)
|
||||
{
|
||||
if (title != null && title.Length > 0)
|
||||
{
|
||||
this.title = title;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
108
MessageboardPlugin/User.cs
Normal file
108
MessageboardPlugin/User.cs
Normal file
@ -0,0 +1,108 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using SharedLibrary;
|
||||
|
||||
namespace MessageBoard
|
||||
{
|
||||
public class User : Identifiable
|
||||
{
|
||||
private string passwordHash; // byte array -> b64 string
|
||||
private string passwordSalt; // byte array -> b64 string
|
||||
public DateTime lastLogin;
|
||||
public string lastLoginString;
|
||||
public readonly DateTime creationDate;
|
||||
public int id { get; private set; }
|
||||
public string avatarURL;
|
||||
|
||||
public string username { get; private set; }
|
||||
public string email { get; private set; }
|
||||
public Rank ranking;
|
||||
|
||||
public int posts;
|
||||
public int privateMessages;
|
||||
public int warnings;
|
||||
|
||||
public List<int> subscribedThreads { get; private set; }
|
||||
|
||||
public User()
|
||||
{
|
||||
username = "Guest";
|
||||
ranking = Plugin.Main.forum.guestRank;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When creating a new user
|
||||
/// </summary>
|
||||
/// <param name="username"></param>
|
||||
/// <param name="email"></param>
|
||||
/// <param name="passwordHash"></param>
|
||||
/// <param name="passwordSalt"></param>
|
||||
/// <param name="posts"></param>
|
||||
/// <param name="privateMessage"></param>
|
||||
/// <param name="warnings"></param>
|
||||
public User(string username, string matchedUsername, string email, string passwordHash, string passwordSalt, Rank ranking)
|
||||
{
|
||||
if (username.Length < 1)
|
||||
throw new Exceptions.UserException("Username is empty");
|
||||
if (email.Length < 1)
|
||||
throw new Exceptions.UserException("Email is empty");
|
||||
|
||||
lastLogin = DateTime.Now;
|
||||
subscribedThreads = new List<int>();
|
||||
|
||||
this.username = username;
|
||||
this.email = email;
|
||||
this.posts = 0;
|
||||
this.privateMessages = 0;
|
||||
this.warnings = 0;
|
||||
this.ranking = ranking;
|
||||
this.passwordHash = passwordHash;
|
||||
this.passwordSalt = passwordSalt;
|
||||
this.creationDate = DateTime.Now;
|
||||
this.avatarURL = "";
|
||||
|
||||
id = 0;
|
||||
}
|
||||
|
||||
public User(int id, string passwordHash, string passwordSalt, string username, string email, int posts, DateTime lastLogin, DateTime creationDate, Rank ranking, string avatarURL)
|
||||
{
|
||||
this.id = id;
|
||||
this.passwordHash = passwordHash;
|
||||
this.passwordSalt = passwordSalt;
|
||||
this.username = username;
|
||||
this.email = email;
|
||||
this.lastLogin = lastLogin;
|
||||
this.creationDate = creationDate;
|
||||
this.ranking = ranking;
|
||||
this.avatarURL = avatarURL;
|
||||
this.posts = posts;
|
||||
|
||||
this.lastLoginString = SharedLibrary.Utilities.timePassed(lastLogin);
|
||||
}
|
||||
|
||||
public int getID()
|
||||
{
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public string getPasswordSalt()
|
||||
{
|
||||
return this.passwordSalt;
|
||||
}
|
||||
|
||||
public string getPasswordHash()
|
||||
{
|
||||
return this.passwordHash;
|
||||
}
|
||||
}
|
||||
|
||||
public struct UserInfo
|
||||
{
|
||||
public string username;
|
||||
public string email;
|
||||
public string matchedUsername;
|
||||
public Rank rank;
|
||||
}
|
||||
}
|
86
MessageboardPlugin/forum/category.html
Normal file
86
MessageboardPlugin/forum/category.html
Normal file
@ -0,0 +1,86 @@
|
||||
<div id="view">
|
||||
<div style="float: left;" id="categoryHeader">
|
||||
|
||||
</div>
|
||||
<a href="home"><i class="fa fa-reply themeBlue" aria-hidden="true" style="padding: 0 0.5em; font-size: 24pt; cursor: pointer; margin-top: -5px;"></i></a>
|
||||
<a href="" id="postThreadButton">
|
||||
<div style="float: right;" id="postThreadCaption">
|
||||
<i class="fa fa-plus" aria-hidden="true"></i>
|
||||
Post
|
||||
</div>
|
||||
</a>
|
||||
<div style="clear: both;"></div>
|
||||
<hr class="simple"/>
|
||||
<div id="categoryContainer">
|
||||
</div>
|
||||
<hr/>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
|
||||
$('#postThreadButton').attr("href", "postthread?id=" + parseGet("id"));
|
||||
|
||||
$( document ).on("actionEventLoad", function() {
|
||||
|
||||
$.getJSON("_categorythreads?id=" + parseGet("id"), function(response) {
|
||||
|
||||
var result = "";
|
||||
|
||||
if (response.errorCode != null)
|
||||
{
|
||||
if (response.errorCode == 1)
|
||||
$('#categoryHeader').append('Permission Denied');
|
||||
else if (response.errorCode == 13)
|
||||
{
|
||||
$('#categoryHeader').html("Invalid Category");
|
||||
$('#postThreadButton').hide();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.length == 0)
|
||||
{
|
||||
$('#categoryHeader').append('No Posts');
|
||||
return;
|
||||
}
|
||||
|
||||
$.each(response, function(i, thread) {
|
||||
result +=
|
||||
"<div class=\"categoryThread table\"> \
|
||||
<i class=\"fa fa-circle-o themeBlue tableCell\" aria-hidden=\"true\"></i> \
|
||||
<div class=\"threadTitle tableCell\"><a href=\"thread?id=" + thread["id"] + "\">" + decodeURIComponent(thread["title"]) + "</a><span class=\"threadAuthor tableCell\"><a href=\"user?id=" + thread["author"].id + "\">" + thread["author"].username + "</a></span></div> \
|
||||
<div class=\"threadTime tableCell\">Last response " + checkJustNow(thread["lastModificationString"]) + "</div> \
|
||||
<div class=\"threadReplyCount tableCell\"><div class=\"threadReplyBG\">"+ thread.replies +"</div></div> \
|
||||
<div class=\"threadActions tableCell\" style='vertical-align: middle; " + shouldHideAction(thread.author) +"'><i postid='"+ thread.id + "' class=\"fa fa-times actionHover actionDelete\" aria-hidden=\"true\"></i></div>\
|
||||
</div>";
|
||||
});
|
||||
|
||||
$('#categoryHeader').html(response[0]["threadCategory"].title);
|
||||
$('#categoryContainer').append(result);
|
||||
});
|
||||
});
|
||||
|
||||
$('#content').on('click', '.actionDelete', function(e) {
|
||||
$.getJSON("_editthread",
|
||||
{
|
||||
id : $(this).attr("postid"),
|
||||
delete : true
|
||||
},
|
||||
function(response) {
|
||||
if (response.success)
|
||||
window.location.replace(response.destination);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<!--
|
||||
<div id="categoryContainer">
|
||||
<div class="categoryThread table">
|
||||
<i class="fa fa-circle-o themeBlue tableCell" aria-hidden="true"></i>
|
||||
<div class="threadTitle tableCell"><a href="#">This is the particular thread title</a><span class="threadAuthor tableCell"><a href="#">Example Author</a></span></div>
|
||||
<div class="threadTime tableCell">5 minutes ago</div>
|
||||
<div class="threadReplyCount tableCell"><div class="threadReplyBG">0</div></div>
|
||||
</div>-->
|
60
MessageboardPlugin/forum/home.html
Normal file
60
MessageboardPlugin/forum/home.html
Normal file
@ -0,0 +1,60 @@
|
||||
<div id="view" class="table">
|
||||
|
||||
<div id="threadView" class="tableCell">
|
||||
<div class="threadBox">
|
||||
|
||||
|
||||
</div>
|
||||
<hr/>
|
||||
</div>
|
||||
|
||||
<div id="recentView" class="tableCell">
|
||||
<div id="recentTitle">
|
||||
Online Users
|
||||
</div>
|
||||
<div id="onlineUsers">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$( document ).ready(function() {
|
||||
|
||||
$.getJSON("_recentthreads", function(response) {
|
||||
|
||||
var result = "";
|
||||
$.each(response, function(i, category) {
|
||||
result += "<div class=\"categoryTitle datThing\"> \
|
||||
<div class=\"title\"><a href=\"category?id=" + category["categoryID"] + "\">" + category["categoryTitle"] + "</a></div> \
|
||||
<div class=\"categoryDescription\">" + category["categoryDescription"] + "</div>" +
|
||||
"</div> \
|
||||
<div class=\"threadPreview table\">";
|
||||
|
||||
$.each(category["recentThreads"], function(i, thread)
|
||||
{
|
||||
result += "<div class=\"individualThreadInfo\">";
|
||||
result += "<i class=\"fa fa-comment\" aria-hidden=\"true\"></i>";
|
||||
result += "<span class=\"threadTitle tableCell\"><a href=\"thread?id=" + thread.id + "\">" + decodeURIComponent(thread.title) + "</a> — <a style='opacity: 0.5;' href=\"user?id=" + thread.author.id + "\">" + thread.author['username'] + "</a></span>";
|
||||
result += "<span class=\"threadInfo tableCell\"><a class=\"themeOrange\" href=\"" + "user?id=" + thread.author['id'] + "\"></a><span class=\"light\">" + checkJustNow(thread.lastModificationString) + "</span></span>";
|
||||
result += "<div style=\"display: table-row;\"></div>";
|
||||
result += "</div>";
|
||||
});
|
||||
|
||||
result += "</div>"
|
||||
});
|
||||
|
||||
|
||||
$('.threadBox').append(result);
|
||||
|
||||
});
|
||||
|
||||
$.getJSON("_stats", function(response) {
|
||||
$.each(response.onlineUsers, function(i, user) {
|
||||
$('#onlineUsers').append('<a href="user?id=' + user.id + '"><p>' + getColorForLevel(user.ranking.name, user.username) + '<p></a>');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
</script>
|
59
MessageboardPlugin/forum/login.html
Normal file
59
MessageboardPlugin/forum/login.html
Normal file
@ -0,0 +1,59 @@
|
||||
<div class="infoBox" style="display : none;">
|
||||
<div class="header">
|
||||
<i class="fa fa-user" aria-hidden="true"></i>
|
||||
Login</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="loginButton" value="Login" type="submit"/>
|
||||
<a href="register">Register</a>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$( document ).ready(function() {
|
||||
|
||||
checkPrivilege();
|
||||
|
||||
});
|
||||
|
||||
function validateInput()
|
||||
{
|
||||
var password = $('form #password');
|
||||
var username = $('form #username');
|
||||
|
||||
if (password.val().length < 1) {
|
||||
showErrorMessage("Password is required!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (username.val().length < 1) {
|
||||
showErrorMessage("Username is required!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
$("#loginButton").click(function(e) {
|
||||
e.preventDefault();
|
||||
if (validateInput())
|
||||
$.getJSON("_login",
|
||||
{
|
||||
username : $('form #username').val(),
|
||||
password : $('form #password').val()
|
||||
},
|
||||
function(result) {
|
||||
if (result["errorCode"] == 0)
|
||||
window.location.replace(result["destination"]);
|
||||
else {
|
||||
showErrorMessage(result["errorCode"]);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
</script>
|
56
MessageboardPlugin/forum/postthread.html
Normal file
56
MessageboardPlugin/forum/postthread.html
Normal file
@ -0,0 +1,56 @@
|
||||
<div id="postThreadContainer">
|
||||
<div class="infoBox" style="width: 80%;">
|
||||
<div class="header">
|
||||
<i class="fa fa-commenting" aria-hidden="true"></i>
|
||||
<span>Post New Thread</span>
|
||||
</div>
|
||||
|
||||
<div class="alertBox">
|
||||
</div>
|
||||
|
||||
<form>
|
||||
<div class="table" style="width: 100%;">
|
||||
<select id="threadCategory" class="tableCell">
|
||||
</select>
|
||||
<input placeholder="Enter thread title..." type="text" id="threadTitle" class="tableCell"/>
|
||||
</div>
|
||||
<textarea id="threadContent" placeholder="Enter thread content..."/></textarea>
|
||||
<input type="submit" value="Post" id="submitThreadButton"/>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$( document ).ready(function() {
|
||||
|
||||
$.getJSON("_categories", function(response) {
|
||||
$.each(response, function(i, category) {
|
||||
$('select').append("<option value='" + category.id + "'>" + category.title + "</option>");
|
||||
});
|
||||
|
||||
$('select option[value="'+ parseGet("id") +'"]').attr("selected",true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
$("#submitThreadButton").click(function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
$.getJSON("_postthread",
|
||||
{
|
||||
title : $('form #threadTitle').val(),
|
||||
content : $('form #threadContent').val(),
|
||||
category : $('select').val(),
|
||||
},
|
||||
|
||||
function(result) {
|
||||
if (result["errorCode"] == 0)
|
||||
window.location.replace(result["destination"]);
|
||||
else {
|
||||
showErrorMessage(result["errorCode"]);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
</script>
|
92
MessageboardPlugin/forum/register.html
Normal file
92
MessageboardPlugin/forum/register.html
Normal file
@ -0,0 +1,92 @@
|
||||
|
||||
<div class="infoBox" style="display:none;">
|
||||
<div class="header">
|
||||
<i style="" class="fa fa-user-plus" aria-hidden="true"></i>
|
||||
Register
|
||||
|
||||
</div>
|
||||
|
||||
<div class="alertBox">
|
||||
</div>
|
||||
<form id="registration" method="get">
|
||||
<input id="username" name="username" type="text"/>
|
||||
<input id="hiddenUsername" type="text" name="hiddenUsername" style="display: none;"/>
|
||||
<label for="username">Username</label>
|
||||
<input id="password" name="password" type="password"/>
|
||||
<label for="password">Password</label>
|
||||
<input id="passwordRepeat" name="passwordRepeat" type="password"/>
|
||||
<label for="passwordRepeat">Verify Password</label>
|
||||
<input id="email" name="email" type="text"/>
|
||||
<label for="email">Email</label>
|
||||
<input id="registerButton" value="Register" type="submit"/>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$( document ).ready(function() {
|
||||
|
||||
checkPrivilege();
|
||||
|
||||
});
|
||||
|
||||
function validateInput()
|
||||
{
|
||||
var password = $('form #password');
|
||||
var repeatPassword = $('form #passwordRepeat');
|
||||
var username = $('form #username');
|
||||
var email = $('form #email');
|
||||
|
||||
if (password.val().length < 5) {
|
||||
showErrorMessage("Passwords must be at least 5 characters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (password.val() != repeatPassword.val()) {
|
||||
showErrorMessage("Passwords must match!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (username.val().length < 3) {
|
||||
showErrorMessage("Username must contain at least 3 characters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (email.val().length < 3) {
|
||||
showErrorMessage("Invalid email address!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
$("#registerButton").click(function(e) {
|
||||
e.preventDefault();
|
||||
if (validateInput())
|
||||
$.getJSON("_register",
|
||||
{
|
||||
username : $('form #username').val(),
|
||||
password : $('form #password').val(),
|
||||
hiddenUsername : $('form #hiddenUsername').val(),
|
||||
passwordRepeat : $('form #passwordRepeat').val(),
|
||||
email : $('form #email').val()
|
||||
},
|
||||
function(result) {
|
||||
if (result["errorCode"] == 0)
|
||||
window.location.replace(result["destination"]);
|
||||
else {
|
||||
showErrorMessage(result["errorCode"]);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
$('input[type="text"], input[type="password"]').click(function() { $('.alertBox').slideUp("fast"); });
|
||||
|
||||
$( document ).ready(function() {
|
||||
$.getJSON("_userinfo", function(result) {
|
||||
if (result["matchedName"] != "null")
|
||||
$('#username, #hiddenUsername').val(result["matchedUsername"]);
|
||||
});
|
||||
});
|
||||
</script>
|
126
MessageboardPlugin/forum/thread.html
Normal file
126
MessageboardPlugin/forum/thread.html
Normal file
@ -0,0 +1,126 @@
|
||||
<div id="threadContainer">
|
||||
<div id="textNav"><a class="themeBlue" href="home">Home</a> » </div>
|
||||
<hr/>
|
||||
<div class="threadStart table" style="width: 100%;">
|
||||
<div class="userInfo tableCell">
|
||||
<div class="userAvatar">
|
||||
<i class="fa fa-user-secret" aria-hidden="true" style="font-size: 8em;"></i>
|
||||
</div>
|
||||
<a class="userProfileLink" href=""><span class="userTitle">_</span></a><br/>
|
||||
<span style="font-size: 9pt;" class="timePosted">_</span>
|
||||
</div>
|
||||
<div class="threadInfo tableCell">
|
||||
<div class="threadTitle" style="float: left;">_</div>
|
||||
<div style="float: right;" id="replyThreadCaption">
|
||||
<i class="fa fa-reply" aria-hidden="true"></i>
|
||||
Reply
|
||||
</div>
|
||||
<div style="clear: both;"></div>
|
||||
<div class="threadContent">_</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="postReplyContainer" style="display: none;">
|
||||
<hr/>
|
||||
<div id="postReplyClose">
|
||||
<i class="fa fa-times" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div id="replyContentContainer">
|
||||
<div class="alertBox">
|
||||
</div>
|
||||
<textarea placeholder="Reply content..." id="replyContentBox"></textarea>
|
||||
<div id="submitReplyButton">
|
||||
<i class="fa fa-reply" aria-hidden="true"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
|
||||
$( document ).on("actionEventLoad", function() {
|
||||
|
||||
$.getJSON("_thread?id=" + parseGet('id'), function(Response) {
|
||||
|
||||
if (Response.errorCode != null)
|
||||
{
|
||||
alert('error!');
|
||||
}
|
||||
$('#textNav').append('<a class="themeBlue" href="category?id=' + Response.Thread.threadCategory.id + '">' + Response.Thread.threadCategory.title + '</a> » ' + decodeURIComponent(Response.Thread.title));
|
||||
$('.threadStart .userTitle').html(Response.Thread.author.username);
|
||||
$('.threadStart .timePosted').html(getDate(Response.Thread.creationDate));
|
||||
$('.threadStart .threadTitle').html(decodeURIComponent(Response.Thread.title));
|
||||
$('.threadStart a.userProfileLink').attr("href", "user?id=" + Response.Thread.author.id);
|
||||
$('.threadStart .threadContent').html(decodeURIComponent(Response.Thread.content));
|
||||
if (Response.Thread.author.avatarURL != "")
|
||||
$('.threadStart .userAvatar').html("").attr("style", "background-image:url('" + Response.Thread.author.avatarURL + "');'");
|
||||
$('#replyThreadButton').attr("href", "postthread?threadid=" + Response.Thread.id);
|
||||
|
||||
$.each(Response.Replies, function(i, eachReply) {
|
||||
|
||||
var cat = "<div class='threadStart table' style='width: 100%;'> \
|
||||
<div class='userInfo tableCell'>";
|
||||
|
||||
|
||||
if (eachReply.author.avatarURL == "")
|
||||
cat += "<div class='userAvatar'><i class='fa fa-user-secret' aria-hidden='true' style='font-size: 8em;'></i>";
|
||||
else
|
||||
cat += "<div class='userAvatar' style=\"background-image:url('" + eachReply.author.avatarURL + "');\">";
|
||||
cat +=
|
||||
"</div> \
|
||||
<a class='userProfileLink' href='user?id="+ eachReply.author.id +"'><span class='userTitle'>" + getColorForLevel(eachReply.author.ranking.name, eachReply.author.username) + "</span></a><br/> \
|
||||
<span style='font-size: 9pt;' class='timePosted'>" + checkJustNow(eachReply.lastModificationString) + "</span> \
|
||||
</div> \
|
||||
<div class='threadInfo tableCell'> \
|
||||
<i style=\"" + shouldHideAction(eachReply.author) + "\" replyid='" + eachReply.id + "' class=\"fa fa-times actionHover actionDelete\" aria-hidden=\"true\"></i> \
|
||||
<div class='threadContent'>" + decodeURIComponent(eachReply.content) + "</div> \
|
||||
</div> \
|
||||
</div>";
|
||||
|
||||
$("#threadContainer").append(cat);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$('#replyThreadCaption').click(function(e) {
|
||||
e.preventDefault();
|
||||
$('#postReplyContainer').slideDown('fast');
|
||||
|
||||
});
|
||||
|
||||
$('#postReplyClose').click(function(e) {
|
||||
$(this).parent().slideUp('fast');
|
||||
});
|
||||
|
||||
$("#submitReplyButton").click(function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
$.getJSON("_postthread",
|
||||
{
|
||||
content : $('#replyContentBox').val(),
|
||||
title : "Reply",
|
||||
threadid : parseGet("id")
|
||||
},
|
||||
|
||||
function(result) {
|
||||
if (result["errorCode"] == 0)
|
||||
window.location.replace(result["destination"]);
|
||||
else {
|
||||
showErrorMessage(result["errorCode"]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$('#content').on('click', '.actionDelete', function(e) {
|
||||
$.getJSON("_editthread",
|
||||
{
|
||||
replyid : $(this).attr("replyid"),
|
||||
delete : true
|
||||
},
|
||||
function(response) {
|
||||
if (response.success)
|
||||
window.location.replace(response.destination);
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
56
MessageboardPlugin/forum/user.html
Normal file
56
MessageboardPlugin/forum/user.html
Normal file
@ -0,0 +1,56 @@
|
||||
<div id="userCover" style="display:none;">
|
||||
</div>
|
||||
|
||||
<div id="userInfoBox">
|
||||
<div class="table" style="width: 100%;">
|
||||
<div class="tableCell" style="vertical-align:middle; width: 70%;">
|
||||
<div class="userInfoField table">
|
||||
<i class="fa fa-user tableCell" aria-hidden="true"></i> <span class="tableCell" id="userCreated">_</span>
|
||||
</div>
|
||||
|
||||
<div class="userInfoField table">
|
||||
<i class="fa fa-clock-o tableCell" aria-hidden="true"></i> <span class="tableCell" id="userLogon">_</span>
|
||||
</div>
|
||||
|
||||
<div class="userInfoField table">
|
||||
<i class="fa fa-comment tableCell" aria-hidden="true"></i> <span class="tableCell" id="userPostCount">_</span>
|
||||
</div>
|
||||
|
||||
<div class="userInfoField table">
|
||||
<i class="fa fa-envelope-o tableCell" aria-hidden="true"></i> <span class="tableCell" id="userEmail"><a href="#" class="themeBlue">_</a></span>
|
||||
</div>
|
||||
|
||||
<div class="userInfoField table">
|
||||
<i class="fa fa-users tableCell" aria-hidden="true"></i> <span class="tableCell" id="userRank">_</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tableCell" style="vertical-align:middle;">
|
||||
<div id="userAvatar" class="">
|
||||
<i class="fa fa-user-secret" aria-hidden="true" style="font-size: 19em; margin-top: -56px;"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr style="width: calc(100% + 2em); margin-bottom: -1em; margin-left: -1em;"/>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
|
||||
$.getJSON("_userinfo?id=" + parseGet('id'), function(user) {
|
||||
if (user == null)
|
||||
return false;
|
||||
$('#userCover').html(user.username);
|
||||
var creationDate = new Date(user.creationDate);
|
||||
$('#userCreated').html("Joined " + (creationDate.getMonth() + 1) + '-' + creationDate.getDate() + '-' + creationDate.getFullYear());
|
||||
$('#userLogon').html("Last seen " + checkJustNow(user.lastLoginString));
|
||||
$('#userPostCount').html(user.posts + " Posts");
|
||||
$('#userEmail a').html(user.email);
|
||||
$('#userEmail a').attr("href", "mailto:" + user.email);
|
||||
$('#userAvatar').html('');
|
||||
$('#userAvatar').attr("style", "background-image:url('" + user.avatarURL + "');'");
|
||||
$('#userRank').html(user.ranking.name);
|
||||
$('#userCover').slideDown('fast');
|
||||
});
|
||||
|
||||
|
||||
</script>
|
6
MessageboardPlugin/packages.config
Normal file
6
MessageboardPlugin/packages.config
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="CryptSharp" version="1.2.0.1" targetFramework="net40" />
|
||||
<package id="MarkdownDeep.NET" version="1.5" targetFramework="net40" />
|
||||
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net40" requireReinstallation="true" />
|
||||
</packages>
|
Binary file not shown.
@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharedLibrary
|
||||
{
|
||||
@ -18,7 +19,7 @@ namespace SharedLibrary
|
||||
}
|
||||
|
||||
//Execute the command
|
||||
abstract public void Execute(Event E);
|
||||
abstract public Task ExecuteAsync(Event E);
|
||||
|
||||
public String Name { get; private set; }
|
||||
public String Description { get; private set; }
|
||||
|
@ -2,24 +2,37 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using SharedLibrary;
|
||||
using SharedLibrary.Network;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IW4MAdmin
|
||||
namespace SharedLibrary.Commands
|
||||
{
|
||||
class Quit : Command
|
||||
{
|
||||
public Quit(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)
|
||||
{
|
||||
E.Owner.Manager.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
public override async Task ExecuteAsync(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!");
|
||||
await 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!");
|
||||
await E.Origin.Tell("This server already has an owner!");
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,15 +40,13 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(Event E)
|
||||
{
|
||||
E.Target.lastOffense = SharedLibrary.Utilities.removeWords(E.Data, 1);
|
||||
E.Target.lastOffense = E.Data.RemoveWords(1);
|
||||
if (E.Origin.Level <= E.Target.Level)
|
||||
E.Origin.Tell("You cannot warn " + E.Target.Name);
|
||||
await E.Origin.Tell("You cannot warn " + E.Target.Name);
|
||||
else
|
||||
{
|
||||
E.Target.Warn(E.Target.lastOffense, E.Origin);
|
||||
}
|
||||
await E.Target.Warn(E.Target.lastOffense, E.Origin);
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,12 +54,12 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(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);
|
||||
await E.Owner.Broadcast(Message);
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,13 +67,13 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(Event E)
|
||||
{
|
||||
E.Target.lastOffense = SharedLibrary.Utilities.removeWords(E.Data, 1);
|
||||
E.Target.lastOffense = SharedLibrary.Utilities.RemoveWords(E.Data, 1);
|
||||
if (E.Origin.Level > E.Target.Level)
|
||||
E.Target.Kick(E.Target.lastOffense, E.Origin);
|
||||
await E.Target.Kick(E.Target.lastOffense, E.Origin);
|
||||
else
|
||||
E.Origin.Tell("You cannot kick " + E.Target.Name);
|
||||
await E.Origin.Tell("You cannot kick " + E.Target.Name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,9 +81,9 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(Event E)
|
||||
{
|
||||
E.Owner.Broadcast("^1" + E.Origin.Name + " - ^6" + E.Data + "^7");
|
||||
await E.Owner.Broadcast("^1" + E.Origin.Name + " - ^6" + E.Data + "^7");
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,14 +91,14 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(Event E)
|
||||
{
|
||||
E.Target.lastOffense = SharedLibrary.Utilities.removeWords(E.Data, 1);
|
||||
String Message = "^1Player Temporarily Banned: ^5" + E.Target.lastOffense + "^7 (1 hour)";
|
||||
E.Target.lastOffense = SharedLibrary.Utilities.RemoveWords(E.Data, 1);
|
||||
String Message = E.Target.lastOffense;
|
||||
if (E.Origin.Level > E.Target.Level)
|
||||
E.Target.tempBan(Message, E.Origin);
|
||||
await E.Target.TempBan(Message, E.Origin);
|
||||
else
|
||||
E.Origin.Tell("You cannot temp ban " + E.Target.Name);
|
||||
await E.Origin.Tell("You cannot temp ban " + E.Target.Name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,22 +106,22 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(Event E)
|
||||
{
|
||||
E.Target.lastOffense = SharedLibrary.Utilities.removeWords(E.Data, 1);
|
||||
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 + ")";
|
||||
Message = "^1Player Banned: ^5" + E.Target.lastOffense;
|
||||
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));
|
||||
await E.Target.Ban(Message, E.Origin);
|
||||
await 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);
|
||||
await E.Origin.Tell("You cannot ban " + E.Target.Name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -118,12 +129,10 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(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");
|
||||
await E.Owner.Unban(E.Data.Trim(), E.Target);
|
||||
await E.Origin.Tell($"Successfully unbanned {E.Target.Name}::{E.Target.npID}");
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,10 +140,10 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(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);
|
||||
await E.Origin.Tell(You);
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,28 +151,31 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(Event E)
|
||||
{
|
||||
StringBuilder playerList = new StringBuilder();
|
||||
lock (E.Owner.getPlayers())
|
||||
int count = 0;
|
||||
for (int i = 0; i < E.Owner.Players.Count; i++)
|
||||
{
|
||||
int count = 0;
|
||||
foreach (Player P in E.Owner.getPlayers())
|
||||
var P = E.Owner.Players[i];
|
||||
|
||||
if (P == null)
|
||||
continue;
|
||||
|
||||
if (P.Masked)
|
||||
playerList.AppendFormat("[^3{0}^7]{3}[^3{1}^7] {2}", Utilities.levelToColor(Player.Permission.User), P.clientID, P.Name, SharedLibrary.Utilities.getSpaces(Player.Permission.SeniorAdmin.ToString().Length - Player.Permission.User.ToString().Length));
|
||||
else
|
||||
playerList.AppendFormat("[^3{0}^7]{3}[^3{1}^7] {2}", Utilities.levelToColor(P.Level), P.clientID, P.Name, SharedLibrary.Utilities.getSpaces(Player.Permission.SeniorAdmin.ToString().Length - P.Level.ToString().Length));
|
||||
|
||||
if (count == 2 || E.Owner.getPlayers().Count == 1)
|
||||
{
|
||||
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++;
|
||||
await E.Origin.Tell(playerList.ToString());
|
||||
count = 0;
|
||||
playerList = new StringBuilder();
|
||||
continue;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -172,48 +184,48 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(Event E)
|
||||
{
|
||||
String cmd = E.Data.Trim();
|
||||
|
||||
if (cmd.Length > 2)
|
||||
{
|
||||
bool found = false;
|
||||
foreach (Command C in E.Owner.getCommands())
|
||||
foreach (Command C in E.Owner.Manager.GetCommands())
|
||||
{
|
||||
if (C.Name.Contains(cmd) || C.Name == cmd)
|
||||
{
|
||||
E.Origin.Tell(" [^3" + C.Name + "^7] " + C.Description);
|
||||
await E.Origin.Tell(" [^3" + C.Name + "^7] " + C.Description);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
E.Origin.Tell("Could not find that command");
|
||||
await E.Origin.Tell("Could not find that command");
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
int count = 0;
|
||||
StringBuilder helpResponse = new StringBuilder();
|
||||
List<Command> test = E.Owner.getCommands();
|
||||
List<Command> CommandList = E.Owner.Manager.GetCommands();
|
||||
|
||||
foreach (Command C in test)
|
||||
foreach (Command C in CommandList)
|
||||
{
|
||||
if (E.Origin.Level >= C.Permission)
|
||||
{
|
||||
helpResponse.Append(" [^3" + C.Name + "^7] ");
|
||||
if (count >= 4)
|
||||
{
|
||||
E.Origin.Tell(helpResponse.ToString());
|
||||
await 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");
|
||||
await E.Origin.Tell(helpResponse.ToString());
|
||||
await E.Origin.Tell("Type !help <cmd> to get command usage example");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -222,22 +234,23 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(Event E)
|
||||
{
|
||||
E.Owner.Broadcast("Performing fast restart in 5 seconds...");
|
||||
E.Owner.fastRestart(5);
|
||||
await E.Owner.Broadcast("Performing fast restart...");
|
||||
await Task.Delay(3000);
|
||||
await E.Owner.ExecuteCommandAsync("fast_restart");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
public override async Task ExecuteAsync(Event E)
|
||||
{
|
||||
E.Owner.Broadcast("Performing map rotate in 5 seconds...");
|
||||
E.Owner.mapRotate(5);
|
||||
await E.Owner.Broadcast("Performing map rotate...");
|
||||
await Task.Delay(3000);
|
||||
await E.Owner.ExecuteCommandAsync("map_rotate");
|
||||
}
|
||||
}
|
||||
|
||||
@ -245,27 +258,41 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(Event E)
|
||||
{
|
||||
if (E.Target == E.Origin)
|
||||
{
|
||||
E.Origin.Tell("You can't set your own level, silly.");
|
||||
await E.Origin.Tell("You can't set your own level, silly.");
|
||||
return;
|
||||
}
|
||||
|
||||
Player.Permission newPerm = SharedLibrary.Utilities.matchPermission(SharedLibrary.Utilities.removeWords(E.Data, 1));
|
||||
Player.Permission newPerm = Utilities.matchPermission(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!");
|
||||
// prevent saving of old permissions on disconnect
|
||||
foreach (var server in E.Owner.Manager.GetServers())
|
||||
{
|
||||
foreach (var player in server.getPlayers())
|
||||
{
|
||||
if (player != null && player.npID == E.Target.npID)
|
||||
{
|
||||
player.setLevel(newPerm);
|
||||
await E.Target.Tell("Congratulations! You have been promoted to ^3" + newPerm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await E.Target.Tell("Congratulations! You have been promoted to ^3" + newPerm);
|
||||
await 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.");
|
||||
await E.Origin.Tell("Invalid group specified.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -273,9 +300,9 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(Event E)
|
||||
{
|
||||
E.Origin.Tell("IW4M Admin is using " + Math.Round(((System.Diagnostics.Process.GetCurrentProcess().PrivateMemorySize64 / 2048f) / 1200f), 1) + "MB");
|
||||
await E.Origin.Tell("IW4M Admin is using " + Math.Round(((System.Diagnostics.Process.GetCurrentProcess().PrivateMemorySize64 / 2048f) / 1200f), 1) + "MB");
|
||||
}
|
||||
}
|
||||
|
||||
@ -283,10 +310,10 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(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));
|
||||
await E.Origin.Tell(String.Format("IW4M Admin has been up for {0} days, {1} hours, and {2} minutes", uptime.Days, uptime.Hours, uptime.Minutes));
|
||||
}
|
||||
}
|
||||
|
||||
@ -294,19 +321,13 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Player P in E.Owner.getPlayers())
|
||||
if (P != null && P.Level > Player.Permission.Flagged && !P.Masked)
|
||||
await E.Origin.Tell(String.Format("[^3{0}^7] {1}", Utilities.levelToColor(P.Level), P.Name));
|
||||
}
|
||||
}
|
||||
|
||||
@ -314,23 +335,23 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(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);
|
||||
await E.Owner.Broadcast("Changing to map ^2" + m.Alias);
|
||||
await Task.Delay(5000);
|
||||
await E.Owner.LoadMap(m.Name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
E.Owner.Broadcast("Attempting to change to unknown map ^1" + newMap);
|
||||
SharedLibrary.Utilities.Wait(3);
|
||||
E.Owner.Map(newMap);
|
||||
await E.Owner.Broadcast("Attempting to change to unknown map ^1" + newMap);
|
||||
await Task.Delay(5000);
|
||||
await E.Owner.LoadMap(newMap);
|
||||
}
|
||||
}
|
||||
|
||||
@ -338,20 +359,20 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(Event E)
|
||||
{
|
||||
var db_players = E.Owner.clientDB.findPlayers(E.Data.Trim());
|
||||
|
||||
if (db_players == null)
|
||||
{
|
||||
E.Origin.Tell("No players found");
|
||||
await 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);
|
||||
await E.Origin.Tell(mesg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -360,13 +381,13 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(Event E)
|
||||
{
|
||||
E.Data = E.Data.Trim();
|
||||
|
||||
if (E.Data.Length < 4)
|
||||
{
|
||||
E.Origin.Tell("You must enter at least 4 letters");
|
||||
await E.Origin.Tell("You must enter at least 4 letters");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -375,7 +396,7 @@ namespace IW4MAdmin
|
||||
|
||||
if (db_aliases == null)
|
||||
{
|
||||
E.Origin.Tell("No players found");
|
||||
await E.Origin.Tell("No players found");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -397,7 +418,7 @@ namespace IW4MAdmin
|
||||
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);
|
||||
await E.Origin.Tell(mesg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -407,14 +428,14 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(Event E)
|
||||
{
|
||||
if (E.Owner.rules.Count < 1)
|
||||
E.Origin.Tell("This server has not set any rules.");
|
||||
await E.Origin.Tell("This server has not set any rules.");
|
||||
else
|
||||
{
|
||||
foreach (String r in E.Owner.rules)
|
||||
E.Origin.Tell("- " + r);
|
||||
await E.Origin.Tell("- " + r);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -423,12 +444,11 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(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));
|
||||
E.Data = Utilities.RemoveWords(E.Data, 1);
|
||||
await E.Target.Tell("^1" + E.Origin.Name + " ^3[PM]^7 - " + E.Data);
|
||||
await E.Origin.Tell(String.Format("To ^3{0} ^7-> {1}", E.Target.Name, E.Data));
|
||||
}
|
||||
}
|
||||
|
||||
@ -436,12 +456,12 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
{
|
||||
public override async Task ExecuteAsync(Event E)
|
||||
{
|
||||
if (E.Owner.Reload())
|
||||
E.Origin.Tell("Sucessfully reloaded configs!");
|
||||
await E.Origin.Tell("Sucessfully reloaded configs!");
|
||||
else
|
||||
E.Origin.Tell("Unable to reload configs :(");
|
||||
await E.Origin.Tell("Unable to reload configs :(");
|
||||
}
|
||||
}
|
||||
|
||||
@ -449,9 +469,9 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(Event E)
|
||||
{
|
||||
E.Origin.currentServer.executeCommand(String.Format("admin_lastevent {0};{1}", "balance", E.Origin.npID)); //Let gsc do the magic
|
||||
await E.Owner.ExecuteCommandAsync(String.Format("admin_lastevent {0};{1}", "balance", E.Origin.npID)); //Let gsc do the magic
|
||||
}
|
||||
}
|
||||
|
||||
@ -459,9 +479,9 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(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
|
||||
await E.Owner.ExecuteCommandAsync(String.Format("admin_lastevent {0};{1};{2};{3}", "goto", E.Origin.npID, E.Target.Name, E.Data)); //Let gsc do the magic
|
||||
}
|
||||
}
|
||||
|
||||
@ -469,24 +489,24 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(Event E)
|
||||
{
|
||||
if (E.Target.Level >= E.Origin.Level)
|
||||
{
|
||||
E.Origin.Tell("You cannot flag " + E.Target.Name);
|
||||
await 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);
|
||||
await 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);
|
||||
await E.Origin.Tell("You have ^5flagged ^7" + E.Target.Name);
|
||||
}
|
||||
|
||||
E.Owner.clientDB.updatePlayer(E.Target);
|
||||
@ -497,35 +517,33 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(Event E)
|
||||
{
|
||||
if (E.Owner.Reports.Find(x => x.Origin == E.Origin) != null)
|
||||
if (E.Owner.Reports.Find(x => (x.Origin == E.Origin && x.Target.npID == E.Target.npID)) != null)
|
||||
{
|
||||
E.Origin.Tell("You have already reported this player");
|
||||
await E.Origin.Tell("You have already reported this player");
|
||||
return;
|
||||
}
|
||||
|
||||
if (E.Target == E.Origin)
|
||||
{
|
||||
E.Origin.Tell("You cannot report yourself, silly.");
|
||||
await 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);
|
||||
await E.Origin.Tell("You cannot report " + E.Target.Name);
|
||||
return;
|
||||
}
|
||||
|
||||
E.Data = SharedLibrary.Utilities.removeWords(E.Data, 1);
|
||||
E.Data = 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();
|
||||
await E.Origin.Tell("Successfully reported " + E.Target.Name);
|
||||
await E.Owner.ExecuteEvent(new Event(Event.GType.Report, E.Data, E.Origin, E.Target, E.Owner));
|
||||
|
||||
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));
|
||||
await E.Owner.ToAdmins(String.Format("^5{0}^7->^1{1}^7: {2}", E.Origin.Name, E.Target.Name, E.Data));
|
||||
}
|
||||
}
|
||||
|
||||
@ -533,29 +551,23 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(Event E)
|
||||
{
|
||||
if (E.Data != null && E.Data.ToLower().Contains("clear"))
|
||||
{
|
||||
E.Owner.Reports = new List<Report>();
|
||||
E.Origin.Tell("Reports successfully cleared!");
|
||||
await E.Origin.Tell("Reports successfully cleared!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (E.Owner.Reports.Count < 1)
|
||||
{
|
||||
E.Origin.Tell("No players reported yet.");
|
||||
await 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));
|
||||
}
|
||||
foreach (Report R in E.Owner.Reports)
|
||||
await E.Origin.Tell(String.Format("^5{0}^7->^1{1}^7: {2}", R.Origin.Name, R.Target.Name, R.Reason));
|
||||
}
|
||||
}
|
||||
|
||||
@ -563,10 +575,10 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(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));
|
||||
E.Data = Utilities.RemoveWords(E.Data, 1);
|
||||
await E.Owner.ExecuteCommandAsync(String.Format("admin_lastevent tell;{0};{1};{2}", E.Origin.npID, E.Target.npID, E.Data));
|
||||
}
|
||||
}
|
||||
|
||||
@ -574,17 +586,17 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(Event E)
|
||||
{
|
||||
if (E.Origin.Masked)
|
||||
{
|
||||
E.Origin.Masked = false;
|
||||
E.Origin.Tell("You are now unmasked");
|
||||
await E.Origin.Tell("You are now unmasked");
|
||||
}
|
||||
else
|
||||
{
|
||||
E.Origin.Masked = true;
|
||||
E.Origin.Tell("You are now masked");
|
||||
await E.Origin.Tell("You are now masked");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -593,11 +605,11 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(Event E)
|
||||
{
|
||||
if (E.Target == null)
|
||||
{
|
||||
E.Origin.Tell("No bans for that player.");
|
||||
await E.Origin.Tell("No bans for that player.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -605,7 +617,7 @@ namespace IW4MAdmin
|
||||
|
||||
if (B == null)
|
||||
{
|
||||
E.Origin.Tell("No active ban was found for that player.");
|
||||
await E.Origin.Tell("No active ban was found for that player.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -613,11 +625,11 @@ namespace IW4MAdmin
|
||||
|
||||
if (Banner == null)
|
||||
{
|
||||
E.Origin.Tell("Ban was found for the player, but origin of the ban is unavailable.");
|
||||
await 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));
|
||||
await E.Origin.Tell(String.Format("^1{0} ^7was banned by ^5{1} ^7for: {2}", E.Target.Name, Banner.Name, B.Reason));
|
||||
}
|
||||
}
|
||||
|
||||
@ -625,17 +637,17 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(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.");
|
||||
await E.Target.Tell("Could not find alias info for that player.");
|
||||
return;
|
||||
}
|
||||
|
||||
E.Target.Tell("[^3" + E.Target.Name + "^7]");
|
||||
await E.Target.Tell("[^3" + E.Target.Name + "^7]");
|
||||
StringBuilder message = new StringBuilder();
|
||||
|
||||
List<Player> playerAliases = E.Owner.getPlayerAliases(E.Target);
|
||||
@ -650,7 +662,7 @@ namespace IW4MAdmin
|
||||
message.Append(S + " | ");
|
||||
}
|
||||
}
|
||||
E.Origin.Tell(message.ToString());
|
||||
await E.Origin.Tell(message.ToString());
|
||||
|
||||
message = new StringBuilder();
|
||||
|
||||
@ -667,7 +679,7 @@ namespace IW4MAdmin
|
||||
}
|
||||
}
|
||||
|
||||
E.Origin.Tell(message.ToString());
|
||||
await E.Origin.Tell(message.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -676,24 +688,33 @@ namespace IW4MAdmin
|
||||
{
|
||||
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)
|
||||
public override async Task ExecuteAsync(Event E)
|
||||
{
|
||||
E.Origin.currentServer.executeCommand(E.Data.Trim());
|
||||
E.Origin.Tell("Successfuly sent RCON command!");
|
||||
await E.Origin.currentServer.ExecuteCommandAsync(E.Data.Trim());
|
||||
await E.Origin.Tell("Successfuly sent RCON command!");
|
||||
}
|
||||
}
|
||||
|
||||
class Plugins : Command
|
||||
class Link : Command
|
||||
{
|
||||
public Plugins(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
|
||||
public Link(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)
|
||||
public override async Task ExecuteAsync(Event E)
|
||||
{
|
||||
E.Origin.Tell("^5Loaded Plugins:");
|
||||
foreach (Plugin P in PluginImporter.potentialPlugins)
|
||||
if (E.Data.Contains("show"))
|
||||
{
|
||||
E.Origin.Tell(String.Format("^3{0} ^7[^3{1}^7] by ^5{2}^7", P.Name, P.Version, P.Author));
|
||||
if (E.Origin.UID == null || E.Origin.UID.Length == 0)
|
||||
await E.Origin.Tell("You have not linked an ID");
|
||||
else
|
||||
await E.Origin.Tell("Your ID is " + E.Origin.UID);
|
||||
}
|
||||
else if (E.Origin.registerUID(E.Data))
|
||||
{
|
||||
E.Owner.clientDB.updatePlayer(E.Origin);
|
||||
await E.Origin.Tell("Your ID has been linked");
|
||||
}
|
||||
else
|
||||
await E.Origin.Tell("That ID is invalid");
|
||||
}
|
||||
}
|
||||
}
|
@ -18,11 +18,11 @@ namespace SharedLibrary
|
||||
Con = new SQLiteConnection(DBCon);
|
||||
}
|
||||
|
||||
catch(System.DllNotFoundException)
|
||||
catch(DllNotFoundException)
|
||||
{
|
||||
Console.WriteLine("Fatal Error: could not locate the SQLite DLL(s)!\nEnsure they are located in the 'lib' folder");
|
||||
Utilities.Wait(5);
|
||||
System.Environment.Exit(0);
|
||||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
Open = false;
|
||||
@ -33,50 +33,75 @@ namespace SharedLibrary
|
||||
|
||||
protected bool Insert(String tableName, Dictionary<String, object> data)
|
||||
{
|
||||
String columns = "";
|
||||
String values = "";
|
||||
Boolean returnCode = true;
|
||||
foreach (KeyValuePair<String, object> val in data)
|
||||
string names = "";
|
||||
string parameters = "";
|
||||
foreach (string key in data.Keys)
|
||||
{
|
||||
columns += String.Format(" {0},", val.Key);
|
||||
values += String.Format(" '{0}',", val.Value);
|
||||
names += key + ',';
|
||||
parameters += '@' + key + ',';
|
||||
}
|
||||
columns = columns.Substring(0, columns.Length - 1);
|
||||
values = values.Substring(0, values.Length - 1);
|
||||
names = names.Substring(0, names.Length - 1);
|
||||
parameters = parameters.Substring(0, parameters.Length - 1);
|
||||
|
||||
SQLiteCommand insertcmd = new SQLiteCommand();
|
||||
insertcmd.Connection = this.Con;
|
||||
insertcmd.CommandText = String.Format("INSERT INTO `{0}` ({1}) VALUES ({2});", tableName, names, parameters);
|
||||
|
||||
foreach (string key in data.Keys)
|
||||
{
|
||||
insertcmd.Parameters.AddWithValue('@' + key, data[key]);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
this.ExecuteNonQuery(String.Format("insert into {0}({1}) values({2});", tableName, columns, values));
|
||||
Con.Open();
|
||||
insertcmd.ExecuteNonQuery();
|
||||
Con.Close();
|
||||
return true;
|
||||
}
|
||||
catch (Exception fail)
|
||||
|
||||
catch (Exception)
|
||||
{
|
||||
Console.WriteLine(fail.Message);
|
||||
returnCode = false;
|
||||
//LOGME
|
||||
return false;
|
||||
}
|
||||
return returnCode;
|
||||
|
||||
}
|
||||
|
||||
protected bool Update(String tableName, Dictionary<String, object> data, String where)
|
||||
protected bool Update(String tableName, Dictionary<String, object> data, KeyValuePair<string, object> where)
|
||||
{
|
||||
String vals = "";
|
||||
Boolean returnCode = true;
|
||||
if (data.Count >= 1)
|
||||
string parameters = "";
|
||||
foreach (string key in data.Keys)
|
||||
{
|
||||
foreach (KeyValuePair<String, object> val in data)
|
||||
{
|
||||
vals += String.Format(" {0} = '{1}',", val.Key, val.Value);
|
||||
}
|
||||
vals = vals.Substring(0, vals.Length - 1);
|
||||
parameters += key + '=' + '@' + key + ',';
|
||||
}
|
||||
|
||||
parameters = parameters.Substring(0, parameters.Length - 1);
|
||||
|
||||
SQLiteCommand updatecmd = new SQLiteCommand();
|
||||
updatecmd.Connection = this.Con;
|
||||
updatecmd.CommandText = String.Format("UPDATE `{0}` SET {1} WHERE {2}=@{2}", tableName, parameters, where.Key);
|
||||
|
||||
foreach (string key in data.Keys)
|
||||
{
|
||||
updatecmd.Parameters.AddWithValue('@' + key, data[key]);
|
||||
}
|
||||
|
||||
updatecmd.Parameters.AddWithValue('@' + where.Key, where.Value);
|
||||
|
||||
try
|
||||
{
|
||||
ExecuteNonQuery(String.Format("update {0} set {1} where {2};", tableName, vals, where));
|
||||
Con.Open();
|
||||
updatecmd.ExecuteNonQuery();
|
||||
Con.Close();
|
||||
return true;
|
||||
}
|
||||
catch (Exception fail)
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(fail.Message);
|
||||
returnCode = false;
|
||||
//LOGME
|
||||
return false;
|
||||
}
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
protected DataRow getDataRow(String Q)
|
||||
@ -89,17 +114,53 @@ namespace SharedLibrary
|
||||
{
|
||||
waitForClose();
|
||||
int rowsUpdated = 0;
|
||||
Request = Request.Replace("!'", "").Replace("!", "") ;
|
||||
try
|
||||
{
|
||||
lock (Con)
|
||||
{
|
||||
Con.Open();
|
||||
SQLiteCommand CMD = new SQLiteCommand(Con);
|
||||
CMD.CommandText = Request;
|
||||
rowsUpdated = CMD.ExecuteNonQuery();
|
||||
Con.Close();
|
||||
}
|
||||
return rowsUpdated;
|
||||
}
|
||||
|
||||
lock (Con)
|
||||
catch (Exception E)
|
||||
{
|
||||
Console.WriteLine(E.Message);
|
||||
Console.WriteLine(E.StackTrace);
|
||||
Console.WriteLine(Request);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
protected DataTable GetDataTable(string tableName, KeyValuePair<string, object> where)
|
||||
{
|
||||
DataTable dt = new DataTable();
|
||||
SQLiteCommand updatecmd = new SQLiteCommand();
|
||||
updatecmd.Connection = this.Con;
|
||||
updatecmd.CommandText = String.Format("SELECT * FROM {0} WHERE `{1}`=@{1};", tableName, where.Key);
|
||||
updatecmd.Parameters.AddWithValue('@' + where.Key, where.Value);
|
||||
|
||||
try
|
||||
{
|
||||
Con.Open();
|
||||
SQLiteCommand CMD = new SQLiteCommand(Con);
|
||||
CMD.CommandText = Request;
|
||||
rowsUpdated = CMD.ExecuteNonQuery();
|
||||
SQLiteDataReader reader = updatecmd.ExecuteReader();
|
||||
dt.Load(reader);
|
||||
reader.Close();
|
||||
Con.Close();
|
||||
}
|
||||
|
||||
return rowsUpdated;
|
||||
catch (Exception e)
|
||||
{
|
||||
//LOGME
|
||||
Console.Write("Couldnotexecute");
|
||||
}
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
||||
protected DataTable GetDataTable(String sql)
|
||||
@ -123,7 +184,7 @@ namespace SharedLibrary
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e.Message);
|
||||
Console.WriteLine(e.Message + " GetDataTable");
|
||||
return new DataTable();
|
||||
}
|
||||
return dt;
|
||||
@ -153,7 +214,7 @@ namespace SharedLibrary
|
||||
{
|
||||
if (!File.Exists(FileName))
|
||||
{
|
||||
String Create = "CREATE TABLE [CLIENTS] ( [Name] TEXT NULL, [npID] TEXT NULL, [Number] INTEGER PRIMARY KEY AUTOINCREMENT, [Level] INT DEFAULT 0 NULL, [LastOffense] TEXT NULL, [Connections] INT DEFAULT 1 NULL, [IP] TEXT NULL, [LastConnection] TEXT NULL);";
|
||||
String Create = "CREATE TABLE [CLIENTS] ( [Name] TEXT NULL, [npID] TEXT NULL, [Number] INTEGER PRIMARY KEY AUTOINCREMENT, [Level] INT DEFAULT 0 NULL, [LastOffense] TEXT NULL, [Connections] INT DEFAULT 1 NULL, [IP] TEXT NULL, [LastConnection] TEXT NULL, [UID] TEXT NULL, [Masked] INT DEFAULT 0);";
|
||||
ExecuteNonQuery(Create);
|
||||
Create = "CREATE TABLE [BANS] ( [TYPE] TEXT NULL, [Reason] TEXT NULL, [npID] TEXT NULL, [bannedByID] TEXT NULL, [IP] TEXT NULL, [TIME] TEXT NULL);";
|
||||
ExecuteNonQuery(Create);
|
||||
@ -172,13 +233,33 @@ namespace SharedLibrary
|
||||
DateTime lastCon = DateTime.MinValue;
|
||||
DateTime.TryParse(ResponseRow["LastConnection"].ToString(), out lastCon);
|
||||
|
||||
return new Player(ResponseRow["Name"].ToString(), ResponseRow["npID"].ToString(), cNum, (Player.Permission)(ResponseRow["Level"]), Convert.ToInt32(ResponseRow["Number"]), ResponseRow["LastOffense"].ToString(), (int)ResponseRow["Connections"], ResponseRow["IP"].ToString(), lastCon);
|
||||
return new Player(ResponseRow["Name"].ToString(), ResponseRow["npID"].ToString(), cNum, (Player.Permission)(ResponseRow["Level"]), Convert.ToInt32(ResponseRow["Number"]), ResponseRow["LastOffense"].ToString(), (int)ResponseRow["Connections"], ResponseRow["IP"].ToString(), lastCon, ResponseRow["UID"].ToString(), ResponseRow["Masked"].ToString() == "1");
|
||||
}
|
||||
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<Player> getRecentPlayers()
|
||||
{
|
||||
List<Player> returnssss = new List<Player>();
|
||||
String Query = String.Format("SELECT * FROM CLIENTS ORDER BY LastConnection desc LIMIT 25");
|
||||
DataTable Result = GetDataTable(Query);
|
||||
|
||||
if (Result != null && Result.Rows.Count > 0)
|
||||
{
|
||||
foreach (DataRow ResponseRow in Result.Rows)
|
||||
{
|
||||
DateTime lastCon = DateTime.MinValue;
|
||||
DateTime.TryParse(ResponseRow["LastConnection"].ToString(), out lastCon);
|
||||
|
||||
returnssss.Add(new Player(ResponseRow["Name"].ToString(), ResponseRow["npID"].ToString(), -1, (Player.Permission)(ResponseRow["Level"]), Convert.ToInt32(ResponseRow["Number"]), ResponseRow["LastOffense"].ToString(), (int)ResponseRow["Connections"], ResponseRow["IP"].ToString(), lastCon, ResponseRow["UID"].ToString(), ResponseRow["Masked"].ToString() == "1"));
|
||||
}
|
||||
}
|
||||
|
||||
return returnssss;
|
||||
}
|
||||
|
||||
public List<Player> getPlayers(List<String> npIDs)
|
||||
{
|
||||
List<Player> returnssss = new List<Player>();
|
||||
@ -194,7 +275,7 @@ namespace SharedLibrary
|
||||
DateTime lastCon = DateTime.MinValue;
|
||||
DateTime.TryParse(ResponseRow["LastConnection"].ToString(), out lastCon);
|
||||
|
||||
returnssss.Add(new Player(ResponseRow["Name"].ToString(), ResponseRow["npID"].ToString(), -1, (Player.Permission)(ResponseRow["Level"]), Convert.ToInt32(ResponseRow["Number"]), ResponseRow["LastOffense"].ToString(), (int)ResponseRow["Connections"], ResponseRow["IP"].ToString(), lastCon));
|
||||
returnssss.Add(new Player(ResponseRow["Name"].ToString(), ResponseRow["npID"].ToString(), -1, (Player.Permission)(ResponseRow["Level"]), Convert.ToInt32(ResponseRow["Number"]), ResponseRow["LastOffense"].ToString(), (int)ResponseRow["Connections"], ResponseRow["IP"].ToString(), lastCon, ResponseRow["UID"].ToString(), ResponseRow["Masked"].ToString() == "1"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -216,7 +297,7 @@ namespace SharedLibrary
|
||||
DateTime lastCon = DateTime.MinValue;
|
||||
DateTime.TryParse(ResponseRow["LastConnection"].ToString(), out lastCon);
|
||||
|
||||
returnssss.Add(new Player(ResponseRow["Name"].ToString(), ResponseRow["npID"].ToString(), -1, (Player.Permission)(ResponseRow["Level"]), Convert.ToInt32(ResponseRow["Number"]), ResponseRow["LastOffense"].ToString(), (int)ResponseRow["Connections"], ResponseRow["IP"].ToString(), lastCon));
|
||||
returnssss.Add(new Player(ResponseRow["Name"].ToString(), ResponseRow["npID"].ToString(), -1, (Player.Permission)(ResponseRow["Level"]), Convert.ToInt32(ResponseRow["Number"]), ResponseRow["LastOffense"].ToString(), (int)ResponseRow["Connections"], ResponseRow["IP"].ToString(), lastCon, ResponseRow["UID"].ToString(), ResponseRow["Masked"].ToString() == "1"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -242,7 +323,7 @@ namespace SharedLibrary
|
||||
LC = DateTime.MinValue;
|
||||
}
|
||||
|
||||
return new Player(p["Name"].ToString(), p["npID"].ToString(), -1, (Player.Permission)(p["Level"]), Convert.ToInt32(p["Number"]), p["LastOffense"].ToString(), Convert.ToInt32(p["Connections"]), p["IP"].ToString(), LC);
|
||||
return new Player(p["Name"].ToString(), p["npID"].ToString(), -1, (Player.Permission)(p["Level"]), Convert.ToInt32(p["Number"]), p["LastOffense"].ToString(), Convert.ToInt32(p["Connections"]), p["IP"].ToString(), LC, p["UID"].ToString(), p["Masked"].ToString() == "1");
|
||||
}
|
||||
|
||||
else
|
||||
@ -264,7 +345,7 @@ namespace SharedLibrary
|
||||
try
|
||||
{
|
||||
LC = DateTime.Parse(p["LastConnection"].ToString());
|
||||
lastKnown.Add(new Player(p["Name"].ToString(), p["npID"].ToString(), -1, (Player.Permission)(p["Level"]), Convert.ToInt32(p["Number"]), p["LastOffense"].ToString(), Convert.ToInt32((DateTime.Now - LC).TotalSeconds), p["IP"].ToString(), LC));
|
||||
lastKnown.Add(new Player(p["Name"].ToString(), p["npID"].ToString(), -1, (Player.Permission)(p["Level"]), Convert.ToInt32(p["Number"]), p["LastOffense"].ToString(), Convert.ToInt32((DateTime.Now - LC).TotalSeconds), p["IP"].ToString(), LC, p["UID"].ToString(), p["Masked"].ToString() == "1"));
|
||||
}
|
||||
|
||||
catch (Exception)
|
||||
@ -301,16 +382,21 @@ namespace SharedLibrary
|
||||
foreach (DataRow p in Result.Rows)
|
||||
{
|
||||
DateTime LC;
|
||||
string Masked = null;
|
||||
try
|
||||
{
|
||||
LC = DateTime.Parse(p["LastConnection"].ToString());
|
||||
Masked = p["Masked"].ToString();
|
||||
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
if (Masked == null)
|
||||
Masked = "0";
|
||||
|
||||
LC = DateTime.MinValue;
|
||||
}
|
||||
|
||||
Players.Add(new Player(p["Name"].ToString(), p["npID"].ToString(), -1, (Player.Permission)(p["Level"]), Convert.ToInt32(p["Number"]), p["LastOffense"].ToString(), Convert.ToInt32(p["Connections"]), p["IP"].ToString(), LC));
|
||||
Players.Add(new Player(p["Name"].ToString(), p["npID"].ToString(), -1, (Player.Permission)(p["Level"]), Convert.ToInt32(p["Number"]), p["LastOffense"].ToString(), Convert.ToInt32(p["Connections"]), p["IP"].ToString(), LC, p["IP"].ToString(), Masked == "1"));
|
||||
}
|
||||
return Players;
|
||||
}
|
||||
@ -352,7 +438,7 @@ namespace SharedLibrary
|
||||
if (Row["TYPE"].ToString().Length != 0)
|
||||
BanType = (Penalty.Type)Enum.Parse(typeof(Penalty.Type), Row["TYPE"].ToString());
|
||||
|
||||
Bans.Add(new Penalty(BanType, Row["Reason"].ToString(), Row["npID"].ToString(), Row["bannedByID"].ToString(), DateTime.Parse(Row["TIME"].ToString()), Row["IP"].ToString()));
|
||||
Bans.Add(new Penalty(BanType, Row["Reason"].ToString().Trim(), Row["npID"].ToString(), Row["bannedByID"].ToString(), DateTime.Parse(Row["TIME"].ToString()), Row["IP"].ToString()));
|
||||
|
||||
}
|
||||
|
||||
@ -363,11 +449,11 @@ namespace SharedLibrary
|
||||
public List<Player> getAdmins()
|
||||
{
|
||||
List<Player> Admins = new List<Player>();
|
||||
String Query = String.Format("SELECT * FROM CLIENTS WHERE LEVEL > '{0}'", 1);
|
||||
String Query = String.Format("SELECT * FROM CLIENTS WHERE Level >= '{0}'", (int)Player.Permission.Moderator);
|
||||
DataTable Result = GetDataTable(Query);
|
||||
|
||||
foreach (DataRow P in Result.Rows)
|
||||
Admins.Add(new Player(P["Name"].ToString(), P["npID"].ToString(), (Player.Permission)P["Level"], P["IP"].ToString()));
|
||||
Admins.Add(new Player(P["Name"].ToString(), P["npID"].ToString(), (Player.Permission)P["Level"], P["IP"].ToString(), P["UID"].ToString()));
|
||||
|
||||
return Admins;
|
||||
}
|
||||
@ -394,6 +480,8 @@ namespace SharedLibrary
|
||||
newPlayer.Add("Connections", 1);
|
||||
newPlayer.Add("IP", P.IP);
|
||||
newPlayer.Add("LastConnection", Utilities.DateTimeSQLite(DateTime.Now));
|
||||
newPlayer.Add("UID", P.UID);
|
||||
newPlayer.Add("Masked", Convert.ToInt32(P.Masked));
|
||||
|
||||
Insert("CLIENTS", newPlayer);
|
||||
}
|
||||
@ -410,8 +498,10 @@ namespace SharedLibrary
|
||||
updatedPlayer.Add("Connections", P.Connections);
|
||||
updatedPlayer.Add("IP", P.IP);
|
||||
updatedPlayer.Add("LastConnection", Utilities.DateTimeSQLite(DateTime.Now));
|
||||
updatedPlayer.Add("UID", P.UID);
|
||||
updatedPlayer.Add("Masked", Convert.ToInt32(P.Masked));
|
||||
|
||||
Update("CLIENTS", updatedPlayer, String.Format("npID = '{0}'", P.npID));
|
||||
Update("CLIENTS", updatedPlayer, new KeyValuePair<string, object>("npID", P.npID ));
|
||||
}
|
||||
|
||||
|
||||
@ -420,7 +510,7 @@ namespace SharedLibrary
|
||||
{
|
||||
Dictionary<String, object> newBan = new Dictionary<String, object>();
|
||||
|
||||
newBan.Add("Reason", B.Reason);
|
||||
newBan.Add("Reason", Utilities.removeNastyChars(B.Reason));
|
||||
newBan.Add("npID", B.npID);
|
||||
newBan.Add("bannedByID", B.bannedByID);
|
||||
newBan.Add("IP", B.IP);
|
||||
@ -515,7 +605,7 @@ namespace SharedLibrary
|
||||
Dictionary<String, object> newPlayer = new Dictionary<String, object>();
|
||||
|
||||
newPlayer.Add("Number", Alias.Number);
|
||||
newPlayer.Add("NAMES", String.Join(";", Alias.Names));
|
||||
newPlayer.Add("NAMES", Utilities.removeNastyChars(String.Join(";", Alias.Names)));
|
||||
newPlayer.Add("IPS", String.Join(";", Alias.IPS));
|
||||
|
||||
Insert("ALIASES", newPlayer);
|
||||
@ -529,7 +619,7 @@ namespace SharedLibrary
|
||||
updatedPlayer.Add("NAMES", String.Join(";", Alias.Names));
|
||||
updatedPlayer.Add("IPS", String.Join(";", Alias.IPS));
|
||||
|
||||
Update("ALIASES", updatedPlayer, String.Format("Number = '{0}'", Alias.Number));
|
||||
Update("ALIASES", updatedPlayer, new KeyValuePair<string, object>("Number", Alias.Number));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,4 +16,15 @@ namespace SharedLibrary
|
||||
public int min;
|
||||
public int max;
|
||||
}
|
||||
|
||||
public class _DVAR<T>
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
public T Value;
|
||||
|
||||
public _DVAR(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,13 +5,15 @@ using System.Text.RegularExpressions;
|
||||
|
||||
namespace SharedLibrary
|
||||
{
|
||||
[Serializable]
|
||||
public class Chat
|
||||
{
|
||||
public Chat(Player O, String M, DateTime D)
|
||||
public Chat(string O, String M, DateTime D)
|
||||
{
|
||||
Origin = O;
|
||||
Name = O;
|
||||
Message = M;
|
||||
Time = D;
|
||||
|
||||
}
|
||||
|
||||
public String timeString()
|
||||
@ -19,11 +21,49 @@ namespace SharedLibrary
|
||||
return Time.ToShortTimeString();
|
||||
}
|
||||
|
||||
public Player Origin { get; private set; }
|
||||
//public Player Origin { get; private set; }
|
||||
public String Message { get; private set; }
|
||||
public DateTime Time { get; private set; }
|
||||
public string Name;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public struct RestEvent
|
||||
{
|
||||
public RestEvent(eType Ty, eVersion V, string M, string T, string O, string Ta)
|
||||
{
|
||||
Type = Ty;
|
||||
Version = V;
|
||||
Message = M;
|
||||
Title = T;
|
||||
Origin = O;
|
||||
Target = Ta;
|
||||
|
||||
ID = Math.Abs(DateTime.Now.GetHashCode());
|
||||
}
|
||||
|
||||
public enum eType
|
||||
{
|
||||
NOTIFICATION,
|
||||
STATUS,
|
||||
ALERT,
|
||||
}
|
||||
|
||||
public enum eVersion
|
||||
{
|
||||
IW4MAdmin
|
||||
}
|
||||
|
||||
public eType Type;
|
||||
public eVersion Version;
|
||||
public string Message;
|
||||
public string Title;
|
||||
public string Origin;
|
||||
public string Target;
|
||||
public int ID;
|
||||
}
|
||||
|
||||
|
||||
public class Event
|
||||
{
|
||||
public enum GType
|
||||
@ -44,7 +84,11 @@ namespace SharedLibrary
|
||||
Tell,
|
||||
Kick,
|
||||
Ban,
|
||||
Remote,
|
||||
Unknown,
|
||||
|
||||
//FROM PLAYER
|
||||
Report
|
||||
}
|
||||
|
||||
public Event(GType t, string d, Player O, Player T, Server S)
|
||||
@ -100,7 +144,7 @@ namespace SharedLibrary
|
||||
if (eventType == ":")
|
||||
return new Event(GType.MapEnd, line[0], new Player("WORLD", "WORLD", 0, 0), null, SV);
|
||||
|
||||
if (line[0].Split('\\').Length > 5) // blaze it
|
||||
if (line[0].Contains("InitGame")) // blaze it
|
||||
return new Event(GType.MapChange, line[0], new Player("WORLD", "WORLD", 0, 0), null, SV);
|
||||
|
||||
|
||||
@ -121,5 +165,6 @@ namespace SharedLibrary
|
||||
public Player Origin;
|
||||
public Player Target;
|
||||
public Server Owner;
|
||||
public Boolean Remote = false;
|
||||
}
|
||||
}
|
||||
|
15
SharedLibrary/Exceptions/CommandException.cs
Normal file
15
SharedLibrary/Exceptions/CommandException.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharedLibrary.Exceptions
|
||||
{
|
||||
public class CommandException : ServerException
|
||||
{
|
||||
public CommandException(string msg) : base(msg) { }
|
||||
// .data contains
|
||||
// "command_name"
|
||||
}
|
||||
}
|
13
SharedLibrary/Exceptions/DvarException.cs
Normal file
13
SharedLibrary/Exceptions/DvarException.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharedLibrary.Exceptions
|
||||
{
|
||||
public class DvarException : ServerException
|
||||
{
|
||||
public DvarException(string msg) : base(msg) { }
|
||||
}
|
||||
}
|
13
SharedLibrary/Exceptions/NetworkException.cs
Normal file
13
SharedLibrary/Exceptions/NetworkException.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharedLibrary.Exceptions
|
||||
{
|
||||
public class NetworkException : ServerException
|
||||
{
|
||||
public NetworkException(string msg) : base(msg) { }
|
||||
}
|
||||
}
|
13
SharedLibrary/Exceptions/ServerException.cs
Normal file
13
SharedLibrary/Exceptions/ServerException.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharedLibrary.Exceptions
|
||||
{
|
||||
public class ServerException : Exception
|
||||
{
|
||||
public ServerException(string msg) : base(msg) { }
|
||||
}
|
||||
}
|
18
SharedLibrary/Extensions/IPlugin.cs
Normal file
18
SharedLibrary/Extensions/IPlugin.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharedLibrary.Extensions
|
||||
{
|
||||
public interface IPlugin
|
||||
{
|
||||
Task OnLoad();
|
||||
Task OnUnload();
|
||||
Task OnEvent(Event E, Server S);
|
||||
Task OnTick(Server S);
|
||||
|
||||
//for logging purposes
|
||||
String Name { get; }
|
||||
float Version { get; }
|
||||
String Author { get; }
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
|
||||
namespace SharedLibrary
|
||||
{
|
||||
@ -10,18 +11,24 @@ namespace SharedLibrary
|
||||
public IFile(String fileName)
|
||||
{
|
||||
//Not safe for directories with more than one folder but meh
|
||||
_Directory = fileName.Split('\\')[0];
|
||||
Name = (fileName.Split('\\'))[fileName.Split('\\').Length - 1];
|
||||
string[] asd = fileName.Split('/');
|
||||
|
||||
if (!Directory.Exists(_Directory))
|
||||
Directory.CreateDirectory(_Directory);
|
||||
if (asd[0] != "")
|
||||
_Directory = asd[0];
|
||||
else
|
||||
_Directory = asd[2];
|
||||
|
||||
Name = (fileName.Split('/'))[fileName.Split('/').Length - 1];
|
||||
|
||||
//if (!Directory.Exists(_Directory))
|
||||
// Directory.CreateDirectory(_Directory);
|
||||
|
||||
if (!File.Exists(fileName))
|
||||
{
|
||||
try
|
||||
{
|
||||
FileStream penis = File.Create(fileName);
|
||||
penis.Close();
|
||||
//FileStream penis = File.Create(fileName);
|
||||
//penis.Close();
|
||||
}
|
||||
|
||||
catch
|
||||
@ -49,6 +56,16 @@ namespace SharedLibrary
|
||||
sze = 0;
|
||||
}
|
||||
|
||||
public IFile()
|
||||
{
|
||||
WebClient request = new WebClient();
|
||||
string url = $"http://raidmax.org/logs/IW4X/games_mp.log";
|
||||
byte[] newFileData = request.DownloadData(url);
|
||||
|
||||
Handle = new StreamReader(new MemoryStream(newFileData));
|
||||
sze = Handle.BaseStream.Length;
|
||||
}
|
||||
|
||||
public long getSize()
|
||||
{
|
||||
sze = Handle.BaseStream.Length;
|
||||
@ -59,8 +76,16 @@ namespace SharedLibrary
|
||||
{
|
||||
if (writeHandle != null)
|
||||
{
|
||||
writeHandle.WriteLine(line);
|
||||
writeHandle.Flush();
|
||||
try
|
||||
{
|
||||
writeHandle.WriteLine(line);
|
||||
writeHandle.Flush();
|
||||
}
|
||||
|
||||
catch (Exception E)
|
||||
{
|
||||
Console.WriteLine("Error during flush", E.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
17
SharedLibrary/Interfaces/IManager.cs
Normal file
17
SharedLibrary/Interfaces/IManager.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharedLibrary.Interfaces
|
||||
{
|
||||
public interface IManager
|
||||
{
|
||||
void Init();
|
||||
void Start();
|
||||
void Stop();
|
||||
List<Server> GetServers();
|
||||
List<Command> GetCommands();
|
||||
}
|
||||
}
|
51
SharedLibrary/Interfaces/ISerializable.cs
Normal file
51
SharedLibrary/Interfaces/ISerializable.cs
Normal file
@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace SharedLibrary.Interfaces
|
||||
{
|
||||
interface ISerializable<T>
|
||||
{
|
||||
void Write();
|
||||
}
|
||||
|
||||
public class SerializeException : Exception
|
||||
{
|
||||
public SerializeException(string msg) : base(msg) { }
|
||||
}
|
||||
|
||||
public class Serialize<T> : ISerializable<T>
|
||||
{
|
||||
public static T Read(string filename)
|
||||
{
|
||||
try
|
||||
{
|
||||
string configText = File.ReadAllText(filename);
|
||||
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(configText);
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new SerializeException($"Could not desialize file {filename}: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public void Write()
|
||||
{
|
||||
try
|
||||
{
|
||||
string configText = Newtonsoft.Json.JsonConvert.SerializeObject(this);
|
||||
File.WriteAllText(Filename(), configText);
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new SerializeException($"Could not serialize file {Filename()}: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public virtual string Filename() { return this.ToString(); }
|
||||
}
|
||||
}
|
@ -15,5 +15,10 @@ namespace SharedLibrary
|
||||
|
||||
public String Name { get; private set; }
|
||||
public String Alias { get; private set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Alias;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ namespace SharedLibrary
|
||||
{
|
||||
public Penalty(Type BType, String Reas, String TargID, String From, DateTime time, String ip)
|
||||
{
|
||||
Reason = Reas;
|
||||
Reason = Reas.Replace("!","");
|
||||
npID = TargID;
|
||||
bannedByID = From;
|
||||
When = time;
|
@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharedLibrary
|
||||
{
|
||||
@ -35,6 +36,11 @@ namespace SharedLibrary
|
||||
Console = 8,
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return ((Player)obj).npID == this.npID;
|
||||
}
|
||||
|
||||
public Player(string n, string id, int num, int l)
|
||||
{
|
||||
Name = n;
|
||||
@ -59,12 +65,14 @@ namespace SharedLibrary
|
||||
LastConnection = DateTime.Now;
|
||||
}
|
||||
|
||||
public Player(string n, string id, Player.Permission P, String I)
|
||||
public Player(String n, String id, Player.Permission P, String I, String UID)
|
||||
{
|
||||
Name = n;
|
||||
npID = id;
|
||||
Level = P;
|
||||
IP = I;
|
||||
clientID = -1;
|
||||
this.UID = UID;
|
||||
}
|
||||
|
||||
public Player(string n, string id, int num, Player.Permission l, int cind, String lo, int con, String IP2)
|
||||
@ -85,7 +93,7 @@ namespace SharedLibrary
|
||||
LastConnection = DateTime.Now;
|
||||
}
|
||||
|
||||
public Player(string n, string id, int num, Player.Permission l, int cind, String lo, int con, String IP2, DateTime LC)
|
||||
public Player(string n, string id, int num, Player.Permission l, int cind, String lo, int con, String IP2, DateTime LC, string UID, bool masked)
|
||||
{
|
||||
Name = n;
|
||||
npID = id;
|
||||
@ -101,6 +109,16 @@ namespace SharedLibrary
|
||||
Warnings = 0;
|
||||
Masked = false;
|
||||
LastConnection = LC;
|
||||
this.UID = UID.Trim();
|
||||
Masked = masked;
|
||||
}
|
||||
|
||||
public bool registerUID(String UID)
|
||||
{
|
||||
if (UID.Length > 5)
|
||||
this.UID = UID;
|
||||
|
||||
return this.UID == UID;
|
||||
}
|
||||
|
||||
public String getLastConnection()
|
||||
@ -124,34 +142,29 @@ namespace SharedLibrary
|
||||
Level = Perm;
|
||||
}
|
||||
|
||||
public void Tell(String Message)
|
||||
public async Task Tell(String Message)
|
||||
{
|
||||
lastEvent.Owner.Tell(Message, this);
|
||||
await lastEvent.Owner.Tell(Message, this);
|
||||
}
|
||||
|
||||
public void Kick(String Message, Player Sender)
|
||||
public async Task Kick(String Message, Player Sender)
|
||||
{
|
||||
lastEvent.Owner.Kick(Message, this, Sender);
|
||||
await lastEvent.Owner.Kick(Message, this, Sender);
|
||||
}
|
||||
|
||||
public void tempBan(String Message, Player Sender)
|
||||
public async Task TempBan(String Message, Player Sender)
|
||||
{
|
||||
lastEvent.Owner.tempBan(Message, this, Sender);
|
||||
await lastEvent.Owner.TempBan(Message, this, Sender);
|
||||
}
|
||||
|
||||
public void Warn(String Message, Player Sender)
|
||||
public async Task Warn(String Message, Player Sender)
|
||||
{
|
||||
lastEvent.Owner.Warn(Message, this, Sender);
|
||||
await lastEvent.Owner.Warn(Message, this, Sender);
|
||||
}
|
||||
|
||||
public void Ban(String Message, Player Sender)
|
||||
public async Task Ban(String Message, Player Sender)
|
||||
{
|
||||
lastEvent.Owner.Ban(Message, this, Sender);
|
||||
}
|
||||
|
||||
public void Alert()
|
||||
{
|
||||
lastEvent.Owner.Alert(this);
|
||||
await lastEvent.Owner.Ban(Message, this, Sender);
|
||||
}
|
||||
|
||||
public String Name { get; private set; }
|
||||
@ -161,6 +174,7 @@ namespace SharedLibrary
|
||||
public int databaseID { get; private set; }
|
||||
public int Connections { get; set; }
|
||||
public String IP { get; private set; }
|
||||
public String UID { get; private set; }
|
||||
public DateTime LastConnection { get; private set; }
|
||||
public Server currentServer { get; private set; }
|
||||
|
||||
@ -169,5 +183,6 @@ namespace SharedLibrary
|
||||
public int Warnings;
|
||||
public Aliases Alias;
|
||||
public bool Masked;
|
||||
public int selectedServer;
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace SharedLibrary
|
||||
{
|
||||
public abstract class Plugin
|
||||
{
|
||||
public abstract void onLoad();
|
||||
public abstract void onUnload();
|
||||
public abstract void onEvent(Event E);
|
||||
|
||||
//for logging purposes
|
||||
public abstract String Name { get; }
|
||||
public abstract float Version { get; }
|
||||
public abstract String Author { get; }
|
||||
}
|
||||
}
|
172
SharedLibrary/RCON.cs
Normal file
172
SharedLibrary/RCON.cs
Normal file
@ -0,0 +1,172 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace SharedLibrary.Network
|
||||
{
|
||||
public static class RCON
|
||||
{
|
||||
enum QueryType
|
||||
{
|
||||
GET_STATUS,
|
||||
GET_INFO,
|
||||
DVAR,
|
||||
COMMAND,
|
||||
}
|
||||
|
||||
public static List<Player> PlayersFromStatus(String[] Status)
|
||||
{
|
||||
List<Player> StatusPlayers = new List<Player>();
|
||||
|
||||
foreach (String S in Status)
|
||||
{
|
||||
String responseLine = S.Trim();
|
||||
|
||||
if (Regex.Matches(responseLine, @"\d+$", RegexOptions.IgnoreCase).Count > 0 && responseLine.Length > 72) // its a client line!
|
||||
{
|
||||
String[] playerInfo = responseLine.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
int cID = -1;
|
||||
String cName = Utilities.StripColors(responseLine.Substring(46, 18)).Trim();
|
||||
String npID = responseLine.Substring(29, 17).Trim(); // DONT TOUCH PLZ
|
||||
int.TryParse(playerInfo[0], out cID);
|
||||
String cIP = responseLine.Substring(72, 20).Trim().Split(':')[0];
|
||||
|
||||
Player P = new Player(cName, npID, cID, cIP);
|
||||
StatusPlayers.Add(P);
|
||||
}
|
||||
}
|
||||
|
||||
return StatusPlayers;
|
||||
}
|
||||
|
||||
static string[] SendQuery(QueryType Type, Server QueryServer, string Parameters = "")
|
||||
{
|
||||
var ServerOOBConnection = new System.Net.Sockets.UdpClient();
|
||||
ServerOOBConnection.Client.SendTimeout = 1000;
|
||||
ServerOOBConnection.Client.ReceiveTimeout = 1000;
|
||||
var Endpoint = new IPEndPoint(IPAddress.Parse(QueryServer.getIP()), QueryServer.getPort());
|
||||
|
||||
string QueryString = String.Empty;
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case QueryType.DVAR:
|
||||
case QueryType.COMMAND:
|
||||
QueryString = $"ÿÿÿÿrcon {QueryServer.Password} {Parameters}";
|
||||
break;
|
||||
case QueryType.GET_STATUS:
|
||||
QueryString = "ÿÿÿÿ getstatus";
|
||||
break;
|
||||
}
|
||||
|
||||
byte[] Payload = GetRequestBytes(QueryString);
|
||||
|
||||
int attempts = 0;
|
||||
retry:
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
ServerOOBConnection.Connect(Endpoint);
|
||||
ServerOOBConnection.Send(Payload, Payload.Length);
|
||||
|
||||
byte[] ReceiveBuffer = new byte[8192];
|
||||
StringBuilder QueryResponseString = new StringBuilder();
|
||||
|
||||
do
|
||||
{
|
||||
ReceiveBuffer = ServerOOBConnection.Receive(ref Endpoint);
|
||||
QueryResponseString.Append(Encoding.ASCII.GetString(ReceiveBuffer).TrimEnd('\0'));
|
||||
} while (ServerOOBConnection.Available > 0);
|
||||
|
||||
ServerOOBConnection.Close();
|
||||
|
||||
if (QueryResponseString.ToString().Contains("Invalid password"))
|
||||
throw new Exceptions.NetworkException("RCON password is invalid");
|
||||
|
||||
int num = int.Parse("0a", System.Globalization.NumberStyles.AllowHexSpecifier);
|
||||
string[] SplitResponse = QueryResponseString.ToString().Split(new char[] { (char)num }, StringSplitOptions.RemoveEmptyEntries);
|
||||
return SplitResponse;
|
||||
}
|
||||
|
||||
catch (SocketException)
|
||||
{
|
||||
attempts++;
|
||||
if (attempts > 5)
|
||||
{
|
||||
var e = new Exceptions.NetworkException("Cannot communicate with server");
|
||||
e.Data["server_address"] = ServerOOBConnection.Client.RemoteEndPoint.ToString();
|
||||
ServerOOBConnection.Close();
|
||||
throw e;
|
||||
}
|
||||
|
||||
Thread.Sleep(1000);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<_DVAR<T>> GetDvarAsync<T>(this Server server, string dvarName)
|
||||
{
|
||||
string[] LineSplit = await Task.FromResult(SendQuery(QueryType.DVAR, server, dvarName));
|
||||
|
||||
if (LineSplit.Length != 3)
|
||||
{
|
||||
var e = new Exceptions.DvarException("DVAR does not exist");
|
||||
e.Data["dvar_name"] = dvarName;
|
||||
throw e;
|
||||
}
|
||||
|
||||
string[] ValueSplit = LineSplit[1].Split(new char[] { '"' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
if (ValueSplit.Length != 5)
|
||||
{
|
||||
var e = new Exceptions.DvarException("DVAR does not exist");
|
||||
e.Data["dvar_name"] = dvarName;
|
||||
throw e;
|
||||
}
|
||||
|
||||
string DvarName = Regex.Replace(ValueSplit[0], @"\^[0-9]", "");
|
||||
string DvarCurrentValue = Regex.Replace(ValueSplit[2], @"\^[0-9]", "");
|
||||
string DvarDefaultValue = Regex.Replace(ValueSplit[4], @"\^[0-9]", "");
|
||||
|
||||
return new _DVAR<T>(DvarName) { Value = (T)Convert.ChangeType(DvarCurrentValue, typeof(T)) };
|
||||
}
|
||||
|
||||
public static async Task SetDvarAsync(this Server server, string dvarName, object dvarValue)
|
||||
{
|
||||
await Task.FromResult(SendQuery(QueryType.DVAR, server, $"{dvarName} {dvarValue}"));
|
||||
}
|
||||
|
||||
public static async Task ExecuteCommandAsync(this Server server, string commandName)
|
||||
{
|
||||
await Task.FromResult(SendQuery(QueryType.COMMAND, server, commandName));
|
||||
}
|
||||
|
||||
public static async Task<List<Player>> GetStatusAsync(this Server server)
|
||||
{
|
||||
string[] response = await Task.FromResult(SendQuery(QueryType.DVAR, server, "status"));
|
||||
return PlayersFromStatus(response);
|
||||
}
|
||||
|
||||
|
||||
static byte[] GetRequestBytes(string Request)
|
||||
{
|
||||
|
||||
Byte[] initialRequestBytes = Encoding.Unicode.GetBytes(Request);
|
||||
Byte[] fixedRequest = new Byte[initialRequestBytes.Length / 2];
|
||||
|
||||
for (int i = 0; i < initialRequestBytes.Length; i++)
|
||||
if (initialRequestBytes[i] != 0)
|
||||
fixedRequest[i / 2] = initialRequestBytes[i];
|
||||
|
||||
return fixedRequest;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,30 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
using SharedLibrary.Network;
|
||||
using SharedLibrary.Commands;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharedLibrary
|
||||
{
|
||||
[Guid("61d3829e-fcbe-44d3-bb7c-51db8c2d7ac5")]
|
||||
public abstract class Server
|
||||
{
|
||||
public Server(string address, int port, string password, int H, int PID)
|
||||
public Server(Interfaces.IManager mgr, string address, int port, string password)
|
||||
{
|
||||
this.PID = PID;
|
||||
Handle = H;
|
||||
Password = password;
|
||||
IP = address;
|
||||
Port = port;
|
||||
clientnum = 0;
|
||||
logFile = new IFile("admin_" + port + ".log", true);
|
||||
Manager = mgr;
|
||||
ClientNum = 0;
|
||||
logFile = new IFile($"Logs/{address}_{port}.log", true);
|
||||
#if DEBUG
|
||||
Log = new Log(logFile, Log.Level.Debug, port);
|
||||
#else
|
||||
Log = new Log(logFile, Log.Level.Production, port);
|
||||
#endif
|
||||
clientDB = new ClientsDB("clients.rm");
|
||||
aliasDB = new AliasesDB("aliases.rm");
|
||||
clientDB = new ClientsDB("Database/clients.rm");
|
||||
aliasDB = new AliasesDB("Database/aliases.rm");
|
||||
|
||||
Bans = new List<Penalty>();
|
||||
players = new List<Player>(new Player[18]);
|
||||
Players = new List<Player>(new Player[18]);
|
||||
events = new Queue<Event>();
|
||||
Macros = new Dictionary<String, Object>();
|
||||
Reports = new List<Report>();
|
||||
@ -33,22 +40,54 @@ namespace SharedLibrary
|
||||
chatHistory = new List<Chat>();
|
||||
lastWebChat = DateTime.Now;
|
||||
nextMessage = 0;
|
||||
initCommands();
|
||||
initMacros();
|
||||
initMessages();
|
||||
initMaps();
|
||||
initRules();
|
||||
|
||||
var commands = mgr.GetCommands();
|
||||
|
||||
owner = clientDB.getOwner();
|
||||
|
||||
if (owner == null)
|
||||
commands.Add(new Owner("owner", "claim ownership of the server", "owner", Player.Permission.User, 0, false));
|
||||
|
||||
commands.Add(new Quit("quit", "quit IW4MAdmin", "q", Player.Permission.Owner, 0, false));
|
||||
commands.Add(new Kick("kick", "kick a player by name. syntax: !kick <player> <reason>.", "k", Player.Permission.Trusted, 2, true));
|
||||
commands.Add(new Say("say", "broadcast message to all players. syntax: !say <message>.", "s", Player.Permission.Moderator, 1, false));
|
||||
commands.Add(new TempBan("tempban", "temporarily ban a player for 1 hour. syntax: !tempban <player> <reason>.", "tb", Player.Permission.Moderator, 2, true));
|
||||
commands.Add(new SBan("ban", "permanently ban a player from the server. syntax: !ban <player> <reason>", "b", Player.Permission.SeniorAdmin, 2, true));
|
||||
commands.Add(new WhoAmI("whoami", "give information about yourself. syntax: !whoami.", "who", Player.Permission.User, 0, false));
|
||||
commands.Add(new List("list", "list active clients syntax: !list.", "l", Player.Permission.Moderator, 0, false));
|
||||
commands.Add(new Help("help", "list all available commands. syntax: !help.", "h", Player.Permission.User, 0, false));
|
||||
commands.Add(new FastRestart("fastrestart", "fast restart current map. syntax: !fastrestart.", "fr", Player.Permission.Moderator, 0, false));
|
||||
commands.Add(new MapRotate("maprotate", "cycle to the next map in rotation. syntax: !maprotate.", "mr", Player.Permission.Administrator, 0, false));
|
||||
commands.Add(new SetLevel("setlevel", "set player to specified administration level. syntax: !setlevel <player> <level>.", "sl", Player.Permission.Owner, 2, true));
|
||||
commands.Add(new Usage("usage", "get current application memory usage. syntax: !usage.", "us", Player.Permission.Moderator, 0, false));
|
||||
commands.Add(new Uptime("uptime", "get current application running time. syntax: !uptime.", "up", Player.Permission.Moderator, 0, false));
|
||||
commands.Add(new Warn("warn", "warn player for infringing rules syntax: !warn <player> <reason>.", "w", Player.Permission.Trusted, 2, true));
|
||||
commands.Add(new WarnClear("warnclear", "remove all warning for a player syntax: !warnclear <player>.", "wc", Player.Permission.Trusted, 1, true));
|
||||
commands.Add(new Unban("unban", "unban player by database id. syntax: !unban @<id>.", "ub", Player.Permission.SeniorAdmin, 1, true));
|
||||
commands.Add(new Admins("admins", "list currently connected admins. syntax: !admins.", "a", Player.Permission.User, 0, false));
|
||||
commands.Add(new MapCMD("map", "change to specified map. syntax: !map", "m", Player.Permission.Administrator, 1, false));
|
||||
commands.Add(new Find("find", "find player in database. syntax: !find <player>", "f", Player.Permission.SeniorAdmin, 1, false));
|
||||
commands.Add(new Rules("rules", "list server rules. syntax: !rules", "r", Player.Permission.User, 0, false));
|
||||
commands.Add(new PrivateMessage("privatemessage", "send message to other player. syntax: !pm <player> <message>", "pm", Player.Permission.User, 2, true));
|
||||
commands.Add(new Flag("flag", "flag a suspicious player and announce to admins on join . syntax !flag <player>:", "flag", Player.Permission.Moderator, 1, true));
|
||||
commands.Add(new _Report("report", "report a player for suspicious behaivor. syntax !report <player> <reason>", "rep", Player.Permission.User, 2, true));
|
||||
commands.Add(new Reports("reports", "get most recent reports. syntax !reports", "reports", Player.Permission.Moderator, 0, false));
|
||||
commands.Add(new _Tell("tell", "send onscreen message to player. syntax !tell <player> <message>", "t", Player.Permission.Moderator, 2, true));
|
||||
commands.Add(new Mask("mask", "hide your online presence from online admin list. syntax: !mask", "mask", Player.Permission.Administrator, 0, false));
|
||||
commands.Add(new BanInfo("baninfo", "get information about a ban for a player. syntax: !baninfo <player>", "bi", Player.Permission.Moderator, 1, true));
|
||||
commands.Add(new Alias("alias", "get past aliases and ips of a player. syntax: !alias <player>", "known", Player.Permission.Moderator, 1, true));
|
||||
commands.Add(new _RCON("rcon", "send rcon command to server. syntax: !rcon <command>", "rcon", Player.Permission.Owner, 1, false));
|
||||
commands.Add(new FindAll("findall", "find a player by their aliase(s). syntax: !findall <player>", "fa", Player.Permission.Moderator, 1, false));
|
||||
}
|
||||
|
||||
//Returns the current server name -- *STRING*
|
||||
public String getName()
|
||||
{
|
||||
return hostname;
|
||||
}
|
||||
|
||||
public String getMap()
|
||||
{
|
||||
return mapname;
|
||||
return Hostname;
|
||||
}
|
||||
|
||||
public String getGametype()
|
||||
@ -71,29 +110,13 @@ namespace SharedLibrary
|
||||
//Returns number of active clients on server -- *INT*
|
||||
public int getNumPlayers()
|
||||
{
|
||||
return clientnum;
|
||||
}
|
||||
|
||||
//Returns the list of commands
|
||||
public List<Command> getCommands()
|
||||
{
|
||||
return commands;
|
||||
return ClientNum;
|
||||
}
|
||||
|
||||
//Returns list of all current players
|
||||
public List<Player> getPlayers()
|
||||
{
|
||||
return players;
|
||||
}
|
||||
|
||||
public int getClientNum()
|
||||
{
|
||||
return clientnum;
|
||||
}
|
||||
|
||||
public int getMaxClients()
|
||||
{
|
||||
return maxClients;
|
||||
return Players.FindAll(x => x != null);
|
||||
}
|
||||
|
||||
//Returns list of all active bans (loaded at runtime)
|
||||
@ -123,21 +146,19 @@ namespace SharedLibrary
|
||||
return clientDB.getPlayers(databaseIDs);
|
||||
}
|
||||
|
||||
abstract public void Stop();
|
||||
|
||||
/// <summary>
|
||||
/// Add a player to the server's player list
|
||||
/// </summary>
|
||||
/// <param name="P">Player pulled from memory reading</param>
|
||||
/// <returns>True if player added sucessfully, false otherwise</returns>
|
||||
abstract public bool addPlayer(Player P);
|
||||
abstract public Task<bool> AddPlayer(Player P);
|
||||
|
||||
/// <summary>
|
||||
/// Remove player by client number
|
||||
/// </summary>
|
||||
/// <param name="cNum">Client ID of player to be removed</param>
|
||||
/// <returns>true if removal succeded, false otherwise</returns>
|
||||
abstract public bool removePlayer(int cNum);
|
||||
abstract public Task RemovePlayer(int cNum);
|
||||
|
||||
/// <summary>
|
||||
/// Get the player from the server's list by line from game long
|
||||
@ -154,9 +175,9 @@ namespace SharedLibrary
|
||||
/// <returns>Matching player if found</returns>
|
||||
public Player clientFromName(String pName)
|
||||
{
|
||||
lock (players)
|
||||
lock (Players)
|
||||
{
|
||||
foreach (var P in players)
|
||||
foreach (var P in Players)
|
||||
{
|
||||
if (P != null && P.Name.ToLower().Contains(pName.ToLower()))
|
||||
return P;
|
||||
@ -179,123 +200,93 @@ namespace SharedLibrary
|
||||
/// <param name="E">Event parameter</param>
|
||||
/// <param name="C">Command requested from the event</param>
|
||||
/// <returns></returns>
|
||||
abstract public Command processCommand(Event E, Command C);
|
||||
abstract public Task<Command> ProcessCommand(Event E, Command C);
|
||||
|
||||
/// <summary>
|
||||
/// Execute a command on the server
|
||||
/// </summary>
|
||||
/// <param name="CMD">Command to execute</param>
|
||||
abstract public void executeCommand(String CMD);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve a Dvar from the server
|
||||
/// </summary>
|
||||
/// <param name="DvarName">Name of Dvar to retrieve</param>
|
||||
/// <returns>Dvar if found</returns>
|
||||
abstract public dvar getDvar(String DvarName);
|
||||
|
||||
/// <summary>
|
||||
/// Set a Dvar on the server
|
||||
/// </summary>
|
||||
/// <param name="Dvar">Name of the</param>
|
||||
/// <param name="Value"></param>
|
||||
abstract public void setDvar(String Dvar, String Value);
|
||||
|
||||
/// <summary>
|
||||
/// Main loop for the monitoring processes of the server ( handles events and connects/disconnects )
|
||||
/// </summary>
|
||||
abstract public void Monitor();
|
||||
virtual public Task<int> ProcessUpdatesAsync()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set up the basic variables ( base path / hostname / etc ) that allow the monitor thread to work
|
||||
/// </summary>
|
||||
/// <returns>True if no issues initializing, false otherwise</returns>
|
||||
abstract public bool intializeBasics();
|
||||
//abstract public bool intializeBasics();
|
||||
|
||||
/// <summary>
|
||||
/// Process any server event
|
||||
/// </summary>
|
||||
/// <param name="E">Event</param>
|
||||
/// <returns>True on sucess</returns>
|
||||
abstract public bool processEvent(Event E);
|
||||
abstract protected Task ProcessEvent(Event E);
|
||||
abstract public Task ExecuteEvent(Event E);
|
||||
|
||||
/// <summary>
|
||||
/// Reloads all the server configurations
|
||||
/// </summary>
|
||||
/// <returns>True on sucess</returns>
|
||||
abstract public bool Reload();
|
||||
abstract public bool _Reload();
|
||||
|
||||
/// <summary>
|
||||
/// Send a message to all players
|
||||
/// </summary>
|
||||
/// <param name="Message">Message to be sent to all players</param>
|
||||
public void Broadcast(String Message)
|
||||
public async Task Broadcast(String Message)
|
||||
{
|
||||
executeCommand("sayraw " + Message);
|
||||
await this.ExecuteCommandAsync($"sayraw {Message}");
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Send a message to a particular players
|
||||
/// </summary>
|
||||
/// <param name="Message">Message to send</param>
|
||||
/// <param name="Target">Player to send message to</param>
|
||||
public void Tell(String Message, Player Target)
|
||||
public async Task Tell(String Message, Player Target)
|
||||
{
|
||||
if (Target.clientID > -1 && Message.Length > 0)
|
||||
executeCommand("tellraw " + Target.clientID + " " + Message + "^7");
|
||||
if (Target.clientID > -1 && Message.Length > 0 && Target.Level != Player.Permission.Console && !Target.lastEvent.Remote)
|
||||
await this.ExecuteCommandAsync($"tellraw {Target.clientID} {Message}^7");
|
||||
|
||||
if (Target.Level == Player.Permission.Console)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Cyan;
|
||||
Console.WriteLine(Utilities.stripColors(Message));
|
||||
Console.WriteLine(Utilities.StripColors(Message));
|
||||
Console.ForegroundColor = ConsoleColor.Gray;
|
||||
}
|
||||
|
||||
if (Target.lastEvent.Remote)
|
||||
commandResult.Enqueue(Utilities.StripColors(Message));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a message to all admins on the server
|
||||
/// </summary>
|
||||
/// <param name="message">Message to send out</param>
|
||||
public void ToAdmins(String message)
|
||||
public async Task ToAdmins(String message)
|
||||
{
|
||||
lock (players) // threading can modify list while we do this
|
||||
foreach (Player P in Players)
|
||||
{
|
||||
foreach (Player P in players)
|
||||
{
|
||||
if (P == null)
|
||||
continue;
|
||||
if (P == null)
|
||||
continue;
|
||||
|
||||
if (P.Level > Player.Permission.Flagged)
|
||||
{
|
||||
P.Alert();
|
||||
P.Tell(message);
|
||||
}
|
||||
}
|
||||
if (P.Level > Player.Permission.Flagged)
|
||||
await P.Tell(message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Alert a player via gsc implementation
|
||||
/// </summary>
|
||||
/// <param name="P"></param>
|
||||
public void Alert(Player P)
|
||||
{
|
||||
executeCommand("admin_lastevent alert;" + P.npID + ";0;mp_killstreak_nuclearstrike");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Kick a player from the server
|
||||
/// </summary>
|
||||
/// <param name="Reason">Reason for kicking</param>
|
||||
/// <param name="Target">Player to kick</param>
|
||||
abstract public void Kick(String Reason, Player Target, Player Origin);
|
||||
abstract public Task Kick(String Reason, Player Target, Player Origin);
|
||||
|
||||
/// <summary>
|
||||
/// Temporarily ban a player ( default 1 hour ) from the server
|
||||
/// </summary>
|
||||
/// <param name="Reason">Reason for banning the player</param>
|
||||
/// <param name="Target">The player to ban</param>
|
||||
abstract public void tempBan(String Reason, Player Target, Player Origin);
|
||||
abstract public Task TempBan(String Reason, Player Target, Player Origin);
|
||||
|
||||
/// <summary>
|
||||
/// Perm ban a player from the server
|
||||
@ -303,9 +294,9 @@ namespace SharedLibrary
|
||||
/// <param name="Reason">The reason for the ban</param>
|
||||
/// <param name="Target">The person to ban</param>
|
||||
/// <param name="Origin">The person who banned the target</param>
|
||||
abstract public void Ban(String Reason, Player Target, Player Origin);
|
||||
abstract public Task Ban(String Reason, Player Target, Player Origin);
|
||||
|
||||
abstract public void Warn(String Reason, Player Target, Player Origin);
|
||||
abstract public Task Warn(String Reason, Player Target, Player Origin);
|
||||
|
||||
/// <summary>
|
||||
/// Unban a player by npID / GUID
|
||||
@ -313,43 +304,20 @@ namespace SharedLibrary
|
||||
/// <param name="npID">npID of the player</param>
|
||||
/// <param name="Target">I don't remember what this is for</param>
|
||||
/// <returns></returns>
|
||||
abstract public bool Unban(String npID, Player Target);
|
||||
|
||||
/// <summary>
|
||||
/// Fast restart the server with a specified delay
|
||||
/// </summary>
|
||||
/// <param name="delay"></param>
|
||||
public void fastRestart(int delay)
|
||||
{
|
||||
Utilities.Wait(delay);
|
||||
executeCommand("fast_restart");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rotate the server to the next map with specified delay
|
||||
/// </summary>
|
||||
/// <param name="delay"></param>
|
||||
public void mapRotate(int delay)
|
||||
{
|
||||
Utilities.Wait(delay);
|
||||
executeCommand("map_rotate");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Map rotate without delay
|
||||
/// </summary>
|
||||
public void mapRotate()
|
||||
{
|
||||
mapRotate(0);
|
||||
}
|
||||
abstract public Task Unban(String npID, Player Target);
|
||||
|
||||
/// <summary>
|
||||
/// Change the current searver map
|
||||
/// </summary>
|
||||
/// <param name="mapName">Non-localized map name</param>
|
||||
public void Map(String mapName)
|
||||
public async Task LoadMap(string mapName)
|
||||
{
|
||||
executeCommand("map " + mapName);
|
||||
await this.ExecuteCommandAsync($"map {mapName}");
|
||||
}
|
||||
|
||||
public async Task LoadMap(Map newMap)
|
||||
{
|
||||
await this.ExecuteCommandAsync($"map {newMap.Name}");
|
||||
}
|
||||
|
||||
public void webChat(Player P, String Message)
|
||||
@ -359,13 +327,13 @@ namespace SharedLibrary
|
||||
if ((requestTime - lastWebChat).TotalSeconds > 1)
|
||||
{
|
||||
Broadcast("^1[WEBCHAT] ^5" + P.Name + "^7 - " + Message);
|
||||
while (chatHistory.Count > Math.Ceiling((double)clientnum / 2))
|
||||
while (chatHistory.Count > Math.Ceiling((double)ClientNum / 2))
|
||||
chatHistory.RemoveAt(0);
|
||||
|
||||
if (Message.Length > 50)
|
||||
Message = Message.Substring(0, 50) + "...";
|
||||
|
||||
chatHistory.Add(new Chat(P, Utilities.stripColors(Message), DateTime.Now));
|
||||
chatHistory.Add(new Chat(P.Name, Utilities.StripColors(Message), DateTime.Now));
|
||||
lastWebChat = DateTime.Now;
|
||||
}
|
||||
}
|
||||
@ -382,7 +350,7 @@ namespace SharedLibrary
|
||||
{
|
||||
maps = new List<Map>();
|
||||
|
||||
IFile mapfile = new IFile("config\\maps.cfg");
|
||||
IFile mapfile = new IFile("config/maps.cfg");
|
||||
String[] _maps = mapfile.readAll();
|
||||
mapfile.Close();
|
||||
if (_maps.Length > 2) // readAll returns minimum one empty string
|
||||
@ -408,7 +376,7 @@ namespace SharedLibrary
|
||||
{
|
||||
messages = new List<String>();
|
||||
|
||||
IFile messageCFG = new IFile("config\\messages.cfg");
|
||||
IFile messageCFG = new IFile("config/messages.cfg");
|
||||
String[] lines = messageCFG.readAll();
|
||||
messageCFG.Close();
|
||||
|
||||
@ -445,7 +413,7 @@ namespace SharedLibrary
|
||||
{
|
||||
rules = new List<String>();
|
||||
|
||||
IFile ruleFile = new IFile("config\\rules.cfg");
|
||||
IFile ruleFile = new IFile("config/rules.cfg");
|
||||
String[] _rules = ruleFile.readAll();
|
||||
ruleFile.Close();
|
||||
if (_rules.Length > 2) // readAll returns minimum one empty string
|
||||
@ -468,6 +436,7 @@ namespace SharedLibrary
|
||||
abstract public void initCommands();
|
||||
|
||||
//Objects
|
||||
public Interfaces.IManager Manager { get; protected set; }
|
||||
public Log Log { get; private set; }
|
||||
public List<Penalty> Bans;
|
||||
public Player owner;
|
||||
@ -484,21 +453,22 @@ namespace SharedLibrary
|
||||
//Info
|
||||
protected String IP;
|
||||
protected int Port;
|
||||
protected String hostname;
|
||||
protected String mapname;
|
||||
protected int clientnum;
|
||||
protected List<Player> players;
|
||||
protected List<Command> commands;
|
||||
public String Hostname { get; protected set; }
|
||||
public Map CurrentMap { get; protected set; }
|
||||
protected string FSGame;
|
||||
public int ClientNum { get; protected set; }
|
||||
public int MaxClients { get; protected set; }
|
||||
public List<Player> Players { get; protected set; }
|
||||
protected List<String> messages;
|
||||
protected int messageTime;
|
||||
protected TimeSpan lastMessage;
|
||||
protected DateTime lastPoll;
|
||||
protected int nextMessage;
|
||||
protected String IW_Ver;
|
||||
protected int maxClients;
|
||||
|
||||
protected Dictionary<String, Object> Macros;
|
||||
protected DateTime lastWebChat;
|
||||
protected int Handle;
|
||||
public string Password { get; private set; }
|
||||
public int Handle { get; private set; }
|
||||
protected int PID;
|
||||
protected IFile logFile;
|
||||
|
||||
@ -507,12 +477,13 @@ namespace SharedLibrary
|
||||
public bool isRunning;
|
||||
|
||||
// Log stuff
|
||||
protected String Basepath;
|
||||
protected String Mod;
|
||||
protected String logPath;
|
||||
|
||||
// Databases
|
||||
public ClientsDB clientDB;
|
||||
public AliasesDB aliasDB;
|
||||
|
||||
//Remote
|
||||
public Queue<String> commandResult = new Queue<string>();
|
||||
}
|
||||
}
|
||||
|
@ -9,8 +9,9 @@
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>SharedLibrary</RootNamespace>
|
||||
<AssemblyName>SharedLibrary</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
@ -21,6 +22,7 @@
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
@ -30,11 +32,16 @@
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<RegisterForComInterop>false</RegisterForComInterop>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<StartupObject />
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data.SQLite">
|
||||
@ -47,7 +54,14 @@
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Ban.cs" />
|
||||
<Compile Include="Commands\NativeCommands.cs" />
|
||||
<Compile Include="Exceptions\CommandException.cs" />
|
||||
<Compile Include="Exceptions\DvarException.cs" />
|
||||
<Compile Include="Exceptions\NetworkException.cs" />
|
||||
<Compile Include="Exceptions\ServerException.cs" />
|
||||
<Compile Include="Interfaces\IManager.cs" />
|
||||
<Compile Include="Interfaces\ISerializable.cs" />
|
||||
<Compile Include="Penalty.cs" />
|
||||
<Compile Include="Command.cs" />
|
||||
<Compile Include="Database.cs" />
|
||||
<Compile Include="Event.cs" />
|
||||
@ -57,15 +71,25 @@
|
||||
<Compile Include="Map.cs" />
|
||||
<Compile Include="Miscellaneous.cs" />
|
||||
<Compile Include="Player.cs" />
|
||||
<Compile Include="Plugin.cs" />
|
||||
<Compile Include="Extensions\IPlugin.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="RCON.cs" />
|
||||
<Compile Include="Report.cs" />
|
||||
<Compile Include="Server.cs" />
|
||||
<Compile Include="Utilities.cs" />
|
||||
<Compile Include="WebService.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>copy /Y "$(TargetDir)$(TargetFileName)" "$(SolutionDir)Admin\lib\SharedLibrary.dll"</PostBuildEvent>
|
||||
<PostBuildEvent>mkdir "$(SolutionDir)Admin\$(OutDir)plugins
|
||||
copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)BUILD\lib"
|
||||
copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)Admin\lib"
|
||||
copy /Y "$(TargetDir)System.Data.SQLite.dll" "$(SolutionDir)BUILD\lib"
|
||||
copy /Y "$(TargetDir)Newtonsoft.Json.dll" "$(SolutionDir)BUILD\lib"
|
||||
copy /Y "$(TargetDir)Newtonsoft.Json.dll" "$(SolutionDir)Admin\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.
|
||||
|
@ -1,5 +1,4 @@
|
||||
#define REPZ_BUILD
|
||||
using System;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
@ -7,7 +6,7 @@ using System.Collections.Generic;
|
||||
|
||||
namespace SharedLibrary
|
||||
{
|
||||
public class Utilities
|
||||
public static class Utilities
|
||||
{
|
||||
//Get string with specified number of spaces -- really only for visual output
|
||||
public static String getSpaces(int Num)
|
||||
@ -29,8 +28,11 @@ namespace SharedLibrary
|
||||
}
|
||||
|
||||
//Remove words from a space delimited string
|
||||
public static String removeWords(String str, int num)
|
||||
public static String RemoveWords(this string str, int num)
|
||||
{
|
||||
if (str == null || str.Length == 0)
|
||||
return "";
|
||||
|
||||
String newStr = String.Empty;
|
||||
String[] tmp = str.Split(' ');
|
||||
|
||||
@ -62,27 +64,15 @@ namespace SharedLibrary
|
||||
public static String removeNastyChars(String str)
|
||||
{
|
||||
if (str != null)
|
||||
return str.Replace("`", "").Replace("\\", "").Replace("\"", "").Replace(""", "").Replace("&", "&").Replace("\"", "''").Replace("'", "");
|
||||
{
|
||||
return str.Replace("`", "").Replace("\\", "").Replace("\"", "").Replace(""", "").Replace("&", "&").Replace("\"", "''").Replace("'", "").Replace("?", "");
|
||||
}
|
||||
|
||||
else
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
public static int GetLineNumber(Exception ex)
|
||||
{
|
||||
var lineNumber = 0;
|
||||
const string lineSearch = ":line ";
|
||||
var index = ex.StackTrace.LastIndexOf(lineSearch);
|
||||
if (index != -1)
|
||||
{
|
||||
var lineNumberText = ex.StackTrace.Substring(index + lineSearch.Length);
|
||||
if (int.TryParse(lineNumberText, out lineNumber))
|
||||
{
|
||||
}
|
||||
}
|
||||
return lineNumber;
|
||||
}
|
||||
|
||||
public static String cleanChars(String S)
|
||||
public static String CleanChars(this string S)
|
||||
{
|
||||
if (S == null)
|
||||
return "";
|
||||
@ -99,11 +89,11 @@ namespace SharedLibrary
|
||||
/// </summary>
|
||||
/// <param name="str">String containing color codes</param>
|
||||
/// <returns></returns>
|
||||
public static String stripColors(String str)
|
||||
public static String StripColors(this string str)
|
||||
{
|
||||
if (str == null)
|
||||
return "";
|
||||
return Regex.Replace(str, @"\^[0-9]", "");
|
||||
return Regex.Replace(str, @"\^([0-9]|\:)", "");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -130,83 +120,7 @@ namespace SharedLibrary
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HTML formatted level color
|
||||
/// </summary>
|
||||
/// <param name="Level">Specified player level</param>
|
||||
/// <returns></returns>
|
||||
public static String levelHTMLFormatted(Player.Permission Level)
|
||||
{
|
||||
switch (Level)
|
||||
{
|
||||
case Player.Permission.User:
|
||||
return "<span style='color:rgb(87, 150, 66)'>" + Level + "</span>";
|
||||
case Player.Permission.Moderator:
|
||||
return "<span style='color:#e7b402'>" + Level + "</span>";
|
||||
case Player.Permission.Administrator:
|
||||
return "<span style='color:#ec82de'>" + Level + "</span>";
|
||||
case Player.Permission.SeniorAdmin:
|
||||
return "<span style='color:#2eb6bf'>" + Level + "</span>";
|
||||
case Player.Permission.Owner:
|
||||
return "<span style='color:rgb(38,120,230)'>" + Level + "</span>";
|
||||
case Player.Permission.Creator:
|
||||
return "<span style='color:rgb(38,120,230)'>" + Level + "</span>";
|
||||
case Player.Permission.Banned:
|
||||
return "<span style='color:rgb(196, 22, 28)'>" + Level + "</span>";
|
||||
case Player.Permission.Flagged:
|
||||
return "<span style='color:rgb(251, 124, 98)'>" + Level + "</span>";
|
||||
case Player.Permission.Trusted:
|
||||
return "<span style='color:orange'>" + Level + "</span>";
|
||||
default:
|
||||
return "<i>" + Level + "</i>";
|
||||
}
|
||||
}
|
||||
|
||||
public static String nameHTMLFormatted(Player P)
|
||||
{
|
||||
switch (P.Level)
|
||||
{
|
||||
case Player.Permission.User:
|
||||
return "<span style='color:rgb(87, 150, 66)'>" + P.Name + "</span>";
|
||||
case Player.Permission.Moderator:
|
||||
return "<span style='color:#e7b402'>" + P.Name + "</span>";
|
||||
case Player.Permission.Administrator:
|
||||
return "<span style='color:#ec82de'>" + P.Name + "</span>";
|
||||
case Player.Permission.SeniorAdmin:
|
||||
return "<span style='color:#2eb6bf'>" + P.Name + "</span>";
|
||||
case Player.Permission.Owner:
|
||||
return "<span style='color:rgb(38,120,230)'>" + P.Name + "</span>";
|
||||
case Player.Permission.Creator:
|
||||
return "<span style='color:rgb(38,120,230)'>" + P.Name + "</span>";
|
||||
case Player.Permission.Banned:
|
||||
return "<span style='color:rgb(196, 22, 28)'>" + P.Name + "</span>";
|
||||
case Player.Permission.Flagged:
|
||||
return "<span style='color:rgb(251, 124, 98)'>" + P.Name + "</span>";
|
||||
case Player.Permission.Trusted:
|
||||
return "<span style='color:orange'>" + P.Name + "</span>";
|
||||
default:
|
||||
return "<i>" + P.Name + "</i>";
|
||||
}
|
||||
}
|
||||
|
||||
public static String penaltyHTMLFormatted(Penalty.Type BType)
|
||||
{
|
||||
switch(BType)
|
||||
{
|
||||
case Penalty.Type.Ban:
|
||||
return "<span style='color:rgb(196, 22, 28)'>" + BType.ToString() + "</span>";
|
||||
case Penalty.Type.TempBan:
|
||||
return "<span style='color:#E6840C'>" + BType.ToString() + "</span>";
|
||||
case Penalty.Type.Kick:
|
||||
return "<span style='color:#8A0578'>" + BType.ToString() + "</span>";
|
||||
case Penalty.Type.Warning:
|
||||
return "<span style='color:#CAB11D'>" + BType.ToString() + "</span>";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static String processMacro(Dictionary<String, Object> Dict, String str)
|
||||
public static String LoadMacro(Dictionary<String, Object> Dict, String str)
|
||||
{
|
||||
MatchCollection Found = Regex.Matches(str, @"\{\{[A-Z]+\}\}", RegexOptions.IgnoreCase);
|
||||
foreach (Match M in Found)
|
||||
@ -280,32 +194,46 @@ namespace SharedLibrary
|
||||
case "oneflag":
|
||||
return "One Flag CTF";
|
||||
default:
|
||||
return "Unknown";
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
public static String DateTimeSQLite(DateTime datetime)
|
||||
{
|
||||
string dateTimeFormat = "{0}-{1}-{2} {3}:{4}:{5}.{6}";
|
||||
return string.Format(dateTimeFormat, datetime.Year, datetime.Month, datetime.Day, datetime.Hour, datetime.Minute, datetime.Second, datetime.Millisecond);
|
||||
return datetime.ToString("yyyy-MM-dd H:mm:ss");
|
||||
}
|
||||
|
||||
public static String timePassed(DateTime start)
|
||||
{
|
||||
TimeSpan Elapsed = DateTime.Now - start;
|
||||
|
||||
if (Elapsed.TotalSeconds < 30)
|
||||
return "just now";
|
||||
if (Elapsed.TotalMinutes < 120)
|
||||
{
|
||||
if (Elapsed.TotalMinutes < 1.5)
|
||||
return "1 minute";
|
||||
return Math.Round(Elapsed.TotalMinutes, 0) + " minutes";
|
||||
}
|
||||
if (Elapsed.TotalHours <= 24)
|
||||
{
|
||||
if (Elapsed.TotalHours < 1.5)
|
||||
return "1 hour";
|
||||
return Math.Round(Elapsed.TotalHours, 0) + " hours";
|
||||
}
|
||||
if (Elapsed.TotalDays <= 365)
|
||||
{
|
||||
if (Elapsed.TotalDays < 1.5)
|
||||
return "1 day";
|
||||
return Math.Round(Elapsed.TotalDays, 0) + " days";
|
||||
}
|
||||
else
|
||||
return "a very long time";
|
||||
}
|
||||
|
||||
public static String timesConnected(int connection)
|
||||
public static String TimesConnected(this Player P)
|
||||
{
|
||||
int connection = P.Connections;
|
||||
String Prefix = String.Empty;
|
||||
if (connection % 10 > 3 || connection % 10 == 0 || (connection % 100 > 9 && connection % 100 < 19))
|
||||
Prefix = "th";
|
||||
@ -349,17 +277,5 @@ namespace SharedLibrary
|
||||
return connection.ToString() + Prefix;
|
||||
}
|
||||
}
|
||||
|
||||
public static Int64 getForumIDFromStr(String npID)
|
||||
{
|
||||
Int64 forumID = 0;
|
||||
if (npID.Length == 16)
|
||||
{
|
||||
forumID = Int64.Parse(npID.Substring(0, 16), System.Globalization.NumberStyles.AllowHexSpecifier);
|
||||
forumID = forumID - 76561197960265728;
|
||||
}
|
||||
|
||||
return forumID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
102
SharedLibrary/WebService.cs
Normal file
102
SharedLibrary/WebService.cs
Normal file
@ -0,0 +1,102 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace SharedLibrary
|
||||
{
|
||||
public class WebService
|
||||
{
|
||||
public static List<IPage> pageList { get; private set; }
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
pageList = new List<IPage>();
|
||||
}
|
||||
}
|
||||
|
||||
public struct HttpResponse
|
||||
{
|
||||
public string contentType;
|
||||
public string content;
|
||||
public Dictionary<string, string> additionalHeaders;
|
||||
}
|
||||
|
||||
public interface IPage
|
||||
{
|
||||
string getPath();
|
||||
string getName();
|
||||
HttpResponse getPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary<string, string> headers);
|
||||
bool isVisible();
|
||||
}
|
||||
|
||||
public abstract class HTMLPage : IPage
|
||||
{
|
||||
private bool visible;
|
||||
|
||||
public HTMLPage()
|
||||
{
|
||||
visible = true;
|
||||
}
|
||||
|
||||
public HTMLPage(bool visible)
|
||||
{
|
||||
this.visible = visible;
|
||||
}
|
||||
|
||||
protected string getContentType()
|
||||
{
|
||||
return "text/html";
|
||||
}
|
||||
|
||||
protected string loadFile(string filename)
|
||||
{
|
||||
string s;
|
||||
|
||||
IFile HTML = new IFile(filename);
|
||||
s = HTML.getLines();
|
||||
HTML.Close();
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
protected string loadHeader()
|
||||
{
|
||||
return loadFile("webfront\\header.html");
|
||||
}
|
||||
|
||||
protected string loadFooter()
|
||||
{
|
||||
return loadFile("webfront\\footer.html");
|
||||
}
|
||||
|
||||
public bool isVisible()
|
||||
{
|
||||
return visible;
|
||||
}
|
||||
|
||||
virtual public string getPath()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
abstract public string getName();
|
||||
virtual public Dictionary<string, string> getHeaders(IDictionary<string, string> requestHeaders)
|
||||
{
|
||||
return new Dictionary<string, string>();
|
||||
}
|
||||
abstract public string getContent(System.Collections.Specialized.NameValueCollection querySet, IDictionary<string, string> headers);
|
||||
|
||||
|
||||
public HttpResponse getPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary<string, string> headers)
|
||||
{
|
||||
HttpResponse resp = new HttpResponse()
|
||||
{
|
||||
content = getContent(querySet, headers),
|
||||
contentType = getContentType(),
|
||||
additionalHeaders = getHeaders(headers)
|
||||
};
|
||||
return resp;
|
||||
}
|
||||
}
|
||||
}
|
4
SharedLibrary/packages.config
Normal file
4
SharedLibrary/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>
|
@ -5,92 +5,152 @@ using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
|
||||
using SharedLibrary.Extensions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace StatsPlugin
|
||||
{
|
||||
public class StatCommand : Command
|
||||
{
|
||||
public StatCommand() : base("stats", "view your stats. syntax !stats", "xlrstats", Player.Permission.User, 0, false) { }
|
||||
|
||||
public override void Execute(Event E)
|
||||
public override async Task ExecuteAsync(Event E)
|
||||
{
|
||||
String statLine;
|
||||
PlayerStats pStats;
|
||||
|
||||
if (E.Target != null)
|
||||
{
|
||||
pStats = Stats.playerStats.getStats(E.Target);
|
||||
pStats = Stats.statLists.Find(x => x.Port == E.Owner.getPort()).playerStats.getStats(E.Target);
|
||||
statLine = String.Format("^5{0} ^7KILLS | ^5{1} ^7DEATHS | ^5{2} ^7KDR | ^5{3} ^7SKILL", pStats.Kills, pStats.Deaths, pStats.KDR, pStats.Skill);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
pStats = Stats.playerStats.getStats(E.Origin);
|
||||
pStats = Stats.statLists.Find(x => x.Port == E.Owner.getPort()).playerStats.getStats(E.Origin);
|
||||
statLine = String.Format("^5{0} ^7KILLS | ^5{1} ^7DEATHS | ^5{2} ^7KDR | ^5{3} ^7SKILL", pStats.Kills, pStats.Deaths, pStats.KDR, pStats.Skill);
|
||||
}
|
||||
|
||||
E.Origin.Tell(statLine);
|
||||
await E.Origin.Tell(statLine);
|
||||
}
|
||||
}
|
||||
|
||||
public class topStats : Command
|
||||
public class TopStats : Command
|
||||
{
|
||||
public topStats() : base("topstats", "view the top 5 players on this server. syntax !topstats", "!ts", Player.Permission.User, 0, false) { }
|
||||
public TopStats() : base("topstats", "view the top 5 players on this server. syntax !topstats", "!ts", Player.Permission.User, 0, false) { }
|
||||
|
||||
public override void Execute(Event E)
|
||||
public override async Task ExecuteAsync(Event E)
|
||||
{
|
||||
List<KeyValuePair<String, PlayerStats>> pStats = Stats.playerStats.topStats();
|
||||
List<KeyValuePair<String, PlayerStats>> pStats = Stats.statLists.Find(x => x.Port == E.Owner.getPort()).playerStats.topStats();
|
||||
StringBuilder msgBlder = new StringBuilder();
|
||||
|
||||
E.Origin.Tell("^5--Top Players--");
|
||||
await E.Origin.Tell("^5--Top Players--");
|
||||
foreach (KeyValuePair<String, PlayerStats> pStat in pStats)
|
||||
{
|
||||
Player P = E.Owner.clientDB.getPlayer(pStat.Key, -1);
|
||||
if (P == null)
|
||||
continue;
|
||||
E.Origin.Tell(String.Format("^3{0}^7 - ^5{1} ^7KDR | ^5{2} ^7SKILL", P.Name, pStat.Value.KDR, pStat.Value.Skill));
|
||||
await E.Origin.Tell(String.Format("^3{0}^7 - ^5{1} ^7KDR | ^5{2} ^7SKILL", P.Name, pStat.Value.KDR, pStat.Value.Skill));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class Stats : Plugin
|
||||
/// <summary>
|
||||
/// Each server runs from the same plugin ( for easier reloading and reduced memory usage ).
|
||||
/// So, to have multiple stat tracking, we must store a stat struct for each server
|
||||
/// </summary>
|
||||
public class Stats : IPlugin
|
||||
{
|
||||
public static StatsDB playerStats { get; private set; }
|
||||
private DateTime[] lastKill = new DateTime[18];
|
||||
private DateTime[] connectionTime = new DateTime[18];
|
||||
private int[] inactiveMinutes = new int[18];
|
||||
private int[] Kills = new int[18];
|
||||
private int[] deathStreaks = new int[18];
|
||||
private int[] killStreaks = new int[18];
|
||||
public static List<StatTracking> statLists;
|
||||
|
||||
public override void onEvent(Event E)
|
||||
public struct StatTracking
|
||||
{
|
||||
playerStats = new StatsDB("stats_" + E.Owner.getPort() + ".rm");
|
||||
public StatsDB playerStats;
|
||||
public DateTime[] lastKill, connectionTime;
|
||||
public int[] inactiveMinutes, Kills, deathStreaks, killStreaks;
|
||||
public int Port;
|
||||
|
||||
public StatTracking(int port)
|
||||
{
|
||||
playerStats = new StatsDB("Database/stats_" + port + ".rm");
|
||||
inactiveMinutes = new int[18];
|
||||
Kills = new int[18];
|
||||
deathStreaks = new int[18];
|
||||
killStreaks = new int[18];
|
||||
lastKill = new DateTime[18];
|
||||
connectionTime = new DateTime[18];
|
||||
Port = port;
|
||||
}
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return "Basic Stats"; }
|
||||
}
|
||||
|
||||
public float Version
|
||||
{
|
||||
get { return 1f; }
|
||||
}
|
||||
|
||||
public string Author
|
||||
{
|
||||
get { return "RaidMax"; }
|
||||
}
|
||||
|
||||
public async Task OnLoad()
|
||||
{
|
||||
statLists = new List<StatTracking>();
|
||||
await Task.Delay(0);
|
||||
}
|
||||
|
||||
public async Task OnUnload()
|
||||
{
|
||||
statLists.Clear();
|
||||
await Task.Delay(0);
|
||||
}
|
||||
|
||||
public async Task OnTick(Server S)
|
||||
{
|
||||
await Task.Delay(0);
|
||||
}
|
||||
|
||||
public async Task OnEvent(Event E, Server S)
|
||||
{
|
||||
if (E.Type == Event.GType.Start)
|
||||
{
|
||||
statLists.Add(new StatTracking(S.getPort()));
|
||||
}
|
||||
|
||||
if (E.Type == Event.GType.Stop)
|
||||
{
|
||||
statLists.RemoveAll(x => x.Port == S.getPort());
|
||||
}
|
||||
|
||||
if (E.Type == Event.GType.Connect)
|
||||
{
|
||||
resetCounters(E.Origin.clientID);
|
||||
resetCounters(E.Origin.clientID, S.getPort());
|
||||
|
||||
PlayerStats checkForTrusted = playerStats.getStats(E.Origin);
|
||||
PlayerStats checkForTrusted = statLists.Find(x => x.Port == S.getPort()).playerStats.getStats(E.Origin);
|
||||
if (checkForTrusted.playTime >= 4320 && E.Origin.Level < Player.Permission.Trusted)
|
||||
{
|
||||
E.Origin.setLevel(Player.Permission.Trusted);
|
||||
E.Owner.clientDB.updatePlayer(E.Origin);
|
||||
E.Origin.Tell("Congratulations, you are now a ^5trusted ^7player! Type ^5!help ^7to view new commands.");
|
||||
E.Origin.Tell("You earned this by playing for ^53 ^7full days!");
|
||||
await E.Origin.Tell("Congratulations, you are now a ^5trusted ^7player! Type ^5!help ^7to view new commands.");
|
||||
await E.Origin.Tell("You earned this by playing for ^53 ^7full days!");
|
||||
}
|
||||
}
|
||||
|
||||
if (E.Type == Event.GType.MapEnd)
|
||||
if (E.Type == Event.GType.MapEnd || E.Type == Event.GType.Stop)
|
||||
{
|
||||
foreach (Player P in E.Owner.getPlayers())
|
||||
foreach (Player P in S.getPlayers())
|
||||
{
|
||||
|
||||
if (P == null)
|
||||
continue;
|
||||
|
||||
calculateAndSaveSkill(P);
|
||||
resetCounters(P.clientID);
|
||||
calculateAndSaveSkill(P, statLists.Find(x =>x.Port == S.getPort()));
|
||||
resetCounters(P.clientID, S.getPort());
|
||||
|
||||
E.Owner.Log.Write("Updated skill for client #" + P.databaseID, Log.Level.Debug);
|
||||
//E.Owner.Log.Write(String.Format("\r\nJoin: {0}\r\nInactive Minutes: {1}\r\nnewPlayTime: {2}\r\nnewSPM: {3}\r\nkdrWeight: {4}\r\nMultiplier: {5}\r\nscoreWeight: {6}\r\nnewSkillFactor: {7}\r\nprojectedNewSkill: {8}\r\nKills: {9}\r\nDeaths: {10}", connectionTime[P.clientID].ToShortTimeString(), inactiveMinutes[P.clientID], newPlayTime, newSPM, kdrWeight, Multiplier, scoreWeight, newSkillFactor, disconnectStats.Skill, disconnectStats.Kills, disconnectStats.Deaths));
|
||||
@ -99,8 +159,8 @@ namespace StatsPlugin
|
||||
|
||||
if (E.Type == Event.GType.Disconnect)
|
||||
{
|
||||
calculateAndSaveSkill(E.Origin);
|
||||
resetCounters(E.Origin.clientID);
|
||||
calculateAndSaveSkill(E.Origin, statLists.Find(x=>x.Port == S.getPort()));
|
||||
resetCounters(E.Origin.clientID, S.getPort());
|
||||
E.Owner.Log.Write("Updated skill for disconnecting client #" + E.Origin.databaseID, Log.Level.Debug);
|
||||
}
|
||||
|
||||
@ -110,27 +170,29 @@ namespace StatsPlugin
|
||||
return;
|
||||
|
||||
Player Killer = E.Origin;
|
||||
PlayerStats killerStats = playerStats.getStats(Killer);
|
||||
StatTracking curServer = statLists.Find(x => x.Port == S.getPort());
|
||||
PlayerStats killerStats = curServer.playerStats.getStats(Killer);
|
||||
|
||||
lastKill[E.Origin.clientID] = DateTime.Now;
|
||||
Kills[E.Origin.clientID]++;
|
||||
|
||||
if ((lastKill[E.Origin.clientID] - DateTime.Now).TotalSeconds > 60)
|
||||
inactiveMinutes[E.Origin.clientID]++;
|
||||
curServer.lastKill[E.Origin.clientID] = DateTime.Now;
|
||||
curServer.Kills[E.Origin.clientID]++;
|
||||
|
||||
if ((curServer.lastKill[E.Origin.clientID] - DateTime.Now).TotalSeconds > 60)
|
||||
curServer.inactiveMinutes[E.Origin.clientID]++;
|
||||
|
||||
killerStats.Kills++;
|
||||
|
||||
if (killerStats.Deaths == 0)
|
||||
killerStats.KDR = killerStats.Kills;
|
||||
else
|
||||
killerStats.KDR = killerStats.Kills / killerStats.Deaths;
|
||||
killerStats.KDR = Math.Round((double)killerStats.Kills / (double)killerStats.Deaths, 2);
|
||||
|
||||
playerStats.updateStats(Killer, killerStats);
|
||||
curServer.playerStats.updateStats(Killer, killerStats);
|
||||
|
||||
killStreaks[Killer.clientID] += 1;
|
||||
deathStreaks[Killer.clientID] = 0;
|
||||
curServer.killStreaks[Killer.clientID] += 1;
|
||||
curServer.deathStreaks[Killer.clientID] = 0;
|
||||
|
||||
Killer.Tell(messageOnStreak(killStreaks[Killer.clientID], deathStreaks[Killer.clientID]));
|
||||
await Killer.Tell(messageOnStreak(curServer.killStreaks[Killer.clientID], curServer.deathStreaks[Killer.clientID]));
|
||||
}
|
||||
|
||||
if (E.Type == Event.GType.Death)
|
||||
@ -139,38 +201,39 @@ namespace StatsPlugin
|
||||
return;
|
||||
|
||||
Player Victim = E.Origin;
|
||||
PlayerStats victimStats = playerStats.getStats(Victim);
|
||||
|
||||
StatTracking curServer = statLists.Find(x => x.Port == S.getPort());
|
||||
PlayerStats victimStats = curServer.playerStats.getStats(Victim);
|
||||
|
||||
victimStats.Deaths++;
|
||||
victimStats.KDR = victimStats.Kills / victimStats.Deaths;
|
||||
victimStats.KDR = Math.Round((double)victimStats.Kills / (double)victimStats.Deaths, 2);
|
||||
|
||||
playerStats.updateStats(Victim, victimStats);
|
||||
curServer.playerStats.updateStats(Victim, victimStats);
|
||||
|
||||
deathStreaks[Victim.clientID] += 1;
|
||||
killStreaks[Victim.clientID] = 0;
|
||||
curServer.deathStreaks[Victim.clientID] += 1;
|
||||
curServer.killStreaks[Victim.clientID] = 0;
|
||||
|
||||
Victim.Tell(messageOnStreak(killStreaks[Victim.clientID], deathStreaks[Victim.clientID]));
|
||||
await Victim.Tell(messageOnStreak(curServer.killStreaks[Victim.clientID], curServer.deathStreaks[Victim.clientID]));
|
||||
}
|
||||
}
|
||||
|
||||
private void calculateAndSaveSkill(Player P)
|
||||
private void calculateAndSaveSkill(Player P, StatTracking curServer)
|
||||
{
|
||||
if (P == null)
|
||||
return;
|
||||
|
||||
PlayerStats disconnectStats = playerStats.getStats(P);
|
||||
if (Kills[P.clientID] == 0)
|
||||
PlayerStats disconnectStats = curServer.playerStats.getStats(P);
|
||||
if (curServer.Kills[P.clientID] == 0)
|
||||
return;
|
||||
|
||||
else if (lastKill[P.clientID] > connectionTime[P.clientID])
|
||||
inactiveMinutes[P.clientID] += (int)(DateTime.Now - lastKill[P.clientID]).TotalMinutes;
|
||||
else if (curServer.lastKill[P.clientID] > curServer.connectionTime[P.clientID])
|
||||
curServer.inactiveMinutes[P.clientID] += (int)(DateTime.Now - curServer.lastKill[P.clientID]).TotalMinutes;
|
||||
|
||||
int newPlayTime = (int)(DateTime.Now - connectionTime[P.clientID]).TotalMinutes - inactiveMinutes[P.clientID];
|
||||
int newPlayTime = (int)(DateTime.Now - curServer.connectionTime[P.clientID]).TotalMinutes - curServer.inactiveMinutes[P.clientID];
|
||||
|
||||
if (newPlayTime < 2)
|
||||
return;
|
||||
|
||||
double newSPM = Kills[P.clientID] * 50 / newPlayTime;
|
||||
double newSPM = curServer.Kills[P.clientID] * 50 / Math.Max(1, newPlayTime);
|
||||
double kdrWeight = Math.Round(Math.Pow(disconnectStats.KDR, 2 / Math.E), 3);
|
||||
double Multiplier;
|
||||
|
||||
@ -190,34 +253,18 @@ namespace StatsPlugin
|
||||
disconnectStats.Skill = disconnectStats.scorePerMinute * kdrWeight / 10;
|
||||
disconnectStats.playTime += newPlayTime;
|
||||
|
||||
playerStats.updateStats(P, disconnectStats);
|
||||
curServer.playerStats.updateStats(P, disconnectStats);
|
||||
}
|
||||
|
||||
private void resetCounters(int cID)
|
||||
{
|
||||
Kills[cID] = 0;
|
||||
connectionTime[cID] = DateTime.Now;
|
||||
inactiveMinutes[cID] = 0;
|
||||
deathStreaks[cID] = 0;
|
||||
killStreaks[cID] = 0;
|
||||
}
|
||||
|
||||
|
||||
public override void onLoad()
|
||||
{
|
||||
for (int i = 0; i < 18; i++)
|
||||
{
|
||||
Kills[i] = 0;
|
||||
connectionTime[i] = DateTime.Now;
|
||||
inactiveMinutes[i] = 0;
|
||||
deathStreaks[i] = 0;
|
||||
killStreaks[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public override void onUnload()
|
||||
private void resetCounters(int cID, int serverPort)
|
||||
{
|
||||
StatTracking selectedPlayers = statLists.Find(x => x.Port == serverPort);
|
||||
|
||||
selectedPlayers.Kills[cID] = 0;
|
||||
selectedPlayers.connectionTime[cID] = DateTime.Now;
|
||||
selectedPlayers.inactiveMinutes[cID] = 0;
|
||||
selectedPlayers.deathStreaks[cID] = 0;
|
||||
selectedPlayers.killStreaks[cID] = 0;
|
||||
}
|
||||
|
||||
private String messageOnStreak(int killStreak, int deathStreak)
|
||||
@ -245,30 +292,6 @@ namespace StatsPlugin
|
||||
|
||||
return Message;
|
||||
}
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Basic Stats";
|
||||
}
|
||||
}
|
||||
|
||||
public override float Version
|
||||
{
|
||||
get
|
||||
{
|
||||
return 0.3f;
|
||||
}
|
||||
}
|
||||
|
||||
public override string Author
|
||||
{
|
||||
get
|
||||
{
|
||||
return "RaidMax";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class StatsDB : Database
|
||||
@ -332,15 +355,15 @@ namespace StatsPlugin
|
||||
updatedPlayer.Add("DEATHS", S.Deaths);
|
||||
updatedPlayer.Add("KDR", Math.Round(S.KDR, 2));
|
||||
updatedPlayer.Add("SKILL", Math.Round(S.Skill, 1));
|
||||
updatedPlayer.Add("SPM", Math.Round(S.scorePerMinute, 0));
|
||||
updatedPlayer.Add("SPM", Math.Round(S.scorePerMinute, 1));
|
||||
updatedPlayer.Add("PLAYTIME", S.playTime);
|
||||
|
||||
Update("STATS", updatedPlayer, String.Format("npID = '{0}'", P.npID));
|
||||
Update("STATS", updatedPlayer, new KeyValuePair<string, object>("npID", P.npID));
|
||||
}
|
||||
|
||||
public List<KeyValuePair<String, PlayerStats>> topStats()
|
||||
{
|
||||
String Query = String.Format("SELECT * FROM STATS WHERE KDR < '{0}' AND KILLS > '{1}' AND PLAYTIME > '{2}' ORDER BY SKILL DESC LIMIT '{3}'", 10, 150, 60, 5);
|
||||
String Query = String.Format("SELECT * FROM STATS WHERE SKILL > 0 AND KDR < '{0}' AND KILLS > '{1}' AND PLAYTIME > '{2}' ORDER BY SKILL DESC LIMIT '{3}'", 10, 150, 60, 5);
|
||||
DataTable Result = GetDataTable(Query);
|
||||
List<KeyValuePair<String, PlayerStats>> pStats = new List<KeyValuePair<String, PlayerStats>>();
|
||||
|
@ -9,8 +9,9 @@
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>StatsPlugin</RootNamespace>
|
||||
<AssemblyName>StatsPlugin</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@ -20,6 +21,7 @@
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
@ -28,12 +30,9 @@
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="SharedLibrary, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\Admin\lib\SharedLibrary.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
@ -43,12 +42,19 @@
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Main.cs" />
|
||||
<Compile Include="Plugin.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SharedLibrary\SharedLibrary.csproj">
|
||||
<Project>{d51eeceb-438a-47da-870f-7d7b41bc24d6}</Project>
|
||||
<Name>SharedLibrary</Name>
|
||||
<Private>False</Private>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)Admin\plugins\SimpleStatsPlugin.dll"</PostBuildEvent>
|
||||
<PostBuildEvent>copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)BUILD\plugins\"</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.
|
||||
|
307
Votemap Plugin/Plugin.cs
Normal file
307
Votemap Plugin/Plugin.cs
Normal file
@ -0,0 +1,307 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using SharedLibrary;
|
||||
using SharedLibrary.Network;
|
||||
using SharedLibrary.Extensions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Votemap_Plugin
|
||||
{
|
||||
/// <summary>
|
||||
/// Allow clients to vote for the next map at the end of a round
|
||||
/// Map choices are defined in the server
|
||||
/// </summary>
|
||||
public class VoteMap : Command
|
||||
{
|
||||
public VoteMap() : base("vote", "vote for the next map. syntax !v <mapname>", "v", Player.Permission.User, 1, false) { }
|
||||
|
||||
/// <summary>
|
||||
/// Properties of Event E
|
||||
/// Owner: The server the event came from
|
||||
/// Origin: The player generating the event
|
||||
/// Target: Optional target the player specified
|
||||
/// Data: Chat message which triggered the command event
|
||||
/// </summary>
|
||||
/// <param name="E">This is the `say` event that comes from the server</param>
|
||||
public override async Task ExecuteAsync(Event E)
|
||||
{
|
||||
var voting = Vote.getServerVotes(E.Owner.getPort());
|
||||
|
||||
// we only want to allow a vote during a vote session
|
||||
if (voting.voteInSession)
|
||||
{
|
||||
if (voting.hasVoted(E.Origin.npID))
|
||||
await E.Origin.Tell("You have already voted. Use ^5!vc ^7to ^5cancel ^7your vote");
|
||||
else
|
||||
{
|
||||
string mapSearch = E.Data.ToLower().Trim();
|
||||
// probably not the most optimized way to match the map.. but nothing is time critical here
|
||||
Map votedMap = E.Owner.maps.Find(m => (m.Alias.ToLower().Contains(mapSearch) || m.Name.Contains(mapSearch)));
|
||||
if (votedMap == null)
|
||||
await E.Origin.Tell("^1" + E.Data + " is not a recognized map");
|
||||
else
|
||||
{
|
||||
voting.castVote(E.Origin.npID, votedMap);
|
||||
await E.Origin.Tell("You voted for ^5" + votedMap.Alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
await E.Origin.Tell("There is no vote in session");
|
||||
}
|
||||
}
|
||||
|
||||
public class VoteCancel : Command
|
||||
{
|
||||
public VoteCancel() : base("votecancel", "cancel your vote for the next map. syntax !vc", "vc", Player.Permission.User, 0, false) { }
|
||||
|
||||
public override async Task ExecuteAsync(Event E)
|
||||
{
|
||||
var voting = Vote.getServerVotes(E.Owner.getPort());
|
||||
|
||||
if (voting.voteInSession)
|
||||
{
|
||||
if (voting.hasVoted(E.Origin.npID))
|
||||
{
|
||||
voting.cancelVote(E.Origin.npID);
|
||||
await E.Origin.Tell("Vote cancelled");
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
await E.Origin.Tell("You have no vote to cancel");
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
await E.Origin.Tell("There is no vote in session");
|
||||
}
|
||||
}
|
||||
|
||||
public class Vote : IPlugin
|
||||
{
|
||||
public class VoteData
|
||||
{
|
||||
public string guid;
|
||||
public Map map;
|
||||
}
|
||||
|
||||
public class MapResult
|
||||
{
|
||||
public Map map;
|
||||
public int voteNum;
|
||||
}
|
||||
|
||||
public class ServerVoting
|
||||
{
|
||||
public int serverID
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
public bool voteInSession;
|
||||
public bool matchEnded;
|
||||
public bool votePassed;
|
||||
public bool waitForLoad;
|
||||
public DateTime voteTimeStart;
|
||||
public DateTime loadStartTime;
|
||||
public List<VoteData> voteList
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public ServerVoting(int id)
|
||||
{
|
||||
serverID = id;
|
||||
voteInSession = false;
|
||||
votePassed = false;
|
||||
matchEnded = false;
|
||||
waitForLoad = true;
|
||||
voteList = new List<VoteData>();
|
||||
}
|
||||
|
||||
public int getTotalVotes()
|
||||
{
|
||||
return voteList.Count;
|
||||
}
|
||||
|
||||
public bool hasVoted(string guid)
|
||||
{
|
||||
return voteList.Exists(x => (x.guid == guid));
|
||||
}
|
||||
|
||||
public void castVote(string guid, Map map)
|
||||
{
|
||||
var vote = new VoteData();
|
||||
vote.guid = guid;
|
||||
vote.map = map;
|
||||
voteList.Add(vote);
|
||||
}
|
||||
|
||||
public void cancelVote(string guid)
|
||||
{
|
||||
voteList.RemoveAll(x => (x.guid == guid));
|
||||
}
|
||||
|
||||
public MapResult getTopMap()
|
||||
{
|
||||
List<MapResult> results = new List<MapResult>();
|
||||
MapResult result = new MapResult();
|
||||
result.map = new Map("Remain", "Remain");
|
||||
result.voteNum = 0;
|
||||
|
||||
foreach (var vote in voteList)
|
||||
{
|
||||
if (!results.Exists(x => (x.map.Name == vote.map.Name)))
|
||||
{
|
||||
MapResult newResult = new MapResult();
|
||||
newResult.map = vote.map;
|
||||
newResult.voteNum = 1;
|
||||
results.Add(newResult);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
var map = results.Find(x => x.map.Name == vote.map.Name);
|
||||
map.voteNum += 1;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var map in results)
|
||||
if (map.voteNum > result.voteNum)
|
||||
result = map;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static List<ServerVoting> serverVotingList;
|
||||
public static int minVotes = 3;
|
||||
|
||||
public string Author
|
||||
{
|
||||
get
|
||||
{
|
||||
return "RaidMax";
|
||||
}
|
||||
}
|
||||
|
||||
public float Version
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Votemap Plugin";
|
||||
}
|
||||
}
|
||||
|
||||
public async Task OnLoad()
|
||||
{
|
||||
serverVotingList = new List<ServerVoting>();
|
||||
}
|
||||
|
||||
public async Task OnUnload()
|
||||
{
|
||||
serverVotingList.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The server monitor thread calls this about every 1 second
|
||||
/// This is not high-precision, but will run 1 time per second
|
||||
/// </summary>
|
||||
/// <param name="S"></param>
|
||||
public async Task OnTick(Server S)
|
||||
{
|
||||
var serverVotes = getServerVotes(S.getPort());
|
||||
|
||||
if (serverVotes != null)
|
||||
{
|
||||
|
||||
if ((DateTime.Now - serverVotes.loadStartTime).TotalSeconds < 30 /* || S.getPlayers().Count < 3*/)
|
||||
return;
|
||||
else
|
||||
serverVotes.waitForLoad = false;
|
||||
|
||||
// dvar that is set & updated by the game script...
|
||||
serverVotes.matchEnded = (await S.GetDvarAsync<int>("scr_gameended")).Value == 1;
|
||||
|
||||
/*
|
||||
Console.WriteLine("===========================");
|
||||
Console.WriteLine("Match ended->" + serverVotes.matchEnded);
|
||||
Console.WriteLine("Vote in session->" + serverVotes.voteInSession);
|
||||
Console.WriteLine("Vote passed->" + serverVotes.votePassed);*/
|
||||
|
||||
if (!serverVotes.voteInSession && serverVotes.matchEnded && serverVotes.voteTimeStart == DateTime.MinValue)
|
||||
{
|
||||
await S.Broadcast("Voting has started for the ^5next map");
|
||||
await S.Broadcast("Type ^5!v <map> ^7to vote for the nextmap!");
|
||||
serverVotes.voteInSession = true;
|
||||
serverVotes.voteTimeStart = DateTime.Now;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!serverVotes.voteInSession && serverVotes.votePassed && (DateTime.Now - serverVotes.voteTimeStart).TotalSeconds > 30)
|
||||
{
|
||||
await S.ExecuteCommandAsync("map " + serverVotes.getTopMap().map.Name);
|
||||
serverVotes.votePassed = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (serverVotes.voteInSession)
|
||||
{
|
||||
if ((DateTime.Now - serverVotes.voteTimeStart).TotalSeconds > 25)
|
||||
{
|
||||
serverVotes.voteInSession = false;
|
||||
|
||||
MapResult m = serverVotes.getTopMap();
|
||||
await S.Broadcast("Voting has ended!");
|
||||
|
||||
if (m.voteNum < minVotes && S.getPlayers().Count > 4)
|
||||
await S.Broadcast("Vote map failed. At least ^5" + minVotes + " ^7people must choose the same map");
|
||||
else
|
||||
{
|
||||
await S.Broadcast(String.Format("Next map is ^5{0} ^7- [^2{1}/{2}^7] votes", m.map.Alias, m.voteNum, serverVotes.getTotalVotes()));
|
||||
serverVotes.votePassed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task OnEvent(Event E, Server S)
|
||||
{
|
||||
if (E.Type == Event.GType.Start)
|
||||
{
|
||||
serverVotingList.Add(new ServerVoting(S.getPort()));
|
||||
}
|
||||
|
||||
if (E.Type == Event.GType.Stop)
|
||||
{
|
||||
serverVotingList.RemoveAll(x => x.serverID == S.getPort());
|
||||
}
|
||||
|
||||
if (E.Type == Event.GType.MapEnd || E.Type == Event.GType.MapChange)
|
||||
{
|
||||
var serverVotes = getServerVotes(S.getPort());
|
||||
serverVotes.voteList.Clear();
|
||||
serverVotes.voteTimeStart = DateTime.MinValue;
|
||||
serverVotes.loadStartTime = DateTime.Now;
|
||||
serverVotes.waitForLoad = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static ServerVoting getServerVotes(int serverID)
|
||||
{
|
||||
return serverVotingList.Find(x => (x.serverID == serverID));
|
||||
}
|
||||
}
|
||||
}
|
64
Votemap Plugin/Votemap Plugin.csproj
Normal file
64
Votemap Plugin/Votemap Plugin.csproj
Normal file
@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{428D8EB9-ECA3-4A66-AA59-3A944378C33F}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Votemap_Plugin</RootNamespace>
|
||||
<AssemblyName>VotemapPlugin</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<StartupObject />
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SharedLibrary\SharedLibrary.csproj">
|
||||
<Project>{d51eeceb-438a-47da-870f-7d7b41bc24d6}</Project>
|
||||
<Name>SharedLibrary</Name>
|
||||
<Private>False</Private>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Plugin.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)BUILD\plugins\"</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.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
@ -1,620 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using SharedLibrary;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Linq;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
namespace Webfront_Plugin
|
||||
{
|
||||
class Framework
|
||||
{
|
||||
private List<Server> activeServers;
|
||||
|
||||
public Framework()
|
||||
{
|
||||
activeServers = new List<Server>();
|
||||
}
|
||||
|
||||
public void addServer(Server S)
|
||||
{
|
||||
activeServers.Add(S);
|
||||
}
|
||||
|
||||
public void removeServer(Server S)
|
||||
{
|
||||
if (S != null && activeServers.Contains(S))
|
||||
{
|
||||
S.Stop();
|
||||
activeServers.Remove(S);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Server> getServers()
|
||||
{
|
||||
return activeServers;
|
||||
}
|
||||
|
||||
private String processTemplate(String Input, String Param)
|
||||
{
|
||||
try
|
||||
{
|
||||
Server requestedServer = null;
|
||||
int requestPageNum = 0;
|
||||
int ID = 0;
|
||||
String Query = "";
|
||||
|
||||
if (Param != null)
|
||||
{
|
||||
NameValueCollection querySet = System.Web.HttpUtility.ParseQueryString(Param);
|
||||
|
||||
if (querySet["server"] != null)
|
||||
requestedServer = activeServers.Find(x => x.pID() == Int32.Parse(querySet["server"]));
|
||||
else
|
||||
requestedServer = activeServers.First();
|
||||
|
||||
if (querySet["page"] != null)
|
||||
requestPageNum = Int32.Parse(querySet["page"]);
|
||||
|
||||
if (querySet["id"] != null)
|
||||
ID = Int32.Parse(querySet["id"]);
|
||||
|
||||
if (querySet["query"] != null)
|
||||
Query = querySet["query"];
|
||||
}
|
||||
|
||||
String Pattern = @"\{\{.+\}\}";
|
||||
Regex Search = new Regex(Pattern, RegexOptions.IgnoreCase);
|
||||
|
||||
MatchCollection Matches = Search.Matches(Input);
|
||||
|
||||
foreach (Match match in Matches)
|
||||
{
|
||||
Input = processReplacements(Input, match.Value, requestPageNum, ID, Query, requestedServer);
|
||||
}
|
||||
|
||||
return Input;
|
||||
}
|
||||
|
||||
catch (Exception E)
|
||||
{
|
||||
Page Error = new error();
|
||||
return Error.Load().Replace("{{ERROR}}", E.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private String parsePagination(int totalItems, int itemsPerPage, int currentPage, String Page)
|
||||
{
|
||||
StringBuilder output = new StringBuilder();
|
||||
|
||||
output.Append("<div id=pages>");
|
||||
|
||||
if (currentPage > 0)
|
||||
output.AppendFormat("<a href=/{0}?page={1}>PREV</a>", Page, currentPage - 1);
|
||||
|
||||
double totalPages = Math.Ceiling(((float)totalItems / itemsPerPage));
|
||||
|
||||
output.Append("<span id=pagination>" + (currentPage + 1) + "/" + totalPages + "</span>");
|
||||
|
||||
if ((currentPage + 1) < totalPages)
|
||||
output.AppendFormat("<a href=/{0}?page={1}>NEXT</a>", Page, currentPage + 1);
|
||||
|
||||
output.Append("</div>");
|
||||
|
||||
return output.ToString();
|
||||
}
|
||||
|
||||
private String processReplacements(String Input, String Macro, int curPage, int ID, String Query, params Server[] Servers)
|
||||
{
|
||||
bool Authenticated = false;
|
||||
bool UserPrivelege = false;
|
||||
|
||||
if (Servers[0] != null && Manager.lastIP != null)
|
||||
{
|
||||
Player User = Servers[0].clientDB.getPlayer(Manager.lastIP.ToString());
|
||||
if (User != null && User.Level > Player.Permission.Flagged)
|
||||
Authenticated = true;
|
||||
if (User != null && User.Level == Player.Permission.User)
|
||||
UserPrivelege = true;
|
||||
}
|
||||
|
||||
if (Macro.Length < 5)
|
||||
return "";
|
||||
|
||||
String Looking = Macro.Substring(2, Macro.Length - 4);
|
||||
|
||||
if (Looking == "SERVERS")
|
||||
{
|
||||
int cycleFix = 0;
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
|
||||
foreach (Server S in activeServers)
|
||||
{
|
||||
StringBuilder players = new StringBuilder();
|
||||
if (S.getClientNum() > 0)
|
||||
{
|
||||
int count = 0;
|
||||
double currentPlayers = S.statusPlayers.Count;
|
||||
|
||||
players.Append("<table cellpadding='0' cellspacing='0' class='players'>");
|
||||
|
||||
foreach (Player P in S.getPlayers())
|
||||
{
|
||||
if (P == null)
|
||||
continue;
|
||||
|
||||
if (count % 2 == 0)
|
||||
{
|
||||
switch (cycleFix)
|
||||
{
|
||||
case 0:
|
||||
players.Append("<tr class='row-grey'>");
|
||||
cycleFix = 1;
|
||||
break;
|
||||
case 1:
|
||||
players.Append("<tr class='row-white'>");
|
||||
cycleFix = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
players.AppendFormat("<td><a href='/player?id={0}'>{1}</a></td>", P.databaseID, SharedLibrary.Utilities.nameHTMLFormatted(P));
|
||||
|
||||
if (count % 2 != 0)
|
||||
{
|
||||
players.Append("</tr>");
|
||||
}
|
||||
|
||||
count++;
|
||||
|
||||
}
|
||||
players.Append("</table>");
|
||||
}
|
||||
buffer.AppendFormat(@"<table cellpadding=0 cellspacing=0 class=server>
|
||||
<tr>
|
||||
<th class=server_title><span>{0}</span></th>
|
||||
<th class=server_map><span>{1}</span></th>
|
||||
<th class=server_players><span>{2}</span></th>
|
||||
<th class=server_gametype><span>{3}</span></th>
|
||||
<th><a href=/bans>Penalties</a></th>
|
||||
<th><a class='history' href='/graph?server={4}'>History</a></th>
|
||||
</tr>
|
||||
</table>
|
||||
{5}",
|
||||
|
||||
S.getName(), S.getMap(), S.getClientNum() + "/" + S.getMaxClients(), SharedLibrary.Utilities.gametypeLocalized(S.getGametype()), S.pID(), players.ToString());
|
||||
|
||||
if (S.getClientNum() > 0)
|
||||
{
|
||||
buffer.AppendFormat("<div class='chatHistory' id='chatHistory_{0}'></div><script type='text/javascript'>$( document ).ready(function() {{ setInterval({1}loadChatMessages({0}, '#chatHistory_{0}'){1}, 2500); }});</script><div class='null' style='clear:both;'></div>", S.pID(), '\"');
|
||||
if (UserPrivelege || Authenticated)
|
||||
buffer.AppendFormat("<form class='chatOutFormat' action={1}javascript:chatRequest({0}, 'chatEntry_{0}'){1}><input class='chatFormat_text' type='text' placeholder='Enter a message...' id='chatEntry_{0}'/><input class='chatFormat_submit' type='submit'/></form>", S.pID(), '\"');
|
||||
}
|
||||
buffer.Append("<hr/>");
|
||||
}
|
||||
return Input.Replace(Macro, buffer.ToString());
|
||||
}
|
||||
|
||||
if(Looking == "CHAT")
|
||||
{
|
||||
StringBuilder chatMessages = new StringBuilder();
|
||||
chatMessages.Append("<table id='table_chatHistory'>");
|
||||
if (Servers.Length > 0 && Servers[0] != null)
|
||||
{
|
||||
foreach (Chat Message in Servers[0].chatHistory)
|
||||
chatMessages.AppendFormat("<tr><td class='chat_name' style='text-align: left;'>{0}</td><td class='chat_message'>{1}</td><td class='chat_time' style='text-align: right;'>{2}</td></tr>", SharedLibrary.Utilities.nameHTMLFormatted(Message.Origin), Message.Message, Message.timeString());
|
||||
}
|
||||
|
||||
chatMessages.Append("</table>");
|
||||
return chatMessages.ToString();
|
||||
}
|
||||
|
||||
if (Looking == "PLAYER")
|
||||
{
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
Server S = activeServers[0];
|
||||
|
||||
buffer.Append("<table class='player_info'><tr><th>Name</th><th>Aliases</th><th>IP</th><th>Rating</th><th>Level</th><th>Connections</th><th>Last Seen</th><th>Profile</th>");
|
||||
List<Player> matchingPlayers = new List<Player>();
|
||||
|
||||
if (ID > 0)
|
||||
matchingPlayers.Add(S.clientDB.getPlayer(ID));
|
||||
|
||||
else if (Query.Length > 2)
|
||||
{
|
||||
matchingPlayers = S.clientDB.findPlayers(Query);
|
||||
|
||||
if (matchingPlayers == null)
|
||||
matchingPlayers = new List<Player>();
|
||||
|
||||
List<int> matchedDatabaseIDs = new List<int>();
|
||||
|
||||
foreach (Aliases matchingAlias in S.aliasDB.findPlayers(Query))
|
||||
matchedDatabaseIDs.Add(matchingAlias.Number);
|
||||
|
||||
foreach (Player matchingP in S.clientDB.getPlayers(matchedDatabaseIDs))
|
||||
{
|
||||
if (matchingPlayers.Find(x => x.databaseID == matchingP.databaseID) == null)
|
||||
matchingPlayers.Add(matchingP);
|
||||
}
|
||||
}
|
||||
|
||||
if (matchingPlayers == null)
|
||||
buffer.Append("</table>");
|
||||
|
||||
else
|
||||
{
|
||||
foreach (Player Player in matchingPlayers)
|
||||
{
|
||||
if (Player == null)
|
||||
continue;
|
||||
|
||||
buffer.Append("<tr>");
|
||||
StringBuilder Names = new StringBuilder();
|
||||
|
||||
|
||||
List<String> nameAlias = new List<String>();
|
||||
List<String> IPAlias = new List<String>();
|
||||
StringBuilder IPs = new StringBuilder();
|
||||
|
||||
if (Authenticated)
|
||||
{
|
||||
List<Aliases> allAlliases = S.getAliases(Player);
|
||||
|
||||
foreach (Aliases A in allAlliases)
|
||||
{
|
||||
|
||||
foreach (String Name in A.Names.Distinct())
|
||||
nameAlias.Add(Name);
|
||||
|
||||
foreach (String IP in A.IPS.Distinct())
|
||||
IPAlias.Add(IP);
|
||||
|
||||
}
|
||||
|
||||
Names.Append("<a href='#' class='pseudoLinkAlias'>Show Aliases</a>");
|
||||
Names.Append("<div class='playerAlias'>");
|
||||
foreach (String Name in nameAlias.Distinct())
|
||||
Names.AppendFormat("<span>{0}</span><br/>", Utilities.stripColors(Name));
|
||||
Names.Append("</div>");
|
||||
|
||||
IPs.Append("<a href='#' class='pseudoLinkIP'>Show IPs</a>");
|
||||
IPs.Append("<div class='playerIPs'>");
|
||||
foreach (String IP in IPAlias)
|
||||
IPs.AppendFormat("<span>{0}</span><br/>", IP);
|
||||
IPs.Append("</div>");
|
||||
}
|
||||
|
||||
if (!Authenticated)
|
||||
{
|
||||
Names.Append("Hidden");
|
||||
IPs.Append("Hidden");
|
||||
}
|
||||
|
||||
Int64 forumID = 0;
|
||||
if (Player.npID.Length == 16)
|
||||
{
|
||||
forumID = Int64.Parse(Player.npID.Substring(0, 16), System.Globalization.NumberStyles.AllowHexSpecifier);
|
||||
forumID = forumID - 76561197960265728;
|
||||
}
|
||||
|
||||
String Screenshot = String.Empty;
|
||||
|
||||
//if (logged)
|
||||
Screenshot = String.Format("<a href='http://server.nbsclan.org/screen.php?id={0}&name={1}' target='_blank'><div style='background-image:url(http://server.nbsclan.org/shutter.png); width: 20px; height: 20px;float: right; position:relative; right: 21%; background-size: contain;'></div></a>", forumID, Player.Name);
|
||||
|
||||
buffer.AppendFormat("<td><a style='float: left;' href='{9}'>{0}</a>{10}</td><td>{1}</td><td>{2}</td><td>{3}</td><td>{4}</td><td>{5}</td><td>{6} ago</td><td><a href='https://repziw4.de/forum/memberlist.php?mode=viewprofile&u={7}'>{8}</a></td>", Player.Name, Names, IPs, 0, SharedLibrary.Utilities.levelHTMLFormatted(Player.Level), Player.Connections, Player.getLastConnection(), forumID, Player.Name, "/player?id=" + Player.databaseID, Screenshot);
|
||||
buffer.Append("</tr>");
|
||||
}
|
||||
|
||||
buffer.Append("</table>");
|
||||
return Input.Replace(Macro, buffer.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
if (Looking == "BANS")
|
||||
{
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
Server S = activeServers[0];
|
||||
|
||||
buffer.Append("<table cellspacing=0 class=bans>");
|
||||
int limitPerPage = 30;
|
||||
int Pagination = curPage;
|
||||
int totalBans = S.Bans.Count;
|
||||
int range;
|
||||
int start = Pagination * limitPerPage;
|
||||
int cycleFix = 0;
|
||||
|
||||
if (totalBans <= limitPerPage)
|
||||
range = totalBans;
|
||||
else if ((totalBans - start) < limitPerPage)
|
||||
range = (totalBans - start);
|
||||
else
|
||||
range = limitPerPage;
|
||||
|
||||
List<Penalty> Bans = new List<Penalty>();
|
||||
|
||||
if (totalBans > 0)
|
||||
Bans = S.Bans.OrderByDescending(x => x.When).ToList().GetRange(start, range);
|
||||
|
||||
if (Bans.Count == 0)
|
||||
buffer.Append("<span style='font-size: 16pt;'>No bans yet.</span>");
|
||||
|
||||
else
|
||||
{
|
||||
buffer.Append("<h1 style=margin-top: 0;>{{TIME}}</h1><hr /><tr><th>Name</th><th>Type</th><th style=text-align:left;>Offense</th><th style=text-align:left;>Penalty By</th><th style='width: 175px; text-align:right;padding-right: 80px;'>Time</th></tr>");
|
||||
|
||||
if (Bans[0] != null)
|
||||
buffer = buffer.Replace("{{TIME}}", "From " + SharedLibrary.Utilities.timePassed(Bans[0].When) + " ago" + " — " + totalBans + " total");
|
||||
|
||||
List<String> npIDs = new List<string>();
|
||||
|
||||
foreach (Penalty B in Bans)
|
||||
npIDs.Add(B.npID);
|
||||
|
||||
|
||||
List<Player> bannedPlayers = S.clientDB.getPlayers(npIDs);
|
||||
|
||||
for (int i = 0; i < Bans.Count; i++)
|
||||
{
|
||||
if (Bans[i] == null)
|
||||
continue;
|
||||
|
||||
Player P = bannedPlayers.Where(x => x.npID == Bans[i].npID).First();
|
||||
Player B;
|
||||
|
||||
if (P.npID == Bans[i].bannedByID || Bans[i].bannedByID == "")
|
||||
B = new Player("IW4MAdmin", "", 0, SharedLibrary.Player.Permission.Banned, 0, "", 0, "");
|
||||
|
||||
else
|
||||
B = S.clientDB.getPlayer(Bans[i].bannedByID, -1);
|
||||
|
||||
if (P == null)
|
||||
P = new Player("Unknown", "n/a", 0, 0, 0, "Unknown", 0, "");
|
||||
if (B == null)
|
||||
B = new Player("Unknown", "n/a", 0, 0, 0, "Unknown", 0, "");
|
||||
|
||||
if (P.lastOffense == String.Empty)
|
||||
P.lastOffense = "Evade";
|
||||
|
||||
if (P != null && B != null)
|
||||
{
|
||||
|
||||
String Prefix;
|
||||
if (cycleFix % 2 == 0)
|
||||
Prefix = "class=row-grey";
|
||||
else
|
||||
Prefix = "class=row-white";
|
||||
|
||||
String Link = "/player?id=" + P.databaseID;
|
||||
buffer.AppendFormat("<tr {4}><td><a href='{5}'>{0}</a></td><td style='width: 150px; border-left: 3px solid #bbb; text-align:left;'>{6}</td><td style='border-left: 3px solid #bbb; text-align:left;'>{1}</td><td style='border-left: 3px solid #bbb;text-align:left;'>{2}</td><td style='width: 175px; text-align:right;'>{3}</td></tr></div>", P.Name, Bans[i].Reason.Substring(0, Math.Min(70, Bans[i].Reason.Length)), SharedLibrary.Utilities.nameHTMLFormatted(B), Bans[i].getWhen(), Prefix, Link, Utilities.penaltyHTMLFormatted(Bans[i].BType));
|
||||
cycleFix++;
|
||||
}
|
||||
}
|
||||
}
|
||||
buffer.Append("</table><hr/>");
|
||||
|
||||
if (totalBans > limitPerPage)
|
||||
buffer.Append(parsePagination(totalBans, limitPerPage, Pagination, "bans"));
|
||||
|
||||
return Input.Replace(Macro, buffer.ToString());
|
||||
}
|
||||
|
||||
if (Looking == "GRAPH")
|
||||
{
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.Append("<script type='text/javascript' src='//www.google.com/jsapi'></script><div id='chart_div'></div>");
|
||||
buffer.Append("<script> var players = [");
|
||||
int count = 1;
|
||||
List<PlayerHistory> run = Servers[0].playerHistory.ToList();
|
||||
foreach (PlayerHistory i in run) //need to reverse for proper timeline
|
||||
{
|
||||
buffer.AppendFormat("[new Date({0}, {1}, {2}, {3}, {4}), {5}]", i.When.Year, i.When.Month - 1, i.When.Day, i.When.Hour, i.When.Minute, i.Players);
|
||||
if (count < run.Count)
|
||||
buffer.Append(",\n");
|
||||
count++;
|
||||
}
|
||||
buffer.Append("];\n");
|
||||
buffer.Append("</script>");
|
||||
return Input.Replace(Macro, buffer.ToString());
|
||||
}
|
||||
|
||||
if (Looking == "TITLE")
|
||||
return Input.Replace(Macro, "IW4MAdmin by RaidMax");
|
||||
|
||||
if (Looking == "VERSION")
|
||||
return Input.Replace(Macro, "1.1");
|
||||
|
||||
if (Looking == "PUBBANS" || Looking == "PUBBANSR")
|
||||
{
|
||||
String pubBans = "=========================================\r\nIW4MAdmin Public Banlist\r\n=========================================\r\n";
|
||||
foreach (Penalty P in activeServers[0].Bans.OrderByDescending(x => x.When).ToList())
|
||||
{
|
||||
if (P.BType == Penalty.Type.Ban)
|
||||
pubBans += String.Format("{0};{1};{2};{3}\r\n",P.npID, P.IP, P.Reason.Trim(), P.When);
|
||||
if (Looking == "PUBBANSR")
|
||||
pubBans += "<br/>";
|
||||
}
|
||||
|
||||
return Input.Replace(Macro, pubBans);
|
||||
}
|
||||
|
||||
return "PLACEHOLDER";
|
||||
|
||||
}
|
||||
|
||||
public String processRequest(Kayak.Http.HttpRequestHead request)
|
||||
{
|
||||
Page requestedPage = new notfound();
|
||||
Page Header = new header();
|
||||
Page Footer = new footer();
|
||||
|
||||
if (request.Path == "/")
|
||||
requestedPage = new main();
|
||||
|
||||
else
|
||||
{
|
||||
string p = request.Path.ToLower().Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries)[0];
|
||||
switch (p)
|
||||
{
|
||||
case "bans":
|
||||
requestedPage = new bans();
|
||||
break;
|
||||
case "player":
|
||||
requestedPage = new player();
|
||||
break;
|
||||
case "graph":
|
||||
requestedPage = new graph();
|
||||
return processTemplate(requestedPage.Load(), request.QueryString);
|
||||
case "chat":
|
||||
requestedPage = new chat();
|
||||
return processTemplate(requestedPage.Load(), request.QueryString);
|
||||
case "error":
|
||||
requestedPage = new error();
|
||||
break;
|
||||
case "pubbans":
|
||||
return processTemplate("{{PUBBANS}}", null);
|
||||
case "pubbansr":
|
||||
return processTemplate("{{PUBBANSR}}", null);
|
||||
default:
|
||||
requestedPage = new notfound();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return processTemplate(Header.Load(), null) + processTemplate(requestedPage.Load(), request.QueryString) + processTemplate(Footer.Load(), null);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class Page
|
||||
{
|
||||
public abstract String Load();
|
||||
public abstract String Name { get; }
|
||||
|
||||
protected String loadHTML()
|
||||
{
|
||||
IFile HTML = new IFile("webfront\\" + this.Name + ".html");
|
||||
String Contents = HTML.getLines();
|
||||
HTML.Close();
|
||||
return Contents;
|
||||
}
|
||||
}
|
||||
|
||||
class notfound : Page
|
||||
{
|
||||
public override String Name
|
||||
{
|
||||
get { return "notfound"; }
|
||||
}
|
||||
|
||||
public override String Load()
|
||||
{
|
||||
return loadHTML();
|
||||
}
|
||||
}
|
||||
|
||||
class main : Page
|
||||
{
|
||||
public override String Name
|
||||
{
|
||||
get { return "main"; }
|
||||
}
|
||||
|
||||
public override String Load()
|
||||
{
|
||||
return loadHTML();
|
||||
}
|
||||
}
|
||||
|
||||
class bans : Page
|
||||
{
|
||||
public override String Name
|
||||
{
|
||||
get { return "bans"; }
|
||||
}
|
||||
|
||||
public override String Load()
|
||||
{
|
||||
return loadHTML();
|
||||
}
|
||||
}
|
||||
|
||||
class header : Page
|
||||
{
|
||||
public override String Name
|
||||
{
|
||||
get { return "header"; }
|
||||
}
|
||||
|
||||
public override String Load()
|
||||
{
|
||||
return loadHTML();
|
||||
}
|
||||
}
|
||||
|
||||
class footer : Page
|
||||
{
|
||||
public override String Name
|
||||
{
|
||||
get { return "footer"; }
|
||||
}
|
||||
|
||||
public override String Load()
|
||||
{
|
||||
return loadHTML();
|
||||
}
|
||||
}
|
||||
|
||||
class player : Page
|
||||
{
|
||||
public override String Name
|
||||
{
|
||||
get { return "player"; }
|
||||
}
|
||||
|
||||
public override String Load()
|
||||
{
|
||||
return loadHTML();
|
||||
}
|
||||
}
|
||||
|
||||
class graph : Page
|
||||
{
|
||||
public override String Name
|
||||
{
|
||||
get { return "graph"; }
|
||||
}
|
||||
|
||||
public override String Load()
|
||||
{
|
||||
return loadHTML();
|
||||
}
|
||||
}
|
||||
|
||||
class chat : Page
|
||||
{
|
||||
public override String Name
|
||||
{
|
||||
get { return "chat"; }
|
||||
}
|
||||
|
||||
public override String Load()
|
||||
{
|
||||
return "{{CHAT}}";
|
||||
}
|
||||
}
|
||||
|
||||
class error : Page
|
||||
{
|
||||
public override String Name
|
||||
{
|
||||
get { return "error"; }
|
||||
}
|
||||
|
||||
public override String Load()
|
||||
{
|
||||
return loadHTML();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
using System;
|
||||
using SharedLibrary;
|
||||
using System.Threading;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Webfront_Plugin
|
||||
{
|
||||
public class Webfront : Plugin
|
||||
{
|
||||
private static Thread webManagerThread;
|
||||
|
||||
public override void onEvent(Event E)
|
||||
{
|
||||
if (E.Type == Event.GType.Start)
|
||||
{
|
||||
Manager.webFront.removeServer(Manager.webFront.getServers().Find(x => x.getPort() == E.Owner.getPort()));
|
||||
Manager.webFront.addServer(E.Owner);
|
||||
E.Owner.Log.Write("Webfront now listening", Log.Level.Production);
|
||||
}
|
||||
if (E.Type == Event.GType.Stop)
|
||||
{
|
||||
Manager.webFront.removeServer(E.Owner);
|
||||
E.Owner.Log.Write("Webfront has lost access to server", Log.Level.Production);
|
||||
}
|
||||
}
|
||||
|
||||
public override void onLoad()
|
||||
{
|
||||
webManagerThread = new Thread(new ThreadStart(Manager.Init));
|
||||
webManagerThread.Name = "Webfront";
|
||||
|
||||
webManagerThread.Start();
|
||||
}
|
||||
|
||||
public override void onUnload()
|
||||
{
|
||||
Manager.webScheduler.Stop();
|
||||
webManagerThread.Join();
|
||||
}
|
||||
|
||||
public override String Name
|
||||
{
|
||||
get { return "Webfront"; }
|
||||
}
|
||||
|
||||
public override float Version
|
||||
{
|
||||
get { return 0.1f; }
|
||||
}
|
||||
|
||||
public override string Author
|
||||
{
|
||||
get
|
||||
{
|
||||
return "RaidMax";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user