Search Unity

Unity3D/Mono and interfacing

Discussion in 'Editor & General Support' started by dmitche3, Apr 9, 2014.

  1. dmitche3

    dmitche3

    Joined:
    Apr 3, 2014
    Posts:
    23
    Has anyone been able to have Unity3D communicate with a non-unity program? I mean, have YOU yourself got it to work and not that you've read a post somewhere.

    I was assigned to see Unity was a viable option. One month later I have to report that answer is no. Unity3D is nice, but since debugging in Mono is worthless and not acceptable, the alternative was to continue game development in Visual studio and debug in VS, but interface with Unity. Two weeks now and three failed attempts have left me with a bad taste. Why?
    1. When exceptions are thrown for all of the communcation errors, the only message is "unidentified object". That is not useful.
    2. If the exception isn't caught in a Try/Catch, Mono goes to lala land.
    3. Unity freezes, Mono freezes, and other situations such as .mdb files being copied and Unity won't let Mono stay attached for debugging, which leads, unattaching Mono, hitting the retry in Unity, reattaching Mono in order to debug. After doing this at least 20-30 times an hour I'd rather not any longer. Unity freezes about 10-20 times a day, and Mono is a disease and should be avoided.
    4. Documentation for Unity is poor. Simply having a page that states the obvious is not good documentation. Having no examples and relying on other users posts is NOT documentation. Finding examples that actually work versus people saying that they work has made me want to give up and let the others have their way with other products.

    So, I'll ask before I sign off possibly for good, has anyone been able to communicate between Unity and a VS/C#/.Net application, OTHER than HTTP? I guess I should say that I'd prefer to stay away from services if possible but as that is my final attempt to do this week as I have no other option. :(
     
    Last edited: Apr 9, 2014
  2. dmitche3

    dmitche3

    Joined:
    Apr 3, 2014
    Posts:
    23
    Finally, after nearly 2+ weeks I've overcome Mono crashes, Unity freezing after each attempt to debug, internal compiler errors that forced me to compile the server code under Visual Studio to test, after each attempt to debug, Mono throwing exceptions that say nothing more than "unidentified object", I finally got remoting to work. As the examples that are pasted all over this web site do not work I WILL post all of my source code after I read the sticky on using code tags.

    Oh boy, I can't wait to throw multi-threading on to this one. As Mono/Unity don't play nice debugging multiple threads ( as they don't shut them down when you exit your code) this is why we as a company won't use Mono as our debugger, and now I don't have to, except for pure Unity code.
     
  3. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    I know that many people like abbreviations, but as Mono and MonoDevelop are clearly not the same, it would make sense to name them properly to avoid confusions.
     
  4. dmitche3

    dmitche3

    Joined:
    Apr 3, 2014
    Posts:
    23
    To summarize, we do all of our development (debugging) in Visual Studio. By using Remoting Unity can call the methods needed to pass information from our servers to the Unity game server thus limiting Unity development to Unity, and game logic to VS/.NET.

    First off, the call for the client method: SampleClient2.Main2 ();

    The client code. This creates a connection to the server and fetches the object 'testclass2'. The client (unity) then runs the testclass2 object on the server (Visual Studio/.Net)

    For testing, I simply ran the server in VS debugger. It would not compile under Unity because of Internal Compiler errors BUT
    it would run in the Mono debugger, just not compile. :( So you could test this out by compiling the client and running the server in the Mono/debugger.

    I wish you all the best of luck. Don't hestitate to ask questions.

    Addendum: You will also need to find and copy the following dlls. Create a folder under your asset folder called "Plugins" and copy the following from your Mono version that was installed with Untiy. Do NOT fetch anything from your Windows directory:

    System.Runtime.Remoting.dll
    System.Runtime.Serialization.dll

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. using System;
    5. using System.Runtime.Remoting;
    6. using System.Runtime.Remoting.Channels;
    7. using System.Runtime.Remoting.Channels.Tcp;
    8. using System.Runtime.Remoting.Channels.Http;
    9. using System.IO;
    10. // using System.Collections;  // REQUIRED FOR .NET
    11. using System.Runtime.Serialization.Formatters;
    12. using System.Threading;
    13.  
    14. public class SampleClient2: MonoBehaviour
    15. {
    16.     public static void Main2() //string [] args)
    17.     {
    18.         // Create a channel for communicating w/ the remote object
    19.         // Notice no port is specified on the client
    20.         TcpChannel chan = new TcpChannel();
    21.        
    22.         // Unity may hang here.  If so, make sure that the channel (port) is not already registered.
    23.         // Also, if you do not name your channels, the default is 'tcp'.  If you attempt to register more than one channel without
    24.         // naming them you will get a duplicate channel.
    25.         ChannelServices.RegisterChannel(chan, false); // the channel 'tcp' is already registered error
    26.  
    27.        
    28.        
    29.         // Create an instance of the remote object
    30.  
    31.         testclass2 obj= null;
    32.         // Crashes here tend to be that the server is not up and waiting for a call.
    33.         try {
    34.              obj = (testclass2) Activator.GetObject(
    35.                 typeof(testclass2),
    36.                 "tcp://localhost:8020/GetCount" );
    37.         }
    38.         catch(Exception ce)
    39.         {
    40.            
    41.             Debug.Log("Abort in main2 trying to fetch object " + ce.Message);
    42.             //Console.WriteLine(ce.Message);
    43.         }
    44.  
    45. // At this point you can use the object.
    46.                     int i = (testclass2)obj).GetCount();
    47.        
    48.         //  While this code should work and I will try to get it to work somehow, the following 'if' statement causes
    49.         // Unity/Mono to crash.
    50.         //          if( obj.Equals(null) )
    51.         //          {
    52.         //              System.Console.WriteLine("Error: unable to locate server");
    53.         //          }
    54.         //          else
    55.         //          {
    56.  
    57.         // Call your remote method.  Warning.  If you have your server app and this client in the same runtime you may not
    58.         // know if you truly are calling the remote method or the local as obj is declared as (testclass2).
    59.         // Therefore, "build and run" your server in a separate executable.
    60.         Debug.Log ("count is " + obj.GetCount());
    61.  
    62.         // The following error pops up for unknown reasons at unknown times. :(
    63.         // Nothing had changed between code runs, Unity was just crashed and was restarted.
    64.  
    65.         // Another strange Unity/Mono error at times is this one:
    66.         //      Mono.Debugger.Soft.VMDisconnectedException: Exception of type 'Mono.Debugger.Soft.VMDisconnectedException' was thrown.
    67.         //              at Mono.Debugger.Soft.Connection.SendReceive(CommandSet command_set, Int32 command, PacketWriter packet) in c:\BuildAgent\work\9ffd76bfa3f1a926\monodevelop\main\contrib\Mono.Debugger.Soft\Mono.Debugger.Soft\Connection.cs:line 1451
    68.         //                  at Mono.Debugger.Soft.Connection.VM_GetThreads() in c:\BuildAgent\work\9ffd76bfa3f1a926\monodevelop\main\contrib\Mono.Debugger.Soft\Mono.Debugger.Soft\Connection.cs:line 1542
    69.         //                  at Mono.Debugger.Soft.VirtualMachine.GetThreads() in c:\BuildAgent\work\9ffd76bfa3f1a926\monodevelop\main\contrib\Mono.Debugger.Soft\Mono.Debugger.Soft\VirtualMachine.cs:line 175
    70.         //                  at Mono.Debugging.Soft.SoftDebuggerSession.GetThread(Int64 processId, Int64 threadId) in c:\BuildAgent\work\9ffd76bfa3f1a926\monodevelop\main\src\addins\MonoDevelop.Debugger.Soft\Mono.Debugging.Soft\SoftDebuggerSession.cs:line 727
    71.         //                  at Mono.Debugging.Soft.SoftDebuggerSession.OnGetThreadBacktrace(Int64 processId, Int64 threadId) in c:\BuildAgent\work\9ffd76bfa3f1a926\monodevelop\main\src\addins\MonoDevelop.Debugger.Soft\Mono.Debugging.Soft\SoftDebuggerSession.cs:line 700
    72.         //                  at Mono.Debugging.Client.DebuggerSession.GetBacktrace(Int64 processId, Int64 threadId) in c:\BuildAgent\work\9ffd76bfa3f1a926\monodevelop\main\src\core\Mono.Debugging\Mono.Debugging.Client\DebuggerSession.cs:line 947
    73.         //                  at Mono.Debugging.Client.ThreadInfo.get_Backtrace() in c:\BuildAgent\work\9ffd76bfa3f1a926\monodevelop\main\src\core\Mono.Debugging\Mono.Debugging.Client\ThreadInfo.cs:line 79
    74.         //                  at Mono.Debugging.Client.ThreadInfo.get_Location() in c:\BuildAgent\work\9ffd76bfa3f1a926\monodevelop\main\src\core\Mono.Debugging\Mono.Debugging.Client\ThreadInfo.cs:line 64
    75.         //                  at MonoDevelop.Debugger.ThreadsPad.AppendThreads(TreeIter it, ProcessInfo p) in c:\BuildAgent\work\9ffd76bfa3f1a926\monodevelop\main\src\addins\MonoDevelop.Debugger\MonoDevelop.Debugger\ThreadsPad.cs:line 176
    76.         //                  at MonoDevelop.Debugger.ThreadsPad.UpdateDisplay() in c:\BuildAgent\work\9ffd76bfa3f1a926\monodevelop\main\src\addins\MonoDevelop.Debugger\MonoDevelop.Debugger\ThreadsPad.cs:line 146
    77.         ////            }
    78.     }
    79. }

    The SERVER CODE:
    Code (csharp):
    1. [//using UnityEngine;
    2. //using System.Collections;
    3.  
    4. using System;
    5. using System.Runtime.Remoting;
    6. using System.Runtime.Remoting.Channels;
    7. using System.Runtime.Remoting.Channels.Tcp;
    8. using System.Runtime.Remoting.Channels.Http;
    9. using System.IO;
    10. using System.Collections;
    11. using System.Runtime.Serialization.Formatters;
    12. using System.Threading;
    13.  
    14. // This is the server.  Start up the channel to listen and for testing I just go
    15. // into a while(true) loop.
    16.  
    17. // This was built and executed on Visual Studio 2013 as Unity/Mono could NOT compile this
    18. // due to internal compiler errors that were of no help trying to debug them.
    19.  
    20. public class SampleServer2 // : MonoBehaviour
    21.     {
    22.  
    23.         public static void Main()
    24.         {
    25.  
    26.             // Create an instance of a channel
    27.             int tcpPort = 8020;
    28.             // ------------------------------------------------------------
    29.             BinaryServerFormatterSinkProvider serverProv =
    30.                 new BinaryServerFormatterSinkProvider();
    31.             serverProv.TypeFilterLevel = TypeFilterLevel.Full;
    32.  
    33.             //UNITY/MONO debugging hangs if the following code is included.  This script was originally provided
    34.             // by others but would not run without tweaking it.
    35.  
    36.             //  RemotingConfiguration.CustomErrorsMode = CustomErrorsModes.Off;
    37.            
    38.             IDictionary propBag = new Hashtable();
    39.             serverProv.TypeFilterLevel = TypeFilterLevel.Full;
    40.             // -----------------------------------------
    41.            
    42.             // I did NOT try security so it may or may not work.
    43.             bool isSecure = false; // [true/false];
    44.             propBag["port"] = tcpPort;
    45.             propBag["typeFilterLevel"] = TypeFilterLevel.Full;
    46.             propBag["name"] = "UniqueChannelName";  // here enter unique channel name
    47.             if (isSecure)  // if you want remoting comm to be secure and encrypted
    48.             {
    49.                 propBag["secure"] = isSecure;
    50.                 propBag["impersonate"] = false;  // change to true to do impersonation
    51.             }
    52.             // -----------------------------------------
    53.            
    54.             // If you hang/crash here you probably have the channel tied up with another instance of the server or
    55.             // program.  Also if you have a firewall (Windows 7) you should see a notification asking for permission
    56.             // for access.
    57.             // You may need to see this link if you have Access Right Problems:
    58.             // http://stackoverflow.com/questions/885744/wcf-servicehost-access-rights
    59.  
    60.             TcpChannel tcpChan = new TcpChannel( propBag, null, serverProv);
    61.            
    62.            
    63.             ChannelServices.RegisterChannel(tcpChan, isSecure);
    64.  
    65.             // Without secure paramete I believe that Mono/Unity croaked again.
    66.             //ChannelServices.RegisterChannel(channel);
    67.            
    68.             // Register as an available service with the name GetCount
    69.             // Every incoming message is serviced by the same object instance.
    70.             RemotingConfiguration.RegisterWellKnownServiceType(
    71.                 typeof(testclass2),
    72.                 "GetCount",
    73.                 WellKnownObjectMode.Singleton );
    74.  
    75.             // keep the program running so that it can answer calls.
    76.            
    77.             while (true)
    78.             { }
    79.         }
    80.        
    81.     }
    82.    
     
    Last edited: Apr 10, 2014
  5. dmitche3

    dmitche3

    Joined:
    Apr 3, 2014
    Posts:
    23
    Correct DantlusTrue. And as there is Monodevelopment, Mono Touch, and I can't begin to know all of the other Mono projects. :) But even if you look at the output from Mono Debugger, even Mono people don't always make it clear as to what is what. I know I'm confused. :)

    In all of these instances I'm referring to Monodevelopment patckage under Unity, which includes the debugger which I believe is called Mono Touch.

    Also, since Unity uses Mono to build objects, that uses Mono classes and Mono objects, I'm not going to try and separate Mono from Unity as they are crossed at the hips.
     
    Last edited: Apr 10, 2014
  6. dmitche3

    dmitche3

    Joined:
    Apr 3, 2014
    Posts:
    23
    I updated the code above to point out how to consume the object once it is obtained from the server.

    Much of this also applies for named pipes.

    If you are not familiar with remoting and named pipes, and you find that this code runs but when you try to replace the method that returns anything other than an 'int' or 'string', you need to know that when using remoting that the class that you are sharing has to be the same between the two systems. You have to create a library that both your server and your client use to define the class/object that you are sharing. Otherwise you will receive errors, or this environment your object will not return a value, even though you may debug the code and see that it is working, the return value will fail the deserialization.

    Another got ya is that you only register channels once. The following code is only done once per channel(port).

    TcpChannel tcpChan = new TcpChannel( propBag, null, serverProv);
    ChannelServices.RegisterChannel(tcpChan, isSecure);

    If you have multiple objects/methods being remoted you will reference the same port for all of them but change the URI in the Activator().

    Example.
    object remObj = Activator.GetObject(typeof(MyRPCClass), "tcp://localhost:8017/ThisIsTheNameToChange");

    I hope that saves some people a few head aches.
     
    Last edited: Apr 13, 2014