mcpywrap 0.4.2__tar.gz → 0.4.4__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.2 → mcpywrap-0.4.4}/CHANGELOG.md +15 -0
- {mcpywrap-0.4.2/mcpywrap.egg-info → mcpywrap-0.4.4}/PKG-INFO +1 -1
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/docs/game-backends.md +1 -1
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/docs/git-dependencies.md +3 -3
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/__init__.py +1 -1
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/code_libraries.py +11 -7
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/commands/connect_cmd.py +11 -2
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/commands/sync_cmd.py +2 -6
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/engines/install.py +1 -1
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/engines/macos.py +30 -6
- mcpywrap-0.4.4/mcpywrap/engines/macos_network.py +47 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/engines/tui.py +4 -2
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/engines/windows.py +22 -16
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/git_cache.py +8 -1
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/git_projects.py +14 -44
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/bridge_payload/Injector.exe +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/bridge_payload/Loader.dll +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/bridge_payload/McpyMcsAuth.dll +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/bridge_payload/manifest.json +3 -3
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/runtime_debug.py +4 -2
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/session_worker.py +2 -2
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/sessions.py +1 -1
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/window_capture/manifest.json +1 -1
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/window_capture/mcpy-window-capture.exe +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/minecraft/template/mod_template.py +2 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/source_files.py +4 -1
- {mcpywrap-0.4.2 → mcpywrap-0.4.4/mcpywrap.egg-info}/PKG-INFO +1 -1
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap.egg-info/SOURCES.txt +2 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/pyproject.toml +1 -1
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/skills/mcpywrap/SKILL.md +5 -2
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/skills/mcpywrap/references/macos-local.md +26 -1
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/skills/mcpywrap/references/project-dependencies.md +2 -1
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_code_libraries.py +20 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_engine_backends.py +22 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_git_projects.py +105 -69
- mcpywrap-0.4.4/tests/test_macos_network.py +120 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_qt_sessions.py +5 -1
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/LICENSE +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/MANIFEST.in +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/README.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/THIRD_PARTY_NOTICES.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/docs/code-libraries.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/docs/development.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/docs/engine-discovery.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/docs/input-sequence.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/docs/launcher-client-python.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/docs/local-dependencies.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/docs/macos-resource-reload.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/docs/mcs-auth.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/docs/qt6-development.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/docs/qumod.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/docs/release-0.4.0.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/docs/release-readiness-0.4.0.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/docs/releasing.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/docs/runtime-debug.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/docs/runtime-input.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/docs/runtime-player.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/docs/runtime-ui.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/docs/shared-log-ui.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/__main__.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/builders/AddonsPack.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/builders/MapPack.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/builders/__init__.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/builders/assembly.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/builders/dependency_manager.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/builders/file_merge.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/builders/project_builder.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/builders/watcher.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/cli.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/command_context.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/commands/__init__.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/commands/add_cmd.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/commands/build_cmd.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/commands/default_cmd.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/commands/dependency_prompt.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/commands/desktop_cmd.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/commands/dev_cmd.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/commands/doctor_cmd.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/commands/edit_cmd.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/commands/engine_cmd.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/commands/init_cmd.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/commands/mod_cmd.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/commands/modsdk_cmd.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/commands/package_cmd.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/commands/publish_cmd.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/commands/record_cmd.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/commands/remove_cmd.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/commands/run_cmd.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/commands/runtime_cmd.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/commands/runtime_input_cmd.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/commands/runtime_player_cmd.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/commands/runtime_ui_cmd.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/commands/serve_cmd.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/commands/session_cmd.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/commands/ui_cmd.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/config.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/custom_packaging.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/dependencies.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/engines/__init__.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/engines/apk_profile.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/engines/backend.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/engines/host.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/engines/official.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/engines/preferences.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/framework_presets.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/frameworks.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/input_executor.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/input_plan.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/SimpleMonitor.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/__init__.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/auth_interaction.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/bridge_assets.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/bridge_payload/publisher.cer +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/diagnostics.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/discovery.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/editor.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/file_logs.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/game.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/host_input.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/hot_reload.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/input_sequence.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/launcher_python.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/log_colorizer.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/log_protocol.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/mcs.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/mcs_auth.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/network.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/private_logs.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/processes.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/recording_worker.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/recordings.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/runtime_cppconfig.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/runtime_input_payload.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/runtime_key_timeline_payload.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/runtime_player_payload.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/runtime_ui.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/runtime_ui_outline.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/runtime_ui_payload.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/session_capabilities.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/studio_server.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/studio_server_ui.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/symlink_helper_global.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/symlink_helper_map.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/symlinks.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/unified_input.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/mcstudio/window.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/minecraft/__init__.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/minecraft/addons.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/minecraft/level_dat.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/minecraft/map.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/minecraft/netease_modsdk.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/minecraft/template/generate_mod_files.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/project_dependencies.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/project_init.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/recording_io.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/remote/__init__.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/remote/client.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/remote/http_server.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/remote/service.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/timeline.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/ui/__init__.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/ui/engine_setup.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/ui/log_view.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/ui/log_window.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/ui/project_ui.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/ui/run_session.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/ui/session_controller.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/ui/session_tools.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/ui/session_views.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/ui/world_config.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/utils/__init__.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/utils/pip_error_parser.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/utils/print_guide.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/utils/project_setup.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap/utils/utils.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap.egg-info/dependency_links.txt +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap.egg-info/entry_points.txt +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap.egg-info/requires.txt +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/mcpywrap.egg-info/top_level.txt +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/native/mcs_auth/Bridge.cs +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/native/mcs_auth/Injector.cs +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/native/mcs_auth/Loader.c +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/native/mcs_auth/publisher.cer +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/native/mcs_auth/publisher.json +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/native/runtime_input/README.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/native/runtime_input/launcher-monotonic.patch +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/native/runtime_input/steady_clock.h +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/native/window_capture/video_capture.h +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/native/window_capture/window_capture.cpp +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/scripts/build_all_native.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/scripts/build_mcs_auth_bridge.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/scripts/build_window_capture.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/scripts/check_mcs_auth_bridge.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/scripts/check_release.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/scripts/check_window_capture.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/setup.cfg +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/skills/mcpywrap/agents/openai.yaml +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/skills/mcpywrap/references/input-sequence.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/skills/mcpywrap/references/input-writing.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/skills/mcpywrap/references/instance-world-settings.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/skills/mcpywrap/references/local-development.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/skills/mcpywrap/references/remote-testing.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/skills/mcpywrap/references/runtime-input.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/skills/mcpywrap/references/runtime-key-timeline.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/skills/mcpywrap/references/runtime-player.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/skills/mcpywrap/references/runtime-ui.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/skills/mcpywrap/references/troubleshooting.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/skills/mcpywrap/scripts/bootstrap.ps1 +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/skills/mcpywrap/scripts/bootstrap.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/skills/mcpywrap/scripts/game_window.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/skills/mcpywrap/scripts/smoke.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/manual/runtime_controls/README.md +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/manual/runtime_controls/client_probe.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/manual/runtime_controls/input_probe.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/manual/runtime_controls/key_timeline_probe.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/manual/runtime_controls/movement.json +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/manual/runtime_controls/run.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/manual/runtime_controls/server_fixture.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/manual/runtime_controls/support.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/manual_dependency_boundaries.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/manual_input_window.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/manual_integration.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/manual_native_recording.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/manual_remote_recording.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/manual_runtime_input.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/manual_runtime_input_unified.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/manual_runtime_key_timeline.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/manual_runtime_player.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/manual_runtime_ui.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_auth_interaction.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_automation.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_build_replace_retry.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_dependency_boundaries.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_engine_compatibility.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_engine_discovery.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_engine_install.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_game_window_skill.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_host_input.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_input_sequence.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_instance_cppconfig.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_launch_encoding.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_launcher_python.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_local_auth_session.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_local_dependencies.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_manual_runtime_controls.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_mcs_auth.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_mouse.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_native_input_sequence.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_native_preferences.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_native_recording.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_network.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_network_sessions.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_pack_uuid_conflicts.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_package.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_qumod_workflow.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_recordings.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_remote.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_remote_scripts.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_resource_reload.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_runtime_debug.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_runtime_input.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_runtime_key_timeline.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_runtime_player.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_runtime_ui.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_runtime_ui_outline.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_session_capabilities.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_shared_logs.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_skill_workflows.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_unified_skill_contract.py +0 -0
- {mcpywrap-0.4.2 → mcpywrap-0.4.4}/tests/test_window_focus.py +0 -0
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# 更新记录
|
|
2
2
|
|
|
3
|
+
## 0.4.4
|
|
4
|
+
|
|
5
|
+
- 修复 Windows 与 macOS 之间同步 Git 依赖时的源码校验失败:获取源码时禁用宿主 Git 的换行、编码与过滤转换,统一保留固定提交中的文件字节。
|
|
6
|
+
- `mcpy sync` 按固定提交直接重新计算 lock 摘要,不改变依赖版本,不再创建锁备份或执行专门迁移;未被修改的旧安装副本自动重建,缓存损坏与手动修改仍会报错。
|
|
7
|
+
- Git 项目依赖和旧代码库使用独立的新源码缓存,首次同步重新获取固定提交,后续可离线复用。补充跨 Git 配置、旧 Windows 缓存、二进制文件与重复同步稳定性的回归测试。
|
|
8
|
+
- Windows 启动时增加原生 HUD 布局日志识别,避免 Python 启动日志异常导致世界就绪状态无法确认。
|
|
9
|
+
- 修复 Mod 模板窗口关闭后未释放对象、在新版 PySide6 下退出进程时可能崩溃的问题。
|
|
10
|
+
|
|
11
|
+
## 0.4.3
|
|
12
|
+
|
|
13
|
+
- macOS 新增无认证服务器连接,复用 `mcpy connect` 与项目 `[tool.mcpywrap.server]` 的 `run` 入口、cppconfig、日志、偏好和退出机制,不装配本地 Mod 或创建本地世界实例。
|
|
14
|
+
- 配套 macOS 运行包 0.4.3 使用现有引擎 Python 入口进服,无新增游戏二进制补丁;首次安装自动取得配套运行包,旧包给出明确升级命令,保留已有世界绑定。
|
|
15
|
+
- 网络会话仅开放客户端 Python;在 worker 中拒绝服务端 Python 和本地 Mod 热更。macOS 初次连接超时会提示失败并回收游戏,进入 HUD 后记录连接验证结果。
|
|
16
|
+
- Skill 补充离线服务器条件、旧运行包升级、状态验证及客户端调试边界。已在 macOS 26.6.2 / APK 3.10.100.299889 上通过本机 Nemisys + SynapseAPI + Nukkit 验证 connect、项目 run、Python 与失败清理;不包含 MCS/MPay 登录、外部 HTTP 资源包或新版统一输入的验收。
|
|
17
|
+
|
|
3
18
|
## 0.4.2
|
|
4
19
|
|
|
5
20
|
- 新增统一 `runtime input capabilities/observe/run/status/cancel/stop` 与 `mcpy.input`。键盘组合、独立边沿、玩家与单节点 UI 操作共用 JSON steps、动作注册表、排时和清理;单次 key 快捷命令只生成同一份计划。
|
|
@@ -19,7 +19,7 @@ WindowsBackend 调用原有 MC Studio 发现、cppconfig 和 Safaia 流程,保
|
|
|
19
19
|
|
|
20
20
|
macOS 首次 mcpy run 自动从内置发布源安装原生运行包和官方 APK,进度在 stderr;也可提前执行 mcpy engine install。--catalog / --apk 是高级覆盖选项。交互式 run 显示共用调试小窗,ui 打开完整管理页;--no-gui / --detach / --json / --non-interactive 抑制调试小窗;Windows 保持手动安装 MC Studio。默认资源目录 ~/Library/Application Support/mcpy,可设置 MCPY_ENGINE_HOME、MCPY_RUNTIME_CATALOG。
|
|
21
21
|
|
|
22
|
-
macOS
|
|
22
|
+
macOS 支持离线 Addon 世界;无认证服务器连接需 CLI 0.4.3+ 与运行包 0.4.3+ 配套,运行包须声明 network_connect_protocol=1(旧 0.4.0 运行包需要显式升级)。connect 与配置了 server 的 run 共用 cppconfig、会话、日志及退出;网络会话仅支持客户端调试,不装配本地 Mod。macOS 不支持 Map、MCS 登录或 Windows 桌面截图/键鼠/录像;需要这些能力时显式使用 Windows 远程端。最低 macOS 13.0,实际游戏只在 26.6.2 验证。运行包尚为 ad-hoc 签名、公证待完成。
|
|
23
23
|
|
|
24
24
|
图形界面的会话操作集中在 ui/session_controller.py;主界面和小窗仅使用共用 SessionControls/PythonConsole 与 LogView。小窗不再另起 Studio TCP 接收器,详见 [共用日志界面](shared-log-ui.md)。
|
|
25
25
|
|
|
@@ -76,11 +76,11 @@ Python的project.dependencies继续表示工具Python依赖,不变成游戏代
|
|
|
76
76
|
|
|
77
77
|
两端提交并使用同一份 `mcpy-git.lock.json`,无需维护平台分支。锁定的是 Git 提交、源码和依赖关系;本机安装目录位于 `.mcpy/`,不提交到 Git。当前依赖都是游戏源码,没有需要分别锁定的 Windows/macOS 原生包。
|
|
78
78
|
|
|
79
|
-
v2 锁使用相同的大小写敏感路径排序;源码由 Git archive
|
|
79
|
+
v2 锁使用相同的大小写敏感路径排序;源码由 Git archive 提取,禁用宿主 Git 的换行、编码、ident 和 filter 转换及全局 attributes,保留提交中的文件字节(包括二进制和原本的 CRLF)。工具生成的文件统一使用 LF。新机器或克隆项目后运行一次 `mcpy sync`,随后正常 `mcpy run`。
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
`mcpy sync` 依据声明中固定的完整 Git 提交重新计算源码和安装内容摘要,直接写回锁文件;不更新依赖版本、不创建备份或执行专门的锁迁移。旧 v1/v2 锁都可通过一次 sync 刷新。新快照使用独立的 `git-archive-v2` 缓存,首次同步会重新获取固定提交,之后可离线复用;旧缓存不参与新摘要计算。已安装副本与旧锁一致时可重建,手动改动或缓存损坏仍会报错。`build/package/run` 继续严格验证锁文件,不隐式重算。
|
|
82
82
|
|
|
83
|
-
终端只显示同步进度、结果和必要操作;`mcpy sync --json`
|
|
83
|
+
终端只显示同步进度、结果和必要操作;`mcpy sync --json` 返回结构化结果。`--migrate-windows-lock` 和 JSON 中始终为空的 `git_lock_migrations` 仅保留旧脚本兼容。团队各设备应使用包含此修复的版本,并提交 sync 更新后的锁文件。
|
|
84
84
|
|
|
85
85
|
## 验证范围
|
|
86
86
|
|
|
@@ -64,9 +64,6 @@ def prepare_sync(root, config=None):
|
|
|
64
64
|
for entry in entries:
|
|
65
65
|
key = identity(entry)
|
|
66
66
|
installed = cache / key
|
|
67
|
-
if installed.is_dir() and key in expected and expected[key] in (digest(installed), windows_checkout_digest(installed, crlf=False)):
|
|
68
|
-
lock['libraries'].append({'declaration': entry, 'sha256': digest(installed)})
|
|
69
|
-
continue
|
|
70
67
|
# 临时仓库不检出文件、不运行依赖代码、hooks 或安装脚本。
|
|
71
68
|
with tempfile.TemporaryDirectory(prefix='fetch-', dir=cache) as temporary:
|
|
72
69
|
temp = Path(temporary)
|
|
@@ -83,12 +80,19 @@ def prepare_sync(root, config=None):
|
|
|
83
80
|
(content / ('MCPY_UPSTREAM_' + file.name)).write_bytes(file.read_bytes())
|
|
84
81
|
validate_game_files(root, [content])
|
|
85
82
|
value = digest(content)
|
|
86
|
-
if key in expected and expected[key] not in (value, windows_checkout_digest(content, crlf=False)):
|
|
87
|
-
raise DependencyError('固定提交的代码库内容与锁文件摘要不符')
|
|
88
83
|
if installed.exists():
|
|
89
|
-
#
|
|
84
|
+
# Rebuild unchanged old installations from canonical source.
|
|
90
85
|
if digest(installed) != value:
|
|
91
|
-
|
|
86
|
+
if key not in expected or expected[key] not in (
|
|
87
|
+
digest(installed), windows_checkout_digest(installed, crlf=False)):
|
|
88
|
+
raise DependencyError(f'代码库缓存已损坏,请移走后重新 sync: {installed}')
|
|
89
|
+
old = temp / 'old'
|
|
90
|
+
os.replace(installed, old)
|
|
91
|
+
try:
|
|
92
|
+
os.replace(content, installed)
|
|
93
|
+
except BaseException:
|
|
94
|
+
os.replace(old, installed)
|
|
95
|
+
raise
|
|
92
96
|
else:
|
|
93
97
|
os.replace(content, installed)
|
|
94
98
|
lock['libraries'].append({'declaration': entry, 'sha256': value})
|
|
@@ -22,5 +22,14 @@ def connect_cmd(host, port, mcs_auth=False, detach=False, request_id=None, **eng
|
|
|
22
22
|
if request_id:
|
|
23
23
|
raise click.UsageError('--request-id 仅用于远程启动')
|
|
24
24
|
from ..engines.backend import get_backend
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
from ..engines.host import EngineError
|
|
26
|
+
backend = get_backend()
|
|
27
|
+
target = ServerTarget(host, port, 'mcs' if mcs_auth else 'none')
|
|
28
|
+
try:
|
|
29
|
+
return backend.connect(target, engine_overrides=engine_overrides, detach=detach)
|
|
30
|
+
except EngineError as error:
|
|
31
|
+
if error.code != 'setup_required' or not backend.managed_install: raise
|
|
32
|
+
from .engine_cmd import perform_install
|
|
33
|
+
click.echo('首次运行:自动下载并准备本地游戏环境…', err=True)
|
|
34
|
+
perform_install()
|
|
35
|
+
return backend.connect(target, engine_overrides=engine_overrides, detach=detach)
|
|
@@ -19,8 +19,6 @@ def sync_cmd(install, migrate_windows_lock=False):
|
|
|
19
19
|
result = sync_project(project_dir(), install, migrate_windows_lock=migrate_windows_lock)
|
|
20
20
|
if json_output():
|
|
21
21
|
return result
|
|
22
|
-
if result['git_lock_migrations']:
|
|
23
|
-
click.echo('已更新跨平台依赖记录,旧文件已备份。')
|
|
24
22
|
count = result['git_projects'] + result['code_libraries']
|
|
25
23
|
click.secho('完成 · %d 个源码依赖已就绪 · %.1fs' % (count, time.monotonic()-started), fg='green')
|
|
26
24
|
if install:
|
|
@@ -38,7 +36,6 @@ def sync_project(path, install=False, migrate_windows_lock=False):
|
|
|
38
36
|
from ..builders.dependency_manager import DependencyManager
|
|
39
37
|
visited, active = set(), set()
|
|
40
38
|
git_count = 0
|
|
41
|
-
migrations = []
|
|
42
39
|
def sync_sources(directory):
|
|
43
40
|
nonlocal git_count
|
|
44
41
|
key = canonical_path(directory)
|
|
@@ -57,8 +54,7 @@ def sync_project(path, install=False, migrate_windows_lock=False):
|
|
|
57
54
|
if target and 'mcpywrap' in read_project(target).get('tool', {}):
|
|
58
55
|
sync_sources(target)
|
|
59
56
|
if git_declarations(directory, source_config) or Path(directory, GIT_LOCK_FILE).exists():
|
|
60
|
-
git_count += sync_projects(directory, source_config
|
|
61
|
-
migration_report=migrations)
|
|
57
|
+
git_count += sync_projects(directory, source_config)
|
|
62
58
|
active.remove(key)
|
|
63
59
|
visited.add(key)
|
|
64
60
|
sync_sources(path)
|
|
@@ -78,4 +74,4 @@ def sync_project(path, install=False, migrate_windows_lock=False):
|
|
|
78
74
|
if proc.returncode:
|
|
79
75
|
raise click.ClickException(proc.stderr or proc.stdout or '项目安装失败')
|
|
80
76
|
return {'project': str(path), 'installed': install, 'code_libraries': library_count,
|
|
81
|
-
'git_projects': git_count, 'git_lock_migrations':
|
|
77
|
+
'git_projects': git_count, 'git_lock_migrations': []}
|
|
@@ -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.3/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'
|
|
@@ -65,7 +65,8 @@ def pinned_runtime(item):
|
|
|
65
65
|
install.verify_game(game, plan['profile'])
|
|
66
66
|
compatibility = install.preflight_runtime(app, game, plan['profile'], meta, plan['runtime_id'])
|
|
67
67
|
return {'runtime': str(app), 'game': str(game), 'profile': plan['profile'], 'runtime_id': plan['runtime_id'],
|
|
68
|
-
'compat_report': compatibility, 'cppconfig_protocol': meta.get('cppconfig_protocol')
|
|
68
|
+
'compat_report': compatibility, 'cppconfig_protocol': meta.get('cppconfig_protocol'),
|
|
69
|
+
'network_connect_protocol': meta.get('network_connect_protocol')}
|
|
69
70
|
|
|
70
71
|
|
|
71
72
|
def run(project, *, new=False, listing=False, delete=None, clean_all=False, force=False,
|
|
@@ -85,9 +86,15 @@ def run(project, *, new=False, listing=False, delete=None, clean_all=False, forc
|
|
|
85
86
|
raise EngineError('MC Studio 身份、EXE 和下载目录参数仅适用于 Windows。', 'unsupported_option',
|
|
86
87
|
'macOS 当前使用开发者 APK 的离线模式;资源由 mcpy engine 管理。')
|
|
87
88
|
config = read_project(project)
|
|
88
|
-
if
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
if not (listing or delete or clean_all):
|
|
90
|
+
from ..mcstudio.network import configured_target, prepare_project
|
|
91
|
+
target = configured_target(config)
|
|
92
|
+
if target is not None:
|
|
93
|
+
if new or instance_prefix or world_config is not None:
|
|
94
|
+
raise click.UsageError('网络模式不支持 --new 或本地世界实例 ID')
|
|
95
|
+
packs = prepare_project(project, config)
|
|
96
|
+
from .macos_network import connect
|
|
97
|
+
return connect(target, project_dir=project, packs=packs, engine_overrides=overrides, detach=detach)
|
|
91
98
|
if config.get('tool', {}).get('mcpywrap', {}).get('project_type', 'addon') != 'addon':
|
|
92
99
|
raise EngineError('macOS 首版支持 Addon 测试,Map 项目尚未接入。', 'unsupported_feature',
|
|
93
100
|
'地图项目请在 Windows 本机运行。')
|
|
@@ -192,6 +199,13 @@ def run(project, *, new=False, listing=False, delete=None, clean_all=False, forc
|
|
|
192
199
|
|
|
193
200
|
def launch_session(data):
|
|
194
201
|
plan = data['launch']
|
|
202
|
+
if data.get('mode') == 'network':
|
|
203
|
+
from types import SimpleNamespace
|
|
204
|
+
from ..mcstudio.network import ServerTarget, unauthenticated_config
|
|
205
|
+
config = unauthenticated_config(
|
|
206
|
+
SimpleNamespace(version=plan['engine_version'], download_dir=plan['game']),
|
|
207
|
+
ServerTarget(**data['network']['target']))
|
|
208
|
+
install.write_json(Path(plan['cppconfig']), config)
|
|
195
209
|
app = Path(plan['runtime'])
|
|
196
210
|
helper = app/'Contents/Resources/launcher/run_netease_dev.py'
|
|
197
211
|
if not helper.is_file():
|
|
@@ -228,7 +242,7 @@ class MacOSBackend(GameBackend):
|
|
|
228
242
|
label = 'macOS · Apple Silicon · Metal'
|
|
229
243
|
capabilities = ('local-worlds', 'macos-local-worlds', 'engine-install', 'macos-engine-install',
|
|
230
244
|
'status', 'logs', 'stop', 'py', 'runtime', 'runtime-ui', 'runtime-player',
|
|
231
|
-
'client-python-requests', 'project-ui', 'reload', 'watch')
|
|
245
|
+
'client-python-requests', 'project-ui', 'reload', 'watch', 'network-sessions')
|
|
232
246
|
managed_install = True
|
|
233
247
|
setup_description = ('在 Apple Silicon Mac 上运行本地 Addon 测试。\n'
|
|
234
248
|
'首次运行会自动下载原生启动器和网易开发者版资源,并在本机完成安装。\n'
|
|
@@ -250,6 +264,10 @@ class MacOSBackend(GameBackend):
|
|
|
250
264
|
options.pop('no_gui', None)
|
|
251
265
|
return run(project, **options)
|
|
252
266
|
|
|
267
|
+
def connect(self, target, **options):
|
|
268
|
+
from .macos_network import connect
|
|
269
|
+
return connect(target, **options)
|
|
270
|
+
|
|
253
271
|
def watch_directory(self, project, data):
|
|
254
272
|
return Path(data['config_path']).parent/'assembled'
|
|
255
273
|
|
|
@@ -380,7 +398,9 @@ else:
|
|
|
380
398
|
request_id = 'startup-' + str(index)
|
|
381
399
|
result = channel._rpc('result', {'request_id': request_id})
|
|
382
400
|
if result.get('request_id') == request_id and result.get('state') in ('failed', 'cancelled'):
|
|
383
|
-
raise EngineError('
|
|
401
|
+
raise EngineError(('服务器连接未完成:' if data.get('mode') == 'network' else '世界启动步骤失败:')
|
|
402
|
+
+ str(result.get('error', result['state'])),
|
|
403
|
+
'connection_failed' if data.get('mode') == 'network' else 'world_start_failed')
|
|
384
404
|
except (OSError, ConnectionError):
|
|
385
405
|
pass
|
|
386
406
|
try:
|
|
@@ -389,9 +409,13 @@ else:
|
|
|
389
409
|
stream.seek(max(0, stream.tell() - 65536))
|
|
390
410
|
if b'"top_screen":"hud_screen"' in stream.read():
|
|
391
411
|
data['world_ready'] = True
|
|
412
|
+
if data.get('mode') == 'network': data['connection_verified'] = True
|
|
392
413
|
return True
|
|
393
414
|
except OSError:
|
|
394
415
|
pass
|
|
416
|
+
if data.get('mode') == 'network' and time.time() - data['created_at'] > 90:
|
|
417
|
+
raise EngineError('90 秒内未进入服务器;请检查地址、端口、协议版本以及服务器是否允许无认证的中国版客户端。',
|
|
418
|
+
'connection_timeout')
|
|
395
419
|
return False
|
|
396
420
|
|
|
397
421
|
def handoff(self, data):
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Anonymous server launch using the shared cppconfig and session lifecycle."""
|
|
2
|
+
from dataclasses import asdict
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
import uuid
|
|
5
|
+
|
|
6
|
+
import click
|
|
7
|
+
from . import install
|
|
8
|
+
from .host import EngineError, require_macos
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def connect(target, *, project_dir=None, packs=(), engine_overrides=None, detach=False):
|
|
12
|
+
from ..command_context import project_dir as current_project, json_output
|
|
13
|
+
from ..mcstudio import sessions
|
|
14
|
+
from ..remote.service import directory_lock
|
|
15
|
+
from .macos import ensure_runtime, pinned_runtime
|
|
16
|
+
require_macos()
|
|
17
|
+
if json_output() and not detach:
|
|
18
|
+
raise click.UsageError('网络运行 --json 需要 --detach;使用 status/logs/stop 管理返回的会话')
|
|
19
|
+
overrides = engine_overrides or {}
|
|
20
|
+
if target.auth != 'none' or overrides.get('game_executable_path') or overrides.get('mcs_download_path'):
|
|
21
|
+
raise EngineError('macOS 服务器连接仅支持无认证模式;MC Studio 身份和 EXE 参数仅适用于 Windows。',
|
|
22
|
+
'unsupported_option')
|
|
23
|
+
root = Path(project_dir or current_project()).resolve()
|
|
24
|
+
with directory_lock(install.home()/'install-lock'):
|
|
25
|
+
state = pinned_runtime({'installation': ensure_runtime()})
|
|
26
|
+
if state.get('network_connect_protocol') != 1:
|
|
27
|
+
raise EngineError('此 macOS 运行包尚不支持连接服务器。', 'runtime_incompatible',
|
|
28
|
+
'请执行 mcpy engine install --catalog ' + install.DEFAULT_CATALOG + ',再重试;已有世界保留原绑定。')
|
|
29
|
+
version = state['profile']['apk']['version']
|
|
30
|
+
requested = overrides.get('engine_version')
|
|
31
|
+
if requested and requested != version:
|
|
32
|
+
raise EngineError('当前资源版本为 ' + version, 'engine_version_mismatch',
|
|
33
|
+
'请使用匹配的资源,或省略 --engine-version。')
|
|
34
|
+
session = uuid.uuid4().hex
|
|
35
|
+
directory = sessions.session_path(root, session)
|
|
36
|
+
plan = {'runtime': state['runtime'], 'game': state['game'],
|
|
37
|
+
'data': str(directory/'native/data'), 'cache': str(directory/'native/cache'),
|
|
38
|
+
'engine_version': version, 'compat_report': state.get('compat_report'),
|
|
39
|
+
'cppconfig': str(directory/'runtime.cppconfig')}
|
|
40
|
+
data = sessions.start(root, backend='macos-arm64', session_id=session, launch=plan,
|
|
41
|
+
network={'target': asdict(target), 'engine': {'version': version}})
|
|
42
|
+
result = sessions.handoff(data)
|
|
43
|
+
if detach:
|
|
44
|
+
return result
|
|
45
|
+
click.echo(f'连接 {target.host}:{target.port}(无认证);不装配本地 Mod。')
|
|
46
|
+
from .tui import watch_session
|
|
47
|
+
return watch_session(root, session)
|
|
@@ -19,10 +19,12 @@ def watch_session(project, session):
|
|
|
19
19
|
backend = get_backend(data.get('backend', 'windows'))
|
|
20
20
|
table = Table.grid(padding=(0, 2))
|
|
21
21
|
table.add_row('平台', backend.label)
|
|
22
|
-
|
|
22
|
+
network = data.get('mode') == 'network'
|
|
23
|
+
table.add_row('状态', ('已进入服务器' if data.get('connection_verified') else '正在连接服务器…')
|
|
24
|
+
if network else ('世界已就绪' if data.get('world_ready') else '引擎已启动,正在准备世界…'))
|
|
23
25
|
table.add_row('会话', session)
|
|
24
26
|
table.add_row('操作', 'Ctrl+C 保存退出;其他终端可使用 logs / runtime py')
|
|
25
|
-
live.update(Panel(table, title='mcpy 本地测试'))
|
|
27
|
+
live.update(Panel(table, title='mcpy 服务器测试' if network else 'mcpy 本地测试'))
|
|
26
28
|
time.sleep(.25)
|
|
27
29
|
except KeyboardInterrupt:
|
|
28
30
|
console.print('正在保存世界并关闭窗口…')
|
|
@@ -13,28 +13,34 @@ class WindowsBackend(GameBackend):
|
|
|
13
13
|
def debug_channel(self, data, write_log):
|
|
14
14
|
from ..mcstudio.runtime_debug import SafaiaChannel
|
|
15
15
|
self._world_ready = data.get('mode') != 'local'
|
|
16
|
-
self.
|
|
16
|
+
self._ready_log_cursors = {}
|
|
17
17
|
if data.get('mode') == 'local': data['world_ready'] = False
|
|
18
18
|
return SafaiaChannel(write_log, ready=lambda: self._world_ready)
|
|
19
19
|
|
|
20
20
|
def refresh(self, data, channel):
|
|
21
21
|
if self._world_ready: return False
|
|
22
22
|
from pathlib import Path
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
23
|
+
import re
|
|
24
|
+
for name in ('log_path', 'engine_log_path'):
|
|
25
|
+
if not data.get(name): continue
|
|
26
|
+
path = Path(data[name])
|
|
27
|
+
offset, pending = self._ready_log_cursors.get(name, (0, b''))
|
|
28
|
+
try:
|
|
29
|
+
with path.open('rb') as stream:
|
|
30
|
+
stream.seek(offset)
|
|
31
|
+
chunk = stream.read(65536)
|
|
32
|
+
offset = stream.tell()
|
|
33
|
+
except FileNotFoundError:
|
|
34
|
+
continue
|
|
35
|
+
text = pending + chunk
|
|
36
|
+
# Both markers require a created gameplay HUD. The native layout
|
|
37
|
+
# marker also works if the Python launch logging handler raises.
|
|
38
|
+
hud = (b'OnHandlePushScreen hud_screen' in text if name == 'log_path' else
|
|
39
|
+
re.search(rb"\bINFO GUI [^\r\n]*\] Layout main thread: [^\r\n]*controls completed [^\r\n]*for screen 'hud\.hud_screen'\.", text))
|
|
40
|
+
self._ready_log_cursors[name] = (offset, text[-1024:])
|
|
41
|
+
if hud:
|
|
42
|
+
self._world_ready = data['world_ready'] = True
|
|
43
|
+
return True
|
|
38
44
|
return False
|
|
39
45
|
|
|
40
46
|
def reload_restriction(self, data, kind):
|
|
@@ -89,7 +89,9 @@ def fetch_snapshot(url, ref):
|
|
|
89
89
|
raise DependencyError('无效Git引用')
|
|
90
90
|
origin = hashlib.sha256(url.encode('utf-8')).hexdigest()
|
|
91
91
|
base = cache_root()
|
|
92
|
-
|
|
92
|
+
# Old archives may contain bytes converted by the host's Git settings.
|
|
93
|
+
# Keep them separate so even a verified old cache cannot reintroduce CRLF.
|
|
94
|
+
snapshots = base / 'git-archive-v2' / origin
|
|
93
95
|
snapshots.mkdir(parents=True, exist_ok=True)
|
|
94
96
|
with _source_lock(base / 'locks' / (origin + '.lock')):
|
|
95
97
|
if re.fullmatch('[0-9a-f]{40}', ref) and (snapshots / ref).exists():
|
|
@@ -99,6 +101,11 @@ def fetch_snapshot(url, ref):
|
|
|
99
101
|
repo, package = stage / 'repo', stage / 'snapshot'
|
|
100
102
|
content = package / 'content'
|
|
101
103
|
_git('init', '--bare', repo)
|
|
104
|
+
# Archive applies checkout conversions too. Preserve blob bytes,
|
|
105
|
+
# including binary/intentional CRLF files, on every host.
|
|
106
|
+
(repo / 'info').mkdir(exist_ok=True)
|
|
107
|
+
(repo / 'info' / 'attributes').write_bytes(
|
|
108
|
+
b'* -text -eol -filter -ident -working-tree-encoding\n')
|
|
102
109
|
_git('-C', repo, 'fetch', '--depth=1', '--no-tags', url, ref)
|
|
103
110
|
commit = _git('-C', repo, 'rev-parse', 'FETCH_HEAD^{commit}').decode().strip()
|
|
104
111
|
if not re.fullmatch('[0-9a-f]{40}', commit) or (re.fullmatch('[0-9a-f]{40}', ref) and commit != ref):
|
|
@@ -108,11 +108,10 @@ def prepare_graph(root, config=None, migrate_windows_lock=False):
|
|
|
108
108
|
root = Path(root).resolve()
|
|
109
109
|
config = read_project(root) if config is None else config
|
|
110
110
|
roots = declarations(root, config)
|
|
111
|
-
expected
|
|
111
|
+
expected = {}
|
|
112
112
|
if (root / LOCK_FILE).exists():
|
|
113
113
|
try:
|
|
114
114
|
prior = json.loads((root / LOCK_FILE).read_text('utf-8'))
|
|
115
|
-
legacy = prior['version'] == 1
|
|
116
115
|
expected = {record['id']: record for record in prior['nodes']}
|
|
117
116
|
except (ValueError, KeyError, TypeError) as exc:
|
|
118
117
|
raise DependencyError('无法读取依赖锁文件 mcpy-git.lock.json。\n请从版本控制恢复该文件后运行 mcpy sync。') from exc
|
|
@@ -120,7 +119,7 @@ def prepare_graph(root, config=None, migrate_windows_lock=False):
|
|
|
120
119
|
raise DependencyError('此项目需要较新版本的 mcpy,请先升级 mcpywrap。')
|
|
121
120
|
registered = long_path(root / '.mcpy/git-projects')
|
|
122
121
|
registered.mkdir(parents=True, exist_ok=True)
|
|
123
|
-
nodes, active
|
|
122
|
+
nodes, active = {}, []
|
|
124
123
|
def visit(entry, supplied_source=None):
|
|
125
124
|
source, commit = supplied_source or fetch_source(root, entry['git'], entry['rev'])
|
|
126
125
|
project, payload, project_config, kind, target = _layout(source, entry)
|
|
@@ -138,11 +137,8 @@ def prepare_graph(root, config=None, migrate_windows_lock=False):
|
|
|
138
137
|
active.append(key)
|
|
139
138
|
source_hash = digest(source)
|
|
140
139
|
previous = expected.get(key)
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
if not migrating or previous['source_sha256'] not in (
|
|
144
|
-
windows_checkout_digest(source), windows_checkout_digest(source, crlf=False)):
|
|
145
|
-
raise DependencyError(f"依赖 {entry['name']} 的源码校验失败。\n请保留 mcpy-git.lock.json,并重新获取该依赖的固定版本。")
|
|
140
|
+
# sync derives checksums from the pinned commit's verified snapshot.
|
|
141
|
+
# Old host-dependent checksums are outputs, not version constraints.
|
|
146
142
|
children = []
|
|
147
143
|
for child in declarations(project, project_config):
|
|
148
144
|
children.append(visit(child))
|
|
@@ -197,65 +193,39 @@ def prepare_graph(root, config=None, migrate_windows_lock=False):
|
|
|
197
193
|
from .dependencies import validate_game_files
|
|
198
194
|
validate_game_files(stage, addon_directories(stage).values())
|
|
199
195
|
content_hash = digest(stage)
|
|
200
|
-
if previous and previous['sha256'] != content_hash and not migrating:
|
|
201
|
-
raise DependencyError(f"依赖 {entry['name']} 的安装内容与锁文件不一致。\n请确认团队使用相同版本的 mcpywrap;不要删除锁文件。")
|
|
202
196
|
final = registered / key
|
|
203
197
|
if final.exists():
|
|
204
198
|
if digest(final) != content_hash:
|
|
205
|
-
#
|
|
206
|
-
|
|
207
|
-
if not migrating or previous['sha256'] not in (
|
|
199
|
+
# Only replace an unchanged installation of the old lock.
|
|
200
|
+
if not previous or previous['sha256'] not in (
|
|
208
201
|
digest(final), windows_checkout_digest(final, crlf=False)):
|
|
209
202
|
raise DependencyError(f"依赖 {entry['name']} 的本地文件已修改。\n请将 {final} 移到项目外备份,再运行 mcpy sync。")
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
backup = Path(tempfile.mkdtemp(prefix=key[:12]+'-', dir=backups))/'project'
|
|
213
|
-
os.replace(final, backup)
|
|
203
|
+
old = Path(temporary) / 'old'
|
|
204
|
+
os.replace(final, old)
|
|
214
205
|
try:
|
|
215
206
|
os.replace(stage, final)
|
|
216
207
|
except BaseException:
|
|
217
|
-
os.replace(
|
|
208
|
+
os.replace(old, final)
|
|
218
209
|
raise
|
|
219
210
|
else:
|
|
220
211
|
os.replace(stage, final)
|
|
221
212
|
record = {'id': key, 'source': identity, 'source_sha256': source_hash, 'sha256': content_hash,
|
|
222
213
|
'kind': kind, 'target': target, 'children': list(dict.fromkeys(children))}
|
|
223
|
-
if migrating:
|
|
224
|
-
migrations.append({'node': key, 'name': entry['name'], 'git': entry['git'], 'rev': commit,
|
|
225
|
-
'old_source_sha256': previous['source_sha256'], 'source_sha256': source_hash,
|
|
226
|
-
'old_registered_sha256': previous['sha256'], 'registered_sha256': content_hash})
|
|
227
214
|
nodes[key] = record
|
|
228
215
|
active.pop()
|
|
229
216
|
return key
|
|
230
217
|
root_ids = [visit(entry) for entry in roots]
|
|
231
|
-
|
|
232
|
-
if migrations:
|
|
233
|
-
lock['_lock_migrations'] = migrations
|
|
234
|
-
return lock
|
|
218
|
+
return {'version': 2, 'declarations': roots, 'roots': root_ids, 'nodes': list(nodes.values())}
|
|
235
219
|
|
|
236
220
|
|
|
237
221
|
def write_lock(root, lock):
|
|
238
|
-
|
|
239
|
-
migrations = data.pop('_lock_migrations', [])
|
|
240
|
-
report = []
|
|
241
|
-
if migrations and (Path(root)/LOCK_FILE).exists():
|
|
242
|
-
old = (Path(root)/LOCK_FILE).read_bytes()
|
|
243
|
-
backup = Path(root)/'.mcpy/lock-backups'/(hashlib.sha256(old).hexdigest()+'.json')
|
|
244
|
-
backup.parent.mkdir(parents=True, exist_ok=True)
|
|
245
|
-
if backup.exists() and backup.read_bytes() != old:
|
|
246
|
-
raise DependencyError('无法备份旧依赖记录,原锁文件未修改。')
|
|
247
|
-
backup.write_bytes(old)
|
|
248
|
-
report.append({'project': str(root), 'backup': str(backup), 'nodes': migrations})
|
|
249
|
-
_write_json(Path(root) / LOCK_FILE, data)
|
|
250
|
-
return report
|
|
222
|
+
_write_json(Path(root) / LOCK_FILE, lock)
|
|
251
223
|
|
|
252
224
|
|
|
253
225
|
def sync_projects(root, config=None, migrate_windows_lock=False, migration_report=None):
|
|
254
|
-
#
|
|
255
|
-
lock = prepare_graph(root, config
|
|
256
|
-
|
|
257
|
-
if migration_report is not None:
|
|
258
|
-
migration_report.extend(report)
|
|
226
|
+
# Legacy arguments are retained for callers; sync simply recalculates the lock.
|
|
227
|
+
lock = prepare_graph(root, config)
|
|
228
|
+
write_lock(root, lock)
|
|
259
229
|
return len(lock['nodes'])
|
|
260
230
|
|
|
261
231
|
|
|
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": "aa185d69f11e138df90f446c239d075ef6ab4e5c5e0457981a6c09f52e04b7b9",
|
|
15
|
+
"Loader.dll": "03956417da34f569dd6e794076f2252ff05cb286fd1a8dc6ce966dc78911330e",
|
|
16
|
+
"McpyMcsAuth.dll": "b1270f169319e8acebca7d49be966d54c769590d708157c3984e33f9a943c1d7",
|
|
17
17
|
"publisher.cer": "e5aa2ac39df40804ed8b08fe8e43c4a2b8923f0d02a360708486b2db5b6303d7"
|
|
18
18
|
}
|
|
19
19
|
}
|
|
@@ -314,6 +314,8 @@ class _ControlHandler(socketserver.BaseRequestHandler):
|
|
|
314
314
|
request = json.loads(recv_exact(self.request, size).decode('utf-8'))
|
|
315
315
|
if request.get('token') != self.server.token:
|
|
316
316
|
raise ValueError('会话控制凭据无效')
|
|
317
|
+
if self.server.mode == 'network' and (request.get('side', 'client') != 'client' or request.get('action') == 'reload'):
|
|
318
|
+
raise ValueError('网络会话仅支持客户端调试,不支持服务端 Python 或本地 Mod 热更')
|
|
317
319
|
if request.get('action') == 'execute':
|
|
318
320
|
options = {'condition': request['condition']} if request.get('condition') is not None else {}
|
|
319
321
|
if options and not hasattr(self.server.channel, 'submit'):
|
|
@@ -357,8 +359,8 @@ class RuntimeControlServer(socketserver.ThreadingTCPServer):
|
|
|
357
359
|
daemon_threads = True
|
|
358
360
|
allow_reuse_address = True
|
|
359
361
|
|
|
360
|
-
def __init__(self, channel, token, project=None, session=None):
|
|
361
|
-
self.channel, self.token = channel, token
|
|
362
|
+
def __init__(self, channel, token, project=None, session=None, mode='local'):
|
|
363
|
+
self.channel, self.token, self.mode = channel, token, mode
|
|
362
364
|
self.input_manager = None
|
|
363
365
|
if project is not None and session is not None:
|
|
364
366
|
from .host_input import HostInputManager
|
|
@@ -57,12 +57,12 @@ def run(project, session):
|
|
|
57
57
|
debug_channel = backend.debug_channel(data, receiver._write)
|
|
58
58
|
debug_channel.start(process.pid)
|
|
59
59
|
token = uuid.uuid4().hex
|
|
60
|
-
control_server = RuntimeControlServer(debug_channel, token, project, session)
|
|
60
|
+
control_server = RuntimeControlServer(debug_channel, token, project, session, mode=data.get('mode', 'local'))
|
|
61
61
|
control_server.start()
|
|
62
62
|
sessions.save(directory/'control.json', {'port': control_server.server_address[1],
|
|
63
63
|
'token': token,
|
|
64
64
|
'unified_input_worker': True,
|
|
65
|
-
'python_reload_sides': ['client', 'server'],
|
|
65
|
+
'python_reload_sides': [] if data.get('mode') == 'network' else ['client', 'server'],
|
|
66
66
|
'client_python_queue': callable(getattr(debug_channel, 'submit', None))})
|
|
67
67
|
data.update(state='running', game=identity(process.pid))
|
|
68
68
|
sessions.save(path, data)
|
|
@@ -114,7 +114,7 @@ def handoff(data):
|
|
|
114
114
|
target = data['network']['target']
|
|
115
115
|
result.update(host=target['host'], port=target['port'], identity_source=target['auth'],
|
|
116
116
|
identity_provided=data['mcs_auth'], authenticated=False,
|
|
117
|
-
connection_verified=False, addons_assembled=False,
|
|
117
|
+
connection_verified=data.get('connection_verified', False), addons_assembled=False,
|
|
118
118
|
engine_version=data['network']['engine']['version'])
|
|
119
119
|
return result
|
|
120
120
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"executable_sha256": "
|
|
2
|
+
"executable_sha256": "4f4f8b0a8eae4b8d409ae90e222886623c4b53ed66525d8267ffaadc1db65442",
|
|
3
3
|
"source_sha256": "0c0b2a02bfecea68b824a486ac1d88cde6bd9fc8ee8e4c9a6939870bd8e710d1",
|
|
4
4
|
"sources": {
|
|
5
5
|
"video_capture.h": "8daee1b8c1c8273bc8d19d39f0559f82c30d7ff900894bcc2cc197d3881532d7",
|
|
Binary file
|
|
@@ -144,6 +144,8 @@ def open_ui_crate_mod(behavior_pack_path, run_event_loop=True):
|
|
|
144
144
|
|
|
145
145
|
# 主窗口
|
|
146
146
|
window = QWidget()
|
|
147
|
+
# Closed embedded editors must release their signal closures before Qt exits.
|
|
148
|
+
window.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose)
|
|
147
149
|
window.setWindowTitle("Minecraft Mod 创建工具")
|
|
148
150
|
window.setMinimumWidth(900) # 增加窗口宽度以适应目录树
|
|
149
151
|
window.setMinimumHeight(600) # 设置窗口最小高度
|
|
@@ -68,7 +68,10 @@ def _git(*args):
|
|
|
68
68
|
return value[4:]
|
|
69
69
|
return value
|
|
70
70
|
try:
|
|
71
|
-
result = subprocess.run(['git', '-c', 'core.hooksPath=', '-c', 'core.longpaths=true',
|
|
71
|
+
result = subprocess.run(['git', '-c', 'core.hooksPath=', '-c', 'core.longpaths=true',
|
|
72
|
+
'-c', 'core.autocrlf=false', '-c', 'core.eol=lf',
|
|
73
|
+
'-c', 'core.attributesFile=' + os.devnull, *map(argument, args)],
|
|
74
|
+
env=dict(os.environ, GIT_ATTR_NOSYSTEM='1'),
|
|
72
75
|
capture_output=True, timeout=180)
|
|
73
76
|
except (OSError, subprocess.TimeoutExpired) as exc:
|
|
74
77
|
raise DependencyError(f'无法获取代码库: {exc}') from exc
|