• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

HTML5 HTML5 JavaScript callbacks & (Array)Buffers in GM Extensions

DukeSoft

Member
Is anyone familiar with sending buffers back and forth through a JS extension for the HTML5 platform? I can send buffers from GM to libraries using buffer_get_address() - that wil give an ArrayBuffer in Javascript, which is good. But when I return a new buffer (an ArrayBuffer) back into GM, stuff breaks. From JS;

Code:
gml_Script_gmcallback_dsnet_data(-1, -1, arrayBuffer); //which is the exact same object type that came back from GM
in the GM script;
Code:
show_debug_message(string(argument2)); // [object ArrayBuffer]
show_debug_message(buffer_get_size(argument2)); // -5
show_debug_message(buffer_tell(argument2)); // -5
show_debug_message(typeof(argument2)); // ptr
show_debug_message(ptr(argument2)); // [object ArrayBuffer]
show_debug_message(buffer_get_address(argument2)); // undefined
show_debug_message(buffer_get_address(ptr(argument2))); // -5
I just don't know how I can use the GM Buffer functions on that JS arraybuffer
hint: -5 is not correct, and using buffer_read only returns "0"

PS: These are questions I had but i couldn't find, so posting them here for future voyagers looking for the answer:

Callback function from javascript to game maker html5:
Prefix your functions in GM with gmcallback_. This will make sure those functions are not obfuscated. They will be available in your JS extension with gml_Script_ prefixed to it. Example;

In GMS: gmcallback_test
In JS: gml_Script_gmcallback_test(-1, -1, <arguments>);

the arguments bit are the argument0 variables you can use. the first and 2nd -1 are required, don't know exactly what it is, but I think its arguments for "on what instance" to execute the code.

Callbacks are ran twice if the gm script has a with():
Yeah, I had that happen too.
Code:
///gmcallback_test
show_debug_message("Outside with");
with (obj_test) {
    show_debug_message("Inside with");
}
When calling that from JS, the output was:
Code:
Outside with
Inside with
Inside with
Fixed it by dropping a "return" within the with statement.
 

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
But when I return a new buffer (an ArrayBuffer) back into GM, stuff breaks. From JS;
You cannot do such a thing, neither on JS or native - get the size from the extension, have the GML side create a new buffer of the said size, and pass it to the extension to populate with data.
 

FrostyCat

Redemption Seeker
In GML, buffers are operated on over numeric IDs, not the actual thing. You are trying to pass in the actual thing through a callback, hence the error. You need to externalize the buffer-handling code into the extension as well, and pass on only things that GML could handle natively. It would be great if the HTML5 export would add new API functions for bringing things like buffers and images into the runner's fold with newly assigned IDs, but that might not happen formally for a very long time.

Also, you must remember that callback functions carry no instance scope, so anything referencing or implying "self" or "other" would fail. A with block definitely implies a sense of "self" and "other", and the repetition could very well be the GMS retrying the code (the default behaviour on an error).
 

DukeSoft

Member
In GML, buffers are operated on over numeric IDs, not the actual thing. You are trying to pass in the actual thing through a callback, hence the error. You need to externalize the buffer-handling code into the extension as well, and pass on only things that GML could handle natively. It would be great if the HTML5 export would add new API functions for bringing things like buffers and images into the runner's fold with newly assigned IDs, but that might not happen formally for a very long time.

Also, you must remember that callback functions carry no instance scope, so anything referencing or implying "self" or "other" would fail. A with block definitely implies a sense of "self" and "other", and the repetition could very well be the GMS retrying the code (the default behaviour on an error).
Yeah, I figured that might be it. I was basically looking for a function calles create_buffer_from_address(). But YAL's idea could work very well, since both GM and JS then still point to the same buffer.

The with() was just to force the execution of a script happening on a specific object, which it does nicely now.

You cannot do such a thing, neither on JS or native - get the size from the extension, have the GML side create a new buffer of the said size, and pass it to the extension to populate with data.
Thats actually a very good idea :) Thanks!
 

DukeSoft

Member
For future reference;

Setup 2 Uint8Arrays (views) for both ArrayBuffers (the referenced one from GM, and your own one), and fill it.
Code:
let gm_buffer_view = new Uint8Array(gm_buffer, gm_buffer.byteOffset, gm_buffer.byteLength);
let own_buffer_view = new Uint8Array(own_buffer, own_buffer.byteOffset, own_buffer.byteLength);

for (let i = 0; i < own_buffer.byteLength; i++) {
    gm_buffer_view[i] = own_buffer_view[i];
}
And the data is now available in GM.
 

DukeSoft

Member
Its working :) I have a solid communication between a GM TCP server and a Websocket browser client. Thanks guys!
 

RizbIT

Member
i have javascript code in which i set up some variables PX and PY. These are updated by javascipt when the phone is moved

How do i get the value of these javascript variable PX and PY into GMS in the step event?
 

Padouk

Member
i have javascript code in which i set up some variables PX and PY. These are updated by javascipt when the phone is moved

How do i get the value of these javascript variable PX and PY into GMS in the step event?
IN GMS:
Create a GML script using the naming convension gmcallback_<whatever>
GML:
function gmcallback_somefunction(px, py) {
    ...
}
In javascript
That function will be accessible using gml_Script_gmcallback_<whatever>(null, null, px, py);
Don't worry about the first two parameters, unless you know what you are doing...
JavaScript:
gml_Script_gmcallback_somefunction(null, null, px, py);
 

RizbIT

Member
IN GMS:
Create a GML script using the naming convension gmcallback_<whatever>
GML:
function gmcallback_somefunction(px, py) {
    ...
}
In javascript
That function will be accessible using gml_Script_gmcallback_<whatever>(null, null, px, py);
Don't worry about the first two parameters, unless you know what you are doing...
JavaScript:
gml_Script_gmcallback_somefunction(null, null, px, py);
ok so the listener event (that updates those variables) i can just call

gml_Script_gmcallback_somefunction(null, null, newpxvalue, newpyvalue);

and then gml script can set values of say global.px and global.py and so they stay updated and i just use those?


Ok but how do you do this in GMS1.4 (i only got html5 module on 1.4)
 
Last edited:

Padouk

Member
and then gml script can set values of say global.px and global.py and so they stay updated and i just use those?
Yes something like that... What I like to do when I create a asynchrone extension like what you are doing is to carry a requestId of sort... in your case it could be the instance id to update...
If I understand well that extension is ment to update the position of an object?


GML:
function YourCoolFunction_StartAsync() {
   //Pass your instance id
   yourextension_yourcoolfunction(id);
}


function gmcallback_YourCoolFunction_EndAsync()(target_id, px, py) {
   //use the returned id
   with(target_id) {
    x = px;
    y = py;
  }
}


Ok but how do you do this in GMS1.4 (i only got html5 module on 1.4)
Ah! Sorry i'll be of little help here. I decided to drop GMS1 from my pipeline when they locked the Marketplace for it.
That same functionally exists since the dawn of time.
updated:
If I remember well, in GMS1.4 you need to invoke the callback without the gml_Script_ prefix... something like
JavaScript:
gmcallback_somefunction(null, null, px, py);
 
Last edited:

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
If I remember well, in GMS1.4 you need to invoke the callback without the null, null and without the gml_Script_ prefix... something like
JavaScript:
gmcallback_somefunction(px, py);
null, null have always been there - they are self and other references. Other than that, the advice is correct. Various HTML5 extensions that I made can be used as a reference for tricks you can do for GML<->JS interop.
 
Top