Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Browser scripting and function calling.

Discussion in 'Web' started by jack-riddell, Jun 20, 2017.

  1. jack-riddell

    jack-riddell

    Joined:
    Feb 11, 2014
    Posts:
    326
    I am trying to create a WebGL plugin that uses an external javascrip library to call functions on the web browser.
    I have followed the instructions here (https://docs.unity3d.com/560/Documentation/Manual/webgl-interactingwithbrowserscripting.html) on calling external javascript functions and can successfully call functions held in .jslib files. My problem is that I can not get javascript functions held in .jslib files to call other javascript funcitons correctly.

    for example the following java script file throws an undefined error when Testfunction1 is called via c#

    Code (JavaScript):
    1. var TestFunctions =
    2. {  
    3.     InternalFunctionCall: function ()
    4.     {
    5.         window.alert(" Function Called");
    6.  
    7.     },
    8.    
    9.     TestFunction1: function ()
    10.     {
    11.         InternalFunctionCall();
    12.     },
    13. }
    14. mergeInto(LibraryManager.library, TestFunctions);
    I have tried defining the functions using ExternalEval (https://docs.unity3d.com/ScriptReference/Application.ExternalEval.html) or storing the functions in other .jslib files but nothing works they always throw an Undefined error when called.

    How do i call external java script functions? How do I integrate an external .jslib Library into a WebGL project?
     
  2. sumpfkraut

    sumpfkraut

    Joined:
    Jan 18, 2013
    Posts:
    242
    jack-riddell likes this.
  3. jack-riddell

    jack-riddell

    Joined:
    Feb 11, 2014
    Posts:
    326
    Thanks for replying but I don't think this addresses my issue.
    Just to clarify my issue is NOT calling unity c# functions from browser scripting its calling one custom java script function from another.

    my issue is I have created a custom javascript .jslib library that I am using to do browser peer to peer communication as well as other things but I am having trouble calling the functions in the library via a unity wrapper. every time I call a function from within another javascript function Unity throws a not defined exception.
     
  4. Marco-Trivellato

    Marco-Trivellato

    Unity Technologies

    Joined:
    Jul 9, 2013
    Posts:
    1,654
    what about this method ?
    Code (csharp):
    1.  
    2. var TestFunctions =
    3. {
    4.     $impl: {
    5.         internalFunctionCall: function()
    6.         {
    7.             window.alert(" Function Called");
    8.         },
    9.     },
    10.  
    11.     InternalFunctionCall: function ()
    12.     {
    13.         impl.internalFunctionCall();
    14.     },
    15. };
    16.  
    17. autoAddDeps(TestFunctions, '$impl');
    18. mergeInto(LibraryManager.library, TestFunctions);
    19.  
    This way you could call the actual implementation from any function of the library.

    We use the same technique in FileSystem.js (<unity install>\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\lib).
     
    Alex-Simson, dinah93 and jack-riddell like this.
  5. jack-riddell

    jack-riddell

    Joined:
    Feb 11, 2014
    Posts:
    326
    This works great thanks but it opens up another issue. Is there any way to call/link functions held in external files? I have a custom library held in a .jslib file that I want to call functions on but I don't know how to link it into the project.

    I was looking at other examples and they were loading in library's as text files then using https://docs.unity3d.com/ScriptReference/Application.ExternalEval.html to run the script and setup the java classes which seems to work (it runs the code at least ) but when I try to access the classes it sets up I get an undefined error.

    Is there a clear and idiot friendly explanation of how the external code is being called? I have a lot of experience with c++ and C# but just started with java script and things that work on a non unity web page throw errors when implemented with unity.
     
  6. Marco-Trivellato

    Marco-Trivellato

    Unity Technologies

    Joined:
    Jul 9, 2013
    Posts:
    1,654
    Do you just want to call jslib functions from C#? If so, then this page should all the info. You could also look at one of the asset store packages, for example this one.
     
  7. sumpfkraut

    sumpfkraut

    Joined:
    Jan 18, 2013
    Posts:
    242
    sry, i was reading the first post again.

    You want call a javascript function located in a HTML file from a jslib?
    or just a function from a different function?

    Code (JavaScript):
    1. var MyJslibPlugin = {
    2.   MyJslibName: function() {
    3.       function subfunction()
    4.       {
    5.         return something;
    6.       }
    7.       var result = subfunction();
    8.     }
    9. }
     
    Last edited: Jun 21, 2017
  8. sumpfkraut

    sumpfkraut

    Joined:
    Jan 18, 2013
    Posts:
    242
    Well, i think i did understand the problem.
    You try to write all functions in one single jslib file. I never did this. But pearhaps you can just delete the last comma after the last function.

    EDIT:
    and add a ; after the last }
     
  9. jack-riddell

    jack-riddell

    Joined:
    Feb 11, 2014
    Posts:
    326
    To clarify my problem here are a few more details.

    My current goal is to connect a bunch of non unity web pages to a single instance of Unity via webRTC peer to peer connections.

    rough diagram of my program structure.
    Network Setup.png
    I have written a class object in java script to handle a single network instance this is a simplified version of it
    Code (JavaScript):
    1. function WebRTCPrototype()
    2. {
    3.     this.WebRTCConnection = null;
    4.  
    5.     this.Connect = function(target, callback)
    6.     {
    7.         //create new connection
    8.         this.WebRTCConnection = new WebRTCConnection ();
    9.  
    10.         //connect to target
    11.         this.WebRTCConnection.ConnectTo(target);
    12.  
    13.         //set callback when message is received
    14.         this.WebRTCConnection.OnMessageCallback = callback;
    15.     }
    16.  
    17.     this.SendMessage = function(message)
    18.     {
    19.         this.WebRTCConnection.SendMessage(message);
    20.     }
    21.  
    22. }
    the networking instance class handles the connection for both the unity connection and the browser controller connection.

    because I need a unique instance of the network instance class for each connection a wrapper class is needed to give unity a single point of entry into the networking library.

    this is a simplified version of the unity wrapper

    Code (JavaScript):
    1. var UnityWrapper =
    2. {
    3.     var Connections ;
    4.  
    5.     var Message ;
    6.  
    7.    //create new network instance
    8.     CreateConnection: function(Target,ID)
    9.    {
    10.         //create new networking instance
    11.          var Connection = new WebRTCPrototype();
    12.  
    13.         //connect to target and set callback
    14.         Connection.connect(target,OnMessage)
    15.    
    16.        //store connection in dictionary array
    17.         Connections[id] = Connection
    18.  
    19.    }
    20.  
    21.     //callback called when message received
    22.     OnMessage: function(message)
    23.     {
    24.         Message = message;
    25.     }
    26.  
    27.     //c# access point to get message
    28.     GetMessage: function()
    29.    {
    30.         return Message;
    31.    }
    32.  
    33.     //send a message to a specific target
    34.     SendMessage: function(ID,message)
    35.     {
    36.         Connections[id].SendMessage(message);
    37.     }
    38.  
    39. }
    I can call functions from C# no problem its calling a java script function in one file from another that's causing the problem.
     
    Last edited: Jun 21, 2017
  10. bsawyer

    bsawyer

    Joined:
    May 6, 2014
    Posts:
    37
    @jack-riddell, I realize this is over a year old but were you able to find a solution?

    I have the same problem you describe in your original post, albeit my scenario is much simpler.

    Following the documentation example, I have a .jslib file containing the methods which Unity calls. Abbreviated:
    Code (JavaScript):
    1. mergeInto(LibraryManager.library, {
    2.  
    3.     SCOInitialize: function() {
    4.         return doInitialize();
    5.     },
    6.  
    7.     doInitialize: function() {
    8.        window.alert("LMS Communication successful!");
    9.        return true;
    10.     },
    11.  
    12. });
    (I realize the above snippet looks redundant, but it's a simplified version of my use case.)

    I also have the corresponding Unity C# script. Snipped:
    Code (CSharp):
    1. [DllImport("__Internal")]
    2. private static extern bool SCOInitialize();
    3.  
    4. void Start()
    5. {
    6.     SCOInitialize();
    7. }
    Unity successfully calls the external SCOInitialize function, but when SCOInitialize then tries to call doInitialize() - which is right freaking there! - I get the popup error on the page:
    This doesn't make sense to me as doInitialize is VERY CLEARLY DEFINED! So, what gives?
     
  11. JJJohan

    JJJohan

    Joined:
    Mar 18, 2016
    Posts:
    214
    I had a quick look through the jslib files in the PlaybackEngines\WebGLSupport\BuildTools\lib to see if any existing jslib files call methods in the same file.

    It looks like you might have to prefix your method call with an underscore.
    This is what audio.js does:

    JS_Sound_Play: function (bufferInstance, channelInstance, offset, delay)
    {
    // stop sound which is playing in the channel currently.
    _JS_Sound_Stop (channelInstance, 0);
    ...
    }

    JS_Sound_Stop: function (channelInstance, delay)
    {
    ...
    }
     
  12. Marco-Trivellato

    Marco-Trivellato

    Unity Technologies

    Joined:
    Jul 9, 2013
    Posts:
    1,654
    I think you need the underscore prefix and you need to add doInitialize() as a dependency of SCOInitialize() otherwise it will be stripped since it's not referenced by the C# script:
    Code (csharp):
    1.  
    2. mergeInto(LibraryManager.library, {
    3.    SCOInitialize__deps: ['doInitialize'],
    4.    SCOInitialize: function() {
    5.       return _doInitialize();
    6.    },
    7.    doInitialize: function() {
    8.       window.alert("LMS Communication successful!");
    9.       return true;
    10.    },
    11. });
     
  13. bsawyer

    bsawyer

    Joined:
    May 6, 2014
    Posts:
    37
    Thanks, that appears to have done the trick.

    I started learning about the dependency stuff late in the evening after my above reply and still spent a while trying to get the syntax right. Having to define the __deps line before every method that wants to use another method in the library seems obtuse and kind of messy. I've seen a few examples of "autoAddDeps" that purport to be a simpler, cleaner alternative but I could never quite get that syntax to work either.

    I feel like what I'm trying to do (call one jslib function from another) is pretty basic - the WebGL: Interacting with browser scripting page should really cover how to solve this problem since jslib's format is so different from regular JavaScript.

    Anyway I've finally got things working!
     
  14. Marco-Trivellato

    Marco-Trivellato

    Unity Technologies

    Joined:
    Jul 9, 2013
    Posts:
    1,654
    Our documentation also says "For more information on how to interact with JavaScript, refer to the emscripten documentation." :)
     
  15. bsawyer

    bsawyer

    Joined:
    May 6, 2014
    Posts:
    37
    And the emscripten documentation is a confusing mess as a Unity developer. I am not a JavaScript programmer or a C/C++ programmer (the intended audience of the documentation). Can you point out where in the documentation it gives the solution? Because I definitely looked! I personally don't have enough familiarity or understanding of emscripten to grok the solution I'm looking for because I don't know where to look, and I would wager many Unity game developers are in the same boat. Like I said, the problem I was trying to solve seems (to me) like something that lots of people reading the Unity documentation will probably run into, so why not add an extra blurb explaining the solution?
     
    Novack and unnanego like this.
  16. Marco-Trivellato

    Marco-Trivellato

    Unity Technologies

    Joined:
    Jul 9, 2013
    Posts:
    1,654
    I have to admit I had to look at examples to figure out how this works. The main reason why we don't have much in our docs regarding js libs is that it really depends on emscripten and we would need to keep our documentation updated.

    Having said that, you are probably right. We should add a short explanation about this..
     
  17. gordonius

    gordonius

    Joined:
    Nov 27, 2015
    Posts:
    3
    bsawyer I suspect we're working on the same type of project based on the function names in your code snippits. Maybe even in same building. Did you ever figure out things on your end? I'm on a project that used to be WebPlayer but is being converted to WebGL (5.6.2.x). I too came across the same unity documentation you did and started moving the .js files that used to be external to the Plugins folder as .jslibs. The first file seemed fine, but it was only a single function. The next file has a bunch of functions but also vars that aren't part of functions. The unity documentation shows the syntax for functions, what's the syntax for vars?
     
  18. bruceb85

    bruceb85

    Joined:
    Sep 26, 2020
    Posts:
    45
    I'm also stuck on this issue: How to call external .js function from unity .jslib plugin?
    I've read every article, tried it all - been at it for the past week with no solution.

    Unity - we understand your scope of responsibility stops right about here, at the jsplugin, but we need support to interface with the outside world.

    We are trying to expand the horizons of unity and its use cases but need your guidance.
     
    unnanego likes this.
  19. jukka_j

    jukka_j

    Unity Technologies

    Joined:
    May 4, 2018
    Posts:
    953
    unnanego likes this.