Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 37 additions & 5 deletions core/fh/bootloader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,14 @@ private static FhManifest[] _init_manifests() {
for (int i = 0; i < ModPaths.Length; i++) {
using FileStream manifest_file = File.OpenRead(ModPaths[i].ManifestPath);

result[i] = JsonSerializer.Deserialize<FhManifest>(manifest_file, FhUtil.InternalJsonOpts)
?? throw new Exception($"Failed to load manifest at {ModPaths[i].ManifestPath}");
try {
result[i] = JsonSerializer.Deserialize<FhManifest>(manifest_file, FhUtil.InternalJsonOpts)
?? throw new Exception($"Manifest at {ModPaths[i].ManifestPath} was empty or uninterpretable.");
}
catch {
FhInternal.Log.Error($"While attempting to read manifest at {ModPaths[i].ManifestPath}:");
throw;
}
}

return result;
Expand Down Expand Up @@ -158,7 +164,15 @@ internal FhLoader() {
/// Performs DLL loading for a mod, returning the <see cref="FhModuleContext"/>s of the instantiated mods.
/// </summary>
internal IEnumerable<FhModuleContext> load_mod(FhManifest manifest) {
string dll_path = FhEnvironment.Finder.get_for_dll(manifest.Id);
string dll_path = FhEnvironment.Finder.get_for_dll(manifest.Id);

/* [fkelava 02/04/26 00:44]
* Fahrenheit supports file-only mods. Such mods contain no DLL, ergo there are no modules in their mod context.
*/

if (!File.Exists(dll_path))
yield break;

FhLoadContext load_context = new FhLoadContext(manifest.Id, dll_path);
Assembly assembly = load_context.LoadFromAssemblyPath(dll_path);

Expand All @@ -179,8 +193,26 @@ internal IEnumerable<FhModuleContext> load_mod(FhManifest manifest) {
continue;
}

FhModule module = Activator.CreateInstance(type) as FhModule ?? throw new Exception($"Constructor of module {type.FullName} threw or faulted.");
FhModulePaths module_paths = FhEnvironment.Finder.get_for_module(manifest.Id, module.ModuleType);
FhModule module;
FhModulePaths module_paths;

try {
/* [fkelava 02/04/26 01:00]
* https://learn.microsoft.com/en-us/dotnet/api/system.activator.createinstance?view=net-10.0#system-activator-createinstance(system-type)
*
* > Returns {...} a reference to the newly created object, or null for Nullable<T> instances.
* > Nullable<T> represents a value type that can be assigned 'null'.
*
* FhModule is a class, thus value types cannot inherit from it, so the return value must be non-null.
*/

module = (Activator.CreateInstance(type) as FhModule)!;
module_paths = FhEnvironment.Finder.get_for_module(manifest.Id, module.ModuleType);
}
catch {
FhInternal.Log.Error($"Constructor of module {type.FullName} threw or faulted.");
throw;
}

yield return new FhModuleContext(module, module_paths);
}
Expand Down
11 changes: 9 additions & 2 deletions core/fh/handles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,15 @@ public bool hook() {

FhInternal.Log.Info($"{hook_fptr.Method.Name}; 0x{addr_target:X8} -> 0x{addr_hook:X8}.");

if (FhPInvoke.MH_CreateHook(addr_target, addr_hook, &addr_original) != 0) throw new Exception("FH_E_NATIVE_HOOK_CREATE_FAILED");
if (FhPInvoke.MH_EnableHook(addr_target) != 0) throw new Exception("FH_E_NATIVE_HOOK_ENABLE_FAILED");
if (FhPInvoke.MH_CreateHook(addr_target, addr_hook, &addr_original) != 0) {
FhInternal.Log.Error($"MH_CreateHook() failed for {hook_fptr.Method.Name}");
return false;
}

if (FhPInvoke.MH_EnableHook(addr_target) != 0) {
FhInternal.Log.Error($"MH_EnableHook() failed for {hook_fptr.Method.Name}");
return false;
}

orig_fptr = Marshal.GetDelegateForFunctionPointer<T>(addr_original);
FhInternal.MethodAddressMap.set(fn_addr, addr_original);
Expand Down
2 changes: 0 additions & 2 deletions core/runtime/src/cd.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ internal unsafe struct Cd {
/// <summary>
/// Performs certain overrides on the game's 'CD' reading emulation
/// to allow for modified files to be properly loaded.
/// <para/>
/// Do not interface with this module. It has no public API.
/// </summary>
[FhLoad(FhGameId.FFX | FhGameId.FFX2 | FhGameId.FFX2LM)]
public unsafe sealed class FhCdInterfaceModule : FhModule {
Expand Down
2 changes: 0 additions & 2 deletions core/runtime/src/devhandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ internal void assign_devices(

/// <summary>
/// Intercepts the game's initialization to obtain the appropriate native API handles.
/// <para/>
/// Do not interface with this module directly.
/// </summary>
[FhLoad(FhGameId.FFX | FhGameId.FFX2 | FhGameId.FFX2LM)]
[SupportedOSPlatform("windows")] // To satisfy CA1416 warning about invoking D3D/DXGI API which TerraFX annotates as supported only on Windows.
Expand Down
14 changes: 1 addition & 13 deletions core/runtime/src/imgui.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,5 @@
// SPDX-License-Identifier: MIT

/* [fkelava 5/7/25 14:16]
* Hexa bundles some definitions for D3D11 structures that we need to use when interfacing
* with its API. They are defined this way because we prefer the TerraFX definitions in all other cases.
*/
using HexaID3D11Device = Hexa.NET.ImGui.Backends.D3D11.ID3D11Device;
using HexaID3D11DeviceContext = Hexa.NET.ImGui.Backends.D3D11.ID3D11DeviceContext;
using HexaID3D11DeviceContextPtr = Hexa.NET.ImGui.Backends.D3D11.ID3D11DeviceContextPtr;
using HexaID3D11DevicePtr = Hexa.NET.ImGui.Backends.D3D11.ID3D11DevicePtr;

using ImGuiImplD3D11 = Hexa.NET.ImGui.Backends.D3D11.ImGuiImplD3D11;
using ImGuiImplWin32 = Hexa.NET.ImGui.Backends.Win32.ImGuiImplWin32;

namespace Fahrenheit.Runtime;

[UnmanagedFunctionPointer(CallingConvention.Winapi)]
Expand Down Expand Up @@ -71,7 +59,7 @@ internal unsafe delegate HRESULT DirectX_D3D11CreateDeviceAndSwapChain(
/// <summary>
/// Provides the ability to use the ImGui GUI toolkit within the game.
/// <para/>
/// Do not interface with this module directly. Instead, implement <see cref="FhModule.render_imgui"/>.
/// In your module, implement <see cref="FhModule.render_imgui"/>.
/// </summary>
[FhLoad(FhGameId.FFX | FhGameId.FFX2 | FhGameId.FFX2LM)]
[SupportedOSPlatform("windows")] // To satisfy CA1416 warning about invoking D3D/DXGI API which TerraFX annotates as supported only on Windows.
Expand Down
2 changes: 1 addition & 1 deletion core/runtime/src/lifecycle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace Fahrenheit.Runtime;
/// Executes the lifecycle methods of <see cref="FhModule"/>.<br/>
/// Also renders the modlist on the main menu.
/// <para/>
/// Do not interface with this module directly. Instead, override <see cref="FhModule.handle_input">.
/// In your module, override <see cref="FhModule.handle_input">.
/// </summary>
[FhLoad(FhGameId.FFX | FhGameId.FFX2 | FhGameId.FFX2LM)]
public unsafe class FhCoreModule : FhModule {
Expand Down
3 changes: 1 addition & 2 deletions core/runtime/src/localstate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ namespace Fahrenheit.Runtime;
/// <summary>
/// Implements the 'local state' mechanism of Fahrenheit.
/// <para/>
/// Do not interface with this module directly. Instead, implement
/// <see cref="FhModule.load_local_state(FileStream, FhLocalStateInfo)"/>
/// In your module, implement <see cref="FhModule.load_local_state(FileStream, FhLocalStateInfo)"/>
/// and <see cref="FhModule.save_local_state(FileStream)"/>.
/// </summary>
[FhLoad(FhGameId.FFX | FhGameId.FFX2 | FhGameId.FFX2LM)]
Expand Down
17 changes: 1 addition & 16 deletions core/runtime/src/resloader.cs
Original file line number Diff line number Diff line change
@@ -1,26 +1,11 @@
// SPDX-License-Identifier: MIT

/* [fkelava 5/7/25 14:16]
* Hexa bundles some definitions for D3D11 structures that we need to use when interfacing
* with its API. They are defined this way because we prefer the TerraFX definitions in all other cases.
*/
using DirectXTex = Hexa.NET.DirectXTex.DirectXTex;
using Hexa_DDSFlags = Hexa.NET.DirectXTex.DDSFlags;
using Hexa_Extensions = Hexa.NET.DirectXTex.Extensions;
using Hexa_HRESULT = HexaGen.Runtime.HResult;
using Hexa_ID3D11Device = Hexa.NET.DirectXTex.ID3D11Device;
using Hexa_ID3D11SRV = Hexa.NET.DirectXTex.ID3D11ShaderResourceView;
using Hexa_ScratchImage = Hexa.NET.DirectXTex.ScratchImage;
using Hexa_TexMetadata = Hexa.NET.DirectXTex.TexMetadata;
using Hexa_TGAFlags = Hexa.NET.DirectXTex.TGAFlags;
using Hexa_WICFlags = Hexa.NET.DirectXTex.WICFlags;

namespace Fahrenheit.Runtime;

/// <summary>
/// Loads textures and other resources at runtime.
/// <para/>
/// Do not interface with this module directly. Instead, call <see cref="FhApi.Resources"/>.
/// In your module, call <see cref="FhApi.Resources"/>.
/// </summary>
[FhLoad(FhGameId.FFX | FhGameId.FFX2 | FhGameId.FFX2LM)]
public unsafe sealed class FhResourceLoaderModule : FhModule, IFhResourceLoader, IFhNativeGraphicsUser {
Expand Down
2 changes: 0 additions & 2 deletions core/runtime/src/save_impl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ internal enum FhSaveExtensionSystemState {

/// <summary>
/// Implements Fahrenheit's extended save system.
/// <para/>
/// Do not interface with this module. It has no public API.
/// </summary>
[FhLoad(FhGameId.FFX | FhGameId.FFX2 | FhGameId.FFX2LM)]
public unsafe sealed class FhSaveExtensionModule : FhModule {
Expand Down
2 changes: 0 additions & 2 deletions core/runtime/src/save_mgr.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ namespace Fahrenheit.Runtime;

/// <summary>
/// Allows multiple sets of saves to exist.
/// <para/>
/// Do not interface with this module. It has no public API.
/// </summary>
[FhLoad(FhGameId.FFX | FhGameId.FFX2 | FhGameId.FFX2LM)]
public sealed class FhSaveManagerModule : FhModule {
Expand Down
25 changes: 24 additions & 1 deletion core/runtime/src/usings.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,27 @@
global using System; // primitives
/* [fkelava 5/7/25 14:16]
* Hexa bundles some definitions for D3D11 structures that we need to use when interfacing
* with its API. They are defined this way because we prefer the TerraFX definitions in all other cases.
*/
global using HexaID3D11Device = Hexa.NET.ImGui.Backends.D3D11.ID3D11Device;
global using HexaID3D11DeviceContext = Hexa.NET.ImGui.Backends.D3D11.ID3D11DeviceContext;
global using HexaID3D11DeviceContextPtr = Hexa.NET.ImGui.Backends.D3D11.ID3D11DeviceContextPtr;
global using HexaID3D11DevicePtr = Hexa.NET.ImGui.Backends.D3D11.ID3D11DevicePtr;

global using ImGuiImplD3D11 = Hexa.NET.ImGui.Backends.D3D11.ImGuiImplD3D11;
global using ImGuiImplWin32 = Hexa.NET.ImGui.Backends.Win32.ImGuiImplWin32;

global using DirectXTex = Hexa.NET.DirectXTex.DirectXTex;
global using Hexa_DDSFlags = Hexa.NET.DirectXTex.DDSFlags;
global using Hexa_Extensions = Hexa.NET.DirectXTex.Extensions;
global using Hexa_HRESULT = HexaGen.Runtime.HResult;
global using Hexa_ID3D11Device = Hexa.NET.DirectXTex.ID3D11Device;
global using Hexa_ID3D11SRV = Hexa.NET.DirectXTex.ID3D11ShaderResourceView;
global using Hexa_ScratchImage = Hexa.NET.DirectXTex.ScratchImage;
global using Hexa_TexMetadata = Hexa.NET.DirectXTex.TexMetadata;
global using Hexa_TGAFlags = Hexa.NET.DirectXTex.TGAFlags;
global using Hexa_WICFlags = Hexa.NET.DirectXTex.WICFlags;

global using System; // primitives
global using System.Buffers.Binary; // BinaryPrimitives et al.
global using System.Collections.Generic; // List<T>, Dictionary<T,U> and others
global using System.Diagnostics.CodeAnalysis; // [NotNullWhen] contract
Expand Down
Loading
Loading