add config file

This commit is contained in:
bird_egop
2026-06-07 00:41:16 +03:00
parent 4e45bd236c
commit 8bed73fb5a
10 changed files with 169 additions and 35 deletions
+27
View File
@@ -0,0 +1,27 @@
namespace NResUI.Abstractions;
public interface IConfigProvider
{
ConfigJson GetConfig();
void Set(ConfigJson config);
}
public class ConfigProvider : IConfigProvider
{
private ConfigJson _instance;
public ConfigProvider(ConfigJson instance)
{
_instance = instance;
}
public void Set(ConfigJson config)
{
_instance = config;
}
public ConfigJson GetConfig()
{
return _instance;
}
}
+6
View File
@@ -0,0 +1,6 @@
namespace NResUI.Abstractions;
public interface ILaunchReceiver
{
void OnLaunch();
}
+20
View File
@@ -26,6 +26,7 @@ public class App
public ImFontPtr OpenSansFont;
private List<IImGuiPanel> _imGuiPanels = [];
private Later _later = new();
public App()
{
@@ -40,6 +41,9 @@ public class App
IServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<ILater>(_later);
serviceCollection.AddSingleton<IConfigProvider>(new ConfigProvider(new ConfigJson()));
foreach (var type in Utils.GetAssignableTypes<IService>())
{
serviceCollection.AddSingleton(type);
@@ -50,6 +54,11 @@ public class App
serviceCollection.AddSingleton(type);
}
foreach (var type in Utils.GetAssignableTypes<ILaunchReceiver>())
{
serviceCollection.AddSingleton(type);
}
serviceCollection.AddSingleton(openGl);
serviceCollection.AddSingleton(window);
@@ -68,6 +77,12 @@ public class App
_imGuiPanels = Utils.GetAssignableTypes<IImGuiPanel>()
.Select(t => (serviceProvider.GetService(t) as IImGuiPanel)!)
.ToList();
foreach (var type in Utils.GetAssignableTypes<ILaunchReceiver>())
{
var launchReceiver = serviceProvider.GetService(type) as ILaunchReceiver;
launchReceiver?.OnLaunch();
}
}
public void OnImGuiRender()
@@ -123,6 +138,11 @@ public class App
{
imGuiPanel.OnImGuiRender();
}
foreach (var action in _later.Enumerate())
{
action();
}
// ImGui.ShowMetricsWindow();
// ImGui.ShowDemoWindow();
+9
View File
@@ -0,0 +1,9 @@
namespace NResUI;
public class ConfigJson
{
/// <summary>
/// Path to the game itself (the folder that contains DATA, MISSIONS, UNITS etc)
/// </summary>
public string GameBasePath { get; set; }
}
+25
View File
@@ -0,0 +1,25 @@
namespace NResUI;
public interface ILater
{
void Execute(Action action);
}
public class Later : ILater
{
private Queue<Action> _queue = new();
public void Execute(Action action)
{
_queue.Enqueue(action);
}
public IEnumerable<Action> Enumerate()
{
while (_queue.Count > 0)
{
var action = _queue.Dequeue();
yield return action;
}
}
}
+5 -3
View File
@@ -16,12 +16,14 @@ public sealed class ViewportPanel : IImGuiPanel
private readonly ViewportScene _scene;
private readonly ViewportCamera _camera = new();
private readonly ViewportInputController _inputController = new();
private readonly IConfigProvider _configProvider;
private string? _loadedModelPath;
private string? _loadError;
public ViewportPanel(GL gl, IWindow window)
public ViewportPanel(GL gl, IWindow window, IConfigProvider configProvider)
{
_configProvider = configProvider;
var cubeMesh = PrimitiveMeshes.CreateCube(gl);
var gridMesh = PrimitiveMeshes.CreateWorldGrid(gl);
@@ -94,7 +96,7 @@ public sealed class ViewportPanel : IImGuiPanel
if (ImGui.Button("Reset cube"))
{
var cubeMesh = PrimitiveMeshes.CreateCube(_renderer.Gl);
_scene.ReplacePieces(new[] { ViewportPiece.CreateUnitCube(0, "Cube", cubeMesh) });
_scene.ReplacePieces([ViewportPiece.CreateUnitCube(0, "Cube", cubeMesh)]);
_loadedModelPath = null;
_loadError = null;
_camera.Reset();
@@ -109,7 +111,7 @@ public sealed class ViewportPanel : IImGuiPanel
private void LoadMsh(string path)
{
var loadResult = MshViewportLoader.LoadFromFile(_renderer.Gl, path);
var loadResult = MshViewportLoader.LoadFromFile(_renderer.Gl, path, _configProvider);
if (!loadResult.IsSuccess)
{
_loadError = loadResult.Error ?? "Unknown error.";
+53
View File
@@ -0,0 +1,53 @@
using System.Text.Json;
using NResUI.Abstractions;
using NResUI.ImGuiUI;
namespace NResUI;
public class LoadConfigOnLaunch : ILaunchReceiver
{
private readonly ILater _later;
private readonly MessageBoxModalPanel _messageBoxModalPanel;
private readonly IConfigProvider _configProvider;
public LoadConfigOnLaunch(ILater later, MessageBoxModalPanel messageBoxModalPanel, IConfigProvider configProvider)
{
_later = later;
_messageBoxModalPanel = messageBoxModalPanel;
_configProvider = configProvider;
}
public void OnLaunch()
{
if (!File.Exists("config.json"))
{
_later.Execute(() =>
{
_messageBoxModalPanel.Show(
"config.json is not present\nViewport may be broken without game files\nPlaceholder file has been created");
});
var config = new ConfigJson() { GameBasePath = "" };
File.WriteAllText("config.json", JsonSerializer.Serialize(config));
_configProvider.Set(config);
}
else
{
var content = File.ReadAllText("config.json");
var config = JsonSerializer.Deserialize<ConfigJson>(content);
if (config is null)
{
_later.Execute(() =>
{
_messageBoxModalPanel.Show("config.json was corrupted\nReplacement has been created");
});
config = new ConfigJson() { GameBasePath = "" };
File.WriteAllText("config.json", JsonSerializer.Serialize(config));
_configProvider.Set(config);
}
else
{
_configProvider.Set(config);
}
}
}
}
Binary file not shown.
@@ -1,6 +1,7 @@
using System.Numerics;
using MshLib;
using NResLib;
using NResUI.Abstractions;
using NResUI.Rendering.Viewport.Meshes;
using Silk.NET.OpenGL;
@@ -11,7 +12,7 @@ public static class MshViewportLoader
private const int DefaultModelState = 0;
private const int DefaultLod = 0;
public static MshViewportLoadResult LoadFromFile(GL gl, string path)
public static MshViewportLoadResult LoadFromFile(GL gl, string path, IConfigProvider configProvider)
{
try
{
@@ -30,7 +31,7 @@ public static class MshViewportLoader
}
fs.Seek(0, SeekOrigin.Begin);
var pieces = LoadModelPieces(gl, fs, archive, path);
var pieces = LoadModelPieces(gl, fs, archive, path, configProvider);
if (pieces.Count == 0)
return MshViewportLoadResult.Failure("MSH was parsed, but no renderable geometry pieces were found.", path);
@@ -42,7 +43,9 @@ public static class MshViewportLoader
}
}
private static List<ViewportPiece> LoadModelPieces(GL gl, FileStream fs, NResArchive archive, string path)
private static List<ViewportPiece> LoadModelPieces(
GL gl, FileStream fs, NResArchive archive, string path, IConfigProvider configProvider
)
{
var nodes = Msh0x01.ReadComponent(fs, archive);
var geometry = Msh0x02.ReadComponent(fs, archive);
@@ -54,7 +57,7 @@ public static class MshViewportLoader
var restPoses = MshRestPoseBuilder.BuildRestPose(nodes, animationDescriptors);
var mshToViewportTransform = Matrix4x4.CreateRotationX(-MathF.PI * 0.5f);
var names = TryReadNames(fs, archive);
var materialLibrary = WeaMaterialLibrary.TryLoadForMsh(gl, path);
var materialLibrary = WeaMaterialLibrary.TryLoadForMsh(gl, path, configProvider);
var pieces = new List<ViewportPiece>();
@@ -1,5 +1,6 @@
using MaterialLib;
using NResLib;
using NResUI.Abstractions;
using NResUI.Rendering.Viewport.OpenGL;
using Silk.NET.OpenGL;
using TexmLib;
@@ -24,7 +25,7 @@ public sealed class WeaMaterialLibrary
: null;
}
public static WeaMaterialLibrary TryLoadForMsh(GL gl, string mshPath)
public static WeaMaterialLibrary TryLoadForMsh(GL gl, string mshPath, IConfigProvider configProvider)
{
var weaPath = FindMatchingWeaPath(mshPath);
if (!File.Exists(weaPath))
@@ -34,9 +35,13 @@ public sealed class WeaMaterialLibrary
if (materialRefs.Count == 0)
return Empty;
// TODO: Hardcoded for now
var materialLibFs = "C:\\IronStrategy\\Material.lib";
var materialLibFs = Path.Combine(configProvider.GetConfig().GameBasePath, "Material.lib");
if (!File.Exists(materialLibFs))
{
return new WeaMaterialLibrary([]);
}
using var materialFs = new FileStream(materialLibFs, FileMode.Open, FileAccess.Read, FileShare.Read);
var parseResult = NResParser.ReadFile(materialFs);
if (parseResult.Archive == null)
@@ -46,7 +51,7 @@ public sealed class WeaMaterialLibrary
foreach (var materialRef in materialRefs)
{
var texture = TryLoadMaterialTexture(gl, materialFs, parseResult.Archive, materialRef.Name, out var texm);
var texture = TryLoadMaterialTexture(gl, materialFs, parseResult.Archive, materialRef.Name, configProvider, out var texm);
result[materialRef.Id] = texture != null
? new ViewportMaterial(materialRef.Name, texture.Value, texm)
: new ViewportMaterial(materialRef.Name);
@@ -194,7 +199,8 @@ public sealed class WeaMaterialLibrary
}
private static uint? TryLoadMaterialTexture(
GL gl, FileStream materialFs, NResArchive materialArchive, string materialName, out TexmFile? texm
GL gl, FileStream materialFs, NResArchive materialArchive, string materialName, IConfigProvider configProvider,
out TexmFile? texm
)
{
texm = null;
@@ -212,7 +218,12 @@ public sealed class WeaMaterialLibrary
var texture = materialFile.Stages[0].TextureName;
var textureLibFs = "C:\\IronStrategy\\Textures.lib";
var textureLibFs = Path.Combine(configProvider.GetConfig().GameBasePath, "Textures.lib");
if (!File.Exists(textureLibFs))
{
return null;
}
using var textureFs = new FileStream(textureLibFs, FileMode.Open, FileAccess.Read, FileShare.Read);
var textureResult = NResParser.ReadFile(textureFs);
@@ -269,27 +280,5 @@ public sealed class WeaMaterialLibrary
Normalize(x.FileName) == normalized);
}
private static string? FindTexturesLib(string? startDirectory)
{
if (string.IsNullOrWhiteSpace(startDirectory))
return null;
var directory = new DirectoryInfo(startDirectory);
while (directory != null)
{
var candidate = Path.Combine(directory.FullName, "Textures.lib");
if (Directory.Exists(candidate))
return candidate;
candidate = Path.Combine(directory.FullName, "textures.lib");
if (Directory.Exists(candidate))
return candidate;
directory = directory.Parent;
}
return null;
}
private readonly record struct WeaMaterialRef(int Id, string Name);
}