[SOLVED] How to define persistable objects?

Discuss how to use the Ren'Py engine to create visual novels and story-based games. New releases are announced in this section.
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
Post Reply
Message
Author
User avatar
AVNSnax
Regular
Posts: 79
Joined: Sun Feb 06, 2022 12:11 am
itch: avnsnax
Contact:

[SOLVED] How to define persistable objects?

#1 Post by AVNSnax »

As the immortal Lloyd Bridges said in Airplane, looks like I picked the wrong week to quit drinking.

I started down a rathole trying to implement my own achievements system that would wrap the rudimentary Steam-flavored achievement class. Everything was working fine until I tried to persist my list of achievements.

I defined a class called Achievement that has a bunch of features like grouped achievements (achievements that are granted when all member achievements have been earned), flags for visibility of an achievement's title and description, alert and menu support, etc. I'm aware of a couple of commercially available add-ons but wanted to roll my own because, "How hard could it be?"

First, Ren'Py complains that my class can't be pickled. Being the trained developer that I am, I had implemented a class for the achievement itself, and a separate class to manage the achievement groups. Nope, the ancillary class must be hashable. So I implement a __hash__ method. Can't make that work, so I gave in and folded the goals object into Achievement itself. One simple class. Nope: my class "must support equality comparison." So I implemented an __eq__ method. Now, it's telling me "TypeError: Achievement is not safe for use in persistent." without any kind of hint as to why. Can someone point me in the right direction for clues? Or should I just bite the bullet and implement my own persistence method?
Last edited by AVNSnax on Thu Apr 04, 2024 5:29 pm, edited 1 time in total.

User avatar
Ocelot
Lemma-Class Veteran
Posts: 2410
Joined: Tue Aug 23, 2016 10:35 am
Github: MiiNiPaa
Discord: MiiNiPaa#4384
Contact:

Re: How to define persistable objects?

#2 Post by Ocelot »

As persistent data is loaded before init python blocks are run, persistent data should only contain types that are native to Python or Ren'Py. Alternatively, classes that are defined in python early blocks can be used, provided those classes can be pickled and implement equality.
My approach in similar cases is to have an immutable class for achievement itself, which would refer to some nestled dictionary in persistent data to store mutable data (like achievement progress, if it was granted, etc.)
< < insert Rick Cook quote here > >

User avatar
AVNSnax
Regular
Posts: 79
Joined: Sun Feb 06, 2022 12:11 am
itch: avnsnax
Contact:

Re: How to define persistable objects?

#3 Post by AVNSnax »

Ocelot wrote: Thu Apr 04, 2024 12:40 am
As persistent data is loaded before init python blocks are run, persistent data should only contain types that are native to Python or Ren'Py. Alternatively, classes that are defined in python early blocks can be used, provided those classes can be pickled and implement equality.
My approach in similar cases is to have an immutable class for achievement itself, which would refer to some nestled dictionary in persistent data to store mutable data (like achievement progress, if it was granted, etc.)
Hmmm. In the class file, I just changed init python: to python early: and it worked. Almost. Things were fine until I tried to quit and Ren'Py went to write out the persistent data. To be persisted, RevertableSet({Achievement:...}) must support equality comparison.

jeffster
Veteran
Posts: 409
Joined: Wed Feb 03, 2021 9:55 pm
Contact:

Re: How to define persistable objects?

#4 Post by jeffster »

AVNSnax wrote: Thu Apr 04, 2024 1:14 am
Ocelot wrote: Thu Apr 04, 2024 12:40 am
As persistent data is loaded before init python blocks are run, persistent data should only contain types that are native to Python or Ren'Py. Alternatively, classes that are defined in python early blocks can be used, provided those classes can be pickled and implement equality.
My approach in similar cases is to have an immutable class for achievement itself, which would refer to some nestled dictionary in persistent data to store mutable data (like achievement progress, if it was granted, etc.)
Hmmm. In the class file, I just changed init python: to python early: and it worked. Almost. Things were fine until I tried to quit and Ren'Py went to write out the persistent data. To be persisted, RevertableSet({Achievement:...}) must support equality comparison.
Docs:
https://renpy.org/doc/html/persistent.html
As persistent data is loaded before init python blocks are run, persistent data should only contain types that are native to Python or Ren'Py. Alternatively, classes that are defined in python early blocks can be used, provided those classes can be pickled and implement equality.

User avatar
AVNSnax
Regular
Posts: 79
Joined: Sun Feb 06, 2022 12:11 am
itch: avnsnax
Contact:

Re: How to define persistable objects?

#5 Post by AVNSnax »

So, the final solution was to use plain ol' dictionaries and lists for the achievement data, and relegate the class object to being a mere data handler. The conversion process was pretty painful, wordy, and backwards. There really ought to be a better way to persist objects, especially for operations that don't easily lend themselves to being just lists of dictionaries.

Post Reply

Who is online

Users browsing this forum: BBN_VN