mirror of
https://github.com/xivdev/Penumbra.git
synced 2026-02-20 23:07:51 +01:00
Continued work on actor identification, migration seems to work.
This commit is contained in:
parent
0444c28187
commit
bda3c1f1ac
11 changed files with 407 additions and 115 deletions
|
|
@ -37,6 +37,7 @@ public partial class ModCollection
|
|||
|
||||
// The list of character collections.
|
||||
private readonly Dictionary< string, ModCollection > _characters = new();
|
||||
public readonly IndividualCollections Individuals = new(Penumbra.Actors);
|
||||
|
||||
public IReadOnlyDictionary< string, ModCollection > Characters
|
||||
=> _characters;
|
||||
|
|
@ -288,6 +289,8 @@ public partial class ModCollection
|
|||
{
|
||||
SaveActiveCollections();
|
||||
}
|
||||
|
||||
MigrateIndividualCollections( jObject );
|
||||
}
|
||||
|
||||
// Migrate ungendered collections to Male and Female for 0.5.9.0.
|
||||
|
|
@ -320,13 +323,12 @@ public partial class ModCollection
|
|||
}
|
||||
|
||||
// Migrate individual collections to Identifiers for 0.6.0.
|
||||
private bool MigrateIndividualCollections(JObject jObject, out IndividualCollections collections)
|
||||
private bool MigrateIndividualCollections(JObject jObject)
|
||||
{
|
||||
var version = jObject[ nameof( Version ) ]?.Value< int >() ?? 0;
|
||||
collections = new IndividualCollections( Penumbra.Actors );
|
||||
if( version > 0 )
|
||||
return false;
|
||||
|
||||
|
||||
// Load character collections. If a player name comes up multiple times, the last one is applied.
|
||||
var characters = jObject[nameof( Characters )]?.ToObject<Dictionary<string, string>>() ?? new Dictionary<string, string>();
|
||||
var dict = new Dictionary< string, ModCollection >( characters.Count );
|
||||
|
|
@ -340,15 +342,14 @@ public partial class ModCollection
|
|||
}
|
||||
else
|
||||
{
|
||||
dict.Add( player, this[idx] );
|
||||
dict.Add( player, this[ idx ] );
|
||||
}
|
||||
}
|
||||
|
||||
collections.Migrate0To1( dict );
|
||||
|
||||
Individuals.Migrate0To1( dict );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public void SaveActiveCollections()
|
||||
{
|
||||
Penumbra.Framework.RegisterDelayed( nameof( SaveActiveCollections ),
|
||||
|
|
|
|||
|
|
@ -94,11 +94,12 @@ public enum CollectionType : byte
|
|||
MaleVeenaNpc,
|
||||
FemaleVeenaNpc,
|
||||
|
||||
Inactive, // A collection was added or removed
|
||||
Default, // The default collection was changed
|
||||
Interface, // The ui collection was changed
|
||||
Character, // A character collection was changed
|
||||
Current, // The current collection was changed
|
||||
Inactive, // A collection was added or removed
|
||||
Default, // The default collection was changed
|
||||
Interface, // The ui collection was changed
|
||||
Character, // A character collection was changed
|
||||
Individual, // An Individual collection was changed
|
||||
Current, // The current collection was changed
|
||||
}
|
||||
|
||||
public static class CollectionTypeExtensions
|
||||
|
|
|
|||
117
Penumbra/Collections/IndividualCollections.Access.cs
Normal file
117
Penumbra/Collections/IndividualCollections.Access.cs
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Penumbra.GameData.Actors;
|
||||
|
||||
namespace Penumbra.Collections;
|
||||
|
||||
public sealed partial class IndividualCollections : IReadOnlyList< (string DisplayName, ModCollection Collection) >
|
||||
{
|
||||
public IEnumerator< (string DisplayName, ModCollection Collection) > GetEnumerator()
|
||||
=> _assignments.Select( kvp => ( kvp.Key, kvp.Value.Collection ) ).GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
=> GetEnumerator();
|
||||
|
||||
public int Count
|
||||
=> _assignments.Count;
|
||||
|
||||
public (string DisplayName, ModCollection Collection) this[ int index ]
|
||||
=> ( _assignments.Keys[ index ], _assignments.Values[ index ].Collection );
|
||||
|
||||
public bool TryGetCollection( ActorIdentifier identifier, [NotNullWhen( true )] out ModCollection? collection )
|
||||
{
|
||||
switch( identifier.Type )
|
||||
{
|
||||
case IdentifierType.Player: return CheckWorlds( identifier, out collection );
|
||||
case IdentifierType.Owned:
|
||||
{
|
||||
if( CheckWorlds( identifier, out collection! ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Handle generic NPC
|
||||
var npcIdentifier = _manager.CreateNpc( identifier.Kind, identifier.DataId );
|
||||
if( npcIdentifier.IsValid && _individuals.TryGetValue( identifier, out collection ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Handle Ownership.
|
||||
if( Penumbra.Config.UseOwnerNameForCharacterCollection )
|
||||
{
|
||||
identifier = _manager.CreatePlayer( identifier.PlayerName, identifier.HomeWorld );
|
||||
return CheckWorlds( identifier, out collection );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
case IdentifierType.Npc: return _individuals.TryGetValue( identifier, out collection );
|
||||
case IdentifierType.Special:
|
||||
switch( identifier.Special )
|
||||
{
|
||||
case SpecialActor.CharacterScreen when Penumbra.Config.UseCharacterCollectionInMainWindow:
|
||||
case SpecialActor.FittingRoom when Penumbra.Config.UseCharacterCollectionInTryOn:
|
||||
case SpecialActor.DyePreview when Penumbra.Config.UseCharacterCollectionInTryOn:
|
||||
case SpecialActor.Portrait when Penumbra.Config.UseCharacterCollectionsInCards:
|
||||
return CheckWorlds( _manager.GetCurrentPlayer(), out collection );
|
||||
case SpecialActor.ExamineScreen:
|
||||
{
|
||||
if( CheckWorlds( _manager.GetInspectPlayer(), out collection! ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if( CheckWorlds( _manager.GetCardPlayer(), out collection! ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if( CheckWorlds( _manager.GetGlamourPlayer(), out collection! ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
collection = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGetCollection( GameObject? gameObject, out ModCollection? collection )
|
||||
=> TryGetCollection( _manager.FromObject( gameObject ), out collection );
|
||||
|
||||
public unsafe bool TryGetCollection( FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* gameObject, out ModCollection? collection )
|
||||
=> TryGetCollection( _manager.FromObject( gameObject ), out collection );
|
||||
|
||||
private bool CheckWorlds( ActorIdentifier identifier, out ModCollection? collection )
|
||||
{
|
||||
if( !identifier.IsValid )
|
||||
{
|
||||
collection = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
if( _individuals.TryGetValue( identifier, out collection ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
identifier = _manager.CreateIndividual( identifier.Type, identifier.PlayerName, ushort.MaxValue, identifier.Kind, identifier.DataId );
|
||||
if( identifier.IsValid && _individuals.TryGetValue( identifier, out collection ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
collection = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
89
Penumbra/Collections/IndividualCollections.Files.cs
Normal file
89
Penumbra/Collections/IndividualCollections.Files.cs
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
using Dalamud.Interface.Internal.Notifications;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.String;
|
||||
using Penumbra.Util;
|
||||
|
||||
namespace Penumbra.Collections;
|
||||
|
||||
public partial class IndividualCollections
|
||||
{
|
||||
public const int Version = 1;
|
||||
|
||||
internal void Migrate0To1( Dictionary< string, ModCollection > old )
|
||||
{
|
||||
static bool FindDataId( string name, IReadOnlyDictionary< uint, string > data, out uint dataId )
|
||||
{
|
||||
var kvp = data.FirstOrDefault( kvp => kvp.Value.Equals( name, StringComparison.OrdinalIgnoreCase ),
|
||||
new KeyValuePair< uint, string >( uint.MaxValue, string.Empty ) );
|
||||
dataId = kvp.Key;
|
||||
return kvp.Value.Length > 0;
|
||||
}
|
||||
|
||||
foreach( var (name, collection) in old )
|
||||
{
|
||||
var kind = ObjectKind.None;
|
||||
var lowerName = name.ToLowerInvariant();
|
||||
// Prefer matching NPC names, fewer false positives than preferring players.
|
||||
if( FindDataId( lowerName, _manager.Companions, out var dataId ) )
|
||||
{
|
||||
kind = ObjectKind.Companion;
|
||||
}
|
||||
else if( FindDataId( lowerName, _manager.Mounts, out dataId ) )
|
||||
{
|
||||
kind = ObjectKind.MountType;
|
||||
}
|
||||
else if( FindDataId( lowerName, _manager.BNpcs, out dataId ) )
|
||||
{
|
||||
kind = ObjectKind.BattleNpc;
|
||||
}
|
||||
else if( FindDataId( lowerName, _manager.ENpcs, out dataId ) )
|
||||
{
|
||||
kind = ObjectKind.EventNpc;
|
||||
}
|
||||
|
||||
var identifier = _manager.CreateNpc( kind, dataId );
|
||||
if( identifier.IsValid )
|
||||
{
|
||||
// If the name corresponds to a valid npc, add it as a group. If this fails, notify users.
|
||||
var group = GetGroup( identifier );
|
||||
var ids = string.Join( ", ", group.Select( i => i.DataId.ToString() ) );
|
||||
if( Add( $"{_manager.ToName( kind, dataId )} ({kind.ToName()})", group, collection ) )
|
||||
{
|
||||
Penumbra.Log.Information( $"Migrated {name} ({kind.ToName()}) to NPC Identifiers [{ids}]." );
|
||||
}
|
||||
else
|
||||
{
|
||||
ChatUtil.NotificationMessage(
|
||||
$"Could not migrate {name} ({collection.AnonymizedName}) which was assumed to be a {kind.ToName()} with IDs [{ids}], please look through your individual collections.",
|
||||
"Migration Failure", NotificationType.Error );
|
||||
}
|
||||
}
|
||||
// If it is not a valid NPC name, check if it can be a player name.
|
||||
else if( ActorManager.VerifyPlayerName( name ) )
|
||||
{
|
||||
identifier = _manager.CreatePlayer( ByteString.FromStringUnsafe( name, false ), ushort.MaxValue );
|
||||
var shortName = string.Join( " ", name.Split().Select( n => $"{n[ 0 ]}." ) );
|
||||
// Try to migrate the player name without logging full names.
|
||||
if( Add( $"{name} ({_manager.ToWorldName( identifier.HomeWorld )})", new[] { identifier }, collection ) )
|
||||
{
|
||||
Penumbra.Log.Information( $"Migrated {shortName} ({collection.AnonymizedName}) to Player Identifier." );
|
||||
}
|
||||
else
|
||||
{
|
||||
ChatUtil.NotificationMessage( $"Could not migrate {shortName} ({collection.AnonymizedName}), please look through your individual collections.",
|
||||
"Migration Failure", NotificationType.Error );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ChatUtil.NotificationMessage(
|
||||
$"Could not migrate {name} ({collection.AnonymizedName}), which can not be a player name nor is it a known NPC name, please look through your individual collections.",
|
||||
"Migration Failure", NotificationType.Error );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,39 +1,13 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.String;
|
||||
|
||||
namespace Penumbra.Collections;
|
||||
|
||||
public partial class IndividualCollections
|
||||
{
|
||||
public const int Version = 1;
|
||||
|
||||
internal void Migrate0To1( Dictionary< string, ModCollection > old )
|
||||
{
|
||||
foreach( var (name, collection) in old )
|
||||
{
|
||||
if( ActorManager.VerifyPlayerName( name ) )
|
||||
{
|
||||
var identifier = _manager.CreatePlayer( ByteString.FromStringUnsafe( name, false ), ushort.MaxValue );
|
||||
if( Add( name, new[] { identifier }, collection ) )
|
||||
{
|
||||
var shortName = string.Join( " ", name.Split().Select( n => $"{n[0]}." ) );
|
||||
Penumbra.Log.Information( $"Migrated {shortName} ({collection.AnonymizedName}) to Player Identifier." );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed partial class IndividualCollections : IReadOnlyList< (string DisplayName, ModCollection Collection) >
|
||||
public sealed partial class IndividualCollections
|
||||
{
|
||||
private readonly ActorManager _manager;
|
||||
private readonly SortedList< string, (IReadOnlyList< ActorIdentifier > Identifiers, ModCollection Collection) > _assignments = new();
|
||||
|
|
@ -48,10 +22,34 @@ public sealed partial class IndividualCollections : IReadOnlyList< (string Displ
|
|||
public IndividualCollections( ActorManager manager )
|
||||
=> _manager = manager;
|
||||
|
||||
public bool CanAdd( params ActorIdentifier[] identifiers )
|
||||
=> identifiers.Length > 0 && identifiers.All( i => i.IsValid && !Individuals.ContainsKey( i ) );
|
||||
public enum AddResult
|
||||
{
|
||||
Valid,
|
||||
AlreadySet,
|
||||
Invalid,
|
||||
}
|
||||
|
||||
public bool CanAdd( IdentifierType type, string name, ushort homeWorld, ObjectKind kind, IEnumerable< uint > dataIds, out ActorIdentifier[] identifiers )
|
||||
public AddResult CanAdd( params ActorIdentifier[] identifiers )
|
||||
{
|
||||
if( identifiers.Length == 0 )
|
||||
{
|
||||
return AddResult.Invalid;
|
||||
}
|
||||
|
||||
if( identifiers.Any( i => !i.IsValid ) )
|
||||
{
|
||||
return AddResult.Invalid;
|
||||
}
|
||||
|
||||
if( identifiers.Any( Individuals.ContainsKey ) )
|
||||
{
|
||||
return AddResult.AlreadySet;
|
||||
}
|
||||
|
||||
return AddResult.Valid;
|
||||
}
|
||||
|
||||
public AddResult CanAdd( IdentifierType type, string name, ushort homeWorld, ObjectKind kind, IEnumerable< uint > dataIds, out ActorIdentifier[] identifiers )
|
||||
{
|
||||
identifiers = Array.Empty< ActorIdentifier >();
|
||||
|
||||
|
|
@ -60,7 +58,7 @@ public sealed partial class IndividualCollections : IReadOnlyList< (string Displ
|
|||
case IdentifierType.Player:
|
||||
if( !ByteString.FromString( name, out var playerName ) )
|
||||
{
|
||||
return false;
|
||||
return AddResult.Invalid;
|
||||
}
|
||||
|
||||
var identifier = _manager.CreatePlayer( playerName, homeWorld );
|
||||
|
|
@ -69,7 +67,7 @@ public sealed partial class IndividualCollections : IReadOnlyList< (string Displ
|
|||
case IdentifierType.Owned:
|
||||
if( !ByteString.FromString( name, out var ownerName ) )
|
||||
{
|
||||
return false;
|
||||
return AddResult.Invalid;
|
||||
}
|
||||
|
||||
identifiers = dataIds.Select( id => _manager.CreateOwned( ownerName, homeWorld, kind, id ) ).ToArray();
|
||||
|
|
@ -119,7 +117,7 @@ public sealed partial class IndividualCollections : IReadOnlyList< (string Displ
|
|||
|
||||
public bool Add( string displayName, ActorIdentifier[] identifiers, ModCollection collection )
|
||||
{
|
||||
if( !CanAdd( identifiers ) || _assignments.ContainsKey( displayName ) )
|
||||
if( CanAdd( identifiers ) != AddResult.Valid || _assignments.ContainsKey( displayName ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -177,49 +175,4 @@ public sealed partial class IndividualCollections : IReadOnlyList< (string Displ
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
public IEnumerator< (string DisplayName, ModCollection Collection) > GetEnumerator()
|
||||
=> _assignments.Select( kvp => ( kvp.Key, kvp.Value.Collection ) ).GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
=> GetEnumerator();
|
||||
|
||||
public int Count
|
||||
=> _assignments.Count;
|
||||
|
||||
public (string DisplayName, ModCollection Collection) this[ int index ]
|
||||
=> ( _assignments.Keys[ index ], _assignments.Values[ index ].Collection );
|
||||
|
||||
public bool TryGetCollection( ActorIdentifier identifier, out ModCollection? collection )
|
||||
{
|
||||
collection = null;
|
||||
if( !identifier.IsValid )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( _individuals.TryGetValue( identifier, out collection ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if( identifier.Type is not (IdentifierType.Player or IdentifierType.Owned) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
identifier = _manager.CreateIndividual( identifier.Type, identifier.PlayerName, ushort.MaxValue, identifier.Kind, identifier.DataId );
|
||||
if( identifier.IsValid && _individuals.TryGetValue( identifier, out collection ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGetCollection( GameObject? gameObject, out ModCollection? collection )
|
||||
=> TryGetCollection( _manager.FromObject( gameObject ), out collection );
|
||||
|
||||
public unsafe bool TryGetCollection( FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* gameObject, out ModCollection? collection )
|
||||
=> TryGetCollection( _manager.FromObject( gameObject ), out collection );
|
||||
}
|
||||
|
|
@ -36,6 +36,7 @@ namespace Penumbra;
|
|||
public class Penumbra : IDalamudPlugin
|
||||
{
|
||||
public const string Repository = "https://raw.githubusercontent.com/xivdev/Penumbra/master/repo.json";
|
||||
|
||||
public string Name
|
||||
=> "Penumbra";
|
||||
|
||||
|
|
@ -93,6 +94,7 @@ public class Penumbra : IDalamudPlugin
|
|||
Identifier = GameData.GameData.GetIdentifier( Dalamud.PluginInterface, Dalamud.GameData );
|
||||
GamePathParser = GameData.GameData.GetGamePathParser();
|
||||
StainManager = new StainManager( Dalamud.PluginInterface, Dalamud.GameData );
|
||||
Actors = new ActorManager( Dalamud.PluginInterface, Dalamud.Objects, Dalamud.ClientState, Dalamud.GameData, Dalamud.GameGui, ResolveCutscene );
|
||||
|
||||
Framework = new FrameworkManager();
|
||||
CharacterUtility = new CharacterUtility();
|
||||
|
|
@ -112,7 +114,6 @@ public class Penumbra : IDalamudPlugin
|
|||
ModFileSystem = ModFileSystem.Load();
|
||||
ObjectReloader = new ObjectReloader();
|
||||
PathResolver = new PathResolver( ResourceLoader );
|
||||
Actors = new ActorManager( Dalamud.PluginInterface, Dalamud.Objects, Dalamud.ClientState, Dalamud.GameData, u => ( short )PathResolver.CutsceneActor( u ) );
|
||||
|
||||
Dalamud.Commands.AddHandler( CommandName, new CommandInfo( OnCommand )
|
||||
{
|
||||
|
|
@ -296,6 +297,9 @@ public class Penumbra : IDalamudPlugin
|
|||
WebServer = null;
|
||||
}
|
||||
|
||||
private short ResolveCutscene( ushort index )
|
||||
=> ( short )PathResolver.CutsceneActor( index );
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
StainManager?.Dispose();
|
||||
|
|
@ -586,7 +590,7 @@ public class Penumbra : IDalamudPlugin
|
|||
return Dalamud.PluginInterface.SourceRepository.Trim().ToLowerInvariant() switch
|
||||
{
|
||||
null => false,
|
||||
Repository => true,
|
||||
Repository => true,
|
||||
"https://raw.githubusercontent.com/xivdev/Penumbra/test/repo.json" => true,
|
||||
_ => false,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ using FFXIVClientStructs.FFXIV.Client.System.Resource;
|
|||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Files;
|
||||
using Penumbra.Interop.Loader;
|
||||
using Penumbra.Interop.Structs;
|
||||
|
|
@ -167,6 +168,24 @@ public partial class ConfigWindow
|
|||
return;
|
||||
}
|
||||
|
||||
static void DrawSpecial( string name, ActorIdentifier id )
|
||||
{
|
||||
if( !id.IsValid )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ImGuiUtil.DrawTableColumn( name );
|
||||
ImGuiUtil.DrawTableColumn( string.Empty );
|
||||
ImGuiUtil.DrawTableColumn( Penumbra.Actors.ToString( id ) );
|
||||
ImGuiUtil.DrawTableColumn( string.Empty );
|
||||
}
|
||||
|
||||
DrawSpecial( "Current Player", Penumbra.Actors.GetCurrentPlayer() );
|
||||
DrawSpecial( "Current Inspect", Penumbra.Actors.GetInspectPlayer() );
|
||||
DrawSpecial( "Current Card", Penumbra.Actors.GetCardPlayer() );
|
||||
DrawSpecial( "Current Glamour", Penumbra.Actors.GetGlamourPlayer() );
|
||||
|
||||
foreach( var obj in Dalamud.Objects )
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn( $"{( ( GameObject* )obj.Address )->ObjectIndex}" );
|
||||
|
|
|
|||
|
|
@ -1,8 +1,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Dalamud.Game.Text;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Internal.Notifications;
|
||||
using Dalamud.Utility;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using OtterGui.Log;
|
||||
|
||||
namespace Penumbra.Util;
|
||||
|
||||
|
|
@ -32,4 +37,19 @@ public static class ChatUtil
|
|||
Message = payload,
|
||||
} );
|
||||
}
|
||||
|
||||
public static void NotificationMessage( string content, string? title = null, NotificationType type = NotificationType.None )
|
||||
{
|
||||
var logLevel = type switch
|
||||
{
|
||||
NotificationType.None => Logger.LogLevel.Information,
|
||||
NotificationType.Success => Logger.LogLevel.Information,
|
||||
NotificationType.Warning => Logger.LogLevel.Warning,
|
||||
NotificationType.Error => Logger.LogLevel.Error,
|
||||
NotificationType.Info => Logger.LogLevel.Information,
|
||||
_ => Logger.LogLevel.Debug,
|
||||
};
|
||||
Dalamud.PluginInterface.UiBuilder.AddNotification( content, title, type );
|
||||
Penumbra.Log.Message( logLevel, title.IsNullOrEmpty() ? content : $"[{title}] {content}" );
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue