Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

SyncVar, Command, ClientRPC inside a custom DLL - Is it possible?

Discussion in 'Multiplayer' started by Freaking-Pingo, Jul 29, 2017.

  1. Freaking-Pingo

    Freaking-Pingo

    Joined:
    Aug 1, 2012
    Posts:
    310
    Hi all,

    I decided to split my code into two seperate projects, a client and a server project. In order for the projects tp share similar code I decided to wrap the shared code into a .dll. However, some of the code that resides in the .dll are Networkbehaviours that makes use of SyncVar, Command and ClientRPC.

    In an ordinary project when compiling, Unity identifies these special markers and generates boilerplate code, but this all happens behind the scenes. Because my code resides in a .dll Unity is not capable of generating the necessary code and thus state syncronisation does not work.

    How would you guys go about this? Is it even possible to use .dll at all in this case? Can I reuse Unity's code generation and apply it to the .dll I build?

    After posting this, I found topics with a similar question:
     
    Last edited: Jul 29, 2017
    nxrighthere and Deleted User like this.
  2. Freaking-Pingo

    Freaking-Pingo

    Joined:
    Aug 1, 2012
    Posts:
    310
    By investigating the source code of UNet it appears that the code generation magic is done by UNetWeaver. I assume I could invoke UNetWeaver myself, but I am not certain what arguments I should pass.
    Code (CSharp):
    1.         public static bool Process(string unityEngine, string unetDLL, string outputDirectory, string[] assemblies, string[] extraAssemblyPaths, IAssemblyResolver assemblyResolver, Action<string> printWarning, Action<string> printError)
    2.         {
    3.             CheckDLLPath(unityEngine);
    4.             CheckDLLPath(unetDLL);
    5.             CheckOutputDirectory(outputDirectory);
    6.             CheckAssemblies(assemblies);
    7.             Log.WarningMethod = printWarning;
    8.             Log.ErrorMethod = printError;
    9.             return Weaver.WeaveAssemblies(assemblies, extraAssemblyPaths, assemblyResolver, outputDirectory, unityEngine, unetDLL);
    10.         }
    I am also wondering, if I succesfully invoke UNetWeaver, what will exist in the output folder? I assume a .dll but I am not certain.
     
    Deleted User likes this.
  3. Deleted User

    Deleted User

    Guest

    Thanks for bumping.
     
  4. Freaking-Pingo

    Freaking-Pingo

    Joined:
    Aug 1, 2012
    Posts:
    310
    For @Wobes and whoever it may interest, I figured out you can invoke UNetWeaver yourself to apply the code generation to your own custom .dll

    I ended up creating a new console project in visual studio. I added UNetWeaver.dll and Mono.Cecil.dll as references to that project.

    I ended up writing the following:

    Code (CSharp):
    1. using System;
    2. using System.IO;
    3. class Program
    4. {
    5.         static void Main(string[] args)
    6.         {
    7.             Unity.UNetWeaver.Program.Process
    8.             (
    9.                 @"D:\Unity\Editor\Data\Managed\UnityEngine.dll",
    10.                 @"D:\Unity\Editor\Data\UnityExtensions\Unity\Networking\UnityEngine.Networking.dll",
    11.                 @"D:\MyUNetWeavingSolution\WeaverOutput\", //Output directory for the new .dll file
    12.                 new string[]
    13.                 {
    14.                     @"D:\MyDLLProject\bin\Release\Assembly-MyDLL.dll" //Your custom dll file. Remember to add "Assembly-" in front of the name
    15.                 },
    16.                 new string[]
    17.                 {
    18.  
    19.                 },
    20.                 null,
    21.                 (str) => Console.WriteLine("Warning: " + str),
    22.                 (str) => Console.WriteLine("Error: " + str)
    23.             );
    24.         }
    25.     }
    Remember, it is important that you add the prefix "Assembly-" to your custom build .dll, so its name becomes something like "Assembly-MyDLL.dll"

    You build or run the executable and a new code-generated DLL should be found in the output folder.

    I could attempt at writing a more general solution, but I believe people are better off doing it themselves at this point.
     
  5. Deleted User

    Deleted User

    Guest

    Thanks!
     
  6. AMNOD

    AMNOD

    Joined:
    Oct 19, 2014
    Posts:
    13

    Hi @Freaking-Pingo
    I managed to use UNetWeaver to inject the code needed for synchronization, RPCs and Commands to work thanks to your assistance. The thing is whenever I run the console project it removes the pdb file generated with my custom dll, thus I'm not able to debug my code whenever I use the dll in another project. Any clue what to do ?
     
  7. Freaking-Pingo

    Freaking-Pingo

    Joined:
    Aug 1, 2012
    Posts:
    310
    Without being completely certain, can't you use the .pdb file from when you build the UNet.dll before running UNetWeaver?
     
  8. AMNOD

    AMNOD

    Joined:
    Oct 19, 2014
    Posts:
    13
    I don't exactly get what you mean, I just use the UnityEngine.Networking.dll in my custom dll which handles a lot of behaviors beside the network behaviors.
    What I do:
    1- Build the dll. At this point, I can attach the debugger to the project that has the dll if I copy it to the project but UNet synchronization doesn't work.
    2- Run UNetWeaver console project on my custom dll, which injects code for UNet attributes and rpc calls. Hence, the lines offset is changed only inside the output dll, that's why I believe it deletes the old pdb cuz it won't work anyways.
    3- I finally get a dll that has UNet synchronization working but I don't have a pdb to debug it.

    I tried using dotpeek to decompile the dll, copy the injected code to my original project and rebuild the dll, thus I won't need to use UNetWeaver, and I can attach my debugger, but that's a really messy solution. I'll have to do this whole process each time I change anything in my NetworkBehaviours.

    Do you have anything in mind that can help ?

    Thanks a lot for the fast reply btw :D
     
  9. Freaking-Pingo

    Freaking-Pingo

    Joined:
    Aug 1, 2012
    Posts:
    310
    I haven't stumbled upon any debug symbol generation when using UNet weaver and I am a little bit too hung up on work to actually investigate it at the moment. Try reach out to Unity Technologies and see if they can provide some information on this. I believe there must be a solution to this we are not aware of.
     
  10. Sam-DreamsMaker

    Sam-DreamsMaker

    Joined:
    May 2, 2015
    Posts:
    13
    Thank you very much guys !

    I made a gift for you, a unity editor script with hotkey
    Have fun everyone ;)

    Code (CSharp):
    1. using UnityEditor;
    2. using System.IO;
    3. using UnityEngine;
    4. using System.Reflection;
    5. using Mono.Cecil;
    6.  
    7. public class UNetDLLBuilder : EditorWindow {
    8.     //if you are more lazy than me, check unity documentation about AssetModificationProcessor
    9.     //-- SamDreamsMaker
    10.  
    11.     //hotkey CTRL-SHIFT-D
    12.     [MenuItem("Window/Unet DLL Builder %#d")]
    13.     public static void BuildUnetDLL()
    14.     {
    15.         string unityFolder = @"D:\Unity\Editor\"; //your Unity3D Folder
    16.         string DLLUnityEngineFolder = Path.Combine(unityFolder,@"Editor\Data\Managed\UnityEngine.dll");//the folder containing UnityEngine.dll
    17.         string DLLUnityEngineNetworking = Path.Combine(unityFolder,@"Editor\Data\UnityExtensions\Unity\Networking\UnityEngine.Networking.dll");//the folder containing UnityEngine.Networking.dl
    18.         string referencesFolder = @"D:\MyUnetDLLProject\References\";//the folder containing references required for your dll
    19.         string pluginFolder = Path.Combine(Application.dataPath,"Plugins"); //output folder for the new .dll file, this example replace the old.
    20.         string targetDLL = "YourDLL.dll";//your dll file name
    21.         string targetFolder = Path.Combine (pluginFolder, targetDLL); //the location of your .dll file
    22.  
    23.  
    24.         //the resolver manage your references
    25.         var resolver = new DefaultAssemblyResolver();
    26.         resolver.AddSearchDirectory(referencesFolder);
    27.  
    28.         bool result = Unity.UNetWeaver.Program.Process
    29.             (
    30.                 @DLLUnityEngineFolder,
    31.                 @DLLUnityEngineNetworking,
    32.                 @pluginFolder,
    33.                 new string[]{targetFolder},
    34.                 new string[]{},
    35.                 resolver,
    36.                 (str) => Debug.Log("Warning: " + str),
    37.                 (str) => Debug.Log("Error: " + str)
    38.             );
    39.         if(result)
    40.             Debug.Log ("Updated DLL : "+targetDLL);
    41.         else
    42.             Debug.Log ("Fail update DLL : "+targetDLL);
    43.     }
    44. }
     
    MarcyR, softrare and Freaking-Pingo like this.
  11. michael_house

    michael_house

    Joined:
    May 24, 2013
    Posts:
    17
    Using this strategy on a UWP dll, there are no warnings or errors, but also no dll is output. What needs to be done differently for a UWP dll?