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.
///