Ren'Py Lists and persistent data

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,581
2,219
Rewritten version of your TestPers project. Only now it works.

I'm basically just implementing the ideas I worked though in the huge post above.

Problem is that it does stuff in a way that pytom (the primary author of RenPy) suggests is .
Specifically, I'm still using class Achiev(): as part of the persistent data.
I'll try and spend some time tomorrow getting it working in a way pytom recommends would be better.
 

Vernam

Newbie
Jan 10, 2021
58
170
Okay. Slightly concerned you quoted my post where I was on the wrong track and completely seem to have missed the huge post where I go through things step by step explaining what is going wrong and what doesn't work and how it could be fixed.
I was joking, I just made the test program and I found the posts so posted it anyway before reading them.
I am a beginner and takes some time for me to really understand :(

Now I have read them fully and finally understand, thanks!
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,581
2,219
Took a little longer than I planned due to other commitments... but...

Another rewritten version of the TestPers project. Updated to only store recommended data types in persistent. storage.


This time I've rewritten it to only store the names of the unlocked achievements in persistent.AchUnlocked.
The rest of the achievement data is stored in a (an array, accessible via a named key).

I've also used a new class called AchievData() so I can refer to the elements of the achievement data by name rather than using a list index.

So:
achievement["Humour"].thumb
-instead of-
achievement["Humour"][0]

Everything works by using the data stored in AchUnlocked() as the key to the dictionary.

It has the added advantage of following PyTom's advice and only storing string objects in the persistent data.
 

Vernam

Newbie
Jan 10, 2021
58
170
Thanks!

I realized I was overcomplicating it using a Class (without really needing it) so I already solved with a persistent list of numbers (persistent.AchUnlocked = [1, 3, 31,...]) and a reference table (AchievList[n][m]) for the data.
I realized I have no need to use names when I add an achievement (You unlocked "X"), i can use only numbers (You unlocked the third Achievement) which are easier to use.

Since the links to TestPers files expire, I made a simple code using your example so that if someone else in the future have my same problem he can understand it and find the solution here.


The summary is:

Using persistent lists the data was getting deleted on restart.
The problem is not in the persistent lists as I wrongly though, you can use them (with numbers, text, etc...).

You don't have permission to view the spoiler content. Log in or register now.

The problem, as , arises when using persistent on a non-base object.
It resets all persistent data on restart.

You don't have permission to view the spoiler content. Log in or register now.

Solution:
don't use a Class when it's not necessary. :)

If everyone agrees and I made no mistakes this thread is [Solved].
 

Sancho1969

Message Maven
Modder
Donor
Jan 19, 2020
12,382
48,059
One of the most interesting threads I've read in some time. Appreciate the diligence. 79flavors's TestPers rewrite is rather epic. Well done and very educational folks. Regards.
 
  • Like
Reactions: 79flavors

moose_puck

Active Member
Sep 6, 2021
741
1,664
I'm just starting to learn the basics of Ren'py, so the content in this thread is definitely punching way above my weight class ... however, I came across it as I was looking for information about adding an achievement system that is persistent even when a player starts a new game. Basically, what I wanted to do was have maybe 10 or 12 trophies to track things like if you completed all the possible endings in the game. Alternatively, I would possibly like to add a way to 'reset' the list (in case of multiple users on the same PC maybe)

This thread was an interesting read and I've bookmarked it and downloaded 79flavor's TestPer files above to look at later (after I get some more fundamentals into me, lol)

I had one noob question though...

What about generating a log-like file of some sort to track achievements? Does renpy have that sort of functionality? I mean, all of the above discussion seems rather complicated for something that should be easier to track. The only real coding I've done in the past was BASIC (way back in the 80's lol) and in old HTML 4 when i was making websites, and I routinely used server side includes to both save file size by sharing common code snippets and also to track variables across multiple pages. That's why I was asking if Renpy had something like this?
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,369
15,285
What about generating a log-like file of some sort to track achievements?
It's one of the worse approach for this kind of task. Every time you'll want to know what happened, and every time you'll want to update the log, you'll have to parse all its content. And whatever if you make the log "computer readable only", it will make the parsing easier, but it will still happen.


It's a trend actually with Ren'Py games ; people tend to copy bad habits way faster than good ones. People use a list to store any important decisions. It's good and all, lists have methods to facilitate this, but there's three problems:

Firstly they should use a set ; a set being a list that will automatically take care of its content to avoid duplicated entries.

Secondly even if it don't looks like it at first, something like, if "whatever" in progressList and "whatever else" in progressList and ( not "this thing" in progressList ):, is worse than it's boolean equivalent, if progressList.whatever and progressList.whatever_else and (not progressList.this_thing ):.
You can read the first one better if you use full sentence (by opposition of the nickname used for the variables), but using full sentences also mean that you'll have more risk to make a typo and break the game because of this.
Plus, except for persistent values that are particular, if you write the name of the variable wrong, Ren'Py will insult you, so you'll learn it very fast and be able to correct this. This will never happen with the list approach, because Ren'Py have no way to know that you wrongly wrote one of the word in the string.

Thirdly, while it feel easier to read a list of fully descriptive sentences, for debug purpose by example, it isn't once the list effectively start to grow. Quickly you'll lost your ability to focus, and pass the whole list without noticing that what you search is effectively in it ; nor noticing the typo you are searching for.
A set of boolean will always be easier to deal with on a long run. Especially if you organize them correctly, starting by a reference to the update ("ch3whatever") or in game day ("d05whatever"), by example. You'll only have to browse through a small portion of your variables, what will always be better than a list of hundred of sentences.
 

moose_puck

Active Member
Sep 6, 2021
741
1,664
It's one of the worse approach for this kind of task. Every time you'll want to know what happened, and every time you'll want to update the log, you'll have to parse all its content. And whatever if you make the log "computer readable only", it will make the parsing easier, but it will still happen.


It's a trend actually with Ren'Py games ; people tend to copy bad habits way faster than good ones. People use a list to store any important decisions. It's good and all, lists have methods to facilitate this, but there's three problems:

Firstly they should use a set ; a set being a list that will automatically take care of its content to avoid duplicated entries.

Secondly even if it don't looks like it at first, something like, if "whatever" in progressList and "whatever else" in progressList and ( not "this thing" in progressList ):, is worse than it's boolean equivalent, if progressList.whatever and progressList.whatever_else and (not progressList.this_thing ):.
You can read the first one better if you use full sentence (by opposition of the nickname used for the variables), but using full sentences also mean that you'll have more risk to make a typo and break the game because of this.
Plus, except for persistent values that are particular, if you write the name of the variable wrong, Ren'Py will insult you, so you'll learn it very fast and be able to correct this. This will never happen with the list approach, because Ren'Py have no way to know that you wrongly wrote one of the word in the string.

Thirdly, while it feel easier to read a list of fully descriptive sentences, for debug purpose by example, it isn't once the list effectively start to grow. Quickly you'll lost your ability to focus, and pass the whole list without noticing that what you search is effectively in it ; nor noticing the typo you are searching for.
A set of boolean will always be easier to deal with on a long run. Especially if you organize them correctly, starting by a reference to the update ("ch3whatever") or in game day ("d05whatever"), by example. You'll only have to browse through a small portion of your variables, what will always be better than a list of hundred of sentences.
Thanks for the reply. You've definitely given me something to think about. I think I need to bend my thinking to use the language of ren'py and not try and change the language to fit what I am thinking. It's like learning a new language... that point where you stop having to do translations in your head and start to actually 'think' in that new language.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,369
15,285
I think I need to bend my thinking to use the language of ren'py and not try and change the language to fit what I am thinking.
It's more going with the flow instead of trying to fight against the tide. Each programming language have its strength, weakness and flaws, as well as its own logic.
It need time, but in the end it's just a small switch in the way you approach a problem. Instead of searching "how you can do this with this language", you wonder "what this language offer me to do this".


It's like learning a new language... that point where you stop having to do translations in your head and start to actually 'think' in that new language.
With in between that awkward period where you go back to something you've just read, because you've a big doubt, was it in English or in your native language ?
The same apply with programming language. Will come a moment when, instead of an abstract view of the problem, it's lines of code (that will rarely works as it) that will pop in your mind. Like you come to think in English or whatever none native language, you also come to think in Python, and not anymore in your native language.