Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend call_replay scope with support for nested store attributes #5076

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

loafylemon
Copy link
Contributor

Synopsis:

This pull request aims to enhance the functionality of renpy.call_replay by enabling support for nested store attributes within the scope parameter and config.replay_scope variable. Currently, when using renpy.call_replay("label", scope={"states.characters.player.health": 100}, the scope assigns the value to a key with the same name, rather than allowing for nested stores as expected.

To address this, the proposed change modifies the behaviour to accommodate nested stores, making it more user-friendly. This improvement aligns with the convention of utilizing dots within keys to represent nested structures in Ren'py, thus ensuring compatibility across all projects.

The ability to work with nested stores offers several advantages in development, such as simplifying organization, preventing the pollution of scopes with unrelated variables, enabling iteration over nested structures, and facilitating the management of saves and changes across different versions of a project.

This modification enhances the flexibility and utility of Ren'py, providing a more efficient and intuitive approach for developers working with complex data structures in their projects.

Please let me know if you need further assistance with this pull request or if you'd like to see the code changes.

Use case:

Let's say you want to use call_replay to implement a gallery feature in your game. With the extended scope support, you can track the state of the gallery for each character individually. By using nested store attributes with the extended call_replay scope, you can effectively organize and manage data for different game elements more efficiently.

@renpytom
Copy link
Member

renpytom commented Dec 7, 2023

It probably makes sense to use renpy.context_dynamic here, once @Gouvernathor implements it, rather than iteration and setattr.

@Gouvernathor
Copy link
Member

Gouvernathor commented Dec 10, 2023

That's not supposed to work, either with renpy.context_dynamic or even with renpy.dynamic.
Those functions work like : either you pass the name of a variable, which may contain dots, and it is set to be dynamic, or you pass keyword arguments which are, well, keywords, and don't contain dots.
The handling of keyword arguments in renpy.dynamic does use setattr, so while there is a way to pass non-keywords as kwargs in Python, if you do it it will still fail.

        $ renpy.dynamic("x", "y", "z")
        $ renpy.dynamic("mystore.serial_number")
        $ renpy.dynamic(players=2, score=0)
        $ renpy.dynamic(**{"mystore.series": 4}) # ugly, and the value won't be set

@loafylemon
Copy link
Contributor Author

loafylemon commented Dec 17, 2023

An alternative approach could involve using reduce from the functools library to streamline the assignment. However, keep in mind that this won't work if the store isn't predefined. This approach has its validity, but its user-friendliness may vary depending on your perspective.

from functools import reduce

def set_replay_scope(target, items):
    for k, v in items.items():
        stores = k.split(".")
        current_obj = reduce(getattr, stores[:-1], target)
        setattr(current_obj, stores[-1], v)
        
set_replay_scope(renpy.store, renpy.config.replay_scope)

I couldn't come up with another way to assign values to nested stores without resorting to a double loop.

@mal
Copy link
Member

mal commented Jan 8, 2024

Quick FYI that I'm working on this, and also the wider issue of usage consistency between dynamic and context_dynamic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants