Skip to content

Commit 66ba962

Browse files
committed
fix: Fixed the issue where static field modifications encapsulated within functions could not be recognized.
1 parent 26990b2 commit 66ba962

File tree

1 file changed

+119
-1
lines changed

1 file changed

+119
-1
lines changed

src/OTAPI.UnifiedServerProcess/Core/Patching/FieldFilterPatching/InitialFieldModificationProcessor.cs

Lines changed: 119 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,75 @@ void AddFieldModification(MethodDefinition method, Dictionary<string, HashSet<In
652652

653653
HashSet<Instruction> extractedStaticInsts = [];
654654

655+
if (method.Name == "FillResearchItemOverrides") {
656+
657+
}
658+
659+
bool UsedStaticField(MethodDefinition method) {
660+
HashSet<string> visited = [];
661+
Stack<MethodDefinition> stack = [];
662+
663+
stack.Push(method);
664+
visited.Add(method.GetIdentifier());
665+
666+
while (stack.Count > 0) {
667+
var caller = stack.Pop();
668+
669+
foreach (var inst in caller.Body.Instructions) {
670+
if (inst.OpCode == OpCodes.Ldsflda || inst.OpCode == OpCodes.Stsfld) {
671+
return true;
672+
}
673+
if (inst.OpCode == OpCodes.Ldsfld) {
674+
var field = ((FieldReference)inst.Operand);
675+
if (!field.FieldType.IsTruelyValueType()) {
676+
return true;
677+
}
678+
}
679+
if (inst.OpCode == OpCodes.Call) {
680+
var resolvedCallee = ((MethodReference)inst.Operand).TryResolve();
681+
if (resolvedCallee is not null
682+
&& resolvedCallee.IsStatic
683+
&& !resolvedCallee.IsConstructor
684+
&& resolvedCallee.ReturnType.FullName == source.MainModule.TypeSystem.Void.FullName) {
685+
if (visited.Add(resolvedCallee.GetIdentifier())) {
686+
stack.Push(resolvedCallee);
687+
}
688+
}
689+
}
690+
}
691+
}
692+
return false;
693+
}
694+
695+
foreach (var inst in method.Body.Instructions) {
696+
697+
if (inst.OpCode != OpCodes.Call) {
698+
continue;
699+
}
700+
701+
var resolvedCallee = ((MethodReference)inst.Operand).TryResolve();
702+
if (resolvedCallee is null
703+
|| !resolvedCallee.IsStatic
704+
|| resolvedCallee.IsConstructor
705+
|| resolvedCallee.ReturnType.FullName != source.MainModule.TypeSystem.Void.FullName) {
706+
continue;
707+
}
708+
709+
if (!UsedStaticField(resolvedCallee)) {
710+
continue;
711+
}
712+
713+
714+
HashSet<Instruction> tmp = [];
715+
ExtractSources(this, method, tmp, inst);
716+
717+
if (IsExtractableStaticPart(source, tmp)) {
718+
foreach (var staticInst in tmp) {
719+
extractedStaticInsts.Add(staticInst);
720+
}
721+
}
722+
}
723+
655724
foreach (var loopBlock in loopBlocks.Values) {
656725
foreach (var fieldModification in loopBlock.FilteredLoopBody) {
657726
if (!source.InitialStaticFields.TryGetValue(fieldModification.Key, out var initFieldDef)) {
@@ -921,7 +990,11 @@ static Instruction CloneAndUpdateMap(Dictionary<Instruction, Instruction> instMa
921990
}
922991
}
923992

924-
foreach (var key in myCalingMethods.Keys.ToArray()) {
993+
foreach (var calleeKV in myCalingMethods.ToArray()) {
994+
var key = calleeKV.Key;
995+
if (calleeKV.Value.Parameters.Count != 0) {
996+
myCalingMethods.Remove(key);
997+
}
925998
if (multipleCalls.TryGetValue(key, out var multipleCallCount) && multipleCallCount != 1) {
926999
myCalingMethods.Remove(key);
9271000
}
@@ -1042,6 +1115,51 @@ private bool IsExtractableStaticPart(FilterArgumentSource source, FieldDefinitio
10421115
}
10431116
return true;
10441117
}
1118+
private bool IsExtractableStaticPart(FilterArgumentSource source, IEnumerable<Instruction> instructions) {
1119+
foreach (var inst in instructions) {
1120+
switch (inst.OpCode.Code) {
1121+
case Code.Ldsfld:
1122+
case Code.Ldsflda:
1123+
case Code.Stsfld: {
1124+
var fieldRef = (FieldReference)inst.Operand;
1125+
var id = fieldRef.GetIdentifier();
1126+
if (source.ModifiedStaticFields.ContainsKey(id)) {
1127+
return false;
1128+
}
1129+
}
1130+
break;
1131+
case Code.Call:
1132+
case Code.Callvirt:
1133+
case Code.Newobj: {
1134+
var methodRef = (MethodReference)inst.Operand;
1135+
var methodDef = methodRef.TryResolve();
1136+
if (methodDef is null) {
1137+
break;
1138+
}
1139+
if (this.CheckUsedContextBoundField(source.ModifiedStaticFields, methodDef)) {
1140+
return false;
1141+
}
1142+
}
1143+
break;
1144+
}
1145+
}
1146+
foreach (var inst in instructions) {
1147+
switch (inst.OpCode.Code) {
1148+
case Code.Ldarg_0:
1149+
case Code.Ldarg_1:
1150+
case Code.Ldarg_2:
1151+
case Code.Ldarg_3:
1152+
case Code.Ldarg_S:
1153+
case Code.Ldarg:
1154+
case Code.Ldarga_S:
1155+
case Code.Ldarga:
1156+
case Code.Starg_S:
1157+
case Code.Starg:
1158+
return false;
1159+
}
1160+
}
1161+
return true;
1162+
}
10451163
/// <summary>
10461164
///
10471165
/// </summary>

0 commit comments

Comments
 (0)