diff --git a/Application/Application.csproj b/Application/Application.csproj index e46d20c11..8ef18759a 100644 --- a/Application/Application.csproj +++ b/Application/Application.csproj @@ -92,6 +92,6 @@ - + diff --git a/Application/BuildScripts/PostPublish.bat b/Application/BuildScripts/PostPublish.bat index a8d975aad..807ee448c 100644 --- a/Application/BuildScripts/PostPublish.bat +++ b/Application/BuildScripts/PostPublish.bat @@ -1,6 +1,8 @@ set SolutionDir=%1 set ProjectDir=%2 set TargetDir=%3 +set CurrentConfiguration=%4 +SET COPYCMD=/Y echo Deleting extra language files @@ -54,9 +56,41 @@ del "%SolutionDir%Publish\Windows\*pdb" if exist "%SolutionDir%Publish\WindowsPrerelease\web.config" del "%SolutionDir%Publish\WindowsPrerelease\web.config" del "%SolutionDir%Publish\WindowsPrerelease\*pdb" -echo making start scripts -@echo dotnet IW4MAdmin.dll > "%SolutionDir%Publish\WindowsPrerelease\StartIW4MAdmin.cmd" -@echo dotnet IW4MAdmin.dll > "%SolutionDir%Publish\Windows\StartIW4MAdmin.cmd" +echo setting up library folders -@(echo #!/bin/bash && echo dotnet IW4MAdmin.dll) > "%SolutionDir%Publish\WindowsPrerelease\StartIW4MAdmin.sh" -@(echo #!/bin/bash && echo dotnet IW4MAdmin.dll) > "%SolutionDir%Publish\Windows\StartIW4MAdmin.sh" +echo PR-Config +if not exist "%SolutionDir%Publish\WindowsPrerelease\Configuration" md "%SolutionDir%Publish\WindowsPrerelease\Configuration" +move "%SolutionDir%Publish\WindowsPrerelease\DefaultSettings.json" "%SolutionDir%Publish\WindowsPrerelease\Configuration\" + +if "%CurrentConfiguration" == "Release" ( + echo R-Config + if not exist "%SolutionDir%Publish\Windows\Configuration" md "%SolutionDir%Publish\Windows\Configuration" + if exist "%SolutionDir%Publish\Windows\DefaultSettings.json" move "%SolutionDir%Publish\Windows\DefaultSettings.json" "%SolutionDir%Publish\Windows\Configuration\DefaultSettings.json" +) + +echo PR-LIB +if not exist "%SolutionDir%Publish\WindowsPrerelease\Lib\" md "%SolutionDir%Publish\WindowsPrerelease\Lib\" +move "%SolutionDir%Publish\WindowsPrerelease\*.dll" "%SolutionDir%Publish\WindowsPrerelease\Lib\" +move "%SolutionDir%Publish\WindowsPrerelease\*.json" "%SolutionDir%Publish\WindowsPrerelease\Lib\" + +if "%CurrentConfiguration" == "Release" ( + echo R-LIB + if not exist "%SolutionDir%Publish\Windows\Lib\" md "%SolutionDir%Publish\Windows\Lib\" + move "%SolutionDir%Publish\Windows\*.dll" "%SolutionDir%Publish\Windows\Lib\" + move "%SolutionDir%Publish\Windows\*.json" "%SolutionDir%Publish\Windows\Lib\" +) + +echo PR-RT +move "%SolutionDir%Publish\WindowsPrerelease\runtimes" "%SolutionDir%Publish\WindowsPrerelease\Lib\runtimes" + +if "%CurrentConfiguration" == "Release" ( + echo R-RT + rem move "%SolutionDir%Publish\Windows\runtimes" "%SolutionDir%Publish\Windows\Lib\runtimes" +) + +echo making start scripts +@echo dotnet Lib/IW4MAdmin.dll > "%SolutionDir%Publish\WindowsPrerelease\StartIW4MAdmin.cmd" +@echo dotnet Lib/IW4MAdmin.dll > "%SolutionDir%Publish\Windows\StartIW4MAdmin.cmd" + +@(echo #!/bin/bash && echo dotnet Lib\IW4MAdmin.dll) > "%SolutionDir%Publish\WindowsPrerelease\StartIW4MAdmin.sh" +@(echo #!/bin/bash && echo dotnet Lib\IW4MAdmin.dll) > "%SolutionDir%Publish\Windows\StartIW4MAdmin.sh" diff --git a/Application/Logger.cs b/Application/Logger.cs index d11a8b56e..0f3597f1e 100644 --- a/Application/Logger.cs +++ b/Application/Logger.cs @@ -22,7 +22,7 @@ namespace IW4MAdmin.Application public Logger(string fn) { - FileName = fn; + FileName = Path.Join("Log", fn); ThreadLock = new object(); if (File.Exists(fn)) File.Delete(fn); diff --git a/Application/Main.cs b/Application/Main.cs index 550731de5..6b945d875 100644 --- a/Application/Main.cs +++ b/Application/Main.cs @@ -16,13 +16,12 @@ namespace IW4MAdmin.Application public class Program { static public double Version { get; private set; } - static public ApplicationManager ServerManager = ApplicationManager.GetInstance(); - public static string OperatingDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + Path.DirectorySeparatorChar; + static public ApplicationManager ServerManager; private static ManualResetEventSlim OnShutdownComplete = new ManualResetEventSlim(); public static void Main(string[] args) { - AppDomain.CurrentDomain.SetData("DataDirectory", OperatingDirectory); + AppDomain.CurrentDomain.SetData("DataDirectory", Utilities.OperatingDirectory); Console.OutputEncoding = Encoding.UTF8; Console.ForegroundColor = ConsoleColor.Gray; @@ -169,15 +168,25 @@ namespace IW4MAdmin.Application private static void OnCancelKey(object sender, ConsoleCancelEventArgs e) { ServerManager.Stop(); - OnShutdownComplete.Wait(5000); + OnShutdownComplete.Wait(); } static void CheckDirectories() { - string curDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + Path.DirectorySeparatorChar; + if (!Directory.Exists(Path.Join(Utilities.OperatingDirectory, "Plugins"))) + { + Directory.CreateDirectory(Path.Join(Utilities.OperatingDirectory, "Plugins")); + } - if (!Directory.Exists($"{curDirectory}Plugins")) - Directory.CreateDirectory($"{curDirectory}Plugins"); + if (!Directory.Exists(Path.Join(Utilities.OperatingDirectory, "Database"))) + { + Directory.CreateDirectory(Path.Join(Utilities.OperatingDirectory, "Database")); + } + + if (!Directory.Exists(Path.Join(Utilities.OperatingDirectory, "Log"))) + { + Directory.CreateDirectory(Path.Join(Utilities.OperatingDirectory, "Log")); + } } } } diff --git a/Application/Manager.cs b/Application/Manager.cs index fccaf38de..d81cf80b9 100644 --- a/Application/Manager.cs +++ b/Application/Manager.cs @@ -18,6 +18,7 @@ using SharedLibraryCore.Database; using SharedLibraryCore.Events; using IW4MAdmin.Application.API.Master; +using IW4MAdmin.Application.Migration; namespace IW4MAdmin.Application { @@ -51,7 +52,9 @@ namespace IW4MAdmin.Application private ApplicationManager() { - Logger = new Logger($@"{Utilities.OperatingDirectory}IW4MAdmin.log"); + Logger = new Logger("IW4MAdmin.log"); + // do any needed migrations + ConfigurationMigration.MoveConfigFolder10518(Logger); _servers = new List(); Commands = new List(); TaskStatuses = new List(); diff --git a/Application/Migration/ConfigurationMigration.cs b/Application/Migration/ConfigurationMigration.cs new file mode 100644 index 000000000..2745d1d13 --- /dev/null +++ b/Application/Migration/ConfigurationMigration.cs @@ -0,0 +1,53 @@ +using SharedLibraryCore; +using SharedLibraryCore.Interfaces; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +namespace IW4MAdmin.Application.Migration +{ + /// + /// helps facilitate the migration of configs from one version and or location + /// to another + /// + class ConfigurationMigration + { + /// + /// moves existing configs from the root folder into a configs folder + /// + public static void MoveConfigFolder10518(ILogger log) + { + string currentDirectory = Utilities.OperatingDirectory; + + // we don't want to do this for migrations or tests where the + // property isn't initialized or it's wrong + if (currentDirectory != null) + { + string configDirectory = Path.Join(currentDirectory, "Configuration"); + + if (!Directory.Exists(configDirectory)) + { + log.WriteDebug($"Creating directory for configs {configDirectory}"); + Directory.CreateDirectory(configDirectory); + } + + var configurationFiles = Directory.EnumerateFiles(currentDirectory, "*.json") + .Select(f => f.Split(Path.DirectorySeparatorChar).Last()) + .Where(f => f.Count(c => c == '.') == 1); + + foreach (var configFile in configurationFiles) + { + log.WriteDebug($"Moving config file {configFile}"); + string destinationPath = Path.Join("Configuration", configFile); + if (!File.Exists(destinationPath)) + { + File.Move(configFile, destinationPath); + } + } + } + } + } +} diff --git a/Plugins/Stats/Helpers/StatManager.cs b/Plugins/Stats/Helpers/StatManager.cs index 3966672ac..ad7f01501 100644 --- a/Plugins/Stats/Helpers/StatManager.cs +++ b/Plugins/Stats/Helpers/StatManager.cs @@ -252,7 +252,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers if (playerStats.ContainsKey(pl.ClientId)) { Log.WriteWarning($"Duplicate ClientId in stats {pl.ClientId}"); - return null; + return playerStats[pl.ClientId]; } // get the client's stats from the database if it exists, otherwise create and attach a new one @@ -281,20 +281,35 @@ namespace IW4MAdmin.Plugins.Stats.Helpers }; // insert if they've not been added - clientStatsSvc.Insert(clientStats); + clientStats = clientStatsSvc.Insert(clientStats); + + if (!playerStats.TryAdd(clientStats.ClientId, clientStats)) + { + Log.WriteWarning("Adding new client to stats failed"); + } + await clientStatsSvc.SaveChangesAsync(); } + else + { + if (!playerStats.TryAdd(clientStats.ClientId, clientStats)) + { + Log.WriteWarning("Adding pre-existing client to stats failed"); + } + } + // migration for previous existing stats if (clientStats.HitLocations.Count == 0) { - clientStats.HitLocations = Enum.GetValues(typeof(IW4Info.HitLocation)).OfType().Select(hl => new EFHitLocationCount() - { - Active = true, - HitCount = 0, - Location = hl - }) - .ToList(); + clientStats.HitLocations = Enum.GetValues(typeof(IW4Info.HitLocation)).OfType() + .Select(hl => new EFHitLocationCount() + { + Active = true, + HitCount = 0, + Location = hl + }) + .ToList(); await statsSvc.ClientStatSvc.SaveChangesAsync(); } @@ -315,14 +330,12 @@ namespace IW4MAdmin.Plugins.Stats.Helpers clientStats.SessionScore = pl.Score; clientStats.LastScore = pl.Score; - Log.WriteInfo($"Adding {pl} to stats"); - - if (!playerStats.TryAdd(pl.ClientId, clientStats)) - Log.WriteDebug($"Could not add client to stats {pl}"); - if (!detectionStats.TryAdd(pl.ClientId, new Cheat.Detection(Log, clientStats))) - Log.WriteDebug("Could not add client to detection"); + { + Log.WriteWarning("Could not add client to detection"); + } + Log.WriteInfo($"Adding {pl} to stats"); return clientStats; } @@ -473,7 +486,6 @@ namespace IW4MAdmin.Plugins.Stats.Helpers var clientStats = Servers[serverId].PlayerStats[attacker.ClientId]; var clientStatsSvc = statsSvc.ClientStatSvc; clientStatsSvc.Update(clientStats); - // increment their hit count if (hit.DeathType == IW4Info.MeansOfDeath.MOD_PISTOL_BULLET || @@ -496,8 +508,8 @@ namespace IW4MAdmin.Plugins.Stats.Helpers if (Plugin.Config.Configuration().EnableAntiCheat) { - await ApplyPenalty(clientDetection.ProcessKill(hit, isDamage), clientDetection, attacker, ctx); - await ApplyPenalty(clientDetection.ProcessTotalRatio(clientStats), clientDetection, attacker, ctx); + ApplyPenalty(clientDetection.ProcessKill(hit, isDamage), clientDetection, attacker, ctx); + ApplyPenalty(clientDetection.ProcessTotalRatio(clientStats), clientDetection, attacker, ctx); } ctx.Set().UpdateRange(clientStats.HitLocations); @@ -526,7 +538,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers } } - async Task ApplyPenalty(Cheat.DetectionPenaltyResult penalty, Cheat.Detection clientDetection, Player attacker, DatabaseContext ctx) + void ApplyPenalty(Cheat.DetectionPenaltyResult penalty, Cheat.Detection clientDetection, Player attacker, DatabaseContext ctx) { switch (penalty.ClientPenalty) { @@ -546,7 +558,9 @@ namespace IW4MAdmin.Plugins.Stats.Helpers $"{penalty.Type}-{(int)penalty.Location}-{Math.Round(penalty.Value, 2)}@{penalty.HitCount}" : $"{penalty.Type}-{Math.Round(penalty.Value, 2)}@{penalty.HitCount}", } - } + }, + Level = Player.Permission.Console, + CurrentServer = attacker.CurrentServer }); if (clientDetection.Tracker.HasChanges) { @@ -558,30 +572,23 @@ namespace IW4MAdmin.Plugins.Stats.Helpers { break; } - var e = new GameEvent() - { - Data = penalty.Type == Cheat.Detection.DetectionType.Bone ? + + string flagReason = penalty.Type == Cheat.Detection.DetectionType.Bone ? $"{penalty.Type}-{(int)penalty.Location}-{Math.Round(penalty.Value, 2)}@{penalty.HitCount}" : - $"{penalty.Type}-{Math.Round(penalty.Value, 2)}@{penalty.HitCount}", - Origin = new Player() - { - ClientId = 1, - Level = Player.Permission.Console, - ClientNumber = -1, - CurrentServer = attacker.CurrentServer - }, - Target = attacker, - Owner = attacker.CurrentServer, - Type = GameEvent.EventType.Flag - }; - // because we created an event it must be processed by the manager - // even if it didn't really do anything - Manager.GetEventHandler().AddEvent(e); - await new CFlag().ExecuteAsync(e); + $"{penalty.Type}-{Math.Round(penalty.Value, 2)}@{penalty.HitCount}"; + + attacker.Flag(flagReason, new Player() + { + ClientId = 1, + Level = Player.Permission.Console, + CurrentServer = attacker.CurrentServer, + }); + if (clientDetection.Tracker.HasChanges) { SaveTrackedSnapshots(clientDetection, ctx); } + break; } } diff --git a/Plugins/Stats/Plugin.cs b/Plugins/Stats/Plugin.cs index 6b473c6dc..88132ad67 100644 --- a/Plugins/Stats/Plugin.cs +++ b/Plugins/Stats/Plugin.cs @@ -231,7 +231,8 @@ namespace IW4MAdmin.Plugins.Stats new ProfileMeta() { Key = "Hit Offset Average", - Value = $"{Math.Round(((float)hitOffsetAverage), 4)}°", + // todo: make sure this is wrapped somewhere else + Value = $"{Math.Round(((float)hitOffsetAverage), 4).ToString(new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName))}°", Sensitive = true }, new ProfileMeta() diff --git a/SharedLibraryCore/Database/DatabaseContext.cs b/SharedLibraryCore/Database/DatabaseContext.cs index ca63ae56b..8739bb525 100644 --- a/SharedLibraryCore/Database/DatabaseContext.cs +++ b/SharedLibraryCore/Database/DatabaseContext.cs @@ -24,7 +24,6 @@ namespace SharedLibraryCore.Database public DbSet EFMeta { get; set; } public DbSet EFChangeHistory { get; set; } - static string _ConnectionString; static string _provider; @@ -52,21 +51,17 @@ namespace SharedLibraryCore.Database { if (string.IsNullOrEmpty(_ConnectionString)) { - string currentPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase); + string currentPath = Utilities.OperatingDirectory; // allows the application to find the database file currentPath = !RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? $"{Path.DirectorySeparatorChar}{currentPath}" : currentPath; - var connectionStringBuilder = new SqliteConnectionStringBuilder { DataSource = $"{currentPath}{Path.DirectorySeparatorChar}Database.db".Substring(6) }; + var connectionStringBuilder = new SqliteConnectionStringBuilder { DataSource = $"{currentPath}{Path.DirectorySeparatorChar}Database{Path.DirectorySeparatorChar}Database.db" }; var connectionString = connectionStringBuilder.ToString(); var connection = new SqliteConnection(connectionString); - //#if DEBUG == true - //optionsBuilder.UseMySql("UserId=root;Password=dev;Host=127.0.0.1;port=3306;Database=IW4MAdmin"); - // optionsBuilder.UseNpgsql("UserId=dev;Password=dev;Host=127.0.0.1;port=5432;Database=IW4MAdmin"); - //#else + optionsBuilder.UseSqlite(connection); - //#endif } else diff --git a/SharedLibraryCore/Helpers/BaseConfigurationHandler.cs b/SharedLibraryCore/Helpers/BaseConfigurationHandler.cs index ba49667b4..3780f1572 100644 --- a/SharedLibraryCore/Helpers/BaseConfigurationHandler.cs +++ b/SharedLibraryCore/Helpers/BaseConfigurationHandler.cs @@ -25,7 +25,7 @@ namespace SharedLibraryCore.Configuration public void Build() { ConfigurationRoot = new ConfigurationBuilder() - .AddJsonFile($"{AppDomain.CurrentDomain.BaseDirectory}{Filename}.json", true) + .AddJsonFile(Path.Join(Utilities.OperatingDirectory, "Configuration", $"{Filename}.json"), true) .Build(); _configuration = ConfigurationRoot.Get(); @@ -37,10 +37,7 @@ namespace SharedLibraryCore.Configuration public Task Save() { var appConfigJSON = JsonConvert.SerializeObject(_configuration, Formatting.Indented); - return Task.Factory.StartNew(() => - { - File.WriteAllText($"{AppDomain.CurrentDomain.BaseDirectory}{Filename}.json", appConfigJSON); - }); + return File.WriteAllTextAsync(Path.Join(AppDomain.CurrentDomain.BaseDirectory, "Configuration", $"{Filename}.json"), appConfigJSON); } public T Configuration() => _configuration; diff --git a/SharedLibraryCore/SharedLibraryCore.csproj b/SharedLibraryCore/SharedLibraryCore.csproj index 6e1126566..489c781d4 100644 --- a/SharedLibraryCore/SharedLibraryCore.csproj +++ b/SharedLibraryCore/SharedLibraryCore.csproj @@ -23,9 +23,9 @@ - - - + + + diff --git a/SharedLibraryCore/Utilities.cs b/SharedLibraryCore/Utilities.cs index 9655ea9f7..82ce9ad0e 100644 --- a/SharedLibraryCore/Utilities.cs +++ b/SharedLibraryCore/Utilities.cs @@ -20,7 +20,11 @@ namespace SharedLibraryCore { public static class Utilities { - public static string OperatingDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + Path.DirectorySeparatorChar; +#if DEBUG == true + public static string OperatingDirectory => $"{Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)}{Path.DirectorySeparatorChar}"; +#else + public static string OperatingDirectory => $"{Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)}{Path.DirectorySeparatorChar}..{Path.DirectorySeparatorChar}"; +#endif public static Encoding EncodingType; public static Localization.Layout CurrentLocalization = new Localization.Layout(new Dictionary()); public static Player IW4MAdminClient = new Player() { ClientId = 1, Level = Player.Permission.Console }; diff --git a/WebfrontCore/Program.cs b/WebfrontCore/Program.cs index 05f537396..661538ba6 100644 --- a/WebfrontCore/Program.cs +++ b/WebfrontCore/Program.cs @@ -30,7 +30,7 @@ namespace WebfrontCore #if DEBUG .UseContentRoot(Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), @"..\..\..\..\", "WebfrontCore"))) #else - .UseContentRoot(Directory.GetCurrentDirectory()) + .UseContentRoot(Path.Join(Directory.GetCurrentDirectory(), "..\\")) #endif .UseUrls(Manager.GetApplicationSettings().Configuration().WebfrontBindUrl) .UseKestrel()