• 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!

Opera GX try .... catch doesn't appear to work with gxc api

peardox

Member
I've tried surrounding the @matharoo profile image example code with try ... catch around the gxc_profile_get_info call but it never actually hits the catch

I resorted to changing the image loaded event to something like this...

GML:
// If the Async ID matches our sprite request
if (async_load[? "id"] == spriteRequest) {
    // If the sprite was loaded successfully
    if (async_load[? "status"] >= 0) {
        // Set avatar sprite to the request ID. The ID of a dynamically loaded
        // sprite is the same id used by the request.
        global.avatar.image = spriteRequest;
    } else if (async_load[? "status"] == -1) {
        // Can't get image - use placeholder
        global.avatar.image = sprite_add(working_directory + "placeholder.png", 1, false, false, 0, 0);
    }
}
This, at least, puts something on the screen by loading a placeholder from datafiles/

Still get the horrid CORS stuff though which seems to indicate that the api itself is not exception-friendly or that try ... catch doesn't work properly in OperaGX

Note - the example raises a deprecation warning (use gxc_profile_get_info), which not especially helpful when that's about half of the available documentation
 

Mr Magnus

Viking King
Where are you putting the try catch? Could you post an example code that demonstrates you trying to use try/catch but it not working?
 

peardox

Member
Like I said - just about everywhere it could be triggered from.

I basically took the sample code, stuck the instance variables in a global struct and wrapped everything in try ... catch

I also tried it with the above code for the image load event just to be sure as debugging async is a pain in the proverbial

This is an adaption of the create event @matharoo shows (but using gxc_profile_get_info) - three possible places exist for an exception - none fire

GML:
global.avatar = {
    URL: "",
    fallbackUrl: working_directory + "placeholder.png",
    image: noone, // This is where the avatar sprite will be loaded
    username: "Loading...", // This is the username
    surface: -1, // This is the surface we will use to draw the circular avatar
    radius: 32,
    circleThickness: 4,
    circleColors: [ $00FEBC, $26171C ]
}

// First we will try to query the parameters from the URL
var _avatarUrl = gxc_get_query_param("avatarUrl");
var _username = gxc_get_query_param("username");

// If they are undefined it means they were not provided in the URL
// We are probably running the project locally, if that is the case
// we need to query for the profile information.
if (is_undefined(_avatarUrl) || is_undefined(_username)) {
    // We will request for an async query for profile information.
    // We also provide a callback function that will be called once
    // the async task finishes.
    try {
        gxc_profile_get_info(function(_status, _result) {
            // We need to check if status is 200
            // The value 200 means the task succeeded
            if (_status == 200) {
                // We can now read the values from inside the _result.data struct
                // to understand the _result structure please read documentation
                var _avatarUrl = _result.data.avatarUrl;
                var _username = _result.data.username;
                
                try {
                    spriteRequest = sprite_add(_avatarUrl, 1, false, false, 0, 0);
                    global.avatar.URL = _avatarUrl;
                    global.avatar.username = _username;
                } catch(e) {
                    show_debug_message("Catch 1 : " + e.longMessage);
                }
            }
        });
    } catch(e) {
        show_debug_message("Catch 2 : " + e.longMessage);
    }
} else {
    // Else means we have successfully queried the
    // parameters from the URL so we use them instead.
    try {
        spriteRequest = sprite_add(_avatarUrl, 1, false, false, 0, 0);
        global.avatar.URL = _avatarUrl;
        global.avatar.username = _username;
    } catch(e) {
        show_debug_message("Catch 3 : " + e.longMessage);
    }
}
 

Mr Magnus

Viking King
Sprite_add is an async function, meaning that if you give it an url to load from it will return a temporary sprite_index, and then make a network request. That request will later result in an image_loaded HTTP event.

I'd wager that if you're getting an exception it's not being raised there, and that you're not catching anything because everything within the try block works just fine.


Just out of curiosity, I presume that if you skip all try/catch blocks you get an exception: otherwise you'd not be looking for where to catch it. What does the exception say?
 

peardox

Member
It's just the usual CORS stuff

runner.html:1 Access to XMLHttpRequest at 'https://play.gxc.gg/users/9478601e-eb3f-4914-810f-0f3286aafb68?d1d46388378d66a9349ab3a1da274dd1' from origin 'http://localhost:58578' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
play.gxc.gg/users/9478601e-eb3f-4914-810f-0f3286aafb68?d1d46388378d66a9349ab3a1da274dd1:1 Failed to load resource: net::ERR_FAILED
This is when running it locally. Yep - I know that's not going to work but the above bodge makes it act the same both locally and on GXC which is useful for developing as otherwise you're forever uploading to GXC

The thing I'm interested in is why the try ... catch is not getting called - it's doing what I expect an exception handler to do.

If exceptions were working as expected then I should be able to get rid of the message as I'm handling the exception myself
 

Mr Magnus

Viking King
Are you actually getting an exception (as in your game comes to a grinding halt and yells at you) or just taking note of the CORS message in the console? If it's just the CORS message the reason you're not getting an exception is because CORS rejections (despite the alarming red color) aren't an exception and don't touch your game at all. They are the browser itself politely informing you that it is refusing to execute / pass on the request response because it believes it to be a security issue: the server didn't explicitly permit you to load this resource and to Opera that is suspicious. This is built in behavior in every browser I know of, you can't stop the browser from doing this on the GML side.

From the game's perspective everything went exactly as planned. It sent out a request successfully, the response came by legit means in an recognized state (rejected), and it triggers the image_loaded event. Nowhere did GML run in to an exception, and thus there is nothing to throw and nothing to catch.

What you are doing in checking the status of the returned request I'd argue is actually the best way to go about it. You send out a request, you get the response, you check if the request succeeded or failed, and you take appropriate action.
 
Last edited:
Top