// Start is called before the first frame update void Start() { GameFieldSize = GameManager.instance.GameFieldSize; CheckForErrors(); if (GameFieldCells == null) { GameFieldCells = new Cell[GameFieldSize.x, GameFieldSize.y]; } BuildGameField(); }
private bool addition(TwoInts.Request req, ref TwoInts.Response resp) { resp.sum = req.a + req.b; long sum = resp.sum; Dispatcher.BeginInvoke(new Action(() => { math.Content = "" + req.a + " + " + req.b + " = ??\n" + sum; })); return true; }
// In this test twoInts is passed to Caller2 on the stack. Then twoInts.Value1 and twoInts.Value2 were passed to Callee2 in registers. // Since Calee2 also has a stack argument (i3) and the call is dispatched as a fast tail call, // it's set up in the incoming argument area of Caller2. JIT lowering code needs to ensure that twoInts // in that area is not overwritten by i3 before twoInts.Value1 and twoInts.Value2 are computed. The JIT had a bug in that code // because twoInts.Value1 and twoInts.Value2 were represented as GT_LCL_FLD and they were incorrectly converted into GT_LCL_VAR // resulting in an identical value passed for both fields. public static bool Caller2(object parameters, long l, double doubleArg, TypedDouble typedDouble1, TwoInts twoInts, TypedDouble typedDouble3) { double param = 19.0; Console.Write("Let's "); Console.Write("Discourage "); Console.Write("Inlining "); Console.Write("Of "); Console.Write("Caller "); Console.Write("Into "); Console.WriteLine("Main."); return(Callee2(twoInts.Value1, twoInts.Value2, typedDouble1.Value, param, 11)); }
public void TestDetoursExt() { lock (TestObject.Lock) { // The following use cases are not meant to be usage examples. // Please take a look at DetourTest and HookTest instead. // Just to verify that having a first chance exception handler doesn't introduce any conflicts. AppDomain.CurrentDomain.FirstChanceException += OnFirstChanceException; #if true using (NativeDetour d = new NativeDetour( // .GetNativeStart() to enforce a native detour. typeof(TestObject).GetMethod("TestStaticMethod").Pin().GetNativeStart(), typeof(DetourExtTest).GetMethod("TestStaticMethod_A") )) { int staticResult = d.GenerateTrampoline <Func <int, int, int> >()(2, 3); Console.WriteLine($"TestStaticMethod(2, 3): {staticResult}"); Assert.Equal(6, staticResult); staticResult = TestObject.TestStaticMethod(2, 3); Console.WriteLine($"TestStaticMethod(2, 3): {staticResult}"); Assert.Equal(12, staticResult); } // We can't create a backup for this. MethodBase dm; using (DynamicMethodDefinition dmd = new DynamicMethodDefinition(typeof(TestObject).GetMethod("TestStaticMethod"))) { dm = dmd.Generate(); } using (NativeDetour d = new NativeDetour( dm, typeof(DetourExtTest).GetMethod("TestStaticMethod_A") )) { int staticResult = d.GenerateTrampoline <Func <int, int, int> >()(2, 3); Console.WriteLine($"TestStaticMethod(2, 3): {staticResult}"); Assert.Equal(6, staticResult); // FIXME: dm.Invoke can fail with a release build in mono 5.X! // staticResult = (int) dm.Invoke(null, new object[] { 2, 3 }); staticResult = ((Func <int, int, int>)dm.CreateDelegate <Func <int, int, int> >())(2, 3); Console.WriteLine($"TestStaticMethod(2, 3): {staticResult}"); Assert.Equal(12, staticResult); } #endif // This wasn't provided by anyone and instead is just an internal test. #if true MethodInfo dummyA = typeof(DetourExtTest).GetMethod("DummyA").Pin(); MethodInfo dummyB = typeof(DetourExtTest).GetMethod("DummyB").Pin(); MethodInfo dummyC = (MethodInfo)dm; IntPtr dummyAPtr = dummyA.GetNativeStart(); Assert.True(DetourHelper.Runtime.TryMemAllocScratchCloseTo(dummyAPtr, out IntPtr allocAPtr, -1) != 0); Assert.NotEqual(IntPtr.Zero, allocAPtr); IntPtr dummyBPtr = dummyB.GetNativeStart(); Assert.True(DetourHelper.Runtime.TryMemAllocScratchCloseTo(dummyBPtr, out IntPtr allocBPtr, -1) != 0); Assert.NotEqual(IntPtr.Zero, allocBPtr); IntPtr dummyCPtr = dummyC.GetNativeStart(); Assert.True(DetourHelper.Runtime.TryMemAllocScratchCloseTo(dummyCPtr, out IntPtr allocCPtr, -1) != 0); Assert.NotEqual(IntPtr.Zero, allocCPtr); Console.WriteLine($"dummyAPtr: 0x{(long) dummyAPtr:X16}"); Console.WriteLine($"allocAPtr: 0x{(long) allocAPtr:X16}"); Console.WriteLine($"dummyBPtr: 0x{(long) dummyBPtr:X16}"); Console.WriteLine($"allocBPtr: 0x{(long) allocBPtr:X16}"); Console.WriteLine($"dummyCPtr: 0x{(long) dummyCPtr:X16}"); Console.WriteLine($"allocCPtr: 0x{(long) allocCPtr:X16}"); // Close scratch allocs should ideally be within a 1 GiB range of the original method. Assert.True(Math.Abs((long)dummyAPtr - (long)allocAPtr) < 1024 * 1024 * 1024, "dummyAPtr and allocAPtr are too far apart."); Assert.True(Math.Abs((long)dummyBPtr - (long)allocBPtr) < 1024 * 1024 * 1024, "dummyBPtr and allocBPtr are too far apart."); Assert.True(Math.Abs((long)dummyCPtr - (long)allocCPtr) < 1024 * 1024 * 1024, "dummyCPtr and allocCPtr are too far apart."); #endif // This was provided by Chicken Bones (tModLoader). // GetEncoding behaves differently on .NET Core and even between .NET Framework versions, // which is why this test only applies to Mono, preferably on Linux to verify if flagging // regions of code as read-writable and then read-executable works for AOT'd code. #if false using (Hook h = new Hook( typeof(Encoding).GetMethod("GetEncoding", new Type[] { typeof(string) }), new Func <Func <string, Encoding>, string, Encoding>((orig, name) => { if (name == "IBM437") { return(null); } return(orig(name)); }) )) { Assert.Null(Encoding.GetEncoding("IBM437")); } #endif // This was provided by a Harmony user. // TextWriter's methods (including all overrides) were unable to be hooked on some runtimes. // FIXME: .NET 5 introduces similar behavior for macOS and Linux, but RD isn't ready for that. See DetourRuntimeNETPlatform for more info. #if true using (MemoryStream ms = new MemoryStream()) { using (StreamWriter writer = new StreamWriter(ms, Encoding.UTF8, 1024, true)) { // In case anyone needs to debug this mess anytime in the future ever again: /*/ * MethodBase m = typeof(StreamWriter).GetMethod("Write", new Type[] { typeof(string) }); * Console.WriteLine($"meth: 0x{(long) m?.MethodHandle.Value:X16}"); * Console.WriteLine($"getf: 0x{(long) m?.MethodHandle.GetFunctionPointer():X16}"); * Console.WriteLine($"fptr: 0x{(long) m?.GetLdftnPointer():X16}"); * Console.WriteLine($"nats: 0x{(long) m?.GetNativeStart():X16}"); * /**/ // Debugger.Break(); writer.Write("A"); using (Hook h = new Hook( typeof(StreamWriter).GetMethod("Write", new Type[] { typeof(string) }), new Action <Action <StreamWriter, string>, StreamWriter, string>((orig, self, value) => { orig(self, "-"); }) )) { // Debugger.Break(); writer.Write("B"); } writer.Write("C"); } ms.Seek(0, SeekOrigin.Begin); using (StreamReader reader = new StreamReader(ms, Encoding.UTF8, false, 1024, true)) { Assert.Equal("A-C", reader.ReadToEnd()); } } #endif #if NETFRAMEWORK && true Assert.Equal("A", new SqlCommand("A").CommandText); using (Hook h = new Hook( typeof(SqlCommand).GetConstructor(new Type[] { typeof(string) }), new Action <Action <SqlCommand, string>, SqlCommand, string>((orig, self, value) => { orig(self, "-"); }) )) { Assert.Equal("-", new SqlCommand("B").CommandText); } Assert.Equal("C", new SqlCommand("C").CommandText); #endif // This was provided by tModLoader. // The .NET Framework codepath failed on making the method writable the for a single user. #if NETFRAMEWORK && true try { throw new Exception(); } catch (Exception e) { Assert.NotEqual("", e.StackTrace.Trim()); } using (Hook h = Type.GetType("Mono.Runtime") != null ? // Mono new Hook( typeof(Exception).GetMethod("GetStackTrace", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance), new Func <Func <Exception, bool, string>, Exception, bool, string>((orig, self, fNeedFileInfo) => { return(""); }) ) : // .NET new Hook( typeof(StackTrace).GetConstructor(new[] { typeof(Exception), typeof(bool) }), new Action <Action <StackTrace, Exception, bool>, StackTrace, Exception, bool>((orig, self, e, fNeedFileInfo) => { orig(self, e, fNeedFileInfo); DynamicData.Set(self, new { frames = new StackFrame[0], m_iNumOfFrames = 0, m_iMethodsToSkip = 0 }); }) )) { try { throw new Exception(); } catch (Exception e) { Assert.Equal("", e.StackTrace.Trim()); } } try { throw new Exception(); } catch (Exception e) { Assert.NotEqual("", e.StackTrace.Trim()); } #endif // This was provided by a Harmony user. // Theoretically this should be a DynamicMethodDefinition test but who knows what else this will unearth. #if true try { new Thrower(1); } catch (Exception e) { Assert.Equal("1", e.Message); } using (Hook h = new Hook( typeof(Thrower).GetConstructor(new Type[] { typeof(int) }), new Action <Action <Thrower, int>, Thrower, int>((orig, self, a) => { try { orig(self, a + 2); } catch (Exception e) { throw new Exception($"{a} + 2 = {e.Message}"); } }) )) { try { new Thrower(1); } catch (Exception e) { Assert.Equal("1 + 2 = 3", e.Message); } } try { new Thrower(1); } catch (Exception e) { Assert.Equal("1", e.Message); } #endif // This was provided by tModLoader. #if true using (Hook h = new Hook( typeof(Process).GetMethod("Start", BindingFlags.Public | BindingFlags.Instance), new Func <Func <Process, bool>, Process, bool>((orig, self) => { return(orig(self)); }) )) { } #endif // This was provided by WEGFan from the Everest team. // It should be preferably tested on x86, as it's where the struct size caused problems. #if true Assert.Equal(new TwoInts() { A = 11111111, B = 22222222 }, DummyTwoInts()); using (Hook h = new Hook( typeof(DetourExtTest).GetMethod("DummyTwoInts", BindingFlags.NonPublic | BindingFlags.Instance), new Func <Func <DetourExtTest, TwoInts>, DetourExtTest, TwoInts>((orig, self) => { TwoInts rv = orig(self); rv.A *= 2; rv.B *= 3; return(rv); }) )) { Assert.Equal(new TwoInts() { A = 11111111 * 2, B = 22222222 * 3 }, DummyTwoInts()); } Assert.Equal(new TwoInts() { A = 11111111, B = 22222222 }, DummyTwoInts()); #endif // This was provided by a Harmony user. // The "struct virtual override" edge case fix itself has got a weird edge case with "struct interface implementations". // Note that .NET Framework differs too heavily and .NET Core 2.1 and older inline the getter. #if NET5_0_OR_GREATER Assert.Equal( new KeyValuePair <int, int>(default, default),