Files
tbd-station-14/Content.Server/Administration/QuickDialogSystem.cs
Moony f98df73fae Adds even more smites and a bunch of tools. (#9825)
* Adds three new smites, headstand, locker stuff, and reptilian species swap.

* Localize all the smites.

* save work

* More smites...

* Final tweaks.

* oops

* !PLEH

* Adds disarm prone and improved hand removal options.

* fix chances.

* take out the trash.

* Add some admin TRICKS instead of more smites.

* oop

* Implements the admin test arena and associated trick.

* Tricks for granting/revoking access.

* e

* mfw

* Implement quick dialogs, for when you don't want to spend 20 minutes writing a simple dialog prompt.

* Forgot the rejuv icon.

* E

* docs

* augh

* Add rename/redescribe buttons.

* Adds objects menu, implements a couple tricks for stations.

* 1984

* Adds a trick for effectively infinite power.

* fixes some icon uggo.

* a

* HALT!

* Pause/unpause buttons.

* Forgor the textures.

* they broke every bone in their body.

* i added more

* more battery actions, touch up battery icon.

* Address reviews.
2022-07-21 17:30:00 -05:00

177 lines
5.7 KiB
C#

using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using Content.Shared.Administration;
using Robust.Server.Player;
using Robust.Shared.Enums;
using Robust.Shared.Network;
using Robust.Shared.Player;
namespace Content.Server.Administration;
/// <summary>
/// This handles the server portion of quick dialogs, including opening them.
/// </summary>
public sealed partial class QuickDialogSystem : EntitySystem
{
[Dependency] private readonly IPlayerManager _playerManager = default!;
/// <summary>
/// Contains the success/cancel actions for a dialog.
/// </summary>
private readonly Dictionary<int, (Action<QuickDialogResponseEvent> okAction, Action cancelAction)> _openDialogs = new();
private readonly Dictionary<NetUserId, List<int>> _openDialogsByUser = new();
private int _nextDialogId = 1;
/// <inheritdoc/>
public override void Initialize()
{
_playerManager.PlayerStatusChanged += PlayerManagerOnPlayerStatusChanged;
SubscribeNetworkEvent<QuickDialogResponseEvent>(Handler);
}
public override void Shutdown()
{
base.Shutdown();
_playerManager.PlayerStatusChanged -= PlayerManagerOnPlayerStatusChanged;
}
private void Handler(QuickDialogResponseEvent msg, EntitySessionEventArgs args)
{
if (!_openDialogs.ContainsKey(msg.DialogId) || !_openDialogsByUser[args.SenderSession.UserId].Contains(msg.DialogId))
{
args.SenderSession.ConnectedClient.Disconnect($"Replied with invalid quick dialog data with id {msg.DialogId}.");
return;
}
switch (msg.ButtonPressed)
{
case QuickDialogButtonFlag.OkButton:
_openDialogs[msg.DialogId].okAction.Invoke(msg);
break;
case QuickDialogButtonFlag.CancelButton:
_openDialogs[msg.DialogId].cancelAction.Invoke();
break;
default:
throw new ArgumentOutOfRangeException();
}
_openDialogs.Remove(msg.DialogId);
_openDialogsByUser[args.SenderSession.UserId].Remove(msg.DialogId);
}
private int GetDialogId()
{
return _nextDialogId++;
}
private void PlayerManagerOnPlayerStatusChanged(object? sender, SessionStatusEventArgs e)
{
if (e.NewStatus != SessionStatus.Disconnected && e.NewStatus != SessionStatus.Zombie)
return;
var user = e.Session.UserId;
if (!_openDialogsByUser.ContainsKey(user))
return;
foreach (var dialogId in _openDialogsByUser[user])
{
_openDialogs[dialogId].cancelAction.Invoke();
_openDialogs.Remove(dialogId);
}
_openDialogsByUser.Remove(user);
}
private void OpenDialogInternal(IPlayerSession session, string title, List<QuickDialogEntry> entries, QuickDialogButtonFlag buttons, Action<QuickDialogResponseEvent> okAction, Action cancelAction)
{
var did = GetDialogId();
RaiseNetworkEvent(
new QuickDialogOpenEvent(
title,
entries,
did,
buttons),
Filter.SinglePlayer(session)
);
_openDialogs.Add(did, (okAction, cancelAction));
if (!_openDialogsByUser.ContainsKey(session.UserId))
_openDialogsByUser.Add(session.UserId, new List<int>());
_openDialogsByUser[session.UserId].Add(did);
}
private bool TryParseQuickDialog<T>(QuickDialogEntryType entryType, string input, [NotNullWhen(true)] out T? output)
{
switch (entryType)
{
case QuickDialogEntryType.Integer:
{
var result = int.TryParse(input, out var val);
output = (T?) (object?) val;
return result;
}
case QuickDialogEntryType.Float:
{
var result = float.TryParse(input, out var val);
output = (T?) (object?) val;
return result;
}
case QuickDialogEntryType.ShortText:
{
if (input.Length > 100)
{
output = default;
return false;
}
output = (T?) (object?) input;
return output is not null;
}
case QuickDialogEntryType.LongText:
{
if (input.Length > 2000)
{
output = default;
return false;
}
output = (T?) (object?) input;
return output is not null;
}
default:
throw new ArgumentOutOfRangeException(nameof(entryType), entryType, null);
}
}
private QuickDialogEntryType TypeToEntryType(Type T)
{
if (T == typeof(int) || T == typeof(uint) || T == typeof(long) || T == typeof(ulong))
{
return QuickDialogEntryType.Integer;
}
else if (T == typeof(float) || T == typeof(double))
{
return QuickDialogEntryType.Float;
}
else if (T == typeof(string)) // People are more likely to notice the input box is too short than they are to notice it's too long.
{
return QuickDialogEntryType.ShortText;
} else if (T == typeof(LongString))
{
return QuickDialogEntryType.LongText;
}
throw new ArgumentException($"Tried to open a dialog with unsupported type {T}.");
}
}
/// <summary>
/// A type used with quick dialogs to indicate you want a large entry window for text and not a short one.
/// </summary>
/// <param name="String">The string retrieved.</param>
public record struct LongString(string String);