Fix typing indicators! (#29492)
* First commit * Removed pause stuff * Make the event better * Forgot to add the comment * Proto id stuff * cool comments * serializer * Added the time stuff
This commit is contained in:
@@ -2,21 +2,36 @@
|
|||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
using Content.Shared.Inventory;
|
||||||
|
|
||||||
namespace Content.Client.Chat.TypingIndicator;
|
namespace Content.Client.Chat.TypingIndicator;
|
||||||
|
|
||||||
public sealed class TypingIndicatorVisualizerSystem : VisualizerSystem<TypingIndicatorComponent>
|
public sealed class TypingIndicatorVisualizerSystem : VisualizerSystem<TypingIndicatorComponent>
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
[Dependency] private readonly InventorySystem _inventory = default!;
|
||||||
|
|
||||||
|
|
||||||
protected override void OnAppearanceChange(EntityUid uid, TypingIndicatorComponent component, ref AppearanceChangeEvent args)
|
protected override void OnAppearanceChange(EntityUid uid, TypingIndicatorComponent component, ref AppearanceChangeEvent args)
|
||||||
{
|
{
|
||||||
if (args.Sprite == null)
|
if (args.Sprite == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!_prototypeManager.TryIndex<TypingIndicatorPrototype>(component.Prototype, out var proto))
|
var currentTypingIndicator = component.TypingIndicatorPrototype;
|
||||||
|
|
||||||
|
var evt = new BeforeShowTypingIndicatorEvent();
|
||||||
|
|
||||||
|
if (TryComp<InventoryComponent>(uid, out var inventoryComp))
|
||||||
|
_inventory.RelayEvent((uid, inventoryComp), ref evt);
|
||||||
|
|
||||||
|
var overrideIndicator = evt.GetMostRecentIndicator();
|
||||||
|
|
||||||
|
if (overrideIndicator != null)
|
||||||
|
currentTypingIndicator = overrideIndicator.Value;
|
||||||
|
|
||||||
|
if (!_prototypeManager.TryIndex(currentTypingIndicator, out var proto))
|
||||||
{
|
{
|
||||||
Log.Error($"Unknown typing indicator id: {component.Prototype}");
|
Log.Error($"Unknown typing indicator id: {component.TypingIndicatorPrototype}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
using Content.Shared.ActionBlocker;
|
using Content.Shared.ActionBlocker;
|
||||||
using Content.Shared.Clothing;
|
using Content.Shared.Clothing;
|
||||||
|
using Content.Shared.Inventory;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
namespace Content.Shared.Chat.TypingIndicator;
|
namespace Content.Shared.Chat.TypingIndicator;
|
||||||
|
|
||||||
@@ -11,6 +13,7 @@ public abstract class SharedTypingIndicatorSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
|
[Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
|
||||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||||
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default ID of <see cref="TypingIndicatorPrototype"/>
|
/// Default ID of <see cref="TypingIndicatorPrototype"/>
|
||||||
@@ -26,6 +29,7 @@ public abstract class SharedTypingIndicatorSystem : EntitySystem
|
|||||||
|
|
||||||
SubscribeLocalEvent<TypingIndicatorClothingComponent, ClothingGotEquippedEvent>(OnGotEquipped);
|
SubscribeLocalEvent<TypingIndicatorClothingComponent, ClothingGotEquippedEvent>(OnGotEquipped);
|
||||||
SubscribeLocalEvent<TypingIndicatorClothingComponent, ClothingGotUnequippedEvent>(OnGotUnequipped);
|
SubscribeLocalEvent<TypingIndicatorClothingComponent, ClothingGotUnequippedEvent>(OnGotUnequipped);
|
||||||
|
SubscribeLocalEvent<TypingIndicatorClothingComponent, InventoryRelayedEvent<BeforeShowTypingIndicatorEvent>>(BeforeShow);
|
||||||
|
|
||||||
SubscribeAllEvent<TypingChangedEvent>(OnTypingChanged);
|
SubscribeAllEvent<TypingChangedEvent>(OnTypingChanged);
|
||||||
}
|
}
|
||||||
@@ -44,20 +48,19 @@ public abstract class SharedTypingIndicatorSystem : EntitySystem
|
|||||||
SetTypingIndicatorEnabled(uid, false);
|
SetTypingIndicatorEnabled(uid, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnGotEquipped(EntityUid uid, TypingIndicatorClothingComponent component, ClothingGotEquippedEvent args)
|
private void OnGotEquipped(Entity<TypingIndicatorClothingComponent> entity, ref ClothingGotEquippedEvent args)
|
||||||
{
|
{
|
||||||
if (!TryComp<TypingIndicatorComponent>(args.Wearer, out var indicator))
|
entity.Comp.GotEquippedTime = _timing.CurTime;
|
||||||
return;
|
|
||||||
|
|
||||||
indicator.Prototype = component.Prototype;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnGotUnequipped(EntityUid uid, TypingIndicatorClothingComponent component, ClothingGotUnequippedEvent args)
|
private void OnGotUnequipped(Entity<TypingIndicatorClothingComponent> entity, ref ClothingGotUnequippedEvent args)
|
||||||
{
|
{
|
||||||
if (!TryComp<TypingIndicatorComponent>(args.Wearer, out var indicator))
|
entity.Comp.GotEquippedTime = null;
|
||||||
return;
|
}
|
||||||
|
|
||||||
indicator.Prototype = InitialIndicatorId;
|
private void BeforeShow(Entity<TypingIndicatorClothingComponent> entity, ref InventoryRelayedEvent<BeforeShowTypingIndicatorEvent> args)
|
||||||
|
{
|
||||||
|
args.Args.TryUpdateTimeAndIndicator(entity.Comp.TypingIndicatorPrototype, entity.Comp.GotEquippedTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnTypingChanged(TypingChangedEvent ev, EntitySessionEventArgs args)
|
private void OnTypingChanged(TypingChangedEvent ev, EntitySessionEventArgs args)
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
using Robust.Shared.Serialization;
|
|
||||||
|
|
||||||
namespace Content.Shared.Chat.TypingIndicator;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Networked event from client.
|
|
||||||
/// Send to server when client started/stopped typing in chat input field.
|
|
||||||
/// </summary>
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public sealed class TypingChangedEvent : EntityEventArgs
|
|
||||||
{
|
|
||||||
public readonly bool IsTyping;
|
|
||||||
|
|
||||||
public TypingChangedEvent(bool isTyping)
|
|
||||||
{
|
|
||||||
IsTyping = isTyping;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +1,28 @@
|
|||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||||
|
|
||||||
namespace Content.Shared.Chat.TypingIndicator;
|
namespace Content.Shared.Chat.TypingIndicator;
|
||||||
|
|
||||||
[RegisterComponent, NetworkedComponent]
|
/// <summary>
|
||||||
|
/// If an item is equipped to someones inventory (Anything but the pockets), and has this component
|
||||||
|
/// the users typing indicator will be replaced by the prototype given in <c>TypingIndicatorPrototype</c>.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent, NetworkedComponent, AutoGenerateComponentPause]
|
||||||
[Access(typeof(SharedTypingIndicatorSystem))]
|
[Access(typeof(SharedTypingIndicatorSystem))]
|
||||||
public sealed partial class TypingIndicatorClothingComponent : Component
|
public sealed partial class TypingIndicatorClothingComponent : Component
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The typing indicator that will override the default typing indicator when the item is equipped to a users
|
||||||
|
/// inventory.
|
||||||
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
[DataField("proto", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<TypingIndicatorPrototype>))]
|
[DataField("proto", required: true)]
|
||||||
public string Prototype = default!;
|
public ProtoId<TypingIndicatorPrototype> TypingIndicatorPrototype = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This stores the time the item was equipped in someones inventory. If null, item is currently not equipped.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoPausedField]
|
||||||
|
public TimeSpan? GotEquippedTime = null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Shared.Chat.TypingIndicator;
|
namespace Content.Shared.Chat.TypingIndicator;
|
||||||
|
|
||||||
@@ -14,7 +14,6 @@ public sealed partial class TypingIndicatorComponent : Component
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Prototype id that store all visual info about typing indicator.
|
/// Prototype id that store all visual info about typing indicator.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[DataField("proto")]
|
||||||
[DataField("proto", customTypeSerializer: typeof(PrototypeIdSerializer<TypingIndicatorPrototype>))]
|
public ProtoId<TypingIndicatorPrototype> TypingIndicatorPrototype = "default";
|
||||||
public string Prototype = SharedTypingIndicatorSystem.InitialIndicatorId;
|
|
||||||
}
|
}
|
||||||
|
|||||||
60
Content.Shared/Chat/TypingIndicator/TypingIndicatorEvents.cs
Normal file
60
Content.Shared/Chat/TypingIndicator/TypingIndicatorEvents.cs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using Content.Shared.Inventory;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Serialization.Manager.Exceptions;
|
||||||
|
|
||||||
|
namespace Content.Shared.Chat.TypingIndicator;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Networked event from client.
|
||||||
|
/// Send to server when client started/stopped typing in chat input field.
|
||||||
|
/// </summary>
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class TypingChangedEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
public readonly bool IsTyping;
|
||||||
|
|
||||||
|
public TypingChangedEvent(bool isTyping)
|
||||||
|
{
|
||||||
|
IsTyping = isTyping;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This event will be broadcast right before displaying an entities typing indicator.
|
||||||
|
/// If _overrideIndicator is not null after the event is finished it will be used.
|
||||||
|
/// </summary>
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class BeforeShowTypingIndicatorEvent : IInventoryRelayEvent
|
||||||
|
{
|
||||||
|
public SlotFlags TargetSlots { get; } = SlotFlags.WITHOUT_POCKET;
|
||||||
|
|
||||||
|
private ProtoId<TypingIndicatorPrototype>? _overrideIndicator = null;
|
||||||
|
private TimeSpan? _latestEquipTime = null;
|
||||||
|
public BeforeShowTypingIndicatorEvent()
|
||||||
|
{
|
||||||
|
_overrideIndicator = null;
|
||||||
|
_latestEquipTime = null;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Will only update the time and indicator if the given time is more recent than
|
||||||
|
/// the stored time or if the stored time is null.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// True if the given time is more recent than the stored time, and false otherwise.
|
||||||
|
/// </returns>
|
||||||
|
public bool TryUpdateTimeAndIndicator(ProtoId<TypingIndicatorPrototype>? indicator, TimeSpan? equipTime)
|
||||||
|
{
|
||||||
|
if (equipTime != null && (_latestEquipTime == null || _latestEquipTime < equipTime))
|
||||||
|
{
|
||||||
|
_latestEquipTime = equipTime;
|
||||||
|
_overrideIndicator = indicator;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public ProtoId<TypingIndicatorPrototype>? GetMostRecentIndicator()
|
||||||
|
{
|
||||||
|
return _overrideIndicator;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user