From 9260713e35924d3aad55527224174da6ec5845b0 Mon Sep 17 00:00:00 2001 From: Eve <85962933+obvEve@users.noreply.github.com> Date: Fri, 11 Sep 2026 20:11:38 +0200 Subject: [PATCH] Minor --- SecretAPI/Debugging/PrefabDebugger.cs | 1 - SecretAPI/Extensions/MirrorExtensions.cs | 3 ++ SecretAPI/Features/DecalHelpers.cs | 28 ++++++------- .../Features/Effects/CustomPlayerEffect.cs | 40 +++++++++++++++++-- .../Effects/CustomTickingPlayerEffect.cs | 2 +- .../Features/UserSettings/CustomSetting.cs | 26 ++++++------ 6 files changed, 68 insertions(+), 32 deletions(-) diff --git a/SecretAPI/Debugging/PrefabDebugger.cs b/SecretAPI/Debugging/PrefabDebugger.cs index e7b28c6..98b5f3f 100644 --- a/SecretAPI/Debugging/PrefabDebugger.cs +++ b/SecretAPI/Debugging/PrefabDebugger.cs @@ -18,7 +18,6 @@ namespace SecretAPI.Debugging; /// /// Debugs base-game prefabs by logging information about them. /// -// ? Possibly write to file instead of server console? internal static class PrefabDebugger { /// diff --git a/SecretAPI/Extensions/MirrorExtensions.cs b/SecretAPI/Extensions/MirrorExtensions.cs index 0e1fcdc..55a1078 100644 --- a/SecretAPI/Extensions/MirrorExtensions.cs +++ b/SecretAPI/Extensions/MirrorExtensions.cs @@ -64,7 +64,10 @@ public static void SendFakeRpcMessage(this Player target, NetworkBehaviour behav public static void SendFakeSyncListData(this Player target, NetworkBehaviour behaviour, ulong listIndex, SyncListChange change) { if (listIndex <= 0) + { Logger.Warn($"[MirrorExtensions.SendFakeSyncListData] Index is {listIndex} - Expected 1 or higher!: + {new StackTrace()}"); + return; // avoid client kick + } SendFakeState(target, behaviour, writer => { diff --git a/SecretAPI/Features/DecalHelpers.cs b/SecretAPI/Features/DecalHelpers.cs index 2283287..ce5f76e 100644 --- a/SecretAPI/Features/DecalHelpers.cs +++ b/SecretAPI/Features/DecalHelpers.cs @@ -15,9 +15,7 @@ namespace SecretAPI.Features; /// public static class DecalHelpers { - private static bool hasData = false; - private static ItemType itemType = ItemType.None; - private static byte subcomponentIndex = 0; + private static AutoSyncData? autoSyncData; /// /// Creates an for spawning a decal that can be sent to players. @@ -31,16 +29,16 @@ public static AutosyncMessage GetDecalMessage(Vector3 position, Vector3 startPos RelativePosition hitPoint = new(position); RelativePosition startRaycastPoint = new(startPosition); - (ItemType itemTypeId, byte moduleIndex) = GetItemData(); + AutoSyncData data = GetAutoSyncData(); - using NetworkWriterPooled? writer = NetworkWriterPool.Get(); - writer.WriteByte(moduleIndex); + using NetworkWriterPooled writer = NetworkWriterPool.Get(); + writer.WriteByte(data.SubcomponentIndex); writer.WriteSubheader(ImpactEffectsModule.RpcType.ImpactDecal); writer.WriteByte((byte)type); writer.WriteRelativePosition(hitPoint); writer.WriteRelativePosition(startRaycastPoint); - return new AutosyncMessage(writer, new ItemIdentifier(itemTypeId, 0)); + return new AutosyncMessage(writer, new ItemIdentifier(data.ItemType, 0)); } /// @@ -88,24 +86,24 @@ public static void SpawnDecalFromDirection(Vector3 position, Vector3 direction, public static void SpawnDecalFromDirection(Vector3 position, Quaternion direction, DecalPoolType type = DecalPoolType.Blood) => GetDecalMessage(position, position - (direction * Vector3.forward), type).SendToAuthenticated(); - private static (ItemType ItemType, byte SubcomponentIndex) GetItemData() + private static AutoSyncData GetAutoSyncData() { - if (hasData) - return (itemType, subcomponentIndex); + if (autoSyncData != null) + return autoSyncData; - foreach (ModularAutosyncItem? autoItem in ModularAutosyncItem.AllTemplates) + foreach (ModularAutosyncItem autoItem in ModularAutosyncItem.AllTemplates) { for (byte b = 0; b < autoItem.AllSubcomponents.Length; b++) { if (autoItem.AllSubcomponents[b] is not ImpactEffectsModule) continue; - subcomponentIndex = b; - itemType = autoItem.ItemTypeId; - hasData = true; - return (itemType, subcomponentIndex); + + return autoSyncData = new AutoSyncData(autoItem.ItemTypeId, b); } } throw new InvalidOperationException("Couldn't find the `InventorySystem.Items.Firearms.Modules.ImpactEffectsModule` in the any ModularAutosyncItem!"); } + + private sealed record AutoSyncData(ItemType ItemType, byte SubcomponentIndex); } \ No newline at end of file diff --git a/SecretAPI/Features/Effects/CustomPlayerEffect.cs b/SecretAPI/Features/Effects/CustomPlayerEffect.cs index dc7d58c..13699b4 100644 --- a/SecretAPI/Features/Effects/CustomPlayerEffect.cs +++ b/SecretAPI/Features/Effects/CustomPlayerEffect.cs @@ -10,23 +10,54 @@ using Logger = LabApi.Features.Console.Logger; +// ! PLEASE NW MAKE CUSTOM EFFECTS GOOD I'M GONNA CRY + /// /// Handles custom player effects. -/// Must register to to work. +/// Must register with in order to work. /// public abstract class CustomPlayerEffect : StatusEffectBase { /// /// Gets a list of types to register (Must inherit ). - /// Must be , can be gotten through typeof(Scp207) /// - public static List EffectsToRegister { get; } = []; + [Obsolete("This is becoming readonly in 4.0 - Use Register()")] + public static List EffectsToRegister { get; } = []; // TODO 4.0: private static HashSet RegisteredEffects /// /// Gets the with this effect. /// public Player Owner => field ??= Player.Get(Hub); + /// + /// Registers a custom effect type. + /// + /// The effect type to register. + public static void Register() + where T : StatusEffectBase => Register(typeof(T)); + + /// + /// Registers a custom effect type. + /// + /// The to register. May not be abstract and must inherit . + public static void Register(Type type) + { + if (!type.IsAssignableFrom(typeof(StatusEffectBase))) + { + Logger.Error($"[CustomPlayerEffect.Register] {type.FullName} does not inherit StatusEffectBase!"); + return; + } + + if (type.IsAbstract) + { + Logger.Error($"[CustomPlayerEffect.Register] {type.FullName} is abstract!"); + return; + } + +#pragma warning disable CS0618 // Type or member is obsolete + EffectsToRegister.Add(type); + } + /// public override string ToString() => $"{GetType().Name}: Owner ({Owner}) - Intensity ({Intensity}) - Duration {Duration}"; @@ -41,6 +72,9 @@ internal static void Initialize() EffectsToRegister.Add(typeof(Depleted)); EffectsToRegister.Add(typeof(BlastResistance)); + // it would probably be better to patch PlayerEffectsController::Awake instead of using sceneLoaded + // this would also allow registering after players join + // although the current way might be the fastest since its just base unity handling it on the prefab SceneManager.sceneLoaded += OnSceneLoaded; } diff --git a/SecretAPI/Features/Effects/CustomTickingPlayerEffect.cs b/SecretAPI/Features/Effects/CustomTickingPlayerEffect.cs index b948220..3355e49 100644 --- a/SecretAPI/Features/Effects/CustomTickingPlayerEffect.cs +++ b/SecretAPI/Features/Effects/CustomTickingPlayerEffect.cs @@ -4,7 +4,7 @@ using UnityEngine; /// -/// Custom Effect for . +/// Custom version of for . /// public abstract class CustomTickingPlayerEffect : CustomPlayerEffect { diff --git a/SecretAPI/Features/UserSettings/CustomSetting.cs b/SecretAPI/Features/UserSettings/CustomSetting.cs index 011a44c..5715e44 100644 --- a/SecretAPI/Features/UserSettings/CustomSetting.cs +++ b/SecretAPI/Features/UserSettings/CustomSetting.cs @@ -58,9 +58,8 @@ protected CustomSetting(ServerSpecificSettingBase setting) public ServerSpecificSettingBase Base { get; } /// - /// Gets the known owner. + /// Gets the known owner or on the initial object. /// - /// This is null on the original object. public Player? KnownOwner { get; private set; } /// @@ -75,7 +74,7 @@ protected CustomSetting(ServerSpecificSettingBase setting) public SettingResponseType LastUpdateType { get; private set; } = SettingResponseType.None; /// - /// Gets a value indicating whether the current value received is different to that prior to the most recent call. + /// Gets a value indicating whether the current value received is different to that prior to the most recent call. /// public virtual bool HasValueChanged { get; } = false; @@ -154,10 +153,7 @@ public bool IsShared set => CollectionId = value ? byte.MinValue : byte.MaxValue; } - /// - /// Registers a collection of settings. - /// - /// The settings to register. + /// public static void Register(params CustomSetting[] settings) => Register((IEnumerable)settings); /// @@ -173,11 +169,8 @@ public static void Register(IEnumerable settings) } } - /// - /// Unregisters collection of settings. - /// - /// The settings to unregister. - public static void UnRegister(params CustomSetting[] settings) => CustomSettings.RemoveAll(settings.Contains); + /// + public static void UnRegister(params CustomSetting[] settings) => UnRegister((IEnumerable)settings); /// /// Unregisters a collection of settings. @@ -185,6 +178,15 @@ public static void Register(IEnumerable settings) /// The settings to unregister. public static void UnRegister(IEnumerable settings) => CustomSettings.RemoveAll(settings.Contains); + /// + public static void UnRegister(params Type[] types) => UnRegister((IEnumerable)types); + + /// + /// Unregisters a collection of setting based on their . + /// + /// A collection of setting types to unregister. This should be the exact type, not the base. + public static void UnRegister(IEnumerable types) => CustomSettings.RemoveAll(s => types.Any(t => s.GetType() == t)); + /// /// Tries to get player specific setting. ///