Javascript plugin

Started by NewK, Aug 06, 2018, 03:37 AM

Previous topic - Next topic

NewK

Would anyone be interested in a javascript plugin?  I've got a basic vcmp javascript plugin working at the moment, still needs some testing but it's working. It runs on V8 and uses a nodejs-style event loop that allows you to do IO operations asynchronously without blocking the main thread. That's one of the advantages over squirrel. Another one is that it's also alot faster than squirrel and this is very noticeable for CPU intensive tasks. Some of my benchmarks showed it to be about 30x faster than squirrel.

All that's left to do right now is create some documentation, although I'd rather not go through the painful process of creating documentation and wasting days setting that up if there's no people interested in the plugin. So with this topic I'd just like to know first if there's anyone that would be interested in this plugin or not, I don't want to invest my time maintaining and documenting it if there's no interest from people ;D


D4rkR420R

I might be just unfamiliar with the language, however can you provide me examples of what Javascript can perform in terms of server development?

MatheuS

if( !sucess ) tryAgain();
Thanks to the VCMP community. It was the happiest period of my life.

MEGAMIND


(SpCy)Alex


vitogta

#5
I'd like to use javascript in vc-mp since this language is part of my job, especially if it comes with multi thread but I'm using rel004 and I never going to move to rel006. So if this plugin will work with 004 I will use that.

Thijn

Quote from: vitogta on Aug 06, 2018, 10:42 AMSo if this plugin will work with 004 I will use that.
Obviously not

vitogta

Quote from: Thijn on Aug 06, 2018, 07:23 PM
Quote from: vitogta on Aug 06, 2018, 10:42 AMSo if this plugin will work with 004 I will use that.
Obviously not
Then not intresting.

NewK

Quote from: KuRuMi^ on Aug 06, 2018, 04:50 AMI might be just unfamiliar with the language, however can you provide me examples of what Javascript can perform in terms of server development?
Well as far as VCMP features go, it has the same VCMP features that the squirrel plugin has. The same events, and the same server functions. The main advantages here in comparison to the squirrel plugin is that your code will run alot faster due to the JIT, and the IO operations can be done asynchronously. For example if you had to execute a slow DB operation that would take 5 seconds to complete, your whole server would be "paused" for the duration of this operation. That means for the players inside your server they would see everyone warping/lagging until the operation was finished. Using this plugin, that would not happen if you executed this operation asynchronously. The plugin would execute this in a background thread instead of using the main server thread and would return a callback with the results. For example if I wanted to query a mysql "users" table and print the nickname of each user to the console, it would look something like this:

    //open mysql connection
    var conn = sql.connect("dbName", "localhost", 3306, "dbUser", "dbPassword");

    //queries users table
    conn.query("select * from  users", function (accounts) {
        accounts.forEach(account => {
            console.log(account.nick);
        });
    });

If you wanted to do it in a synchronous manner you could do that too you'd just need to remove the callback and it would behave synchronously:
var accounts = conn.query("select * from  users");

Quote from: vitogta on Aug 06, 2018, 07:26 PM
Quote from: Thijn on Aug 06, 2018, 07:23 PM
Quote from: vitogta on Aug 06, 2018, 10:42 AMSo if this plugin will work with 004 I will use that.
Obviously not
Then not intresting.
Actually, the plugin will work on rel004 if you use a rel004 server executable.  You just wont be able to use any of the new features/bugfixes from rel005 and rel006 versions obviously.

This plugin relies on the vcmp java plugin to expose the vcmp "environment" to the javacript context. VCMP server functions and events are exposed from the java plugin and can be used seemlessly from javascript. Java will also be used to implement  IO, multithreading and any other external library that's needed. It will then provide access to all of that through simple javascript APIs.

ysc3839

I wonder how you deal with asynchronous event loop?
As for Python, it requires a blocking event loop to run async code.So I have to run it on another thread.
Another problem is if it's safe to call server function on another thread?

.

Quote from: NewK on Aug 06, 2018, 10:54 PM...
This plugin relies on the vcmp java plugin to expose the vcmp "environment" to the javacript context. VCMP server functions and events are exposed from the java plugin and can be used seemlessly from javascript. Java will also be used to implement  IO, multithreading and any other external library that's needed. It will then provide access to all of that through simple javascript APIs.

I kinda knew that was the case. Doing this via c/c++ for v8 or some other engine would be a little overkill.
.

EK.IceFlake

It'd be nice, but one of the main advantages of JavaScript is the number of libraries there are out there. Most of the libraries that deal with IO stuff won't work because they rely on Node.JS's API.

NewK

Quote from: ysc3839 on Aug 07, 2018, 09:18 AMI wonder how you deal with asynchronous event loop?
I implemented an event loop similar to the way libuv did it for node.js. The event loop is single threaded and runs on the main thread (server thread) just like all the javascript code. Event loop iterations are processed onServerFrame. The event loop has a thread-safe linked queue that simply receives the results of the asynchronous operations that are run on the other threads. On each event loop iteration, if the queue is not empty, the results are dispatched to the javascript context through callbacks.

Quote from: ysc3839 on Aug 07, 2018, 09:18 AMAnother problem is if it's safe to call server function on another thread?
Nah, it's not safe to call server functions from another thread. Infact, on the java plugin if you try to do this, it will not let you and will throw an exception. But the java plugin provides a proper way to do it through server.sync(). That will pause the main thread for a few moments to ensure thread safety and will let you use the server API from other threads. But that's something to use with the actual java plugin, it won't be used on this javascript plugin

Quote from: . on Aug 07, 2018, 11:40 AMI kinda knew that was the case. Doing this via c/c++ for v8 or some other engine would be a little overkill.
Yea, the idea here was to rely on the already existing java plugin to facilitate maintainability. Easier to maintain this way. The next time a new VCMP update is released I just need to update the java plugin and this plugin will automatically be updated aswell. No need to mantain two separate codebases this way :P

Quote from: EK.IceFlake on Aug 07, 2018, 01:13 PMIt'd be nice, but one of the main advantages of JavaScript is the number of libraries there are out there. Most of the libraries that deal with IO stuff won't work because they rely on Node.JS's API.
No, that's not one of the main advantages of javascript, that's one of the main advantages of node.js. Do not mix up the 2, those are 2 very different things. Javascript is not node.js and node.js is not javascript. Node.js is simply a set of C++ APIs that are made available to a javascript context running on top of V8. I never claimed this to be a node.js plugin, I said this is a javascript plugin, as in, actual ecmascript.  Think of it this way: Nodejs is a set of C++ APIs exposed to a javascript context running on V8. This plugin is a set of Java APIs exposed to a javascript context running on V8. Java was used to rely on the already existing VCMP Java plugin to expose VCMP functionality and to share the same codebase so it's easier to maintain in the future.

vitogta

#13
Can you write a simple example, I want to get player's position and some other player's data (from instance), then I want to make some heavy calculation with this data in another theread (without blocking main theread) then (when calculations are done) I want to call a function with the result of those calculations as an argument in main theread (to interact player's instance by this function).

ps also is it possible to interact with another plugins like database or hashing in another (not-main) theread?

NewK

Quote from: vitogta on Aug 07, 2018, 02:20 PMCan you write a simple example, I want to get player's position and some other player's data (from instance), then I want to make some heavy calculation with this data in another theread (without blocking main theread) then (when calculations are done) I want to call a function with the result of those calculations as an argument in main theread (to interact player's instance by this function).
At the moment it's not possible to manually spawn threads yourself, javascript is not a very good language to do this type of thing because it would involve spawning a new V8 Runtime instance per thread, starting a new V8 instance is a bit slow and memory intensive. This was never the objective of the plugin, for such control over threads, the java plugin should be used instead. This plugin spawns the threads itself on the background, executes the operation, and simply calls a javascript function when that operation is finished with the results, but it never spawns any additional V8 instances, it simply returns to the already created V8 instance. Maybe in the future I'll look into this again but there's no "good" solutions. Node.js has this implemented, but even so, the node.js team still recommends not using it due the same issues I've described above.

For what you want to do, I'd just send an http request to an http server running on localhost, do the heavy calculation there, and return the result to the vcmp server. I already have an httpclient made that allows you to execute requests asynchronously without blocking the main thread, it would look something like this:

function onPlayerEnterVehicle(player, vehicle, slot) {
    var data = {
        X: player.pos.X,
        Y: player.pos.Y,
        Z: player.pos.Z
    };

    http.postJson("https://httpbin.org/post", data,
        function (response) {
            var resp = response.body().string();

            //if the response is a json string you can convert it to a JSON object like this
            var calculationResultFromServer = JSON.parse(resp);

            // call your function
            functionToCall(calculationResultFromServer);
        })
}
That's just an example on the PlayerEnterVehicle event but you could use it anywhere you want to. I sent the http request to httpbin.org just to test it but you'd just replace that URL with your http server endpoint.

Quoteps also is it possible to interact with another plugins like database or hashing in another (not-main) theread?
Well as I said above, you can't manually spawn threads but you can use multiple different async operations inside each other. For example, combining the examples above:

  //open mysql connection
    var conn = sql.connect("dbName", "localhost", 3306, "dbUser", "dbPassword");
    var data = {
        X: player.pos.X,
        Y: player.pos.Y,
        Z: player.pos.Z
    };

    http.postJson("https://httpbin.org/post", data,
        function (response) {
            var resp = response.body().string();

            //if the response is a json string you can convert it to a JSON object like this
            var obj = JSON.parse(resp);
             
            //create a prepared statement to avoid any sql injection attacks
           var stm = conn.instance.prepareStatement("select * from  users where level=? and admin=? ");
           stm.setInteger(1, obj.level);
           stm.setBoolean(2, obj.isAdmin);

            conn.query(stm, function (accounts) {
             //print results to console
               accounts.forEach(account => {
                   console.log(account.nick);
               });
            });
     })