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

View File

@ -31,7 +31,7 @@ namespace StatsPlugin.Cheat
public const int HighSampleMinKills = 100;
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)
{

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

View File

@ -10,55 +10,20 @@ namespace StatsPlugin.Helpers
{
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>
/// Get a message from the configuration encouraging or discouraging clients
/// </summary>
/// <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>
/// <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 deathstreakMessage = config.GetProperty<Dictionary<int, string>>("DeathstreakMessages");
var killstreakMessage = Plugin.Config.Configuration().KillstreakMessages;
var deathstreakMessage = Plugin.Config.Configuration().DeathstreakMessages;
string message = "";
if (killstreakMessage.ContainsKey(killStreak))
message =killstreakMessage[killStreak];
else if (deathstreakMessage.ContainsKey(deathStreak))
message = deathstreakMessage[deathStreak];
return message;
string message = killstreakMessage.FirstOrDefault(m => m.Count == killStreak)?.Message;
message = (message == null) ? deathstreakMessage.FirstOrDefault(m => m.Count == deathStreak)?.Message : message;
return message ?? "";
}
}
}

View File

@ -5,10 +5,12 @@ using System.Text;
using System.Threading.Tasks;
using SharedLibrary;
using SharedLibrary.Configuration;
using SharedLibrary.Dtos;
using SharedLibrary.Helpers;
using SharedLibrary.Interfaces;
using SharedLibrary.Services;
using StatsPlugin.Config;
using StatsPlugin.Helpers;
using StatsPlugin.Models;
@ -24,6 +26,7 @@ namespace StatsPlugin
public static StatManager Manager { get; private set; }
private IManager ServerManager;
public static BaseConfigurationHandler<StatsConfiguration> Config { get; private set; }
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
async Task<List<ProfileMeta>> getStats(int clientId)
{
@ -203,9 +214,7 @@ namespace StatsPlugin
ServerManager = manager;
return Task.FromResult(
Manager = new StatManager(manager)
);
Manager = new StatManager(manager);
}
public async Task OnTickAsync(Server S)

View File

@ -124,6 +124,8 @@
<Compile Include="Commands\ResetStats.cs" />
<Compile Include="Commands\TopStats.cs" />
<Compile Include="Commands\ViewStats.cs" />
<Compile Include="Config\StreakMessageConfiguration.cs" />
<Compile Include="Config\StatsConfiguration.cs" />
<Compile Include="Helpers\ServerStats.cs" />
<Compile Include="Helpers\StatManager.cs" />
<Compile Include="Helpers\StreakMessage.cs" />
@ -150,11 +152,6 @@
<Name>SharedLibrary</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions">
<Version>1.1.2</Version>
</PackageReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<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.Objects;
using SharedLibrary.Helpers;
using SharedLibrary.Configuration;
namespace Welcome_Plugin
{
@ -64,11 +65,17 @@ namespace Welcome_Plugin
public string Name => "Welcome Plugin";
private Dictionary<int, ConfigurationManager> Configs;
private BaseConfigurationHandler<WelcomeConfiguration> Config;
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()
@ -84,39 +91,15 @@ namespace Welcome_Plugin
if (E.Type == Event.GType.Connect)
{
Player newPlayer = E.Origin;
var cfg = Configs[S.GetHashCode()];
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)
await E.Owner.ToAdmins($"^1NOTICE: ^7Flagged player ^5{newPlayer.Name} ^7has joined!");
else
await E.Owner.Broadcast(ProcessAnnouncement(cfg.GetProperty<string>("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));
}
await E.Owner.Broadcast(ProcessAnnouncement(Config.Configuration().UserAnnouncementMessage, newPlayer));
}
}

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="Plugin.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="WelcomeConfiguration.cs" />
</ItemGroup>
<ItemGroup>
<None Include="GeoIP.dat" />

View File

@ -424,7 +424,7 @@ namespace SharedLibrary.Commands
if (newPerm == Player.Permission.Owner && E.Origin.Level != Player.Permission.Console)
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");
return;
@ -585,7 +585,8 @@ namespace SharedLibrary.Commands
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())
await E.Owner.Broadcast("The server owner has not set any rules");
@ -595,7 +596,12 @@ namespace SharedLibrary.Commands
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())
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
{
public class ApplicationConfiguration
public class ApplicationConfiguration : IBaseConfiguration
{
public bool EnableMultipleOwners { get; set; }
public bool EnableTrustedRank { get; set; }
public bool EnableClientVPNs { get; set; }
public bool EnableAntiCheat { get; set; }
public bool EnableDiscordLink { get; set; }
public string DiscordInviteCode { get; set; }
public string IPHubAPIKey { get; set; }
public List<ServerConfiguration> Servers { get; set; }
public int AutoMessagePeriod { 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 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 string IPAddress { get; set; }
public short Port { 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 DateTime When { get; set; }
public bool Sensitive { get; set; }
public string WhenString => Utilities.GetTimePassed(When, false);
public string Key { 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<Helpers.MessageToken> GetMessageTokens();
IList<Player> GetActiveClients();
ApplicationConfiguration GetApplicationSettings();
IConfigurationHandler<ApplicationConfiguration> GetApplicationSettings();
ClientService GetClientService();
AliasService GetAliasService();
PenaltyService GetPenaltyService();

View File

@ -15,7 +15,6 @@ using SharedLibrary.Configuration;
namespace SharedLibrary
{
[Guid("61d3829e-fcbe-44d3-bb7c-51db8c2d7ac5")]
public abstract class Server
{
public enum Game
@ -44,7 +43,6 @@ namespace SharedLibrary
NextMessage = 0;
InitializeTokens();
InitializeAutoMessages();
InitializeRules();
}
//Returns current server IP set by `net_ip` -- *STRING*
@ -253,7 +251,7 @@ namespace SharedLibrary
protected void InitializeMaps()
{
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>
@ -264,22 +262,11 @@ namespace SharedLibrary
{
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()
{
return $"{IP}_{Port}";
@ -303,10 +290,9 @@ namespace SharedLibrary
public Interfaces.ILogger Logger { get; private set; }
public ServerConfiguration ServerConfig { get; private set; }
public List<Map> Maps { get; protected set; }
public List<string> Rules { get; protected set; }
public List<Report> Reports { get; 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; }
// Info

View File

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

View File

@ -48,6 +48,8 @@ namespace IW4MAdmin
Console.Write("Enter server RCON password: ");
newConfig.Password = Console.ReadLine();
newConfig.AutoMessages = new List<string>();
newConfig.Rules = new List<string>();
configList.Add(newConfig);
@ -57,39 +59,5 @@ namespace IW4MAdmin
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();
public static string OperatingDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + Path.DirectorySeparatorChar;
public static void Start()
public static bool Start()
{
AppDomain.CurrentDomain.SetData("DataDirectory", OperatingDirectory);
System.Diagnostics.Process.GetCurrentProcess().PriorityClass = System.Diagnostics.ProcessPriorityClass.BelowNormal;
@ -66,6 +66,8 @@ namespace IW4MAdmin
Console.WriteLine("Shutdown complete");
});
return true;
}
catch (Exception e)
@ -78,7 +80,7 @@ namespace IW4MAdmin
}
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
return;
return false;
}
}
@ -86,15 +88,6 @@ namespace IW4MAdmin
{
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"))
Directory.CreateDirectory($"{curDirectory}Logs");

View File

@ -37,11 +37,11 @@ namespace IW4MAdmin
ClientService ClientSvc;
AliasService AliasSvc;
PenaltyService PenaltySvc;
IConfigurationRoot AppSettings;
BaseConfigurationHandler<ApplicationConfiguration> ConfigHandler;
#if FTP_LOG
const int UPDATE_FREQUENCY = 700;
#else
const int UPDATE_FREQUENCY = 750;
const int UPDATE_FREQUENCY = 450;
#endif
private ApplicationManager()
@ -56,13 +56,7 @@ namespace IW4MAdmin
PenaltySvc = new PenaltyService();
AdministratorIPs = new List<int>();
ServerEventOccurred += EventAPI.OnServerEventOccurred;
}
private void BuildConfiguration()
{
AppSettings = new ConfigurationBuilder()
.AddJsonFile($"{AppDomain.CurrentDomain.BaseDirectory}IW4MAdminSettings.json")
.Build();
ConfigHandler = new BaseConfigurationHandler<ApplicationConfiguration>("IW4MAdminSettings");
}
public IList<Server> GetServers()
@ -88,6 +82,27 @@ namespace IW4MAdmin
.ToList();
#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
SharedLibrary.Plugins.PluginImporter.Load(this);
@ -107,26 +122,7 @@ namespace IW4MAdmin
}
#endregion
#region CONFIG
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)
foreach (var Conf in config.Servers)
{
try
{
@ -285,6 +281,6 @@ namespace IW4MAdmin
public AliasService GetAliasService() => AliasSvc;
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)
{
#if DEBUG
return false;
#endif
return await Task.FromResult(false);
#else
try
{
using (var RequestClient = new System.Net.Http.HttpClient())
@ -30,6 +31,7 @@ namespace WebfrontCore.Application.Misc
{
return false;
}
#endif
}
}
}

View File

@ -144,8 +144,8 @@ namespace IW4MAdmin
await ExecuteEvent(new Event(Event.GType.Connect, "", player, null, this));
if (!Manager.GetApplicationSettings().EnableClientVPNs &&
await VPNCheck.UsingVPN(player.IPAddressString, Manager.GetApplicationSettings().IPHubAPIKey))
if (!Manager.GetApplicationSettings().Configuration().EnableClientVPNs &&
await VPNCheck.UsingVPN(player.IPAddressString, Manager.GetApplicationSettings().Configuration().IPHubAPIKey))
{
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)
{
E.Target = matchingPlayers.First();
E.Data = Regex.Replace(E.Data, $"{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($"{E.Target.Name}"), "", 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() ||
E.Data == String.Empty) &&
@ -465,7 +465,9 @@ namespace IW4MAdmin
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]));
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");
// give trusted rank
if (Manager.GetApplicationSettings().EnableTrustedRank &&
if (Manager.GetApplicationSettings().Configuration().EnableTrustedRank &&
E.Origin.TotalConnectionTime / 60.0 >= 2880 &&
E.Origin.Level < Player.Permission.Trusted &&
E.Origin.Level != Player.Permission.Flagged)
@ -960,7 +962,6 @@ namespace IW4MAdmin
{
InitializeMaps();
InitializeAutoMessages();
InitializeRules();
return true;
}
catch (Exception E)
@ -968,7 +969,6 @@ namespace IW4MAdmin
Logger.WriteError("Unable to reload configs! - " + E.Message);
BroadcastMessages = new List<String>();
Maps = new List<Map>();
Rules = new List<String>();
return false;
}
}

View File

@ -22,7 +22,8 @@ namespace WebfrontCore.Controllers
Manager.AdministratorIPs.Contains(context.HttpContext.Connection.RemoteIpAddress.ToString().ConvertToIP());
ViewBag.Authorized = Authorized;
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);
}
}

View File

@ -1,19 +1,17 @@
{
"AutoMessagePeriod": 60,
"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",
"^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",
"Did you know 8/10 people agree with unverified statistics?",
"^5{{TOTALKILLS}} ^7innocent people have been murdered in this server!"
"Did you know 8/10 people agree with unverified statistics?"
],
"Rules": [
"GlobalRules": [
"Cheating/Exploiting is not allowed",
"Respect other players",
"Administrators have the final say",
"No Racism or excessive trolling",
"No racism or excessive trolling",
"Keep grenade launcher use to a minimum",
"Balance teams at ALL times"
],

View File

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

View File

@ -70,7 +70,7 @@
</ItemGroup>
<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>
</Project>

View File

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

View File

@ -2,7 +2,8 @@ Version 1.6:
CHANGELOG:
-migrated from SQLite to EntityFramework
-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
-got rid of pesky "error on character" message
-optimizations to commands