From a0d7f5374ab3a389311de5fd143e83a5c78688fb Mon Sep 17 00:00:00 2001 From: Julien Date: Sun, 2 Jun 2024 12:54:09 +0200 Subject: [PATCH] Allow to change source locations --- .../MapWorkspace.cs | 9 +++- GameRealisticMap.Arma3.CommandLine/Program.cs | 8 +-- .../Arma3DemoMapGenerator.cs | 3 +- GameRealisticMap.Arma3/Arma3MapGenerator.cs | 9 ++-- .../Arma3TerrainBuilderGenerator.cs | 9 ++-- .../Demo/Arma3GdtDemoMapGenerator.cs | 3 +- .../ViewModels/ConditionTestMapViewModel.cs | 6 ++- .../Modules/Main/MainModule.cs | 7 ++- .../Modules/Main/Services/GrmConfigService.cs | 30 +++++++++++ .../Main/Services/IGrmConfigService.cs | 14 +++++ .../Main/ViewModels/GrmSourcesViewModel.cs | 51 +++++++++++++++++++ .../Modules/Main/Views/GrmSourcesView.xaml | 41 +++++++++++++++ .../Modules/Main/Views/GrmSourcesView.xaml.cs | 28 ++++++++++ .../ViewModels/MapConfigEditorViewModel.cs | 12 ++--- .../ViewModels/MapPreviewViewModel.cs | 8 +-- GameRealisticMap/BuildersCatalog.cs | 9 ++-- .../Configuration/DefaultSourceLocations.cs | 17 +++++++ .../Configuration/ISourceLocations.cs | 17 +++++++ .../Configuration/SourceLocations.cs | 39 ++++++++++++++ .../Configuration/SourceLocationsJson.cs | 12 +++++ .../ElevationModel/RawElevationBuilder.cs | 11 ++-- .../Nature/Weather/WeatherBuilder.cs | 9 ++-- GameRealisticMap/Osm/OsmDataOverPassLoader.cs | 26 +++------- GameRealisticMap/Preview/PreviewRender.cs | 18 +++---- .../Satellite/RawSatelliteImageBuilder.cs | 9 ++-- GameRealisticMap/Satellite/S2Cloudless.cs | 7 ++- 26 files changed, 342 insertions(+), 70 deletions(-) create mode 100644 GameRealisticMap.Studio/Modules/Main/Services/GrmConfigService.cs create mode 100644 GameRealisticMap.Studio/Modules/Main/Services/IGrmConfigService.cs create mode 100644 GameRealisticMap.Studio/Modules/Main/ViewModels/GrmSourcesViewModel.cs create mode 100644 GameRealisticMap.Studio/Modules/Main/Views/GrmSourcesView.xaml create mode 100644 GameRealisticMap.Studio/Modules/Main/Views/GrmSourcesView.xaml.cs create mode 100644 GameRealisticMap/Configuration/DefaultSourceLocations.cs create mode 100644 GameRealisticMap/Configuration/ISourceLocations.cs create mode 100644 GameRealisticMap/Configuration/SourceLocations.cs create mode 100644 GameRealisticMap/Configuration/SourceLocationsJson.cs diff --git a/GameRealisticMap.Arma3.CommandLine/MapWorkspace.cs b/GameRealisticMap.Arma3.CommandLine/MapWorkspace.cs index f4d6a5ad..695fe092 100644 --- a/GameRealisticMap.Arma3.CommandLine/MapWorkspace.cs +++ b/GameRealisticMap.Arma3.CommandLine/MapWorkspace.cs @@ -1,24 +1,27 @@ using GameRealisticMap.Arma3.Assets; using GameRealisticMap.Arma3.IO; using GameRealisticMap.Arma3.TerrainBuilder; +using GameRealisticMap.Configuration; using GameRealisticMap.Reporting; namespace GameRealisticMap.Arma3.CommandLine { internal class MapWorkspace : IDisposable { - public MapWorkspace(ProjectDrive projectDrive, Arma3Assets assets, Arma3MapConfig a3config, ConsoleProgressSystem progress) + public MapWorkspace(ProjectDrive projectDrive, Arma3Assets assets, Arma3MapConfig a3config, ConsoleProgressSystem progress, ISourceLocations sources) { ProjectDrive = projectDrive; Assets = assets; MapConfig = a3config; Progress = progress; + Sources = sources; } public ProjectDrive ProjectDrive { get; } public Arma3Assets Assets { get; } public Arma3MapConfig MapConfig { get; } public ConsoleProgressSystem Progress { get; } + public ISourceLocations Sources { get; } public static async Task Create(Arma3MapConfig a3config, string searchPath) { @@ -42,7 +45,9 @@ public static async Task Create(Arma3MapConfig a3config, string se var assets = await Arma3Assets.LoadFromFile(models, a3config.AssetConfigFile); - return new MapWorkspace(projectDrive, assets, a3config, progress); + var sources = await SourceLocations.Load(); + + return new MapWorkspace(projectDrive, assets, a3config, progress, sources); } public void Dispose() diff --git a/GameRealisticMap.Arma3.CommandLine/Program.cs b/GameRealisticMap.Arma3.CommandLine/Program.cs index 251a7c93..c853f8dc 100644 --- a/GameRealisticMap.Arma3.CommandLine/Program.cs +++ b/GameRealisticMap.Arma3.CommandLine/Program.cs @@ -28,7 +28,7 @@ static async Task Main(string[] args) private static async Task GenerateTerrainBuilder(GenerateTerrainBuilderOptions opts) { using var workspace = await opts.CreateWorkspace(); - var generator = new Arma3TerrainBuilderGenerator(workspace.Assets, workspace.ProjectDrive); + var generator = new Arma3TerrainBuilderGenerator(workspace.Assets, workspace.ProjectDrive, workspace.Sources); Directory.CreateDirectory(opts.TargetDirectory); await generator.GenerateTerrainBuilderFiles(workspace.Progress, workspace.MapConfig, opts.TargetDirectory); return 0; @@ -37,7 +37,7 @@ private static async Task GenerateTerrainBuilder(GenerateTerrainBuilderOpti private static async Task GenerateObjectLayer(GenerateObjectLayerOptions opts) { using var workspace = await opts.CreateWorkspace(); - var generator = new Arma3TerrainBuilderGenerator(workspace.Assets, workspace.ProjectDrive); + var generator = new Arma3TerrainBuilderGenerator(workspace.Assets, workspace.ProjectDrive, workspace.Sources); Directory.CreateDirectory(opts.TargetDirectory); await generator.GenerateOnlyOneLayer(workspace.Progress, workspace.MapConfig, opts.LayerName, opts.TargetDirectory); return 0; @@ -46,7 +46,7 @@ private static async Task GenerateObjectLayer(GenerateObjectLayerOptions op private static async Task GenerateWrp(GenerateWrpOptions opts) { using var workspace = await opts.CreateWorkspace(); - var generator = new Arma3MapGenerator(workspace.Assets, workspace.ProjectDrive, new NonePboCompilerFactory()); + var generator = new Arma3MapGenerator(workspace.Assets, workspace.ProjectDrive, new NonePboCompilerFactory(), workspace.Sources); await generator.GenerateWrp(workspace.Progress, workspace.MapConfig, !opts.SkipPaa); return 0; } @@ -58,7 +58,7 @@ private static async Task GenerateMod(GenerateModOptions opts) throw new PlatformNotSupportedException("Mod generation works only on Windows"); } using var workspace = await opts.CreateWorkspace(); - var generator = new Arma3MapGenerator(workspace.Assets, workspace.ProjectDrive, new PboCompilerFactory(workspace.ProjectDrive)); + var generator = new Arma3MapGenerator(workspace.Assets, workspace.ProjectDrive, new PboCompilerFactory(workspace.ProjectDrive), workspace.Sources); await generator.GenerateMod(workspace.Progress, workspace.MapConfig); return 0; } diff --git a/GameRealisticMap.Arma3/Arma3DemoMapGenerator.cs b/GameRealisticMap.Arma3/Arma3DemoMapGenerator.cs index d20b253d..304a61f0 100644 --- a/GameRealisticMap.Arma3/Arma3DemoMapGenerator.cs +++ b/GameRealisticMap.Arma3/Arma3DemoMapGenerator.cs @@ -5,6 +5,7 @@ using GameRealisticMap.Arma3.Assets; using GameRealisticMap.Arma3.GameEngine; using GameRealisticMap.Arma3.IO; +using GameRealisticMap.Configuration; using GameRealisticMap.Demo; using GameRealisticMap.ElevationModel; using GameRealisticMap.Geometries; @@ -26,7 +27,7 @@ public class Arma3DemoMapGenerator : Arma3MapGenerator private readonly IDemoNaming demoNaming; public Arma3DemoMapGenerator(IArma3RegionAssets assets, ProjectDrive projectDrive, string name, IPboCompilerFactory pboCompilerFactory, IDemoNaming? demoNaming = null) - : base(assets, projectDrive, pboCompilerFactory) + : base(assets, projectDrive, pboCompilerFactory, new DefaultSourceLocations()) { this.name = name; this.demoNaming = demoNaming ?? new DefaultDemoNaming(); diff --git a/GameRealisticMap.Arma3/Arma3MapGenerator.cs b/GameRealisticMap.Arma3/Arma3MapGenerator.cs index 2b69937c..1122adab 100644 --- a/GameRealisticMap.Arma3/Arma3MapGenerator.cs +++ b/GameRealisticMap.Arma3/Arma3MapGenerator.cs @@ -4,6 +4,7 @@ using GameRealisticMap.Arma3.GameEngine; using GameRealisticMap.Arma3.Imagery; using GameRealisticMap.Arma3.IO; +using GameRealisticMap.Configuration; using GameRealisticMap.ElevationModel; using GameRealisticMap.ManMade.Places; using GameRealisticMap.ManMade.Roads; @@ -19,12 +20,14 @@ public class Arma3MapGenerator protected readonly IArma3RegionAssets assets; private readonly ProjectDrive projectDrive; private readonly IPboCompilerFactory pboCompilerFactory; + protected readonly ISourceLocations sources; - public Arma3MapGenerator(IArma3RegionAssets assets, ProjectDrive projectDrive, IPboCompilerFactory pboCompilerFactory) + public Arma3MapGenerator(IArma3RegionAssets assets, ProjectDrive projectDrive, IPboCompilerFactory pboCompilerFactory, ISourceLocations sources) { this.assets = assets; this.projectDrive = projectDrive; this.pboCompilerFactory = pboCompilerFactory; + this.sources = sources; } public async Task GetImagerySource(IProgressTask progress, Arma3MapConfig a3config, IHugeImageStorage hugeImageStorage) @@ -49,7 +52,7 @@ public Arma3MapGenerator(IArma3RegionAssets assets, ProjectDrive projectDrive, I protected virtual BuildContext CreateBuildContext(IProgressTask progress, Arma3MapConfig a3config, IOsmDataSource osmSource, IHugeImageStorage? hugeImageStorage = null) { - var builders = new BuildersCatalog(progress, assets); + var builders = new BuildersCatalog(progress, assets, sources); return new BuildContext(builders, progress, a3config.TerrainArea, osmSource, a3config.Imagery, hugeImageStorage); } @@ -115,7 +118,7 @@ protected virtual BuildContext CreateBuildContext(IProgressTask progress, Arma3M protected virtual async Task LoadOsmData(IProgressTask progress, Arma3MapConfig a3config) { - var loader = new OsmDataOverPassLoader(progress); + var loader = new OsmDataOverPassLoader(progress, sources); return await loader.Load(a3config.TerrainArea); } diff --git a/GameRealisticMap.Arma3/Arma3TerrainBuilderGenerator.cs b/GameRealisticMap.Arma3/Arma3TerrainBuilderGenerator.cs index 87df14ba..619939d9 100644 --- a/GameRealisticMap.Arma3/Arma3TerrainBuilderGenerator.cs +++ b/GameRealisticMap.Arma3/Arma3TerrainBuilderGenerator.cs @@ -5,6 +5,7 @@ using GameRealisticMap.Arma3.IO; using GameRealisticMap.Arma3.TerrainBuilder; using GameRealisticMap.Arma3.TerrainBuilder.TmlFiles; +using GameRealisticMap.Configuration; using GameRealisticMap.ElevationModel; using GameRealisticMap.ManMade.Places; using GameRealisticMap.ManMade.Roads; @@ -25,20 +26,22 @@ public class Arma3TerrainBuilderGenerator { private readonly IArma3RegionAssets assets; private readonly ProjectDrive projectDrive; + protected readonly ISourceLocations sources; private const int MaxTerrainBuilderImageSize = 25000; // ~1.8 GB at 24 bpp private record ImageryPart(int X, int Y, int E, int N, int Size, string Name); - public Arma3TerrainBuilderGenerator(IArma3RegionAssets assets, ProjectDrive projectDrive) + public Arma3TerrainBuilderGenerator(IArma3RegionAssets assets, ProjectDrive projectDrive, ISourceLocations sources) { this.assets = assets; this.projectDrive = projectDrive; + this.sources = sources; } private BuildContext CreateBuildContext(IProgressTask progress, Arma3MapConfig a3config, IOsmDataSource osmSource, IHugeImageStorage? hugeImageStorage = null) { - var builders = new BuildersCatalog(progress, assets); + var builders = new BuildersCatalog(progress, assets, sources); return new BuildContext(builders, progress, a3config.TerrainArea, osmSource, a3config.Imagery, hugeImageStorage); } @@ -76,7 +79,7 @@ private BuildContext CreateBuildContext(IProgressTask progress, Arma3MapConfig a private async Task LoadOsmData(IProgressTask progress, Arma3MapConfig a3config) { - var loader = new OsmDataOverPassLoader(progress); + var loader = new OsmDataOverPassLoader(progress, sources); return await loader.Load(a3config.TerrainArea); } diff --git a/GameRealisticMap.Arma3/Demo/Arma3GdtDemoMapGenerator.cs b/GameRealisticMap.Arma3/Demo/Arma3GdtDemoMapGenerator.cs index 91fa57e3..6d5cc3c5 100644 --- a/GameRealisticMap.Arma3/Demo/Arma3GdtDemoMapGenerator.cs +++ b/GameRealisticMap.Arma3/Demo/Arma3GdtDemoMapGenerator.cs @@ -4,6 +4,7 @@ using GameRealisticMap.Arma3.GameEngine; using GameRealisticMap.Arma3.GameEngine.Roads; using GameRealisticMap.Arma3.IO; +using GameRealisticMap.Configuration; using GameRealisticMap.ElevationModel; using GameRealisticMap.ManMade.Places; using GameRealisticMap.ManMade.Roads; @@ -17,7 +18,7 @@ namespace GameRealisticMap.Arma3.Demo public sealed class Arma3GdtDemoMapGenerator : Arma3MapGenerator { public Arma3GdtDemoMapGenerator(IEnumerable definitions, ProjectDrive projectDrive, IPboCompilerFactory pboCompilerFactory) - : base(CreateAssets(definitions), projectDrive, pboCompilerFactory) + : base(CreateAssets(definitions), projectDrive, pboCompilerFactory, new DefaultSourceLocations()) { } diff --git a/GameRealisticMap.Studio/Modules/ConditionTool/ViewModels/ConditionTestMapViewModel.cs b/GameRealisticMap.Studio/Modules/ConditionTool/ViewModels/ConditionTestMapViewModel.cs index 9cd05bcd..94684db6 100644 --- a/GameRealisticMap.Studio/Modules/ConditionTool/ViewModels/ConditionTestMapViewModel.cs +++ b/GameRealisticMap.Studio/Modules/ConditionTool/ViewModels/ConditionTestMapViewModel.cs @@ -6,6 +6,7 @@ using GameRealisticMap.Conditions; using GameRealisticMap.Geometries; using GameRealisticMap.Osm; +using GameRealisticMap.Studio.Modules.Main.Services; using GameRealisticMap.Studio.Modules.MapConfigEditor.ViewModels; using GameRealisticMap.Studio.Modules.Reporting; using GameRealisticMap.Studio.Shared; @@ -63,8 +64,9 @@ private async Task DoGenerateData(IProgressTaskUI taskUI) var config = await map.GetBuildersConfigSafe(a3config); - var catalog = new BuildersCatalog(taskUI, config); - var loader = new OsmDataOverPassLoader(taskUI); + var sources = IoC.Get().GetSources(); + var catalog = new BuildersCatalog(taskUI, config, sources); + var loader = new OsmDataOverPassLoader(taskUI, sources); var osmSource = await loader.Load(a3config.TerrainArea); var context = new BuildContext(catalog, taskUI, a3config.TerrainArea, osmSource, new ImageryOptions()); conditionEvaluator = context.GetData(); diff --git a/GameRealisticMap.Studio/Modules/Main/MainModule.cs b/GameRealisticMap.Studio/Modules/Main/MainModule.cs index 38b4be72..333f19c3 100644 --- a/GameRealisticMap.Studio/Modules/Main/MainModule.cs +++ b/GameRealisticMap.Studio/Modules/Main/MainModule.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using System.Windows.Media.Imaging; using Caliburn.Micro; +using GameRealisticMap.Studio.Modules.Main.Services; using GameRealisticMap.Studio.Modules.Main.ViewModels; using Gemini.Framework; using Gemini.Framework.Services; @@ -15,11 +16,13 @@ namespace GameRealisticMap.Studio.Modules.Main public class MainModule : ModuleBase { private readonly IMainWindow _mainWindow; + private readonly IGrmConfigService _config; [ImportingConstructor] - public MainModule(IMainWindow mainWindow) + public MainModule(IMainWindow mainWindow, IGrmConfigService config) { _mainWindow = mainWindow; + _config = config; } public override void Initialize() @@ -31,6 +34,8 @@ public override void Initialize() public override async Task PostInitializeAsync() { + await _config.Load(); + await _mainWindow.Shell.OpenDocumentAsync(IoC.Get()); var args = Environment.GetCommandLineArgs(); diff --git a/GameRealisticMap.Studio/Modules/Main/Services/GrmConfigService.cs b/GameRealisticMap.Studio/Modules/Main/Services/GrmConfigService.cs new file mode 100644 index 00000000..3ebb49be --- /dev/null +++ b/GameRealisticMap.Studio/Modules/Main/Services/GrmConfigService.cs @@ -0,0 +1,30 @@ +using System; +using System.ComponentModel.Composition; +using System.IO; +using System.Threading.Tasks; +using GameRealisticMap.Configuration; + +namespace GameRealisticMap.Studio.Modules.Main.Services +{ + [Export(typeof(IGrmConfigService))] + internal class GrmConfigService : IGrmConfigService + { + private ISourceLocations? sources; + + public ISourceLocations GetSources() + { + return sources ?? new DefaultSourceLocations(); + } + + public async Task Load() + { + sources = await SourceLocations.Load(); + } + + public async Task SetSources(ISourceLocations newSources) + { + await SourceLocations.Save(newSources); + sources = await SourceLocations.Load(); + } + } +} diff --git a/GameRealisticMap.Studio/Modules/Main/Services/IGrmConfigService.cs b/GameRealisticMap.Studio/Modules/Main/Services/IGrmConfigService.cs new file mode 100644 index 00000000..4e2c6ef4 --- /dev/null +++ b/GameRealisticMap.Studio/Modules/Main/Services/IGrmConfigService.cs @@ -0,0 +1,14 @@ +using System.Threading.Tasks; +using GameRealisticMap.Configuration; + +namespace GameRealisticMap.Studio.Modules.Main.Services +{ + public interface IGrmConfigService + { + ISourceLocations GetSources(); + + Task SetSources(ISourceLocations sources); + + Task Load(); + } +} diff --git a/GameRealisticMap.Studio/Modules/Main/ViewModels/GrmSourcesViewModel.cs b/GameRealisticMap.Studio/Modules/Main/ViewModels/GrmSourcesViewModel.cs new file mode 100644 index 00000000..d67f4047 --- /dev/null +++ b/GameRealisticMap.Studio/Modules/Main/ViewModels/GrmSourcesViewModel.cs @@ -0,0 +1,51 @@ +using System; +using System.ComponentModel.Composition; +using System.Threading.Tasks; +using Caliburn.Micro; +using GameRealisticMap.Configuration; +using GameRealisticMap.Studio.Modules.Main.Services; +using Gemini.Modules.Settings; + +namespace GameRealisticMap.Studio.Modules.Main.ViewModels +{ + [PartCreationPolicy(CreationPolicy.NonShared)] + [Export(typeof(ISettingsEditorAsync))] + internal class GrmSourcesViewModel : PropertyChangedBase, ISettingsEditorAsync, ISourceLocations + { + private readonly IGrmConfigService configService; + + [ImportingConstructor] + public GrmSourcesViewModel(IGrmConfigService configService) + { + this.configService = configService; + var sources = configService.GetSources(); + MapToolkitSRTM15Plus = sources.MapToolkitSRTM15Plus; + MapToolkitSRTM1 = sources.MapToolkitSRTM1; + MapToolkitAW3D30 = sources.MapToolkitAW3D30; + WeatherStats = sources.WeatherStats; + OverpassApiInterpreter = sources.OverpassApiInterpreter; + S2CloudlessBasePath = sources.S2CloudlessBasePath; + } + + public string SettingsPageName => "Sources"; + + public string SettingsPagePath => "Game Realistic Map"; + + public Uri MapToolkitSRTM15Plus { get; set; } + + public Uri MapToolkitSRTM1 { get; set; } + + public Uri MapToolkitAW3D30 { get; set; } + + public Uri WeatherStats { get; set; } + + public Uri OverpassApiInterpreter { get; set; } + + public Uri S2CloudlessBasePath { get; set; } + + public async Task ApplyChangesAsync() + { + await configService.SetSources(this); + } + } +} diff --git a/GameRealisticMap.Studio/Modules/Main/Views/GrmSourcesView.xaml b/GameRealisticMap.Studio/Modules/Main/Views/GrmSourcesView.xaml new file mode 100644 index 00000000..65b18580 --- /dev/null +++ b/GameRealisticMap.Studio/Modules/Main/Views/GrmSourcesView.xaml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/GameRealisticMap.Studio/Modules/Main/Views/GrmSourcesView.xaml.cs b/GameRealisticMap.Studio/Modules/Main/Views/GrmSourcesView.xaml.cs new file mode 100644 index 00000000..63d904d8 --- /dev/null +++ b/GameRealisticMap.Studio/Modules/Main/Views/GrmSourcesView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace GameRealisticMap.Studio.Modules.Main.Views +{ + /// + /// Logique d'interaction pour GrmSourcesView.xaml + /// + public partial class GrmSourcesView : UserControl + { + public GrmSourcesView() + { + InitializeComponent(); + } + } +} diff --git a/GameRealisticMap.Studio/Modules/MapConfigEditor/ViewModels/MapConfigEditorViewModel.cs b/GameRealisticMap.Studio/Modules/MapConfigEditor/ViewModels/MapConfigEditorViewModel.cs index 6be7a931..1c3cf895 100644 --- a/GameRealisticMap.Studio/Modules/MapConfigEditor/ViewModels/MapConfigEditorViewModel.cs +++ b/GameRealisticMap.Studio/Modules/MapConfigEditor/ViewModels/MapConfigEditorViewModel.cs @@ -317,7 +317,7 @@ private async Task DoGeneratePreview(IProgressTaskUI task, bool ignoreElevation) { var a3config = Config.ToArma3MapConfig(); var config = await GetBuildersConfigSafe(a3config); - var render = new PreviewRender(a3config.TerrainArea, a3config.Imagery, config); + var render = new PreviewRender(a3config.TerrainArea, a3config.Imagery, config, IoC.Get().GetSources()); var target = Path.Combine(Path.GetTempPath(), "grm-preview.html"); await render.RenderHtml(task, target, ignoreElevation); task.AddSuccessAction(() => ShellHelper.OpenUri(target), Labels.ViewResultInWebBrowser); @@ -446,7 +446,7 @@ private async Task DoGenerateMod(IProgressTaskUI task) var assets = await GetAssets(_arma3DataModule.Library, a3config); - var generator = new Arma3MapGenerator(assets, _arma3DataModule.ProjectDrive, _arma3DataModule.CreatePboCompilerFactory()); + var generator = new Arma3MapGenerator(assets, _arma3DataModule.ProjectDrive, _arma3DataModule.CreatePboCompilerFactory(), IoC.Get().GetSources()); var freindlyName = await generator.GenerateMod(task, a3config); @@ -474,7 +474,7 @@ private async Task DoGenerateMap(IProgressTaskUI task) var assets = await GetAssets(_arma3DataModule.Library, a3config); - var generator = new Arma3MapGenerator(assets, _arma3DataModule.ProjectDrive, _arma3DataModule.CreatePboCompilerFactory()); + var generator = new Arma3MapGenerator(assets, _arma3DataModule.ProjectDrive, _arma3DataModule.CreatePboCompilerFactory(), IoC.Get().GetSources()); var results = await generator.GenerateWrp(task, a3config); @@ -532,7 +532,7 @@ private async Task DoImagery(IProgressTaskUI task, Func act Arma3Assets assets = await GetAssets(library, a3config); - var generator = new Arma3MapGenerator(assets, projectDrive, _arma3DataModule.CreatePboCompilerFactory()); + var generator = new Arma3MapGenerator(assets, projectDrive, _arma3DataModule.CreatePboCompilerFactory(), IoC.Get().GetSources()); var target = Path.Combine(Path.GetTempPath(), a3config.WorldName); @@ -555,7 +555,7 @@ private async Task DoRawSat(IProgressTaskUI task) Arma3Assets assets = await GetAssets(library, a3config); - var generator = new Arma3MapGenerator(assets, projectDrive, _arma3DataModule.CreatePboCompilerFactory()); + var generator = new Arma3MapGenerator(assets, projectDrive, _arma3DataModule.CreatePboCompilerFactory(), IoC.Get().GetSources()); var target = Path.Combine(Path.GetTempPath(), a3config.WorldName); Directory.CreateDirectory(target); @@ -609,7 +609,7 @@ private async Task DoGenerateTerrainBuilder(IProgressTaskUI task) var assets = await GetAssets(_arma3DataModule.Library, a3config); - var generator = new Arma3TerrainBuilderGenerator(assets, _arma3DataModule.ProjectDrive); + var generator = new Arma3TerrainBuilderGenerator(assets, _arma3DataModule.ProjectDrive, IoC.Get().GetSources()); var freindlyName = await generator.GenerateTerrainBuilderFiles(task, a3config, target); diff --git a/GameRealisticMap.Studio/Modules/MapConfigEditor/ViewModels/MapPreviewViewModel.cs b/GameRealisticMap.Studio/Modules/MapConfigEditor/ViewModels/MapPreviewViewModel.cs index ebb470cb..c2523603 100644 --- a/GameRealisticMap.Studio/Modules/MapConfigEditor/ViewModels/MapPreviewViewModel.cs +++ b/GameRealisticMap.Studio/Modules/MapConfigEditor/ViewModels/MapPreviewViewModel.cs @@ -15,6 +15,7 @@ using GameRealisticMap.Nature.Trees; using GameRealisticMap.Osm; using GameRealisticMap.Reporting; +using GameRealisticMap.Studio.Modules.Main.Services; using GameRealisticMap.Studio.Modules.Reporting; using GameRealisticMap.Studio.Shared; using GameRealisticMap.Studio.Toolkit; @@ -69,7 +70,7 @@ public MapPreviewViewModel(MapConfigEditorViewModel map) }; - var builders = new BuildersCatalog(new NoProgressSystem(), new DefaultBuildersConfig()); + var builders = new BuildersCatalog(new NoProgressSystem(), new DefaultBuildersConfig(), IoC.Get().GetSources()); Optionals.AddRange(builders.VisitAll(new Visitor(this)).Where(o => o != null).Cast()); } @@ -107,8 +108,9 @@ private async Task DoGenerateData(IProgressTaskUI taskUI) SizeInMeters = a3config.SizeInMeters; NotifyOfPropertyChange(nameof(SizeInMeters)); var config = await map.GetBuildersConfigSafe(a3config); - var catalog = new BuildersCatalog(taskUI, config); - var loader = new OsmDataOverPassLoader(taskUI); + var sources = IoC.Get().GetSources(); + var catalog = new BuildersCatalog(taskUI, config, sources); + var loader = new OsmDataOverPassLoader(taskUI, sources); var osmSource = await loader.Load(a3config.TerrainArea); var context = new BuildContext(catalog, taskUI, a3config.TerrainArea, osmSource, new ImageryOptions()); PreviewMapData = new PreviewMapData(context); diff --git a/GameRealisticMap/BuildersCatalog.cs b/GameRealisticMap/BuildersCatalog.cs index 76c4a822..65867211 100644 --- a/GameRealisticMap/BuildersCatalog.cs +++ b/GameRealisticMap/BuildersCatalog.cs @@ -1,4 +1,5 @@ using GameRealisticMap.Conditions; +using GameRealisticMap.Configuration; using GameRealisticMap.ElevationModel; using GameRealisticMap.ManMade; using GameRealisticMap.ManMade.Airports; @@ -30,12 +31,12 @@ public class BuildersCatalog : IBuidersCatalog { private readonly Dictionary builders = new Dictionary(); - public BuildersCatalog(IProgressSystem progress, IBuildersConfig config) + public BuildersCatalog(IProgressSystem progress, IBuildersConfig config, ISourceLocations sources) { Register(new OceanBuilder(progress)); Register(new CoastlineBuilder(progress)); - Register(new RawSatelliteImageBuilder(progress)); - Register(new RawElevationBuilder(progress)); + Register(new RawSatelliteImageBuilder(progress, sources)); + Register(new RawElevationBuilder(progress, sources)); Register(new CategoryAreaBuilder(progress)); Register(new RoadsBuilder(progress, config.Roads)); Register(new BuildingsBuilder(progress, config.Buildings)); @@ -73,7 +74,7 @@ public BuildersCatalog(IProgressSystem progress, IBuildersConfig config) Register(new DefaultAgriculturalAreasBuilder(progress)); Register(new ConditionEvaluatorBuilder()); Register(new ElevationContourBuilder(progress)); - Register(new WeatherBuilder(progress)); + Register(new WeatherBuilder(progress, sources)); Register(new IceSurfaceBuilder(progress)); Register(new ScreeBuilder(progress)); Register(new ElevationOutOfBoundsBuilder()); diff --git a/GameRealisticMap/Configuration/DefaultSourceLocations.cs b/GameRealisticMap/Configuration/DefaultSourceLocations.cs new file mode 100644 index 00000000..5b230028 --- /dev/null +++ b/GameRealisticMap/Configuration/DefaultSourceLocations.cs @@ -0,0 +1,17 @@ +namespace GameRealisticMap.Configuration +{ + public class DefaultSourceLocations : ISourceLocations + { + public Uri MapToolkitSRTM15Plus => new Uri("https://dem.pmad.net/SRTM15Plus/"); + + public Uri MapToolkitSRTM1 => new Uri("https://dem.pmad.net/SRTM1/"); + + public Uri MapToolkitAW3D30 => new Uri("https://dem.pmad.net/AW3D30/"); + + public Uri WeatherStats => new Uri("https://weatherdata.pmad.net/ERA5AVG/"); + + public Uri OverpassApiInterpreter => new Uri("https://overpass-api.de/api/interpreter"); + + public Uri S2CloudlessBasePath => new Uri("https://tiles.maps.eox.at/wmts/1.0.0/s2cloudless-2020_3857/default/GoogleMapsCompatible/"); + } +} diff --git a/GameRealisticMap/Configuration/ISourceLocations.cs b/GameRealisticMap/Configuration/ISourceLocations.cs new file mode 100644 index 00000000..d1da5536 --- /dev/null +++ b/GameRealisticMap/Configuration/ISourceLocations.cs @@ -0,0 +1,17 @@ +namespace GameRealisticMap.Configuration +{ + public interface ISourceLocations + { + Uri MapToolkitSRTM15Plus { get; } + + Uri MapToolkitSRTM1 { get; } + + Uri MapToolkitAW3D30 { get; } + + Uri WeatherStats { get; } + + Uri OverpassApiInterpreter { get; } + + Uri S2CloudlessBasePath { get; } + } +} diff --git a/GameRealisticMap/Configuration/SourceLocations.cs b/GameRealisticMap/Configuration/SourceLocations.cs new file mode 100644 index 00000000..f70eede9 --- /dev/null +++ b/GameRealisticMap/Configuration/SourceLocations.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; + +namespace GameRealisticMap.Configuration +{ + public static class SourceLocations + { + public static string DefaultLocation { get; } = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + "GameRealisticMap", "sources.json"); + + public static async Task Load() + { + if (File.Exists(DefaultLocation)) + { + using var stream = File.OpenRead(DefaultLocation); + return await JsonSerializer.DeserializeAsync(stream) ?? (ISourceLocations)new DefaultSourceLocations(); + } + return new DefaultSourceLocations(); + } + + public static async Task Save(ISourceLocations locations) + { + using var stream = File.Create(DefaultLocation); + await JsonSerializer.SerializeAsync(stream, new SourceLocationsJson() { + MapToolkitAW3D30 = locations.MapToolkitAW3D30, + MapToolkitSRTM1 = locations.MapToolkitSRTM1, + MapToolkitSRTM15Plus = locations.MapToolkitSRTM15Plus, + OverpassApiInterpreter = locations.OverpassApiInterpreter, + S2CloudlessBasePath = locations.S2CloudlessBasePath, + WeatherStats = locations.WeatherStats + }); + } + } +} diff --git a/GameRealisticMap/Configuration/SourceLocationsJson.cs b/GameRealisticMap/Configuration/SourceLocationsJson.cs new file mode 100644 index 00000000..9fa89976 --- /dev/null +++ b/GameRealisticMap/Configuration/SourceLocationsJson.cs @@ -0,0 +1,12 @@ +namespace GameRealisticMap.Configuration +{ + public sealed class SourceLocationsJson : ISourceLocations + { + public required Uri MapToolkitSRTM15Plus { get; set; } + public required Uri MapToolkitSRTM1 { get; set; } + public required Uri MapToolkitAW3D30 { get; set; } + public required Uri WeatherStats { get; set; } + public required Uri OverpassApiInterpreter { get; set; } + public required Uri S2CloudlessBasePath { get; set; } + } +} diff --git a/GameRealisticMap/ElevationModel/RawElevationBuilder.cs b/GameRealisticMap/ElevationModel/RawElevationBuilder.cs index 52e96480..94147df8 100644 --- a/GameRealisticMap/ElevationModel/RawElevationBuilder.cs +++ b/GameRealisticMap/ElevationModel/RawElevationBuilder.cs @@ -1,4 +1,5 @@ using System.Numerics; +using GameRealisticMap.Configuration; using GameRealisticMap.Geometries; using GameRealisticMap.IO; using GameRealisticMap.Nature.Ocean; @@ -16,10 +17,12 @@ namespace GameRealisticMap.ElevationModel internal class RawElevationBuilder : IDataBuilder, IDataSerializer { private readonly IProgressSystem progress; + private readonly ISourceLocations sources; - public RawElevationBuilder(IProgressSystem progress) + public RawElevationBuilder(IProgressSystem progress, ISourceLocations sources) { this.progress = progress; + this.sources = sources; } private const float InvSinCos45 = 1.4142135623730949f; @@ -151,17 +154,17 @@ private RawElevationSource CreateSource(IBuildContext context) var dbCredits = new List() { "SRTM1", "STRM15+" }; // Elevation of ground, but really low resolution (460m at equator) - var fulldb = new DemDatabase(new DemHttpStorage(new Uri("https://dem.pmad.net/SRTM15Plus/"))); + var fulldb = new DemDatabase(new DemHttpStorage(sources.MapToolkitSRTM15Plus)); var viewFull = fulldb.CreateView(startView, endView).GetAwaiter().GetResult().ToDataCell(); var detaildb = fulldb; // Elevation of surface, Partial world covergae, but better resolution (30m at equator) - var srtm = new DemDatabase(new DemHttpStorage(new Uri("https://dem.pmad.net/SRTM1/"))); + var srtm = new DemDatabase(new DemHttpStorage(sources.MapToolkitSRTM1)); IDemDataCell view; if (!srtm.HasFullData(start, end).GetAwaiter().GetResult()) { // Alternative Elevation of surface, but requires JAXA credits - var aw3d30 = new DemDatabase(new DemHttpStorage(new Uri("https://dem.pmad.net/AW3D30/"))); + var aw3d30 = new DemDatabase(new DemHttpStorage(sources.MapToolkitAW3D30)); if (!aw3d30.HasFullData(start, end).GetAwaiter().GetResult()) { view = viewFull; diff --git a/GameRealisticMap/Nature/Weather/WeatherBuilder.cs b/GameRealisticMap/Nature/Weather/WeatherBuilder.cs index 871b19d1..8404daa8 100644 --- a/GameRealisticMap/Nature/Weather/WeatherBuilder.cs +++ b/GameRealisticMap/Nature/Weather/WeatherBuilder.cs @@ -1,4 +1,5 @@ -using GameRealisticMap.Reporting; +using GameRealisticMap.Configuration; +using GameRealisticMap.Reporting; using WeatherStats.Databases; namespace GameRealisticMap.Nature.Weather @@ -6,15 +7,17 @@ namespace GameRealisticMap.Nature.Weather internal class WeatherBuilder : IDataBuilder { private readonly IProgressSystem progress; + private readonly ISourceLocations sources; - public WeatherBuilder(IProgressSystem progress) + public WeatherBuilder(IProgressSystem progress, ISourceLocations sources) { this.progress = progress; + this.sources = sources; } public WeatherData Build(IBuildContext context) { - var db = WeatherStatsDatabase.Create("https://weatherdata.pmad.net/ERA5AVG/"); + var db = WeatherStatsDatabase.Create(sources.WeatherStats.AbsoluteUri); var center = context.Area.TerrainPointToLatLng( new Geometries.TerrainPoint( diff --git a/GameRealisticMap/Osm/OsmDataOverPassLoader.cs b/GameRealisticMap/Osm/OsmDataOverPassLoader.cs index f2a98637..ec1e8f56 100644 --- a/GameRealisticMap/Osm/OsmDataOverPassLoader.cs +++ b/GameRealisticMap/Osm/OsmDataOverPassLoader.cs @@ -1,16 +1,19 @@ -using GameRealisticMap.Reporting; +using GameRealisticMap.Configuration; +using GameRealisticMap.Reporting; namespace GameRealisticMap.Osm { public class OsmDataOverPassLoader : IOsmDataLoader { private readonly IProgressSystem progress; + private readonly ISourceLocations sources; private readonly string cacheDirectory = Path.Combine(Path.GetTempPath(), "GameRealisticMap", "OverPass"); private readonly int cacheDays = 1; - public OsmDataOverPassLoader(IProgressSystem progress) + public OsmDataOverPassLoader(IProgressSystem progress, ISourceLocations sources) { this.progress = progress; + this.sources = sources; } public async Task Load(ITerrainArea area) @@ -32,21 +35,6 @@ private async Task DownloadFromOverPass(LatLngBounds box, string cacheFileName) { using var report = progress.CreateStep("Download from OSM", 1); Directory.CreateDirectory(cacheDirectory); - //double margin = 0.03; - //var uri = FormattableString.Invariant($"https://overpass-api.de/api/map?bbox={box.Left - margin},{box.Bottom - margin},{box.Right + margin},{box.Top + margin}"); - //progress.WriteLine($"GET {uri}"); - //using (var client = new HttpClient()) - //{ - // using (var target = File.Create(cacheFileName)) - // { - // using (var download = await client.GetStreamAsync(uri)) - // { - // await download.CopyToAsync(target); - // } - // } - //} - - // https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_API_by_Example#Example:_Simplest_possible_map_call var qlbb = FormattableString.Invariant($"{box.Bottom},{box.Left},{box.Top},{box.Right}"); var query = FormattableString.Invariant(@$"[timeout:300]; @@ -73,8 +61,8 @@ private async Task DownloadFromOverPass(LatLngBounds box, string cacheFileName) rel(br); ); out;"); ; - var uri = "https://overpass-api.de/api/interpreter"; - progress.WriteLine($"POST {uri}"); + var uri = sources.OverpassApiInterpreter; + progress.WriteLine($"POST {uri.AbsoluteUri}"); progress.WriteLine($"{query}"); using (var client = new HttpClient()) { diff --git a/GameRealisticMap/Preview/PreviewRender.cs b/GameRealisticMap/Preview/PreviewRender.cs index fdcc1775..0de1407b 100644 --- a/GameRealisticMap/Preview/PreviewRender.cs +++ b/GameRealisticMap/Preview/PreviewRender.cs @@ -1,11 +1,9 @@ using System.Text.Json; +using GameRealisticMap.Configuration; using GameRealisticMap.ElevationModel; -using GameRealisticMap.Geometries; -using GameRealisticMap.ManMade.Roads.Libraries; using GameRealisticMap.Osm; using GameRealisticMap.Reporting; using GeoJSON.Text.Feature; -using GeoJSON.Text.Geometry; namespace GameRealisticMap.Preview { @@ -14,17 +12,19 @@ public class PreviewRender private readonly ITerrainArea terrainArea; private readonly IImageryOptions imagery; private readonly IBuildersConfig config; + private readonly ISourceLocations sources; public PreviewRender(ITerrainArea terrainArea, IImageryOptions imagery) - : this(terrainArea, imagery, new DefaultBuildersConfig()) + : this(terrainArea, imagery, new DefaultBuildersConfig(), new DefaultSourceLocations()) { } - public PreviewRender(ITerrainArea terrainArea, IImageryOptions imagery, IBuildersConfig config) + public PreviewRender(ITerrainArea terrainArea, IImageryOptions imagery, IBuildersConfig config, ISourceLocations sources) { this.terrainArea = terrainArea; this.imagery = imagery; this.config = config; + this.sources = sources; } public async Task RenderHtml(IProgressTask progress, string targetFile, bool ignoreElevation = false) @@ -37,11 +37,11 @@ public async Task RenderHtml(IProgressTask progress, string targetFile, bool ign filter = (t) => t != typeof(ElevationContourData); } - var catalog = new BuildersCatalog(progress, config); + var catalog = new BuildersCatalog(progress, config, sources); var count = catalog.CountOfType(filter); progress.Total = count + 2; - var loader = new OsmDataOverPassLoader(progress); + var loader = new OsmDataOverPassLoader(progress, sources); var osmSource = await loader.Load(terrainArea); progress.ReportOneDone(); if (progress.CancellationToken.IsCancellationRequested) @@ -82,10 +82,10 @@ public async Task RenderHtml(IProgressTask progress, string targetFile) { try { - var catalog = new BuildersCatalog(progress, config); + var catalog = new BuildersCatalog(progress, config, sources); progress.Total = 3; - var loader = new OsmDataOverPassLoader(progress); + var loader = new OsmDataOverPassLoader(progress, sources); var osmSource = await loader.Load(terrainArea); progress.ReportOneDone(); if (progress.CancellationToken.IsCancellationRequested) diff --git a/GameRealisticMap/Satellite/RawSatelliteImageBuilder.cs b/GameRealisticMap/Satellite/RawSatelliteImageBuilder.cs index f37e97f1..487ff479 100644 --- a/GameRealisticMap/Satellite/RawSatelliteImageBuilder.cs +++ b/GameRealisticMap/Satellite/RawSatelliteImageBuilder.cs @@ -1,5 +1,6 @@ using System.Numerics; using System.Threading.Tasks; +using GameRealisticMap.Configuration; using GameRealisticMap.Geometries; using GameRealisticMap.IO; using GameRealisticMap.Reporting; @@ -14,10 +15,12 @@ namespace GameRealisticMap.Satellite internal class RawSatelliteImageBuilder : IDataBuilder, IDataSerializer { private readonly IProgressSystem progress; + private readonly ISourceLocations sources; - public RawSatelliteImageBuilder(IProgressSystem progress) + public RawSatelliteImageBuilder(IProgressSystem progress, ISourceLocations sources) { this.progress = progress; + this.sources = sources; } public RawSatelliteImageData Build(IBuildContext context) @@ -35,7 +38,7 @@ public RawSatelliteImageData Build(IBuildContext context) var himage = new HugeImage(context.HugeImageStorage, nameof(RawSatelliteImageBuilder), new Size(totalSize)); using (var report2 = progress.CreateStep("S2C", himage.Parts.Sum(t => t.RealRectangle.Height))) { - using var src = new S2Cloudless(progress); + using var src = new S2Cloudless(progress, sources); foreach (var part in himage.Parts) { LoadPart(context, totalSize, part, report2, src).Wait(); @@ -97,7 +100,7 @@ public async Task Write(IPackageWriter package, RawSatelliteImageData data) private Image LoadImage(IBuildContext context, int tileSize, IProgressInteger report, Vector2 start, int done) { var imageryResolution = context.Imagery.Resolution; - using var src = new S2Cloudless(progress); + using var src = new S2Cloudless(progress, sources); var img = new Image(tileSize, tileSize); var parallel = 16; var dh = img.Height / parallel; diff --git a/GameRealisticMap/Satellite/S2Cloudless.cs b/GameRealisticMap/Satellite/S2Cloudless.cs index 8b8baaa9..d8f6f4c3 100644 --- a/GameRealisticMap/Satellite/S2Cloudless.cs +++ b/GameRealisticMap/Satellite/S2Cloudless.cs @@ -1,4 +1,6 @@ using System.Collections.Concurrent; +using System.Net; +using GameRealisticMap.Configuration; using GameRealisticMap.Reporting; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Formats; @@ -16,6 +18,7 @@ internal class S2Cloudless : IDisposable private readonly HttpClient httpClient; private readonly SemaphoreSlim downloadSemaphore = new SemaphoreSlim(1, 1); private readonly ConcurrentDictionary<(int,int), Task>> cache = new ConcurrentDictionary<(int, int), Task>>(); + private readonly string endPoint; private int estimatedCachePressure = 0; @@ -24,14 +27,14 @@ internal class S2Cloudless : IDisposable private static readonly int zoomLevel = 15; // best compromise, almost equal to zoomLevel 16 result, 20% faster to process private static readonly int halfTileCount = (int)Math.Pow(2, zoomLevel) / 2; private static readonly int tileSize = 256; - private static readonly string endPoint = "https://tiles.maps.eox.at/wmts/1.0.0/s2cloudless-2020_3857/default/GoogleMapsCompatible/"; private const double rMajor = 6378137; //Equatorial Radius, WGS84 private const double shift = Math.PI * rMajor; - public S2Cloudless(IProgressSystem progress) + public S2Cloudless(IProgressSystem progress, ISourceLocations sources) { this.progress = progress; + endPoint = sources.S2CloudlessBasePath.AbsoluteUri; httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/111.0"); }