From e6a294e9200525ac6cac09bfda8a8f959effaa01 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Sun, 18 Jan 2026 12:29:59 +0100 Subject: [PATCH] Improve settings loading performance --- PlayerSettings/CPlayerSettings.cs | 121 +++++++++++++++++++----------- PlayerSettings/Main.cs | 38 ++++++---- PlayerSettings/SettingsApi.cs | 83 ++++++++++---------- 3 files changed, 139 insertions(+), 103 deletions(-) diff --git a/PlayerSettings/CPlayerSettings.cs b/PlayerSettings/CPlayerSettings.cs index b235c9d..4f997b9 100644 --- a/PlayerSettings/CPlayerSettings.cs +++ b/PlayerSettings/CPlayerSettings.cs @@ -8,19 +8,28 @@ namespace PlayerSettings { - internal class CPlayerSettings - { - private int userid; - private CCSPlayerController player; - private Dictionary cached_values; - - public CPlayerSettings(CCSPlayerController _player) - { - player = _player; - userid = -1; - Storage.GetUserIdAsync(player, (userid) => this.userid = userid); - cached_values = new Dictionary(); - } + internal class CPlayerSettings + { + private int userid; + private CCSPlayerController player; + private Dictionary cached_values; + private readonly Dictionary pending_updates; + private readonly TaskCompletionSource userIdReady; + + public CPlayerSettings(CCSPlayerController _player) + { + player = _player; + userid = -1; + cached_values = new Dictionary(); + pending_updates = new Dictionary(); + userIdReady = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + Storage.GetUserIdAsync(player, (userid) => + { + this.userid = userid; + userIdReady.TrySetResult(userid); + FlushPendingUpdates(); + }); + } public string GetValue(string param, string default_value) { @@ -34,36 +43,58 @@ public string GetValue(string param, string default_value) return value; } - public void SetValue(string param, string value) - { - cached_values[param] = value; - Storage.SetUserSettingValue(userid, param, value); - } - - public int UserId() - { - return userid; - } - - public bool EqualPlayer(CCSPlayerController _player) - { - return player == _player; - } - - internal void ParseLoadedSettings(List> rows, List> actions) - { - Task.Run(() => - { - foreach (var row in rows) - { - cached_values[row[0]] = row[1]; - } - }).ContinueWith((_) => - { - foreach (var action in actions) - Server.NextFrameAsync(() => action(player)); - }); - } + public void SetValue(string param, string value) + { + cached_values[param] = value; + if (userid == -1) + { + pending_updates[param] = value; + return; + } + + Storage.SetUserSettingValue(userid, param, value); + } - } -} + public int UserId() + { + return userid; + } + + public Task WaitForUserIdAsync() + { + if (userid != -1) + return Task.FromResult(userid); + + return userIdReady.Task; + } + + public bool EqualPlayer(CCSPlayerController _player) + { + return player == _player; + } + + internal void ParseLoadedSettings(List> rows, List> actions) + { + foreach (var row in rows) + { + cached_values[row[0]] = row[1]; + } + + var actionsSnapshot = actions.ToArray(); + foreach (var action in actionsSnapshot) + Server.NextFrameAsync(() => action(player)); + } + + private void FlushPendingUpdates() + { + if (pending_updates.Count == 0) + return; + + foreach (var entry in pending_updates) + Storage.SetUserSettingValue(userid, entry.Key, entry.Value); + + pending_updates.Clear(); + } + + } +} diff --git a/PlayerSettings/Main.cs b/PlayerSettings/Main.cs index 4c84743..36c8496 100644 --- a/PlayerSettings/Main.cs +++ b/PlayerSettings/Main.cs @@ -35,27 +35,33 @@ public void OnConfigParsed(PluginConfig config) private ISettingsApi? _api; private readonly PluginCapability _pluginCapability = new("settings:nfcore"); - public override void Load(bool hotReload) - { - _api = new SettingsApi(); - Capabilities.RegisterPluginCapability(_pluginCapability, () => _api); - RegisterListener(OnClientAuthorized); - - if (hotReload) - foreach (var player in Utilities.GetPlayers()) - OnClientAuthorized(player.Slot, player.AuthorizedSteamID); - } + public override void Load(bool hotReload) + { + _api = new SettingsApi(); + Capabilities.RegisterPluginCapability(_pluginCapability, () => _api); + RegisterListener(OnClientAuthorized); + RegisterListener(OnClientDisconnect); + + if (hotReload) + foreach (var player in Utilities.GetPlayers()) + OnClientAuthorized(player.Slot, player.AuthorizedSteamID); + } public override void Unload(bool hotReload) { Storage.Close(); } - private void OnClientAuthorized(int slot, SteamID steamID) - { - ((SettingsApi)_api).LoadOnConnect(Utilities.GetPlayerFromSlot(slot)); - } -} + private void OnClientAuthorized(int slot, SteamID steamID) + { + ((SettingsApi)_api).LoadOnConnect(Utilities.GetPlayerFromSlot(slot)); + } + + private void OnClientDisconnect(int slot) + { + ((SettingsApi)_api).RemovePlayer(slot); + } +} public struct DatabaseParams { @@ -78,4 +84,4 @@ public bool IsLocal() { return (Host == "127.0.0.1:3306" && Name == "" && User == "" && Password == "") || Host == ""; } -} \ No newline at end of file +} diff --git a/PlayerSettings/SettingsApi.cs b/PlayerSettings/SettingsApi.cs index 9978b00..e4e8b68 100644 --- a/PlayerSettings/SettingsApi.cs +++ b/PlayerSettings/SettingsApi.cs @@ -9,18 +9,19 @@ namespace PlayerSettings { - internal class SettingsApi : ISettingsApi - { - private CPlayerSettings[] settings; - internal List> actions = new List>(); - public SettingsApi() - { - settings = Array.Empty(); - if (actions == null) - actions = new List>(); - else - actions.Clear(); - } + internal class SettingsApi : ISettingsApi + { + private readonly Dictionary settingsBySlot; + internal List> actions = new List>(); + public SettingsApi() + { + settingsBySlot = new Dictionary(); + if (actions == null) + actions = new List>(); + else + actions.Clear(); + SettingItems.Init(); + } public void AddHook(Action action) { @@ -32,28 +33,23 @@ public void RemHook(Action action) actions.RemoveAll(x => x == action); } - private CPlayerSettings FindUser(CCSPlayerController player) - { - foreach (var item in this.settings) - { - if (item.EqualPlayer(player)) - { - //Console.WriteLine($"Returned found: {item.UserId()}"); - return item; - } - } - - var newInst = new CPlayerSettings(player); - AddPlayerInst(newInst); - return newInst; - } - - private void AddPlayerInst(CPlayerSettings inst) - { - Array.Resize(ref settings, settings.Length + 1); - settings[settings.Length - 1] = inst; - } - + private CPlayerSettings FindUser(CCSPlayerController player) + { + if (settingsBySlot.TryGetValue(player.Slot, out var existing)) + { + if (existing.EqualPlayer(player)) + return existing; + } + + var newInst = new CPlayerSettings(player); + settingsBySlot[player.Slot] = newInst; + return newInst; + } + + internal void RemovePlayer(int slot) + { + settingsBySlot.Remove(slot); + } public string GetPlayerSettingsValue(CCSPlayerController player, string param, string default_value) { @@ -66,14 +62,17 @@ public void SetPlayerSettingsValue(CCSPlayerController player, string param, str FindUser(player).SetValue(param, value); } - internal void LoadOnConnect(CCSPlayerController player) - { - var user = FindUser(player); - - Task.Run(() => { while (user.UserId() == -1) Task.Delay(50).Wait(); }).ContinueWith((_) => - Storage.LoadSettings(user.UserId(), (vars) => user.ParseLoadedSettings(vars, actions)) - ); - } + internal void LoadOnConnect(CCSPlayerController player) + { + var user = FindUser(player); + _ = LoadOnConnectAsync(user); + } + + private async Task LoadOnConnectAsync(CPlayerSettings user) + { + await user.WaitForUserIdAsync().ConfigureAwait(false); + Storage.LoadSettings(user.UserId(), (vars) => user.ParseLoadedSettings(vars, actions)); + } public void RegisterTogglableSetting(string name, string viewName) {