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

Problem using an external JS library in Unity

Discussion in 'Scripting' started by Arkkonnen, Apr 27, 2016.

  1. Arkkonnen

    Arkkonnen

    Joined:
    Apr 27, 2016
    Posts:
    18
    Hi,

    I am trying to establish a connection between my serious game (developed in unity's javascript) and a remote learning recording system.

    For that I was intending to use the TinCanJS library, which is coded in JavaScript, but when i add the TinCanJS scripts to my assets folder, i start getting a lot of syntax errors.

    Is there any way for me to import the library, so i can just call the library functions from my unity scripts?

    Thank you
     
  2. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,194
    Unity's "JavaScript" is not JavaScript. It's not even close. There is no common ground between JS and what Unity's using that will allow you to import JavaScript code into Unity.

    If you want to use a JS library, you'll have to get it running in a JS engine somewhere, and then communicate with it over some protocol (like Json). You could also make a web app that lives between the remote learning system and your game, which uses your library.


    The "JavaScript" Unity uses has been dubbed UnityScript by the community (and Unity uses the name internally now). It's a .NET-language (like C#), which has been made to "look like" JavaScript. It has a bunch of anti-features, and should never be used for anything.
     
    Kiwasi likes this.
  3. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    JavaScript in Unity is not real JavaScript. It's a .NET language with superficial similarities to JavaScript.

    You are going to have to treat the real JavaScript as a seperate program and set up communication stuff and all that. You can't use it out of the box.
     
  4. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    http://wiki.unity3d.com/index.php/UnityScript_versus_JavaScript

    I swear, this is like one of the weirdest things IMO... not even Unity themselves can follow any name consistency, jumping back and forth between calling it unityscript and javascript.

    And yet, it's NOT javascript.

    Like it's as if their marketing team is pushing them to call it javascript because it's attractive to new comers who are familiar with what javascript is, so they can dig their hands in easier and not be scared of having to learn a scary new language like unityscript!

    Despite them still having to learn said new language, because it's not actually javascript.

    Ughhhhhhhh
     
    Kiwasi likes this.
  5. Arkkonnen

    Arkkonnen

    Joined:
    Apr 27, 2016
    Posts:
    18
  6. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    is 'tincan.dll' a .net library?

    dll doesn't necessarily mean it's .net

    also it has to be .Net 3.5 or earlier
     
  7. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    Is it this library?
    https://github.com/RusticiSoftware/TinCan.NET

    If so... yes, that's .Net, and it says it uses .Net 3.5, so that should work (because unity actually uses a modified version of the mono framework that targets .net 2.0, but contains a lot of 3.5 in it, some parts are missing... they usually aren't an issue, but the might bite you when importing some libraries... but give it a try, you'll know if it fails or not when you actually use it).
     
  8. Arkkonnen

    Arkkonnen

    Joined:
    Apr 27, 2016
    Posts:
    18
    Yes, that is the library i was talking about!

    But since it is a C# library, i guess i should be calling its functions from a c# script, am I right or did i get something wrong?

    Thanks!
     
  9. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    As long as you're importing the dll as a plugin, no, you don't need to access it from C#. It can be accessed from either C# or Unityscript/JS.

    There's only one issue with accessing C# from US/JS and vice versa, and that's got to do with unity compilation order. Your custom C# and JS scripts are compiled into separate dll's, so they can't access one another until they've been compiled, but if the compile order has one compiling after another, than you can't access it since it's not compiled yet.

    See:
    http://docs.unity3d.com/Manual/ScriptCompileOrderFolders.html
    (see, see, in that there they refer to it as unityscript... come on guys, make up your damn mind!)


    But this library is already compiled. So, no worries.
     
  10. Arkkonnen

    Arkkonnen

    Joined:
    Apr 27, 2016
    Posts:
    18
    Ok, i understand. So, here's what I've done. I go to assets->import new asset and i select the TinCan.dll file (i imagine this could be done just by dragging the file into unity). The file gets placed in the Standard Assets folder, which acording to the link you gave me is the first to get compiled.
    Then in one of my scripts (placed outside of the Standard Assets folder, so it should get compiled afterwards) i have typed "import TinCan;" (the file is named TinCan.dll), but i still get an error in the console "Namespace TinCan not found, maybe you forgot to add an assembly reference?"
    I have also tried import TinCan.RemoteLRS, because this is the class i'd like to use first, with the same result.

    Any idea?

    Thanks a lot, you have no idea how much i appreciate your help!
     
  11. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    TinCan.dll is a dll, it's ALREADY compiled.

    You don't need to import it using assets->import new asset, you can just drop it in a folder. Heck you could just drop it in the root Assets folder.

    Also, where did you get TinCan.dll, are you 100% certain that it's for that project?

    Also, rebuild your project, or refresh your project files (Assets->Refresh), make sure that the new dll is referenced by the visualstudio/monodevelop project files.
     
  12. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,194
    I tried the .dll from the top of here, and can import it just fine if I put the dll under standard Assets. I dragged the file into Unity. Are you getting any error messages when you select the .dll?


    If you want to import only one class from a namespace, the syntax is:

    Code (csharp):
    1. using put_whatever_here = SomeNamespace.SomeClass;
    So in your case,

    Code (csharp):
    1. using RemoteLRS = TinCan.RemoteLRS;
    It's very seldom any good reason to do that - the syntax is generally used to avoid name conflicts (such as between System.Random and UnityEngine.Random)

    Edit: If you're using UnityScript, this might be failing because the language is fundamentally broken, and has probably made up it's own syntax for imports or have made them crash on Wednesdays or whatever.
     
  13. Arkkonnen

    Arkkonnen

    Joined:
    Apr 27, 2016
    Posts:
    18
    I used exactly the same dll as Baste did. I drag it into the assets folder, or standard assets folder. The difference is i am trying to reference it from a unityscript not a c#, so shouldnt i be doing imports instead of using?

    Thanks!
     
  14. Arkkonnen

    Arkkonnen

    Joined:
    Apr 27, 2016
    Posts:
    18
    One thing i see is the TinCan.dll file doesn't appear in my MonoDevelop file tree. All my scripts are there, but the .dll isn't where i placed it. I see it on the unity gui but not on MonoDevelop's.
     
  15. Arkkonnen

    Arkkonnen

    Joined:
    Apr 27, 2016
    Posts:
    18
    Here's how my project looks like. The TinCan.dll is in the Standard Assets folder (i dragged it in there)

    upload_2016-4-27_18-35-58.png

    Then in the MyScripts folder i have a script called LRSCommunication.js, which looks like this:

    upload_2016-4-27_18-38-20.png

    And in the console i can read an error in red:
    "Assets/My Scripts/LRSCommunication.js(2,8): BCE0021: Namespace 'TinCan' not found, maybe you forgot to add an assembly reference?"

    I've read in some other unity3D threads that import is the unityscript equivalent of using, so that's why i tried this way.
     
  16. Arkkonnen

    Arkkonnen

    Joined:
    Apr 27, 2016
    Posts:
    18
    Hi again!

    So, here's the summary on what i've been doing:

    I am using the tincan.dll (by dropping it in my assets folder) from the top of https://github.com/RusticiSoftware/TinCan.NET/releases, and if i create a C# script and type "using TinCan" it throws no error in the unity console.

    The problem is i am working on an existing project coded in unityscript so it would be very helpful if I could use the library from a unityscript. I have read that "import library" is the equivalent in unityscript to "using library" in C#, but when I do type the "import TinCan" line, i get the following error in unity console "Assets/My Scripts/LRSCom.js(3,8): BCE0021: Namespace 'TinCan' not found, maybe you forgot to add an assembly reference?".

    I have also tried placing the .dll in the Plugins folder, and Standard Assets folder, but i get the same error.

    Is there anything that I am doing wrong, or should I assume that this combination (using the .dll library from a unityscript) won't work, and move on to another aproach?

    Thank you!
     
  17. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,194
    I honestly have no idea how you make importing work in UnityScript. My default advice (never use UnityScript ever) won't help you.

    I checked the same thing, and it seems like the import statement isn't finding the TinCan dll. It might be that UnityScript's importing works differently.

    What I did manage to work was to grab the TinCan stuff from a C# script, and then use that in UnityScript. I put this C# script next to the .dll in the Standard Assets folder:

    Code (csharp):
    1. using TinCan;
    2.  
    3. public static class TinCanBridge {
    4.  
    5.     public static RemoteLRS GetRemoteLRS() {
    6.         return new RemoteLRS();
    7.     }
    8. }
    Which made this UnityScript work fine:

    Code (csharp):
    1. #pragma strict
    2.  
    3. function Start () {
    4.     var lrs = TinCanBridge.GetRemoteLRS();
    5. }
    Which means that if you just wrap everything you need from TinCan in a C# method, then you can use it. It might be that there's a way to successfully import stuff in UnityScript, but I think just straight up switching to C# is a better use of your time.

    Really, UnityScript is a bad language, Unity seems to regret that they made it, and it doesn't exist outside of Unity. None of the forum regulars (the ones of us you'll be asking questions if you get stuck) knows the language well, so if you run into bugs, you'll probably be on your own unless somebody's waiting for their build to finish and can take time to investigate.
     
    KelsoMRK and Kiwasi like this.
  18. passerbycmc

    passerbycmc

    Joined:
    Feb 12, 2015
    Posts:
    1,739
    put that dll in Assets/Plugins, though also why use UnityScript, it is a terrible language especially when their is C# available to use that also has many more resources available to it.
     
  19. Arkkonnen

    Arkkonnen

    Joined:
    Apr 27, 2016
    Posts:
    18
    The reason I am using unityscript is because I am working on an already existing project (not mine), which is fully coded in unityscript , so I was trying to keep it that way. It's not that I decided to use unityscript at any point.

    Nevertheless, the TinCanBridge solution looks like the best option for me, so I'm going to give it a try.

    Thanks a lot to all of you!
     
  20. Arkkonnen

    Arkkonnen

    Joined:
    Apr 27, 2016
    Posts:
    18
    Hello again, I'm back!
    The TinCanBridge solution Baste posted is working just fine, but I've come to trouble a few steps ahead in the process.

    Instead of using an static class, i've decided to go for a more object oriented solution, so here's how my "TinCanBridge" class looks like right now.

    Code (CSharp):
    1.  
    2. public class TinCanInterface{
    3.  
    4.     private string endpoint;
    5.     private string user;
    6.     private string pass;
    7.  
    8.     private RemoteLRS lrs = null;
    9.  
    10.     public TinCanInterface(string endpoint, string user, string password){
    11.         this.endpoint = endpoint;
    12.         this.user = user;
    13.         this.pass = password;
    14.     }
    15.  
    16.     public void SetupLRS(string endpoint, string user, string password){
    17.         lrs = new RemoteLRS (endpoint, user, password);
    18.     }
    19.  
    20.     public void SendStatement(){
    21.        
    22.         StatementLRSResponse lrsResponse = this.lrs.SaveStatement (new Statement ());
    23.    
    24.     }
    25. }
    26.  
    Meanwhile, I am intending to use this from the follwing unityscript:

    Code (JavaScript):
    1.  
    2.  
    3. function Start () {
    4.  
    5.     var lrsConnection = new TinCanInterface();
    6.     lrsConnection.SetupLRS(lrsAddress, lrsUser, lrsPass);
    7.     lrsConnection.sendStatement();
    8. }
    9.  
    10. function Update () {
    11.  
    12. }
    As you can see, the idea is just to send an empty statement to check the connection is stablished.

    The thing is i am getting an error in the unity console that i don't understand at all. I think it has something to do with the Statement type internally using JSON, but i don't get it. Here's the full error drop:
    Unhandled Exception: System.TypeLoadException: Could not load type 'TinCan.Json.JsonModel' from assembly 'TinCan, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.

    at (wrapper managed-to-native) System.MonoType:GetMethodsByName (string,System.Reflection.BindingFlags,bool,System.Type)

    at System.MonoType.GetMethods (BindingFlags bindingAttr) [0x00000] in <filename unknown>:0

    at Mono.CSharp.MemberCache.AddMethods (BindingFlags bf, System.Type type) [0x00000] in <filename unknown>:0

    at Mono.CSharp.MemberCache.AddMethods (System.Type type) [0x00000] in <filename unknown>:0

    at Mono.CSharp.MemberCache..ctor (IMemberContainer container) [0x00000] in <filename unknown>:0

    at Mono.CSharp.TypeHandle..ctor (System.Type type) [0x00000] in <filename unknown>:0

    at Mono.CSharp.TypeHandle.GetTypeHandle (System.Type t) [0x00000] in <filename unknown>:0

    at Mono.CSharp.TypeHandle.GetMemberCache (System.Type t) [0x00000] in <filename unknown>:0

    at Mono.CSharp.TypeManager.LookupMemberCache (System.Type t) [0x00000] in <filename unknown>:0

    at Mono.CSharp.TypeHandle..ctor (System.Type type) [0x00000] in <filename unknown>:0

    at Mono.CSharp.TypeHandle.GetTypeHandle (System.Type t) [0x00000] in <filename unknown>:0

    at Mono.CSharp.TypeHandle.GetMemberCache (System.Type t) [0x00000] in <filename unknown>:0

    at Mono.CSharp.TypeManager.LookupMemberCache (System.Type t) [0x00000] in <filename unknown>:0

    at Mono.CSharp.TypeHandle..ctor (System.Type type) [0x00000] in <filename unknown>:0

    at Mono.CSharp.TypeHandle.GetTypeHandle (System.Type t) [0x00000] in <filename unknown>:0

    at Mono.CSharp.TypeHandle.GetMemberCache (System.Type t) [0x00000] in <filename unknown>:0

    at Mono.CSharp.TypeManager.MemberLookup_FindMembers (System.Type t, MemberTypes mt, BindingFlags bf, System.String name, System.Boolean& used_cache) [0x00000] in <filename unknown>:0

    at Mono.CSharp.TypeManager.RealMemberLookup (System.Type invocation_type, System.Type qualifier_type, System.Type queried_type, MemberTypes mt, BindingFlags original_bf, System.String name, IList almost_match) [0x00000] in <filename unknown>:0

    at Mono.CSharp.TypeManager.MemberLookup (System.Type invocation_type, System.Type qualifier_type, System.Type queried_type, MemberTypes mt, BindingFlags original_bf, System.String name, IList almost_match) [0x00000] in <filename unknown>:0

    at Mono.CSharp.Expression.MemberLookup (Mono.CSharp.CompilerContext ctx, System.Type container_type, System.Type qualifier_type, System.Type queried_type, System.String name, MemberTypes mt, BindingFlags bf, Location loc) [0x00000] in <filename unknown>:0

    at Mono.CSharp.Expression.MemberLookupFinal (Mono.CSharp.ResolveContext ec, System.Type qualifier_type, System.Type queried_type, System.String name, MemberTypes mt, BindingFlags bf, Location loc) [0x00000] in <filename unknown>:0

    at Mono.CSharp.New.DoResolve (Mono.CSharp.ResolveContext ec) [0x00000] in <filename unknown>:0

    at Mono.CSharp.Expression.Resolve (Mono.CSharp.ResolveContext ec, ResolveFlags flags) [0x00000] in <filename unknown>:0

    at Mono.CSharp.Expression.Resolve (Mono.CSharp.ResolveContext ec) [0x00000] in <filename unknown>:0

    at Mono.CSharp.Argument.Resolve (Mono.CSharp.ResolveContext ec) [0x00000] in <filename unknown>:0

    at Mono.CSharp.Arguments.Resolve (Mono.CSharp.ResolveContext ec, System.Boolean& dynamic) [0x00000] in <filename unknown>:0

    at Mono.CSharp.Invocation.DoResolve (Mono.CSharp.ResolveContext ec) [0x00000] in <filename unknown>:0

    at Mono.CSharp.Expression.Resolve (Mono.CSharp.ResolveContext ec, ResolveFlags flags) [0x00000] in <filename unknown>:0

    at Mono.CSharp.Expression.Resolve (Mono.CSharp.ResolveContext ec) [0x00000] in <filename unknown>:0

    at Mono.CSharp.Assign.DoResolve (Mono.CSharp.ResolveContext ec) [0x00000] in <filename unknown>:0

    at Mono.CSharp.SimpleAssign.DoResolve (Mono.CSharp.ResolveContext ec) [0x00000] in <filename unknown>:0

    at Mono.CSharp.Expression.Resolve (Mono.CSharp.ResolveContext ec, ResolveFlags flags) [0x00000] in <filename unknown>:0

    at Mono.CSharp.Expression.Resolve (Mono.CSharp.ResolveContext ec) [0x00000] in <filename unknown>:0

    at Mono.CSharp.ExpressionStatement.ResolveStatement (Mono.CSharp.BlockContext ec) [0x00000] in <filename unknown>:0

    at Mono.CSharp.StatementExpression.Resolve (Mono.CSharp.BlockContext ec) [0x00000] in <filename unknown>:0

    at Mono.CSharp.Block.Resolve (Mono.CSharp.BlockContext ec) [0x00000] in <filename unknown>:0

    at Mono.CSharp.ToplevelBlock.Resolve (Mono.CSharp.FlowBranching parent, Mono.CSharp.BlockContext rc, Mono.CSharp.ParametersCompiled ip, IMethodData md) [0x00000] in <filename unknown>:0

    Internal compiler error at Assets/Standard Assets/TinCanInterface.cs(21,21):: exception caught while emitting MethodBuilder [TinCanInterface::SendStatement]
    The following assembly referenced from D:\Facultat\TFG\Entrega PFG\src\Project\Virtual PC\Assets\Standard Assets\TinCan.dll could not be loaded:
    Assembly: Newtonsoft.Json (assemblyref_index=1)
    Version: 8.0.0.0
    Public Key: 30ad4fe6b2a6aeed
    The assembly was not found in the Global Assembly Cache, a path listed in the MONO_PATH environment variable, or in the location of the executing assembly (D:\Facultat\TFG\Entrega PFG\src\Project\Virtual PC\Assets\Standard Assets\).

    Could not load file or assembly 'Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed' or one of its dependencies.

    I am sorry that i have to come to you again, but any help will do.

    Thanks a lot.
     
  21. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,194
    The error happens just from the bridge script. In particular, this line:

    Code (csharp):
    1. StatementLRSResponse lrsResponse = this.lrs.SaveStatement (new Statement ());
    causes the compiler to crash.

    For reading the error report, this is the important bit:

    This means that TinCan's relying on a Json.net library. It seems to be this one.

    This is probably why TinCan's web page recommends installing it with NuGet, as that tool resolves dependencies like this. I have no idea how NuGet interacts with Unity, though - probably poorly, but it might work.

    Your choices are:

    - try to figure out what NuGet does, how it works, how to use it with Unity, and install TinCan through taht
    - figure out all of the reliances TinCan has, and all of the stuff those things rely on (might only be the Json package, might be a ton of packages), and add the correct version of their dll's to your Unity project.


    Your JS script also won't compile, but that's because you're calling new TinCanInterface(); when you gave TinCanInterface's constructor three arguments. That's not a hard problem to solve.
     
    Arkkonnen, KelsoMRK and Kiwasi like this.
  22. Arkkonnen

    Arkkonnen

    Joined:
    Apr 27, 2016
    Posts:
    18
    Hello,

    I think it is worth to post what worked for me because someone could find this post afterwards.

    I downloaded the Json.NET package from https://json.codeplex.com/releases/view/620338, and dropped the Newtonsoft.Json.dll file (bin/Net20) and dropped into my assets folder. That made the console error disappear (also I had to solve the constructor mistake, but that's not the subject here).

    Thank you!
     
  23. gubhare

    gubhare

    Joined:
    Oct 3, 2016
    Posts:
    3
    Hello All,

    This is all interesting stuff and all your individual posts are valuable. I am trying to connect and send xAPI statements through unity.

    I did everything mentioned in this post and then finally installing Newtonsoft.Json.dll in the assets folder as well and it would still not work. Finally found that the you have to change the project setting on the player object and tset the optimisation to .NET 2.0 instead of .NET 2.0 subset.
     
  24. AMNOD

    AMNOD

    Joined:
    Oct 19, 2014
    Posts:
    13
    Hi all,
    Thanks very much for the useful info posted here. I'm new to LMS and tin can and I need to use tin can in my unity project. I'm using C# not US so I needn't go through the hassle of creating a bridge for US. The problem is that I'm targeting 3 platforms: WebGl, android and iOS. So, will I have to create a unity plugin for each using the corresponding tin can library ?
    My second question is how to test the functionality of tin can ?

    Thanks in advance