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
This commit is contained in:
119
scratch-gui/src/lib/unity-build-loader.js
Normal file
119
scratch-gui/src/lib/unity-build-loader.js
Normal file
@@ -0,0 +1,119 @@
|
||||
import CONFIG from '../playground/config.js';
|
||||
|
||||
const FILES = {
|
||||
dataUrl: 'mstest5.data.br',
|
||||
frameworkUrl: 'mstest5.framework.js.br',
|
||||
codeUrl: 'mstest5.wasm.br'
|
||||
};
|
||||
|
||||
// 压缩后 wasm 约 4.4MB;用户侧曾出现只下到 ~800KB 的截断包
|
||||
const MIN_BYTES = {
|
||||
dataUrl: 1024 * 1024,
|
||||
frameworkUrl: 20 * 1024,
|
||||
codeUrl: 2 * 1024 * 1024
|
||||
};
|
||||
|
||||
const WASM_MAGIC = [0x00, 0x61, 0x73, 0x6d];
|
||||
|
||||
function withVersion(url) {
|
||||
const version = CONFIG.version || Date.now();
|
||||
return `${url}${url.includes('?') ? '&' : '?'}v=${encodeURIComponent(version)}`;
|
||||
}
|
||||
|
||||
function buildCandidates() {
|
||||
const local = '/unity/Build';
|
||||
const cdn = CONFIG.unitycdnbuilddir;
|
||||
if (CONFIG.usecdn) {
|
||||
return [cdn, local].filter(Boolean);
|
||||
}
|
||||
return [local, cdn].filter(Boolean);
|
||||
}
|
||||
|
||||
function isUncompressedWasm(buffer) {
|
||||
const bytes = new Uint8Array(buffer);
|
||||
return WASM_MAGIC.every((value, index) => bytes[index] === value);
|
||||
}
|
||||
|
||||
function looksLikeJavascript(buffer) {
|
||||
const head = new TextDecoder().decode(buffer.slice(0, 80));
|
||||
return /function|unityFramework|^\s*var |^\s*const |^\s*!function/.test(head);
|
||||
}
|
||||
|
||||
function looksLikeUnityData(buffer) {
|
||||
const head = new TextDecoder().decode(buffer.slice(0, 16));
|
||||
return head.startsWith('UnityWebData1.0');
|
||||
}
|
||||
|
||||
function toTrustedUrl(fileName, buffer, sourceUrl) {
|
||||
if (fileName.endsWith('.wasm.br') && isUncompressedWasm(buffer)) {
|
||||
return URL.createObjectURL(new Blob([buffer], { type: 'application/wasm' }));
|
||||
}
|
||||
if (fileName.endsWith('.js.br') && looksLikeJavascript(buffer)) {
|
||||
return URL.createObjectURL(new Blob([buffer], { type: 'application/javascript' }));
|
||||
}
|
||||
if (fileName.endsWith('.data.br') && looksLikeUnityData(buffer)) {
|
||||
return URL.createObjectURL(new Blob([buffer]));
|
||||
}
|
||||
return sourceUrl;
|
||||
}
|
||||
|
||||
async function fetchCompleteAsset(fileName, minBytes) {
|
||||
let lastError = null;
|
||||
for (const base of buildCandidates()) {
|
||||
const url = withVersion(`${base}/${fileName}`);
|
||||
try {
|
||||
const response = await fetch(url, { cache: 'no-store' });
|
||||
if (!response.ok) {
|
||||
lastError = new Error(`${url} HTTP ${response.status}`);
|
||||
continue;
|
||||
}
|
||||
const buffer = await response.arrayBuffer();
|
||||
if (buffer.byteLength < minBytes) {
|
||||
console.warn(`[Unity] ${fileName} 被截断: ${buffer.byteLength} bytes(来自 ${url}),期望至少 ${minBytes}`);
|
||||
lastError = new Error(`${fileName} truncated: ${buffer.byteLength}`);
|
||||
continue;
|
||||
}
|
||||
console.log(`[Unity] ${fileName} 下载完整: ${buffer.byteLength} bytes from ${url}`);
|
||||
return toTrustedUrl(fileName, buffer, url);
|
||||
} catch (error) {
|
||||
console.warn(`[Unity] 下载失败 ${url}`, error);
|
||||
lastError = error;
|
||||
}
|
||||
}
|
||||
throw lastError || new Error(`无法完整下载 ${fileName}`);
|
||||
}
|
||||
|
||||
export async function getUnityPlayerConfig() {
|
||||
const [dataUrl, frameworkUrl, codeUrl] = await Promise.all([
|
||||
fetchCompleteAsset(FILES.dataUrl, MIN_BYTES.dataUrl),
|
||||
fetchCompleteAsset(FILES.frameworkUrl, MIN_BYTES.frameworkUrl),
|
||||
fetchCompleteAsset(FILES.codeUrl, MIN_BYTES.codeUrl)
|
||||
]);
|
||||
|
||||
const streamingAssetsUrl = (CONFIG.usecdn && CONFIG.unitycdndir)
|
||||
? `${CONFIG.unitycdndir}/StreamingAssets`
|
||||
: '/unity/StreamingAssets';
|
||||
|
||||
return {
|
||||
dataUrl,
|
||||
frameworkUrl,
|
||||
codeUrl,
|
||||
streamingAssetsUrl,
|
||||
companyName: 'DefaultCompany',
|
||||
productName: 'Web A',
|
||||
productVersion: String(CONFIG.version || '1.0')
|
||||
};
|
||||
}
|
||||
|
||||
export function loadUnityLoaderScript() {
|
||||
if (typeof window.createUnityInstance === 'function') {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
const script = document.createElement('script');
|
||||
script.src = withVersion('/unity/Build/mstest5.loader.js');
|
||||
script.onload = () => resolve();
|
||||
script.onerror = () => reject(new Error('Unity loader 加载失败'));
|
||||
document.body.appendChild(script);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user