Skip to content

Commit 7e39b3a

Browse files
committed
chore: global language manager
1 parent 62a6331 commit 7e39b3a

File tree

3 files changed

+119
-18
lines changed

3 files changed

+119
-18
lines changed

src/OTAPI.UnifiedServerProcess/Core/FunctionalFeatures/IMethodCheckCacheFeature.cs

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,17 @@ public static bool AddPredefineMethodUsedContext<TFeature>(
2323
string methodId) {
2424
return PredefineMethodUsedContext.Add(methodId);
2525
}
26+
static readonly Dictionary<string, bool> overwriteContextBoundCheck = [];
27+
public static void ForceOverrideContextBoundCheck<TFeature>(
28+
this TFeature _,
29+
string methodId, bool isContextBound) {
30+
overwriteContextBoundCheck[methodId] = isContextBound;
31+
}
32+
public static bool ForceOverrideContextBoundCheck<TFeature>(
33+
this TFeature _,
34+
MethodDefinition method, bool isContextBound) {
35+
return overwriteContextBoundCheck[method.GetIdentifier()] = isContextBound;
36+
}
2637
private static bool ParamCheck(MethodReferenceData referenceData, MethodDefinition callee, out bool shouldAddToCheckList) {
2738
shouldAddToCheckList = true;
2839
if (!callee.HasBody) {
@@ -58,6 +69,10 @@ public static bool CheckUsedContextBoundField<TFeature>(
5869

5970
var methodId = checkMethod.GetIdentifier();
6071

72+
if (overwriteContextBoundCheck.TryGetValue(methodId, out bool isContextBound)) {
73+
return isContextBound;
74+
}
75+
6176
if (useCache && checkUsedContextBountFieldCache.TryGetValue(methodId, out bool value) && value) {
6277
return value;
6378
}
@@ -150,25 +165,33 @@ public static bool CheckUsedContextBoundField<TFeature>(
150165
continue;
151166
}
152167
foreach (var callee in useds.ImplementedMethods()) {
153-
if (PredefineMethodUsedContext.Contains(callee.GetIdentifier())) {
154-
return CacheReturn(true, useCache, methodId);
155-
}
156-
if (ParamCheck(useds, callee, out var shouldAddToCheckList)) {
157-
return CacheReturn(true, useCache, methodId);
158-
}
159-
if (shouldAddToCheckList) {
160-
worklist.Push(callee);
168+
169+
if (overwriteContextBoundCheck.TryGetValue(callee.GetIdentifier(), out bool isCalleeContextBound)) {
170+
if (isCalleeContextBound) {
171+
return CacheReturn(true, useCache, methodId);
172+
}
161173
}
162-
if (callee.Name == ".ctor" && callee.DeclaringType.Name.OrdinalStartsWith('<')) {
163-
foreach (var autoGenerate in callee.DeclaringType.Methods) {
164-
if (autoGenerate.Name == ".ctor") {
165-
continue;
166-
}
167-
if (ParamCheck(useds, autoGenerate, out shouldAddToCheckList)) {
168-
return CacheReturn(true, useCache, methodId);
169-
}
170-
if (shouldAddToCheckList) {
171-
worklist.Push(autoGenerate);
174+
else {
175+
if (PredefineMethodUsedContext.Contains(callee.GetIdentifier())) {
176+
return CacheReturn(true, useCache, methodId);
177+
}
178+
if (ParamCheck(useds, callee, out var shouldAddToCheckList)) {
179+
return CacheReturn(true, useCache, methodId);
180+
}
181+
if (shouldAddToCheckList) {
182+
worklist.Push(callee);
183+
}
184+
if (callee.Name == ".ctor" && callee.DeclaringType.Name.OrdinalStartsWith('<')) {
185+
foreach (var autoGenerate in callee.DeclaringType.Methods) {
186+
if (autoGenerate.Name == ".ctor") {
187+
continue;
188+
}
189+
if (ParamCheck(useds, autoGenerate, out shouldAddToCheckList)) {
190+
return CacheReturn(true, useCache, methodId);
191+
}
192+
if (shouldAddToCheckList) {
193+
worklist.Push(autoGenerate);
194+
}
172195
}
173196
}
174197
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
using ModFramework;
2+
using Mono.Cecil;
3+
using MonoMod.Utils;
4+
using OTAPI.UnifiedServerProcess.Commons;
5+
using OTAPI.UnifiedServerProcess.Core.Analysis.MethodCallAnalysis;
6+
using OTAPI.UnifiedServerProcess.Core.FunctionalFeatures;
7+
using OTAPI.UnifiedServerProcess.Core.Patching.Framework;
8+
using OTAPI.UnifiedServerProcess.Loggers;
9+
using System;
10+
using System.Collections.Generic;
11+
using System.Linq;
12+
using System.Text;
13+
using System.Threading.Tasks;
14+
15+
namespace OTAPI.UnifiedServerProcess.Core.Patching.SimplePatching
16+
{
17+
public class LangManagerPrePatcher(ILogger logger, ModuleDefinition module, MethodCallGraph callGraph) : Patcher(logger), IMethodCheckCacheFeature
18+
{
19+
public override string Name => nameof(LangManagerPrePatcher);
20+
21+
public MethodCallGraph MethodCallGraph => callGraph;
22+
23+
public override void Patch() {
24+
var runGame = module.GetType("Terraria.Program").Method("mfwh_orig_RunGame");
25+
var callSetLanguage = runGame.Body.Instructions
26+
.First(inst => inst.Operand is MethodReference { DeclaringType.Name: "LanguageManager", Name: "SetLanguage" });
27+
var getDefaultCulture = callSetLanguage.Previous;
28+
var loadLangManagerInstance = callSetLanguage.Previous.Previous;
29+
30+
runGame.Body.Instructions.Remove(loadLangManagerInstance);
31+
runGame.Body.Instructions.Remove(getDefaultCulture);
32+
runGame.Body.Instructions.Remove(callSetLanguage);
33+
34+
var globalInitialize = module
35+
.GetType(Constants.GlobalInitializerTypeName)
36+
.Method(Constants.GlobalInitializerEntryPointName);
37+
globalInitialize.Body.Instructions.InsertRange(0, [
38+
loadLangManagerInstance,
39+
getDefaultCulture,
40+
callSetLanguage,
41+
]);
42+
43+
44+
var langManager = module.GetType("Terraria.Localization.LanguageManager");
45+
var loadFilesForCulture = langManager.Method("LoadFilesForCulture");
46+
47+
foreach (var inst in loadFilesForCulture.Body.Instructions) {
48+
if (inst.Operand is MethodReference { DeclaringType.Name: "Console" } methodRef) {
49+
var originalDeclaringType = methodRef.DeclaringType;
50+
var declaringType = new TypeReference(originalDeclaringType.Namespace, originalDeclaringType.Name, originalDeclaringType.Module, originalDeclaringType.Scope);
51+
var cloned = new MethodReference(methodRef.Name, methodRef.ReturnType, declaringType) { HasThis = methodRef.HasThis };
52+
cloned.Parameters.AddRange(methodRef.Parameters.Select(x => x.Clone()));
53+
cloned.DeclaringType.Name = "Console_Placeholder_DontRedirect";
54+
inst.Operand = cloned;
55+
}
56+
}
57+
58+
this.ForceOverrideContextBoundCheck(loadFilesForCulture, false);
59+
}
60+
}
61+
public class LangManagerPostPatcher(ILogger logger, ModuleDefinition module) : Patcher(logger)
62+
{
63+
public override string Name => nameof(LangManagerPostPatcher);
64+
65+
public override void Patch() {
66+
var langManager = module.GetType("Terraria.Localization.LanguageManager");
67+
var loadFilesForCulture = langManager.Method("LoadFilesForCulture");
68+
69+
foreach (var inst in loadFilesForCulture.Body.Instructions) {
70+
if (inst.Operand is MethodReference { DeclaringType.Name: "Console_Placeholder_DontRedirect" } methodRef) {
71+
methodRef.DeclaringType.Name = "Console";
72+
}
73+
}
74+
}
75+
}
76+
}

src/OTAPI.UnifiedServerProcess/Core/PatchingLogic.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ public static void Patch(ILogger logger, ModuleDefinition module) {
3434
new PatchChain(logger)
3535
.Then(new SimplifyMacrosPatcher(logger, module))
3636
.Then(new RemoveUnusedCodePatcherAtBegin(logger, module))
37+
.Then(new LangManagerPrePatcher(logger, module, analyzers.MethodCallGraph))
3738

3839
.DefineArgument(new FilterArgumentSource(module, initialMethods))
3940
.RegisterProcessor(new AddModifiedFieldsProcessor(rawModifiedStaticFields, initialStaticFields))
@@ -71,6 +72,7 @@ public static void Patch(ILogger logger, ModuleDefinition module) {
7172
.Finalize()
7273

7374
.Then(new AdjustAutoPropertiesPatcher(logger, module))
75+
.Then(new LangManagerPostPatcher(logger, module))
7476
.Then(new RemoveUnusedCodePatcherAtEnd(logger, rootContextDef, module))
7577
.Then(new OptimizeMacrosPatcher(logger, module))
7678

0 commit comments

Comments
 (0)