#nullable enable using Content.Client.UserInterface.Systems.Bwoink; using Content.Shared.Administration; using JetBrains.Annotations; using Robust.Client.Audio; using Robust.Shared.Network; using Robust.Shared.Player; using Robust.Shared.Timing; namespace Content.Client.Administration.Systems { [UsedImplicitly] public sealed class BwoinkSystem : SharedBwoinkSystem { [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly AudioSystem _audio = default!; [Dependency] private readonly AdminSystem _adminSystem = default!; public event EventHandler? OnBwoinkTextMessageRecieved; private (TimeSpan Timestamp, bool Typing) _lastTypingUpdateSent; protected override void OnBwoinkTextMessage(BwoinkTextMessage message, EntitySessionEventArgs eventArgs) { OnBwoinkTextMessageRecieved?.Invoke(this, message); } public void Send(NetUserId channelId, string text, bool playSound) { var info = _adminSystem.PlayerInfos.GetValueOrDefault(channelId)?.Connected ?? true; _audio.PlayGlobal(info ? AHelpUIController.AHelpSendSound : AHelpUIController.AHelpErrorSound, Filter.Local(), false); // Reuse the channel ID as the 'true sender'. // Server will ignore this and if someone makes it not ignore this (which is bad, allows impersonation!!!), that will help. RaiseNetworkEvent(new BwoinkTextMessage(channelId, channelId, text, playSound: playSound)); SendInputTextUpdated(channelId, false); } public void SendInputTextUpdated(NetUserId channel, bool typing) { if (_lastTypingUpdateSent.Typing == typing && _lastTypingUpdateSent.Timestamp + TimeSpan.FromSeconds(1) > _timing.RealTime) return; _lastTypingUpdateSent = (_timing.RealTime, typing); RaiseNetworkEvent(new BwoinkClientTypingUpdated(channel, typing)); } } }