CatStation/Content.Server/Corvax/Api/AHelp/AHelpBotCommandSystem.cs
2026-07-18 13:04:31 +07:00

199 lines
7.6 KiB
C#

using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Server.Administration.Systems;
using Content.Server.GameTicking;
using Content.Shared.GameTicking;
using Content.Shared.Mind;
using Content.Shared.Objectives.Systems;
using Content.Shared.Roles;
using Robust.Server.Player;
using Robust.Shared.Enums;
using Robust.Shared.Network;
using Robust.Shared.Player;
using Robust.Shared.Utility;
namespace Content.Server.Corvax.Api.AHelp;
public sealed partial class AHelpBotCommandSystem : EntitySystem
{
[Dependency] private IPlayerManager _playerManager = default!;
[Dependency] private BwoinkSystem _bwoinkSystem = default!;
[Dependency] private GameTicker _gameTicker = default!;
[Dependency] private SharedMindSystem _minds = default!;
[Dependency] private SharedObjectivesSystem _objectives = default!;
[Dependency] private SharedRoleSystem _roles = default!;
internal AHelpApiCommandResponse ExecuteCommand(AHelpApiCommand command)
{
try
{
return command.Type switch
{
"list_players" => new AHelpApiCommandResponse(
command.CommandId,
true,
null,
Players: _playerManager.Sessions.OrderBy(session => session.Name).Select(BuildPlayerInfo).ToArray()),
"list_objectives" => HandleListObjectives(command),
"open_ahelp" => HandleOpenAHelp(command),
"send_ahelp_message" => HandleSendAHelpMessage(command),
_ => new AHelpApiCommandResponse(command.CommandId, false, $"Unsupported command type '{command.Type}'"),
};
}
catch (Exception e)
{
return new AHelpApiCommandResponse(command.CommandId, false, e.Message);
}
}
private AHelpApiCommandResponse HandleOpenAHelp(AHelpApiCommand command)
{
if (string.IsNullOrWhiteSpace(command.Ckey) || string.IsNullOrWhiteSpace(command.Text))
return new AHelpApiCommandResponse(command.CommandId, false, "ckey and text are required");
if (!TryGetSessionByCkey(command.Ckey, out var target))
return new AHelpApiCommandResponse(command.CommandId, false, $"Player '{command.Ckey}' not found");
RelayExternalMessageToAHelp(target.UserId, GetAuthorName(command), command.Text);
return new AHelpApiCommandResponse(
command.CommandId,
true,
UserId: target.UserId.ToString(),
Ckey: target.Name,
CharacterName: _minds.GetCharacterName(target.UserId));
}
private AHelpApiCommandResponse HandleSendAHelpMessage(AHelpApiCommand command)
{
if (string.IsNullOrWhiteSpace(command.Text))
return new AHelpApiCommandResponse(command.CommandId, false, "text is required");
if (!Guid.TryParse(command.ConversationId ?? command.UserId, out var userGuid))
return new AHelpApiCommandResponse(command.CommandId, false, "conversationId or userId must be a NetUserId guid");
var userId = new NetUserId(userGuid);
if (!_bwoinkSystem.CorvaxHasActiveAHelpConversation(userId) &&
!_playerManager.TryGetSessionById(userId, out _))
{
return new AHelpApiCommandResponse(command.CommandId, false, "AHelp conversation is not active");
}
RelayExternalMessageToAHelp(userId, GetAuthorName(command), command.Text);
return new AHelpApiCommandResponse(command.CommandId, true);
}
private AHelpApiCommandResponse HandleListObjectives(AHelpApiCommand command)
{
if (string.IsNullOrWhiteSpace(command.Ckey))
return new AHelpApiCommandResponse(command.CommandId, false, "ckey is required");
if (!TryGetSessionByCkey(command.Ckey, out var target))
return new AHelpApiCommandResponse(command.CommandId, false, $"Player '{command.Ckey}' not found");
if (!_minds.TryGetMind(target, out var mindId, out var mind))
return new AHelpApiCommandResponse(command.CommandId, false, $"Player '{target.Name}' does not have a mind");
var objectives = mind.Objectives
.Select((objective, index) =>
{
var info = _objectives.GetInfo(objective, mindId, mind);
return info == null
? new AHelpApiObjectiveInfo(index, objective.ToString(), null, null, 0, false)
: new AHelpApiObjectiveInfo(
index,
objective.ToString(),
info.Value.Title,
info.Value.Description,
(int) (info.Value.Progress * 100f),
true);
})
.ToArray();
return new AHelpApiCommandResponse(
command.CommandId,
true,
null,
UserId: target.UserId.ToString(),
Ckey: target.Name,
CharacterName: _minds.GetCharacterName(target.UserId),
Objectives: objectives);
}
private AHelpApiPlayerInfo BuildPlayerInfo(ICommonSession session)
{
string? characterName = null;
var job = "-";
var roleNames = new List<string>();
var antagonist = false;
var foundJob = false;
if (_minds.TryGetMind(session.UserId, out var mind))
{
characterName = mind.Value.Comp.CharacterName;
foreach (var role in _roles.MindGetAllRoleInfo((mind.Value.Owner, mind.Value.Comp)))
{
var roleName = Loc.GetString(role.Name);
if (!string.IsNullOrWhiteSpace(roleName))
roleNames.Add(roleName);
if (role.Antagonist)
{
antagonist = true;
}
else if (!foundJob && !string.IsNullOrWhiteSpace(roleName))
{
foundJob = true;
job = roleName;
}
}
}
return new AHelpApiPlayerInfo(
session.UserId.ToString(),
session.Name,
session.Status.ToString(),
characterName,
job,
roleNames.ToArray(),
antagonist);
}
private bool TryGetSessionByCkey(string ckey, [NotNullWhen(true)] out ICommonSession? session)
{
if (_playerManager.TryGetSessionByUsername(ckey, out session))
return true;
session = _playerManager.Sessions.FirstOrDefault(player =>
string.Equals(player.Name, ckey, StringComparison.OrdinalIgnoreCase));
return session != null;
}
private void RelayExternalMessageToAHelp(NetUserId userId, string authorName, string text)
{
var plainText = text.ReplaceLineEndings(" ");
_bwoinkSystem.CorvaxSendAHelpToGame(userId, BuildExternalBwoinkText(authorName, plainText));
_bwoinkSystem.CorvaxQueueAHelpWebhookMessage(userId, new AHelpMessageParams(
$"{authorName}[D]",
plainText,
true,
_gameTicker.RunLevel == GameRunLevel.InRound
? _gameTicker.RoundDuration().ToString("hh\\:mm\\:ss")
: string.Empty,
_gameTicker.RunLevel,
playedSound: true));
}
private static string GetAuthorName(AHelpApiCommand command)
{
return string.IsNullOrWhiteSpace(command.AuthorName)
? command.AuthorExternalId ?? "External"
: command.AuthorName;
}
private static string BuildExternalBwoinkText(string authorName, string text)
{
return $"[color=red]{FormattedMessage.EscapeText(authorName)} \\[D\\][/color]: {FormattedMessage.EscapeText(text)}";
}
}