renpy/doc/persistent.html
2023-01-18 23:13:55 +01:00

402 lines
25 KiB
HTML

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Persistent Data &#8212; Ren&#39;Py Documentation</title>
<link rel="stylesheet" href="_static/renpydoc.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<link rel="stylesheet" type="text/css" href="_static/bootstrap-3.3.6/css/bootstrap.min.css" />
<link rel="stylesheet" type="text/css" href="_static/bootstrap-3.3.6/css/bootstrap-theme.min.css" />
<link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css" />
<script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<script type="text/javascript" src="_static/language_data.js"></script>
<script type="text/javascript" src="_static/js/jquery-1.11.0.min.js"></script>
<script type="text/javascript" src="_static/js/jquery-fix.js"></script>
<script type="text/javascript" src="_static/bootstrap-3.3.6/js/bootstrap.min.js"></script>
<script type="text/javascript" src="_static/bootstrap-sphinx.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="Transforms and Transitions in Python" href="trans_trans_python.html" />
<link rel="prev" title="Saving, Loading, and Rollback" href="save_load_rollback.html" />
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge,chrome=1'>
<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1'>
<meta name="apple-mobile-web-app-capable" content="yes">
</head><body>
<div id="navbar" class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<!-- .btn-navbar is used as the toggle for collapsed navbar content -->
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="index.html">
Ren&#39;Py Documentation</a>
<span class="navbar-text navbar-version pull-left"><b>7.5.3</b></span>
</div>
<div class="collapse navbar-collapse nav-collapse">
<ul class="nav navbar-nav">
<li><a href="https://www.renpy.org">Home Page</a></li>
<li><a href="https://www.renpy.org/doc/html/">Online Documentation</a></li>
<li class="dropdown globaltoc-container">
<a role="button"
id="dLabelGlobalToc"
data-toggle="dropdown"
data-target="#"
href="index.html">Site <b class="caret"></b></a>
<ul class="dropdown-menu globaltoc"
role="menu"
aria-labelledby="dLabelGlobalToc"><ul>
<li class="toctree-l1"><a class="reference internal" href="quickstart.html">Quickstart</a></li>
<li class="toctree-l1"><a class="reference internal" href="gui.html">GUI Customization Guide</a></li>
</ul>
<ul>
<li class="toctree-l1"><a class="reference internal" href="language_basics.html">Language Basics</a></li>
<li class="toctree-l1"><a class="reference internal" href="label.html">Labels &amp; Control Flow</a></li>
<li class="toctree-l1"><a class="reference internal" href="dialogue.html">Dialogue and Narration</a></li>
<li class="toctree-l1"><a class="reference internal" href="displaying_images.html">Displaying Images</a></li>
<li class="toctree-l1"><a class="reference internal" href="menus.html">In-Game Menus</a></li>
<li class="toctree-l1"><a class="reference internal" href="python.html">Python Statements</a></li>
<li class="toctree-l1"><a class="reference internal" href="conditional.html">Conditional Statements</a></li>
<li class="toctree-l1"><a class="reference internal" href="audio.html">Audio</a></li>
<li class="toctree-l1"><a class="reference internal" href="movie.html">Movie</a></li>
<li class="toctree-l1"><a class="reference internal" href="voice.html">Voice</a></li>
</ul>
<ul>
<li class="toctree-l1"><a class="reference internal" href="text.html">Text</a></li>
<li class="toctree-l1"><a class="reference internal" href="translation.html">Translation</a></li>
<li class="toctree-l1"><a class="reference internal" href="displayables.html">Displayables</a></li>
<li class="toctree-l1"><a class="reference internal" href="transforms.html">Transforms</a></li>
<li class="toctree-l1"><a class="reference internal" href="transitions.html">Transitions</a></li>
<li class="toctree-l1"><a class="reference internal" href="atl.html">Animation and Transformation Language</a></li>
<li class="toctree-l1"><a class="reference internal" href="matrixcolor.html">Matrixcolor</a></li>
<li class="toctree-l1"><a class="reference internal" href="layeredimage.html">Layered Images</a></li>
<li class="toctree-l1"><a class="reference internal" href="3dstage.html">3D Stage</a></li>
<li class="toctree-l1"><a class="reference internal" href="live2d.html">Live2D Cubism</a></li>
</ul>
<ul>
<li class="toctree-l1"><a class="reference internal" href="style.html">Styles</a></li>
<li class="toctree-l1"><a class="reference internal" href="style_properties.html">Style Properties</a></li>
<li class="toctree-l1"><a class="reference internal" href="screens.html">Screens and Screen Language</a></li>
<li class="toctree-l1"><a class="reference internal" href="screen_actions.html">Screen Actions, Values, and Functions</a></li>
<li class="toctree-l1"><a class="reference internal" href="screen_special.html">Special Screen Names</a></li>
<li class="toctree-l1"><a class="reference internal" href="screen_optimization.html">Screen Language Optimization</a></li>
<li class="toctree-l1"><a class="reference internal" href="config.html">Configuration Variables</a></li>
<li class="toctree-l1"><a class="reference internal" href="preferences.html">Preference Variables</a></li>
<li class="toctree-l1"><a class="reference internal" href="store_variables.html">Store Variables</a></li>
<li class="toctree-l1"><a class="reference internal" href="mouse.html">Custom Mouse Cursors</a></li>
</ul>
<ul>
<li class="toctree-l1"><a class="reference internal" href="launcher.html">Launcher</a></li>
<li class="toctree-l1"><a class="reference internal" href="developer_tools.html">Developer Tools</a></li>
<li class="toctree-l1"><a class="reference internal" href="director.html">Interactive Director</a></li>
</ul>
<ul>
<li class="toctree-l1"><a class="reference internal" href="nvl_mode.html">NVL-Mode Tutorial</a></li>
<li class="toctree-l1"><a class="reference internal" href="input.html">Text Input</a></li>
<li class="toctree-l1"><a class="reference internal" href="side_image.html">Side Images</a></li>
<li class="toctree-l1"><a class="reference internal" href="rooms.html">Image Gallery, Music Room, and Replay Actions</a></li>
<li class="toctree-l1"><a class="reference internal" href="drag_drop.html">Drag and Drop</a></li>
<li class="toctree-l1"><a class="reference internal" href="sprites.html">Sprites</a></li>
<li class="toctree-l1"><a class="reference internal" href="keymap.html">Customizing the Keymap</a></li>
<li class="toctree-l1"><a class="reference internal" href="achievement.html">Achievements</a></li>
<li class="toctree-l1"><a class="reference internal" href="history.html">Dialogue History</a></li>
<li class="toctree-l1"><a class="reference internal" href="multiple.html">Multiple Character Dialogue</a></li>
<li class="toctree-l1"><a class="reference internal" href="splashscreen_presplash.html">Splashscreen and Presplash</a></li>
</ul>
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="statement_equivalents.html">Statement Equivalents</a></li>
<li class="toctree-l1"><a class="reference internal" href="save_load_rollback.html">Saving, Loading, and Rollback</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">Persistent Data</a></li>
<li class="toctree-l1"><a class="reference internal" href="trans_trans_python.html">Transforms and Transitions in Python</a></li>
<li class="toctree-l1"><a class="reference internal" href="gui_advanced.html">Advanced GUI</a></li>
<li class="toctree-l1"><a class="reference internal" href="screen_python.html">Screens and Python</a></li>
<li class="toctree-l1"><a class="reference internal" href="modes.html">Modes</a></li>
<li class="toctree-l1"><a class="reference internal" href="cdd.html">Creator-Defined Displayables</a></li>
<li class="toctree-l1"><a class="reference internal" href="cds.html">Creator-Defined Statements</a></li>
<li class="toctree-l1"><a class="reference internal" href="custom_text_tags.html">Custom Text Tags</a></li>
<li class="toctree-l1"><a class="reference internal" href="character_callbacks.html">Character Callbacks</a></li>
<li class="toctree-l1"><a class="reference internal" href="file_python.html">File Access</a></li>
<li class="toctree-l1"><a class="reference internal" href="color_class.html">Color Class</a></li>
<li class="toctree-l1"><a class="reference internal" href="matrix.html">Matrix</a></li>
<li class="toctree-l1"><a class="reference internal" href="model.html">Model-Based Rendering</a></li>
<li class="toctree-l1"><a class="reference internal" href="other.html">Other Functions and Variables</a></li>
</ul>
<ul>
<li class="toctree-l1"><a class="reference internal" href="build.html">Building Distributions</a></li>
<li class="toctree-l1"><a class="reference internal" href="updater.html">Web Updater</a></li>
<li class="toctree-l1"><a class="reference internal" href="android.html">Android</a></li>
<li class="toctree-l1"><a class="reference internal" href="chromeos.html">Chrome OS/Chromebook</a></li>
<li class="toctree-l1"><a class="reference internal" href="ios.html">iOS</a></li>
<li class="toctree-l1"><a class="reference internal" href="iap.html">In-App Purchasing</a></li>
<li class="toctree-l1"><a class="reference internal" href="gesture.html">Gestures</a></li>
<li class="toctree-l1"><a class="reference internal" href="raspi.html">Raspberry Pi</a></li>
</ul>
<ul>
<li class="toctree-l1"><a class="reference internal" href="security.html">Security</a></li>
<li class="toctree-l1"><a class="reference internal" href="problems.html">Dealing with Problems</a></li>
<li class="toctree-l1"><a class="reference internal" href="environment_variables.html">Environment Variables</a></li>
<li class="toctree-l1"><a class="reference internal" href="self_voicing.html">Self-Voicing</a></li>
</ul>
<ul>
<li class="toctree-l1"><a class="reference internal" href="editor.html">Text Editor Integration</a></li>
<li class="toctree-l1"><a class="reference internal" href="skins.html">Skins</a></li>
<li class="toctree-l1"><a class="reference internal" href="translating_renpy.html">Translating Ren'Py</a></li>
</ul>
<ul>
<li class="toctree-l1"><a class="reference internal" href="changelog.html">Changelog (Ren'Py 7.x-)</a></li>
<li class="toctree-l1"><a class="reference internal" href="changelog6.html">Changelog (Ren'Py 6.11 - 6.99)</a></li>
<li class="toctree-l1"><a class="reference internal" href="incompatible.html">Incompatible Changes</a></li>
<li class="toctree-l1"><a class="reference internal" href="distributor.html">Distributor Notes</a></li>
<li class="toctree-l1"><a class="reference internal" href="license.html">License</a></li>
<li class="toctree-l1"><a class="reference internal" href="credits.html">Credits</a></li>
<li class="toctree-l1"><a class="reference internal" href="sponsors.html">Ren'Py Development Sponsors</a></li>
</ul>
<ul>
<li class="toctree-l1"><a class="reference internal" href="thequestion.html">Script of The Question</a></li>
<li class="toctree-l1"><a class="reference internal" href="thequestion_nvl.html">NVL-mode script for The Question</a></li>
</ul>
</ul>
</li>
</ul>
<form class="navbar-form navbar-right" action="search.html" method="get">
<div class="form-group">
<input type="text" name="q" class="form-control" placeholder="Search" />
</div>
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-md-3">
<div id="sidebar" class="bs-sidenav" role="complementary"><ul>
<li><a class="reference internal" href="#">Persistent Data</a><ul>
<li><a class="reference internal" href="#merging-persistent-data">Merging Persistent Data</a></li>
<li><a class="reference internal" href="#persistent-functions">Persistent Functions</a></li>
<li><a class="reference internal" href="#multi-game-persistence">Multi-Game Persistence</a></li>
</ul>
</li>
</ul>
</div>
</div>
<div class="col-md-9 content">
<div class="section" id="persistent-data">
<h1>Persistent Data<a class="headerlink" href="#persistent-data" title="Permalink to this headline"> link</a></h1>
<p>Ren'Py supports persistent data, saved data that is not
associated with a particular point in a game. Persistent data is
accessed through fields of the persistent object, which is bound to the
variable <code class="docutils literal notranslate"><span class="pre">persistent</span></code>.</p>
<p>All data reachable through fields on <code class="docutils literal notranslate"><span class="pre">persistent</span></code> is saved when
Ren'Py terminates, or when <a class="reference internal" href="#renpy.save_persistent" title="renpy.save_persistent"><code class="xref py py-func docutils literal notranslate"><span class="pre">renpy.save_persistent()</span></code></a> is called.
Persistent data is loaded when Ren'Py starts, and when Ren'Py detects
that the persistent data has been updated on disk.</p>
<p>The persistent object is special in that an access to an undefined field will
have a None value, rather than causing an exception. If something other than
None is to be the default of a persistent value,
the <a class="reference internal" href="python.html#default-statement"><span class="std std-ref">default</span></a> statement should be used:</p>
<div class="highlight-renpy notranslate"><div class="highlight"><pre><span></span><span class="k">default</span> <span class="n">persistent</span><span class="o">.</span><span class="n">main_background</span> <span class="o">=</span> <span class="s2">&quot;princess_not_saved&quot;</span>
</pre></div>
</div>
<p>An example use of persistent is the creation of an unlockable image gallery.
This is done by storing a flag in persistent that determines if the gallery has
been unlocked, as in</p>
<div class="highlight-renpy notranslate"><div class="highlight"><pre><span></span><span class="k">label</span> <span class="n">gallery</span><span class="p">:</span>
<span class="k">if</span> <span class="k">not</span> <span class="n">persistent</span><span class="o">.</span><span class="n">gallery_unlocked</span><span class="p">:</span>
<span class="k">show</span> <span class="na">background</span>
<span class="n">centered</span> <span class="s2">&quot;You haven&#39;t unlocked this gallery yet.&quot;</span>
<span class="k">$</span> <span class="n">renpy</span><span class="o">.</span><span class="n">full_restart</span><span class="p">()</span>
<span class="c1"># Actually show the gallery here.</span>
</pre></div>
</div>
<p>When the user gets an ending that causes the gallery to be unlocked, the flag
must be set to True.</p>
<div class="highlight-renpy notranslate"><div class="highlight"><pre><span></span><span class="k">$</span> <span class="n">persistent</span><span class="o">.</span><span class="n">gallery_unlocked</span> <span class="o">=</span> <span class="kc">True</span>
</pre></div>
</div>
<p>As persistent data is loaded before <code class="docutils literal notranslate"><span class="pre">init</span> <span class="pre">python</span></code> blocks are run, persistent data
should only contain types that are native to Python or Ren'Py. Alternatively,
classes that are defined in <code class="docutils literal notranslate"><span class="pre">python</span> <span class="pre">early</span></code> blocks can be used, provided
those classes can be pickled and implement equality.</p>
<div class="section" id="merging-persistent-data">
<h2>Merging Persistent Data<a class="headerlink" href="#merging-persistent-data" title="Permalink to this headline"> link</a></h2>
<p>There are cases where Ren'Py has to merge persistent data from two
sources. For example, Ren'Py may need to merge persistent data stored
on a USB drive with persistent data from the local machine.</p>
<p>Ren'Py does this merging on a field-by-field basis, taking the value
of the field that was updated more recently. In some cases, this is
not the desired behavior. In that case, the <a class="reference internal" href="#renpy.register_persistent" title="renpy.register_persistent"><code class="xref py py-func docutils literal notranslate"><span class="pre">renpy.register_persistent()</span></code></a>
function can be used.</p>
<p>For example, if we have a set of seen endings, we'd like to take the
union of that set when merging data.</p>
<div class="highlight-renpy notranslate"><div class="highlight"><pre><span></span><span class="k">init</span> <span class="k">python</span><span class="p">:</span>
<span class="k">if</span> <span class="n">persistent</span><span class="o">.</span><span class="n">endings</span> <span class="k">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">persistent</span><span class="o">.</span><span class="n">endings</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">merge_endings</span><span class="p">(</span><span class="k">old</span><span class="p">,</span> <span class="k">new</span><span class="p">,</span> <span class="n">current</span><span class="p">):</span>
<span class="n">current</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="k">old</span><span class="p">)</span>
<span class="n">current</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="k">new</span><span class="p">)</span>
<span class="k">return</span> <span class="n">current</span>
<span class="n">renpy</span><span class="o">.</span><span class="n">register_persistent</span><span class="p">(</span><span class="s1">&#39;endings&#39;</span><span class="p">,</span> <span class="n">merge_endings</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="section" id="persistent-functions">
<h2>Persistent Functions<a class="headerlink" href="#persistent-functions" title="Permalink to this headline"> link</a></h2>
<dl class="function">
<dt id="persistent._clear">
<code class="descclassname">persistent.</code><code class="descname">_clear</code><span class="sig-paren">(</span><em>progress=False</em><span class="sig-paren">)</span><a class="headerlink" href="#persistent._clear" title="Permalink to this definition"> link</a></dt>
<dd><p>Resets the persistent data.</p>
<dl class="docutils">
<dt><cite>progress</cite></dt>
<dd>If true, also resets progress data that Ren'Py keeps.</dd>
</dl>
<p>Note that this will delete all persistent data, and will not re-apply
defaults until Ren'Py restarts.</p>
</dd></dl>
<dl class="function">
<dt id="renpy.register_persistent">
<code class="descclassname">renpy.</code><code class="descname">register_persistent</code><span class="sig-paren">(</span><em>field</em>, <em>func</em><span class="sig-paren">)</span><a class="headerlink" href="#renpy.register_persistent" title="Permalink to this definition"> link</a></dt>
<dd><p>Registers a function that is used to merge values of a persistent field
loaded from disk with values of current persistent object.</p>
<dl class="docutils">
<dt><cite>field</cite></dt>
<dd>The name of a field on the persistent object.</dd>
<dt><cite>function</cite></dt>
<dd><p class="first">A function that is called with three parameters, <cite>old</cite>, <cite>new</cite>, and
<cite>current</cite>:</p>
<dl class="docutils">
<dt><cite>old</cite></dt>
<dd>The value of the field in the older object.</dd>
<dt><cite>new</cite></dt>
<dd>The value of the field in the newer object.</dd>
<dt><cite>current</cite></dt>
<dd>The value of the field in the current persistent object. This is
provided for cases where the identity of the object referred to
by the field can't change.</dd>
</dl>
<p class="last">The function is expected to return the new value of the field in the
persistent object.</p>
</dd>
</dl>
</dd></dl>
<dl class="function">
<dt id="renpy.save_persistent">
<code class="descclassname">renpy.</code><code class="descname">save_persistent</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#renpy.save_persistent" title="Permalink to this definition"> link</a></dt>
<dd><p>Saves the persistent data to disk.</p>
</dd></dl>
</div>
<div class="section" id="multi-game-persistence">
<h2>Multi-Game Persistence<a class="headerlink" href="#multi-game-persistence" title="Permalink to this headline"> link</a></h2>
<p>Multi-Game persistence is a feature that lets you share information between
Ren'Py games. This may be useful if you plan to make a series of games, and
want to have them share information.</p>
<p>To use multipersistent data, a MultiPersistent object must be created at init
time (preferably using <code class="docutils literal notranslate"><span class="pre">define</span></code>).
The user can then update this object, and save it to disk by
calling its save method. Undefined fields default to None. To ensure the
object can be loaded again in a different game, we strongly advise against
storing instances of user-defined types in the object.</p>
<dl class="class">
<dt id="MultiPersistent">
<em class="property">class </em><code class="descname">MultiPersistent</code><span class="sig-paren">(</span><em>key</em>, <em>save_on_quit=False</em><span class="sig-paren">)</span><a class="headerlink" href="#MultiPersistent" title="Permalink to this definition"> link</a></dt>
<dd><p>Creates a new <code class="docutils literal notranslate"><span class="pre">MultiPersistent</span></code> object. This should only be called at init time,
and it returns a new <code class="docutils literal notranslate"><span class="pre">MultiPersistent</span></code> with the given key.</p>
<dl class="docutils">
<dt><cite>key</cite></dt>
<dd>The key used to to access the multipersistent data. Games using the
same key will access the same multipersistent data.</dd>
<dt><cite>save_on_quit</cite></dt>
<dd>If it is True, this object will be automatically saved when Ren'Py terminates.</dd>
</dl>
<dl class="method">
<dt id="MultiPersistent.save">
<code class="descname">save</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#MultiPersistent.save" title="Permalink to this definition"> link</a></dt>
<dd><p>Saves the multipersistent data to disk. This must be called after
the data is modified.</p>
</dd></dl>
</dd></dl>
<p>As an example, take the first part of a two-part game:</p>
<div class="highlight-renpy notranslate"><div class="highlight"><pre><span></span><span class="k">define</span> <span class="n">mp</span> <span class="o">=</span> <span class="n">MultiPersistent</span><span class="p">(</span><span class="s2">&quot;demo.renpy.org&quot;</span><span class="p">)</span>
<span class="k">label</span> <span class="n">start</span><span class="p">:</span>
<span class="c1"># ...</span>
<span class="c1"># Record the fact that the user beat part 1.</span>
<span class="k">$</span> <span class="n">mp</span><span class="o">.</span><span class="n">beat_part_1</span> <span class="o">=</span> <span class="kc">True</span>
<span class="k">$</span> <span class="n">mp</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
<span class="n">e</span> <span class="s2">&quot;You beat part 1. See you in part 2!&quot;</span>
</pre></div>
</div>
<p>And the second part:</p>
<div class="highlight-renpy notranslate"><div class="highlight"><pre><span></span><span class="k">define</span> <span class="n">mp</span> <span class="o">=</span> <span class="n">MultiPersistent</span><span class="p">(</span><span class="s2">&quot;demo.renpy.org&quot;</span><span class="p">)</span>
<span class="k">label</span> <span class="n">start</span><span class="p">:</span>
<span class="k">if</span> <span class="n">mp</span><span class="o">.</span><span class="n">beat_part_1</span><span class="p">:</span>
<span class="n">e</span> <span class="s2">&quot;I see you&#39;ve beaten part 1, so welcome back!&quot;</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">e</span> <span class="s2">&quot;Hmm, you haven&#39;t played part 1, why not try it first?&quot;</span>
</pre></div>
</div>
</div>
</div>
</div>
</div>
</div>
<footer class="footer">
<div class="container">
<p class="pull-right">
<a href="#">Back to top</a>
</p>
<p>
&copy; Copyright 2012-2022, Tom Rothamel.<br/>
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.6.<br/>
</p>
</div>
</footer>
</body>
</html>