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

GameMaker Persistence is a lie?

Dupletor

Member
I made an object persistent, and I refer to the object on the clean up event of another object.
If I activate the clean up event by changing room, the game breaks because the an instance of the object that is persistent (and initialized in the first opened room) does not exist.
And that only seems to happen in the transition frame. If the clean up event is called through destruction, everything works, and since any room creation the reference exists.

Isn't it supposed to be persistent?
 
With out code its hard to tell why this is happening, but my guess is that the error is how your referring to the persistent object.
 
C

Catastrophe

Guest
Actually this was super easy to test so I just did it with two objects and two rooms.

It seems this is actually true, but with a bizarre twist. Cleanup ONLY bugs out if the other object is persistent: if the referred object is not persistent it does not crash. Furthermore it also bugs out if you close the game.

I'm pissed, I had a joe wilson You lie video handy :(

If I were to hazard a guess YYG did some hack to temporarily take persistent object out of existence at the moment non-persistent objects get destroyed :rolleyes:
I'm surprised the bug lasted this long, but then, that would mean people actually appropriately used cleanup lol.
 
Last edited by a moderator:

TsukaYuriko

☄️
Forum Staff
Moderator
We shall dub them Schrödinger's objects starting from now. :D

Either way, this sounds like a bug. It wouldn't surprise me if this had been in for some time already, though - I can't think of many cases where you'd need to refer to a persistent object in the Clean Up event rather than just straight-forward, well, cleaning up. Please file a ticket with an associated sample on the bug tracker.
 
C

Catastrophe

Guest
Oof.

"Thank you for reporting this, but it's not a bug or something we need to address, as the game doesn't crash - you correctly get a code error telling you that you can't modify that object as it no longer exists at the time of the cleanup event. Your persistent object has been moved to the "don't destroy me" list by this point, as it's not going to be cleaned up, so that's why it's not being found."

"Your "crash fix" is simply "if (instance_exists(obj2)) { derp.x = 5; }""

I assume they mean it's just not worth the effort to fix, as it may not be, but it's clearly a bug haha >.>

Here's how I would do it:

Make wrapper scripts for game_end() and room_goto()
in the wrapper, before you call the game maker functions, do

(or in a persistent game controller, put it in room_end/game_end)

with (all){
event_user(15)
}

and

with (all){
if (!persistent)
event_user(15)
};

and in destroy call ev_user15. And in the event descript put "functional cleanup" xD

Edit: Although if you're using the controller method, room_end is called during game end as well, so you'd have to make it a bit more nuanced to work.
 
Last edited by a moderator:

Mike

nobody important
GMC Elder
It's not a bug.... it's the way the engine works to allow persistence and cleanup. It's actually always done this, even pre-studio days.

There's lots of odd behaviour things as you start up and swap rooms. Things like... when you swap rooms, events don't run the way you think they do, is but one example.

Just one of those things you have to remember, although it would be nice to have an actual "list" of these quirks somewhere....
 

Yal

🐧 *penguin noises*
GMC Elder
A similar quirk that I remember leading to a bunch of confusion is how the Room Start event would be triggered every time you entered a persistent room, not just the first time (which is when you'd think the room "started")... but I guess that could be chalked up to the newbie mistake of interpreting programming terms as spoken english.
 

Joe Ellis

Member
I think it's as simple as when the room changes, persistent instances are destroyed but then added to the new room. I would just avoid referencing instances during room change, I don't see why there would be any need to, just do it once the room has changed or just before
 

Mike

nobody important
GMC Elder
Well, it's not quit that simple. The engine can't destroy them as you lose all the variables they contain. They are simply "unavailable" while you switch rooms...

While you could picture it that way if it helps, but that may lead you to think you lose all it's instance data too...
 

Joe Ellis

Member
I was thinking they get copied\cloned exactly then put back into the world, that's basically what happens

*quite
 
Last edited:

Mike

nobody important
GMC Elder
That I can't remember specifically.... I'm pretty sure they are just moved into a separate list, then are re-added to the new room's instance list, but it's been well over a year since I've seen that code, so I'm not sure.
 

Joe Ellis

Member
Yeah that makes sense, I'd do that rather than copying them

I just realized, your like the ex-yoyo member...
 

Roldy

Member
Just ran into this.

Persistent instances are removed from instance list during Clean Up event while a room transition is occurring.

Is there any known way to access the 'Persistent Instance' list during this time?

I good way to see this is put two instances in a room. One persistent the other not.

Put a break point in the non-persistent instances Room End event and Clean Up events.

Then trigger a room transition.

When the debugger halts on Room End event the debugger's instance list will show both persistent and non persistent instances.

But when it gets to the Clean Up event all persistent instances have been removed from the instance list.


The only reason I ran into this is because instance_destroy will trigger an instance's Destroy event, which triggers Clean Up. However a room transition does NOT trigger the Destroy event but DOES trigger Clean up Event. Meaning there isn't an obvious event to handle things when an instance is removed from the game (either destroyed or on room transition) if the persistent instances need to be referenced.

I suppose a solution is avoid Clean Up event, handle clean up code in Destroy event and call instance_destroy in Room End event, or avoid persistent instances.
 
Last edited:

Roldy

Member
How about this?
GML:
with(all){
  if(persistent){
    //Do whatever you need to do here
  }
}
No won't work. All persistent instances are removed from the instance list. Trying to access via instance id, object id, or keyword all will fail.

Running the above code:


GML:
with(all){  // with(all) will iterate through the instance list

  if(persistent){ // but since all persistent instances have been removed from the instance list 
    // this will never be called
  }
}
 

samspade

Member
No won't work. All persistent instances are removed from the instance list. Trying to access via instance id, object id, or keyword all will fail.

Running the above code:


GML:
with(all){  // with(all) will iterate through the instance list

  if(persistent){ // but since all persistent instances have been removed from the instance list
    // this will never be called
  }
}
While true for with and object id, I'm pretty sure you can access inactive instances by id. They do still exist, they just don't interact with a lot of the built in GM events/game loop/functions etc.
 

Roldy

Member
While true for with and object id, I'm pretty sure you can access inactive instances by id. They do still exist, they just don't interact with a lot of the built in GM events/game loop/functions etc.
Incorrect. They are not 'inactive' they have been removed from the instance list. You can confirm this in the debugger. If you have code that will then post it. I'll double check access with instance ID.

From the manual on de-activating functions:

Code:
So, these functions should be used with great care as they can cause problems when not used properly,
particularly with persistent objects,
as a persistent object that has been deactivated will not be moved to the next room unless it is re-activated first (effectively deleting it from the game).
So they havn't been set 'inactive' in the normal sense.

During a room transition from inside a Clean Up event, If you try to access a persistent object via instance id, object id, or keyword all it will fail.

Its a small thing. I'll just avoid using Clean Up.

EDIT: Just retested access via instance id.

You will get a fatal error when trying to access a persistent instance by instance id during Clean Up event triggered by a room transition.
 
Last edited:

kburkhart84

Firehammer Games
The manual does say 'inactive' instances can still be accessed via instance ID. Maybe that isn't true anymore. Will check.
When they talk about "inactive" instances in that case, they are referring to instances that have been deactivated with the appropriate function call. I don't think under the hood they implemented that the same as they are doing for persistent objects between rooms.
 

Roldy

Member
When they talk about "inactive" instances in that case, they are referring to instances that have been deactivated with the appropriate function call. I don't think under the hood they implemented that the same as they are doing for persistent objects between rooms.
Agreed. I double checked it.
 

samspade

Member
Incorrect. They are not 'inactive' they have been removed from the instance list. You can confirm this in the debugger. If you have code that will then post it. I'll double check access with instance ID.
I double checked and you can indeed reference inactive objects so long as you do so directly with their instance id. You can easily check this with the following test.

test_obj_a create event

GML:
global.savid_inst = id;
message = "Hello World";

instance_deactivate_object(id);
test_obj_b step event

GML:
if (keyboard_check_pressed(vk_space)) {
    global.savid_inst.message = "Goodbye";
}


if (keyboard_check_pressed(vk_enter)) {
    instance_activate_object(global.savid_inst);
}
Run in the debugger and push space and then enter. Not only will message be goodbye, despite being set while the instance was inactive and you can reactive it using the instance id as well.
 

Roldy

Member
I double checked and you can indeed reference inactive objects so long as you do so directly with their instance id. You can easily check this with the following test.

test_obj_a create event

GML:
global.savid_inst = id;
message = "Hello World";

instance_deactivate_object(id);
test_obj_b step event

GML:
if (keyboard_check_pressed(vk_space)) {
    global.savid_inst.message = "Goodbye";
}


if (keyboard_check_pressed(vk_enter)) {
    instance_activate_object(global.savid_inst);
}
Run in the debugger and push space and then enter. Not only will message be goodbye, despite being set while the instance was inactive and you can reactive it using the instance id as well.
That is true.

However the topic is about persistent instances being referenced in a Clean Up event during a room transition.

They have not been 'deactivated.' So you can't access them with instance id.
 

samspade

Member
I'm not sure I understand. Quoting your original post:

The only reason I ran into this is because instance_destroy will trigger an instance's Destroy event, which triggers Clean Up. However a room transition does NOT trigger the Destroy event but DOES trigger Clean up Event. Meaning there isn't an obvious event to handle things when an instance is removed from the game (either destroyed or on room transition) if the persistent instances need to be referenced.

I suppose a solution is avoid Clean Up event, handle clean up code in Destroy event and call instance_destroy in Room End event, or avoid persistent instances.
A room transition does not trigger the clean up event. This is not what the original post is about. The original post is about the fact if non-persistent object A refers to persistent object B in object A's cleanup event, it can cause an error regardless of whether object B is persistent because clean up events will trigger for non-persistent objects (not persistent objects) in a room change because B may have been temporarily deactivated. The solution to this is for an instance to avoid referencing any other instance but itself in its own cleanup event, which is good code practice anyway. It does not mean that you shouldn't use cleanup events or avoid persistence or call instance_destroy from a room end event.
 

Roldy

Member
A room transition does not trigger the clean up event.
CLEAN UP: This event will be called after any event that removes an instance of the object from the room. So, it will be triggered if the instance is destroyed, if the room ends, or if the game ends,
I believe you are confused. You have the tools to test it.

This is not what the original post is about.

From the OP:

If I activate the clean up event by changing room, the game breaks because the an instance of the object that is persistent (and initialized in the first opened room) does not exist.

If the clean up event is called through destruction, everything works, and since any room creation the reference exists.
We are talking about Clean Up events triggered by room transition and how persistent instances behave during that time. That is the topic.

Again, re-read the thread until it is clear and makes sense to you. If you are really interested in it, test along the way.

Honestly IMO the inconsistent part is that room transitions don't trigger the Destroy event. If it did then everything would be consistent. For every create there should be a destroy.

But as said, Its not a big deal, just nice to know about.
 
Last edited:

samspade

Member
The manual's quote "CLEAN UP: This event will be called after any event that removes an instance of the object from the room." Is only true for non persistent objects. It is not true for a persistent object (although this could be more clear as I don't see anything in the manual which discusses this aspect either here or in the persistence page). You can test this very easily by putting a show_debug_message in a persistent object's clean up event and changing rooms. Or, if you would prefer a more real world example, by creating a data structure, putting in some information, destroying that data structure in the clean up event, changing rooms and checking the contents of the data structure. This is something I do regularly in many projects. The clean up event will not fire on room change for persistent objects because the object is not destroyed.

The reason the OP says "If I activate the clean up event by changing room" is because a non-persistant object is being destroyed on room change which references a persistent object. This causes an error when the persistent object doesn't exist, even though as a persistent object it should. The reason, as explained in the follow up posts is that persistent objects are temporarily moved from whatever place they're currently kept to somewhere else so that they are not destroyed. The solution to this problem is to not reference other instances in a clean up event.
 

Roldy

Member
The manual's quote "CLEAN UP: This event will be called after any event that removes an instance of the object from the room." Is only true for non persistent objects. It is not true for a persistent object.
You are confused on the topic. You are repeating what everyone has already said but as an argument.

The topic is: non-persistent instances, accessing persistent instances, from a clean up event triggered by a room transition.

Re-read that sentence until it is clear. If you have more information on that topic then please respond.
 

Roldy

Member
So @Bart just provided a sort of solution to this in a another thread: https://forum.yoyogames.com/index.p...ntrols-to-object-variables.76380/#post-452955

You cannot access persistent objects during a Clean Up event triggered by a room transition using instance id, object id, or with(all) etc...

But you can access them if you make a reference (a pointer) like so and use an accessor.

Example:

PersistentObject:Create event
GML:
someMemberVariable = [0]; // we turn this variable into an array of size 1
NonPersistentObject:Create event

GML:
linkedVariable = PersistentObject.someMemberVariable;
NonPersistentObject:Clean Up event

GML:
linkedVariable[@0]++;  // now a variable of a persistent instance has been accessed
                       // if accessed during a Clean UP event triggered by a room transition
                       // it will not error because we are not using
                       // instance id, object id, or with(all)
                       // they all use the internal instance list (where persistent instances have been removed)
                       // we are instead directly pointing at the variable memory location
                       // when we enter the next room the persistent instance someMemberVariablewill be incremented
This definitely seems like undocumented behavior and might be dangerous.

But it does work and that is interesting.
 

kburkhart84

Firehammer Games
LOL, I specifically mentioned in that thread that I'd be scared to do this because of it being undocumented. I think there should be a suggestion made for them to expand on this and make actual pointers for regular variables. With 2.3 you can copy references to methods and structs which works, but not regular variables.
 

Yal

🐧 *penguin noises*
GMC Elder
How about doing a with(all){if(persistent){ /.../ sweep in the Room End event, where they're still going to be accessible? It only happens on room transitions anyway. To trigger a cleanup for things you want gone, you could explicitly destroy them from the body of that loop.
 
Top