mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-13 12:14:17 +01:00
fix #11, reshuffled some UI and added a button to the main menu/lobby
This commit is contained in:
parent
15eb435929
commit
8adeab1ba5
12 changed files with 399 additions and 134 deletions
|
|
@ -12,6 +12,10 @@ namespace Penumbra
|
||||||
|
|
||||||
public bool IsEnabled { get; set; } = true;
|
public bool IsEnabled { get; set; } = true;
|
||||||
|
|
||||||
|
public bool ShowAdvanced { get; set; } = false;
|
||||||
|
|
||||||
|
public bool DisableFileSystemNotifications { get; set; } = false;
|
||||||
|
|
||||||
public string CurrentCollection { get; set; } = @"D:/ffxiv/fs_mods/";
|
public string CurrentCollection { get; set; } = @"D:/ffxiv/fs_mods/";
|
||||||
|
|
||||||
public List< string > ModCollections { get; set; } = new();
|
public List< string > ModCollections { get; set; } = new();
|
||||||
|
|
|
||||||
50
Penumbra/Game/GameUtils.cs
Normal file
50
Penumbra/Game/GameUtils.cs
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Dalamud.Plugin;
|
||||||
|
using Reloaded.Hooks.Definitions.X64;
|
||||||
|
|
||||||
|
namespace Penumbra.Game
|
||||||
|
{
|
||||||
|
public class GameUtils
|
||||||
|
{
|
||||||
|
private readonly DalamudPluginInterface _pluginInterface;
|
||||||
|
|
||||||
|
[Function( CallingConventions.Microsoft )]
|
||||||
|
public unsafe delegate void* LoadPlayerResourcesPrototype( IntPtr pResourceManager );
|
||||||
|
|
||||||
|
[Function( CallingConventions.Microsoft )]
|
||||||
|
public unsafe delegate void* UnloadPlayerResourcesPrototype( IntPtr pResourceManager );
|
||||||
|
|
||||||
|
|
||||||
|
public LoadPlayerResourcesPrototype LoadPlayerResources { get; private set; }
|
||||||
|
public UnloadPlayerResourcesPrototype UnloadPlayerResources { get; private set; }
|
||||||
|
|
||||||
|
// Object addresses
|
||||||
|
private IntPtr _playerResourceManagerAddress;
|
||||||
|
public IntPtr PlayerResourceManagerPtr => Marshal.ReadIntPtr( _playerResourceManagerAddress );
|
||||||
|
|
||||||
|
public GameUtils( DalamudPluginInterface pluginInterface )
|
||||||
|
{
|
||||||
|
_pluginInterface = pluginInterface;
|
||||||
|
|
||||||
|
var scanner = _pluginInterface.TargetModuleScanner;
|
||||||
|
|
||||||
|
var loadPlayerResourcesAddress =
|
||||||
|
scanner.ScanText(
|
||||||
|
"E8 ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? BA ?? ?? ?? ?? 41 B8 ?? ?? ?? ?? 48 8B 48 30 48 8B 01 FF 50 10 48 85 C0 74 0A " );
|
||||||
|
var unloadPlayerResourcesAddress =
|
||||||
|
scanner.ScanText( "41 55 48 81 EC ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 84 24 ?? ?? ?? ?? 4C 8B E9 48 83 C1 08" );
|
||||||
|
|
||||||
|
_playerResourceManagerAddress = scanner.GetStaticAddressFromSig( "0F 44 FE 48 8B 0D ?? ?? ?? ?? 48 85 C9 74 05" );
|
||||||
|
|
||||||
|
LoadPlayerResources = Marshal.GetDelegateForFunctionPointer< LoadPlayerResourcesPrototype >( loadPlayerResourcesAddress );
|
||||||
|
UnloadPlayerResources = Marshal.GetDelegateForFunctionPointer< UnloadPlayerResourcesPrototype >( unloadPlayerResourcesAddress );
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe void ReloadPlayerResources()
|
||||||
|
{
|
||||||
|
UnloadPlayerResources( PlayerResourceManagerPtr );
|
||||||
|
LoadPlayerResources( PlayerResourceManagerPtr );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
Penumbra/Importer/ImporterState.cs
Normal file
10
Penumbra/Importer/ImporterState.cs
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
namespace Penumbra.Importer
|
||||||
|
{
|
||||||
|
public enum ImporterState
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
WritingPackToDisk,
|
||||||
|
ExtractingModFiles,
|
||||||
|
Done
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using Lumina.Data;
|
||||||
|
|
||||||
|
namespace Penumbra.Importer
|
||||||
|
{
|
||||||
|
public class MagicTempFileStreamManagerAndDeleterFuckery : SqPackStream, IDisposable
|
||||||
|
{
|
||||||
|
private readonly FileStream _fileStream;
|
||||||
|
|
||||||
|
public MagicTempFileStreamManagerAndDeleterFuckery( FileStream stream ) : base( stream )
|
||||||
|
{
|
||||||
|
_fileStream = stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public new void Dispose()
|
||||||
|
{
|
||||||
|
var filePath = _fileStream.Name;
|
||||||
|
|
||||||
|
base.Dispose();
|
||||||
|
_fileStream.Dispose();
|
||||||
|
|
||||||
|
File.Delete( filePath );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -16,13 +16,40 @@ namespace Penumbra.Importer
|
||||||
{
|
{
|
||||||
private readonly DirectoryInfo _outDirectory;
|
private readonly DirectoryInfo _outDirectory;
|
||||||
|
|
||||||
|
private const string TempFileName = "textools-import";
|
||||||
|
private readonly string _resolvedTempFilePath = null;
|
||||||
|
|
||||||
|
public ImporterState State { get; private set; }
|
||||||
|
|
||||||
|
public long TotalProgress { get; private set; }
|
||||||
|
public long CurrentProgress { get; private set; }
|
||||||
|
|
||||||
|
public float Progress
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if( CurrentProgress != 0 )
|
||||||
|
{
|
||||||
|
// ReSharper disable twice RedundantCast
|
||||||
|
return ( float )CurrentProgress / ( float )TotalProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string CurrentModPack { get; private set; }
|
||||||
|
|
||||||
public TexToolsImport( DirectoryInfo outDirectory )
|
public TexToolsImport( DirectoryInfo outDirectory )
|
||||||
{
|
{
|
||||||
_outDirectory = outDirectory;
|
_outDirectory = outDirectory;
|
||||||
|
_resolvedTempFilePath = Path.Combine( _outDirectory.FullName, TempFileName );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ImportModPack( FileInfo modPackFile )
|
public void ImportModPack( FileInfo modPackFile )
|
||||||
{
|
{
|
||||||
|
CurrentModPack = modPackFile.Name;
|
||||||
|
|
||||||
switch( modPackFile.Extension )
|
switch( modPackFile.Extension )
|
||||||
{
|
{
|
||||||
case ".ttmp":
|
case ".ttmp":
|
||||||
|
|
@ -33,6 +60,29 @@ namespace Penumbra.Importer
|
||||||
ImportV2ModPack( modPackFile );
|
ImportV2ModPack( modPackFile );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
State = ImporterState.Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteZipEntryToTempFile( Stream s )
|
||||||
|
{
|
||||||
|
var fs = new FileStream( _resolvedTempFilePath, FileMode.Create );
|
||||||
|
s.CopyTo( fs );
|
||||||
|
fs.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private SqPackStream GetMagicSqPackDeleterStream( ZipFile file, string entryName )
|
||||||
|
{
|
||||||
|
State = ImporterState.WritingPackToDisk;
|
||||||
|
|
||||||
|
// write shitty zip garbage to disk
|
||||||
|
var entry = file.GetEntry( entryName );
|
||||||
|
using var s = file.GetInputStream( entry );
|
||||||
|
|
||||||
|
WriteZipEntryToTempFile( s );
|
||||||
|
|
||||||
|
var fs = new FileStream( _resolvedTempFilePath, FileMode.Open );
|
||||||
|
return new MagicTempFileStreamManagerAndDeleterFuckery( fs );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ImportV1ModPack( FileInfo modPackFile )
|
private void ImportV1ModPack( FileInfo modPackFile )
|
||||||
|
|
@ -59,8 +109,7 @@ namespace Penumbra.Importer
|
||||||
};
|
};
|
||||||
|
|
||||||
// Open the mod data file from the modpack as a SqPackStream
|
// Open the mod data file from the modpack as a SqPackStream
|
||||||
var mpd = extractedModPack.GetEntry( "TTMPD.mpd" );
|
using var modData = GetMagicSqPackDeleterStream( extractedModPack, "TTMPD.mpd" );
|
||||||
var modData = GetSqPackStreamFromZipEntry( extractedModPack, mpd );
|
|
||||||
|
|
||||||
var newModFolder = new DirectoryInfo(
|
var newModFolder = new DirectoryInfo(
|
||||||
Path.Combine( _outDirectory.FullName,
|
Path.Combine( _outDirectory.FullName,
|
||||||
|
|
@ -115,8 +164,7 @@ namespace Penumbra.Importer
|
||||||
};
|
};
|
||||||
|
|
||||||
// Open the mod data file from the modpack as a SqPackStream
|
// Open the mod data file from the modpack as a SqPackStream
|
||||||
var mpd = extractedModPack.GetEntry( "TTMPD.mpd" );
|
using var modData = GetMagicSqPackDeleterStream( extractedModPack, "TTMPD.mpd" );
|
||||||
var modData = GetSqPackStreamFromZipEntry( extractedModPack, mpd );
|
|
||||||
|
|
||||||
var newModFolder = new DirectoryInfo( Path.Combine( _outDirectory.FullName,
|
var newModFolder = new DirectoryInfo( Path.Combine( _outDirectory.FullName,
|
||||||
Path.GetFileNameWithoutExtension( modList.Name ) ) );
|
Path.GetFileNameWithoutExtension( modList.Name ) ) );
|
||||||
|
|
@ -142,12 +190,12 @@ namespace Penumbra.Importer
|
||||||
Name = modList.Name,
|
Name = modList.Name,
|
||||||
Description = string.IsNullOrEmpty( modList.Description )
|
Description = string.IsNullOrEmpty( modList.Description )
|
||||||
? "Mod imported from TexTools mod pack"
|
? "Mod imported from TexTools mod pack"
|
||||||
: modList.Description
|
: modList.Description,
|
||||||
|
Version = modList.Version
|
||||||
};
|
};
|
||||||
|
|
||||||
// Open the mod data file from the modpack as a SqPackStream
|
// Open the mod data file from the modpack as a SqPackStream
|
||||||
var mpd = extractedModPack.GetEntry( "TTMPD.mpd" );
|
using var modData = GetMagicSqPackDeleterStream( extractedModPack, "TTMPD.mpd" );
|
||||||
var modData = GetSqPackStreamFromZipEntry( extractedModPack, mpd );
|
|
||||||
|
|
||||||
var newModFolder = new DirectoryInfo(
|
var newModFolder = new DirectoryInfo(
|
||||||
Path.Combine( _outDirectory.FullName,
|
Path.Combine( _outDirectory.FullName,
|
||||||
|
|
@ -187,13 +235,24 @@ namespace Penumbra.Importer
|
||||||
|
|
||||||
private void ExtractSimpleModList( DirectoryInfo outDirectory, IEnumerable< SimpleMod > mods, SqPackStream dataStream )
|
private void ExtractSimpleModList( DirectoryInfo outDirectory, IEnumerable< SimpleMod > mods, SqPackStream dataStream )
|
||||||
{
|
{
|
||||||
|
State = ImporterState.ExtractingModFiles;
|
||||||
|
|
||||||
|
// haha allocation go brr
|
||||||
|
var wtf = mods.ToList();
|
||||||
|
|
||||||
|
TotalProgress = wtf.LongCount();
|
||||||
|
|
||||||
// Extract each SimpleMod into the new mod folder
|
// Extract each SimpleMod into the new mod folder
|
||||||
foreach( var simpleMod in mods )
|
foreach( var simpleMod in wtf )
|
||||||
{
|
{
|
||||||
if( simpleMod == null )
|
if( simpleMod == null )
|
||||||
|
{
|
||||||
|
// do we increment here too???? can this even happen?????
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
ExtractMod( outDirectory, simpleMod, dataStream );
|
ExtractMod( outDirectory, simpleMod, dataStream );
|
||||||
|
CurrentProgress++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -228,10 +287,5 @@ namespace Penumbra.Importer
|
||||||
s.CopyTo( ms );
|
s.CopyTo( ms );
|
||||||
return encoding.GetString( ms.ToArray() );
|
return encoding.GetString( ms.ToArray() );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SqPackStream GetSqPackStreamFromZipEntry( ZipFile file, ZipEntry entry )
|
|
||||||
{
|
|
||||||
return new( GetStreamFromZipEntry( file, entry ) );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7,6 +7,10 @@ namespace Penumbra.Models
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string Author { get; set; }
|
public string Author { get; set; }
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
|
|
||||||
|
public string Version { get; set; }
|
||||||
|
|
||||||
|
public string Website { get; set; }
|
||||||
|
|
||||||
public Dictionary< string, string > FileSwaps { get; } = new();
|
public Dictionary< string, string > FileSwaps { get; } = new();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ namespace Penumbra.Mods
|
||||||
public List< ModInfo > ModSettings { get; set; }
|
public List< ModInfo > ModSettings { get; set; }
|
||||||
public ResourceMod[] EnabledMods { get; set; }
|
public ResourceMod[] EnabledMods { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public ModCollection( DirectoryInfo basePath )
|
public ModCollection( DirectoryInfo basePath )
|
||||||
{
|
{
|
||||||
_basePath = basePath;
|
_basePath = basePath;
|
||||||
|
|
@ -117,7 +118,7 @@ namespace Penumbra.Mods
|
||||||
public void ReorderMod( ModInfo info, bool up )
|
public void ReorderMod( ModInfo info, bool up )
|
||||||
{
|
{
|
||||||
// todo: certified fucked tier
|
// todo: certified fucked tier
|
||||||
|
|
||||||
var prio = info.Priority;
|
var prio = info.Priority;
|
||||||
var swapPrio = up ? prio + 1 : prio - 1;
|
var swapPrio = up ? prio + 1 : prio - 1;
|
||||||
var swapMeta = ModSettings.FirstOrDefault( x => x.Priority == swapPrio );
|
var swapMeta = ModSettings.FirstOrDefault( x => x.Priority == swapPrio );
|
||||||
|
|
@ -126,10 +127,10 @@ namespace Penumbra.Mods
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
info.Priority = swapPrio;
|
info.Priority = swapPrio;
|
||||||
swapMeta.Priority = prio;
|
swapMeta.Priority = prio;
|
||||||
|
|
||||||
// reorder mods list
|
// reorder mods list
|
||||||
ModSettings = ModSettings.OrderBy( x => x.Priority ).ToList();
|
ModSettings = ModSettings.OrderBy( x => x.Priority ).ToList();
|
||||||
EnabledMods = GetOrderedAndEnabledModList().ToArray();
|
EnabledMods = GetOrderedAndEnabledModList().ToArray();
|
||||||
|
|
@ -137,8 +138,7 @@ namespace Penumbra.Mods
|
||||||
// save new prios
|
// save new prios
|
||||||
Save();
|
Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public ModInfo FindModSettings( string name )
|
public ModInfo FindModSettings( string name )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Penumbra.Models;
|
using Penumbra.Models;
|
||||||
|
|
||||||
namespace Penumbra.Mods
|
namespace Penumbra.Mods
|
||||||
{
|
{
|
||||||
public class ModManager
|
public class ModManager : IDisposable
|
||||||
{
|
{
|
||||||
public readonly Dictionary< string, FileInfo > ResolvedFiles = new();
|
public readonly Dictionary< string, FileInfo > ResolvedFiles = new();
|
||||||
public readonly Dictionary< string, string > SwappedFiles = new();
|
public readonly Dictionary< string, string > SwappedFiles = new();
|
||||||
|
|
@ -23,6 +24,33 @@ namespace Penumbra.Mods
|
||||||
DiscoverMods( _basePath );
|
DiscoverMods( _basePath );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// private void FileSystemWatcherOnChanged( object sender, FileSystemEventArgs e )
|
||||||
|
// {
|
||||||
|
// #if DEBUG
|
||||||
|
// PluginLog.Verbose( "file changed: {FullPath}", e.FullPath );
|
||||||
|
// #endif
|
||||||
|
//
|
||||||
|
// if( _plugin.ImportInProgress )
|
||||||
|
// {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if( _plugin.Configuration.DisableFileSystemNotifications )
|
||||||
|
// {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// var file = e.FullPath;
|
||||||
|
//
|
||||||
|
// if( !ResolvedFiles.Any( x => x.Value.FullName == file ) )
|
||||||
|
// {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// PluginLog.Log( "a loaded file has been modified - file: {FullPath}", file );
|
||||||
|
// _plugin.GameUtils.ReloadPlayerResources();
|
||||||
|
// }
|
||||||
|
|
||||||
public void DiscoverMods( string basePath )
|
public void DiscoverMods( string basePath )
|
||||||
{
|
{
|
||||||
DiscoverMods( new DirectoryInfo( basePath ) );
|
DiscoverMods( new DirectoryInfo( basePath ) );
|
||||||
|
|
@ -43,7 +71,21 @@ namespace Penumbra.Mods
|
||||||
|
|
||||||
_basePath = basePath;
|
_basePath = basePath;
|
||||||
|
|
||||||
ResolvedFiles.Clear();
|
// haha spaghet
|
||||||
|
// _fileSystemWatcher?.Dispose();
|
||||||
|
// _fileSystemWatcher = new FileSystemWatcher( _basePath.FullName )
|
||||||
|
// {
|
||||||
|
// NotifyFilter = NotifyFilters.LastWrite |
|
||||||
|
// NotifyFilters.FileName |
|
||||||
|
// NotifyFilters.DirectoryName,
|
||||||
|
// IncludeSubdirectories = true,
|
||||||
|
// EnableRaisingEvents = true
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// _fileSystemWatcher.Changed += FileSystemWatcherOnChanged;
|
||||||
|
// _fileSystemWatcher.Created += FileSystemWatcherOnChanged;
|
||||||
|
// _fileSystemWatcher.Deleted += FileSystemWatcherOnChanged;
|
||||||
|
// _fileSystemWatcher.Renamed += FileSystemWatcherOnChanged;
|
||||||
|
|
||||||
Mods = new ModCollection( basePath );
|
Mods = new ModCollection( basePath );
|
||||||
Mods.Load();
|
Mods.Load();
|
||||||
|
|
@ -62,7 +104,7 @@ namespace Penumbra.Mods
|
||||||
foreach( var mod in Mods.GetOrderedAndEnabledModList() )
|
foreach( var mod in Mods.GetOrderedAndEnabledModList() )
|
||||||
{
|
{
|
||||||
mod.FileConflicts?.Clear();
|
mod.FileConflicts?.Clear();
|
||||||
|
|
||||||
// fixup path
|
// fixup path
|
||||||
var baseDir = mod.ModBasePath.FullName;
|
var baseDir = mod.ModBasePath.FullName;
|
||||||
|
|
||||||
|
|
@ -138,5 +180,10 @@ namespace Penumbra.Mods
|
||||||
|
|
||||||
return GetCandidateForGameFile( gameResourcePath )?.FullName ?? GetSwappedFilePath( gameResourcePath );
|
return GetCandidateForGameFile( gameResourcePath )?.FullName ?? GetSwappedFilePath( gameResourcePath );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
// _fileSystemWatcher?.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7,5 +7,6 @@
|
||||||
"RepoUrl": "https://github.com/xivdev/Penumbra",
|
"RepoUrl": "https://github.com/xivdev/Penumbra",
|
||||||
"ApplicableVersion": "any",
|
"ApplicableVersion": "any",
|
||||||
"Tags": [ "modding" ],
|
"Tags": [ "modding" ],
|
||||||
"DalamudApiLevel": 69420
|
"DalamudApiLevel": 69420,
|
||||||
|
"LoadPriority": 69420
|
||||||
}
|
}
|
||||||
|
|
@ -1,11 +1,6 @@
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.IO;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using Dalamud.Game.Command;
|
using Dalamud.Game.Command;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using Penumbra.Extensions;
|
using Penumbra.Game;
|
||||||
using Penumbra.Mods;
|
using Penumbra.Mods;
|
||||||
using Penumbra.UI;
|
using Penumbra.UI;
|
||||||
|
|
||||||
|
|
@ -18,6 +13,7 @@ namespace Penumbra
|
||||||
private const string CommandName = "/penumbra";
|
private const string CommandName = "/penumbra";
|
||||||
|
|
||||||
public DalamudPluginInterface PluginInterface { get; set; }
|
public DalamudPluginInterface PluginInterface { get; set; }
|
||||||
|
|
||||||
public Configuration Configuration { get; set; }
|
public Configuration Configuration { get; set; }
|
||||||
|
|
||||||
public ResourceLoader ResourceLoader { get; set; }
|
public ResourceLoader ResourceLoader { get; set; }
|
||||||
|
|
@ -26,21 +22,26 @@ namespace Penumbra
|
||||||
|
|
||||||
public SettingsInterface SettingsInterface { get; set; }
|
public SettingsInterface SettingsInterface { get; set; }
|
||||||
|
|
||||||
|
public GameUtils GameUtils { get; set; }
|
||||||
|
|
||||||
public string PluginDebugTitleStr { get; private set; }
|
public string PluginDebugTitleStr { get; private set; }
|
||||||
|
|
||||||
|
public bool ImportInProgress => SettingsInterface?.IsImportRunning ?? true;
|
||||||
|
|
||||||
public void Initialize( DalamudPluginInterface pluginInterface )
|
public void Initialize( DalamudPluginInterface pluginInterface )
|
||||||
{
|
{
|
||||||
PluginInterface = pluginInterface;
|
PluginInterface = pluginInterface;
|
||||||
|
|
||||||
Configuration = PluginInterface.GetPluginConfig() as Configuration ?? new Configuration();
|
Configuration = PluginInterface.GetPluginConfig() as Configuration ?? new Configuration();
|
||||||
Configuration.Initialize( PluginInterface );
|
Configuration.Initialize( PluginInterface );
|
||||||
|
|
||||||
|
GameUtils = new GameUtils( PluginInterface );
|
||||||
|
|
||||||
ModManager = new ModManager();
|
ModManager = new ModManager();
|
||||||
ModManager.DiscoverMods( Configuration.CurrentCollection );
|
ModManager.DiscoverMods( Configuration.CurrentCollection );
|
||||||
|
|
||||||
ResourceLoader = new ResourceLoader( this );
|
ResourceLoader = new ResourceLoader( this );
|
||||||
|
|
||||||
|
|
||||||
PluginInterface.CommandManager.AddHandler( CommandName, new CommandInfo( OnCommand )
|
PluginInterface.CommandManager.AddHandler( CommandName, new CommandInfo( OnCommand )
|
||||||
{
|
{
|
||||||
HelpMessage = "/penumbra - toggle ui\n/penumbra reload - reload mod file lists & discover any new mods"
|
HelpMessage = "/penumbra - toggle ui\n/penumbra reload - reload mod file lists & discover any new mods"
|
||||||
|
|
@ -48,7 +49,7 @@ namespace Penumbra
|
||||||
|
|
||||||
ResourceLoader.Init();
|
ResourceLoader.Init();
|
||||||
ResourceLoader.Enable();
|
ResourceLoader.Enable();
|
||||||
|
|
||||||
SettingsInterface = new SettingsInterface( this );
|
SettingsInterface = new SettingsInterface( this );
|
||||||
PluginInterface.UiBuilder.OnBuildUi += SettingsInterface.Draw;
|
PluginInterface.UiBuilder.OnBuildUi += SettingsInterface.Draw;
|
||||||
|
|
||||||
|
|
@ -57,6 +58,8 @@ namespace Penumbra
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
ModManager?.Dispose();
|
||||||
|
|
||||||
PluginInterface.UiBuilder.OnBuildUi -= SettingsInterface.Draw;
|
PluginInterface.UiBuilder.OnBuildUi -= SettingsInterface.Draw;
|
||||||
|
|
||||||
PluginInterface.CommandManager.RemoveHandler( CommandName );
|
PluginInterface.CommandManager.RemoveHandler( CommandName );
|
||||||
|
|
|
||||||
|
|
@ -36,13 +36,6 @@ namespace Penumbra
|
||||||
public unsafe delegate void* GetResourceAsyncPrototype( IntPtr pFileManager, uint* pCategoryId, char* pResourceType,
|
public unsafe delegate void* GetResourceAsyncPrototype( IntPtr pFileManager, uint* pCategoryId, char* pResourceType,
|
||||||
uint* pResourceHash, char* pPath, void* pUnknown, bool isUnknown );
|
uint* pResourceHash, char* pPath, void* pUnknown, bool isUnknown );
|
||||||
|
|
||||||
[Function( CallingConventions.Microsoft )]
|
|
||||||
public unsafe delegate void* LoadPlayerResourcesPrototype( IntPtr pResourceManager );
|
|
||||||
|
|
||||||
[Function( CallingConventions.Microsoft )]
|
|
||||||
public unsafe delegate void* UnloadPlayerResourcesPrototype( IntPtr pResourceManager );
|
|
||||||
|
|
||||||
|
|
||||||
// Hooks
|
// Hooks
|
||||||
public IHook< GetResourceSyncPrototype > GetResourceSyncHook { get; private set; }
|
public IHook< GetResourceSyncPrototype > GetResourceSyncHook { get; private set; }
|
||||||
public IHook< GetResourceAsyncPrototype > GetResourceAsyncHook { get; private set; }
|
public IHook< GetResourceAsyncPrototype > GetResourceAsyncHook { get; private set; }
|
||||||
|
|
@ -52,14 +45,6 @@ namespace Penumbra
|
||||||
public ReadFilePrototype ReadFile { get; private set; }
|
public ReadFilePrototype ReadFile { get; private set; }
|
||||||
|
|
||||||
|
|
||||||
public LoadPlayerResourcesPrototype LoadPlayerResources { get; private set; }
|
|
||||||
public UnloadPlayerResourcesPrototype UnloadPlayerResources { get; private set; }
|
|
||||||
|
|
||||||
// Object addresses
|
|
||||||
private IntPtr _playerResourceManagerAddress;
|
|
||||||
public IntPtr PlayerResourceManagerPtr => Marshal.ReadIntPtr( _playerResourceManagerAddress );
|
|
||||||
|
|
||||||
|
|
||||||
public bool LogAllFiles = false;
|
public bool LogAllFiles = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -91,20 +76,6 @@ namespace Penumbra
|
||||||
GetResourceAsyncHook = new Hook< GetResourceAsyncPrototype >( GetResourceAsyncHandler, ( long )getResourceAsyncAddress );
|
GetResourceAsyncHook = new Hook< GetResourceAsyncPrototype >( GetResourceAsyncHandler, ( long )getResourceAsyncAddress );
|
||||||
|
|
||||||
ReadFile = Marshal.GetDelegateForFunctionPointer< ReadFilePrototype >( readFileAddress );
|
ReadFile = Marshal.GetDelegateForFunctionPointer< ReadFilePrototype >( readFileAddress );
|
||||||
|
|
||||||
/////
|
|
||||||
|
|
||||||
var loadPlayerResourcesAddress =
|
|
||||||
scanner.ScanText(
|
|
||||||
"E8 ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? BA ?? ?? ?? ?? 41 B8 ?? ?? ?? ?? 48 8B 48 30 48 8B 01 FF 50 10 48 85 C0 74 0A " );
|
|
||||||
var unloadPlayerResourcesAddress =
|
|
||||||
scanner.ScanText( "41 55 48 81 EC ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 84 24 ?? ?? ?? ?? 4C 8B E9 48 83 C1 08" );
|
|
||||||
|
|
||||||
_playerResourceManagerAddress = scanner.GetStaticAddressFromSig( "0F 44 FE 48 8B 0D ?? ?? ?? ?? 48 85 C9 74 05" );
|
|
||||||
|
|
||||||
LoadPlayerResources = Marshal.GetDelegateForFunctionPointer< LoadPlayerResourcesPrototype >( loadPlayerResourcesAddress );
|
|
||||||
UnloadPlayerResources = Marshal.GetDelegateForFunctionPointer< UnloadPlayerResourcesPrototype >( unloadPlayerResourcesAddress );
|
|
||||||
ReadFile = Marshal.GetDelegateForFunctionPointer< ReadFilePrototype >( readFileAddress );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -215,12 +186,6 @@ namespace Penumbra
|
||||||
return ReadFile( pFileHandler, pFileDesc, priority, isSync );
|
return ReadFile( pFileHandler, pFileDesc, priority, isSync );
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe void ReloadPlayerResource()
|
|
||||||
{
|
|
||||||
UnloadPlayerResources( PlayerResourceManagerPtr );
|
|
||||||
LoadPlayerResources( PlayerResourceManagerPtr );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Enable()
|
public void Enable()
|
||||||
{
|
{
|
||||||
if( IsEnabled )
|
if( IsEnabled )
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,8 @@ namespace Penumbra.UI
|
||||||
private int? _selectedModDeleteIndex;
|
private int? _selectedModDeleteIndex;
|
||||||
private ModInfo _selectedMod;
|
private ModInfo _selectedMod;
|
||||||
|
|
||||||
private bool _isImportRunning = false;
|
public bool IsImportRunning = false;
|
||||||
|
private TexToolsImport _texToolsImport = null!;
|
||||||
|
|
||||||
public SettingsInterface( Plugin plugin )
|
public SettingsInterface( Plugin plugin )
|
||||||
{
|
{
|
||||||
|
|
@ -72,6 +73,39 @@ namespace Penumbra.UI
|
||||||
ImGui.EndMainMenuBar();
|
ImGui.EndMainMenuBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( !_plugin.PluginInterface.ClientState.Condition.Any() && !Visible )
|
||||||
|
{
|
||||||
|
// draw mods button on da menu :DDD
|
||||||
|
var ss = ImGui.GetIO().DisplaySize;
|
||||||
|
var padding = 50;
|
||||||
|
var width = 200;
|
||||||
|
var height = 45;
|
||||||
|
|
||||||
|
// magic numbers
|
||||||
|
ImGui.SetNextWindowPos( new Vector2( ss.X - padding - width, ss.Y - padding - height ), ImGuiCond.Always );
|
||||||
|
|
||||||
|
if(
|
||||||
|
ImGui.Begin(
|
||||||
|
"Penumbra Menu Buttons",
|
||||||
|
ImGuiWindowFlags.AlwaysAutoResize |
|
||||||
|
ImGuiWindowFlags.NoBackground |
|
||||||
|
ImGuiWindowFlags.NoDecoration |
|
||||||
|
ImGuiWindowFlags.NoMove |
|
||||||
|
ImGuiWindowFlags.NoScrollbar |
|
||||||
|
ImGuiWindowFlags.NoResize |
|
||||||
|
ImGuiWindowFlags.NoSavedSettings
|
||||||
|
)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if( ImGui.Button( "Manage Mods", new Vector2( width, height ) ) )
|
||||||
|
{
|
||||||
|
Visible = !Visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.End();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if( !Visible )
|
if( !Visible )
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
@ -91,11 +125,19 @@ namespace Penumbra.UI
|
||||||
ImGui.BeginTabBar( "PenumbraSettings" );
|
ImGui.BeginTabBar( "PenumbraSettings" );
|
||||||
|
|
||||||
DrawSettingsTab();
|
DrawSettingsTab();
|
||||||
|
DrawImportTab();
|
||||||
|
|
||||||
if( !_isImportRunning )
|
|
||||||
|
if( !IsImportRunning )
|
||||||
{
|
{
|
||||||
DrawResourceMods();
|
DrawModBrowser();
|
||||||
DrawEffectiveFileList();
|
|
||||||
|
DrawInstalledMods();
|
||||||
|
|
||||||
|
if( _plugin.Configuration.ShowAdvanced )
|
||||||
|
{
|
||||||
|
DrawEffectiveFileList();
|
||||||
|
}
|
||||||
|
|
||||||
DrawDeleteModal();
|
DrawDeleteModal();
|
||||||
}
|
}
|
||||||
|
|
@ -105,6 +147,105 @@ namespace Penumbra.UI
|
||||||
ImGui.End();
|
ImGui.End();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DrawImportTab()
|
||||||
|
{
|
||||||
|
var ret = ImGui.BeginTabItem( "Import Mods" );
|
||||||
|
if( !ret )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !IsImportRunning )
|
||||||
|
{
|
||||||
|
if( ImGui.Button( "Import TexTools Modpacks" ) )
|
||||||
|
{
|
||||||
|
IsImportRunning = true;
|
||||||
|
|
||||||
|
Task.Run( async () =>
|
||||||
|
{
|
||||||
|
var picker = new OpenFileDialog
|
||||||
|
{
|
||||||
|
Multiselect = true,
|
||||||
|
Filter = "TexTools TTMP Modpack (*.ttmp2)|*.ttmp*|All files (*.*)|*.*",
|
||||||
|
CheckFileExists = true,
|
||||||
|
Title = "Pick one or more modpacks."
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await picker.ShowDialogAsync();
|
||||||
|
|
||||||
|
if( result == DialogResult.OK )
|
||||||
|
{
|
||||||
|
foreach( var fileName in picker.FileNames )
|
||||||
|
{
|
||||||
|
PluginLog.Log( "-> {0} START", fileName );
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_texToolsImport = new TexToolsImport( new DirectoryInfo( _plugin.Configuration.CurrentCollection ) );
|
||||||
|
_texToolsImport.ImportModPack( new FileInfo( fileName ) );
|
||||||
|
}
|
||||||
|
catch( Exception ex )
|
||||||
|
{
|
||||||
|
PluginLog.LogError( ex, "Could not import one or more modpacks." );
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginLog.Log( "-> {0} OK!", fileName );
|
||||||
|
}
|
||||||
|
|
||||||
|
_texToolsImport = null;
|
||||||
|
ReloadMods();
|
||||||
|
}
|
||||||
|
|
||||||
|
IsImportRunning = false;
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui.Button( "Import in progress..." );
|
||||||
|
|
||||||
|
if( _texToolsImport != null )
|
||||||
|
{
|
||||||
|
switch( _texToolsImport.State )
|
||||||
|
{
|
||||||
|
case ImporterState.None:
|
||||||
|
break;
|
||||||
|
case ImporterState.WritingPackToDisk:
|
||||||
|
ImGui.Text( "Writing modpack to disk before extracting..." );
|
||||||
|
break;
|
||||||
|
case ImporterState.ExtractingModFiles:
|
||||||
|
{
|
||||||
|
var str =
|
||||||
|
$"{_texToolsImport.CurrentModPack} - {_texToolsImport.CurrentProgress} of {_texToolsImport.TotalProgress} files";
|
||||||
|
|
||||||
|
ImGui.ProgressBar( _texToolsImport.Progress, new Vector2( -1, 0 ), str );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ImporterState.Done:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Conditional( "DEBUG" )]
|
||||||
|
void DrawModBrowser()
|
||||||
|
{
|
||||||
|
var ret = ImGui.BeginTabItem( "Available Mods" );
|
||||||
|
if( !ret )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Text( "woah" );
|
||||||
|
|
||||||
|
ImGui.EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
void DrawSettingsTab()
|
void DrawSettingsTab()
|
||||||
{
|
{
|
||||||
var ret = ImGui.BeginTabItem( "Settings" );
|
var ret = ImGui.BeginTabItem( "Settings" );
|
||||||
|
|
@ -113,11 +254,14 @@ namespace Penumbra.UI
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool dirty = false;
|
||||||
|
|
||||||
// FUCKKKKK
|
// FUCKKKKK
|
||||||
var basePath = _plugin.Configuration.CurrentCollection;
|
var basePath = _plugin.Configuration.CurrentCollection;
|
||||||
if( ImGui.InputText( "Root Folder", ref basePath, 255 ) )
|
if( ImGui.InputText( "Root Folder", ref basePath, 255 ) )
|
||||||
{
|
{
|
||||||
_plugin.Configuration.CurrentCollection = basePath;
|
_plugin.Configuration.CurrentCollection = basePath;
|
||||||
|
dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( ImGui.Button( "Rediscover Mods" ) )
|
if( ImGui.Button( "Rediscover Mods" ) )
|
||||||
|
|
@ -134,77 +278,34 @@ namespace Penumbra.UI
|
||||||
|
|
||||||
ImGui.SetCursorPosY( ImGui.GetCursorPosY() + 15 );
|
ImGui.SetCursorPosY( ImGui.GetCursorPosY() + 15 );
|
||||||
|
|
||||||
#if DEBUG
|
var showAdvanced = _plugin.Configuration.ShowAdvanced;
|
||||||
|
if( ImGui.Checkbox( "Show Advanced Settings", ref showAdvanced ) )
|
||||||
ImGui.Text( "debug shit" );
|
|
||||||
|
|
||||||
if( ImGui.Button( "Reload Player Resource" ) )
|
|
||||||
{
|
{
|
||||||
_plugin.ResourceLoader.ReloadPlayerResource();
|
_plugin.Configuration.ShowAdvanced = showAdvanced;
|
||||||
|
dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( _plugin.ResourceLoader != null )
|
if( _plugin.Configuration.ShowAdvanced )
|
||||||
{
|
{
|
||||||
ImGui.Checkbox( "DEBUG Log all loaded files", ref _plugin.ResourceLoader.LogAllFiles );
|
if( _plugin.ResourceLoader != null )
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.SetCursorPosY( ImGui.GetCursorPosY() + 15 );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( !_isImportRunning )
|
|
||||||
{
|
|
||||||
if( ImGui.Button( "Import TexTools Modpacks" ) )
|
|
||||||
{
|
{
|
||||||
_isImportRunning = true;
|
ImGui.Checkbox( "Log all loaded files", ref _plugin.ResourceLoader.LogAllFiles );
|
||||||
|
}
|
||||||
|
|
||||||
Task.Run( async () =>
|
var fswatch = _plugin.Configuration.DisableFileSystemNotifications;
|
||||||
{
|
if( ImGui.Checkbox( "Disable filesystem change notifications", ref fswatch ) )
|
||||||
var picker = new OpenFileDialog
|
{
|
||||||
{
|
_plugin.Configuration.DisableFileSystemNotifications = fswatch;
|
||||||
Multiselect = true,
|
dirty = true;
|
||||||
Filter = "TexTools TTMP Modpack (*.ttmp2)|*.ttmp*|All files (*.*)|*.*",
|
}
|
||||||
CheckFileExists = true,
|
|
||||||
Title = "Pick one or more modpacks."
|
|
||||||
};
|
|
||||||
|
|
||||||
var result = await picker.ShowDialogAsync();
|
if( ImGui.Button( "Reload Player Resource" ) )
|
||||||
|
{
|
||||||
if( result == DialogResult.OK )
|
_plugin.GameUtils.ReloadPlayerResources();
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var importer =
|
|
||||||
new TexToolsImport( new DirectoryInfo( _plugin.Configuration.CurrentCollection ) );
|
|
||||||
|
|
||||||
foreach( var fileName in picker.FileNames )
|
|
||||||
{
|
|
||||||
PluginLog.Log( "-> {0} START", fileName );
|
|
||||||
|
|
||||||
importer.ImportModPack( new FileInfo( fileName ) );
|
|
||||||
|
|
||||||
PluginLog.Log( "-> {0} OK!", fileName );
|
|
||||||
}
|
|
||||||
|
|
||||||
ReloadMods();
|
|
||||||
}
|
|
||||||
catch( Exception ex )
|
|
||||||
{
|
|
||||||
PluginLog.LogError( ex, "Could not import one or more modpacks." );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_isImportRunning = false;
|
|
||||||
} );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
ImGui.Button( "Import in progress..." );
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.SetCursorPosY( ImGui.GetCursorPosY() + 15 );
|
if( dirty )
|
||||||
|
|
||||||
if( ImGui.Button( "Save Settings" ) )
|
|
||||||
{
|
{
|
||||||
_plugin.Configuration.Save();
|
_plugin.Configuration.Save();
|
||||||
}
|
}
|
||||||
|
|
@ -385,9 +486,9 @@ namespace Penumbra.UI
|
||||||
ImGui.EndPopup();
|
ImGui.EndPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrawResourceMods()
|
void DrawInstalledMods()
|
||||||
{
|
{
|
||||||
var ret = ImGui.BeginTabItem( "Mods" );
|
var ret = ImGui.BeginTabItem( "Installed Mods" );
|
||||||
if( !ret )
|
if( !ret )
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue