feat: Use Server Client attribute outside of NetworkBehaviour (#2150)

* adding generated test for other baseclasses

* removing errors when attribute is not in networkbehaviour

* temp weaver tests

* updating weaver tests for monobehaviour

* adding weaver tests for non-networkbehaviour

* moving where serverclient attributes are processed

* removing un-used code

* regenerate tests
This commit is contained in:
James Frowen 2020-08-21 16:02:37 +01:00 committed by GitHub
parent c6fa49c72a
commit eec49fafce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 4182 additions and 55 deletions

View File

@ -49,24 +49,6 @@ static void ProcessMethods(TypeDefinition td)
{
Weaver.Error($"TargetRpc {md.Name} must be declared inside a NetworkBehaviour", md);
}
string attributeName = ca.Constructor.DeclaringType.ToString();
switch (attributeName)
{
case "Mirror.ServerAttribute":
Weaver.Error($"Server method {md.Name} must be declared inside a NetworkBehaviour", md);
break;
case "Mirror.ServerCallbackAttribute":
Weaver.Error($"ServerCallback method {md.Name} must be declared inside a NetworkBehaviour", md);
break;
case "Mirror.ClientAttribute":
Weaver.Error($"Client method {md.Name} must be declared inside a NetworkBehaviour", md);
break;
case "Mirror.ClientCallbackAttribute":
Weaver.Error($"ClientCallback method {md.Name} must be declared inside a NetworkBehaviour", md);
break;
}
}
}
}

View File

@ -41,7 +41,7 @@ static void ProcessSiteClass(TypeDefinition td)
//Console.WriteLine(" ProcessSiteClass " + td);
foreach (MethodDefinition md in td.Methods)
{
ProcessSiteMethod(td, md);
ProcessSiteMethod(md);
}
foreach (TypeDefinition nested in td.NestedTypes)
@ -50,7 +50,7 @@ static void ProcessSiteClass(TypeDefinition td)
}
}
static void ProcessSiteMethod(TypeDefinition td, MethodDefinition md)
static void ProcessSiteMethod(MethodDefinition md)
{
// process all references to replaced members with properties
//Weaver.DLog(td, " ProcessSiteMethod " + md);
@ -62,18 +62,11 @@ static void ProcessSiteMethod(TypeDefinition td, MethodDefinition md)
if (md.IsAbstract)
{
if (ServerClientAttributeProcessor.HasServerClientAttribute(md))
{
Weaver.Error("Server or Client Attributes can't be added to abstract method. Server and Client Attributes are not inherited so they need to be applied to the override methods instead.", md);
}
return;
}
if (md.Body != null && md.Body.Instructions != null)
{
// TODO move this to NetworkBehaviourProcessor
ServerClientAttributeProcessor.ProcessMethodAttributes(td, md);
for (int iCount = 0; iCount < md.Body.Instructions.Count;)
{
Instruction instr = md.Body.Instructions[iCount];

View File

@ -8,6 +8,44 @@ namespace Mirror.Weaver
/// </summary>
static class ServerClientAttributeProcessor
{
public static bool ProcessSiteClass(TypeDefinition td)
{
bool modified = false;
foreach (MethodDefinition md in td.Methods)
{
modified |= ProcessSiteMethod(td, md);
}
foreach (TypeDefinition nested in td.NestedTypes)
{
modified |= ProcessSiteClass(nested);
}
return modified;
}
static bool ProcessSiteMethod(TypeDefinition td, MethodDefinition md)
{
if (md.Name == ".cctor" ||
md.Name == NetworkBehaviourProcessor.ProcessedFunctionName ||
md.Name.StartsWith(Weaver.InvokeRpcPrefix))
return false;
if (md.IsAbstract)
{
if (HasServerClientAttribute(md))
{
Weaver.Error("Server or Client Attributes can't be added to abstract method. Server and Client Attributes are not inherited so they need to be applied to the override methods instead.", md);
}
return false;
}
if (md.Body != null && md.Body.Instructions != null)
{
return ProcessMethodAttributes(td, md);
}
return false;
}
public static bool HasServerClientAttribute(MethodDefinition md)
{
foreach (CustomAttribute attr in md.CustomAttributes)
@ -26,37 +64,39 @@ public static bool HasServerClientAttribute(MethodDefinition md)
return false;
}
public static void ProcessMethodAttributes(TypeDefinition td, MethodDefinition md)
public static bool ProcessMethodAttributes(TypeDefinition td, MethodDefinition md)
{
bool modified = false;
foreach (CustomAttribute attr in md.CustomAttributes)
{
switch (attr.Constructor.DeclaringType.ToString())
{
case "Mirror.ServerAttribute":
InjectServerGuard(td, md, true);
InjectServerGuard(md, true);
modified = true;
break;
case "Mirror.ServerCallbackAttribute":
InjectServerGuard(td, md, false);
InjectServerGuard(md, false);
modified = true;
break;
case "Mirror.ClientAttribute":
InjectClientGuard(td, md, true);
InjectClientGuard(md, true);
modified = true;
break;
case "Mirror.ClientCallbackAttribute":
InjectClientGuard(td, md, false);
InjectClientGuard(md, false);
modified = true;
break;
default:
break;
}
}
return modified;
}
static void InjectServerGuard(TypeDefinition td, MethodDefinition md, bool logWarning)
static void InjectServerGuard(MethodDefinition md, bool logWarning)
{
if (!Weaver.IsNetworkBehaviour(td))
{
Weaver.Error($"Server method {md.Name} must be declared in a NetworkBehaviour", md);
return;
}
ILProcessor worker = md.Body.GetILProcessor();
Instruction top = md.Body.Instructions[0];
@ -72,13 +112,8 @@ static void InjectServerGuard(TypeDefinition td, MethodDefinition md, bool logWa
worker.InsertBefore(top, worker.Create(OpCodes.Ret));
}
static void InjectClientGuard(TypeDefinition td, MethodDefinition md, bool logWarning)
static void InjectClientGuard(MethodDefinition md, bool logWarning)
{
if (!Weaver.IsNetworkBehaviour(td))
{
Weaver.Error($"Client method {md.Name} must be declared in a NetworkBehaviour", md);
return;
}
ILProcessor worker = md.Body.GetILProcessor();
Instruction top = md.Body.Instructions[0];

View File

@ -278,6 +278,7 @@ static bool WeaveModule(ModuleDefinition moduleDefinition)
{
modified |= WeaveNetworkBehavior(td);
modified |= WeaveMessage(td);
modified |= ServerClientAttributeProcessor.ProcessSiteClass(td);
}
}
watch.Stop();
@ -330,7 +331,7 @@ static bool Weave(string assName, AssemblyDefinition unityAssembly, AssemblyDefi
// this must be done for ALL code, not just NetworkBehaviours
try
{
PropertySiteProcessor.ProcessSitesModule(CurrentAssembly.MainModule);
PropertySiteProcessor.ProcessSitesModule(moduleDefinition);
}
catch (Exception e)
{

File diff suppressed because it is too large Load Diff

View File

@ -89,8 +89,8 @@ static string ReturnTypeToFullName(string returnType)
static string[] baseClassArray = new string[]
{
"NetworkBehaviour",
//"MonoBehaviour",
//"ClassWithNoConstructor" // non unity class
"MonoBehaviour",
"ClassWithNoConstructor" // non unity class
};
const string NameSpace = BaseNameSpace + ".Attributes";
@ -114,6 +114,8 @@ static string Classes(string baseClass, IEnumerable<string> functions, IEnumerab
{
string mergedFunctions = Merge(functions);
string mergedTests = Merge(tests);
string setupBody = SetupForBaseClass(baseClass);
string teardownBody = TearDownForBaseClass(baseClass);
return $@"
public class {AttributeBehaviourName(baseClass)} : {baseClass}
@ -142,14 +144,13 @@ public class AttributeTest_{baseClass}
[OneTimeSetUp]
public void SetUp()
{{
go = new GameObject();
behaviour = go.AddComponent<{AttributeBehaviourName(baseClass)}>();
{setupBody}
}}
[OneTimeTearDown]
public void TearDown()
{{
UnityEngine.Object.DestroyImmediate(go);
{teardownBody}
NetworkClient.connectState = ConnectState.None;
NetworkServer.active = false;
}}
@ -158,6 +159,50 @@ public void TearDown()
}}";
}
static string SetupForBaseClass(string baseClass)
{
switch (baseClass)
{
case "NetworkBehaviour":
case "MonoBehaviour":
return SetupBodyMonoBehaviour(baseClass);
default:
return SetupBodyClass(baseClass);
}
}
static string TearDownForBaseClass(string baseClass)
{
switch (baseClass)
{
case "NetworkBehaviour":
case "MonoBehaviour":
return TearDownBodyMonoBehaviour();
default:
return TearDownBodyClass();
}
}
static string SetupBodyMonoBehaviour(string baseClass)
{
return
$@"go = new GameObject();
behaviour = go.AddComponent<{AttributeBehaviourName(baseClass)}>();";
}
static string TearDownBodyMonoBehaviour()
{
return "UnityEngine.Object.DestroyImmediate(go);";
}
static string SetupBodyClass(string baseClass)
{
return $@"behaviour = new {AttributeBehaviourName(baseClass)}();";
}
static string TearDownBodyClass()
{
return "";
}
static string AttributeBehaviourName(string baseClass)
{
return $"AttributeBehaviour_{baseClass}";
@ -171,6 +216,7 @@ static string AttributeOutFunctionName(string attribute, string returnType)
return $"{attribute}_{returnType}_out_Function";
}
static string AttributeFunction(string attribute, string returnType)
{
return $@"

View File

@ -100,11 +100,17 @@
<Compile Include="WeaverClientServerAttributeTests~\ClientAttributeOnAbstractMethod.cs" />
<Compile Include="WeaverClientServerAttributeTests~\ClientAttributeOnOverrideMethod.cs" />
<Compile Include="WeaverClientServerAttributeTests~\ClientAttributeOnVirutalMethod.cs" />
<Compile Include="WeaverClientServerAttributeTests~\MonoBehaviourClient.cs" />
<Compile Include="WeaverClientServerAttributeTests~\MonoBehaviourServer.cs" />
<Compile Include="WeaverClientServerAttributeTests~\NetworkBehaviourClient.cs" />
<Compile Include="WeaverClientServerAttributeTests~\NetworkBehaviourServer.cs" />
<Compile Include="WeaverClientServerAttributeTests~\RegularClassClient.cs" />
<Compile Include="WeaverClientServerAttributeTests~\RegularClassServer.cs" />
<Compile Include="WeaverClientServerAttributeTests~\ServerAttributeOnAbstractMethod.cs" />
<Compile Include="WeaverClientServerAttributeTests~\ServerAttributeOnOverrideMethod.cs" />
<Compile Include="WeaverClientServerAttributeTests~\ServerAttributeOnVirutalMethod.cs" />
<Compile Include="WeaverClientServerAttributeTests~\StaticClassClient.cs" />
<Compile Include="WeaverClientServerAttributeTests~\StaticClassServer.cs" />
<Compile Include="WeaverCommandTests~\AbstractCommand.cs" />
<Compile Include="WeaverCommandTests~\CommandCantBeStatic.cs" />
<Compile Include="WeaverCommandTests~\CommandThatIgnoresAuthority.cs" />

View File

@ -74,6 +74,59 @@ public void ClientAttributeOnOverrideMethod()
CheckAddedCode(networkClientGetActive, "WeaverClientServerAttributeTests.ClientAttributeOnOverrideMethod.ClientAttributeOnOverrideMethod", "ClientOnlyMethod");
}
[Test]
public void StaticClassClient()
{
Assert.That(weaverErrors, Is.Empty);
string networkClientGetActive = WeaverTypes.NetworkClientGetActive.ToString();
CheckAddedCode(networkClientGetActive, "WeaverClientServerAttributeTests.StaticClassClient.StaticClassClient", "ClientOnlyMethod");
}
[Test]
public void RegularClassClient()
{
Assert.That(weaverErrors, Is.Empty);
string networkClientGetActive = WeaverTypes.NetworkClientGetActive.ToString();
CheckAddedCode(networkClientGetActive, "WeaverClientServerAttributeTests.RegularClassClient.RegularClassClient", "ClientOnlyMethod");
}
[Test]
public void MonoBehaviourClient()
{
Assert.That(weaverErrors, Is.Empty);
string networkClientGetActive = WeaverTypes.NetworkClientGetActive.ToString();
CheckAddedCode(networkClientGetActive, "WeaverClientServerAttributeTests.MonoBehaviourClient.MonoBehaviourClient", "ClientOnlyMethod");
}
[Test]
public void StaticClassServer()
{
Assert.That(weaverErrors, Is.Empty);
string networkServerGetActive = WeaverTypes.NetworkServerGetActive.ToString();
CheckAddedCode(networkServerGetActive, "WeaverClientServerAttributeTests.StaticClassServer.StaticClassServer", "ServerOnlyMethod");
}
[Test]
public void RegularClassServer()
{
Assert.That(weaverErrors, Is.Empty);
string networkServerGetActive = WeaverTypes.NetworkServerGetActive.ToString();
CheckAddedCode(networkServerGetActive, "WeaverClientServerAttributeTests.RegularClassServer.RegularClassServer", "ServerOnlyMethod");
}
[Test]
public void MonoBehaviourServer()
{
Assert.That(weaverErrors, Is.Empty);
string networkServerGetActive = WeaverTypes.NetworkServerGetActive.ToString();
CheckAddedCode(networkServerGetActive, "WeaverClientServerAttributeTests.MonoBehaviourServer.MonoBehaviourServer", "ServerOnlyMethod");
}
/// <summary>
/// Checks that first Instructions in MethodBody is addedString
/// </summary>

View File

@ -0,0 +1,11 @@
using Mirror;
using UnityEngine;
namespace WeaverClientServerAttributeTests.MonoBehaviourClient
{
class MonoBehaviourClient : MonoBehaviour
{
[Client]
void ClientOnlyMethod() { }
}
}

View File

@ -0,0 +1,11 @@
using Mirror;
using UnityEngine;
namespace WeaverClientServerAttributeTests.MonoBehaviourServer
{
class MonoBehaviourServer : MonoBehaviour
{
[Server]
void ServerOnlyMethod() { }
}
}

View File

@ -0,0 +1,10 @@
using Mirror;
namespace WeaverClientServerAttributeTests.RegularClassClient
{
class RegularClassClient
{
[Client]
void ClientOnlyMethod() { }
}
}

View File

@ -0,0 +1,10 @@
using Mirror;
namespace WeaverClientServerAttributeTests.RegularClassServer
{
class RegularClassServer
{
[Server]
void ServerOnlyMethod() { }
}
}

View File

@ -0,0 +1,10 @@
using Mirror;
namespace WeaverClientServerAttributeTests.StaticClassClient
{
static class StaticClassClient
{
[Client]
static void ClientOnlyMethod() { }
}
}

View File

@ -0,0 +1,10 @@
using Mirror;
namespace WeaverClientServerAttributeTests.StaticClassServer
{
static class StaticClassServer
{
[Server]
static void ServerOnlyMethod() { }
}
}

View File

@ -1,4 +1,4 @@
using NUnit.Framework;
using NUnit.Framework;
namespace Mirror.Weaver.Tests
{
@ -43,25 +43,25 @@ public void MonoBehaviourTargetRpc()
[Test]
public void MonoBehaviourServer()
{
Assert.That(weaverErrors, Contains.Item("Server method ThisCantBeOutsideNetworkBehaviour must be declared inside a NetworkBehaviour (at System.Void WeaverMonoBehaviourTests.MonoBehaviourServer.MonoBehaviourServer::ThisCantBeOutsideNetworkBehaviour())"));
Assert.That(weaverErrors, Is.Empty);
}
[Test]
public void MonoBehaviourServerCallback()
{
Assert.That(weaverErrors, Contains.Item("ServerCallback method ThisCantBeOutsideNetworkBehaviour must be declared inside a NetworkBehaviour (at System.Void WeaverMonoBehaviourTests.MonoBehaviourServerCallback.MonoBehaviourServerCallback::ThisCantBeOutsideNetworkBehaviour())"));
Assert.That(weaverErrors, Is.Empty);
}
[Test]
public void MonoBehaviourClient()
{
Assert.That(weaverErrors, Contains.Item("Client method ThisCantBeOutsideNetworkBehaviour must be declared inside a NetworkBehaviour (at System.Void WeaverMonoBehaviourTests.MonoBehaviourClient.MonoBehaviourClient::ThisCantBeOutsideNetworkBehaviour())"));
Assert.That(weaverErrors, Is.Empty);
}
[Test]
public void MonoBehaviourClientCallback()
{
Assert.That(weaverErrors, Contains.Item("ClientCallback method ThisCantBeOutsideNetworkBehaviour must be declared inside a NetworkBehaviour (at System.Void WeaverMonoBehaviourTests.MonoBehaviourClientCallback.MonoBehaviourClientCallback::ThisCantBeOutsideNetworkBehaviour())"));
Assert.That(weaverErrors, Is.Empty);
}
}
}