diff --git a/AmongUs.props b/AmongUs.props index b7a170a..ff68350 100644 --- a/AmongUs.props +++ b/AmongUs.props @@ -9,7 +9,7 @@ - + diff --git a/Reactor.Benchmarks/SingleThreadedInProcessEmitToolchain.cs b/Reactor.Benchmarks/SingleThreadedInProcessEmitToolchain.cs index 2772892..9f4e4b2 100644 --- a/Reactor.Benchmarks/SingleThreadedInProcessEmitToolchain.cs +++ b/Reactor.Benchmarks/SingleThreadedInProcessEmitToolchain.cs @@ -1,3 +1,5 @@ +#pragma warning disable SA1611, SA1615 + using BenchmarkDotNet.Engines; using BenchmarkDotNet.Loggers; using BenchmarkDotNet.Toolchains; diff --git a/Reactor.Benchmarks/packages.lock.json b/Reactor.Benchmarks/packages.lock.json index e03c8cb..8007400 100644 --- a/Reactor.Benchmarks/packages.lock.json +++ b/Reactor.Benchmarks/packages.lock.json @@ -30,9 +30,9 @@ }, "BepInEx.AutoPlugin": { "type": "Direct", - "requested": "[1.0.1, )", - "resolved": "1.0.1", - "contentHash": "G4YpTHG9rtkDJof+ld7Er4E+sCOlgsjG4bJ1itx1ub7dgff6qqHLy9ksX1ehgO0AdBOPVyVl/GKJg9o7iNl8HA==" + "requested": "[1.1.0, )", + "resolved": "1.1.0", + "contentHash": "/7Nmc1EA9lYlGBiyz6qPAaHvlcJHEjFZ1RFpGX+8EBj3GrgoX5kbpnZusuSHoOlLx0l+CnzKuQNE54B8UaGPyw==" }, "BepInEx.IL2CPP.MSBuild": { "type": "Direct", @@ -57,6 +57,15 @@ "Samboy063.Cpp2IL.Core": "2022.0.7.2" } }, + "StyleCop.Analyzers": { + "type": "Direct", + "requested": "[1.2.0-beta.435, )", + "resolved": "1.2.0-beta.435", + "contentHash": "TADk7vdGXtfTnYCV7GyleaaRTQjfoSfZXprQrVMm7cSJtJbFc1QIbWPyLvrgrfGdfHbGmUPvaN4ODKNxg2jgPQ==", + "dependencies": { + "StyleCop.Analyzers.Unstable": "1.2.0.435" + } + }, "AssetRipper.VersionUtilities": { "type": "Transitive", "resolved": "1.2.1", @@ -463,6 +472,11 @@ "resolved": "2.0.2", "contentHash": "4EQgYdNZ92SyaO7YFk6olVnebF5V+jrHyMUjvPq89tLeMo8NSfgDF+6Zwq/lgh9j/0yfQp9Lkm0ZA0rUATCZFA==" }, + "StyleCop.Analyzers.Unstable": { + "type": "Transitive", + "resolved": "1.2.0.435", + "contentHash": "ouwPWZxbOV3SmCZxIRqHvljkSzkCyi1tDoMzQtDb/bRP8ctASV/iRJr+A2Gdj0QLaLmWnqTWDrH82/iP+X80Lg==" + }, "System.CodeDom": { "type": "Transitive", "resolved": "6.0.0", diff --git a/Reactor.Debugger/packages.lock.json b/Reactor.Debugger/packages.lock.json index d94a3f8..5e55856 100644 --- a/Reactor.Debugger/packages.lock.json +++ b/Reactor.Debugger/packages.lock.json @@ -10,9 +10,9 @@ }, "BepInEx.AutoPlugin": { "type": "Direct", - "requested": "[1.0.1, )", - "resolved": "1.0.1", - "contentHash": "G4YpTHG9rtkDJof+ld7Er4E+sCOlgsjG4bJ1itx1ub7dgff6qqHLy9ksX1ehgO0AdBOPVyVl/GKJg9o7iNl8HA==" + "requested": "[1.1.0, )", + "resolved": "1.1.0", + "contentHash": "/7Nmc1EA9lYlGBiyz6qPAaHvlcJHEjFZ1RFpGX+8EBj3GrgoX5kbpnZusuSHoOlLx0l+CnzKuQNE54B8UaGPyw==" }, "BepInEx.IL2CPP.MSBuild": { "type": "Direct", @@ -37,6 +37,15 @@ "Samboy063.Cpp2IL.Core": "2022.0.7.2" } }, + "StyleCop.Analyzers": { + "type": "Direct", + "requested": "[1.2.0-beta.435, )", + "resolved": "1.2.0-beta.435", + "contentHash": "TADk7vdGXtfTnYCV7GyleaaRTQjfoSfZXprQrVMm7cSJtJbFc1QIbWPyLvrgrfGdfHbGmUPvaN4ODKNxg2jgPQ==", + "dependencies": { + "StyleCop.Analyzers.Unstable": "1.2.0.435" + } + }, "AssetRipper.VersionUtilities": { "type": "Transitive", "resolved": "1.2.1", @@ -303,6 +312,11 @@ "resolved": "2.0.2", "contentHash": "4EQgYdNZ92SyaO7YFk6olVnebF5V+jrHyMUjvPq89tLeMo8NSfgDF+6Zwq/lgh9j/0yfQp9Lkm0ZA0rUATCZFA==" }, + "StyleCop.Analyzers.Unstable": { + "type": "Transitive", + "resolved": "1.2.0.435", + "contentHash": "ouwPWZxbOV3SmCZxIRqHvljkSzkCyi1tDoMzQtDb/bRP8ctASV/iRJr+A2Gdj0QLaLmWnqTWDrH82/iP+X80Lg==" + }, "System.Collections": { "type": "Transitive", "resolved": "4.3.0", diff --git a/Reactor.Example/packages.lock.json b/Reactor.Example/packages.lock.json index d94a3f8..5e55856 100644 --- a/Reactor.Example/packages.lock.json +++ b/Reactor.Example/packages.lock.json @@ -10,9 +10,9 @@ }, "BepInEx.AutoPlugin": { "type": "Direct", - "requested": "[1.0.1, )", - "resolved": "1.0.1", - "contentHash": "G4YpTHG9rtkDJof+ld7Er4E+sCOlgsjG4bJ1itx1ub7dgff6qqHLy9ksX1ehgO0AdBOPVyVl/GKJg9o7iNl8HA==" + "requested": "[1.1.0, )", + "resolved": "1.1.0", + "contentHash": "/7Nmc1EA9lYlGBiyz6qPAaHvlcJHEjFZ1RFpGX+8EBj3GrgoX5kbpnZusuSHoOlLx0l+CnzKuQNE54B8UaGPyw==" }, "BepInEx.IL2CPP.MSBuild": { "type": "Direct", @@ -37,6 +37,15 @@ "Samboy063.Cpp2IL.Core": "2022.0.7.2" } }, + "StyleCop.Analyzers": { + "type": "Direct", + "requested": "[1.2.0-beta.435, )", + "resolved": "1.2.0-beta.435", + "contentHash": "TADk7vdGXtfTnYCV7GyleaaRTQjfoSfZXprQrVMm7cSJtJbFc1QIbWPyLvrgrfGdfHbGmUPvaN4ODKNxg2jgPQ==", + "dependencies": { + "StyleCop.Analyzers.Unstable": "1.2.0.435" + } + }, "AssetRipper.VersionUtilities": { "type": "Transitive", "resolved": "1.2.1", @@ -303,6 +312,11 @@ "resolved": "2.0.2", "contentHash": "4EQgYdNZ92SyaO7YFk6olVnebF5V+jrHyMUjvPq89tLeMo8NSfgDF+6Zwq/lgh9j/0yfQp9Lkm0ZA0rUATCZFA==" }, + "StyleCop.Analyzers.Unstable": { + "type": "Transitive", + "resolved": "1.2.0.435", + "contentHash": "ouwPWZxbOV3SmCZxIRqHvljkSzkCyi1tDoMzQtDb/bRP8ctASV/iRJr+A2Gdj0QLaLmWnqTWDrH82/iP+X80Lg==" + }, "System.Collections": { "type": "Transitive", "resolved": "4.3.0", diff --git a/Reactor.Networking.Shared/Mod.cs b/Reactor.Networking.Shared/Mod.cs index 76a57b9..f540a02 100644 --- a/Reactor.Networking.Shared/Mod.cs +++ b/Reactor.Networking.Shared/Mod.cs @@ -8,8 +8,18 @@ using System.Text; namespace Reactor.Networking; +/// +/// Represents a Reactor.Protocol mod. +/// public readonly struct Mod : IEquatable { + /// + /// Initializes a new instance of the struct. + /// + /// The id of the mod. + /// The version of the mod. + /// The flags of the mod. + /// The name of the mod. public Mod(string id, string version, ModFlags flags, string? name = null) { Id = id; @@ -18,38 +28,62 @@ public readonly struct Mod : IEquatable Name = name; } + /// + /// Gets the id of the mod. + /// public string Id { get; } + + /// + /// Gets the version of the mod. + /// public string Version { get; } + + /// + /// Gets the flags of the mod. + /// public ModFlags Flags { get; } + + /// + /// Gets the name of the mod. + /// public string? Name { get; } + /// + /// Gets a value indicating whether the mod is required on all clients. + /// public bool IsRequiredOnAllClients => (Flags & ModFlags.RequireOnAllClients) != 0; + /// public bool Equals(Mod other) { return Id == other.Id && Version == other.Version; } + /// public override bool Equals(object? obj) { return obj is Mod other && Equals(other); } + /// public static bool operator ==(Mod left, Mod right) { return left.Equals(right); } + /// public static bool operator !=(Mod left, Mod right) { return !(left == right); } + /// public override int GetHashCode() { return HashCode.Combine(Id, Version); } + /// public override string ToString() { return $"{Name ?? Id} ({Version})"; diff --git a/Reactor.Networking.Shared/ModFlags.cs b/Reactor.Networking.Shared/ModFlags.cs index 58c361f..b11c868 100644 --- a/Reactor.Networking.Shared/ModFlags.cs +++ b/Reactor.Networking.Shared/ModFlags.cs @@ -2,9 +2,15 @@ using System; namespace Reactor.Networking; +/// +/// Represents flags of the mod. +/// [Flags] public enum ModFlags : ushort { + /// + /// No flags. + /// None = 0, /// diff --git a/Reactor.Networking.Shared/Reactor.Networking.Shared.csproj b/Reactor.Networking.Shared/Reactor.Networking.Shared.csproj index 9402022..1ba48f2 100644 --- a/Reactor.Networking.Shared/Reactor.Networking.Shared.csproj +++ b/Reactor.Networking.Shared/Reactor.Networking.Shared.csproj @@ -15,6 +15,7 @@ true true true + true @@ -22,6 +23,10 @@ true $(ContentTargetFolders)\cs\any\$(PackageId)\%(RecursiveDir)\ + + true + contentFiles\cs\any\Reactor.Networking.Shared\\ + diff --git a/Reactor.Networking.Shared/ReactorGameDataFlag.cs b/Reactor.Networking.Shared/ReactorGameDataFlag.cs index 1851fd7..50d1d2d 100644 --- a/Reactor.Networking.Shared/ReactorGameDataFlag.cs +++ b/Reactor.Networking.Shared/ReactorGameDataFlag.cs @@ -1,6 +1,12 @@ namespace Reactor.Networking; +/// +/// Represents a GameData flag for Reactor messages. +/// public enum ReactorGameDataFlag : byte { + /// + /// KickWithReason GameData message. + /// KickWithReason, } diff --git a/Reactor.Networking.Shared/ReactorMessageFlags.cs b/Reactor.Networking.Shared/ReactorMessageFlags.cs index 36d5f89..b0f6147 100644 --- a/Reactor.Networking.Shared/ReactorMessageFlags.cs +++ b/Reactor.Networking.Shared/ReactorMessageFlags.cs @@ -1,6 +1,12 @@ namespace Reactor.Networking; +/// +/// Represents a message flag for Reactor messages. +/// public enum ReactorMessageFlags : byte { + /// + /// Handshake message. + /// Handshake, } diff --git a/Reactor/Localization/CustomStringName.cs b/Reactor/Localization/CustomStringName.cs index d2e3b6e..7034dd4 100644 --- a/Reactor/Localization/CustomStringName.cs +++ b/Reactor/Localization/CustomStringName.cs @@ -6,14 +6,25 @@ using Il2CppInterop.Runtime.InteropTypes.Arrays; namespace Reactor.Localization; +/// +/// Provides a way to use custom static StringNames. +/// public class CustomStringName { private static int _lastId = -1; private static readonly List _list = new(); + /// + /// Gets a list of all s. + /// public static IReadOnlyList List => _list.AsReadOnly(); + /// + /// Registers a with specified . + /// + /// The value. + /// A . public static CustomStringName Register(string value) { var customStringName = new CustomStringName(_lastId--, value); @@ -22,8 +33,14 @@ public class CustomStringName return customStringName; } + /// + /// Gets the id. + /// public int Id { get; } + /// + /// Gets the value. + /// public string Value { get; } private CustomStringName(int id, string value) @@ -32,7 +49,18 @@ public class CustomStringName Value = value; } + /// + /// Defines an implicit conversion of a to a . + /// + /// The . + /// A . public static implicit operator StringNames(CustomStringName name) => (StringNames) name.Id; + + /// + /// Defines an explicit conversion of a to a . + /// + /// The . + /// A . public static explicit operator CustomStringName?(StringNames name) => List.SingleOrDefault(x => x.Id == (int) name); [HarmonyPatch(typeof(TranslationController), nameof(TranslationController.GetString), typeof(StringNames), typeof(Il2CppReferenceArray))] diff --git a/Reactor/Networking/Attributes/MessageConverterAttribute.cs b/Reactor/Networking/Attributes/MessageConverterAttribute.cs index f792211..e3515be 100644 --- a/Reactor/Networking/Attributes/MessageConverterAttribute.cs +++ b/Reactor/Networking/Attributes/MessageConverterAttribute.cs @@ -7,11 +7,19 @@ using Reactor.Networking.Serialization; namespace Reactor.Networking.Attributes; +/// +/// Automatically registers a . +/// [AttributeUsage(AttributeTargets.Class)] public sealed class MessageConverterAttribute : Attribute { private static readonly HashSet _registeredAssemblies = new(); + /// + /// Registers all s annotated with in the specified . + /// + /// This is called automatically on plugin assemblies so you probably don't need to call this. + /// The assembly to search. public static void Register(Assembly assembly) { if (_registeredAssemblies.Contains(assembly)) return; diff --git a/Reactor/Networking/Attributes/MethodRpcAttribute.cs b/Reactor/Networking/Attributes/MethodRpcAttribute.cs index 3eb0ffe..0f336dd 100644 --- a/Reactor/Networking/Attributes/MethodRpcAttribute.cs +++ b/Reactor/Networking/Attributes/MethodRpcAttribute.cs @@ -10,21 +10,49 @@ using Reactor.Utilities; namespace Reactor.Networking.Attributes; +/// +/// Automatically registers a method rpc. +/// [AttributeUsage(AttributeTargets.Method)] public sealed class MethodRpcAttribute : Attribute { private static readonly HashSet _registeredAssemblies = new(); + /// + /// Gets the id of the rpc. + /// public uint Id { get; } - public SendOption Option { get; set; } = SendOption.Reliable; + + /// + /// Gets or sets the send option of the rpc. + /// + public SendOption SendOption { get; set; } = SendOption.Reliable; + + /// + /// Gets or sets the local handling of the rpc. + /// public RpcLocalHandling LocalHandling { get; set; } = RpcLocalHandling.Before; + + /// + /// Gets or sets a value indicating whether the rpc should be sent immediately. + /// public bool SendImmediately { get; set; } + /// + /// Initializes a new instance of the class. + /// + /// The id of the rpc. public MethodRpcAttribute(uint id) { Id = id; } + /// + /// Registers all method rpc's annotated with in the specified . + /// + /// This is called automatically on plugin assemblies so you probably don't need to call this. + /// The assembly to search. + /// The plugin to register the rpc to. public static void Register(Assembly assembly, BasePlugin plugin) { if (_registeredAssemblies.Contains(assembly)) return; @@ -43,7 +71,7 @@ public sealed class MethodRpcAttribute : Attribute try { - var customRpc = new MethodRpc(plugin, method, attribute.Id, attribute.Option, attribute.LocalHandling, attribute.SendImmediately); + var customRpc = new MethodRpc(plugin, method, attribute.Id, attribute.SendOption, attribute.LocalHandling, attribute.SendImmediately); PluginSingleton.Instance.CustomRpcManager.Register(customRpc); } catch (Exception e) diff --git a/Reactor/Networking/Attributes/ReactorModFlagsAttribute.cs b/Reactor/Networking/Attributes/ReactorModFlagsAttribute.cs index 0f1d8a0..9363cb9 100644 --- a/Reactor/Networking/Attributes/ReactorModFlagsAttribute.cs +++ b/Reactor/Networking/Attributes/ReactorModFlagsAttribute.cs @@ -4,17 +4,27 @@ using System.Reflection; namespace Reactor.Networking.Attributes; +/// +/// Describes the of the annotated plugin class. +/// [AttributeUsage(AttributeTargets.Class)] public sealed class ReactorModFlagsAttribute : Attribute { + /// + /// Gets flags of the mod. + /// public ModFlags Flags { get; } + /// + /// Initializes a new instance of the class. + /// + /// Flags of the mod. public ReactorModFlagsAttribute(ModFlags flags) { Flags = flags; } - public static ModFlags GetModFlags(Type type) + internal static ModFlags GetModFlags(Type type) { var attribute = type.GetCustomAttribute(); if (attribute != null) diff --git a/Reactor/Networking/Attributes/RegisterCustomRpcAttribute.cs b/Reactor/Networking/Attributes/RegisterCustomRpcAttribute.cs index fd19434..74d94f9 100644 --- a/Reactor/Networking/Attributes/RegisterCustomRpcAttribute.cs +++ b/Reactor/Networking/Attributes/RegisterCustomRpcAttribute.cs @@ -9,25 +9,33 @@ using Reactor.Utilities; namespace Reactor.Networking.Attributes; /// -/// Utility attribute for automatically registering CustomRpc +/// Automatically registers a rpc. /// [AttributeUsage(AttributeTargets.Class)] public sealed class RegisterCustomRpcAttribute : Attribute { private static readonly HashSet _registeredAssemblies = new(); + /// + /// Gets the id of the rpc. + /// public uint Id { get; } + /// + /// Initializes a new instance of the class. + /// + /// The id of the rpc. public RegisterCustomRpcAttribute(uint id) { Id = id; } /// - /// Registers all types marked with from the specified assembly as custom rpcs + /// Registers all rpc's annotated with in the specified . /// - /// - /// + /// This is called automatically on plugin assemblies so you probably don't need to call this. + /// The assembly to search. + /// The plugin to register the rpc to. public static void Register(Assembly assembly, BasePlugin plugin) { if (_registeredAssemblies.Contains(assembly)) return; diff --git a/Reactor/Networking/Extensions/ClientExtensions.cs b/Reactor/Networking/Extensions/ClientExtensions.cs index 287dfd3..42e025d 100644 --- a/Reactor/Networking/Extensions/ClientExtensions.cs +++ b/Reactor/Networking/Extensions/ClientExtensions.cs @@ -3,8 +3,17 @@ using InnerNet; namespace Reactor.Networking.Extensions; +/// +/// Provides extension methods for . +/// public static class ClientExtensions { + /// + /// Kicks a client with id equal to with a . + /// + /// The to send the message from. + /// The target client's id. + /// The kick reason. public static void KickWithReason(this InnerNetClient innerNetClient, int targetClientId, string reason) { var writer = MessageWriter.Get(SendOption.Reliable); @@ -22,6 +31,11 @@ public static class ClientExtensions writer.Recycle(); } + /// + /// Disconnects a local with a custom reason. + /// + /// The to disconnect. + /// The custom reason to disconnect with. public static void DisconnectWithReason(this InnerNetClient innerNetClient, string reason) { innerNetClient.LastCustomDisconnect = reason; diff --git a/Reactor/Networking/Extensions/ExtraMessageExtensions.cs b/Reactor/Networking/Extensions/ExtraMessageExtensions.cs index 7f35e88..f124fa0 100644 --- a/Reactor/Networking/Extensions/ExtraMessageExtensions.cs +++ b/Reactor/Networking/Extensions/ExtraMessageExtensions.cs @@ -5,6 +5,9 @@ using UnityEngine; namespace Reactor.Networking.Extensions; +/// +/// Provides extension methods for and . +/// public static class ExtraMessageExtensions { private const float MIN = -50f; @@ -15,6 +18,11 @@ public static class ExtraMessageExtensions return Mathf.Clamp((t - MIN) / (MAX - MIN), 0f, 1f); } + /// + /// Writes a to the . + /// + /// The to write to. + /// The to write. public static void Write(this MessageWriter writer, Vector2 value) { var x = (ushort) (ReverseLerp(value.x) * ushort.MaxValue); @@ -24,6 +32,11 @@ public static class ExtraMessageExtensions writer.Write(y); } + /// + /// Reads a from the . + /// + /// The to read from. + /// A from the . public static Vector2 ReadVector2(this MessageReader reader) { var x = reader.ReadUInt16() / (float) ushort.MaxValue; @@ -32,6 +45,12 @@ public static class ExtraMessageExtensions return new Vector2(Mathf.Lerp(MIN, MAX, x), Mathf.Lerp(MIN, MAX, y)); } + /// + /// Sends a message on the with an . + /// + /// The connection to send the message on. + /// The message to send. + /// The callback to invoke when this packet is acknowledged. public static void Send(this UdpConnection connection, MessageWriter msg, Action ackCallback) { if (msg.SendOption != SendOption.Reliable) diff --git a/Reactor/Networking/ModList.cs b/Reactor/Networking/ModList.cs index 2b1c174..89d0ad0 100644 --- a/Reactor/Networking/ModList.cs +++ b/Reactor/Networking/ModList.cs @@ -11,13 +11,24 @@ using Reactor.Networking.Patches; namespace Reactor.Networking; +/// +/// Represents currently loaded mods. +/// public static class ModList { + /// + /// Gets current mods. + /// public static IReadOnlyCollection Current { get; private set; } = null!; private static readonly Dictionary _modById = new(); private static readonly Dictionary _modByPluginType = new(); + /// + /// Gets a mod by it's id. + /// + /// The id of the mod. + /// The mod with the specified . public static Mod GetById(string id) { return _modById[id]; @@ -42,6 +53,12 @@ public static class ModList return _netIdByMod[mod]; } + /// + /// Reads a reference from the . + /// + /// The to read from. + /// A from the . + /// This will try to read by net id and fallback to a regular id otherwise. public static Mod ReadMod(this MessageReader reader) { var netId = reader.ReadPackedUInt32(); @@ -54,16 +71,22 @@ public static class ModList return GetById(id); } - public static void Write(this MessageWriter writer, Mod mod) + /// + /// Writes a reference to the . + /// + /// The to write to. + /// The to write. + /// This will write the net id if is true, regular id otherwise. + public static void Write(this MessageWriter writer, Mod value) { - if (mod.IsRequiredOnAllClients) + if (value.IsRequiredOnAllClients) { - writer.WritePacked(mod.GetNetId()); + writer.WritePacked(value.GetNetId()); } else { writer.WritePacked(0); - writer.Write(mod.Id); + writer.Write(value.Id); } } diff --git a/Reactor/Networking/Patches/ReactorConnection.cs b/Reactor/Networking/Patches/ReactorConnection.cs index c550546..b0155e7 100644 --- a/Reactor/Networking/Patches/ReactorConnection.cs +++ b/Reactor/Networking/Patches/ReactorConnection.cs @@ -3,10 +3,19 @@ using InnerNet; namespace Reactor.Networking.Patches; +/// +/// Provides information about the reactor protocol state of the current connection. +/// public class ReactorConnection { + /// + /// Gets the syncer. + /// public Syncer? Syncer { get; internal set; } + /// + /// Gets the current instance of . + /// public static ReactorConnection? Instance { get; private set; } [HarmonyPatch] @@ -30,8 +39,18 @@ public class ReactorConnection } } +/// +/// Specifies who syncs the mod list and handles compatibility. +/// public enum Syncer { + /// + /// A custom region server. + /// Server, + + /// + /// The host of the game. + /// Host, } diff --git a/Reactor/Networking/Rpc/CustomRpc.cs b/Reactor/Networking/Rpc/CustomRpc.cs index a310b83..fe161eb 100644 --- a/Reactor/Networking/Rpc/CustomRpc.cs +++ b/Reactor/Networking/Rpc/CustomRpc.cs @@ -5,77 +5,137 @@ using InnerNet; namespace Reactor.Networking.Rpc; +/// +/// Base type for custom rpc's but typed with generics. +/// +/// The type of the plugin the the rpc is attached to. +/// The type of the . +/// The type of the rpc data. public abstract class CustomRpc : UnsafeCustomRpc where TPlugin : BasePlugin where TInnerNetObject : InnerNetObject { + /// protected CustomRpc(TPlugin plugin, uint id) : base(plugin, id) { } + /// public TPlugin Plugin => (TPlugin) UnsafePlugin; + + /// public override Type InnerNetObjectType => typeof(TInnerNetObject); + /// public abstract void Write(MessageWriter writer, TData? data); + + /// public abstract TData Read(MessageReader reader); + + /// public abstract void Handle(TInnerNetObject innerNetObject, TData? data); + /// public override void UnsafeWrite(MessageWriter writer, object? data) { Write(writer, (TData?) data); } + /// public override object? UnsafeRead(MessageReader reader) { return Read(reader); } + /// public override void UnsafeHandle(InnerNetObject innerNetObject, object? data) { Handle((TInnerNetObject) innerNetObject, (TData?) data); } - public void Send(InnerNetObject netObject, TData data, bool immediately = false, Action? ackCallback = null) + /// + /// Sends this custom rpc on the specified with the specified . + /// + /// The to send the rpc on. + /// The data to send. + /// Whether to send it immediately. + /// The callback to invoke when this packet is acknowledged. + public void Send(InnerNetObject innerNetObject, TData data, bool immediately = false, Action? ackCallback = null) { - UnsafeSend(netObject, data, immediately, ackCallback: ackCallback); + UnsafeSend(innerNetObject, data, immediately, ackCallback: ackCallback); } - public void SendTo(InnerNetObject netObject, int targetId, TData data, Action? ackCallback = null) + /// + /// Sends this custom rpc on the specified with the specified to the specified target. + /// + /// The to send the rpc on. + /// Target client id, defaults to broadcast. + /// The data to send. + /// The callback to invoke when this packet is acknowledged. + public void SendTo(InnerNetObject innerNetObject, int targetClientId, TData data, Action? ackCallback = null) { - UnsafeSend(netObject, data, true, targetId, ackCallback); + UnsafeSend(innerNetObject, data, true, targetClientId, ackCallback); } } +/// +/// Base type for custom rpc's but typed with generics and without any data. +/// +/// The type of the plugin the the rpc is attached to. +/// The type of the . public abstract class CustomRpc : UnsafeCustomRpc where TPlugin : BasePlugin where TInnerNetObject : InnerNetObject { + /// protected CustomRpc(TPlugin plugin, uint id) : base(plugin, id) { } + /// public TPlugin Plugin => (TPlugin) UnsafePlugin; + + /// public override Type InnerNetObjectType => typeof(TInnerNetObject); + /// + /// Handles the rpc. + /// + /// The the rpc is being handled on. public abstract void Handle(TInnerNetObject innerNetObject); + /// public override void UnsafeWrite(MessageWriter writer, object? data) { } + /// public override object? UnsafeRead(MessageReader reader) { return null; } + /// public override void UnsafeHandle(InnerNetObject innerNetObject, object? data) { Handle((TInnerNetObject) innerNetObject); } - public void Send(InnerNetObject netObject, bool immediately = false, Action? ackCallback = null) + /// + /// Sends this custom rpc on the specified . + /// + /// The to send the rpc on. + /// Whether to send it immediately. + /// The callback to invoke when this packet is acknowledged. + public void Send(InnerNetObject innerNetObject, bool immediately = false, Action? ackCallback = null) { - UnsafeSend(netObject, immediately, ackCallback: ackCallback); + UnsafeSend(innerNetObject, immediately, ackCallback: ackCallback); } - public void SendTo(InnerNetObject netObject, int targetId, Action? ackCallback = null) + /// + /// Sends this custom rpc on the specified to the specified target. + /// + /// The to send the rpc on. + /// Target client id, defaults to broadcast. + /// The callback to invoke when this packet is acknowledged. + public void SendTo(InnerNetObject innerNetObject, int targetClientId, Action? ackCallback = null) { - UnsafeSend(netObject, null, true, targetId, ackCallback); + UnsafeSend(innerNetObject, null, true, targetClientId, ackCallback); } } diff --git a/Reactor/Networking/Rpc/CustomRpcManager.cs b/Reactor/Networking/Rpc/CustomRpcManager.cs index 1406969..de260ee 100644 --- a/Reactor/Networking/Rpc/CustomRpcManager.cs +++ b/Reactor/Networking/Rpc/CustomRpcManager.cs @@ -10,16 +10,29 @@ using Reactor.Utilities; namespace Reactor.Networking.Rpc; +/// +/// Manages custom rpc's. +/// public class CustomRpcManager { + /// + /// Rpc call id for the reactor's custom rpc wrapper. + /// public const byte CallId = byte.MaxValue; private readonly List _list = new(); private readonly Dictionary>> _map = new(); + /// + /// Gets a list of all custom rpc's. + /// public IReadOnlyList List => _list.AsReadOnly(); - public UnsafeCustomRpc Register(UnsafeCustomRpc customRpc) + /// + /// Registers a custom rpc. + /// + /// The custom rpc to register. + public void Register(UnsafeCustomRpc customRpc) { customRpc.Manager = this; _list.Add(customRpc); @@ -31,10 +44,17 @@ public class CustomRpcManager { typeof(Rpc<>).MakeGenericType(customRpc.GetType()).GetProperty("Instance")!.SetValue(null, customRpc); } - - return customRpc; } + /// + /// Implementation of for reading and handling reactor custom rpc's. + /// You can use this in your custom to use reactor custom rpc's on it. + /// + /// The the rpc is handled on. + /// The call id of the rpc. + /// The with the data of the rpc. + /// A value indicating whether the rpc was handled. + /// Reactor patches base game s to use this. public static bool HandleRpc(InnerNetObject innerNetObject, byte callId, MessageReader reader) { if (callId == CallId) diff --git a/Reactor/Networking/Rpc/MethodRpc.cs b/Reactor/Networking/Rpc/MethodRpc.cs index ebcb76f..46e2266 100644 --- a/Reactor/Networking/Rpc/MethodRpc.cs +++ b/Reactor/Networking/Rpc/MethodRpc.cs @@ -15,10 +15,24 @@ using Reactor.Utilities; namespace Reactor.Networking.Rpc; +/// +/// Provides a custom rpc for method rpc. +/// public class MethodRpc : UnsafeCustomRpc { - public delegate object HandleDelegate(InnerNetObject innerNetObject, object[] args); + private delegate object HandleDelegate(InnerNetObject innerNetObject, object[] args); + private readonly HandleDelegate _handle; + + /// + /// Initializes a new instance of the class. + /// + /// The plugin that the rpc is attached to. + /// The method of the method rpc. + /// The id of the rpc. + /// The send option of the rpc. + /// The local handling method of the rpc. + /// The value indicating whether the rpc should be sent immediately. public MethodRpc(BasePlugin plugin, MethodInfo method, uint id, SendOption option, RpcLocalHandling localHandling, bool sendImmediately) : base(plugin, id) { Method = method; @@ -54,35 +68,58 @@ public class MethodRpc : UnsafeCustomRpc InnerNetObjectType = method.DeclaringType; } - Handle = Hook(method, parameters, method.IsStatic); + _handle = Hook(method, parameters, method.IsStatic); } + /// + /// Gets the method of the method rpc. + /// public MethodInfo Method { get; } - public HandleDelegate Handle { get; } + /// protected internal override bool IsSingleton => false; + /// public override Type InnerNetObjectType { get; } + + /// public override RpcLocalHandling LocalHandling { get; } + + /// public override SendOption SendOption { get; } + + /// + /// Gets a value indicating whether the method rpc should be sent immediately. + /// public bool SendImmediately { get; } + /// public override void UnsafeWrite(MessageWriter writer, object? data) { var args = (object[]) data!; MessageSerializer.Serialize(writer, args); } + /// public override object UnsafeRead(MessageReader reader) { - var args = MessageSerializer.Deserialize(reader, this); + var parameters = Method.GetParameters(); + var args = new object[parameters.Length - 1]; + + for (var i = 1; i < parameters.Length; i++) + { + var parameter = parameters[i]; + args[i - 1] = reader.Deserialize(parameter.ParameterType); + } + return args; } + /// public override void UnsafeHandle(InnerNetObject innerNetObject, object? data) { var args = (object[]) data!; - var result = Handle(innerNetObject, args); + var result = _handle(innerNetObject, args); if (result is IEnumerator enumerator) { @@ -90,6 +127,11 @@ public class MethodRpc : UnsafeCustomRpc } } + /// + /// Sends this method rpc on the specified with the specified . + /// + /// The to send the rpc on. + /// The arguments to serialize and send. public void Send(InnerNetObject innerNetObject, object[] args) { UnsafeSend(innerNetObject, args, SendImmediately); @@ -98,7 +140,7 @@ public class MethodRpc : UnsafeCustomRpc private static readonly MethodInfo _sendMethod = AccessTools.Method(typeof(MethodRpc), nameof(Send)); /// - /// Hooks the rpc with a dynamic method that sends it + /// Hooks the rpc with a dynamic method that sends it. /// private HandleDelegate Hook(MethodInfo method, ParameterInfo[] parameters, bool isStatic) { diff --git a/Reactor/Networking/Rpc/PlayerCustomRpc.cs b/Reactor/Networking/Rpc/PlayerCustomRpc.cs index 5468c3b..47c9d8a 100644 --- a/Reactor/Networking/Rpc/PlayerCustomRpc.cs +++ b/Reactor/Networking/Rpc/PlayerCustomRpc.cs @@ -3,36 +3,69 @@ using BepInEx.Unity.IL2CPP; namespace Reactor.Networking.Rpc; +/// +/// Shorthand for with as the TInnerNetObject. +/// +/// The type of the plugin the the rpc is attached to. +/// The type of the rpc data. public abstract class PlayerCustomRpc : CustomRpc where TPlugin : BasePlugin { + /// protected PlayerCustomRpc(TPlugin plugin, uint id) : base(plugin, id) { } + /// + /// Sends this custom rpc on the local player with the specified . + /// + /// The data to send. + /// Whether to send it immediately. + /// The callback to invoke when this packet is acknowledged. public void Send(TData data, bool immediately = false, Action? ackCallback = null) { Send(PlayerControl.LocalPlayer, data, immediately, ackCallback); } - public void SendTo(int targetId, TData data, Action? ackCallback = null) + /// + /// Sends this custom rpc on the local player with the specified to the specified target. + /// + /// Target client id, defaults to broadcast. + /// The data to send. + /// The callback to invoke when this packet is acknowledged. + public void SendTo(int targetClientId, TData data, Action? ackCallback = null) { - SendTo(PlayerControl.LocalPlayer, targetId, data, ackCallback); + SendTo(PlayerControl.LocalPlayer, targetClientId, data, ackCallback); } } +/// +/// Shorthand for with as the TInnerNetObject. +/// +/// The type of the plugin the the rpc is attached to. public abstract class PlayerCustomRpc : CustomRpc where TPlugin : BasePlugin { + /// protected PlayerCustomRpc(TPlugin plugin, uint id) : base(plugin, id) { } + /// + /// Sends this custom rpc on the local player. + /// + /// Whether to send it immediately. + /// The callback to invoke when this packet is acknowledged. public void Send(bool immediately = false, Action? ackCallback = null) { Send(PlayerControl.LocalPlayer, immediately, ackCallback); } - public void SendTo(int targetId, Action? ackCallback = null) + /// + /// Sends this custom rpc on the local player to the specified target. + /// + /// Target client id, defaults to broadcast. + /// The callback to invoke when this packet is acknowledged. + public void SendTo(int targetClientId, Action? ackCallback = null) { - SendTo(PlayerControl.LocalPlayer, targetId, ackCallback); + SendTo(PlayerControl.LocalPlayer, targetClientId, ackCallback); } } diff --git a/Reactor/Networking/Rpc/Rpc.cs b/Reactor/Networking/Rpc/Rpc.cs index ee09389..f43c710 100644 --- a/Reactor/Networking/Rpc/Rpc.cs +++ b/Reactor/Networking/Rpc/Rpc.cs @@ -2,10 +2,17 @@ using System; namespace Reactor.Networking.Rpc; +/// +/// Provides access to singleton custom rpc's. +/// +/// The type of the custom rpc. public static class Rpc where T : UnsafeCustomRpc { private static T? _instance; + /// + /// Gets an instance of rpc. + /// public static T Instance { get diff --git a/Reactor/Networking/Rpc/RpcLocalHandling.cs b/Reactor/Networking/Rpc/RpcLocalHandling.cs index ee4aafb..7c9bf9a 100644 --- a/Reactor/Networking/Rpc/RpcLocalHandling.cs +++ b/Reactor/Networking/Rpc/RpcLocalHandling.cs @@ -1,8 +1,22 @@ namespace Reactor.Networking.Rpc; +/// +/// Specifies how the rpc should be handled locally. +/// public enum RpcLocalHandling { + /// + /// Don't do anything. + /// None, + + /// + /// Invoke Handle before sending. + /// Before, + + /// + /// Invoke Handle after sending. + /// After, } diff --git a/Reactor/Networking/Rpc/UnsafeCustomRpc.cs b/Reactor/Networking/Rpc/UnsafeCustomRpc.cs index f210527..e04af54 100644 --- a/Reactor/Networking/Rpc/UnsafeCustomRpc.cs +++ b/Reactor/Networking/Rpc/UnsafeCustomRpc.cs @@ -11,20 +11,53 @@ using Buffer = Il2CppSystem.Buffer; namespace Reactor.Networking.Rpc; +/// +/// Base type for custom rpc's. +/// public abstract class UnsafeCustomRpc { internal CustomRpcManager? Manager { get; set; } + + /// + /// Gets a value indicating whether the rpc is a singleton and can be used with . + /// protected internal virtual bool IsSingleton => true; + /// + /// Gets the id of the rpc. + /// public uint Id { get; } + + /// + /// Gets the plugin of the rpc. + /// public BasePlugin UnsafePlugin { get; } + + /// + /// Gets the mod of the rpc. + /// public Mod Mod { get; } + /// + /// Gets the InnerNetObject type the rpc targets. + /// public abstract Type InnerNetObjectType { get; } + /// + /// Gets the send option of the rpc. + /// public virtual SendOption SendOption => SendOption.Reliable; + + /// + /// Gets the local handling method of the rpc. + /// public abstract RpcLocalHandling LocalHandling { get; } + /// + /// Initializes a new instance of the class. + /// + /// The plugin that the rpc is attached to. + /// The id of the rpc. protected UnsafeCustomRpc(BasePlugin plugin, uint id) { UnsafePlugin = plugin; @@ -32,10 +65,35 @@ public abstract class UnsafeCustomRpc Id = id; } + /// + /// Writes to the . + /// + /// The writer to write to. + /// The data to be written. public abstract void UnsafeWrite(MessageWriter writer, object? data); + + /// + /// Reads rpc data from the . + /// + /// The reader to read from. + /// The rpc data from the . public abstract object? UnsafeRead(MessageReader reader); + + /// + /// Handles rpc data. + /// + /// The the rpc is being handled on. + /// The data associated with the rpc. public abstract void UnsafeHandle(InnerNetObject innerNetObject, object? data); + /// + /// Sends this custom rpc on the specified with the specified . + /// + /// The to send the rpc on. + /// The data to send. + /// Whether to send it immediately. + /// Target client id, defaults to broadcast. + /// The callback to invoke when this packet is acknowledged. public void UnsafeSend(InnerNetObject innerNetObject, object? data, bool immediately = false, int targetClientId = -1, Action? ackCallback = null) { if (innerNetObject == null) throw new ArgumentNullException(nameof(innerNetObject)); diff --git a/Reactor/Networking/Serialization/InnerNetObjectConverter.cs b/Reactor/Networking/Serialization/InnerNetObjectConverter.cs index 93cf47c..ab66380 100644 --- a/Reactor/Networking/Serialization/InnerNetObjectConverter.cs +++ b/Reactor/Networking/Serialization/InnerNetObjectConverter.cs @@ -8,30 +8,41 @@ using Reactor.Networking.Attributes; namespace Reactor.Networking.Serialization; +/// +/// Provides a MessageConverter for . +/// [MessageConverter] -public class InnerNetObjectConverter : MessageConverter +public class InnerNetObjectConverter : MessageConverter { private static readonly MethodInfo _readNetObject = AccessTools.Method(typeof(MessageExtensions), nameof(MessageExtensions.ReadNetObject)); - private static readonly Dictionary> _readNetObjectMap = new(); + private static readonly Dictionary> _readNetObjectMap = new(); - public static InnerNetObject ReadNetObject(MessageReader reader, Type t) + /// + /// but without generics. + /// + /// The to read from. + /// The type of the . + /// The read from the . + public static InnerNetObject? ReadNetObject(MessageReader reader, Type innerNetObjectType) { - if (_readNetObjectMap.TryGetValue(t, out var value)) + if (_readNetObjectMap.TryGetValue(innerNetObjectType, out var value)) { return value(reader); } - var @delegate = _readNetObject.MakeGenericMethod(t).CreateDelegate>(); - _readNetObjectMap[t] = @delegate; + var @delegate = _readNetObject.MakeGenericMethod(innerNetObjectType).CreateDelegate>(); + _readNetObjectMap[innerNetObjectType] = @delegate; return @delegate(reader); } - public override void Write(MessageWriter writer, InnerNetObject value) + /// + public override void Write(MessageWriter writer, InnerNetObject? value) { - MessageExtensions.WriteNetObject(writer, value); + writer.WriteNetObject(value); } - public override InnerNetObject Read(MessageReader reader, Type objectType) + /// + public override InnerNetObject? Read(MessageReader reader, Type objectType) { return ReadNetObject(reader, objectType); } diff --git a/Reactor/Networking/Serialization/MessageConverter.cs b/Reactor/Networking/Serialization/MessageConverter.cs index 2019464..05c6762 100644 --- a/Reactor/Networking/Serialization/MessageConverter.cs +++ b/Reactor/Networking/Serialization/MessageConverter.cs @@ -3,26 +3,60 @@ using Hazel; namespace Reactor.Networking.Serialization; +/// +/// Base type for MessageConverter's. +/// public abstract class UnsafeMessageConverter { + /// + /// Writes the to the . + /// + /// The to write to. + /// The value to write. public abstract void UnsafeWrite(MessageWriter writer, object value); + + /// + /// Reads an object of from the . + /// + /// The to read from. + /// The type of the object being read. + /// The object read from the . public abstract object UnsafeRead(MessageReader reader, Type objectType); + /// + /// Checks whether this MessageConverter can convert the specified type. + /// + /// The type to check. + /// A value indicating whether this MessageConverter can convert the specified type. public abstract bool CanConvert(Type objectType); } +/// +/// Base type for MessageConverter's but typed with generics. +/// +/// The type of the value being converted. public abstract class MessageConverter : UnsafeMessageConverter { + /// public abstract void Write(MessageWriter writer, T value); + /// + /// Reads a from the . + /// + /// The to read from. + /// The type of the object being read. + /// The object read from the . public abstract T Read(MessageReader reader, Type objectType); + /// public override bool CanConvert(Type objectType) { return typeof(T).IsAssignableFrom(objectType); } + /// public override void UnsafeWrite(MessageWriter writer, object value) => Write(writer, (T) value); + /// public override object UnsafeRead(MessageReader reader, Type objectType) => Read(reader, objectType)!; } diff --git a/Reactor/Networking/Serialization/MessageSerializer.cs b/Reactor/Networking/Serialization/MessageSerializer.cs index a11799c..3f92591 100644 --- a/Reactor/Networking/Serialization/MessageSerializer.cs +++ b/Reactor/Networking/Serialization/MessageSerializer.cs @@ -3,23 +3,34 @@ using System.Collections.Generic; using System.Linq; using Hazel; using Reactor.Networking.Extensions; -using Reactor.Networking.Rpc; using UnityEngine; namespace Reactor.Networking.Serialization; +/// +/// Provides de/serializing of objects from/into /. +/// public static class MessageSerializer { private static List MessageConverters { get; } = new(); private static Dictionary MessageConverterMap { get; } = new(); + /// + /// Registers a MessageConverter. + /// + /// The MessageConverter to be registered. public static void Register(UnsafeMessageConverter messageConverter) { MessageConverters.Add(messageConverter); MessageConverterMap.Clear(); } + /// + /// Finds a MessageConverter for the specified . + /// + /// The type of an object. + /// A MessageConverted that can convert the specified . public static UnsafeMessageConverter? FindConverter(Type type) { if (MessageConverterMap.TryGetValue(type, out var value)) @@ -33,6 +44,11 @@ public static class MessageSerializer return converter; } + /// + /// Serializes to the . + /// + /// The to write to. + /// The args to be written. public static void Serialize(MessageWriter writer, object[] args) { foreach (var arg in args) @@ -41,9 +57,14 @@ public static class MessageSerializer } } - public static void Serialize(this MessageWriter writer, object o) + /// + /// Serializes an to the . + /// + /// The to write to. + /// The to be written. + public static void Serialize(this MessageWriter writer, object @object) { - switch (o) + switch (@object) { case int i: writer.WritePacked(i); @@ -73,84 +94,76 @@ public static class MessageSerializer writer.Write(i); break; default: - var converter = FindConverter(o.GetType()); + var converter = FindConverter(@object.GetType()); if (converter != null) { - converter.UnsafeWrite(writer, o); + converter.UnsafeWrite(writer, @object); break; } - throw new NotSupportedException("Couldn't serialize " + o.GetType()); + throw new NotSupportedException("Couldn't serialize " + @object.GetType()); } } - public static object[] Deserialize(MessageReader reader, MethodRpc methodRpc) + /// + /// Deserializes an of from the . + /// + /// The to read from. + /// The of the object. + /// An from the . + public static object Deserialize(this MessageReader reader, Type objectType) { - var parameters = methodRpc.Method.GetParameters(); - var args = new object[parameters.Length - 1]; - - for (var i = 1; i < parameters.Length; i++) - { - var parameter = parameters[i]; - args[i - 1] = reader.Deserialize(parameter.ParameterType); - } - - return args; - } - - public static object Deserialize(this MessageReader reader, Type t) - { - if (t == typeof(int)) + if (objectType == typeof(int)) { return reader.ReadPackedInt32(); } - if (t == typeof(uint)) + if (objectType == typeof(uint)) { return reader.ReadPackedUInt32(); } - if (t == typeof(byte)) + if (objectType == typeof(byte)) { return reader.ReadByte(); } - if (t == typeof(float)) + if (objectType == typeof(float)) { return reader.ReadSingle(); } - if (t == typeof(sbyte)) + if (objectType == typeof(sbyte)) { return reader.ReadSByte(); } - if (t == typeof(ushort)) + if (objectType == typeof(ushort)) { return reader.ReadUInt16(); } - if (t == typeof(bool)) + if (objectType == typeof(bool)) { return reader.ReadBoolean(); } - if (t == typeof(Vector2)) + if (objectType == typeof(Vector2)) { return reader.ReadVector2(); } - if (t == typeof(string)) + if (objectType == typeof(string)) { return reader.ReadString(); } - var converter = FindConverter(t); + var converter = FindConverter(objectType); if (converter != null) { - return converter.UnsafeRead(reader, t); + return converter.UnsafeRead(reader, objectType); } - throw new NotSupportedException("Couldn't deserialize " + t); + throw new NotSupportedException("Couldn't deserialize " + objectType); } } diff --git a/Reactor/Patches/Fixes/CursorPosPatch.cs b/Reactor/Patches/Fixes/CursorPosPatch.cs index 01fc3f3..912ebc2 100644 --- a/Reactor/Patches/Fixes/CursorPosPatch.cs +++ b/Reactor/Patches/Fixes/CursorPosPatch.cs @@ -6,7 +6,7 @@ using UnityEngine; namespace Reactor.Patches.Fixes; /// -/// "Fixes" an issue where empty TextBoxes have wrong cursor positions +/// "Fixes" an issue where empty TextBoxes have wrong cursor positions. /// [HarmonyPatch(typeof(TextMeshProExtensions), nameof(TextMeshProExtensions.CursorPos))] internal static class CursorPosPatch diff --git a/Reactor/Patches/Fixes/ServerInfoFixesPatch.cs b/Reactor/Patches/Fixes/ServerInfoFixesPatch.cs index 33244af..b1dce94 100644 --- a/Reactor/Patches/Fixes/ServerInfoFixesPatch.cs +++ b/Reactor/Patches/Fixes/ServerInfoFixesPatch.cs @@ -17,9 +17,7 @@ internal static class ServerInfoFixesPatch Info($"Joining {__instance.networkAddress}:{__instance.networkPort}"); } - /// - /// Fixes hardcoded port and filters out IPv6 in DnsRegionInfo - /// + // Fixes hardcoded port and filters out IPv6 in DnsRegionInfo. [HarmonyPatch(typeof(DnsRegionInfo), nameof(DnsRegionInfo.PopulateServers))] [HarmonyPrefix] public static bool FixPopulateServers(DnsRegionInfo __instance) diff --git a/Reactor/Patches/Miscellaneous/StandaloneSteamPatch.cs b/Reactor/Patches/Miscellaneous/StandaloneSteamPatch.cs index b1b7dd1..0e6a33a 100644 --- a/Reactor/Patches/Miscellaneous/StandaloneSteamPatch.cs +++ b/Reactor/Patches/Miscellaneous/StandaloneSteamPatch.cs @@ -6,7 +6,7 @@ using HarmonyLib; namespace Reactor.Patches.Miscellaneous; /// -/// Allows launching steam builds outside of steam +/// Allows launching steam builds outside of steam. /// [HarmonyPatch] internal static class StandaloneSteamPatch diff --git a/Reactor/Patches/ReactorVersionShower.cs b/Reactor/Patches/ReactorVersionShower.cs index f5ac84f..d381e8f 100644 --- a/Reactor/Patches/ReactorVersionShower.cs +++ b/Reactor/Patches/ReactorVersionShower.cs @@ -10,13 +10,20 @@ using Version = SemanticVersioning.Version; namespace Reactor.Patches; +/// +/// Shows the reactor version on the main menu. +/// public static class ReactorVersionShower { + /// + /// Gets the text. + /// public static TextMeshPro? Text { get; private set; } - public static event TextUpdatedHandler? TextUpdated; - - public delegate void TextUpdatedHandler(TextMeshPro text); + /// + /// Occurs when is updated. + /// + public static event Action? TextUpdated; internal static void Initialize() { @@ -59,6 +66,9 @@ public static class ReactorVersionShower return $"{version.Major}.{version.Minor}.{version.Patch}{(version.PreRelease == null ? string.Empty : $"-{version.PreRelease}")}"; } + /// + /// Updates with reactor version and fires . + /// public static void UpdateText() { if (Text == null) return; diff --git a/Reactor/Reactor.csproj b/Reactor/Reactor.csproj index cf0fca3..f532132 100644 --- a/Reactor/Reactor.csproj +++ b/Reactor/Reactor.csproj @@ -5,6 +5,7 @@ Core mod and API for Among Us true + true true diff --git a/Reactor/ReactorPlugin.cs b/Reactor/ReactorPlugin.cs index ec5d606..228bc3d 100644 --- a/Reactor/ReactorPlugin.cs +++ b/Reactor/ReactorPlugin.cs @@ -18,17 +18,28 @@ using UnityEngine.SceneManagement; namespace Reactor; +/// +/// Reactor's main class. +/// [BepInAutoPlugin("gg.reactor.api")] [BepInProcess("Among Us.exe")] public partial class ReactorPlugin : BasePlugin { + /// + /// Gets harmony instance. + /// public Harmony Harmony { get; } = new(Id); + + /// + /// Gets custom rpc manager. + /// public CustomRpcManager CustomRpcManager { get; } = new(); - public ConfigEntry? AllowVanillaServers { get; private set; } + internal ConfigEntry? AllowVanillaServers { get; private set; } internal RegionInfoWatcher RegionInfoWatcher { get; } = new(); + /// public ReactorPlugin() { PluginSingleton.Instance = this; @@ -40,6 +51,7 @@ public partial class ReactorPlugin : BasePlugin MethodRpcAttribute.Initialize(); } + /// public override void Load() { AllowVanillaServers = Config.Bind("Features", "Allow vanilla servers", false, "Whether reactor should ignore servers not responding to modded handshake. This config is ignored if any plugin uses custom rpcs!"); @@ -63,6 +75,7 @@ public partial class ReactorPlugin : BasePlugin })); } + /// public override bool Unload() { Harmony.UnpatchSelf(); diff --git a/Reactor/Utilities/AssetBundleManager.cs b/Reactor/Utilities/AssetBundleManager.cs index 6cc0d43..6645864 100644 --- a/Reactor/Utilities/AssetBundleManager.cs +++ b/Reactor/Utilities/AssetBundleManager.cs @@ -10,10 +10,19 @@ using UnityEngine; namespace Reactor.Utilities; +/// +/// Provides a standard way of loading asset bundles from a file or embedded resource. +/// public static class AssetBundleManager { + /// + /// Extension of a asset bundle. + /// public const string BundleExtension = ".bundle"; + /// + /// Gets the target name of the current system. + /// public static string TargetName { get; } static AssetBundleManager() @@ -48,6 +57,11 @@ public static class AssetBundleManager } } + /// + /// Gets the file name for an asset bundle named . + /// + /// The name of the asset bundle. + /// File name of the asset bundle. public static string GetFileName(string assetBundleName) => $"{assetBundleName}-{TargetName}{BundleExtension}"; private static bool TryFindFile(Assembly assembly, string fileName, [NotNullWhen(true)] out string? path) @@ -85,11 +99,24 @@ public static class AssetBundleManager return false; } + /// + /// Synchronously loads an named from the calling assembly. + /// + /// The name of the asset bundle. + /// The loaded assetbundle. + /// Couldn't find an assetbundle named . public static AssetBundle Load(string name) { return Load(Assembly.GetCallingAssembly(), name); } + /// + /// Synchronously loads an named from the specified . + /// + /// The specified assembly. + /// The name of the asset bundle. + /// The loaded assetbundle. + /// Couldn't find an assetbundle named . public static AssetBundle Load(Assembly assembly, string name) { var fileName = GetFileName(name); @@ -107,11 +134,24 @@ public static class AssetBundleManager throw new AssetBundleNotFoundException(name); } + /// + /// Asynchronously loads an named from the calling assembly. + /// + /// The name of the asset bundle. + /// The loaded assetbundle. + /// Couldn't find an assetbundle named . public static AssetBundleCreateRequest LoadAsync(string name) { return LoadAsync(Assembly.GetCallingAssembly(), name); } + /// + /// Asynchronously loads an named from the specified . + /// + /// The specified assembly. + /// The name of the asset bundle. + /// The loaded assetbundle. + /// Couldn't find an assetbundle named . public static AssetBundleCreateRequest LoadAsync(Assembly assembly, string name) { var fileName = GetFileName(name); @@ -130,6 +170,9 @@ public static class AssetBundleManager } } +/// +/// The exception that is thrown when an assetbundle is not found. +/// public class AssetBundleNotFoundException : IOException { internal AssetBundleNotFoundException(string name) : base("Couldn't find an assetbundle named " + name) diff --git a/Reactor/Utilities/Attributes/RegisterInIl2CppAttribute.cs b/Reactor/Utilities/Attributes/RegisterInIl2CppAttribute.cs index 47ec0f6..0235d3f 100644 --- a/Reactor/Utilities/Attributes/RegisterInIl2CppAttribute.cs +++ b/Reactor/Utilities/Attributes/RegisterInIl2CppAttribute.cs @@ -8,20 +8,30 @@ using Il2CppInterop.Runtime.Injection; namespace Reactor.Utilities.Attributes; /// -/// Utility attribute for automatically calling +/// Automatically registers an il2cpp type using . /// [AttributeUsage(AttributeTargets.Class)] public sealed class RegisterInIl2CppAttribute : Attribute { private static readonly HashSet _registeredAssemblies = new(); + /// + /// Gets il2cpp interfaces to be injected with this type. + /// public Type[] Interfaces { get; } + /// + /// Initializes a new instance of the class without any interfaces. + /// public RegisterInIl2CppAttribute() { Interfaces = Type.EmptyTypes; } + /// + /// Initializes a new instance of the class with interfaces. + /// + /// Il2Cpp interfaces to be injected with this type. public RegisterInIl2CppAttribute(params Type[] interfaces) { Interfaces = interfaces; @@ -51,9 +61,10 @@ public sealed class RegisterInIl2CppAttribute : Attribute } /// - /// Registers in Il2Cpp all types marked with from the specified assembly.
+ /// Registers all Il2Cpp types annotated with in the specified . ///
- /// + /// This is called automatically on plugin assemblies so you probably don't need to call this. + /// The assembly to search. public static void Register(Assembly assembly) { if (_registeredAssemblies.Contains(assembly)) return; diff --git a/Reactor/Utilities/CanvasUtilities.cs b/Reactor/Utilities/CanvasUtilities.cs index 7c8b0dc..7ceff92 100644 --- a/Reactor/Utilities/CanvasUtilities.cs +++ b/Reactor/Utilities/CanvasUtilities.cs @@ -5,8 +5,15 @@ using UnityEngine.UI; namespace Reactor.Utilities; +/// +/// Provides utilities for working with unity canvas ui. +/// public static class CanvasUtilities { + /// + /// Creates a canvas. + /// + /// A canvas . public static GameObject CreateCanvas() { var gameObject = new GameObject("Canvas"); @@ -23,6 +30,10 @@ public static class CanvasUtilities return gameObject; } + /// + /// Creates an EventSystem. + /// + /// An EventSystem . public static GameObject CreateEventSystem() { var gameObject = new GameObject("EventSystem"); @@ -34,8 +45,11 @@ public static class CanvasUtilities } /// - /// Shortcut for empty texture + /// Creates an empty texture of specified and . /// + /// The width of the texture. + /// The height of the texture. + /// An empty texture of specified size. public static Texture2D CreateEmptyTexture(int width = 0, int height = 0) { return new Texture2D(width, height, TextureFormat.RGBA32, Texture.GenerateAllMips, false, IntPtr.Zero); diff --git a/Reactor/Utilities/Coroutines.cs b/Reactor/Utilities/Coroutines.cs index 319bf0f..d050a26 100644 --- a/Reactor/Utilities/Coroutines.cs +++ b/Reactor/Utilities/Coroutines.cs @@ -8,6 +8,9 @@ using UnityEngine; namespace Reactor.Utilities; +/// +/// Provides utilities for starting coroutines. +/// public static class Coroutines { [RegisterInIl2Cpp] @@ -33,20 +36,29 @@ public static class Coroutines private static readonly ConditionalWeakTable _ourCoroutineStore = new(); - [return: NotNullIfNotNull("routine")] - public static IEnumerator? Start(IEnumerator? routine) + /// + /// Starts a coroutine. + /// + /// The coroutine to start. + /// Specified . + [return: NotNullIfNotNull("coroutine")] + public static IEnumerator? Start(IEnumerator? coroutine) { - if (routine != null) + if (coroutine != null) { - _ourCoroutineStore.AddOrUpdate(routine, Component.Instance!.StartCoroutine(routine)); + _ourCoroutineStore.AddOrUpdate(coroutine, Component.Instance!.StartCoroutine(coroutine)); } - return routine; + return coroutine; } - public static void Stop(IEnumerator? enumerator) + /// + /// Stops a coroutine. + /// + /// The coroutine to stop. + public static void Stop(IEnumerator? coroutine) { - if (enumerator != null && _ourCoroutineStore.TryGetValue(enumerator, out var routine)) + if (coroutine != null && _ourCoroutineStore.TryGetValue(coroutine, out var routine)) { Component.Instance!.StopCoroutine(routine); } diff --git a/Reactor/Utilities/DefaultBundle.cs b/Reactor/Utilities/DefaultBundle.cs index 3de1e0e..8b104a3 100644 --- a/Reactor/Utilities/DefaultBundle.cs +++ b/Reactor/Utilities/DefaultBundle.cs @@ -4,8 +4,14 @@ using UnityEngine.UI; namespace Reactor.Utilities; +/// +/// Provides unity things that were stripped. +/// public static class DefaultBundle { + /// + /// Gets standard resources used for canvas ui. + /// public static DefaultControls.Resources StandardResources { get; internal set; } = null!; internal static void Load() diff --git a/Reactor/Utilities/Dispatcher.cs b/Reactor/Utilities/Dispatcher.cs index aedf8c6..7e5f25b 100644 --- a/Reactor/Utilities/Dispatcher.cs +++ b/Reactor/Utilities/Dispatcher.cs @@ -6,9 +6,15 @@ using UnityEngine; namespace Reactor.Utilities; +/// +/// Dispatches actions on Unity main thread. +/// [RegisterInIl2Cpp] public sealed class Dispatcher : MonoBehaviour { + /// + /// Gets the instance. + /// public static Dispatcher Instance { get; private set; } = null!; private readonly Queue _queue = new(); @@ -29,6 +35,10 @@ public sealed class Dispatcher : MonoBehaviour } } + /// + /// Enqueues an . + /// + /// The action to enqueue. [HideFromIl2Cpp] public void Enqueue(Action action) { diff --git a/Reactor/Utilities/Extensions/AssetBundleExtensions.cs b/Reactor/Utilities/Extensions/AssetBundleExtensions.cs index 596361a..000c63a 100644 --- a/Reactor/Utilities/Extensions/AssetBundleExtensions.cs +++ b/Reactor/Utilities/Extensions/AssetBundleExtensions.cs @@ -3,10 +3,20 @@ using UnityEngine; namespace Reactor.Utilities.Extensions; +/// +/// Provides extension methods for . +/// public static class AssetBundleExtensions { - public static T? LoadAsset(this AssetBundle assetBundle, string name) where T : Object + /// + /// Loads an asset with from the with the specified type. + /// + /// The to load the asset from. + /// The name of the asset. + /// The type of the asset. + /// The loaded asset or null if it wasn't found. + public static T? LoadAsset(this AssetBundle bundle, string name) where T : Object { - return assetBundle.LoadAsset(name, Il2CppType.Of())?.Cast(); + return bundle.LoadAsset(name, Il2CppType.Of())?.Cast(); } } diff --git a/Reactor/Utilities/Extensions/GUIExtensions.cs b/Reactor/Utilities/Extensions/GUIExtensions.cs index ff4a15e..394193e 100644 --- a/Reactor/Utilities/Extensions/GUIExtensions.cs +++ b/Reactor/Utilities/Extensions/GUIExtensions.cs @@ -3,13 +3,15 @@ using UnityEngine; namespace Reactor.Utilities.Extensions; /// -/// GUI utilities +/// Provides extension methods for unity imgui. /// public static class GUIExtensions { /// - /// Clamp Rect to screen size + /// Clamps to the screen size. /// + /// The to clamp. + /// A clamped rect. public static Rect ClampScreen(this Rect rect) { rect.x = Mathf.Clamp(rect.x, 0, Screen.width - rect.width); @@ -19,8 +21,10 @@ public static class GUIExtensions } /// - /// Reset Rect size + /// Set 's and to 0. /// + /// The to reset. + /// A rect with reset size. public static Rect ResetSize(this Rect rect) { rect.width = rect.height = 0; @@ -29,13 +33,23 @@ public static class GUIExtensions } /// - /// Create from + /// Creates a from the . /// - public static Sprite CreateSprite(this Texture2D tex) + /// Texture from which to obtain the sprite graphic. + /// Sprite's pivot point relative to its graphic rectangle. + /// The number of pixels in the sprite that correspond to one unit in world space. + /// A sprite. + public static Sprite CreateSprite(this Texture2D texture, Vector2? pivot = null, float pixelsPerUnit = 100f) { - return Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f, 0.5f), 100f); + return Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), pivot ?? new Vector2(0.5f, 0.5f), pixelsPerUnit); } + /// + /// Sets 's width and height. + /// + /// The to set the size of. + /// The width. + /// The height. public static void SetSize(this RectTransform rectTransform, float width, float height) { rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, width); diff --git a/Reactor/Utilities/Extensions/Il2CppInteropExtensions.cs b/Reactor/Utilities/Extensions/Il2CppInteropExtensions.cs index d13e1f6..41f58ed 100644 --- a/Reactor/Utilities/Extensions/Il2CppInteropExtensions.cs +++ b/Reactor/Utilities/Extensions/Il2CppInteropExtensions.cs @@ -3,8 +3,17 @@ using Il2CppInterop.Runtime.InteropTypes.Arrays; namespace Reactor.Utilities.Extensions; +/// +/// Provides extension methods for Il2CppInterop. +/// public static class Il2CppInteropExtensions { + /// + /// Creates a span over a . + /// + /// The array to create a span over. + /// The type of items in the . + /// A span. public static unsafe Span ToSpan(this Il2CppStructArray array) where T : unmanaged { return new Span(IntPtr.Add(array.Pointer, IntPtr.Size * 4).ToPointer(), array.Length); diff --git a/Reactor/Utilities/Extensions/RandomExtensions.cs b/Reactor/Utilities/Extensions/RandomExtensions.cs index fb6ea0d..369ec4a 100644 --- a/Reactor/Utilities/Extensions/RandomExtensions.cs +++ b/Reactor/Utilities/Extensions/RandomExtensions.cs @@ -4,29 +4,45 @@ using System.Linq; namespace Reactor.Utilities.Extensions; +/// +/// Provides Random related extension methods. +/// public static class RandomExtensions { /// - /// Returns random from using + /// Returns a random double that is within a specified range. /// - public static T? Random(this IEnumerable input, Random random) - { - var list = input as IList ?? input.ToList(); - return list.Count == 0 ? default : list[random.Next(0, list.Count)]; - } - - /// Returns a random double that is within a specified range. + /// The to get the random number from. + /// The minimum value of the range. + /// The maximum value of the range. + /// A random double that is within a specified range. public static double NextDouble(this Random random, double minValue, double maxValue) { return random.NextDouble() * (maxValue - minValue) + minValue; } /// - /// Returns random from + /// Returns a random from the . /// + /// The input enumerable to take the item from. + /// The type of items. + /// A random item from the enumerable. public static T? Random(this IEnumerable input) { var list = input as IList ?? input.ToList(); return list.Count == 0 ? default : list[UnityEngine.Random.Range(0, list.Count)]; } + + /// + /// Returns a random from the using . + /// + /// The input enumerable to take the item from. + /// The to get the random number from. + /// The type of items. + /// A random item from the enumerable. + public static T? Random(this IEnumerable input, Random random) + { + var list = input as IList ?? input.ToList(); + return list.Count == 0 ? default : list[random.Next(0, list.Count)]; + } } diff --git a/Reactor/Utilities/Extensions/ReflectionExtensions.cs b/Reactor/Utilities/Extensions/ReflectionExtensions.cs index db66c6f..0eeb8b7 100644 --- a/Reactor/Utilities/Extensions/ReflectionExtensions.cs +++ b/Reactor/Utilities/Extensions/ReflectionExtensions.cs @@ -14,17 +14,30 @@ using MethodInfo = System.Reflection.MethodInfo; namespace Reactor.Utilities.Extensions; +/// +/// Provides extension methods for reflection. +/// public static class ReflectionExtensions { + /// + /// Gets a for the specified . + /// + /// The . + /// A . public static Il2CppMethodInfo ToIl2CppMethodInfo(this MethodInfo methodInfo) { var il2CppMethodField = Il2CppInteropUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(methodInfo); if (il2CppMethodField == null) throw new ArgumentException($"'{methodInfo.Name}' is not an il2cpp method", nameof(methodInfo)); var il2CppMethod = (IntPtr) il2CppMethodField.GetValue(null)!; - return new Il2CppSystem.Reflection.MethodInfo(IL2CPP.il2cpp_method_get_object(il2CppMethod, IntPtr.Zero)); + return new Il2CppMethodInfo(IL2CPP.il2cpp_method_get_object(il2CppMethod, IntPtr.Zero)); } + /// + /// Gets enumerator's MoveNext type for the specified . + /// + /// The enumerator . + /// A for enumerator's MoveNext type. public static Il2CppSystemType GetEnumeratorMoveNextType(this Il2CppMethodInfo methodInfo) { var customAttribute = Il2CppCustomAttributeExtensions.GetCustomAttribute(methodInfo, Il2CppType.Of()).TryCast(); @@ -33,6 +46,11 @@ public static class ReflectionExtensions return customAttribute._StateMachineType_k__BackingField; } + /// + /// Gets a for the specified . + /// + /// The . + /// A . public static Type ToSystemType(this Il2CppSystemType type) { var result = Type.GetType(type.AssemblyQualifiedName); @@ -51,16 +69,37 @@ public static class ReflectionExtensions throw new TypeLoadException("Failed to find a system type for " + type.AssemblyQualifiedName); } + /// + /// Gets MoveNext for specified enumerator method. + /// + /// The enclosing type of the method. + /// The name of the method. + /// A . public static MethodInfo EnumeratorMoveNext(Type type, string methodName) { return AccessTools.Method(AccessTools.Method(type, methodName).ToIl2CppMethodInfo().GetEnumeratorMoveNextType().ToSystemType(), "MoveNext"); } - public static IEnumerable GetMethods(this Type type, BindingFlags bindingAttr, Type returnType, params Type[] parameterTypes) + /// + /// Gets all method from the with the specified , and . + /// + /// The type to search the methods in. + /// The . + /// The return type. + /// The parameter types. + /// An array of objects representing all methods defined for the current that match the specified binding constraints. + public static IEnumerable GetMethods(this Type type, BindingFlags bindingFlags, Type returnType, params Type[] parameterTypes) { - return type.GetMethods(bindingAttr).Where(x => x.ReturnType == returnType && x.GetParameters().Select(x => x.ParameterType).SequenceEqual(parameterTypes)); + return type.GetMethods(bindingFlags).Where(x => x.ReturnType == returnType && x.GetParameters().Select(x => x.ParameterType).SequenceEqual(parameterTypes)); } + /// + /// Gets all method from the with the specified and . + /// + /// The type to search the methods in. + /// The return type. + /// The parameter types. + /// An array of objects representing all methods defined for the current that match the specified binding constraints. public static IEnumerable GetMethods(this Type type, Type returnType, params Type[] parameterTypes) { return type.GetMethods(AccessTools.all, returnType, parameterTypes); diff --git a/Reactor/Utilities/SceneManagerUtilities.cs b/Reactor/Utilities/Extensions/SceneManagerExtensions.cs similarity index 78% rename from Reactor/Utilities/SceneManagerUtilities.cs rename to Reactor/Utilities/Extensions/SceneManagerExtensions.cs index a410b37..1867f1b 100644 --- a/Reactor/Utilities/SceneManagerUtilities.cs +++ b/Reactor/Utilities/Extensions/SceneManagerExtensions.cs @@ -3,13 +3,17 @@ using System.Diagnostics.CodeAnalysis; using UnityEngine.Events; using UnityEngine.SceneManagement; -namespace Reactor.Utilities; +namespace Reactor.Utilities.Extensions; -public static class SceneManagerUtilities +/// +/// Provides extension methods for . +/// +public static class SceneManagerExtensions { /// /// Adds a delegate to get one notification when a scene has loaded. /// + /// The action. [SuppressMessage("Naming", "CA1707:Identifiers should not contain underscores", Justification = "This supplements existing methods like add_sceneLoaded and remove_sceneLoaded")] public static void once_sceneLoaded(Action value) { diff --git a/Reactor/Utilities/Extensions/StreamExtensions.cs b/Reactor/Utilities/Extensions/StreamExtensions.cs index dd7b80e..5595af9 100644 --- a/Reactor/Utilities/Extensions/StreamExtensions.cs +++ b/Reactor/Utilities/Extensions/StreamExtensions.cs @@ -8,13 +8,20 @@ using Reactor.Utilities.Attributes; namespace Reactor.Utilities.Extensions; +/// +/// Provides extension methods for . +/// public static class StreamExtensions { + /// + /// Provides a which uses under the hood. + /// [RegisterInIl2Cpp] public class StreamWrapper : Il2CppSystem.IO.Stream { private readonly Stream _stream; + /// public StreamWrapper(Stream stream) : base(ClassInjector.DerivedConstructorPointer()) { ClassInjector.DerivedConstructorBody(this); @@ -29,31 +36,37 @@ public static class StreamExtensions return new Span(rawBuffer + offset, count); } + /// public override int Read(Il2CppStructArray buffer, int offset, int count) { return _stream.Read(GetSpan(buffer, offset, count)); } + /// public override void Write(Il2CppStructArray buffer, int offset, int count) { _stream.Write(GetSpan(buffer, offset, count)); } + /// public override void Flush() { _stream.Flush(); } + /// public override void Close() { _stream.Close(); } + /// public override void Dispose() { _stream.Dispose(); } + /// public override long Seek(long offset, Il2CppSystem.IO.SeekOrigin origin) { return _stream.Seek(offset, origin switch @@ -65,16 +78,25 @@ public static class StreamExtensions }); } + /// public override void SetLength(long value) { _stream.SetLength(value); } + /// public override bool CanRead => _stream.CanRead; + + /// public override bool CanSeek => _stream.CanSeek; + + /// public override bool CanWrite => _stream.CanWrite; + + /// public override long Length => _stream.Length; + /// public override long Position { get => _stream.Position; @@ -83,13 +105,17 @@ public static class StreamExtensions } /// - /// Wraps a System Stream into an Il2Cpp Stream + /// Wraps a into a . /// + /// The stream to wrap. + /// A for the specified . public static StreamWrapper AsIl2Cpp(this Stream stream) => new(stream); /// - /// Fully read stream, can be used as workaround for il2cpp streams. + /// Fully reads the stream. /// + /// The stream to read. + /// A byte array read from the . public static byte[] ReadFully(this Stream input) { using var ms = new MemoryStream(); diff --git a/Reactor/Utilities/Extensions/UnityExtensions.cs b/Reactor/Utilities/Extensions/UnityExtensions.cs index e12b2f4..3560b4c 100644 --- a/Reactor/Utilities/Extensions/UnityExtensions.cs +++ b/Reactor/Utilities/Extensions/UnityExtensions.cs @@ -2,6 +2,9 @@ using UnityEngine; namespace Reactor.Utilities.Extensions; +/// +/// Provides extension methods for unity. +/// public static class UnityExtensions { /// @@ -9,7 +12,7 @@ public static class UnityExtensions /// /// The color to be converted. /// Hexadecimal string representing the color. - /// https://docs.unity3d.com/ScriptReference/ColorUtility.ToHtmlStringRGBA.html + /// https://docs.unity3d.com/ScriptReference/ColorUtility.ToHtmlStringRGBA.html. public static string ToHtmlStringRGBA(this Color32 color) { return $"{color.r:X2}{color.g:X2}{color.b:X2}{color.a:X2}"; @@ -26,8 +29,10 @@ public static class UnityExtensions private static readonly int _addColor = Shader.PropertyToID("_AddColor"); /// - /// Sets color outline for renderers using default Among Us shader + /// Sets the outline for renderer using the default Among Us shader. /// + /// The renderer to set the color on. + /// The color or null to disable the outline. public static void SetOutline(this Renderer renderer, Color? color) { renderer.material.SetFloat(_outline, color.HasValue ? 1 : 0); diff --git a/Reactor/Utilities/Extensions/UnityObjectExtensions.cs b/Reactor/Utilities/Extensions/UnityObjectExtensions.cs index 81ffbd2..f87902c 100644 --- a/Reactor/Utilities/Extensions/UnityObjectExtensions.cs +++ b/Reactor/Utilities/Extensions/UnityObjectExtensions.cs @@ -1,42 +1,67 @@ using UnityEngine; +using UnityObject = UnityEngine.Object; namespace Reactor.Utilities.Extensions; +/// +/// Provides extension methods for . +/// public static class UnityObjectExtensions { /// - /// Stops from being destroyed + /// Stops from being destroyed. /// - /// Object to stop from being destroyed - /// Passed - public static T DontDestroy(this T obj) where T : Object + /// The object to stop from being destroyed. + /// The type of the object. + /// Passed . + public static T DontDestroy(this T obj) where T : UnityObject { obj.hideFlags |= HideFlags.HideAndDontSave; return obj.DontDestroyOnLoad(); } - public static T DontUnload(this T obj) where T : Object + /// + /// Stops from being unloaded. + /// + /// The object to stop from being unloaded. + /// The type of the object. + /// Passed . + public static T DontUnload(this T obj) where T : UnityObject { obj.hideFlags |= HideFlags.DontUnloadUnusedAsset; return obj; } - public static T DontDestroyOnLoad(this T obj) where T : Object + /// + /// Stops from being destroyed on load. + /// + /// The object to stop from being destroyed on load. + /// The type of the object. + /// Passed . + public static T DontDestroyOnLoad(this T obj) where T : UnityObject { - Object.DontDestroyOnLoad(obj); + UnityObject.DontDestroyOnLoad(obj); return obj; } - public static void Destroy(this Object obj) + /// + /// Destroys the . + /// + /// The object to destroy. + public static void Destroy(this UnityObject obj) { - Object.Destroy(obj); + UnityObject.Destroy(obj); } - public static void DestroyImmediate(this Object obj) + /// + /// Destroys the immediately. + /// + /// The object to destroy immediately. + public static void DestroyImmediate(this UnityObject obj) { - Object.DestroyImmediate(obj); + UnityObject.DestroyImmediate(obj); } } diff --git a/Reactor/Utilities/Il2CppEqualityComparer.cs b/Reactor/Utilities/Il2CppEqualityComparer.cs index 9096f7e..8064c28 100644 --- a/Reactor/Utilities/Il2CppEqualityComparer.cs +++ b/Reactor/Utilities/Il2CppEqualityComparer.cs @@ -3,10 +3,14 @@ using Il2CppSystem.Runtime.CompilerServices; namespace Reactor.Utilities; +/// public sealed class Il2CppEqualityComparer : IEqualityComparer where T : Il2CppSystem.Object { private static Il2CppEqualityComparer? _instance; + /// + /// Gets the instance. + /// public static Il2CppEqualityComparer Instance { get diff --git a/Reactor/Utilities/ImGui/DragWindow.cs b/Reactor/Utilities/ImGui/DragWindow.cs index 6635ea6..14c2545 100644 --- a/Reactor/Utilities/ImGui/DragWindow.cs +++ b/Reactor/Utilities/ImGui/DragWindow.cs @@ -4,20 +4,25 @@ using UnityEngine; namespace Reactor.Utilities.ImGui; +/// +/// Draggable version of . +/// public class DragWindow : Window { + /// public DragWindow(Rect rect, string title, Action func) : base(rect, title, func) { Func = id => { func(id); - UnityEngine.GUI.DragWindow(new Rect(0, 0, 10000, 20)); + GUI.DragWindow(new Rect(0, 0, 10000, 20)); Rect = Rect.ClampScreen(); }; } - public DragWindow(Rect rect, string title, Action func) : this(rect, title, id => func()) + /// + public DragWindow(Rect rect, string title, Action func) : this(rect, title, _ => func()) { } } diff --git a/Reactor/Utilities/ImGui/Window.cs b/Reactor/Utilities/ImGui/Window.cs index 9b19466..f9af416 100644 --- a/Reactor/Utilities/ImGui/Window.cs +++ b/Reactor/Utilities/ImGui/Window.cs @@ -4,22 +4,53 @@ using UnityEngine; namespace Reactor.Utilities.ImGui; +/// +/// Utility wrapper over .. +/// public class Window { private static int _lastWindowId; + /// + /// Gets the next window id. + /// + /// A window id. public static int NextWindowId() { return _lastWindowId++; } + /// + /// Gets or sets the id of the window. + /// public int Id { get; set; } = NextWindowId(); + /// + /// Gets or sets a value indicating whether the window is enabled and shown. + /// public bool Enabled { get; set; } = true; + + /// + /// Gets or sets the rect of the window. + /// public Rect Rect { get; set; } + + /// + /// Gets or sets the render function of the window. + /// public Action Func { get; set; } + + /// + /// Gets or sets the title of the window. + /// public string Title { get; set; } + /// + /// Initializes a new instance of the class. + /// + /// The rect. + /// The title. + /// The render function. public Window(Rect rect, string title, Action func) { Rect = rect; @@ -27,11 +58,15 @@ public class Window Func = func; } - public Window(Rect rect, string title, Action func) : this(rect, title, id => func()) + /// + public Window(Rect rect, string title, Action func) : this(rect, title, _ => func()) { } - public void OnGUI() + /// + /// Draws the window gui. + /// + public virtual void OnGUI() { if (Enabled) { diff --git a/Reactor/Utilities/Logger.cs b/Reactor/Utilities/Logger.cs index abcab0b..03e5e5d 100644 --- a/Reactor/Utilities/Logger.cs +++ b/Reactor/Utilities/Logger.cs @@ -5,8 +5,15 @@ using BepInEx.Unity.IL2CPP; namespace Reactor.Utilities; +/// +/// Provides singleton access to plugins logger. +/// +/// The type of the plugin. public static class Logger where T : BasePlugin { + /// + /// Gets the instance. + /// public static ManualLogSource Instance => PluginSingleton.Instance.Log; /// diff --git a/Reactor/Utilities/PluginSingleton.cs b/Reactor/Utilities/PluginSingleton.cs index 18937c0..0b4cf92 100644 --- a/Reactor/Utilities/PluginSingleton.cs +++ b/Reactor/Utilities/PluginSingleton.cs @@ -5,10 +5,17 @@ using BepInEx.Unity.IL2CPP; namespace Reactor.Utilities; +/// +/// Provides singleton access to plugins instance. +/// +/// The type of the plugin. public static class PluginSingleton where T : BasePlugin { private static T? _instance; + /// + /// Gets or sets an instance of plugin. + /// public static T Instance { get => _instance ??= IL2CPPChainloader.Instance.Plugins.Values.Select(x => x.Instance).OfType().Single(); diff --git a/Reactor/packages.lock.json b/Reactor/packages.lock.json index 4b7f1cb..a901255 100644 --- a/Reactor/packages.lock.json +++ b/Reactor/packages.lock.json @@ -10,9 +10,9 @@ }, "BepInEx.AutoPlugin": { "type": "Direct", - "requested": "[1.0.1, )", - "resolved": "1.0.1", - "contentHash": "G4YpTHG9rtkDJof+ld7Er4E+sCOlgsjG4bJ1itx1ub7dgff6qqHLy9ksX1ehgO0AdBOPVyVl/GKJg9o7iNl8HA==" + "requested": "[1.1.0, )", + "resolved": "1.1.0", + "contentHash": "/7Nmc1EA9lYlGBiyz6qPAaHvlcJHEjFZ1RFpGX+8EBj3GrgoX5kbpnZusuSHoOlLx0l+CnzKuQNE54B8UaGPyw==" }, "BepInEx.IL2CPP.MSBuild": { "type": "Direct", @@ -47,6 +47,15 @@ "Microsoft.SourceLink.Common": "1.1.1" } }, + "StyleCop.Analyzers": { + "type": "Direct", + "requested": "[1.2.0-beta.435, )", + "resolved": "1.2.0-beta.435", + "contentHash": "TADk7vdGXtfTnYCV7GyleaaRTQjfoSfZXprQrVMm7cSJtJbFc1QIbWPyLvrgrfGdfHbGmUPvaN4ODKNxg2jgPQ==", + "dependencies": { + "StyleCop.Analyzers.Unstable": "1.2.0.435" + } + }, "AssetRipper.VersionUtilities": { "type": "Transitive", "resolved": "1.2.1", @@ -323,6 +332,11 @@ "resolved": "2.0.2", "contentHash": "4EQgYdNZ92SyaO7YFk6olVnebF5V+jrHyMUjvPq89tLeMo8NSfgDF+6Zwq/lgh9j/0yfQp9Lkm0ZA0rUATCZFA==" }, + "StyleCop.Analyzers.Unstable": { + "type": "Transitive", + "resolved": "1.2.0.435", + "contentHash": "ouwPWZxbOV3SmCZxIRqHvljkSzkCyi1tDoMzQtDb/bRP8ctASV/iRJr+A2Gdj0QLaLmWnqTWDrH82/iP+X80Lg==" + }, "System.Collections": { "type": "Transitive", "resolved": "4.3.0",