mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Extend the item identification a bit to count unidentifiable items and handle icons, demihumans and monsters.
This commit is contained in:
parent
1ad7787e4c
commit
06deddcd8a
7 changed files with 714 additions and 672 deletions
|
|
@ -7,8 +7,8 @@ using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
using Penumbra.GameData.Util;
|
using Penumbra.GameData.Util;
|
||||||
|
|
||||||
namespace Penumbra.GameData
|
namespace Penumbra.GameData;
|
||||||
{
|
|
||||||
internal class GamePathParser : IGamePathParser
|
internal class GamePathParser : IGamePathParser
|
||||||
{
|
{
|
||||||
private const string CharacterFolder = "chara";
|
private const string CharacterFolder = "chara";
|
||||||
|
|
@ -34,7 +34,7 @@ namespace Penumbra.GameData
|
||||||
private readonly Dictionary<FileType, Dictionary<ObjectType, Regex[]>> _regexes = new()
|
private readonly Dictionary<FileType, Dictionary<ObjectType, Regex[]>> _regexes = new()
|
||||||
{ { FileType.Font, new Dictionary< ObjectType, Regex[] >(){ { ObjectType.Font, new Regex[]{ new(@"common/font/(?'fontname'.*)_(?'id'\d\d)(_lobby)?\.fdt") } } } }
|
{ { FileType.Font, new Dictionary< ObjectType, Regex[] >(){ { ObjectType.Font, new Regex[]{ new(@"common/font/(?'fontname'.*)_(?'id'\d\d)(_lobby)?\.fdt") } } } }
|
||||||
, { FileType.Texture, new Dictionary< ObjectType, Regex[] >()
|
, { FileType.Texture, new Dictionary< ObjectType, Regex[] >()
|
||||||
{ { ObjectType.Icon, new Regex[]{ new(@"ui/icon/(?'group'\d*)(/(?'lang'[a-z]{2}))?(/(?'hq'hq))?/(?'id'\d*)\.tex") } }
|
{ { ObjectType.Icon, new Regex[]{ new(@"ui/icon/(?'group'\d*)(/(?'lang'[a-z]{2}))?(/(?'hq'hq))?/(?'id'\d*)(?'hr'_hr1)?\.tex") } }
|
||||||
, { ObjectType.Map, new Regex[]{ new(@"ui/map/(?'id'[a-z0-9]{4})/(?'variant'\d{2})/\k'id'\k'variant'(?'suffix'[a-z])?(_[a-z])?\.tex") } }
|
, { ObjectType.Map, new Regex[]{ new(@"ui/map/(?'id'[a-z0-9]{4})/(?'variant'\d{2})/\k'id'\k'variant'(?'suffix'[a-z])?(_[a-z])?\.tex") } }
|
||||||
, { ObjectType.Weapon, new Regex[]{ new(@"chara/weapon/w(?'id'\d{4})/obj/body/b(?'weapon'\d{4})/texture/v(?'variant'\d{2})_w\k'id'b\k'weapon'(_[a-z])?_[a-z]\.tex") } }
|
, { ObjectType.Weapon, new Regex[]{ new(@"chara/weapon/w(?'id'\d{4})/obj/body/b(?'weapon'\d{4})/texture/v(?'variant'\d{2})_w\k'id'b\k'weapon'(_[a-z])?_[a-z]\.tex") } }
|
||||||
, { ObjectType.Monster, new Regex[]{ new(@"chara/monster/m(?'monster'\d{4})/obj/body/b(?'id'\d{4})/texture/v(?'variant'\d{2})_m\k'monster'b\k'id'(_[a-z])?_[a-z]\.tex") } }
|
, { ObjectType.Monster, new Regex[]{ new(@"chara/monster/m(?'monster'\d{4})/obj/body/b(?'id'\d{4})/texture/v(?'variant'\d{2})_m\k'monster'b\k'id'(_[a-z])?_[a-z]\.tex") } }
|
||||||
|
|
@ -58,7 +58,7 @@ namespace Penumbra.GameData
|
||||||
, { ObjectType.Equipment, new Regex[]{ new(@"chara/equipment/e(?'id'\d{4})/material/v(?'variant'\d{4})/mt_c(?'race'\d{4})e\k'id'_(?'slot'[a-z]{3})_[a-z]\.mtrl") } }
|
, { ObjectType.Equipment, new Regex[]{ new(@"chara/equipment/e(?'id'\d{4})/material/v(?'variant'\d{4})/mt_c(?'race'\d{4})e\k'id'_(?'slot'[a-z]{3})_[a-z]\.mtrl") } }
|
||||||
, { ObjectType.DemiHuman, new Regex[]{ new(@"chara/demihuman/d(?'id'\d{4})/obj/equipment/e(?'equip'\d{4})/material/v(?'variant'\d{4})/mt_d\k'id'e\k'equip'_(?'slot'[a-z]{3})_[a-z]\.mtrl") } }
|
, { ObjectType.DemiHuman, new Regex[]{ new(@"chara/demihuman/d(?'id'\d{4})/obj/equipment/e(?'equip'\d{4})/material/v(?'variant'\d{4})/mt_d\k'id'e\k'equip'_(?'slot'[a-z]{3})_[a-z]\.mtrl") } }
|
||||||
, { ObjectType.Accessory, new Regex[]{ new(@"chara/accessory/a(?'id'\d{4})/material/v(?'variant'\d{4})/mt_c(?'race'\d{4})a\k'id'_(?'slot'[a-z]{3})_[a-z]\.mtrl") } }
|
, { ObjectType.Accessory, new Regex[]{ new(@"chara/accessory/a(?'id'\d{4})/material/v(?'variant'\d{4})/mt_c(?'race'\d{4})a\k'id'_(?'slot'[a-z]{3})_[a-z]\.mtrl") } }
|
||||||
, { ObjectType.Character, new Regex[]{ new(@"chara/human/c(?'race'\d{4})/obj/(?'type'[a-z]+)/(?'typeabr'[a-z])(?'id'\d{4})/material/v(?'variant'\d{4})/mt_c\k'race'\k'typeabr'\k'id'(_(?'slot'[a-z]{3}))?_[a-z]\.mtrl") } } } }
|
, { ObjectType.Character, new Regex[]{ new( @"chara/human/c(?'race'\d{4})/obj/(?'type'[a-z]+)/(?'typeabr'[a-z])(?'id'\d{4})/material(/v(?'variant'\d{4}))?/mt_c\k'race'\k'typeabr'\k'id'(_(?'slot'[a-z]{3}))?_[a-z]\.mtrl" ) } } } }
|
||||||
, { FileType.Imc, new Dictionary< ObjectType, Regex[] >()
|
, { FileType.Imc, new Dictionary< ObjectType, Regex[] >()
|
||||||
{ { ObjectType.Weapon, new Regex[]{ new(@"chara/weapon/w(?'id'\d{4})/obj/body/b(?'weapon'\d{4})/b\k'weapon'\.imc") } }
|
{ { ObjectType.Weapon, new Regex[]{ new(@"chara/weapon/w(?'id'\d{4})/obj/body/b(?'weapon'\d{4})/b\k'weapon'\.imc") } }
|
||||||
, { ObjectType.Monster, new Regex[]{ new(@"chara/monster/m(?'monster'\d{4})/obj/body/b(?'id'\d{4})/b\k'id'\.imc") } }
|
, { ObjectType.Monster, new Regex[]{ new(@"chara/monster/m(?'monster'\d{4})/obj/body/b(?'id'\d{4})/b\k'id'\.imc") } }
|
||||||
|
|
@ -243,7 +243,7 @@ namespace Penumbra.GameData
|
||||||
: CustomizationType.Skin;
|
: CustomizationType.Skin;
|
||||||
if( fileType == FileType.Material )
|
if( fileType == FileType.Material )
|
||||||
{
|
{
|
||||||
var variant = byte.Parse( groups[ "variant" ].Value );
|
var variant = groups[ "variant" ].Success ? byte.Parse( groups[ "variant" ].Value ) : ( byte )0;
|
||||||
return GameObjectInfo.Customization( fileType, type, id, gr, bodySlot, variant );
|
return GameObjectInfo.Customization( fileType, type, id, gr, bodySlot, variant );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -253,10 +253,11 @@ namespace Penumbra.GameData
|
||||||
private static GameObjectInfo HandleIcon( FileType fileType, GroupCollection groups )
|
private static GameObjectInfo HandleIcon( FileType fileType, GroupCollection groups )
|
||||||
{
|
{
|
||||||
var hq = groups[ "hq" ].Success;
|
var hq = groups[ "hq" ].Success;
|
||||||
|
var hr = groups[ "hr" ].Success;
|
||||||
var id = uint.Parse( groups[ "id" ].Value );
|
var id = uint.Parse( groups[ "id" ].Value );
|
||||||
if( !groups[ "lang" ].Success )
|
if( !groups[ "lang" ].Success )
|
||||||
{
|
{
|
||||||
return GameObjectInfo.Icon( fileType, id, hq );
|
return GameObjectInfo.Icon( fileType, id, hq, hr );
|
||||||
}
|
}
|
||||||
|
|
||||||
var language = groups[ "lang" ].Value switch
|
var language = groups[ "lang" ].Value switch
|
||||||
|
|
@ -267,7 +268,7 @@ namespace Penumbra.GameData
|
||||||
"fr" => Dalamud.ClientLanguage.French,
|
"fr" => Dalamud.ClientLanguage.French,
|
||||||
_ => Dalamud.ClientLanguage.English,
|
_ => Dalamud.ClientLanguage.English,
|
||||||
};
|
};
|
||||||
return GameObjectInfo.Icon( fileType, id, hq, language );
|
return GameObjectInfo.Icon( fileType, id, hq, hr, language );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static GameObjectInfo HandleMap( FileType fileType, GroupCollection groups )
|
private static GameObjectInfo HandleMap( FileType fileType, GroupCollection groups )
|
||||||
|
|
@ -329,4 +330,3 @@ namespace Penumbra.GameData
|
||||||
return match.Success ? match.Groups[ "key" ].Value.ToLowerInvariant() : string.Empty;
|
return match.Success ? match.Groups[ "key" ].Value.ToLowerInvariant() : string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Linq;
|
|
||||||
using Dalamud;
|
using Dalamud;
|
||||||
using Dalamud.Data;
|
using Dalamud.Data;
|
||||||
using Lumina.Excel.GeneratedSheets;
|
using Lumina.Excel.GeneratedSheets;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
using Penumbra.GameData.Util;
|
using Penumbra.GameData.Util;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
using Action = Lumina.Excel.GeneratedSheets.Action;
|
using Action = Lumina.Excel.GeneratedSheets.Action;
|
||||||
|
|
||||||
namespace Penumbra.GameData
|
namespace Penumbra.GameData;
|
||||||
{
|
|
||||||
internal class ObjectIdentification : IObjectIdentifier
|
internal class ObjectIdentification : IObjectIdentifier
|
||||||
{
|
{
|
||||||
public static DataManager? DataManager = null!;
|
public static DataManager? DataManager = null!;
|
||||||
|
|
@ -221,23 +221,55 @@ namespace Penumbra.GameData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void AddCounterString( IDictionary< string, object? > set, string data )
|
||||||
|
{
|
||||||
|
if( set.TryGetValue( data, out var obj ) && obj is int counter )
|
||||||
|
{
|
||||||
|
set[ data ] = counter + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
set[ data ] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void IdentifyParsed( IDictionary< string, object? > set, GameObjectInfo info )
|
private void IdentifyParsed( IDictionary< string, object? > set, GameObjectInfo info )
|
||||||
{
|
{
|
||||||
switch( info.ObjectType )
|
switch( info.ObjectType )
|
||||||
{
|
{
|
||||||
case ObjectType.Unknown:
|
case ObjectType.Unknown:
|
||||||
|
switch( info.FileType )
|
||||||
|
{
|
||||||
|
case FileType.Sound:
|
||||||
|
AddCounterString( set, FileType.Sound.ToString() );
|
||||||
|
break;
|
||||||
|
case FileType.Animation:
|
||||||
|
case FileType.Pap:
|
||||||
|
AddCounterString( set, FileType.Animation.ToString() );
|
||||||
|
break;
|
||||||
|
case FileType.Shader:
|
||||||
|
AddCounterString( set, FileType.Shader.ToString() );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
case ObjectType.LoadingScreen:
|
case ObjectType.LoadingScreen:
|
||||||
case ObjectType.Map:
|
case ObjectType.Map:
|
||||||
case ObjectType.Interface:
|
case ObjectType.Interface:
|
||||||
case ObjectType.Vfx:
|
case ObjectType.Vfx:
|
||||||
case ObjectType.World:
|
case ObjectType.World:
|
||||||
case ObjectType.Housing:
|
case ObjectType.Housing:
|
||||||
case ObjectType.DemiHuman:
|
|
||||||
case ObjectType.Monster:
|
|
||||||
case ObjectType.Icon:
|
|
||||||
case ObjectType.Font:
|
case ObjectType.Font:
|
||||||
// Don't do anything for these cases.
|
AddCounterString( set, info.ObjectType.ToString() );
|
||||||
|
break;
|
||||||
|
case ObjectType.DemiHuman:
|
||||||
|
set[ $"Demi Human: {info.PrimaryId}" ] = null;
|
||||||
|
break;
|
||||||
|
case ObjectType.Monster:
|
||||||
|
set[ $"Monster: {info.PrimaryId}" ] = null;
|
||||||
|
break;
|
||||||
|
case ObjectType.Icon:
|
||||||
|
set[ $"Icon: {info.IconId}" ] = null;
|
||||||
break;
|
break;
|
||||||
case ObjectType.Accessory:
|
case ObjectType.Accessory:
|
||||||
case ObjectType.Equipment:
|
case ObjectType.Equipment:
|
||||||
|
|
@ -322,4 +354,3 @@ namespace Penumbra.GameData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
@ -3,8 +3,8 @@ using System.Runtime.InteropServices;
|
||||||
using Dalamud;
|
using Dalamud;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
|
|
||||||
namespace Penumbra.GameData.Structs
|
namespace Penumbra.GameData.Structs;
|
||||||
{
|
|
||||||
[StructLayout( LayoutKind.Explicit )]
|
[StructLayout( LayoutKind.Explicit )]
|
||||||
public struct GameObjectInfo : IComparable
|
public struct GameObjectInfo : IComparable
|
||||||
{
|
{
|
||||||
|
|
@ -79,13 +79,13 @@ namespace Penumbra.GameData.Structs
|
||||||
Variant = variant,
|
Variant = variant,
|
||||||
};
|
};
|
||||||
|
|
||||||
public static GameObjectInfo Icon( FileType type, uint iconId, bool hq, ClientLanguage lang = ClientLanguage.English )
|
public static GameObjectInfo Icon( FileType type, uint iconId, bool hq, bool hr, ClientLanguage lang = ClientLanguage.English )
|
||||||
=> new()
|
=> new()
|
||||||
{
|
{
|
||||||
FileType = type,
|
FileType = type,
|
||||||
ObjectType = ObjectType.Map,
|
ObjectType = ObjectType.Icon,
|
||||||
IconId = iconId,
|
IconId = iconId,
|
||||||
IconHq = hq,
|
IconHqHr = ( byte )( hq ? hr ? 3 : 1 : hr ? 2 : 0 ),
|
||||||
Language = lang,
|
Language = lang,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -137,7 +137,7 @@ namespace Penumbra.GameData.Structs
|
||||||
public byte Variant; // Equipment, Weapon, Customization, Map, Monster, Demihuman
|
public byte Variant; // Equipment, Weapon, Customization, Map, Monster, Demihuman
|
||||||
|
|
||||||
[FieldOffset( 6 )]
|
[FieldOffset( 6 )]
|
||||||
public bool IconHq; // Icon
|
public byte IconHqHr; // Icon
|
||||||
|
|
||||||
[FieldOffset( 7 )]
|
[FieldOffset( 7 )]
|
||||||
public EquipSlot EquipSlot; // Equipment, Demihuman
|
public EquipSlot EquipSlot; // Equipment, Demihuman
|
||||||
|
|
@ -157,4 +157,3 @@ namespace Penumbra.GameData.Structs
|
||||||
public int CompareTo( object? r )
|
public int CompareTo( object? r )
|
||||||
=> Identifier.CompareTo( r );
|
=> Identifier.CompareTo( r );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
@ -437,7 +437,11 @@ public partial class ModCollection
|
||||||
}
|
}
|
||||||
else if( !data.Item1.Contains( modPath.Mod ) )
|
else if( !data.Item1.Contains( modPath.Mod ) )
|
||||||
{
|
{
|
||||||
_changedItems[ name ] = ( data.Item1.Append( modPath.Mod ), obj );
|
_changedItems[ name ] = ( data.Item1.Append( modPath.Mod ), obj is int x && data.Item2 is int y ? x + y : obj);
|
||||||
|
}
|
||||||
|
else if (obj is int x && data.Item2 is int y)
|
||||||
|
{
|
||||||
|
_changedItems[name] = (data.Item1, x + y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ public partial class ModFileSystemSelector
|
||||||
0 => !( leaf.FullName().Contains( _modFilter.Lower, IgnoreCase ) || mod.Name.Contains( _modFilter ) ),
|
0 => !( leaf.FullName().Contains( _modFilter.Lower, IgnoreCase ) || mod.Name.Contains( _modFilter ) ),
|
||||||
1 => !mod.Name.Contains( _modFilter ),
|
1 => !mod.Name.Contains( _modFilter ),
|
||||||
2 => !mod.Author.Contains( _modFilter ),
|
2 => !mod.Author.Contains( _modFilter ),
|
||||||
3 => !mod.LowerChangedItemsString.Contains( _modFilter ),
|
3 => !mod.LowerChangedItemsString.Contains( _modFilter.Lower, IgnoreCase ),
|
||||||
_ => false, // Should never happen
|
_ => false, // Should never happen
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,9 @@ public partial class ConfigWindow
|
||||||
{
|
{
|
||||||
// Functions in here for less pollution.
|
// Functions in here for less pollution.
|
||||||
bool FilterChangedItem( KeyValuePair< string, (SingleArray< Mod >, object?) > item )
|
bool FilterChangedItem( KeyValuePair< string, (SingleArray< Mod >, object?) > item )
|
||||||
=> ( _changedItemFilter.IsEmpty || item.Key.Contains( _changedItemFilter.Lower, StringComparison.InvariantCultureIgnoreCase ) )
|
=> ( _changedItemFilter.IsEmpty
|
||||||
|
|| ChangedItemName( item.Key, item.Value.Item2 )
|
||||||
|
.Contains( _changedItemFilter.Lower, StringComparison.InvariantCultureIgnoreCase ) )
|
||||||
&& ( _changedItemModFilter.IsEmpty || item.Value.Item1.Any( m => m.Name.Contains( _changedItemModFilter ) ) );
|
&& ( _changedItemModFilter.IsEmpty || item.Value.Item1.Any( m => m.Name.Contains( _changedItemModFilter ) ) );
|
||||||
|
|
||||||
void DrawChangedItemColumn( KeyValuePair< string, (SingleArray< Mod >, object?) > item )
|
void DrawChangedItemColumn( KeyValuePair< string, (SingleArray< Mod >, object?) > item )
|
||||||
|
|
|
||||||
|
|
@ -28,10 +28,16 @@ public partial class ConfigWindow
|
||||||
private static unsafe void Text( ResourceHandle* resource )
|
private static unsafe void Text( ResourceHandle* resource )
|
||||||
=> Text( resource->FileName(), resource->FileNameLength );
|
=> Text( resource->FileName(), resource->FileNameLength );
|
||||||
|
|
||||||
|
|
||||||
|
// Apply Changed Item Counters to the Name if necessary.
|
||||||
|
private static string ChangedItemName( string name, object? data )
|
||||||
|
=> data is int counter ? $"{counter} Files Manipulating {name}s" : name;
|
||||||
|
|
||||||
// Draw a changed item, invoking the Api-Events for clicks and tooltips.
|
// Draw a changed item, invoking the Api-Events for clicks and tooltips.
|
||||||
// Also draw the item Id in grey if requested
|
// Also draw the item Id in grey if requested
|
||||||
private void DrawChangedItem( string name, object? data, bool drawId )
|
private void DrawChangedItem( string name, object? data, bool drawId )
|
||||||
{
|
{
|
||||||
|
name = ChangedItemName( name, data );
|
||||||
var ret = ImGui.Selectable( name ) ? MouseButton.Left : MouseButton.None;
|
var ret = ImGui.Selectable( name ) ? MouseButton.Left : MouseButton.None;
|
||||||
ret = ImGui.IsItemClicked( ImGuiMouseButton.Right ) ? MouseButton.Right : ret;
|
ret = ImGui.IsItemClicked( ImGuiMouseButton.Right ) ? MouseButton.Right : ret;
|
||||||
ret = ImGui.IsItemClicked( ImGuiMouseButton.Middle ) ? MouseButton.Middle : ret;
|
ret = ImGui.IsItemClicked( ImGuiMouseButton.Middle ) ? MouseButton.Middle : ret;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue