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; public ImFontPtr OpenSansFont;
private List<IImGuiPanel> _imGuiPanels = []; private List<IImGuiPanel> _imGuiPanels = [];
private Later _later = new();
public App() public App()
{ {
@@ -40,6 +41,9 @@ public class App
IServiceCollection serviceCollection = new ServiceCollection(); IServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<ILater>(_later);
serviceCollection.AddSingleton<IConfigProvider>(new ConfigProvider(new ConfigJson()));
foreach (var type in Utils.GetAssignableTypes<IService>()) foreach (var type in Utils.GetAssignableTypes<IService>())
{ {
serviceCollection.AddSingleton(type); serviceCollection.AddSingleton(type);
@@ -50,6 +54,11 @@ public class App
serviceCollection.AddSingleton(type); serviceCollection.AddSingleton(type);
} }
foreach (var type in Utils.GetAssignableTypes<ILaunchReceiver>())
{
serviceCollection.AddSingleton(type);
}
serviceCollection.AddSingleton(openGl); serviceCollection.AddSingleton(openGl);
serviceCollection.AddSingleton(window); serviceCollection.AddSingleton(window);
@@ -68,6 +77,12 @@ public class App
_imGuiPanels = Utils.GetAssignableTypes<IImGuiPanel>() _imGuiPanels = Utils.GetAssignableTypes<IImGuiPanel>()
.Select(t => (serviceProvider.GetService(t) as IImGuiPanel)!) .Select(t => (serviceProvider.GetService(t) as IImGuiPanel)!)
.ToList(); .ToList();
foreach (var type in Utils.GetAssignableTypes<ILaunchReceiver>())
{
var launchReceiver = serviceProvider.GetService(type) as ILaunchReceiver;
launchReceiver?.OnLaunch();
}
} }
public void OnImGuiRender() public void OnImGuiRender()
@@ -123,6 +138,11 @@ public class App
{ {
imGuiPanel.OnImGuiRender(); imGuiPanel.OnImGuiRender();
} }
foreach (var action in _later.Enumerate())
{
action();
}
// ImGui.ShowMetricsWindow(); // ImGui.ShowMetricsWindow();
// ImGui.ShowDemoWindow(); // 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 ViewportScene _scene;
private readonly ViewportCamera _camera = new(); private readonly ViewportCamera _camera = new();
private readonly ViewportInputController _inputController = new(); private readonly ViewportInputController _inputController = new();
private readonly IConfigProvider _configProvider;
private string? _loadedModelPath; private string? _loadedModelPath;
private string? _loadError; 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 cubeMesh = PrimitiveMeshes.CreateCube(gl);
var gridMesh = PrimitiveMeshes.CreateWorldGrid(gl); var gridMesh = PrimitiveMeshes.CreateWorldGrid(gl);
@@ -94,7 +96,7 @@ public sealed class ViewportPanel : IImGuiPanel
if (ImGui.Button("Reset cube")) if (ImGui.Button("Reset cube"))
{ {
var cubeMesh = PrimitiveMeshes.CreateCube(_renderer.Gl); var cubeMesh = PrimitiveMeshes.CreateCube(_renderer.Gl);
_scene.ReplacePieces(new[] { ViewportPiece.CreateUnitCube(0, "Cube", cubeMesh) }); _scene.ReplacePieces([ViewportPiece.CreateUnitCube(0, "Cube", cubeMesh)]);
_loadedModelPath = null; _loadedModelPath = null;
_loadError = null; _loadError = null;
_camera.Reset(); _camera.Reset();
@@ -109,7 +111,7 @@ public sealed class ViewportPanel : IImGuiPanel
private void LoadMsh(string path) private void LoadMsh(string path)
{ {
var loadResult = MshViewportLoader.LoadFromFile(_renderer.Gl, path); var loadResult = MshViewportLoader.LoadFromFile(_renderer.Gl, path, _configProvider);
if (!loadResult.IsSuccess) if (!loadResult.IsSuccess)
{ {
_loadError = loadResult.Error ?? "Unknown error."; _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 System.Numerics;
using MshLib; using MshLib;
using NResLib; using NResLib;
using NResUI.Abstractions;
using NResUI.Rendering.Viewport.Meshes; using NResUI.Rendering.Viewport.Meshes;
using Silk.NET.OpenGL; using Silk.NET.OpenGL;
@@ -11,7 +12,7 @@ public static class MshViewportLoader
private const int DefaultModelState = 0; private const int DefaultModelState = 0;
private const int DefaultLod = 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 try
{ {
@@ -30,7 +31,7 @@ public static class MshViewportLoader
} }
fs.Seek(0, SeekOrigin.Begin); fs.Seek(0, SeekOrigin.Begin);
var pieces = LoadModelPieces(gl, fs, archive, path); var pieces = LoadModelPieces(gl, fs, archive, path, configProvider);
if (pieces.Count == 0) if (pieces.Count == 0)
return MshViewportLoadResult.Failure("MSH was parsed, but no renderable geometry pieces were found.", path); 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 nodes = Msh0x01.ReadComponent(fs, archive);
var geometry = Msh0x02.ReadComponent(fs, archive); var geometry = Msh0x02.ReadComponent(fs, archive);
@@ -54,7 +57,7 @@ public static class MshViewportLoader
var restPoses = MshRestPoseBuilder.BuildRestPose(nodes, animationDescriptors); var restPoses = MshRestPoseBuilder.BuildRestPose(nodes, animationDescriptors);
var mshToViewportTransform = Matrix4x4.CreateRotationX(-MathF.PI * 0.5f); var mshToViewportTransform = Matrix4x4.CreateRotationX(-MathF.PI * 0.5f);
var names = TryReadNames(fs, archive); var names = TryReadNames(fs, archive);
var materialLibrary = WeaMaterialLibrary.TryLoadForMsh(gl, path); var materialLibrary = WeaMaterialLibrary.TryLoadForMsh(gl, path, configProvider);
var pieces = new List<ViewportPiece>(); var pieces = new List<ViewportPiece>();
@@ -1,5 +1,6 @@
using MaterialLib; using MaterialLib;
using NResLib; using NResLib;
using NResUI.Abstractions;
using NResUI.Rendering.Viewport.OpenGL; using NResUI.Rendering.Viewport.OpenGL;
using Silk.NET.OpenGL; using Silk.NET.OpenGL;
using TexmLib; using TexmLib;
@@ -24,7 +25,7 @@ public sealed class WeaMaterialLibrary
: null; : null;
} }
public static WeaMaterialLibrary TryLoadForMsh(GL gl, string mshPath) public static WeaMaterialLibrary TryLoadForMsh(GL gl, string mshPath, IConfigProvider configProvider)
{ {
var weaPath = FindMatchingWeaPath(mshPath); var weaPath = FindMatchingWeaPath(mshPath);
if (!File.Exists(weaPath)) if (!File.Exists(weaPath))
@@ -34,9 +35,13 @@ public sealed class WeaMaterialLibrary
if (materialRefs.Count == 0) if (materialRefs.Count == 0)
return Empty; return Empty;
// TODO: Hardcoded for now var materialLibFs = Path.Combine(configProvider.GetConfig().GameBasePath, "Material.lib");
var materialLibFs = "C:\\IronStrategy\\Material.lib";
if (!File.Exists(materialLibFs))
{
return new WeaMaterialLibrary([]);
}
using var materialFs = new FileStream(materialLibFs, FileMode.Open, FileAccess.Read, FileShare.Read); using var materialFs = new FileStream(materialLibFs, FileMode.Open, FileAccess.Read, FileShare.Read);
var parseResult = NResParser.ReadFile(materialFs); var parseResult = NResParser.ReadFile(materialFs);
if (parseResult.Archive == null) if (parseResult.Archive == null)
@@ -46,7 +51,7 @@ public sealed class WeaMaterialLibrary
foreach (var materialRef in materialRefs) 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 result[materialRef.Id] = texture != null
? new ViewportMaterial(materialRef.Name, texture.Value, texm) ? new ViewportMaterial(materialRef.Name, texture.Value, texm)
: new ViewportMaterial(materialRef.Name); : new ViewportMaterial(materialRef.Name);
@@ -194,7 +199,8 @@ public sealed class WeaMaterialLibrary
} }
private static uint? TryLoadMaterialTexture( 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; texm = null;
@@ -212,7 +218,12 @@ public sealed class WeaMaterialLibrary
var texture = materialFile.Stages[0].TextureName; 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); using var textureFs = new FileStream(textureLibFs, FileMode.Open, FileAccess.Read, FileShare.Read);
var textureResult = NResParser.ReadFile(textureFs); var textureResult = NResParser.ReadFile(textureFs);
@@ -269,27 +280,5 @@ public sealed class WeaMaterialLibrary
Normalize(x.FileName) == normalized); 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); private readonly record struct WeaMaterialRef(int Id, string Name);
} }