mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-13 12:14:17 +01:00
176 lines
No EOL
6.3 KiB
C#
176 lines
No EOL
6.3 KiB
C#
using Lumina.Excel.GeneratedSheets;
|
|
using Penumbra.Collections;
|
|
using Penumbra.GameData.Enums;
|
|
using Penumbra.GameData.Structs;
|
|
using Penumbra.Meta.Manipulations;
|
|
using Penumbra.String.Classes;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using Penumbra.Meta;
|
|
using Penumbra.Mods.Manager;
|
|
using Penumbra.Services;
|
|
|
|
namespace Penumbra.Mods.ItemSwap;
|
|
|
|
public class ItemSwapContainer
|
|
{
|
|
private readonly MetaFileManager _manager;
|
|
private readonly IdentifierService _identifier;
|
|
|
|
private Dictionary< Utf8GamePath, FullPath > _modRedirections = new();
|
|
private HashSet< MetaManipulation > _modManipulations = new();
|
|
|
|
public IReadOnlyDictionary< Utf8GamePath, FullPath > ModRedirections
|
|
=> _modRedirections;
|
|
|
|
public IReadOnlySet< MetaManipulation > ModManipulations
|
|
=> _modManipulations;
|
|
|
|
public readonly List< Swap > Swaps = new();
|
|
|
|
public bool Loaded { get; private set; }
|
|
|
|
public void Clear()
|
|
{
|
|
Swaps.Clear();
|
|
Loaded = false;
|
|
}
|
|
|
|
public enum WriteType
|
|
{
|
|
UseSwaps,
|
|
NoSwaps,
|
|
}
|
|
|
|
public bool WriteMod( ModManager manager, Mod mod, WriteType writeType = WriteType.NoSwaps, DirectoryInfo? directory = null, int groupIndex = -1, int optionIndex = 0 )
|
|
{
|
|
var convertedManips = new HashSet< MetaManipulation >( Swaps.Count );
|
|
var convertedFiles = new Dictionary< Utf8GamePath, FullPath >( Swaps.Count );
|
|
var convertedSwaps = new Dictionary< Utf8GamePath, FullPath >( Swaps.Count );
|
|
directory ??= mod.ModPath;
|
|
try
|
|
{
|
|
foreach( var swap in Swaps.SelectMany( s => s.WithChildren() ) )
|
|
{
|
|
switch( swap )
|
|
{
|
|
case FileSwap file:
|
|
// Skip, nothing to do
|
|
if( file.SwapToModdedEqualsOriginal )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
|
|
if( writeType == WriteType.UseSwaps && file.SwapToModdedExistsInGame && !file.DataWasChanged )
|
|
{
|
|
convertedSwaps.TryAdd( file.SwapFromRequestPath, file.SwapToModded );
|
|
}
|
|
else
|
|
{
|
|
var path = file.GetNewPath( directory.FullName );
|
|
var bytes = file.FileData.Write();
|
|
Directory.CreateDirectory( Path.GetDirectoryName( path )! );
|
|
File.WriteAllBytes( path, bytes );
|
|
convertedFiles.TryAdd( file.SwapFromRequestPath, new FullPath( path ) );
|
|
}
|
|
|
|
break;
|
|
case MetaSwap meta:
|
|
if( !meta.SwapAppliedIsDefault )
|
|
{
|
|
convertedManips.Add( meta.SwapApplied );
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
manager.OptionEditor.OptionSetFiles( mod, groupIndex, optionIndex, convertedFiles );
|
|
manager.OptionEditor.OptionSetFileSwaps( mod, groupIndex, optionIndex, convertedSwaps );
|
|
manager.OptionEditor.OptionSetManipulations( mod, groupIndex, optionIndex, convertedManips );
|
|
return true;
|
|
}
|
|
catch( Exception e )
|
|
{
|
|
Penumbra.Log.Error( $"Could not write FileSwapContainer to {mod.ModPath}:\n{e}" );
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public void LoadMod( Mod? mod, ModSettings? settings )
|
|
{
|
|
Clear();
|
|
if( mod == null )
|
|
{
|
|
_modRedirections = new Dictionary< Utf8GamePath, FullPath >();
|
|
_modManipulations = new HashSet< MetaManipulation >();
|
|
}
|
|
else
|
|
{
|
|
( _modRedirections, _modManipulations ) = ModSettings.GetResolveData( mod, settings );
|
|
}
|
|
}
|
|
|
|
public ItemSwapContainer(MetaFileManager manager, IdentifierService identifier)
|
|
{
|
|
_manager = manager;
|
|
_identifier = identifier;
|
|
LoadMod( null, null );
|
|
}
|
|
|
|
private Func< Utf8GamePath, FullPath > PathResolver( ModCollection? collection )
|
|
=> collection != null
|
|
? p => collection.ResolvePath( p ) ?? new FullPath( p )
|
|
: p => ModRedirections.TryGetValue( p, out var path ) ? path : new FullPath( p );
|
|
|
|
private Func< MetaManipulation, MetaManipulation > MetaResolver( ModCollection? collection )
|
|
{
|
|
var set = collection?.MetaCache?.Manipulations.ToHashSet() ?? _modManipulations;
|
|
return m => set.TryGetValue( m, out var a ) ? a : m;
|
|
}
|
|
|
|
public EquipItem[] LoadEquipment( EquipItem from, EquipItem to, ModCollection? collection = null, bool useRightRing = true, bool useLeftRing = true )
|
|
{
|
|
Swaps.Clear();
|
|
Loaded = false;
|
|
var ret = EquipmentSwap.CreateItemSwap( _manager, _identifier.AwaitedService, Swaps, PathResolver( collection ), MetaResolver( collection ), from, to, useRightRing, useLeftRing );
|
|
Loaded = true;
|
|
return ret;
|
|
}
|
|
|
|
public EquipItem[] LoadTypeSwap( EquipSlot slotFrom, EquipItem from, EquipSlot slotTo, EquipItem to, ModCollection? collection = null )
|
|
{
|
|
Swaps.Clear();
|
|
Loaded = false;
|
|
var ret = EquipmentSwap.CreateTypeSwap( _manager, _identifier.AwaitedService, Swaps, PathResolver( collection ), MetaResolver( collection ), slotFrom, from, slotTo, to );
|
|
Loaded = true;
|
|
return ret;
|
|
}
|
|
|
|
public bool LoadCustomization( MetaFileManager manager, BodySlot slot, GenderRace race, SetId from, SetId to, ModCollection? collection = null )
|
|
{
|
|
var pathResolver = PathResolver( collection );
|
|
var mdl = CustomizationSwap.CreateMdl( manager, pathResolver, slot, race, from, to );
|
|
var type = slot switch
|
|
{
|
|
BodySlot.Hair => EstManipulation.EstType.Hair,
|
|
BodySlot.Face => EstManipulation.EstType.Face,
|
|
_ => ( EstManipulation.EstType )0,
|
|
};
|
|
|
|
var metaResolver = MetaResolver( collection );
|
|
var est = ItemSwap.CreateEst( manager, pathResolver, metaResolver, type, race, from, to, true );
|
|
|
|
Swaps.Add( mdl );
|
|
if( est != null )
|
|
{
|
|
Swaps.Add( est );
|
|
}
|
|
|
|
Loaded = true;
|
|
return true;
|
|
}
|
|
} |