tModLoader v0.11.8.9
A mod to make and play Terraria mods
MonoModHooks.cs
Go to the documentation of this file.
1using MonoMod.RuntimeDetour;
2using MonoMod.RuntimeDetour.HookGen;
3using MonoMod.Utils;
4using System;
5using System.Collections.Generic;
6using System.Diagnostics;
7using System.Linq;
8using System.Reflection;
9using System.Reflection.Emit;
10using Terraria.ModLoader.Core;
11using Terraria.ModLoader.Default;
12
13namespace Terraria.ModLoader
14{
15 public static class MonoModHooks
16 {
17 private static Dictionary<Type, string> defaultAliases = new Dictionary<Type, string> {
18 { typeof(object), "object" },
19 { typeof(bool), "bool" },
20 { typeof(float), "float" },
21 { typeof(double), "double" },
22 { typeof(decimal), "decimal" },
23 { typeof(byte), "byte" },
24 { typeof(sbyte), "sbyte" },
25 { typeof(short), "short" },
26 { typeof(ushort), "ushort" },
27 { typeof(int), "int" },
28 { typeof(uint), "uint" },
29 { typeof(long), "long" },
30 { typeof(ulong), "ulong" },
31 { typeof(char), "char" },
32 { typeof(string), "string" }
33 };
34
35 private static DetourModManager manager = new DetourModManager();
36 private static HashSet<Assembly> NativeDetouringGranted = new HashSet<Assembly>();
37
38 private static bool isInitialized;
39 internal static void Initialize() {
40 if (isInitialized)
41 return;
42
43 HookEndpointManager.OnAdd += (m, d) => {
44 Logging.tML.Debug($"Hook On.{StringRep(m)} added by {GetOwnerName(d)}");
45 return true;
46 };
47 HookEndpointManager.OnRemove += (m, d) => {
48 Logging.tML.Debug($"Hook On.{StringRep(m)} removed by {GetOwnerName(d)}");
49 return true;
50 };
51 HookEndpointManager.OnModify += (m, d) => {
52 Logging.tML.Debug($"Hook IL.{StringRep(m)} modified by {GetOwnerName(d)}");
53 return true;
54 };
55 HookEndpointManager.OnUnmodify += (m, d) => {
56 Logging.tML.Debug($"Hook IL.{StringRep(m)} unmodified by {GetOwnerName(d)}");
57 return true;
58 };
59
60 manager.OnHook += (asm, from, to, target) => {
62 Logging.tML.Debug($"Hook {StringRep(from)} -> {StringRep(to)} by {asm.GetName().Name}");
63 };
64
65 manager.OnILHook += (asm, from, manipulator) => {
67 Logging.tML.Debug($"ILHook {StringRep(from)} by {asm.GetName().Name}");
68 };
69
70 manager.OnDetour += (asm, from, to) => {
72 Logging.tML.Debug($"Detour {StringRep(from)} -> {StringRep(to)} by {asm.GetName().Name}");
73 };
74
75 manager.OnNativeDetour += (asm, method, from, to) => {
77 Logging.tML.Debug($"NativeDetour {StringRep(method)} [{from} -> {to}] by {asm.GetName().Name}");
78 };
79
80 isInitialized = true;
81 }
82
83 private static void NativeAccessCheck(Assembly asm) {
84 if (NativeDetouringGranted.Contains(asm))
85 return;
86
87 throw new UnauthorizedAccessException(
88 $"Native detouring permissions not granted to {asm.GetName().Name}. \n" +
89 $"Mods should use HookEndpointManager for compatibility. \n" +
90 $"If Detour or NativeDetour are required, call MonoModHooks.RequestNativeAccess()");
91 }
92
93 public static void RequestNativeAccess() {
94 var stack = new StackTrace();
95 var asm = stack.GetFrame(1).GetMethod().DeclaringType.Assembly;
97 Logging.tML.Warn($"Granted native detouring access to {asm.GetName().Name}");
98 }
99
100 private static string GetOwnerName(Delegate d) {
101 return d.Method.DeclaringType.Assembly.GetName().Name;
102 }
103
104 private static string StringRep(MethodBase m) {
105 var paramString = string.Join(", ", m.GetParameters().Select(p => {
106 var t = p.ParameterType;
107 var s = "";
108
109 if (t.IsByRef) {
110 s = p.IsOut ? "out " : "ref ";
111 t = t.GetElementType();
112 }
113
114 return s + (defaultAliases.TryGetValue(t, out string n) ? n : t.Name);
115 }));
116
117 var owner = m.DeclaringType?.FullName ??
118 (m is DynamicMethod ? "dynamic" : "unknown");
119 return $"{owner}::{m.Name}({paramString})";
120 }
121
122 internal static void RemoveAll(Mod mod) {
123 if (mod is ModLoaderMod)
124 return;
125
126 int hooks = 0, detours = 0, ndetours = 0;
127 bool OnHookUndo(object obj) {
128 hooks++;
129 return true;
130 }
131 bool OnDetourUndo(object obj) {
132 detours++;
133 return true;
134 }
135 bool OnNativeDetourUndo(object obj) {
136 ndetours++;
137 return true;
138 }
139
140 Hook.OnUndo += OnHookUndo;
141 Detour.OnUndo += OnDetourUndo;
142 NativeDetour.OnUndo += OnNativeDetourUndo;
143
144 foreach (var asm in AssemblyManager.GetModAssemblies(mod.Name))
145 manager.Unload(asm);
146
147 Hook.OnUndo -= OnHookUndo;
148 Detour.OnUndo -= OnDetourUndo;
149 NativeDetour.OnUndo -= OnNativeDetourUndo;
150
151 if (hooks > 0 || detours > 0 || ndetours > 0)
152 Logging.tML.Debug($"Unloaded {hooks} hooks, {detours} detours and {ndetours} native detours from {mod.Name}");
153 }
154 }
155}
static string GetOwnerName(Delegate d)
static Dictionary< Type, string > defaultAliases
Definition: MonoModHooks.cs:17
static string StringRep(MethodBase m)
static void NativeAccessCheck(Assembly asm)
Definition: MonoModHooks.cs:83
static HashSet< Assembly > NativeDetouringGranted
Definition: MonoModHooks.cs:36
static DetourModManager manager
Definition: MonoModHooks.cs:35