From 79ad4962d47e7a00ab83800bc8d414c612cb0b4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mustafa=20SAVA=C5=9E?= Date: Sat, 6 Jun 2026 01:50:43 +0300 Subject: [PATCH 1/4] fix increment & helper methods --- .../API/Features/CustomRole.cs | 77 +++++++++++++++++++ .../Events/PlayerHandlers.cs | 30 ++------ 2 files changed, 83 insertions(+), 24 deletions(-) diff --git a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs index f2dd9bc8d8..9894ec264a 100644 --- a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs +++ b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs @@ -54,6 +54,11 @@ public abstract class CustomRole /// public static HashSet Registered { get; } = new(); + /// + /// Gets or sets a value indicating whether the role is enabled. + /// + public virtual bool IsEnabled { get; set; } = true; + /// /// Gets or sets the custom RoleID of the role. /// @@ -323,6 +328,39 @@ public static IEnumerable RegisterRoles(bool byAttribute = false) return roles; } + /// + /// Registers all the 's present in the current plugin's config. + /// + /// The source containing the custom roles. + /// An optional collection of s to ignore during registration. + /// A of which contains all registered 's. + public static IEnumerable RegisterRolesFromSource(object source, IEnumerable? ignoredRoles = null) + { + List roles = new(); + + if (source == null) + return roles; + + PropertyInfo[] properties = source.GetType().GetProperties(); + + foreach (PropertyInfo property in properties) + { + if (!typeof(CustomRole).IsAssignableFrom(property.PropertyType)) + continue; + + if (property.GetValue(source) is not CustomRole configRole) + continue; + + if (ignoredRoles != null && ignoredRoles.Any(ignored => ignored.GetType() == configRole.GetType())) + continue; + + if (configRole.TryRegister()) + roles.Add(configRole); + } + + return roles; + } + /// /// Registers all the 's present in the current assembly. /// @@ -486,6 +524,39 @@ public static IEnumerable UnregisterRoles(IEnumerable targetTy /// A of which contains all unregistered 's. public static IEnumerable UnregisterRoles(IEnumerable targetRoles, bool isIgnored = false) => UnregisterRoles(targetRoles.Select(x => x.GetType()), isIgnored); + /// + /// Unregisters all the 's present in the current plugin's config. + /// + /// The source containing the target roles. + /// An optional collection of s to ignore during unregisteration. + /// A of which contains all unregistered 's. + public static IEnumerable UnregisterFromSource(object source, IEnumerable? ignoredRoles = null) + { + List roles = new(); + + if (source == null) + return roles; + + PropertyInfo[] properties = source.GetType().GetProperties(); + + foreach (PropertyInfo property in properties) + { + if (!typeof(CustomRole).IsAssignableFrom(property.PropertyType)) + continue; + + if (property.GetValue(source) is not CustomRole configRole) + continue; + + if (ignoredRoles != null && ignoredRoles.Any(ignored => ignored.GetType() == configRole.GetType())) + continue; + + if (configRole.TryUnregister()) + roles.Add(configRole); + } + + return roles; + } + /// /// ResyncCustomRole Friendly Fire with Player (Append, or Overwrite). /// @@ -810,6 +881,12 @@ internal bool TryRegister() if (!CustomRoles.Instance!.Config.IsEnabled) return false; + if (!IsEnabled) + { + Log.Debug($"Custom role {Name} is not enabled and will not be registered."); + return false; + } + if (!Registered.Contains(this)) { if (Registered.Any(r => r.Id == Id)) diff --git a/EXILED/Exiled.CustomRoles/Events/PlayerHandlers.cs b/EXILED/Exiled.CustomRoles/Events/PlayerHandlers.cs index 47a153221d..d637dbd0e3 100644 --- a/EXILED/Exiled.CustomRoles/Events/PlayerHandlers.cs +++ b/EXILED/Exiled.CustomRoles/Events/PlayerHandlers.cs @@ -17,6 +17,8 @@ namespace Exiled.CustomRoles.Events using Exiled.CustomRoles.API.Features; using Exiled.Events.EventArgs.Player; + using UnityEngine; + /// /// Handles general events for players. /// @@ -66,9 +68,7 @@ internal void OnSpawningRagdoll(SpawningRagdollEventArgs ev) internal void OnSpawned(SpawnedEventArgs ev) { if (!ValidSpawnReasons.Contains(ev.Reason) || ev.Player.HasAnyCustomRole()) - { return; - } float totalChance = 0f; List eligibleRoles = new(8); @@ -83,17 +83,13 @@ internal void OnSpawned(SpawnedEventArgs ev) } if (eligibleRoles.Count == 0) - { return; - } - float lotterySize = Math.Max(100f, totalChance); + float lotterySize = Mathf.Max(100f, totalChance); float randomRoll = (float)Loader.Loader.Random.NextDouble() * lotterySize; if (randomRoll >= totalChance) - { return; - } foreach (CustomRole candidateRole in eligibleRoles) { @@ -103,23 +99,9 @@ internal void OnSpawned(SpawnedEventArgs ev) continue; } - if (candidateRole.SpawnProperties is null) - { - candidateRole.AddRole(ev.Player); - break; - } - - int newSpawnCount = candidateRole.SpawnedPlayers++; - if (newSpawnCount <= candidateRole.SpawnProperties.Limit) - { - candidateRole.AddRole(ev.Player); - break; - } - else - { - candidateRole.SpawnedPlayers--; - randomRoll -= candidateRole.SpawnChance; - } + candidateRole.SpawnedPlayers++; + candidateRole.AddRole(ev.Player); + break; } } } From 90fb5ab17cd64b0e45d3f7b084bfe7db2eb7f388 Mon Sep 17 00:00:00 2001 From: MS <100300664+MS-crew@users.noreply.github.com> Date: Sat, 6 Jun 2026 11:44:55 +0300 Subject: [PATCH 2/4] Update CustomRole.cs --- EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs index 9894ec264a..7f33a0b24e 100644 --- a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs +++ b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs @@ -341,6 +341,8 @@ public static IEnumerable RegisterRolesFromSource(object source, IEn if (source == null) return roles; + HashSet? ignoredTypes = ignoredRoles?.Select(x => x.GetType()).ToHashSet(); + PropertyInfo[] properties = source.GetType().GetProperties(); foreach (PropertyInfo property in properties) @@ -351,7 +353,7 @@ public static IEnumerable RegisterRolesFromSource(object source, IEn if (property.GetValue(source) is not CustomRole configRole) continue; - if (ignoredRoles != null && ignoredRoles.Any(ignored => ignored.GetType() == configRole.GetType())) + if (ignoredRoles != null && ignoredTypes.Contains(configRole.GetType())) continue; if (configRole.TryRegister()) @@ -537,6 +539,8 @@ public static IEnumerable UnregisterFromSource(object source, IEnume if (source == null) return roles; + HashSet? ignoredTypes = ignoredRoles?.Select(x => x.GetType()).ToHashSet(); + PropertyInfo[] properties = source.GetType().GetProperties(); foreach (PropertyInfo property in properties) @@ -547,7 +551,7 @@ public static IEnumerable UnregisterFromSource(object source, IEnume if (property.GetValue(source) is not CustomRole configRole) continue; - if (ignoredRoles != null && ignoredRoles.Any(ignored => ignored.GetType() == configRole.GetType())) + if (ignoredRoles != null && ignoredTypes.Contains(configRole.GetType())) continue; if (configRole.TryUnregister()) From fb82cb6fa6da7c907d2b5e0bafb02eb43fc1ccba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mustafa=20SAVA=C5=9E?= Date: Sat, 6 Jun 2026 11:50:32 +0300 Subject: [PATCH 3/4] fix and renaming --- .../API/Features/CustomRole.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs index 7f33a0b24e..add0d807d1 100644 --- a/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs +++ b/EXILED/Exiled.CustomRoles/API/Features/CustomRole.cs @@ -350,14 +350,14 @@ public static IEnumerable RegisterRolesFromSource(object source, IEn if (!typeof(CustomRole).IsAssignableFrom(property.PropertyType)) continue; - if (property.GetValue(source) is not CustomRole configRole) + if (property.GetValue(source) is not CustomRole sourceRole) continue; - if (ignoredRoles != null && ignoredTypes.Contains(configRole.GetType())) + if (ignoredTypes != null && ignoredTypes.Contains(sourceRole.GetType())) continue; - if (configRole.TryRegister()) - roles.Add(configRole); + if (sourceRole.TryRegister()) + roles.Add(sourceRole); } return roles; @@ -548,14 +548,14 @@ public static IEnumerable UnregisterFromSource(object source, IEnume if (!typeof(CustomRole).IsAssignableFrom(property.PropertyType)) continue; - if (property.GetValue(source) is not CustomRole configRole) + if (property.GetValue(source) is not CustomRole sourceRole) continue; - if (ignoredRoles != null && ignoredTypes.Contains(configRole.GetType())) + if (ignoredTypes != null && ignoredTypes.Contains(sourceRole.GetType())) continue; - if (configRole.TryUnregister()) - roles.Add(configRole); + if (sourceRole.TryUnregister()) + roles.Add(sourceRole); } return roles; From 863a7a0b20991c43658678a10de2657e9362d301 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mustafa=20SAVA=C5=9E?= Date: Wed, 10 Jun 2026 12:26:18 +0300 Subject: [PATCH 4/4] fg --- EXILED/Exiled.CustomRoles/Events/PlayerHandlers.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EXILED/Exiled.CustomRoles/Events/PlayerHandlers.cs b/EXILED/Exiled.CustomRoles/Events/PlayerHandlers.cs index d637dbd0e3..38ed195d64 100644 --- a/EXILED/Exiled.CustomRoles/Events/PlayerHandlers.cs +++ b/EXILED/Exiled.CustomRoles/Events/PlayerHandlers.cs @@ -75,7 +75,7 @@ internal void OnSpawned(SpawnedEventArgs ev) foreach (CustomRole role in CustomRole.Registered) { - if (role.Role == ev.Player.Role.Type && !role.IgnoreSpawnSystem && role.SpawnChance > 0 && !role.Check(ev.Player) && (role.SpawnProperties is null || role.SpawnedPlayers < role.SpawnProperties.Limit) && (role.MinPlayers is 0 || Server.PlayerConnectedCount >= role.MinPlayers)) + if (role.Role == ev.Player.Role.Type && !role.IgnoreSpawnSystem && role.SpawnChance > 0 && (role.SpawnProperties is null || role.SpawnedPlayers < role.SpawnProperties.Limit) && (role.MinPlayers is 0 || Server.PlayerConnectedCount >= role.MinPlayers)) { eligibleRoles.Add(role); totalChance += role.SpawnChance;