TADS 3 Adv3: How to remove old instances of a class?

Hey, I’ve got an issue that feels like there’s a million ways to go about it, and I was hoping for some advice on what you think might be the most efficient way of dealing with that issue.

The General Issue:
What is the best way to go about removing old, individual instances of a specific class?

The Specific Issue:
I have a mechanic in my game that spawns items - a hunting snare to be specific, and it has a chance to spawn a new instance of animal meat after being set and left alone for a while. I would like there to be a specific mechanic that would “clean up” an instance after existing in the game for a specific amount of time. If nothing is done with these instances of animal meat, and the player doesn’t take or use them, I don’t want them piling up and just… hanging out? Is there a way I can run through every instance of my animal meat class that isn’t in nil and just, move them to nil? How would I go about that? Something to do with foreach in (what location would this be, !nil ?). Would it be possible to have these instances on their own timers so that there isn’t just one massive sweep that removes all instances? Or would that just be an insane hassle to deal with and an unnecessary performance sink?

How would you go about doing this? In what manner would be the most efficient and performance friendly? Any advice or general pointers are appreciated.

Sorry if the answer is staring me right in the face :upside_down_face:

1 Like

If you’re just worried about “getting them out of the game”, then moving them into nil is sufficient. Otherwise if you know they’re not referenced any more, you can run the garbage collector. As for each one having a timer, you can do that with Daemons and Fuses. I created a ResettableEvent class to make your use case and many other use cases more streamlined. You could check it out Sharing a ResettableEvent class for TADS 3 or just have fun playing with Daemons and Fuses on your own…
I had several different flavors of disappearing objects, but the most basic type looked something like this:

  class EphemDmn: RDaemon
  	events { 
       if(!gPlayerChar.canSee(linkObj) 
               || !linkObj.ofKind(EphemeralDecoration) && ct >= 8) 
         linkObj.zap; 
    }	
;

where zap is a method that mainly moves into nil but also carries out any needed side effects depending on the class it’s used with, and linkObj is the animal meat instance that this Daemon is attached to. This particular Daemon will zap a certain class’s instances as soon as they go out of sight of the PC, or if the instance is EphemeralDecoration the instance will die eight turns after this daemon has been started (typically also provided the PC is out of sight, so we don’t have to explain mysterious disappearances from under our nose).
Somewhere there is defined an Ephemeral class that takes care of including an EphemDmn for each instance upon declaration or construction.
There’s more about usage in the link. Hope you can find some use for it, I sure did!

2 Likes

Having spent entirely too much time debugging this sort of thing, two caveats:

  • Setting the location to nil is only sufficient if you know the object is referenced nowhere else. Which is probably true for an “ordinary” in-game object…a plain Thing instead of one of the many Thing subclasses. Doors and other travel connectors automagically get additional references that need to be cleared, for example.
  • Clearing all references and manually running the garbage collector is not guaranteed to free an object immediately. In fact, it consistently will not do that unless a bunch of other stuff also needs to be garbage collected at the same time. But if you’re just trying to manually force deletion of a single object it almost certainly won’t work.
    To be clear, if you’ve cleared all references to an object, and it wasn’t an object declared in the source, then it’ll get cleared eventually. My point is that manually calling t3RunGC() will not immediately clear all unreferenced objects.

A while back I added some fancy reference-counting logic to the debugToolKit module specifically because of how tricky this kind of thing can be. I’m working on a bunch of procgen code and my mistaken belief that you could immediately clear unreferenced instances cost me many hours of debugging time.

3 Likes