mirror of
https://github.com/MaSzyna-EU07/StarterNG.git
synced 2026-11-15 20:44:12 +01:00
Compare commits
6 Commits
v1.5.230
...
fix/reshad
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e2dbf9eac | ||
|
|
91c496ab48 | ||
|
|
744720d922 | ||
|
|
b5ba67430f | ||
|
|
c261d4b0ab | ||
|
|
3aa6a256a5 |
@@ -65,6 +65,19 @@ public class PhysicsAndAssetsTests
|
||||
Assert.Equal(125, physics.VMax);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_dot_in_the_model_name_is_part_of_the_name()
|
||||
{
|
||||
// As in the game: cd/9-107_v1 holds 9-107.13.fiz, 9-107.6.fiz and more.
|
||||
var installation = new TestInstallation(new InMemoryFileSystem()
|
||||
.WithFile(Fiz("cd", "9-107_v1", "9-107.13"), "Load: LoadAccepted=coal MaxLoad=58")
|
||||
.WithFile(Fiz("cd", "9-107_v1", "9-107.6"), "Load: LoadAccepted=coal MaxLoad=55"));
|
||||
|
||||
Assert.Equal(58, installation.Physics.For("cd/9-107_v1/", "9-107.13")!.MaxLoad);
|
||||
Assert.Equal(55, installation.Physics.For("cd/9-107_v1/", "9-107.6")!.MaxLoad);
|
||||
Assert.Equal(58, installation.Physics.For("cd/9-107_v1/", "9-107.13.e3d")!.MaxLoad);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_dumb_variant_stands_in_when_the_model_has_no_fiz_of_its_own()
|
||||
{
|
||||
|
||||
45
StarterNG.Tests/SoftwareRenderTests.cs
Normal file
45
StarterNG.Tests/SoftwareRenderTests.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using Avalonia;
|
||||
using StarterNG.Infrastructure;
|
||||
|
||||
namespace StarterNG.Tests;
|
||||
|
||||
public class SoftwareRenderTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("--software-render")]
|
||||
[InlineData("--Software-Render")]
|
||||
public void The_switch_asks_for_it_in_any_case(string arg)
|
||||
{
|
||||
Assert.True(SoftwareRender.AskedIn(new[] { "--other", arg }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Without_the_switch_the_graphics_card_draws()
|
||||
{
|
||||
Assert.False(SoftwareRender.AskedIn(Array.Empty<string>()));
|
||||
Assert.False(SoftwareRender.AskedIn(new[] { "--software" }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Windows_draws_on_the_processor_into_a_plain_window_surface()
|
||||
{
|
||||
var options = SoftwareRender.Win32Options;
|
||||
|
||||
Assert.Equal(new[] { Win32RenderingMode.Software }, options.RenderingMode);
|
||||
Assert.Equal(new[] { Win32CompositionMode.RedirectionSurface }, options.CompositionMode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void X11_draws_on_the_processor()
|
||||
{
|
||||
Assert.Equal(new[] { X11RenderingMode.Software }, SoftwareRender.X11Options.RenderingMode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Both_platforms_options_go_to_the_same_builder()
|
||||
{
|
||||
var builder = AppBuilder.Configure<Avalonia.Application>();
|
||||
|
||||
Assert.Same(builder, SoftwareRender.ApplyTo(builder));
|
||||
}
|
||||
}
|
||||
98
StarterNG.Tests/SystemGraphicsLibrariesTests.cs
Normal file
98
StarterNG.Tests/SystemGraphicsLibrariesTests.cs
Normal file
@@ -0,0 +1,98 @@
|
||||
using StarterNG.Infrastructure;
|
||||
|
||||
namespace StarterNG.Tests;
|
||||
|
||||
public class SystemGraphicsLibrariesTests
|
||||
{
|
||||
private const string System32 = @"C:\Windows\System32";
|
||||
private const string Game = @"E:\SteamLibrary\steamapps\common\MaSzyna";
|
||||
|
||||
private static readonly IntPtr Dxgi = new(0x1000);
|
||||
private static readonly IntPtr D3d11 = new(0x2000);
|
||||
|
||||
private static SystemGraphicsLibraries Take(Func<string, bool> beside, Dictionary<string, IntPtr> system)
|
||||
{
|
||||
return SystemGraphicsLibraries.Take(System32, Game, beside, Load);
|
||||
|
||||
bool Load(string path, out IntPtr handle)
|
||||
{
|
||||
handle = system.GetValueOrDefault(Path.GetFileName(path));
|
||||
return handle != IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
private static SystemGraphicsLibraries WithDxgiAndD3d11(Func<string, bool> beside) =>
|
||||
Take(beside, new Dictionary<string, IntPtr> { ["dxgi.dll"] = Dxgi, ["d3d11.dll"] = D3d11 });
|
||||
|
||||
[Fact]
|
||||
public void An_import_by_name_gets_the_system_library_with_or_without_its_extension()
|
||||
{
|
||||
var taken = WithDxgiAndD3d11(_ => false);
|
||||
|
||||
Assert.Equal(Dxgi, taken.Resolve("dxgi"));
|
||||
Assert.Equal(Dxgi, taken.Resolve("dxgi.dll"));
|
||||
Assert.Equal(D3d11, taken.Resolve("D3D11.DLL"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Other_libraries_and_ones_the_system_lacks_are_left_to_the_usual_search()
|
||||
{
|
||||
var taken = WithDxgiAndD3d11(_ => false);
|
||||
|
||||
Assert.Equal(IntPtr.Zero, taken.Resolve("user32.dll"));
|
||||
Assert.Equal(IntPtr.Zero, taken.Resolve("opengl32"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void They_are_loaded_from_the_system_folder_dxgi_first()
|
||||
{
|
||||
var asked = new List<string>();
|
||||
SystemGraphicsLibraries.Take(System32, Game, _ => false, Load);
|
||||
|
||||
Assert.Equal(SystemGraphicsLibraries.Names.Select(n => Path.Combine(System32, n + ".dll")), asked);
|
||||
Assert.Equal("dxgi", SystemGraphicsLibraries.Names[0]);
|
||||
|
||||
bool Load(string path, out IntPtr handle)
|
||||
{
|
||||
asked.Add(path);
|
||||
handle = IntPtr.Zero;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_wrapper_beside_the_starter_is_noted()
|
||||
{
|
||||
var taken = WithDxgiAndD3d11(path => path == Path.Combine(Game, "dxgi.dll"));
|
||||
|
||||
Assert.Equal(new[] { "dxgi.dll" }, taken.Shadowed);
|
||||
Assert.Contains("dxgi.dll", taken.Note);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void With_nothing_beside_the_starter_there_is_nothing_to_note()
|
||||
{
|
||||
var taken = WithDxgiAndD3d11(_ => false);
|
||||
|
||||
Assert.Empty(taken.Shadowed);
|
||||
Assert.Null(taken.Note);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Only_windows_has_system_libraries_to_take()
|
||||
{
|
||||
var taken = SystemGraphicsLibraries.TakeOnWindows();
|
||||
|
||||
Assert.Equal(OperatingSystem.IsWindows(), taken is not null);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void An_assembly_with_a_resolver_of_its_own_keeps_it()
|
||||
{
|
||||
var taken = WithDxgiAndD3d11(_ => false);
|
||||
var assembly = typeof(SystemGraphicsLibrariesTests).Assembly;
|
||||
|
||||
Assert.True(taken.ServeTo(assembly));
|
||||
Assert.False(taken.ServeTo(assembly));
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,6 @@ public static class AppInfo
|
||||
#if DEBUG
|
||||
text += " (DEBUG)";
|
||||
#endif
|
||||
return text + " public beta";
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
32
StarterNG/Infrastructure/SoftwareRender.cs
Normal file
32
StarterNG/Infrastructure/SoftwareRender.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Avalonia;
|
||||
|
||||
namespace StarterNG.Infrastructure;
|
||||
|
||||
/// <summary>
|
||||
/// Drawn by the processor instead of the graphics card, for a machine on which the
|
||||
/// window comes up empty. Each platform reads only its own options, so both are given.
|
||||
/// </summary>
|
||||
public static class SoftwareRender
|
||||
{
|
||||
public const string Switch = "--software-render";
|
||||
|
||||
public static bool AskedIn(IEnumerable<string> args) =>
|
||||
args.Any(a => string.Equals(a, Switch, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
public static Win32PlatformOptions Win32Options => new()
|
||||
{
|
||||
RenderingMode = new[] { Win32RenderingMode.Software },
|
||||
CompositionMode = new[] { Win32CompositionMode.RedirectionSurface }
|
||||
};
|
||||
|
||||
public static X11PlatformOptions X11Options => new()
|
||||
{
|
||||
RenderingMode = new[] { X11RenderingMode.Software }
|
||||
};
|
||||
|
||||
public static AppBuilder ApplyTo(AppBuilder builder) =>
|
||||
builder.With(Win32Options).With(X11Options);
|
||||
}
|
||||
90
StarterNG/Infrastructure/SystemGraphicsLibraries.cs
Normal file
90
StarterNG/Infrastructure/SystemGraphicsLibraries.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace StarterNG.Infrastructure;
|
||||
|
||||
/// <summary>
|
||||
/// The starter sits in the simulator's folder, and so do the graphics wrappers a player
|
||||
/// puts there for the simulator - ReShade and the like, named after the system library
|
||||
/// they stand in for. Windows looks in the program's own folder first, so the starter's
|
||||
/// window drew through them too, and with some of them it drew nothing at all.
|
||||
/// Loaded from System32 by full path before anything asks for them, these names are
|
||||
/// taken: a native library that asks by name gets the system one. .NET looks beside the
|
||||
/// program by full path before it asks by name, so the window code's own imports are
|
||||
/// handed the same libraries. The simulator is a process of its own and still finds its
|
||||
/// wrappers.
|
||||
/// Elsewhere there is nothing of the kind to keep out. Under Wine or Proton the system
|
||||
/// folder is the prefix's, so what is taken there is what would have been taken anyway.
|
||||
/// </summary>
|
||||
public sealed class SystemGraphicsLibraries
|
||||
{
|
||||
public delegate bool Loader(string path, out IntPtr handle);
|
||||
|
||||
// dxgi ahead of d3d11, which asks for it.
|
||||
public static readonly IReadOnlyList<string> Names = new[] { "dxgi", "d3d11", "d3d9", "opengl32" };
|
||||
|
||||
private readonly Dictionary<string, IntPtr> _loaded = new(StringComparer.OrdinalIgnoreCase);
|
||||
private readonly List<string> _shadowed = new();
|
||||
|
||||
private SystemGraphicsLibraries()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>The files of these names that lay beside the starter.</summary>
|
||||
public IReadOnlyList<string> Shadowed => _shadowed;
|
||||
|
||||
/// <summary>What goes to the log about them, or null when none lay there.</summary>
|
||||
public string? Note => _shadowed.Count > 0
|
||||
? $"Graphics libraries beside the starter, left to the simulator: {string.Join(", ", _shadowed)}"
|
||||
: null;
|
||||
|
||||
/// <summary>The libraries of this Windows, or null on any other system.</summary>
|
||||
public static SystemGraphicsLibraries? TakeOnWindows() =>
|
||||
OperatingSystem.IsWindows()
|
||||
? Take(Environment.SystemDirectory, AppContext.BaseDirectory, File.Exists, NativeLibrary.TryLoad)
|
||||
: null;
|
||||
|
||||
public static SystemGraphicsLibraries Take(string systemDirectory, string ownDirectory,
|
||||
Func<string, bool> exists, Loader load)
|
||||
{
|
||||
var taken = new SystemGraphicsLibraries();
|
||||
foreach (string name in Names)
|
||||
{
|
||||
string file = name + ".dll";
|
||||
if (exists(Path.Combine(ownDirectory, file)))
|
||||
taken._shadowed.Add(file);
|
||||
if (load(Path.Combine(systemDirectory, file), out IntPtr handle))
|
||||
taken._loaded[name] = handle;
|
||||
}
|
||||
return taken;
|
||||
}
|
||||
|
||||
/// <summary>The system library for an import of one of these names; zero leaves it to the usual search.</summary>
|
||||
public IntPtr Resolve(string libraryName)
|
||||
{
|
||||
string name = libraryName.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)
|
||||
? libraryName[..^4]
|
||||
: libraryName;
|
||||
return _loaded.TryGetValue(name, out IntPtr handle) ? handle : IntPtr.Zero;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The assembly's imports of these names get the system libraries. False when it
|
||||
/// has a resolver of its own already; that one decides.
|
||||
/// </summary>
|
||||
public bool ServeTo(Assembly importer)
|
||||
{
|
||||
try
|
||||
{
|
||||
NativeLibrary.SetDllImportResolver(importer, (name, _, _) => Resolve(name));
|
||||
return true;
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,7 @@ public sealed class FizPhysicsRepository : IPhysicsRepository
|
||||
if (string.IsNullOrEmpty(model))
|
||||
return null;
|
||||
|
||||
string name = Path.GetFileNameWithoutExtension(model);
|
||||
string name = Path.GetFileName(model);
|
||||
if (name.Length == 0)
|
||||
return null;
|
||||
|
||||
@@ -60,7 +60,10 @@ public sealed class FizPhysicsRepository : IPhysicsRepository
|
||||
if (_cache.TryGetValue(key, out var cached))
|
||||
return cached;
|
||||
|
||||
var physics = Read(folder, name);
|
||||
// The name as written first: in 9-107.13 the dot is part of the name, not an extension.
|
||||
string bare = Path.GetFileNameWithoutExtension(name);
|
||||
var physics = Read(folder, name)
|
||||
?? (bare.Length > 0 && bare != name ? Read(folder, bare) : null);
|
||||
_cache[key] = physics;
|
||||
return physics;
|
||||
}
|
||||
|
||||
@@ -10,12 +10,22 @@ namespace StarterNG;
|
||||
static class Program
|
||||
{
|
||||
|
||||
private static bool _softwareRender;
|
||||
|
||||
[STAThread]
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
// Ahead of everything that could draw: what lies beside the starter is the simulator's.
|
||||
var graphics = SystemGraphicsLibraries.TakeOnWindows();
|
||||
graphics?.ServeTo(typeof(Win32PlatformOptions).Assembly);
|
||||
|
||||
_softwareRender = SoftwareRender.AskedIn(args);
|
||||
|
||||
// Composition root first: everything below, including the crash handlers,
|
||||
// resolves its collaborators from this graph.
|
||||
AppServices.Initialize();
|
||||
if (graphics?.Note is { } note)
|
||||
Diagnostics.Log(note);
|
||||
|
||||
AppDomain.CurrentDomain.UnhandledException += (_, e) =>
|
||||
{
|
||||
@@ -63,9 +73,13 @@ static class Program
|
||||
};
|
||||
}
|
||||
|
||||
private static AppBuilder WithSoftwareRenderIfAsked(this AppBuilder builder) =>
|
||||
_softwareRender ? SoftwareRender.ApplyTo(builder) : builder;
|
||||
|
||||
public static AppBuilder BuildAvaloniaApp()
|
||||
=> AppBuilder.Configure<App>()
|
||||
.UsePlatformDetect()
|
||||
.WithSoftwareRenderIfAsked()
|
||||
.WithInterFont()
|
||||
.WithDiagnosticsLogging()
|
||||
.AfterSetup(_ => LogUiExceptions());
|
||||
|
||||
Reference in New Issue
Block a user