Jump to content


Photo

Asynchronous Javascript


  • Please log in to reply
17 replies to this topic

#1 Oracizan

Oracizan

    Mutant Dreamer

  • GMC Member
  • 543 posts
  • Version:GM:Studio

Posted 13 January 2012 - 10:47 PM

Greetings.

I've been fiddling around with Facebook/Gamemaker integration. I've created a javascript extension that communicates with Facebook, and all has been good, up until I ran into some asynchronous javascript code.

The issue seems to be that the asynchronous javascript code does not finish executing until after the function has finished. While the asyc code is still trying to gather a value, the function has already returned a value of 'undefined' to gamemaker.

Forcing asyc code to be sync (linear) code via waiting is a big no-no with javascript it seems, so is there a way for gamemaker to retrieve the value of an async function? Or, is there a way to have the function finish and then holler over to the GM game that the value is nice and ready for it to come pickup now?

I'm thinking out loud here...pay me no mind. I'm just perplexed as to what I can do. :confused:
  • 0

#2 Smarty

Smarty

    GMC Member

  • Retired Staff
  • 7465 posts
  • Version:GM:Studio

Posted 17 January 2012 - 07:30 PM

This has always been a problem when creating extensions for GameMaker - there is no way to send a callback to the game (there are so-called 'web events' in GameMaker but they weren't meant for asynchronous callbacks). You need to poll for it somehow.

Although I'm not exactly at home in Javascript, this seems to be one way to do it: create a callback function in JS to catch the return information from the server. Make that function store the value in a variable. Create a GameMaker function that can retrieve the result of that variable. Also create a GameMaker function that can check the readystate property for the HTTPrequest.

What you need to do then is first fire off the AJAX request, then periodically poll the readystate (once every step, for example). When the readystate has a definitive result, you use retrieve the result. Obviously, you'll need to put in some intelligence to make sure the request is fired off only once, and to catch errors in the response.
  • 0

#3 blackhawkrobbo

blackhawkrobbo

    GMC Member

  • GMC Member
  • 751 posts
  • Version:GM:Studio

Posted 19 January 2012 - 11:28 AM

JacksonJarrr managed to create an asynchronous script: http://gmc.yoyogames...howtopic=529540
  • 0

#4 Oracizan

Oracizan

    Mutant Dreamer

  • GMC Member
  • 543 posts
  • Version:GM:Studio

Posted 20 January 2012 - 02:27 AM

Thank you both for your posts! I eventually created a function that allows me to do basically the same thing that you are both describing, but it was hack job and it wasn't pretty. The async javascript changes the html contents of an invisible div when it finishes, and then GM uses another JS function to check when the contents of that div are changed. I won't go into too much detail because it is bad, bad coding technique and not really something I encourage others to emulate. :tongue:

I saw a few examples of async scripts already on here, but I couldn't figure out how to make them work with Facebook, hence the hackish way of passing variables back and forth (For the record, the Facebook OAuth system is horrendous to use and poorly, poorly documented).

In pretty much any other situation that requires async I'd say that JacksonJarr's extension will have it covered.

Edited by Oracizan, 20 January 2012 - 02:27 AM.

  • 0

#5 blackhawkrobbo

blackhawkrobbo

    GMC Member

  • GMC Member
  • 751 posts
  • Version:GM:Studio

Posted 20 January 2012 - 09:58 AM

Hey Oracizan,

Yeah, well, in this beta version hack jobs and such are allowed if you ask me :)
I'm planning to make a facebook GEX, maybe you'd like to help me out with that in the future.

Good luck buddy!
  • 0

#6 Smarty

Smarty

    GMC Member

  • Retired Staff
  • 7465 posts
  • Version:GM:Studio

Posted 20 January 2012 - 10:52 AM

Thank you both for your posts! I eventually created a function that allows me to do basically the same thing that you are both describing, but it was hack job and it wasn't pretty. The async javascript changes the html contents of an invisible div when it finishes, and then GM uses another JS function to check when the contents of that div are changed. I won't go into too much detail because it is bad, bad coding technique and not really something I encourage others to emulate. :tongue:

Why? Aren't extensions for GM4HTML5 executed in the exact same window as the game itself? AFAICS the only thing you'd need to do is store the value in a global variable.

I saw a few examples of async scripts already on here, but I couldn't figure out how to make them work with Facebook, hence the hackish way of passing variables back and forth (For the record, the Facebook OAuth system is horrendous to use and poorly, poorly documented).

I found it a difficult read as well, but it does seem to provide the required information... One way to pass variables back and forth, as the documentation for server-side authentication notes, is by passing the values you need to keep track of in the redirect URI. So basically you're sending the values off to Facebook, and Facebook kindly sends them back for you to pick up from the URL parameters. The latter can be done both on the server and in a browser. In fact, for server-side authentication you MUST pass something like a session ID back and forth so you know which session has just been authenticated.

Edit: I'd be a bit cautious about using someone's extension if it isn't open-source, if it handles the authentication for you in such a black-box manner and you don't know what (else) is going on.

Edited by Smarty, 20 January 2012 - 10:55 AM.

  • 0

#7 blackhawkrobbo

blackhawkrobbo

    GMC Member

  • GMC Member
  • 751 posts
  • Version:GM:Studio

Posted 20 January 2012 - 07:39 PM

Edit: I'd be a bit cautious about using someone's extension if it isn't open-source, if it handles the authentication for you in such a black-box manner and you don't know what (else) is going on.


You can check out the source on the JS file in a GEX, right?
  • 0

#8 Smarty

Smarty

    GMC Member

  • Retired Staff
  • 7465 posts
  • Version:GM:Studio

Posted 20 January 2012 - 07:42 PM

You can check out the source on the JS file in a GEX, right?

Also when it's compiled into a GEX, rather than created on the spot? I haven't tried yet for GM4HTML5, but the old extension mechanism obfuscated GML scripts before they went into the GEX.
  • 0

#9

  • Guests

Posted 20 January 2012 - 10:54 PM

We've come up with a nice way to allow "call backs" into the engine, this will let you do async stuff in extensions and then basically throw normal GameMaker events (I'd suggest user events). We'll have to test, but it should be fine.... Not sure when it'll go in, but it'll avoid all the polling.

#10 paul23

paul23

    GMC Member

  • Global Moderators
  • 3801 posts
  • Version:GM:Studio

Posted 20 January 2012 - 11:23 PM

We've come up with a nice way to allow "call backs" into the engine, this will let you do async stuff in extensions and then basically throw normal GameMaker events (I'd suggest user events). We'll have to test, but it should be fine.... Not sure when it'll go in, but it'll avoid all the polling.

Might this sometime also be added for other extensions? Or do we have to wait for GM 9/much later?
  • 0

#11 JacksonYarr

JacksonYarr

    GMC Member

  • GMC Member
  • 248 posts
  • Version:GM:Studio

Posted 20 January 2012 - 11:52 PM

Also when it's compiled into a GEX, rather than created on the spot? I haven't tried yet for GM4HTML5, but the old extension mechanism obfuscated GML scripts before they went into the GEX.


Yes, assuming the javascript file wasn't already obfuscated when the extension was made - the unobfuscated source file can be found in either <ProjectFolder>\extensions\<ExtensionName> - or when compiled, the unobfuscated source file can be found in the html5game folder.
  • 0

#12 Oracizan

Oracizan

    Mutant Dreamer

  • GMC Member
  • 543 posts
  • Version:GM:Studio

Posted 21 January 2012 - 12:30 AM

Why? Aren't extensions for GM4HTML5 executed in the exact same window as the game itself? AFAICS the only thing you'd need to do is store the value in a global variable.

You are probably right. :thumbsup: I've only used javascript sparingly before, so with GM:HTML5 I'm learning as I go along. The html content swapping was the first method I stumbled upon of sending a variable that worked with async javascript, so I latched onto it for dear life.

I found it a difficult read as well, but it does seem to provide the required information... One way to pass variables back and forth, as the documentation for server-side authentication notes, is by passing the values you need to keep track of in the redirect URI. So basically you're sending the values off to Facebook, and Facebook kindly sends them back for you to pick up from the URL parameters. The latter can be done both on the server and in a browser. In fact, for server-side authentication you MUST pass something like a session ID back and forth so you know which session has just been authenticated.

All of that is true (except for the part about the facebook documentation providing the required information...I'd dispute that. :rolleyes: ), but that's not the issue that I ran into. I was using the pay dialog method of FB, for which the URL parameter method usually works, but with GM there is an added layer of communication. It goes like this:

(1: GM) -> (2: JS) -> (3: PHP) -> (4: FB) -> (5: PHP) -> (6: JS) -> (7: GM)

(1) to (2) to (3) is trivial. The issue comes in at (3) to (4) where PHP calls FB. FB creates a pay dialog with asynchronous JS, meaning that the rest of the code continues. Without waiting for (4), steps (5) to (6) to (7) occur. At this point, as far as GM is concerned, the function call that started this chain of communication is finished.

The FB dialog initiates a new JS script after the user responds on the dialog, which normally works just fine. But in the case of GM:HTML5, this new JS code has no simple way of passing the info back to GM - hence the need for polling.

We've come up with a nice way to allow "call backs" into the engine, this will let you do async stuff in extensions and then basically throw normal GameMaker events (I'd suggest user events). We'll have to test, but it should be fine.... Not sure when it'll go in, but it'll avoid all the polling.

If I understand you correctly, Mike, this would not eliminate the need for polling in this example. FB dialog communication is a two-step deal: A function first tells facebook that it needs to show a certain dialog, and then ends. FB then calls back to a file on the server with the information that the user entered into the dialog for you to do whatever you need with it. The problem is that the server can't initiate communication with GM - so as far as I can tell GM still has to constantly poll.
  • 0

#13 Smarty

Smarty

    GMC Member

  • Retired Staff
  • 7465 posts
  • Version:GM:Studio

Posted 21 January 2012 - 04:04 PM

Yes, assuming the javascript file wasn't already obfuscated when the extension was made - the unobfuscated source file can be found in either <ProjectFolder>\extensions\<ExtensionName> - or when compiled, the unobfuscated source file can be found in the html5game folder.

Excellent, thanks for telling us.

If I understand you correctly, Mike, this would not eliminate the need for polling in this example. FB dialog communication is a two-step deal: A function first tells facebook that it needs to show a certain dialog, and then ends. FB then calls back to a file on the server with the information that the user entered into the dialog for you to do whatever you need with it. The problem is that the server can't initiate communication with GM - so as far as I can tell GM still has to constantly poll.

On your server you have a callback PHP file. FB calls this file twice, and the second time is to tell your server that the (and which) order is completed. As far as I understand the method this all happens in the child window that was opened by Facebook to do all the authentication and payment. However, the child window was originally opened by the GM game so it should still have a reference to the parent, right? So all you need to do is include a piece of JS script in the callback that calls the 'payment completed' function in the parent window, where the game is.

It should, though, probably not do much more then trigger your game to pick up the bought content from the server (rather than have it pre-included in the -game) since ultimately all JS is client-side and prone to hacks.
  • 0

#14 Oracizan

Oracizan

    Mutant Dreamer

  • GMC Member
  • 543 posts
  • Version:GM:Studio

Posted 21 January 2012 - 04:41 PM

On your server you have a callback PHP file. FB calls this file twice, and the second time is to tell your server that the (and which) order is completed. As far as I understand the method this all happens in the child window that was opened by Facebook to do all the authentication and payment. However, the child window was originally opened by the GM game so it should still have a reference to the parent, right? So all you need to do is include a piece of JS script in the callback that calls the 'payment completed' function in the parent window, where the game is.

Keep in mind that the 'parent' in this case is the html page containing the GM game and not the GM game itself. The only legitimate "gateway" from external sources to the GM game is through 'return' in GM JS extensions scripts. In the case of FB, because of async, the GM extension function that made the call has already ended and the "gateway" is shut. By the time the FB variables are ready to make the trek back to GM, that ship has already sailed. You can enact all the external JS you want to change HTML on the page or set global JS variables, but external JS cannot interact with GM at the moment without a lot of fiddling around with obfuscated JS that's not meant to happen.

External JS has no way of knocking on GM's gate, so GM has to continuously poke its head out and yell "Anybody here? No? Okay, then, check again in three seconds."

I'm not trying to sound condescending by talking about "gateways" and "GM poking it's head out and shouting" instead of using proper terminology, so please don't be offended. It's just my way of thinking of it. :blush:
  • 0

#15 Smarty

Smarty

    GMC Member

  • Retired Staff
  • 7465 posts
  • Version:GM:Studio

Posted 21 January 2012 - 08:15 PM

Keep in mind that the 'parent' in this case is the html page containing the GM game and not the GM game itself. The only legitimate "gateway" from external sources to the GM game is through 'return' in GM JS extensions scripts.

Um, didn't Mike just say they're going to allow for a method to fire GM events (functions) using external JS? That's your callback, and it's going to be there in addition to the standard synchronous calls. My suggestion was how you could deal with it once these callbacks are there (notice I commented on your question to Mike). I don't see why you think there would be polling involved - your callback.php script (see FB documentation), which is what the FB authentication dialog redirects the browser to once the payment is settled, can fire off the game's event using client-side Javascript.

Edited by Smarty, 21 January 2012 - 08:16 PM.

  • 0

#16 Oracizan

Oracizan

    Mutant Dreamer

  • GMC Member
  • 543 posts
  • Version:GM:Studio

Posted 21 January 2012 - 08:56 PM

I think I see where our disagreement is.

We've come up with a nice way to allow "call backs" into the engine, this will let you do async stuff in extensions and then basically throw normal GameMaker events (I'd suggest user events).


The emphasis is mine on the word "extensions". I took it to mean that the javascript used in extensions would be able to execute code asynchronously to GM, not that any old async JS could call to Gamemaker. If it is the latter case you're completely correct, and that would be an incredibly useful feature!
  • 0

#17 Smarty

Smarty

    GMC Member

  • Retired Staff
  • 7465 posts
  • Version:GM:Studio

Posted 21 January 2012 - 09:14 PM

The emphasis is mine on the word "extensions". I took it to mean that the javascript used in extensions would be able to execute code asynchronously to GM, not that any old async JS could call to Gamemaker.

Ah, I see what you mean. Yes, that's one way to interpret it. However I didn't think JS offers anything substantial to protect its functions and objects from being accessed outside of the GM engine and its extensions, so if you could do it from an extension, you should be able to do it from elsewhere.
  • 0

#18 Oracizan

Oracizan

    Mutant Dreamer

  • GMC Member
  • 543 posts
  • Version:GM:Studio

Posted 21 January 2012 - 09:29 PM

It would be entirely possible to dig through the GM code and access whatever you need with external JS, if slightly annoying and inconvenient to do because of GM's obfuscation of the JS code.
  • 0




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users