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 @@
[*.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
# Standard properties
charset = utf-8
end_of_line = lf
insert_final_newline = true
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
csharp_style_prefer_top_level_statements = true:silent
[*]
# Microsoft .NET properties
csharp_indent_braces=false
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_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}]
indent_style=tab
indent_size=tab
@ -3601,6 +3587,21 @@ indent_style=space
indent_size=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}]
indent_style=space
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_simplified_interpolation = 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);
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;
}

View file

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

View file

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

View file

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

View file

@ -47,7 +47,8 @@ public static class ActiveCollectionMigration
if (!storage.ByName(collectionName, out var collection))
{
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);
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));
if (m != null && m != yourself)
return string.Empty;
var f = ByType(CollectionTypeExtensions.FromParts(race, Gender.Female, false));
if (f != null && f != yourself)
return string.Empty;
@ -460,14 +461,16 @@ public class ActiveCollections : ISavable, IDisposable
if (male == null)
{
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)
return
$"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)
{
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;

View file

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

View file

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

View file

@ -47,7 +47,8 @@ public sealed partial class IndividualCollections : IReadOnlyList<(string Displa
return true;
// 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);
if (npcIdentifier.IsValid && _individuals.TryGetValue(npcIdentifier, out collection))
return true;
@ -56,7 +57,8 @@ public sealed partial class IndividualCollections : IReadOnlyList<(string Displa
if (!_config.UseOwnerNameForCharacterCollection)
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);
return CheckWorlds(identifier, out collection);
}
@ -142,7 +144,8 @@ public sealed partial class IndividualCollections : IReadOnlyList<(string Displa
if (_individuals.TryGetValue(identifier, out collection))
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);
if (identifier.IsValid && _individuals.TryGetValue(identifier, out collection))
return true;

View file

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

View file

@ -132,7 +132,8 @@ public sealed partial class IndividualCollections
_ => throw new NotImplementedException(),
};
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();
}

View file

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

View file

@ -92,7 +92,7 @@ public partial class ModCollection
// Used for short periods of changed files.
public MetaList.MetaReverter TemporarilySetEqdpFile(CharacterUtility utility, GenderRace genderRace, bool 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)
=> _cache?.Meta.TemporarilySetEqpFile()

View file

@ -1,6 +1,7 @@
using Penumbra.Mods;
using Penumbra.Mods.Manager;
using Penumbra.Collections.Manager;
using Penumbra.Mods.Subclasses;
using Penumbra.Services;
namespace Penumbra.Collections;
@ -142,7 +143,8 @@ public partial class ModCollection
public static ModCollection CreateEmpty(string name, int index, int modCount)
{
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>());
}

View file

@ -3,6 +3,7 @@ using Penumbra.Mods;
using Penumbra.Services;
using Newtonsoft.Json;
using Penumbra.Mods.Manager;
using Penumbra.Mods.Subclasses;
using Penumbra.Util;
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)
return false;
_config.MinimumSize.X = Configuration.Constants.MinimumSizeX;
_config.MinimumSize.Y = Configuration.Constants.MinimumSizeY;
_config.Save();

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -59,9 +59,7 @@ public partial class TexToolsMeta
{
var idx = entries.FindIndex(t => t.type == type);
if (idx < 0)
{
return null;
}
reader.BaseStream.Seek(entries[idx].offset, SeekOrigin.Begin);
return reader.ReadBytes(entries[idx].size);
@ -92,9 +90,7 @@ public partial class TexToolsMeta
{
var builder = new StringBuilder();
for (var c = reader.ReadChar(); c != 0; c = reader.ReadChar())
{
builder.Append(c);
}
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)
: this(size.Width, size.Height, pixelData)
{
}
{ }
public Image<Rgba32> ToImage()
=> Image.LoadPixelData<Rgba32>(PixelData, Width, Height);

View file

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

View file

@ -80,7 +80,8 @@ public sealed unsafe class LiveColorTablePreviewer : LiveMaterialPreviewerBase
textureSize[0] = TextureWidth;
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)
return;

View file

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

View file

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

View file

@ -37,7 +37,8 @@ public class 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)
{
Name = uiData.Name;
@ -69,7 +70,7 @@ public class ResourceNode
}
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)
=> 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 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);
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 = "")

View file

@ -4,21 +4,25 @@ namespace Penumbra.Interop.SafeHandles;
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)
throw new ArgumentException("Non-owning SafeResourceHandle with IncRef is unsupported");
if (incRef && handle != null)
handle->IncRef();
SetHandle((nint)handle);
}
public static SafeResourceHandle CreateInvalid()
=> new(null, incRef: false);
=> new(null, false);
protected override bool ReleaseHandle()
{

View file

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

View file

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

View file

@ -26,7 +26,8 @@ public unsafe struct Material
[FieldOffset(0x38)]
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)]
public struct TextureEntry

View file

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

View file

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

View file

@ -4,12 +4,13 @@ using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
namespace Penumbra.Interop.Structs;
public unsafe static class TextureUtility
public static unsafe class TextureUtility
{
private static readonly Functions Funcs = new();
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)
=> ((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 mask = Eqp.Mask(Slot);
if ((entry & mask) == Entry)
{
return false;
}
file[SetId] = (entry & ~mask) | Entry;
return true;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -10,18 +10,20 @@ namespace Penumbra.Mods.ItemSwap;
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.
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)
{
throw new Exception($"The Customization ID {idFrom} is too large for {slot}.");
}
var mdlPathFrom = GamePaths.Character.Mdl.Path(race, slot, idFrom, slot.ToCustomizationType());
var mdlPathTo = GamePaths.Character.Mdl.Path(race, slot, idTo, slot.ToCustomizationType());
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())
{
@ -39,7 +41,8 @@ public static class CustomizationSwap
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)
{
variant = slot is BodySlot.Face or BodySlot.Zear ? byte.MaxValue : variant;
@ -49,7 +52,8 @@ public static class CustomizationSwap
var newFileName = fileName;
newFileName = ItemSwap.ReplaceRace(newFileName, gameRaceTo, race, gameRaceTo != race);
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);
var actualMtrlFromPath = mtrlFromPath;
@ -73,7 +77,8 @@ public static class CustomizationSwap
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)
{
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}";
return FileSwap.CreateSwap(manager, ResourceType.Shpk, redirections, path, path);

View file

@ -265,7 +265,8 @@ public static class EquipmentSwap
{
items = identifier.Identify(slotFrom.IsEquipment()
? 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();
}
@ -283,11 +284,13 @@ public static class EquipmentSwap
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)
=> 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,
Variant variantFrom, Variant variantTo, ImcFile imcFileFrom, ImcFile imcFileTo)
{
@ -401,7 +404,8 @@ public static class EquipmentSwap
ref MtrlFile.Texture texture, ref bool 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)
{
var path = texture.Path;
@ -428,13 +432,15 @@ public static class EquipmentSwap
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}";
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;
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)
{
if (path.FullName.Length > 0)
{
try
{
if (path.IsRooted)
@ -48,7 +47,6 @@ public static class ItemSwap
{
Penumbra.Log.Debug($"Could not load file {path}:\n{e}");
}
}
data = Array.Empty<byte>();
return false;
@ -72,9 +70,7 @@ public static class ItemSwap
{
file = new GenericFile(manager, path);
if (file.Valid)
{
return true;
}
file = null;
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);
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);
return FileSwap.CreateSwap(manager, ResourceType.Sklb, redirections, sklbPath, sklbPath);
}
/// <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)
{
if (type == 0)
{
return null;
}
var (gender, race) = genderRace.Split();
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];
if (i == str.Length - 1 || str[i + 1] == '\0')
{
break;
}
hash2 = ((hash2 << 5) + hash2) ^ str[i + 1];
}

View file

@ -6,6 +6,7 @@ using Penumbra.Meta.Manipulations;
using Penumbra.String.Classes;
using Penumbra.Meta;
using Penumbra.Mods.Manager;
using Penumbra.Mods.Subclasses;
using Penumbra.Services;
namespace Penumbra.Mods.ItemSwap;
@ -40,7 +41,8 @@ public class ItemSwapContainer
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 convertedFiles = new Dictionary<Utf8GamePath, FullPath>(Swaps.Count);
@ -55,9 +57,7 @@ public class ItemSwapContainer
case FileSwap file:
// Skip, nothing to do
if (file.SwapToModdedEqualsOriginal)
{
continue;
}
if (writeType == WriteType.UseSwaps && file.SwapToModdedExistsInGame && !file.DataWasChanged)
{
@ -75,9 +75,7 @@ public class ItemSwapContainer
break;
case MetaSwap meta:
if (!meta.SwapAppliedIsDefault)
{
convertedManips.Add(meta.SwapApplied);
}
break;
}
@ -127,11 +125,13 @@ public class ItemSwapContainer
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();
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;
return ret;
}
@ -140,12 +140,14 @@ public class ItemSwapContainer
{
Swaps.Clear();
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;
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 mdl = CustomizationSwap.CreateMdl(manager, pathResolver, slot, race, from, to);
@ -161,9 +163,7 @@ public class ItemSwapContainer
Swaps.Add(mdl);
if (est != null)
{
Swaps.Add(est);
}
Loaded = true;
return true;

View file

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

View file

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

View file

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

View file

@ -6,7 +6,6 @@ using Penumbra.Api.Enums;
using Penumbra.Mods.Subclasses;
using Penumbra.Services;
using Penumbra.String.Classes;
using Penumbra.Util;
namespace Penumbra.Mods.Manager;
@ -19,7 +18,9 @@ public static partial class ModMigration
private static partial Regex GroupStartRegex();
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)
{

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -4,9 +4,8 @@ using Newtonsoft.Json.Linq;
using OtterGui;
using OtterGui.Filesystem;
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>
public sealed class MultiModGroup : IModGroup

View file

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

View file

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

View file

@ -5,7 +5,6 @@ using Penumbra.Mods.Manager;
using Penumbra.Mods.Subclasses;
using Penumbra.Services;
using Penumbra.String.Classes;
using Penumbra.Util;
namespace Penumbra.Mods;
@ -27,7 +26,10 @@ public class TemporaryMod : IMod
=> Array.Empty<IModGroup>();
public IEnumerable<SubMod> AllSubMods
=> new[] { Default };
=> new[]
{
Default,
};
public TemporaryMod()
=> Default = new SubMod(this);
@ -44,7 +46,8 @@ public class TemporaryMod : IMod
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;
try

View file

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

View file

@ -7,6 +7,7 @@ using Penumbra.Interop.Services;
using Penumbra.Mods;
using Penumbra.Mods.Editor;
using Penumbra.Mods.Manager;
using Penumbra.Mods.Subclasses;
using Penumbra.UI.Classes;
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 });
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));
}
catch (Exception e)

View file

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

View file

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

View file

@ -25,7 +25,8 @@ public class StainService : IDisposable
{
using var t = timer.Measure(StartTimeType.Stains);
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);
TemplateCombo = new StainTemplateCombo(StmFile.Entries.Keys.Prepend((ushort)0));
Penumbra.Log.Verbose($"[{nameof(StainService)}] Created.");

View file

@ -1,4 +1,3 @@
using System.Reflection;
using Dalamud.Interface.Internal.Notifications;
using Dalamud.Plugin;
@ -34,7 +33,8 @@ public class ValidityChecker
public void LogExceptions()
{
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.

View file

@ -12,7 +12,8 @@ namespace Penumbra.Services;
public sealed class IdentifierService : AsyncServiceWrapper<IObjectIdentifier>
{
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.Raii;
using Penumbra.Mods;
using Penumbra.Mods.Subclasses;
using Penumbra.String.Classes;
using Penumbra.UI.Classes;

View file

@ -114,10 +114,8 @@ public partial class ModEditWindow
{
var ret = false;
if (tab.Mtrl.HasDyeTable)
{
for (var i = 0; i < MtrlFile.ColorTable.NumRows; ++i)
ret |= tab.Mtrl.ApplyDyeTemplate(_stainService.StmFile, i, dyeId);
}
tab.UpdateColorTablePreview();
@ -301,7 +299,8 @@ public partial class ModEditWindow
ImGui.SameLine();
var tmpFloat = row.SpecularStrength;
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;
ret = true;

View file

@ -8,7 +8,6 @@ using Penumbra.Interop.Structs;
using Penumbra.Meta;
using Penumbra.Meta.Files;
using Penumbra.Meta.Manipulations;
using Penumbra.Mods;
using Penumbra.Mods.Editor;
using Penumbra.UI.Classes;
@ -66,17 +65,23 @@ public partial class ModEditWindow
if (!child)
return;
DrawEditHeader(_editor.MetaEditor.Eqp, "Equipment Parameter Edits (EQP)###EQP", 5, EqpRow.Draw, EqpRow.DrawNew , _editor.MetaEditor.OtherEqpCount);
DrawEditHeader(_editor.MetaEditor.Eqdp, "Racial Model Edits (EQDP)###EQDP", 7, EqdpRow.Draw, EqdpRow.DrawNew, _editor.MetaEditor.OtherEqdpCount);
DrawEditHeader(_editor.MetaEditor.Eqp, "Equipment Parameter Edits (EQP)###EQP", 5, EqpRow.Draw, EqpRow.DrawNew,
_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.Est, "Extra Skeleton Parameters (EST)###EST", 7, EstRow.Draw, EstRow.DrawNew , _editor.MetaEditor.OtherEstCount);
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);
DrawEditHeader(_editor.MetaEditor.Est, "Extra Skeleton Parameters (EST)###EST", 7, EstRow.Draw, EstRow.DrawNew,
_editor.MetaEditor.OtherEstCount);
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>
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)
{
const ImGuiTableFlags flags = ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.BordersInnerV;
@ -92,6 +97,7 @@ public partial class ModEditWindow
ImGuiUtil.TextColored(ColorId.RedundantAssignment.Value() | 0xFF000000, text);
ImGui.SetCursorPos(newPos);
}
if (!header)
return;
@ -223,7 +229,8 @@ public partial class ModEditWindow
ImGui.TableNextColumn();
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);
}
@ -232,7 +239,8 @@ public partial class ModEditWindow
ImGui.TableNextColumn();
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);
}
@ -241,7 +249,8 @@ public partial class ModEditWindow
ImGui.TableNextColumn();
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);
}
@ -250,7 +259,8 @@ public partial class ModEditWindow
ImGui.TableNextColumn();
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);
}
@ -288,7 +298,8 @@ public partial class ModEditWindow
ImGuiUtil.HoverTooltip(EquipSlotTooltip);
// 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 (bit1, bit2) = meta.Entry.ToBits(meta.Slot);
ImGui.TableNextColumn();
@ -370,7 +381,8 @@ public partial class ModEditWindow
if (_new.ObjectType is ObjectType.Equipment)
{
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)
?? new ImcEntry());
@ -379,7 +391,8 @@ public partial class ModEditWindow
else if (_new.ObjectType is ObjectType.Accessory)
{
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)
?? new ImcEntry());
@ -388,7 +401,8 @@ public partial class ModEditWindow
else
{
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)
?? new ImcEntry());
@ -405,7 +419,8 @@ public partial class ModEditWindow
if (_new.ObjectType is ObjectType.DemiHuman)
{
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)
?? new ImcEntry());
@ -787,7 +802,8 @@ public partial class ModEditWindow
using var color = ImRaii.PushColor(ImGuiCol.FrameBg,
def < value ? ColorId.IncreasedMetaValue.Value() : ColorId.DecreasedMetaValue.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));
ImGuiUtil.HoverTooltip($"Default Value: {def:0.###}");

View file

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

View file

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

View file

@ -489,16 +489,22 @@ public partial class ModEditWindow
continue;
foreach (var (key, keyIdx) in node.SystemKeys.WithIndex())
{
ImRaii.TreeNode($"System Key 0x{tab.Shpk.SystemKeys[keyIdx].Id:X8} = 0x{key:X8}",
ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose();
}
foreach (var (key, keyIdx) in node.SceneKeys.WithIndex())
{
ImRaii.TreeNode($"Scene Key 0x{tab.Shpk.SceneKeys[keyIdx].Id:X8} = 0x{key:X8}",
ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose();
}
foreach (var (key, keyIdx) in node.MaterialKeys.WithIndex())
{
ImRaii.TreeNode($"Material Key 0x{tab.Shpk.MaterialKeys[keyIdx].Id:X8} = 0x{key:X8}",
ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet).Dispose();
}
foreach (var (key, keyIdx) in node.SubViewKeys.WithIndex())
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);
foreach (var selector in tab.Shpk.NodeSelectors)
{
ImRaii.TreeNode($"#{selector.Value:D4}: Selector: 0x{selector.Key:X8}", ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.Bullet)
.Dispose();
}
}
}
private static void DrawOtherShaderPackageDetails(ShpkTab tab)
{

View file

@ -193,7 +193,8 @@ public partial class ModEditWindow
private void OpenSaveAsDialog(string defaultExtension)
{
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)
{

View file

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

View file

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

View file

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

View file

@ -47,13 +47,17 @@ public class PenumbraChangelog
private static void Add7_3_0(Changelog log)
=> 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("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 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("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("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.")
@ -66,21 +70,31 @@ public class PenumbraChangelog
private static void Add7_2_0(Changelog log)
=> 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("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(
"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("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(
"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("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 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 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("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("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 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.")
@ -94,21 +108,29 @@ public class PenumbraChangelog
private static void Add7_1_2(Changelog log)
=> 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("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(
"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("Some miscellaneous small bug fixes.")
.RegisterEntry("Slight changes in behaviour for deduplicator/normalizer, mostly backend.")
.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("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)
=> 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.")
.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)
.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.")
.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)
.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("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.")
@ -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 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 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)
=> 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 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.");
private static void Add7_0_0(Changelog log)
=> 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.")
.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)
.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.")
.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("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("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("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("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(
"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("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("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 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 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("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.")

View file

@ -21,13 +21,16 @@ public static class Combos
=> ImGuiUtil.GenericEnumCombo(label, unscaledWidth * UiHelpers.Scale, current, out gender, RaceEnumExtensions.ToName, 1);
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)
=> 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)
=> 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)
=> ImGuiUtil.GenericEnumCombo(label, 150 * UiHelpers.Scale, current, out subRace, RaceEnumExtensions.ToName, 1);

View file

@ -31,7 +31,8 @@ public class InheritanceUi
public void Draw()
{
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);
DrawCurrentCollectionInheritance();
@ -122,7 +123,8 @@ public class InheritanceUi
_seenInheritedCollections.Contains(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());
DrawInheritanceTreeClicks(inheritance, false);

View file

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

View file

@ -14,6 +14,7 @@ using Penumbra.Collections.Manager;
using Penumbra.Communication;
using Penumbra.Mods;
using Penumbra.Mods.Manager;
using Penumbra.Mods.Subclasses;
using Penumbra.Services;
using Penumbra.UI.Classes;
using ChatService = Penumbra.Services.ChatService;
@ -376,8 +377,10 @@ public sealed class ModFileSystemSelector : FileSystemSelector<Mod, ModFileSyste
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.");
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("Selected mods inside an also selected folder will be ignored when dragging and move inside their folder instead of directly into the target.");
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(
"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);
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.");

View file

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

View file

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

View file

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

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