diff --git a/ghidra_scripts/extract_engine_surface.py b/ghidra_scripts/extract_engine_surface.py index d5f6cb0..2a66aae 100644 --- a/ghidra_scripts/extract_engine_surface.py +++ b/ghidra_scripts/extract_engine_surface.py @@ -328,9 +328,59 @@ def extract_methods(program): methods.extend(own) if base is not None: inheritance.append({"runner": runner, "base_runner": base}) + if not methods: + # Piklib 6.1 predates prepareMthHashSet: methods are dispatched by NAME inside + # ::run, so recover the names from there instead (no numeric ids). + methods = extract_methods_by_name(program) return methods, inheritance +def _extract_name_methods_from_run(program, run_func, owner, runner): + """Piklib 6.1's `run(CXString name, ...)` is a chain of `CXString(tmp, "name")` then + `equalsIgnoreCase(name)`; the literal built right before each compare is a method name.""" + listing = program.getListing() + methods = [] + recent = [] + pending = None + seen = set() + it = listing.getInstructions(resolve_thunk(run_func).getBody(), True) + while it.hasNext(): + instr = it.next() + if instr.getMnemonicString() == "CALL": + f = call_target(program, instr) + nm = f.getName() if f is not None else None + if nm == "CXString": # CXString(tmp, ) builds the literal + s = lookback_string(program, recent) + if s is not None and _is_method_name(s): + pending = s + elif nm == "equalsIgnoreCase" and pending is not None: + if pending not in seen: + seen.add(pending) + methods.append({"owner": owner, "runner": runner, "name": pending, "id": None}) + pending = None + recent.append(instr) + if len(recent) > LOOKBACK: + recent.pop(0) + return methods + + +def extract_methods_by_name(program): + """Name-dispatched method recovery for engines without prepareMthHashSet (Piklib 6.1).""" + fm = program.getFunctionManager() + methods = [] + it = fm.getFunctions(True) + while it.hasNext(): + f = it.next() + if f.getName() != "run": + continue + ns = f.getParentNamespace() + runner = ns.getName() if ns is not None else "?" + if not runner.endswith("_Runner"): + continue + methods.extend(_extract_name_methods_from_run(program, f, _owner_from_runner(runner), runner)) + return methods + + _VTBL_OFF = re.compile(r"\[\w+ \+ (0x[0-9a-fA-F]+)\]") _MEM_OFF = re.compile(r"\[\w+ \+ (0x[0-9a-fA-F]+)\]") diff --git a/snapshots/PIKLib61.dll.snapshot.json b/snapshots/PIKLib61.dll.snapshot.json index 173316c..94a92f4 100644 --- a/snapshots/PIKLib61.dll.snapshot.json +++ b/snapshots/PIKLib61.dll.snapshot.json @@ -4,7 +4,7 @@ "engine": "Piklib", "factory_addr": "0x100395c0", "name": "PIKLib61.dll", - "sha256": null + "sha256": "694ce89d3030dc81b136cef2667fcd853e3f28ebe91d82ff0850e94a1935fbcb" }, "events": [ { @@ -1233,7 +1233,1124 @@ ], "method_dispatch": [], "method_inheritance": [], - "methods": [], + "methods": [ + { + "id": null, + "name": "show", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "hide", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "pause", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "resume", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "setPosition", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "move", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "load", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "clearClipping", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "setClipping", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "play", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "setFrame", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "stop", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "isPlaying", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "isPaused", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "getPositionX", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "getPositionY", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "getWidth", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "getHeight", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "getFrame", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "getFrameName", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "getFrameNo", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "getEventName", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "isNear", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "isInside", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "playRand", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "monitorCollision", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "removeMonitorCollision", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "setForward", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "setBackward", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "nextFrame", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "prevFrame", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "setPriority", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "getAlpha", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "getPixel", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "setFPS", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "mergeAlpha", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "invalidate", + "owner": "CMC_Animo", + "runner": "CMC_Animo_Runner" + }, + { + "id": null, + "name": "exit", + "owner": "CMC_Application", + "runner": "CMC_Application_Runner" + }, + { + "id": null, + "name": "restart", + "owner": "CMC_Application", + "runner": "CMC_Application_Runner" + }, + { + "id": null, + "name": "goto", + "owner": "CMC_Application", + "runner": "CMC_Application_Runner" + }, + { + "id": null, + "name": "add", + "owner": "CMC_Array", + "runner": "CMC_Array_Runner" + }, + { + "id": null, + "name": "getSize", + "owner": "CMC_Array", + "runner": "CMC_Array_Runner" + }, + { + "id": null, + "name": "insertAt", + "owner": "CMC_Array", + "runner": "CMC_Array_Runner" + }, + { + "id": null, + "name": "removeAt", + "owner": "CMC_Array", + "runner": "CMC_Array_Runner" + }, + { + "id": null, + "name": "changeAt", + "owner": "CMC_Array", + "runner": "CMC_Array_Runner" + }, + { + "id": null, + "name": "removeAll", + "owner": "CMC_Array", + "runner": "CMC_Array_Runner" + }, + { + "id": null, + "name": "get", + "owner": "CMC_Array", + "runner": "CMC_Array_Runner" + }, + { + "id": null, + "name": "check", + "owner": "CMC_BasicCondition", + "runner": "CMC_BasicCondition_Runner" + }, + { + "id": null, + "name": "run", + "owner": "CMC_Behaviour", + "runner": "CMC_Behaviour_Runner" + }, + { + "id": null, + "name": "runC", + "owner": "CMC_Behaviour", + "runner": "CMC_Behaviour_Runner" + }, + { + "id": null, + "name": "setRect", + "owner": "CMC_Button", + "runner": "CMC_Button_Runner" + }, + { + "id": null, + "name": "enable", + "owner": "CMC_Button", + "runner": "CMC_Button_Runner" + }, + { + "id": null, + "name": "disable", + "owner": "CMC_Button", + "runner": "CMC_Button_Runner" + }, + { + "id": null, + "name": "enableDragging", + "owner": "CMC_Button", + "runner": "CMC_Button_Runner" + }, + { + "id": null, + "name": "disableDragging", + "owner": "CMC_Button", + "runner": "CMC_Button_Runner" + }, + { + "id": null, + "name": "disableButVisible", + "owner": "CMC_Button", + "runner": "CMC_Button_Runner" + }, + { + "id": null, + "name": "accent", + "owner": "CMC_Button", + "runner": "CMC_Button_Runner" + }, + { + "id": null, + "name": "setStd", + "owner": "CMC_Button", + "runner": "CMC_Button_Runner" + }, + { + "id": null, + "name": "setOnMove", + "owner": "CMC_Button", + "runner": "CMC_Button_Runner" + }, + { + "id": null, + "name": "setOnClick", + "owner": "CMC_Button", + "runner": "CMC_Button_Runner" + }, + { + "id": null, + "name": "refresh", + "owner": "CMC_CanvasObserver", + "runner": "CMC_CanvasObserver_Runner" + }, + { + "id": null, + "name": "add", + "owner": "CMC_CanvasObserver", + "runner": "CMC_CanvasObserver_Runner" + }, + { + "id": null, + "name": "remove", + "owner": "CMC_CanvasObserver", + "runner": "CMC_CanvasObserver_Runner" + }, + { + "id": null, + "name": "setBackground", + "owner": "CMC_CanvasObserver", + "runner": "CMC_CanvasObserver_Runner" + }, + { + "id": null, + "name": "getGraphicsAt", + "owner": "CMC_CanvasObserver", + "runner": "CMC_CanvasObserver_Runner" + }, + { + "id": null, + "name": "load", + "owner": "CMC_CNVLoader", + "runner": "CMC_CNVLoader_Runner" + }, + { + "id": null, + "name": "release", + "owner": "CMC_CNVLoader", + "runner": "CMC_CNVLoader_Runner" + }, + { + "id": null, + "name": "show", + "owner": "CMC_Dialog", + "runner": "CMC_Dialog_Runner" + }, + { + "id": null, + "name": "next", + "owner": "CMC_Episode", + "runner": "CMC_Episode_Runner" + }, + { + "id": null, + "name": "prev", + "owner": "CMC_Episode", + "runner": "CMC_Episode_Runner" + }, + { + "id": null, + "name": "back", + "owner": "CMC_Episode", + "runner": "CMC_Episode_Runner" + }, + { + "id": null, + "name": "restart", + "owner": "CMC_Episode", + "runner": "CMC_Episode_Runner" + }, + { + "id": null, + "name": "goto", + "owner": "CMC_Episode", + "runner": "CMC_Episode_Runner" + }, + { + "id": null, + "name": "getLatestScene", + "owner": "CMC_Episode", + "runner": "CMC_Episode_Runner" + }, + { + "id": null, + "name": "setColor", + "owner": "CMC_Font", + "runner": "CMC_Font_Runner" + }, + { + "id": null, + "name": "setFamily", + "owner": "CMC_Font", + "runner": "CMC_Font_Runner" + }, + { + "id": null, + "name": "setStyle", + "owner": "CMC_Font", + "runner": "CMC_Font_Runner" + }, + { + "id": null, + "name": "add", + "owner": "CMC_Groupped", + "runner": "CMC_Groupped_Runner" + }, + { + "id": null, + "name": "addClone", + "owner": "CMC_Groupped", + "runner": "CMC_Groupped_Runner" + }, + { + "id": null, + "name": "remove", + "owner": "CMC_Groupped", + "runner": "CMC_Groupped_Runner" + }, + { + "id": null, + "name": "removeAll", + "owner": "CMC_Groupped", + "runner": "CMC_Groupped_Runner" + }, + { + "id": null, + "name": "getSize", + "owner": "CMC_Groupped", + "runner": "CMC_Groupped_Runner" + }, + { + "id": null, + "name": "getName", + "owner": "CMC_Groupped", + "runner": "CMC_Groupped_Runner" + }, + { + "id": null, + "name": "show", + "owner": "CMC_Image", + "runner": "CMC_Image_Runner" + }, + { + "id": null, + "name": "hide", + "owner": "CMC_Image", + "runner": "CMC_Image_Runner" + }, + { + "id": null, + "name": "setPosition", + "owner": "CMC_Image", + "runner": "CMC_Image_Runner" + }, + { + "id": null, + "name": "move", + "owner": "CMC_Image", + "runner": "CMC_Image_Runner" + }, + { + "id": null, + "name": "load", + "owner": "CMC_Image", + "runner": "CMC_Image_Runner" + }, + { + "id": null, + "name": "clearClipping", + "owner": "CMC_Image", + "runner": "CMC_Image_Runner" + }, + { + "id": null, + "name": "setClipping", + "owner": "CMC_Image", + "runner": "CMC_Image_Runner" + }, + { + "id": null, + "name": "getPositionX", + "owner": "CMC_Image", + "runner": "CMC_Image_Runner" + }, + { + "id": null, + "name": "getPositionY", + "owner": "CMC_Image", + "runner": "CMC_Image_Runner" + }, + { + "id": null, + "name": "getWidth", + "owner": "CMC_Image", + "runner": "CMC_Image_Runner" + }, + { + "id": null, + "name": "getHeight", + "owner": "CMC_Image", + "runner": "CMC_Image_Runner" + }, + { + "id": null, + "name": "isNear", + "owner": "CMC_Image", + "runner": "CMC_Image_Runner" + }, + { + "id": null, + "name": "isInside", + "owner": "CMC_Image", + "runner": "CMC_Image_Runner" + }, + { + "id": null, + "name": "monitorCollision", + "owner": "CMC_Image", + "runner": "CMC_Image_Runner" + }, + { + "id": null, + "name": "removeMonitorCollision", + "owner": "CMC_Image", + "runner": "CMC_Image_Runner" + }, + { + "id": null, + "name": "setScaleFactor", + "owner": "CMC_Image", + "runner": "CMC_Image_Runner" + }, + { + "id": null, + "name": "setPriority", + "owner": "CMC_Image", + "runner": "CMC_Image_Runner" + }, + { + "id": null, + "name": "getAlpha", + "owner": "CMC_Image", + "runner": "CMC_Image_Runner" + }, + { + "id": null, + "name": "getPixel", + "owner": "CMC_Image", + "runner": "CMC_Image_Runner" + }, + { + "id": null, + "name": "mergeAlpha", + "owner": "CMC_Image", + "runner": "CMC_Image_Runner" + }, + { + "id": null, + "name": "invalidate", + "owner": "CMC_Image", + "runner": "CMC_Image_Runner" + }, + { + "id": null, + "name": "enable", + "owner": "CMC_Keyboard", + "runner": "CMC_Keyboard_Runner" + }, + { + "id": null, + "name": "disable", + "owner": "CMC_Keyboard", + "runner": "CMC_Keyboard_Runner" + }, + { + "id": null, + "name": "show", + "owner": "CMC_Mouse", + "runner": "CMC_Mouse_Runner" + }, + { + "id": null, + "name": "hide", + "owner": "CMC_Mouse", + "runner": "CMC_Mouse_Runner" + }, + { + "id": null, + "name": "enable", + "owner": "CMC_Mouse", + "runner": "CMC_Mouse_Runner" + }, + { + "id": null, + "name": "disable", + "owner": "CMC_Mouse", + "runner": "CMC_Mouse_Runner" + }, + { + "id": null, + "name": "getPosX", + "owner": "CMC_Mouse", + "runner": "CMC_Mouse_Runner" + }, + { + "id": null, + "name": "getPosY", + "owner": "CMC_Mouse", + "runner": "CMC_Mouse_Runner" + }, + { + "id": null, + "name": "getLastClickPosX", + "owner": "CMC_Mouse", + "runner": "CMC_Mouse_Runner" + }, + { + "id": null, + "name": "getLastClickPosY", + "owner": "CMC_Mouse", + "runner": "CMC_Mouse_Runner" + }, + { + "id": null, + "name": "set", + "owner": "CMC_Mouse", + "runner": "CMC_Mouse_Runner" + }, + { + "id": null, + "name": "setPosition", + "owner": "CMC_Mouse", + "runner": "CMC_Mouse_Runner" + }, + { + "id": null, + "name": "move", + "owner": "CMC_Mouse", + "runner": "CMC_Mouse_Runner" + }, + { + "id": null, + "name": "connect", + "owner": "CMC_Network", + "runner": "CMC_Network_Runner" + }, + { + "id": null, + "name": "close", + "owner": "CMC_Network", + "runner": "CMC_Network_Runner" + }, + { + "id": null, + "name": "send", + "owner": "CMC_Network", + "runner": "CMC_Network_Runner" + }, + { + "id": null, + "name": "getReceived", + "owner": "CMC_Network", + "runner": "CMC_Network_Runner" + }, + { + "id": null, + "name": "get", + "owner": "CMC_Rand", + "runner": "CMC_Rand_Runner" + }, + { + "id": null, + "name": "getPlenty", + "owner": "CMC_Rand", + "runner": "CMC_Rand_Runner" + }, + { + "id": null, + "name": "send", + "owner": "CMC", + "runner": "CMC_Runner" + }, + { + "id": null, + "name": "addToGroup", + "owner": "CMC", + "runner": "CMC_Runner" + }, + { + "id": null, + "name": "addToArray", + "owner": "CMC", + "runner": "CMC_Runner" + }, + { + "id": null, + "name": "startMusic", + "owner": "CMC_Scene", + "runner": "CMC_Scene_Runner" + }, + { + "id": null, + "name": "stopMusic", + "owner": "CMC_Scene", + "runner": "CMC_Scene_Runner" + }, + { + "id": null, + "name": "getDraggedName", + "owner": "CMC_Scene", + "runner": "CMC_Scene_Runner" + }, + { + "id": null, + "name": "getPlayingSeq", + "owner": "CMC_Scene", + "runner": "CMC_Scene_Runner" + }, + { + "id": null, + "name": "run", + "owner": "CMC_Scene", + "runner": "CMC_Scene_Runner" + }, + { + "id": null, + "name": "play", + "owner": "CMC_Sequence", + "runner": "CMC_Sequence_Runner" + }, + { + "id": null, + "name": "stop", + "owner": "CMC_Sequence", + "runner": "CMC_Sequence_Runner" + }, + { + "id": null, + "name": "pause", + "owner": "CMC_Sequence", + "runner": "CMC_Sequence_Runner" + }, + { + "id": null, + "name": "resume", + "owner": "CMC_Sequence", + "runner": "CMC_Sequence_Runner" + }, + { + "id": null, + "name": "show", + "owner": "CMC_Sequence", + "runner": "CMC_Sequence_Runner" + }, + { + "id": null, + "name": "hide", + "owner": "CMC_Sequence", + "runner": "CMC_Sequence_Runner" + }, + { + "id": null, + "name": "isplaying", + "owner": "CMC_Sequence", + "runner": "CMC_Sequence_Runner" + }, + { + "id": null, + "name": "play", + "owner": "CMC_Sound", + "runner": "CMC_Sound_Runner" + }, + { + "id": null, + "name": "stop", + "owner": "CMC_Sound", + "runner": "CMC_Sound_Runner" + }, + { + "id": null, + "name": "pause", + "owner": "CMC_Sound", + "runner": "CMC_Sound_Runner" + }, + { + "id": null, + "name": "resume", + "owner": "CMC_Sound", + "runner": "CMC_Sound_Runner" + }, + { + "id": null, + "name": "load", + "owner": "CMC_Sound", + "runner": "CMC_Sound_Runner" + }, + { + "id": null, + "name": "getDate", + "owner": "CMC_System", + "runner": "CMC_System_Runner" + }, + { + "id": null, + "name": "getDateString", + "owner": "CMC_System", + "runner": "CMC_System_Runner" + }, + { + "id": null, + "name": "getDay", + "owner": "CMC_System", + "runner": "CMC_System_Runner" + }, + { + "id": null, + "name": "getDayOfWeek", + "owner": "CMC_System", + "runner": "CMC_System_Runner" + }, + { + "id": null, + "name": "getDayOfWeekString", + "owner": "CMC_System", + "runner": "CMC_System_Runner" + }, + { + "id": null, + "name": "getMonth", + "owner": "CMC_System", + "runner": "CMC_System_Runner" + }, + { + "id": null, + "name": "getMonthString", + "owner": "CMC_System", + "runner": "CMC_System_Runner" + }, + { + "id": null, + "name": "getYear", + "owner": "CMC_System", + "runner": "CMC_System_Runner" + }, + { + "id": null, + "name": "getTimeString", + "owner": "CMC_System", + "runner": "CMC_System_Runner" + }, + { + "id": null, + "name": "getHour", + "owner": "CMC_System", + "runner": "CMC_System_Runner" + }, + { + "id": null, + "name": "getMinutes", + "owner": "CMC_System", + "runner": "CMC_System_Runner" + }, + { + "id": null, + "name": "getSeconds", + "owner": "CMC_System", + "runner": "CMC_System_Runner" + }, + { + "id": null, + "name": "setText", + "owner": "CMC_Text", + "runner": "CMC_Text_Runner" + }, + { + "id": null, + "name": "setJustify", + "owner": "CMC_Text", + "runner": "CMC_Text_Runner" + }, + { + "id": null, + "name": "show", + "owner": "CMC_Text", + "runner": "CMC_Text_Runner" + }, + { + "id": null, + "name": "hide", + "owner": "CMC_Text", + "runner": "CMC_Text_Runner" + }, + { + "id": null, + "name": "setPosition", + "owner": "CMC_Text", + "runner": "CMC_Text_Runner" + }, + { + "id": null, + "name": "move", + "owner": "CMC_Text", + "runner": "CMC_Text_Runner" + }, + { + "id": null, + "name": "load", + "owner": "CMC_Text", + "runner": "CMC_Text_Runner" + }, + { + "id": null, + "name": "clearClipping", + "owner": "CMC_Text", + "runner": "CMC_Text_Runner" + }, + { + "id": null, + "name": "setClipping", + "owner": "CMC_Text", + "runner": "CMC_Text_Runner" + }, + { + "id": null, + "name": "getPositionX", + "owner": "CMC_Text", + "runner": "CMC_Text_Runner" + }, + { + "id": null, + "name": "getPositionY", + "owner": "CMC_Text", + "runner": "CMC_Text_Runner" + }, + { + "id": null, + "name": "getWidth", + "owner": "CMC_Text", + "runner": "CMC_Text_Runner" + }, + { + "id": null, + "name": "getHeight", + "owner": "CMC_Text", + "runner": "CMC_Text_Runner" + }, + { + "id": null, + "name": "isNear", + "owner": "CMC_Text", + "runner": "CMC_Text_Runner" + }, + { + "id": null, + "name": "monitorCollision", + "owner": "CMC_Text", + "runner": "CMC_Text_Runner" + }, + { + "id": null, + "name": "removeMonitorCollision", + "owner": "CMC_Text", + "runner": "CMC_Text_Runner" + }, + { + "id": null, + "name": "setPriority", + "owner": "CMC_Text", + "runner": "CMC_Text_Runner" + }, + { + "id": null, + "name": "enable", + "owner": "CMC_Timer", + "runner": "CMC_Timer_Runner" + }, + { + "id": null, + "name": "disable", + "owner": "CMC_Timer", + "runner": "CMC_Timer_Runner" + }, + { + "id": null, + "name": "getTicks", + "owner": "CMC_Timer", + "runner": "CMC_Timer_Runner" + }, + { + "id": null, + "name": "reset", + "owner": "CMC_Timer", + "runner": "CMC_Timer_Runner" + }, + { + "id": null, + "name": "set", + "owner": "CMC_Timer", + "runner": "CMC_Timer_Runner" + }, + { + "id": null, + "name": "set", + "owner": "CMC_Variable", + "runner": "CMC_Variable_Runner" + }, + { + "id": null, + "name": "switch", + "owner": "CMC_Variable", + "runner": "CMC_Variable_Runner" + }, + { + "id": null, + "name": "clear", + "owner": "CMC_Variable", + "runner": "CMC_Variable_Runner" + }, + { + "id": null, + "name": "inc", + "owner": "CMC_Variable", + "runner": "CMC_Variable_Runner" + }, + { + "id": null, + "name": "dec", + "owner": "CMC_Variable", + "runner": "CMC_Variable_Runner" + }, + { + "id": null, + "name": "add", + "owner": "CMC_Variable", + "runner": "CMC_Variable_Runner" + }, + { + "id": null, + "name": "mul", + "owner": "CMC_Variable", + "runner": "CMC_Variable_Runner" + }, + { + "id": null, + "name": "resetINI", + "owner": "CMC_Variable", + "runner": "CMC_Variable_Runner" + }, + { + "id": null, + "name": "setDefault", + "owner": "CMC_Variable", + "runner": "CMC_Variable_Runner" + } + ], "schema_version": 4, "struct_layout": [ { diff --git a/tests/test_versions.py b/tests/test_versions.py index f544ac3..e647c33 100644 --- a/tests/test_versions.py +++ b/tests/test_versions.py @@ -30,9 +30,13 @@ def test_piklib61_early_engine_partial_surface(): names = {t["script_name"] for t in s.types} assert len(names) >= 20 and {"ANIMO", "ARRAY", "BUTTON"} <= names assert all(t.get("cpp_class") is None or t["cpp_class"].startswith("CMC_") for t in s.types) - # events + script fields work; method registration (prepareMthHashSet) doesn't exist yet assert s.events and s.fields - assert s.methods == [] and s.method_dispatch == [] + # 6.1 predates prepareMthHashSet: methods are dispatched by NAME in run(), so they're + # recovered without numeric ids, and the id-switch dispatch axis stays empty. + assert s.methods and all(m["id"] is None for m in s.methods) + assert s.method_dispatch == [] + animo = {m["name"] for m in s.methods if m["owner"] == "CMC_Animo"} + assert {"show", "hide", "play"} <= animo # 6.1 uses lower/camelCase names def test_piklib71_full_surface(): @@ -43,10 +47,12 @@ def test_piklib71_full_surface(): assert sum(1 for t in s.types if t.get("cpp_class")) > len(s.types) // 2 -def test_61_to_71_diff_adds_methods(): +def test_61_to_71_method_id_evolution(): s61, s71 = _load(P61), _load(P71) shared = {t["script_name"] for t in s61.types} & {t["script_name"] for t in s71.types} - assert {"ANIMO", "ARRAY", "BUTTON"} <= shared # stable core across the two early versions - # 7.1 introduces the registered-method machinery 6.1 lacked entirely - d = compute_diff(s61, s71) - assert len(d["methods"]["added"]) > 100 and d["methods"]["removed"] == [] + assert {"ANIMO", "ARRAY", "BUTTON"} <= shared # stable type core across the two early versions + # both expose a rich method surface, but only 7.1 carries numeric ids (prepareMthHashSet); + # 6.1's are name-only. (Names also differ in case - 6.1 camelCase vs 7.1 UPPERCASE - which is + # why a raw method diff is noisy without case folding.) + assert len(s61.methods) > 100 and all(m["id"] is None for m in s61.methods) + assert len(s71.methods) > 100 and all(m["id"] is not None for m in s71.methods)