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:
Pieter-Jan Briers
2022-08-07 08:00:42 +02:00
committed by GitHub
parent 6b94db0336
commit e852ada6c8
91 changed files with 5044 additions and 247 deletions

View File

@@ -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);

View File

@@ -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>();
}
}
}

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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()