feat: converter accepts the constructs of goodluke and SaintlyCorruption
`init -490 screen`, `import x as y` and `from m import A as B`, classes with @renpy.pure, pickle hooks
on classes, `*` items in tuples and lists, generator functions (yield statements; the player runs them
to the end), multi-line expressions that need brackets, Null() and Animation() images, images given as
expressions (`"path/{}.png".format(x)`, f-strings), window statements in init, `offset` in ATL, input
widgets with their values and the focus/confirm actions, `continue` and `break` in screens, `drag`
and DiamondBox-style `fixed` with cell_size, `getattr(...)()` calls, transforms called with arguments,
and the whitelist for the new runtime. JSON files of a game are shipped as data files. Also fixes
blocking_names failing on a call of a call during full conversion.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f2fcd05467
commit
e66160cffa
12 files changed
+176
-31
No files matched your search
@@ -124,6 +124,15 @@ CALLS |= set(NATIVE_CLASSES)
|
||||
CALLS |= {"renpy.Render", "renpy.render", "renpy.redraw", "renpy.displayable", "renpy.IgnoreEvent",
|
||||
"renpy.display.layout.LiveComposite", "renpy.display.layout.Fixed", "pygame.key.get_mods",
|
||||
"pygame.mouse.get_pressed", "pygame.mouse.get_pos"}
|
||||
CALLS |= {"ConditionSwitch", "DynamicImage", "renpy.register_sl_displayable", "renpy.capture_focus", "renpy.clear_capture_focus", "renpy.get_widget", "renpy.display.focus.set_focused",
|
||||
"renpy.file", "renpy.open_file", "loads", "dumps", "json.loads", "json.dumps", "Animation", "im.matrix", "renpy.context", "renpy.call_in_new_context", "renpy.get_focus_rect", "gui.rebuild", "FontGroup", "RenpyText",
|
||||
"MatrixColor", "im.Image", "im.AlphaMask", "GLMovie", "renpy.display.im.Image", "colorsys.rgb_to_hls",
|
||||
"colorsys.hls_to_rgb"}
|
||||
CALLS |= {"next", "repr", "dict.fromkeys", "colorsys.rgb_to_hsv", "colorsys.hsv_to_rgb", "fnmatch.fnmatch",
|
||||
"traceback.format_exc", "traceback.print_exc", "math.log1p", "math.expm1", "renpy.in_rollback",
|
||||
"renpy.is_in_test", "renpy.retain_after_load", "renpy.context_nesting_level", "renpy.current_screen",
|
||||
"renpy.substitutions.substitute", "renpy.set_screen_variable", "renpy.music.register_channel",
|
||||
"renpy.music.get_loop", "renpy.music.get_channel"}
|
||||
CALLS |= {"Matrix", "renpy.has_live2d", "renpy.fetch", "renpy.display.draw.kill_textures",
|
||||
"renpy.display.render.free_memory", "cache.get_total_size"}
|
||||
CALLS |= {"Move", "absolute", "type", "id", "vars", "Flatten", "LiveComposite", "Composite", "defaultdict", "OrderedDict", "deepcopy",
|
||||
@@ -149,6 +158,10 @@ SCREEN_CALLS |= set("""FileAction FileSave FileLoad FileDelete FileTakeScreensho
|
||||
FileLoadable FileUsedSlot FileNewest FileSaveName FileTime FileJson FileScreenshot FileCurrentScreenshot
|
||||
FileCurrentPage FilePageName FileSlotName""".split())
|
||||
SCREEN_CALLS |= {"renpy.translation.translate_string"}
|
||||
# Text fields and the actions around them (see InputValue in screens.ts)
|
||||
SCREEN_CALLS |= set("""VariableInputValue ScreenVariableInputValue FieldInputValue DictInputValue FilePageNameInputValue
|
||||
CurrentScreenName CaptureFocus ClearFocus InvertSelected UploadSync DownloadSync Confirm""".split())
|
||||
METHODS_INPUT = {"Enable", "Disable", "Toggle"}
|
||||
# Screen language helpers for audio, focus and pictures that play (see screens.ts)
|
||||
SCREEN_CALLS |= {"Movie", "MixerValue", "AudioPositionValue", "PauseAudio", "ToggleSetMembership",
|
||||
"GetFocusRect", "ToggleFocus", "XScrollValue", "YScrollValue", "Preference", "Start"}
|
||||
@@ -173,7 +186,7 @@ METHODS = set("append extend insert pop remove index count reverse sort clear co
|
||||
|
||||
METHODS |= NATIVE_METHODS
|
||||
# Methods of generators made by `renpy.random.Random()` / `random.Random()`
|
||||
METHODS |= {"blit", "subpixel_blit", "fill", "canvas", "get_size", "add_shader", "add_uniform", "add_property",
|
||||
METHODS |= {"add_style_property", "add_prefix_style_property", "add_pattern", "get_context", "read", "readlines", "close", "sub", "subn", "search", "match", "findall", "finditer", "split", "time", "_clear", "Enable", "Disable", "Toggle", "encode", "blit", "subpixel_blit", "fill", "canvas", "get_size", "add_shader", "add_uniform", "add_property",
|
||||
"add_focus", "circle", "rect", "line", "lines", "polygon"}
|
||||
METHODS |= {"fullmatch", "hexdigest", "randint", "randrange", "random", "choice", "choices", "sample", "shuffle", "uniform"}
|
||||
|
||||
@@ -380,7 +393,8 @@ def blocking_names(data) -> list[str]:
|
||||
elif isinstance(value, dict):
|
||||
if value.get("k") == "call":
|
||||
function = value["f"]
|
||||
last = function.get("id") if function.get("k") == "name" else function.get("a")
|
||||
last = function.get("id") if function.get("k") == "name" else (
|
||||
function.get("a") if function.get("k") == "attr" else None) # `f()()` has neither
|
||||
dotted = (function["o"]["id"] + "." + function["a"]) if (function.get("k") == "attr" and
|
||||
function["o"].get("k") == "name") else last
|
||||
if dotted in waiting or last in known or last in waiting:
|
||||
@@ -504,6 +518,7 @@ def audit_ir(data) -> None:
|
||||
list(used_screens.values())])
|
||||
user_names |= {name for name, _ in data.defaults}
|
||||
user_names |= set(data.characters) | {"narrator"}
|
||||
user_names |= set(data.transforms) | set(data.atl) # `store.move_in(0.3)`: a transform called with arguments
|
||||
|
||||
def dotted(value):
|
||||
if value.get("k") == "name":
|
||||
@@ -524,8 +539,9 @@ def audit_ir(data) -> None:
|
||||
and (function.get("a") in METHODS or function.get("a") in user_methods
|
||||
or function.get("a") in user_names))
|
||||
# `MainMenu(confirm=False)()`: calling the action a screen action constructor returned
|
||||
if function.get("k") == "call" and dotted(function.get("f", {})) in SCREEN_CALLS:
|
||||
is_method = True
|
||||
if function.get("k") == "call" and (dotted(function.get("f", {})) in SCREEN_CALLS
|
||||
or dotted(function.get("f", {})) == "getattr"):
|
||||
is_method = True # an action a constructor returned, or `getattr(obj, "f", fallback)()`
|
||||
# `globals()[who + "_here"](...)`: a function picked by name; some function must carry that ending
|
||||
if function.get("k") == "sub" and function["o"].get("k") == "call" \
|
||||
and dotted(function["o"]["f"]) == "globals":
|
||||
|
||||
Reference in new issue
Block a user