Skip to content

Commit 8759b4c

Browse files
committed
Merge remote-tracking branch 'upstream/main'
2 parents 8b36b57 + 9f6653a commit 8759b4c

File tree

63 files changed

+2039
-793
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+2039
-793
lines changed

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ jobs:
3737
- name: Archive
3838
run: Compress-Archive -Path CustomizePlus/bin/Release/* -DestinationPath CustomizePlus.zip
3939
- name: Upload a Build Artifact
40-
uses: actions/upload-artifact@v2.2.1
40+
uses: actions/upload-artifact@v4
4141
with:
4242
path: |
4343
./CustomizePlus/bin/Release/*

.github/workflows/test_release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ jobs:
3737
- name: Archive
3838
run: Compress-Archive -Path CustomizePlus/bin/Release/* -DestinationPath CustomizePlus.zip
3939
- name: Upload a Build Artifact
40-
uses: actions/upload-artifact@v2.2.1
40+
uses: actions/upload-artifact@v4
4141
with:
4242
path: |
4343
./CustomizePlus/bin/Release/*

CustomizePlus.GameData/CustomizePlus.GameData.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<TargetFramework>net8.0-windows</TargetFramework>
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
using CustomizePlus.GameData.ReverseSearchDictionaries;
2+
using Dalamud.Game.ClientState.Objects.Enums;
3+
using OtterGui.Services;
4+
using Penumbra.GameData.DataContainers;
5+
using Penumbra.GameData.Structs;
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Diagnostics.CodeAnalysis;
9+
using System.Linq;
10+
using System.Runtime.CompilerServices;
11+
using System.Text;
12+
using System.Threading.Tasks;
13+
14+
namespace CustomizePlus.GameData.Data;
15+
16+
/// <summary> A collection service for all the name dictionaries required for reverse name search. </summary>
17+
/// note: this is mvp for profile upgrading purposes, not intended to be used for anything else.
18+
public sealed class ReverseNameDicts(
19+
ReverseSearchDictMount _mounts,
20+
ReverseSearchDictCompanion _companions,
21+
ReverseSearchDictBNpc _bNpcs,
22+
ReverseSearchDictENpc _eNpcs)
23+
: IAsyncService
24+
{
25+
/// <summary> Valid Mount ids by name in title case. </summary>
26+
public readonly ReverseSearchDictMount Mounts = _mounts;
27+
28+
/// <summary> Valid Companion ids by name in title case. </summary>
29+
public readonly ReverseSearchDictCompanion Companions = _companions;
30+
31+
/// <summary> Valid BNPC ids by name in title case. </summary>
32+
public readonly ReverseSearchDictBNpc BNpcs = _bNpcs;
33+
34+
/// <summary> Valid ENPC ids by name in title case. </summary>
35+
public readonly ReverseSearchDictENpc ENpcs = _eNpcs;
36+
37+
/// <summary> Finished when all name dictionaries are finished. </summary>
38+
public Task Awaiter { get; } =
39+
Task.WhenAll(_mounts.Awaiter, _companions.Awaiter, _bNpcs.Awaiter, _eNpcs.Awaiter);
40+
41+
/// <inheritdoc/>
42+
public bool Finished
43+
=> Awaiter.IsCompletedSuccessfully;
44+
45+
/// <summary> Convert a given name for a certain ObjectKind to an ID. </summary>
46+
/// <returns> default or a valid id. </returns>
47+
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
48+
public uint ToID(ObjectKind kind, string name)
49+
=> TryGetID(kind, name, out var ret) ? ret : default;
50+
51+
/// <summary> Convert a given ID for a certain ObjectKind to a name. </summary>
52+
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
53+
public bool TryGetID(ObjectKind kind, string name, [NotNullWhen(true)] out uint npcId)
54+
{
55+
npcId = default;
56+
return kind switch
57+
{
58+
ObjectKind.MountType => Mounts.TryGetValue(name, out npcId),
59+
ObjectKind.Companion => Companions.TryGetValue(name, out npcId),
60+
ObjectKind.BattleNpc => BNpcs.TryGetValue(name, out npcId),
61+
ObjectKind.EventNpc => ENpcs.TryGetValue(name, out npcId),
62+
_ => false,
63+
};
64+
}
65+
}

CustomizePlus.GameData/Extensions/ActorIdentifierExtensions.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,40 @@ public static string ToNameWithoutOwnerName(this ActorIdentifier identifier)
2828
return PenumbraExtensions.Manager.Data.ToName(identifier.Kind, identifier.DataId);
2929
}
3030

31+
/// <summary>
32+
/// Matches() method but ignoring ownership for owned objects or if one of identifiers is NPC while the other one is Owned.
33+
/// </summary>
34+
public static bool MatchesIgnoringOwnership(this ActorIdentifier identifier, ActorIdentifier other)
35+
{
36+
//carbuncles and other battle minions
37+
if ((identifier.Type == IdentifierType.Npc && other.Type == IdentifierType.Owned) ||
38+
(identifier.Type == IdentifierType.Owned && other.Type == IdentifierType.Npc))
39+
return PenumbraExtensions.Manager.DataIdEquals(identifier, other);
40+
41+
if (identifier.Type != other.Type)
42+
return false;
43+
44+
return identifier.Type switch
45+
{
46+
IdentifierType.Owned => PenumbraExtensions.Manager.DataIdEquals(identifier, other),
47+
_ => identifier.Matches(other)
48+
};
49+
}
50+
51+
/// <summary>
52+
/// Check if owned actor is owned by local player. Will return false if Type is not Owned.
53+
/// </summary>
54+
public static bool IsOwnedByLocalPlayer(this ActorIdentifier identifier)
55+
{
56+
if (identifier.Type != IdentifierType.Owned)
57+
return false;
58+
59+
if (PenumbraExtensions.Manager == null)
60+
return false;
61+
62+
return identifier.PlayerName == PenumbraExtensions.Manager.GetCurrentPlayer().PlayerName;
63+
}
64+
3165
/// <summary>
3266
/// Wrapper around Incognito which returns non-incognito name in debug builds
3367
/// </summary>
@@ -56,6 +90,23 @@ public static string IncognitoDebug(this ActorIdentifier identifier)
5690
}
5791
}
5892

93+
public static string TypeToString(this ActorIdentifier identifier)
94+
{
95+
return identifier.Type switch
96+
{
97+
IdentifierType.Player => $" ({PenumbraExtensions.Manager?.Data.ToWorldName(identifier.HomeWorld) ?? "Unknown"})",
98+
IdentifierType.Retainer => $"{identifier.Retainer switch
99+
{
100+
ActorIdentifier.RetainerType.Bell => " (Bell)",
101+
ActorIdentifier.RetainerType.Mannequin => " (Mannequin)",
102+
_ => " (Retainer)",
103+
}}",
104+
IdentifierType.Owned => " (Companion/Mount)",
105+
IdentifierType.Npc => " (NPC)",
106+
_ => "",
107+
};
108+
}
109+
59110
/// <summary>
60111
/// For now used to determine if root scaling should be allowed or not
61112
/// </summary>
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
using Dalamud.Plugin.Services;
2+
using Dalamud.Plugin;
3+
using FFXIVClientStructs.FFXIV.Common.Lua;
4+
using OtterGui.Log;
5+
using Penumbra.GameData.Data;
6+
using Penumbra.GameData.DataContainers.Bases;
7+
using Penumbra.GameData.Structs;
8+
using System;
9+
using System.Collections;
10+
using System.Collections.Generic;
11+
using System.Diagnostics.CodeAnalysis;
12+
using System.Linq;
13+
using System.Text;
14+
using System.Threading.Tasks;
15+
16+
namespace CustomizePlus.GameData.ReverseSearchDictionaries.Bases;
17+
18+
/// <summary> A base class for dictionaries from NPC names to their IDs. </summary>
19+
/// <param name="pluginInterface"> The plugin interface. </param>
20+
/// <param name="log"> A logger. </param>
21+
/// <param name="gameData"> The data manger to fetch the data from. </param>
22+
/// <param name="name"> The name of the data share. </param>
23+
/// <param name="version"> The version of the data share. </param>
24+
/// <param name="factory"> The factory function to create the data from. </param>
25+
public abstract class ReverseNameDictionary(
26+
IDalamudPluginInterface pluginInterface,
27+
Logger log,
28+
IDataManager gameData,
29+
string name,
30+
int version,
31+
Func<IReadOnlyDictionary<string, uint>> factory)
32+
: DataSharer<IReadOnlyDictionary<string, uint>>(pluginInterface, log, name, gameData.Language, version, factory),
33+
IReadOnlyDictionary<string, NpcId>
34+
{
35+
/// <inheritdoc/>
36+
public IEnumerator<KeyValuePair<string, NpcId>> GetEnumerator()
37+
=> Value.Select(kvp => new KeyValuePair<string, NpcId>(kvp.Key, new NpcId(kvp.Value))).GetEnumerator();
38+
39+
/// <inheritdoc/>
40+
IEnumerator IEnumerable.GetEnumerator()
41+
=> GetEnumerator();
42+
43+
/// <inheritdoc/>
44+
public int Count
45+
=> Value.Count;
46+
47+
/// <inheritdoc/>
48+
public bool ContainsKey(string key)
49+
=> Value.ContainsKey(key);
50+
51+
/// <inheritdoc/>
52+
public bool TryGetValue(string key, [NotNullWhen(true)] out NpcId value)
53+
{
54+
if (!Value.TryGetValue(key, out var uintVal))
55+
{
56+
value = default;
57+
return false;
58+
}
59+
60+
value = new NpcId(uintVal);
61+
return true;
62+
}
63+
64+
/// <inheritdoc/>
65+
public NpcId this[string key]
66+
=> new NpcId(Value[key]);
67+
68+
/// <inheritdoc/>
69+
public IEnumerable<string> Keys
70+
=> Value.Keys;
71+
72+
/// <inheritdoc/>
73+
public IEnumerable<NpcId> Values
74+
=> Value.Values.Select(k => new NpcId(k));
75+
76+
/// <inheritdoc/>
77+
protected override long ComputeMemory()
78+
=> DataUtility.DictionaryMemory(16, Count) + Keys.Sum(v => v.Length * 2); //this seems to be only used by diagnostics stuff so I don't particularly care for this to be correct.
79+
80+
/// <inheritdoc/>
81+
protected override int ComputeTotalCount()
82+
=> Count;
83+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using Dalamud.Plugin.Services;
2+
using Dalamud.Plugin;
3+
using OtterGui.Log;
4+
using Penumbra.GameData.Data;
5+
using System.Collections.Frozen;
6+
using System.Diagnostics.CodeAnalysis;
7+
using Lumina.Excel.GeneratedSheets;
8+
using CustomizePlus.GameData.ReverseSearchDictionaries.Bases;
9+
10+
namespace CustomizePlus.GameData.ReverseSearchDictionaries;
11+
12+
/// <summary> A dictionary that matches names to battle npc ids. </summary>
13+
public sealed class ReverseSearchDictBNpc(IDalamudPluginInterface pluginInterface, Logger log, IDataManager gameData)
14+
: ReverseNameDictionary(pluginInterface, log, gameData, "ReverseSearchBNpcs", 7, () => CreateBNpcData(gameData))
15+
{
16+
/// <summary> Create the data. </summary>
17+
private static IReadOnlyDictionary<string, uint> CreateBNpcData(IDataManager gameData)
18+
{
19+
var sheet = gameData.GetExcelSheet<BNpcName>(gameData.Language)!;
20+
var dict = new Dictionary<string, uint>((int)sheet.RowCount);
21+
foreach (var n in sheet.Where(n => n.Singular.RawData.Length > 0))
22+
dict.TryAdd(DataUtility.ToTitleCaseExtended(n.Singular, n.Article), n.RowId);
23+
return dict.ToFrozenDictionary();
24+
}
25+
26+
/// <inheritdoc cref="ReverseNameDictionary.TryGetValue"/>
27+
public bool TryGetValue(string key, [NotNullWhen(true)] out uint value)
28+
=> Value.TryGetValue(key, out value);
29+
30+
/// <inheritdoc cref="ReverseNameDictionary.this"/>
31+
public uint this[string key]
32+
=> Value[key];
33+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using Dalamud.Plugin.Services;
2+
using Dalamud.Plugin;
3+
using OtterGui.Log;
4+
using Penumbra.GameData.Data;
5+
using System.Collections.Frozen;
6+
using System.Diagnostics.CodeAnalysis;
7+
using Lumina.Excel.GeneratedSheets;
8+
using CustomizePlus.GameData.ReverseSearchDictionaries.Bases;
9+
10+
namespace CustomizePlus.GameData.ReverseSearchDictionaries;
11+
12+
/// <summary> A dictionary that matches companion names to their ids. </summary>
13+
public sealed class ReverseSearchDictCompanion(IDalamudPluginInterface pluginInterface, Logger log, IDataManager gameData)
14+
: ReverseNameDictionary(pluginInterface, log, gameData, "ReverseSearchCompanions", 7, () => CreateCompanionData(gameData))
15+
{
16+
/// <summary> Create the data. </summary>
17+
private static IReadOnlyDictionary<string, uint> CreateCompanionData(IDataManager gameData)
18+
{
19+
var sheet = gameData.GetExcelSheet<Companion>(gameData.Language)!;
20+
var dict = new Dictionary<string, uint>((int)sheet.RowCount);
21+
foreach (var c in sheet.Where(c => c.Singular.RawData.Length > 0 && c.Order < ushort.MaxValue))
22+
dict.TryAdd(DataUtility.ToTitleCaseExtended(c.Singular, c.Article), c.RowId);
23+
return dict.ToFrozenDictionary();
24+
}
25+
26+
/// <inheritdoc cref="ReverseNameDictionary.TryGetValue"/>
27+
public bool TryGetValue(string key, [NotNullWhen(true)] out uint value)
28+
=> Value.TryGetValue(key, out value);
29+
30+
/// <inheritdoc cref="ReverseNameDictionary.this"/>
31+
public uint this[string key]
32+
=> Value[key];
33+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using Dalamud.Plugin.Services;
2+
using Dalamud.Plugin;
3+
using OtterGui.Log;
4+
using Penumbra.GameData.Data;
5+
using System.Collections.Frozen;
6+
using System.Diagnostics.CodeAnalysis;
7+
using Lumina.Excel.GeneratedSheets;
8+
using CustomizePlus.GameData.ReverseSearchDictionaries.Bases;
9+
10+
namespace CustomizePlus.GameData.ReverseSearchDictionaries;
11+
12+
/// <summary> A dictionary that matches names to event npc ids. </summary>
13+
public sealed class ReverseSearchDictENpc(IDalamudPluginInterface pluginInterface, Logger log, IDataManager gameData)
14+
: ReverseNameDictionary(pluginInterface, log, gameData, "ReverseSearchENpcs", 7, () => CreateENpcData(gameData))
15+
{
16+
/// <summary> Create the data. </summary>
17+
private static IReadOnlyDictionary<string, uint> CreateENpcData(IDataManager gameData)
18+
{
19+
var sheet = gameData.GetExcelSheet<ENpcResident>(gameData.Language)!;
20+
var dict = new Dictionary<string, uint>((int)sheet.RowCount);
21+
foreach (var n in sheet.Where(e => e.Singular.RawData.Length > 0))
22+
dict.TryAdd(DataUtility.ToTitleCaseExtended(n.Singular, n.Article), n.RowId);
23+
return dict.ToFrozenDictionary();
24+
}
25+
26+
/// <inheritdoc cref="ReverseNameDictionary.TryGetValue"/>
27+
public bool TryGetValue(string key, [NotNullWhen(true)] out uint value)
28+
=> Value.TryGetValue(key, out value);
29+
30+
/// <inheritdoc cref="ReverseNameDictionary.this"/>
31+
public uint this[string key]
32+
=> Value[key];
33+
}

0 commit comments

Comments
 (0)