|
1 | 1 | mergeInto(LibraryManager.library, { |
2 | 2 | $THUAI9WebGLBridge: { |
3 | 3 | maxBase64Bytes: 16 * 1024 * 1024, |
| 4 | + maxRemotePlaybackBytes: 64 * 1024 * 1024, |
| 5 | + activePlaybackObjectUrl: null, |
| 6 | + objectUrlCleanupRegistered: false, |
4 | 7 | sendMessage: function (gameObjectName, methodName, payload) { |
5 | 8 | if (typeof SendMessage === 'function') { SendMessage(gameObjectName, methodName, payload || ''); return; } |
6 | 9 | var unityInstance = window.unityInstance || window.THUAIGameInstance || window.gameInstance || (typeof Module !== 'undefined' ? Module : null); |
7 | 10 | if (unityInstance && typeof unityInstance.SendMessage === 'function') { unityInstance.SendMessage(gameObjectName, methodName, payload || ''); return; } |
8 | 11 | console.error('[THUAI9] Unity SendMessage is not available', { gameObjectName: gameObjectName, methodName: methodName }); |
9 | 12 | }, |
| 13 | + sendMessageLater: function (gameObjectName, methodName, payload) { |
| 14 | + var send = function () { THUAI9WebGLBridge.sendMessage(gameObjectName, methodName, payload || ''); }; |
| 15 | + if (typeof window.setTimeout === 'function') { window.setTimeout(send, 0); return; } |
| 16 | + send(); |
| 17 | + }, |
10 | 18 | arrayBufferToBase64: function (arrayBuffer) { |
11 | 19 | var bytes = new Uint8Array(arrayBuffer), chunkSize = 0x8000, binary = ''; |
12 | 20 | for (var i = 0; i < bytes.length; i += chunkSize) binary += String.fromCharCode.apply(null, bytes.subarray(i, i + chunkSize)); |
@@ -35,53 +43,90 @@ mergeInto(LibraryManager.library, { |
35 | 43 | dispatchCustomEvent: function (eventName, detail) { |
36 | 44 | if (typeof window.CustomEvent === 'function') { window.dispatchEvent(new CustomEvent(eventName, { detail: detail })); return; } |
37 | 45 | var event = document.createEvent('CustomEvent'); event.initCustomEvent(eventName, false, false, detail); window.dispatchEvent(event); |
| 46 | + }, |
| 47 | + dispatchCustomEventLater: function (eventName, detail) { |
| 48 | + var dispatch = function () { THUAI9WebGLBridge.dispatchCustomEvent(eventName, detail); }; |
| 49 | + if (typeof window.setTimeout === 'function') { window.setTimeout(dispatch, 0); return; } |
| 50 | + dispatch(); |
| 51 | + }, |
| 52 | + revokeActivePlaybackObjectUrl: function () { |
| 53 | + if (!THUAI9WebGLBridge.activePlaybackObjectUrl) return; |
| 54 | + try { URL.revokeObjectURL(THUAI9WebGLBridge.activePlaybackObjectUrl); } catch (_) {} |
| 55 | + THUAI9WebGLBridge.activePlaybackObjectUrl = null; |
| 56 | + }, |
| 57 | + ensureObjectUrlCleanup: function () { |
| 58 | + if (THUAI9WebGLBridge.objectUrlCleanupRegistered || typeof window.addEventListener !== 'function') return; |
| 59 | + THUAI9WebGLBridge.objectUrlCleanupRegistered = true; |
| 60 | + window.addEventListener('beforeunload', function () { |
| 61 | + THUAI9WebGLBridge.revokeActivePlaybackObjectUrl(); |
| 62 | + }); |
38 | 63 | } |
39 | 64 | }, |
40 | 65 | THUAI9_SelectPlaybackFile__deps: ['$THUAI9WebGLBridge'], |
41 | 66 | THUAI9_SelectPlaybackFile: function (gameObjectNamePtr, callbackNamePtr) { |
42 | 67 | var gameObjectName = UTF8ToString(gameObjectNamePtr); var callbackName = UTF8ToString(callbackNamePtr); |
43 | 68 | var input = document.createElement('input'); input.type = 'file'; input.accept = '.thuaipb,application/octet-stream'; input.style.display = 'none'; |
44 | | - input.onchange = function () { var file = input.files && input.files[0]; if (!file) { input.remove(); return; } var url = URL.createObjectURL(file); var payload = JSON.stringify({ url: url, name: file.name || 'playback.thuaipb', size: file.size || 0 }); THUAI9WebGLBridge.sendMessage(gameObjectName, callbackName, payload); THUAI9WebGLBridge.dispatchCustomEvent('thuai9-playback-file-selected', { url: url, name: file.name, size: file.size }); input.remove(); }; |
| 69 | + input.onchange = function () { |
| 70 | + var file = input.files && input.files[0]; |
| 71 | + if (!file) { input.remove(); return; } |
| 72 | + var size = file.size || 0; |
| 73 | + var name = file.name || 'playback.thuaipb'; |
| 74 | + if (size > THUAI9WebGLBridge.maxRemotePlaybackBytes) { |
| 75 | + THUAI9WebGLBridge.dispatchCustomEvent('thuai9-playback-error', 'file-too-large:' + size); |
| 76 | + input.remove(); |
| 77 | + return; |
| 78 | + } |
| 79 | + |
| 80 | + THUAI9WebGLBridge.revokeActivePlaybackObjectUrl(); |
| 81 | + THUAI9WebGLBridge.ensureObjectUrlCleanup(); |
| 82 | + var url = URL.createObjectURL(file); |
| 83 | + THUAI9WebGLBridge.activePlaybackObjectUrl = url; |
| 84 | + var payload = JSON.stringify({ url: url, name: name, size: size }); |
| 85 | + THUAI9WebGLBridge.sendMessageLater(gameObjectName, callbackName, payload); |
| 86 | + THUAI9WebGLBridge.dispatchCustomEventLater('thuai9-playback-file-selected', { url: url, name: name, size: size }); |
| 87 | + input.remove(); |
| 88 | + }; |
45 | 89 | document.body.appendChild(input); input.click(); |
46 | 90 | }, |
47 | 91 | THUAI9_ClearDevelopmentConsole: function () { |
48 | 92 | if (typeof console !== 'undefined' && typeof console.clear === 'function') console.clear(); |
49 | 93 | }, |
50 | 94 | THUAI9_NotifyUnityReady__deps: ['$THUAI9WebGLBridge'], |
51 | 95 | THUAI9_NotifyUnityReady: function (gameObjectNamePtr) { |
| 96 | + THUAI9WebGLBridge.ensureObjectUrlCleanup(); |
52 | 97 | var gameObjectName = UTF8ToString(gameObjectNamePtr); window.THUAI9Unity = window.THUAI9Unity || {}; window.THUAI9Unity.gameObjectName = gameObjectName; |
53 | | - window.THUAI9Unity.sendMessage = function (methodName, payload) { THUAI9WebGLBridge.sendMessage(gameObjectName, methodName, payload || ''); }; |
| 98 | + window.THUAI9Unity.sendMessage = function (methodName, payload) { THUAI9WebGLBridge.sendMessageLater(gameObjectName, methodName, payload || ''); }; |
54 | 99 | window.THUAI9Unity.setPlaybackFile = function (url, name) { |
55 | 100 | var selection = (url && typeof url === 'object') |
56 | 101 | ? url |
57 | 102 | : { url: THUAI9WebGLBridge.normalizeUrl(url), name: name || url }; |
58 | 103 | if (selection.url) selection.url = THUAI9WebGLBridge.normalizeUrl(selection.url); |
59 | | - THUAI9WebGLBridge.sendMessage(gameObjectName, 'SetPlaybackFile', JSON.stringify(selection)); |
| 104 | + THUAI9WebGLBridge.sendMessageLater(gameObjectName, 'SetPlaybackFile', JSON.stringify(selection)); |
60 | 105 | }; |
61 | 106 | window.THUAI9Unity.loadPlaybackBase64 = function (base64, name) { |
62 | 107 | var normalized = THUAI9WebGLBridge.normalizeBase64(base64); |
63 | 108 | var estimatedBytes = THUAI9WebGLBridge.estimateBase64ByteCount(normalized); |
64 | 109 | if (estimatedBytes > THUAI9WebGLBridge.maxBase64Bytes) { |
65 | | - THUAI9WebGLBridge.dispatchCustomEvent('thuai9-playback-error', 'base64-too-large:' + estimatedBytes); |
| 110 | + THUAI9WebGLBridge.dispatchCustomEventLater('thuai9-playback-error', 'base64-too-large:' + estimatedBytes); |
66 | 111 | return; |
67 | 112 | } |
68 | | - THUAI9WebGLBridge.sendMessage(gameObjectName, 'LoadPlaybackBase64', JSON.stringify({ data: normalized, name: name || 'playback.thuaipb' })); |
| 113 | + THUAI9WebGLBridge.sendMessageLater(gameObjectName, 'LoadPlaybackBase64', JSON.stringify({ data: normalized, name: name || 'playback.thuaipb' })); |
69 | 114 | }; |
70 | | - window.THUAI9Unity.requestPlaybackFile = function () { THUAI9WebGLBridge.sendMessage(gameObjectName, 'RequestPlaybackFile', ''); }; |
71 | | - window.THUAI9Unity.play = function () { THUAI9WebGLBridge.sendMessage(gameObjectName, 'PlayPlayback', ''); }; |
72 | | - window.THUAI9Unity.pause = function () { THUAI9WebGLBridge.sendMessage(gameObjectName, 'PausePlayback', ''); }; |
73 | | - window.THUAI9Unity.togglePlayPause = function () { THUAI9WebGLBridge.sendMessage(gameObjectName, 'TogglePlayback', ''); }; |
74 | | - window.THUAI9Unity.stop = function () { THUAI9WebGLBridge.sendMessage(gameObjectName, 'StopPlayback', ''); }; |
75 | | - window.THUAI9Unity.seekToFrame = function (frameIndex) { THUAI9WebGLBridge.sendMessage(gameObjectName, 'SeekPlaybackFrame', String(frameIndex || 0)); }; |
76 | | - window.THUAI9Unity.setSpeed = function (speed) { THUAI9WebGLBridge.sendMessage(gameObjectName, 'SetPlaybackSpeed', String(speed || 1)); }; |
77 | | - window.THUAI9Unity.stepForward = function () { THUAI9WebGLBridge.sendMessage(gameObjectName, 'StepPlaybackForward', ''); }; |
78 | | - window.THUAI9Unity.stepBackward = function () { THUAI9WebGLBridge.sendMessage(gameObjectName, 'StepPlaybackBackward', ''); }; |
79 | | - THUAI9WebGLBridge.dispatchCustomEvent('thuai9-unity-ready', { gameObjectName: gameObjectName, mode: 'playback' }); |
| 115 | + window.THUAI9Unity.requestPlaybackFile = function () { THUAI9WebGLBridge.sendMessageLater(gameObjectName, 'RequestPlaybackFile', ''); }; |
| 116 | + window.THUAI9Unity.play = function () { THUAI9WebGLBridge.sendMessageLater(gameObjectName, 'PlayPlayback', ''); }; |
| 117 | + window.THUAI9Unity.pause = function () { THUAI9WebGLBridge.sendMessageLater(gameObjectName, 'PausePlayback', ''); }; |
| 118 | + window.THUAI9Unity.togglePlayPause = function () { THUAI9WebGLBridge.sendMessageLater(gameObjectName, 'TogglePlayback', ''); }; |
| 119 | + window.THUAI9Unity.stop = function () { THUAI9WebGLBridge.sendMessageLater(gameObjectName, 'StopPlayback', ''); }; |
| 120 | + window.THUAI9Unity.seekToFrame = function (frameIndex) { THUAI9WebGLBridge.sendMessageLater(gameObjectName, 'SeekPlaybackFrame', String(frameIndex || 0)); }; |
| 121 | + window.THUAI9Unity.setSpeed = function (speed) { THUAI9WebGLBridge.sendMessageLater(gameObjectName, 'SetPlaybackSpeed', String(speed || 1)); }; |
| 122 | + window.THUAI9Unity.stepForward = function () { THUAI9WebGLBridge.sendMessageLater(gameObjectName, 'StepPlaybackForward', ''); }; |
| 123 | + window.THUAI9Unity.stepBackward = function () { THUAI9WebGLBridge.sendMessageLater(gameObjectName, 'StepPlaybackBackward', ''); }; |
| 124 | + THUAI9WebGLBridge.dispatchCustomEventLater('thuai9-unity-ready', { gameObjectName: gameObjectName, mode: 'playback' }); |
80 | 125 | }, |
81 | 126 | THUAI9_DispatchUnityEvent__deps: ['$THUAI9WebGLBridge'], |
82 | 127 | THUAI9_DispatchUnityEvent: function (eventNamePtr, payloadPtr) { |
83 | 128 | var eventName = UTF8ToString(eventNamePtr); var payload = UTF8ToString(payloadPtr); |
84 | | - THUAI9WebGLBridge.dispatchCustomEvent('thuai9-unity-event', { eventName: eventName, payload: payload }); |
85 | | - THUAI9WebGLBridge.dispatchCustomEvent('thuai9-' + eventName, payload); |
| 129 | + THUAI9WebGLBridge.dispatchCustomEventLater('thuai9-unity-event', { eventName: eventName, payload: payload }); |
| 130 | + THUAI9WebGLBridge.dispatchCustomEventLater('thuai9-' + eventName, payload); |
86 | 131 | } |
87 | 132 | }); |
0 commit comments