SharedTypingIndicatorSystem.cs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. using Content.Shared.ActionBlocker;
  2. using Content.Shared.Clothing;
  3. using Content.Shared.Inventory;
  4. using Robust.Shared.Player;
  5. using Robust.Shared.Timing;
  6. namespace Content.Shared.Chat.TypingIndicator;
  7. /// <summary>
  8. /// Supports typing indicators on entities.
  9. /// </summary>
  10. public abstract class SharedTypingIndicatorSystem : EntitySystem
  11. {
  12. [Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
  13. [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
  14. [Dependency] private readonly IGameTiming _timing = default!;
  15. /// <summary>
  16. /// Default ID of <see cref="TypingIndicatorPrototype"/>
  17. /// </summary>
  18. [ValidatePrototypeId<TypingIndicatorPrototype>]
  19. public const string InitialIndicatorId = "default";
  20. public override void Initialize()
  21. {
  22. base.Initialize();
  23. SubscribeLocalEvent<PlayerAttachedEvent>(OnPlayerAttached);
  24. SubscribeLocalEvent<TypingIndicatorComponent, PlayerDetachedEvent>(OnPlayerDetached);
  25. SubscribeLocalEvent<TypingIndicatorClothingComponent, ClothingGotEquippedEvent>(OnGotEquipped);
  26. SubscribeLocalEvent<TypingIndicatorClothingComponent, ClothingGotUnequippedEvent>(OnGotUnequipped);
  27. SubscribeLocalEvent<TypingIndicatorClothingComponent, InventoryRelayedEvent<BeforeShowTypingIndicatorEvent>>(BeforeShow);
  28. SubscribeAllEvent<TypingChangedEvent>(OnTypingChanged);
  29. }
  30. private void OnPlayerAttached(PlayerAttachedEvent ev)
  31. {
  32. // when player poses entity we want to make sure that there is typing indicator
  33. EnsureComp<TypingIndicatorComponent>(ev.Entity);
  34. // we also need appearance component to sync visual state
  35. EnsureComp<AppearanceComponent>(ev.Entity);
  36. }
  37. private void OnPlayerDetached(EntityUid uid, TypingIndicatorComponent component, PlayerDetachedEvent args)
  38. {
  39. // player left entity body - hide typing indicator
  40. SetTypingIndicatorEnabled(uid, false);
  41. }
  42. private void OnGotEquipped(Entity<TypingIndicatorClothingComponent> entity, ref ClothingGotEquippedEvent args)
  43. {
  44. entity.Comp.GotEquippedTime = _timing.CurTime;
  45. }
  46. private void OnGotUnequipped(Entity<TypingIndicatorClothingComponent> entity, ref ClothingGotUnequippedEvent args)
  47. {
  48. entity.Comp.GotEquippedTime = null;
  49. }
  50. private void BeforeShow(Entity<TypingIndicatorClothingComponent> entity, ref InventoryRelayedEvent<BeforeShowTypingIndicatorEvent> args)
  51. {
  52. args.Args.TryUpdateTimeAndIndicator(entity.Comp.TypingIndicatorPrototype, entity.Comp.GotEquippedTime);
  53. }
  54. private void OnTypingChanged(TypingChangedEvent ev, EntitySessionEventArgs args)
  55. {
  56. var uid = args.SenderSession.AttachedEntity;
  57. if (!Exists(uid))
  58. {
  59. Log.Warning($"Client {args.SenderSession} sent TypingChangedEvent without an attached entity.");
  60. return;
  61. }
  62. // check if this entity can speak or emote
  63. if (!_actionBlocker.CanEmote(uid.Value) && !_actionBlocker.CanSpeak(uid.Value))
  64. {
  65. // nah, make sure that typing indicator is disabled
  66. SetTypingIndicatorEnabled(uid.Value, false);
  67. return;
  68. }
  69. SetTypingIndicatorEnabled(uid.Value, ev.IsTyping);
  70. }
  71. private void SetTypingIndicatorEnabled(EntityUid uid, bool isEnabled, AppearanceComponent? appearance = null)
  72. {
  73. if (!Resolve(uid, ref appearance, false))
  74. return;
  75. _appearance.SetData(uid, TypingIndicatorVisuals.IsTyping, isEnabled, appearance);
  76. }
  77. }