Make line endings explicit in editorconfig and share in sub projects, also apply editorconfig everywhere and move some namespaces.

This commit is contained in:
Ottermandias 2023-09-18 16:56:16 +02:00
parent 53adb6fa54
commit 2b4a01df06
155 changed files with 1620 additions and 1614 deletions

View file

@ -1,21 +1,31 @@
# Standard properties
[*.proto] charset = utf-8
indent_style=tab end_of_line = lf
indent_size=tab insert_final_newline = true
tab_width=4 csharp_indent_labels = one_less_than_current
csharp_prefer_simple_using_statement = true:suggestion
[*.{asax,ascx,aspx,axaml,cs,cshtml,css,htm,html,js,jsx,master,paml,razor,skin,ts,tsx,vb,xaml,xamlx,xoml}] csharp_prefer_braces = true:silent
indent_style=space csharp_style_prefer_method_group_conversion = true:silent
indent_size=4 csharp_style_expression_bodied_methods = false:silent
tab_width=4 csharp_style_expression_bodied_constructors = false:silent
csharp_style_expression_bodied_operators = false:silent
[*.{appxmanifest,axml,build,config,csproj,dbml,discomap,dtd,json,jsproj,lsproj,njsproj,nuspec,proj,props,resjson,resw,resx,StyleCop,targets,tasks,vbproj,xml,xsd}] csharp_style_expression_bodied_properties = true:silent
indent_style=space csharp_style_expression_bodied_indexers = true:silent
indent_size=2 csharp_style_expression_bodied_accessors = true:silent
tab_width=2 csharp_style_expression_bodied_lambdas = true:silent
csharp_style_expression_bodied_local_functions = false:silent
csharp_style_throw_expression = true:suggestion
csharp_style_prefer_null_check_over_type_check = true:suggestion
csharp_prefer_simple_default_expression = true:suggestion
csharp_style_prefer_local_over_anonymous_function = true:suggestion
csharp_style_prefer_index_operator = true:suggestion
csharp_style_prefer_range_operator = true:suggestion
csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
csharp_style_prefer_tuple_swap = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion
csharp_style_prefer_top_level_statements = true:silent
[*] [*]
# Microsoft .NET properties # Microsoft .NET properties
csharp_indent_braces=false csharp_indent_braces=false
csharp_indent_switch_labels=true csharp_indent_switch_labels=true
@ -3567,30 +3577,6 @@ resharper_xaml_x_key_attribute_disallowed_highlighting=error
resharper_xml_doc_comment_syntax_problem_highlighting=warning resharper_xml_doc_comment_syntax_problem_highlighting=warning
resharper_xunit_xunit_test_with_console_output_highlighting=warning resharper_xunit_xunit_test_with_console_output_highlighting=warning
# Standard properties
end_of_line= crlf
csharp_indent_labels = one_less_than_current
csharp_prefer_simple_using_statement = true:suggestion
csharp_prefer_braces = true:silent
csharp_style_prefer_method_group_conversion = true:silent
csharp_style_expression_bodied_methods = false:silent
csharp_style_expression_bodied_constructors = false:silent
csharp_style_expression_bodied_operators = false:silent
csharp_style_expression_bodied_properties = true:silent
csharp_style_expression_bodied_indexers = true:silent
csharp_style_expression_bodied_accessors = true:silent
csharp_style_expression_bodied_lambdas = true:silent
csharp_style_expression_bodied_local_functions = false:silent
csharp_style_throw_expression = true:suggestion
csharp_style_prefer_null_check_over_type_check = true:suggestion
csharp_prefer_simple_default_expression = true:suggestion
csharp_style_prefer_local_over_anonymous_function = true:suggestion
csharp_style_prefer_index_operator = true:suggestion
csharp_style_prefer_range_operator = true:suggestion
csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
csharp_style_prefer_tuple_swap = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion
[*.{cshtml,htm,html,proto,razor}] [*.{cshtml,htm,html,proto,razor}]
indent_style=tab indent_style=tab
indent_size=tab indent_size=tab
@ -3601,6 +3587,21 @@ indent_style=space
indent_size=4 indent_size=4
tab_width=4 tab_width=4
[ "*.proto" ]
indent_style=tab
indent_size=tab
tab_width=4
[*.{asax,ascx,aspx,axaml,cs,cshtml,css,htm,html,js,jsx,master,paml,razor,skin,ts,tsx,vb,xaml,xamlx,xoml}]
indent_style=space
indent_size=4
tab_width=4
[*.{appxmanifest,axml,build,config,csproj,dbml,discomap,dtd,json,jsproj,lsproj,njsproj,nuspec,proj,props,resjson,resw,resx,StyleCop,targets,tasks,vbproj,xml,xsd}]
indent_style=space
indent_size=2
tab_width=2
[*.{appxmanifest,asax,ascx,aspx,axaml,axml,build,c,c++,cc,cginc,compute,config,cp,cpp,cs,cshtml,csproj,css,cu,cuh,cxx,dbml,discomap,dtd,h,hh,hlsl,hlsli,hlslinc,hpp,htm,html,hxx,inc,inl,ino,ipp,js,json,jsproj,jsx,lsproj,master,mpp,mq4,mq5,mqh,njsproj,nuspec,paml,proj,props,proto,razor,resjson,resw,resx,skin,StyleCop,targets,tasks,tpp,ts,tsx,usf,ush,vb,vbproj,xaml,xamlx,xml,xoml,xsd}] [*.{appxmanifest,asax,ascx,aspx,axaml,axml,build,c,c++,cc,cginc,compute,config,cp,cpp,cs,cshtml,csproj,css,cu,cuh,cxx,dbml,discomap,dtd,h,hh,hlsl,hlsli,hlslinc,hpp,htm,html,hxx,inc,inl,ino,ipp,js,json,jsproj,jsx,lsproj,master,mpp,mq4,mq5,mqh,njsproj,nuspec,paml,proj,props,proto,razor,resjson,resw,resx,skin,StyleCop,targets,tasks,tpp,ts,tsx,usf,ush,vb,vbproj,xaml,xamlx,xml,xoml,xsd}]
indent_style=space indent_style=space
indent_size= 4 indent_size= 4
@ -3621,3 +3622,4 @@ dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_compound_assignment = true:suggestion dotnet_style_prefer_compound_assignment = true:suggestion
dotnet_style_prefer_simplified_interpolation = true:suggestion dotnet_style_prefer_simplified_interpolation = true:suggestion
dotnet_style_namespace_match_folder = true:suggestion dotnet_style_namespace_match_folder = true:suggestion
insert_final_newline = true

@ -1 +1 @@
Subproject commit 316f3da4a3ce246afe5b98c1568d73fcd7b6b22d Subproject commit 22846625192884c6e9f5ec4429fb579875b519e9

@ -1 +1 @@
Subproject commit 0507b1f093f5382e03242e5da991752361b70c6e Subproject commit f004e069824a1588244e06080b32bab170f78077

@ -1 +1 @@
Subproject commit 0e0c1e1ee116c259abd00e1d5c3450ad40f92a98 Subproject commit 620a7edf009b92288257ce7d64fffb8fba44d8b5

View file

@ -633,7 +633,8 @@ public class PenumbraApi : IDisposable, IPenumbraApi
_modManager.AddMod(dir); _modManager.AddMod(dir);
if (_config.UseFileSystemCompression) if (_config.UseFileSystemCompression)
new FileCompactor(Penumbra.Log).StartMassCompact(dir.EnumerateFiles("*.*", SearchOption.AllDirectories), CompressionAlgorithm.Xpress8K); new FileCompactor(Penumbra.Log).StartMassCompact(dir.EnumerateFiles("*.*", SearchOption.AllDirectories),
CompressionAlgorithm.Xpress8K);
return PenumbraApiEc.Success; return PenumbraApiEc.Success;
} }

View file

@ -6,6 +6,7 @@ using Penumbra.Api.Enums;
using Penumbra.Communication; using Penumbra.Communication;
using Penumbra.String.Classes; using Penumbra.String.Classes;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
using Penumbra.Mods.Subclasses;
namespace Penumbra.Collections.Cache; namespace Penumbra.Collections.Cache;

View file

@ -1,4 +1,3 @@
using System.Collections.Concurrent;
using Dalamud.Game; using Dalamud.Game;
using OtterGui.Classes; using OtterGui.Classes;
using Penumbra.Api; using Penumbra.Api;

View file

@ -49,7 +49,6 @@ public struct EqpCache : IDisposable
var def = ExpandedEqpFile.GetDefault(manager, manip.SetId); var def = ExpandedEqpFile.GetDefault(manager, manip.SetId);
manip = new EqpManipulation(def, manip.Slot, manip.SetId); manip = new EqpManipulation(def, manip.Slot, manip.SetId);
return manip.Apply(_eqpFile!); return manip.Apply(_eqpFile!);
} }
public void Dispose() public void Dispose()

View file

@ -47,7 +47,8 @@ public static class ActiveCollectionMigration
if (!storage.ByName(collectionName, out var collection)) if (!storage.ByName(collectionName, out var collection))
{ {
Penumbra.Chat.NotificationMessage( Penumbra.Chat.NotificationMessage(
$"Last choice of <{player}>'s Collection {collectionName} is not available, reset to {ModCollection.Empty.Name}.", "Load Failure", $"Last choice of <{player}>'s Collection {collectionName} is not available, reset to {ModCollection.Empty.Name}.",
"Load Failure",
NotificationType.Warning); NotificationType.Warning);
dict.Add(player, ModCollection.Empty); dict.Add(player, ModCollection.Empty);
} }

View file

@ -442,6 +442,7 @@ public class ActiveCollections : ISavable, IDisposable
var m = ByType(CollectionTypeExtensions.FromParts(race, Gender.Male, false)); var m = ByType(CollectionTypeExtensions.FromParts(race, Gender.Male, false));
if (m != null && m != yourself) if (m != null && m != yourself)
return string.Empty; return string.Empty;
var f = ByType(CollectionTypeExtensions.FromParts(race, Gender.Female, false)); var f = ByType(CollectionTypeExtensions.FromParts(race, Gender.Female, false));
if (f != null && f != yourself) if (f != null && f != yourself)
return string.Empty; return string.Empty;
@ -460,14 +461,16 @@ public class ActiveCollections : ISavable, IDisposable
if (male == null) if (male == null)
{ {
if (female == null && @base == yourself) if (female == null && @base == yourself)
return $"Assignment is redundant due to overwriting Base{racialString} with an identical collection.\nYou can remove it."; return
$"Assignment is redundant due to overwriting Base{racialString} with an identical collection.\nYou can remove it.";
if (female == yourself && @base == yourself) if (female == yourself && @base == yourself)
return return
$"Assignment is redundant due to overwriting Base and Female Players{racialString} with an identical collection.\nYou can remove it."; $"Assignment is redundant due to overwriting Base and Female Players{racialString} with an identical collection.\nYou can remove it.";
} }
else if (male == yourself && female == null && @base == yourself) else if (male == yourself && female == null && @base == yourself)
{ {
return $"Assignment is redundant due to overwriting Base and Male Players{racialString} with an identical collection.\nYou can remove it."; return
$"Assignment is redundant due to overwriting Base and Male Players{racialString} with an identical collection.\nYou can remove it.";
} }
break; break;

View file

@ -2,6 +2,7 @@ using OtterGui;
using Penumbra.Api.Enums; using Penumbra.Api.Enums;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
using Penumbra.Mods.Subclasses;
using Penumbra.Services; using Penumbra.Services;
namespace Penumbra.Collections.Manager; namespace Penumbra.Collections.Manager;

View file

@ -5,6 +5,7 @@ using OtterGui.Filesystem;
using Penumbra.Communication; using Penumbra.Communication;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
using Penumbra.Mods.Subclasses;
using Penumbra.Services; using Penumbra.Services;
namespace Penumbra.Collections.Manager; namespace Penumbra.Collections.Manager;

View file

@ -47,7 +47,8 @@ public sealed partial class IndividualCollections : IReadOnlyList<(string Displa
return true; return true;
// Handle generic NPC // Handle generic NPC
var npcIdentifier = _actorService.AwaitedService.CreateIndividualUnchecked(IdentifierType.Npc, ByteString.Empty, ushort.MaxValue, var npcIdentifier = _actorService.AwaitedService.CreateIndividualUnchecked(IdentifierType.Npc, ByteString.Empty,
ushort.MaxValue,
identifier.Kind, identifier.DataId); identifier.Kind, identifier.DataId);
if (npcIdentifier.IsValid && _individuals.TryGetValue(npcIdentifier, out collection)) if (npcIdentifier.IsValid && _individuals.TryGetValue(npcIdentifier, out collection))
return true; return true;
@ -56,7 +57,8 @@ public sealed partial class IndividualCollections : IReadOnlyList<(string Displa
if (!_config.UseOwnerNameForCharacterCollection) if (!_config.UseOwnerNameForCharacterCollection)
return false; return false;
identifier = _actorService.AwaitedService.CreateIndividualUnchecked(IdentifierType.Player, identifier.PlayerName, identifier.HomeWorld.Id, identifier = _actorService.AwaitedService.CreateIndividualUnchecked(IdentifierType.Player, identifier.PlayerName,
identifier.HomeWorld.Id,
ObjectKind.None, uint.MaxValue); ObjectKind.None, uint.MaxValue);
return CheckWorlds(identifier, out collection); return CheckWorlds(identifier, out collection);
} }
@ -142,7 +144,8 @@ public sealed partial class IndividualCollections : IReadOnlyList<(string Displa
if (_individuals.TryGetValue(identifier, out collection)) if (_individuals.TryGetValue(identifier, out collection))
return true; return true;
identifier = _actorService.AwaitedService.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, ushort.MaxValue, identifier.Kind, identifier = _actorService.AwaitedService.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, ushort.MaxValue,
identifier.Kind,
identifier.DataId); identifier.DataId);
if (identifier.IsValid && _individuals.TryGetValue(identifier, out collection)) if (identifier.IsValid && _individuals.TryGetValue(identifier, out collection))
return true; return true;

View file

@ -27,6 +27,7 @@ public partial class IndividualCollections
{ {
if (_actorService.Valid) if (_actorService.Valid)
return ReadJObjectInternal(obj, storage); return ReadJObjectInternal(obj, storage);
void Func() void Func()
{ {
if (ReadJObjectInternal(obj, storage)) if (ReadJObjectInternal(obj, storage))
@ -35,6 +36,7 @@ public partial class IndividualCollections
Loaded.Invoke(); Loaded.Invoke();
_actorService.FinishedCreation -= Func; _actorService.FinishedCreation -= Func;
} }
_actorService.FinishedCreation += Func; _actorService.FinishedCreation += Func;
return false; return false;
} }
@ -85,6 +87,7 @@ public partial class IndividualCollections
NotificationType.Error); NotificationType.Error);
} }
} }
return changes; return changes;
} }

View file

@ -132,7 +132,8 @@ public sealed partial class IndividualCollections
_ => throw new NotImplementedException(), _ => throw new NotImplementedException(),
}; };
return table.Where(kvp => kvp.Value == name) return table.Where(kvp => kvp.Value == name)
.Select(kvp => manager.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, identifier.HomeWorld.Id, identifier.Kind, .Select(kvp => manager.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, identifier.HomeWorld.Id,
identifier.Kind,
kvp.Key)).ToArray(); kvp.Key)).ToArray();
} }

View file

@ -1,5 +1,6 @@
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
using Penumbra.Mods.Subclasses;
using Penumbra.Services; using Penumbra.Services;
using Penumbra.Util; using Penumbra.Util;

View file

@ -92,7 +92,7 @@ public partial class ModCollection
// Used for short periods of changed files. // Used for short periods of changed files.
public MetaList.MetaReverter TemporarilySetEqdpFile(CharacterUtility utility, GenderRace genderRace, bool accessory) public MetaList.MetaReverter TemporarilySetEqdpFile(CharacterUtility utility, GenderRace genderRace, bool accessory)
=> _cache?.Meta.TemporarilySetEqdpFile(genderRace, accessory) => _cache?.Meta.TemporarilySetEqdpFile(genderRace, accessory)
?? utility.TemporarilyResetResource(Interop.Structs.CharacterUtilityData.EqdpIdx(genderRace, accessory)); ?? utility.TemporarilyResetResource(CharacterUtilityData.EqdpIdx(genderRace, accessory));
public MetaList.MetaReverter TemporarilySetEqpFile(CharacterUtility utility) public MetaList.MetaReverter TemporarilySetEqpFile(CharacterUtility utility)
=> _cache?.Meta.TemporarilySetEqpFile() => _cache?.Meta.TemporarilySetEqpFile()

View file

@ -1,6 +1,7 @@
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
using Penumbra.Collections.Manager; using Penumbra.Collections.Manager;
using Penumbra.Mods.Subclasses;
using Penumbra.Services; using Penumbra.Services;
namespace Penumbra.Collections; namespace Penumbra.Collections;
@ -142,7 +143,8 @@ public partial class ModCollection
public static ModCollection CreateEmpty(string name, int index, int modCount) public static ModCollection CreateEmpty(string name, int index, int modCount)
{ {
Debug.Assert(index >= 0, "Empty collection created with negative index."); Debug.Assert(index >= 0, "Empty collection created with negative index.");
return new ModCollection(name, index, 0, CurrentVersion, Enumerable.Repeat((ModSettings?) null, modCount).ToList(), new List<ModCollection>(), return new ModCollection(name, index, 0, CurrentVersion, Enumerable.Repeat((ModSettings?)null, modCount).ToList(),
new List<ModCollection>(),
new Dictionary<string, ModSettings.SavedSettings>()); new Dictionary<string, ModSettings.SavedSettings>());
} }

View file

@ -3,6 +3,7 @@ using Penumbra.Mods;
using Penumbra.Services; using Penumbra.Services;
using Newtonsoft.Json; using Newtonsoft.Json;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
using Penumbra.Mods.Subclasses;
using Penumbra.Util; using Penumbra.Util;
namespace Penumbra.Collections; namespace Penumbra.Collections;

View file

@ -208,6 +208,7 @@ public class CommandHandler : IDisposable
{ {
if (_config.MinimumSize.X == Configuration.Constants.MinimumSizeX && _config.MinimumSize.Y == Configuration.Constants.MinimumSizeY) if (_config.MinimumSize.X == Configuration.Constants.MinimumSizeX && _config.MinimumSize.Y == Configuration.Constants.MinimumSizeY)
return false; return false;
_config.MinimumSize.X = Configuration.Constants.MinimumSizeX; _config.MinimumSize.X = Configuration.Constants.MinimumSizeX;
_config.MinimumSize.Y = Configuration.Constants.MinimumSizeY; _config.MinimumSize.Y = Configuration.Constants.MinimumSizeY;
_config.Save(); _config.Save();

View file

@ -45,7 +45,6 @@ public sealed class CollectionChange : EventWrapper<Action<CollectionType, ModCo
/// <seealso cref="UI.ModsTab.ModFileSystemSelector.OnCollectionChange"/> /// <seealso cref="UI.ModsTab.ModFileSystemSelector.OnCollectionChange"/>
ModFileSystemSelector = 0, ModFileSystemSelector = 0,
} }
public CollectionChange() public CollectionChange()

View file

@ -21,7 +21,7 @@ public sealed class ModDataChanged : EventWrapper<Action<ModDataChangeType, Mod,
/// <seealso cref="Mods.Manager.ModCacheManager.OnModDataChange"/> /// <seealso cref="Mods.Manager.ModCacheManager.OnModDataChange"/>
ModCacheManager = 0, ModCacheManager = 0,
/// <seealso cref="Mods.ModFileSystem.OnDataChange"/> /// <seealso cref="Mods.Manager.ModFileSystem.OnDataChange"/>
ModFileSystem = 0, ModFileSystem = 0,
} }

View file

@ -1,4 +1,5 @@
using OtterGui.Classes; using OtterGui.Classes;
using Penumbra.Mods.Manager;
namespace Penumbra.Communication; namespace Penumbra.Communication;
@ -19,7 +20,7 @@ public sealed class ModDiscoveryFinished : EventWrapper<Action, ModDiscoveryFini
/// <seealso cref="Mods.Manager.ModCacheManager.OnModDiscoveryFinished"/> /// <seealso cref="Mods.Manager.ModCacheManager.OnModDiscoveryFinished"/>
ModCacheManager = 0, ModCacheManager = 0,
/// <seealso cref="Mods.ModFileSystem.Reload"/> /// <seealso cref="Mods.Manager.ModFileSystem.Reload"/>
ModFileSystem = 0, ModFileSystem = 0,
} }

View file

@ -16,6 +16,7 @@ public sealed class ModDiscoveryStarted : EventWrapper<Action, ModDiscoveryStart
/// <seealso cref="UI.ModsTab.ModFileSystemSelector.StoreCurrentSelection"/> /// <seealso cref="UI.ModsTab.ModFileSystemSelector.StoreCurrentSelection"/>
ModFileSystemSelector = 200, ModFileSystemSelector = 200,
} }
public ModDiscoveryStarted() public ModDiscoveryStarted()
: base(nameof(ModDiscoveryStarted)) : base(nameof(ModDiscoveryStarted))
{ } { }

View file

@ -30,7 +30,7 @@ public sealed class ModPathChanged : EventWrapper<Action<ModPathChangeType, Mod,
/// <seealso cref="Mods.Manager.ModExportManager.OnModPathChange"/> /// <seealso cref="Mods.Manager.ModExportManager.OnModPathChange"/>
ModExportManager = 0, ModExportManager = 0,
/// <seealso cref="Mods.ModFileSystem.OnModPathChange"/> /// <seealso cref="Mods.Manager.ModFileSystem.OnModPathChange"/>
ModFileSystem = 0, ModFileSystem = 0,
/// <seealso cref="Mods.Manager.ModManager.OnModPathChange"/> /// <seealso cref="Mods.Manager.ModManager.OnModPathChange"/>
@ -48,6 +48,7 @@ public sealed class ModPathChanged : EventWrapper<Action<ModPathChangeType, Mod,
/// <seealso cref="Collections.Cache.CollectionCacheManager.OnModChangeRemoval"/> /// <seealso cref="Collections.Cache.CollectionCacheManager.OnModChangeRemoval"/>
CollectionCacheManagerRemoval = 100, CollectionCacheManagerRemoval = 100,
} }
public ModPathChanged() public ModPathChanged()
: base(nameof(ModPathChanged)) : base(nameof(ModPathChanged))
{ } { }

View file

@ -6,13 +6,14 @@ using OtterGui.Classes;
using OtterGui.Filesystem; using OtterGui.Filesystem;
using OtterGui.Widgets; using OtterGui.Widgets;
using Penumbra.Api.Enums; using Penumbra.Api.Enums;
using Penumbra.GameData.Enums;
using Penumbra.Import.Structs; using Penumbra.Import.Structs;
using Penumbra.Interop.Services; using Penumbra.Interop.Services;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.Mods.Manager;
using Penumbra.Services; using Penumbra.Services;
using Penumbra.UI; using Penumbra.UI;
using Penumbra.UI.Classes; using Penumbra.UI.Classes;
using Penumbra.UI.ResourceWatcher;
using Penumbra.UI.Tabs; using Penumbra.UI.Tabs;
using ErrorEventArgs = Newtonsoft.Json.Serialization.ErrorEventArgs; using ErrorEventArgs = Newtonsoft.Json.Serialization.ErrorEventArgs;

View file

@ -2,11 +2,13 @@
global using System; global using System;
global using System.Collections; global using System.Collections;
global using System.Collections.Concurrent;
global using System.Collections.Generic; global using System.Collections.Generic;
global using System.Diagnostics; global using System.Diagnostics;
global using System.IO; global using System.IO;
global using System.Linq; global using System.Linq;
global using System.Numerics; global using System.Numerics;
global using System.Reflection;
global using System.Runtime.CompilerServices; global using System.Runtime.CompilerServices;
global using System.Runtime.InteropServices; global using System.Runtime.InteropServices;
global using System.Security.Cryptography; global using System.Security.Cryptography;

View file

@ -78,9 +78,7 @@ public partial class TexToolsImporter
var obj = JObject.Load(j); var obj = JObject.Load(j);
name = obj[nameof(Mod.Name)]?.Value<string>()?.RemoveInvalidPathSymbols() ?? string.Empty; name = obj[nameof(Mod.Name)]?.Value<string>()?.RemoveInvalidPathSymbols() ?? string.Empty;
if (name.Length == 0) if (name.Length == 0)
{
throw new Exception("Invalid mod archive: mod meta has no name."); throw new Exception("Invalid mod archive: mod meta has no name.");
}
using var f = File.OpenWrite(Path.Combine(_currentModDirectory.FullName, reader.Entry.Key)); using var f = File.OpenWrite(Path.Combine(_currentModDirectory.FullName, reader.Entry.Key));
s.Seek(0, SeekOrigin.Begin); s.Seek(0, SeekOrigin.Begin);
@ -122,9 +120,7 @@ public partial class TexToolsImporter
var entry = archive.Entries.FirstOrDefault(e => !e.IsDirectory && Path.GetFileName(e.Key) == "meta.json"); var entry = archive.Entries.FirstOrDefault(e => !e.IsDirectory && Path.GetFileName(e.Key) == "meta.json");
// None found. // None found.
if (entry == null) if (entry == null)
{
throw new Exception("Invalid mod archive: No meta.json contained."); throw new Exception("Invalid mod archive: No meta.json contained.");
}
var ret = string.Empty; var ret = string.Empty;
leadDir = false; leadDir = false;
@ -136,19 +132,20 @@ public partial class TexToolsImporter
var directory = Path.GetDirectoryName(entry.Key); var directory = Path.GetDirectoryName(entry.Key);
// Should not happen. // Should not happen.
if (directory.IsNullOrEmpty()) if (directory.IsNullOrEmpty())
{
throw new Exception("Invalid mod archive: Unknown error fetching meta.json."); throw new Exception("Invalid mod archive: Unknown error fetching meta.json.");
}
ret = directory; ret = directory;
// Check that all other files are also contained in the top-level directory. // Check that all other files are also contained in the top-level directory.
if( ret.IndexOfAny( new[] { '/', '\\' } ) >= 0 if (ret.IndexOfAny(new[]
|| !archive.Entries.All( e => e.Key.StartsWith( ret ) && ( e.Key.Length == ret.Length || e.Key[ ret.Length ] is '/' or '\\' ) ) )
{ {
'/',
'\\',
})
>= 0
|| !archive.Entries.All(e => e.Key.StartsWith(ret) && (e.Key.Length == ret.Length || e.Key[ret.Length] is '/' or '\\')))
throw new Exception( throw new Exception(
"Invalid mod archive: meta.json in wrong location. It needs to be either at root or one directory deep, in which all other files must be nested too."); "Invalid mod archive: meta.json in wrong location. It needs to be either at root or one directory deep, in which all other files must be nested too.");
} }
}
return ret; return ret;

View file

@ -37,13 +37,9 @@ public partial class TexToolsImporter
ImGui.ProgressBar(percentage, size, $"Mod {_currentModPackIdx + 1} / {_modPackCount}"); ImGui.ProgressBar(percentage, size, $"Mod {_currentModPackIdx + 1} / {_modPackCount}");
ImGui.NewLine(); ImGui.NewLine();
if (State == ImporterState.DeduplicatingFiles) if (State == ImporterState.DeduplicatingFiles)
{
ImGui.TextUnformatted($"Deduplicating {_currentModName}..."); ImGui.TextUnformatted($"Deduplicating {_currentModName}...");
}
else else
{
ImGui.TextUnformatted($"Extracting {_currentModName}..."); ImGui.TextUnformatted($"Extracting {_currentModName}...");
}
if (_currentNumOptions > 1) if (_currentNumOptions > 1)
{ {
@ -53,11 +49,9 @@ public partial class TexToolsImporter
ImGui.ProgressBar(percentage, size, $"Option {_currentOptionIdx + 1} / {_currentNumOptions}"); ImGui.ProgressBar(percentage, size, $"Option {_currentOptionIdx + 1} / {_currentNumOptions}");
ImGui.NewLine(); ImGui.NewLine();
if (State != ImporterState.DeduplicatingFiles) if (State != ImporterState.DeduplicatingFiles)
{
ImGui.TextUnformatted( ImGui.TextUnformatted(
$"Extracting option {(_currentGroupName.Length == 0 ? string.Empty : $"{_currentGroupName} - ")}{_currentOptionName}..."); $"Extracting option {(_currentGroupName.Length == 0 ? string.Empty : $"{_currentGroupName} - ")}{_currentOptionName}...");
} }
}
ImGui.NewLine(); ImGui.NewLine();
ImGui.NewLine(); ImGui.NewLine();
@ -65,11 +59,9 @@ public partial class TexToolsImporter
ImGui.ProgressBar(percentage, size, $"File {_currentFileIdx + 1} / {_currentNumFiles}"); ImGui.ProgressBar(percentage, size, $"File {_currentFileIdx + 1} / {_currentNumFiles}");
ImGui.NewLine(); ImGui.NewLine();
if (State != ImporterState.DeduplicatingFiles) if (State != ImporterState.DeduplicatingFiles)
{
ImGui.TextUnformatted($"Extracting file {_currentFileName}..."); ImGui.TextUnformatted($"Extracting file {_currentFileName}...");
} }
} }
}
private void DrawEndState() private void DrawEndState()
@ -80,9 +72,7 @@ public partial class TexToolsImporter
ImGui.NewLine(); ImGui.NewLine();
using var table = ImRaii.Table("##files", 2); using var table = ImRaii.Table("##files", 2);
if (!table) if (!table)
{
return; return;
}
foreach (var (file, dir, ex) in ExtractedMods) foreach (var (file, dir, ex) in ExtractedMods)
{ {

View file

@ -47,10 +47,8 @@ public partial class TexToolsMeta
{ {
var def = CmpFile.GetDefault(manager, subRace, attribute); var def = CmpFile.GetDefault(manager, subRace, attribute);
if (keepDefault || value != def) if (keepDefault || value != def)
{
ret.MetaManipulations.Add(new RspManipulation(subRace, attribute, value)); ret.MetaManipulations.Add(new RspManipulation(subRace, attribute, value));
} }
}
if (gender == 1) if (gender == 1)
{ {

View file

@ -59,9 +59,7 @@ public partial class TexToolsMeta
{ {
var idx = entries.FindIndex(t => t.type == type); var idx = entries.FindIndex(t => t.type == type);
if (idx < 0) if (idx < 0)
{
return null; return null;
}
reader.BaseStream.Seek(entries[idx].offset, SeekOrigin.Begin); reader.BaseStream.Seek(entries[idx].offset, SeekOrigin.Begin);
return reader.ReadBytes(entries[idx].size); return reader.ReadBytes(entries[idx].size);
@ -92,9 +90,7 @@ public partial class TexToolsMeta
{ {
var builder = new StringBuilder(); var builder = new StringBuilder();
for (var c = reader.ReadChar(); c != 0; c = reader.ReadChar()) for (var c = reader.ReadChar(); c != 0; c = reader.ReadChar())
{
builder.Append(c); builder.Append(c);
}
return builder.ToString(); return builder.ToString();
} }

View file

@ -13,8 +13,7 @@ public readonly record struct RgbaPixelData(int Width, int Height, byte[] PixelD
public RgbaPixelData((int Width, int Height) size, byte[] pixelData) public RgbaPixelData((int Width, int Height) size, byte[] pixelData)
: this(size.Width, size.Height, pixelData) : this(size.Width, size.Height, pixelData)
{ { }
}
public Image<Rgba32> ToImage() public Image<Rgba32> ToImage()
=> Image.LoadPixelData<Rgba32>(PixelData, Width, Height); => Image.LoadPixelData<Rgba32>(PixelData, Width, Height);

View file

@ -1,4 +1,3 @@
using System.Collections.Concurrent;
using Dalamud.Interface; using Dalamud.Interface;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using ImGuiScene; using ImGuiScene;

View file

@ -80,7 +80,8 @@ public sealed unsafe class LiveColorTablePreviewer : LiveMaterialPreviewerBase
textureSize[0] = TextureWidth; textureSize[0] = TextureWidth;
textureSize[1] = TextureHeight; textureSize[1] = TextureHeight;
using var texture = new SafeTextureHandle(Structs.TextureUtility.Create2D(Device.Instance(), textureSize, 1, 0x2460, 0x80000804, 7), false); using var texture =
new SafeTextureHandle(Structs.TextureUtility.Create2D(Device.Instance(), textureSize, 1, 0x2460, 0x80000804, 7), false);
if (texture.IsInvalid) if (texture.IsInvalid)
return; return;

View file

@ -1,5 +1,6 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using FFXIVClientStructs.FFXIV.Client.System.Resource; using FFXIVClientStructs.FFXIV.Client.System.Resource;
using Penumbra.Api.Enums;
using Penumbra.Collections; using Penumbra.Collections;
using Penumbra.Collections.Manager; using Penumbra.Collections.Manager;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;

View file

@ -1,4 +1,3 @@
using System.Collections.Concurrent;
using Dalamud.Hooking; using Dalamud.Hooking;
using Dalamud.Utility.Signatures; using Dalamud.Utility.Signatures;
using Penumbra.Collections; using Penumbra.Collections;

View file

@ -37,7 +37,8 @@ public class ResourceNode
Children = new List<ResourceNode>(); Children = new List<ResourceNode>();
} }
public ResourceNode(UIData uiData, ResourceType type, nint objectAddress, nint resourceHandle, Utf8GamePath[] possibleGamePaths, FullPath fullPath, public ResourceNode(UIData uiData, ResourceType type, nint objectAddress, nint resourceHandle, Utf8GamePath[] possibleGamePaths,
FullPath fullPath,
ulong length, bool @internal) ulong length, bool @internal)
{ {
Name = uiData.Name; Name = uiData.Name;
@ -69,7 +70,7 @@ public class ResourceNode
} }
public ResourceNode WithUIData(string? name, ChangedItemIcon icon) public ResourceNode WithUIData(string? name, ChangedItemIcon icon)
=> string.Equals(Name, name, StringComparison.Ordinal) && Icon == icon ? this : new ResourceNode(new(name, icon), this); => string.Equals(Name, name, StringComparison.Ordinal) && Icon == icon ? this : new ResourceNode(new UIData(name, icon), this);
public ResourceNode WithUIData(UIData uiData) public ResourceNode WithUIData(UIData uiData)
=> string.Equals(Name, uiData.Name, StringComparison.Ordinal) && Icon == uiData.Icon ? this : new ResourceNode(uiData, this); => string.Equals(Name, uiData.Name, StringComparison.Ordinal) && Icon == uiData.Icon ? this : new ResourceNode(uiData, this);
@ -77,6 +78,6 @@ public class ResourceNode
public readonly record struct UIData(string? Name, ChangedItemIcon Icon) public readonly record struct UIData(string? Name, ChangedItemIcon Icon)
{ {
public readonly UIData PrependName(string prefix) public readonly UIData PrependName(string prefix)
=> Name == null ? this : new(prefix + Name, Icon); => Name == null ? this : new UIData(prefix + Name, Icon);
} }
} }

View file

@ -119,7 +119,9 @@ public class ResourceTree
var legacyDecalNode = context.CreateNodeFromTex((TextureResourceHandle*)human->LegacyBodyDecal); var legacyDecalNode = context.CreateNodeFromTex((TextureResourceHandle*)human->LegacyBodyDecal);
if (legacyDecalNode != null) if (legacyDecalNode != null)
Nodes.Add(globalContext.WithUiData ? legacyDecalNode.WithUIData(legacyDecalNode.Name ?? "Legacy Body Decal", legacyDecalNode.Icon) : legacyDecalNode); Nodes.Add(globalContext.WithUiData
? legacyDecalNode.WithUIData(legacyDecalNode.Name ?? "Legacy Body Decal", legacyDecalNode.Icon)
: legacyDecalNode);
} }
private unsafe void AddSkeleton(List<ResourceNode> nodes, ResolveContext context, Skeleton* skeleton, string prefix = "") private unsafe void AddSkeleton(List<ResourceNode> nodes, ResolveContext context, Skeleton* skeleton, string prefix = "")

View file

@ -4,21 +4,25 @@ namespace Penumbra.Interop.SafeHandles;
public unsafe class SafeResourceHandle : SafeHandle public unsafe class SafeResourceHandle : SafeHandle
{ {
public ResourceHandle* ResourceHandle => (ResourceHandle*)handle; public ResourceHandle* ResourceHandle
=> (ResourceHandle*)handle;
public override bool IsInvalid => handle == 0; public override bool IsInvalid
=> handle == 0;
public SafeResourceHandle(ResourceHandle* handle, bool incRef, bool ownsHandle = true) : base(0, ownsHandle) public SafeResourceHandle(ResourceHandle* handle, bool incRef, bool ownsHandle = true)
: base(0, ownsHandle)
{ {
if (incRef && !ownsHandle) if (incRef && !ownsHandle)
throw new ArgumentException("Non-owning SafeResourceHandle with IncRef is unsupported"); throw new ArgumentException("Non-owning SafeResourceHandle with IncRef is unsupported");
if (incRef && handle != null) if (incRef && handle != null)
handle->IncRef(); handle->IncRef();
SetHandle((nint)handle); SetHandle((nint)handle);
} }
public static SafeResourceHandle CreateInvalid() public static SafeResourceHandle CreateInvalid()
=> new(null, incRef: false); => new(null, false);
protected override bool ReleaseHandle() protected override bool ReleaseHandle()
{ {

View file

@ -5,14 +5,18 @@ namespace Penumbra.Interop.SafeHandles;
public unsafe class SafeTextureHandle : SafeHandle public unsafe class SafeTextureHandle : SafeHandle
{ {
public Texture* Texture => (Texture*)handle; public Texture* Texture
=> (Texture*)handle;
public override bool IsInvalid => handle == 0; public override bool IsInvalid
=> handle == 0;
public SafeTextureHandle(Texture* handle, bool incRef, bool ownsHandle = true) : base(0, ownsHandle) public SafeTextureHandle(Texture* handle, bool incRef, bool ownsHandle = true)
: base(0, ownsHandle)
{ {
if (incRef && !ownsHandle) if (incRef && !ownsHandle)
throw new ArgumentException("Non-owning SafeTextureHandle with IncRef is unsupported"); throw new ArgumentException("Non-owning SafeTextureHandle with IncRef is unsupported");
if (incRef && handle != null) if (incRef && handle != null)
TextureUtility.IncRef(handle); TextureUtility.IncRef(handle);
SetHandle((nint)handle); SetHandle((nint)handle);
@ -27,7 +31,7 @@ public unsafe class SafeTextureHandle : SafeHandle
} }
public static SafeTextureHandle CreateInvalid() public static SafeTextureHandle CreateInvalid()
=> new(null, incRef: false); => new(null, false);
protected override bool ReleaseHandle() protected override bool ReleaseHandle()
{ {
@ -37,6 +41,7 @@ public unsafe class SafeTextureHandle : SafeHandle
handle = this.handle; handle = this.handle;
this.handle = 0; this.handle = 0;
} }
if (handle != 0) if (handle != 0)
TextureUtility.DecRef((Texture*)handle); TextureUtility.DecRef((Texture*)handle);

View file

@ -265,11 +265,13 @@ public unsafe class GameEventManager : IDisposable
private readonly Hook<TestDelegate>? _testHook = null; private readonly Hook<TestDelegate>? _testHook = null;
private delegate void TestDelegate(nint a1, int a2); private delegate void TestDelegate(nint a1, int a2);
private void TestDetour(nint a1, int a2) private void TestDetour(nint a1, int a2)
{ {
Penumbra.Log.Information($"Test: {a1:X} {a2}"); Penumbra.Log.Information($"Test: {a1:X} {a2}");
_testHook!.Original(a1, a2); _testHook!.Original(a1, a2);
} }
private void EnableDebugHook() private void EnableDebugHook()
=> _testHook?.Enable(); => _testHook?.Enable();

View file

@ -26,7 +26,8 @@ public unsafe struct Material
[FieldOffset(0x38)] [FieldOffset(0x38)]
public ushort TextureCount; public ushort TextureCount;
public Texture* Texture( int index ) => Textures[index].ResourceHandle->KernelTexture; public Texture* Texture(int index)
=> Textures[index].ResourceHandle->KernelTexture;
[StructLayout(LayoutKind.Explicit, Size = 0x18)] [StructLayout(LayoutKind.Explicit, Size = 0x18)]
public struct TextureEntry public struct TextureEntry

View file

@ -55,9 +55,7 @@ public unsafe struct ResourceHandle
public byte* FileNamePtr() public byte* FileNamePtr()
{ {
if (FileNameLength > SsoSize) if (FileNameLength > SsoSize)
{
return FileNameData; return FileNameData;
}
fixed (byte** name = &FileNameData) fixed (byte** name = &FileNameData)
{ {
@ -128,9 +126,7 @@ public unsafe struct ResourceHandle
public bool SetData(IntPtr data, int length) public bool SetData(IntPtr data, int length)
{ {
if (Data == null) if (Data == null)
{
return false; return false;
}
Data->DataPtr = length != 0 ? (byte*)data : null; Data->DataPtr = length != 0 ? (byte*)data : null;
Data->DataLength = (ulong)length; Data->DataLength = (ulong)length;

View file

@ -7,12 +7,11 @@ public unsafe struct SeFileDescriptor
public FileMode FileMode; public FileMode FileMode;
[FieldOffset(0x30)] [FieldOffset(0x30)]
public void* FileDescriptor; // public void* FileDescriptor;
[FieldOffset(0x50)] [FieldOffset(0x50)]
public ResourceHandle* ResourceHandle; // public ResourceHandle* ResourceHandle;
[FieldOffset(0x70)] [FieldOffset(0x70)]
public char Utf16FileName; // public char Utf16FileName;
} }

View file

@ -4,12 +4,13 @@ using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
namespace Penumbra.Interop.Structs; namespace Penumbra.Interop.Structs;
public unsafe static class TextureUtility public static unsafe class TextureUtility
{ {
private static readonly Functions Funcs = new(); private static readonly Functions Funcs = new();
public static Texture* Create2D(Device* device, int* size, byte mipLevel, uint textureFormat, uint flags, uint unk) public static Texture* Create2D(Device* device, int* size, byte mipLevel, uint textureFormat, uint flags, uint unk)
=> ((delegate* unmanaged<Device*, int*, byte, uint, uint, uint, Texture*>)Funcs.TextureCreate2D)(device, size, mipLevel, textureFormat, flags, unk); => ((delegate* unmanaged<Device*, int*, byte, uint, uint, uint, Texture*>)Funcs.TextureCreate2D)(device, size, mipLevel, textureFormat,
flags, unk);
public static bool InitializeContents(Texture* texture, void* contents) public static bool InitializeContents(Texture* texture, void* contents)
=> ((delegate* unmanaged<Texture*, void*, bool>)Funcs.TextureInitializeContents)(texture, contents); => ((delegate* unmanaged<Texture*, void*, bool>)Funcs.TextureInitializeContents)(texture, contents);

View file

@ -58,9 +58,7 @@ public readonly struct EqpManipulation : IMetaManipulation< EqpManipulation >
var entry = file[SetId]; var entry = file[SetId];
var mask = Eqp.Mask(Slot); var mask = Eqp.Mask(Slot);
if ((entry & mask) == Entry) if ((entry & mask) == Entry)
{
return false; return false;
}
file[SetId] = (entry & ~mask) | Entry; file[SetId] = (entry & ~mask) | Entry;
return true; return true;

View file

@ -74,15 +74,11 @@ public readonly struct EstManipulation : IMetaManipulation< EstManipulation >
{ {
var r = Race.CompareTo(other.Race); var r = Race.CompareTo(other.Race);
if (r != 0) if (r != 0)
{
return r; return r;
}
var g = Gender.CompareTo(other.Gender); var g = Gender.CompareTo(other.Gender);
if (g != 0) if (g != 0)
{
return g; return g;
}
var s = Slot.CompareTo(other.Slot); var s = Slot.CompareTo(other.Slot);
return s != 0 ? s : SetId.Id.CompareTo(other.SetId.Id); return s != 0 ? s : SetId.Id.CompareTo(other.SetId.Id);
@ -109,6 +105,7 @@ public readonly struct EstManipulation : IMetaManipulation< EstManipulation >
return false; return false;
if (Names.CombinedRace(Gender, Race) == GenderRace.Unknown) if (Names.CombinedRace(Gender, Race) == GenderRace.Unknown)
return false; return false;
// No known check for set id or entry. // No known check for set id or entry.
return true; return true;
} }

View file

@ -43,17 +43,13 @@ public readonly struct GmpManipulation : IMetaManipulation< GmpManipulation >
{ {
var entry = file[SetId]; var entry = file[SetId];
if (entry == Entry) if (entry == Entry)
{
return false; return false;
}
file[SetId] = Entry; file[SetId] = Entry;
return true; return true;
} }
public bool Validate() public bool Validate()
{
// No known conditions. // No known conditions.
return true; => true;
}
} }

View file

@ -10,6 +10,7 @@ using Penumbra.Interop.Services;
using Penumbra.Interop.Structs; using Penumbra.Interop.Structs;
using Penumbra.Meta.Files; using Penumbra.Meta.Files;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.Mods.Subclasses;
using Penumbra.Services; using Penumbra.Services;
using ResidentResourceManager = Penumbra.Interop.Services.ResidentResourceManager; using ResidentResourceManager = Penumbra.Interop.Services.ResidentResourceManager;

View file

@ -1,4 +1,5 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using Penumbra.Mods.Subclasses;
using Penumbra.String.Classes; using Penumbra.String.Classes;
namespace Penumbra.Mods; namespace Penumbra.Mods;

View file

@ -9,6 +9,7 @@ public class ModBackup
{ {
/// <summary> Set when reading Config and migrating from v4 to v5. </summary> /// <summary> Set when reading Config and migrating from v4 to v5. </summary>
public static bool MigrateModBackups = false; public static bool MigrateModBackups = false;
public static bool CreatingBackup { get; private set; } public static bool CreatingBackup { get; private set; }
private readonly Mod _mod; private readonly Mod _mod;

View file

@ -1,4 +1,5 @@
using OtterGui; using OtterGui;
using Penumbra.Mods.Subclasses;
using Penumbra.String.Classes; using Penumbra.String.Classes;
namespace Penumbra.Mods.Editor; namespace Penumbra.Mods.Editor;

View file

@ -1,5 +1,6 @@
using Penumbra.Mods.Editor; using Penumbra.Mods.Editor;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
using Penumbra.Mods.Subclasses;
using Penumbra.String.Classes; using Penumbra.String.Classes;
namespace Penumbra.Mods; namespace Penumbra.Mods;

View file

@ -5,6 +5,7 @@ using Penumbra.Api.Enums;
using Penumbra.Communication; using Penumbra.Communication;
using Penumbra.Meta.Manipulations; using Penumbra.Meta.Manipulations;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
using Penumbra.Mods.Subclasses;
using Penumbra.Services; using Penumbra.Services;
using Penumbra.String.Classes; using Penumbra.String.Classes;
using Penumbra.UI.ModsTab; using Penumbra.UI.ModsTab;

View file

@ -1,5 +1,6 @@
using Penumbra.Meta.Manipulations; using Penumbra.Meta.Manipulations;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
using Penumbra.Mods.Subclasses;
namespace Penumbra.Mods; namespace Penumbra.Mods;
@ -146,6 +147,7 @@ public class ModMetaEditor
} }
} }
} }
Split(currentOption.Manipulations); Split(currentOption.Manipulations);
} }

View file

@ -2,6 +2,7 @@ using Dalamud.Interface.Internal.Notifications;
using OtterGui; using OtterGui;
using OtterGui.Tasks; using OtterGui.Tasks;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
using Penumbra.Mods.Subclasses;
using Penumbra.String.Classes; using Penumbra.String.Classes;
namespace Penumbra.Mods; namespace Penumbra.Mods;

View file

@ -1,5 +1,6 @@
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
using Penumbra.Mods.Subclasses;
using Penumbra.String.Classes; using Penumbra.String.Classes;
using Penumbra.Util; using Penumbra.Util;

View file

@ -10,18 +10,20 @@ namespace Penumbra.Mods.ItemSwap;
public static class CustomizationSwap public static class CustomizationSwap
{ {
/// The .mdl file for customizations is unique per racecode, slot and id, thus the .mdl redirection itself is independent of the mode. /// The .mdl file for customizations is unique per racecode, slot and id, thus the .mdl redirection itself is independent of the mode.
public static FileSwap CreateMdl( MetaFileManager manager, Func< Utf8GamePath, FullPath > redirections, BodySlot slot, GenderRace race, SetId idFrom, SetId idTo ) public static FileSwap CreateMdl(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections, BodySlot slot, GenderRace race,
SetId idFrom, SetId idTo)
{ {
if (idFrom.Id > byte.MaxValue) if (idFrom.Id > byte.MaxValue)
{
throw new Exception($"The Customization ID {idFrom} is too large for {slot}."); throw new Exception($"The Customization ID {idFrom} is too large for {slot}.");
}
var mdlPathFrom = GamePaths.Character.Mdl.Path(race, slot, idFrom, slot.ToCustomizationType()); var mdlPathFrom = GamePaths.Character.Mdl.Path(race, slot, idFrom, slot.ToCustomizationType());
var mdlPathTo = GamePaths.Character.Mdl.Path(race, slot, idTo, slot.ToCustomizationType()); var mdlPathTo = GamePaths.Character.Mdl.Path(race, slot, idTo, slot.ToCustomizationType());
var mdl = FileSwap.CreateSwap(manager, ResourceType.Mdl, redirections, mdlPathFrom, mdlPathTo); var mdl = FileSwap.CreateSwap(manager, ResourceType.Mdl, redirections, mdlPathFrom, mdlPathTo);
var range = slot == BodySlot.Tail && race is GenderRace.HrothgarMale or GenderRace.HrothgarFemale or GenderRace.HrothgarMaleNpc or GenderRace.HrothgarMaleNpc ? 5 : 1; var range = slot == BodySlot.Tail
&& race is GenderRace.HrothgarMale or GenderRace.HrothgarFemale or GenderRace.HrothgarMaleNpc or GenderRace.HrothgarMaleNpc
? 5
: 1;
foreach (ref var materialFileName in mdl.AsMdl()!.Materials.AsSpan()) foreach (ref var materialFileName in mdl.AsMdl()!.Materials.AsSpan())
{ {
@ -39,7 +41,8 @@ public static class CustomizationSwap
return mdl; return mdl;
} }
public static FileSwap CreateMtrl( MetaFileManager manager, Func< Utf8GamePath, FullPath > redirections, BodySlot slot, GenderRace race, SetId idFrom, SetId idTo, byte variant, public static FileSwap CreateMtrl(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections, BodySlot slot, GenderRace race,
SetId idFrom, SetId idTo, byte variant,
ref string fileName, ref bool dataWasChanged) ref string fileName, ref bool dataWasChanged)
{ {
variant = slot is BodySlot.Face or BodySlot.Zear ? byte.MaxValue : variant; variant = slot is BodySlot.Face or BodySlot.Zear ? byte.MaxValue : variant;
@ -49,7 +52,8 @@ public static class CustomizationSwap
var newFileName = fileName; var newFileName = fileName;
newFileName = ItemSwap.ReplaceRace(newFileName, gameRaceTo, race, gameRaceTo != race); newFileName = ItemSwap.ReplaceRace(newFileName, gameRaceTo, race, gameRaceTo != race);
newFileName = ItemSwap.ReplaceBody(newFileName, slot, idTo, idFrom, idFrom != idTo); newFileName = ItemSwap.ReplaceBody(newFileName, slot, idTo, idFrom, idFrom != idTo);
newFileName = ItemSwap.AddSuffix( newFileName, ".mtrl", $"_c{race.ToRaceCode()}", gameRaceFrom != race || MaterialHandling.IsSpecialCase( race, idFrom ) ); newFileName = ItemSwap.AddSuffix(newFileName, ".mtrl", $"_c{race.ToRaceCode()}",
gameRaceFrom != race || MaterialHandling.IsSpecialCase(race, idFrom));
newFileName = ItemSwap.AddSuffix(newFileName, ".mtrl", $"_{slot.ToAbbreviation()}{idFrom.Id:D4}", gameSetIdFrom != idFrom); newFileName = ItemSwap.AddSuffix(newFileName, ".mtrl", $"_{slot.ToAbbreviation()}{idFrom.Id:D4}", gameSetIdFrom != idFrom);
var actualMtrlFromPath = mtrlFromPath; var actualMtrlFromPath = mtrlFromPath;
@ -73,7 +77,8 @@ public static class CustomizationSwap
return mtrl; return mtrl;
} }
public static FileSwap CreateTex( MetaFileManager manager, Func< Utf8GamePath, FullPath > redirections, BodySlot slot, GenderRace race, SetId idFrom, ref MtrlFile.Texture texture, public static FileSwap CreateTex(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections, BodySlot slot, GenderRace race,
SetId idFrom, ref MtrlFile.Texture texture,
ref bool dataWasChanged) ref bool dataWasChanged)
{ {
var path = texture.Path; var path = texture.Path;
@ -101,7 +106,8 @@ public static class CustomizationSwap
} }
public static FileSwap CreateShader( MetaFileManager manager, Func< Utf8GamePath, FullPath > redirections, ref string shaderName, ref bool dataWasChanged ) public static FileSwap CreateShader(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections, ref string shaderName,
ref bool dataWasChanged)
{ {
var path = $"shader/sm5/shpk/{shaderName}"; var path = $"shader/sm5/shpk/{shaderName}";
return FileSwap.CreateSwap(manager, ResourceType.Shpk, redirections, path, path); return FileSwap.CreateSwap(manager, ResourceType.Shpk, redirections, path, path);

View file

@ -265,7 +265,8 @@ public static class EquipmentSwap
{ {
items = identifier.Identify(slotFrom.IsEquipment() items = identifier.Identify(slotFrom.IsEquipment()
? GamePaths.Equipment.Mdl.Path(idFrom, GenderRace.MidlanderMale, slotFrom) ? GamePaths.Equipment.Mdl.Path(idFrom, GenderRace.MidlanderMale, slotFrom)
: GamePaths.Accessory.Mdl.Path(idFrom, GenderRace.MidlanderMale, slotFrom)).Select(kvp => kvp.Value).OfType<EquipItem>().ToArray(); : GamePaths.Accessory.Mdl.Path(idFrom, GenderRace.MidlanderMale, slotFrom)).Select(kvp => kvp.Value).OfType<EquipItem>()
.ToArray();
variants = Enumerable.Range(0, imc.Count + 1).Select(i => (Variant)i).ToArray(); variants = Enumerable.Range(0, imc.Count + 1).Select(i => (Variant)i).ToArray();
} }
@ -283,11 +284,13 @@ public static class EquipmentSwap
return new MetaSwap(manips, manipFrom, manipTo); return new MetaSwap(manips, manipFrom, manipTo);
} }
public static MetaSwap CreateImc(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections, Func<MetaManipulation, MetaManipulation> manips, EquipSlot slot, public static MetaSwap CreateImc(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections,
Func<MetaManipulation, MetaManipulation> manips, EquipSlot slot,
SetId idFrom, SetId idTo, Variant variantFrom, Variant variantTo, ImcFile imcFileFrom, ImcFile imcFileTo) SetId idFrom, SetId idTo, Variant variantFrom, Variant variantTo, ImcFile imcFileFrom, ImcFile imcFileTo)
=> CreateImc(manager, redirections, manips, slot, slot, idFrom, idTo, variantFrom, variantTo, imcFileFrom, imcFileTo); => CreateImc(manager, redirections, manips, slot, slot, idFrom, idTo, variantFrom, variantTo, imcFileFrom, imcFileTo);
public static MetaSwap CreateImc(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections, Func<MetaManipulation, MetaManipulation> manips, public static MetaSwap CreateImc(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections,
Func<MetaManipulation, MetaManipulation> manips,
EquipSlot slotFrom, EquipSlot slotTo, SetId idFrom, SetId idTo, EquipSlot slotFrom, EquipSlot slotTo, SetId idFrom, SetId idTo,
Variant variantFrom, Variant variantTo, ImcFile imcFileFrom, ImcFile imcFileTo) Variant variantFrom, Variant variantTo, ImcFile imcFileFrom, ImcFile imcFileTo)
{ {
@ -401,7 +404,8 @@ public static class EquipmentSwap
ref MtrlFile.Texture texture, ref bool dataWasChanged) ref MtrlFile.Texture texture, ref bool dataWasChanged)
=> CreateTex(manager, redirections, prefix, EquipSlot.Unknown, EquipSlot.Unknown, idFrom, idTo, ref texture, ref dataWasChanged); => CreateTex(manager, redirections, prefix, EquipSlot.Unknown, EquipSlot.Unknown, idFrom, idTo, ref texture, ref dataWasChanged);
public static FileSwap CreateTex(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections, char prefix, EquipSlot slotFrom, EquipSlot slotTo, SetId idFrom, public static FileSwap CreateTex(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections, char prefix, EquipSlot slotFrom,
EquipSlot slotTo, SetId idFrom,
SetId idTo, ref MtrlFile.Texture texture, ref bool dataWasChanged) SetId idTo, ref MtrlFile.Texture texture, ref bool dataWasChanged)
{ {
var path = texture.Path; var path = texture.Path;
@ -428,13 +432,15 @@ public static class EquipmentSwap
return FileSwap.CreateSwap(manager, ResourceType.Tex, redirections, newPath, path, path); return FileSwap.CreateSwap(manager, ResourceType.Tex, redirections, newPath, path, path);
} }
public static FileSwap CreateShader(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections, ref string shaderName, ref bool dataWasChanged) public static FileSwap CreateShader(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections, ref string shaderName,
ref bool dataWasChanged)
{ {
var path = $"shader/sm5/shpk/{shaderName}"; var path = $"shader/sm5/shpk/{shaderName}";
return FileSwap.CreateSwap(manager, ResourceType.Shpk, redirections, path, path); return FileSwap.CreateSwap(manager, ResourceType.Shpk, redirections, path, path);
} }
public static FileSwap CreateAtex(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections, ref string filePath, ref bool dataWasChanged) public static FileSwap CreateAtex(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections, ref string filePath,
ref bool dataWasChanged)
{ {
var oldPath = filePath; var oldPath = filePath;
filePath = ItemSwap.AddSuffix(filePath, ".atex", $"_{Path.GetFileName(filePath).GetStableHashCode():x8}"); filePath = ItemSwap.AddSuffix(filePath, ".atex", $"_{Path.GetFileName(filePath).GetStableHashCode():x8}");

View file

@ -28,7 +28,6 @@ public static class ItemSwap
private static bool LoadFile(MetaFileManager manager, FullPath path, out byte[] data) private static bool LoadFile(MetaFileManager manager, FullPath path, out byte[] data)
{ {
if (path.FullName.Length > 0) if (path.FullName.Length > 0)
{
try try
{ {
if (path.IsRooted) if (path.IsRooted)
@ -48,7 +47,6 @@ public static class ItemSwap
{ {
Penumbra.Log.Debug($"Could not load file {path}:\n{e}"); Penumbra.Log.Debug($"Could not load file {path}:\n{e}");
} }
}
data = Array.Empty<byte>(); data = Array.Empty<byte>();
return false; return false;
@ -72,9 +70,7 @@ public static class ItemSwap
{ {
file = new GenericFile(manager, path); file = new GenericFile(manager, path);
if (file.Valid) if (file.Valid)
{
return true; return true;
}
file = null; file = null;
return false; return false;
@ -138,26 +134,27 @@ public static class ItemSwap
} }
public static FileSwap CreatePhyb(MetaFileManager manager, Func< Utf8GamePath, FullPath > redirections, EstManipulation.EstType type, GenderRace race, ushort estEntry ) public static FileSwap CreatePhyb(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections, EstManipulation.EstType type,
GenderRace race, ushort estEntry)
{ {
var phybPath = GamePaths.Skeleton.Phyb.Path(race, EstManipulation.ToName(type), estEntry); var phybPath = GamePaths.Skeleton.Phyb.Path(race, EstManipulation.ToName(type), estEntry);
return FileSwap.CreateSwap(manager, ResourceType.Phyb, redirections, phybPath, phybPath); return FileSwap.CreateSwap(manager, ResourceType.Phyb, redirections, phybPath, phybPath);
} }
public static FileSwap CreateSklb(MetaFileManager manager, Func< Utf8GamePath, FullPath > redirections, EstManipulation.EstType type, GenderRace race, ushort estEntry ) public static FileSwap CreateSklb(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections, EstManipulation.EstType type,
GenderRace race, ushort estEntry)
{ {
var sklbPath = GamePaths.Skeleton.Sklb.Path(race, EstManipulation.ToName(type), estEntry); var sklbPath = GamePaths.Skeleton.Sklb.Path(race, EstManipulation.ToName(type), estEntry);
return FileSwap.CreateSwap(manager, ResourceType.Sklb, redirections, sklbPath, sklbPath); return FileSwap.CreateSwap(manager, ResourceType.Sklb, redirections, sklbPath, sklbPath);
} }
/// <remarks> metaChanges is not manipulated, but IReadOnlySet does not support TryGetValue. </remarks> /// <remarks> metaChanges is not manipulated, but IReadOnlySet does not support TryGetValue. </remarks>
public static MetaSwap? CreateEst( MetaFileManager manager, Func< Utf8GamePath, FullPath > redirections, Func< MetaManipulation, MetaManipulation > manips, EstManipulation.EstType type, public static MetaSwap? CreateEst(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections,
Func<MetaManipulation, MetaManipulation> manips, EstManipulation.EstType type,
GenderRace genderRace, SetId idFrom, SetId idTo, bool ownMdl) GenderRace genderRace, SetId idFrom, SetId idTo, bool ownMdl)
{ {
if (type == 0) if (type == 0)
{
return null; return null;
}
var (gender, race) = genderRace.Split(); var (gender, race) = genderRace.Split();
var fromDefault = new EstManipulation(gender, race, type, idFrom, EstFile.GetDefault(manager, type, genderRace, idFrom)); var fromDefault = new EstManipulation(gender, race, type, idFrom, EstFile.GetDefault(manager, type, genderRace, idFrom));
@ -190,9 +187,7 @@ public static class ItemSwap
{ {
hash1 = ((hash1 << 5) + hash1) ^ str[i]; hash1 = ((hash1 << 5) + hash1) ^ str[i];
if (i == str.Length - 1 || str[i + 1] == '\0') if (i == str.Length - 1 || str[i + 1] == '\0')
{
break; break;
}
hash2 = ((hash2 << 5) + hash2) ^ str[i + 1]; hash2 = ((hash2 << 5) + hash2) ^ str[i + 1];
} }

View file

@ -6,6 +6,7 @@ using Penumbra.Meta.Manipulations;
using Penumbra.String.Classes; using Penumbra.String.Classes;
using Penumbra.Meta; using Penumbra.Meta;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
using Penumbra.Mods.Subclasses;
using Penumbra.Services; using Penumbra.Services;
namespace Penumbra.Mods.ItemSwap; namespace Penumbra.Mods.ItemSwap;
@ -40,7 +41,8 @@ public class ItemSwapContainer
NoSwaps, NoSwaps,
} }
public bool WriteMod( ModManager manager, Mod mod, WriteType writeType = WriteType.NoSwaps, DirectoryInfo? directory = null, int groupIndex = -1, int optionIndex = 0 ) 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 convertedManips = new HashSet<MetaManipulation>(Swaps.Count);
var convertedFiles = new Dictionary<Utf8GamePath, FullPath>(Swaps.Count); var convertedFiles = new Dictionary<Utf8GamePath, FullPath>(Swaps.Count);
@ -55,9 +57,7 @@ public class ItemSwapContainer
case FileSwap file: case FileSwap file:
// Skip, nothing to do // Skip, nothing to do
if (file.SwapToModdedEqualsOriginal) if (file.SwapToModdedEqualsOriginal)
{
continue; continue;
}
if (writeType == WriteType.UseSwaps && file.SwapToModdedExistsInGame && !file.DataWasChanged) if (writeType == WriteType.UseSwaps && file.SwapToModdedExistsInGame && !file.DataWasChanged)
{ {
@ -75,9 +75,7 @@ public class ItemSwapContainer
break; break;
case MetaSwap meta: case MetaSwap meta:
if (!meta.SwapAppliedIsDefault) if (!meta.SwapAppliedIsDefault)
{
convertedManips.Add(meta.SwapApplied); convertedManips.Add(meta.SwapApplied);
}
break; break;
} }
@ -127,11 +125,13 @@ public class ItemSwapContainer
return m => set.TryGetValue(m, out var a) ? a : m; 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 ) public EquipItem[] LoadEquipment(EquipItem from, EquipItem to, ModCollection? collection = null, bool useRightRing = true,
bool useLeftRing = true)
{ {
Swaps.Clear(); Swaps.Clear();
Loaded = false; Loaded = false;
var ret = EquipmentSwap.CreateItemSwap( _manager, _identifier.AwaitedService, Swaps, PathResolver( collection ), MetaResolver( collection ), from, to, useRightRing, useLeftRing ); var ret = EquipmentSwap.CreateItemSwap(_manager, _identifier.AwaitedService, Swaps, PathResolver(collection), MetaResolver(collection),
from, to, useRightRing, useLeftRing);
Loaded = true; Loaded = true;
return ret; return ret;
} }
@ -140,12 +140,14 @@ public class ItemSwapContainer
{ {
Swaps.Clear(); Swaps.Clear();
Loaded = false; Loaded = false;
var ret = EquipmentSwap.CreateTypeSwap( _manager, _identifier.AwaitedService, Swaps, PathResolver( collection ), MetaResolver( collection ), slotFrom, from, slotTo, to ); var ret = EquipmentSwap.CreateTypeSwap(_manager, _identifier.AwaitedService, Swaps, PathResolver(collection), MetaResolver(collection),
slotFrom, from, slotTo, to);
Loaded = true; Loaded = true;
return ret; return ret;
} }
public bool LoadCustomization( MetaFileManager manager, BodySlot slot, GenderRace race, SetId from, SetId to, ModCollection? collection = null ) public bool LoadCustomization(MetaFileManager manager, BodySlot slot, GenderRace race, SetId from, SetId to,
ModCollection? collection = null)
{ {
var pathResolver = PathResolver(collection); var pathResolver = PathResolver(collection);
var mdl = CustomizationSwap.CreateMdl(manager, pathResolver, slot, race, from, to); var mdl = CustomizationSwap.CreateMdl(manager, pathResolver, slot, race, from, to);
@ -161,9 +163,7 @@ public class ItemSwapContainer
Swaps.Add(mdl); Swaps.Add(mdl);
if (est != null) if (est != null)
{
Swaps.Add(est); Swaps.Add(est);
}
Loaded = true; Loaded = true;
return true; return true;

View file

@ -2,11 +2,9 @@ using System.Diagnostics.CodeAnalysis;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using OtterGui.Filesystem; using OtterGui.Filesystem;
using Penumbra.Communication; using Penumbra.Communication;
using Penumbra.Mods.Manager;
using Penumbra.Services; using Penumbra.Services;
using Penumbra.Util;
namespace Penumbra.Mods; namespace Penumbra.Mods.Manager;
public sealed class ModFileSystem : FileSystem<Mod>, IDisposable, ISavable public sealed class ModFileSystem : FileSystem<Mod>, IDisposable, ISavable
{ {

View file

@ -1,4 +1,3 @@
using System.Collections.Concurrent;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using Dalamud.Interface.Internal.Notifications; using Dalamud.Interface.Internal.Notifications;
using Penumbra.Import; using Penumbra.Import;

View file

@ -1,4 +1,3 @@
using System.Collections.Concurrent;
using Penumbra.Communication; using Penumbra.Communication;
using Penumbra.Mods.Editor; using Penumbra.Mods.Editor;
using Penumbra.Services; using Penumbra.Services;

View file

@ -6,7 +6,6 @@ using Penumbra.Api.Enums;
using Penumbra.Mods.Subclasses; using Penumbra.Mods.Subclasses;
using Penumbra.Services; using Penumbra.Services;
using Penumbra.String.Classes; using Penumbra.String.Classes;
using Penumbra.Util;
namespace Penumbra.Mods.Manager; namespace Penumbra.Mods.Manager;
@ -19,7 +18,9 @@ public static partial class ModMigration
private static partial Regex GroupStartRegex(); private static partial Regex GroupStartRegex();
public static bool Migrate(ModCreator creator, SaveService saveService, Mod mod, JObject json, ref uint fileVersion) public static bool Migrate(ModCreator creator, SaveService saveService, Mod mod, JObject json, ref uint fileVersion)
=> MigrateV0ToV1(creator, saveService, mod, json, ref fileVersion) || MigrateV1ToV2(saveService, mod, ref fileVersion) || MigrateV2ToV3(mod, ref fileVersion); => MigrateV0ToV1(creator, saveService, mod, json, ref fileVersion)
|| MigrateV1ToV2(saveService, mod, ref fileVersion)
|| MigrateV2ToV3(mod, ref fileVersion);
private static bool MigrateV2ToV3(Mod _, ref uint fileVersion) private static bool MigrateV2ToV3(Mod _, ref uint fileVersion)
{ {

View file

@ -5,7 +5,7 @@ using Penumbra.String.Classes;
namespace Penumbra.Mods; namespace Penumbra.Mods;
public sealed partial class Mod : IMod public sealed class Mod : IMod
{ {
public static readonly TemporaryMod ForcedFiles = new() public static readonly TemporaryMod ForcedFiles = new()
{ {

View file

@ -113,10 +113,8 @@ public partial class ModCreator
} }
if (changes) if (changes)
{
_saveService.SaveAllOptionGroups(mod, true); _saveService.SaveAllOptionGroups(mod, true);
} }
}
/// <summary> Load the default option for a given mod.</summary> /// <summary> Load the default option for a given mod.</summary>
public void LoadDefaultOption(Mod mod) public void LoadDefaultOption(Mod mod)

View file

@ -2,7 +2,6 @@ using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
using Penumbra.Services; using Penumbra.Services;
using Penumbra.Util;
namespace Penumbra.Mods; namespace Penumbra.Mods;

View file

@ -1,7 +1,6 @@
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Penumbra.Services; using Penumbra.Services;
using Penumbra.Util;
namespace Penumbra.Mods; namespace Penumbra.Mods;

View file

@ -1,9 +1,8 @@
using Newtonsoft.Json; using Newtonsoft.Json;
using Penumbra.Meta.Manipulations; using Penumbra.Meta.Manipulations;
using Penumbra.Mods.Subclasses;
using Penumbra.String.Classes; using Penumbra.String.Classes;
namespace Penumbra.Mods; namespace Penumbra.Mods.Subclasses;
public interface ISubMod public interface ISubMod
{ {

View file

@ -3,10 +3,9 @@ using OtterGui.Filesystem;
using Penumbra.Api.Enums; using Penumbra.Api.Enums;
using Penumbra.Meta.Manipulations; using Penumbra.Meta.Manipulations;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
using Penumbra.Mods.Subclasses;
using Penumbra.String.Classes; using Penumbra.String.Classes;
namespace Penumbra.Mods; namespace Penumbra.Mods.Subclasses;
/// <summary> Contains the settings for a given mod. </summary> /// <summary> Contains the settings for a given mod. </summary>
public class ModSettings public class ModSettings

View file

@ -4,9 +4,8 @@ using Newtonsoft.Json.Linq;
using OtterGui; using OtterGui;
using OtterGui.Filesystem; using OtterGui.Filesystem;
using Penumbra.Api.Enums; using Penumbra.Api.Enums;
using Penumbra.Mods.Subclasses;
namespace Penumbra.Mods; namespace Penumbra.Mods.Subclasses;
/// <summary> Groups that allow all available options to be selected at once. </summary> /// <summary> Groups that allow all available options to be selected at once. </summary>
public sealed class MultiModGroup : IModGroup public sealed class MultiModGroup : IModGroup

View file

@ -3,9 +3,8 @@ using Newtonsoft.Json.Linq;
using OtterGui; using OtterGui;
using OtterGui.Filesystem; using OtterGui.Filesystem;
using Penumbra.Api.Enums; using Penumbra.Api.Enums;
using Penumbra.Mods.Subclasses;
namespace Penumbra.Mods; namespace Penumbra.Mods.Subclasses;
/// <summary> Groups that allow only one of their available options to be selected. </summary> /// <summary> Groups that allow only one of their available options to be selected. </summary>
public sealed class SingleModGroup : IModGroup public sealed class SingleModGroup : IModGroup
@ -47,12 +46,9 @@ public sealed class SingleModGroup : IModGroup
DefaultSettings = json[nameof(DefaultSettings)]?.ToObject<uint>() ?? 0u, DefaultSettings = json[nameof(DefaultSettings)]?.ToObject<uint>() ?? 0u,
}; };
if (ret.Name.Length == 0) if (ret.Name.Length == 0)
{
return null; return null;
}
if (options != null) if (options != null)
{
foreach (var child in options.Children()) foreach (var child in options.Children())
{ {
var subMod = new SubMod(mod); var subMod = new SubMod(mod);
@ -60,7 +56,6 @@ public sealed class SingleModGroup : IModGroup
subMod.Load(mod.ModPath, child, out _); subMod.Load(mod.ModPath, child, out _);
ret.OptionData.Add(subMod); ret.OptionData.Add(subMod);
} }
}
if ((int)ret.DefaultSettings >= ret.Count) if ((int)ret.DefaultSettings >= ret.Count)
ret.DefaultSettings = 0; ret.DefaultSettings = 0;
@ -90,9 +85,7 @@ public sealed class SingleModGroup : IModGroup
public bool MoveOption(int optionIdxFrom, int optionIdxTo) public bool MoveOption(int optionIdxFrom, int optionIdxTo)
{ {
if (!OptionData.Move(optionIdxFrom, optionIdxTo)) if (!OptionData.Move(optionIdxFrom, optionIdxTo))
{
return false; return false;
}
// Update default settings with the move. // Update default settings with the move.
if (DefaultSettings == optionIdxFrom) if (DefaultSettings == optionIdxFrom)
@ -102,10 +95,8 @@ public sealed class SingleModGroup : IModGroup
else if (optionIdxFrom < optionIdxTo) else if (optionIdxFrom < optionIdxTo)
{ {
if (DefaultSettings > optionIdxFrom && DefaultSettings <= optionIdxTo) if (DefaultSettings > optionIdxFrom && DefaultSettings <= optionIdxTo)
{
--DefaultSettings; --DefaultSettings;
} }
}
else if (DefaultSettings < optionIdxFrom && DefaultSettings >= optionIdxTo) else if (DefaultSettings < optionIdxFrom && DefaultSettings >= optionIdxTo)
{ {
++DefaultSettings; ++DefaultSettings;
@ -118,8 +109,6 @@ public sealed class SingleModGroup : IModGroup
public void UpdatePositions(int from = 0) public void UpdatePositions(int from = 0)
{ {
foreach (var (o, i) in OptionData.WithIndex().Skip(from)) foreach (var (o, i) in OptionData.WithIndex().Skip(from))
{
o.SetPosition(o.GroupIdx, i); o.SetPosition(o.GroupIdx, i);
} }
} }
}

View file

@ -1,11 +1,8 @@
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Penumbra.Import;
using Penumbra.Meta;
using Penumbra.Meta.Manipulations; using Penumbra.Meta.Manipulations;
using Penumbra.Mods.Subclasses;
using Penumbra.String.Classes; using Penumbra.String.Classes;
namespace Penumbra.Mods; namespace Penumbra.Mods.Subclasses;
/// <summary> /// <summary>
/// A sub mod is a collection of /// A sub mod is a collection of

View file

@ -5,7 +5,6 @@ using Penumbra.Mods.Manager;
using Penumbra.Mods.Subclasses; using Penumbra.Mods.Subclasses;
using Penumbra.Services; using Penumbra.Services;
using Penumbra.String.Classes; using Penumbra.String.Classes;
using Penumbra.Util;
namespace Penumbra.Mods; namespace Penumbra.Mods;
@ -27,7 +26,10 @@ public class TemporaryMod : IMod
=> Array.Empty<IModGroup>(); => Array.Empty<IModGroup>();
public IEnumerable<SubMod> AllSubMods public IEnumerable<SubMod> AllSubMods
=> new[] { Default }; => new[]
{
Default,
};
public TemporaryMod() public TemporaryMod()
=> Default = new SubMod(this); => Default = new SubMod(this);
@ -44,7 +46,8 @@ public class TemporaryMod : IMod
Default.ManipulationData = manips; Default.ManipulationData = manips;
} }
public static void SaveTempCollection( Configuration config, SaveService saveService, ModManager modManager, ModCollection collection, string? character = null ) public static void SaveTempCollection(Configuration config, SaveService saveService, ModManager modManager, ModCollection collection,
string? character = null)
{ {
DirectoryInfo? dir = null; DirectoryInfo? dir = null;
try try

View file

@ -20,6 +20,7 @@ using Penumbra.UI.Tabs;
using ChangedItemClick = Penumbra.Communication.ChangedItemClick; using ChangedItemClick = Penumbra.Communication.ChangedItemClick;
using ChangedItemHover = Penumbra.Communication.ChangedItemHover; using ChangedItemHover = Penumbra.Communication.ChangedItemHover;
using OtterGui.Tasks; using OtterGui.Tasks;
using Penumbra.UI;
namespace Penumbra; namespace Penumbra;

View file

@ -7,6 +7,7 @@ using Penumbra.Interop.Services;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.Mods.Editor; using Penumbra.Mods.Editor;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
using Penumbra.Mods.Subclasses;
using Penumbra.UI.Classes; using Penumbra.UI.Classes;
namespace Penumbra.Services; namespace Penumbra.Services;
@ -331,7 +332,8 @@ public class ConfigMigrationService
dict = dict.ToDictionary(kvp => kvp.Key, kvp => kvp.Value with { Priority = maxPriority - kvp.Value.Priority }); dict = dict.ToDictionary(kvp => kvp.Key, kvp => kvp.Value with { Priority = maxPriority - kvp.Value.Priority });
var emptyStorage = new ModStorage(); var emptyStorage = new ModStorage();
var collection = ModCollection.CreateFromData(_saveService, emptyStorage, ModCollection.DefaultCollectionName, 0, 1, dict, Array.Empty<string>()); var collection = ModCollection.CreateFromData(_saveService, emptyStorage, ModCollection.DefaultCollectionName, 0, 1, dict,
Array.Empty<string>());
_saveService.ImmediateSave(new ModCollectionSave(emptyStorage, collection)); _saveService.ImmediateSave(new ModCollectionSave(emptyStorage, collection));
} }
catch (Exception e) catch (Exception e)

View file

@ -6,7 +6,6 @@ using Dalamud.Game.Gui;
using Dalamud.Interface; using Dalamud.Interface;
using Dalamud.IoC; using Dalamud.IoC;
using Dalamud.Plugin; using Dalamud.Plugin;
using System.Reflection;
using Dalamud.Interface.DragDrop; using Dalamud.Interface.DragDrop;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;

View file

@ -21,6 +21,7 @@ using Penumbra.UI;
using Penumbra.UI.AdvancedWindow; using Penumbra.UI.AdvancedWindow;
using Penumbra.UI.Classes; using Penumbra.UI.Classes;
using Penumbra.UI.ModsTab; using Penumbra.UI.ModsTab;
using Penumbra.UI.ResourceWatcher;
using Penumbra.UI.Tabs; using Penumbra.UI.Tabs;
namespace Penumbra.Services; namespace Penumbra.Services;

View file

@ -25,7 +25,8 @@ public class StainService : IDisposable
{ {
using var t = timer.Measure(StartTimeType.Stains); using var t = timer.Measure(StartTimeType.Stains);
StainData = new StainData(pluginInterface, dataManager, dataManager.Language); StainData = new StainData(pluginInterface, dataManager, dataManager.Language);
StainCombo = new FilterComboColors(140, StainData.Data.Prepend(new KeyValuePair<byte, (string Name, uint Dye, bool Gloss)>(0, ("None", 0, false)))); StainCombo = new FilterComboColors(140,
StainData.Data.Prepend(new KeyValuePair<byte, (string Name, uint Dye, bool Gloss)>(0, ("None", 0, false))));
StmFile = new StmFile(dataManager); StmFile = new StmFile(dataManager);
TemplateCombo = new StainTemplateCombo(StmFile.Entries.Keys.Prepend((ushort)0)); TemplateCombo = new StainTemplateCombo(StmFile.Entries.Keys.Prepend((ushort)0));
Penumbra.Log.Verbose($"[{nameof(StainService)}] Created."); Penumbra.Log.Verbose($"[{nameof(StainService)}] Created.");

View file

@ -1,4 +1,3 @@
using System.Reflection;
using Dalamud.Interface.Internal.Notifications; using Dalamud.Interface.Internal.Notifications;
using Dalamud.Plugin; using Dalamud.Plugin;
@ -34,7 +33,8 @@ public class ValidityChecker
public void LogExceptions() public void LogExceptions()
{ {
if (ImcExceptions.Count > 0) if (ImcExceptions.Count > 0)
Penumbra.Chat.NotificationMessage( $"{ImcExceptions} IMC Exceptions thrown during Penumbra load. Please repair your game files.", "Warning", NotificationType.Warning ); Penumbra.Chat.NotificationMessage($"{ImcExceptions} IMC Exceptions thrown during Penumbra load. Please repair your game files.",
"Warning", NotificationType.Warning);
} }
// Because remnants of penumbra in devPlugins cause issues, we check for them to warn users to remove them. // Because remnants of penumbra in devPlugins cause issues, we check for them to warn users to remove them.

View file

@ -12,7 +12,8 @@ namespace Penumbra.Services;
public sealed class IdentifierService : AsyncServiceWrapper<IObjectIdentifier> public sealed class IdentifierService : AsyncServiceWrapper<IObjectIdentifier>
{ {
public IdentifierService(StartTracker tracker, DalamudPluginInterface pi, IDataManager data, ItemService items) public IdentifierService(StartTracker tracker, DalamudPluginInterface pi, IDataManager data, ItemService items)
: base(nameof(IdentifierService), tracker, StartTimeType.Identifier, () => GameData.GameData.GetIdentifier(pi, data, items.AwaitedService)) : base(nameof(IdentifierService), tracker, StartTimeType.Identifier,
() => GameData.GameData.GetIdentifier(pi, data, items.AwaitedService))
{ } { }
} }

View file

@ -4,6 +4,7 @@ using OtterGui;
using OtterGui.Classes; using OtterGui.Classes;
using OtterGui.Raii; using OtterGui.Raii;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.Mods.Subclasses;
using Penumbra.String.Classes; using Penumbra.String.Classes;
using Penumbra.UI.Classes; using Penumbra.UI.Classes;

View file

@ -114,10 +114,8 @@ public partial class ModEditWindow
{ {
var ret = false; var ret = false;
if (tab.Mtrl.HasDyeTable) if (tab.Mtrl.HasDyeTable)
{
for (var i = 0; i < MtrlFile.ColorTable.NumRows; ++i) for (var i = 0; i < MtrlFile.ColorTable.NumRows; ++i)
ret |= tab.Mtrl.ApplyDyeTemplate(_stainService.StmFile, i, dyeId); ret |= tab.Mtrl.ApplyDyeTemplate(_stainService.StmFile, i, dyeId);
}
tab.UpdateColorTablePreview(); tab.UpdateColorTablePreview();
@ -301,7 +299,8 @@ public partial class ModEditWindow
ImGui.SameLine(); ImGui.SameLine();
var tmpFloat = row.SpecularStrength; var tmpFloat = row.SpecularStrength;
ImGui.SetNextItemWidth(floatSize); ImGui.SetNextItemWidth(floatSize);
if (ImGui.DragFloat("##SpecularStrength", ref tmpFloat, 0.01f, 0f, HalfMaxValue, "%.2f") && FixFloat(ref tmpFloat, row.SpecularStrength)) if (ImGui.DragFloat("##SpecularStrength", ref tmpFloat, 0.01f, 0f, HalfMaxValue, "%.2f")
&& FixFloat(ref tmpFloat, row.SpecularStrength))
{ {
row.SpecularStrength = tmpFloat; row.SpecularStrength = tmpFloat;
ret = true; ret = true;

View file

@ -8,7 +8,6 @@ using Penumbra.Interop.Structs;
using Penumbra.Meta; using Penumbra.Meta;
using Penumbra.Meta.Files; using Penumbra.Meta.Files;
using Penumbra.Meta.Manipulations; using Penumbra.Meta.Manipulations;
using Penumbra.Mods;
using Penumbra.Mods.Editor; using Penumbra.Mods.Editor;
using Penumbra.UI.Classes; using Penumbra.UI.Classes;
@ -66,17 +65,23 @@ public partial class ModEditWindow
if (!child) if (!child)
return; return;
DrawEditHeader(_editor.MetaEditor.Eqp, "Equipment Parameter Edits (EQP)###EQP", 5, EqpRow.Draw, EqpRow.DrawNew , _editor.MetaEditor.OtherEqpCount); DrawEditHeader(_editor.MetaEditor.Eqp, "Equipment Parameter Edits (EQP)###EQP", 5, EqpRow.Draw, EqpRow.DrawNew,
DrawEditHeader(_editor.MetaEditor.Eqdp, "Racial Model Edits (EQDP)###EQDP", 7, EqdpRow.Draw, EqdpRow.DrawNew, _editor.MetaEditor.OtherEqdpCount); _editor.MetaEditor.OtherEqpCount);
DrawEditHeader(_editor.MetaEditor.Eqdp, "Racial Model Edits (EQDP)###EQDP", 7, EqdpRow.Draw, EqdpRow.DrawNew,
_editor.MetaEditor.OtherEqdpCount);
DrawEditHeader(_editor.MetaEditor.Imc, "Variant Edits (IMC)###IMC", 10, ImcRow.Draw, ImcRow.DrawNew, _editor.MetaEditor.OtherImcCount); DrawEditHeader(_editor.MetaEditor.Imc, "Variant Edits (IMC)###IMC", 10, ImcRow.Draw, ImcRow.DrawNew, _editor.MetaEditor.OtherImcCount);
DrawEditHeader(_editor.MetaEditor.Est, "Extra Skeleton Parameters (EST)###EST", 7, EstRow.Draw, EstRow.DrawNew , _editor.MetaEditor.OtherEstCount); DrawEditHeader(_editor.MetaEditor.Est, "Extra Skeleton Parameters (EST)###EST", 7, EstRow.Draw, EstRow.DrawNew,
DrawEditHeader(_editor.MetaEditor.Gmp, "Visor/Gimmick Edits (GMP)###GMP", 7, GmpRow.Draw, GmpRow.DrawNew , _editor.MetaEditor.OtherGmpCount); _editor.MetaEditor.OtherEstCount);
DrawEditHeader(_editor.MetaEditor.Rsp, "Racial Scaling Edits (RSP)###RSP", 5, RspRow.Draw, RspRow.DrawNew , _editor.MetaEditor.OtherRspCount); DrawEditHeader(_editor.MetaEditor.Gmp, "Visor/Gimmick Edits (GMP)###GMP", 7, GmpRow.Draw, GmpRow.DrawNew,
_editor.MetaEditor.OtherGmpCount);
DrawEditHeader(_editor.MetaEditor.Rsp, "Racial Scaling Edits (RSP)###RSP", 5, RspRow.Draw, RspRow.DrawNew,
_editor.MetaEditor.OtherRspCount);
} }
/// <summary> The headers for the different meta changes all have basically the same structure for different types.</summary> /// <summary> The headers for the different meta changes all have basically the same structure for different types.</summary>
private void DrawEditHeader<T>(IReadOnlyCollection<T> items, string label, int numColumns, Action<MetaFileManager, T, ModEditor, Vector2> draw, private void DrawEditHeader<T>(IReadOnlyCollection<T> items, string label, int numColumns,
Action<MetaFileManager, T, ModEditor, Vector2> draw,
Action<MetaFileManager, ModEditor, Vector2> drawNew, int otherCount) Action<MetaFileManager, ModEditor, Vector2> drawNew, int otherCount)
{ {
const ImGuiTableFlags flags = ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.BordersInnerV; const ImGuiTableFlags flags = ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.BordersInnerV;
@ -92,6 +97,7 @@ public partial class ModEditWindow
ImGuiUtil.TextColored(ColorId.RedundantAssignment.Value() | 0xFF000000, text); ImGuiUtil.TextColored(ColorId.RedundantAssignment.Value() | 0xFF000000, text);
ImGui.SetCursorPos(newPos); ImGui.SetCursorPos(newPos);
} }
if (!header) if (!header)
return; return;
@ -223,7 +229,8 @@ public partial class ModEditWindow
ImGui.TableNextColumn(); ImGui.TableNextColumn();
if (IdInput("##eqdpId", IdWidth, _new.SetId.Id, out var setId, 0, ExpandedEqpGmpBase.Count - 1, _new.SetId <= 1)) if (IdInput("##eqdpId", IdWidth, _new.SetId.Id, out var setId, 0, ExpandedEqpGmpBase.Count - 1, _new.SetId <= 1))
{ {
var newDefaultEntry = ExpandedEqdpFile.GetDefault(metaFileManager, Names.CombinedRace(_new.Gender, _new.Race), _new.Slot.IsAccessory(), setId); var newDefaultEntry = ExpandedEqdpFile.GetDefault(metaFileManager, Names.CombinedRace(_new.Gender, _new.Race),
_new.Slot.IsAccessory(), setId);
_new = new EqdpManipulation(newDefaultEntry, _new.Slot, _new.Gender, _new.Race, setId); _new = new EqdpManipulation(newDefaultEntry, _new.Slot, _new.Gender, _new.Race, setId);
} }
@ -232,7 +239,8 @@ public partial class ModEditWindow
ImGui.TableNextColumn(); ImGui.TableNextColumn();
if (Combos.Race("##eqdpRace", _new.Race, out var race)) if (Combos.Race("##eqdpRace", _new.Race, out var race))
{ {
var newDefaultEntry = ExpandedEqdpFile.GetDefault(metaFileManager, Names.CombinedRace(_new.Gender, race), _new.Slot.IsAccessory(), _new.SetId); var newDefaultEntry = ExpandedEqdpFile.GetDefault(metaFileManager, Names.CombinedRace(_new.Gender, race),
_new.Slot.IsAccessory(), _new.SetId);
_new = new EqdpManipulation(newDefaultEntry, _new.Slot, _new.Gender, race, _new.SetId); _new = new EqdpManipulation(newDefaultEntry, _new.Slot, _new.Gender, race, _new.SetId);
} }
@ -241,7 +249,8 @@ public partial class ModEditWindow
ImGui.TableNextColumn(); ImGui.TableNextColumn();
if (Combos.Gender("##eqdpGender", _new.Gender, out var gender)) if (Combos.Gender("##eqdpGender", _new.Gender, out var gender))
{ {
var newDefaultEntry = ExpandedEqdpFile.GetDefault(metaFileManager, Names.CombinedRace(gender, _new.Race), _new.Slot.IsAccessory(), _new.SetId); var newDefaultEntry = ExpandedEqdpFile.GetDefault(metaFileManager, Names.CombinedRace(gender, _new.Race),
_new.Slot.IsAccessory(), _new.SetId);
_new = new EqdpManipulation(newDefaultEntry, _new.Slot, gender, _new.Race, _new.SetId); _new = new EqdpManipulation(newDefaultEntry, _new.Slot, gender, _new.Race, _new.SetId);
} }
@ -250,7 +259,8 @@ public partial class ModEditWindow
ImGui.TableNextColumn(); ImGui.TableNextColumn();
if (Combos.EqdpEquipSlot("##eqdpSlot", _new.Slot, out var slot)) if (Combos.EqdpEquipSlot("##eqdpSlot", _new.Slot, out var slot))
{ {
var newDefaultEntry = ExpandedEqdpFile.GetDefault(metaFileManager, Names.CombinedRace(_new.Gender, _new.Race), slot.IsAccessory(), _new.SetId); var newDefaultEntry = ExpandedEqdpFile.GetDefault(metaFileManager, Names.CombinedRace(_new.Gender, _new.Race),
slot.IsAccessory(), _new.SetId);
_new = new EqdpManipulation(newDefaultEntry, slot, _new.Gender, _new.Race, _new.SetId); _new = new EqdpManipulation(newDefaultEntry, slot, _new.Gender, _new.Race, _new.SetId);
} }
@ -288,7 +298,8 @@ public partial class ModEditWindow
ImGuiUtil.HoverTooltip(EquipSlotTooltip); ImGuiUtil.HoverTooltip(EquipSlotTooltip);
// Values // Values
var defaultEntry = ExpandedEqdpFile.GetDefault(metaFileManager, Names.CombinedRace(meta.Gender, meta.Race), meta.Slot.IsAccessory(), meta.SetId); var defaultEntry = ExpandedEqdpFile.GetDefault(metaFileManager, Names.CombinedRace(meta.Gender, meta.Race), meta.Slot.IsAccessory(),
meta.SetId);
var (defaultBit1, defaultBit2) = defaultEntry.ToBits(meta.Slot); var (defaultBit1, defaultBit2) = defaultEntry.ToBits(meta.Slot);
var (bit1, bit2) = meta.Entry.ToBits(meta.Slot); var (bit1, bit2) = meta.Entry.ToBits(meta.Slot);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
@ -370,7 +381,8 @@ public partial class ModEditWindow
if (_new.ObjectType is ObjectType.Equipment) if (_new.ObjectType is ObjectType.Equipment)
{ {
if (Combos.EqpEquipSlot("##imcSlot", 100, _new.EquipSlot, out var slot)) if (Combos.EqpEquipSlot("##imcSlot", 100, _new.EquipSlot, out var slot))
_new = new ImcManipulation(_new.ObjectType, _new.BodySlot, _new.PrimaryId, _new.SecondaryId, _new.Variant.Id, slot, _new.Entry) _new = new ImcManipulation(_new.ObjectType, _new.BodySlot, _new.PrimaryId, _new.SecondaryId, _new.Variant.Id, slot,
_new.Entry)
.Copy(GetDefault(metaFileManager, _new) .Copy(GetDefault(metaFileManager, _new)
?? new ImcEntry()); ?? new ImcEntry());
@ -379,7 +391,8 @@ public partial class ModEditWindow
else if (_new.ObjectType is ObjectType.Accessory) else if (_new.ObjectType is ObjectType.Accessory)
{ {
if (Combos.AccessorySlot("##imcSlot", _new.EquipSlot, out var slot)) if (Combos.AccessorySlot("##imcSlot", _new.EquipSlot, out var slot))
_new = new ImcManipulation(_new.ObjectType, _new.BodySlot, _new.PrimaryId, _new.SecondaryId, _new.Variant.Id, slot, _new.Entry) _new = new ImcManipulation(_new.ObjectType, _new.BodySlot, _new.PrimaryId, _new.SecondaryId, _new.Variant.Id, slot,
_new.Entry)
.Copy(GetDefault(metaFileManager, _new) .Copy(GetDefault(metaFileManager, _new)
?? new ImcEntry()); ?? new ImcEntry());
@ -388,7 +401,8 @@ public partial class ModEditWindow
else else
{ {
if (IdInput("##imcId2", 100 * UiHelpers.Scale, _new.SecondaryId.Id, out var setId2, 0, ushort.MaxValue, false)) if (IdInput("##imcId2", 100 * UiHelpers.Scale, _new.SecondaryId.Id, out var setId2, 0, ushort.MaxValue, false))
_new = new ImcManipulation(_new.ObjectType, _new.BodySlot, _new.PrimaryId, setId2, _new.Variant.Id, _new.EquipSlot, _new.Entry) _new = new ImcManipulation(_new.ObjectType, _new.BodySlot, _new.PrimaryId, setId2, _new.Variant.Id, _new.EquipSlot,
_new.Entry)
.Copy(GetDefault(metaFileManager, _new) .Copy(GetDefault(metaFileManager, _new)
?? new ImcEntry()); ?? new ImcEntry());
@ -405,7 +419,8 @@ public partial class ModEditWindow
if (_new.ObjectType is ObjectType.DemiHuman) if (_new.ObjectType is ObjectType.DemiHuman)
{ {
if (Combos.EqpEquipSlot("##imcSlot", 70, _new.EquipSlot, out var slot)) if (Combos.EqpEquipSlot("##imcSlot", 70, _new.EquipSlot, out var slot))
_new = new ImcManipulation(_new.ObjectType, _new.BodySlot, _new.PrimaryId, _new.SecondaryId, _new.Variant.Id, slot, _new.Entry) _new = new ImcManipulation(_new.ObjectType, _new.BodySlot, _new.PrimaryId, _new.SecondaryId, _new.Variant.Id, slot,
_new.Entry)
.Copy(GetDefault(metaFileManager, _new) .Copy(GetDefault(metaFileManager, _new)
?? new ImcEntry()); ?? new ImcEntry());
@ -787,7 +802,8 @@ public partial class ModEditWindow
using var color = ImRaii.PushColor(ImGuiCol.FrameBg, using var color = ImRaii.PushColor(ImGuiCol.FrameBg,
def < value ? ColorId.IncreasedMetaValue.Value() : ColorId.DecreasedMetaValue.Value(), def < value ? ColorId.IncreasedMetaValue.Value() : ColorId.DecreasedMetaValue.Value(),
def != value); def != value);
if (ImGui.DragFloat("##rspValue", ref value, 0.001f, RspManipulation.MinValue, RspManipulation.MaxValue) && value is >= RspManipulation.MinValue and <= RspManipulation.MaxValue) if (ImGui.DragFloat("##rspValue", ref value, 0.001f, RspManipulation.MinValue, RspManipulation.MaxValue)
&& value is >= RspManipulation.MinValue and <= RspManipulation.MaxValue)
editor.MetaEditor.Change(meta.Copy(value)); editor.MetaEditor.Change(meta.Copy(value));
ImGuiUtil.HoverTooltip($"Default Value: {def:0.###}"); ImGuiUtil.HoverTooltip($"Default Value: {def:0.###}");

View file

@ -36,9 +36,7 @@ public partial class ModEditWindow
private static bool DrawOtherModelDetails(MdlFile file, bool _) private static bool DrawOtherModelDetails(MdlFile file, bool _)
{ {
if (!ImGui.CollapsingHeader("Further Content")) if (!ImGui.CollapsingHeader("Further Content"))
{
return false; return false;
}
using (var table = ImRaii.Table("##data", 2, ImGuiTableFlags.SizingFixedFit)) using (var table = ImRaii.Table("##data", 2, ImGuiTableFlags.SizingFixedFit))
{ {
@ -88,46 +86,31 @@ public partial class ModEditWindow
using (var attributes = ImRaii.TreeNode("Attributes", ImGuiTreeNodeFlags.DefaultOpen)) using (var attributes = ImRaii.TreeNode("Attributes", ImGuiTreeNodeFlags.DefaultOpen))
{ {
if (attributes) if (attributes)
{
foreach (var attribute in file.Attributes) foreach (var attribute in file.Attributes)
{
ImRaii.TreeNode(attribute, ImGuiTreeNodeFlags.Leaf).Dispose(); ImRaii.TreeNode(attribute, ImGuiTreeNodeFlags.Leaf).Dispose();
} }
}
}
using (var bones = ImRaii.TreeNode("Bones", ImGuiTreeNodeFlags.DefaultOpen)) using (var bones = ImRaii.TreeNode("Bones", ImGuiTreeNodeFlags.DefaultOpen))
{ {
if (bones) if (bones)
{
foreach (var bone in file.Bones) foreach (var bone in file.Bones)
{
ImRaii.TreeNode(bone, ImGuiTreeNodeFlags.Leaf).Dispose(); ImRaii.TreeNode(bone, ImGuiTreeNodeFlags.Leaf).Dispose();
} }
}
}
using (var shapes = ImRaii.TreeNode("Shapes", ImGuiTreeNodeFlags.DefaultOpen)) using (var shapes = ImRaii.TreeNode("Shapes", ImGuiTreeNodeFlags.DefaultOpen))
{ {
if (shapes) if (shapes)
{
foreach (var shape in file.Shapes) foreach (var shape in file.Shapes)
{
ImRaii.TreeNode(shape.ShapeName, ImGuiTreeNodeFlags.Leaf).Dispose(); ImRaii.TreeNode(shape.ShapeName, ImGuiTreeNodeFlags.Leaf).Dispose();
} }
}
}
if (file.RemainingData.Length > 0) if (file.RemainingData.Length > 0)
{ {
using var t = ImRaii.TreeNode($"Additional Data (Size: {file.RemainingData.Length})###AdditionalData"); using var t = ImRaii.TreeNode($"Additional Data (Size: {file.RemainingData.Length})###AdditionalData");
if (t) if (t)
{
ImGuiUtil.TextWrapped(string.Join(' ', file.RemainingData.Select(c => $"{c:X2}"))); ImGuiUtil.TextWrapped(string.Join(' ', file.RemainingData.Select(c => $"{c:X2}")));
} }
}
return false; return false;
} }
} }

View file

@ -7,6 +7,7 @@ using Penumbra.GameData.Files;
using Penumbra.Interop.ResourceTree; using Penumbra.Interop.ResourceTree;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.Mods.Editor; using Penumbra.Mods.Editor;
using Penumbra.Mods.Subclasses;
using Penumbra.String.Classes; using Penumbra.String.Classes;
namespace Penumbra.UI.AdvancedWindow; namespace Penumbra.UI.AdvancedWindow;

View file

@ -489,16 +489,22 @@ public partial class ModEditWindow
continue; continue;
foreach (var (key, keyIdx) in node.SystemKeys.WithIndex()) foreach (var (key, keyIdx) in node.SystemKeys.WithIndex())
{
ImRaii.TreeNode($"System Key 0x{tab.Shpk.SystemKeys[keyIdx].Id:X8} = 0x{key:X8}", ImRaii.TreeNode($"System Key 0x{tab.Shpk.SystemKeys[keyIdx].Id:X8} = 0x{key:X8}",
ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose();
}
foreach (var (key, keyIdx) in node.SceneKeys.WithIndex()) foreach (var (key, keyIdx) in node.SceneKeys.WithIndex())
{
ImRaii.TreeNode($"Scene Key 0x{tab.Shpk.SceneKeys[keyIdx].Id:X8} = 0x{key:X8}", ImRaii.TreeNode($"Scene Key 0x{tab.Shpk.SceneKeys[keyIdx].Id:X8} = 0x{key:X8}",
ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose();
}
foreach (var (key, keyIdx) in node.MaterialKeys.WithIndex()) foreach (var (key, keyIdx) in node.MaterialKeys.WithIndex())
{
ImRaii.TreeNode($"Material Key 0x{tab.Shpk.MaterialKeys[keyIdx].Id:X8} = 0x{key:X8}", ImRaii.TreeNode($"Material Key 0x{tab.Shpk.MaterialKeys[keyIdx].Id:X8} = 0x{key:X8}",
ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose();
}
foreach (var (key, keyIdx) in node.SubViewKeys.WithIndex()) foreach (var (key, keyIdx) in node.SubViewKeys.WithIndex())
ImRaii.TreeNode($"Sub-View Key #{keyIdx} = 0x{key:X8}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose(); ImRaii.TreeNode($"Sub-View Key #{keyIdx} = 0x{key:X8}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose();
@ -530,10 +536,12 @@ public partial class ModEditWindow
{ {
using var font = ImRaii.PushFont(UiBuilder.MonoFont); using var font = ImRaii.PushFont(UiBuilder.MonoFont);
foreach (var selector in tab.Shpk.NodeSelectors) foreach (var selector in tab.Shpk.NodeSelectors)
{
ImRaii.TreeNode($"#{selector.Value:D4}: Selector: 0x{selector.Key:X8}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet) ImRaii.TreeNode($"#{selector.Value:D4}: Selector: 0x{selector.Key:X8}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet)
.Dispose(); .Dispose();
} }
} }
}
private static void DrawOtherShaderPackageDetails(ShpkTab tab) private static void DrawOtherShaderPackageDetails(ShpkTab tab)
{ {

View file

@ -193,7 +193,8 @@ public partial class ModEditWindow
private void OpenSaveAsDialog(string defaultExtension) private void OpenSaveAsDialog(string defaultExtension)
{ {
var fileName = Path.GetFileNameWithoutExtension(_left.Path.Length > 0 ? _left.Path : _right.Path); var fileName = Path.GetFileNameWithoutExtension(_left.Path.Length > 0 ? _left.Path : _right.Path);
_fileDialog.OpenSavePicker("Save Texture as TEX, DDS or PNG...", "Textures{.png,.dds,.tex},.tex,.dds,.png", fileName, defaultExtension, (a, b) => _fileDialog.OpenSavePicker("Save Texture as TEX, DDS or PNG...", "Textures{.png,.dds,.tex},.tex,.dds,.png", fileName, defaultExtension,
(a, b) =>
{ {
if (a) if (a)
{ {

View file

@ -6,7 +6,6 @@ using Dalamud.Interface.Windowing;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using ImGuiNET; using ImGuiNET;
using OtterGui; using OtterGui;
using OtterGui.Compression;
using OtterGui.Raii; using OtterGui.Raii;
using Penumbra.Collections.Manager; using Penumbra.Collections.Manager;
using Penumbra.Communication; using Penumbra.Communication;
@ -19,6 +18,7 @@ using Penumbra.Meta;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.Mods.Editor; using Penumbra.Mods.Editor;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
using Penumbra.Mods.Subclasses;
using Penumbra.Services; using Penumbra.Services;
using Penumbra.String; using Penumbra.String;
using Penumbra.String.Classes; using Penumbra.String.Classes;

View file

@ -2,9 +2,9 @@ using Dalamud.Interface;
using ImGuiNET; using ImGuiNET;
using OtterGui; using OtterGui;
using OtterGui.Raii; using OtterGui.Raii;
using Penumbra.Mods;
using Penumbra.Mods.Editor; using Penumbra.Mods.Editor;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
using Penumbra.Mods.Subclasses;
using Penumbra.UI.Classes; using Penumbra.UI.Classes;
namespace Penumbra.UI.AdvancedWindow; namespace Penumbra.UI.AdvancedWindow;

View file

@ -138,6 +138,7 @@ public class ResourceTreeViewer
ImGui.Dummy(new Vector2(ImGui.GetFrameHeight())); ImGui.Dummy(new Vector2(ImGui.GetFrameHeight()));
ImGui.SameLine(0f, ImGui.GetStyle().ItemInnerSpacing.X); ImGui.SameLine(0f, ImGui.GetStyle().ItemInnerSpacing.X);
} }
_changedItemDrawer.DrawCategoryIcon(resourceNode.Icon); _changedItemDrawer.DrawCategoryIcon(resourceNode.Icon);
ImGui.SameLine(0f, ImGui.GetStyle().ItemInnerSpacing.X); ImGui.SameLine(0f, ImGui.GetStyle().ItemInnerSpacing.X);
ImGui.TableHeader(resourceNode.Name); ImGui.TableHeader(resourceNode.Name);

View file

@ -47,13 +47,17 @@ public class PenumbraChangelog
private static void Add7_3_0(Changelog log) private static void Add7_3_0(Changelog log)
=> log.NextVersion("Version 0.7.3.0") => log.NextVersion("Version 0.7.3.0")
.RegisterEntry("Added the ability to drag and drop mod files from external sources (like a file explorer or browser) into Penumbras mod selector to import them.") .RegisterEntry(
"Added the ability to drag and drop mod files from external sources (like a file explorer or browser) into Penumbras mod selector to import them.")
.RegisterEntry("You can also drag and drop texture files into the textures tab of the Advanced Editing Window.", 1) .RegisterEntry("You can also drag and drop texture files into the textures tab of the Advanced Editing Window.", 1)
.RegisterEntry("Added a priority display to the mod selector using the currently selected collections priorities. This can be hidden in settings.") .RegisterEntry(
"Added a priority display to the mod selector using the currently selected collections priorities. This can be hidden in settings.")
.RegisterEntry("Added IPC for texture conversion, improved texture handling backend and threading.") .RegisterEntry("Added IPC for texture conversion, improved texture handling backend and threading.")
.RegisterEntry("Added Dalamud Substitution so that other plugins can more easily use replaced icons from Penumbras Interface collection when using Dalamuds new Texture Provider.") .RegisterEntry(
"Added Dalamud Substitution so that other plugins can more easily use replaced icons from Penumbras Interface collection when using Dalamuds new Texture Provider.")
.RegisterEntry("Added a filter to texture selection combos in the textures tab of the Advanced Editing Window.") .RegisterEntry("Added a filter to texture selection combos in the textures tab of the Advanced Editing Window.")
.RegisterEntry("Changed behaviour when failing to load group JSON files for mods - the pre-existing but failing files are now backed up before being deleted or overwritten.") .RegisterEntry(
"Changed behaviour when failing to load group JSON files for mods - the pre-existing but failing files are now backed up before being deleted or overwritten.")
.RegisterEntry("Further backend changes, mostly relating to the Glamourer rework.") .RegisterEntry("Further backend changes, mostly relating to the Glamourer rework.")
.RegisterEntry("Fixed an issue with modded decals not loading correctly when used with the Glamourer rework.") .RegisterEntry("Fixed an issue with modded decals not loading correctly when used with the Glamourer rework.")
.RegisterEntry("Fixed missing scaling with UI Scale for some combos.") .RegisterEntry("Fixed missing scaling with UI Scale for some combos.")
@ -66,21 +70,31 @@ public class PenumbraChangelog
private static void Add7_2_0(Changelog log) private static void Add7_2_0(Changelog log)
=> log.NextVersion("Version 0.7.2.0") => log.NextVersion("Version 0.7.2.0")
.RegisterEntry("Added Changed Item Categories and icons that can filter for specific types of Changed Items, in the Changed Items Tab as well as in the Changed Items panel for specific mods..") .RegisterEntry(
.RegisterEntry("Icons at the top can be clicked to filter, as well as right-clicked to open a context menu with the option to inverse-filter for them", 1) "Added Changed Item Categories and icons that can filter for specific types of Changed Items, in the Changed Items Tab as well as in the Changed Items panel for specific mods..")
.RegisterEntry(
"Icons at the top can be clicked to filter, as well as right-clicked to open a context menu with the option to inverse-filter for them",
1)
.RegisterEntry("There is also an ALL button that can be toggled.", 1) .RegisterEntry("There is also an ALL button that can be toggled.", 1)
.RegisterEntry("Modded files in the Font category now resolve from the Interface assignment instead of the base assignment, despite not technically being in the UI category.") .RegisterEntry(
.RegisterEntry("Timeline files will no longer be associated with specific characters in cutscenes, since there is no way to correctly do this, and it could cause crashes if IVCS-requiring animations were used on characters without IVCS.") "Modded files in the Font category now resolve from the Interface assignment instead of the base assignment, despite not technically being in the UI category.")
.RegisterEntry(
"Timeline files will no longer be associated with specific characters in cutscenes, since there is no way to correctly do this, and it could cause crashes if IVCS-requiring animations were used on characters without IVCS.")
.RegisterEntry("File deletion in the Advanced Editing Window now also checks for your configured deletion key combo.") .RegisterEntry("File deletion in the Advanced Editing Window now also checks for your configured deletion key combo.")
.RegisterEntry("The Texture tab in the Advanced Editing Window now has some quick convert buttons to just convert the selected texture to a different format in-place.") .RegisterEntry(
.RegisterEntry("These buttons only appear if only one texture is selected on the left side, it is not otherwise manipulated, and the texture is a .tex file.", 1) "The Texture tab in the Advanced Editing Window now has some quick convert buttons to just convert the selected texture to a different format in-place.")
.RegisterEntry(
"These buttons only appear if only one texture is selected on the left side, it is not otherwise manipulated, and the texture is a .tex file.",
1)
.RegisterEntry("The text part of the mod filter in the mod selector now also resets when right-clicking the drop-down arrow.") .RegisterEntry("The text part of the mod filter in the mod selector now also resets when right-clicking the drop-down arrow.")
.RegisterEntry("The Dissolve Folder option in the mod selector context menu has been moved to the bottom.") .RegisterEntry("The Dissolve Folder option in the mod selector context menu has been moved to the bottom.")
.RegisterEntry("Somewhat improved IMC handling to prevent some issues.") .RegisterEntry("Somewhat improved IMC handling to prevent some issues.")
.RegisterEntry("Improved the handling of mod renames on mods with default-search names to correctly rename their search-name in (hopefully) all cases too.") .RegisterEntry(
"Improved the handling of mod renames on mods with default-search names to correctly rename their search-name in (hopefully) all cases too.")
.RegisterEntry("A lot of backend improvements and changes related to the pending Glamourer rework.") .RegisterEntry("A lot of backend improvements and changes related to the pending Glamourer rework.")
.RegisterEntry("Fixed an issue where the displayed active collection count in the support info was wrong.") .RegisterEntry("Fixed an issue where the displayed active collection count in the support info was wrong.")
.RegisterEntry("Fixed an issue with created directories dealing badly with non-standard whitespace characters like half-width or non-breaking spaces.") .RegisterEntry(
"Fixed an issue with created directories dealing badly with non-standard whitespace characters like half-width or non-breaking spaces.")
.RegisterEntry("Fixed an issue with unknown animation and vfx edits not being recognized correctly.") .RegisterEntry("Fixed an issue with unknown animation and vfx edits not being recognized correctly.")
.RegisterEntry("Fixed an issue where changing option descriptions to be empty was not working correctly.") .RegisterEntry("Fixed an issue where changing option descriptions to be empty was not working correctly.")
.RegisterEntry("Fixed an issue with texture names in the resource tree of the On-Screen views.") .RegisterEntry("Fixed an issue with texture names in the resource tree of the On-Screen views.")
@ -94,21 +108,29 @@ public class PenumbraChangelog
private static void Add7_1_2(Changelog log) private static void Add7_1_2(Changelog log)
=> log.NextVersion("Version 0.7.1.2") => log.NextVersion("Version 0.7.1.2")
.RegisterEntry("Changed threaded handling of collection caches. Maybe this fixes the startup problems some people are experiencing.") .RegisterEntry(
.RegisterEntry("This is just testing and may not be the solution, or may even make things worse. Sorry if I have to put out multiple small patches again to get this right.", 1) "Changed threaded handling of collection caches. Maybe this fixes the startup problems some people are experiencing.")
.RegisterEntry(
"This is just testing and may not be the solution, or may even make things worse. Sorry if I have to put out multiple small patches again to get this right.",
1)
.RegisterEntry("Fixed Penumbra failing to load if the main configuration file is corrupted.") .RegisterEntry("Fixed Penumbra failing to load if the main configuration file is corrupted.")
.RegisterEntry("Some miscellaneous small bug fixes.") .RegisterEntry("Some miscellaneous small bug fixes.")
.RegisterEntry("Slight changes in behaviour for deduplicator/normalizer, mostly backend.") .RegisterEntry("Slight changes in behaviour for deduplicator/normalizer, mostly backend.")
.RegisterEntry("A typo in the 0.7.1.0 Changelog has been fixed.") .RegisterEntry("A typo in the 0.7.1.0 Changelog has been fixed.")
.RegisterEntry("Fixed left rings not being valid for IMC entries after validation. (7.1.1)") .RegisterEntry("Fixed left rings not being valid for IMC entries after validation. (7.1.1)")
.RegisterEntry("Relaxed the scaling restrictions for RSP scaling values to go from 0.01 to 512.0 instead of the prior upper limit of 8.0, in interface as well as validation, to better support the fetish community. (7.1.1)"); .RegisterEntry(
"Relaxed the scaling restrictions for RSP scaling values to go from 0.01 to 512.0 instead of the prior upper limit of 8.0, in interface as well as validation, to better support the fetish community. (7.1.1)");
private static void Add7_1_0(Changelog log) private static void Add7_1_0(Changelog log)
=> log.NextVersion("Version 0.7.1.0") => log.NextVersion("Version 0.7.1.0")
.RegisterEntry("Updated for patch 6.4 - there may be some oversights on edge cases, but I could not find any issues myself.") .RegisterEntry("Updated for patch 6.4 - there may be some oversights on edge cases, but I could not find any issues myself.")
.RegisterHighlight("This update changed some Dragoon skills that were moving the player character before to not do that anymore. If you have any mods that applied to those skills, please make sure that they do not contain any redirections for .tmb files. If skills that should no longer move your character still do that for some reason, this is detectable by the server.", 1) .RegisterHighlight(
.RegisterEntry("Added a Mod Merging tab in the Advanced Editing Window. This can help you merge multiple mods to one, or split off specific options from an existing mod into a new mod.") "This update changed some Dragoon skills that were moving the player character before to not do that anymore. If you have any mods that applied to those skills, please make sure that they do not contain any redirections for .tmb files. If skills that should no longer move your character still do that for some reason, this is detectable by the server.",
.RegisterEntry("Added advanced options to configure the minimum allowed window size for the main window (to reduce it). This is not quite supported and may look bad, so only use it if you really need smaller windows.") 1)
.RegisterEntry(
"Added a Mod Merging tab in the Advanced Editing Window. This can help you merge multiple mods to one, or split off specific options from an existing mod into a new mod.")
.RegisterEntry(
"Added advanced options to configure the minimum allowed window size for the main window (to reduce it). This is not quite supported and may look bad, so only use it if you really need smaller windows.")
.RegisterEntry("The last tab selected in the main window is now saved and re-used when relaunching Penumbra.") .RegisterEntry("The last tab selected in the main window is now saved and re-used when relaunching Penumbra.")
.RegisterEntry("Added a hook to correctly associate some sounds that are played while weapons are drawn.") .RegisterEntry("Added a hook to correctly associate some sounds that are played while weapons are drawn.")
.RegisterEntry("Added a hook to correctly associate sounds that are played while dismounting.") .RegisterEntry("Added a hook to correctly associate sounds that are played while dismounting.")
@ -125,7 +147,8 @@ public class PenumbraChangelog
.RegisterEntry("Fixed an issue with the file selectors not always opening at the expected locations. (0.7.0.7)") .RegisterEntry("Fixed an issue with the file selectors not always opening at the expected locations. (0.7.0.7)")
.RegisterEntry("Fixed some cache handling issues. (0.7.0.5 - 0.7.0.10)") .RegisterEntry("Fixed some cache handling issues. (0.7.0.5 - 0.7.0.10)")
.RegisterEntry("Fixed an issue with multiple collection context menus appearing for some identifiers (0.7.0.5)") .RegisterEntry("Fixed an issue with multiple collection context menus appearing for some identifiers (0.7.0.5)")
.RegisterEntry("Fixed an issue where the Update Bibo button did only work if the Advanced Editing window was opened before. (0.7.0.5)"); .RegisterEntry(
"Fixed an issue where the Update Bibo button did only work if the Advanced Editing window was opened before. (0.7.0.5)");
private static void Add7_0_4(Changelog log) private static void Add7_0_4(Changelog log)
=> log.NextVersion("Version 0.7.0.4") => log.NextVersion("Version 0.7.0.4")
@ -145,26 +168,36 @@ public class PenumbraChangelog
.RegisterEntry("Fixed a bug that showed the Your Character collection as redundant even if it was not.") .RegisterEntry("Fixed a bug that showed the Your Character collection as redundant even if it was not.")
.RegisterEntry("Fixed a bug that caused some required collection caches to not be built on startup and thus mods not to apply.") .RegisterEntry("Fixed a bug that caused some required collection caches to not be built on startup and thus mods not to apply.")
.RegisterEntry("Fixed a bug that showed the current collection as unused even if it was used."); .RegisterEntry("Fixed a bug that showed the current collection as unused even if it was used.");
private static void Add7_0_0(Changelog log) private static void Add7_0_0(Changelog log)
=> log.NextVersion("Version 0.7.0.0") => log.NextVersion("Version 0.7.0.0")
.RegisterHighlight("The entire backend was reworked (this is still in progress). While this does not come with a lot of functionality changes, basically every file and functionality was touched.") .RegisterHighlight(
.RegisterEntry("This may have (re-)introduced some bugs that have not yet been noticed despite a long testing period - there are not many users of the testing branch.", 1) "The entire backend was reworked (this is still in progress). While this does not come with a lot of functionality changes, basically every file and functionality was touched.")
.RegisterEntry(
"This may have (re-)introduced some bugs that have not yet been noticed despite a long testing period - there are not many users of the testing branch.",
1)
.RegisterEntry("If you encounter any - but especially breaking or lossy - bugs, please report them immediately.", 1) .RegisterEntry("If you encounter any - but especially breaking or lossy - bugs, please report them immediately.", 1)
.RegisterEntry("This also fixed or improved numerous bugs and issues that will not be listed here.", 1) .RegisterEntry("This also fixed or improved numerous bugs and issues that will not be listed here.", 1)
.RegisterEntry("GitHub currently reports 321 changed files with 34541 additions and 28464 deletions.", 1) .RegisterEntry("GitHub currently reports 321 changed files with 34541 additions and 28464 deletions.", 1)
.RegisterEntry("Added Notifications on many failures that previously only wrote to log.") .RegisterEntry("Added Notifications on many failures that previously only wrote to log.")
.RegisterEntry("Reworked the Collections Tab to hopefully be much more intuitive. It should be self-explanatory now.") .RegisterEntry("Reworked the Collections Tab to hopefully be much more intuitive. It should be self-explanatory now.")
.RegisterEntry("The tutorial was adapted to the new window, if you are unsure, maybe try restarting it.", 1) .RegisterEntry("The tutorial was adapted to the new window, if you are unsure, maybe try restarting it.", 1)
.RegisterEntry("You can now toggle an incognito mode in the collection window so it shows shortened names of collections and players.", 1) .RegisterEntry(
.RegisterEntry("You can get an overview about the current usage of a selected collection and its active and unused mod settings in the Collection Details panel.", 1) "You can now toggle an incognito mode in the collection window so it shows shortened names of collections and players.", 1)
.RegisterEntry(
"You can get an overview about the current usage of a selected collection and its active and unused mod settings in the Collection Details panel.",
1)
.RegisterEntry("The currently selected collection is now highlighted in green (default, configurable) in multiple places.", 1) .RegisterEntry("The currently selected collection is now highlighted in green (default, configurable) in multiple places.", 1)
.RegisterEntry("Mods now have a 'Collections' panel in the Mod Panel containing an overview about usage of the mod in all collections.") .RegisterEntry(
"Mods now have a 'Collections' panel in the Mod Panel containing an overview about usage of the mod in all collections.")
.RegisterEntry("The 'Changed Items' and 'Effective Changes' tab now contain a collection selector.") .RegisterEntry("The 'Changed Items' and 'Effective Changes' tab now contain a collection selector.")
.RegisterEntry("Added the On-Screen tab to find what files a specific character is actually using (by Ny).") .RegisterEntry("Added the On-Screen tab to find what files a specific character is actually using (by Ny).")
.RegisterEntry("Added 3 Quick Move folders in the mod selector that can be setup in context menus for easier cleanup.") .RegisterEntry("Added 3 Quick Move folders in the mod selector that can be setup in context menus for easier cleanup.")
.RegisterEntry("Added handling for certain animation files for mounts and fashion accessories to correctly associate them to players.") .RegisterEntry(
"Added handling for certain animation files for mounts and fashion accessories to correctly associate them to players.")
.RegisterEntry("The file selectors in the Advanced Mod Editing Window now use filterable combos.") .RegisterEntry("The file selectors in the Advanced Mod Editing Window now use filterable combos.")
.RegisterEntry("The Advanced Mod Editing Window now shows the number of meta edits and file swaps in unselected options and highlights the option selector.") .RegisterEntry(
"The Advanced Mod Editing Window now shows the number of meta edits and file swaps in unselected options and highlights the option selector.")
.RegisterEntry("Added API/IPC to start unpacking and installing mods from external tools (by Sebastina).") .RegisterEntry("Added API/IPC to start unpacking and installing mods from external tools (by Sebastina).")
.RegisterEntry("Hidden files and folders are now ignored for unused files in Advanced Mod Editing (by myr)") .RegisterEntry("Hidden files and folders are now ignored for unused files in Advanced Mod Editing (by myr)")
.RegisterEntry("Paths in mods are now automatically trimmed of whitespace on loading.") .RegisterEntry("Paths in mods are now automatically trimmed of whitespace on loading.")

View file

@ -21,13 +21,16 @@ public static class Combos
=> ImGuiUtil.GenericEnumCombo(label, unscaledWidth * UiHelpers.Scale, current, out gender, RaceEnumExtensions.ToName, 1); => ImGuiUtil.GenericEnumCombo(label, unscaledWidth * UiHelpers.Scale, current, out gender, RaceEnumExtensions.ToName, 1);
public static bool EqdpEquipSlot(string label, EquipSlot current, out EquipSlot slot) public static bool EqdpEquipSlot(string label, EquipSlot current, out EquipSlot slot)
=> ImGuiUtil.GenericEnumCombo( label, 100 * UiHelpers.Scale, current, out slot, EquipSlotExtensions.EqdpSlots, EquipSlotExtensions.ToName ); => ImGuiUtil.GenericEnumCombo(label, 100 * UiHelpers.Scale, current, out slot, EquipSlotExtensions.EqdpSlots,
EquipSlotExtensions.ToName);
public static bool EqpEquipSlot(string label, float width, EquipSlot current, out EquipSlot slot) public static bool EqpEquipSlot(string label, float width, EquipSlot current, out EquipSlot slot)
=> ImGuiUtil.GenericEnumCombo( label, width * UiHelpers.Scale, current, out slot, EquipSlotExtensions.EquipmentSlots, EquipSlotExtensions.ToName ); => ImGuiUtil.GenericEnumCombo(label, width * UiHelpers.Scale, current, out slot, EquipSlotExtensions.EquipmentSlots,
EquipSlotExtensions.ToName);
public static bool AccessorySlot(string label, EquipSlot current, out EquipSlot slot) public static bool AccessorySlot(string label, EquipSlot current, out EquipSlot slot)
=> ImGuiUtil.GenericEnumCombo( label, 100 * UiHelpers.Scale, current, out slot, EquipSlotExtensions.AccessorySlots, EquipSlotExtensions.ToName ); => ImGuiUtil.GenericEnumCombo(label, 100 * UiHelpers.Scale, current, out slot, EquipSlotExtensions.AccessorySlots,
EquipSlotExtensions.ToName);
public static bool SubRace(string label, SubRace current, out SubRace subRace) public static bool SubRace(string label, SubRace current, out SubRace subRace)
=> ImGuiUtil.GenericEnumCombo(label, 150 * UiHelpers.Scale, current, out subRace, RaceEnumExtensions.ToName, 1); => ImGuiUtil.GenericEnumCombo(label, 150 * UiHelpers.Scale, current, out subRace, RaceEnumExtensions.ToName, 1);

View file

@ -31,7 +31,8 @@ public class InheritanceUi
public void Draw() public void Draw()
{ {
using var id = ImRaii.PushId("##Inheritance"); using var id = ImRaii.PushId("##Inheritance");
ImGuiUtil.DrawColoredText(($"The {TutorialService.SelectedCollection} ", 0), (Name(_active.Current), ColorId.SelectedCollection.Value() | 0xFF000000), (" inherits from:", 0)); ImGuiUtil.DrawColoredText(($"The {TutorialService.SelectedCollection} ", 0),
(Name(_active.Current), ColorId.SelectedCollection.Value() | 0xFF000000), (" inherits from:", 0));
ImGui.Dummy(Vector2.One); ImGui.Dummy(Vector2.One);
DrawCurrentCollectionInheritance(); DrawCurrentCollectionInheritance();
@ -122,7 +123,8 @@ public class InheritanceUi
_seenInheritedCollections.Contains(inheritance)); _seenInheritedCollections.Contains(inheritance));
_seenInheritedCollections.Add(inheritance); _seenInheritedCollections.Add(inheritance);
ImRaii.TreeNode($"{Name(inheritance)}###{inheritance.Name}", ImGuiTreeNodeFlags.NoTreePushOnOpen | ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet); ImRaii.TreeNode($"{Name(inheritance)}###{inheritance.Name}",
ImGuiTreeNodeFlags.NoTreePushOnOpen | ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet);
var (minRect, maxRect) = (ImGui.GetItemRectMin(), ImGui.GetItemRectMax()); var (minRect, maxRect) = (ImGui.GetItemRectMin(), ImGui.GetItemRectMax());
DrawInheritanceTreeClicks(inheritance, false); DrawInheritanceTreeClicks(inheritance, false);

View file

@ -1,5 +1,3 @@
using System.Collections.Concurrent;
using System.Reflection;
using Dalamud.Interface; using Dalamud.Interface;
using Dalamud.Interface.ImGuiFileDialog; using Dalamud.Interface.ImGuiFileDialog;
using Dalamud.Utility; using Dalamud.Utility;

View file

@ -14,6 +14,7 @@ using Penumbra.Collections.Manager;
using Penumbra.Communication; using Penumbra.Communication;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
using Penumbra.Mods.Subclasses;
using Penumbra.Services; using Penumbra.Services;
using Penumbra.UI.Classes; using Penumbra.UI.Classes;
using ChatService = Penumbra.Services.ChatService; using ChatService = Penumbra.Services.ChatService;
@ -376,8 +377,10 @@ public sealed class ModFileSystemSelector : FileSystemSelector<Mod, ModFileSyste
ImGui.BulletText( ImGui.BulletText(
"You can drag and drop mods and subfolders into existing folders. Dropping them onto mods is the same as dropping them onto the parent of the mod."); "You can drag and drop mods and subfolders into existing folders. Dropping them onto mods is the same as dropping them onto the parent of the mod.");
indent.Push(); indent.Push();
ImGui.BulletText("You can select multiple mods and folders by holding Control while clicking them, and then drag all of them at once." ); ImGui.BulletText(
ImGui.BulletText("Selected mods inside an also selected folder will be ignored when dragging and move inside their folder instead of directly into the target."); "You can select multiple mods and folders by holding Control while clicking them, and then drag all of them at once.");
ImGui.BulletText(
"Selected mods inside an also selected folder will be ignored when dragging and move inside their folder instead of directly into the target.");
indent.Pop(1); indent.Pop(1);
ImGui.BulletText("Right-clicking a folder opens a context menu."); ImGui.BulletText("Right-clicking a folder opens a context menu.");
ImGui.BulletText("Right-clicking empty space allows you to expand or collapse all folders at once."); ImGui.BulletText("Right-clicking empty space allows you to expand or collapse all folders at once.");

View file

@ -4,6 +4,7 @@ using ImGuiNET;
using OtterGui; using OtterGui;
using OtterGui.Raii; using OtterGui.Raii;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.Mods.Manager;
using Penumbra.UI.AdvancedWindow; using Penumbra.UI.AdvancedWindow;
namespace Penumbra.UI.ModsTab; namespace Penumbra.UI.ModsTab;

View file

@ -3,9 +3,7 @@ using ImGuiNET;
using OtterGui.Raii; using OtterGui.Raii;
using OtterGui; using OtterGui;
using OtterGui.Widgets; using OtterGui.Widgets;
using Penumbra.Mods;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
using Penumbra.UI.Classes;
namespace Penumbra.UI.ModsTab; namespace Penumbra.UI.ModsTab;

View file

@ -4,10 +4,8 @@ using OtterGui;
using OtterGui.Widgets; using OtterGui.Widgets;
using Penumbra.Api.Enums; using Penumbra.Api.Enums;
using Penumbra.Collections; using Penumbra.Collections;
using Penumbra.Mods;
using Penumbra.UI.Classes; using Penumbra.UI.Classes;
using Dalamud.Interface.Components; using Dalamud.Interface.Components;
using Dalamud.Interface;
using Penumbra.Collections.Manager; using Penumbra.Collections.Manager;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
using Penumbra.Mods.Subclasses; using Penumbra.Mods.Subclasses;

Some files were not shown because too many files have changed in this diff Show more