Play time tracking: Job timers 3: more titles: when the (#9978)
Co-authored-by: Veritius <veritiusgaming@gmail.com> Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
This commit is contained in:
committed by
GitHub
parent
6b94db0336
commit
e852ada6c8
@@ -17,6 +17,7 @@ using Content.Client.MainMenu;
|
||||
using Content.Client.MobState.Overlays;
|
||||
using Content.Client.Parallax;
|
||||
using Content.Client.Parallax.Managers;
|
||||
using Content.Client.Players.PlayTimeTracking;
|
||||
using Content.Client.Preferences;
|
||||
using Content.Client.Radiation;
|
||||
using Content.Client.Sandbox;
|
||||
@@ -125,6 +126,7 @@ namespace Content.Client.Entry
|
||||
IoCManager.Resolve<ViewportManager>().Initialize();
|
||||
IoCManager.Resolve<GhostKickManager>().Initialize();
|
||||
IoCManager.Resolve<ExtendedDisconnectInformationManager>().Initialize();
|
||||
IoCManager.Resolve<PlayTimeTrackingManager>().Initialize();
|
||||
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ using Content.Client.Items.Managers;
|
||||
using Content.Client.Launcher;
|
||||
using Content.Client.Module;
|
||||
using Content.Client.Parallax.Managers;
|
||||
using Content.Client.Players.PlayTimeTracking;
|
||||
using Content.Client.Preferences;
|
||||
using Content.Client.Screenshot;
|
||||
using Content.Client.Stylesheets;
|
||||
@@ -47,6 +48,7 @@ namespace Content.Client.IoC
|
||||
IoCManager.Register<ISharedAdminLogManager, SharedAdminLogManager>();
|
||||
IoCManager.Register<GhostKickManager>();
|
||||
IoCManager.Register<ExtendedDisconnectInformationManager>();
|
||||
IoCManager.Register<PlayTimeTrackingManager>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,54 +134,61 @@ namespace Content.Client.LateJoin
|
||||
|
||||
var firstCategory = true;
|
||||
|
||||
foreach (var job in gameTicker.JobsAvailable[id].OrderBy(x => x.Key))
|
||||
foreach (var department in _prototypeManager.EnumeratePrototypes<DepartmentPrototype>())
|
||||
{
|
||||
var prototype = _prototypeManager.Index<JobPrototype>(job.Key);
|
||||
foreach (var department in prototype.Departments)
|
||||
var departmentName = Loc.GetString($"department-{department.ID}");
|
||||
_jobCategories[id] = new Dictionary<string, BoxContainer>();
|
||||
_jobButtons[id] = new Dictionary<string, JobButton>();
|
||||
var stationAvailable = gameTicker.JobsAvailable[id];
|
||||
|
||||
var category = new BoxContainer
|
||||
{
|
||||
if (!_jobCategories.TryGetValue(id, out var _))
|
||||
_jobCategories[id] = new Dictionary<string, BoxContainer>();
|
||||
if (!_jobButtons.TryGetValue(id, out var _))
|
||||
_jobButtons[id] = new Dictionary<string, JobButton>();
|
||||
if (!_jobCategories[id].TryGetValue(department, out var category))
|
||||
Orientation = LayoutOrientation.Vertical,
|
||||
Name = department.ID,
|
||||
ToolTip = Loc.GetString("late-join-gui-jobs-amount-in-department-tooltip",
|
||||
("departmentName", departmentName))
|
||||
};
|
||||
|
||||
if (firstCategory)
|
||||
{
|
||||
firstCategory = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
category.AddChild(new Control
|
||||
{
|
||||
category = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical,
|
||||
Name = department,
|
||||
ToolTip = Loc.GetString("late-join-gui-jobs-amount-in-department-tooltip",
|
||||
("departmentName", department))
|
||||
};
|
||||
MinSize = new Vector2(0, 23),
|
||||
});
|
||||
}
|
||||
|
||||
if (firstCategory)
|
||||
category.AddChild(new PanelContainer
|
||||
{
|
||||
Children =
|
||||
{
|
||||
new Label
|
||||
{
|
||||
firstCategory = false;
|
||||
StyleClasses = { "LabelBig" },
|
||||
Text = Loc.GetString("late-join-gui-department-jobs-label", ("departmentName", departmentName))
|
||||
}
|
||||
else
|
||||
{
|
||||
category.AddChild(new Control
|
||||
{
|
||||
MinSize = new Vector2(0, 23),
|
||||
});
|
||||
}
|
||||
|
||||
category.AddChild(new PanelContainer
|
||||
{
|
||||
Children =
|
||||
{
|
||||
new Label
|
||||
{
|
||||
StyleClasses = { "LabelBig" },
|
||||
Text = Loc.GetString("late-join-gui-department-jobs-label", ("departmentName", department))
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
_jobCategories[id][department] = category;
|
||||
jobList.AddChild(category);
|
||||
}
|
||||
});
|
||||
|
||||
var jobButton = new JobButton(prototype.ID, job.Value);
|
||||
_jobCategories[id][department.ID] = category;
|
||||
jobList.AddChild(category);
|
||||
var jobsAvailable = new List<JobPrototype>();
|
||||
|
||||
foreach (var jobId in department.Roles)
|
||||
{
|
||||
if (!stationAvailable.ContainsKey(jobId)) continue;
|
||||
jobsAvailable.Add(_prototypeManager.Index<JobPrototype>(jobId));
|
||||
}
|
||||
|
||||
jobsAvailable.Sort((x, y) => -string.Compare(x.LocalizedName, y.LocalizedName, StringComparison.CurrentCultureIgnoreCase));
|
||||
|
||||
foreach (var prototype in jobsAvailable)
|
||||
{
|
||||
var value = stationAvailable[prototype.ID];
|
||||
var jobButton = new JobButton(prototype.ID, value);
|
||||
|
||||
var jobSelector = new BoxContainer
|
||||
{
|
||||
@@ -205,8 +212,8 @@ namespace Content.Client.LateJoin
|
||||
|
||||
var jobLabel = new Label
|
||||
{
|
||||
Text = job.Value != null ?
|
||||
Loc.GetString("late-join-gui-job-slot-capped", ("jobName", prototype.LocalizedName), ("amount", job.Value)) :
|
||||
Text = value != null ?
|
||||
Loc.GetString("late-join-gui-job-slot-capped", ("jobName", prototype.LocalizedName), ("amount", value)) :
|
||||
Loc.GetString("late-join-gui-job-slot-uncapped", ("jobName", prototype.LocalizedName))
|
||||
};
|
||||
|
||||
@@ -219,7 +226,7 @@ namespace Content.Client.LateJoin
|
||||
SelectedId?.Invoke((id, jobButton.JobId));
|
||||
};
|
||||
|
||||
if (job.Value == 0)
|
||||
if (value == 0)
|
||||
{
|
||||
jobButton.Disabled = true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
using Content.Shared.CCVar;
|
||||
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.Prototypes;
|
||||
|
||||
namespace Content.Client.Players.PlayTimeTracking;
|
||||
|
||||
public sealed class PlayTimeTrackingManager
|
||||
{
|
||||
[Dependency] private readonly IBaseClient _client = default!;
|
||||
[Dependency] private readonly IClientNetManager _net = default!;
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypes = default!;
|
||||
|
||||
private readonly Dictionary<string, TimeSpan> _roles = new();
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_net.RegisterNetMessage<MsgPlayTime>(RxPlayTime);
|
||||
|
||||
_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 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}");
|
||||
}*/
|
||||
}
|
||||
|
||||
public bool IsAllowed(JobPrototype job, [NotNullWhen(false)] out string? reason)
|
||||
{
|
||||
reason = null;
|
||||
|
||||
if (job.Requirements == null ||
|
||||
!_cfg.GetCVar(CCVars.GameRoleTimers))
|
||||
return true;
|
||||
|
||||
var player = _playerManager.LocalPlayer?.Session;
|
||||
|
||||
if (player == null) return true;
|
||||
|
||||
var roles = _roles;
|
||||
var reasonBuilder = new StringBuilder();
|
||||
|
||||
var first = true;
|
||||
foreach (var requirement in job.Requirements)
|
||||
{
|
||||
if (JobRequirements.TryRequirementMet(requirement, roles, out reason, _prototypes))
|
||||
continue;
|
||||
|
||||
if (!first)
|
||||
reasonBuilder.Append('\n');
|
||||
first = false;
|
||||
|
||||
reasonBuilder.AppendLine(reason);
|
||||
}
|
||||
|
||||
reason = reasonBuilder.Length == 0 ? null : reasonBuilder.ToString();
|
||||
return reason == null;
|
||||
}
|
||||
}
|
||||
@@ -235,7 +235,7 @@ namespace Content.Client.Preferences.UI
|
||||
if (!disposing)
|
||||
return;
|
||||
|
||||
IoCManager.Resolve<IEntityManager>().DeleteEntity((EntityUid) _previewDummy);
|
||||
IoCManager.Resolve<IEntityManager>().DeleteEntity(_previewDummy);
|
||||
_previewDummy = default;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,10 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Client.CharacterAppearance;
|
||||
using Content.Client.HUD.UI;
|
||||
using Content.Client.Lobby.UI;
|
||||
using Content.Client.Message;
|
||||
using Content.Client.Players.PlayTimeTracking;
|
||||
using Content.Client.Stylesheets;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.CharacterAppearance;
|
||||
@@ -341,56 +343,65 @@ namespace Content.Client.Preferences.UI
|
||||
|
||||
_jobPriorities = new List<JobPrioritySelector>();
|
||||
_jobCategories = new Dictionary<string, BoxContainer>();
|
||||
var spriteSystem = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<SpriteSystem>();
|
||||
|
||||
var firstCategory = true;
|
||||
var playTime = IoCManager.Resolve<PlayTimeTrackingManager>();
|
||||
|
||||
foreach (var job in prototypeManager.EnumeratePrototypes<JobPrototype>().OrderBy(j => j.LocalizedName))
|
||||
foreach (var department in _prototypeManager.EnumeratePrototypes<DepartmentPrototype>())
|
||||
{
|
||||
if(!job.SetPreference) { continue; }
|
||||
var departmentName = Loc.GetString($"department-{department.ID}");
|
||||
|
||||
foreach (var department in job.Departments)
|
||||
if (!_jobCategories.TryGetValue(department.ID, out var category))
|
||||
{
|
||||
if (!_jobCategories.TryGetValue(department, out var category))
|
||||
category = new BoxContainer
|
||||
{
|
||||
category = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical,
|
||||
Name = department,
|
||||
ToolTip = Loc.GetString("humanoid-profile-editor-jobs-amount-in-department-tooltip",
|
||||
("departmentName", department))
|
||||
};
|
||||
Orientation = LayoutOrientation.Vertical,
|
||||
Name = department.ID,
|
||||
ToolTip = Loc.GetString("humanoid-profile-editor-jobs-amount-in-department-tooltip",
|
||||
("departmentName", departmentName))
|
||||
};
|
||||
|
||||
if (firstCategory)
|
||||
{
|
||||
firstCategory = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
category.AddChild(new Control
|
||||
{
|
||||
MinSize = new Vector2(0, 23),
|
||||
});
|
||||
}
|
||||
|
||||
category.AddChild(new PanelContainer
|
||||
if (firstCategory)
|
||||
{
|
||||
firstCategory = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
category.AddChild(new Control
|
||||
{
|
||||
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.FromHex("#464966")},
|
||||
Children =
|
||||
{
|
||||
new Label
|
||||
{
|
||||
Text = Loc.GetString("humanoid-profile-editor-department-jobs-label",
|
||||
("departmentName" ,department))
|
||||
}
|
||||
}
|
||||
MinSize = new Vector2(0, 23),
|
||||
});
|
||||
|
||||
_jobCategories[department] = category;
|
||||
_jobList.AddChild(category);
|
||||
}
|
||||
|
||||
var selector = new JobPrioritySelector(job, spriteSystem);
|
||||
category.AddChild(new PanelContainer
|
||||
{
|
||||
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.FromHex("#464966")},
|
||||
Children =
|
||||
{
|
||||
new Label
|
||||
{
|
||||
Text = Loc.GetString("humanoid-profile-editor-department-jobs-label",
|
||||
("departmentName", departmentName))
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
_jobCategories[department.ID] = category;
|
||||
_jobList.AddChild(category);
|
||||
}
|
||||
|
||||
var jobs = department.Roles.Select(o => _prototypeManager.Index<JobPrototype>(o)).Where(o => o.SetPreference).ToList();
|
||||
jobs.Sort((x, y) => -string.Compare(x.LocalizedName, y.LocalizedName, StringComparison.CurrentCultureIgnoreCase));
|
||||
|
||||
foreach (var job in jobs)
|
||||
{
|
||||
var selector = new JobPrioritySelector(job);
|
||||
|
||||
if (!playTime.IsAllowed(job, out var reason))
|
||||
{
|
||||
selector.LockRequirements(reason);
|
||||
}
|
||||
|
||||
category.AddChild(selector);
|
||||
_jobPriorities.Add(selector);
|
||||
|
||||
@@ -418,6 +429,7 @@ namespace Content.Client.Preferences.UI
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -992,7 +1004,10 @@ namespace Content.Client.Preferences.UI
|
||||
|
||||
public event Action<JobPriority>? PriorityChanged;
|
||||
|
||||
public JobPrioritySelector(JobPrototype job, SpriteSystem sprites)
|
||||
private StripeBack _lockStripe;
|
||||
private Label _requirementsLabel;
|
||||
|
||||
public JobPrioritySelector(JobPrototype job)
|
||||
{
|
||||
Job = job;
|
||||
|
||||
@@ -1021,9 +1036,32 @@ namespace Content.Client.Preferences.UI
|
||||
Stretch = TextureRect.StretchMode.KeepCentered
|
||||
};
|
||||
|
||||
var specifier = new SpriteSpecifier.Rsi(new ResourcePath("/Textures/Interface/Misc/job_icons.rsi"),
|
||||
job.Icon);
|
||||
icon.Texture = sprites.Frame0(specifier);
|
||||
if (job.Icon != null)
|
||||
{
|
||||
var specifier = new SpriteSpecifier.Rsi(new ResourcePath("/Textures/Interface/Misc/job_icons.rsi"),
|
||||
job.Icon);
|
||||
icon.Texture = specifier.Frame0();
|
||||
}
|
||||
|
||||
_requirementsLabel = new Label()
|
||||
{
|
||||
Text = Loc.GetString("role-timer-locked"),
|
||||
Visible = true,
|
||||
HorizontalAlignment = HAlignment.Center,
|
||||
StyleClasses = {StyleBase.StyleClassLabelSubText},
|
||||
};
|
||||
|
||||
_lockStripe = new StripeBack()
|
||||
{
|
||||
Visible = false,
|
||||
HorizontalExpand = true,
|
||||
TooltipDelay = 0.2f,
|
||||
MouseFilter = MouseFilterMode.Stop,
|
||||
Children =
|
||||
{
|
||||
_requirementsLabel
|
||||
}
|
||||
};
|
||||
|
||||
AddChild(new BoxContainer
|
||||
{
|
||||
@@ -1032,10 +1070,26 @@ namespace Content.Client.Preferences.UI
|
||||
{
|
||||
icon,
|
||||
new Label {Text = job.LocalizedName, MinSize = (175, 0)},
|
||||
_optionButton
|
||||
_optionButton,
|
||||
_lockStripe,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void LockRequirements(string requirements)
|
||||
{
|
||||
_lockStripe.ToolTip = requirements;
|
||||
_lockStripe.Visible = true;
|
||||
_optionButton.Visible = false;
|
||||
}
|
||||
|
||||
// TODO: Subscribe to roletimers event. I am too lazy to do this RN But I doubt most people will notice fn
|
||||
public void UnlockRequirements()
|
||||
{
|
||||
_requirementsLabel.Visible = false;
|
||||
_lockStripe.Visible = false;
|
||||
_optionButton.Visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateAntagPreferences()
|
||||
|
||||
Reference in New Issue
Block a user