Prevent game from crashing

O

orSQUADstra

Guest
I'm using GM 8.0, as it has obsolete functions that I simply need for my project. What I'm looking for is a way to prevent the "game" from crashing.
What I'd like to achieve is to simply have the game destroy the object that is causing the fatal error instead of crashing the whole game. Is there any workaround for this?
 

jo-thijs

Member
I'm using GM 8.0, as it has obsolete functions that I simply need for my project. What I'm looking for is a way to prevent the "game" from crashing.
What I'd like to achieve is to simply have the game destroy the object that is causing the fatal error instead of crashing the whole game. Is there any workaround for this?
I feel like if you're at a point where you expect your system to crash and are just trying to hide it, you're doing something wrong.

You're using execute_string, right?
Why is this esssential to your project?

As for a workaround, you could try to find or create an extension that hacks your game to replace the behavior of errors.
However, this won't get you anywhere.

You could try to interprete your string and change it so that it becomes valid GML code that won't crash.

You could try to find an extension that provides alternatives to string_execute.

Or you could change your project setup so that crash producing strings never occur in the first place.
 
O

orSQUADstra

Guest
I feel like if you're at a point where you expect your system to crash and are just trying to hide it, you're doing something wrong.

You're using execute_string, right?
Why is this esssential to your project?

As for a workaround, you could try to find or create an extension that hacks your game to replace the behavior of errors.
However, this won't get you anywhere.

You could try to interprete your string and change it so that it becomes valid GML code that won't crash.

You could try to find an extension that provides alternatives to string_execute.

Or you could change your project setup so that crash producing strings never occur in the first place.
Not just with execute_string, but anything just in general. For example, it's pretty lame when your game crashes when there's a division by 0 somewhere because of a bug in your game (not talking about the system here).

But to answer this question:
You're using execute_string, right?
Why is this esssential to your project?
I only use execute_string in a "terminal", so I can do some debugging and setting stuff in runtime easily. But that's the only case I actually use execute_string - at least, so far.
There's another thing that is more essential - object_add(), object_event_add(). In GM OS, these are very important to have and are used for third party programs. This allows you to write your own "Shell" programs (as I call them) easily - what it does, is when you double click a folder that ends with ".shl" in GM OS, it reads the text files in it, and thus creating the program. So, it does play pretty important role in here, and not much I could replace them with.
 
O

orSQUADstra

Guest
Pretty lame to be trying to divide by zero, I'd say.
I mean, I was dividing something with instance_count(), which was expected to always be 1 or greater. There was just something I f#cked up and all the instances were destroyed. Plus that was like 2 years ago lol
 
Last edited by a moderator:

jo-thijs

Member
Not just with execute_string, but anything just in general. For example, it's pretty lame when your game crashes when there's a division by 0 somewhere because of a bug in your game (not talking about the system here).
Do you mean you divide by 0 or the user writes code that divides by 0?
In the former case, you should try to find your bug instead of trying to hide it, so you would want error messages to pop up.

I only use execute_string in a "terminal", so I can do some debugging and setting stuff in runtime easily. But that's the only case I actually use execute_string - at least, so far.
There's another thing that is more essential - object_add(), object_event_add(). In GM OS, these are very important to have and are used for third party programs. This allows you to write your own "Shell" programs (as I call them) easily - what it does, is when you double click a folder that ends with ".shl" in GM OS, it reads the text files in it, and thus creating the program. So, it does play pretty important role in here, and not much I could replace them with.
That's ... really bad for an OS.
A GML code here would correspond to an assembly program executed in priviledge mode on normal OSes.
It's extremely easy for any system that can execute shell programs to destroy your entire OS.

You shouldn't allow the user to just execute any GML code he wants like that.
If you do anyway, you can just say the crash is the user's fault for trying to execute faulty code and they should deal with it,
just like it'll be your fault when you execute binary code in priveledge mode that destroys your entire system.

Anyway, there's no real workaround for this.
You could save the state of the OS just before running the program to ease the pain of the user when they screw up.
You could make your project execute another GameMaker exe that will execute the program in isolation.

The only good solution is to write a parser to limit what the user can execute and perhaps just use a new language entirely.
 
O

orSQUADstra

Guest
Do you mean you divide by 0 or the user writes code that divides by 0?
In the former case, you should try to find your bug instead of trying to hide it, so you would want error messages to pop up.


That's ... really bad for an OS.
A GML code here would correspond to an assembly program executed in priviledge mode on normal OSes.
It's extremely easy for any system that can execute shell programs to destroy your entire OS.

You shouldn't allow the user to just execute any GML code he wants like that.
If you do anyway, you can just say the crash is the user's fault for trying to execute faulty code and they should deal with it,
just like it'll be your fault when you execute binary code in priveledge mode that destroys your entire system.

Anyway, there's no real workaround for this.
You could save the state of the OS just before running the program to ease the pain of the user when they screw up.
You could make your project execute another GameMaker exe that will execute the program in isolation.

The only good solution is to write a parser to limit what the user can execute and perhaps just use a new language entirely.
Obviously there are limits to what the user can do. Certain functions and codeblocks are on the "blacklist", so the system won't even run the program if it finds them.

But alright, if there's no workaround for this then there's none and that's it.
 

jo-thijs

Member
Obviously there are limits to what the user can do. Certain functions and codeblocks are on the "blacklist", so the system won't even run the program if it finds them.

But alright, if there's no workaround for this then there's none and that's it.
Yeah, the only other thing you could try (that I can think of)
is to find an extension of someone who tried to implement something similar to execute_string (for gamemaker studio for example),
but with a separate parse step and execute step so you can easily change the results of the parse step to avoid crashes.
 
W

Wraithious

Guest
Not just with execute_string, but anything just in general. For example, it's pretty lame when your game crashes when there's a division by 0 somewhere because of a bug in your game (not talking about the system here).
In that kind of situation you should definatly be checking for that, it's really really easy to check
Code:
if (instance_count(pizza_slices) > 0)
{
 pizza_eaters_fed = pie_slices / instance_count(pizza_slices);
}
 
O

orSQUADstra

Guest
In that kind of situation you should definatly be checking for that, it's really really easy to check
Code:
if (instance_count(pizza_slices) > 0)
{
 pizza_eaters_fed = pie_slices / instance_count(pizza_slices);
}
Obviously I do check that, what causes the problem in my project is for example I have execute_string(keyboard_string), and I forget to put an argument in there
 
S

Silver_Mantis

Guest
The best answer is: Simply learn.
You're going to have the worst experience as a programmer if you cannot find multiple ways to solve a problem.
Sooner or later everything you know will be out of date and you'll have to either quit and give up, or adapt and just learn to ways to code.
I had to learn new things when I switched from GM1.4 to GMS2. Especially about cameras and layers.
It's all part of game design. Don't get frustrated by learning something new, be challenged by it and then do something about it. :)
 
O

orSQUADstra

Guest
The best answer is: Simply learn.
You're going to have the worst experience as a programmer if you cannot find multiple ways to solve a problem.
Sooner or later everything you know will be out of date and you'll have to either quit and give up, or adapt and just learn to ways to code.
I had to learn new things when I switched from GM1.4 to GMS2. Especially about cameras and layers.
It's all part of game design. Don't get frustrated by learning something new, be challenged by it and then do something about it. :)
Jesus f#cking christ people, only if you would read the comments. It's not what you're talking about. Let's say there's my so called terminal. It uses execute_string(keyboard_string) . There's a typo? Boom, game crashes. I simply want it that if there's something that would crash the game, destroy the object or something.
 
W

Wraithious

Guest
Jesus f#cking christ people, only if you would read the comments. It's not what you're talking about. Let's say there's my so called terminal. It uses execute_string(keyboard_string) . There's a typo? Boom, game crashes. I simply want it that if there's something that would crash the game, destroy the object or something.
This one requires you to do a little more work to prevent that, but you can just make a script containing all the things keyboard_string could equal and still be valid, so before calling string_execute, call the script and feed it the string from keyboard_string, and if an exact match is found use string_execute, if not then destroy your object.
 
O

orSQUADstra

Guest
This one requires you to do a little more work to prevent that, but you can just make a script containing all the things keyboard_string could equal and still be valid, so before calling string_execute, call the script and feed it the string from keyboard_string, and if an exact match is found use string_execute, if not then destroy your object.
So, if I understand it right, I should have literally any code in existence and check if keyboard_string is the same as one of them? That doesn't sound too efficient to be honest, and given that there are literally infintie variations of codes...
 

Tsa05

Member
You know, when the game crashes, how there's a message saying that the game crashed? Where do you suppose that message comes from?

I'll answer.

GameMaker is higher power than the code it runs.

Literally, the YYG people have to write things like this:
Code:
function divide(numerator, denominator){
     if(denominator < 0){
          throw("Cannot Divide by Zero");
     }else{
          return numerator / denominator;
     }
}
Well, not that, specifically because I assume that they are using libraries that already throw some common errors.
But basically, that's the deal. Everything that they tell GameMaker to do has to be surrounded by conditional checks to make sure that ALL possible errors result in an error box.

GameMaker checks everything that it's about to do, and tells the user that there's an error if the user tries to program it badly. In other words, it doesn't really crash at all. Instead, GameMaker correctly catches the error, tells the user that something went wrong that is hard to deal with, and then closes the software. NO Bluescreen of Death, NO frozen computer process--you get a nice error message instead of a true crash. GameMaker prevents crashes by intentionally doing something else--showing an error box--instead of executing code that would crash the computer.

You want to write a system that permits a user to execute commands. You want to intercept those commands, check whether they would cause a crash, and do something else instead. That's what you're telling us. But you're using execute_string, so you can't do what you say you want, because you're explicitly losing control of the code.

Rather than checking for the errors, catching them, and providing feedback, you're passing them straight into GameMaker's code interpreter (that's what execute_string does). So, you're asking GameMaker to handle the errors, and GameMaker does that in precisely the manner it was programmed. GameMaker prevents the computer from crashing by displaying an error box with information about the command that *would* have caused a crash.

You want to prevent that box; if you just send code into GameMaker, then errors will be handled by GameMaker, and that's why you see the error box. It's the way that GameMaker handles things. If you want it handled differently, you've got to interpret the commands in the way that you want them handled.

So, if I understand it right, I should have literally any code in existence and check if keyboard_string is the same as one of them?
And now you accurately understand how the GM8 runner works.
 

sylvain_l

Member
So, if I understand it right, I should have literally any code in existence and check if keyboard_string is the same as one of them? That doesn't sound too efficient to be honest, and given that there are literally infintie variations of codes...
not sure how it would work as you can literally name any variable/function/script what you want (as long as it legal in GML) and being syntaxically correct doesn't prevent that when you execute you endup with a denominator variable being 0 in a division.


theorycally, you would have to manage to recreate a sandbox environnement with your own GML interpreter where you could test the execution of your code.
YelloAfterLife did such a thing. But as it's web based I suspect that he's using javascript try/catch/final feature to ease his work for handling bogus code.
 

Humayun

Member
There is no easy way to prevent crashing when using gamemaker native execution. "execute_string" function is just same as GM 8 IDE events code, because old version of gamemaker execute code at runtime. "execute_string" function execution is treated same as other execution. So there is no way to prevent crashing. Gamemaker don't enable sandboxing with "execute_string" function. But there are several ways but you have to change your shell programs execution.

One way is described above run your shell programs in another executable. Start it with parameters of your shell file. Set it border less and forground. Set its position relative to your main window.

Another way is to create your own compile system for your shell. Create compiler and interpreter. Create syntax of your new shell programming. Start with simple syntax like
object_create(0) //Create object give it index 0
object_set_pos(0,100,100) //Set position of object index 0 to 100,100

Create compiler which would convert theses text to binary form. Detect possible errors here. For example give object_create an id.
So in binary format it would:

CALL OBJ_CREATE 0

Give CALL and OBJ_CREATE IDs to be used in binary format. Here CALL actually calls internal function OBJ_CREATE with argument 0.
For example CALL has id 100 OBJ_CREATE has ID 2. In binary format it would be like this:

01100100 00000100

Now it would by easy for your new interpreter to execute.
 
W

Wraithious

Guest
So, if I understand it right, I should have literally any code in existence and check if keyboard_string is the same as one of them? That doesn't sound too efficient to be honest, and given that there are literally infintie variations of codes...
If you're using execute_string to allow ANY function in gamemaker to be executed then yes, yes you do need to go into the manual and get their names and put them ALL in your script (or array, or ds list, or text file, or ini file or enum.. however you want to do it) to check against, and as far as that being 'efficient' or not isn't of any relevance whatsoever if that is what you are doing, it is however one way to make sure your game doesn't CRASH which is wayyy more efficient than risking a crash because a user spells something incorrectly, so the answer is yes, you are understanding what I said correctly.
 
Last edited by a moderator:
O

orSQUADstra

Guest
If you're using execute_string to allow ANY function in gamemaker to be executed then yes, yes you do need to go into the manual and get their names and put them ALL in your script (or array, or ds list, or text file, or ini file or enum.. however you want to do it) to check against, and as far as that being 'efficient' or not isn't of any relevance whatsoever if that is what you are doing, it is however one way to make sure your game doesn't CRASH which is wayyy more efficient than risking a crash because a user spells something incorrectly, so the answer is yes, you are understanding what I said correctly.
Ahhh, you mean the functions. At first I thought you meant every possible script that an user might come up with lol
 

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
Regarding error handling, try-catch is on the roadmap. However, using it carelessly has disastrous effects - for example, games made with Unity do not show any error messages by default (instead dumping them into a file) and instead become increasingly more broken because code halts mid-execution when an unhandled error happens. So you get reports like "everything was fine, then enemies started disappearing, then me gun stopped shooting, and the game got stuck on loading screen, pls fix" and good luck fixing that if they've already ran the game again and log file got overwritten.

Regarding executing arbitrary code, you can write a custom interpreter that would safeguard what it executes. I finished a post about this yesterday.
 
O

orSQUADstra

Guest
Regarding error handling, try-catch is on the roadmap. However, using it carelessly has disastrous effects - for example, games made with Unity do not show any error messages by default (instead dumping them into a file) and instead become increasingly more broken because code halts mid-execution when an unhandled error happens. So you get reports like "everything was fine, then enemies started disappearing, then me gun stopped shooting, and the game got stuck on loading screen, pls fix" and good luck fixing that if they've already ran the game again and log file got overwritten.

Regarding executing arbitrary code, you can write a custom interpreter that would safeguard what it executes. I finished a post about this yesterday.
That's all nice and good, but I'm using GM 8.0
 

kupo15

Member
Is there a way to execute a script in GMS2 when a crash is triggered? For example it would be great if I could run my scr_save_replay when a crash happened so that I can replay the events leading up to to the crash over and over
 

jo-thijs

Member
That's all nice and good, but I'm using GM 8.0
YAL's example code doesn't use anything essential to GM:S though.
With a little bit of porting, you can get it to work in GM8 too.

However, you said the reason you were using GM8 was because you needed functions that execute GML.
This system would get rid of that need, so couldn't you use GM:S with that now?

Is there a way to execute a script in GMS2 when a crash is triggered? For example it would be great if I could run my scr_save_replay when a crash happened so that I can replay the events leading up to to the crash over and over
Not yet.
However, YellowAfterLife mentioned try-catch is on the roadmap, so it might be coming in the future.
Someone on the GMC also found a way to execute their own C++ code when certain errors were thrown in GM:S 1 on some windows target.

You shouldn't be needing this though.
If you structure your project well, record the initial random seeds,
record the (change in the) player's input every step and always start recoring when you start your game
and have a method to play back these recordings,
you can alreay do this without changing the behavior of errors.
 

kupo15

Member
You shouldn't be needing this though.
If you structure your project well, record the initial random seeds,
record the (change in the) player's input every step and always start recoring when you start your game
and have a method to play back these recordings,
you can alreay do this without changing the behavior of errors.
For the most part I don't but there are occassions where the error report is not helpful like this one
Code:
___________________________________________
############################################################################################
FATAL ERROR in
action number 1
of  Step Event2
for object player_parent:

Push :: Execution Error - Variable Index [0,10] out of range [1,7] - 5.<unknown variable>(100423,10)
at gml_Script_scr_win_settings
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
gml_Script_scr_win_settings (line 0)
gml_Script_scr_knockout
gml_Script_scr_hurt
gml_Object_player_parent_Step_2

I think I may have a clue where to look and I know when this gets triggered but this crash doesn't happen all the time. Cases like this is where saving my replays would be helpful. I already record all the stats and inputs of the game however I don't save it to an ini file until you choose to save the replay but by the time the game has crashed its too late to do that. Unless you are suggesting I save my replays every frame to an ini I don't see how else to capture the crucial moments leading up to the crash. I don't think opening and saving to an ini file every frame is a good idea as I believe it hurts the framerate especially when you are saving progressively more data every frame.
 
O

orSQUADstra

Guest
However, you said the reason you were using GM8 was because you needed functions that execute GML.
This system would get rid of that need, so couldn't you use GM:S with that now?
Well, why I'm using GM8 here is because of that, and because of object_add() and object_event_add(), also because of the open filesystem.
 

jo-thijs

Member
For the most part I don't but there are occassions where the error report is not helpful like this one
Code:
___________________________________________
############################################################################################
FATAL ERROR in
action number 1
of  Step Event2
for object player_parent:

Push :: Execution Error - Variable Index [0,10] out of range [1,7] - 5.<unknown variable>(100423,10)
at gml_Script_scr_win_settings
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
gml_Script_scr_win_settings (line 0)
gml_Script_scr_knockout
gml_Script_scr_hurt
gml_Object_player_parent_Step_2

I think I may have a clue where to look and I know when this gets triggered but this crash doesn't happen all the time. Cases like this is where saving my replays would be helpful. I already record all the stats and inputs of the game however I don't save it to an ini file until you choose to save the replay but by the time the game has crashed its too late to do that. Unless you are suggesting I save my replays every frame to an ini I don't see how else to capture the crucial moments leading up to the crash. I don't think opening and saving to an ini file every frame is a good idea as I believe it hurts the framerate especially when you are saving progressively more data every frame.
Good point.

You wouldn't be saving every frame though, only the frames in which user input changes.
This might be close to every frame though if you're recording mouse movement in an intensive game.

You might still be fine writing the recording every step to a file (you would append the file with the new data only), but opening and closing a file every frame is indeed pretty performance intensive.
Alternatively, you could just output the recordings to the console using show_debug_message
or you could be using features such as clipboard_set_text every step.
You could also try to append the recording file every couple of seconds and use another method to be able to recover from intermediate input loss.
Perhaps extensions might also help create efficient for this.

Now, as to the error you're getting, it's indeed confusing looking, but it contains a bit of info still.
You know it happened in object player_parent.
You know it happened in a step event (I forgot which step event is number 2, but I think it's the end step event).
It tells you it happened in the first action you've got in there.
It further tells you you had an "index out of bounds" error in an array.
It tells you you provided index 10 or [0, 10], while the array was either a 1-dimensional array with length 7 or a 2-dimensional array with height 1 and length 7 at height 0.
The -5 tells you the array was global.
The 100423 tells you the instance id who was executing the code that caused this error.
It also tells you that your (end) step event first executed the inherited event of its parent object player_parent.
There the script scr_hurt was executed.
Then the script scr_knockout was executed.
Finally, that script executed scr_win_settings where the actual error occured.

Well, why I'm using GM8 here is because of that, and because of object_add() and object_event_add(), also because of the open filesystem.
object_add and object_event_add are non-essential, you can work your way around those once you've got a workaround for execute_string.
The sandboxed filesystem is an issue, but that can be fixed through extensions.
 
O

orSQUADstra

Guest
object_add and object_event_add are non-essential, you can work your way around those once you've got a workaround for execute_string.
The sandboxed filesystem is an issue, but that can be fixed through extensions.
Every window I have is a separate object in my project, and it's good like that. That was it's much easier to link non-window objects to window objects. To me, in this case, object_add and object_event_add are essential.
 

kupo15

Member
You wouldn't be saving every frame though, only the frames in which user input changes.
Good point but on second thought I have to record every frame. Not only can you play back recorded matches in order but you can FF and Rewind the replay so I need to have all player states recorded every frame to do that (x,y,image_index,sprite etc) BUT for the purposes of recording a glitch only those features are not needed and I could simply record when the inputs change.

Your alternate options are pretty interesting though, especially that copy to clipboard. I could update the clipboard every frame with the new replay data that is being recorded and then when the game crashes the entire replay data will be saved up until the crash without needing to save it to my ini file. Furthermore I could record the last 5 seconds worth of data instead of everything to keep the file small as I only need the data surrounding the crash. Thanks for the ideas!

Thanks for the breakdown of the error report. Didn't know it reference a global variable. Its just strange that it didn't provide an exact line or variable name...not sure why the variable name is unknown. I think it has to be IN the scr_win_settings and I think that 10 is the key clue. The character that was involved during the crash is character 10 yet I only have 7 characters so I think maybe I simply made a mistake in creating that array and didn't make it go up to 10. That'll be the first place I check, thanks!
 

jo-thijs

Member
Your alternate options are pretty interesting though, especially that copy to clipboard. I could update the clipboard every frame with the new replay data that is being recorded and then when the game crashes the entire replay data will be saved up until the crash without needing to save it to my ini file. Furthermore I could record the last 5 seconds worth of data instead of everything to keep the file small as I only need the data surrounding the crash. Thanks for the ideas!
You're welcome!
I forgot to mention though, I'm not sure what the performance of using the clipboard is.

Thanks for the breakdown of the error report. Didn't know it reference a global variable. Its just strange that it didn't provide an exact line or variable name...not sure why the variable name is unknown. I think it has to be IN the scr_win_settings and I think that 10 is the key clue. The character that was involved during the crash is character 10 yet I only have 7 characters so I think maybe I simply made a mistake in creating that array and didn't make it go up to 10. That'll be the first place I check, thanks!
Apparently I misread the -5, it's actually 5, so it's an array prefixed with object index 5, which is the 6th object in your asset tree.
I'm not sure about the unknown variable name and the line 0 either.
I think the character involved is character 11 though, as you were using index 10 and indices start from 0.

EDIT: Oh, and I confirmed that step 2 means end step event.
In general, the numbers correspond to the values of the ev_* constants, which are listed in order in the manual, starting from 0.

EDIT: After some testing, it seems like the variable always turns up as <unknown> when you prefix the variable with an object index,
with the instance id of an instance of another object index or with other (refering to an instance of an other object index).
 
Last edited:

kupo15

Member
I think the character involved is character 11 though, as you were using index 10 and indices start from 0.

EDIT: Oh, and I confirmed that step 2 means end step event.
In general, the numbers correspond to the values of the ev_* constants, which are listed in order in the manual, starting from 0.
I guess you are right with it being 11 haha Inside the code that particular character is set as "character = 10" so I suspect in the array that is crashing is referencing is something like array[0,character]. That is my hope anyway
I can also confirm the end step as well as I remember offhand that the entire stack is in the end step! And thanks for mentioning the 5. another thing I didn't know about the error report and should be helpful as well. Luckily my scr_win_settings is not that big assuming the error is found INSIDE that code which it appears to be. What line though I'm not sure!
 
Top