mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Test Penumbra loading CharacterUtility.
This commit is contained in:
parent
32cf729aa8
commit
5aeff6d40f
5 changed files with 92 additions and 84 deletions
|
|
@ -62,13 +62,12 @@ public unsafe class CharacterUtility : IDisposable
|
||||||
public CharacterUtility()
|
public CharacterUtility()
|
||||||
{
|
{
|
||||||
SignatureHelper.Initialise( this );
|
SignatureHelper.Initialise( this );
|
||||||
|
LoadingFinished += () => PluginLog.Debug( "Loading of CharacterUtility finished." );
|
||||||
Dalamud.Framework.Update += LoadDefaultResources;
|
LoadDefaultResources( true );
|
||||||
LoadingFinished += () => PluginLog.Debug( "Loading of CharacterUtility finished." );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We store the default data of the resources so we can always restore them.
|
// We store the default data of the resources so we can always restore them.
|
||||||
private void LoadDefaultResources( object _ )
|
private void LoadDefaultResources( bool repeat )
|
||||||
{
|
{
|
||||||
var missingCount = 0;
|
var missingCount = 0;
|
||||||
if( Address == null )
|
if( Address == null )
|
||||||
|
|
@ -95,10 +94,15 @@ public unsafe class CharacterUtility : IDisposable
|
||||||
|
|
||||||
if( missingCount == 0 )
|
if( missingCount == 0 )
|
||||||
{
|
{
|
||||||
Dalamud.Framework.Update -= LoadDefaultResources;
|
Ready = true;
|
||||||
Ready = true;
|
|
||||||
LoadingFinished.Invoke();
|
LoadingFinished.Invoke();
|
||||||
}
|
}
|
||||||
|
else if( repeat )
|
||||||
|
{
|
||||||
|
PluginLog.Debug( "Custom load of character resources triggered." );
|
||||||
|
LoadCharacterResources();
|
||||||
|
LoadDefaultResources( false );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the data of one of the stored resources to a given pointer and length.
|
// Set the data of one of the stored resources to a given pointer and length.
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,8 @@ public unsafe partial class ResourceLoader
|
||||||
[FieldOffset( 20 )]
|
[FieldOffset( 20 )]
|
||||||
public uint SegmentLength;
|
public uint SegmentLength;
|
||||||
|
|
||||||
public bool IsPartialRead => SegmentLength != 0;
|
public bool IsPartialRead
|
||||||
|
=> SegmentLength != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public delegate ResourceHandle* GetResourceSyncPrototype( ResourceManager* resourceManager, ResourceCategory* pCategoryId,
|
public delegate ResourceHandle* GetResourceSyncPrototype( ResourceManager* resourceManager, ResourceCategory* pCategoryId,
|
||||||
|
|
@ -83,12 +84,25 @@ public unsafe partial class ResourceLoader
|
||||||
|
|
||||||
ResourceRequested?.Invoke( gamePath, isSync );
|
ResourceRequested?.Invoke( gamePath, isSync );
|
||||||
|
|
||||||
|
// Force metadata tables to load synchronously and not be able to be replaced.
|
||||||
|
switch( *resourceType )
|
||||||
|
{
|
||||||
|
case ResourceType.Eqp:
|
||||||
|
case ResourceType.Gmp:
|
||||||
|
case ResourceType.Eqdp:
|
||||||
|
case ResourceType.Cmp:
|
||||||
|
case ResourceType.Est:
|
||||||
|
PluginLog.Verbose( "Forced resource {gamePath} to be loaded synchronously.", gamePath );
|
||||||
|
return CallOriginalHandler( true, resourceManager, categoryId, resourceType, resourceHash, path, pGetResParams, isUnk );
|
||||||
|
}
|
||||||
|
|
||||||
// If no replacements are being made, we still want to be able to trigger the event.
|
// If no replacements are being made, we still want to be able to trigger the event.
|
||||||
var (resolvedPath, data) = ResolvePath( gamePath, *categoryId, *resourceType, *resourceHash );
|
var (resolvedPath, data) = ResolvePath( gamePath, *categoryId, *resourceType, *resourceHash );
|
||||||
PathResolved?.Invoke( gamePath, *resourceType, resolvedPath, data );
|
PathResolved?.Invoke( gamePath, *resourceType, resolvedPath, data );
|
||||||
if( resolvedPath == null )
|
if( resolvedPath == null )
|
||||||
{
|
{
|
||||||
var retUnmodified = CallOriginalHandler( isSync, resourceManager, categoryId, resourceType, resourceHash, path, pGetResParams, isUnk );
|
var retUnmodified =
|
||||||
|
CallOriginalHandler( isSync, resourceManager, categoryId, resourceType, resourceHash, path, pGetResParams, isUnk );
|
||||||
ResourceLoaded?.Invoke( ( Structs.ResourceHandle* )retUnmodified, gamePath, null, data );
|
ResourceLoaded?.Invoke( ( Structs.ResourceHandle* )retUnmodified, gamePath, null, data );
|
||||||
return retUnmodified;
|
return retUnmodified;
|
||||||
}
|
}
|
||||||
|
|
@ -247,13 +261,15 @@ public unsafe partial class ResourceLoader
|
||||||
private int ComputeHash( Utf8String path, GetResourceParameters* pGetResParams )
|
private int ComputeHash( Utf8String path, GetResourceParameters* pGetResParams )
|
||||||
{
|
{
|
||||||
if( pGetResParams == null || !pGetResParams->IsPartialRead )
|
if( pGetResParams == null || !pGetResParams->IsPartialRead )
|
||||||
|
{
|
||||||
return path.Crc32;
|
return path.Crc32;
|
||||||
|
}
|
||||||
|
|
||||||
// When the game requests file only partially, crc32 includes that information, in format of:
|
// When the game requests file only partially, crc32 includes that information, in format of:
|
||||||
// path/to/file.ext.hex_offset.hex_size
|
// path/to/file.ext.hex_offset.hex_size
|
||||||
// ex) music/ex4/BGM_EX4_System_Title.scd.381adc.30000
|
// ex) music/ex4/BGM_EX4_System_Title.scd.381adc.30000
|
||||||
return Utf8String.Join(
|
return Utf8String.Join(
|
||||||
(byte)'.',
|
( byte )'.',
|
||||||
path,
|
path,
|
||||||
Utf8String.FromStringUnsafe( pGetResParams->SegmentOffset.ToString( "x" ), true ),
|
Utf8String.FromStringUnsafe( pGetResParams->SegmentOffset.ToString( "x" ), true ),
|
||||||
Utf8String.FromStringUnsafe( pGetResParams->SegmentLength.ToString( "x" ), true )
|
Utf8String.FromStringUnsafe( pGetResParams->SegmentLength.ToString( "x" ), true )
|
||||||
|
|
|
||||||
|
|
@ -22,75 +22,16 @@ using Penumbra.Collections;
|
||||||
using Penumbra.Interop.Loader;
|
using Penumbra.Interop.Loader;
|
||||||
using Penumbra.Interop.Resolver;
|
using Penumbra.Interop.Resolver;
|
||||||
using Penumbra.Mods;
|
using Penumbra.Mods;
|
||||||
|
using CharacterUtility = Penumbra.Interop.CharacterUtility;
|
||||||
|
using ResidentResourceManager = Penumbra.Interop.ResidentResourceManager;
|
||||||
|
|
||||||
namespace Penumbra;
|
namespace Penumbra;
|
||||||
|
|
||||||
public class MainClass : IDalamudPlugin
|
public class Penumbra : IDalamudPlugin
|
||||||
{
|
{
|
||||||
private Penumbra? _penumbra;
|
|
||||||
private readonly CharacterUtility _characterUtility;
|
|
||||||
public static bool DevPenumbraExists;
|
|
||||||
public static bool IsNotInstalledPenumbra;
|
|
||||||
|
|
||||||
public MainClass( DalamudPluginInterface pluginInterface )
|
|
||||||
{
|
|
||||||
Dalamud.Initialize( pluginInterface );
|
|
||||||
DevPenumbraExists = CheckDevPluginPenumbra();
|
|
||||||
IsNotInstalledPenumbra = CheckIsNotInstalled();
|
|
||||||
GameData.GameData.GetIdentifier( Dalamud.GameData, Dalamud.ClientState.ClientLanguage );
|
|
||||||
_characterUtility = new CharacterUtility();
|
|
||||||
_characterUtility.LoadingFinished += ()
|
|
||||||
=> _penumbra = new Penumbra( _characterUtility );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_penumbra?.Dispose();
|
|
||||||
_characterUtility.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Name
|
public string Name
|
||||||
=> Penumbra.Name;
|
=> "Penumbra";
|
||||||
|
|
||||||
// Because remnants of penumbra in devPlugins cause issues, we check for them to warn users to remove them.
|
|
||||||
private static bool CheckDevPluginPenumbra()
|
|
||||||
{
|
|
||||||
#if !DEBUG
|
|
||||||
var path = Path.Combine( Dalamud.PluginInterface.DalamudAssetDirectory.Parent?.FullName ?? "INVALIDPATH", "devPlugins", "Penumbra" );
|
|
||||||
var dir = new DirectoryInfo( path );
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return dir.Exists && dir.EnumerateFiles( "*.dll", SearchOption.AllDirectories ).Any();
|
|
||||||
}
|
|
||||||
catch( Exception e )
|
|
||||||
{
|
|
||||||
PluginLog.Error( $"Could not check for dev plugin Penumbra:\n{e}" );
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the loaded version of penumbra itself is in devPlugins.
|
|
||||||
private static bool CheckIsNotInstalled()
|
|
||||||
{
|
|
||||||
#if !DEBUG
|
|
||||||
var checkedDirectory = Dalamud.PluginInterface.AssemblyLocation.Directory?.Parent?.Parent?.Name;
|
|
||||||
var ret = checkedDirectory?.Equals( "installedPlugins", StringComparison.OrdinalIgnoreCase ) ?? false;
|
|
||||||
if (!ret)
|
|
||||||
PluginLog.Error($"Penumbra is not correctly installed. Application loaded from \"{Dalamud.PluginInterface.AssemblyLocation.Directory!.FullName}\"." );
|
|
||||||
return !ret;
|
|
||||||
#else
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Penumbra : IDisposable
|
|
||||||
{
|
|
||||||
public const string Name = "Penumbra";
|
|
||||||
private const string CommandName = "/penumbra";
|
private const string CommandName = "/penumbra";
|
||||||
|
|
||||||
public static readonly string Version = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? string.Empty;
|
public static readonly string Version = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? string.Empty;
|
||||||
|
|
@ -98,6 +39,9 @@ public class Penumbra : IDisposable
|
||||||
public static readonly string CommitHash =
|
public static readonly string CommitHash =
|
||||||
Assembly.GetExecutingAssembly().GetCustomAttribute< AssemblyInformationalVersionAttribute >()?.InformationalVersion ?? "Unknown";
|
Assembly.GetExecutingAssembly().GetCustomAttribute< AssemblyInformationalVersionAttribute >()?.InformationalVersion ?? "Unknown";
|
||||||
|
|
||||||
|
public static bool DevPenumbraExists;
|
||||||
|
public static bool IsNotInstalledPenumbra;
|
||||||
|
|
||||||
public static Configuration Config { get; private set; } = null!;
|
public static Configuration Config { get; private set; } = null!;
|
||||||
|
|
||||||
public static ResidentResourceManager ResidentResources { get; private set; } = null!;
|
public static ResidentResourceManager ResidentResources { get; private set; } = null!;
|
||||||
|
|
@ -122,9 +66,12 @@ public class Penumbra : IDisposable
|
||||||
|
|
||||||
internal WebServer? WebServer;
|
internal WebServer? WebServer;
|
||||||
|
|
||||||
public Penumbra( CharacterUtility characterUtility )
|
public Penumbra( DalamudPluginInterface pluginInterface )
|
||||||
{
|
{
|
||||||
CharacterUtility = characterUtility;
|
Dalamud.Initialize( pluginInterface );
|
||||||
|
GameData.GameData.GetIdentifier( Dalamud.GameData, Dalamud.ClientState.ClientLanguage );
|
||||||
|
DevPenumbraExists = CheckDevPluginPenumbra();
|
||||||
|
IsNotInstalledPenumbra = CheckIsNotInstalled();
|
||||||
|
|
||||||
Framework = new FrameworkManager();
|
Framework = new FrameworkManager();
|
||||||
Backup.CreateBackup( PenumbraBackupFiles() );
|
Backup.CreateBackup( PenumbraBackupFiles() );
|
||||||
|
|
@ -134,8 +81,10 @@ public class Penumbra : IDisposable
|
||||||
TempMods = new TempModManager();
|
TempMods = new TempModManager();
|
||||||
MetaFileManager = new MetaFileManager();
|
MetaFileManager = new MetaFileManager();
|
||||||
ResourceLoader = new ResourceLoader( this );
|
ResourceLoader = new ResourceLoader( this );
|
||||||
ResourceLogger = new ResourceLogger( ResourceLoader );
|
ResourceLoader.EnableHooks();
|
||||||
ModManager = new Mod.Manager( Config.ModDirectory );
|
ResourceLogger = new ResourceLogger( ResourceLoader );
|
||||||
|
CharacterUtility = new CharacterUtility();
|
||||||
|
ModManager = new Mod.Manager( Config.ModDirectory );
|
||||||
ModManager.DiscoverMods();
|
ModManager.DiscoverMods();
|
||||||
CollectionManager = new ModCollection.Manager( ModManager );
|
CollectionManager = new ModCollection.Manager( ModManager );
|
||||||
ModFileSystem = ModFileSystem.Load();
|
ModFileSystem = ModFileSystem.Load();
|
||||||
|
|
@ -151,18 +100,17 @@ public class Penumbra : IDisposable
|
||||||
|
|
||||||
SetupInterface( out _configWindow, out _launchButton, out _windowSystem );
|
SetupInterface( out _configWindow, out _launchButton, out _windowSystem );
|
||||||
|
|
||||||
if( Config.EnableHttpApi )
|
|
||||||
{
|
|
||||||
CreateWebServer();
|
|
||||||
}
|
|
||||||
|
|
||||||
ResourceLoader.EnableHooks();
|
|
||||||
if( Config.EnableMods )
|
if( Config.EnableMods )
|
||||||
{
|
{
|
||||||
ResourceLoader.EnableReplacements();
|
ResourceLoader.EnableReplacements();
|
||||||
PathResolver.Enable();
|
PathResolver.Enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( Config.EnableHttpApi )
|
||||||
|
{
|
||||||
|
CreateWebServer();
|
||||||
|
}
|
||||||
|
|
||||||
if( Config.DebugMode )
|
if( Config.DebugMode )
|
||||||
{
|
{
|
||||||
ResourceLoader.EnableDebug();
|
ResourceLoader.EnableDebug();
|
||||||
|
|
@ -508,8 +456,11 @@ public class Penumbra : IDisposable
|
||||||
{
|
{
|
||||||
var collection = CollectionManager.ByType( type );
|
var collection = CollectionManager.ByType( type );
|
||||||
if( collection != null )
|
if( collection != null )
|
||||||
|
{
|
||||||
sb.AppendFormat( "> **`{0,-29}`** {1}... ({2})\n", type.ToName(), CollectionName( collection ), collection.Index );
|
sb.AppendFormat( "> **`{0,-29}`** {1}... ({2})\n", type.ToName(), CollectionName( collection ), collection.Index );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach( var (name, collection) in CollectionManager.Characters )
|
foreach( var (name, collection) in CollectionManager.Characters )
|
||||||
{
|
{
|
||||||
sb.AppendFormat( "> **`{2,-29}`** {0}... ({1})\n", CollectionName( collection ),
|
sb.AppendFormat( "> **`{2,-29}`** {0}... ({1})\n", CollectionName( collection ),
|
||||||
|
|
@ -523,4 +474,39 @@ public class Penumbra : IDisposable
|
||||||
|
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Because remnants of penumbra in devPlugins cause issues, we check for them to warn users to remove them.
|
||||||
|
private static bool CheckDevPluginPenumbra()
|
||||||
|
{
|
||||||
|
#if !DEBUG
|
||||||
|
var path = Path.Combine( Dalamud.PluginInterface.DalamudAssetDirectory.Parent?.FullName ?? "INVALIDPATH", "devPlugins", "Penumbra" );
|
||||||
|
var dir = new DirectoryInfo( path );
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return dir.Exists && dir.EnumerateFiles( "*.dll", SearchOption.AllDirectories ).Any();
|
||||||
|
}
|
||||||
|
catch( Exception e )
|
||||||
|
{
|
||||||
|
PluginLog.Error( $"Could not check for dev plugin Penumbra:\n{e}" );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the loaded version of penumbra itself is in devPlugins.
|
||||||
|
private static bool CheckIsNotInstalled()
|
||||||
|
{
|
||||||
|
#if !DEBUG
|
||||||
|
var checkedDirectory = Dalamud.PluginInterface.AssemblyLocation.Directory?.Parent?.Parent?.Name;
|
||||||
|
var ret = checkedDirectory?.Equals( "installedPlugins", StringComparison.OrdinalIgnoreCase ) ?? false;
|
||||||
|
if (!ret)
|
||||||
|
PluginLog.Error($"Penumbra is not correctly installed. Application loaded from \"{Dalamud.PluginInterface.AssemblyLocation.Directory!.FullName}\"." );
|
||||||
|
return !ret;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -9,5 +9,7 @@
|
||||||
"Tags": [ "modding" ],
|
"Tags": [ "modding" ],
|
||||||
"DalamudApiLevel": 6,
|
"DalamudApiLevel": 6,
|
||||||
"LoadPriority": 69420,
|
"LoadPriority": 69420,
|
||||||
|
"LoadRequiredState": 2,
|
||||||
|
"LoadSync": true,
|
||||||
"IconUrl": "https://raw.githubusercontent.com/xivdev/Penumbra/master/images/icon.png"
|
"IconUrl": "https://raw.githubusercontent.com/xivdev/Penumbra/master/images/icon.png"
|
||||||
}
|
}
|
||||||
|
|
@ -60,7 +60,7 @@ public sealed partial class ConfigWindow : Window, IDisposable
|
||||||
+ "It is recommended to not use TexTools and Penumbra (or other Lumina-based tools) at the same time.\n\n"
|
+ "It is recommended to not use TexTools and Penumbra (or other Lumina-based tools) at the same time.\n\n"
|
||||||
+ "Please use the Launcher's Repair Game Files function to repair your client installation." );
|
+ "Please use the Launcher's Repair Game Files function to repair your client installation." );
|
||||||
}
|
}
|
||||||
else if( MainClass.IsNotInstalledPenumbra )
|
else if( Penumbra.IsNotInstalledPenumbra )
|
||||||
{
|
{
|
||||||
DrawProblemWindow(
|
DrawProblemWindow(
|
||||||
$"You are loading a release version of Penumbra from \"{Dalamud.PluginInterface.AssemblyLocation.Directory?.FullName ?? "Unknown"}\" instead of the installedPlugins directory.\n\n"
|
$"You are loading a release version of Penumbra from \"{Dalamud.PluginInterface.AssemblyLocation.Directory?.FullName ?? "Unknown"}\" instead of the installedPlugins directory.\n\n"
|
||||||
|
|
@ -68,7 +68,7 @@ public sealed partial class ConfigWindow : Window, IDisposable
|
||||||
+ "If you do not know how to do this, please take a look at the readme in Penumbras github repository or join us in discord.\n"
|
+ "If you do not know how to do this, please take a look at the readme in Penumbras github repository or join us in discord.\n"
|
||||||
+ "If you are developing for Penumbra and see this, you should compile your version in debug mode to avoid it." );
|
+ "If you are developing for Penumbra and see this, you should compile your version in debug mode to avoid it." );
|
||||||
}
|
}
|
||||||
else if( MainClass.DevPenumbraExists )
|
else if( Penumbra.DevPenumbraExists )
|
||||||
{
|
{
|
||||||
DrawProblemWindow(
|
DrawProblemWindow(
|
||||||
$"You are loading a installed version of Penumbra from \"{Dalamud.PluginInterface.AssemblyLocation.Directory?.FullName ?? "Unknown"}\", "
|
$"You are loading a installed version of Penumbra from \"{Dalamud.PluginInterface.AssemblyLocation.Directory?.FullName ?? "Unknown"}\", "
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue