영구 데이터

Ren'Py는 게임의 특정 시점과 연결되지 않는 저장 데이터인 영구 데이터를 지원합니다. 영구 데이터는 persistent 변수에 연결된 persistent 객체의 필드로 접근합니다.

persistent의 필드를 통해 도달할 수 있는 모든 데이터는 Ren'Py를 종료하거나 renpy.save_persistent()를 호출할 때 저장됩니다. 영구 데이터는 Ren'Py를 시작할 때, 그리고 디스크에서 영구 데이터가 갱신된 것을 Ren'Py가 감지할 때 불러옵니다.

persistent 객체는 정의되지 않은 필드에 접근해도 예외를 발생시키지 않고 None을 반환한다는 특징이 있습니다. 영구 값의 기본값을 None 이외의 값으로 설정하려면 default 문을 사용해야 합니다.

default persistent.main_background = "princess_not_saved"

persistent의 활용 예로 잠금 해제 가능한 이미지 갤러리를 만들 수 있습니다. 다음과 같이 갤러리의 잠금 해제 여부를 결정하는 플래그를 persistent에 저장합니다.

label gallery:

    if not persistent.gallery_unlocked:
        show background
        centered "아직 이 갤러리는 잠겨 있습니다."
        $ renpy.full_restart()

    # Actually show the gallery here.

사용자가 갤러리를 잠금 해제하는 엔딩을 보면 플래그를 True로 설정해야 합니다.

$ persistent.gallery_unlocked = True

영구 데이터는 init python 블록이 실행되기 전에 불러오므로 Python 또는 Ren'Py의 기본 형식만 포함해야 합니다. 또는 피클로 직렬화할 수 있고 동등성 비교를 구현한 클래스라면 python early 블록에서 정의한 클래스를 사용할 수 있습니다.

밑줄 두 개(__)로 시작하는 필드도 지원하지만, 이 절에서 설명한 이름 맹글링이 적용되어 정의한 파일에 종속됩니다. 따라서 두 배포 버전 사이에 파일 이름을 바꾸면 이전 버전에서 해당 필드가 가졌던 값에 접근할 수 없게 됩니다.

또한 이러한 필드는 persistent._clear() 메서드의 영향을 받지 않습니다.

밑줄 하나 _로 시작하는 필드는 예약되어 있으므로 사용하지 않아야 합니다.

영구 데이터 병합

Ren'Py가 두 출처의 영구 데이터를 병합해야 할 때가 있습니다. 예를 들어 USB 드라이브에 저장된 영구 데이터와 로컬 컴퓨터의 영구 데이터를 병합해야 할 수 있습니다.

Ren'Py는 필드별로 더 최근에 갱신된 값을 선택하여 병합합니다. 원하는 동작이 아니라면 renpy.register_persistent() 함수를 사용할 수 있습니다.

예를 들어 이미 본 엔딩들의 집합이 있다면 데이터를 병합할 때 두 집합의 합집합을 얻는 것이 좋습니다.

init python:
    if persistent.endings is None:
        persistent.endings = set()

    def merge_endings(old, new, current):
        current.update(old)
        current.update(new)
        return current

    renpy.register_persistent('endings', merge_endings)

영구 데이터 함수

persistent._hasattr(field_name)

field_name 영구 필드가 설정되었는지 검사합니다. 명시적으로 None을 설정한 필드와 한 번도 설정하지 않은 필드를 구분할 수 있습니다.

persistent._clear(progress=False)

__로 시작하는 필드를 제외하고 영구 데이터를 초기화합니다.

progress

참이면 Ren'Py가 보관하는 진행 데이터도 초기화합니다.

기본값도 다시 적용됩니다.

renpy.register_persistent(field, func)

디스크에서 불러온 영구 필드 값과 현재 persistent 객체의 값을 병합할 때 사용할 함수를 등록합니다.

field

persistent 객체 필드의 이름입니다.

function

old, new, current의 세 매개변수로 호출되는 함수입니다.

old

이전 객체에 있는 필드 값입니다.

new

더 새로운 객체에 있는 필드 값입니다.

current

현재 persistent 객체의 필드 값입니다. 필드가 참조하는 객체의 동일성을 변경할 수 없는 경우를 위해 제공됩니다.

함수는 persistent 객체에 넣을 새 필드 값을 반환해야 합니다.

renpy.save_persistent()

영구 데이터를 디스크에 저장합니다.

여러 게임 간의 영구 데이터 공유

여러 게임 간의 영구 데이터 공유는 Ren'Py 게임 사이에서 정보를 공유하는 기능입니다. 연작 게임을 만들면서 서로 정보를 공유하려는 경우 유용할 수 있습니다.

공유 영구 데이터를 사용하려면 초기화 시점에 MultiPersistent 객체를 만들어야 합니다. define 사용을 권장합니다. 이후 객체를 갱신하고 save 메서드를 호출해 디스크에 저장할 수 있습니다. 정의되지 않은 필드의 기본값은 None입니다. 다른 게임에서도 객체를 다시 불러올 수 있도록 사용자 정의 형식의 인스턴스를 객체에 저장하지 않을 것을 강력히 권장합니다.

class MultiPersistent(name, save_on_quit=False)

새 MultiPersistent 객체를 만듭니다. 초기화 시점에만 호출해야 하며, 지정한 이름의 새 MultiPersistent를 반환합니다.

name

공유 영구 데이터에 접근할 때 사용하는 이름입니다. 같은 이름을 사용하는 게임은 같은 공유 영구 데이터에 접근합니다.

save_on_quit

True이면 Ren'Py를 종료할 때 이 객체를 자동으로 저장합니다.

save()

공유 영구 데이터를 디스크에 저장합니다. 데이터를 수정한 뒤 반드시 호출해야 합니다.

예를 들어 두 편으로 구성된 게임의 첫 번째 편은 다음과 같습니다.

define mp = MultiPersistent("demo.renpy.org")

label start:

    # ...

    # Record the fact that the user beat part 1.

    $ mp.beat_part_1 = True
    $ mp.save()

    e "1부를 클리어하셨네요. 2부에서 만나요!"

두 번째 편은 다음과 같습니다.

define mp = MultiPersistent("demo.renpy.org")

label start:

    if mp.beat_part_1:
        e "1부를 클리어하셨군요. 다시 오신 것을 환영해요!"
    else:
        e "음, 아직 1부를 플레이하지 않으셨네요. 먼저 해 보시는 게 어때요?"