Search Unity

UNetWeaver compile exception in NetworkBehaviour

Discussion in 'UNet' started by KelsoMRK, Jun 12, 2015.

  1. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    As soon as I decorate a method with a Command attribute like this

    Code (csharp):
    1.  
    2. [Command]
    3. public void CmdAddPlayer(NetworkConnection connection, string playerName, int playerAvatar)
    4. {
    5.     RpcAddPlayer(connection, playerName, playerAvatar);
    6. }
    7.  
    8.  public void RpcAddPlayer(NetworkConnection connection, string playerName, int playerAvatar)
    9. {
    10.     AddTeam(connection, playerName, playerAvatar);
    11.  }
    12.  
    I get the following compile time exception that won't go away until I restart Unity regardless of other code changes I make including removing the attribute

    Code (csharp):
    1.  
    2. UNetWeaver error: Exception :System.ArgumentException: Member 'UnityEngine.Networking.NetBuffer' is declared in another module and needs to be imported
    3.   at Mono.Cecil.MetadataBuilder.LookupToken (IMetadataTokenProvider provider) [0x00000] in <filename unknown>:0
    4.   at Mono.Cecil.SignatureWriter.MakeTypeDefOrRefCodedRID (Mono.Cecil.TypeReference type) [0x00000] in <filename unknown>:0
    5.   at Mono.Cecil.SignatureWriter.WriteTypeSignature (Mono.Cecil.TypeReference type) [0x00000] in <filename unknown>:0
    6.   at Mono.Cecil.MetadataBuilder.GetVariablesSignature (Mono.Collections.Generic.Collection`1 variables) [0x00000] in <filename unknown>:0
    7.   at Mono.Cecil.MetadataBuilder.GetLocalVariableBlobIndex (Mono.Collections.Generic.Collection`1 variables) [0x00000] in <filename unknown>:0
    8.   at Mono.Cecil.Cil.CodeWriter.GetStandAloneSignature (Mono.Collections.Generic.Collection`1 variables) [0x00000] in <filename unknown>:0
    9.   at Mono.Cecil.Cil.CodeWriter.WriteFatHeader () [0x00000] in <filename unknown>:0
    10.   at Mono.Cecil.Cil.CodeWriter.WriteResolvedMethodBody (Mono.Cecil.MethodDefinition method) [0x00000] in <filename unknown>:0
    11.   at Mono.Cecil.Cil.CodeWriter.WriteMethodBody (Mono.Cecil.MethodDefinition method) [0x00000] in <filename unknown>:0
    12.   at Mono.Cecil.MetadataBuilder.AddMethod (Mono.Cecil.MethodDefinition method) [0x00000] in <filename unknown>:0
    13.   at Mono.Cecil.MetadataBuilder.AddMethods (Mono.Cecil.TypeDefinition type) [0x00000] in <filename unknown>:0
    14.   at Mono.Cecil.MetadataBuilder.AddType (Mono.Cecil.TypeDefinition type) [0x00000] in <filename unknown>:0
    15.   at Mono.Cecil.MetadataBuilder.AddTypeDefs () [0x00000] in <filename unknown>:0
    16.   at Mono.Cecil.MetadataBuilder.BuildTypes () [0x00000] in <filename unknown>:0
    17.   at Mono.Cecil.MetadataBuilder.BuildModule () [0x00000] in <filename unknown>:0
    18.   at Mono.Cecil.MetadataBuilder.BuildMetadata () [0x00000] in <filename unknown>:0
    19.   at Mono.Cecil.ModuleWriter.<BuildMetadata>b__0 (Mono.Cecil.MetadataBuilder builder, Mono.Cecil.MetadataReader _) [0x00000] in <filename unknown>:0
    20.   at Mono.Cecil.ModuleDefinition.Read[MetadataBuilder,MetadataBuilder] (Mono.Cecil.MetadataBuilder item, System.Func`3 read) [0x00000] in <filename unknown>:0
    21.   at Mono.Cecil.ModuleWriter.BuildMetadata (Mono.Cecil.ModuleDefinition module, Mono.Cecil.MetadataBuilder metadata) [0x00000] in <filename unknown>:0
    22.   at Mono.Cecil.ModuleWriter.WriteModuleTo (Mono.Cecil.ModuleDefinition module, System.IO.Stream stream, Mono.Cecil.WriterParameters parameters) [0x00000] in <filename unknown>:0
    23.   at Mono.Cecil.ModuleDefinition.Write (System.IO.Stream stream, Mono.Cecil.WriterParameters parameters) [0x00000] in <filename unknown>:0
    24.   at Mono.Cecil.ModuleDefinition.Write (System.String fileName, Mono.Cecil.WriterParameters parameters) [0x00000] in <filename unknown>:0
    25.   at Mono.Cecil.AssemblyDefinition.Write (System.String fileName, Mono.Cecil.WriterParameters parameters) [0x00000] in <filename unknown>:0
    26.   at Unity.UNetWeaver.Weaver.Weave (System.String assName, IEnumerable`1 dependencies, System.String unityEngineDLLPath, System.String unityUNetDLLPath, System.String outputDir) [0x00167] in C:\buildslave\unity\build\Extensions\Networking\Weaver\UNetWeaver.cs:1507
    27.   at Unity.UNetWeaver.Weaver.WeaveAssemblies (IEnumerable`1 assemblies, IEnumerable`1 dependencies, System.String outputDir, System.String unityEngineDLLPath, System.String unityUNetDLLPath) [0x00060] in C:\buildslave\unity\build\Extensions\Networking\Weaver\UNetWeaver.cs:1531
    28. UnityEngine.Debug:LogError(Object)
    29. Unity.UNetWeaver.Log:Error(String) (at C:/buildslave/unity/build/Extensions/Networking/Weaver/Program.cs:19)
    30. Unity.UNetWeaver.Weaver:WeaveAssemblies(IEnumerable`1, IEnumerable`1, String, String, String) (at C:/buildslave/unity/build/Extensions/Networking/Weaver/UNetWeaver.cs:1538)
    31. Unity.UNetWeaver.Program:Process(String, String, String, String[], String[], Action`1, Action`1) (at C:/buildslave/unity/build/Extensions/Networking/Weaver/Program.cs:33)
    32. UnityEditor.Scripting.Serialization.Weaver:WeaveUnetFromEditor(String, String, String, String, Boolean)
    33.  
    My goal was to send that command to the server when a client connected and then have the server send another RPC to all connected clients (hence the rpc method below).

    Eventually I can get the editor to the point where my deprecated RPC warning messages show as compile errors which again clear if I restart the editor.
     
  2. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,562
    I don't think you can pass a NetworkConnection object in a command.

    These (commands) get rewritten using the tool (the one that is failing for you) to automatically inject code that serializes the method call into a network call.

    This can include something like creating a new method with a new name that will wrap this method call (serialize its arguments) and send it to the server.

    My guess is that this fails once it tries to serialize the NetworkConnection class.

    BTW: by the looks of it, the weaver tool uses Mono.Cecil (the error message seems to be from Cecil). The same error may probably occur in case you define any [Command] method that takes an argument of a type that's defined in another assembly.

    In order to resolve it, that type should be "resolved" (e.g: you need to resolve a MethodDefinition for it in Mono.Cecil terms). Maybe @seanr can confirm whether that's a real bug...
     
  3. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    You cannot pass a NetworkConnection to a command.. More validation of the arguments to network function is being added to give better feedback on this issue.
     
  4. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Thanks for the replies guys. How can the server determine who sent the command then?
     
  5. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    a command is called on the player object associated with the client that called command.
     
  6. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Ok. That makes sense.

    Here's the functionality I'm trying to convert. When a client connects to the server a new instance of a Team class is created for all players via a series of RPC calls. Teams hold information like player name, which faction they're playing, what house color they've chosen, etc. We use NetworkPlayer as a qualifier for each Team instance.

    So when a client connects we network instantiate a prefab that then sends an RPC to the server with player information and the owner of that network view to use as the qualifier. The server sends RPC calls to all the clients also passing that NetworkPlayer. The RPC calls are buffered so any new client connections "just get" the current teams. In addition, we have some lookup methods to find Teams based on the networkview owner of units once the game has started.

    So my thought was to use NetworkConnection like NetworkPlayer and send a Command to the server that then sent a ClientRpc to the clients. But, since we can't do this by passing NetworkConnection I need another way to globally and uniquely identify players.

    I see this: http://docs.unity3d.com/ScriptReference/Networking.NetworkBehaviour-playerControllerId.html but the doc says that this is only valid for local players so I'm guessing this is not the same ID across all players?

    Next I saw these:
    http://docs.unity3d.com/ScriptReference/Networking.NetworkBehaviour-connectionToClient.html
    http://docs.unity3d.com/ScriptReference/Networking.NetworkBehaviour-connectionToServer.html
    which seem like they might be what I want with the caveat that I need to check if we're the client or the server (and it appears that there is a mistake in the documentation since they both say "only valid on the server" but the documentation for NetworkIdentity appears to be correct so I'll go with that).

    So is playerControllerId something I can use straight away or should the Command use connectionToServer/Client in order to get at this (http://docs.unity3d.com/ScriptReference/Networking.NetworkConnection-connectionId.html) and pass that ID in the ClientRpc?

    Also (last question) - are IDs recycled? So if I have connections 0, 1 and 2 and 1 disconnects will the next new connection use 1 or 3?
     
  7. chrismarch

    chrismarch

    Joined:
    Jul 24, 2013
    Posts:
    472
    If you want to uniquely identify your player object, use the NetworkBehaviour.netId that is available in the context of your Command and ClientRpc method invocations (server or client). Or just use cache the object or compoent reference if you want to avoid looking them up later with the NetworkServer or ClientScene methods.
     
    KelsoMRK likes this.
  8. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Thanks - this seems to be working well so far!
     
  9. EndUser

    EndUser

    Joined:
    Aug 12, 2013
    Posts:
    51
    Salut!

    And what can I put "networkConnection" into
    Code (CSharp):
    1. NetworkServer.AddPlayerForConnection(networkConnection, gobjPrefab, 0);
    ?

    How can I convert NetworkBehaviour.netId into networkConnection?

    I'm trying to figure out how client can make server to spawn a player.
    http://answers.unity3d.com/questions/990677/networking-hlapi-spawning-objects.html
    csisy says that I can make server execute AddPlayerForConnection().
    Is networkConnection on local player is the same as networkConnection on server side of the same script?

    Thank you!
     
    Last edited: Jul 30, 2015