Compare commits

..

12 Commits

Author SHA1 Message Date
Evan
bae333ba7c Merge branch 'cocos-main'
# Conflicts:
#	docker-conf/conf.d/nginx.conf
#	nginx.conf
#	scratch-blocks/build.py
#	scratch-blocks/cleanup.sh
#	scratch-blocks/i18n/create_messages.py
#	scratch-blocks/i18n/dedup_json.py
#	scratch-blocks/i18n/js_to_json.py
#	scratch-blocks/i18n/json_to_js.py
#	scratch-blocks/i18n/sync_tx_translations.js
#	scratch-blocks/i18n/xliff_to_json.py
#	scratch-blocks/local_build.sh
#	scratch-blocks/media/icons/control_forever.svg
#	scratch-blocks/media/icons/control_repeat.svg
#	scratch-blocks/media/icons/control_wait.svg
#	scratch-blocks/media/icons/event_broadcast_blue.svg
#	scratch-blocks/media/icons/event_broadcast_coral.svg
#	scratch-blocks/media/icons/event_broadcast_green.svg
#	scratch-blocks/media/icons/event_broadcast_magenta.svg
#	scratch-blocks/media/icons/event_broadcast_orange.svg
#	scratch-blocks/media/icons/event_broadcast_purple.svg
#	scratch-blocks/media/icons/event_when-broadcast-received_blue.svg
#	scratch-blocks/media/icons/event_when-broadcast-received_coral.svg
#	scratch-blocks/media/icons/event_when-broadcast-received_green.svg
#	scratch-blocks/media/icons/event_when-broadcast-received_magenta.svg
#	scratch-blocks/media/icons/event_when-broadcast-received_orange.svg
#	scratch-blocks/media/icons/event_when-broadcast-received_purple.svg
#	scratch-blocks/media/icons/event_whenflagclicked.svg
#	scratch-blocks/media/icons/set-led_blue.svg
#	scratch-blocks/media/icons/set-led_coral.svg
#	scratch-blocks/media/icons/set-led_green.svg
#	scratch-blocks/media/icons/set-led_magenta.svg
#	scratch-blocks/media/icons/set-led_mystery.svg
#	scratch-blocks/media/icons/set-led_orange.svg
#	scratch-blocks/media/icons/set-led_purple.svg
#	scratch-blocks/media/icons/set-led_white.svg
#	scratch-blocks/media/icons/set-led_yellow.svg
#	scratch-blocks/media/icons/wedo_motor-clockwise.svg
#	scratch-blocks/media/icons/wedo_motor-counterclockwise.svg
#	scratch-blocks/media/icons/wedo_when-distance_close.svg
#	scratch-blocks/media/icons/wedo_when-tilt-backward.svg
#	scratch-blocks/media/icons/wedo_when-tilt-forward.svg
#	scratch-blocks/media/icons/wedo_when-tilt-left.svg
#	scratch-blocks/media/icons/wedo_when-tilt-right.svg
#	scratch-blocks/media/icons/wedo_when-tilt.svg
#	scratch-blocks/package-lock.json
#	scratch-blocks/pull_from_blockly.sh
#	scratch-gui/competitio_login/index.html
#	scratch-gui/package-lock.json
#	scratch-gui/package.json
#	scratch-gui/prune-gh-pages.sh
#	scratch-gui/src/components/menu-bar/menu-bar.css
#	scratch-gui/src/components/menu-bar/menu-bar.jsx
#	scratch-gui/src/components/nopermission-modal/NoPermissionModal.jsx
#	scratch-gui/src/components/stage-cpp-unity/currentLevelChoose.jsx
#	scratch-gui/src/components/stage-cpp-unity/stage-unity.jsx
#	scratch-gui/src/components/stage-cpp/cpp-parser.js
#	scratch-gui/src/components/stage-cpp/stage-cpp-clang.jsx
#	scratch-gui/src/components/stage-cpp/stage-cpp.css
#	scratch-gui/src/components/stage-python-unity/currentLevelChoose.jsx
#	scratch-gui/src/components/stage-python-unity/stage-unity.jsx
#	scratch-gui/src/components/stage-python/stage-python.css
#	scratch-gui/src/components/stage-python/stage-python.jsx
#	scratch-gui/src/components/stage-unity/currentLevelChoose.jsx
#	scratch-gui/src/components/stage-unity/stage-unity.jsx
#	scratch-gui/src/lib/libraries/decks/steps/add-effects.es.png
#	scratch-gui/src/lib/libraries/decks/steps/animate-char-add-sound.es.png
#	scratch-gui/src/lib/libraries/decks/steps/animate-char-change-color.es.png
#	scratch-gui/src/lib/libraries/decks/steps/animate-char-jump.es.png
#	scratch-gui/src/lib/libraries/decks/steps/animate-char-move.es.png
#	scratch-gui/src/lib/libraries/decks/steps/animate-char-say-something.es.png
#	scratch-gui/src/lib/libraries/decks/steps/animate-char-talk.es.png
#	scratch-gui/src/lib/libraries/decks/steps/change-size.es.png
#	scratch-gui/src/lib/libraries/decks/steps/chase-game-change-score.es.png
#	scratch-gui/src/lib/libraries/decks/steps/chase-game-move-randomly.es.png
#	scratch-gui/src/lib/libraries/decks/steps/chase-game-play-sound.es.png
#	scratch-gui/src/lib/libraries/decks/steps/chase-game-right-left.es.png
#	scratch-gui/src/lib/libraries/decks/steps/chase-game-up-down.es.png
#	scratch-gui/src/lib/libraries/decks/steps/cn-backdrop.es.png
#	scratch-gui/src/lib/libraries/decks/steps/cn-collect.es.png
#	scratch-gui/src/lib/libraries/decks/steps/cn-glide.es.png
#	scratch-gui/src/lib/libraries/decks/steps/cn-say.es.png
#	scratch-gui/src/lib/libraries/decks/steps/cn-score.es.png
#	scratch-gui/src/lib/libraries/decks/steps/code-cartoon-01-say-something.es.png
#	scratch-gui/src/lib/libraries/decks/steps/code-cartoon-02-animate.es.png
#	scratch-gui/src/lib/libraries/decks/steps/code-cartoon-03-select-different-character.LTR.png
#	scratch-gui/src/lib/libraries/decks/steps/code-cartoon-04-use-minus-sign.es.png
#	scratch-gui/src/lib/libraries/decks/steps/code-cartoon-05-grow-shrink.es.png
#	scratch-gui/src/lib/libraries/decks/steps/code-cartoon-06-select-another-different-character.LTR.png
#	scratch-gui/src/lib/libraries/decks/steps/code-cartoon-07-jump.es.png
#	scratch-gui/src/lib/libraries/decks/steps/code-cartoon-08-change-scenes.es.png
#	scratch-gui/src/lib/libraries/decks/steps/code-cartoon-09-glide-around.es.png
#	scratch-gui/src/lib/libraries/decks/steps/code-cartoon-10-change-costumes.es.png
#	scratch-gui/src/lib/libraries/decks/steps/code-cartoon-11-choose-more-characters.LTR.png
#	scratch-gui/src/lib/libraries/decks/steps/fly-choose-character.LTR.png
#	scratch-gui/src/lib/libraries/decks/steps/fly-flying-heart.es.png
#	scratch-gui/src/lib/libraries/decks/steps/fly-keep-score.es.png
#	scratch-gui/src/lib/libraries/decks/steps/fly-make-interactive.es.png
#	scratch-gui/src/lib/libraries/decks/steps/fly-move-scenery.es.png
#	scratch-gui/src/lib/libraries/decks/steps/fly-object-to-collect.LTR.png
#	scratch-gui/src/lib/libraries/decks/steps/fly-say-something.es.png
#	scratch-gui/src/lib/libraries/decks/steps/fly-select-flyer.LTR.png
#	scratch-gui/src/lib/libraries/decks/steps/fly-switch-costume.es.png
#	scratch-gui/src/lib/libraries/decks/steps/glide-around-back-and-forth.es.png
#	scratch-gui/src/lib/libraries/decks/steps/glide-around-point.es.png
#	scratch-gui/src/lib/libraries/decks/steps/hide-show.es.png
#	scratch-gui/src/lib/libraries/decks/steps/imagine-change-costumes.es.png
#	scratch-gui/src/lib/libraries/decks/steps/imagine-choose-another-backdrop.LTR.png
#	scratch-gui/src/lib/libraries/decks/steps/imagine-choose-another-sprite.LTR.png
#	scratch-gui/src/lib/libraries/decks/steps/imagine-choose-any-sprite.LTR.png
#	scratch-gui/src/lib/libraries/decks/steps/imagine-choose-backdrop.LTR.png
#	scratch-gui/src/lib/libraries/decks/steps/imagine-choose-sound.es.png
#	scratch-gui/src/lib/libraries/decks/steps/imagine-click-green-flag.es.png
#	scratch-gui/src/lib/libraries/decks/steps/imagine-fly-around.es.png
#	scratch-gui/src/lib/libraries/decks/steps/imagine-glide-to-point.es.png
#	scratch-gui/src/lib/libraries/decks/steps/imagine-grow-shrink.es.png
#	scratch-gui/src/lib/libraries/decks/steps/imagine-left-right.es.png
#	scratch-gui/src/lib/libraries/decks/steps/imagine-type-what-you-want.es.png
#	scratch-gui/src/lib/libraries/decks/steps/imagine-up-down.es.png
#	scratch-gui/src/lib/libraries/decks/steps/move-arrow-keys-left-right.es.png
#	scratch-gui/src/lib/libraries/decks/steps/move-arrow-keys-up-down.es.png
#	scratch-gui/src/lib/libraries/decks/steps/music-make-beat.es.png
#	scratch-gui/src/lib/libraries/decks/steps/music-make-beatbox.es.png
#	scratch-gui/src/lib/libraries/decks/steps/music-make-song.es.png
#	scratch-gui/src/lib/libraries/decks/steps/music-play-sound.es.png
#	scratch-gui/src/lib/libraries/decks/steps/name-change-color.es.png
#	scratch-gui/src/lib/libraries/decks/steps/name-grow.es.png
#	scratch-gui/src/lib/libraries/decks/steps/name-play-sound.es.png
#	scratch-gui/src/lib/libraries/decks/steps/name-spin.es.png
#	scratch-gui/src/lib/libraries/decks/steps/pong-add-backdrop.LTR.png
#	scratch-gui/src/lib/libraries/decks/steps/pong-add-ball-sprite.LTR.png
#	scratch-gui/src/lib/libraries/decks/steps/pong-add-code-to-ball.es.png
#	scratch-gui/src/lib/libraries/decks/steps/pong-bounce-around.es.png
#	scratch-gui/src/lib/libraries/decks/steps/pong-choose-score.es.png
#	scratch-gui/src/lib/libraries/decks/steps/pong-game-over.es.png
#	scratch-gui/src/lib/libraries/decks/steps/pong-insert-change-score.es.png
#	scratch-gui/src/lib/libraries/decks/steps/pong-move-the-paddle.es.png
#	scratch-gui/src/lib/libraries/decks/steps/pong-reset-score.es.png
#	scratch-gui/src/lib/libraries/decks/steps/pong-select-ball.LTR.png
#	scratch-gui/src/lib/libraries/decks/steps/pop-game-change-color.es.png
#	scratch-gui/src/lib/libraries/decks/steps/pop-game-change-score.es.png
#	scratch-gui/src/lib/libraries/decks/steps/pop-game-play-sound.es.png
#	scratch-gui/src/lib/libraries/decks/steps/pop-game-random-position.es.png
#	scratch-gui/src/lib/libraries/decks/steps/pop-game-reset-score.es.png
#	scratch-gui/src/lib/libraries/decks/steps/record-a-sound-choose-sound.es.png
#	scratch-gui/src/lib/libraries/decks/steps/record-a-sound-click-record.es.png
#	scratch-gui/src/lib/libraries/decks/steps/record-a-sound-play-your-sound.es.png
#	scratch-gui/src/lib/libraries/decks/steps/record-a-sound-press-record-button.es.png
#	scratch-gui/src/lib/libraries/decks/steps/record-a-sound-sounds-tab.es.png
#	scratch-gui/src/lib/libraries/decks/steps/speech-change-color.es.png
#	scratch-gui/src/lib/libraries/decks/steps/speech-grow-shrink.es.png
#	scratch-gui/src/lib/libraries/decks/steps/speech-move-around.es.png
#	scratch-gui/src/lib/libraries/decks/steps/speech-say-something.es.png
#	scratch-gui/src/lib/libraries/decks/steps/speech-set-voice.es.png
#	scratch-gui/src/lib/libraries/decks/steps/speech-song.es.png
#	scratch-gui/src/lib/libraries/decks/steps/speech-spin.es.png
#	scratch-gui/src/lib/libraries/decks/steps/spin-point-in-direction.es.png
#	scratch-gui/src/lib/libraries/decks/steps/spin-turn.es.png
#	scratch-gui/src/lib/libraries/decks/steps/story-conversation.es.png
#	scratch-gui/src/lib/libraries/decks/steps/story-hide-character.es.png
#	scratch-gui/src/lib/libraries/decks/steps/story-say-something.es.png
#	scratch-gui/src/lib/libraries/decks/steps/story-show-character.es.png
#	scratch-gui/src/lib/libraries/decks/steps/story-switch-backdrop.es.png
#	scratch-gui/src/lib/libraries/decks/steps/switch-costumes.es.png
#	scratch-gui/src/lib/libraries/decks/steps/talking-10-choose-third-backdrop.LTR.png
#	scratch-gui/src/lib/libraries/decks/steps/talking-12-dance-moves.es.png
#	scratch-gui/src/lib/libraries/decks/steps/talking-2-choose-sprite.LTR.png
#	scratch-gui/src/lib/libraries/decks/steps/talking-4-choose-backdrop.LTR.png
#	scratch-gui/src/lib/libraries/decks/steps/talking-6-choose-another-sprite.LTR.png
#	scratch-gui/src/lib/libraries/decks/steps/talking-7-move-around.es.png
#	scratch-gui/src/lib/libraries/decks/steps/talking-8-choose-another-backdrop.LTR.png
#	scratch-gui/src/lib/libraries/decks/steps/video-animate.es.png
#	scratch-gui/src/lib/libraries/decks/steps/video-pet.es.png
#	scratch-gui/src/lib/libraries/decks/steps/video-pop.es.png
#	scratch-gui/src/playground/aboutus.ejs
#	scratch-gui/src/playground/checkStatus.js
#	scratch-gui/src/playground/competition.ejs
#	scratch-gui/src/playground/competition.js
#	scratch-gui/src/playground/competition_list.ejs
#	scratch-gui/src/playground/competition_list.js
#	scratch-gui/src/playground/competition_sum.ejs
#	scratch-gui/src/playground/competition_sum.js
#	scratch-gui/src/playground/config.js
#	scratch-gui/src/playground/home.ejs
#	scratch-gui/src/playground/import-check.js
#	scratch-gui/src/playground/leaderboard.ejs
#	scratch-gui/src/playground/login-new.ejs
#	scratch-gui/src/playground/login.ejs
#	scratch-gui/src/playground/login.js
#	scratch-gui/src/playground/matchsum.js
#	scratch-gui/src/playground/programming-learning.ejs
#	scratch-gui/src/playground/programming-learning.js
#	scratch-gui/src/playground/signup-new.ejs
#	scratch-gui/src/playground/third-part-login.js
#	scratch-gui/src/playground/welcome.ejs
#	scratch-gui/src/playground/welcome.js
#	scratch-gui/static/css/welcome-new.css
#	scratch-gui/static/pyodide/pyodide.asm.wasm.br
#	scratch-gui/static/unity/Build/mstest5.data.br
#	scratch-gui/static/unity/Build/mstest5.framework.js.br
#	scratch-gui/static/unity/Build/mstest5.loader.js
#	scratch-gui/static/unity/Build/mstest5.wasm.br
#	scratch-gui/static/unity/StreamingAssets/aa/AddressablesLink/link.xml
#	scratch-gui/static/unity/StreamingAssets/aa/catalog.json
#	scratch-gui/static/unity/StreamingAssets/aa/settings.json
#	scratch-gui/webpack.config.js
#	scratch-l10n/scripts/build-data.js
#	scratch-l10n/scripts/build-i18n-src.js
#	scratch-l10n/scripts/tw-push.js
#	scratch-l10n/scripts/tx-pull-help-articles.js
#	scratch-l10n/scripts/tx-pull-help-names.js
#	scratch-l10n/scripts/tx-pull-locale-articles.js
#	scratch-l10n/scripts/tx-pull-www.js
#	scratch-l10n/scripts/tx-push-help.js
#	scratch-l10n/scripts/tx-push-src.js
#	scratch-l10n/scripts/update-translations.sh
#	scratch-l10n/scripts/validate-www.js
#	scratch-vm/package-lock.json
#	scratch-vm/src/extensions/scratch3_music/assets/instruments/11-saxophone/36.mp3
#	scratch-vm/src/extensions/scratch3_music/assets/instruments/11-saxophone/60.mp3
#	scratch-vm/src/extensions/scratch3_music/assets/instruments/11-saxophone/84.mp3
#	scratch-vm/src/extensions/scratch3_music/assets/instruments/5-electric-guitar/60.mp3
#	scratch-vm/test/fixtures/sprite.json
2026-09-07 11:35:22 +08:00
Evan
aaccb73773 feat: 更新cocos的包 2026-09-02 15:39:11 +08:00
Evan
9c27042e27 feat:init 2026-09-01 14:14:48 +08:00
Evan
6a3e797a9a cocos 2026-08-31 14:05:47 +08:00
sxg
74b983c74e c++解释器修改 2026-08-31 10:24:13 +08:00
sxg
a699896116 LF 2026-08-26 14:27:41 +08:00
Evan
43b983fb99 更换cocos 2026-08-26 13:55:55 +08:00
Evan
4fc07b1458 Merge branch 'main' of https://git.tianfurunhe.com/lyf/001code-html--cocos
# Conflicts:
#	scratch-gui/src/playground/config.js
#	scratch-gui/static/unity/Build/mstest5.loader.js
#	scratch-gui/static/unity/StreamingAssets/aa/WebGL/defaultlocalgroup_scenes_all_44c83ead579edde0422cd5707e20fce8.bundle.br
#	scratch-gui/static/unity/StreamingAssets/aa/catalog.json
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/91601-91700.json
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/91601-91700.json.br
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/91701-91800.json
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/91701-91800.json.br
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/91801-91900.json
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/91801-91900.json.br
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/91901-92000.json
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/91901-92000.json.br
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/92001-92100.json
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/92001-92100.json.br
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/92101-92200.json
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/92101-92200.json.br
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/92201-92300.json
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/92201-92300.json.br
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/92301-92400.json
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/92301-92400.json.br
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/92401-92500.json
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/92401-92500.json.br
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/92501-92600.json
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/92501-92600.json.br
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/92601-92700.json
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/92601-92700.json.br
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/92701-92800.json
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/92701-92800.json.br
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/92801-92900.json
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/92801-92900.json.br
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/92901-93000.json
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/92901-93000.json.br
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/93001-93100.json
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/93001-93100.json.br
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/93101-93200.json
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/93101-93200.json.br
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/93201-93300.json
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/93201-93300.json.br
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/93301-93400.json
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/93301-93400.json.br
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/93401-93500.json
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/93401-93500.json.br
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/93501-93600.json
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/93501-93600.json.br
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/93601-93700.json
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/93601-93700.json.br
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/93701-93800.json
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/93701-93800.json.br
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/93801-93900.json
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/93801-93900.json.br
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/93901-94000.json
#	scratch-gui/static/unity/StreamingAssets/aa/levels-db/93901-94000.json.br
#	scratch-gui/static/unity/StreamingAssets/aa/levels-manifest.json
#	scratch-gui/static/unity/StreamingAssets/aa/settings.json
#	scratch-gui/static/unity/levels-database.json
#	scratch-gui/static/unity/levels-database.json.br
#	scratch-gui/static/unity/levels-db-index.json
#	scratch-gui/static/unity/levels-db-index.json.br
2026-07-17 17:29:53 +08:00
Evan
3bafb1e10d cocos 2026-07-17 17:19:24 +08:00
b08562d603 no message 2026-06-18 13:58:39 +08:00
33070ad827 no message 2026-06-16 16:27:02 +08:00
6e0a1fbcbb Initial commit of 001code-html Scratch frontend project.
Includes scratch-gui, scratch-vm, scratch-blocks, scratch-render, scratch-l10n, and deployment config.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-16 15:37:45 +08:00
421 changed files with 3729 additions and 540 deletions

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
.DS_Store
node_modules/
npm-debug.log*
.secrets

View File

@@ -17,6 +17,23 @@ server {
return 301 /competition.html?competition_id=13; return 301 /competition.html?competition_id=13;
} }
<<<<<<< HEAD
# Brotli 压缩 WebAssembly 文件处理
location ~* \.wasm\.br$ {
default_type "";
add_header Content-Encoding br;
add_header Content-Type application/wasm always;
add_header Vary Accept-Encoding;
expires 30d;
}
location ~* \.asm\.js\.br$ {
default_type "";
add_header Content-Encoding br;
add_header Content-Type application/javascript always;
add_header Vary Accept-Encoding;
expires 30d;
=======
# Unity 预压缩文件:禁止再次 gzip避免 Content-Length 与实际内容不一致 # Unity 预压缩文件:禁止再次 gzip避免 Content-Length 与实际内容不一致
location ~* \.wasm\.br$ { location ~* \.wasm\.br$ {
gzip off; gzip off;
@@ -45,15 +62,22 @@ server {
add_header Vary Accept-Encoding; add_header Vary Accept-Encoding;
add_header Accept-Ranges bytes; add_header Accept-Ranges bytes;
expires 1h; expires 1h;
>>>>>>> cocos-main
} }
# 通用 Brotli 文件处理 # 通用 Brotli 文件处理
location ~* \.br$ { location ~* \.br$ {
<<<<<<< HEAD
add_header Content-Encoding br;
add_header Vary Accept-Encoding;
expires 30d;
=======
gzip off; gzip off;
add_header Content-Encoding br; add_header Content-Encoding br;
add_header Vary Accept-Encoding; add_header Vary Accept-Encoding;
add_header Accept-Ranges bytes; add_header Accept-Ranges bytes;
expires 1h; expires 1h;
>>>>>>> cocos-main
} }
# 静态资源缓存配置 # 静态资源缓存配置

View File

@@ -4,10 +4,6 @@ server {
index index.html index.htm default.htm default.html; index index.html index.htm default.htm default.html;
root /usr/share/nginx/html; root /usr/share/nginx/html;
# 1. 添加 resolver 指令
# 127.0.0.11 是 Docker 内置的 DNS 服务器地址 并且将缓存设置为10s
# resolver 127.0.0.11 valid=10s;
# gzip 配置 # gzip 配置
gzip on; gzip on;
gzip_static on; gzip_static on;
@@ -22,37 +18,21 @@ server {
return 301 /competition.html?competition_id=13; return 301 /competition.html?competition_id=13;
} }
# Unity 预压缩文件:禁止再次 gzip避免 Content-Length 与实际内容不一致 # Brotli 压缩 WebAssembly 文件处理
location ~* \.wasm\.br$ { location ~* \.wasm\.br$ {
gzip off; default_type "";
gzip_static off;
default_type application/wasm;
add_header Content-Encoding br; add_header Content-Encoding br;
add_header Content-Type application/wasm always; add_header Content-Type application/wasm always;
add_header Vary Accept-Encoding; add_header Vary Accept-Encoding;
add_header Accept-Ranges bytes; expires 30d;
expires 1h;
} }
location ~* \.js\.br$ { location ~* \.asm\.js\.br$ {
gzip off; default_type "";
gzip_static off;
default_type application/javascript;
add_header Content-Encoding br; add_header Content-Encoding br;
add_header Content-Type application/javascript always; add_header Content-Type application/javascript always;
add_header Vary Accept-Encoding; add_header Vary Accept-Encoding;
add_header Accept-Ranges bytes; expires 30d;
expires 1h;
}
location ~* \.data\.br$ {
gzip off;
gzip_static off;
default_type application/octet-stream;
add_header Content-Encoding br;
add_header Vary Accept-Encoding;
add_header Accept-Ranges bytes;
expires 1h;
} }
# 通用 Brotli 文件处理 # 通用 Brotli 文件处理
@@ -78,12 +58,10 @@ server {
access_log off; access_log off;
} }
# 纯 CDN/cdn-unity/ → OSS 游戏包config.js unityCdnUseSiteProxy: true
# 路径需与 unityCdnRemote 保持一致,更新 OSS 目录时同步修改 # 路径需与 unityCdnRemote 保持一致,更新 OSS 目录时同步修改
# location /cdn-unity/ { # location /cdn-unity/ {
# # 2. 将域名赋值给一个变量 # proxy_pass https://oss.eanic.cn/001_code_cocos_res_20260616/;
# set $oss_backend "https://oss.eanic.cn";
# # 3. proxy_pass 使用变量,这样 Nginx 就会在运行时解析域名
# proxy_pass $oss_backend/001_code_cocos_res_20260616/;
# proxy_ssl_server_name on; # proxy_ssl_server_name on;
# proxy_set_header Host oss.eanic.cn; # proxy_set_header Host oss.eanic.cn;
# proxy_hide_header Access-Control-Allow-Origin; # proxy_hide_header Access-Control-Allow-Origin;

0
scratch-blocks/build.py Normal file → Executable file
View File

0
scratch-blocks/cleanup.sh Normal file → Executable file
View File

0
scratch-blocks/i18n/create_messages.py Normal file → Executable file
View File

0
scratch-blocks/i18n/dedup_json.py Normal file → Executable file
View File

0
scratch-blocks/i18n/js_to_json.py Normal file → Executable file
View File

0
scratch-blocks/i18n/json_to_js.py Normal file → Executable file
View File

0
scratch-blocks/i18n/sync_tx_translations.js Normal file → Executable file
View File

0
scratch-blocks/i18n/xliff_to_json.py Normal file → Executable file
View File

0
scratch-blocks/local_build.sh Normal file → Executable file
View File

0
scratch-blocks/media/icons/control_forever.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

0
scratch-blocks/media/icons/control_repeat.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

0
scratch-blocks/media/icons/control_wait.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

0
scratch-blocks/media/icons/event_broadcast_blue.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

0
scratch-blocks/media/icons/event_broadcast_coral.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

0
scratch-blocks/media/icons/event_broadcast_green.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

0
scratch-blocks/media/icons/event_broadcast_magenta.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

0
scratch-blocks/media/icons/event_broadcast_orange.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

0
scratch-blocks/media/icons/event_broadcast_purple.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

0
scratch-blocks/media/icons/event_whenflagclicked.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 634 B

After

Width:  |  Height:  |  Size: 634 B

0
scratch-blocks/media/icons/set-led_blue.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

0
scratch-blocks/media/icons/set-led_coral.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

0
scratch-blocks/media/icons/set-led_green.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

0
scratch-blocks/media/icons/set-led_magenta.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

0
scratch-blocks/media/icons/set-led_mystery.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

0
scratch-blocks/media/icons/set-led_orange.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

0
scratch-blocks/media/icons/set-led_purple.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

0
scratch-blocks/media/icons/set-led_white.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

0
scratch-blocks/media/icons/set-led_yellow.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

0
scratch-blocks/media/icons/wedo_motor-clockwise.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

0
scratch-blocks/media/icons/wedo_when-tilt-backward.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

0
scratch-blocks/media/icons/wedo_when-tilt-forward.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

0
scratch-blocks/media/icons/wedo_when-tilt-left.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

0
scratch-blocks/media/icons/wedo_when-tilt-right.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

0
scratch-blocks/media/icons/wedo_when-tilt.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@@ -144,7 +144,6 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.7.tgz", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.7.tgz",
"integrity": "sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==", "integrity": "sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"@ampproject/remapping": "^2.2.0", "@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.23.5", "@babel/code-frame": "^7.23.5",
@@ -915,7 +914,6 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
"integrity": "sha512-Ajr4IcMXq/2QmMkEmSvxqfLN5zGmJ92gHXAeOXq1OekoH2rfDNsgdDoL2f7QaRCy7G/E6TpxBVdRuNraMztGHw==", "integrity": "sha512-Ajr4IcMXq/2QmMkEmSvxqfLN5zGmJ92gHXAeOXq1OekoH2rfDNsgdDoL2f7QaRCy7G/E6TpxBVdRuNraMztGHw==",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"co": "^4.6.0", "co": "^4.6.0",
"fast-deep-equal": "^1.0.0", "fast-deep-equal": "^1.0.0",
@@ -1573,7 +1571,6 @@
"url": "https://github.com/sponsors/ai" "url": "https://github.com/sponsors/ai"
} }
], ],
"peer": true,
"dependencies": { "dependencies": {
"caniuse-lite": "^1.0.30001565", "caniuse-lite": "^1.0.30001565",
"electron-to-chromium": "^1.4.601", "electron-to-chromium": "^1.4.601",
@@ -6912,7 +6909,6 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"fast-deep-equal": "^3.1.1", "fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0", "fast-json-stable-stringify": "^2.0.0",
@@ -7808,7 +7804,6 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"fast-deep-equal": "^3.1.1", "fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0", "fast-json-stable-stringify": "^2.0.0",
@@ -8946,7 +8941,6 @@
"resolved": "https://registry.npmjs.org/webpack/-/webpack-4.47.0.tgz", "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.47.0.tgz",
"integrity": "sha512-td7fYwgLSrky3fI1EuU5cneU4+pbH6GgOfuKNS1tNPcfdGinGELAqsb/BP4nnvZyKSG2i/xFGU7+n2PvZA8HJQ==", "integrity": "sha512-td7fYwgLSrky3fI1EuU5cneU4+pbH6GgOfuKNS1tNPcfdGinGELAqsb/BP4nnvZyKSG2i/xFGU7+n2PvZA8HJQ==",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"@webassemblyjs/ast": "1.9.0", "@webassemblyjs/ast": "1.9.0",
"@webassemblyjs/helper-module-context": "1.9.0", "@webassemblyjs/helper-module-context": "1.9.0",
@@ -9101,7 +9095,6 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"fast-deep-equal": "^3.1.1", "fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0", "fast-json-stable-stringify": "^2.0.0",

0
scratch-blocks/pull_from_blockly.sh Normal file → Executable file
View File

View File

@@ -7688,9 +7688,9 @@
} }
}, },
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001649", "version": "1.0.30001810",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001649.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz",
"integrity": "sha512-fJegqZZ0ZX8HOWr6rcafGr72+xcgJKI9oWfDW5DrD7ExUtgZC7a7R7ZYmZqplh7XDocFdGeIFn7roAxhOeYrPQ==", "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@@ -7704,7 +7704,8 @@
"type": "github", "type": "github",
"url": "https://github.com/sponsors/ai" "url": "https://github.com/sponsors/ai"
} }
] ],
"license": "CC-BY-4.0"
}, },
"node_modules/canvas-toBlob": { "node_modules/canvas-toBlob": {
"version": "1.0.0", "version": "1.0.0",

View File

@@ -15,7 +15,7 @@
"build:cdn-pure": "npm run clean && cross-env NODE_ENV=production UNITY_CDN_PURE=1 webpack --colors --bail", "build:cdn-pure": "npm run clean && cross-env NODE_ENV=production UNITY_CDN_PURE=1 webpack --colors --bail",
"build:test": "npm run clean && cross-env NODE_ENV=production node scripts\\patch-config.js && webpack --colors --bail", "build:test": "npm run clean && cross-env NODE_ENV=production node scripts\\patch-config.js && webpack --colors --bail",
"build:prod": "npm run clean && cross-env NODE_ENV=production node scripts\\patch-config.js && webpack --colors --bail", "build:prod": "npm run clean && cross-env NODE_ENV=production node scripts\\patch-config.js && webpack --colors --bail",
"clean": "rimraf ./build && mkdirp build && rimraf ./dist && mkdirp dist", "clean": "rimraf ./build && mkdirp build && rimraf ./dist && mkdirp dist && rimraf ./node_modules/.cache",
"deploy": "touch build/.nojekyll && gh-pages -t -d build -m \"[skip ci] Build for $(git log --pretty=format:%H -n1)\"", "deploy": "touch build/.nojekyll && gh-pages -t -d build -m \"[skip ci] Build for $(git log --pretty=format:%H -n1)\"",
"prepublish": "node scripts/prepublish.mjs", "prepublish": "node scripts/prepublish.mjs",
"prune": "./prune-gh-pages.sh", "prune": "./prune-gh-pages.sh",

0
scratch-gui/prune-gh-pages.sh Normal file → Executable file
View File

View File

@@ -11,6 +11,7 @@ import RankBadgeGenerator from '../../playground/rank-badge-generator.js';
// const friendToggle = new FriendToggle(); // const friendToggle = new FriendToggle();
window.RankBadgeGenerator = RankBadgeGenerator; window.RankBadgeGenerator = RankBadgeGenerator;
window.CONFIG = CONFIG; window.CONFIG = CONFIG;
import disableDevtool from 'disable-devtool';
import { initDisableDevtool } from '../../playground/devtool-control.js'; import { initDisableDevtool } from '../../playground/devtool-control.js';
import { getUnityPlayerConfig, loadUnityLoaderScript } from '../../lib/unity-build-loader.js'; import { getUnityPlayerConfig, loadUnityLoaderScript } from '../../lib/unity-build-loader.js';
import { debug } from 'scratch-vm/src/util/log.js'; import { debug } from 'scratch-vm/src/util/log.js';
@@ -547,29 +548,39 @@ const UnityComponent = function (props) {
const [hasAlerted, setHasAlerted] = useState(false); const [hasAlerted, setHasAlerted] = useState(false);
useEffect(() => { useEffect(() => {
initDisableDevtool({ if (CONFIG.disabledev) {
ondevtoolopen: () => { disableDevtool({
ondevtoolopen: () => {
// 临时禁用 onbeforeunload 事件监听,以防止弹出确认离开弹窗 // 临时禁用 onbeforeunload 事件监听,以防止弹出确认离开弹窗
const originalOnBeforeUnload = window.onbeforeunload; const originalOnBeforeUnload = window.onbeforeunload;
window.onbeforeunload = null; window.onbeforeunload = null;
window.cppCodeStopRun(); window.cppCodeStopRun();
window.loadCppProject(""); window.loadCppProject("");
// 销毁 Unity 实例 // 销毁游戏实例Cocos 兼容Quit 可能不存在)
if (window.unityInstance) { if (window.unityInstance) {
window.unityInstance.Quit().then(() => { const quit = window.unityInstance.Quit;
window.unityInstance = null; if (typeof quit === 'function') {
}); Promise.resolve(quit.call(window.unityInstance)).then(() => {
} window.unityInstance = null;
});
} else {
window.unityInstance = null;
}
}
// 延迟跳转到目标页面,确保销毁 // 延迟跳转到目标页面,确保销毁
window.location.href = localStorage.getItem('returnUrl'); window.location.href = localStorage.getItem('returnUrl');
// window.location.href = '/matchsum.html'; // window.location.href = '/matchsum.html';
// 恢复原始的 onbeforeunload 监听器 // 恢复原始的 onbeforeunload 监听器
window.onbeforeunload = originalOnBeforeUnload; window.onbeforeunload = originalOnBeforeUnload;
} },
}); interval: 500, // 检测间隔时间
clearLog: true, // 清除控制台的日志
disableMenu: true, // 禁用右键菜单
});
}
}, []); }, []);
useEffect(() => { useEffect(() => {
@@ -583,7 +594,7 @@ const UnityComponent = function (props) {
//计算真实关卡位置 //计算真实关卡位置
let realLvId = 0; let realLvId = 0;
if (localStorage.getItem('platformMode') === 'normal') { if (localStorage.getItem('platformMode') === 'normal') {
realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber) + window.gamelvdata.currentlv realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber, window.gamelvdataJson.gamemode) + window.gamelvdata.currentlv
} else { } else {
realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber) realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber)
} }
@@ -693,7 +704,7 @@ const UnityComponent = function (props) {
window.iscreate = 1; window.iscreate = 1;
let realLvId = 0; let realLvId = 0;
if (localStorage.getItem('platformMode') === 'normal') { if (localStorage.getItem('platformMode') === 'normal') {
realLvId = CONFIG.getRealLvId(gamelvdataJson.gamelv, gamelvdataJson.gameid, gamelvdataJson.ismatch, gamelvdataJson.gameNumber) + window.gamelvdata.currentlv realLvId = CONFIG.getRealLvId(gamelvdataJson.gamelv, gamelvdataJson.gameid, gamelvdataJson.ismatch, gamelvdataJson.gameNumber, gamelvdataJson.gamemode) + window.gamelvdata.currentlv
} else { } else {
realLvId = CONFIG.getRealLvId(gamelvdataJson.gamelv, gamelvdataJson.gameid, gamelvdataJson.ismatch, gamelvdataJson.gameNumber) realLvId = CONFIG.getRealLvId(gamelvdataJson.gamelv, gamelvdataJson.gameid, gamelvdataJson.ismatch, gamelvdataJson.gameNumber)
} }
@@ -710,7 +721,8 @@ const UnityComponent = function (props) {
// 延迟 500 毫秒后切换关卡,只执行一次 // 延迟 500 毫秒后切换关卡,只执行一次
setTimeout(() => { setTimeout(() => {
if (localStorage.getItem('platformMode') === 'normal') { if (localStorage.getItem('platformMode') === 'normal') {
const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber) + window.gamelvdata.currentlv
const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber, window.gamelvdataJson.gamemode) + window.gamelvdata.currentlv
window.unityInstance.SendMessage("GameController", "SwitchLevel", realLvId); window.unityInstance.SendMessage("GameController", "SwitchLevel", realLvId);
} else { } else {
const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber) const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber)
@@ -769,7 +781,8 @@ const UnityComponent = function (props) {
const savedProject = window.cppCode; const savedProject = window.cppCode;
setIsLockNextButton(true); setIsLockNextButton(true);
const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber) + window.gamelvdata.currentlv
const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber, window.gamelvdataJson.gamemode) + window.gamelvdata.currentlv
const trialCount = localStorage.getItem('trial_count'); const trialCount = localStorage.getItem('trial_count');
if (localStorage.getItem('permission') === "0" && (realLvId - CONFIG.BEGINNING_REAL_LVID) >= trialCount && currentlv > 9) { if (localStorage.getItem('permission') === "0" && (realLvId - CONFIG.BEGINNING_REAL_LVID) >= trialCount && currentlv > 9) {
@@ -1152,8 +1165,9 @@ const UnityComponent = function (props) {
} else { } else {
setIsNextButtonComplete(false); setIsNextButtonComplete(false);
} }
window.gamelvdata.currentlv = window.gamelvdata.currentlv + 1 window.gamelvdata.currentlv = window.gamelvdata.currentlv + 1
const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber) + window.gamelvdata.currentlv const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber, window.gamelvdataJson.gamemode) + window.gamelvdata.currentlv
window.unityInstance.SendMessage("GameController", "SwitchLevel", realLvId); window.unityInstance.SendMessage("GameController", "SwitchLevel", realLvId);
CONFIG.checkGameStyle(realLvId); CONFIG.checkGameStyle(realLvId);
@@ -1210,7 +1224,8 @@ const UnityComponent = function (props) {
}; };
const handleRetry = () => { const handleRetry = () => {
const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber) + window.gamelvdata.currentlv
const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber, window.gamelvdataJson.gamemode) + window.gamelvdata.currentlv
window.unityInstance.SendMessage("GameController", "SwitchLevel", realLvId); window.unityInstance.SendMessage("GameController", "SwitchLevel", realLvId);
console.log("Retrying the current level..."); console.log("Retrying the current level...");
}; };
@@ -1218,46 +1233,86 @@ const UnityComponent = function (props) {
useEffect(() => { useEffect(() => {
const canvas = canvasRef.current; const canvas = canvasRef.current;
let cancelled = false;
const bootUnity = async () => { // if (canvas && !window.unityInstance) {
const config = await getUnityPlayerConfig(); const unityUrl = "/unity";
await loadUnityLoaderScript(); const buildUrl = "/unity/Build";
if (cancelled || !canvas) { const cdnRoot = CONFIG.usecdn ? getUnityCdnRoot() : unityUrl;
return; const cdnBuildRoot = CONFIG.usecdn ? getUnityCdnBuildRoot() : buildUrl;
} let loaderUrl = CONFIG.usecdn
? `${cdnBuildRoot}/mstest5.loader.js`
: `${buildUrl}/mstest5.loader.js`;
let config = {
dataUrl: buildUrl + "/mstest5.data.br",
frameworkUrl: buildUrl + "/mstest5.framework.js.br",
codeUrl: buildUrl + "/mstest5.wasm.br",
streamingAssetsUrl: unityUrl + "/StreamingAssets",
companyName: "DefaultCompany",
productName: "Web A",
productVersion: "1.0",
};
if (CONFIG.usecdn) {
config = {
dataUrl: cdnBuildRoot + "/mstest5.data.br",
frameworkUrl: cdnBuildRoot + "/mstest5.framework.js.br",
codeUrl: cdnBuildRoot + "/mstest5.wasm.br",
streamingAssetsUrl: cdnRoot + "/StreamingAssets",
// dataUrl: buildUrl + "/Build.data.br",
// frameworkUrl: buildUrl + "/Build.framework.js.br",
// codeUrl: buildUrl + "/Build.wasm.br",
// streamingAssetsUrl: unityUrl + "/StreamingAssets",
companyName: "DefaultCompany",
productName: "Web A",
productVersion: "1.0",
};
}
const script = document.createElement("script");
script.src = loaderUrl;
script.onload = () => {
window.iscreate = 0; window.iscreate = 0;
const unityInstance = await createUnityInstance(canvas, config, () => {}); const boot = () => {
if (cancelled) { createUnityInstance(canvas, config, (progress) => {
return; // console.log(`加载进度: ${progress * 100}%`);
} }).then((unityInstance) => {
window.unityInstance = unityInstance; window.unityInstance = unityInstance;
window.waitForUnityStepFinish = waitForUnityStepFinish; window.waitForUnityStepFinish = waitForUnityStepFinish;
window.waitForUnityVehicleStepFinish = waitForUnityVehicleStepFinish; window.waitForUnityVehicleStepFinish = waitForUnityVehicleStepFinish;
window.sleepForUnityStepFinish = sleepForUnityStepFinish; window.sleepForUnityStepFinish = sleepForUnityStepFinish;
window.sleepByStepForUnityStepFinish = sleepByStepForUnityStepFinish; window.sleepByStepForUnityStepFinish = sleepByStepForUnityStepFinish;
console.log("Unity 实例创建成功"); console.log("Unity 实例创建成功");
window.processData = processData; window.processData = processData;
window.processVehicleData = processVehicleData; window.processVehicleData = processVehicleData;
window.externalResult = externalResult; window.externalResult = externalResult;
window.externalLevelInfo = externalLevelInfo; window.externalLevelInfo = externalLevelInfo;
let realLvId = 0; //计算真实关卡位置
if (localStorage.getItem('platformMode') === 'normal') { let realLvId = 0;
realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber) + window.gamelvdata.currentlv if (localStorage.getItem('platformMode') === 'normal') {
realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber, window.gamelvdataJson.gamemode) + window.gamelvdata.currentlv
} else {
realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber)
}
CONFIG.checkGameStyle(realLvId);
window.unityInstance.SendMessage("GameController", "SwitchLevel", realLvId);
}).catch((message) => {
console.error(`Unity 实例创建失败: ${message}`);
});
};
if (CONFIG.usecdn) {
prefetchLevelsDatabase(cdnRoot).then(boot).catch((err) => {
console.error('[unity-cdn] 关卡库预取失败', err);
boot();
});
} else { } else {
realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber) boot();
} }
CONFIG.checkGameStyle(realLvId);
window.unityInstance.SendMessage("GameController", "SwitchLevel", realLvId);
}; };
bootUnity().catch((message) => { document.body.appendChild(script);
console.error(`Unity 实例创建失败: ${message}`); // } else {
}); // console.log("Unity 实例已经存在,跳过初始化");
// }
return () => {
cancelled = true;
};
}, []); }, []);
// 修改 formatDateTime 函数 // 修改 formatDateTime 函数

View File

@@ -771,40 +771,18 @@ export class CppCodeExecutor {
continue; continue;
} }
// 检查是否是函数调用(包括带参数的 // 检查是否是自定义函数调用(包括带括号的实参,如 f((n + 1));
const functionCallMatch = line.match(/(\w+)\s*\(([^)]*)\)\s*;?/); const customCall = this.parseCustomFunctionCall(line);
if (functionCallMatch) { if (customCall) {
const functionName = functionCallMatch[1]; statements.push({
const argumentsStr = functionCallMatch[2]; type: 'function_call',
functionName: customCall.functionName,
// 排除C++关键字和控制结构 arguments: customCall.arguments,
const cppKeywords = [ lineNumber: isMainFunction ? this.getActualLineNumber(i) : i + 1,
'for', 'while', 'if', 'else', 'switch', 'case', 'return', content: line // 保存原始内容用于行号映射
'int', 'string', 'bool', 'void', 'float', 'double', 'char' });
]; i++;
continue;
// 检查是否是游戏API函数这些不是自定义函数
const gameApiFunctions = [
'playerMove', 'playerJump', 'turnLeft', 'turnRight',
'vehicleMove', 'turnVehicleLeft', 'turnVehicleRight',
'player_data', 'player_position', 'vehicle_position'
];
if (!cppKeywords.includes(functionName) &&
!gameApiFunctions.includes(functionName) &&
!line.includes('cout')) {
// 这是自定义函数调用
const parsedArguments = this.parseArguments(argumentsStr);
statements.push({
type: 'function_call',
functionName: functionName,
arguments: parsedArguments,
lineNumber: isMainFunction ? this.getActualLineNumber(i) : i + 1,
content: line // 保存原始内容用于行号映射
});
i++;
continue;
}
} }
// 解析不同类型的语句 // 解析不同类型的语句
@@ -821,8 +799,8 @@ export class CppCodeExecutor {
statements.push(whileLoop); statements.push(whileLoop);
i = whileLoop.endIndex; i = whileLoop.endIndex;
} else { } else {
// 检查是否是break或continue语句 // 检查是否是break或continue或return语句
if (line === 'break;' || line === 'continue;') { if (line === 'break;' || line === 'continue;' || line.startsWith('return')) {
statements.push({ statements.push({
type: 'control', type: 'control',
subtype: line === 'break;' ? 'break' : 'continue', subtype: line === 'break;' ? 'break' : 'continue',
@@ -866,21 +844,27 @@ export class CppCodeExecutor {
let braceCount = 0; let braceCount = 0;
let bodyStart = startIndex + 1; let bodyStart = startIndex + 1;
let bodyEnd = startIndex + 1; let bodyEnd = startIndex + 1;
let hasBrace = false;
for (let i = startIndex; i < lines.length; i++) { for (let i = startIndex; i < lines.length; i++) {
const line = lines[i]; const line = lines[i];
debugLog(`🔍 检查行 ${i}: "${line.trim()}" (大括号计数: ${braceCount})`); debugLog(`🔍 检查行 ${i}: "${line.trim()}" (大括号计数: ${braceCount})`);
if (line.includes('{')) braceCount++; if (line.includes('{')) { braceCount++; hasBrace = true; }
if (line.includes('}')) braceCount--; if (line.includes('}')) braceCount--;
if (braceCount === 0 && i > startIndex) { if (hasBrace && braceCount === 0 && i > startIndex) {
bodyEnd = i; bodyEnd = i;
debugLog(`🔍 找到循环体结束位置: ${bodyEnd}`); debugLog(`🔍 找到循环体结束位置: ${bodyEnd}`);
break; break;
} }
if (!hasBrace && i > startIndex && line.trim() && !line.trim().startsWith('//')) {
bodyEnd = i + 1;
debugLog(`🔍 找到无大括号循环体结束位置: ${bodyEnd}`);
break;
}
} }
// 如果没有找到结束大括号,可能是格式问题 // 如果没有找到结束大括号,可能是格式问题
if (bodyEnd === startIndex + 1) { if (hasBrace && bodyEnd === startIndex + 1) {
debugLog(`⚠️ 警告:没有找到循环体结束大括号,检查代码格式`); debugLog(`⚠️ 警告:没有找到循环体结束大括号,检查代码格式`);
debugLog(`⚠️ 当前所有行内容:`); debugLog(`⚠️ 当前所有行内容:`);
lines.forEach((line, index) => { lines.forEach((line, index) => {
@@ -914,7 +898,7 @@ export class CppCodeExecutor {
increment, increment,
body: bodyStatements, body: bodyStatements,
lineNumber: isMainFunction ? this.getActualLineNumber(startIndex) : startIndex + 1, lineNumber: isMainFunction ? this.getActualLineNumber(startIndex) : startIndex + 1,
endIndex: bodyEnd + 1 endIndex: hasBrace ? bodyEnd + 1 : bodyEnd
}; };
} }
@@ -935,11 +919,26 @@ export class CppCodeExecutor {
const condition = ifMatch[1]; const condition = ifMatch[1];
// 最小化修改如果if同行包含执行语句把它拆分拆到下一行
const afterIf = ifLine.substring(ifMatch.index + ifMatch[0].length).trim();
if (afterIf && afterIf !== '{') {
if (afterIf.startsWith('{')) {
lines[startIndex] = ifLine.substring(0, ifLine.lastIndexOf(afterIf)) + '{';
const afterBrace = afterIf.substring(1).trim();
if (afterBrace) lines.splice(startIndex + 1, 0, afterBrace);
} else {
lines[startIndex] = ifLine.substring(0, ifLine.lastIndexOf(afterIf)).trim();
lines.splice(startIndex + 1, 0, afterIf);
}
}
// 找到if语句体 // 找到if语句体
let braceCount = 0; let braceCount = 0;
let bodyStart = startIndex + 1; let bodyStart = startIndex + 1;
let bodyEnd = startIndex + 1; let bodyEnd = startIndex + 1;
let ifClosingLine = ''; // 保存if语句的结束行可能包含else let ifClosingLine = ''; // 保存if语句的结束行可能包含else
let hasBrace = false;
for (let i = startIndex; i < lines.length; i++) { for (let i = startIndex; i < lines.length; i++) {
const line = lines[i]; const line = lines[i];
@@ -954,15 +953,31 @@ export class CppCodeExecutor {
break; break;
} }
if (line.includes('{')) braceCount++; if (line.includes('{')) { braceCount++; hasBrace = true; }
if (line.includes('}')) braceCount--; if (line.includes('}')) braceCount--;
if (braceCount === 0 && i > startIndex) {
if (hasBrace && braceCount === 0 && i > startIndex) {
// 普通的}结束 // 普通的}结束
bodyEnd = i; bodyEnd = i;
ifClosingLine = trimmedLine; ifClosingLine = trimmedLine;
debugLog(`🔍 if语句结束位置: 行${i}, 内容: "${ifClosingLine}", 是否包含else: ${ifClosingLine.includes('else')}`); debugLog(`🔍 if语句结束位置: 行${i}, 内容: "${ifClosingLine}", 是否包含else: ${ifClosingLine.includes('else')}`);
break; break;
} }
if (!hasBrace && i > startIndex && trimmedLine && !trimmedLine.startsWith('//')) {
bodyEnd = i + 1;
// 尝试寻找后续的else
for (let j = i + 1; j < lines.length; j++) {
const nextLine = lines[j].trim();
if (!nextLine || nextLine.startsWith('//')) continue;
if (nextLine.startsWith('else')) {
ifClosingLine = nextLine;
debugLog(`🔍 无大括号单行语句后发现else: 行${j}, 内容: "${ifClosingLine}"`);
}
break;
}
break;
}
} }
let bodyLines = lines.slice(bodyStart, bodyEnd); let bodyLines = lines.slice(bodyStart, bodyEnd);
@@ -984,7 +999,7 @@ export class CppCodeExecutor {
// 解析else if 和 else 分支 // 解析else if 和 else 分支
const elseIfBranches = []; const elseIfBranches = [];
let elseStatements = []; let elseStatements = [];
let currentIndex = bodyEnd + 1; let currentIndex = hasBrace ? bodyEnd + 1 : bodyEnd;
// 首先检查if结束行是否包含else处理 } else { 的情况) // 首先检查if结束行是否包含else处理 } else { 的情况)
if (ifClosingLine.includes('else')) { if (ifClosingLine.includes('else')) {
@@ -1110,15 +1125,20 @@ export class CppCodeExecutor {
let elseIfBraceCount = 0; let elseIfBraceCount = 0;
let elseIfBodyStart = currentIndex + 1; let elseIfBodyStart = currentIndex + 1;
let elseIfBodyEnd = currentIndex + 1; let elseIfBodyEnd = currentIndex + 1;
let elseIfHasBrace = false;
for (let i = currentIndex; i < lines.length; i++) { for (let i = currentIndex; i < lines.length; i++) {
const line = lines[i]; const line = lines[i];
if (line.includes('{')) elseIfBraceCount++; if (line.includes('{')) { elseIfBraceCount++; elseIfHasBrace = true; }
if (line.includes('}')) elseIfBraceCount--; if (line.includes('}')) elseIfBraceCount--;
if (elseIfBraceCount === 0 && i > currentIndex) { if (elseIfHasBrace && elseIfBraceCount === 0 && i > currentIndex) {
elseIfBodyEnd = i; elseIfBodyEnd = i;
break; break;
} }
if (!elseIfHasBrace && i > currentIndex && line.trim() && !line.trim().startsWith('//')) {
elseIfBodyEnd = i + 1;
break;
}
} }
const elseIfBodyLines = lines.slice(elseIfBodyStart, elseIfBodyEnd); const elseIfBodyLines = lines.slice(elseIfBodyStart, elseIfBodyEnd);
@@ -1131,7 +1151,7 @@ export class CppCodeExecutor {
debugLog(`🔍 解析else if语句体条件: ${elseIfCondition}, 行数: ${elseIfBodyLines.length}, 语句数: ${elseIfStatements.length}`); debugLog(`🔍 解析else if语句体条件: ${elseIfCondition}, 行数: ${elseIfBodyLines.length}, 语句数: ${elseIfStatements.length}`);
currentIndex = elseIfBodyEnd + 1; currentIndex = elseIfHasBrace ? elseIfBodyEnd + 1 : elseIfBodyEnd;
continue; continue;
} }
@@ -1143,15 +1163,20 @@ export class CppCodeExecutor {
let elseBraceCount = 0; let elseBraceCount = 0;
let elseBodyStart = currentIndex + 1; let elseBodyStart = currentIndex + 1;
let elseBodyEnd = currentIndex + 1; let elseBodyEnd = currentIndex + 1;
let elseHasBrace = false;
for (let i = currentIndex; i < lines.length; i++) { for (let i = currentIndex; i < lines.length; i++) {
const line = lines[i]; const line = lines[i];
if (line.includes('{')) elseBraceCount++; if (line.includes('{')) { elseBraceCount++; elseHasBrace = true; }
if (line.includes('}')) elseBraceCount--; if (line.includes('}')) elseBraceCount--;
if (elseBraceCount === 0 && i > currentIndex) { if (elseHasBrace && elseBraceCount === 0 && i > currentIndex) {
elseBodyEnd = i; elseBodyEnd = i;
break; break;
} }
if (!elseHasBrace && i > currentIndex && line.trim() && !line.trim().startsWith('//')) {
elseBodyEnd = i + 1;
break;
}
} }
let elseBodyLines = lines.slice(elseBodyStart, elseBodyEnd); let elseBodyLines = lines.slice(elseBodyStart, elseBodyEnd);
@@ -1173,7 +1198,7 @@ export class CppCodeExecutor {
debugLog(`🔍 解析else语句体行数: ${elseBodyLines.length}, 语句数: ${elseStatements.length}`); debugLog(`🔍 解析else语句体行数: ${elseBodyLines.length}, 语句数: ${elseStatements.length}`);
currentIndex = elseBodyEnd + 1; currentIndex = elseHasBrace ? elseBodyEnd + 1 : elseBodyEnd;
break; // else分支是最后一个不再继续 break; // else分支是最后一个不再继续
} }
@@ -1208,15 +1233,20 @@ export class CppCodeExecutor {
let braceCount = 0; let braceCount = 0;
let bodyStart = startIndex + 1; let bodyStart = startIndex + 1;
let bodyEnd = startIndex + 1; let bodyEnd = startIndex + 1;
let hasBrace = false;
for (let i = startIndex; i < lines.length; i++) { for (let i = startIndex; i < lines.length; i++) {
const line = lines[i]; const line = lines[i];
if (line.includes('{')) braceCount++; if (line.includes('{')) { braceCount++; hasBrace = true; }
if (line.includes('}')) braceCount--; if (line.includes('}')) braceCount--;
if (braceCount === 0 && i > startIndex) { if (hasBrace && braceCount === 0 && i > startIndex) {
bodyEnd = i; bodyEnd = i;
break; break;
} }
if (!hasBrace && i > startIndex && line.trim() && !line.trim().startsWith('//')) {
bodyEnd = i + 1;
break;
}
} }
let bodyLines = lines.slice(bodyStart, bodyEnd); let bodyLines = lines.slice(bodyStart, bodyEnd);
@@ -1239,7 +1269,7 @@ export class CppCodeExecutor {
condition, condition,
body: bodyStatements, body: bodyStatements,
lineNumber: isMainFunction ? this.getActualLineNumber(startIndex) : startIndex + 1, lineNumber: isMainFunction ? this.getActualLineNumber(startIndex) : startIndex + 1,
endIndex: bodyEnd + 1 endIndex: hasBrace ? bodyEnd + 1 : bodyEnd
}; };
} }
@@ -1259,7 +1289,7 @@ export class CppCodeExecutor {
// 高亮当前执行行 // 高亮当前执行行
if (this.setHighlightedLine) { if (this.setHighlightedLine) {
// this.setHighlightedLine(statement.lineNumber); this.setHighlightedLine(statement.lineNumber);
} }
await new Promise(resolve => setTimeout(resolve, 0)); await new Promise(resolve => setTimeout(resolve, 0));
@@ -1282,6 +1312,9 @@ export class CppCodeExecutor {
await this.executeFunctionCall(statement); await this.executeFunctionCall(statement);
break; break;
case 'control': case 'control':
if (statement.content.startsWith('return')) {
throw new Error('RETURN_INTERRUPT');
}
// break和continue在各自的循环中处理这里只记录 // break和continue在各自的循环中处理这里只记录
debugLog(`🔄 控制语句: ${statement.subtype}`); debugLog(`🔄 控制语句: ${statement.subtype}`);
break; break;
@@ -1291,29 +1324,16 @@ export class CppCodeExecutor {
async executeSimpleStatement(content) { async executeSimpleStatement(content) {
debugLog(`🔍 执行简单语句: ${content}`); debugLog(`🔍 执行简单语句: ${content}`);
// 检查是否是函数调用(包括带参数的 // 检查是否是自定义函数调用(包括带括号的实参,如 f((n + 1));
const functionCallMatch = content.match(/(\w+)\s*\(([^)]*)\)\s*;?/); const customCall = this.parseCustomFunctionCall(content);
if (functionCallMatch) { if (customCall && this.functions.has(customCall.functionName)) {
const functionName = functionCallMatch[1]; console.log(`📞 调用自定义函数: ${customCall.functionName}(${customCall.arguments.join(', ')})`);
const argumentsStr = functionCallMatch[2]; await this.executeFunctionCall({
type: 'function_call',
// 排除C++关键字和控制结构 functionName: customCall.functionName,
const cppKeywords = [ arguments: customCall.arguments
'for', 'while', 'if', 'else', 'switch', 'case', 'return', });
'int', 'string', 'bool', 'void', 'float', 'double', 'char' return;
];
// 检查是否是自定义函数(排除关键字)
if (!cppKeywords.includes(functionName) && this.functions.has(functionName)) {
console.log(`📞 调用自定义函数: ${functionName}(${argumentsStr})`);
const parsedArguments = this.parseArguments(argumentsStr);
await this.executeFunctionCall({
type: 'function_call',
functionName: functionName,
arguments: parsedArguments
});
return;
}
} }
// 自增/自减语句 (如 a++; 或 ++a;) // 自增/自减语句 (如 a++; 或 ++a;)
@@ -1792,8 +1812,12 @@ export class CppCodeExecutor {
}); });
try { try {
// 创建函数作用域(保存当前变量状态) // 最小改动:防递归数据污染,只备份会被覆盖的同名参数变量
const savedVariables = new Map(this.variables); const savedParams = new Map();
for (let i = 0; i < functionInfo.parameters.length; i++) {
const pName = functionInfo.parameters[i].name;
if (this.variables.has(pName)) savedParams.set(pName, this.variables.get(pName));
}
// 设置函数参数变量 // 设置函数参数变量
for (let i = 0; i < functionInfo.parameters.length; i++) { for (let i = 0; i < functionInfo.parameters.length; i++) {
@@ -1808,32 +1832,42 @@ export class CppCodeExecutor {
} }
// 执行函数体中的所有语句 // 执行函数体中的所有语句
for (const functionStatement of functionInfo.body) { try {
if (this.shouldStop()) break; for (const functionStatement of functionInfo.body) {
if (this.shouldStop()) break;
// 使用预先计算好的精确行号,如果没有则计算行号 // 使用预先计算好的精确行号,如果没有则计算行号
let adjustedStatement; let adjustedStatement;
if (functionStatement.exactLineNumber) { if (functionStatement.exactLineNumber) {
adjustedStatement = { adjustedStatement = {
...functionStatement, ...functionStatement,
lineNumber: functionStatement.exactLineNumber lineNumber: functionStatement.exactLineNumber
}; };
console.log(`🎯 使用函数内精确行号: "${functionStatement.content}" -> 第${functionStatement.exactLineNumber}行 (函数: ${functionName})`); console.log(`🎯 使用函数内精确行号: "${functionStatement.content}" -> 第${functionStatement.exactLineNumber}行 (函数: ${functionName})`);
} else { } else {
// 需要更精确地计算函数内语句的实际行号 // 需要更精确地计算函数内语句的实际行号
const actualLineNumber = this.calculateActualLineNumber(functionName, functionStatement); const actualLineNumber = this.calculateActualLineNumber(functionName, functionStatement);
adjustedStatement = { adjustedStatement = {
...functionStatement, ...functionStatement,
lineNumber: actualLineNumber lineNumber: actualLineNumber
}; };
}
await this.executeStatement(adjustedStatement);
} }
} catch (e) {
await this.executeStatement(adjustedStatement); if (e.message !== 'RETURN_INTERRUPT') throw e;
} }
// 恢复函数调用前的变量状态(简单的作用域实现) // 最小改动:仅恢复递归调用前的参数状态,保留全局变量的修改
// 注意这是简化版本实际C++的作用域更复杂 for (let i = 0; i < functionInfo.parameters.length; i++) {
this.variables = savedVariables; const pName = functionInfo.parameters[i].name;
if (savedParams.has(pName)) {
this.variables.set(pName, savedParams.get(pName));
} else {
this.variables.delete(pName);
}
}
console.log(`✅ 函数${functionName}执行完成`); console.log(`✅ 函数${functionName}执行完成`);
@@ -2089,7 +2123,46 @@ export class CppCodeExecutor {
} }
} }
// 解析函数调用参数 // 解析自定义函数调用,正确处理实参里的嵌套括号(如 f((n + 1))
parseCustomFunctionCall(content) {
if (!content) {
return null;
}
const cppKeywords = [
'for', 'while', 'if', 'else', 'switch', 'case', 'return',
'int', 'string', 'bool', 'void', 'float', 'double', 'char'
];
const gameApiFunctions = [
'playerMove', 'playerJump', 'turnLeft', 'turnRight',
'vehicleMove', 'turnVehicleLeft', 'turnVehicleRight',
'player_data', 'player_position', 'vehicle_position'
];
const nameMatch = content.match(/(\w+)\s*\(/);
if (!nameMatch) {
return null;
}
const functionName = nameMatch[1];
if (cppKeywords.includes(functionName) ||
gameApiFunctions.includes(functionName) ||
content.includes('cout')) {
return null;
}
const parsedArguments = this.extractFunctionArguments(content, functionName);
if (parsedArguments === null) {
return null;
}
return {
functionName,
arguments: parsedArguments
};
}
// 解析函数调用参数,按逗号分割时忽略括号内的逗号
parseArguments(argumentsStr) { parseArguments(argumentsStr) {
const argumentsList = []; const argumentsList = [];
@@ -2097,14 +2170,29 @@ export class CppCodeExecutor {
return argumentsList; // 无参数调用 return argumentsList; // 无参数调用
} }
// 分割参数,支持多个参数 let currentArg = '';
const argParts = argumentsStr.split(','); let nestedParens = 0;
for (const argPart of argParts) { for (let j = 0; j < argumentsStr.length; j++) {
const trimmed = argPart.trim(); const char = argumentsStr[j];
if (trimmed) {
argumentsList.push(trimmed); if (char === '(') {
nestedParens++;
} else if (char === ')') {
nestedParens--;
} else if (char === ',' && nestedParens === 0) {
if (currentArg.trim()) {
argumentsList.push(currentArg.trim());
}
currentArg = '';
continue;
} }
currentArg += char;
}
if (currentArg.trim()) {
argumentsList.push(currentArg.trim());
} }
return argumentsList; return argumentsList;
@@ -2332,28 +2420,10 @@ export class CppCodeExecutor {
// 处理一元运算符(负号) // 处理一元运算符(负号)
expr = this.handleUnaryOperators(expr); expr = this.handleUnaryOperators(expr);
// 按运算优先级解析:乘法、除法和模运算优先 // 按正确的运算优先级解析:
if (expr.includes('*') || expr.includes('/') || expr.includes('%')) { // 加法和减法是最低优先级,因此在此处最先切分。
return this.parseMultiplicationDivision(expr); // 切分后的每一项将交给 parseAdditionSubtraction在其中处理更高级别的乘除法。
} return this.parseAdditionSubtraction(expr);
// 然后处理加法和减法
if (expr.includes('+') || expr.includes('-')) {
return this.parseAdditionSubtraction(expr);
}
// 如果是单个值
if (/^-?\d+$/.test(expr)) {
return parseInt(expr);
}
// 变量查找
if (this.variables.has(expr)) {
return this.variables.get(expr);
}
debugLog(`⚠️ 无法识别的表达式: ${expr}, 返回默认值 0`);
return 0;
} catch (error) { } catch (error) {
debugLog(`⚠️ 表达式解析错误: ${expr}, 错误: ${error.message}`); debugLog(`⚠️ 表达式解析错误: ${expr}, 错误: ${error.message}`);
@@ -2490,20 +2560,49 @@ export class CppCodeExecutor {
// 计算单个标记的值 // 计算单个标记的值
evaluateToken(token) { evaluateToken(token) {
token = token.trim(); token = token.trim();
if (!token) return 0;
// 如果包含乘除法或模运算,交给乘除法解析器处理
if (token.includes('*') || token.includes('/') || token.includes('%')) {
return this.parseMultiplicationDivision(token);
}
// 布尔常量
if (token === 'true') return 1;
if (token === 'false') return 0;
// 数字 // 数字
if (/^-?\d+$/.test(token)) { if (/^-?\d+$/.test(token)) {
return parseInt(token); return parseInt(token);
} }
// 变量 // 变量查找
if (this.variables.has(token)) { if (this.variables.has(token)) {
return this.variables.get(token); return this.variables.get(token);
} }
// 如果包含乘除法或模运算,递归处理 // 对象属性访问 (如 pos.x, pos.y, pos.z)
if (token.includes('*') || token.includes('/') || token.includes('%')) { if (token.includes('.')) {
return this.parseMultiplicationDivision(token); const [objName, propName] = token.split('.');
if (this.variables.has(objName)) {
const obj = this.variables.get(objName);
if (obj && typeof obj === 'object' && obj[propName] !== undefined) {
return obj[propName];
}
}
}
// 游戏API调用
if (token.includes('player_data(')) {
const match = token.match(/player_data\s*\(\s*"(.+?)"\s*\)/);
if (match) return window.cppGameAPI.player_data(match[1]);
}
if (token.includes('player_position(')) {
const match = token.match(/player_position\s*\(\s*"(.+?)"\s*\)/);
if (match) return window.cppGameAPI.player_position(match[1]);
}
if (token.includes('vehicle_position()')) {
return window.cppGameAPI.vehicle_position();
} }
debugLog(`⚠️ 无法解析标记: ${token}`); debugLog(`⚠️ 无法解析标记: ${token}`);
@@ -2544,35 +2643,8 @@ export class CppCodeExecutor {
return null; return null;
} }
// 解析参数 // 解析参数,按逗号分割时忽略括号内的逗号
if (!argsString.trim()) { const args = this.parseArguments(argsString);
return [];
}
// 按逗号分割参数,但要考虑括号嵌套
const args = [];
let currentArg = '';
let nestedParens = 0;
for (let j = 0; j < argsString.length; j++) {
const char = argsString[j];
if (char === '(') {
nestedParens++;
} else if (char === ')') {
nestedParens--;
} else if (char === ',' && nestedParens === 0) {
args.push(currentArg.trim());
currentArg = '';
continue;
}
currentArg += char;
}
if (currentArg.trim()) {
args.push(currentArg.trim());
}
debugLog(`🔍 函数${functionName}提取到的参数:`, args); debugLog(`🔍 函数${functionName}提取到的参数:`, args);
return args; return args;

View File

@@ -32,34 +32,29 @@ const StageWrapperCppClang = () => {
const [wasmModule, setWasmModule] = useState(null); const [wasmModule, setWasmModule] = useState(null);
const [syntaxErrorModalVisible, setSyntaxErrorModalVisible] = useState(false); const [syntaxErrorModalVisible, setSyntaxErrorModalVisible] = useState(false);
const [syntaxErrors, setSyntaxErrors] = useState([]); const [syntaxErrors, setSyntaxErrors] = useState([]);
const [apiDrawerOpen, setApiDrawerOpen] = useState(false);
const [windowWidth, setWindowWidth] = useState(window.innerWidth);
const [overlayActive, setOverlayActive] = useState(false); const [overlayActive, setOverlayActive] = useState(false);
const [apiSelectedCategory, setApiSelectedCategory] = useState('syntax');
const [isApiPanelReady, setIsApiPanelReady] = useState(() => window.iscreate === 1);
// Unity 加载完成前API 面板显示加载态并屏蔽点击5 秒兜底自动解除)
useEffect(() => {
if (isApiPanelReady) return undefined;
const timer = setInterval(() => {
if (window.iscreate === 1) {
setIsApiPanelReady(true);
clearInterval(timer);
}
}, 300);
const fallback = setTimeout(() => {
setIsApiPanelReady(true);
clearInterval(timer);
}, 5000);
return () => {
clearInterval(timer);
clearTimeout(fallback);
};
}, [isApiPanelReady]);
const MAX_CODE_LINES = 500; const MAX_CODE_LINES = 500;
// CodeMirror编辑器引用 // CodeMirror编辑器引用
const editorRef = useRef(null); const editorRef = useRef(null);
const lastValidCppCodeRef = useRef(cppCode); const lastValidCppCodeRef = useRef(cppCode);
// 计算CodeMirror宽度的函数
const getCodeMirrorWidth = () => {
if (!apiDrawerOpen) return '54vw';
// 根据屏幕宽度调整
if (windowWidth <= 900) {
return '19vw'; // 54vw - 35vw = 19vw
} else if (windowWidth <= 1200) {
return '29vw'; // 54vw - 25vw = 29vw
} else {
return '34vw'; // 54vw - 20vw = 34vw
}
};
// API参考数据 // API参考数据
const apiReference = { const apiReference = {
player: { player: {
@@ -243,6 +238,17 @@ const StageWrapperCppClang = () => {
useEffect(() => { useEffect(() => {
initializeEmscripten(); initializeEmscripten();
// 添加窗口大小变化监听器
const handleResize = () => {
setWindowWidth(window.innerWidth);
};
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, []); }, []);
// 初始化基于Emscripten的C++执行环境 // 初始化基于Emscripten的C++执行环境
@@ -1112,15 +1118,22 @@ const StageWrapperCppClang = () => {
); );
}; };
// API参考面板 // API参考抽屉组件
const ApiDrawer = () => { const ApiDrawer = () => {
const selectedCategory = apiSelectedCategory; const [selectedCategory, setSelectedCategory] = useState('syntax');
const setSelectedCategory = setApiSelectedCategory;
return ( return (
<div className={styles.apiDrawer}> <div className={`${styles.apiDrawer} ${apiDrawerOpen ? styles.apiDrawerOpen : ''}`}>
{/* 抽屉头部 */}
<div className={styles.apiDrawerHeader}> <div className={styles.apiDrawerHeader}>
<h3>🔧 API参考</h3> <h3>🔧 API参考</h3>
<button
className={styles.apiDrawerClose}
onClick={() => setApiDrawerOpen(false)}
title="关闭API参考"
>
×
</button>
</div> </div>
{/* 抽屉内容 */} {/* 抽屉内容 */}
@@ -1163,12 +1176,6 @@ const StageWrapperCppClang = () => {
))} ))}
</div> </div>
</div> </div>
{!isApiPanelReady && (
<div className={styles.apiDrawerLoading}>
<div className={styles.apiDrawerLoadingSpinner}></div>
<div className={styles.apiDrawerLoadingText}>游戏引擎加载中完成后即可插入代码</div>
</div>
)}
</div> </div>
); );
}; };
@@ -1202,6 +1209,9 @@ const StageWrapperCppClang = () => {
} }
}); });
// 关闭API参考窗口
setApiDrawerOpen(false);
// 聚焦编辑器 // 聚焦编辑器
view.focus(); view.focus();
} }
@@ -1213,22 +1223,47 @@ const StageWrapperCppClang = () => {
<ErrorModal /> <ErrorModal />
<CompilationModal /> <CompilationModal />
<SyntaxErrorModal /> <SyntaxErrorModal />
<div <div onWheel={(e) => e.stopPropagation()} style={{
className={styles.editorWithApi} height: '100vh',
onWheel={(e) => e.stopPropagation()} width: '100%',
> position: 'relative',
<ApiDrawer /> overflow: 'hidden'
<div className={styles.editorPane}> }}>
<div style={{
position: 'relative',
height: '100%',
width: '100%'
}}>
{/* API抽屉标签 */}
<div
className={`${styles.apiDrawerTab} ${apiDrawerOpen ? styles.apiDrawerTabOpen : ''}`}
onClick={() => setApiDrawerOpen(!apiDrawerOpen)}
title={apiDrawerOpen ? "关闭API参考" : "打开API参考"}
>
<div className={styles.apiDrawerTabIcon}>
{apiDrawerOpen ? '▶' : '◀'}
</div>
<div className={styles.apiDrawerTabText}>
{apiDrawerOpen ? '关闭' : 'API'}
</div>
</div>
{/* API抽屉 */}
<ApiDrawer />
{/* CodeMirror编辑器 */}
<div style={{ position: 'relative', width: '100%', height: '100%' }}>
<CodeMirror <CodeMirror
ref={editorRef} ref={editorRef}
style={{ style={{
width: '100%', width: getCodeMirrorWidth(),
height: '100%', height: '100%',
position: 'relative', position: 'relative',
top: 0, top: 0,
left: 0, left: 0,
backgroundColor: '#010101', backgroundColor: '#010101',
fontSize: '20px' fontSize: '20px',
transition: 'width 0.3s ease'
}} }}
value={cppCode} value={cppCode}
theme={abcdef} theme={abcdef}
@@ -1348,6 +1383,7 @@ const StageWrapperCppClang = () => {
</div> </div>
)} )}
</div> </div>
</div>
</div> </div>
</> </>
); );

View File

@@ -378,31 +378,127 @@
color: #f44336; color: #f44336;
} }
/* API参考 + 编辑器并排:参考在左,编辑器靠右 */ /* API抽屉标签样式 */
.editorWithApi { .apiDrawerTab {
position: fixed;
top: 50%;
right: 0;
transform: translateY(-50%);
width: 45px;
height: 90px;
background: hsla(215, 100%, 65%, 1);
border: 1px solid hsla(215, 100%, 65%, 1);
border-right: none;
border-radius: 12px 0 0 12px;
cursor: pointer;
z-index: 1001;
display: flex; display: flex;
flex-direction: row; flex-direction: column;
height: 100%; align-items: center;
width: 54vw; justify-content: center;
overflow: hidden; gap: 6px;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: -4px 0 12px rgba(0, 0, 0, 0.25);
color: #FFFFFF;
backdrop-filter: blur(10px);
} }
.editorPane { .apiDrawerTab:hover {
flex: 1; background: hsla(215, 100%, 65%, 1);
min-width: 0; transform: translateY(-50%) translateX(-3px);
height: 100%; box-shadow: -6px 0 18px rgba(0, 0, 0, 0.35);
position: relative; color: #FFFFFF;
overflow: hidden;
} }
.apiDrawerTab.apiDrawerTabOpen {
background: linear-gradient(135deg, #D35400 0%, #E67E22 100%);
border-color: #E67E22;
right: 20vw;
color: #FFFFFF;
}
.apiDrawerTab.apiDrawerTabOpen:hover {
background: linear-gradient(135deg, #E67E22 0%, #F39C12 100%);
color: #FFFFFF;
}
.apiDrawerTabIcon {
font-size: 14px;
font-weight: bold;
line-height: 1;
color: #FFFFFF;
opacity: 0.9;
transition: all 0.2s ease;
}
.apiDrawerTab:hover .apiDrawerTabIcon {
opacity: 1;
transform: scale(1.1);
}
.apiDrawerTabText {
font-size: 12px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 1.5px;
writing-mode: vertical-lr;
text-orientation: mixed;
line-height: 1;
color: #FFFFFF;
opacity: 0.8;
transition: all 0.2s ease;
}
.apiDrawerTab:hover .apiDrawerTabText {
opacity: 1;
letter-spacing: 2px;
}
/* 响应式抽屉标签 */
@media (max-width: 1200px) {
.apiDrawerTab.apiDrawerTabOpen {
right: 25vw;
}
}
@media (max-width: 900px) {
.apiDrawerTab.apiDrawerTabOpen {
right: 35vw;
}
.apiDrawerTab {
width: 35px;
height: 75px;
gap: 4px;
}
.apiDrawerTabIcon {
font-size: 12px;
}
.apiDrawerTabText {
font-size: 8px;
letter-spacing: 1px;
}
.apiDrawerTab:hover .apiDrawerTabText {
letter-spacing: 1.5px;
}
}
/* API抽屉样式 */
.apiDrawer { .apiDrawer {
position: relative; position: fixed;
flex-shrink: 0; top: 0;
right: -20vw;
/* 初始隐藏在右侧 */
width: 20vw; width: 20vw;
height: 100%; height: 100vh;
background: linear-gradient(135deg, #1e1e1e 0%, #2d2d2d 100%); background: linear-gradient(135deg, #1e1e1e 0%, #2d2d2d 100%);
border-right: 2px solid #444; border-left: 2px solid #444;
box-shadow: 2px 0 12px rgba(0, 0, 0, 0.2); box-shadow: -5px 0 20px rgba(0, 0, 0, 0.3);
z-index: 1000;
transition: right 0.3s ease;
overflow: hidden; overflow: hidden;
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View File

@@ -11,6 +11,7 @@ import RankBadgeGenerator from '../../playground/rank-badge-generator.js';
// const friendToggle = new FriendToggle(); // const friendToggle = new FriendToggle();
window.RankBadgeGenerator = RankBadgeGenerator; window.RankBadgeGenerator = RankBadgeGenerator;
window.CONFIG = CONFIG; window.CONFIG = CONFIG;
import disableDevtool from 'disable-devtool';
import { initDisableDevtool } from '../../playground/devtool-control.js'; import { initDisableDevtool } from '../../playground/devtool-control.js';
import { getUnityPlayerConfig, loadUnityLoaderScript } from '../../lib/unity-build-loader.js'; import { getUnityPlayerConfig, loadUnityLoaderScript } from '../../lib/unity-build-loader.js';
import { debug } from 'scratch-vm/src/util/log.js'; import { debug } from 'scratch-vm/src/util/log.js';
@@ -547,29 +548,39 @@ const UnityComponent = function (props) {
const [hasAlerted, setHasAlerted] = useState(false); const [hasAlerted, setHasAlerted] = useState(false);
useEffect(() => { useEffect(() => {
initDisableDevtool({ if (CONFIG.disabledev) {
ondevtoolopen: () => { disableDevtool({
ondevtoolopen: () => {
// 临时禁用 onbeforeunload 事件监听,以防止弹出确认离开弹窗 // 临时禁用 onbeforeunload 事件监听,以防止弹出确认离开弹窗
const originalOnBeforeUnload = window.onbeforeunload; const originalOnBeforeUnload = window.onbeforeunload;
window.onbeforeunload = null; window.onbeforeunload = null;
window.pythonCodeStopRun(); window.pythonCodeStopRun();
window.loadPythonProject(""); window.loadPythonProject("");
// 销毁 Unity 实例 // 销毁游戏实例Cocos 兼容Quit 可能不存在)
if (window.unityInstance) { if (window.unityInstance) {
window.unityInstance.Quit().then(() => { const quit = window.unityInstance.Quit;
window.unityInstance = null; if (typeof quit === 'function') {
}); Promise.resolve(quit.call(window.unityInstance)).then(() => {
} window.unityInstance = null;
});
} else {
window.unityInstance = null;
}
}
// 延迟跳转到目标页面,确保销毁 // 延迟跳转到目标页面,确保销毁
window.location.href = localStorage.getItem('returnUrl'); window.location.href = localStorage.getItem('returnUrl');
// window.location.href = '/matchsum.html'; // window.location.href = '/matchsum.html';
// 恢复原始的 onbeforeunload 监听器 // 恢复原始的 onbeforeunload 监听器
window.onbeforeunload = originalOnBeforeUnload; window.onbeforeunload = originalOnBeforeUnload;
} },
}); interval: 500, // 检测间隔时间
clearLog: true, // 清除控制台的日志
disableMenu: true, // 禁用右键菜单
});
}
}, []); }, []);
useEffect(() => { useEffect(() => {
@@ -583,7 +594,7 @@ const UnityComponent = function (props) {
//计算真实关卡位置 //计算真实关卡位置
let realLvId = 0; let realLvId = 0;
if (localStorage.getItem('platformMode') === 'normal') { if (localStorage.getItem('platformMode') === 'normal') {
realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber) + window.gamelvdata.currentlv realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber, window.gamelvdataJson.gamemode) + window.gamelvdata.currentlv
} else { } else {
realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber) realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber)
} }
@@ -693,7 +704,7 @@ const UnityComponent = function (props) {
window.iscreate = 1; window.iscreate = 1;
let realLvId = 0; let realLvId = 0;
if (localStorage.getItem('platformMode') === 'normal') { if (localStorage.getItem('platformMode') === 'normal') {
realLvId = CONFIG.getRealLvId(gamelvdataJson.gamelv, gamelvdataJson.gameid, gamelvdataJson.ismatch, gamelvdataJson.gameNumber) + window.gamelvdata.currentlv realLvId = CONFIG.getRealLvId(gamelvdataJson.gamelv, gamelvdataJson.gameid, gamelvdataJson.ismatch, gamelvdataJson.gameNumber, gamelvdataJson.gamemode) + window.gamelvdata.currentlv
} else { } else {
realLvId = CONFIG.getRealLvId(gamelvdataJson.gamelv, gamelvdataJson.gameid, gamelvdataJson.ismatch, gamelvdataJson.gameNumber) realLvId = CONFIG.getRealLvId(gamelvdataJson.gamelv, gamelvdataJson.gameid, gamelvdataJson.ismatch, gamelvdataJson.gameNumber)
} }
@@ -710,7 +721,7 @@ const UnityComponent = function (props) {
// 延迟 500 毫秒后切换关卡,只执行一次 // 延迟 500 毫秒后切换关卡,只执行一次
setTimeout(() => { setTimeout(() => {
if (localStorage.getItem('platformMode') === 'normal') { if (localStorage.getItem('platformMode') === 'normal') {
const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber) + window.gamelvdata.currentlv const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber, window.gamelvdataJson.gamemode) + window.gamelvdata.currentlv
window.unityInstance.SendMessage("GameController", "SwitchLevel", realLvId); window.unityInstance.SendMessage("GameController", "SwitchLevel", realLvId);
} else { } else {
const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber) const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber)
@@ -767,7 +778,7 @@ const UnityComponent = function (props) {
const savedProject = window.pythonCode; const savedProject = window.pythonCode;
setIsLockNextButton(true); setIsLockNextButton(true);
const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber) + window.gamelvdata.currentlv const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber, window.gamelvdataJson.gamemode) + window.gamelvdata.currentlv
const trialCount = localStorage.getItem('trial_count'); const trialCount = localStorage.getItem('trial_count');
if (localStorage.getItem('permission') === "0" && (realLvId - CONFIG.BEGINNING_REAL_LVID) >= trialCount && currentlv > 9) { if (localStorage.getItem('permission') === "0" && (realLvId - CONFIG.BEGINNING_REAL_LVID) >= trialCount && currentlv > 9) {
@@ -1147,7 +1158,7 @@ const UnityComponent = function (props) {
setIsNextButtonComplete(false); setIsNextButtonComplete(false);
} }
window.gamelvdata.currentlv = window.gamelvdata.currentlv + 1 window.gamelvdata.currentlv = window.gamelvdata.currentlv + 1
const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber) + window.gamelvdata.currentlv const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber, window.gamelvdataJson.gamemode) + window.gamelvdata.currentlv
window.unityInstance.SendMessage("GameController", "SwitchLevel", realLvId); window.unityInstance.SendMessage("GameController", "SwitchLevel", realLvId);
CONFIG.checkGameStyle(realLvId); CONFIG.checkGameStyle(realLvId);
@@ -1199,7 +1210,7 @@ const UnityComponent = function (props) {
}; };
const handleRetry = () => { const handleRetry = () => {
const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber) + window.gamelvdata.currentlv const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber, window.gamelvdataJson.gamemode) + window.gamelvdata.currentlv
window.unityInstance.SendMessage("GameController", "SwitchLevel", realLvId); window.unityInstance.SendMessage("GameController", "SwitchLevel", realLvId);
console.log("Retrying the current level..."); console.log("Retrying the current level...");
}; };
@@ -1207,46 +1218,86 @@ const UnityComponent = function (props) {
useEffect(() => { useEffect(() => {
const canvas = canvasRef.current; const canvas = canvasRef.current;
let cancelled = false;
const bootUnity = async () => { // if (canvas && !window.unityInstance) {
const config = await getUnityPlayerConfig(); const unityUrl = "/unity";
await loadUnityLoaderScript(); const buildUrl = "/unity/Build";
if (cancelled || !canvas) { const cdnRoot = CONFIG.usecdn ? getUnityCdnRoot() : unityUrl;
return; const cdnBuildRoot = CONFIG.usecdn ? getUnityCdnBuildRoot() : buildUrl;
} let loaderUrl = CONFIG.usecdn
? `${cdnBuildRoot}/mstest5.loader.js`
: `${buildUrl}/mstest5.loader.js`;
let config = {
dataUrl: buildUrl + "/mstest5.data.br",
frameworkUrl: buildUrl + "/mstest5.framework.js.br",
codeUrl: buildUrl + "/mstest5.wasm.br",
streamingAssetsUrl: unityUrl + "/StreamingAssets",
companyName: "DefaultCompany",
productName: "Web A",
productVersion: "1.0",
};
if (CONFIG.usecdn) {
config = {
dataUrl: cdnBuildRoot + "/mstest5.data.br",
frameworkUrl: cdnBuildRoot + "/mstest5.framework.js.br",
codeUrl: cdnBuildRoot + "/mstest5.wasm.br",
streamingAssetsUrl: cdnRoot + "/StreamingAssets",
// dataUrl: buildUrl + "/Build.data.br",
// frameworkUrl: buildUrl + "/Build.framework.js.br",
// codeUrl: buildUrl + "/Build.wasm.br",
// streamingAssetsUrl: unityUrl + "/StreamingAssets",
companyName: "DefaultCompany",
productName: "Web A",
productVersion: "1.0",
};
}
const script = document.createElement("script");
script.src = loaderUrl;
script.onload = () => {
window.iscreate = 0; window.iscreate = 0;
const unityInstance = await createUnityInstance(canvas, config, () => {}); const boot = () => {
if (cancelled) { createUnityInstance(canvas, config, (progress) => {
return; // console.log(`加载进度: ${progress * 100}%`);
} }).then((unityInstance) => {
window.unityInstance = unityInstance; window.unityInstance = unityInstance;
window.waitForUnityStepFinish = waitForUnityStepFinish; window.waitForUnityStepFinish = waitForUnityStepFinish;
window.waitForUnityVehicleStepFinish = waitForUnityVehicleStepFinish; window.waitForUnityVehicleStepFinish = waitForUnityVehicleStepFinish;
window.sleepForUnityStepFinish = sleepForUnityStepFinish; window.sleepForUnityStepFinish = sleepForUnityStepFinish;
window.sleepByStepForUnityStepFinish = sleepByStepForUnityStepFinish; window.sleepByStepForUnityStepFinish = sleepByStepForUnityStepFinish;
console.log("Unity 实例创建成功"); console.log("Unity 实例创建成功");
window.processData = processData; window.processData = processData;
window.processVehicleData = processVehicleData; window.processVehicleData = processVehicleData;
window.externalResult = externalResult; window.externalResult = externalResult;
window.externalLevelInfo = externalLevelInfo; window.externalLevelInfo = externalLevelInfo;
let realLvId = 0; //计算真实关卡位置
if (localStorage.getItem('platformMode') === 'normal') { let realLvId = 0;
realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber) + window.gamelvdata.currentlv if (localStorage.getItem('platformMode') === 'normal') {
realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber, window.gamelvdataJson.gamemode) + window.gamelvdata.currentlv
} else {
realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber)
}
CONFIG.checkGameStyle(realLvId);
window.unityInstance.SendMessage("GameController", "SwitchLevel", realLvId);
}).catch((message) => {
console.error(`Unity 实例创建失败: ${message}`);
});
};
if (CONFIG.usecdn) {
prefetchLevelsDatabase(cdnRoot).then(boot).catch((err) => {
console.error('[unity-cdn] 关卡库预取失败', err);
boot();
});
} else { } else {
realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber) boot();
} }
CONFIG.checkGameStyle(realLvId);
window.unityInstance.SendMessage("GameController", "SwitchLevel", realLvId);
}; };
bootUnity().catch((message) => { document.body.appendChild(script);
console.error(`Unity 实例创建失败: ${message}`); // } else {
}); // console.log("Unity 实例已经存在,跳过初始化");
// }
return () => {
cancelled = true;
};
}, []); }, []);
// 修改 formatDateTime 函数 // 修改 formatDateTime 函数

View File

@@ -150,7 +150,7 @@ const CurrentLevelChoose = ({ onCancel }) => {
} }
// window.handleClickNewProjectWithUnity(); // window.handleClickNewProjectWithUnity();
} }
const realLvId_tmp = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber); const realLvId_tmp = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber, window.gamelvdataJson.gamemode);
const realLvId = realLvId_tmp + cellIndex const realLvId = realLvId_tmp + cellIndex
window.unityInstance.SendMessage("GameController", "SwitchLevel", realLvId); window.unityInstance.SendMessage("GameController", "SwitchLevel", realLvId);
CONFIG.checkGameStyle(realLvId); CONFIG.checkGameStyle(realLvId);

View File

@@ -11,6 +11,7 @@ import RankBadgeGenerator from '../../playground/rank-badge-generator.js';
// const friendToggle = new FriendToggle(); // const friendToggle = new FriendToggle();
window.RankBadgeGenerator = RankBadgeGenerator; window.RankBadgeGenerator = RankBadgeGenerator;
window.CONFIG = CONFIG; window.CONFIG = CONFIG;
import disableDevtool from 'disable-devtool';
import { initDisableDevtool } from '../../playground/devtool-control.js'; import { initDisableDevtool } from '../../playground/devtool-control.js';
import { getUnityPlayerConfig, loadUnityLoaderScript } from '../../lib/unity-build-loader.js'; import { getUnityPlayerConfig, loadUnityLoaderScript } from '../../lib/unity-build-loader.js';
import { debug } from 'scratch-vm/src/util/log.js'; import { debug } from 'scratch-vm/src/util/log.js';
@@ -741,33 +742,43 @@ const UnityComponent = function (props) {
const [hasAlerted, setHasAlerted] = useState(false); const [hasAlerted, setHasAlerted] = useState(false);
useEffect(() => { useEffect(() => {
initDisableDevtool({ if (CONFIG.disabledev) {
ondevtoolopen: () => { disableDevtool({
ondevtoolopen: () => {
// 临时禁用 onbeforeunload 事件监听,以防止弹出确认离开弹窗 // 临时禁用 onbeforeunload 事件监听,以防止弹出确认离开弹窗
const originalOnBeforeUnload = window.onbeforeunload; const originalOnBeforeUnload = window.onbeforeunload;
window.onbeforeunload = null; window.onbeforeunload = null;
// 停止 Scratch VM 的所有活动 // 停止 Scratch VM 的所有活动
vm.stopAll(); vm.stopAll();
// 清空积木 // 清空积木
vm.editingTarget.blocks.deleteAllBlocks(); vm.editingTarget.blocks.deleteAllBlocks();
vm.emitWorkspaceUpdate(); vm.emitWorkspaceUpdate();
// 销毁 Unity 实例 // 销毁游戏实例Cocos 兼容Quit 可能不存在)
if (window.unityInstance) { if (window.unityInstance) {
window.unityInstance.Quit().then(() => { const quit = window.unityInstance.Quit;
window.unityInstance = null; if (typeof quit === 'function') {
}); Promise.resolve(quit.call(window.unityInstance)).then(() => {
} window.unityInstance = null;
});
} else {
window.unityInstance = null;
}
}
// 延迟跳转到目标页面,确保销毁 // 延迟跳转到目标页面,确保销毁
window.location.href = localStorage.getItem('returnUrl') window.location.href = localStorage.getItem('returnUrl')
// 恢复原始的 onbeforeunload 监听器 // 恢复原始的 onbeforeunload 监听器
window.onbeforeunload = originalOnBeforeUnload; window.onbeforeunload = originalOnBeforeUnload;
} },
}); interval: 500, // 检测间隔时间
clearLog: true, // 清除控制台的日志
disableMenu: true, // 禁用右键菜单
});
}
}, []); }, []);
useEffect(() => { useEffect(() => {
@@ -781,7 +792,7 @@ const UnityComponent = function (props) {
//计算真实关卡位置 //计算真实关卡位置
let realLvId = 0; let realLvId = 0;
if (localStorage.getItem('platformMode') === 'normal') { if (localStorage.getItem('platformMode') === 'normal') {
realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber) + window.gamelvdata.currentlv realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber, window.gamelvdataJson.gamemode) + window.gamelvdata.currentlv
} else { } else {
realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber) realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber)
} }
@@ -905,7 +916,7 @@ const UnityComponent = function (props) {
window.iscreate = 1; window.iscreate = 1;
let realLvId = 0; let realLvId = 0;
if (localStorage.getItem('platformMode') === 'normal') { if (localStorage.getItem('platformMode') === 'normal') {
realLvId = CONFIG.getRealLvId(gamelvdataJson.gamelv, gamelvdataJson.gameid, gamelvdataJson.ismatch, gamelvdataJson.gameNumber) + window.gamelvdata.currentlv realLvId = CONFIG.getRealLvId(gamelvdataJson.gamelv, gamelvdataJson.gameid, gamelvdataJson.ismatch, gamelvdataJson.gameNumber, gamelvdataJson.gamemode) + window.gamelvdata.currentlv
} else { } else {
realLvId = CONFIG.getRealLvId(gamelvdataJson.gamelv, gamelvdataJson.gameid, gamelvdataJson.ismatch, gamelvdataJson.gameNumber) realLvId = CONFIG.getRealLvId(gamelvdataJson.gamelv, gamelvdataJson.gameid, gamelvdataJson.ismatch, gamelvdataJson.gameNumber)
} }
@@ -922,7 +933,7 @@ const UnityComponent = function (props) {
// 延迟 500 毫秒后切换关卡,只执行一次 // 延迟 500 毫秒后切换关卡,只执行一次
setTimeout(() => { setTimeout(() => {
if (localStorage.getItem('platformMode') === 'normal') { if (localStorage.getItem('platformMode') === 'normal') {
const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber) + window.gamelvdata.currentlv const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber, window.gamelvdataJson.gamemode) + window.gamelvdata.currentlv
window.unityInstance.SendMessage("GameController", "SwitchLevel", realLvId); window.unityInstance.SendMessage("GameController", "SwitchLevel", realLvId);
} else { } else {
const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber) const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber)
@@ -984,7 +995,7 @@ const UnityComponent = function (props) {
} }
setIsLockNextButton(true); setIsLockNextButton(true);
const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber) + window.gamelvdata.currentlv const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber, window.gamelvdataJson.gamemode) + window.gamelvdata.currentlv
const trialCount = localStorage.getItem('trial_count'); const trialCount = localStorage.getItem('trial_count');
if (localStorage.getItem('permission') === "0" && (realLvId - CONFIG.BEGINNING_REAL_LVID) >= trialCount && currentlv > 9) { if (localStorage.getItem('permission') === "0" && (realLvId - CONFIG.BEGINNING_REAL_LVID) >= trialCount && currentlv > 9) {
@@ -1403,7 +1414,7 @@ const UnityComponent = function (props) {
setIsNextButtonComplete(false); setIsNextButtonComplete(false);
} }
window.gamelvdata.currentlv = window.gamelvdata.currentlv + 1 window.gamelvdata.currentlv = window.gamelvdata.currentlv + 1
const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber) + window.gamelvdata.currentlv const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber, window.gamelvdataJson.gamemode) + window.gamelvdata.currentlv
console.log(window.gamelvdata.currentlv, window.gamelvdataJson.gameNumber) console.log(window.gamelvdata.currentlv, window.gamelvdataJson.gameNumber)
removeGlobalKeyboardShield(); removeGlobalKeyboardShield();
window.unityInstance.SendMessage("GameController", "SwitchLevel", realLvId); window.unityInstance.SendMessage("GameController", "SwitchLevel", realLvId);
@@ -1461,7 +1472,7 @@ const UnityComponent = function (props) {
}; };
const handleRetry = () => { const handleRetry = () => {
const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber) + window.gamelvdata.currentlv const realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber, window.gamelvdataJson.gamemode) + window.gamelvdata.currentlv
removeGlobalKeyboardShield(); removeGlobalKeyboardShield();
window.unityInstance.SendMessage("GameController", "SwitchLevel", realLvId); window.unityInstance.SendMessage("GameController", "SwitchLevel", realLvId);
console.log("Retrying the current level...realLvId...", realLvId); console.log("Retrying the current level...realLvId...", realLvId);
@@ -1470,47 +1481,87 @@ const UnityComponent = function (props) {
useEffect(() => { useEffect(() => {
const canvas = canvasRef.current; const canvas = canvasRef.current;
let cancelled = false;
const bootUnity = async () => { // if (canvas && !window.unityInstance) {
const config = await getUnityPlayerConfig(); const unityUrl = "/unity";
await loadUnityLoaderScript(); const buildUrl = "/unity/Build";
if (cancelled || !canvas) { const cdnRoot = CONFIG.usecdn ? getUnityCdnRoot() : unityUrl;
return; const cdnBuildRoot = CONFIG.usecdn ? getUnityCdnBuildRoot() : buildUrl;
} let loaderUrl = CONFIG.usecdn
? `${cdnBuildRoot}/mstest5.loader.js`
: `${buildUrl}/mstest5.loader.js`;
let config = {
dataUrl: buildUrl + "/mstest5.data.br",
frameworkUrl: buildUrl + "/mstest5.framework.js.br",
codeUrl: buildUrl + "/mstest5.wasm.br",
streamingAssetsUrl: unityUrl + "/StreamingAssets",
companyName: "DefaultCompany",
productName: "Web A",
productVersion: "1.0",
};
if (CONFIG.usecdn) {
config = {
dataUrl: cdnBuildRoot + "/mstest5.data.br",
frameworkUrl: cdnBuildRoot + "/mstest5.framework.js.br",
codeUrl: cdnBuildRoot + "/mstest5.wasm.br",
streamingAssetsUrl: cdnRoot + "/StreamingAssets",
// dataUrl: buildUrl + "/Build.data.br",
// frameworkUrl: buildUrl + "/Build.framework.js.br",
// codeUrl: buildUrl + "/Build.wasm.br",
// streamingAssetsUrl: unityUrl + "/StreamingAssets",
companyName: "DefaultCompany",
productName: "Web A",
productVersion: "1.0",
};
}
const script = document.createElement("script");
script.src = loaderUrl;
script.onload = () => {
window.iscreate = 0; window.iscreate = 0;
const unityInstance = await createUnityInstance(canvas, config, () => {}); const boot = () => {
if (cancelled) { createUnityInstance(canvas, config, (progress) => {
return; // console.log(`加载进度: ${progress * 100}%`);
} }).then((unityInstance) => {
window.unityInstance = unityInstance; window.unityInstance = unityInstance;
window.waitForUnityStepFinish = waitForUnityStepFinish; window.waitForUnityStepFinish = waitForUnityStepFinish;
window.waitForUnityVehicleStepFinish = waitForUnityVehicleStepFinish; window.waitForUnityVehicleStepFinish = waitForUnityVehicleStepFinish;
window.sleepForUnityStepFinish = sleepForUnityStepFinish; window.sleepForUnityStepFinish = sleepForUnityStepFinish;
window.sleepByStepForUnityStepFinish = sleepByStepForUnityStepFinish; window.sleepByStepForUnityStepFinish = sleepByStepForUnityStepFinish;
console.log("Unity 实例创建成功"); console.log("Unity 实例创建成功");
window.processData = processData; window.processData = processData;
window.processVehicleData = processVehicleData; window.processVehicleData = processVehicleData;
window.externalResult = externalResult; window.externalResult = externalResult;
window.externalLevelInfo = externalLevelInfo; window.externalLevelInfo = externalLevelInfo;
//计算真实关卡位置
let realLvId = 0; let realLvId = 0;
if (localStorage.getItem('platformMode') === 'normal') { if (localStorage.getItem('platformMode') === 'normal') {
realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber) + window.gamelvdata.currentlv realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber, window.gamelvdataJson.gamemode) + window.gamelvdata.currentlv
} else {
realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber)
}
CONFIG.checkGameStyle(realLvId);
window.unityInstance.SendMessage("GameController", "SwitchLevel", realLvId);
}).catch((message) => {
console.error(`Unity 实例创建失败: ${message}`);
});
};
if (CONFIG.usecdn) {
prefetchLevelsDatabase(cdnRoot).then(boot).catch((err) => {
console.error('[unity-cdn] 关卡库预取失败', err);
boot();
});
} else { } else {
realLvId = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber) boot();
} }
CONFIG.checkGameStyle(realLvId);
window.unityInstance.SendMessage("GameController", "SwitchLevel", realLvId);
}; };
bootUnity().catch((message) => { document.body.appendChild(script);
console.error(`Unity 实例创建失败: ${message}`); // } else {
}); // console.log("Unity 实例已经存在,跳过初始化");
// }
return () => {
cancelled = true;
};
}, []); }, []);
const formatDateTime = (dateStr) => { const formatDateTime = (dateStr) => {

View File

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 89 KiB

View File

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 62 KiB

View File

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

View File

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View File

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 86 KiB

View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

View File

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View File

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

View File

Before

Width:  |  Height:  |  Size: 99 KiB

After

Width:  |  Height:  |  Size: 99 KiB

View File

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

View File

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 62 KiB

View File

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

View File

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 57 KiB

View File

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 56 KiB

View File

Before

Width:  |  Height:  |  Size: 113 KiB

After

Width:  |  Height:  |  Size: 113 KiB

View File

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 77 KiB

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Some files were not shown because too many files have changed in this diff Show More