fix: Duplicate IL2CPP hashes when building to WebGL (#3061) (#3072)

* fix: Duplicate IL2CPP hashes when building to WebGL (#3061)

* change to tryget

* Update DistanceInterestManagement.cs

* Update MethodProcessor.cs

* GenerateMethodName

* Update MethodProcessor.cs

* Update Assets/Mirror/Editor/Weaver/Weaver.cs

* Update Weaver.cs

Co-authored-by: vis2k <info@noobtuts.com>

* fix callers to replacement rpcs which used to call the deadlock

* improve generated name

Co-authored-by: cooper <60411087+cxxpxr@users.noreply.github.com>
This commit is contained in:
vis2k 2022-01-29 23:19:13 +08:00 committed by GitHub
parent e781448419
commit da09e71576
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 68 additions and 25 deletions

View File

@ -78,7 +78,9 @@ protected static void InvokeCmdCmdThrust(NetworkBehaviour obj, NetworkReader rea
*/ */
public static MethodDefinition ProcessCommandInvoke(WeaverTypes weaverTypes, Readers readers, Logger Log, TypeDefinition td, MethodDefinition method, MethodDefinition cmdCallFunc, ref bool WeavingFailed) public static MethodDefinition ProcessCommandInvoke(WeaverTypes weaverTypes, Readers readers, Logger Log, TypeDefinition td, MethodDefinition method, MethodDefinition cmdCallFunc, ref bool WeavingFailed)
{ {
MethodDefinition cmd = new MethodDefinition(Weaver.InvokeRpcPrefix + method.Name, string cmdName = Weaver.GenerateMethodName(Weaver.InvokeRpcPrefix, method);
MethodDefinition cmd = new MethodDefinition(cmdName,
MethodAttributes.Family | MethodAttributes.Static | MethodAttributes.HideBySig, MethodAttributes.Family | MethodAttributes.Static | MethodAttributes.HideBySig,
weaverTypes.Import(typeof(void))); weaverTypes.Import(typeof(void)));

View File

@ -17,7 +17,8 @@ public static class MethodProcessor
// FixRemoteCallToBaseMethod replaces them afterwards. // FixRemoteCallToBaseMethod replaces them afterwards.
public static MethodDefinition SubstituteMethod(Logger Log, TypeDefinition td, MethodDefinition md, ref bool WeavingFailed) public static MethodDefinition SubstituteMethod(Logger Log, TypeDefinition td, MethodDefinition md, ref bool WeavingFailed)
{ {
string newName = RpcPrefix + md.Name; string newName = Weaver.GenerateMethodName(RpcPrefix, md);
MethodDefinition cmd = new MethodDefinition(newName, md.Attributes, md.ReturnType); MethodDefinition cmd = new MethodDefinition(newName, md.Attributes, md.ReturnType);
// force the substitute method to be protected. // force the substitute method to be protected.
@ -79,28 +80,43 @@ public static void FixRemoteCallToBaseMethod(Logger Log, TypeDefinition type, Me
foreach (Instruction instruction in method.Body.Instructions) foreach (Instruction instruction in method.Body.Instructions)
{ {
// if call to base.CmdDoSomething within this.CallCmdDoSomething // is this instruction a Call to a method?
if (IsCallToMethod(instruction, out MethodDefinition calledMethod) && // if yes, output the method so we can check it.
calledMethod.Name == baseRemoteCallName) if (IsCallToMethod(instruction, out MethodDefinition calledMethod))
{ {
TypeDefinition baseType = type.BaseType.Resolve(); // when considering if 'calledMethod' is a call to 'method',
MethodDefinition baseMethod = baseType.GetMethodInBaseType(callName); // we originally compared .Name.
//
if (baseMethod == null) // to fix IL2CPP build bugs with overloaded Rpcs, we need to
// generated rpc names like
// RpcTest(string value) => RpcTestString(strig value)
// RpcTest(int value) => RpcTestInt(int value)
// to make them unique.
//
// calledMethod.Name is still "RpcTest", so we need to
// convert this to the generated name as well before comparing.
string calledMethodName_Generated = Weaver.GenerateMethodName("", calledMethod);
if (calledMethodName_Generated == baseRemoteCallName)
{ {
Log.Error($"Could not find base method for {callName}", method); TypeDefinition baseType = type.BaseType.Resolve();
WeavingFailed = true; MethodDefinition baseMethod = baseType.GetMethodInBaseType(callName);
return;
}
if (!baseMethod.IsVirtual) if (baseMethod == null)
{ {
Log.Error($"Could not find base method that was virtual {callName}", method); Log.Error($"Could not find base method for {callName}", method);
WeavingFailed = true; WeavingFailed = true;
return; return;
} }
instruction.Operand = baseMethod; if (!baseMethod.IsVirtual)
{
Log.Error($"Could not find base method that was virtual {callName}", method);
WeavingFailed = true;
return;
}
instruction.Operand = baseMethod;
}
} }
} }
} }

View File

@ -8,10 +8,10 @@ public static class RpcProcessor
{ {
public static MethodDefinition ProcessRpcInvoke(WeaverTypes weaverTypes, Writers writers, Readers readers, Logger Log, TypeDefinition td, MethodDefinition md, MethodDefinition rpcCallFunc, ref bool WeavingFailed) public static MethodDefinition ProcessRpcInvoke(WeaverTypes weaverTypes, Writers writers, Readers readers, Logger Log, TypeDefinition td, MethodDefinition md, MethodDefinition rpcCallFunc, ref bool WeavingFailed)
{ {
MethodDefinition rpc = new MethodDefinition( string rpcName = Weaver.GenerateMethodName(Weaver.InvokeRpcPrefix, md);
Weaver.InvokeRpcPrefix + md.Name,
MethodAttributes.Family | MethodAttributes.Static | MethodAttributes.HideBySig, MethodDefinition rpc = new MethodDefinition(rpcName, MethodAttributes.Family | MethodAttributes.Static | MethodAttributes.HideBySig,
weaverTypes.Import(typeof(void))); weaverTypes.Import(typeof(void)));
ILProcessor worker = rpc.Body.GetILProcessor(); ILProcessor worker = rpc.Body.GetILProcessor();
Instruction label = worker.Create(OpCodes.Nop); Instruction label = worker.Create(OpCodes.Nop);

View File

@ -15,7 +15,9 @@ public static bool HasNetworkConnectionParameter(MethodDefinition md)
public static MethodDefinition ProcessTargetRpcInvoke(WeaverTypes weaverTypes, Readers readers, Logger Log, TypeDefinition td, MethodDefinition md, MethodDefinition rpcCallFunc, ref bool WeavingFailed) public static MethodDefinition ProcessTargetRpcInvoke(WeaverTypes weaverTypes, Readers readers, Logger Log, TypeDefinition td, MethodDefinition md, MethodDefinition rpcCallFunc, ref bool WeavingFailed)
{ {
MethodDefinition rpc = new MethodDefinition(Weaver.InvokeRpcPrefix + md.Name, MethodAttributes.Family | string trgName = Weaver.GenerateMethodName(Weaver.InvokeRpcPrefix, md);
MethodDefinition rpc = new MethodDefinition(trgName, MethodAttributes.Family |
MethodAttributes.Static | MethodAttributes.Static |
MethodAttributes.HideBySig, MethodAttributes.HideBySig,
weaverTypes.Import(typeof(void))); weaverTypes.Import(typeof(void)));

View File

@ -31,6 +31,29 @@ internal class Weaver
// multi threaded logging. // multi threaded logging.
public Logger Log; public Logger Log;
// remote actions now support overloads,
// -> but IL2CPP doesnt like it when two generated methods
// -> have the same signature,
// -> so, append the signature to the generated method name,
// -> to create a unique name
// Example:
// RpcTeleport(Vector3 position) -> InvokeUserCode_RpcTeleport__Vector3()
// RpcTeleport(Vector3 position, Quaternion rotation) -> InvokeUserCode_RpcTeleport__Vector3Quaternion()
// fixes https://github.com/vis2k/Mirror/issues/3060
public static string GenerateMethodName(string initialPrefix, MethodDefinition md)
{
initialPrefix += md.Name;
for (int i = 0; i < md.Parameters.Count; ++i)
{
// with __ so it's more obvious that this is the parameter suffix.
// otherwise RpcTest(int) => RpcTestInt(int) which is not obvious.
initialPrefix += $"__{md.Parameters[i].ParameterType.Name}";
}
return initialPrefix;
}
public Weaver(Logger Log) public Weaver(Logger Log)
{ {
this.Log = Log; this.Log = Log;