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.
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/CHANGELOG.md +12 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/MANIFEST.in +2 -0
- {mcpywrap-0.4.4/mcpywrap.egg-info → mcpywrap-0.4.6}/PKG-INFO +2 -2
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/README.md +1 -1
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/game-backends.md +8 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/qt6-development.md +15 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/runtime-input.md +1 -1
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/__init__.py +1 -1
- mcpywrap-0.4.6/mcpywrap/engines/android_icon.py +186 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/engines/install.py +5 -1
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/engines/macos.py +6 -2
- mcpywrap-0.4.6/mcpywrap/engines/macos_icons.py +159 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/engines/macos_network.py +1 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/auth_interaction.py +6 -4
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/bridge_payload/Injector.exe +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/bridge_payload/Loader.dll +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/bridge_payload/McpyMcsAuth.dll +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/bridge_payload/manifest.json +3 -3
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/studio_server_ui.py +2 -1
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/window_capture/manifest.json +1 -1
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/window_capture/mcpy-window-capture.exe +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/minecraft/template/mod_template.py +2 -1
- mcpywrap-0.4.6/mcpywrap/ui/application.py +58 -0
- mcpywrap-0.4.6/mcpywrap/ui/assets/mcpy.icns +0 -0
- mcpywrap-0.4.6/mcpywrap/ui/assets/mcpy.icon/Assets/01-cube.svg +5 -0
- mcpywrap-0.4.6/mcpywrap/ui/assets/mcpy.icon/Assets/02-prompt.svg +4 -0
- mcpywrap-0.4.6/mcpywrap/ui/assets/mcpy.icon/icon.json +56 -0
- mcpywrap-0.4.6/mcpywrap/ui/assets/mcpy.png +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/ui/log_window.py +2 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/ui/project_ui.py +4 -3
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/ui/run_session.py +2 -2
- {mcpywrap-0.4.4 → mcpywrap-0.4.6/mcpywrap.egg-info}/PKG-INFO +2 -2
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap.egg-info/SOURCES.txt +11 -0
- mcpywrap-0.4.6/native/runtime_input/README.md +33 -0
- mcpywrap-0.4.6/native/runtime_input/manifest-monotonic.patch +147 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/pyproject.toml +2 -1
- mcpywrap-0.4.6/scripts/build_app_icon.py +55 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/scripts/check_release.py +15 -2
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/SKILL.md +2 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/references/macos-local.md +17 -1
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/references/runtime-input.md +1 -1
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual_runtime_input_unified.py +75 -9
- mcpywrap-0.4.6/tests/test_application_icons.py +176 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_instance_cppconfig.py +3 -0
- mcpywrap-0.4.4/native/runtime_input/README.md +0 -11
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/LICENSE +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/THIRD_PARTY_NOTICES.md +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/code-libraries.md +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/development.md +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/engine-discovery.md +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/git-dependencies.md +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/input-sequence.md +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/launcher-client-python.md +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/local-dependencies.md +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/macos-resource-reload.md +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/mcs-auth.md +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/qumod.md +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/release-0.4.0.md +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/release-readiness-0.4.0.md +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/releasing.md +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/runtime-debug.md +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/runtime-player.md +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/runtime-ui.md +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/docs/shared-log-ui.md +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/__main__.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/builders/AddonsPack.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/builders/MapPack.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/builders/__init__.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/builders/assembly.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/builders/dependency_manager.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/builders/file_merge.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/builders/project_builder.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/builders/watcher.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/cli.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/code_libraries.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/command_context.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/__init__.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/add_cmd.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/build_cmd.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/connect_cmd.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/default_cmd.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/dependency_prompt.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/desktop_cmd.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/dev_cmd.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/doctor_cmd.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/edit_cmd.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/engine_cmd.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/init_cmd.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/mod_cmd.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/modsdk_cmd.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/package_cmd.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/publish_cmd.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/record_cmd.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/remove_cmd.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/run_cmd.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/runtime_cmd.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/runtime_input_cmd.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/runtime_player_cmd.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/runtime_ui_cmd.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/serve_cmd.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/session_cmd.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/sync_cmd.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/commands/ui_cmd.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/config.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/custom_packaging.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/dependencies.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/engines/__init__.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/engines/apk_profile.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/engines/backend.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/engines/host.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/engines/official.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/engines/preferences.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/engines/tui.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/engines/windows.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/framework_presets.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/frameworks.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/git_cache.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/git_projects.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/input_executor.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/input_plan.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/SimpleMonitor.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/__init__.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/bridge_assets.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/bridge_payload/publisher.cer +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/diagnostics.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/discovery.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/editor.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/file_logs.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/game.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/host_input.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/hot_reload.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/input_sequence.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/launcher_python.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/log_colorizer.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/log_protocol.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/mcs.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/mcs_auth.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/network.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/private_logs.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/processes.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/recording_worker.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/recordings.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/runtime_cppconfig.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/runtime_debug.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/runtime_input_payload.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/runtime_key_timeline_payload.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/runtime_player_payload.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/runtime_ui.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/runtime_ui_outline.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/runtime_ui_payload.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/session_capabilities.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/session_worker.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/sessions.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/studio_server.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/symlink_helper_global.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/symlink_helper_map.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/symlinks.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/unified_input.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/mcstudio/window.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/minecraft/__init__.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/minecraft/addons.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/minecraft/level_dat.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/minecraft/map.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/minecraft/netease_modsdk.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/minecraft/template/generate_mod_files.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/project_dependencies.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/project_init.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/recording_io.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/remote/__init__.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/remote/client.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/remote/http_server.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/remote/service.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/source_files.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/timeline.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/ui/__init__.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/ui/engine_setup.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/ui/log_view.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/ui/session_controller.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/ui/session_tools.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/ui/session_views.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/ui/world_config.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/utils/__init__.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/utils/pip_error_parser.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/utils/print_guide.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/utils/project_setup.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap/utils/utils.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap.egg-info/dependency_links.txt +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap.egg-info/entry_points.txt +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap.egg-info/requires.txt +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/mcpywrap.egg-info/top_level.txt +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/native/mcs_auth/Bridge.cs +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/native/mcs_auth/Injector.cs +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/native/mcs_auth/Loader.c +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/native/mcs_auth/publisher.cer +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/native/mcs_auth/publisher.json +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/native/runtime_input/launcher-monotonic.patch +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/native/runtime_input/steady_clock.h +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/native/window_capture/video_capture.h +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/native/window_capture/window_capture.cpp +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/scripts/build_all_native.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/scripts/build_mcs_auth_bridge.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/scripts/build_window_capture.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/scripts/check_mcs_auth_bridge.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/scripts/check_window_capture.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/setup.cfg +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/agents/openai.yaml +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/references/input-sequence.md +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/references/input-writing.md +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/references/instance-world-settings.md +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/references/local-development.md +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/references/project-dependencies.md +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/references/remote-testing.md +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/references/runtime-key-timeline.md +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/references/runtime-player.md +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/references/runtime-ui.md +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/references/troubleshooting.md +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/scripts/bootstrap.ps1 +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/scripts/bootstrap.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/scripts/game_window.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/skills/mcpywrap/scripts/smoke.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual/runtime_controls/README.md +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual/runtime_controls/client_probe.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual/runtime_controls/input_probe.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual/runtime_controls/key_timeline_probe.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual/runtime_controls/movement.json +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual/runtime_controls/run.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual/runtime_controls/server_fixture.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual/runtime_controls/support.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual_dependency_boundaries.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual_input_window.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual_integration.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual_native_recording.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual_remote_recording.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual_runtime_input.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual_runtime_key_timeline.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual_runtime_player.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/manual_runtime_ui.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_auth_interaction.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_automation.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_build_replace_retry.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_code_libraries.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_dependency_boundaries.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_engine_backends.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_engine_compatibility.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_engine_discovery.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_engine_install.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_game_window_skill.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_git_projects.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_host_input.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_input_sequence.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_launch_encoding.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_launcher_python.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_local_auth_session.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_local_dependencies.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_macos_network.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_manual_runtime_controls.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_mcs_auth.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_mouse.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_native_input_sequence.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_native_preferences.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_native_recording.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_network.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_network_sessions.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_pack_uuid_conflicts.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_package.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_qt_sessions.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_qumod_workflow.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_recordings.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_remote.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_remote_scripts.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_resource_reload.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_runtime_debug.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_runtime_input.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_runtime_key_timeline.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_runtime_player.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_runtime_ui.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_runtime_ui_outline.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_session_capabilities.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_shared_logs.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_skill_workflows.py +0 -0
- {mcpywrap-0.4.4 → mcpywrap-0.4.6}/tests/test_unified_skill_contract.py +0 -0
- {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,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mcpywrap
|
|
3
|
-
Version: 0.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。
|
|
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。
|
|
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
|
|
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
|
验证采用假时钟检查时序、调用顺序、部分失败、取消、幂等和快照;可选实机脚本覆盖真实客户端与服务端读回。旧入口不改变其修饰键排序、时间原点或输入后端;仅从默认发现入口隐藏,兼容参考保留。
|
|
@@ -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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
53
|
-
|
|
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
|
|
85
|
-
|
|
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)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
"Loader.c": "f2f1f781ce82fc30c62a6ce22bb048d3b023f6ff500e6ec8228da28b4dbf1b4a"
|
|
12
12
|
},
|
|
13
13
|
"files": {
|
|
14
|
-
"Injector.exe": "
|
|
15
|
-
"Loader.dll": "
|
|
16
|
-
"McpyMcsAuth.dll": "
|
|
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
|
-
|
|
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": "
|
|
2
|
+
"executable_sha256": "059cb625d222865ab52e7689414e3624ec1cdd16e0362840e1621eb09211155c",
|
|
3
3
|
"source_sha256": "0c0b2a02bfecea68b824a486ac1d88cde6bd9fc8ee8e4c9a6939870bd8e710d1",
|
|
4
4
|
"sources": {
|
|
5
5
|
"video_capture.h": "8daee1b8c1c8273bc8d19d39f0559f82c30d7ff900894bcc2cc197d3881532d7",
|
|
Binary file
|
|
@@ -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
|
-
|
|
110
|
+
from ...ui.application import create_application
|
|
111
|
+
app = create_application(sys.argv)
|
|
111
112
|
|
|
112
113
|
# 设置优先使用的中文字体列表
|
|
113
114
|
preferred_fonts = [
|