mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 10:17:22 +01:00
mod reordering, deleting, conflict resolution, some other fixes
This commit is contained in:
parent
fbb39a8626
commit
7f1fd95a78
10 changed files with 605 additions and 203 deletions
|
|
@ -1,6 +1,7 @@
|
|||
using Dalamud.Configuration;
|
||||
using Dalamud.Plugin;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Penumbra
|
||||
{
|
||||
|
|
@ -11,7 +12,9 @@ namespace Penumbra
|
|||
|
||||
public bool IsEnabled { get; set; } = true;
|
||||
|
||||
public string BaseFolder { get; set; } = @"D:/ffxiv/fs_mods/";
|
||||
public string CurrentCollection { get; set; } = @"D:/ffxiv/fs_mods/";
|
||||
|
||||
public List< string > ModCollections { get; set; } = new();
|
||||
|
||||
// the below exist just to make saving less cumbersome
|
||||
|
||||
|
|
|
|||
|
|
@ -1,100 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Dalamud.Plugin;
|
||||
using Penumbra.Models;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Penumbra
|
||||
{
|
||||
public class ModManager
|
||||
{
|
||||
public DirectoryInfo BasePath { get; set; }
|
||||
|
||||
public readonly Dictionary< string, ResourceMod > AvailableMods = new Dictionary< string, ResourceMod >();
|
||||
|
||||
public readonly Dictionary< string, FileInfo > ResolvedFiles = new Dictionary< string, FileInfo >();
|
||||
|
||||
public ModManager( DirectoryInfo basePath )
|
||||
{
|
||||
BasePath = basePath;
|
||||
}
|
||||
|
||||
public ModManager()
|
||||
{
|
||||
}
|
||||
|
||||
public void DiscoverMods()
|
||||
{
|
||||
if( BasePath == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( !BasePath.Exists )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AvailableMods.Clear();
|
||||
ResolvedFiles.Clear();
|
||||
|
||||
// get all mod dirs
|
||||
foreach( var modDir in BasePath.EnumerateDirectories() )
|
||||
{
|
||||
var metaFile = modDir.EnumerateFiles().FirstOrDefault( f => f.Name == "meta.json" );
|
||||
|
||||
if( metaFile == null )
|
||||
{
|
||||
PluginLog.LogError( "mod meta is missing for resource mod: {ResourceModLocation}", modDir );
|
||||
continue;
|
||||
}
|
||||
|
||||
var meta = JsonConvert.DeserializeObject< Models.ModMeta >( File.ReadAllText( metaFile.FullName ) );
|
||||
|
||||
var mod = new ResourceMod
|
||||
{
|
||||
Meta = meta,
|
||||
ModBasePath = modDir
|
||||
};
|
||||
|
||||
AvailableMods[ modDir.Name ] = mod;
|
||||
mod.RefreshModFiles();
|
||||
}
|
||||
|
||||
// todo: sort the mods by priority here so that the file discovery works correctly
|
||||
|
||||
foreach( var mod in AvailableMods.Select( m => m.Value ) )
|
||||
{
|
||||
// fixup path
|
||||
var baseDir = mod.ModBasePath.FullName;
|
||||
|
||||
foreach( var file in mod.ModFiles )
|
||||
{
|
||||
var path = file.FullName.Substring( baseDir.Length ).ToLowerInvariant()
|
||||
.TrimStart( '\\' ).Replace( '\\', '/' );
|
||||
|
||||
// todo: notify when collisions happen? or some extra state on the file? not sure yet
|
||||
// this code is shit all the same
|
||||
|
||||
if( !ResolvedFiles.ContainsKey( path ) )
|
||||
{
|
||||
ResolvedFiles[ path ] = file;
|
||||
}
|
||||
else
|
||||
{
|
||||
PluginLog.LogError(
|
||||
"a different mod already fucks this file: {FilePath}",
|
||||
ResolvedFiles[ path ].FullName
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public FileInfo GetCandidateForGameFile( string resourcePath )
|
||||
{
|
||||
return ResolvedFiles.TryGetValue( resourcePath.ToLowerInvariant(), out var fileInfo ) ? fileInfo : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Penumbra/Models/ModInfo.cs
Normal file
15
Penumbra/Models/ModInfo.cs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
using Newtonsoft.Json;
|
||||
using Penumbra.Mods;
|
||||
|
||||
namespace Penumbra.Models
|
||||
{
|
||||
public class ModInfo
|
||||
{
|
||||
public string FolderName { get; set; }
|
||||
public bool Enabled { get; set; }
|
||||
public int Priority { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public ResourceMod Mod { get; set; }
|
||||
}
|
||||
}
|
||||
182
Penumbra/Mods/ModCollection.cs
Normal file
182
Penumbra/Mods/ModCollection.cs
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Dalamud.Plugin;
|
||||
using Newtonsoft.Json;
|
||||
using Penumbra.Models;
|
||||
|
||||
namespace Penumbra.Mods
|
||||
{
|
||||
public class ModCollection
|
||||
{
|
||||
private readonly DirectoryInfo _basePath;
|
||||
|
||||
public List< ModInfo > ModSettings { get; set; }
|
||||
public ResourceMod[] EnabledMods { get; set; }
|
||||
|
||||
public ModCollection( DirectoryInfo basePath )
|
||||
{
|
||||
_basePath = basePath;
|
||||
}
|
||||
|
||||
public void Load()
|
||||
{
|
||||
// find the collection json
|
||||
var collectionPath = Path.Combine( _basePath.FullName, "collection.json" );
|
||||
if( File.Exists( collectionPath ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
ModSettings = JsonConvert.DeserializeObject< List< ModInfo > >( File.ReadAllText( collectionPath ) );
|
||||
ModSettings = ModSettings.OrderBy( x => x.Priority ).ToList();
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
PluginLog.Error( $"failed to read log collection information, failed path: {collectionPath}, err: {e.Message}" );
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
if( ModSettings != null )
|
||||
{
|
||||
foreach( var ms in ModSettings )
|
||||
{
|
||||
PluginLog.Information(
|
||||
"mod: {ModName} Enabled: {Enabled} Priority: {Priority}",
|
||||
ms.FolderName, ms.Enabled, ms.Priority
|
||||
);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ModSettings ??= new();
|
||||
var foundMods = new List< string >();
|
||||
|
||||
foreach( var modDir in _basePath.EnumerateDirectories() )
|
||||
{
|
||||
var metaFile = modDir.EnumerateFiles().FirstOrDefault( f => f.Name == "meta.json" );
|
||||
|
||||
if( metaFile == null )
|
||||
{
|
||||
PluginLog.LogError( "mod meta is missing for resource mod: {ResourceModLocation}", modDir );
|
||||
continue;
|
||||
}
|
||||
|
||||
var meta = JsonConvert.DeserializeObject< ModMeta >( File.ReadAllText( metaFile.FullName ) );
|
||||
|
||||
var mod = new ResourceMod
|
||||
{
|
||||
Meta = meta,
|
||||
ModBasePath = modDir
|
||||
};
|
||||
|
||||
var modEntry = FindOrCreateModSettings( mod );
|
||||
foundMods.Add( modDir.Name );
|
||||
mod.RefreshModFiles();
|
||||
}
|
||||
|
||||
// remove any mods from the collection we didn't find
|
||||
ModSettings = ModSettings.Where(
|
||||
x =>
|
||||
foundMods.Any(
|
||||
fm => string.Equals( x.FolderName, fm, StringComparison.InvariantCultureIgnoreCase )
|
||||
)
|
||||
).ToList();
|
||||
|
||||
// reorder the resourcemods list so we can just directly iterate
|
||||
EnabledMods = GetOrderedAndEnabledModList().ToArray();
|
||||
|
||||
// write the collection metadata back to disk
|
||||
Save();
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
var collectionPath = Path.Combine( _basePath.FullName, "collection.json" );
|
||||
|
||||
try
|
||||
{
|
||||
var data = JsonConvert.SerializeObject( ModSettings.OrderBy( x => x.Priority ).ToList() );
|
||||
File.WriteAllText( collectionPath, data );
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
PluginLog.Error( $"failed to write log collection information, failed path: {collectionPath}, err: {e.Message}" );
|
||||
}
|
||||
}
|
||||
|
||||
public void ReorderMod( ModInfo info, bool up )
|
||||
{
|
||||
// todo: certified fucked tier
|
||||
|
||||
var prio = info.Priority;
|
||||
var swapPrio = up ? prio + 1 : prio - 1;
|
||||
var swapMeta = ModSettings.FirstOrDefault( x => x.Priority == swapPrio );
|
||||
|
||||
if( swapMeta == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
info.Priority = swapPrio;
|
||||
swapMeta.Priority = prio;
|
||||
|
||||
// reorder mods list
|
||||
ModSettings = ModSettings.OrderBy( x => x.Priority ).ToList();
|
||||
EnabledMods = GetOrderedAndEnabledModList().ToArray();
|
||||
|
||||
// save new prios
|
||||
Save();
|
||||
}
|
||||
|
||||
public ModInfo FindModSettings( string name )
|
||||
{
|
||||
var settings = ModSettings.FirstOrDefault(
|
||||
x => string.Equals( x.FolderName, name, StringComparison.InvariantCultureIgnoreCase )
|
||||
);
|
||||
#if DEBUG
|
||||
PluginLog.Information( "finding mod {ModName} - found: {ModSettingsExist}", name, settings != null );
|
||||
#endif
|
||||
return settings;
|
||||
}
|
||||
|
||||
public ModInfo AddModSettings( ResourceMod mod )
|
||||
{
|
||||
var entry = new ModInfo
|
||||
{
|
||||
Priority = ModSettings.Count,
|
||||
FolderName = mod.ModBasePath.Name,
|
||||
Enabled = true,
|
||||
Mod = mod
|
||||
};
|
||||
|
||||
#if DEBUG
|
||||
PluginLog.Information( "creating mod settings {ModName}", entry.FolderName );
|
||||
#endif
|
||||
|
||||
ModSettings.Add( entry );
|
||||
return entry;
|
||||
}
|
||||
|
||||
public ModInfo FindOrCreateModSettings( ResourceMod mod )
|
||||
{
|
||||
var settings = FindModSettings( mod.ModBasePath.Name );
|
||||
if( settings != null )
|
||||
{
|
||||
settings.Mod = mod;
|
||||
return settings;
|
||||
}
|
||||
|
||||
return AddModSettings( mod );
|
||||
}
|
||||
|
||||
public IEnumerable< ResourceMod > GetOrderedAndEnabledModList()
|
||||
{
|
||||
return ModSettings
|
||||
.Where( x => x.Enabled )
|
||||
.OrderBy( x => x.Priority )
|
||||
.Select( x => x.Mod );
|
||||
}
|
||||
}
|
||||
}
|
||||
104
Penumbra/Mods/ModManager.cs
Normal file
104
Penumbra/Mods/ModManager.cs
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Penumbra.Models;
|
||||
|
||||
namespace Penumbra.Mods
|
||||
{
|
||||
public class ModManager
|
||||
{
|
||||
public readonly Dictionary< string, FileInfo > ResolvedFiles = new();
|
||||
|
||||
public ModCollection Mods { get; set; }
|
||||
|
||||
public ResourceMod[] AvailableMods => Mods?.EnabledMods;
|
||||
|
||||
private DirectoryInfo _basePath;
|
||||
|
||||
public void DiscoverMods()
|
||||
{
|
||||
if( _basePath == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DiscoverMods( _basePath );
|
||||
}
|
||||
|
||||
public void DiscoverMods( string basePath )
|
||||
{
|
||||
DiscoverMods( new DirectoryInfo( basePath ) );
|
||||
}
|
||||
|
||||
public void DiscoverMods( DirectoryInfo basePath )
|
||||
{
|
||||
if( basePath == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( !basePath.Exists )
|
||||
{
|
||||
Directory.CreateDirectory( basePath.FullName );
|
||||
}
|
||||
|
||||
_basePath = basePath;
|
||||
|
||||
ResolvedFiles.Clear();
|
||||
|
||||
Mods = new ModCollection( basePath );
|
||||
Mods.Load();
|
||||
Mods.Save();
|
||||
|
||||
CalculateEffectiveFileList();
|
||||
}
|
||||
|
||||
public void CalculateEffectiveFileList()
|
||||
{
|
||||
ResolvedFiles.Clear();
|
||||
|
||||
var registeredFiles = new Dictionary< string, string >();
|
||||
|
||||
foreach( var mod in Mods.GetOrderedAndEnabledModList() )
|
||||
{
|
||||
mod.FileConflicts?.Clear();
|
||||
|
||||
// fixup path
|
||||
var baseDir = mod.ModBasePath.FullName;
|
||||
|
||||
foreach( var file in mod.ModFiles )
|
||||
{
|
||||
var path = file.FullName.Substring( baseDir.Length )
|
||||
.TrimStart( '\\' ).Replace( '\\', '/' );
|
||||
|
||||
if( !ResolvedFiles.ContainsKey( path ) )
|
||||
{
|
||||
ResolvedFiles[ path ] = file;
|
||||
registeredFiles[ path ] = mod.Meta.Name;
|
||||
}
|
||||
else if( registeredFiles.TryGetValue( path, out var modName ) )
|
||||
{
|
||||
mod.AddConflict( modName, path );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ChangeModPriority( ModInfo info, bool up = false )
|
||||
{
|
||||
Mods.ReorderMod( info, up );
|
||||
CalculateEffectiveFileList();
|
||||
}
|
||||
|
||||
public void DeleteMod( ResourceMod mod )
|
||||
{
|
||||
Directory.Delete( mod.ModBasePath.FullName, true );
|
||||
DiscoverMods();
|
||||
}
|
||||
|
||||
|
||||
public FileInfo GetCandidateForGameFile( string resourcePath )
|
||||
{
|
||||
return ResolvedFiles.TryGetValue( resourcePath.ToLowerInvariant(), out var fileInfo ) ? fileInfo : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,9 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Dalamud.Plugin;
|
||||
using Penumbra.Models;
|
||||
|
||||
namespace Penumbra
|
||||
namespace Penumbra.Mods
|
||||
{
|
||||
public class ResourceMod
|
||||
{
|
||||
|
|
@ -12,7 +11,9 @@ namespace Penumbra
|
|||
|
||||
public DirectoryInfo ModBasePath { get; set; }
|
||||
|
||||
public List< FileInfo > ModFiles { get; } = new List< FileInfo >();
|
||||
public List< FileInfo > ModFiles { get; } = new();
|
||||
|
||||
public Dictionary< string, List< string > > FileConflicts { get; set; } = new();
|
||||
|
||||
public void RefreshModFiles()
|
||||
{
|
||||
|
|
@ -31,5 +32,23 @@ namespace Penumbra
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddConflict( string modName, string path )
|
||||
{
|
||||
if( FileConflicts.TryGetValue( modName, out var arr ) )
|
||||
{
|
||||
if( !arr.Contains( path ) )
|
||||
{
|
||||
arr.Add( path );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
FileConflicts[ modName ] = new List< string >
|
||||
{
|
||||
path
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,56 +1,63 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<AssemblyTitle>Penumbra</AssemblyTitle>
|
||||
<Company>absolute gangstas</Company>
|
||||
<Product>Penumbra</Product>
|
||||
<Copyright>Copyright © 2020</Copyright>
|
||||
<FileVersion>1.0.0.0</FileVersion>
|
||||
<AssemblyVersion>1.0.0.0</AssemblyVersion>
|
||||
<OutputPath>bin\$(Configuration)\</OutputPath>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugType>full</DebugType>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Dalamud">
|
||||
<HintPath>..\libs\Dalamud.dll</HintPath>
|
||||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\Dalamud.dll</HintPath>
|
||||
<HintPath>$(DALAMUD_ROOT)\Dalamud.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="ImGui.NET">
|
||||
<HintPath>..\libs\ImGui.NET.dll</HintPath>
|
||||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\ImGui.NET.dll</HintPath>
|
||||
<HintPath>$(DALAMUD_ROOT)\ImGui.NET.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="ImGuiScene">
|
||||
<HintPath>..\libs\ImGuiScene.dll</HintPath>
|
||||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\ImGuiScene.dll</HintPath>
|
||||
<HintPath>$(DALAMUD_ROOT)\ImGuiScene.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Lumina">
|
||||
<HintPath>..\libs\Lumina.dll</HintPath>
|
||||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\Lumina.dll</HintPath>
|
||||
<HintPath>$(DALAMUD_ROOT)\Lumina.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DotNetZip" Version="1.13.8" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="Reloaded.Hooks" Version="2.4.1" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<AssemblyTitle>Penumbra</AssemblyTitle>
|
||||
<Company>absolute gangstas</Company>
|
||||
<Product>Penumbra</Product>
|
||||
<Copyright>Copyright © 2020</Copyright>
|
||||
<FileVersion>1.0.0.0</FileVersion>
|
||||
<AssemblyVersion>1.0.0.0</AssemblyVersion>
|
||||
<OutputPath>bin\$(Configuration)\</OutputPath>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugType>full</DebugType>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Dalamud">
|
||||
<HintPath>..\libs\Dalamud.dll</HintPath>
|
||||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\Dalamud.dll</HintPath>
|
||||
<HintPath>$(DALAMUD_ROOT)\Dalamud.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="ImGui.NET">
|
||||
<HintPath>..\libs\ImGui.NET.dll</HintPath>
|
||||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\ImGui.NET.dll</HintPath>
|
||||
<HintPath>$(DALAMUD_ROOT)\ImGui.NET.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="ImGuiScene">
|
||||
<HintPath>..\libs\ImGuiScene.dll</HintPath>
|
||||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\ImGuiScene.dll</HintPath>
|
||||
<HintPath>$(DALAMUD_ROOT)\ImGuiScene.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Lumina">
|
||||
<HintPath>..\libs\Lumina.dll</HintPath>
|
||||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\Lumina.dll</HintPath>
|
||||
<HintPath>$(DALAMUD_ROOT)\Lumina.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DotNetZip" Version="1.13.8" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="Reloaded.Hooks" Version="2.4.1" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -1,6 +1,13 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using Dalamud.Game.Command;
|
||||
using Dalamud.Plugin;
|
||||
using Penumbra.Extensions;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.UI;
|
||||
|
||||
namespace Penumbra
|
||||
{
|
||||
|
|
@ -19,6 +26,8 @@ namespace Penumbra
|
|||
|
||||
public SettingsInterface SettingsInterface { get; set; }
|
||||
|
||||
public string PluginDebugTitleStr { get; private set; }
|
||||
|
||||
public void Initialize( DalamudPluginInterface pluginInterface )
|
||||
{
|
||||
PluginInterface = pluginInterface;
|
||||
|
|
@ -26,8 +35,8 @@ namespace Penumbra
|
|||
Configuration = PluginInterface.GetPluginConfig() as Configuration ?? new Configuration();
|
||||
Configuration.Initialize( PluginInterface );
|
||||
|
||||
ModManager = new ModManager( new DirectoryInfo( Configuration.BaseFolder ) );
|
||||
ModManager.DiscoverMods();
|
||||
ModManager = new ModManager();
|
||||
ModManager.DiscoverMods( Configuration.CurrentCollection );
|
||||
|
||||
ResourceLoader = new ResourceLoader( this );
|
||||
|
||||
|
|
@ -39,9 +48,11 @@ namespace Penumbra
|
|||
|
||||
ResourceLoader.Init();
|
||||
ResourceLoader.Enable();
|
||||
|
||||
|
||||
SettingsInterface = new SettingsInterface( this );
|
||||
PluginInterface.UiBuilder.OnBuildUi += SettingsInterface.Draw;
|
||||
|
||||
PluginDebugTitleStr = $"{Name} - Debug Build";
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
{
|
||||
LoadUnpackedResource = 0,
|
||||
LoadFileResource = 1, // Shit in My Games uses this
|
||||
LoadSqpackResource = 0x0B
|
||||
// some shit here, the game does some jump if its < 0xA for other files for some reason but there's no impl, probs debug?
|
||||
LoadIndexResource = 0xA, // load index/index2
|
||||
LoadSqPackResource = 0xB
|
||||
}
|
||||
}
|
||||
|
|
@ -3,15 +3,15 @@ using System.Diagnostics;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Runtime.Remoting.Messaging;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Plugin;
|
||||
using ImGuiNET;
|
||||
using Penumbra.Importer;
|
||||
using Penumbra.Models;
|
||||
|
||||
namespace Penumbra
|
||||
namespace Penumbra.UI
|
||||
{
|
||||
public class SettingsInterface
|
||||
{
|
||||
|
|
@ -22,11 +22,14 @@ namespace Penumbra
|
|||
private static readonly Vector2 AutoFillSize = new Vector2( -1, -1 );
|
||||
private static readonly Vector2 ModListSize = new Vector2( 200, -1 );
|
||||
|
||||
private static readonly Vector2 MinSettingsSize = new Vector2( 650, 450 );
|
||||
private static readonly Vector2 MinSettingsSize = new Vector2( 800, 450 );
|
||||
private static readonly Vector2 MaxSettingsSize = new Vector2( 69420, 42069 );
|
||||
|
||||
private const string DialogDeleteMod = "PenumbraDeleteMod";
|
||||
|
||||
private int _selectedModIndex;
|
||||
private ResourceMod _selectedMod;
|
||||
private int? _selectedModDeleteIndex;
|
||||
private ModInfo _selectedMod;
|
||||
|
||||
private bool _isImportRunning = false;
|
||||
|
||||
|
|
@ -38,7 +41,11 @@ namespace Penumbra
|
|||
public void Draw()
|
||||
{
|
||||
ImGui.SetNextWindowSizeConstraints( MinSettingsSize, MaxSettingsSize );
|
||||
#if DEBUG
|
||||
var ret = ImGui.Begin( _plugin.PluginDebugTitleStr );
|
||||
#else
|
||||
var ret = ImGui.Begin( _plugin.Name );
|
||||
#endif
|
||||
if( !ret )
|
||||
{
|
||||
return;
|
||||
|
|
@ -50,6 +57,8 @@ namespace Penumbra
|
|||
DrawResourceMods();
|
||||
DrawEffectiveFileList();
|
||||
|
||||
DrawDeleteModal();
|
||||
|
||||
ImGui.EndTabBar();
|
||||
|
||||
ImGui.End();
|
||||
|
|
@ -64,17 +73,17 @@ namespace Penumbra
|
|||
}
|
||||
|
||||
// FUCKKKKK
|
||||
var basePath = _plugin.Configuration.BaseFolder;
|
||||
var basePath = _plugin.Configuration.CurrentCollection;
|
||||
if( ImGui.InputText( "Root Folder", ref basePath, 255 ) )
|
||||
{
|
||||
_plugin.Configuration.BaseFolder = basePath;
|
||||
_plugin.Configuration.CurrentCollection = basePath;
|
||||
}
|
||||
|
||||
if( ImGui.Button( "Rediscover Mods" ) )
|
||||
{
|
||||
ReloadMods();
|
||||
}
|
||||
|
||||
|
||||
if( ImGui.Button( "Reload Player Resource" ) )
|
||||
{
|
||||
_plugin.ResourceLoader.ReloadPlayerResource();
|
||||
|
|
@ -103,7 +112,7 @@ namespace Penumbra
|
|||
try
|
||||
{
|
||||
var importer =
|
||||
new TexToolsImport( new DirectoryInfo( _plugin.Configuration.BaseFolder ) );
|
||||
new TexToolsImport( new DirectoryInfo( _plugin.Configuration.CurrentCollection ) );
|
||||
|
||||
foreach( var fileName in picker.FileNames )
|
||||
{
|
||||
|
|
@ -135,7 +144,7 @@ namespace Penumbra
|
|||
{
|
||||
_plugin.Configuration.Save();
|
||||
}
|
||||
|
||||
|
||||
if( _plugin.ResourceLoader != null )
|
||||
{
|
||||
ImGui.Checkbox( "DEBUG Log all loaded files", ref _plugin.ResourceLoader.LogAllFiles );
|
||||
|
|
@ -151,16 +160,45 @@ namespace Penumbra
|
|||
ImGui.PushStyleVar( ImGuiStyleVar.ItemSpacing, new Vector2( 0, 0 ) );
|
||||
|
||||
// Inlay selector list
|
||||
ImGui.BeginChild( "availableModList", new Vector2( 180, -ImGui.GetFrameHeightWithSpacing() ), true );
|
||||
ImGui.BeginChild( "availableModList", new Vector2( 240, -ImGui.GetFrameHeightWithSpacing() ), true );
|
||||
|
||||
for( var modIndex = 0; modIndex < _plugin.ModManager.AvailableMods.Count; modIndex++ )
|
||||
if( _plugin.ModManager.Mods != null )
|
||||
{
|
||||
var mod = _plugin.ModManager.AvailableMods.ElementAt( modIndex );
|
||||
|
||||
if( ImGui.Selectable( mod.Value.Meta.Name, modIndex == _selectedModIndex ) )
|
||||
for( var modIndex = 0; modIndex < _plugin.ModManager.Mods.ModSettings.Count; modIndex++ )
|
||||
{
|
||||
_selectedModIndex = modIndex;
|
||||
_selectedMod = mod.Value;
|
||||
var settings = _plugin.ModManager.Mods.ModSettings[ modIndex ];
|
||||
|
||||
var changedColour = false;
|
||||
if( !settings.Enabled )
|
||||
{
|
||||
ImGui.PushStyleColor( ImGuiCol.Text, 0xFF666666 );
|
||||
changedColour = true;
|
||||
}
|
||||
else if( settings.Mod.FileConflicts.Any() )
|
||||
{
|
||||
ImGui.PushStyleColor( ImGuiCol.Text, 0xFFAAAAFF );
|
||||
changedColour = true;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
var selected = ImGui.Selectable(
|
||||
$"id={modIndex} {settings.Mod.Meta.Name}",
|
||||
modIndex == _selectedModIndex
|
||||
);
|
||||
#else
|
||||
var selected = ImGui.Selectable( settings.Mod.Meta.Name, modIndex == _selectedModIndex );
|
||||
#endif
|
||||
|
||||
if( changedColour )
|
||||
{
|
||||
ImGui.PopStyleColor();
|
||||
}
|
||||
|
||||
if( selected )
|
||||
{
|
||||
_selectedModIndex = modIndex;
|
||||
_selectedMod = settings;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -172,14 +210,16 @@ namespace Penumbra
|
|||
ImGui.PushFont( UiBuilder.IconFont );
|
||||
if( _selectedModIndex != 0 )
|
||||
{
|
||||
if( ImGui.Button( FontAwesomeIcon.ArrowUp.ToIconString(), new Vector2( 45, 0 ) ) )
|
||||
if( ImGui.Button( FontAwesomeIcon.ArrowUp.ToIconString(), new Vector2( 60, 0 ) ) )
|
||||
{
|
||||
_plugin.ModManager.ChangeModPriority( _selectedMod );
|
||||
_selectedModIndex -= 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.PushStyleVar( ImGuiStyleVar.Alpha, 0.5f );
|
||||
ImGui.Button( FontAwesomeIcon.ArrowUp.ToIconString(), new Vector2( 45, 0 ) );
|
||||
ImGui.Button( FontAwesomeIcon.ArrowUp.ToIconString(), new Vector2( 60, 0 ) );
|
||||
ImGui.PopStyleVar();
|
||||
}
|
||||
|
||||
|
|
@ -192,16 +232,18 @@ namespace Penumbra
|
|||
|
||||
ImGui.SameLine();
|
||||
|
||||
if( _selectedModIndex != _plugin.ModManager.AvailableMods.Count - 1 )
|
||||
if( _selectedModIndex != _plugin.ModManager.Mods?.ModSettings.Count - 1 )
|
||||
{
|
||||
if( ImGui.Button( FontAwesomeIcon.ArrowDown.ToIconString(), new Vector2( 45, 0 ) ) )
|
||||
if( ImGui.Button( FontAwesomeIcon.ArrowDown.ToIconString(), new Vector2( 60, 0 ) ) )
|
||||
{
|
||||
_plugin.ModManager.ChangeModPriority( _selectedMod, true );
|
||||
_selectedModIndex += 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.PushStyleVar( ImGuiStyleVar.Alpha, 0.5f );
|
||||
ImGui.Button( FontAwesomeIcon.ArrowDown.ToIconString(), new Vector2( 45, 0 ) );
|
||||
ImGui.Button( FontAwesomeIcon.ArrowDown.ToIconString(), new Vector2( 60, 0 ) );
|
||||
ImGui.PopStyleVar();
|
||||
}
|
||||
|
||||
|
|
@ -215,8 +257,9 @@ namespace Penumbra
|
|||
|
||||
ImGui.SameLine();
|
||||
|
||||
if( ImGui.Button( FontAwesomeIcon.Trash.ToIconString(), new Vector2( 45, 0 ) ) )
|
||||
if( ImGui.Button( FontAwesomeIcon.Trash.ToIconString(), new Vector2( 60, 0 ) ) )
|
||||
{
|
||||
_selectedModDeleteIndex = _selectedModIndex;
|
||||
}
|
||||
|
||||
ImGui.PopFont();
|
||||
|
|
@ -228,7 +271,7 @@ namespace Penumbra
|
|||
|
||||
ImGui.SameLine();
|
||||
|
||||
if( ImGui.Button( FontAwesomeIcon.Plus.ToIconString(), new Vector2( 45, 0 ) ) )
|
||||
if( ImGui.Button( FontAwesomeIcon.Plus.ToIconString(), new Vector2( 60, 0 ) ) )
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -242,14 +285,67 @@ namespace Penumbra
|
|||
ImGui.EndGroup();
|
||||
}
|
||||
|
||||
void DrawResourceMods()
|
||||
void DrawDeleteModal()
|
||||
{
|
||||
var ret = ImGui.BeginTabItem( "Resource Mods" );
|
||||
if( _selectedModDeleteIndex != null )
|
||||
ImGui.OpenPopup( DialogDeleteMod );
|
||||
|
||||
var ret = ImGui.BeginPopupModal( DialogDeleteMod );
|
||||
if( !ret )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( _selectedMod?.Mod == null )
|
||||
{
|
||||
ImGui.CloseCurrentPopup();
|
||||
ImGui.EndPopup();
|
||||
}
|
||||
|
||||
ImGui.Text( "Are you sure you want to delete the following mod:" );
|
||||
// todo: why the fuck does this become null??????
|
||||
ImGui.Text( _selectedMod?.Mod?.Meta?.Name );
|
||||
|
||||
if( ImGui.Button( "Yes, delete it" ) )
|
||||
{
|
||||
ImGui.CloseCurrentPopup();
|
||||
_plugin.ModManager.DeleteMod( _selectedMod.Mod );
|
||||
_selectedMod = null;
|
||||
_selectedModIndex = 0;
|
||||
_selectedModDeleteIndex = null;
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
if( ImGui.Button( "No, keep it" ) )
|
||||
{
|
||||
ImGui.CloseCurrentPopup();
|
||||
_selectedModDeleteIndex = null;
|
||||
}
|
||||
|
||||
ImGui.EndPopup();
|
||||
}
|
||||
|
||||
void DrawResourceMods()
|
||||
{
|
||||
var ret = ImGui.BeginTabItem( "Mods" );
|
||||
if( !ret )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( _plugin.ModManager.Mods == null )
|
||||
{
|
||||
ImGui.Text( "You don't have any mods :(" );
|
||||
ImGui.SetCursorPosY( ImGui.GetCursorPosY() + 20 );
|
||||
ImGui.Text( "You'll need to install them first by creating a folder close to the root of your drive (preferably an SSD)." );
|
||||
ImGui.Text( "For example: D:/ffxiv/mods/" );
|
||||
ImGui.Text( "And pasting that path into the settings tab and clicking the 'Rediscover Mods' button." );
|
||||
ImGui.Text( "You can return to this tab once you've done that." );
|
||||
ImGui.EndTabItem();
|
||||
return;
|
||||
}
|
||||
|
||||
DrawModsSelector();
|
||||
|
||||
ImGui.SameLine();
|
||||
|
|
@ -260,29 +356,78 @@ namespace Penumbra
|
|||
{
|
||||
ImGui.BeginChild( "selectedModInfo", AutoFillSize, true );
|
||||
|
||||
ImGui.Text( _selectedMod.Meta.Name );
|
||||
ImGui.Text( _selectedMod.Mod.Meta.Name );
|
||||
ImGui.SameLine();
|
||||
ImGui.TextColored( new Vector4( 1f, 1f, 1f, 0.66f ), "by" );
|
||||
ImGui.SameLine();
|
||||
ImGui.Text( _selectedMod.Meta.Author );
|
||||
ImGui.Text( _selectedMod.Mod.Meta.Author );
|
||||
|
||||
ImGui.TextWrapped( _selectedMod.Meta.Description ?? "" );
|
||||
ImGui.TextWrapped( _selectedMod.Mod.Meta.Description ?? "" );
|
||||
|
||||
ImGui.SetCursorPosY( ImGui.GetCursorPosY() + 12 );
|
||||
ImGui.SetCursorPosY( ImGui.GetCursorPosY() + 10 );
|
||||
|
||||
// list files
|
||||
ImGui.Text( "Files:" );
|
||||
ImGui.SetNextItemWidth( -1 );
|
||||
if( ImGui.ListBoxHeader( "##", AutoFillSize ) )
|
||||
var enabled = _selectedMod.Enabled;
|
||||
if( ImGui.Checkbox( "Enabled", ref enabled ) )
|
||||
{
|
||||
foreach( var file in _selectedMod.ModFiles )
|
||||
_selectedMod.Enabled = enabled;
|
||||
_plugin.ModManager.Mods.Save();
|
||||
_plugin.ModManager.CalculateEffectiveFileList();
|
||||
}
|
||||
|
||||
if( ImGui.Button( "Open Mod Folder" ) )
|
||||
{
|
||||
Process.Start( _selectedMod.Mod.ModBasePath.FullName );
|
||||
}
|
||||
|
||||
ImGui.BeginTabBar( "PenumbraPluginDetails" );
|
||||
if( ImGui.BeginTabItem( "Files" ) )
|
||||
{
|
||||
ImGui.SetNextItemWidth( -1 );
|
||||
if( ImGui.ListBoxHeader( "##", AutoFillSize ) )
|
||||
{
|
||||
ImGui.Selectable( file.FullName );
|
||||
foreach( var file in _selectedMod.Mod.ModFiles )
|
||||
{
|
||||
ImGui.Selectable( file.FullName );
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.ListBoxFooter();
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
|
||||
if( _selectedMod.Mod.FileConflicts.Any() )
|
||||
{
|
||||
if( ImGui.BeginTabItem( "File Conflicts" ) )
|
||||
{
|
||||
ImGui.SetNextItemWidth( -1 );
|
||||
if( ImGui.ListBoxHeader( "##", AutoFillSize ) )
|
||||
{
|
||||
foreach( var kv in _selectedMod.Mod.FileConflicts )
|
||||
{
|
||||
var mod = kv.Key;
|
||||
var files = kv.Value;
|
||||
|
||||
if( ImGui.Selectable( mod ) )
|
||||
{
|
||||
SelectModByName( mod );
|
||||
}
|
||||
|
||||
ImGui.Indent( 15 );
|
||||
foreach( var file in files )
|
||||
{
|
||||
ImGui.Selectable( file );
|
||||
}
|
||||
|
||||
ImGui.Unindent( 15 );
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.ListBoxFooter();
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.ListBoxFooter();
|
||||
|
||||
ImGui.EndTabBar();
|
||||
ImGui.EndChild();
|
||||
}
|
||||
catch( Exception ex )
|
||||
|
|
@ -294,6 +439,23 @@ namespace Penumbra
|
|||
ImGui.EndTabItem();
|
||||
}
|
||||
|
||||
void SelectModByName( string name )
|
||||
{
|
||||
for( var modIndex = 0; modIndex < _plugin.ModManager.Mods.ModSettings.Count; modIndex++ )
|
||||
{
|
||||
var mod = _plugin.ModManager.Mods.ModSettings[ modIndex ];
|
||||
|
||||
if( mod.Mod.Meta.Name != name )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_selectedMod = mod;
|
||||
_selectedModIndex = modIndex;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void DrawEffectiveFileList()
|
||||
{
|
||||
var ret = ImGui.BeginTabItem( "Effective File List" );
|
||||
|
|
@ -319,10 +481,7 @@ namespace Penumbra
|
|||
private void ReloadMods()
|
||||
{
|
||||
_selectedMod = null;
|
||||
|
||||
// haha yikes
|
||||
_plugin.ModManager = new ModManager( new DirectoryInfo( _plugin.Configuration.BaseFolder ) );
|
||||
_plugin.ModManager.DiscoverMods();
|
||||
_plugin.ModManager.DiscoverMods( _plugin.Configuration.CurrentCollection );
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue