fixed issue with not escaping regex for validating commands

This commit is contained in:
RaidMax 2018-03-18 21:25:11 -05:00
parent 1ac7956c22
commit f7b41537d7
33 changed files with 354 additions and 286 deletions

View File

@ -173,8 +173,8 @@ namespace StatsPlugin.Cheat
double marginOfError = Thresholds.GetMarginOfError(chestKills); double marginOfError = Thresholds.GetMarginOfError(chestKills);
double lerpAmount = Math.Min(1.0, (chestKills - Thresholds.LowSampleMinKills) / (double)(Thresholds.HighSampleMinKills - Thresholds.LowSampleMinKills)); double lerpAmount = Math.Min(1.0, (chestKills - Thresholds.LowSampleMinKills) / (double)(Thresholds.HighSampleMinKills - Thresholds.LowSampleMinKills));
// determine max acceptable ratio of chest to abdomen kills // determine max acceptable ratio of chest to abdomen kills
double chestAbdomenRatioLerpValueForFlag = Thresholds.Lerp(Thresholds.ChestAbdomenRatioThresholdLowSample(2.25), Thresholds.ChestAbdomenRatioThresholdHighSample(2.25), lerpAmount) + marginOfError; double chestAbdomenRatioLerpValueForFlag = Thresholds.Lerp(Thresholds.ChestAbdomenRatioThresholdLowSample(3), Thresholds.ChestAbdomenRatioThresholdHighSample(3), lerpAmount) + marginOfError;
double chestAbdomenLerpValueForBan = Thresholds.Lerp(Thresholds.ChestAbdomenRatioThresholdLowSample(3.25), Thresholds.ChestAbdomenRatioThresholdHighSample(3.25), lerpAmount) + marginOfError; double chestAbdomenLerpValueForBan = Thresholds.Lerp(Thresholds.ChestAbdomenRatioThresholdLowSample(4), Thresholds.ChestAbdomenRatioThresholdHighSample(4), lerpAmount) + marginOfError;
double currentChestAbdomenRatio = HitLocationCount[IW4Info.HitLocation.torso_upper] / (double)HitLocationCount[IW4Info.HitLocation.torso_lower]; double currentChestAbdomenRatio = HitLocationCount[IW4Info.HitLocation.torso_upper] / (double)HitLocationCount[IW4Info.HitLocation.torso_lower];
@ -198,7 +198,7 @@ namespace StatsPlugin.Cheat
{ {
ClientPenalty = Penalty.PenaltyType.Ban, ClientPenalty = Penalty.PenaltyType.Ban,
RatioAmount = currentChestAbdomenRatio, RatioAmount = currentChestAbdomenRatio,
Bone = IW4Info.HitLocation.torso_upper, Bone = 0,
KillCount = chestKills KillCount = chestKills
}; };
} }
@ -219,7 +219,7 @@ namespace StatsPlugin.Cheat
{ {
ClientPenalty = Penalty.PenaltyType.Flag, ClientPenalty = Penalty.PenaltyType.Flag,
RatioAmount = currentChestAbdomenRatio, RatioAmount = currentChestAbdomenRatio,
Bone = IW4Info.HitLocation.torso_upper, Bone = 0,
KillCount = chestKills KillCount = chestKills
}; };
} }

View File

@ -31,7 +31,7 @@ namespace StatsPlugin.Cheat
public const int HighSampleMinKills = 100; public const int HighSampleMinKills = 100;
public const double KillTimeThreshold = 0.2; public const double KillTimeThreshold = 0.2;
public static double GetMarginOfError(int numKills) => 0.98 / Math.Sqrt(numKills); public static double GetMarginOfError(int numKills) => 1.6455 / Math.Sqrt(numKills);
public static double Lerp(double v1, double v2, double amount) public static double Lerp(double v1, double v2, double amount)
{ {

View File

@ -0,0 +1,61 @@
using SharedLibrary.Configuration;
using SharedLibrary.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StatsPlugin.Config
{
class StatsConfiguration : IBaseConfiguration
{
public bool EnableAntiCheat { get; set; }
public List<StreakMessageConfiguration> KillstreakMessages { get; set; }
public List<StreakMessageConfiguration> DeathstreakMessages { get; set; }
public string Name() => "Stats";
public IBaseConfiguration Generate()
{
var config = new StatsConfiguration();
Console.Write("Enable server-side anti-cheat? [y/n]: ");
config.EnableAntiCheat = (Console.ReadLine().ToLower().FirstOrDefault() as char?) == 'y';
config.KillstreakMessages = new List<StreakMessageConfiguration>()
{
new StreakMessageConfiguration(){
Count = -1,
Message = "Try not to kill yourself anymore"
},
new StreakMessageConfiguration() {
Count = 5,
Message = "Great job! You're on a ^55 killstreak!"
},
new StreakMessageConfiguration()
{
Count = 10,
Message = "Amazing! ^510 kills ^7without dying!"
},
new StreakMessageConfiguration(){
Count = 25,
Message = "You better call in that nuke, ^525 killstreak^7!"
}
};
config.DeathstreakMessages = new List<StreakMessageConfiguration>()
{
new StreakMessageConfiguration()
{
Count = 5,
Message = "Pick it up soldier, you've died ^55 times ^7in a row..."
},
new StreakMessageConfiguration(){
Count = 10,
Message = "Seriously? ^510 deaths ^7without getting a kill?"
},
};
return config;
}
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StatsPlugin.Config
{
public class StreakMessageConfiguration
{
public int Count { get; set; }
public string Message { get; set; }
}
}

View File

@ -10,6 +10,8 @@ using SharedLibrary.Objects;
using SharedLibrary.Services; using SharedLibrary.Services;
using StatsPlugin.Models; using StatsPlugin.Models;
using SharedLibrary.Commands; using SharedLibrary.Commands;
using SharedLibrary.Configuration;
using StatsPlugin.Config;
namespace StatsPlugin.Helpers namespace StatsPlugin.Helpers
{ {
@ -17,7 +19,6 @@ namespace StatsPlugin.Helpers
{ {
private ConcurrentDictionary<int, ServerStats> Servers; private ConcurrentDictionary<int, ServerStats> Servers;
private ConcurrentDictionary<int, ThreadSafeStatsService> ContextThreads; private ConcurrentDictionary<int, ThreadSafeStatsService> ContextThreads;
private ConcurrentDictionary<int, StreakMessage> StreakMessages;
private ILogger Log; private ILogger Log;
private IManager Manager; private IManager Manager;
@ -25,7 +26,6 @@ namespace StatsPlugin.Helpers
{ {
Servers = new ConcurrentDictionary<int, ServerStats>(); Servers = new ConcurrentDictionary<int, ServerStats>();
ContextThreads = new ConcurrentDictionary<int, ThreadSafeStatsService>(); ContextThreads = new ConcurrentDictionary<int, ThreadSafeStatsService>();
StreakMessages = new ConcurrentDictionary<int, StreakMessage>();
Log = mgr.GetLogger(); Log = mgr.GetLogger();
Manager = mgr; Manager = mgr;
} }
@ -48,7 +48,6 @@ namespace StatsPlugin.Helpers
int serverId = sv.GetHashCode(); int serverId = sv.GetHashCode();
var statsSvc = new ThreadSafeStatsService(); var statsSvc = new ThreadSafeStatsService();
ContextThreads.TryAdd(serverId, statsSvc); ContextThreads.TryAdd(serverId, statsSvc);
StreakMessages.TryAdd(serverId, new StreakMessage(sv));
// get the server from the database if it exists, otherwise create and insert a new one // get the server from the database if it exists, otherwise create and insert a new one
var server = statsSvc.ServerSvc.Find(c => c.ServerId == serverId).FirstOrDefault(); var server = statsSvc.ServerSvc.Find(c => c.ServerId == serverId).FirstOrDefault();
@ -247,7 +246,7 @@ namespace StatsPlugin.Helpers
//statsSvc.KillStatsSvc.Insert(kill); //statsSvc.KillStatsSvc.Insert(kill);
//await statsSvc.KillStatsSvc.SaveChangesAsync(); //await statsSvc.KillStatsSvc.SaveChangesAsync();
if(Manager.GetApplicationSettings().EnableAntiCheat) if(Plugin.Config.Configuration().EnableAntiCheat)
{ {
async Task executePenalty(Cheat.DetectionPenaltyResult penalty) async Task executePenalty(Cheat.DetectionPenaltyResult penalty)
{ {
@ -313,10 +312,9 @@ namespace StatsPlugin.Helpers
CalculateKill(attackerStats, victimStats); CalculateKill(attackerStats, victimStats);
// show encouragement/discouragement // show encouragement/discouragement
var streakMessageGen = StreakMessages[serverId];
string streakMessage = (attackerStats.ClientId != victimStats.ClientId) ? string streakMessage = (attackerStats.ClientId != victimStats.ClientId) ?
streakMessageGen.MessageOnStreak(attackerStats.KillStreak, attackerStats.DeathStreak) : StreakMessage.MessageOnStreak(attackerStats.KillStreak, attackerStats.DeathStreak) :
streakMessageGen.MessageOnStreak(-1, -1); StreakMessage.MessageOnStreak(-1, -1);
if (streakMessage != string.Empty) if (streakMessage != string.Empty)
await attacker.Tell(streakMessage); await attacker.Tell(streakMessage);

View File

@ -10,55 +10,20 @@ namespace StatsPlugin.Helpers
{ {
public class StreakMessage public class StreakMessage
{ {
private ConfigurationManager config;
public StreakMessage(Server sv)
{
config = new ConfigurationManager(sv);
// initialize default messages
if (config.GetProperty<Dictionary<int, string>>("KillstreakMessages") == null)
{
var killstreakMessages = new Dictionary<int, string>()
{
{ -1, "Try not to kill yourself anymore" },
{ 5, "Great job! You're on a ^55 killstreak!" },
{ 10, "Amazing! ^510 kills ^7without dying!" },
{ 25, "You better call in that nuke, ^525 killstreak^7!" }
};
config.AddProperty(new KeyValuePair<string, object>("KillstreakMessages", killstreakMessages));
}
if (config.GetProperty<Dictionary<int, string>>("DeathstreakMessages") == null)
{
var deathstreakMessages = new Dictionary<int, string>()
{
{ 5, "Pick it up soldier, you've died ^55 times ^7in a row..." },
{ 10, "Seriously? ^510 deaths ^7without getting a kill?" },
};
config.AddProperty(new KeyValuePair<string, object>("DeathstreakMessages", deathstreakMessages));
}
}
/// <summary> /// <summary>
/// Get a message from the configuration encouraging or discouraging clients /// Get a message from the configuration encouraging or discouraging clients
/// </summary> /// </summary>
/// <param name="killStreak">how many kills the client has without dying</param> /// <param name="killStreak">how many kills the client has without dying</param>
/// <param name="deathStreak">how many deaths the client has without getting a kill</param> /// <param name="deathStreak">how many deaths the client has without getting a kill</param>
/// <returns>message to send to the client</returns> /// <returns>message to send to the client</returns>
public string MessageOnStreak(int killStreak, int deathStreak) public static string MessageOnStreak(int killStreak, int deathStreak)
{ {
var killstreakMessage = config.GetProperty<Dictionary<int, string>>("KillstreakMessages"); var killstreakMessage = Plugin.Config.Configuration().KillstreakMessages;
var deathstreakMessage = config.GetProperty<Dictionary<int, string>>("DeathstreakMessages"); var deathstreakMessage = Plugin.Config.Configuration().DeathstreakMessages;
string message = ""; string message = killstreakMessage.FirstOrDefault(m => m.Count == killStreak)?.Message;
message = (message == null) ? deathstreakMessage.FirstOrDefault(m => m.Count == deathStreak)?.Message : message;
if (killstreakMessage.ContainsKey(killStreak)) return message ?? "";
message =killstreakMessage[killStreak];
else if (deathstreakMessage.ContainsKey(deathStreak))
message = deathstreakMessage[deathStreak];
return message;
} }
} }
} }

View File

@ -5,10 +5,12 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using SharedLibrary; using SharedLibrary;
using SharedLibrary.Configuration;
using SharedLibrary.Dtos; using SharedLibrary.Dtos;
using SharedLibrary.Helpers; using SharedLibrary.Helpers;
using SharedLibrary.Interfaces; using SharedLibrary.Interfaces;
using SharedLibrary.Services; using SharedLibrary.Services;
using StatsPlugin.Config;
using StatsPlugin.Helpers; using StatsPlugin.Helpers;
using StatsPlugin.Models; using StatsPlugin.Models;
@ -24,6 +26,7 @@ namespace StatsPlugin
public static StatManager Manager { get; private set; } public static StatManager Manager { get; private set; }
private IManager ServerManager; private IManager ServerManager;
public static BaseConfigurationHandler<StatsConfiguration> Config { get; private set; }
public async Task OnEventAsync(Event E, Server S) public async Task OnEventAsync(Event E, Server S)
{ {
@ -80,8 +83,16 @@ namespace StatsPlugin
} }
} }
public Task OnLoadAsync(IManager manager) public async Task OnLoadAsync(IManager manager)
{ {
// load custom configuration
Config = new BaseConfigurationHandler<StatsConfiguration>("StatsPluginSettings");
if (Config.Configuration()== null)
{
Config.Set((StatsConfiguration)new StatsConfiguration().Generate());
await Config.Save();
}
// meta data info // meta data info
async Task<List<ProfileMeta>> getStats(int clientId) async Task<List<ProfileMeta>> getStats(int clientId)
{ {
@ -203,9 +214,7 @@ namespace StatsPlugin
ServerManager = manager; ServerManager = manager;
return Task.FromResult( Manager = new StatManager(manager);
Manager = new StatManager(manager)
);
} }
public async Task OnTickAsync(Server S) public async Task OnTickAsync(Server S)

View File

@ -124,6 +124,8 @@
<Compile Include="Commands\ResetStats.cs" /> <Compile Include="Commands\ResetStats.cs" />
<Compile Include="Commands\TopStats.cs" /> <Compile Include="Commands\TopStats.cs" />
<Compile Include="Commands\ViewStats.cs" /> <Compile Include="Commands\ViewStats.cs" />
<Compile Include="Config\StreakMessageConfiguration.cs" />
<Compile Include="Config\StatsConfiguration.cs" />
<Compile Include="Helpers\ServerStats.cs" /> <Compile Include="Helpers\ServerStats.cs" />
<Compile Include="Helpers\StatManager.cs" /> <Compile Include="Helpers\StatManager.cs" />
<Compile Include="Helpers\StreakMessage.cs" /> <Compile Include="Helpers\StreakMessage.cs" />
@ -150,11 +152,6 @@
<Name>SharedLibrary</Name> <Name>SharedLibrary</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions">
<Version>1.1.2</Version>
</PackageReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup> <PropertyGroup>
<PostBuildEvent>copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)BUILD\plugins\"</PostBuildEvent> <PostBuildEvent>copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)BUILD\plugins\"</PostBuildEvent>

View File

@ -7,6 +7,7 @@ using System.Threading.Tasks;
using SharedLibrary.Network; using SharedLibrary.Network;
using SharedLibrary.Objects; using SharedLibrary.Objects;
using SharedLibrary.Helpers; using SharedLibrary.Helpers;
using SharedLibrary.Configuration;
namespace Welcome_Plugin namespace Welcome_Plugin
{ {
@ -64,11 +65,17 @@ namespace Welcome_Plugin
public string Name => "Welcome Plugin"; public string Name => "Welcome Plugin";
private Dictionary<int, ConfigurationManager> Configs; private BaseConfigurationHandler<WelcomeConfiguration> Config;
public async Task OnLoadAsync(IManager manager) public async Task OnLoadAsync(IManager manager)
{ {
await Task.FromResult(Configs = new Dictionary<int, ConfigurationManager>()); // load custom configuration
Config = new BaseConfigurationHandler<WelcomeConfiguration>("WelcomePluginSettings");
if (Config.Configuration() == null)
{
Config.Set((WelcomeConfiguration)new WelcomeConfiguration().Generate());
await Config.Save();
}
} }
public async Task OnUnloadAsync() public async Task OnUnloadAsync()
@ -84,39 +91,15 @@ namespace Welcome_Plugin
if (E.Type == Event.GType.Connect) if (E.Type == Event.GType.Connect)
{ {
Player newPlayer = E.Origin; Player newPlayer = E.Origin;
var cfg = Configs[S.GetHashCode()];
if (newPlayer.Level >= Player.Permission.Trusted && !E.Origin.Masked) if (newPlayer.Level >= Player.Permission.Trusted && !E.Origin.Masked)
await E.Owner.Broadcast(ProcessAnnouncement(cfg.GetProperty<string>("PrivilegedAnnouncementMessage"), newPlayer)); await E.Owner.Broadcast(ProcessAnnouncement(Config.Configuration().PrivilegedAnnouncementMessage, newPlayer));
await newPlayer.Tell(ProcessAnnouncement(cfg.GetProperty<string>("UserWelcomeMessage"), newPlayer)); await newPlayer.Tell(ProcessAnnouncement(Config.Configuration().UserWelcomeMessage, newPlayer));
if (newPlayer.Level == Player.Permission.Flagged) if (newPlayer.Level == Player.Permission.Flagged)
await E.Owner.ToAdmins($"^1NOTICE: ^7Flagged player ^5{newPlayer.Name} ^7has joined!"); await E.Owner.ToAdmins($"^1NOTICE: ^7Flagged player ^5{newPlayer.Name} ^7has joined!");
else else
await E.Owner.Broadcast(ProcessAnnouncement(cfg.GetProperty<string>("UserAnnouncementMessage"), newPlayer)); await E.Owner.Broadcast(ProcessAnnouncement(Config.Configuration().UserAnnouncementMessage, newPlayer));
}
if (E.Type == Event.GType.Start)
{
var cfg = new ConfigurationManager(S);
Configs.Add(S.GetHashCode(), cfg);
if (cfg.GetProperty<string>("UserWelcomeMessage") == null)
{
string welcomeMsg = "Welcome ^5{{ClientName}}^7, this is your ^5{{TimesConnected}} ^7time connecting!";
cfg.AddProperty(new KeyValuePair<string, dynamic>("UserWelcomeMessage", welcomeMsg));
}
if (cfg.GetProperty<string>("PrivilegedAnnouncementMessage") == null)
{
string annoucementMsg = "{{ClientLevel}} {{ClientName}} has joined the server";
cfg.AddProperty(new KeyValuePair<string, dynamic>("PrivilegedAnnouncementMessage", annoucementMsg));
}
if (cfg.GetProperty<string>("UserAnnouncementMessage") == null)
{
string annoucementMsg = "^5{{ClientName}} ^7hails from ^5{{ClientLocation}}";
cfg.AddProperty(new KeyValuePair<string, dynamic>("UserAnnouncementMessage", annoucementMsg));
}
} }
} }

View File

@ -0,0 +1,26 @@
using SharedLibrary.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Welcome_Plugin
{
class WelcomeConfiguration : IBaseConfiguration
{
public string UserAnnouncementMessage { get; set; }
public string UserWelcomeMessage { get; set; }
public string PrivilegedAnnouncementMessage { get; set; }
public IBaseConfiguration Generate()
{
UserAnnouncementMessage = "^5{{ClientName}} ^7hails from ^5{{ClientLocation}}";
UserWelcomeMessage = "Welcome ^5{{ClientName}}^7, this is your ^5{{TimesConnected}} ^7time connecting!";
PrivilegedAnnouncementMessage = "{{ClientLevel}} {{ClientName}} has joined the server";
return this;
}
public string Name() => "WelcomeConfiguration";
}
}

View File

@ -120,6 +120,7 @@
<Compile Include="CountryLookup.cs" /> <Compile Include="CountryLookup.cs" />
<Compile Include="Plugin.cs" /> <Compile Include="Plugin.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="WelcomeConfiguration.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="GeoIP.dat" /> <None Include="GeoIP.dat" />

View File

@ -424,7 +424,7 @@ namespace SharedLibrary.Commands
if (newPerm == Player.Permission.Owner && E.Origin.Level != Player.Permission.Console) if (newPerm == Player.Permission.Owner && E.Origin.Level != Player.Permission.Console)
newPerm = Player.Permission.Banned; newPerm = Player.Permission.Banned;
if (newPerm == Player.Permission.Owner && !E.Owner.Manager.GetApplicationSettings().EnableMultipleOwners) if (newPerm == Player.Permission.Owner && !E.Owner.Manager.GetApplicationSettings().Configuration().EnableMultipleOwners)
{ {
await E.Origin.Tell("There can only be 1 owner. Modify your appsettings if multiple owners are required"); await E.Origin.Tell("There can only be 1 owner. Modify your appsettings if multiple owners are required");
return; return;
@ -585,7 +585,8 @@ namespace SharedLibrary.Commands
public override async Task ExecuteAsync(Event E) public override async Task ExecuteAsync(Event E)
{ {
if (E.Owner.Rules.Count < 1) if (E.Owner.Manager.GetApplicationSettings().Configuration().GlobalRules?.Count < 1 &&
E.Owner.ServerConfig.Rules?.Count < 1)
{ {
if (E.Message.IsBroadcastCommand()) if (E.Message.IsBroadcastCommand())
await E.Owner.Broadcast("The server owner has not set any rules"); await E.Owner.Broadcast("The server owner has not set any rules");
@ -595,7 +596,12 @@ namespace SharedLibrary.Commands
else else
{ {
foreach (String r in E.Owner.Rules) var rules = new List<string>();
rules.AddRange(E.Owner.Manager.GetApplicationSettings().Configuration().GlobalRules);
if (E.Owner.ServerConfig.Rules != null)
rules.AddRange(E.Owner.ServerConfig.Rules);
foreach (string r in rules)
{ {
if (E.Message.IsBroadcastCommand()) if (E.Message.IsBroadcastCommand())
await E.Owner.Broadcast($"- {r}"); await E.Owner.Broadcast($"- {r}");

View File

@ -1,20 +1,53 @@
using System.Collections.Generic; using SharedLibrary.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
namespace SharedLibrary.Configuration namespace SharedLibrary.Configuration
{ {
public class ApplicationConfiguration public class ApplicationConfiguration : IBaseConfiguration
{ {
public bool EnableMultipleOwners { get; set; } public bool EnableMultipleOwners { get; set; }
public bool EnableTrustedRank { get; set; } public bool EnableTrustedRank { get; set; }
public bool EnableClientVPNs { get; set; } public bool EnableClientVPNs { get; set; }
public bool EnableAntiCheat { get; set; }
public bool EnableDiscordLink { get; set; } public bool EnableDiscordLink { get; set; }
public string DiscordInviteCode { get; set; } public string DiscordInviteCode { get; set; }
public string IPHubAPIKey { get; set; } public string IPHubAPIKey { get; set; }
public List<ServerConfiguration> Servers { get; set; } public List<ServerConfiguration> Servers { get; set; }
public int AutoMessagePeriod { get; set; } public int AutoMessagePeriod { get; set; }
public List<string> AutoMessages { get; set; } public List<string> AutoMessages { get; set; }
public List<string> Rules { get; set; } public List<string> GlobalRules { get; set; }
public List<MapConfiguration> Maps { get; set; } public List<MapConfiguration> Maps { get; set; }
public IBaseConfiguration Generate()
{
Console.Write("Enable multiple owners? [y/n]: ");
EnableMultipleOwners = (Console.ReadLine().ToLower().FirstOrDefault() as char?) == 'y';
Console.Write("Enable trusted rank? [y/n]: ");
EnableTrustedRank = (Console.ReadLine().ToLower().FirstOrDefault() as char?) == 'y';
Console.Write("Enable client VPNs [y/n]: ");
EnableClientVPNs = (Console.ReadLine().ToLower().FirstOrDefault() as char?) == 'y';
if (EnableClientVPNs)
{
Console.Write("Enter iphub.info api key: ");
IPHubAPIKey = Console.ReadLine();
}
Console.Write("Display discord link on webfront [y/n]: ");
EnableDiscordLink = (Console.ReadLine().ToLower().FirstOrDefault() as char?) == 'y';
if (EnableDiscordLink)
{
Console.Write("Enter discord invite link: ");
DiscordInviteCode = Console.ReadLine();
}
return this;
}
public string Name() => "ApplicationConfiguration";
} }
} }

View File

@ -1,9 +1,13 @@
namespace SharedLibrary.Configuration using System.Collections.Generic;
namespace SharedLibrary.Configuration
{ {
public class ServerConfiguration public class ServerConfiguration
{ {
public string IPAddress { get; set; } public string IPAddress { get; set; }
public short Port { get; set; } public short Port { get; set; }
public string Password { get; set; } public string Password { get; set; }
public List<string> Rules { get; set; }
public List<string> AutoMessages { get; set; }
} }
} }

View File

@ -10,7 +10,6 @@ namespace SharedLibrary.Dtos
public class ProfileMeta : SharedInfo public class ProfileMeta : SharedInfo
{ {
public DateTime When { get; set; } public DateTime When { get; set; }
public bool Sensitive { get; set; }
public string WhenString => Utilities.GetTimePassed(When, false); public string WhenString => Utilities.GetTimePassed(When, false);
public string Key { get; set; } public string Key { get; set; }
public dynamic Value { get; set; } public dynamic Value { get; set; }

View File

@ -0,0 +1,53 @@
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using SharedLibrary.Interfaces;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SharedLibrary.Configuration
{
public class BaseConfigurationHandler<T> : IConfigurationHandler<T> where T : IBaseConfiguration
{
string Filename;
IConfigurationRoot ConfigurationRoot { get; set; }
T _configuration;
public BaseConfigurationHandler(string fn)
{
Filename = fn;
Build();
}
public void Build()
{
ConfigurationRoot = new ConfigurationBuilder()
.AddJsonFile($"{AppDomain.CurrentDomain.BaseDirectory}{Filename}.json", true)
.Build();
_configuration = ConfigurationRoot.Get<T>();
if (_configuration == null)
_configuration = default(T);
}
public Task Save()
{
var appConfigJSON = JsonConvert.SerializeObject(_configuration, Formatting.Indented);
return Task.Factory.StartNew(() =>
{
File.WriteAllText($"{AppDomain.CurrentDomain.BaseDirectory}{Filename}.json", appConfigJSON);
});
}
public T Configuration() => _configuration;
public void Set(T config)
{
_configuration = config;
}
}
}

View File

@ -1,69 +0,0 @@
using Microsoft.CSharp.RuntimeBinder;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
namespace SharedLibrary.Helpers
{
public class ConfigurationManager
{
ConcurrentDictionary<string, dynamic> ConfigSet;
Server ServerInstance;
public ConfigurationManager(Server S)
{
try
{
ConfigSet = Interfaces.Serialize<ConcurrentDictionary<string, dynamic>>.Read($"{Utilities.OperatingDirectory}config/plugins_{S.ToString()}.cfg");
}
catch (Exception)
{
S.Logger.WriteInfo("ConfigurationManager could not deserialize configuration file, so initializing default config set");
ConfigSet = new ConcurrentDictionary<string, dynamic>();
}
ServerInstance = S;
SaveChanges();
}
private void SaveChanges()
{
Interfaces.Serialize<ConcurrentDictionary<string, dynamic>>.Write($"{Utilities.OperatingDirectory}config/plugins_{ServerInstance.ToString()}.cfg", ConfigSet);
}
public void AddProperty(KeyValuePair<string, dynamic> prop)
{
if (!ConfigSet.ContainsKey(prop.Key))
ConfigSet.TryAdd(prop.Key, prop.Value);
SaveChanges();
}
public void UpdateProperty(KeyValuePair<string, dynamic> prop)
{
if (ConfigSet.ContainsKey(prop.Key))
ConfigSet[prop.Key] = prop.Value;
SaveChanges();
}
public T GetProperty<T>(string prop)
{
try
{
return ConfigSet[prop].ToObject<T>();
}
catch (RuntimeBinderException)
{
return ConfigSet[prop];
}
catch (Exception)
{
return default(T);
}
}
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SharedLibrary.Interfaces
{
public interface IBaseConfiguration
{
string Name();
IBaseConfiguration Generate();
}
}

View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SharedLibrary.Interfaces
{
public interface IConfigurationHandler<T> where T : IBaseConfiguration
{
Task Save();
void Build();
T Configuration();
void Set(T config);
}
}

View File

@ -18,7 +18,7 @@ namespace SharedLibrary.Interfaces
IList<Command> GetCommands(); IList<Command> GetCommands();
IList<Helpers.MessageToken> GetMessageTokens(); IList<Helpers.MessageToken> GetMessageTokens();
IList<Player> GetActiveClients(); IList<Player> GetActiveClients();
ApplicationConfiguration GetApplicationSettings(); IConfigurationHandler<ApplicationConfiguration> GetApplicationSettings();
ClientService GetClientService(); ClientService GetClientService();
AliasService GetAliasService(); AliasService GetAliasService();
PenaltyService GetPenaltyService(); PenaltyService GetPenaltyService();

View File

@ -15,7 +15,6 @@ using SharedLibrary.Configuration;
namespace SharedLibrary namespace SharedLibrary
{ {
[Guid("61d3829e-fcbe-44d3-bb7c-51db8c2d7ac5")]
public abstract class Server public abstract class Server
{ {
public enum Game public enum Game
@ -44,7 +43,6 @@ namespace SharedLibrary
NextMessage = 0; NextMessage = 0;
InitializeTokens(); InitializeTokens();
InitializeAutoMessages(); InitializeAutoMessages();
InitializeRules();
} }
//Returns current server IP set by `net_ip` -- *STRING* //Returns current server IP set by `net_ip` -- *STRING*
@ -253,7 +251,7 @@ namespace SharedLibrary
protected void InitializeMaps() protected void InitializeMaps()
{ {
Maps = new List<Map>(); Maps = new List<Map>();
Maps.AddRange(Manager.GetApplicationSettings().Maps.First(m => m.Game == GameName).Maps); Maps.AddRange(Manager.GetApplicationSettings().Configuration().Maps.First(m => m.Game == GameName).Maps);
} }
/// <summary> /// <summary>
@ -264,22 +262,11 @@ namespace SharedLibrary
{ {
BroadcastMessages = new List<String>(); BroadcastMessages = new List<String>();
BroadcastMessages.AddRange(Manager.GetApplicationSettings().AutoMessages); if(ServerConfig.AutoMessages != null)
BroadcastMessages.AddRange(ServerConfig.AutoMessages);
BroadcastMessages.AddRange(Manager.GetApplicationSettings().Configuration().AutoMessages);
} }
/// <summary>
/// Initialize the rules configuration
/// todo: this needs to be a serialized file
/// </summary>
protected void InitializeRules()
{
Rules = new List<String>();
Rules.AddRange(Manager.GetApplicationSettings().Rules);
}
public ConfigurationManager Configuration { get; private set; }
public override string ToString() public override string ToString()
{ {
return $"{IP}_{Port}"; return $"{IP}_{Port}";
@ -303,10 +290,9 @@ namespace SharedLibrary
public Interfaces.ILogger Logger { get; private set; } public Interfaces.ILogger Logger { get; private set; }
public ServerConfiguration ServerConfig { get; private set; } public ServerConfiguration ServerConfig { get; private set; }
public List<Map> Maps { get; protected set; } public List<Map> Maps { get; protected set; }
public List<string> Rules { get; protected set; }
public List<Report> Reports { get; set; } public List<Report> Reports { get; set; }
public List<ChatInfo> ChatHistory { get; protected set; } public List<ChatInfo> ChatHistory { get; protected set; }
public Queue<Helpers.PlayerHistory> PlayerHistory { get; private set; } public Queue<PlayerHistory> PlayerHistory { get; private set; }
public Game GameName { get; protected set; } public Game GameName { get; protected set; }
// Info // Info

View File

@ -172,9 +172,11 @@
<Compile Include="Exceptions\NetworkException.cs" /> <Compile Include="Exceptions\NetworkException.cs" />
<Compile Include="Exceptions\SerializationException.cs" /> <Compile Include="Exceptions\SerializationException.cs" />
<Compile Include="Exceptions\ServerException.cs" /> <Compile Include="Exceptions\ServerException.cs" />
<Compile Include="Helpers\ConfigurationManager.cs" /> <Compile Include="Helpers\BaseConfigurationHandler.cs" />
<Compile Include="Helpers\ParseEnum.cs" /> <Compile Include="Helpers\ParseEnum.cs" />
<Compile Include="Helpers\Vector3.cs" /> <Compile Include="Helpers\Vector3.cs" />
<Compile Include="Interfaces\IBaseConfiguration.cs" />
<Compile Include="Interfaces\IConfigurationHandler.cs" />
<Compile Include="Interfaces\IEntityService.cs" /> <Compile Include="Interfaces\IEntityService.cs" />
<Compile Include="Interfaces\ILogger.cs" /> <Compile Include="Interfaces\ILogger.cs" />
<Compile Include="Interfaces\IManager.cs" /> <Compile Include="Interfaces\IManager.cs" />
@ -228,9 +230,18 @@
<PackageReference Include="EntityFramework.SqlServerCompact"> <PackageReference Include="EntityFramework.SqlServerCompact">
<Version>6.2.0</Version> <Version>6.2.0</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration">
<Version>1.1.2</Version>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions"> <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions">
<Version>1.1.2</Version> <Version>1.1.2</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration.Binder">
<Version>1.1.2</Version>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration.Json">
<Version>1.1.2</Version>
</PackageReference>
<PackageReference Include="Newtonsoft.Json"> <PackageReference Include="Newtonsoft.Json">
<Version>11.0.1</Version> <Version>11.0.1</Version>
</PackageReference> </PackageReference>

View File

@ -48,6 +48,8 @@ namespace IW4MAdmin
Console.Write("Enter server RCON password: "); Console.Write("Enter server RCON password: ");
newConfig.Password = Console.ReadLine(); newConfig.Password = Console.ReadLine();
newConfig.AutoMessages = new List<string>();
newConfig.Rules = new List<string>();
configList.Add(newConfig); configList.Add(newConfig);
@ -57,39 +59,5 @@ namespace IW4MAdmin
return configList; return configList;
} }
public static ApplicationConfiguration GenerateApplicationConfig()
{
var config = new ApplicationConfiguration();
Console.Write("Enable multiple owners? [y/n]: ");
config.EnableMultipleOwners = (Console.ReadLine().ToLower().FirstOrDefault() as char?) == 'y';
Console.Write("Enable trusted rank? [y/n]: ");
config.EnableTrustedRank = (Console.ReadLine().ToLower().FirstOrDefault() as char?) == 'y';
Console.Write("Enable server-side anti-cheat [y/n]: ");
config.EnableAntiCheat = (Console.ReadLine().ToLower().FirstOrDefault() as char?) == 'y';
Console.Write("Enable client VPNS [y/n]: ");
config.EnableClientVPNs = (Console.ReadLine().ToLower().FirstOrDefault() as char?) == 'y';
if (!config.EnableClientVPNs)
{
Console.Write("Enter iphub.info api key: ");
config.IPHubAPIKey = Console.ReadLine();
}
Console.Write("Display Discord link on webfront [y/n]: ");
config.EnableDiscordLink = (Console.ReadLine().ToLower().FirstOrDefault() as char?) == 'y';
if (config.EnableDiscordLink)
{
Console.Write("Enter Discord invite link: ");
config.DiscordInviteCode = Console.ReadLine();
}
return config;
}
} }
} }

View File

@ -16,7 +16,7 @@ namespace IW4MAdmin
static public ApplicationManager ServerManager = ApplicationManager.GetInstance(); static public ApplicationManager ServerManager = ApplicationManager.GetInstance();
public static string OperatingDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + Path.DirectorySeparatorChar; public static string OperatingDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + Path.DirectorySeparatorChar;
public static void Start() public static bool Start()
{ {
AppDomain.CurrentDomain.SetData("DataDirectory", OperatingDirectory); AppDomain.CurrentDomain.SetData("DataDirectory", OperatingDirectory);
System.Diagnostics.Process.GetCurrentProcess().PriorityClass = System.Diagnostics.ProcessPriorityClass.BelowNormal; System.Diagnostics.Process.GetCurrentProcess().PriorityClass = System.Diagnostics.ProcessPriorityClass.BelowNormal;
@ -66,6 +66,8 @@ namespace IW4MAdmin
Console.WriteLine("Shutdown complete"); Console.WriteLine("Shutdown complete");
}); });
return true;
} }
catch (Exception e) catch (Exception e)
@ -78,7 +80,7 @@ namespace IW4MAdmin
} }
Console.WriteLine("Press any key to exit..."); Console.WriteLine("Press any key to exit...");
Console.ReadKey(); Console.ReadKey();
return; return false;
} }
} }
@ -86,15 +88,6 @@ namespace IW4MAdmin
{ {
string curDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + Path.DirectorySeparatorChar; string curDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + Path.DirectorySeparatorChar;
if (!Directory.Exists($"{curDirectory}Config"))
{
Console.WriteLine("Warning: Config folder does not exist");
Directory.CreateDirectory($"{curDirectory}Config");
}
if (!Directory.Exists($"{curDirectory}Config/Servers"))
Directory.CreateDirectory($"{curDirectory}Config/Servers");
if (!Directory.Exists($"{curDirectory}Logs")) if (!Directory.Exists($"{curDirectory}Logs"))
Directory.CreateDirectory($"{curDirectory}Logs"); Directory.CreateDirectory($"{curDirectory}Logs");

View File

@ -37,11 +37,11 @@ namespace IW4MAdmin
ClientService ClientSvc; ClientService ClientSvc;
AliasService AliasSvc; AliasService AliasSvc;
PenaltyService PenaltySvc; PenaltyService PenaltySvc;
IConfigurationRoot AppSettings; BaseConfigurationHandler<ApplicationConfiguration> ConfigHandler;
#if FTP_LOG #if FTP_LOG
const int UPDATE_FREQUENCY = 700; const int UPDATE_FREQUENCY = 700;
#else #else
const int UPDATE_FREQUENCY = 750; const int UPDATE_FREQUENCY = 450;
#endif #endif
private ApplicationManager() private ApplicationManager()
@ -56,13 +56,7 @@ namespace IW4MAdmin
PenaltySvc = new PenaltyService(); PenaltySvc = new PenaltyService();
AdministratorIPs = new List<int>(); AdministratorIPs = new List<int>();
ServerEventOccurred += EventAPI.OnServerEventOccurred; ServerEventOccurred += EventAPI.OnServerEventOccurred;
} ConfigHandler = new BaseConfigurationHandler<ApplicationConfiguration>("IW4MAdminSettings");
private void BuildConfiguration()
{
AppSettings = new ConfigurationBuilder()
.AddJsonFile($"{AppDomain.CurrentDomain.BaseDirectory}IW4MAdminSettings.json")
.Build();
} }
public IList<Server> GetServers() public IList<Server> GetServers()
@ -88,6 +82,27 @@ namespace IW4MAdmin
.ToList(); .ToList();
#endregion #endregion
#region CONFIG
var config = ConfigHandler.Configuration();
if (config?.Servers == null)
{
var newConfig = (ApplicationConfiguration)ConfigHandler.Configuration().Generate();
ConfigHandler.Set(newConfig);
newConfig.AutoMessagePeriod = config.AutoMessagePeriod;
newConfig.AutoMessages = config.AutoMessages;
newConfig.GlobalRules = config.GlobalRules;
newConfig.Maps = config.Maps;
newConfig.Servers = ConfigurationGenerator.GenerateServerConfig(new List<ServerConfiguration>());
config = newConfig;
await ConfigHandler.Save();
}
else if (config.Servers.Count == 0)
throw new ServerException("A server configuration in IW4MAdminSettings.json is invalid");
#region PLUGINS #region PLUGINS
SharedLibrary.Plugins.PluginImporter.Load(this); SharedLibrary.Plugins.PluginImporter.Load(this);
@ -107,26 +122,7 @@ namespace IW4MAdmin
} }
#endregion #endregion
#region CONFIG foreach (var Conf in config.Servers)
BuildConfiguration();
var settings = AppSettings.Get<ApplicationConfiguration>();
if (settings?.Servers == null)
{
var newSettings = ConfigurationGenerator.GenerateApplicationConfig();
newSettings.Servers = ConfigurationGenerator.GenerateServerConfig(new List<ServerConfiguration>());
newSettings.AutoMessagePeriod = settings.AutoMessagePeriod;
newSettings.AutoMessages = settings.AutoMessages;
newSettings.Rules = settings.Rules;
newSettings.Maps = settings.Maps;
settings = newSettings;
var appConfigJSON = JsonConvert.SerializeObject(newSettings, Formatting.Indented);
File.WriteAllText($"{AppDomain.CurrentDomain.BaseDirectory}IW4MAdminSettings.json", appConfigJSON);
BuildConfiguration();
}
foreach (var Conf in settings.Servers)
{ {
try try
{ {
@ -285,6 +281,6 @@ namespace IW4MAdmin
public AliasService GetAliasService() => AliasSvc; public AliasService GetAliasService() => AliasSvc;
public PenaltyService GetPenaltyService() => PenaltySvc; public PenaltyService GetPenaltyService() => PenaltySvc;
public ApplicationConfiguration GetApplicationSettings() => AppSettings.Get<ApplicationConfiguration>(); public IConfigurationHandler<ApplicationConfiguration> GetApplicationSettings() => ConfigHandler;
} }
} }

View File

@ -12,8 +12,9 @@ namespace WebfrontCore.Application.Misc
public static async Task<bool> UsingVPN(string ip, string apiKey) public static async Task<bool> UsingVPN(string ip, string apiKey)
{ {
#if DEBUG #if DEBUG
return false; return await Task.FromResult(false);
#endif
#else
try try
{ {
using (var RequestClient = new System.Net.Http.HttpClient()) using (var RequestClient = new System.Net.Http.HttpClient())
@ -30,6 +31,7 @@ namespace WebfrontCore.Application.Misc
{ {
return false; return false;
} }
#endif
} }
} }
} }

View File

@ -144,8 +144,8 @@ namespace IW4MAdmin
await ExecuteEvent(new Event(Event.GType.Connect, "", player, null, this)); await ExecuteEvent(new Event(Event.GType.Connect, "", player, null, this));
if (!Manager.GetApplicationSettings().EnableClientVPNs && if (!Manager.GetApplicationSettings().Configuration().EnableClientVPNs &&
await VPNCheck.UsingVPN(player.IPAddressString, Manager.GetApplicationSettings().IPHubAPIKey)) await VPNCheck.UsingVPN(player.IPAddressString, Manager.GetApplicationSettings().Configuration().IPHubAPIKey))
{ {
await player.Kick("VPNs are not allowed on this server", new Player() { ClientId = 1 }); await player.Kick("VPNs are not allowed on this server", new Player() { ClientId = 1 });
} }
@ -314,8 +314,8 @@ namespace IW4MAdmin
else if (matchingPlayers.Count == 1) else if (matchingPlayers.Count == 1)
{ {
E.Target = matchingPlayers.First(); E.Target = matchingPlayers.First();
E.Data = Regex.Replace(E.Data, $"{E.Target.Name}", "", RegexOptions.IgnoreCase).Trim(); E.Data = Regex.Replace(E.Data, Regex.Escape($"{E.Target.Name}"), "", RegexOptions.IgnoreCase).Trim();
E.Data = Regex.Replace(E.Data, $"{Args[0]}", "", RegexOptions.IgnoreCase).Trim(); E.Data = Regex.Replace(E.Data, Regex.Escape($"{Args[0]}"), "", RegexOptions.IgnoreCase).Trim();
if ((E.Data.Trim() == E.Target.Name.ToLower().Trim() || if ((E.Data.Trim() == E.Target.Name.ToLower().Trim() ||
E.Data == String.Empty) && E.Data == String.Empty) &&
@ -465,7 +465,9 @@ namespace IW4MAdmin
playerCountStart = DateTime.Now; playerCountStart = DateTime.Now;
} }
if (LastMessage.TotalSeconds > Manager.GetApplicationSettings().AutoMessagePeriod && BroadcastMessages.Count > 0 && ClientNum > 0) if (LastMessage.TotalSeconds > Manager.GetApplicationSettings().Configuration().AutoMessagePeriod
&& BroadcastMessages.Count > 0
&& ClientNum > 0)
{ {
await Broadcast(Utilities.ProcessMessageToken(Manager.GetMessageTokens(), BroadcastMessages[NextMessage])); await Broadcast(Utilities.ProcessMessageToken(Manager.GetMessageTokens(), BroadcastMessages[NextMessage]));
NextMessage = NextMessage == (BroadcastMessages.Count - 1) ? 0 : NextMessage + 1; NextMessage = NextMessage == (BroadcastMessages.Count - 1) ? 0 : NextMessage + 1;
@ -664,7 +666,7 @@ namespace IW4MAdmin
await E.Origin.Tell($"There are ^5{Reports.Count} ^7recent reports"); await E.Origin.Tell($"There are ^5{Reports.Count} ^7recent reports");
// give trusted rank // give trusted rank
if (Manager.GetApplicationSettings().EnableTrustedRank && if (Manager.GetApplicationSettings().Configuration().EnableTrustedRank &&
E.Origin.TotalConnectionTime / 60.0 >= 2880 && E.Origin.TotalConnectionTime / 60.0 >= 2880 &&
E.Origin.Level < Player.Permission.Trusted && E.Origin.Level < Player.Permission.Trusted &&
E.Origin.Level != Player.Permission.Flagged) E.Origin.Level != Player.Permission.Flagged)
@ -960,7 +962,6 @@ namespace IW4MAdmin
{ {
InitializeMaps(); InitializeMaps();
InitializeAutoMessages(); InitializeAutoMessages();
InitializeRules();
return true; return true;
} }
catch (Exception E) catch (Exception E)
@ -968,7 +969,6 @@ namespace IW4MAdmin
Logger.WriteError("Unable to reload configs! - " + E.Message); Logger.WriteError("Unable to reload configs! - " + E.Message);
BroadcastMessages = new List<String>(); BroadcastMessages = new List<String>();
Maps = new List<Map>(); Maps = new List<Map>();
Rules = new List<String>();
return false; return false;
} }
} }

View File

@ -22,7 +22,8 @@ namespace WebfrontCore.Controllers
Manager.AdministratorIPs.Contains(context.HttpContext.Connection.RemoteIpAddress.ToString().ConvertToIP()); Manager.AdministratorIPs.Contains(context.HttpContext.Connection.RemoteIpAddress.ToString().ConvertToIP());
ViewBag.Authorized = Authorized; ViewBag.Authorized = Authorized;
ViewBag.Url = Startup.Configuration["Web:Address"]; ViewBag.Url = Startup.Configuration["Web:Address"];
ViewBag.DiscordLink = Manager.GetApplicationSettings().DiscordInviteCode; string inviteLink = Manager.GetApplicationSettings().Configuration().DiscordInviteCode;
ViewBag.DiscordLink = inviteLink.Contains("http") ? inviteLink : $"https://discordapp.com/invite/{inviteLink}";
base.OnActionExecuting(context); base.OnActionExecuting(context);
} }
} }

View File

@ -1,19 +1,17 @@
{ {
"AutoMessagePeriod": 60, "AutoMessagePeriod": 60,
"AutoMessages": [ "AutoMessages": [
"Over ^5{{TOTALPLAYTIME}} ^7man hours have been played on this server!",
"This server uses ^5IW4M Admin v{{VERSION}} ^7get it at ^5raidmax.org/IW4MAdmin", "This server uses ^5IW4M Admin v{{VERSION}} ^7get it at ^5raidmax.org/IW4MAdmin",
"^5IW4M Admin ^7sees ^5YOU!", "^5IW4M Admin ^7sees ^5YOU!",
"This server has harvested the information of ^5{{TOTALPLAYERS}} ^7players!", "This server has seen a total of ^5{{TOTALPLAYERS}} ^7players!",
"Cheaters are ^1unwelcome ^7 on this server", "Cheaters are ^1unwelcome ^7 on this server",
"Did you know 8/10 people agree with unverified statistics?", "Did you know 8/10 people agree with unverified statistics?"
"^5{{TOTALKILLS}} ^7innocent people have been murdered in this server!"
], ],
"Rules": [ "GlobalRules": [
"Cheating/Exploiting is not allowed", "Cheating/Exploiting is not allowed",
"Respect other players", "Respect other players",
"Administrators have the final say", "Administrators have the final say",
"No Racism or excessive trolling", "No racism or excessive trolling",
"Keep grenade launcher use to a minimum", "Keep grenade launcher use to a minimum",
"Balance teams at ALL times" "Balance teams at ALL times"
], ],

View File

@ -21,7 +21,8 @@ namespace WebfrontCore
.AddEnvironmentVariables(); .AddEnvironmentVariables();
Configuration = builder.Build(); Configuration = builder.Build();
IW4MAdmin.Program.Start(); if (!IW4MAdmin.Program.Start())
Environment.Exit(-1);
} }
public static IConfigurationRoot Configuration { get; private set; } public static IConfigurationRoot Configuration { get; private set; }

View File

@ -70,7 +70,7 @@
</ItemGroup> </ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent"> <Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="xcopy /Y &quot;$(SolutionDir)BUILD\Plugins&quot; &quot;$(TargetDir)Plugins\&quot;&#xD;&#xA;xcopy /Y /I /E &quot;$(SolutionDir)BUILD\Lib&quot; &quot;$(TargetDir)&quot; &#xD;&#xA;" /> <Exec Command="xcopy /Y &quot;$(SolutionDir)BUILD\Plugins&quot; &quot;$(TargetDir)Plugins\&quot;&#xD;&#xA;" />
</Target> </Target>
</Project> </Project>

View File

@ -76,6 +76,7 @@ function refreshClientActivity() {
cache: false cache: false
}) })
.done(function (response) { .done(function (response) {
//const clientCount = $(response).find('.col-6 span').length;
$('#server_clientactivity_' + serverId).html(response); $('#server_clientactivity_' + serverId).html(response);
}) })
.fail(function (jqxhr, textStatus, error) { .fail(function (jqxhr, textStatus, error) {

View File

@ -2,7 +2,8 @@ Version 1.6:
CHANGELOG: CHANGELOG:
-migrated from SQLite to EntityFramework -migrated from SQLite to EntityFramework
-migrated from kayak to ASP.Net Core MVC -migrated from kayak to ASP.Net Core MVC
-webfront redone using boostrap and now mobile-friendly -webfront redone using bootstrap and now mobile-friendly
-moved configuration files into IW4MAdminSettings.json
-added profile page to view client history -added profile page to view client history
-got rid of pesky "error on character" message -got rid of pesky "error on character" message
-optimizations to commands -optimizations to commands