From 3bc9c122a23999f732171f35f57fa5bb669ee2b8 Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Fri, 23 May 2025 08:58:34 +0200 Subject: [PATCH 01/11] update subs --- ModdingToolBase | 2 +- src/DevLauncher/Properties/launchSettings.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ModdingToolBase b/ModdingToolBase index 7893e04..91cee75 160000 --- a/ModdingToolBase +++ b/ModdingToolBase @@ -1 +1 @@ -Subproject commit 7893e0437e9bc8880962b1b553839eb9cc57b1e9 +Subproject commit 91cee75996d5fa6483595e8605dcea40def0824e diff --git a/src/DevLauncher/Properties/launchSettings.json b/src/DevLauncher/Properties/launchSettings.json index 98701b1..0707b69 100644 --- a/src/DevLauncher/Properties/launchSettings.json +++ b/src/DevLauncher/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "Build & Run Mod": { "commandName": "Project", - "commandLineArgs": "--verboseBootstrapLogging -verbose --skipUpdate", + "commandLineArgs": "--verboseBootstrapLogging -verbose", "workingDirectory": "C:\\Privat\\Steam\\steamapps\\common\\Star Wars Empire at War\\corruption\\Mods\\republic-at-war" }, "DAT2LocFile": { From 73b667ab53d2c212f5abe0c4c8decd05d0480ef8 Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Fri, 23 May 2025 10:35:36 +0200 Subject: [PATCH 02/11] update sub --- ModdingToolBase | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ModdingToolBase b/ModdingToolBase index 91cee75..044d3cc 160000 --- a/ModdingToolBase +++ b/ModdingToolBase @@ -1 +1 @@ -Subproject commit 91cee75996d5fa6483595e8605dcea40def0824e +Subproject commit 044d3ccad5f33e68c5f5737d273fbe1ed8fd6b88 From 539c7a477c3a38889368819b014d41afda0b05ae Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Sun, 8 Mar 2026 11:22:36 +0100 Subject: [PATCH 03/11] increase git timeout --- src/DevLauncher/Properties/launchSettings.json | 2 +- src/DevLauncher/Services/GitService.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/DevLauncher/Properties/launchSettings.json b/src/DevLauncher/Properties/launchSettings.json index 0707b69..4c349f6 100644 --- a/src/DevLauncher/Properties/launchSettings.json +++ b/src/DevLauncher/Properties/launchSettings.json @@ -17,7 +17,7 @@ }, "Release Republic at War": { "commandName": "Project", - "commandLineArgs": "release --uploaderDir D:\\Modding\\eawuploader --skipUpdate", + "commandLineArgs": "release --uploaderDir E:\\Modding\\eawuploader --skipUpdate", "workingDirectory": "C:\\Program Files (x86)\\Steam\\steamapps\\common\\Star Wars Empire at War\\corruption\\Mods\\Republic_at_War" }, "Merge Diffs into Localization": { diff --git a/src/DevLauncher/Services/GitService.cs b/src/DevLauncher/Services/GitService.cs index bc94c6b..894a8e7 100644 --- a/src/DevLauncher/Services/GitService.cs +++ b/src/DevLauncher/Services/GitService.cs @@ -91,7 +91,7 @@ public void Fetch() }; - if (!Process.Start(startInfo)!.WaitForExit(3000)) + if (!Process.Start(startInfo)!.WaitForExit(10000)) throw new InvalidOperationException("Unable to fetch from origin."); } } \ No newline at end of file From 84aa55872462a56707547386d32bfaa788731caa Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Sun, 8 Mar 2026 12:10:44 +0100 Subject: [PATCH 04/11] update to new libs --- Directory.Build.props | 2 +- ModVerify | 2 +- ModdingToolBase | 2 +- .../DevLauncher.Tests.csproj | 10 +- src/DevLauncher/DevLauncher.csproj | 27 +++-- src/DevLauncher/DevLauncherEnvironment.cs | 5 +- src/DevLauncher/Options/VerifyOption.cs | 6 - .../Pipelines/BuildAndRunPipeline.cs | 3 +- .../Pipelines/BuildAndVerifyPipeline.cs | 80 ------------- src/DevLauncher/Pipelines/BuildPipeline.cs | 106 ++++++++---------- .../Pipelines/ReleaseRawPipeline.cs | 45 ++++---- src/DevLauncher/Pipelines/Steps/LaunchStep.cs | 4 +- src/DevLauncher/Program.cs | 11 +- .../Properties/launchSettings.json | 5 - src/DevLauncher/RawDevLauncher.cs | 14 --- src/MegCompile/MegCompile.csproj | 16 +-- src/RawDevTools/RawDevTools.csproj | 12 +- .../Steps/Build/CleanOutdatedAssetsStep.cs | 24 ++-- .../Steps/Build/CompileLocalizationStep.cs | 13 ++- .../Steps/Build/Meg/PackMegFileStep.cs | 8 +- src/RawDevTools/Steps/Build/PackIconsStep.cs | 8 +- .../Steps/Releasing/CopyReleaseStep.cs | 23 ++-- .../CreateUploadMetaArtifactsStep.cs | 13 ++- src/RawDevTools/Steps/SingleActionPipeline.cs | 21 ++-- src/TextCompile/TextCompile.csproj | 16 +-- 25 files changed, 202 insertions(+), 274 deletions(-) delete mode 100644 src/DevLauncher/Options/VerifyOption.cs delete mode 100644 src/DevLauncher/Pipelines/BuildAndVerifyPipeline.cs diff --git a/Directory.Build.props b/Directory.Build.props index e638e40..f9cd8ce 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -3,7 +3,7 @@ all - 3.7.115 + 3.9.50 \ No newline at end of file diff --git a/ModVerify b/ModVerify index 59b5a3f..4eb6a1c 160000 --- a/ModVerify +++ b/ModVerify @@ -1 +1 @@ -Subproject commit 59b5a3f00b5d5445fecf1c4a1013ce412d47b80f +Subproject commit 4eb6a1c0567b68c6a0f858426c478c7572f4d81c diff --git a/ModdingToolBase b/ModdingToolBase index 044d3cc..e12f6ce 160000 --- a/ModdingToolBase +++ b/ModdingToolBase @@ -1 +1 @@ -Subproject commit 044d3ccad5f33e68c5f5737d273fbe1ed8fd6b88 +Subproject commit e12f6ceedb83fe9e3372dd89c68d508f8479cf92 diff --git a/src/DevLauncher.Tests/DevLauncher.Tests.csproj b/src/DevLauncher.Tests/DevLauncher.Tests.csproj index 65466d9..a54378b 100644 --- a/src/DevLauncher.Tests/DevLauncher.Tests.csproj +++ b/src/DevLauncher.Tests/DevLauncher.Tests.csproj @@ -10,15 +10,15 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/DevLauncher/DevLauncher.csproj b/src/DevLauncher/DevLauncher.csproj index fd9c2b4..106a1a8 100644 --- a/src/DevLauncher/DevLauncher.csproj +++ b/src/DevLauncher/DevLauncher.csproj @@ -19,15 +19,15 @@ - - + + - - + + - - + + @@ -38,14 +38,23 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - all + + + + + + compile + runtime; build; native; contentfiles; analyzers; buildtransitive + + + compile runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/DevLauncher/DevLauncherEnvironment.cs b/src/DevLauncher/DevLauncherEnvironment.cs index 67a4da7..76dc6d5 100644 --- a/src/DevLauncher/DevLauncherEnvironment.cs +++ b/src/DevLauncher/DevLauncherEnvironment.cs @@ -7,14 +7,13 @@ namespace RepublicAtWar.DevLauncher; -internal class DevLauncherEnvironment(Assembly assembly, IFileSystem fileSystem) : UpdatableApplicationEnvironment(assembly, fileSystem) +internal class DevLauncherEnvironment(Assembly assembly, IFileSystem fileSystem) + : UpdatableApplicationEnvironment(assembly, fileSystem) { private const string ToolPathName = "RawDevLauncher"; public override string ApplicationName => "Republic at War DevLauncher"; - public override Uri? RepositoryUrl => null; - public override ICollection UpdateMirrors { get; } = new List { new($"https://republicatwar.com/downloads/{ToolPathName}") diff --git a/src/DevLauncher/Options/VerifyOption.cs b/src/DevLauncher/Options/VerifyOption.cs deleted file mode 100644 index 3dca4d0..0000000 --- a/src/DevLauncher/Options/VerifyOption.cs +++ /dev/null @@ -1,6 +0,0 @@ -using CommandLine; - -namespace RepublicAtWar.DevLauncher.Options; - -[Verb("verify")] -internal class VerifyOption : RaWBuildOption; \ No newline at end of file diff --git a/src/DevLauncher/Pipelines/BuildAndRunPipeline.cs b/src/DevLauncher/Pipelines/BuildAndRunPipeline.cs index c355f5a..68ba836 100644 --- a/src/DevLauncher/Pipelines/BuildAndRunPipeline.cs +++ b/src/DevLauncher/Pipelines/BuildAndRunPipeline.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; using AnakinRaW.CommonUtilities.SimplePipeline; using AnakinRaW.CommonUtilities.SimplePipeline.Steps; @@ -22,7 +23,7 @@ internal class BuildAndRunPipeline( private readonly BuildSettings _buildSettings = buildSettings ?? throw new ArgumentNullException(nameof(buildSettings)); private readonly LaunchSettings _launchSettings = launchSettings ?? throw new ArgumentNullException(nameof(launchSettings)); - protected override Task> BuildSteps() + protected override Task> CreateRunnerSteps(CancellationToken token) { return Task.FromResult>(new List { diff --git a/src/DevLauncher/Pipelines/BuildAndVerifyPipeline.cs b/src/DevLauncher/Pipelines/BuildAndVerifyPipeline.cs deleted file mode 100644 index ff08d20..0000000 --- a/src/DevLauncher/Pipelines/BuildAndVerifyPipeline.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using AET.ModVerify.Pipeline; -using AET.ModVerify.Pipeline.Progress; -using AET.ModVerify.Reporting; -using AET.ModVerify.Reporting.Settings; -using AET.ModVerify.Settings; -using AnakinRaW.CommonUtilities.SimplePipeline; -using AnakinRaW.CommonUtilities.SimplePipeline.Progress; -using AnakinRaW.CommonUtilities.SimplePipeline.Steps; -using Microsoft.Extensions.DependencyInjection; -using PG.StarWarsGame.Engine; -using PG.StarWarsGame.Infrastructure.Games; -using PG.StarWarsGame.Infrastructure.Mods; -using RepublicAtWar.DevTools.Steps.Settings; - -namespace RepublicAtWar.DevLauncher.Pipelines; - -internal class BuildAndVerifyPipeline(IPhysicalMod mod, IGame fallbackGame, BuildSettings buildSettings, IServiceProvider serviceProvider) - : SequentialPipeline(serviceProvider) -{ - public override string ToString() - { - return $"Build & Verify {mod.Name}"; - } - - protected override Task> BuildSteps() - { - return Task.FromResult>(new List - { - new RunPipelineStep(new BuildPipeline(mod, buildSettings, ServiceProvider), ServiceProvider), - new RunPipelineStep(CreateVerifyPipeline(), ServiceProvider), - }); - } - - private GameVerifyPipeline CreateVerifyPipeline() - { - var gameLocations = new GameLocations( - [mod.Directory.FullName], - mod.Game.Directory.FullName, - [fallbackGame.Directory.FullName, LauncherConstants.RaWFallbackAssetPathEaW] - ); - - var settings = new VerifyPipelineSettings - { - GameVerifySettings = GameVerifySettings.Default, - VerifiersProvider = new DefaultGameVerifiersProvider() - }; - - var globalReportSettings = new GlobalVerifyReportSettings - { - Baseline = VerificationBaseline.Empty, - Suppressions = SuppressionList.Empty - }; - - var gameEngineService = ServiceProvider.GetRequiredService(); - - var engineErrorReporter = new ConcurrentGameEngineErrorReporter(); - - var gameEngine = gameEngineService.InitializeAsync( - GameEngineType.Foc, - gameLocations, - engineErrorReporter, - null, - false, - CancellationToken.None).GetAwaiter().GetResult(); - - return new GameVerifyPipeline(gameEngine, engineErrorReporter, settings, globalReportSettings, new NullVerifyProgressReporter(), ServiceProvider); - } - - private class NullVerifyProgressReporter : IVerifyProgressReporter - { - public void Report(double progress, string? progressText, ProgressType type, VerifyProgressInfo detailedProgress) - { - - } - } -} \ No newline at end of file diff --git a/src/DevLauncher/Pipelines/BuildPipeline.cs b/src/DevLauncher/Pipelines/BuildPipeline.cs index 7106e48..b5324e6 100644 --- a/src/DevLauncher/Pipelines/BuildPipeline.cs +++ b/src/DevLauncher/Pipelines/BuildPipeline.cs @@ -1,12 +1,13 @@ using System; using System.Collections.Generic; using System.IO.Abstractions; +using System.Linq; using System.Threading; using System.Threading.Tasks; using AnakinRaW.CommonUtilities.SimplePipeline; using AnakinRaW.CommonUtilities.SimplePipeline.Runners; +using AnakinRaW.CommonUtilities.SimplePipeline.Steps; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using PG.StarWarsGame.Engine; using PG.StarWarsGame.Engine.Localization; using PG.StarWarsGame.Infrastructure.Mods; @@ -17,49 +18,44 @@ namespace RepublicAtWar.DevLauncher.Pipelines; -internal sealed class BuildPipeline(IPhysicalMod mod, BuildSettings settings, IServiceProvider serviceProvider) - : Pipeline(serviceProvider) +internal sealed class BuildPipeline : SequentialPipeline { - private readonly IFileSystem _fileSystem = serviceProvider.GetRequiredService(); + private readonly IFileSystem _fileSystem; - private readonly IGameLanguageManager _languageManager = serviceProvider - .GetRequiredService().GetLanguageManager(GameEngineType.Foc); + private readonly IGameLanguageManager _languageManager; - private readonly BuildSettings _settings = settings ?? throw new ArgumentNullException(nameof(settings)); + private readonly BuildSettings _settings; + private readonly IPhysicalMod _mod; - private readonly List _buildSteps = new(); - private readonly List _preBuildSteps = new(); - - private readonly ParallelStepRunner _buildRunner = new(4, serviceProvider); - private readonly SequentialStepRunner _preBuildRunner = new(serviceProvider); - - protected override bool FailFast => true; + public BuildPipeline(IPhysicalMod mod, BuildSettings settings, IServiceProvider serviceProvider) : base(serviceProvider) + { + _mod = mod; + _fileSystem = serviceProvider.GetRequiredService(); + _languageManager = serviceProvider + .GetRequiredService().GetLanguageManager(GameEngineType.Foc); + _settings = settings ?? throw new ArgumentNullException(nameof(settings)); + FailFast = true; + } public override string ToString() { - return $"Building {mod.Name}"; + return $"Building {_mod.Name}"; } - protected override Task PrepareCoreAsync() + protected override Task> CreateRunnerSteps(CancellationToken token) { - _preBuildSteps.Clear(); - _preBuildSteps.AddRange(CreatePreBuildSteps()); - foreach (var buildStep in _preBuildSteps) - _preBuildRunner.AddStep(buildStep); - - _buildSteps.Clear(); - _buildSteps.AddRange(CreateBuildSteps()); - foreach (var buildStep in _buildSteps) - _buildRunner.AddStep(buildStep); - - return Task.FromResult(true); + return Task.FromResult>(new List + { + new RunPipelineStep(new PreBuildPipeline(this, ServiceProvider), ServiceProvider), + new RunPipelineStep(new CoreBuildPipeline(this, ServiceProvider), ServiceProvider) + }); } private IEnumerable CreateBuildSteps() { - yield return new PackMegFileStep(new RawAiPackMegConfiguration(mod, ServiceProvider), _settings, ServiceProvider); - yield return new PackMegFileStep(new RawCustomMapsPackMegConfiguration(mod, ServiceProvider), _settings, ServiceProvider); - yield return new PackMegFileStep(new RawNonLocalizedSfxMegConfiguration(mod, ServiceProvider), _settings, ServiceProvider); + yield return new PackMegFileStep(new RawAiPackMegConfiguration(_mod, ServiceProvider), _settings, ServiceProvider); + yield return new PackMegFileStep(new RawCustomMapsPackMegConfiguration(_mod, ServiceProvider), _settings, ServiceProvider); + yield return new PackMegFileStep(new RawNonLocalizedSfxMegConfiguration(_mod, ServiceProvider), _settings, ServiceProvider); yield return new PackIconsStep(_settings, ServiceProvider); yield return new CompileLocalizationStep(_settings, ServiceProvider); @@ -72,7 +68,7 @@ private IEnumerable CreateBuildSteps() continue; yield return new PackMegFileStep( - new RawLocalizedSfx2DMegConfiguration(focLanguage, isRaWSupported, mod, ServiceProvider), + new RawLocalizedSfx2DMegConfiguration(focLanguage, isRaWSupported, _mod, ServiceProvider), _settings, ServiceProvider); } @@ -82,44 +78,36 @@ private IList CreatePreBuildSteps() { return new List { - new CleanOutdatedAssetsStep(mod, ServiceProvider) + new CleanOutdatedAssetsStep(_mod, ServiceProvider) }; } - protected override async Task RunCoreAsync(CancellationToken token) + private bool IsSupportedByRaw(LanguageType focLanguage) { - try - { - Logger?.LogInformation("Running Prebuild..."); - _preBuildRunner.Error -= OnError; - await _preBuildRunner.RunAsync(token); - } - finally - { - Logger?.LogInformation("Finished Prebuild..."); - _preBuildRunner.Error -= OnError; - } - - ThrowIfAnyStepsFailed(_preBuildSteps); + var path = _fileSystem.Path.Combine(_mod.Directory.FullName, "Data/Audio/Units", focLanguage.ToString()); + return _fileSystem.Directory.Exists(path); + } - try + private class CoreBuildPipeline(BuildPipeline parent, IServiceProvider serviceProvider) + : StepRunnerPipeline(serviceProvider) + { + protected override Task> CreateRunnerSteps(CancellationToken token) { - Logger?.LogInformation("Running Build..."); - _buildRunner.Error -= OnError; - await _buildRunner.RunAsync(token); + return Task.FromResult>(parent.CreateBuildSteps().ToList()); } - finally + + protected override IStepRunner CreateRunner() { - Logger?.LogInformation("Finished Build..."); - _buildRunner.Error -= OnError; + return new AsyncStepRunner(4, ServiceProvider); } - - ThrowIfAnyStepsFailed(_buildSteps); } - - private bool IsSupportedByRaw(LanguageType focLanguage) + + private class PreBuildPipeline(BuildPipeline parent, IServiceProvider serviceProvider) + : SequentialPipeline(serviceProvider) { - var path = _fileSystem.Path.Combine(mod.Directory.FullName, "Data/Audio/Units", focLanguage.ToString()); - return _fileSystem.Directory.Exists(path); + protected override Task> CreateRunnerSteps(CancellationToken token) + { + return Task.FromResult(parent.CreatePreBuildSteps()); + } } } \ No newline at end of file diff --git a/src/DevLauncher/Pipelines/ReleaseRawPipeline.cs b/src/DevLauncher/Pipelines/ReleaseRawPipeline.cs index 59fdf6e..7260a7e 100644 --- a/src/DevLauncher/Pipelines/ReleaseRawPipeline.cs +++ b/src/DevLauncher/Pipelines/ReleaseRawPipeline.cs @@ -38,32 +38,14 @@ public ReleaseRawPipeline( _empireAtWarGame = empireAtWarGame; _logger = serviceProvider.GetService()?.CreateLogger(GetType()); } - protected override Task RunCoreAsync(CancellationToken token) - { - _logger?.LogInformation("Release Republic at War"); - - if (!_buildSettings.CleanBuild) - { - _logger?.LogWarning("Releasing without Clean build!!!"); - _logger?.LogWarning("Releasing without Clean build!!!"); - _logger?.LogWarning("Releasing without Clean build!!!"); - } - return base.RunCoreAsync(token); - } - protected override void DisposeResources() - { - _progressBarReporter?.Dispose(); - _progressBarReporter = null; - base.DisposeResources(); - } - protected override Task> BuildSteps() + protected override Task> CreateRunnerSteps(CancellationToken token) { return Task.Run>(() => { var createArtifactStep = new CreateUploadMetaArtifactsStep(ServiceProvider); - + var copyStep = new CopyReleaseStep(createArtifactStep, _releaseSettings, ServiceProvider); _progressBarReporter = new(copyStep); @@ -78,6 +60,27 @@ protected override Task> BuildSteps() // Copy to Release copyStep }; - }); + }, CancellationToken.None); + } + + protected override void OnExecuteStarted() + { + base.OnExecuteStarted(); + + _logger?.LogInformation("Release Republic at War"); + + if (!_buildSettings.CleanBuild) + { + _logger?.LogWarning("Releasing without Clean build!!!"); + _logger?.LogWarning("Releasing without Clean build!!!"); + _logger?.LogWarning("Releasing without Clean build!!!"); + } + } + + protected override void DisposeResources() + { + _progressBarReporter?.Dispose(); + _progressBarReporter = null; + base.DisposeResources(); } } \ No newline at end of file diff --git a/src/DevLauncher/Pipelines/Steps/LaunchStep.cs b/src/DevLauncher/Pipelines/Steps/LaunchStep.cs index cb60b1e..7d0d4b1 100644 --- a/src/DevLauncher/Pipelines/Steps/LaunchStep.cs +++ b/src/DevLauncher/Pipelines/Steps/LaunchStep.cs @@ -1,5 +1,6 @@ using System; using System.Threading; +using System.Threading.Tasks; using AET.Modinfo.Model; using AnakinRaW.CommonUtilities.SimplePipeline.Steps; using PG.StarWarsGame.Infrastructure.Clients.Arguments; @@ -14,11 +15,12 @@ internal class LaunchStep(LaunchSettings options, IPhysicalMod mod, IServiceProv { private readonly IPhysicalMod _mod = mod ?? throw new ArgumentNullException(nameof(mod)); - protected override void RunCore(CancellationToken token) + protected override Task RunCoreAsync(CancellationToken token) { var launcher = new GameLauncher(options, _mod, Services); var args = CreateGameArgs(); launcher.Launch(args); + return Task.CompletedTask; } private ArgumentCollection CreateGameArgs() diff --git a/src/DevLauncher/Program.cs b/src/DevLauncher/Program.cs index 9be543b..bac989e 100644 --- a/src/DevLauncher/Program.cs +++ b/src/DevLauncher/Program.cs @@ -107,16 +107,19 @@ private async Task RunAppCoreAsync(string[] args, IServiceProvider appServi } } - protected override void ResetApp(Microsoft.Extensions.Logging.ILogger? logger) + protected override void ResetApp() { - logger?.LogDebug("Resetting Application"); + Logger?.LogDebug("Resetting Application"); + + base.ResetApp(); + var deleteResult = ApplicationEnvironment.ApplicationLocalDirectory.TryDeleteWithRetry(); if (!deleteResult) - logger?.LogWarning("Failed to delete application local directory."); + Logger?.LogWarning("Failed to delete application local directory."); ApplicationEnvironment.ApplicationLocalDirectory.Create(); } - protected override void CreateAppServices(IServiceCollection services, IReadOnlyCollection args) + protected override void CreateAppServices(IServiceCollection services, IReadOnlyList args) { var verboseLogging = false; diff --git a/src/DevLauncher/Properties/launchSettings.json b/src/DevLauncher/Properties/launchSettings.json index 4c349f6..e517f5d 100644 --- a/src/DevLauncher/Properties/launchSettings.json +++ b/src/DevLauncher/Properties/launchSettings.json @@ -24,11 +24,6 @@ "commandName": "Project", "commandLineArgs": "mergeLoc --skipUpdate", "workingDirectory": "C:\\Program Files (x86)\\Steam\\steamapps\\common\\Star Wars Empire at War\\corruption\\Mods\\Republic_at_War" - }, - "Build & Verify Republic at War": { - "commandName": "Project", - "commandLineArgs": "verify --skipUpdate", - "workingDirectory": "C:\\Privat\\Steam\\steamapps\\common\\Star Wars Empire at War\\corruption\\Mods\\republic-at-war" } } } \ No newline at end of file diff --git a/src/DevLauncher/RawDevLauncher.cs b/src/DevLauncher/RawDevLauncher.cs index 17b3145..f74e6fb 100644 --- a/src/DevLauncher/RawDevLauncher.cs +++ b/src/DevLauncher/RawDevLauncher.cs @@ -69,7 +69,6 @@ private async Task UpdateLauncher(IReadOnlyList args) typeof(PrepareLocalizationsOption), typeof(MergeLocalizationOption), typeof(ReleaseRepublicAtWarOption), - typeof(VerifyOption) ]; var parseResult = _looseArgumentParser.ParseArguments(args, optionTypes); @@ -106,9 +105,6 @@ private async Task RunCore(DevToolsOptionBase options) case MergeLocalizationOption: launcherPipeline = new MergeLocalizationsAction(serviceProvider); break; - case VerifyOption verifyOption: - launcherPipeline = CreateBuildVerifyPipeline(verifyOption, gameFinderResult, serviceProvider); - break; default: throw new ArgumentException($"The option '{options.GetType().FullName}' is not implemented", nameof(options)); @@ -127,16 +123,6 @@ private async Task RunCore(DevToolsOptionBase options) } } - private static IPipeline CreateBuildVerifyPipeline(VerifyOption options, GameFinderResult gameFinderResult, IServiceProvider services) - { - var buildSettings = new BuildSettings - { - WarnAsError = options.WarnAsError, - CleanBuild = options.CleanBuild - }; - return new BuildAndVerifyPipeline(gameFinderResult.RepublicAtWar, gameFinderResult.FallbackGame, buildSettings, services); - } - private static IPipeline CreateBuildRunPipeline(BuildAndRunOption options, GameFinderResult gameFinderResult, IServiceProvider services) { var buildSettings = new BuildSettings diff --git a/src/MegCompile/MegCompile.csproj b/src/MegCompile/MegCompile.csproj index f0186c2..3d4808c 100644 --- a/src/MegCompile/MegCompile.csproj +++ b/src/MegCompile/MegCompile.csproj @@ -15,18 +15,18 @@ - - - - - - + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + diff --git a/src/RawDevTools/RawDevTools.csproj b/src/RawDevTools/RawDevTools.csproj index d5cccdf..b47feff 100644 --- a/src/RawDevTools/RawDevTools.csproj +++ b/src/RawDevTools/RawDevTools.csproj @@ -43,13 +43,13 @@ - + - - - - - + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/RawDevTools/Steps/Build/CleanOutdatedAssetsStep.cs b/src/RawDevTools/Steps/Build/CleanOutdatedAssetsStep.cs index af12d65..be76bd8 100644 --- a/src/RawDevTools/Steps/Build/CleanOutdatedAssetsStep.cs +++ b/src/RawDevTools/Steps/Build/CleanOutdatedAssetsStep.cs @@ -1,6 +1,7 @@ using System; using System.IO.Abstractions; using System.Threading; +using System.Threading.Tasks; using AnakinRaW.CommonUtilities.FileSystem; using AnakinRaW.CommonUtilities.SimplePipeline.Steps; using Microsoft.Extensions.DependencyInjection; @@ -15,18 +16,21 @@ public class CleanOutdatedAssetsStep(IPhysicalMod mod, IServiceProvider serviceP { private readonly IFileSystem _fileSystem = serviceProvider.GetRequiredService(); - protected override void RunCore(CancellationToken token) + protected override Task RunCoreAsync(CancellationToken token) { - Logger?.LogInformation("Cleaning outdated assets..."); - var matcher = new Matcher(); - matcher.AddInclude("Data/Audio/SFX/sfx2d_*.meg"); - - foreach (var fileToDelete in matcher.GetResultsInFullPath(mod.Directory.FullName)) + return Task.Run(() => { - Logger?.LogDebug($"Deleting old asset '{fileToDelete}'"); - _fileSystem.File.DeleteWithRetry(fileToDelete); - } + Logger?.LogInformation("Cleaning outdated assets..."); + var matcher = new Matcher(); + matcher.AddInclude("Data/Audio/SFX/sfx2d_*.meg"); + + foreach (var fileToDelete in matcher.GetResultsInFullPath(mod.Directory.FullName)) + { + Logger?.LogDebug($"Deleting old asset '{fileToDelete}'"); + _fileSystem.File.DeleteWithRetry(fileToDelete); + } - Logger?.LogInformation("Finished cleaning outdated assets."); + Logger?.LogInformation("Finished cleaning outdated assets."); + }, CancellationToken.None); } } \ No newline at end of file diff --git a/src/RawDevTools/Steps/Build/CompileLocalizationStep.cs b/src/RawDevTools/Steps/Build/CompileLocalizationStep.cs index 35f5275..d2d0d08 100644 --- a/src/RawDevTools/Steps/Build/CompileLocalizationStep.cs +++ b/src/RawDevTools/Steps/Build/CompileLocalizationStep.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO.Abstractions; using System.Threading; +using System.Threading.Tasks; using AnakinRaW.CommonUtilities.SimplePipeline.Steps; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -15,12 +16,16 @@ public class CompileLocalizationStep(BuildSettings settings, IServiceProvider se private readonly IFileSystem _fileSystem = serviceProvider.GetRequiredService(); private readonly ILogger? _logger = serviceProvider.GetService()?.CreateLogger(typeof(CompileLocalizationStep)); - protected override void RunCore(CancellationToken token) + protected override Task RunCoreAsync(CancellationToken token) { - var localizationFiles = _fileSystem.Directory.EnumerateFiles("Data\\Text", "MasterTextFile_*.txt"); + return Task.Run(() => + { + var localizationFiles = _fileSystem.Directory + .EnumerateFiles("Data\\Text", "MasterTextFile_*.txt"); - foreach (var localizationFile in localizationFiles) - CompileDatFromLocalizationFile(localizationFile); + foreach (var localizationFile in localizationFiles) + CompileDatFromLocalizationFile(localizationFile); + }, CancellationToken.None); } private void CompileDatFromLocalizationFile(string file) diff --git a/src/RawDevTools/Steps/Build/Meg/PackMegFileStep.cs b/src/RawDevTools/Steps/Build/Meg/PackMegFileStep.cs index 1cf5a15..da6f4ef 100644 --- a/src/RawDevTools/Steps/Build/Meg/PackMegFileStep.cs +++ b/src/RawDevTools/Steps/Build/Meg/PackMegFileStep.cs @@ -3,6 +3,7 @@ using System.IO.Abstractions; using System.Linq; using System.Threading; +using System.Threading.Tasks; using AnakinRaW.CommonUtilities.SimplePipeline.Steps; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileSystemGlobbing; @@ -25,7 +26,12 @@ public class PackMegFileStep(IPackMegConfiguration config, BuildSettings setting private readonly IPackMegConfiguration _config = config ?? throw new ArgumentNullException(nameof(config)); - protected override void RunCore(CancellationToken token) + protected override Task RunCoreAsync(CancellationToken token) + { + return Task.Run(() => RunCore(token), CancellationToken.None); + } + + private void RunCore(CancellationToken token) { var matcher = new Matcher(StringComparison.OrdinalIgnoreCase); foreach (var fileToPack in _config.FilesToPack) diff --git a/src/RawDevTools/Steps/Build/PackIconsStep.cs b/src/RawDevTools/Steps/Build/PackIconsStep.cs index 855191f..846e756 100644 --- a/src/RawDevTools/Steps/Build/PackIconsStep.cs +++ b/src/RawDevTools/Steps/Build/PackIconsStep.cs @@ -5,6 +5,7 @@ using System.IO.Abstractions; using System.Reflection; using System.Threading; +using System.Threading.Tasks; using AnakinRaW.CommonUtilities; using AnakinRaW.CommonUtilities.FileSystem; using AnakinRaW.CommonUtilities.SimplePipeline.Steps; @@ -28,7 +29,12 @@ public class PackIconsStep(BuildSettings settings, IServiceProvider serviceProvi private const string DummyMasterTextFileXml = "Data\\Text\\MasterTextFile.xml"; private const string ModCompileExe = "ModCompile.exe"; - protected override void RunCore(CancellationToken token) + protected override Task RunCoreAsync(CancellationToken token) + { + return Task.Run(() => RunCore(token), CancellationToken.None); + } + + private void RunCore(CancellationToken token) { if (!_fileSystem.Directory.Exists(IconsDirectory)) { diff --git a/src/RawDevTools/Steps/Releasing/CopyReleaseStep.cs b/src/RawDevTools/Steps/Releasing/CopyReleaseStep.cs index 6aa4734..1c0c6f9 100644 --- a/src/RawDevTools/Steps/Releasing/CopyReleaseStep.cs +++ b/src/RawDevTools/Steps/Releasing/CopyReleaseStep.cs @@ -75,10 +75,10 @@ private Matcher CreateBlacklist() return matcher; } - protected override void RunCore(CancellationToken token) + protected override async Task RunCoreAsync(CancellationToken token) { - _buildArtifactsStep.Wait(); - + await _buildArtifactsStep; + _logger?.LogInformation("Copying Release to SteamUploader ..."); if (!_fileSystem.Directory.Exists(_settings.UploaderDirectory)) @@ -101,16 +101,13 @@ protected override void RunCore(CancellationToken token) var steamJsonFile = _buildArtifactsStep.SteamJsonName; _fileSystem.File.Copy(steamJsonFile, _fileSystem.Path.Combine(uploaderWsContentPath, steamJsonFile), true); - Task.Run(async () => - { - await new DirectoryCopier(_fileSystem).CopyDirectoryAsync(source, - assetCopyPath, - new CopyProgress(this), - ShallCopyFile, 4, - token); - }, CancellationToken.None) - .Wait(token); - + await new DirectoryCopier(_fileSystem).CopyDirectoryAsync(source, + assetCopyPath, + new CopyProgress(this), + ShallCopyFile, + 4, + token); + _logger?.LogInformation($"Copied assets to SteamUploader at '{assetCopyPath}'"); } diff --git a/src/RawDevTools/Steps/Releasing/CreateUploadMetaArtifactsStep.cs b/src/RawDevTools/Steps/Releasing/CreateUploadMetaArtifactsStep.cs index d139674..af925c1 100644 --- a/src/RawDevTools/Steps/Releasing/CreateUploadMetaArtifactsStep.cs +++ b/src/RawDevTools/Steps/Releasing/CreateUploadMetaArtifactsStep.cs @@ -3,16 +3,18 @@ using System.IO.Abstractions; using System.Text.RegularExpressions; using System.Threading; +using System.Threading.Tasks; using AET.Modinfo.Model; using AET.Modinfo.Spec; using AnakinRaW.CommonUtilities.SimplePipeline.Steps; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Semver; +using ILogger = Microsoft.Extensions.Logging.ILogger; namespace RepublicAtWar.DevTools.Steps.Releasing; -public class CreateUploadMetaArtifactsStep(IServiceProvider serviceProvider) : SynchronizedStep(serviceProvider) +public class CreateUploadMetaArtifactsStep(IServiceProvider serviceProvider) : PipelineStep(serviceProvider) { private readonly IFileSystem _fileSystem = serviceProvider.GetRequiredService(); private readonly ILogger? _logger = serviceProvider.GetService()?.CreateLogger(typeof(CreateUploadMetaArtifactsStep)); @@ -23,7 +25,12 @@ public class CreateUploadMetaArtifactsStep(IServiceProvider serviceProvider) : S internal string SteamJsonName { get; private set; } = null!; - protected override void RunSynchronized(CancellationToken token) + protected override Task RunCoreAsync(CancellationToken token) + { + return Task.Run(() => RunCore(token), CancellationToken.None); + } + + private void RunCore(CancellationToken token) { _logger?.LogInformation("Creating Modinfo, Steam json and splashes..."); @@ -32,7 +39,7 @@ protected override void RunSynchronized(CancellationToken token) _replacementVariables.Add("version-minor", ToMinorOnly(version)); var baseInfo = ModinfoData.Parse(_fileSystem.File.ReadAllText("modinfo-base.json")); - + IModinfo releaseInfo; string steamDescription; if (version.IsPrerelease) diff --git a/src/RawDevTools/Steps/SingleActionPipeline.cs b/src/RawDevTools/Steps/SingleActionPipeline.cs index 3b822c0..1709a3e 100644 --- a/src/RawDevTools/Steps/SingleActionPipeline.cs +++ b/src/RawDevTools/Steps/SingleActionPipeline.cs @@ -8,22 +8,25 @@ namespace RepublicAtWar.DevTools.Steps; -public abstract class SingleActionPipeline(IServiceProvider serviceProvider, bool warningAsError) : SequentialPipeline(serviceProvider) +public abstract class SingleActionPipeline(IServiceProvider serviceProvider, bool warningAsError) + : SequentialPipeline(serviceProvider) { - protected override Task> BuildSteps() + + private class SimpleRunnerStep(Action action, IServiceProvider serviceProvider) + : PipelineStep(serviceProvider) { - return Task.FromResult>(new List + protected override Task RunCoreAsync(CancellationToken token) { - new SimpleRunnerStep(RunAction, ServiceProvider) - }); + return Task.Run(() => action(token), CancellationToken.None); + } } - private class SimpleRunnerStep(Action action, IServiceProvider serviceProvider) : PipelineStep(serviceProvider) + protected override Task> CreateRunnerSteps(CancellationToken token) { - protected override void RunCore(CancellationToken token) + return Task.FromResult>(new List { - action(token); - } + new SimpleRunnerStep(RunAction, ServiceProvider) + }); } protected abstract void RunAction(CancellationToken cancellationToken); diff --git a/src/TextCompile/TextCompile.csproj b/src/TextCompile/TextCompile.csproj index 5c129c8..e060ac5 100644 --- a/src/TextCompile/TextCompile.csproj +++ b/src/TextCompile/TextCompile.csproj @@ -15,18 +15,18 @@ - - - - - - + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + From 4ce8bd27b6eccba1ce1d37b1c6cf349d0d58ff43 Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Sun, 8 Mar 2026 12:19:51 +0100 Subject: [PATCH 05/11] prettier logging --- .../Pipelines/Actions/CreateLocalizationDiffsAction.cs | 2 +- .../Pipelines/Actions/InitializeLocalizationAction.cs | 4 ++-- src/DevLauncher/Program.cs | 4 ++-- src/DevLauncher/Update/RawDevLauncherUpdater.cs | 2 +- src/RawDevTools/Localization/LocalizationFileValidator.cs | 2 +- src/RawDevTools/Services/LocalizationFileService.cs | 3 ++- src/RawDevTools/Services/ModFinderService.cs | 6 ++++-- src/RawDevTools/Steps/Build/CleanOutdatedAssetsStep.cs | 2 +- src/RawDevTools/Steps/Build/CompileLocalizationStep.cs | 6 +++--- .../Build/Meg/Config/RawLocalizedSFX2DMegConfiguration.cs | 4 ++-- src/RawDevTools/Steps/Build/Meg/PackMegFileStep.cs | 6 +++--- src/RawDevTools/Steps/Releasing/CopyReleaseStep.cs | 2 +- 12 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/DevLauncher/Pipelines/Actions/CreateLocalizationDiffsAction.cs b/src/DevLauncher/Pipelines/Actions/CreateLocalizationDiffsAction.cs index 3c27909..8689dd9 100644 --- a/src/DevLauncher/Pipelines/Actions/CreateLocalizationDiffsAction.cs +++ b/src/DevLauncher/Pipelines/Actions/CreateLocalizationDiffsAction.cs @@ -44,7 +44,7 @@ protected override void RunAction(CancellationToken cancellationToken) if (locFile.Language == LanguageType.English) continue; - Logger?.LogInformation($"Creating Diff for data '{langFile}'"); + Logger?.LogInformation("Creating Diff for data '{LangFile}'", langFile); var masterText = _localizationFileService.CreateModelFromLocalizationFile(locFile); diff --git a/src/DevLauncher/Pipelines/Actions/InitializeLocalizationAction.cs b/src/DevLauncher/Pipelines/Actions/InitializeLocalizationAction.cs index 71caca3..58c5aa0 100644 --- a/src/DevLauncher/Pipelines/Actions/InitializeLocalizationAction.cs +++ b/src/DevLauncher/Pipelines/Actions/InitializeLocalizationAction.cs @@ -31,7 +31,7 @@ internal class InitializeLocalizationAction(IServiceProvider serviceProvider) : protected override void RunAction(CancellationToken cancellationToken) { - Logger?.LogInformation($"Processing data '{EnglishDAT}'"); + Logger?.LogInformation("Processing data '{DatFile}'", EnglishDAT); var englishMtfPath = _fileSystem.Path.Combine("Data\\Text", EnglishDAT); var englishMasterText = _datFileService.LoadAs(englishMtfPath, DatFileType.OrderedByCrc32).Content; @@ -40,7 +40,7 @@ protected override void RunAction(CancellationToken cancellationToken) foreach (var datFile in datFiles) { - Logger?.LogInformation($"Processing data '{_fileSystem.Path.GetFileName(datFile)}'"); + Logger?.LogInformation("Processing data '{FileName}'", _fileSystem.Path.GetFileName(datFile)); var language = _localizationFileService.LanguageNameFromFileName(datFile.AsSpan()); diff --git a/src/DevLauncher/Program.cs b/src/DevLauncher/Program.cs index bac989e..d1a5347 100644 --- a/src/DevLauncher/Program.cs +++ b/src/DevLauncher/Program.cs @@ -87,7 +87,7 @@ private async Task RunAppCoreAsync(string[] args, IServiceProvider appServi { var returnCode = await new RawDevLauncher(UpdatableApplicationEnvironment!, appServiceProvider) .RunAsync(args); - logger?.LogInformation($"RaW DevLauncher finished with code: {returnCode}"); + logger?.LogInformation("RaW DevLauncher finished with code: {ExitCode}", returnCode); return returnCode; } catch (Exception e) @@ -109,7 +109,7 @@ private async Task RunAppCoreAsync(string[] args, IServiceProvider appServi protected override void ResetApp() { - Logger?.LogDebug("Resetting Application"); + Logger?.LogDebug("Resetting Application..."); base.ResetApp(); diff --git a/src/DevLauncher/Update/RawDevLauncherUpdater.cs b/src/DevLauncher/Update/RawDevLauncherUpdater.cs index 4785455..ac4d185 100644 --- a/src/DevLauncher/Update/RawDevLauncherUpdater.cs +++ b/src/DevLauncher/Update/RawDevLauncherUpdater.cs @@ -34,7 +34,7 @@ public async Task AutoUpdateApplication(ProductBranch branch) { Console.ForegroundColor = ConsoleColor.DarkRed; Console.WriteLine($"Error while {currentAction}: {e.Message}"); - Logger?.LogError(e, $"Unable to check for updates: {e.Message}"); + Logger?.LogError(e, "Unable to check for updates: {Message}", e.Message); Console.ResetColor(); } } diff --git a/src/RawDevTools/Localization/LocalizationFileValidator.cs b/src/RawDevTools/Localization/LocalizationFileValidator.cs index 1bf9a9c..5c0d5fe 100644 --- a/src/RawDevTools/Localization/LocalizationFileValidator.cs +++ b/src/RawDevTools/Localization/LocalizationFileValidator.cs @@ -121,7 +121,7 @@ public LanguageType GetLanguage(string language) { LogOrThrow($"Unrecognized language '{language}'"); // If we don't throw, we return English - _logger?.LogWarning($"Language '{language}' is not supported. Fallback to English!"); + _logger?.LogWarning("Language '{Language}' is not supported. Fallback to English!", language); } return languageType; } diff --git a/src/RawDevTools/Services/LocalizationFileService.cs b/src/RawDevTools/Services/LocalizationFileService.cs index c98e411..3c1aba3 100644 --- a/src/RawDevTools/Services/LocalizationFileService.cs +++ b/src/RawDevTools/Services/LocalizationFileService.cs @@ -104,7 +104,8 @@ public void CompileLocalizationFile(LocalizationFile localizationFile, string da { var result = builder.AddEntry(entry.Key, entry.Value); if (!result.Added) - _logger?.LogWarning($"Unable to add KEY '{entry.Key}' to the DAT for language {localizationFile.Language}: {result.Message}"); + _logger?.LogWarning("Unable to add KEY '{Key}' to the DAT for language {Language}: {Message}", + entry.Key, localizationFile.Language, result.Message); } builder.Build(new DatFileInformation { FilePath = _fileSystem.Path.GetFullPath(datFile) }, overwrite); diff --git a/src/RawDevTools/Services/ModFinderService.cs b/src/RawDevTools/Services/ModFinderService.cs index 540b88b..3363ba5 100644 --- a/src/RawDevTools/Services/ModFinderService.cs +++ b/src/RawDevTools/Services/ModFinderService.cs @@ -52,7 +52,8 @@ public GameFinderResult FindAndAddModInCurrentDirectory() if (focDetectionResult.GameLocation is null) throw new GameException("Unable to find game installation: Wrong install path?"); - _logger?.LogInformation($"Found game {focDetectionResult.GameIdentity} at '{focDetectionResult.GameLocation.FullName}'"); + _logger?.LogInformation("Found game {GameIdentity} at '{Name}'", + focDetectionResult.GameIdentity, focDetectionResult.GameLocation.FullName); var foc = _gameFactory.CreateGame(focDetectionResult, CultureInfo.InvariantCulture); @@ -69,7 +70,8 @@ public GameFinderResult FindAndAddModInCurrentDirectory() var eawDetectionResult = gd.Detect(GameType.Eaw); if (eawDetectionResult.GameLocation is null) throw new GameException("Unable to find Empire at War installation."); - _logger?.LogInformation($"Found game {eawDetectionResult.GameIdentity} at '{eawDetectionResult.GameLocation.FullName}'"); + _logger?.LogInformation("Found game {GameIdentity} at '{Name}'", + eawDetectionResult.GameIdentity, eawDetectionResult.GameLocation.FullName); var eaw = _gameFactory.CreateGame(eawDetectionResult, CultureInfo.InvariantCulture); diff --git a/src/RawDevTools/Steps/Build/CleanOutdatedAssetsStep.cs b/src/RawDevTools/Steps/Build/CleanOutdatedAssetsStep.cs index be76bd8..d2bbdc6 100644 --- a/src/RawDevTools/Steps/Build/CleanOutdatedAssetsStep.cs +++ b/src/RawDevTools/Steps/Build/CleanOutdatedAssetsStep.cs @@ -26,7 +26,7 @@ protected override Task RunCoreAsync(CancellationToken token) foreach (var fileToDelete in matcher.GetResultsInFullPath(mod.Directory.FullName)) { - Logger?.LogDebug($"Deleting old asset '{fileToDelete}'"); + Logger?.LogDebug("Deleting old asset '{File}'", fileToDelete); _fileSystem.File.DeleteWithRetry(fileToDelete); } diff --git a/src/RawDevTools/Steps/Build/CompileLocalizationStep.cs b/src/RawDevTools/Steps/Build/CompileLocalizationStep.cs index d2d0d08..5262dfb 100644 --- a/src/RawDevTools/Steps/Build/CompileLocalizationStep.cs +++ b/src/RawDevTools/Steps/Build/CompileLocalizationStep.cs @@ -36,11 +36,11 @@ private void CompileDatFromLocalizationFile(string file) var updateChecker = new TimeStampBasesUpdateChecker(settings.CleanBuild, Services); if (!settings.CleanBuild && !updateChecker.RequiresUpdate(datFilePath, new List { file })) { - _logger?.LogDebug($"DAT data '{datFileName}' is already up to date. Skipping build."); + _logger?.LogDebug("DAT data '{DatFile}' is already up to date. Skipping build.", datFileName); return; } - _logger?.LogInformation($"Writing DAT data '{datFileName}'..."); + _logger?.LogInformation("Writing DAT data '{DatFile}'...", datFileName); var locFileService = new LocalizationFileService(Services, settings.WarnAsError); @@ -51,6 +51,6 @@ private void CompileDatFromLocalizationFile(string file) locFileService.CompileLocalizationFile(localizationFile, datFilePath, true); - _logger?.LogInformation($"Finished writing DAT data for language {localizationFile.Language}"); + _logger?.LogInformation("Finished writing DAT data for language {Language}", localizationFile.Language); } } \ No newline at end of file diff --git a/src/RawDevTools/Steps/Build/Meg/Config/RawLocalizedSFX2DMegConfiguration.cs b/src/RawDevTools/Steps/Build/Meg/Config/RawLocalizedSFX2DMegConfiguration.cs index 65a22e7..491cde6 100644 --- a/src/RawDevTools/Steps/Build/Meg/Config/RawLocalizedSFX2DMegConfiguration.cs +++ b/src/RawDevTools/Steps/Build/Meg/Config/RawLocalizedSFX2DMegConfiguration.cs @@ -54,7 +54,7 @@ private IEnumerable GetFilesToPack() if (IsLanguageSupported) throw new DirectoryNotFoundException($"Unable to find SFX directory: '{path}'"); - Logger?.LogDebug($"Unsupported Language {_language} - Switching to English"); + Logger?.LogDebug("Unsupported Language {Language} - Switching to English", _language); path = $"Data\\Audio\\Units\\{LanguageType.English}"; } @@ -71,7 +71,7 @@ private string LocalizeFileName(string fileName) { var newFileName = _gameLanguageManager.LocalizeFileName(fileName, _language, out var localized); if (!localized) - Logger?.LogWarning($"Unable to localize file '{fileName}'"); + Logger?.LogWarning("Unable to localize file '{File}'", fileName); return newFileName; } } \ No newline at end of file diff --git a/src/RawDevTools/Steps/Build/Meg/PackMegFileStep.cs b/src/RawDevTools/Steps/Build/Meg/PackMegFileStep.cs index da6f4ef..866b3be 100644 --- a/src/RawDevTools/Steps/Build/Meg/PackMegFileStep.cs +++ b/src/RawDevTools/Steps/Build/Meg/PackMegFileStep.cs @@ -48,11 +48,11 @@ private void RunCore(CancellationToken token) if (!settings.CleanBuild && !updateChecker.RequiresUpdate(megFilePath, files)) { - _logger?.LogDebug($"MEG data '{megFileName}' is already up to date. Skipping build."); + _logger?.LogDebug("MEG data '{MegFile}' is already up to date. Skipping build.", megFileName); return; } - _logger?.LogInformation($"Writing MEG data '{megFileName}'..."); + _logger?.LogInformation("Writing MEG data '{MegFile}'...", megFileName); using var megBuilder = new EmpireAtWarMegBuilder(_config.VirtualRootDirectory.FullName, _serviceProvider); @@ -76,6 +76,6 @@ private void RunCore(CancellationToken token) } megBuilder.Build(new MegFileInformation(megFilePath, MegFileVersion.V1), true); - _logger?.LogInformation($"Finished writing MEG data '{megFileName}'..."); + _logger?.LogInformation("Finished writing MEG data '{MegFile}'...", megFileName); } } \ No newline at end of file diff --git a/src/RawDevTools/Steps/Releasing/CopyReleaseStep.cs b/src/RawDevTools/Steps/Releasing/CopyReleaseStep.cs index 1c0c6f9..32bda17 100644 --- a/src/RawDevTools/Steps/Releasing/CopyReleaseStep.cs +++ b/src/RawDevTools/Steps/Releasing/CopyReleaseStep.cs @@ -108,7 +108,7 @@ protected override async Task RunCoreAsync(CancellationToken token) 4, token); - _logger?.LogInformation($"Copied assets to SteamUploader at '{assetCopyPath}'"); + _logger?.LogInformation("Copied assets to SteamUploader at '{Path}'", assetCopyPath); } private bool ShallCopyFile(string fileToCopy) From 7dea09fe458dea11c22d60ed7d8872ca0bd4ac77 Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Sun, 8 Mar 2026 13:07:22 +0100 Subject: [PATCH 06/11] draft new make all apps compile --- RawDevTools.sln | 11 +---- src/DevLauncher/DevLauncher.csproj | 1 - src/DevLauncher/Program.cs | 5 +-- src/MegCompile/MegCompile.csproj | 3 +- src/MegCompile/PackSfxMegPipeline.cs | 44 +++++++++---------- src/MegCompile/Program.cs | 3 +- .../Services/RepublicAtWarService.cs | 28 ++++++++++++ src/TextCompile/CompileTextDiffsPipeline.cs | 16 +++++-- src/TextCompile/MergeDiffIntoDatStep.cs | 5 ++- 9 files changed, 71 insertions(+), 45 deletions(-) create mode 100644 src/RawDevTools/Services/RepublicAtWarService.cs diff --git a/RawDevTools.sln b/RawDevTools.sln index 6f4e119..6f39e92 100644 --- a/RawDevTools.sln +++ b/RawDevTools.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.6.33626.354 +# Visual Studio Version 18 +VisualStudioVersion = 18.4.11519.219 insiders MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevLauncher", "src\DevLauncher\DevLauncher.csproj", "{1BA491BC-2CD6-4270-9573-5FF9529D8D89}" EndProject @@ -39,8 +39,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PG.StarWarsGame.Files.ALO", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PG.StarWarsGame.Engine", "ModVerify\src\PetroglyphTools\PG.StarWarsGame.Engine\PG.StarWarsGame.Engine.csproj", "{301A0BA8-303F-415E-A961-4755FB3978D8}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ModVerify.CliApp", "ModVerify\src\ModVerify.CliApp\ModVerify.CliApp.csproj", "{C5703F53-DC3D-4B4E-9E18-365124C72793}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RawDevTools", "src\RawDevTools\RawDevTools.csproj", "{E4F63116-B94A-43FB-ABA9-B9D491D9F6D9}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TextCompile", "src\TextCompile\TextCompile.csproj", "{50E34854-BF6B-4170-BB4C-74830AB5609B}" @@ -113,10 +111,6 @@ Global {301A0BA8-303F-415E-A961-4755FB3978D8}.Debug|Any CPU.Build.0 = Debug|Any CPU {301A0BA8-303F-415E-A961-4755FB3978D8}.Release|Any CPU.ActiveCfg = Release|Any CPU {301A0BA8-303F-415E-A961-4755FB3978D8}.Release|Any CPU.Build.0 = Release|Any CPU - {C5703F53-DC3D-4B4E-9E18-365124C72793}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C5703F53-DC3D-4B4E-9E18-365124C72793}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C5703F53-DC3D-4B4E-9E18-365124C72793}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C5703F53-DC3D-4B4E-9E18-365124C72793}.Release|Any CPU.Build.0 = Release|Any CPU {E4F63116-B94A-43FB-ABA9-B9D491D9F6D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E4F63116-B94A-43FB-ABA9-B9D491D9F6D9}.Debug|Any CPU.Build.0 = Debug|Any CPU {E4F63116-B94A-43FB-ABA9-B9D491D9F6D9}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -163,7 +157,6 @@ Global {D6AC444F-5CC4-4DAC-B974-E3E64B9761A3} = {FF4C3704-0C74-40B5-A38D-AF29B6385D85} {94267A81-F31C-4381-9E2B-868C0AC0E65A} = {FF4C3704-0C74-40B5-A38D-AF29B6385D85} {301A0BA8-303F-415E-A961-4755FB3978D8} = {FF4C3704-0C74-40B5-A38D-AF29B6385D85} - {C5703F53-DC3D-4B4E-9E18-365124C72793} = {D4C9B8AA-96E5-49F4-B8A4-765144E16548} {50E34854-BF6B-4170-BB4C-74830AB5609B} = {5A7785E7-C59E-4F2D-9596-352844693272} {BB759AD8-EEAC-4994-80A8-34E60B2FDA86} = {5A7785E7-C59E-4F2D-9596-352844693272} {846253D9-D766-8852-74B9-E1E04B9F2A81} = {3E986062-E81F-4833-A127-24FA73FBCB1B} diff --git a/src/DevLauncher/DevLauncher.csproj b/src/DevLauncher/DevLauncher.csproj index 106a1a8..6f7f992 100644 --- a/src/DevLauncher/DevLauncher.csproj +++ b/src/DevLauncher/DevLauncher.csproj @@ -60,7 +60,6 @@ - diff --git a/src/DevLauncher/Program.cs b/src/DevLauncher/Program.cs index d1a5347..50944ba 100644 --- a/src/DevLauncher/Program.cs +++ b/src/DevLauncher/Program.cs @@ -1,5 +1,4 @@ -using AET.ModVerify.Reporting.Reporters; -using AET.SteamAbstraction; +using AET.SteamAbstraction; using AnakinRaW.ApplicationBase; using AnakinRaW.ApplicationBase.Environment; using AnakinRaW.ApplicationBase.Update; @@ -145,8 +144,6 @@ protected override void CreateAppServices(IServiceCollection services, IReadOnly PetroglyphCommons.ContributeServices(services); PetroglyphEngineServiceContribution.ContributeServices(services); - services.RegisterJsonReporter(); - services.RegisterTextFileReporter(); services.AddSingleton(sp => new GitService(".", sp)); diff --git a/src/MegCompile/MegCompile.csproj b/src/MegCompile/MegCompile.csproj index 3d4808c..b319200 100644 --- a/src/MegCompile/MegCompile.csproj +++ b/src/MegCompile/MegCompile.csproj @@ -12,7 +12,8 @@ $(SolutionDir)RAW.ico - + disable + diff --git a/src/MegCompile/PackSfxMegPipeline.cs b/src/MegCompile/PackSfxMegPipeline.cs index f799c3f..d50d45f 100644 --- a/src/MegCompile/PackSfxMegPipeline.cs +++ b/src/MegCompile/PackSfxMegPipeline.cs @@ -1,47 +1,43 @@ -using System; -using System.Collections.Generic; -using System.IO.Abstractions; -using System.Threading.Tasks; +using AET.Modinfo.Spec; using AnakinRaW.CommonUtilities.SimplePipeline; -using Microsoft.Extensions.DependencyInjection; -using PG.StarWarsGame.Engine; -using PG.StarWarsGame.Engine.Localization; +using AnakinRaW.CommonUtilities.SimplePipeline.Runners; using PG.StarWarsGame.Infrastructure.Mods; +using RepublicAtWar.DevTools.Services; using RepublicAtWar.DevTools.Steps.Build.Meg; using RepublicAtWar.DevTools.Steps.Build.Meg.Config; using RepublicAtWar.DevTools.Steps.Settings; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; namespace RepublicAtWar.MegCompile; -internal class PackSfxMegPipeline(IPhysicalMod mod, BuildSettings settings, IServiceProvider serviceProvider) : ParallelPipeline(serviceProvider, 2) +internal class PackSfxMegPipeline(IPhysicalMod mod, BuildSettings settings, IServiceProvider serviceProvider) + : StepRunnerPipeline(serviceProvider) { - private readonly IFileSystem _fileSystem = serviceProvider.GetRequiredService(); - - protected override Task> BuildSteps() + private readonly RepublicAtWarService _republicAtWarService = new(serviceProvider); + + protected override IStepRunner CreateRunner() { - var languageManager = ServiceProvider.GetRequiredService() - .GetLanguageManager(GameEngineType.Foc); + return new AsyncStepRunner(2, ServiceProvider); + } + protected override Task> CreateRunnerSteps(CancellationToken token) + { IList steps = new List(); - foreach (var focLanguage in languageManager.SupportedLanguages) + foreach (var supportedLanguage in _republicAtWarService.GetSupportedLanguages()) { - var isRaWSupported = IsSupportedByRaw(focLanguage); + var hasSfxSupport = supportedLanguage.support.HasFlag(LanguageSupportLevel.SFX); // There is no need to build non-supported languages if we don't do a release or force a clean build - if (!isRaWSupported) + if (!hasSfxSupport) continue; steps.Add(new PackMegFileStep( - new RawLocalizedSfx2DMegConfiguration(focLanguage, isRaWSupported, mod, ServiceProvider), settings, + new RawLocalizedSfx2DMegConfiguration(supportedLanguage.langauge, hasSfxSupport, mod, ServiceProvider), settings, ServiceProvider)); } - return Task.FromResult(steps); } - - private bool IsSupportedByRaw(LanguageType focLanguage) - { - var path = _fileSystem.Path.Combine(mod.Directory.FullName, "Data/Audio/Units", focLanguage.ToString()); - return _fileSystem.Directory.Exists(path); - } } \ No newline at end of file diff --git a/src/MegCompile/Program.cs b/src/MegCompile/Program.cs index 9f9ac26..c55a61c 100644 --- a/src/MegCompile/Program.cs +++ b/src/MegCompile/Program.cs @@ -48,7 +48,8 @@ static async Task Main() private async Task Run() { var gameFinderResult = new ModFinderService(serviceProvider).FindAndAddModInCurrentDirectory(); - var pipeline = new PackSfxMegPipeline(gameFinderResult.RepublicAtWar, new BuildSettings { CleanBuild = true }, serviceProvider); + var pipeline = new PackSfxMegPipeline(gameFinderResult.RepublicAtWar, + new BuildSettings { CleanBuild = true }, serviceProvider); await pipeline.RunAsync(); } diff --git a/src/RawDevTools/Services/RepublicAtWarService.cs b/src/RawDevTools/Services/RepublicAtWarService.cs new file mode 100644 index 0000000..383d086 --- /dev/null +++ b/src/RawDevTools/Services/RepublicAtWarService.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using AET.Modinfo.Spec; +using Microsoft.Extensions.DependencyInjection; +using PG.StarWarsGame.Engine; +using PG.StarWarsGame.Engine.Localization; + +namespace RepublicAtWar.DevTools.Services; + +public sealed class RepublicAtWarService(IServiceProvider serviceProvider) +{ + private readonly IGameLanguageManager _languageManager = serviceProvider + .GetRequiredService().GetLanguageManager(GameEngineType.Foc); + + public IEnumerable<(LanguageType langauge, LanguageSupportLevel support)> GetSupportedLanguages() + { + var supportedLanguages = _languageManager.SupportedLanguages; + + foreach (var language in supportedLanguages) + { + if (language is LanguageType.English or LanguageType.German) + yield return (language, LanguageSupportLevel.FullLocalized); + else + yield return (language, LanguageSupportLevel.Text); + } + } +} \ No newline at end of file diff --git a/src/TextCompile/CompileTextDiffsPipeline.cs b/src/TextCompile/CompileTextDiffsPipeline.cs index e2efe7f..ed6e2dd 100644 --- a/src/TextCompile/CompileTextDiffsPipeline.cs +++ b/src/TextCompile/CompileTextDiffsPipeline.cs @@ -1,19 +1,27 @@ using System; using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; using AnakinRaW.CommonUtilities.SimplePipeline; using RepublicAtWar.DevTools.Steps.Settings; namespace RepublicAtWar.TextCompile; -internal class CompileTextDiffsPipeline(BuildSettings settings, IServiceProvider serviceProvider, bool failFast = true) - : SequentialPipeline(serviceProvider, failFast) +internal class CompileTextDiffsPipeline : SequentialPipeline { - protected override Task> BuildSteps() + private readonly BuildSettings _settings; + + public CompileTextDiffsPipeline(BuildSettings settings, IServiceProvider serviceProvider) : base(serviceProvider) + { + _settings = settings; + FailFast = true; + } + + protected override Task> CreateRunnerSteps(CancellationToken token) { IList steps = new List { - new MergeDiffIntoDatStep(ServiceProvider, settings) + new MergeDiffIntoDatStep(ServiceProvider, _settings) }; return Task.FromResult(steps); } diff --git a/src/TextCompile/MergeDiffIntoDatStep.cs b/src/TextCompile/MergeDiffIntoDatStep.cs index 93527b1..ecf9c31 100644 --- a/src/TextCompile/MergeDiffIntoDatStep.cs +++ b/src/TextCompile/MergeDiffIntoDatStep.cs @@ -3,6 +3,7 @@ using System.IO.Abstractions; using System.Linq; using System.Threading; +using System.Threading.Tasks; using AnakinRaW.CommonUtilities.SimplePipeline.Steps; using Microsoft.Extensions.DependencyInjection; using PG.StarWarsGame.Engine.Localization; @@ -19,7 +20,7 @@ internal class MergeDiffIntoDatStep(IServiceProvider serviceProvider, BuildSetti private readonly LocalizationFileService _localizationFileService = new(serviceProvider, buildSettings.WarnAsError); - protected override void RunCore(CancellationToken token) + protected override Task RunCoreAsync(CancellationToken token) { var diffFiles = _fileSystem.Directory.EnumerateFiles("Data\\Text", "Diff_MasterTextFile_*.txt"); var textFiles = _fileSystem.Directory.EnumerateFiles("Data\\Text", "MasterTextFile_*.txt"); @@ -33,6 +34,8 @@ protected override void RunCore(CancellationToken token) var locFile = _localizationFileService.ReadLocalizationFile(textFile); _localizationFileService.CompileLocalizationFile(locFile, datFile , true); } + + return Task.CompletedTask; } private void MergeDiffIntoDatOrText(string diffFile) From a1d1112531fd6cb7f489f96b3010af062a49d5b4 Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Sun, 8 Mar 2026 13:08:18 +0100 Subject: [PATCH 07/11] draft localization verify --- src/DevLauncher/Pipelines/BuildPipeline.cs | 32 ++++++----------- .../Pipelines/ReleaseRawPipeline.cs | 34 +++++++++++++++---- .../CreateUploadMetaArtifactsStep.cs | 7 +--- .../Steps/Releasing/VerifyLocalizationStep.cs | 31 +++++++++++++++++ 4 files changed, 69 insertions(+), 35 deletions(-) create mode 100644 src/RawDevTools/Steps/Releasing/VerifyLocalizationStep.cs diff --git a/src/DevLauncher/Pipelines/BuildPipeline.cs b/src/DevLauncher/Pipelines/BuildPipeline.cs index b5324e6..a5369f7 100644 --- a/src/DevLauncher/Pipelines/BuildPipeline.cs +++ b/src/DevLauncher/Pipelines/BuildPipeline.cs @@ -1,16 +1,14 @@ using System; using System.Collections.Generic; -using System.IO.Abstractions; using System.Linq; using System.Threading; using System.Threading.Tasks; +using AET.Modinfo.Spec; using AnakinRaW.CommonUtilities.SimplePipeline; using AnakinRaW.CommonUtilities.SimplePipeline.Runners; using AnakinRaW.CommonUtilities.SimplePipeline.Steps; -using Microsoft.Extensions.DependencyInjection; -using PG.StarWarsGame.Engine; -using PG.StarWarsGame.Engine.Localization; using PG.StarWarsGame.Infrastructure.Mods; +using RepublicAtWar.DevTools.Services; using RepublicAtWar.DevTools.Steps.Build; using RepublicAtWar.DevTools.Steps.Build.Meg; using RepublicAtWar.DevTools.Steps.Build.Meg.Config; @@ -20,20 +18,16 @@ namespace RepublicAtWar.DevLauncher.Pipelines; internal sealed class BuildPipeline : SequentialPipeline { - private readonly IFileSystem _fileSystem; - - private readonly IGameLanguageManager _languageManager; - + private readonly RepublicAtWarService _republicAtWarService; private readonly BuildSettings _settings; private readonly IPhysicalMod _mod; + public BuildPipeline(IPhysicalMod mod, BuildSettings settings, IServiceProvider serviceProvider) : base(serviceProvider) { _mod = mod; - _fileSystem = serviceProvider.GetRequiredService(); - _languageManager = serviceProvider - .GetRequiredService().GetLanguageManager(GameEngineType.Foc); _settings = settings ?? throw new ArgumentNullException(nameof(settings)); + _republicAtWarService = new RepublicAtWarService(serviceProvider); FailFast = true; } @@ -58,17 +52,17 @@ private IEnumerable CreateBuildSteps() yield return new PackMegFileStep(new RawNonLocalizedSfxMegConfiguration(_mod, ServiceProvider), _settings, ServiceProvider); yield return new PackIconsStep(_settings, ServiceProvider); yield return new CompileLocalizationStep(_settings, ServiceProvider); - - foreach (var focLanguage in _languageManager.SupportedLanguages) + + foreach (var supportedLanguage in _republicAtWarService.GetSupportedLanguages()) { - var isRaWSupported = IsSupportedByRaw(focLanguage); + var hasSfxSupport = supportedLanguage.support.HasFlag(LanguageSupportLevel.SFX); // There is no need to build non-supported languages if we don't do a release or force a clean build - if (!isRaWSupported && !_settings.CleanBuild) + if (!hasSfxSupport && !_settings.CleanBuild) continue; yield return new PackMegFileStep( - new RawLocalizedSfx2DMegConfiguration(focLanguage, isRaWSupported, _mod, ServiceProvider), + new RawLocalizedSfx2DMegConfiguration(supportedLanguage.langauge, hasSfxSupport, _mod, ServiceProvider), _settings, ServiceProvider); } @@ -82,12 +76,6 @@ private IList CreatePreBuildSteps() }; } - private bool IsSupportedByRaw(LanguageType focLanguage) - { - var path = _fileSystem.Path.Combine(_mod.Directory.FullName, "Data/Audio/Units", focLanguage.ToString()); - return _fileSystem.Directory.Exists(path); - } - private class CoreBuildPipeline(BuildPipeline parent, IServiceProvider serviceProvider) : StepRunnerPipeline(serviceProvider) { diff --git a/src/DevLauncher/Pipelines/ReleaseRawPipeline.cs b/src/DevLauncher/Pipelines/ReleaseRawPipeline.cs index 7260a7e..b77a156 100644 --- a/src/DevLauncher/Pipelines/ReleaseRawPipeline.cs +++ b/src/DevLauncher/Pipelines/ReleaseRawPipeline.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; +using AET.Modinfo.Model; using AnakinRaW.CommonUtilities.SimplePipeline; using AnakinRaW.CommonUtilities.SimplePipeline.Steps; using Microsoft.Extensions.DependencyInjection; @@ -11,6 +8,12 @@ using RepublicAtWar.DevLauncher.Utilities; using RepublicAtWar.DevTools.Steps.Releasing; using RepublicAtWar.DevTools.Steps.Settings; +using Semver; +using System; +using System.Collections.Generic; +using System.IO.Abstractions; +using System.Threading; +using System.Threading.Tasks; namespace RepublicAtWar.DevLauncher.Pipelines; @@ -21,9 +24,12 @@ internal class ReleaseRawPipeline : SequentialPipeline private readonly ReleaseSettings _releaseSettings; private readonly IPhysicalMod _republicAtWar; private readonly IGame _empireAtWarGame; + private readonly IFileSystem _fileSystem; private ProgressBarReporter? _progressBarReporter; + private SemVersion _modVersion = null!; + public ReleaseRawPipeline( IPhysicalMod republicAtWar, IGame empireAtWarGame, @@ -37,14 +43,16 @@ public ReleaseRawPipeline( _republicAtWar = republicAtWar ?? throw new ArgumentNullException(nameof(republicAtWar)); _empireAtWarGame = empireAtWarGame; _logger = serviceProvider.GetService()?.CreateLogger(GetType()); + _fileSystem = serviceProvider.GetRequiredService(); } - protected override Task> CreateRunnerSteps(CancellationToken token) { + _modVersion = SemVersion.Parse(_fileSystem.File.ReadAllText("version.txt"), SemVersionStyles.Strict); + return Task.Run>(() => { - var createArtifactStep = new CreateUploadMetaArtifactsStep(ServiceProvider); + var createArtifactStep = new CreateUploadMetaArtifactsStep(_modVersion, ServiceProvider); var copyStep = new CopyReleaseStep(createArtifactStep, _releaseSettings, ServiceProvider); _progressBarReporter = new(copyStep); @@ -55,6 +63,9 @@ protected override Task> CreateRunnerSteps(CancellationToken token) new RunPipelineStep(new BuildPipeline(_republicAtWar, _buildSettings, ServiceProvider), ServiceProvider), // Verify // new RunPipelineStep(new VerifyPipeline(_options, _republicAtWar, _empireAtWarGame, ServiceProvider), ServiceProvider), + + new VerifyLocalizationStep(_republicAtWar, _buildSettings, _modVersion.IsPrerelease, ServiceProvider), + // Build Release artifacts createArtifactStep, // Copy to Release @@ -67,7 +78,7 @@ protected override void OnExecuteStarted() { base.OnExecuteStarted(); - _logger?.LogInformation("Release Republic at War"); + _logger?.LogInformation("Releasing {Raw}...", "Republic at War"); if (!_buildSettings.CleanBuild) { @@ -75,6 +86,15 @@ protected override void OnExecuteStarted() _logger?.LogWarning("Releasing without Clean build!!!"); _logger?.LogWarning("Releasing without Clean build!!!"); } + + if (_modVersion.IsPrerelease) + { + Console.ForegroundColor = ConsoleColor.DarkYellow; + Console.WriteLine("Building a preview version!!!"); + Console.WriteLine("Building a preview version!!!"); + Console.WriteLine("Building a preview version!!!"); + Console.ResetColor(); + } } protected override void DisposeResources() diff --git a/src/RawDevTools/Steps/Releasing/CreateUploadMetaArtifactsStep.cs b/src/RawDevTools/Steps/Releasing/CreateUploadMetaArtifactsStep.cs index af925c1..b394a94 100644 --- a/src/RawDevTools/Steps/Releasing/CreateUploadMetaArtifactsStep.cs +++ b/src/RawDevTools/Steps/Releasing/CreateUploadMetaArtifactsStep.cs @@ -14,7 +14,7 @@ namespace RepublicAtWar.DevTools.Steps.Releasing; -public class CreateUploadMetaArtifactsStep(IServiceProvider serviceProvider) : PipelineStep(serviceProvider) +public class CreateUploadMetaArtifactsStep(SemVersion version, IServiceProvider serviceProvider) : PipelineStep(serviceProvider) { private readonly IFileSystem _fileSystem = serviceProvider.GetRequiredService(); private readonly ILogger? _logger = serviceProvider.GetService()?.CreateLogger(typeof(CreateUploadMetaArtifactsStep)); @@ -34,7 +34,6 @@ private void RunCore(CancellationToken token) { _logger?.LogInformation("Creating Modinfo, Steam json and splashes..."); - var version = SemVersion.Parse(_fileSystem.File.ReadAllText("version.txt"), SemVersionStyles.Strict); _replacementVariables.Add("version", version.ToString()); _replacementVariables.Add("version-minor", ToMinorOnly(version)); @@ -44,10 +43,6 @@ private void RunCore(CancellationToken token) string steamDescription; if (version.IsPrerelease) { - Console.WriteLine("Building a preview version!!!"); - Console.WriteLine("Building a preview version!!!"); - Console.WriteLine("Building a preview version!!!"); - releaseInfo = ModinfoData.Parse(_fileSystem.File.ReadAllText("modinfo-beta.json")); steamDescription = _fileSystem.File.ReadAllText("SteamText-Beta.txt"); _fileSystem.File.Copy("splash-beta.png", "splash.png", true); diff --git a/src/RawDevTools/Steps/Releasing/VerifyLocalizationStep.cs b/src/RawDevTools/Steps/Releasing/VerifyLocalizationStep.cs new file mode 100644 index 0000000..74282d9 --- /dev/null +++ b/src/RawDevTools/Steps/Releasing/VerifyLocalizationStep.cs @@ -0,0 +1,31 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using AnakinRaW.CommonUtilities.SimplePipeline.Steps; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using PG.StarWarsGame.Infrastructure.Mods; +using RepublicAtWar.DevTools.Steps.Settings; + +namespace RepublicAtWar.DevTools.Steps.Releasing; + +public class VerifyLocalizationStep( + IPhysicalMod republicAtWar, + BuildSettings buildSettings, + bool modVersionIsPrerelease, + IServiceProvider serviceProvider) : PipelineStep(serviceProvider) +{ + private readonly ILogger? _logger = + serviceProvider.GetService()?.CreateLogger(typeof(VerifyLocalizationStep)); + + + protected override Task RunCoreAsync(CancellationToken token) + { + return Task.Run(() => RunCore(token), CancellationToken.None); + } + + private void RunCore(CancellationToken token) + { + _logger?.LogInformation("Verifying localization..."); + } +} \ No newline at end of file From 996a9f4950951fcd47ff44e4baeb12fd3092fd22 Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Sun, 8 Mar 2026 15:19:20 +0100 Subject: [PATCH 08/11] add localization verification --- .../Pipelines/ReleaseRawPipeline.cs | 6 +- .../Services/LocalizationFileService.cs | 4 +- .../Steps/Releasing/VerifyLocalizationStep.cs | 275 +++++++++++++++++- 3 files changed, 277 insertions(+), 8 deletions(-) diff --git a/src/DevLauncher/Pipelines/ReleaseRawPipeline.cs b/src/DevLauncher/Pipelines/ReleaseRawPipeline.cs index b77a156..1936d5b 100644 --- a/src/DevLauncher/Pipelines/ReleaseRawPipeline.cs +++ b/src/DevLauncher/Pipelines/ReleaseRawPipeline.cs @@ -44,6 +44,8 @@ public ReleaseRawPipeline( _empireAtWarGame = empireAtWarGame; _logger = serviceProvider.GetService()?.CreateLogger(GetType()); _fileSystem = serviceProvider.GetRequiredService(); + + FailFast = true; } protected override Task> CreateRunnerSteps(CancellationToken token) @@ -64,7 +66,7 @@ protected override Task> CreateRunnerSteps(CancellationToken token) // Verify // new RunPipelineStep(new VerifyPipeline(_options, _republicAtWar, _empireAtWarGame, ServiceProvider), ServiceProvider), - new VerifyLocalizationStep(_republicAtWar, _buildSettings, _modVersion.IsPrerelease, ServiceProvider), + new VerifyLocalizationStep(_republicAtWar, _modVersion.IsPrerelease, ServiceProvider), // Build Release artifacts createArtifactStep, @@ -78,7 +80,7 @@ protected override void OnExecuteStarted() { base.OnExecuteStarted(); - _logger?.LogInformation("Releasing {Raw}...", "Republic at War"); + _logger?.LogInformation("Releasing {Raw} v{Version}...", "Republic at War", _modVersion); if (!_buildSettings.CleanBuild) { diff --git a/src/RawDevTools/Services/LocalizationFileService.cs b/src/RawDevTools/Services/LocalizationFileService.cs index 3c1aba3..0dd727d 100644 --- a/src/RawDevTools/Services/LocalizationFileService.cs +++ b/src/RawDevTools/Services/LocalizationFileService.cs @@ -19,8 +19,8 @@ namespace RepublicAtWar.DevTools.Services; public class LocalizationFileService(IServiceProvider serviceProvider, bool warningAsError = false) { - private const string EnglishDAT = "MasterTextFile_English.DAT"; - private const string EnglishText = "MasterTextFile_English.txt"; + internal const string EnglishDAT = "MasterTextFile_English.DAT"; + internal const string EnglishText = "MasterTextFile_English.txt"; private readonly IServiceProvider _serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); private readonly IFileSystem _fileSystem = serviceProvider.GetRequiredService(); diff --git a/src/RawDevTools/Steps/Releasing/VerifyLocalizationStep.cs b/src/RawDevTools/Steps/Releasing/VerifyLocalizationStep.cs index 74282d9..d59b223 100644 --- a/src/RawDevTools/Steps/Releasing/VerifyLocalizationStep.cs +++ b/src/RawDevTools/Steps/Releasing/VerifyLocalizationStep.cs @@ -1,23 +1,42 @@ using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Abstractions; +using System.Linq; +using System.Text; using System.Threading; using System.Threading.Tasks; using AnakinRaW.CommonUtilities.SimplePipeline.Steps; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using PG.StarWarsGame.Engine; +using PG.StarWarsGame.Engine.Localization; +using PG.StarWarsGame.Files.DAT.Data; +using PG.StarWarsGame.Files.DAT.Files; +using PG.StarWarsGame.Files.DAT.Services; +using PG.StarWarsGame.Files.MEG.Data.Archives; +using PG.StarWarsGame.Files.MEG.Services; using PG.StarWarsGame.Infrastructure.Mods; -using RepublicAtWar.DevTools.Steps.Settings; +using RepublicAtWar.DevTools.Services; namespace RepublicAtWar.DevTools.Steps.Releasing; public class VerifyLocalizationStep( IPhysicalMod republicAtWar, - BuildSettings buildSettings, - bool modVersionIsPrerelease, + bool isPrerelease, IServiceProvider serviceProvider) : PipelineStep(serviceProvider) { private readonly ILogger? _logger = serviceProvider.GetService()?.CreateLogger(typeof(VerifyLocalizationStep)); + private readonly IFileSystem _fileSystem = serviceProvider.GetRequiredService(); + private readonly IDatFileService _datFileService = serviceProvider.GetRequiredService(); + private readonly IDatModelService _datModelService = serviceProvider.GetRequiredService(); + private readonly IMegFileService _megFileService = serviceProvider.GetRequiredService(); + private readonly RepublicAtWarService _republicAtWarService = new(serviceProvider); + private readonly IGameLanguageManager _languageManager = serviceProvider + .GetRequiredService().GetLanguageManager(GameEngineType.Foc); + protected override Task RunCoreAsync(CancellationToken token) { @@ -25,7 +44,255 @@ protected override Task RunCoreAsync(CancellationToken token) } private void RunCore(CancellationToken token) - { + { _logger?.LogInformation("Verifying localization..."); + + var reportBuilder = new StringBuilder(); + var hasErrors = false; + + var supportedLanguages = _republicAtWarService.GetSupportedLanguages() + .Select(x => x.langauge) + .ToList(); + + hasErrors |= VerifyText(reportBuilder, supportedLanguages, token); + hasErrors |= VerifySpeech(reportBuilder, supportedLanguages, token); + hasErrors |= VerifySfx(reportBuilder, supportedLanguages, token); + + var reportPath = _fileSystem.Path.Combine(republicAtWar.Directory.FullName, "localization_verification.txt"); + if (!hasErrors) + { + if (_fileSystem.File.Exists(reportPath)) + _fileSystem.File.Delete(reportPath); + _logger?.LogInformation("Localization verification passed."); + return; + } + + _fileSystem.File.WriteAllText(reportPath, reportBuilder.ToString()); + + LogOrThrow(reportPath); + } + + private void LogOrThrow(string reportPath) + { + if (!isPrerelease) + throw new InvalidOperationException("Localization verification failed. See localization_verification.txt for details."); + _logger?.LogWarning("Localization verification failed. Report written to {ReportPath}", reportPath); + } + + private bool VerifyText( + StringBuilder reportBuilder, + IReadOnlyCollection supportedLanguages, + CancellationToken token) + { + var hasErrors = false; + var textDir = _fileSystem.Path.Combine(republicAtWar.Directory.FullName, "Data", "Text"); + if (!_fileSystem.Directory.Exists(textDir)) + { + reportBuilder.AppendLine($"Text directory not found: {textDir}"); + return false; + } + + var englishDatModel = GetDatModel(LanguageType.English); + + if (englishDatModel == null) + throw new FileNotFoundException($"Missing required English reference file: MasterTextFile_English.dat in {textDir}"); + + token.ThrowIfCancellationRequested(); + + foreach (var language in supportedLanguages) + { + if (language == LanguageType.English) + continue; + + var langDatModel = GetDatModel(language); + + if (langDatModel == null) + { + reportBuilder.AppendLine($"Missing DAT file for {language}: MasterTextFile_{language}.dat"); + hasErrors = true; + continue; + } + + var missingKeys = _datModelService.GetMissingKeysFromBase(englishDatModel, langDatModel).ToList(); + if (missingKeys.Any()) + { + reportBuilder.AppendLine($"Language {language} is missing {missingKeys.Count} keys from MasterTextFile_{language}.dat:"); + foreach (var key in missingKeys) + reportBuilder.AppendLine($" - {key}"); + hasErrors = true; + } + + var additionalKeys = _datModelService.GetMissingKeysFromBase(langDatModel, englishDatModel).ToList(); + if (additionalKeys.Any()) + { + reportBuilder.AppendLine($"Language {language} has {additionalKeys.Count} additional keys in MasterTextFile_{language}.dat (not in English):"); + foreach (var key in additionalKeys) + reportBuilder.AppendLine($" - {key}"); + hasErrors = true; + } + } + return hasErrors; + } + + private IDatModel? GetDatModel(LanguageType language) + { + var textDir = _fileSystem.Path.Combine(republicAtWar.Directory.FullName, "Data", "Text"); + if (!_fileSystem.Directory.Exists(textDir)) + return null; + + var expectedFileName = $"MasterTextFile_{language}.dat"; + + var filePath = _fileSystem.Directory.EnumerateFiles(textDir, "*.dat") + .FirstOrDefault(f => _fileSystem.Path.GetFileName(f).Equals(expectedFileName, StringComparison.OrdinalIgnoreCase)); + + return filePath == null ? null : _datFileService.LoadAs(filePath, DatFileType.OrderedByCrc32).Content; + } + + private bool VerifySpeech(StringBuilder reportBuilder, + IReadOnlyCollection supportedLanguages, + CancellationToken token) + { + var speechDir = _fileSystem.Path.Combine(republicAtWar.Directory.FullName, "Data", "Audio", "Speech"); + var englishSpeechDir = _fileSystem.Path.Combine(speechDir, "English"); + + if (!_fileSystem.Directory.Exists(englishSpeechDir)) + throw new DirectoryNotFoundException($"Missing required English reference speech directory: {englishSpeechDir}"); + + var englishFiles = _fileSystem.Directory.GetFiles(englishSpeechDir, "*", SearchOption.TopDirectoryOnly) + .Select(f => _fileSystem.Path.GetFileName(f)) + .ToList(); + + var hasErrors = VerifyEnglishFilesLocalizable(reportBuilder, englishFiles, "Speech"); + + foreach (var language in supportedLanguages) + { + if (language == LanguageType.English) + continue; + + token.ThrowIfCancellationRequested(); + + var langSpeechDir = _fileSystem.Path.Combine(speechDir, language.ToString()); + if (!_fileSystem.Directory.Exists(langSpeechDir)) + { + reportBuilder.AppendLine($"Missing speech directory for {language}: {langSpeechDir}"); + hasErrors = true; + continue; + } + + var langFiles = new HashSet(_fileSystem.Directory.GetFiles(langSpeechDir, "*", SearchOption.TopDirectoryOnly) + .Select(f => _fileSystem.Path.GetFileName(f)), StringComparer.OrdinalIgnoreCase); + + hasErrors |= VerifyFileParity(reportBuilder, language, englishFiles, langFiles, langSpeechDir); + } + + return hasErrors; + } + + private bool VerifyEnglishFilesLocalizable(StringBuilder reportBuilder, IEnumerable englishFiles, string category) + { + var nonLocalizable = englishFiles.Where(f => !_languageManager.IsFileNameLocalizable(f, true)).ToList(); + if (nonLocalizable.Any()) + { + reportBuilder.AppendLine($"The following English files in {category} are not localizable and should be renamed:"); + foreach (var f in nonLocalizable) + reportBuilder.AppendLine($" - {f}"); + return true; + } + return false; + } + + private bool VerifyFileParity( + StringBuilder reportBuilder, + LanguageType language, + IEnumerable englishFiles, + HashSet langFiles, + string location) + { + var hasErrors = false; + var missingInLang = new List(); + var expectedLocalizedNames = new HashSet(StringComparer.OrdinalIgnoreCase); + + foreach (var englishFile in englishFiles) + { + var localizedName = _languageManager.LocalizeFileName(englishFile, language, out _); + expectedLocalizedNames.Add(localizedName); + if (!langFiles.Contains(localizedName)) + missingInLang.Add(localizedName); + } + + if (missingInLang.Any()) + { + reportBuilder.AppendLine($"Language {language} has {missingInLang.Count} missing/mismatching files in {location}."); + foreach (var missingFile in missingInLang) + reportBuilder.AppendLine($" - {missingFile}"); + hasErrors = true; + } + + var additionalInLang = langFiles.Where(f => !expectedLocalizedNames.Contains(f)).ToList(); + if (additionalInLang.Any()) + { + reportBuilder.AppendLine($"Language {language} has {additionalInLang.Count} additional files in {location} (not in English):"); + foreach (var extraFile in additionalInLang) + reportBuilder.AppendLine($" - {extraFile}"); + hasErrors = true; + } + + return hasErrors; + } + + private bool VerifySfx(StringBuilder reportBuilder, + IReadOnlyCollection supportedLanguages, + CancellationToken token) + { + var englishMeg = GetMegArchive("Data/Audio/SFX/voices_English.meg"); + if (englishMeg == null) + throw new FileNotFoundException("Missing required English reference SFX MEG: Data/Audio/SFX/voices_English.meg"); + + return VerifyMegInternal(reportBuilder, supportedLanguages, englishMeg, l => $"Data/Audio/SFX/voices_{l}.meg", token); + } + + private bool VerifyMegInternal(StringBuilder reportBuilder, + IReadOnlyCollection supportedLanguages, + IMegArchive englishArchive, + Func megPathFunc, + CancellationToken token) + { + var englishFiles = englishArchive.Select(entry => entry.Path).ToList(); + + var hasErrors = VerifyEnglishFilesLocalizable(reportBuilder, englishFiles, "SFX"); + + foreach (var language in supportedLanguages) + { + if (language == LanguageType.English) + continue; + + token.ThrowIfCancellationRequested(); + + var megPath = megPathFunc(language); + var langArchive = GetMegArchive(megPath); + + if (langArchive == null) + { + reportBuilder.AppendLine($"Missing MEG file for {language}: {megPath}"); + hasErrors = true; + continue; + } + + var langFiles = new HashSet(StringComparer.OrdinalIgnoreCase); + foreach (var entry in langArchive) + langFiles.Add(entry.Path); + + hasErrors |= VerifyFileParity(reportBuilder, language, englishFiles, langFiles, megPath); + } + + return hasErrors; + } + + private IMegArchive? GetMegArchive(string relativePath) + { + var fullPath = _fileSystem.Path.Combine(republicAtWar.Directory.FullName, relativePath); + return !_fileSystem.File.Exists(fullPath) + ? null + : _megFileService.Load(fullPath).Archive; } } \ No newline at end of file From f455c8e2293a274485ee6d175bb3b4ba1276a5ac Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Sun, 8 Mar 2026 15:40:42 +0100 Subject: [PATCH 09/11] add file type validation for localization verification --- .../Steps/Releasing/VerifyLocalizationStep.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/RawDevTools/Steps/Releasing/VerifyLocalizationStep.cs b/src/RawDevTools/Steps/Releasing/VerifyLocalizationStep.cs index d59b223..089a18d 100644 --- a/src/RawDevTools/Steps/Releasing/VerifyLocalizationStep.cs +++ b/src/RawDevTools/Steps/Releasing/VerifyLocalizationStep.cs @@ -164,6 +164,15 @@ private bool VerifySpeech(StringBuilder reportBuilder, var hasErrors = VerifyEnglishFilesLocalizable(reportBuilder, englishFiles, "Speech"); + var nonMp3Files = englishFiles.Where(f => !_fileSystem.Path.GetExtension(f).Equals(".mp3", StringComparison.OrdinalIgnoreCase)).ToList(); + if (nonMp3Files.Any()) + { + reportBuilder.AppendLine("The following English files in Speech are not .mp3 files:"); + foreach (var f in nonMp3Files) + reportBuilder.AppendLine($" - {f}"); + hasErrors = true; + } + foreach (var language in supportedLanguages) { if (language == LanguageType.English) @@ -261,6 +270,15 @@ private bool VerifyMegInternal(StringBuilder reportBuilder, var hasErrors = VerifyEnglishFilesLocalizable(reportBuilder, englishFiles, "SFX"); + var nonWavFiles = englishFiles.Where(f => !_fileSystem.Path.GetExtension(f).Equals(".wav", StringComparison.OrdinalIgnoreCase)).ToList(); + if (nonWavFiles.Any()) + { + reportBuilder.AppendLine("The following English files in SFX are not .wav files:"); + foreach (var f in nonWavFiles) + reportBuilder.AppendLine($" - {f}"); + hasErrors = true; + } + foreach (var language in supportedLanguages) { if (language == LanguageType.English) From 2f41e8dd1d98e9700bf29445bde8784a7f5f4981 Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Sun, 8 Mar 2026 15:41:08 +0100 Subject: [PATCH 10/11] add step to localize unsupported speech files during build --- src/DevLauncher/Pipelines/BuildPipeline.cs | 2 +- .../Steps/Build/CleanOutdatedAssetsStep.cs | 20 +++++ .../Build/LocalizeUnsupportedSpeechStep.cs | 78 +++++++++++++++++++ 3 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 src/RawDevTools/Steps/Build/LocalizeUnsupportedSpeechStep.cs diff --git a/src/DevLauncher/Pipelines/BuildPipeline.cs b/src/DevLauncher/Pipelines/BuildPipeline.cs index a5369f7..c124398 100644 --- a/src/DevLauncher/Pipelines/BuildPipeline.cs +++ b/src/DevLauncher/Pipelines/BuildPipeline.cs @@ -22,7 +22,6 @@ internal sealed class BuildPipeline : SequentialPipeline private readonly BuildSettings _settings; private readonly IPhysicalMod _mod; - public BuildPipeline(IPhysicalMod mod, BuildSettings settings, IServiceProvider serviceProvider) : base(serviceProvider) { _mod = mod; @@ -52,6 +51,7 @@ private IEnumerable CreateBuildSteps() yield return new PackMegFileStep(new RawNonLocalizedSfxMegConfiguration(_mod, ServiceProvider), _settings, ServiceProvider); yield return new PackIconsStep(_settings, ServiceProvider); yield return new CompileLocalizationStep(_settings, ServiceProvider); + yield return new LocalizeUnsupportedSpeechStep(_mod, _settings, ServiceProvider); foreach (var supportedLanguage in _republicAtWarService.GetSupportedLanguages()) { diff --git a/src/RawDevTools/Steps/Build/CleanOutdatedAssetsStep.cs b/src/RawDevTools/Steps/Build/CleanOutdatedAssetsStep.cs index d2bbdc6..dff76f6 100644 --- a/src/RawDevTools/Steps/Build/CleanOutdatedAssetsStep.cs +++ b/src/RawDevTools/Steps/Build/CleanOutdatedAssetsStep.cs @@ -4,6 +4,9 @@ using System.Threading.Tasks; using AnakinRaW.CommonUtilities.FileSystem; using AnakinRaW.CommonUtilities.SimplePipeline.Steps; +using AET.Modinfo.Spec; +using PG.StarWarsGame.Engine.Localization; +using RepublicAtWar.DevTools.Services; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileSystemGlobbing; using Microsoft.Extensions.Logging; @@ -30,6 +33,23 @@ protected override Task RunCoreAsync(CancellationToken token) _fileSystem.File.DeleteWithRetry(fileToDelete); } + var republicAtWarService = new RepublicAtWarService(Services); + foreach (var (language, support) in republicAtWarService.GetSupportedLanguages()) + { + if (language == LanguageType.English) + continue; + + if (support.HasFlag(LanguageSupportLevel.Speech)) + continue; + + var targetDir = _fileSystem.Path.Combine(mod.Directory.FullName, "Data\\Audio\\Speech", language.ToString()); + if (_fileSystem.Directory.Exists(targetDir)) + { + Logger?.LogDebug("Deleting (unsupported) localized speech directory '{Directory}'", targetDir); + _fileSystem.Directory.Delete(targetDir, true); + } + } + Logger?.LogInformation("Finished cleaning outdated assets."); }, CancellationToken.None); } diff --git a/src/RawDevTools/Steps/Build/LocalizeUnsupportedSpeechStep.cs b/src/RawDevTools/Steps/Build/LocalizeUnsupportedSpeechStep.cs new file mode 100644 index 0000000..81fab7b --- /dev/null +++ b/src/RawDevTools/Steps/Build/LocalizeUnsupportedSpeechStep.cs @@ -0,0 +1,78 @@ +using System; +using System.IO.Abstractions; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using AET.Modinfo.Spec; +using AnakinRaW.CommonUtilities.FileSystem; +using AnakinRaW.CommonUtilities.SimplePipeline.Steps; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using PG.StarWarsGame.Engine; +using PG.StarWarsGame.Engine.Localization; +using PG.StarWarsGame.Infrastructure; +using RepublicAtWar.DevTools.Services; +using RepublicAtWar.DevTools.Steps.Settings; + +namespace RepublicAtWar.DevTools.Steps.Build; + +public class LocalizeUnsupportedSpeechStep(IPhysicalPlayableObject physicalGameObject, BuildSettings settings, IServiceProvider serviceProvider) + : PipelineStep(serviceProvider) +{ + private readonly IFileSystem _fileSystem = serviceProvider.GetRequiredService(); + private readonly ILogger? _logger = serviceProvider.GetService()?.CreateLogger(typeof(LocalizeUnsupportedSpeechStep)); + private readonly RepublicAtWarService _republicAtWarService = new(serviceProvider); + private readonly IGameLanguageManager _gameLanguageManager = serviceProvider.GetRequiredService() + .GetLanguageManager(GameEngineType.Foc); + + protected override Task RunCoreAsync(CancellationToken token) + { + return Task.Run(() => + { + var languages = _republicAtWarService.GetSupportedLanguages().ToList(); + var englishSpeechDir = _fileSystem.Path.Combine(physicalGameObject.Directory.FullName, "Data\\Audio\\Speech\\English"); + + if (!_fileSystem.Directory.Exists(englishSpeechDir)) + throw new InvalidOperationException("English speech directory not found. Skipping localization."); + + foreach (var (language, support) in languages) + { + if (language == LanguageType.English) + continue; + + if (support.HasFlag(LanguageSupportLevel.Speech)) + continue; + + LocalizeSpeechFromEnglish(language, englishSpeechDir); + } + }, CancellationToken.None); + } + + private void LocalizeSpeechFromEnglish(LanguageType language, string englishSpeechDir) + { + var targetDir = _fileSystem.Path.Combine(physicalGameObject.Directory.FullName, "Data\\Audio\\Speech", language.ToString()); + + _logger?.LogInformation("Localizing speech for language {Language} using English language files...", language); + + var overwriteOption = settings.CleanBuild + ? DirectoryOverwriteOption.CleanOverwrite + : DirectoryOverwriteOption.MergeOverwrite; + + _fileSystem.DirectoryInfo.New(englishSpeechDir).Copy(targetDir, null, overwriteOption); + + var speechFiles = _fileSystem.Directory.GetFiles(targetDir, "*.mp3"); + foreach (var speechFile in speechFiles) + { + var fileName = _fileSystem.Path.GetFileName(speechFile); + var localizedFileName = _gameLanguageManager.LocalizeFileName(fileName, language, out var localized); + + if (!localized) + continue; + + var targetPath = _fileSystem.Path.Combine(targetDir, localizedFileName); + _fileSystem.File.Move(speechFile, targetPath); + } + + _logger?.LogInformation("Finished localizing speech for language {Language}", language); + } +} From efc06c66482b1761559738b0fe0ec3e16fbb64c7 Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Sun, 8 Mar 2026 15:56:50 +0100 Subject: [PATCH 11/11] fix deploy --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b7146db..497ece0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -77,7 +77,7 @@ jobs: - name: Create Manifest run: dotnet ./dev/${{env.MANIFEST_CREATOR}} -a binaries/${{env.TOOL_EXE}} --appDataFiles binaries/${{env.UPDATER_EXE}} --origin ${{env.ORIGIN_BASE}} -o ./binaries -b ${{env.BRANCH_NAME}} - name: Upload Build - run: dotnet ./dev/${{env.SFTP_UPLOADER}} -h $host --port $port -u ${{secrets.SFTP_USER}} -p ${{secrets.SFTP_PASSWORD}} --base $base_path -s $source + run: dotnet ./dev/${{env.SFTP_UPLOADER}} ftp --host $host --port $port -u ${{secrets.SFTP_USER}} -p ${{secrets.SFTP_PASSWORD}} --base $base_path -s $source env: host: republicatwar.com port: 1579