mcpywrap 0.4.3__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.3 → mcpywrap-0.4.4}/CHANGELOG.md +8 -0
- {mcpywrap-0.4.3/mcpywrap.egg-info → mcpywrap-0.4.4}/PKG-INFO +1 -1
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/git-dependencies.md +3 -3
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/__init__.py +1 -1
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/code_libraries.py +11 -7
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/sync_cmd.py +2 -6
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/engines/windows.py +22 -16
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/git_cache.py +8 -1
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/git_projects.py +14 -44
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/bridge_payload/Injector.exe +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/bridge_payload/Loader.dll +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/bridge_payload/McpyMcsAuth.dll +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/bridge_payload/manifest.json +3 -3
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/window_capture/manifest.json +1 -1
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/window_capture/mcpy-window-capture.exe +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/minecraft/template/mod_template.py +2 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/source_files.py +4 -1
- {mcpywrap-0.4.3 → mcpywrap-0.4.4/mcpywrap.egg-info}/PKG-INFO +1 -1
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/pyproject.toml +1 -1
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/SKILL.md +1 -1
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/references/project-dependencies.md +2 -1
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_code_libraries.py +20 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_engine_backends.py +22 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_git_projects.py +105 -69
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_qt_sessions.py +5 -1
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/LICENSE +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/MANIFEST.in +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/README.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/THIRD_PARTY_NOTICES.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/code-libraries.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/development.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/engine-discovery.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/game-backends.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/input-sequence.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/launcher-client-python.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/local-dependencies.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/macos-resource-reload.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/mcs-auth.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/qt6-development.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/qumod.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/release-0.4.0.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/release-readiness-0.4.0.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/releasing.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/runtime-debug.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/runtime-input.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/runtime-player.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/runtime-ui.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/docs/shared-log-ui.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/__main__.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/builders/AddonsPack.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/builders/MapPack.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/builders/__init__.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/builders/assembly.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/builders/dependency_manager.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/builders/file_merge.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/builders/project_builder.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/builders/watcher.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/cli.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/command_context.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/__init__.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/add_cmd.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/build_cmd.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/connect_cmd.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/default_cmd.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/dependency_prompt.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/desktop_cmd.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/dev_cmd.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/doctor_cmd.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/edit_cmd.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/engine_cmd.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/init_cmd.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/mod_cmd.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/modsdk_cmd.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/package_cmd.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/publish_cmd.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/record_cmd.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/remove_cmd.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/run_cmd.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/runtime_cmd.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/runtime_input_cmd.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/runtime_player_cmd.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/runtime_ui_cmd.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/serve_cmd.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/session_cmd.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/commands/ui_cmd.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/config.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/custom_packaging.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/dependencies.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/engines/__init__.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/engines/apk_profile.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/engines/backend.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/engines/host.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/engines/install.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/engines/macos.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/engines/macos_network.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/engines/official.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/engines/preferences.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/engines/tui.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/framework_presets.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/frameworks.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/input_executor.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/input_plan.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/SimpleMonitor.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/__init__.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/auth_interaction.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/bridge_assets.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/bridge_payload/publisher.cer +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/diagnostics.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/discovery.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/editor.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/file_logs.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/game.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/host_input.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/hot_reload.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/input_sequence.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/launcher_python.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/log_colorizer.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/log_protocol.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/mcs.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/mcs_auth.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/network.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/private_logs.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/processes.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/recording_worker.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/recordings.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/runtime_cppconfig.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/runtime_debug.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/runtime_input_payload.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/runtime_key_timeline_payload.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/runtime_player_payload.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/runtime_ui.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/runtime_ui_outline.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/runtime_ui_payload.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/session_capabilities.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/session_worker.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/sessions.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/studio_server.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/studio_server_ui.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/symlink_helper_global.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/symlink_helper_map.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/symlinks.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/unified_input.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/mcstudio/window.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/minecraft/__init__.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/minecraft/addons.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/minecraft/level_dat.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/minecraft/map.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/minecraft/netease_modsdk.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/minecraft/template/generate_mod_files.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/project_dependencies.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/project_init.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/recording_io.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/remote/__init__.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/remote/client.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/remote/http_server.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/remote/service.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/timeline.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/ui/__init__.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/ui/engine_setup.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/ui/log_view.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/ui/log_window.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/ui/project_ui.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/ui/run_session.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/ui/session_controller.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/ui/session_tools.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/ui/session_views.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/ui/world_config.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/utils/__init__.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/utils/pip_error_parser.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/utils/print_guide.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/utils/project_setup.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap/utils/utils.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap.egg-info/SOURCES.txt +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap.egg-info/dependency_links.txt +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap.egg-info/entry_points.txt +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap.egg-info/requires.txt +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/mcpywrap.egg-info/top_level.txt +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/native/mcs_auth/Bridge.cs +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/native/mcs_auth/Injector.cs +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/native/mcs_auth/Loader.c +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/native/mcs_auth/publisher.cer +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/native/mcs_auth/publisher.json +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/native/runtime_input/README.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/native/runtime_input/launcher-monotonic.patch +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/native/runtime_input/steady_clock.h +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/native/window_capture/video_capture.h +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/native/window_capture/window_capture.cpp +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/scripts/build_all_native.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/scripts/build_mcs_auth_bridge.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/scripts/build_window_capture.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/scripts/check_mcs_auth_bridge.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/scripts/check_release.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/scripts/check_window_capture.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/setup.cfg +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/agents/openai.yaml +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/references/input-sequence.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/references/input-writing.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/references/instance-world-settings.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/references/local-development.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/references/macos-local.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/references/remote-testing.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/references/runtime-input.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/references/runtime-key-timeline.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/references/runtime-player.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/references/runtime-ui.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/references/troubleshooting.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/scripts/bootstrap.ps1 +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/scripts/bootstrap.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/scripts/game_window.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/skills/mcpywrap/scripts/smoke.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual/runtime_controls/README.md +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual/runtime_controls/client_probe.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual/runtime_controls/input_probe.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual/runtime_controls/key_timeline_probe.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual/runtime_controls/movement.json +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual/runtime_controls/run.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual/runtime_controls/server_fixture.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual/runtime_controls/support.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual_dependency_boundaries.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual_input_window.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual_integration.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual_native_recording.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual_remote_recording.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual_runtime_input.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual_runtime_input_unified.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual_runtime_key_timeline.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual_runtime_player.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/manual_runtime_ui.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_auth_interaction.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_automation.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_build_replace_retry.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_dependency_boundaries.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_engine_compatibility.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_engine_discovery.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_engine_install.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_game_window_skill.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_host_input.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_input_sequence.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_instance_cppconfig.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_launch_encoding.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_launcher_python.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_local_auth_session.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_local_dependencies.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_macos_network.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_manual_runtime_controls.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_mcs_auth.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_mouse.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_native_input_sequence.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_native_preferences.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_native_recording.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_network.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_network_sessions.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_pack_uuid_conflicts.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_package.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_qumod_workflow.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_recordings.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_remote.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_remote_scripts.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_resource_reload.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_runtime_debug.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_runtime_input.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_runtime_key_timeline.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_runtime_player.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_runtime_ui.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_runtime_ui_outline.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_session_capabilities.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_shared_logs.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_skill_workflows.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_unified_skill_contract.py +0 -0
- {mcpywrap-0.4.3 → mcpywrap-0.4.4}/tests/test_window_focus.py +0 -0
|
@@ -1,5 +1,13 @@
|
|
|
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
|
+
|
|
3
11
|
## 0.4.3
|
|
4
12
|
|
|
5
13
|
- macOS 新增无认证服务器连接,复用 `mcpy connect` 与项目 `[tool.mcpywrap.server]` 的 `run` 入口、cppconfig、日志、偏好和退出机制,不装配本地 Mod 或创建本地世界实例。
|
|
@@ -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})
|
|
@@ -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': []}
|
|
@@ -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
|
}
|
|
@@ -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
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "mcpywrap"
|
|
7
|
-
version = "0.4.
|
|
7
|
+
version = "0.4.4"
|
|
8
8
|
description = "A wrapper for Minecraft China Edition Addons management"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [{name = "boybook", email = "boybook@easecation.net"}]
|
|
@@ -63,7 +63,7 @@ description: 使用 mcpywrap 管理《我的世界》中国版 Addon/地图、
|
|
|
63
63
|
`--project` 必须是调用端路径且目录已存在;纯连接不需要 init。远程实际会话保存在 Windows 的 serve 数据目录。
|
|
64
64
|
远程结果中的 `project/image` 是调用端路径;`remote_project/executable/log_path/engine_log_path` 是 Windows 信息。读取远程日志用 logs,不在 macOS 打开 Windows 路径。
|
|
65
65
|
|
|
66
|
-
Windows/macOS 共用依赖锁;克隆后用 `sync --json`
|
|
66
|
+
Windows/macOS 共用依赖锁;克隆后用 `sync --json` 恢复。sync 按固定 Git 提交重新计算跨平台摘要并写回锁,不改变依赖版本,也不创建备份或要求迁移。两端 CLI 都应包含此修复;首次使用新的源码缓存需联网获取固定提交。
|
|
67
67
|
|
|
68
68
|
## 项目工作流
|
|
69
69
|
|
|
@@ -116,7 +116,8 @@ export.path相对该项目描述。没有export时工具可识别符合既有目
|
|
|
116
116
|
| 新克隆缺少缓存 | 执行sync,保留现有锁定提交 |
|
|
117
117
|
| 布局无法识别 | 查上游export/目录,再传明确subdir、kind、target;不猜安装位置 |
|
|
118
118
|
| 目标已有手工框架或另一依赖 | 核对归属并制定明确迁移;不直接覆盖或删业务目录 |
|
|
119
|
-
|
|
|
119
|
+
| 旧平台锁摘要不符 | 更新两端 CLI 后运行 sync,按固定提交直接重算锁;不必删除锁或更改依赖版本 |
|
|
120
|
+
| 共享源码缓存损坏 | 定位具体缓存条目并重新获取;不清空全部缓存,不把手动改动写入锁 |
|
|
120
121
|
| 获取来源失败 | 保留失败信息及现有声明,不静默换镜像、更新版本或转为pip安装 |
|
|
121
122
|
| 构建成功但游戏导入失败 | 检查产物路径、入口、端侧与游戏日志;不是工具Python缺包的充分证据 |
|
|
122
123
|
|
|
@@ -87,6 +87,26 @@ class CodeLibraries(unittest.TestCase):
|
|
|
87
87
|
self.build()
|
|
88
88
|
self.assertFalse((self.out / 'behavior_pack/MyMod/Library').exists())
|
|
89
89
|
|
|
90
|
+
def test_windows_lock_and_installation_are_recalculated_from_pinned_source(self):
|
|
91
|
+
from mcpywrap.source_files import digest
|
|
92
|
+
sync_libraries(self.main)
|
|
93
|
+
path = self.main / LOCK_FILE
|
|
94
|
+
canonical = path.read_bytes()
|
|
95
|
+
installed = resolve_libraries(self.main)[0]['source']
|
|
96
|
+
for file in installed.rglob('*'):
|
|
97
|
+
if file.is_file():
|
|
98
|
+
file.write_bytes(file.read_bytes().replace(b'\r\n', b'\n').replace(b'\n', b'\r\n'))
|
|
99
|
+
lock = json.loads(canonical)
|
|
100
|
+
lock['libraries'][0]['sha256'] = digest(installed)
|
|
101
|
+
self.assertNotEqual(lock['libraries'][0]['sha256'], json.loads(canonical)['libraries'][0]['sha256'])
|
|
102
|
+
path.write_text(json.dumps(lock))
|
|
103
|
+
clone = self.root / 'clone'
|
|
104
|
+
shutil.copytree(self.main, clone, ignore=shutil.ignore_patterns('.mcpy'))
|
|
105
|
+
for project in (self.main, clone):
|
|
106
|
+
sync_libraries(project)
|
|
107
|
+
resolve_libraries(project)
|
|
108
|
+
self.assertEqual((project / LOCK_FILE).read_bytes(), canonical)
|
|
109
|
+
|
|
90
110
|
def test_tamper_failed_fetch_and_handwritten_conflicts_preserve_output(self):
|
|
91
111
|
sync_libraries(self.main)
|
|
92
112
|
self.build()
|
|
@@ -18,6 +18,28 @@ from mcpywrap.engines.windows import WindowsBackend
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
class BackendTests(unittest.TestCase):
|
|
21
|
+
def test_windows_native_hud_layout_when_python_launch_log_is_missing(self):
|
|
22
|
+
backend=WindowsBackend()
|
|
23
|
+
game=self.root/'game.log';engine=self.root/'engine.log'
|
|
24
|
+
data={'mode':'local','log_path':str(game),'engine_log_path':str(engine)}
|
|
25
|
+
channel=backend.debug_channel(data,lambda text:None);self.addCleanup(channel.close)
|
|
26
|
+
game.write_bytes(b'UI registered\n')
|
|
27
|
+
engine.write_bytes(b"[INFO GUI 1 2] Destroyed 'world_loading_progress_screen'\n[INFO GUI 1 2] Layout main thread: Full re-layout of 364 controls completed in 3ms for screen 'pause.pause_screen'.\n")
|
|
28
|
+
self.assertFalse(backend.refresh(data,channel));self.assertFalse(channel.ready())
|
|
29
|
+
marker=b"[2026-10-10 16:54:45:664 INFO GUI 90568 80348] Layout main thread: Full re-layout of 364 controls completed in 3.714000ms for screen 'hud.hud_screen'."
|
|
30
|
+
with engine.open('ab') as stream:stream.write(marker[:120])
|
|
31
|
+
self.assertFalse(backend.refresh(data,channel))
|
|
32
|
+
with engine.open('ab') as stream:stream.write(marker[120:]+b'\n')
|
|
33
|
+
self.assertTrue(backend.refresh(data,channel));self.assertTrue(data['world_ready']);self.assertTrue(channel.ready())
|
|
34
|
+
self.assertFalse(backend.refresh(data,channel))
|
|
35
|
+
|
|
36
|
+
def test_windows_native_hud_requires_engine_log_not_arbitrary_python_text(self):
|
|
37
|
+
backend=WindowsBackend();game=self.root/'game.log'
|
|
38
|
+
data={'mode':'local','log_path':str(game),'engine_log_path':str(self.root/'missing.log')}
|
|
39
|
+
channel=backend.debug_channel(data,lambda text:None);self.addCleanup(channel.close)
|
|
40
|
+
game.write_bytes(b"[INFO GUI 1 2] Layout main thread: 10 controls completed for screen 'hud.hud_screen'.\n")
|
|
41
|
+
self.assertFalse(backend.refresh(data,channel));self.assertFalse(channel.ready())
|
|
42
|
+
|
|
21
43
|
def test_windows_world_readiness_waits_for_client_system_initialization(self):
|
|
22
44
|
backend = WindowsBackend()
|
|
23
45
|
path = self.root/'game.log'
|