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