mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Add keeping track of seen players to player watcher.
This commit is contained in:
parent
906e057943
commit
743f83d12e
3 changed files with 340 additions and 333 deletions
|
|
@ -3,18 +3,18 @@ using System.Collections.Generic;
|
||||||
using Dalamud.Game.ClientState.Objects.Types;
|
using Dalamud.Game.ClientState.Objects.Types;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
|
|
||||||
namespace Penumbra.PlayerWatch
|
namespace Penumbra.PlayerWatch;
|
||||||
{
|
|
||||||
public delegate void PlayerChange( Character actor );
|
|
||||||
|
|
||||||
public interface IPlayerWatcherBase : IDisposable
|
public delegate void PlayerChange( Character actor );
|
||||||
{
|
|
||||||
|
public interface IPlayerWatcherBase : IDisposable
|
||||||
|
{
|
||||||
public int Version { get; }
|
public int Version { get; }
|
||||||
public bool Valid { get; }
|
public bool Valid { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IPlayerWatcher : IPlayerWatcherBase
|
public interface IPlayerWatcher : IPlayerWatcherBase
|
||||||
{
|
{
|
||||||
public event PlayerChange? PlayerChanged;
|
public event PlayerChange? PlayerChanged;
|
||||||
public bool Active { get; }
|
public bool Active { get; }
|
||||||
|
|
||||||
|
|
@ -26,6 +26,5 @@ namespace Penumbra.PlayerWatch
|
||||||
public void RemovePlayerFromWatch( string playerName );
|
public void RemovePlayerFromWatch( string playerName );
|
||||||
public CharacterEquipment UpdatePlayerWithoutEvent( Character actor );
|
public CharacterEquipment UpdatePlayerWithoutEvent( Character actor );
|
||||||
|
|
||||||
public IEnumerable< (string, (uint, CharacterEquipment)[]) > WatchedPlayers();
|
public IEnumerable< (string, (ulong, CharacterEquipment)[]) > WatchedPlayers();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -9,22 +9,22 @@ using Dalamud.Game.ClientState.Objects.Types;
|
||||||
using Dalamud.Logging;
|
using Dalamud.Logging;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
|
|
||||||
namespace Penumbra.PlayerWatch
|
namespace Penumbra.PlayerWatch;
|
||||||
|
|
||||||
|
internal readonly struct WatchedPlayer
|
||||||
{
|
{
|
||||||
internal readonly struct WatchedPlayer
|
public readonly Dictionary< ulong, CharacterEquipment > FoundActors;
|
||||||
{
|
|
||||||
public readonly Dictionary< uint, CharacterEquipment > FoundActors;
|
|
||||||
public readonly HashSet< PlayerWatcher > RegisteredWatchers;
|
public readonly HashSet< PlayerWatcher > RegisteredWatchers;
|
||||||
|
|
||||||
public WatchedPlayer( PlayerWatcher watcher )
|
public WatchedPlayer( PlayerWatcher watcher )
|
||||||
{
|
{
|
||||||
FoundActors = new Dictionary< uint, CharacterEquipment >(4);
|
FoundActors = new Dictionary< ulong, CharacterEquipment >( 4 );
|
||||||
RegisteredWatchers = new HashSet< PlayerWatcher >{ watcher };
|
RegisteredWatchers = new HashSet< PlayerWatcher > { watcher };
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal class PlayerWatchBase : IDisposable
|
internal class PlayerWatchBase : IDisposable
|
||||||
{
|
{
|
||||||
public const int GPosePlayerIdx = 201;
|
public const int GPosePlayerIdx = 201;
|
||||||
public const int GPoseTableEnd = GPosePlayerIdx + 48;
|
public const int GPoseTableEnd = GPosePlayerIdx + 48;
|
||||||
private const int ObjectsPerFrame = 32;
|
private const int ObjectsPerFrame = 32;
|
||||||
|
|
@ -34,6 +34,7 @@ namespace Penumbra.PlayerWatch
|
||||||
private readonly ObjectTable _objects;
|
private readonly ObjectTable _objects;
|
||||||
internal readonly HashSet< PlayerWatcher > RegisteredWatchers = new();
|
internal readonly HashSet< PlayerWatcher > RegisteredWatchers = new();
|
||||||
internal readonly Dictionary< string, WatchedPlayer > Equip = new();
|
internal readonly Dictionary< string, WatchedPlayer > Equip = new();
|
||||||
|
internal HashSet< ulong > SeenActors;
|
||||||
private int _frameTicker;
|
private int _frameTicker;
|
||||||
private bool _inGPose;
|
private bool _inGPose;
|
||||||
private bool _enabled;
|
private bool _enabled;
|
||||||
|
|
@ -44,6 +45,7 @@ namespace Penumbra.PlayerWatch
|
||||||
_framework = framework;
|
_framework = framework;
|
||||||
_clientState = clientState;
|
_clientState = clientState;
|
||||||
_objects = objects;
|
_objects = objects;
|
||||||
|
SeenActors = new HashSet< ulong >( _objects.Length );
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void RegisterWatcher( PlayerWatcher watcher )
|
internal void RegisterWatcher( PlayerWatcher watcher )
|
||||||
|
|
@ -83,14 +85,14 @@ namespace Penumbra.PlayerWatch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static uint GetId( GameObject actor )
|
private static ulong GetId( GameObject actor )
|
||||||
=> actor.ObjectId ^ actor.OwnerId;
|
=> actor.ObjectId | ( ( ulong )actor.OwnerId << 32 );
|
||||||
|
|
||||||
internal CharacterEquipment UpdatePlayerWithoutEvent( Character actor )
|
internal CharacterEquipment UpdatePlayerWithoutEvent( Character actor )
|
||||||
{
|
{
|
||||||
var name = actor.Name.ToString();
|
var name = actor.Name.ToString();
|
||||||
var equipment = new CharacterEquipment( actor );
|
var equipment = new CharacterEquipment( actor );
|
||||||
if (Equip.TryGetValue( name, out var watched ))
|
if( Equip.TryGetValue( name, out var watched ) )
|
||||||
{
|
{
|
||||||
watched.FoundActors[ GetId( actor ) ] = equipment;
|
watched.FoundActors[ GetId( actor ) ] = equipment;
|
||||||
}
|
}
|
||||||
|
|
@ -242,6 +244,12 @@ namespace Penumbra.PlayerWatch
|
||||||
else if( _frameTicker == _objects.Length - 1 )
|
else if( _frameTicker == _objects.Length - 1 )
|
||||||
{
|
{
|
||||||
_frameTicker = 0;
|
_frameTicker = 0;
|
||||||
|
foreach( var (_, equip) in Equip.Values.SelectMany( d => d.FoundActors.Where( p => !SeenActors.Contains( p.Key ) ) ) )
|
||||||
|
{
|
||||||
|
equip.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
SeenActors.Clear();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -292,14 +300,15 @@ namespace Penumbra.PlayerWatch
|
||||||
}
|
}
|
||||||
|
|
||||||
var id = GetId( character );
|
var id = GetId( character );
|
||||||
PluginLog.Verbose( "Comparing Gear for {PlayerName} ({Id}) at {Address}...", character.Name, id, character.Address);
|
SeenActors.Add( id );
|
||||||
|
PluginLog.Verbose( "Comparing Gear for {PlayerName} ({Id}) at {Address}...", character.Name, id, character.Address );
|
||||||
if( !watch.FoundActors.TryGetValue( id, out var equip ) )
|
if( !watch.FoundActors.TryGetValue( id, out var equip ) )
|
||||||
{
|
{
|
||||||
equip = new CharacterEquipment( character );
|
equip = new CharacterEquipment( character );
|
||||||
watch.FoundActors[ id ] = equip;
|
watch.FoundActors[ id ] = equip;
|
||||||
TriggerEvents( watch.RegisteredWatchers, character );
|
TriggerEvents( watch.RegisteredWatchers, character );
|
||||||
}
|
}
|
||||||
else if (!equip.CompareAndUpdate( character ))
|
else if( !equip.CompareAndUpdate( character ) )
|
||||||
{
|
{
|
||||||
TriggerEvents( watch.RegisteredWatchers, character );
|
TriggerEvents( watch.RegisteredWatchers, character );
|
||||||
}
|
}
|
||||||
|
|
@ -307,5 +316,4 @@ namespace Penumbra.PlayerWatch
|
||||||
break; // Only one comparison per frame.
|
break; // Only one comparison per frame.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -7,11 +7,12 @@ using Dalamud.Game.ClientState.Objects;
|
||||||
using Dalamud.Game.ClientState.Objects.Types;
|
using Dalamud.Game.ClientState.Objects.Types;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
|
|
||||||
namespace Penumbra.PlayerWatch
|
namespace Penumbra.PlayerWatch;
|
||||||
|
|
||||||
|
public class PlayerWatcher : IPlayerWatcher
|
||||||
{
|
{
|
||||||
public class PlayerWatcher : IPlayerWatcher
|
public int Version
|
||||||
{
|
=> 3;
|
||||||
public int Version { get; } = 2;
|
|
||||||
|
|
||||||
private static PlayerWatchBase? _playerWatch;
|
private static PlayerWatchBase? _playerWatch;
|
||||||
|
|
||||||
|
|
@ -86,18 +87,17 @@ namespace Penumbra.PlayerWatch
|
||||||
return _playerWatch!.UpdatePlayerWithoutEvent( actor );
|
return _playerWatch!.UpdatePlayerWithoutEvent( actor );
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable< (string, (uint, CharacterEquipment)[]) > WatchedPlayers()
|
public IEnumerable< (string, (ulong, CharacterEquipment)[]) > WatchedPlayers()
|
||||||
{
|
{
|
||||||
CheckValidity();
|
CheckValidity();
|
||||||
return _playerWatch!.Equip
|
return _playerWatch!.Equip
|
||||||
.Where( kvp => kvp.Value.RegisteredWatchers.Contains( this ) )
|
.Where( kvp => kvp.Value.RegisteredWatchers.Contains( this ) )
|
||||||
.Select( kvp => ( kvp.Key, kvp.Value.FoundActors.Select( kvp2 => ( kvp2.Key, kvp2.Value ) ).ToArray() ) );
|
.Select( kvp => ( kvp.Key, kvp.Value.FoundActors.Select( kvp2 => ( kvp2.Key, kvp2.Value ) ).ToArray() ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class PlayerWatchFactory
|
public static class PlayerWatchFactory
|
||||||
{
|
{
|
||||||
public static IPlayerWatcher Create( Framework framework, ClientState clientState, ObjectTable objects )
|
public static IPlayerWatcher Create( Framework framework, ClientState clientState, ObjectTable objects )
|
||||||
=> new PlayerWatcher( framework, clientState, objects );
|
=> new PlayerWatcher( framework, clientState, objects );
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue