mcpywrap 0.4.4__tar.gz → 0.4.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (282) hide show
  1. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/CHANGELOG.md +12 -0
  2. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/MANIFEST.in +2 -0
  3. {mcpywrap-0.4.4/mcpywrap.egg-info → mcpywrap-0.4.6}/PKG-INFO +2 -2
  4. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/README.md +1 -1
  5. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/game-backends.md +8 -0
  6. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/qt6-development.md +15 -0
  7. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/runtime-input.md +1 -1
  8. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/__init__.py +1 -1
  9. mcpywrap-0.4.6/mcpywrap/engines/android_icon.py +186 -0
  10. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/engines/install.py +5 -1
  11. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/engines/macos.py +6 -2
  12. mcpywrap-0.4.6/mcpywrap/engines/macos_icons.py +159 -0
  13. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/engines/macos_network.py +1 -0
  14. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/auth_interaction.py +6 -4
  15. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/bridge_payload/Injector.exe +0 -0
  16. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/bridge_payload/Loader.dll +0 -0
  17. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/bridge_payload/McpyMcsAuth.dll +0 -0
  18. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/bridge_payload/manifest.json +3 -3
  19. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/studio_server_ui.py +2 -1
  20. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/window_capture/manifest.json +1 -1
  21. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/window_capture/mcpy-window-capture.exe +0 -0
  22. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/minecraft/template/mod_template.py +2 -1
  23. mcpywrap-0.4.6/mcpywrap/ui/application.py +58 -0
  24. mcpywrap-0.4.6/mcpywrap/ui/assets/mcpy.icns +0 -0
  25. mcpywrap-0.4.6/mcpywrap/ui/assets/mcpy.icon/Assets/01-cube.svg +5 -0
  26. mcpywrap-0.4.6/mcpywrap/ui/assets/mcpy.icon/Assets/02-prompt.svg +4 -0
  27. mcpywrap-0.4.6/mcpywrap/ui/assets/mcpy.icon/icon.json +56 -0
  28. mcpywrap-0.4.6/mcpywrap/ui/assets/mcpy.png +0 -0
  29. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/ui/log_window.py +2 -0
  30. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/ui/project_ui.py +4 -3
  31. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/ui/run_session.py +2 -2
  32. {mcpywrap-0.4.4 → mcpywrap-0.4.6/mcpywrap.egg-info}/PKG-INFO +2 -2
  33. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap.egg-info/SOURCES.txt +11 -0
  34. mcpywrap-0.4.6/native/runtime_input/README.md +33 -0
  35. mcpywrap-0.4.6/native/runtime_input/manifest-monotonic.patch +147 -0
  36. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/pyproject.toml +2 -1
  37. mcpywrap-0.4.6/scripts/build_app_icon.py +55 -0
  38. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/scripts/check_release.py +15 -2
  39. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/SKILL.md +2 -0
  40. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/references/macos-local.md +17 -1
  41. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/references/runtime-input.md +1 -1
  42. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual_runtime_input_unified.py +75 -9
  43. mcpywrap-0.4.6/tests/test_application_icons.py +176 -0
  44. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_instance_cppconfig.py +3 -0
  45. mcpywrap-0.4.4/native/runtime_input/README.md +0 -11
  46. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/LICENSE +0 -0
  47. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/THIRD_PARTY_NOTICES.md +0 -0
  48. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/code-libraries.md +0 -0
  49. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/development.md +0 -0
  50. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/engine-discovery.md +0 -0
  51. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/git-dependencies.md +0 -0
  52. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/input-sequence.md +0 -0
  53. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/launcher-client-python.md +0 -0
  54. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/local-dependencies.md +0 -0
  55. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/macos-resource-reload.md +0 -0
  56. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/mcs-auth.md +0 -0
  57. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/qumod.md +0 -0
  58. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/release-0.4.0.md +0 -0
  59. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/release-readiness-0.4.0.md +0 -0
  60. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/releasing.md +0 -0
  61. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/runtime-debug.md +0 -0
  62. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/runtime-player.md +0 -0
  63. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/runtime-ui.md +0 -0
  64. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/shared-log-ui.md +0 -0
  65. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/__main__.py +0 -0
  66. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/builders/AddonsPack.py +0 -0
  67. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/builders/MapPack.py +0 -0
  68. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/builders/__init__.py +0 -0
  69. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/builders/assembly.py +0 -0
  70. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/builders/dependency_manager.py +0 -0
  71. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/builders/file_merge.py +0 -0
  72. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/builders/project_builder.py +0 -0
  73. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/builders/watcher.py +0 -0
  74. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/cli.py +0 -0
  75. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/code_libraries.py +0 -0
  76. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/command_context.py +0 -0
  77. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/__init__.py +0 -0
  78. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/add_cmd.py +0 -0
  79. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/build_cmd.py +0 -0
  80. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/connect_cmd.py +0 -0
  81. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/default_cmd.py +0 -0
  82. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/dependency_prompt.py +0 -0
  83. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/desktop_cmd.py +0 -0
  84. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/dev_cmd.py +0 -0
  85. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/doctor_cmd.py +0 -0
  86. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/edit_cmd.py +0 -0
  87. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/engine_cmd.py +0 -0
  88. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/init_cmd.py +0 -0
  89. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/mod_cmd.py +0 -0
  90. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/modsdk_cmd.py +0 -0
  91. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/package_cmd.py +0 -0
  92. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/publish_cmd.py +0 -0
  93. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/record_cmd.py +0 -0
  94. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/remove_cmd.py +0 -0
  95. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/run_cmd.py +0 -0
  96. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/runtime_cmd.py +0 -0
  97. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/runtime_input_cmd.py +0 -0
  98. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/runtime_player_cmd.py +0 -0
  99. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/runtime_ui_cmd.py +0 -0
  100. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/serve_cmd.py +0 -0
  101. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/session_cmd.py +0 -0
  102. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/sync_cmd.py +0 -0
  103. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/ui_cmd.py +0 -0
  104. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/config.py +0 -0
  105. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/custom_packaging.py +0 -0
  106. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/dependencies.py +0 -0
  107. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/engines/__init__.py +0 -0
  108. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/engines/apk_profile.py +0 -0
  109. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/engines/backend.py +0 -0
  110. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/engines/host.py +0 -0
  111. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/engines/official.py +0 -0
  112. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/engines/preferences.py +0 -0
  113. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/engines/tui.py +0 -0
  114. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/engines/windows.py +0 -0
  115. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/framework_presets.py +0 -0
  116. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/frameworks.py +0 -0
  117. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/git_cache.py +0 -0
  118. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/git_projects.py +0 -0
  119. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/input_executor.py +0 -0
  120. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/input_plan.py +0 -0
  121. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/SimpleMonitor.py +0 -0
  122. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/__init__.py +0 -0
  123. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/bridge_assets.py +0 -0
  124. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/bridge_payload/publisher.cer +0 -0
  125. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/diagnostics.py +0 -0
  126. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/discovery.py +0 -0
  127. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/editor.py +0 -0
  128. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/file_logs.py +0 -0
  129. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/game.py +0 -0
  130. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/host_input.py +0 -0
  131. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/hot_reload.py +0 -0
  132. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/input_sequence.py +0 -0
  133. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/launcher_python.py +0 -0
  134. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/log_colorizer.py +0 -0
  135. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/log_protocol.py +0 -0
  136. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/mcs.py +0 -0
  137. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/mcs_auth.py +0 -0
  138. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/network.py +0 -0
  139. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/private_logs.py +0 -0
  140. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/processes.py +0 -0
  141. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/recording_worker.py +0 -0
  142. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/recordings.py +0 -0
  143. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/runtime_cppconfig.py +0 -0
  144. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/runtime_debug.py +0 -0
  145. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/runtime_input_payload.py +0 -0
  146. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/runtime_key_timeline_payload.py +0 -0
  147. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/runtime_player_payload.py +0 -0
  148. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/runtime_ui.py +0 -0
  149. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/runtime_ui_outline.py +0 -0
  150. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/runtime_ui_payload.py +0 -0
  151. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/session_capabilities.py +0 -0
  152. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/session_worker.py +0 -0
  153. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/sessions.py +0 -0
  154. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/studio_server.py +0 -0
  155. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/symlink_helper_global.py +0 -0
  156. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/symlink_helper_map.py +0 -0
  157. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/symlinks.py +0 -0
  158. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/unified_input.py +0 -0
  159. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/window.py +0 -0
  160. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/minecraft/__init__.py +0 -0
  161. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/minecraft/addons.py +0 -0
  162. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/minecraft/level_dat.py +0 -0
  163. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/minecraft/map.py +0 -0
  164. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/minecraft/netease_modsdk.py +0 -0
  165. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/minecraft/template/generate_mod_files.py +0 -0
  166. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/project_dependencies.py +0 -0
  167. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/project_init.py +0 -0
  168. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/recording_io.py +0 -0
  169. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/remote/__init__.py +0 -0
  170. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/remote/client.py +0 -0
  171. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/remote/http_server.py +0 -0
  172. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/remote/service.py +0 -0
  173. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/source_files.py +0 -0
  174. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/timeline.py +0 -0
  175. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/ui/__init__.py +0 -0
  176. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/ui/engine_setup.py +0 -0
  177. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/ui/log_view.py +0 -0
  178. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/ui/session_controller.py +0 -0
  179. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/ui/session_tools.py +0 -0
  180. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/ui/session_views.py +0 -0
  181. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/ui/world_config.py +0 -0
  182. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/utils/__init__.py +0 -0
  183. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/utils/pip_error_parser.py +0 -0
  184. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/utils/print_guide.py +0 -0
  185. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/utils/project_setup.py +0 -0
  186. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/utils/utils.py +0 -0
  187. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap.egg-info/dependency_links.txt +0 -0
  188. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap.egg-info/entry_points.txt +0 -0
  189. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap.egg-info/requires.txt +0 -0
  190. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap.egg-info/top_level.txt +0 -0
  191. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/native/mcs_auth/Bridge.cs +0 -0
  192. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/native/mcs_auth/Injector.cs +0 -0
  193. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/native/mcs_auth/Loader.c +0 -0
  194. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/native/mcs_auth/publisher.cer +0 -0
  195. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/native/mcs_auth/publisher.json +0 -0
  196. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/native/runtime_input/launcher-monotonic.patch +0 -0
  197. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/native/runtime_input/steady_clock.h +0 -0
  198. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/native/window_capture/video_capture.h +0 -0
  199. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/native/window_capture/window_capture.cpp +0 -0
  200. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/scripts/build_all_native.py +0 -0
  201. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/scripts/build_mcs_auth_bridge.py +0 -0
  202. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/scripts/build_window_capture.py +0 -0
  203. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/scripts/check_mcs_auth_bridge.py +0 -0
  204. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/scripts/check_window_capture.py +0 -0
  205. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/setup.cfg +0 -0
  206. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/agents/openai.yaml +0 -0
  207. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/references/input-sequence.md +0 -0
  208. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/references/input-writing.md +0 -0
  209. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/references/instance-world-settings.md +0 -0
  210. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/references/local-development.md +0 -0
  211. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/references/project-dependencies.md +0 -0
  212. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/references/remote-testing.md +0 -0
  213. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/references/runtime-key-timeline.md +0 -0
  214. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/references/runtime-player.md +0 -0
  215. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/references/runtime-ui.md +0 -0
  216. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/references/troubleshooting.md +0 -0
  217. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/scripts/bootstrap.ps1 +0 -0
  218. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/scripts/bootstrap.py +0 -0
  219. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/scripts/game_window.py +0 -0
  220. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/scripts/smoke.py +0 -0
  221. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual/runtime_controls/README.md +0 -0
  222. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual/runtime_controls/client_probe.py +0 -0
  223. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual/runtime_controls/input_probe.py +0 -0
  224. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual/runtime_controls/key_timeline_probe.py +0 -0
  225. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual/runtime_controls/movement.json +0 -0
  226. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual/runtime_controls/run.py +0 -0
  227. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual/runtime_controls/server_fixture.py +0 -0
  228. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual/runtime_controls/support.py +0 -0
  229. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual_dependency_boundaries.py +0 -0
  230. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual_input_window.py +0 -0
  231. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual_integration.py +0 -0
  232. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual_native_recording.py +0 -0
  233. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual_remote_recording.py +0 -0
  234. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual_runtime_input.py +0 -0
  235. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual_runtime_key_timeline.py +0 -0
  236. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual_runtime_player.py +0 -0
  237. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual_runtime_ui.py +0 -0
  238. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_auth_interaction.py +0 -0
  239. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_automation.py +0 -0
  240. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_build_replace_retry.py +0 -0
  241. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_code_libraries.py +0 -0
  242. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_dependency_boundaries.py +0 -0
  243. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_engine_backends.py +0 -0
  244. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_engine_compatibility.py +0 -0
  245. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_engine_discovery.py +0 -0
  246. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_engine_install.py +0 -0
  247. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_game_window_skill.py +0 -0
  248. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_git_projects.py +0 -0
  249. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_host_input.py +0 -0
  250. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_input_sequence.py +0 -0
  251. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_launch_encoding.py +0 -0
  252. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_launcher_python.py +0 -0
  253. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_local_auth_session.py +0 -0
  254. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_local_dependencies.py +0 -0
  255. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_macos_network.py +0 -0
  256. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_manual_runtime_controls.py +0 -0
  257. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_mcs_auth.py +0 -0
  258. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_mouse.py +0 -0
  259. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_native_input_sequence.py +0 -0
  260. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_native_preferences.py +0 -0
  261. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_native_recording.py +0 -0
  262. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_network.py +0 -0
  263. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_network_sessions.py +0 -0
  264. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_pack_uuid_conflicts.py +0 -0
  265. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_package.py +0 -0
  266. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_qt_sessions.py +0 -0
  267. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_qumod_workflow.py +0 -0
  268. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_recordings.py +0 -0
  269. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_remote.py +0 -0
  270. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_remote_scripts.py +0 -0
  271. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_resource_reload.py +0 -0
  272. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_runtime_debug.py +0 -0
  273. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_runtime_input.py +0 -0
  274. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_runtime_key_timeline.py +0 -0
  275. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_runtime_player.py +0 -0
  276. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_runtime_ui.py +0 -0
  277. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_runtime_ui_outline.py +0 -0
  278. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_session_capabilities.py +0 -0
  279. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_shared_logs.py +0 -0
  280. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_skill_workflows.py +0 -0
  281. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_unified_skill_contract.py +0 -0
  282. {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_window_focus.py +0 -0
@@ -1,5 +1,17 @@
1
1
  # 更新记录
2
2
 
3
+ ## 0.4.6
4
+
5
+ - macOS 默认安装配套原生运行包 0.4.4,补齐游戏内 Python 2 单调时钟接口,修复统一输入返回 `missing_monotonic_clock`、键盘及玩家/UI 计划无法执行的问题。
6
+ - 补齐原生浮点接口的结构识别规则与回归测试;不使用 CPU 时间、系统日期或游戏帧数作为替代时钟,未知结构仍明确禁用对应能力。
7
+ - 实机验收覆盖计时、重叠移动跳跃、组合键取消释放、移动中攻击、聊天开关和带修饰键的 UI 点击;改进 macOS 冷启动等待、测试角色复位和瞄准目标确认。
8
+ - 已安装旧资源的用户需显式执行 `mcpy --local engine install --catalog https://github.com/EaseCation/mcpelauncher-manifest/releases/download/mcpy-runtime-v0.4.4/catalog.json`,然后使用 `run --new` 创建实例。升级 CLI 不修改旧世界的运行包绑定。
9
+
10
+ ## 0.4.5
11
+
12
+ - macOS 自动从已校验的开发者 APK 解析游戏图标,转换为多尺寸 ICNS,并用于本地签名的运行副本;保留原始运行包完整性与签名,已有安装可从匹配缓存补全。
13
+ - mcpy 管理界面、调试浮窗与辅助窗口统一应用图标;采用 Icon Composer 27 分层源和 Apple 渲染器生成圆角、反射及高光,提供带 Dock 留白的静态 PNG/ICNS。
14
+
3
15
  ## 0.4.4
4
16
 
5
17
  - 修复 Windows 与 macOS 之间同步 Git 依赖时的源码校验失败:获取源码时禁用宿主 Git 的换行、编码与过滤转换,统一保留固定提交中的文件字节。
@@ -1,4 +1,6 @@
1
1
  include LICENSE README.md CHANGELOG.md
2
+ recursive-include mcpywrap/ui/assets *.svg *.png *.icns *.json
3
+ include scripts/build_app_icon.py
2
4
  include docs/releasing.md
3
5
  include docs/runtime-debug.md
4
6
  include docs/runtime-ui.md docs/runtime-player.md
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcpywrap
3
- Version: 0.4.4
3
+ Version: 0.4.6
4
4
  Summary: A wrapper for Minecraft China Edition Addons management
5
5
  Author-email: boybook <boybook@easecation.net>
6
6
  License-Expression: MIT
@@ -219,7 +219,7 @@ Agent通过CLI管理项目和操作游戏。0.4.2起只有一条日常输入流
219
219
 
220
220
  严禁业务代码依赖mcpy.*:这些方法只存在于临时注入的调试会话。默认backend=game;原始设备测试显式设置windows-sendinput。旧player/ui、key/mouse/input-sequence入口仍兼容,但从默认帮助隐藏。
221
221
 
222
- 时间规划中at_ms可省略,按前一步计划结束加delay_ms编译;真正的实际停顿用wait。Mac旧运行包缺单调时钟时新计划明确不支持,不自动切后端或回退CPU时间。
222
+ 时间规划中at_ms可省略,按前一步计划结束加delay_ms编译;真正的实际停顿用wait。macOS运行包0.4.4补齐单调时钟,CLI 0.4.6默认指向该版本;已有资源须[显式升级并新建实例](skills/mcpywrap/references/macos-local.md#统一输入时钟修复cli-046--运行包-044)。旧包仍明确不支持,不自动切后端或回退CPU时间。
223
223
 
224
224
  常用入口:`mcpy --project <目录> --non-interactive <命令> --json`。
225
225
 
@@ -191,7 +191,7 @@ Agent通过CLI管理项目和操作游戏。0.4.2起只有一条日常输入流
191
191
 
192
192
  严禁业务代码依赖mcpy.*:这些方法只存在于临时注入的调试会话。默认backend=game;原始设备测试显式设置windows-sendinput。旧player/ui、key/mouse/input-sequence入口仍兼容,但从默认帮助隐藏。
193
193
 
194
- 时间规划中at_ms可省略,按前一步计划结束加delay_ms编译;真正的实际停顿用wait。Mac旧运行包缺单调时钟时新计划明确不支持,不自动切后端或回退CPU时间。
194
+ 时间规划中at_ms可省略,按前一步计划结束加delay_ms编译;真正的实际停顿用wait。macOS运行包0.4.4补齐单调时钟,CLI 0.4.6默认指向该版本;已有资源须[显式升级并新建实例](skills/mcpywrap/references/macos-local.md#统一输入时钟修复cli-046--运行包-044)。旧包仍明确不支持,不自动切后端或回退CPU时间。
195
195
 
196
196
  常用入口:`mcpy --project <目录> --non-interactive <命令> --json`。
197
197
 
@@ -36,3 +36,11 @@ smoke.py 的 --client-file/--server-file 通过同一 CLI 等待世界/HUD、分
36
36
  两端单人实例共用 cppconfig 的 world_info;存储、启动转换、保存优先级和创建参数见[实例世界设置](instance-world-settings.md)。
37
37
 
38
38
  版本发现使用 `mcpy --local engine check-updates --json`:实时查询网易 pe/pe_old,返回真实完整版本和 URL;不得递增版本号或猜测 CDN 路径。该命令只检查,不下载或替换实例。新版本 compatibility=not_checked 需实际 APK 校验与结构兼容检查,不能把“发现版本”当作“可运行”。无需先执行此命令:首次 run 的自动安装已经查询 pe。已有本地版本/实例继续运行;缺失的旧版本若不在官方频道中则不可下载,不猜 CDN 路径。
39
+
40
+ ## macOS 游戏图标
41
+
42
+ 安装 APK 时读取 `AndroidManifest.xml` 中 `application/android:icon` 的资源引用,再通过 `resources.arsc` 解析别名和多分辨率变体,选择最大的可解码位图。图标仅来自用户本机已校验的官方 APK,不随 Python wheel 或原生发行包分发。支持 PNG/WebP/JPEG 位图;自适应 XML 存在同资源位图变体时使用该变体,仅有 XML/矢量图时提示暂不支持,不猜用通知或登录图标。
43
+
44
+ 转换结果在每个引擎的 `game` 同级 `icons` 目录保存为透明 PNG 与多尺寸 ICNS(16–1024 像素及 Retina 表示),记录 APK 摘要、资源路径、原始尺寸与输出摘要。保留宽高比和透明度;放大不会增加原始图像细节。已有安装在下一次启动时可从匹配的 APK 缓存自动补全,不需要重装游戏。缓存已删除时可执行 `mcpy engine install --apk <匹配的原 APK>`;缺少图标不会阻止游戏启动。
45
+
46
+ 游戏启动前,在安装锁内按原生运行包和图标摘要创建 `runtimes/<id>/applications/<摘要>/Minecraft China.app` 本地副本,设置中文应用名、`CFBundleIconFile`,重新进行 ad-hoc 签名并验证。之后复用副本,每次启动检查签名。原始运行包的文件、发行完整性清单和签名不变;本地副本只用于实际游戏进程,实例固定的原生运行版本、游戏资源、数据目录和控制协议仍保持原绑定。图标转换或签名失败时向 stderr 记录原因,继续使用原始运行包。无需 Xcode、Android SDK、Pillow 或重新编译原生启动器。
@@ -52,3 +52,18 @@ mcpy 自身继续使用 MIT;GUI 改为 PySide6-Essentials 和 Shiboken6,选
52
52
  后台结果通过显式 Slot 更新主线程界面,发行声明随 wheel 携带于 THIRD_PARTY_NOTICES.md。
53
53
 
54
54
  交互式 run 的调试小窗复用 SessionController/SessionLogWindow,不启动第二套日志服务。置顶使用原生 QCheckBox,随系统主题显示;关闭小窗只隐藏视图,游戏退出后清理控制器和监控。Ctrl+C 与“保存退出”调用同一停止接口。
55
+
56
+ ## 应用图标
57
+
58
+ GUI 入口共用 `ui.application.create_application`:Qt 应用名与菜单显示名为 mcpy,管理页、日志小窗、模板和登录提示使用同一图标。Qt 的应用级图标也交给 Cocoa 用于 Dock。直接运行 Python 时,LaunchServices 仍可能把进程名称缓存为 Python;设置 Qt 显示名不等同于已安装独立 mcpy.app。已打开的小窗需要重新启动后应用新图标。
59
+
60
+ 图标源为 `mcpywrap/ui/assets/mcpy.icon`,是可由 Icon Composer 27 编辑的分层文档:深蓝背景、薄荷绿方块、白色命令提示符。背景满幅不透明,前景 SVG 未预裁切;命令提示符保留不透明,以确保小尺寸对比度。不把 Minecraft 游戏图标用作 mcpy 品牌图标。
61
+
62
+ 设计依据 Apple [App icons HIG](https://developer.apple.com/design/human-interface-guidelines/app-icons)(2026-06-08 更新)和 [Icon Composer 文档](https://developer.apple.com/documentation/xcode/creating-your-app-icon-using-icon-composer):
63
+
64
+ - 1024×1024 画布、sRGB;圆角遮罩、高光、边缘反射和层间阴影由 Apple 渲染器生成,不自行用固定半径模拟系统连续圆角。
65
+ - 方块范围 x=248–776、y=224–816,主要内容距离未裁切画布边缘至少 208 px。此数值是本设计的留白选择,HIG 并未规定统一的 macOS 安全区百分比。
66
+ - 分层源背景不预留透明外框。导出给传统 Qt/ICNS 的静态图标时,参考 actool 的 macOS 兼容输出,在 1024 画布内将系统渲染图形放入 824×824 区域,四周留 100 px 透明区,防止 Dock 中图标显得过大。分层源与静态兼容文件的留白不能混用。
67
+ - 图标已用 Icon Composer 27 渲染,并通过 Xcode 27 actool 编译。保留 `.icon` 原始分层素材,PNG 和 ICNS 则用于当前 Qt 应用;静态资源不具备随光照变化的动态 Liquid Glass,也不会自动切换 dark/clear/tinted 外观。将来独立打包 mcpy.app 时可接入编译后的 Assets.car,不能仅给 PNG 加反光就宣称支持全部动态外观。
68
+
69
+ 维护者运行 `python scripts/build_app_icon.py` 重建 PNG 和 ICNS,需要本机 Xcode 27 / Icon Composer 27 与 PySide6;运行时无需 Xcode。ICNS 提供 16、32、128、256、512 点的 1×/2× 图像。wheel 包含静态图标和可编辑分层源。
@@ -10,6 +10,6 @@ Agent 的推荐入口是 `runtime input observe → run → status/cancel`;公
10
10
 
11
11
  Windows适配在会话worker中保留状态与幂等历史,单个调度线程推进操作;远程input端点只传参数。统一游戏控制层预留防止新旧游戏写请求插入设备计划;已持有的系统键或修饰键拒绝接管。未知释放保持busy,支持stop重试,不扩大为多请求共享输入。
12
12
 
13
- 原生Mac时钟primitive和启动器源码补丁在 `native/runtime_input`。旧运行包缺少经过确认的Python单调时钟时,能力明确关闭;实际Apple Silicon的二进制结构规则、编译和实机验收必须单独完成,不以Windows测试代替。原始pointer/text尚未验证的游戏后端能力保持不支持。
13
+ 原生Mac时钟primitive和配套启动器/结构规则补丁在 `native/runtime_input`。CLI 0.4.6 默认指向运行包 0.4.4,提供 `launcher.steady_clock`;已在 Apple Silicon / macOS 26.6.2 / 开发包 3.9.100.297020 通过 8 项实机用例,3.10.100.299889 通过结构识别检查。旧运行包仍返回 `missing_monotonic_clock`,需显式升级资源并新建实例;原始pointer/text缺能力时保持不支持。
14
14
 
15
15
  验证采用假时钟检查时序、调用顺序、部分失败、取消、幂等和快照;可选实机脚本覆盖真实客户端与服务端读回。旧入口不改变其修饰键排序、时间原点或输入后端;仅从默认发现入口隐藏,兼容参考保留。
@@ -1,4 +1,4 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """mcpywrap - 我的世界中国版 Addon 开发依赖、构建与游戏测试工具。"""
3
3
 
4
- __version__ = '0.4.4'
4
+ __version__ = '0.4.6'
@@ -0,0 +1,186 @@
1
+ """Read an APK's declared launcher icon, without an Android SDK or filename guesses.
2
+
3
+ Prefer the largest raster variant of application/@android:icon. Adaptive XML
4
+ is not a bitmap: use its legacy variant when present, otherwise report that it
5
+ cannot be converted. No unrelated notification/login artwork is substituted.
6
+ """
7
+ import struct
8
+ from xml.etree import ElementTree
9
+
10
+ ANDROID = 'http://schemas.android.com/apk/res/android'
11
+
12
+
13
+ def _u16(data, offset):
14
+ return struct.unpack_from('<H', data, offset)[0]
15
+
16
+
17
+ def _u32(data, offset):
18
+ return struct.unpack_from('<I', data, offset)[0]
19
+
20
+
21
+ def _chunks(data, start, end):
22
+ while start < end:
23
+ kind, header, size = struct.unpack_from('<HHI', data, start)
24
+ if header < 8 or size < header or start + size > end:
25
+ raise ValueError('Invalid Android resource chunk')
26
+ yield kind, header, data[start:start + size]
27
+ start += size
28
+
29
+
30
+ def _strings(data):
31
+ header = _u16(data, 2)
32
+ count, flags, start = _u32(data, 8), _u32(data, 16), _u32(data, 20)
33
+ if header + count * 4 > len(data):
34
+ raise ValueError('Invalid Android string pool')
35
+ utf8 = bool(flags & 0x100)
36
+
37
+ def length(pos):
38
+ value = data[pos] if utf8 else _u16(data, pos)
39
+ width, mask = (1, 0x80) if utf8 else (2, 0x8000)
40
+ if value & mask:
41
+ low = data[pos + width] if utf8 else _u16(data, pos + width)
42
+ return ((value & (mask - 1)) << (width * 8)) | low, pos + width * 2
43
+ return value, pos + width
44
+
45
+ result = []
46
+ for index in range(count):
47
+ pos = start + _u32(data, header + index * 4)
48
+ if pos < start or pos >= len(data):
49
+ raise ValueError('Invalid Android string offset')
50
+ size, pos = length(pos)
51
+ if utf8:
52
+ size, pos = length(pos)
53
+ end = pos + size * (1 if utf8 else 2)
54
+ if end > len(data):
55
+ raise ValueError('Invalid Android string extent')
56
+ result.append(data[pos:end].decode('utf-8' if utf8 else 'utf-16-le'))
57
+ return result
58
+
59
+
60
+ def manifest_icon(data):
61
+ if data.lstrip().startswith(b'<'):
62
+ application = ElementTree.fromstring(data).find('application')
63
+ value = application.get('{%s}icon' % ANDROID) if application is not None else None
64
+ if value and value.startswith('@0x'):
65
+ return int(value[1:], 16)
66
+ return value
67
+ if _u16(data, 0) != 3 or _u32(data, 4) != len(data):
68
+ raise ValueError('Invalid Android manifest')
69
+ strings = []
70
+ for kind, header, chunk in _chunks(data, _u16(data, 2), len(data)):
71
+ if kind == 1:
72
+ strings = _strings(chunk)
73
+ elif kind == 0x102 and strings[_u32(chunk, header + 4)] == 'application':
74
+ offset, width, count = struct.unpack_from('<HHH', chunk, header + 8)
75
+ if width < 20 or header + offset + width * count > len(chunk):
76
+ raise ValueError('Invalid manifest attributes')
77
+ for index in range(count):
78
+ at = header + offset + index * width
79
+ namespace, name = _u32(chunk, at), _u32(chunk, at + 4)
80
+ if namespace != 0xffffffff and strings[namespace] == ANDROID and strings[name] == 'icon':
81
+ kind, value = chunk[at + 15], _u32(chunk, at + 16)
82
+ if kind == 1:
83
+ return value
84
+ if kind == 3:
85
+ return strings[value]
86
+ return None
87
+
88
+
89
+ def resource_values(data, resource):
90
+ """Resolve simple resource references across configurations, including aliases."""
91
+ if _u16(data, 0) != 2 or _u32(data, 4) != len(data):
92
+ raise ValueError('Invalid Android resource table')
93
+ global_strings, packages = [], []
94
+ for kind, header, chunk in _chunks(data, _u16(data, 2), len(data)):
95
+ if kind == 1:
96
+ global_strings = _strings(chunk)
97
+ elif kind == 0x200:
98
+ packages.append((header, chunk))
99
+
100
+ def resolve(identity, seen):
101
+ if identity in seen or len(seen) > 16:
102
+ return []
103
+ seen = seen | {identity}
104
+ values = []
105
+ for header, package in packages:
106
+ if _u32(package, 8) != identity >> 24:
107
+ continue
108
+ type_offset = _u32(package, 284) if header >= 288 else 0
109
+ for kind, size, chunk in _chunks(package, header, len(package)):
110
+ if kind != 0x201 or chunk[8] + type_offset != (identity >> 16) & 255:
111
+ continue
112
+ count, start, index = _u32(chunk, 12), _u32(chunk, 16), identity & 0xffff
113
+ flags = chunk[9]
114
+ if start < size or start > len(chunk):
115
+ raise ValueError('Invalid Android entries')
116
+ if flags & 1: # Sparse (entry index, offset / 4) pairs.
117
+ if size + count * 4 > start:
118
+ raise ValueError('Invalid sparse entries')
119
+ offsets = dict(struct.unpack_from('<HH', chunk, size + i * 4) for i in range(count))
120
+ offset = offsets.get(index)
121
+ if offset is None:
122
+ continue
123
+ offset *= 4
124
+ else:
125
+ width = 2 if flags & 2 else 4
126
+ if size + count * width > start:
127
+ raise ValueError('Invalid entry offsets')
128
+ if index >= count:
129
+ continue
130
+ offset = (_u16 if width == 2 else _u32)(chunk, size + index * width)
131
+ if offset == (0xffff if width == 2 else 0xffffffff):
132
+ continue
133
+ if width == 2:
134
+ offset *= 4
135
+ at = start + offset
136
+ entry_size, entry_flags = struct.unpack_from('<HH', chunk, at)
137
+ if entry_flags & 1: # Complex/bag entry.
138
+ continue
139
+ if entry_flags & 8: # Compact entry packs type into flags, value into key.
140
+ value_kind, value = entry_flags >> 8, _u32(chunk, at + 4)
141
+ else:
142
+ if entry_size < 8 or at + entry_size + 8 > len(chunk):
143
+ raise ValueError('Invalid resource value')
144
+ value_kind, value = chunk[at + entry_size + 3], _u32(chunk, at + entry_size + 4)
145
+ if value_kind == 3:
146
+ values.append(global_strings[value])
147
+ elif value_kind == 1:
148
+ values.extend(resolve(value, seen))
149
+ return values
150
+
151
+ return resolve(resource, set())
152
+
153
+
154
+ def read_icon(archive):
155
+ from PySide6.QtGui import QImageReader
156
+ from PySide6.QtCore import QBuffer, QByteArray, QIODevice
157
+
158
+ def read(name, limit):
159
+ info = archive.getinfo(name)
160
+ if info.file_size > limit:
161
+ raise ValueError('Android icon resource is too large')
162
+ return archive.read(info)
163
+
164
+ icon = manifest_icon(read('AndroidManifest.xml', 4 * 1024**2))
165
+ if not icon:
166
+ raise ValueError('APK application does not declare an icon')
167
+ paths = resource_values(read('resources.arsc', 32 * 1024**2), icon) if isinstance(icon, int) else [icon]
168
+ candidates = []
169
+ for path in set(paths):
170
+ if not path.startswith('res/') or not path.lower().endswith(('.png', '.webp', '.jpg', '.jpeg')):
171
+ continue
172
+ raw = read(path, 16 * 1024**2)
173
+ buffer = QBuffer()
174
+ buffer.setData(QByteArray(raw))
175
+ buffer.open(QIODevice.OpenModeFlag.ReadOnly)
176
+ reader = QImageReader(buffer)
177
+ size = reader.size()
178
+ if size.width() <= 0 or size.height() <= 0 or max(size.width(), size.height()) > 4096:
179
+ continue
180
+ image = reader.read()
181
+ if not image.isNull():
182
+ candidates.append((image.width() * image.height(), path, image))
183
+ if not candidates:
184
+ raise ValueError('APK icon has no supported raster variant (adaptive/vector XML is not a bitmap)')
185
+ _, path, image = max(candidates, key=lambda row: (row[0], row[1]))
186
+ return path, image
@@ -24,7 +24,7 @@ from .host import EngineError, describe, require_macos
24
24
 
25
25
  CATALOG_ENV = 'MCPY_RUNTIME_CATALOG'
26
26
  DEFAULT_CATALOG = ('https://github.com/EaseCation/mcpelauncher-manifest/releases/download/'
27
- 'mcpy-runtime-v0.4.3/catalog.json')
27
+ 'mcpy-runtime-v0.4.4/catalog.json')
28
28
  # Public constant from the official ApkDownload component, verified 2026-10-05.
29
29
  # https://mcdev.webapp.163.com/static/js/4.05713153ba17aea6db53.js
30
30
  CDN_CONSTANT = 'mEE7Cot48r9j2AvEL2N6jpXEc'
@@ -630,6 +630,7 @@ def install(location=None, apk=None, progress=None):
630
630
  finally:
631
631
  if stage.exists(): shutil.rmtree(stage)
632
632
  apk_meta = profile['apk']
633
+ apk_path = None
633
634
  if apk:
634
635
  apk_path = Path(apk).expanduser().resolve()
635
636
  if apk_path.stat().st_size != apk_meta['size'] or digest(apk_path) != apk_meta['sha256']:
@@ -651,6 +652,9 @@ def install(location=None, apk=None, progress=None):
651
652
  _replace(stage, game)
652
653
  finally:
653
654
  if stage.exists(): shutil.rmtree(stage)
655
+ from .macos_icons import optional_icons
656
+ _phase(progress, '准备游戏图标')
657
+ optional_icons(game, profile, apk_path)
654
658
  _phase(progress, '检查运行兼容性')
655
659
  metadata = verify_runtime(destination/'McpyRuntime.app', destination/'McpyRuntime.integrity.json', profile)
656
660
  preflight_runtime(destination/'McpyRuntime.app', game, profile, metadata, runtime['id'])
@@ -64,7 +64,9 @@ def pinned_runtime(item):
64
64
  raise EngineError('当前系统低于此实例的最低 macOS 要求', 'os_too_old')
65
65
  install.verify_game(game, plan['profile'])
66
66
  compatibility = install.preflight_runtime(app, game, plan['profile'], meta, plan['runtime_id'])
67
- return {'runtime': str(app), 'game': str(game), 'profile': plan['profile'], 'runtime_id': plan['runtime_id'],
67
+ from .macos_icons import optional_runtime_application
68
+ application = optional_runtime_application(app, game)
69
+ return {'runtime': str(app), 'application': str(application), 'game': str(game), 'profile': plan['profile'], 'runtime_id': plan['runtime_id'],
68
70
  'compat_report': compatibility, 'cppconfig_protocol': meta.get('cppconfig_protocol'),
69
71
  'network_connect_protocol': meta.get('network_connect_protocol')}
70
72
 
@@ -167,6 +169,7 @@ def run(project, *, new=False, listing=False, delete=None, clean_all=False, forc
167
169
  finally:
168
170
  if stage.exists(): shutil.rmtree(stage)
169
171
  plan = {'runtime': state['runtime'], 'game': state['game'], 'data': str(directory/'data'),
172
+ 'application': state.get('application'),
170
173
  'cache': str(directory/'cache'), 'engine_version': version,
171
174
  'compat_report': state.get('compat_report')}
172
175
  config_path = Path(item['config_path'])
@@ -210,7 +213,8 @@ def launch_session(data):
210
213
  helper = app/'Contents/Resources/launcher/run_netease_dev.py'
211
214
  if not helper.is_file():
212
215
  raise EngineError('运行包缺少启动适配器,请重新安装。', 'runtime_incompatible')
213
- command = [sys.executable, str(helper), '--runtime', str(app), '--game-dir', plan['game'],
216
+ display_app = plan.get('application') or app
217
+ command = [sys.executable, str(helper), '--runtime', str(display_app), '--game-dir', plan['game'],
214
218
  '--data-dir', plan['data'], '--cache-dir', plan['cache'], '--angle-backend', 'metal',
215
219
  '--debug-loopback', '--exec-client', '--log', data['engine_log_path']]
216
220
  if plan.get('cppconfig'):
@@ -0,0 +1,159 @@
1
+ """Local APK artwork and signed, disposable app copies; release files stay immutable."""
2
+ from pathlib import Path
3
+ import plistlib
4
+ import shutil
5
+ import struct
6
+ import subprocess
7
+ import tempfile
8
+ import zipfile
9
+ import zlib
10
+ from xml.etree.ElementTree import ParseError
11
+
12
+ from . import install
13
+
14
+ SCHEMA = 1
15
+
16
+
17
+ def _png(image):
18
+ from PySide6.QtCore import QBuffer, QIODevice
19
+ buffer = QBuffer()
20
+ buffer.open(QIODevice.OpenModeFlag.WriteOnly)
21
+ if not image.save(buffer, 'PNG'):
22
+ raise ValueError('Could not encode application icon')
23
+ return bytes(buffer.data())
24
+
25
+
26
+ def write_icons(image, directory):
27
+ """Encode RGBA PNG representations at macOS point/Retina sizes in an ICNS."""
28
+ from PySide6.QtCore import Qt
29
+ from PySide6.QtGui import QImage, QPainter
30
+ directory = Path(directory)
31
+ directory.mkdir(parents=True, exist_ok=True)
32
+ canvas = QImage(1024, 1024, QImage.Format.Format_ARGB32)
33
+ canvas.fill(Qt.GlobalColor.transparent)
34
+ scaled = image.scaled(1024, 1024, Qt.AspectRatioMode.KeepAspectRatio,
35
+ Qt.TransformationMode.SmoothTransformation)
36
+ painter = QPainter(canvas)
37
+ painter.drawImage((1024 - scaled.width()) // 2, (1024 - scaled.height()) // 2, scaled)
38
+ painter.end()
39
+ (directory/'game.png').write_bytes(_png(canvas))
40
+ chunks = []
41
+ for tag, size in ((b'icp4', 16), (b'icp5', 32), (b'icp6', 64), (b'ic07', 128),
42
+ (b'ic08', 256), (b'ic09', 512), (b'ic10', 1024),
43
+ (b'ic11', 32), (b'ic12', 64), (b'ic13', 256), (b'ic14', 512)):
44
+ raw = _png(canvas.scaled(size, size, Qt.AspectRatioMode.IgnoreAspectRatio,
45
+ Qt.TransformationMode.SmoothTransformation))
46
+ chunks.append(tag + struct.pack('>I', len(raw) + 8) + raw)
47
+ payload = b''.join(chunks)
48
+ (directory/'game.icns').write_bytes(b'icns' + struct.pack('>I', len(payload) + 8) + payload)
49
+
50
+
51
+ def _valid_icons(directory, profile):
52
+ try:
53
+ receipt = install.read_json(directory/'icon.json')
54
+ return (receipt['schema'] == SCHEMA and receipt['apk_sha256'] == profile['apk']['sha256']
55
+ and all(install.digest(directory/name) == receipt['files'][name]
56
+ for name in ('game.png', 'game.icns')))
57
+ except (OSError, ValueError, KeyError, TypeError):
58
+ return False
59
+
60
+
61
+ def prepare_icons(game, profile, apk=None):
62
+ """Migrate existing installs using a matching cache, without another download."""
63
+ from .android_icon import read_icon
64
+ game = Path(game)
65
+ directory = game.parent/'icons'
66
+ if _valid_icons(directory, profile):
67
+ return directory
68
+ source = Path(apk) if apk else install.home()/'cache'/profile['apk']['filename']
69
+ if not source.is_file():
70
+ raise ValueError('找不到匹配 APK;可用 mcpy engine install --apk <原 APK> 补全游戏图标')
71
+ if source.stat().st_size != profile['apk']['size'] or install.digest(source) != profile['apk']['sha256']:
72
+ raise ValueError('图标来源 APK 摘要不匹配')
73
+ game.parent.mkdir(parents=True, exist_ok=True)
74
+ stage = Path(tempfile.mkdtemp(prefix='.icons-', dir=game.parent))
75
+ try:
76
+ with zipfile.ZipFile(source) as archive:
77
+ resource, image = read_icon(archive)
78
+ write_icons(image, stage)
79
+ install.write_json(stage/'icon.json', {
80
+ 'schema': SCHEMA, 'apk_sha256': profile['apk']['sha256'], 'resource': resource,
81
+ 'source_size': [image.width(), image.height()],
82
+ 'files': {name: install.digest(stage/name) for name in ('game.png', 'game.icns')}})
83
+ install._replace(stage, directory)
84
+ finally:
85
+ if stage.exists():
86
+ shutil.rmtree(stage)
87
+ return directory
88
+
89
+
90
+ def _codesign(*arguments):
91
+ result = subprocess.run(['/usr/bin/codesign', *map(str, arguments)], capture_output=True, timeout=60)
92
+ if result.returncode:
93
+ raise ValueError('本地图标运行包签名失败:' + result.stderr.decode('utf-8', 'replace')[:1000])
94
+
95
+
96
+ def runtime_application(app, game):
97
+ """Build once per verified runtime/icon. Caller holds the engine install lock."""
98
+ app, game = Path(app), Path(game)
99
+ profile = install.read_json(game/'installed.json')['profile']
100
+ icons = prepare_icons(game, profile)
101
+ identity = {'schema': SCHEMA, 'runtime': install.digest(app.parent/'McpyRuntime.integrity.json'),
102
+ 'icon': install.digest(icons/'game.icns')}
103
+ import hashlib
104
+ import json
105
+ key = hashlib.sha256(json.dumps(identity, sort_keys=True).encode()).hexdigest()
106
+ destination = app.parent/'applications'/key
107
+ name = 'Minecraft China.app'
108
+ derived = destination/name
109
+ try:
110
+ if install.read_json(destination/'application.json') == identity:
111
+ _codesign('--verify', '--deep', '--strict', derived)
112
+ return derived
113
+ except (OSError, ValueError, subprocess.SubprocessError):
114
+ pass
115
+ if destination.exists():
116
+ install._require_idle(destination)
117
+ destination.parent.mkdir(parents=True, exist_ok=True)
118
+ stage = Path(tempfile.mkdtemp(prefix='.application-', dir=destination.parent))
119
+ try:
120
+ target = stage/name
121
+ shutil.copytree(app, target)
122
+ shutil.copy2(icons/'game.icns', target/'Contents/Resources/game.icns')
123
+ plist = target/'Contents/Info.plist'
124
+ info = plistlib.loads(plist.read_bytes())
125
+ info.update(CFBundleName='我的世界中国版', CFBundleDisplayName='我的世界中国版',
126
+ CFBundleIconFile='game.icns', CFBundleIdentifier='net.easecation.mcpy.game.' + key[:16])
127
+ plist.write_bytes(plistlib.dumps(info))
128
+ _codesign('--force', '--sign', '-', '--preserve-metadata=entitlements,flags', '--timestamp=none', target)
129
+ _codesign('--verify', '--deep', '--strict', target)
130
+ install.write_json(stage/'application.json', identity)
131
+ install._replace(stage, destination)
132
+ finally:
133
+ if stage.exists():
134
+ shutil.rmtree(stage)
135
+ return derived
136
+
137
+
138
+ def warn_icon(error):
139
+ # Called by both JSON CLI and workers; warnings must never contaminate stdout.
140
+ import sys
141
+ print('游戏图标暂未应用:' + str(error), file=sys.stderr, flush=True)
142
+
143
+
144
+ def optional_icons(game, profile, apk=None):
145
+ try:
146
+ return prepare_icons(game, profile, apk)
147
+ except (OSError, ValueError, KeyError, IndexError, struct.error, zipfile.BadZipFile,
148
+ zlib.error, ParseError, ImportError) as error:
149
+ warn_icon(error)
150
+ return None
151
+
152
+
153
+ def optional_runtime_application(app, game):
154
+ try:
155
+ return runtime_application(app, game)
156
+ except (OSError, ValueError, KeyError, IndexError, struct.error, zipfile.BadZipFile,
157
+ zlib.error, ParseError, ImportError, subprocess.SubprocessError) as error:
158
+ warn_icon(error)
159
+ return Path(app)
@@ -34,6 +34,7 @@ def connect(target, *, project_dir=None, packs=(), engine_overrides=None, detach
34
34
  session = uuid.uuid4().hex
35
35
  directory = sessions.session_path(root, session)
36
36
  plan = {'runtime': state['runtime'], 'game': state['game'],
37
+ 'application': state.get('application'),
37
38
  'data': str(directory/'native/data'), 'cache': str(directory/'native/cache'),
38
39
  'engine_version': version, 'compat_report': state.get('compat_report'),
39
40
  'cppconfig': str(directory/'runtime.cppconfig')}
@@ -49,8 +49,9 @@ ConvertTo-Json -InputObject $items -Compress
49
49
 
50
50
 
51
51
  def confirm_certificate(certificate):
52
- from PySide6.QtWidgets import QApplication, QMessageBox
53
- app = QApplication.instance() or QApplication([])
52
+ from PySide6.QtWidgets import QMessageBox
53
+ from ..ui.application import create_application
54
+ app = create_application()
54
55
  dialog = QMessageBox()
55
56
  dialog.setWindowTitle('启用 MC Studio 登录身份')
56
57
  dialog.setIcon(QMessageBox.Icon.Warning)
@@ -81,6 +82,7 @@ def install_certificate(certificate):
81
82
 
82
83
 
83
84
  def show_failure(message):
84
- from PySide6.QtWidgets import QApplication, QMessageBox
85
- app = QApplication.instance() or QApplication([])
85
+ from PySide6.QtWidgets import QMessageBox
86
+ from ..ui.application import create_application
87
+ app = create_application()
86
88
  QMessageBox.warning(None, '暂时无法使用 MC Studio 登录身份', message)
@@ -11,9 +11,9 @@
11
11
  "Loader.c": "f2f1f781ce82fc30c62a6ce22bb048d3b023f6ff500e6ec8228da28b4dbf1b4a"
12
12
  },
13
13
  "files": {
14
- "Injector.exe": "aa185d69f11e138df90f446c239d075ef6ab4e5c5e0457981a6c09f52e04b7b9",
15
- "Loader.dll": "03956417da34f569dd6e794076f2252ff05cb286fd1a8dc6ce966dc78911330e",
16
- "McpyMcsAuth.dll": "b1270f169319e8acebca7d49be966d54c769590d708157c3984e33f9a943c1d7",
14
+ "Injector.exe": "621284073f4b383c30d25eca393df4d4c979afc5fd8c0fda6f73967845759515",
15
+ "Loader.dll": "471c4ec3d7c3315f1c77c2e7514f818066f6176f79196b996efdff31247bb379",
16
+ "McpyMcsAuth.dll": "a051488fb21310f4934d55bf1e5485ae8e5e209b74299699fde0047de27e4108",
17
17
  "publisher.cer": "e5aa2ac39df40804ed8b08fe8e43c4a2b8923f0d02a360708486b2db5b6303d7"
18
18
  }
19
19
  }
@@ -80,7 +80,8 @@ class StudioLoggerUI(LogWindow):
80
80
 
81
81
 
82
82
  def run_studio_server_ui(host='0.0.0.0', port=8000):
83
- app = QApplication.instance() or QApplication(sys.argv)
83
+ from ..ui.application import create_application
84
+ app = create_application(sys.argv)
84
85
  window = StudioLoggerUI(host, port); window.show()
85
86
  if sys.platform == 'win32': set_windows_dark_titlebar(int(window.winId()))
86
87
  signal.signal(signal.SIGINT, lambda *_: window.close())
@@ -1,5 +1,5 @@
1
1
  {
2
- "executable_sha256": "4f4f8b0a8eae4b8d409ae90e222886623c4b53ed66525d8267ffaadc1db65442",
2
+ "executable_sha256": "059cb625d222865ab52e7689414e3624ec1cdd16e0362840e1621eb09211155c",
3
3
  "source_sha256": "0c0b2a02bfecea68b824a486ac1d88cde6bd9fc8ee8e4c9a6939870bd8e710d1",
4
4
  "sources": {
5
5
  "video_capture.h": "8daee1b8c1c8273bc8d19d39f0559f82c30d7ff900894bcc2cc197d3881532d7",
@@ -107,7 +107,8 @@ def open_ui_crate_mod(behavior_pack_path, run_event_loop=True):
107
107
  Args:
108
108
  behavior_pack_path: 行为包目录的路径
109
109
  """
110
- app = QApplication.instance() or QApplication(sys.argv)
110
+ from ...ui.application import create_application
111
+ app = create_application(sys.argv)
111
112
 
112
113
  # 设置优先使用的中文字体列表
113
114
  preferred_fonts = [