diff --git a/sdks/csharp/src/SpacetimeDBClient.cs b/sdks/csharp/src/SpacetimeDBClient.cs index b5ed336e314..1129319c31c 100644 --- a/sdks/csharp/src/SpacetimeDBClient.cs +++ b/sdks/csharp/src/SpacetimeDBClient.cs @@ -135,6 +135,12 @@ public abstract class DbConnectionBase : IDbConne where DbConnection : DbConnectionBase, new() where Tables : RemoteTablesBase { + /// + /// This isn't reset since [RuntimeInitializeOnLoadMethod] methods cannot be in generic types + /// We assume that the user will reset this if needed; Unity will give an error about this field not being reset. + /// One way we can get around this in the future is using AutoStaticsCleanup + /// But that requires Unity 6.5 + /// internal static bool IsTesting { get; set; } = false; public static DbConnectionBuilder Builder() => new(); @@ -292,23 +298,6 @@ internal struct ParsedMessage private static readonly Status Committed = new Status.Committed(default); -#if UNITY_5_3_OR_NEWER - /// - /// Resets the static instance to prevent data persistence when Enter Play Mode Options (Disable Domain Reloading) is active. - /// RuntimeInitializeOnLoadMethod is used since it is supported in older versions of Unity. - /// AutoStaticsCleanup and NoAutoStaticsCleanup is only supported in Unity 6+ - /// - /// - /// See the Unity Domain Reloading Manual - /// and the RuntimeInitializeOnLoadMethodAttribute API Docs for details. - /// - [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] - private static void ResetStaticFields() - { - IsTesting = false; - } -#endif - /// /// Get a description of a message suitable for storing in the tracker metadata. /// diff --git a/sdks/csharp/src/Table.cs b/sdks/csharp/src/Table.cs index 5847f5728df..e23ad41871a 100644 --- a/sdks/csharp/src/Table.cs +++ b/sdks/csharp/src/Table.cs @@ -187,6 +187,22 @@ public RemoteTableHandleBase(IDbConnection conn, bool isEventTable = false) : ba { IsEventTable = isEventTable; } + +#if UNITY_5_3_OR_NEWER + /// + /// Resets the static instance to prevent data persistence when Enter Play Mode Options (Disable Domain Reloading) is active. + /// RuntimeInitializeOnLoadMethod can't be used here since this is a generic class, so we have to handle it ourselves. + /// AutoStaticsCleanup and NoAutoStaticsCleanup is only supported in Unity 6+ + /// + /// + /// See the Unity Domain Reloading Manual + /// and the RuntimeInitializeOnLoadMethodAttribute API Docs for details. + /// + static RemoteTableHandleBase() + { + RemoteTableHandleStaticReset.Register(() => _serializer = null); + } +#endif // This method needs to be overridden by autogen. protected virtual object? GetPrimaryKey(Row row) => null; @@ -245,24 +261,6 @@ private static IReadWrite Serializer } } - -#if UNITY_5_3_OR_NEWER - /// - /// Resets the static instance to prevent data persistence when Enter Play Mode Options (Disable Domain Reloading) is active. - /// RuntimeInitializeOnLoadMethod is used since it is supported in older versions of Unity. - /// AutoStaticsCleanup and NoAutoStaticsCleanup is only supported in Unity 6+ - /// - /// - /// See the Unity Domain Reloading Manual - /// and the RuntimeInitializeOnLoadMethodAttribute API Docs for details. - /// - [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] - private static void ResetStaticFields() - { - _serializer = null; - } -#endif - // The function to use for decoding a type value. Row DecodeValue(BinaryReader reader) => Serializer.Read(reader); @@ -683,5 +681,37 @@ public abstract class RemoteEventTableHandle : RemoteTableHan { protected RemoteEventTableHandle(IDbConnection conn) : base(conn, isEventTable: true) { } } + +#if UNITY_5_3_OR_NEWER + /// + /// Provides a mechanism for registering and invoking static reset callbacks + /// during Unity's subsystem registration phase. + /// This is because Unity's RuntimeInitializeOnLoadMethod can't be used in generic classes + /// One way we can get around this in the future is using AutoStaticsCleanup + /// But that requires Unity 6.5 + /// + /// + /// Our generic static constructor doesn't necessarily execute for every table type before Unity's SubsystemRegistration callback runs + /// So this will only reset types that have already been initialized/registered. Which should be okay. + /// + internal static class RemoteTableHandleStaticReset + { + private static readonly List Resets = new(); + + internal static void Register(Action reset) + { + Resets.Add(reset); + } + + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] + private static void Reset() + { + foreach (var reset in Resets) + { + reset(); + } + } + } +#endif } #nullable disable