Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
max_line_length = 120
max_line_length = 160
tab_width = 4
trim_trailing_whitespace = true
ij_continuation_indent_size = 4
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,32 +45,31 @@ public void AssemblyNamespaceDependenciesAreAvailable() {
Assert.DoesNotThrow(() => container.Get<DependencyB>());
}

[UsedImplicitly]
public class ManualDependency {

[Test]
public void AssemblyFilteredDependenciesAreAvailable() {
var container = new DependencyContainerBuilder()
.ScanAssembly(GetType().Assembly, it => typeof(IDependencyA).IsAssignableFrom(it))
.Build();
Assert.DoesNotThrow(() => container.Get<DependencyA>());
Assert.Throws<MissingDependencyException>(() => container.Get<DependencyB>());
}

[Dependency, UsedImplicitly]
public class DependencyA {
[UsedImplicitly]
public class ManualDependency;

}
public interface IDependencyA;

[Dependency, UsedImplicitly]
public class DependencyB {
public class DependencyA : IDependencyA;

}
[Dependency, UsedImplicitly]
public class DependencyB;

[UsedImplicitly]
public class SingletonAccessor {
public SingletonDependency Singleton { get; }

public SingletonAccessor(SingletonDependency singleton) {
Singleton = singleton;
}
public class SingletonAccessor(SingletonDependency singleton) {
public SingletonDependency Singleton { get; } = singleton;
}

public class SingletonDependency {

}
public class SingletonDependency;

}
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using HarmonyLib;
using JetBrains.Annotations;
using MultiplayerMod.Core.Dependency;
using MultiplayerMod.Core.Extensions;
using MultiplayerMod.Multiplayer.Chores;
using MultiplayerMod.Multiplayer.StateMachines.Configuration;
using MultiplayerMod.Test.Environment;
using MultiplayerMod.Test.GameRuntime;
using NUnit.Framework;
using static MultiplayerMod.Test.Core.Patch.Compatibility.PatchesCompatibilityMetadata;
Expand All @@ -13,6 +16,11 @@ namespace MultiplayerMod.Test.Core.Patch.Compatibility;
[TestFixture]
public class PatchesCompatibility : PlayableGameTest {

[ConfigureDependencies, UsedImplicitly]
private static void SetUp(DependencyContainerBuilder builder) {
builder.AddStateMachineAndChoreConfigurers();
}

[Test]
[Ignore("Manual run only")]
public void Generate() {
Expand All @@ -23,10 +31,8 @@ public void Generate() {

private static List<string> GetChoresStateMachines() {
var context = new StateMachineConfigurationContext(DependencyContainer);
ChoresMultiplayerConfiguration.Configuration
.Select(it => it.StatesConfigurer)
.NotNull()
.ForEach(it => it.Configure(context));
var configurers = DependencyContainer.Get<List<IStateMachineConfigurer>>();
configurers.ForEach(it => it.Configure(context));

return context.Configurations
.Select(it => it.StateMachineType)
Expand Down Expand Up @@ -54,11 +60,12 @@ public void Verify() {
var possiblyIncompatible = new List<string>();
foreach (var type in Metadata.Keys) {
var methods = type.GetAllMethods()
.Select(it => it.GetSignature(SignatureOptions.NoDeclaringType))
.Where(it => it.HasMethodBody())
.Select(it => new MethodMetadata(type, it.GetSignature(SignatureOptions.NoDeclaringType), HashAlgorithm.ComputeHash(it).ToHexString()))
.ToHashSet();
var diff = Metadata[type]
.Where(it => !methods.Contains(it.Key))
.Select(it => $"{type.GetSignature(SignatureOptions.Namespace)}->{it.Value.Signature}");
.Where(it => !methods.Contains(it.Value))
.Select(it => $"{type.GetSignature(SignatureOptions.Namespace)}::{it.Value.Signature}");
possiblyIncompatible.AddRange(diff);
}
if (possiblyIncompatible.Count > 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ public static class PatchesCompatibilityMetadata {
/// </summary>
[SuppressMessage("ReSharper", "ArrangeObjectCreationWhenTypeNotEvident")]
private static readonly List<MethodMetadata> methodsMetadata = [
new(typeof(AttackChore.States), "InitializeStates(StateMachine.BaseState&)", "76d0303d40ba0af708b454459541a2c0620c7abb"),
new(typeof(ThreatMonitor), "InitializeStates(StateMachine.BaseState&)", "fe07b4523742ada76bdfadf86e281046171db20d"),
new(typeof(IdleChore.States), "InitializeStates(StateMachine.BaseState&)", "e72be5f2d127b7a3a2362cb51c37c77e89e8a4df"),
new(typeof(IdleMonitor), "InitializeStates(StateMachine.BaseState&)", "1a64a103a806e7a88f9e51134681bfd9d821b01a"),
new(typeof(MoveToSafetyChore.States), "InitializeStates(StateMachine.BaseState&)", "17d5fdb636b49e3942fb13457dcb63d38801a363"),
new(typeof(SafeCellMonitor), "InitializeStates(StateMachine.BaseState&)", "ba30939582cc4532763ffb2250a03d175f2a6db7"),
new(typeof(IdleStates), "InitializeStates(StateMachine.BaseState&)", "5b018cf4bf9b0df92febb4d544f9163cf30c18b6")
new(typeof(AttackChore.States), "InitializeStates(StateMachine.BaseState&)", "6cd856c28e54e7624864c1e1b5e0788a5c01947b"),
new(typeof(ThreatMonitor), "InitializeStates(StateMachine.BaseState&)", "e5fb426a773768edde854bd4ad8320028aa90f90"),
new(typeof(IdleChore.States), "InitializeStates(StateMachine.BaseState&)", "1f76fc606b70389d3ae9871387aec31753e0abce"),
new(typeof(IdleMonitor), "InitializeStates(StateMachine.BaseState&)", "fb533a4363ea6d7b9b3f5d7a2eed1bb7418fa775"),
new(typeof(IdleStates), "InitializeStates(StateMachine.BaseState&)", "1b7443635910b683ccd9a8dd03d17d8fbe4e1c4f"),
new(typeof(MoveToSafetyChore.States), "InitializeStates(StateMachine.BaseState&)", "c2edad05c741576db71406d7d2e97ccdb0e37186"),
new(typeof(SafeCellMonitor), "InitializeStates(StateMachine.BaseState&)", "fb3ac7a4f21a714afc82921f811ebd4d3aa6a3e9")
];

public static readonly HashAlgorithm HashAlgorithm = SHA1.Create();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System.Reflection;
using MultiplayerMod.Core.Reflection;
using NUnit.Framework;

namespace MultiplayerMod.Test.Core.Reflection;

[TestFixture]
public class DynamicFieldAccessorTests {

private const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;

private int intValue = 1;
private string stringValue = "one";

[Test]
public void GetValueTypeField() {
var field = typeof(DynamicFieldAccessorTests).GetField(nameof(intValue), flags)!;
var accessor = new DynamicFieldAccessor<int>(this, field);
Assert.That(accessor.Get(), Is.EqualTo(1));
}

[Test]
public void SetValueTypeField() {
var field = typeof(DynamicFieldAccessorTests).GetField(nameof(intValue), flags)!;
var accessor = new DynamicFieldAccessor<int>(this, field);
accessor.Set(2);
Assert.That(intValue, Is.EqualTo(2));
}

[Test]
public void GetObjectField() {
var field = typeof(DynamicFieldAccessorTests).GetField(nameof(stringValue), flags)!;
var accessor = new DynamicFieldAccessor<string>(this, field);
Assert.That(accessor.Get(), Is.EqualTo("one"));
}

[Test]
public void SetObjectField() {
var field = typeof(DynamicFieldAccessorTests).GetField(nameof(stringValue), flags)!;
var accessor = new DynamicFieldAccessor<string>(this, field);
accessor.Set("two");
Assert.That(stringValue, Is.EqualTo("two"));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using MultiplayerMod.Core.Reflection;
using NUnit.Framework;

namespace MultiplayerMod.Test.Core.Reflection;

[TestFixture]
public class DynamicMethodDelegateTests {

private const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;

[Test]
public void ReturnValueType() {
var method = typeof(DynamicMethodDelegateTests).GetMethod(nameof(GetFive), flags)!;
var dynamic = new DynamicMethodDelegate(this, method);
var result = (int) dynamic.Invoke()!;
Assert.That(result, Is.EqualTo(5));
}

[Test]
public void ReturnObject() {
var method = typeof(DynamicMethodDelegateTests).GetMethod(nameof(GetList), flags)!;
var dynamic = new DynamicMethodDelegate(this, method);
var result = (List<string>) dynamic.Invoke()!;
Assert.That(result, Is.EqualTo(new[] { "one", "two", "three" }));
}

[Test]
public void ArrayParameter() {
var method = typeof(DynamicMethodDelegateTests).GetMethod(nameof(ArraySum), flags)!;
var dynamic = new DynamicMethodDelegate(this, method);
var result = (int) dynamic.Invoke(new [] { 1, 2, 3 })!;
Assert.That(result, Is.EqualTo(6));
}

[Test]
public void ObjectParameter() {
var method = typeof(DynamicMethodDelegateTests).GetMethod(nameof(Concat), flags)!;
var dynamic = new DynamicMethodDelegate(this, method);
var result = (string) dynamic.Invoke("Foo", "Bar")!;
Assert.That(result, Is.EqualTo("FooBar"));
}

[Test]
public void ReferenceArgument() {
var method = typeof(DynamicMethodDelegateTests).GetMethod(nameof(IncreaseByRef), flags)!;
var dynamic = new DynamicMethodDelegate(this, method);
var args = new object[] { 42 };
var result = dynamic.Invoke(args);
Assert.That(result, Is.EqualTo(42));
Assert.That(args[0], Is.EqualTo(43));
}

private int GetFive() => 5;

private int IncreaseByRef(ref int value) => value++;

private List<string> GetList() => ["one", "two", "three"];

private int ArraySum(int[] array) => array.Sum();

private string Concat(string a, string b) => a + b;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using MultiplayerMod.Core.Dependency;
using MultiplayerMod.Core.Events;
using MultiplayerMod.ModRuntime.Context;
using MultiplayerMod.Multiplayer;
using MultiplayerMod.Multiplayer.Chores;
using MultiplayerMod.Multiplayer.Commands.Registry;
using MultiplayerMod.Multiplayer.Objects;
using MultiplayerMod.Multiplayer.Players;
using MultiplayerMod.Multiplayer.StateMachines.Configuration;
using MultiplayerMod.Test.Environment.Network;
using MultiplayerMod.Test.Multiplayer;

namespace MultiplayerMod.Test.Environment;

public static class DependencyContainerBuilderExtensions {

public static DependencyContainerBuilder AddSystem(this DependencyContainerBuilder builder) => builder
.AddType<TestRuntime>()
.AddType<EventDispatcher>()
.AddType<ExecutionLevelManager>()
.AddType<ExecutionContextManager>()
.AddType<MultiplayerGame>()
.AddType<MultiplayerObjects>()
.AddType<MultiplayerCommandRegistry>();

public static DependencyContainerBuilder AddNetworking(this DependencyContainerBuilder builder) => builder
.AddType<TestMultiplayerServer>()
.AddType<TestMultiplayerClient>()
.AddSingleton(new MultiplayerTools.TestPlayerProfileProvider(new PlayerProfile("Test")))
.AddSingleton(new TestMultiplayerClientId(1));

public static DependencyContainerBuilder AddStateMachineAndChoreConfigurers(this DependencyContainerBuilder builder) => builder
.ScanAssembly(
typeof(IChoreConfigurer).Assembly,
it => typeof(IChoreConfigurer).IsAssignableFrom(it) || typeof(IStateMachineConfigurer).IsAssignableFrom(it)
);

}
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,11 @@ public void Send(IMultiplayerClientId player, IMultiplayerCommand command) {
(player as TestMultiplayerClientId)!.Client.Receive(CommandTools.Copy(command));
}

public void Send(IMultiplayerCommand command, MultiplayerCommandOptions options) {
public void SendAll(IMultiplayerCommand command) => Send(command, MultiplayerCommandOptions.None);

public void Send(IMultiplayerCommand command) => Send(command,MultiplayerCommandOptions.SkipHost);

private void Send(IMultiplayerCommand command, MultiplayerCommandOptions options) {
var oldRuntime = (TestRuntime) Runtime.Instance;
try {
runtime.Activate();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.Collections;
using HarmonyLib;
using JetBrains.Annotations;
using UnityEngine;

namespace MultiplayerMod.Test.Environment.Unity.Patches.Unity;

[UsedImplicitly]
[HarmonyPatch(typeof(MonoBehaviour))]
public class MonoBehaviourPatch {

[UsedImplicitly]
[HarmonyPrefix]
[HarmonyPatch(nameof(MonoBehaviour.StartCoroutine), typeof(IEnumerator))]
private static bool StartCoroutine(MonoBehaviour __instance, IEnumerator routine) {
// Disabled for now, process if required.
return false;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,16 @@ IEnumerable<CodeInstruction> instructions
};
}

[UsedImplicitly]
[HarmonyTranspiler]
[HarmonyPatch(nameof(SystemInfo.operatingSystem), MethodType.Getter)]
private static IEnumerable<CodeInstruction> SystemInfo_get_OperatingSystem(
IEnumerable<CodeInstruction> instructions
) {
return new List<CodeInstruction> {
new(OpCodes.Ldstr, "Windows 11 (10.0.22621) 64bit"),
new(OpCodes.Ret)
};
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using HarmonyLib;
using MultiplayerMod.Core.Extensions;
using MultiplayerMod.Core.Scheduling;
Expand All @@ -17,7 +16,7 @@ public static class UnityTestRuntime {
private static readonly Harmony harmony = new("Unity.Test");

private static readonly List<Type> unityPatches = typeof(UnityTestRuntime).Assembly.GetTypes()
.Where(type => type.Namespace.StartsWith(typeof(UnityTestRuntime).Namespace + ".Patches"))
.Where(type => type.Namespace?.StartsWith(typeof(UnityTestRuntime).Namespace + ".Patches") == true)
.ToList();

private static readonly Dictionary<Type, Dictionary<UnityEvent, MethodInfo>> eventMethodCache = new();
Expand Down
14 changes: 2 additions & 12 deletions src/MultiplayerMod.Test/GameRuntime/PlayableGameTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
using MultiplayerMod.Test.Environment.Patches;
using MultiplayerMod.Test.Environment.Unity;
using MultiplayerMod.Test.GameRuntime.Patches;
using MultiplayerMod.Test.Multiplayer;
using NUnit.Framework;
using UnityEngine;

Expand Down Expand Up @@ -183,18 +182,9 @@ protected static unsafe void ResetGrid(int widthInCells, int heightInCells) {

private static void SetupDependencies() {
var builder = new DependencyContainerBuilder()
.AddType<MultiplayerGame>()
.AddType<MultiplayerObjects>()
.AddType<ExecutionLevelManager>()
.AddType<ExecutionContextManager>()
.AddType<EventDispatcher>()
.AddType<TestRuntime>()
.AddSystem()
.AddNetworking()
.AddType<ControlFlowCustomizer>()
.AddType<TestMultiplayerServer>()
.AddType<TestMultiplayerClient>()
.AddSingleton(new MultiplayerTools.TestPlayerProfileProvider(new PlayerProfile("Test")))
.AddSingleton(new TestMultiplayerClientId(1))
.AddType<MultiplayerCommandRegistry>()
.AddSingleton(Harmony);

ResolveCustomizationProviders<ConfigureDependenciesAttribute>(methods => methods
Expand Down
Loading