mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Update to API4, use IPC instead of API-project. Replace Actor in most visible names with Object, Character or Player..
This commit is contained in:
parent
3680d2b63f
commit
4dfc2cf665
60 changed files with 812 additions and 740 deletions
|
|
@ -1,11 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Dalamud.Game.ClientState.Actors.Types;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Penumbra.PlayerWatch
|
||||
{
|
||||
public delegate void ActorChange( Actor actor );
|
||||
public delegate void PlayerChange( Character actor );
|
||||
|
||||
public interface IPlayerWatcherBase : IDisposable
|
||||
{
|
||||
|
|
@ -15,7 +15,7 @@ namespace Penumbra.PlayerWatch
|
|||
|
||||
public interface IPlayerWatcher : IPlayerWatcherBase
|
||||
{
|
||||
public event ActorChange? ActorChanged;
|
||||
public event PlayerChange? PlayerChanged;
|
||||
public bool Active { get; }
|
||||
|
||||
public void Enable();
|
||||
|
|
@ -24,8 +24,8 @@ namespace Penumbra.PlayerWatch
|
|||
|
||||
public void AddPlayerToWatch( string playerName );
|
||||
public void RemovePlayerFromWatch( string playerName );
|
||||
public ActorEquipment UpdateActorWithoutEvent( Actor actor );
|
||||
public CharacterEquipment UpdatePlayerWithoutEvent( Character actor );
|
||||
|
||||
public IEnumerable< (string, ActorEquipment) > WatchedPlayers();
|
||||
public IEnumerable< (string, CharacterEquipment) > WatchedPlayers();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<TargetFramework>net5.0-windows</TargetFramework>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<AssemblyTitle>Penumbra.PlayerWatch</AssemblyTitle>
|
||||
<Company>absolute gangstas</Company>
|
||||
<Product>Penumbra</Product>
|
||||
|
|
|
|||
|
|
@ -1,36 +1,45 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Dalamud.Game.ClientState.Actors;
|
||||
using Dalamud.Game.ClientState.Actors.Types;
|
||||
using Dalamud.Plugin;
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Game.ClientState;
|
||||
using Dalamud.Game.ClientState.Objects;
|
||||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Logging;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Penumbra.PlayerWatch
|
||||
{
|
||||
internal class PlayerWatchBase : IDisposable
|
||||
{
|
||||
public const int GPosePlayerActorIdx = 201;
|
||||
public const int GPoseActorEnd = GPosePlayerActorIdx + 48;
|
||||
private const int ActorsPerFrame = 8;
|
||||
public const int GPosePlayerIdx = 201;
|
||||
public const int GPoseTableEnd = GPosePlayerIdx + 48;
|
||||
private const int ObjectsPerFrame = 8;
|
||||
|
||||
private readonly DalamudPluginInterface _pi;
|
||||
internal readonly HashSet< PlayerWatcher > RegisteredWatchers = new();
|
||||
internal readonly Dictionary< string, (ActorEquipment, HashSet< PlayerWatcher >) > Equip = new();
|
||||
private int _frameTicker;
|
||||
private bool _inGPose = false;
|
||||
private bool _enabled = false;
|
||||
private bool _cancel = false;
|
||||
private readonly Framework _framework;
|
||||
private readonly ClientState _clientState;
|
||||
private readonly ObjectTable _objects;
|
||||
internal readonly HashSet< PlayerWatcher > RegisteredWatchers = new();
|
||||
internal readonly Dictionary< string, (CharacterEquipment, HashSet< PlayerWatcher >) > Equip = new();
|
||||
private int _frameTicker;
|
||||
private bool _inGPose;
|
||||
private bool _enabled;
|
||||
private bool _cancel;
|
||||
|
||||
internal PlayerWatchBase( DalamudPluginInterface pi )
|
||||
=> _pi = pi;
|
||||
internal PlayerWatchBase( Framework framework, ClientState clientState, ObjectTable objects )
|
||||
{
|
||||
_framework = framework;
|
||||
_clientState = clientState;
|
||||
_objects = objects;
|
||||
}
|
||||
|
||||
internal void RegisterWatcher( PlayerWatcher watcher )
|
||||
{
|
||||
RegisteredWatchers.Add( watcher );
|
||||
if( watcher.Active )
|
||||
{
|
||||
EnableActorWatch();
|
||||
EnablePlayerWatch();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -51,20 +60,20 @@ namespace Penumbra.PlayerWatch
|
|||
{
|
||||
if( RegisteredWatchers.Any( w => w.Active ) )
|
||||
{
|
||||
EnableActorWatch();
|
||||
EnablePlayerWatch();
|
||||
}
|
||||
else
|
||||
{
|
||||
DisableActorWatch();
|
||||
DisablePlayerWatch();
|
||||
}
|
||||
}
|
||||
|
||||
internal ActorEquipment UpdateActorWithoutEvent( Actor actor )
|
||||
internal CharacterEquipment UpdatePlayerWithoutEvent( Character actor )
|
||||
{
|
||||
var equipment = new ActorEquipment( actor );
|
||||
if( Equip.ContainsKey( actor.Name ) )
|
||||
var equipment = new CharacterEquipment( actor );
|
||||
if( Equip.ContainsKey( actor.Name.ToString() ) )
|
||||
{
|
||||
Equip[ actor.Name ] = ( equipment, Equip[ actor.Name ].Item2 );
|
||||
Equip[ actor.Name.ToString() ] = ( equipment, Equip[ actor.Name.ToString() ].Item2 );
|
||||
}
|
||||
|
||||
return equipment;
|
||||
|
|
@ -78,7 +87,7 @@ namespace Penumbra.PlayerWatch
|
|||
}
|
||||
else
|
||||
{
|
||||
Equip[ playerName ] = ( new ActorEquipment(), new HashSet< PlayerWatcher > { watcher } );
|
||||
Equip[ playerName ] = ( new CharacterEquipment(), new HashSet< PlayerWatcher > { watcher } );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -94,35 +103,35 @@ namespace Penumbra.PlayerWatch
|
|||
}
|
||||
}
|
||||
|
||||
internal void EnableActorWatch()
|
||||
internal void EnablePlayerWatch()
|
||||
{
|
||||
if( !_enabled )
|
||||
{
|
||||
_enabled = true;
|
||||
_pi.Framework.OnUpdateEvent += OnFrameworkUpdate;
|
||||
_pi.ClientState.TerritoryChanged += OnTerritoryChange;
|
||||
_pi.ClientState.OnLogout += OnLogout;
|
||||
_enabled = true;
|
||||
_framework.Update += OnFrameworkUpdate;
|
||||
_clientState.TerritoryChanged += OnTerritoryChange;
|
||||
_clientState.Logout += OnLogout;
|
||||
}
|
||||
}
|
||||
|
||||
internal void DisableActorWatch()
|
||||
internal void DisablePlayerWatch()
|
||||
{
|
||||
if( _enabled )
|
||||
{
|
||||
_enabled = false;
|
||||
_pi.Framework.OnUpdateEvent -= OnFrameworkUpdate;
|
||||
_pi.ClientState.TerritoryChanged -= OnTerritoryChange;
|
||||
_pi.ClientState.OnLogout -= OnLogout;
|
||||
_enabled = false;
|
||||
_framework.Update -= OnFrameworkUpdate;
|
||||
_clientState.TerritoryChanged -= OnTerritoryChange;
|
||||
_clientState.Logout -= OnLogout;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
=> DisableActorWatch();
|
||||
=> DisablePlayerWatch();
|
||||
|
||||
private void OnTerritoryChange( object _1, ushort _2 )
|
||||
private void OnTerritoryChange( object? _1, ushort _2 )
|
||||
=> Clear();
|
||||
|
||||
private void OnLogout( object _1, object _2 )
|
||||
private void OnLogout( object? _1, object? _2 )
|
||||
=> Clear();
|
||||
|
||||
internal void Clear()
|
||||
|
|
@ -137,66 +146,66 @@ namespace Penumbra.PlayerWatch
|
|||
_frameTicker = 0;
|
||||
}
|
||||
|
||||
private static void TriggerEvents( IEnumerable< PlayerWatcher > watchers, Actor actor )
|
||||
private static void TriggerEvents( IEnumerable< PlayerWatcher > watchers, Character player )
|
||||
{
|
||||
PluginLog.Debug( "Triggering events for {ActorName} at {Address}.", actor.Name, actor.Address );
|
||||
PluginLog.Debug( "Triggering events for {PlayerName} at {Address}.", player.Name, player.Address );
|
||||
foreach( var watcher in watchers.Where( w => w.Active ) )
|
||||
{
|
||||
watcher.Trigger( actor );
|
||||
watcher.Trigger( player );
|
||||
}
|
||||
}
|
||||
|
||||
internal void TriggerGPose()
|
||||
{
|
||||
for( var i = GPosePlayerActorIdx; i < GPoseActorEnd; ++i )
|
||||
for( var i = GPosePlayerIdx; i < GPoseTableEnd; ++i )
|
||||
{
|
||||
var actor = _pi.ClientState.Actors[ i ];
|
||||
if( actor == null )
|
||||
var player = _objects[ i ];
|
||||
if( player == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( Equip.TryGetValue( actor.Name, out var watcher ) )
|
||||
if( Equip.TryGetValue( player.Name.ToString(), out var watcher ) )
|
||||
{
|
||||
TriggerEvents( watcher.Item2, actor );
|
||||
TriggerEvents( watcher.Item2, ( Character )player );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Actor CheckGPoseActor( Actor actor )
|
||||
private Character CheckGPoseObject( GameObject player )
|
||||
{
|
||||
if( !_inGPose )
|
||||
{
|
||||
return actor;
|
||||
return ( Character )player;
|
||||
}
|
||||
|
||||
for( var i = GPosePlayerActorIdx; i < GPoseActorEnd; ++i )
|
||||
for( var i = GPosePlayerIdx; i < GPoseTableEnd; ++i )
|
||||
{
|
||||
var a = _pi.ClientState.Actors[ i ];
|
||||
var a = _objects[ i ];
|
||||
if( a == null )
|
||||
{
|
||||
return actor;
|
||||
return ( Character )player;
|
||||
}
|
||||
|
||||
if( a.Name == actor.Name )
|
||||
if( a.Name == player.Name )
|
||||
{
|
||||
return a;
|
||||
return ( Character )a;
|
||||
}
|
||||
}
|
||||
|
||||
return actor;
|
||||
return ( Character )player;
|
||||
}
|
||||
|
||||
private bool TryGetPlayer( GameObject gameObject, out (CharacterEquipment, HashSet< PlayerWatcher >) equip )
|
||||
{
|
||||
equip = default;
|
||||
var name = gameObject.Name.ToString();
|
||||
return name.Length != 0 && Equip.TryGetValue( name, out equip );
|
||||
}
|
||||
|
||||
private void OnFrameworkUpdate( object framework )
|
||||
{
|
||||
if( _pi.ClientState.LocalPlayer == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var actors = _pi.ClientState.Actors;
|
||||
|
||||
var newInGPose = actors[ GPosePlayerActorIdx ] != null;
|
||||
var newInGPose = _objects[ GPosePlayerIdx ] != null;
|
||||
|
||||
if( newInGPose != _inGPose )
|
||||
{
|
||||
|
|
@ -212,28 +221,21 @@ namespace Penumbra.PlayerWatch
|
|||
_inGPose = newInGPose;
|
||||
}
|
||||
|
||||
for( var i = 0; i < ActorsPerFrame; ++i )
|
||||
for( var i = 0; i < ObjectsPerFrame; ++i )
|
||||
{
|
||||
if( _pi.ClientState.LocalPlayer == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_frameTicker = _frameTicker < actors.Length - 2
|
||||
_frameTicker = _frameTicker < GPosePlayerIdx - 2
|
||||
? _frameTicker + 2
|
||||
: 0;
|
||||
|
||||
var actor = actors[ _frameTicker ];
|
||||
if( actor == null
|
||||
|| actor.ObjectKind != ObjectKind.Player
|
||||
|| actor.Name == null
|
||||
|| actor.Name.Length == 0
|
||||
|| !Equip.TryGetValue( actor.Name, out var equip ) )
|
||||
var actor = _objects[ _frameTicker ];
|
||||
if( actor == null
|
||||
|| actor.ObjectKind != ObjectKind.Player
|
||||
|| !TryGetPlayer( actor, out var equip ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
actor = CheckGPoseActor( actor );
|
||||
var character = CheckGPoseObject( actor );
|
||||
|
||||
if( _cancel )
|
||||
{
|
||||
|
|
@ -241,10 +243,10 @@ namespace Penumbra.PlayerWatch
|
|||
return;
|
||||
}
|
||||
|
||||
PluginLog.Verbose( "Comparing Gear for {ActorName} at {Address}...", actor.Name, actor.Address );
|
||||
if( !equip.Item1.CompareAndUpdate( actor ) )
|
||||
PluginLog.Verbose( "Comparing Gear for {PlayerName} at {Address}...", character.Name, character.Address );
|
||||
if( !equip.Item1.CompareAndUpdate( character ) )
|
||||
{
|
||||
TriggerEvents( equip.Item2, actor );
|
||||
TriggerEvents( equip.Item2, character );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,28 +1,30 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Dalamud.Game.ClientState.Actors.Types;
|
||||
using Dalamud.Plugin;
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Game.ClientState;
|
||||
using Dalamud.Game.ClientState.Objects;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Penumbra.PlayerWatch
|
||||
{
|
||||
public class PlayerWatcher : IPlayerWatcher
|
||||
{
|
||||
public int Version { get; } = 1;
|
||||
public int Version { get; } = 2;
|
||||
|
||||
private static PlayerWatchBase? _playerWatch;
|
||||
|
||||
public event ActorChange? ActorChanged;
|
||||
public event PlayerChange? PlayerChanged;
|
||||
|
||||
public bool Active { get; set; } = true;
|
||||
|
||||
public bool Valid
|
||||
=> _playerWatch != null;
|
||||
|
||||
internal PlayerWatcher( DalamudPluginInterface pi )
|
||||
internal PlayerWatcher( Framework framework, ClientState clientState, ObjectTable objects )
|
||||
{
|
||||
_playerWatch ??= new PlayerWatchBase( pi );
|
||||
_playerWatch ??= new PlayerWatchBase( framework, clientState, objects );
|
||||
_playerWatch.RegisterWatcher( this );
|
||||
}
|
||||
|
||||
|
|
@ -38,8 +40,8 @@ namespace Penumbra.PlayerWatch
|
|||
_playerWatch?.CheckActiveStatus();
|
||||
}
|
||||
|
||||
internal void Trigger( Actor actor )
|
||||
=> ActorChanged?.Invoke( actor );
|
||||
internal void Trigger( Character actor )
|
||||
=> PlayerChanged?.Invoke( actor );
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
|
@ -48,8 +50,8 @@ namespace Penumbra.PlayerWatch
|
|||
return;
|
||||
}
|
||||
|
||||
Active = false;
|
||||
ActorChanged = null;
|
||||
Active = false;
|
||||
PlayerChanged = null;
|
||||
_playerWatch.UnregisterWatcher( this );
|
||||
if( _playerWatch.RegisteredWatchers.Count == 0 )
|
||||
{
|
||||
|
|
@ -78,13 +80,13 @@ namespace Penumbra.PlayerWatch
|
|||
_playerWatch!.RemovePlayerFromWatch( playerName, this );
|
||||
}
|
||||
|
||||
public ActorEquipment UpdateActorWithoutEvent( Actor actor )
|
||||
public CharacterEquipment UpdatePlayerWithoutEvent( Character actor )
|
||||
{
|
||||
CheckValidity();
|
||||
return _playerWatch!.UpdateActorWithoutEvent( actor );
|
||||
return _playerWatch!.UpdatePlayerWithoutEvent( actor );
|
||||
}
|
||||
|
||||
public IEnumerable< (string, ActorEquipment) > WatchedPlayers()
|
||||
public IEnumerable< (string, CharacterEquipment) > WatchedPlayers()
|
||||
{
|
||||
CheckValidity();
|
||||
return _playerWatch!.Equip
|
||||
|
|
@ -95,7 +97,7 @@ namespace Penumbra.PlayerWatch
|
|||
|
||||
public static class PlayerWatchFactory
|
||||
{
|
||||
public static IPlayerWatcher Create( DalamudPluginInterface pi )
|
||||
=> new PlayerWatcher( pi );
|
||||
public static IPlayerWatcher Create( Framework framework, ClientState clientState, ObjectTable objects )
|
||||
=> new PlayerWatcher( framework, clientState, objects );
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue