From 8de45204e218a4594f72b8e41f8e97d7a4ccaa35 Mon Sep 17 00:00:00 2001 From: kim jeong yong Date: Tue, 20 Jan 2026 15:03:15 +0900 Subject: [PATCH] =?UTF-8?q?=EC=97=94=EC=A7=84=20=ED=83=80=EC=9D=B4?= =?UTF-8?q?=EB=A8=B8=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84=20=EB=B0=8F?= =?UTF-8?q?=20=EB=B8=94=EB=A1=9D=20=EB=82=B4=20setTimeout=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=20=EB=B0=A9=EC=8B=9D=20=EB=A6=AC=ED=8C=A9=ED=84=B0?= =?UTF-8?q?=EB=A7=81.=20Engine=20=ED=81=B4=EB=9E=98=EC=8A=A4=EC=97=90=20?= =?UTF-8?q?=ED=83=80=EC=9D=B4=EB=A8=B8=20=EA=B4=80=EB=A6=AC=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=EB=A5=BC=20=EC=B6=94=EA=B0=80=ED=95=98?= =?UTF-8?q?=EA=B3=A0,=20=EB=B8=94=EB=A1=9D=20=EC=8A=A4=ED=81=AC=EB=A6=BD?= =?UTF-8?q?=ED=8A=B8=EC=97=90=EC=84=9C=20=EC=8B=A4=ED=96=89=20=ED=83=80?= =?UTF-8?q?=EC=9D=B4=EB=B0=8D=20=EC=A0=9C=EC=96=B4=EB=A5=BC=20=EC=9C=84?= =?UTF-8?q?=ED=95=B4=20Entry.engine.setTimeout=EC=9D=84=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/class/engine.js | 111 ++++++++++++++++++++++++ src/playground/blocks/block_analysis.js | 2 +- src/playground/blocks/block_looks.js | 2 +- src/playground/blocks/block_sound.js | 6 +- 4 files changed, 116 insertions(+), 5 deletions(-) diff --git a/src/class/engine.js b/src/class/engine.js index 6e94c4fbda..d4d6e6040b 100644 --- a/src/class/engine.js +++ b/src/class/engine.js @@ -15,6 +15,15 @@ Entry.Engine = class Engine { this.popup = null; this.isUpdating = true; this.speeds = [1, 15, 30, 45, 60]; + this.engineTimer = { + isInit: false, + isPaused: false, + start: 0, + pauseStart: 0, + pausedTime: 0, + }; + this._engineTimeouts = []; + this._engineTimeoutSeq = 0; this.attachKeyboardCapture(); @@ -558,6 +567,8 @@ Entry.Engine = class Engine { audioUtils.stopRecord(); clearInterval(this.ticker); this.ticker = null; + this._stopEngineTimer(); + this._clearEngineTimeouts(); } /** @@ -570,6 +581,7 @@ Entry.Engine = class Engine { if (Entry.hw.communicationType !== 'manual') { Entry.hw.update(); } + this._processEngineTimeouts(); } }; @@ -646,6 +658,7 @@ Entry.Engine = class Engine { container.takeSequenceSnapshot(); Entry.scene.takeStartSceneSnapshot(); this.state = EntryEngineState.run; + this._resetEngineTimer(); this.fireEvent('start'); this.achieveEnabled = !(disableAchieve === false); } @@ -788,6 +801,8 @@ Entry.Engine = class Engine { } this.state = EntryEngineState.stop; + this._stopEngineTimer(); + this._clearEngineTimeouts(); this.setEnableInputField(false); Entry.dispatchEvent('stop'); Entry.stage.hideInputField(); @@ -822,6 +837,7 @@ Entry.Engine = class Engine { delete timer.pauseStart; } this.state = EntryEngineState.run; + this._resumeEngineTimer(); Entry.Utils.recoverSoundInstances(); if (visible && this.runButton) { this.setPauseButton(this.option); @@ -849,6 +865,7 @@ Entry.Engine = class Engine { timer.pausedTime += new Date().getTime() - timer.pauseStart; timer.pauseStart = new Date().getTime(); } + this._pauseEngineTimer(); Entry.Utils.pauseSoundInstances(); if (visible && this.runButton) { this.setPauseButton(this.option); @@ -1297,4 +1314,98 @@ Entry.Engine = class Engine { this.execPromises[index + i] = execPromise; }); } + + _resetEngineTimer() { + const timer = this.engineTimer; + timer.start = new Date().getTime(); + timer.pausedTime = 0; + timer.pauseStart = 0; + timer.isPaused = false; + timer.isInit = true; + } + + _pauseEngineTimer() { + const timer = this.engineTimer; + if (!timer.isInit || timer.isPaused) { + return; + } + timer.isPaused = true; + timer.pauseStart = new Date().getTime(); + } + + _resumeEngineTimer() { + const timer = this.engineTimer; + if (!timer.isInit || !timer.isPaused) { + return; + } + if (timer.pauseStart) { + timer.pausedTime += new Date().getTime() - timer.pauseStart; + } + timer.pauseStart = 0; + timer.isPaused = false; + } + + _stopEngineTimer() { + const timer = this.engineTimer; + timer.isInit = false; + timer.isPaused = false; + timer.start = 0; + timer.pauseStart = 0; + timer.pausedTime = 0; + } + + _getEngineTimeMs() { + const timer = this.engineTimer; + if (!timer.isInit) { + return 0; + } + const now = timer.isPaused && timer.pauseStart ? timer.pauseStart : new Date().getTime(); + return Math.max(now - timer.start - timer.pausedTime, 0); + } + + _processEngineTimeouts() { + if (!this._engineTimeouts.length) { + return; + } + const nowMs = this._getEngineTimeMs(); + const timeouts = this._engineTimeouts; + let writeIndex = 0; + for (let i = 0; i < timeouts.length; i++) { + const item = timeouts[i]; + if (item.targetTimeMs <= nowMs) { + try { + item.callback(); + } catch (e) { + console.error('Engine setTimeout callback error', e); + } + } else { + timeouts[writeIndex++] = item; + } + } + if (writeIndex !== timeouts.length) { + timeouts.length = writeIndex; + } + } + + _clearEngineTimeouts() { + this._engineTimeouts = []; + } + + setTimeout(callback, delay) { + if (typeof callback !== 'function') { + return null; + } + const id = ++this._engineTimeoutSeq; + const targetTimeMs = this._getEngineTimeMs() + Math.max(Number(delay) || 0, 0); + this._engineTimeouts.push({ + id, + callback, + targetTimeMs, + }); + return id; + } + + clearTimeout(id) { + this._engineTimeouts = this._engineTimeouts.filter((item) => item.id !== id); + } }; diff --git a/src/playground/blocks/block_analysis.js b/src/playground/blocks/block_analysis.js index ca7de58c7a..14f4c2aef6 100644 --- a/src/playground/blocks/block_analysis.js +++ b/src/playground/blocks/block_analysis.js @@ -856,7 +856,7 @@ module.exports = { const tableId = script.getField('MATRIX', script); const timeValue = script.getNumberValue('SECOND', script); DataTable.showTable(tableId); - setTimeout(() => { + Entry.engine.setTimeout(() => { DataTable.closeModal(); }, timeValue * 1000); return script.callReturn(); diff --git a/src/playground/blocks/block_looks.js b/src/playground/blocks/block_looks.js index 85bffef242..867e99ecac 100644 --- a/src/playground/blocks/block_looks.js +++ b/src/playground/blocks/block_looks.js @@ -152,7 +152,7 @@ module.exports = { } }; sprite.stopDialog = stopDialog; - timeoutId = setTimeout(stopDialog, timeValue * 1000); + timeoutId = Entry.engine.setTimeout(stopDialog, timeValue * 1000); } if (script.timeFlag == 0) { delete script.timeFlag; diff --git a/src/playground/blocks/block_sound.js b/src/playground/blocks/block_sound.js index 57fd60651b..b370535d25 100644 --- a/src/playground/blocks/block_sound.js +++ b/src/playground/blocks/block_sound.js @@ -296,7 +296,7 @@ module.exports = { const duration = Math.floor( (sound.duration * 1000) / Entry.playbackRateValue ); - setTimeout(() => { + Entry.engine.setTimeout(() => { script.playState = 0; }, duration); } @@ -384,7 +384,7 @@ module.exports = { const instance = Entry.Utils.playSound(sound.id); Entry.Utils.addSoundInstances(instance, sprite); const timeValue = script.getNumberValue('SECOND', script); - setTimeout(() => { + Entry.engine.setTimeout(() => { instance.stop(); script.playState = 0; }, timeValue * 1000); @@ -498,7 +498,7 @@ module.exports = { }); Entry.Utils.addSoundInstances(instance, sprite); - setTimeout(() => { + Entry.engine.setTimeout(() => { script.playState = 0; }, duration); }