196 lines
6.3 KiB
C#
196 lines
6.3 KiB
C#
using System.Diagnostics.CodeAnalysis;
|
||
using Content.Client.Lobby;
|
||
using Content.Shared.CCVar;
|
||
using Content.Shared.Players;
|
||
using Content.Shared.Players.JobWhitelist;
|
||
using Content.Shared.Players.PlayTimeTracking;
|
||
using Content.Shared.Roles;
|
||
using Robust.Client;
|
||
using Robust.Client.Player;
|
||
using Robust.Shared.Configuration;
|
||
using Robust.Shared.Network;
|
||
using Robust.Shared.Player;
|
||
using Robust.Shared.Prototypes;
|
||
using Robust.Shared.Utility;
|
||
using Content.Shared.Preferences;
|
||
|
||
namespace Content.Client.Players.PlayTimeTracking;
|
||
|
||
public sealed class JobRequirementsManager : ISharedPlaytimeManager
|
||
{
|
||
[Dependency] private readonly IBaseClient _client = default!;
|
||
[Dependency] private readonly IClientNetManager _net = default!;
|
||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||
[Dependency] private readonly IPrototypeManager _prototypes = default!;
|
||
[Dependency] private readonly IClientPreferencesManager _clientPreferences = default!;
|
||
|
||
private readonly Dictionary<string, TimeSpan> _roles = new();
|
||
private readonly List<string> _roleBans = new();
|
||
private readonly List<string> _jobWhitelists = new();
|
||
|
||
private ISawmill _sawmill = default!;
|
||
|
||
public event Action? Updated;
|
||
|
||
public void Initialize()
|
||
{
|
||
_sawmill = Logger.GetSawmill("job_requirements");
|
||
|
||
// Yeah the client manager handles role bans and playtime but the server ones are separate DEAL.
|
||
_net.RegisterNetMessage<MsgRoleBans>(RxRoleBans);
|
||
_net.RegisterNetMessage<MsgPlayTime>(RxPlayTime);
|
||
_net.RegisterNetMessage<MsgJobWhitelist>(RxJobWhitelist);
|
||
|
||
_client.RunLevelChanged += ClientOnRunLevelChanged;
|
||
}
|
||
|
||
private void ClientOnRunLevelChanged(object? sender, RunLevelChangedEventArgs e)
|
||
{
|
||
if (e.NewLevel == ClientRunLevel.Initialize)
|
||
{
|
||
// Reset on disconnect, just in case.
|
||
_roles.Clear();
|
||
}
|
||
}
|
||
|
||
private void RxRoleBans(MsgRoleBans message)
|
||
{
|
||
_sawmill.Debug($"Received roleban info containing {message.Bans.Count} entries.");
|
||
|
||
if (_roleBans.Equals(message.Bans))
|
||
return;
|
||
|
||
_roleBans.Clear();
|
||
_roleBans.AddRange(message.Bans);
|
||
Updated?.Invoke();
|
||
}
|
||
|
||
private void RxPlayTime(MsgPlayTime message)
|
||
{
|
||
_roles.Clear();
|
||
|
||
// NOTE: do not assign _roles = message.Trackers due to implicit data sharing in integration tests.
|
||
foreach (var (tracker, time) in message.Trackers)
|
||
{
|
||
_roles[tracker] = time;
|
||
}
|
||
|
||
/*var sawmill = Logger.GetSawmill("play_time");
|
||
foreach (var (tracker, time) in _roles)
|
||
{
|
||
sawmill.Info($"{tracker}: {time}");
|
||
}*/
|
||
Updated?.Invoke();
|
||
}
|
||
|
||
private void RxJobWhitelist(MsgJobWhitelist message)
|
||
{
|
||
_jobWhitelists.Clear();
|
||
_jobWhitelists.AddRange(message.Whitelist);
|
||
Updated?.Invoke();
|
||
}
|
||
|
||
public bool IsAllowed(JobPrototype job, [NotNullWhen(false)] out FormattedMessage? reason)
|
||
{
|
||
reason = null;
|
||
|
||
if (_roleBans.Contains($"Job:{job.ID}"))
|
||
{
|
||
reason = FormattedMessage.FromUnformatted(Loc.GetString("role-ban"));
|
||
return false;
|
||
}
|
||
|
||
if (!CheckWhitelist(job, out reason))
|
||
return false;
|
||
|
||
var player = _playerManager.LocalSession;
|
||
if (player == null)
|
||
return true;
|
||
|
||
// Sunrise-Start
|
||
if (_clientPreferences.Preferences != null)
|
||
{
|
||
var profile = (HumanoidCharacterProfile) _clientPreferences.Preferences.SelectedCharacter;
|
||
|
||
if (job.SpeciesBlacklist.Contains(profile.Species))
|
||
{
|
||
reason = FormattedMessage.FromUnformatted($"Расса {Loc.GetString($"species-name-{profile.Species.Id.ToLower()}")} не может занимать эту должность. Для спонсоров ограничений нет");
|
||
return false;
|
||
}
|
||
}
|
||
// Sunrise-End
|
||
|
||
return CheckRoleTime(job, out reason);
|
||
}
|
||
|
||
public bool CheckRoleTime(JobPrototype job, [NotNullWhen(false)] out FormattedMessage? reason)
|
||
{
|
||
var reqs = _entManager.System<SharedRoleSystem>().GetJobRequirement(job);
|
||
return CheckRoleTime(reqs, out reason);
|
||
}
|
||
|
||
public bool CheckRoleTime(HashSet<JobRequirement>? requirements, [NotNullWhen(false)] out FormattedMessage? reason)
|
||
{
|
||
reason = null;
|
||
|
||
if (requirements == null || !_cfg.GetCVar(CCVars.GameRoleTimers))
|
||
return true;
|
||
|
||
var reasons = new List<string>();
|
||
foreach (var requirement in requirements)
|
||
{
|
||
if (JobRequirements.TryRequirementMet(requirement, _roles, out var jobReason, _entManager, _prototypes))
|
||
continue;
|
||
|
||
reasons.Add(jobReason.ToMarkup());
|
||
}
|
||
|
||
reason = reasons.Count == 0 ? null : FormattedMessage.FromMarkup(string.Join('\n', reasons));
|
||
return reason == null;
|
||
}
|
||
|
||
public bool CheckWhitelist(JobPrototype job, [NotNullWhen(false)] out FormattedMessage? reason)
|
||
{
|
||
reason = default;
|
||
if (!_cfg.GetCVar(CCVars.GameRoleWhitelist))
|
||
return true;
|
||
|
||
if (job.Whitelisted && !_jobWhitelists.Contains(job.ID))
|
||
{
|
||
reason = FormattedMessage.FromUnformatted(Loc.GetString("role-not-whitelisted"));
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
public TimeSpan FetchOverallPlaytime()
|
||
{
|
||
return _roles.TryGetValue("Overall", out var overallPlaytime) ? overallPlaytime : TimeSpan.Zero;
|
||
}
|
||
|
||
public IEnumerable<KeyValuePair<string, TimeSpan>> FetchPlaytimeByRoles()
|
||
{
|
||
var jobsToMap = _prototypes.EnumeratePrototypes<JobPrototype>();
|
||
|
||
foreach (var job in jobsToMap)
|
||
{
|
||
if (_roles.TryGetValue(job.PlayTimeTracker, out var locJobName))
|
||
{
|
||
yield return new KeyValuePair<string, TimeSpan>(job.Name, locJobName);
|
||
}
|
||
}
|
||
}
|
||
|
||
public IReadOnlyDictionary<string, TimeSpan> GetPlayTimes(ICommonSession session)
|
||
{
|
||
if (session != _playerManager.LocalSession)
|
||
{
|
||
return new Dictionary<string, TimeSpan>();
|
||
}
|
||
|
||
return _roles;
|
||
}
|
||
}
|