@akashic/headless-driver 2.13.9 → 2.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/TimeKeeper.d.ts +7 -0
- package/lib/TimeKeeper.js +22 -0
- package/lib/runner/Platform.d.ts +1 -0
- package/lib/runner/Runner.d.ts +17 -3
- package/lib/runner/Runner.js +50 -2
- package/lib/runner/RunnerManager.d.ts +2 -1
- package/lib/runner/RunnerManager.js +1 -0
- package/lib/runner/types.d.ts +1 -0
- package/lib/runner/v1/RunnerV1.d.ts +1 -1
- package/lib/runner/v1/RunnerV1.js +20 -19
- package/lib/runner/v1/platform/assets/NullAudioAsset.js +2 -2
- package/lib/runner/v1/platform/assets/NullImageAsset.js +2 -2
- package/lib/runner/v1/platform/assets/NullVideoAsset.js +2 -2
- package/lib/runner/v2/RunnerV2.d.ts +1 -1
- package/lib/runner/v2/RunnerV2.js +20 -19
- package/lib/runner/v2/platform/assets/NullAudioAsset.js +2 -2
- package/lib/runner/v2/platform/assets/NullImageAsset.js +2 -2
- package/lib/runner/v2/platform/assets/NullVideoAsset.js +2 -2
- package/lib/runner/v3/RunnerV3.d.ts +1 -1
- package/lib/runner/v3/RunnerV3.js +35 -19
- package/lib/runner/v3/platform/audios/NullAudioAsset.js +2 -2
- package/lib/runner/v3/platform/graphics/null/NullImageAsset.js +2 -2
- package/lib/runner/v3/platform/videos/NullVideoAsset.js +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TimeKeeper = void 0;
|
|
4
|
+
class TimeKeeper {
|
|
5
|
+
constructor() {
|
|
6
|
+
this._currentTime = 0;
|
|
7
|
+
// NOTE: this を束縛するためアロー関数で定義
|
|
8
|
+
this.now = () => {
|
|
9
|
+
return this._currentTime;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
advance(ms) {
|
|
13
|
+
this._currentTime += ms;
|
|
14
|
+
}
|
|
15
|
+
rewind() {
|
|
16
|
+
this._currentTime = 0;
|
|
17
|
+
}
|
|
18
|
+
set(time) {
|
|
19
|
+
this._currentTime = time;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.TimeKeeper = TimeKeeper;
|
package/lib/runner/Platform.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ export declare abstract class Platform {
|
|
|
20
20
|
protected errorHandler: (err: any) => void;
|
|
21
21
|
protected loadFileHandler: RunnerLoadFileHandler;
|
|
22
22
|
constructor(param: PlatformParameters);
|
|
23
|
+
abstract advanceLoopers(ms: number): void;
|
|
23
24
|
sendToExternal(_playId: string, data: any): void;
|
|
24
25
|
loadGameConfiguration: (url: string, callback: (err: Error | null, data?: string | Uint8Array) => void) => void;
|
|
25
26
|
}
|
package/lib/runner/Runner.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
1
2
|
import type { AMFlow } from "@akashic/amflow";
|
|
2
3
|
import { Trigger } from "@akashic/trigger";
|
|
4
|
+
import { TimeKeeper } from "../TimeKeeper";
|
|
3
5
|
import type { Platform } from "./Platform";
|
|
4
|
-
import type { RunnerAdvanceConditionFunc, RunnerExecutionMode, RunnerLoadFileHandler, RunnerPlayer, RunnerPointEvent, RunnerRenderingMode } from "./types";
|
|
6
|
+
import type { RunnerAdvanceConditionFunc, RunnerExecutionMode, RunnerLoadFileHandler, RunnerLoopMode, RunnerPlayer, RunnerPointEvent, RunnerRenderingMode } from "./types";
|
|
5
7
|
export interface RunnerParameters {
|
|
6
8
|
contentUrl: string;
|
|
7
9
|
assetBaseUrl: string;
|
|
@@ -12,6 +14,7 @@ export interface RunnerParameters {
|
|
|
12
14
|
runnerId: string;
|
|
13
15
|
amflow: AMFlow;
|
|
14
16
|
executionMode: RunnerExecutionMode;
|
|
17
|
+
loopMode?: RunnerLoopMode;
|
|
15
18
|
trusted?: boolean;
|
|
16
19
|
renderingMode?: RunnerRenderingMode;
|
|
17
20
|
loadFileHandler: RunnerLoadFileHandler;
|
|
@@ -38,6 +41,7 @@ export declare abstract class Runner {
|
|
|
38
41
|
*/
|
|
39
42
|
abstract readonly g: any;
|
|
40
43
|
abstract platform: Platform | null;
|
|
44
|
+
abstract fps: number | null;
|
|
41
45
|
errorTrigger: Trigger<Error>;
|
|
42
46
|
sendToExternalTrigger: Trigger<any>;
|
|
43
47
|
private params;
|
|
@@ -50,6 +54,7 @@ export declare abstract class Runner {
|
|
|
50
54
|
get configurationBaseUrl(): string | undefined;
|
|
51
55
|
get amflow(): AMFlow;
|
|
52
56
|
get executionMode(): RunnerExecutionMode;
|
|
57
|
+
get loopMode(): RunnerLoopMode;
|
|
53
58
|
get trusted(): boolean;
|
|
54
59
|
get renderingMode(): RunnerRenderingMode;
|
|
55
60
|
get loadFileHandler(): RunnerLoadFileHandler;
|
|
@@ -61,6 +66,9 @@ export declare abstract class Runner {
|
|
|
61
66
|
get externalValue(): {
|
|
62
67
|
[key: string]: any;
|
|
63
68
|
} | undefined;
|
|
69
|
+
protected timekeeper: TimeKeeper;
|
|
70
|
+
protected timekeeperTimerId: NodeJS.Timer | null;
|
|
71
|
+
protected timekeeperPrevTime: number;
|
|
64
72
|
constructor(params: RunnerParameters);
|
|
65
73
|
/**
|
|
66
74
|
* Runner を開始する。
|
|
@@ -84,11 +92,11 @@ export declare abstract class Runner {
|
|
|
84
92
|
* Runner を指定ミリ秒だけ進行する。
|
|
85
93
|
* @param ms 進行するミリ秒。
|
|
86
94
|
*/
|
|
87
|
-
abstract advance(ms: number): void
|
|
95
|
+
abstract advance(ms: number): Promise<void>;
|
|
88
96
|
/**
|
|
89
97
|
* Runner を一フレーム進行する。
|
|
90
98
|
*/
|
|
91
|
-
abstract step(): void
|
|
99
|
+
abstract step(): Promise<void>;
|
|
92
100
|
/**
|
|
93
101
|
* Runner に対して任意のポイントイベントを発火させる。
|
|
94
102
|
* @param event 発火させるポイントイベント
|
|
@@ -105,6 +113,12 @@ export declare abstract class Runner {
|
|
|
105
113
|
* @param timeout タイムアウトまでのミリ秒数。省略時は `5000` 。ゲーム内時間ではなく実時間である点に注意。
|
|
106
114
|
*/
|
|
107
115
|
advanceUntil(condition: RunnerAdvanceConditionFunc, timeout?: number): Promise<void>;
|
|
116
|
+
/**
|
|
117
|
+
* 次フレームを飛ばさない程度に時間を進める。
|
|
118
|
+
*/
|
|
108
119
|
protected abstract _stepMinimal(): void;
|
|
120
|
+
protected advancePlatform(ms: number): void;
|
|
121
|
+
protected startTimekeeper(): void;
|
|
122
|
+
protected stopTimekeeper(): void;
|
|
109
123
|
protected onError(error: Error): void;
|
|
110
124
|
}
|
package/lib/runner/Runner.js
CHANGED
|
@@ -11,6 +11,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.Runner = void 0;
|
|
13
13
|
const trigger_1 = require("@akashic/trigger");
|
|
14
|
+
const TimeKeeper_1 = require("../TimeKeeper");
|
|
14
15
|
class Runner {
|
|
15
16
|
get runnerId() {
|
|
16
17
|
return this.params.runnerId;
|
|
@@ -39,6 +40,10 @@ class Runner {
|
|
|
39
40
|
get executionMode() {
|
|
40
41
|
return this.params.executionMode;
|
|
41
42
|
}
|
|
43
|
+
get loopMode() {
|
|
44
|
+
var _a;
|
|
45
|
+
return (_a = this.params.loopMode) !== null && _a !== void 0 ? _a : "realtime";
|
|
46
|
+
}
|
|
42
47
|
get trusted() {
|
|
43
48
|
return !!this.params.trusted;
|
|
44
49
|
}
|
|
@@ -64,6 +69,9 @@ class Runner {
|
|
|
64
69
|
constructor(params) {
|
|
65
70
|
this.errorTrigger = new trigger_1.Trigger();
|
|
66
71
|
this.sendToExternalTrigger = new trigger_1.Trigger();
|
|
72
|
+
this.timekeeper = new TimeKeeper_1.TimeKeeper();
|
|
73
|
+
this.timekeeperTimerId = null;
|
|
74
|
+
this.timekeeperPrevTime = 0;
|
|
67
75
|
this.params = params;
|
|
68
76
|
}
|
|
69
77
|
/**
|
|
@@ -74,9 +82,9 @@ class Runner {
|
|
|
74
82
|
advanceUntil(condition, timeout = 5000) {
|
|
75
83
|
return __awaiter(this, void 0, void 0, function* () {
|
|
76
84
|
return new Promise((resolve, reject) => {
|
|
77
|
-
const limit =
|
|
85
|
+
const limit = performance.now() + timeout;
|
|
78
86
|
const handler = () => {
|
|
79
|
-
if (limit <
|
|
87
|
+
if (limit < performance.now()) {
|
|
80
88
|
return void reject(new Error("Runner#advanceUntil(): processing timeout"));
|
|
81
89
|
}
|
|
82
90
|
try {
|
|
@@ -93,6 +101,46 @@ class Runner {
|
|
|
93
101
|
});
|
|
94
102
|
});
|
|
95
103
|
}
|
|
104
|
+
advancePlatform(ms) {
|
|
105
|
+
// 以下のメソッドプロパティが存在することは呼び出し側で保証する
|
|
106
|
+
const fps = this.fps;
|
|
107
|
+
const platform = this.platform;
|
|
108
|
+
const timekeeper = this.timekeeper;
|
|
109
|
+
const frame = 1000 / fps;
|
|
110
|
+
const frameWithGrace = frame * 1.2; // 1 フレームよりも少し大きめの値
|
|
111
|
+
const steps = Math.floor(ms / frame);
|
|
112
|
+
let progress = 0;
|
|
113
|
+
for (let i = 0; i < steps; i++) {
|
|
114
|
+
const now = timekeeper.now();
|
|
115
|
+
// NOTE: 浮動小数による誤差を考慮し、 1 フレームよりも少し大きめに目標時刻を進め、その後 Looper を確実に進めた後に再度目標時刻を正常値に戻す。
|
|
116
|
+
timekeeper.advance(frameWithGrace);
|
|
117
|
+
// NOTE: game-driver の内部実装により Looper 経由で一度に進める時間に制限がある。
|
|
118
|
+
// そのため一度に進める時間を fps に応じて分割する。
|
|
119
|
+
platform.advanceLoopers(frame);
|
|
120
|
+
timekeeper.set(now + frame);
|
|
121
|
+
progress += frame;
|
|
122
|
+
}
|
|
123
|
+
timekeeper.advance(ms - progress);
|
|
124
|
+
platform.advanceLoopers(ms - progress);
|
|
125
|
+
}
|
|
126
|
+
startTimekeeper() {
|
|
127
|
+
this.stopTimekeeper();
|
|
128
|
+
const duration = 1000 / this.fps / 2; // this.fps != null の条件でのみしか呼ばれないため non-null assertion を利用
|
|
129
|
+
this.timekeeperPrevTime = performance.now();
|
|
130
|
+
this.timekeeperTimerId = setInterval(() => {
|
|
131
|
+
const now = performance.now();
|
|
132
|
+
const delta = now - this.timekeeperPrevTime;
|
|
133
|
+
this.timekeeper.advance(delta);
|
|
134
|
+
this.timekeeperPrevTime = now;
|
|
135
|
+
}, duration);
|
|
136
|
+
}
|
|
137
|
+
stopTimekeeper() {
|
|
138
|
+
if (this.timekeeperTimerId == null) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
clearInterval(this.timekeeperTimerId);
|
|
142
|
+
this.timekeeperTimerId = null;
|
|
143
|
+
}
|
|
96
144
|
onError(error) {
|
|
97
145
|
this.stop();
|
|
98
146
|
this.errorTrigger.fire(error);
|
|
@@ -2,7 +2,7 @@ import type { AMFlowClient } from "../play/amflow/AMFlowClient";
|
|
|
2
2
|
import type { PlayManager } from "../play/PlayManager";
|
|
3
3
|
import type { EncodingType } from "../utils";
|
|
4
4
|
import type { RunnerStartParameters } from "./Runner";
|
|
5
|
-
import type { RunnerExecutionMode, RunnerPlayer, RunnerRenderingMode } from "./types";
|
|
5
|
+
import type { RunnerExecutionMode, RunnerLoopMode, RunnerPlayer, RunnerRenderingMode } from "./types";
|
|
6
6
|
import type { RunnerV1Game } from "./v1";
|
|
7
7
|
import { RunnerV1 } from "./v1";
|
|
8
8
|
import type { RunnerV2Game } from "./v2";
|
|
@@ -14,6 +14,7 @@ export interface CreateRunnerParameters {
|
|
|
14
14
|
amflow: AMFlowClient;
|
|
15
15
|
playToken: string;
|
|
16
16
|
executionMode: RunnerExecutionMode;
|
|
17
|
+
loopMode?: RunnerLoopMode;
|
|
17
18
|
gameArgs?: any;
|
|
18
19
|
player?: RunnerPlayer;
|
|
19
20
|
/**
|
|
@@ -105,6 +105,7 @@ class RunnerManager {
|
|
|
105
105
|
playToken: params.playToken,
|
|
106
106
|
amflow,
|
|
107
107
|
executionMode: params.executionMode,
|
|
108
|
+
loopMode: params.loopMode,
|
|
108
109
|
trusted: params.trusted,
|
|
109
110
|
renderingMode: params.renderingMode,
|
|
110
111
|
loadFileHandler: this.createLoadFileHandler(params.allowedUrls),
|
package/lib/runner/types.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { EncodingType } from "../utils";
|
|
2
2
|
export type RunnerExecutionMode = "active" | "passive";
|
|
3
|
+
export type RunnerLoopMode = "realtime" | "replay";
|
|
3
4
|
export type RunnerRenderingMode = "none" | "canvas";
|
|
4
5
|
export type RunnerAdvanceConditionFunc = () => boolean;
|
|
5
6
|
export interface RunnerPointEvent {
|
|
@@ -15,7 +15,7 @@ export declare class RunnerV1 extends Runner {
|
|
|
15
15
|
stop(): void;
|
|
16
16
|
pause(): void;
|
|
17
17
|
resume(): void;
|
|
18
|
-
step(): void
|
|
18
|
+
step(): Promise<void>;
|
|
19
19
|
protected _stepMinimal(): void;
|
|
20
20
|
advance(ms: number): Promise<void>;
|
|
21
21
|
changeGameDriverState(param: gdr.GameDriverInitializeParameterObject): Promise<void>;
|
|
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.RunnerV1 = void 0;
|
|
13
|
+
const promises_1 = require("node:timers/promises");
|
|
13
14
|
const engine_files_v1_1 = require("engine-files-v1");
|
|
14
15
|
const Runner_1 = require("../Runner");
|
|
15
16
|
const PlatformV1_1 = require("./platform/PlatformV1");
|
|
@@ -44,6 +45,7 @@ class RunnerV1 extends Runner_1.Runner {
|
|
|
44
45
|
this.driver.stopGame();
|
|
45
46
|
this.driver = null;
|
|
46
47
|
}
|
|
48
|
+
this.stopTimekeeper();
|
|
47
49
|
this.running = false;
|
|
48
50
|
}
|
|
49
51
|
pause() {
|
|
@@ -52,6 +54,7 @@ class RunnerV1 extends Runner_1.Runner {
|
|
|
52
54
|
return;
|
|
53
55
|
}
|
|
54
56
|
this.platform.pauseLoopers();
|
|
57
|
+
this.stopTimekeeper();
|
|
55
58
|
this.running = false;
|
|
56
59
|
}
|
|
57
60
|
resume() {
|
|
@@ -60,26 +63,31 @@ class RunnerV1 extends Runner_1.Runner {
|
|
|
60
63
|
return;
|
|
61
64
|
}
|
|
62
65
|
this.platform.resumeLoopers();
|
|
66
|
+
this.startTimekeeper();
|
|
63
67
|
this.running = true;
|
|
64
68
|
}
|
|
65
69
|
step() {
|
|
66
|
-
|
|
67
|
-
this.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
this.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
70
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
71
|
+
if (this.fps == null || this.platform == null) {
|
|
72
|
+
this.errorTrigger.fire(new Error("Cannot call Runner#step() before initialized"));
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (this.running) {
|
|
76
|
+
this.errorTrigger.fire(new Error("Cannot call Runner#step() in running"));
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
this.timekeeper.advance(1000 / this.fps);
|
|
80
|
+
this.platform.advanceLoopers(Math.ceil(1000 / this.fps));
|
|
81
|
+
yield (0, promises_1.setImmediate)();
|
|
82
|
+
});
|
|
75
83
|
}
|
|
76
84
|
_stepMinimal() {
|
|
77
85
|
if (this.fps == null || this.platform == null) {
|
|
78
|
-
this.errorTrigger.fire(new Error("RunnerV1#
|
|
86
|
+
this.errorTrigger.fire(new Error("RunnerV1#_stepMinimal(): Cannot call Runner#step() before initialized"));
|
|
79
87
|
return;
|
|
80
88
|
}
|
|
81
89
|
if (this.running) {
|
|
82
|
-
this.errorTrigger.fire(new Error("RunnerV1#
|
|
90
|
+
this.errorTrigger.fire(new Error("RunnerV1#_stepMinimal(): Cannot call Runner#step() in running"));
|
|
83
91
|
return;
|
|
84
92
|
}
|
|
85
93
|
// NOTE: 現状 PDI の API 仕様により this.step() では厳密なフレーム更新ができない。そこで、一フレームの 1/2 の時間で進行することでフレームが飛んでしまうことを防止する。
|
|
@@ -103,14 +111,7 @@ class RunnerV1 extends Runner_1.Runner {
|
|
|
103
111
|
skipThreshold: Math.ceil(ms / this.fps) + 1
|
|
104
112
|
}
|
|
105
113
|
});
|
|
106
|
-
|
|
107
|
-
let progress = 0;
|
|
108
|
-
while (progress <= ms) {
|
|
109
|
-
// NOTE: game-driver の内部実装により Looper 経由で一度に進める時間に制限がある。
|
|
110
|
-
// そのため一度に進める時間を fps に応じて分割する。
|
|
111
|
-
this.platform.advanceLoopers(delta);
|
|
112
|
-
progress += delta;
|
|
113
|
-
}
|
|
114
|
+
this.advancePlatform(ms);
|
|
114
115
|
yield this.changeGameDriverState({
|
|
115
116
|
loopConfiguration: {
|
|
116
117
|
loopMode,
|
|
@@ -4,9 +4,9 @@ exports.NullAudioAsset = void 0;
|
|
|
4
4
|
const engine_files_v1_1 = require("engine-files-v1");
|
|
5
5
|
class NullAudioAsset extends engine_files_v1_1.akashicEngine.AudioAsset {
|
|
6
6
|
_load(loader) {
|
|
7
|
-
|
|
7
|
+
setImmediate(() => {
|
|
8
8
|
loader._onAssetLoad(this);
|
|
9
|
-
}
|
|
9
|
+
});
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
exports.NullAudioAsset = NullAudioAsset;
|
|
@@ -9,9 +9,9 @@ class NullImageAsset extends engine_files_v1_1.akashicEngine.ImageAsset {
|
|
|
9
9
|
this._surface = null;
|
|
10
10
|
}
|
|
11
11
|
_load(loader) {
|
|
12
|
-
|
|
12
|
+
setImmediate(() => {
|
|
13
13
|
loader._onAssetLoad(this);
|
|
14
|
-
}
|
|
14
|
+
});
|
|
15
15
|
}
|
|
16
16
|
asSurface() {
|
|
17
17
|
return this._surface || (this._surface = new NullSurface_1.NullSurface(this.width, this.height, null));
|
|
@@ -10,9 +10,9 @@ class NullVideoAsset extends engine_files_v1_1.akashicEngine.VideoAsset {
|
|
|
10
10
|
this._player = new engine_files_v1_1.akashicEngine.VideoPlayer();
|
|
11
11
|
}
|
|
12
12
|
_load(loader) {
|
|
13
|
-
|
|
13
|
+
setImmediate(() => {
|
|
14
14
|
loader._onAssetLoad(this);
|
|
15
|
-
}
|
|
15
|
+
});
|
|
16
16
|
}
|
|
17
17
|
asSurface() {
|
|
18
18
|
return this._surface || (this._surface = new NullSurface_1.NullSurface(this.width, this.height, null));
|
|
@@ -15,7 +15,7 @@ export declare class RunnerV2 extends Runner {
|
|
|
15
15
|
stop(): void;
|
|
16
16
|
pause(): void;
|
|
17
17
|
resume(): void;
|
|
18
|
-
step(): void
|
|
18
|
+
step(): Promise<void>;
|
|
19
19
|
advance(ms: number): Promise<void>;
|
|
20
20
|
changeGameDriverState(param: gdr.GameDriverInitializeParameterObject): Promise<void>;
|
|
21
21
|
firePointEvent(event: RunnerPointEvent): void;
|
|
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.RunnerV2 = void 0;
|
|
13
|
+
const promises_1 = require("node:timers/promises");
|
|
13
14
|
const engine_files_v2_1 = require("engine-files-v2");
|
|
14
15
|
const Runner_1 = require("../Runner");
|
|
15
16
|
const PlatformV2_1 = require("./platform/PlatformV2");
|
|
@@ -44,6 +45,7 @@ class RunnerV2 extends Runner_1.Runner {
|
|
|
44
45
|
this.driver.stopGame();
|
|
45
46
|
this.driver = null;
|
|
46
47
|
}
|
|
48
|
+
this.stopTimekeeper();
|
|
47
49
|
this.running = false;
|
|
48
50
|
}
|
|
49
51
|
pause() {
|
|
@@ -52,6 +54,7 @@ class RunnerV2 extends Runner_1.Runner {
|
|
|
52
54
|
return;
|
|
53
55
|
}
|
|
54
56
|
this.platform.pauseLoopers();
|
|
57
|
+
this.stopTimekeeper();
|
|
55
58
|
this.running = false;
|
|
56
59
|
}
|
|
57
60
|
resume() {
|
|
@@ -60,18 +63,23 @@ class RunnerV2 extends Runner_1.Runner {
|
|
|
60
63
|
return;
|
|
61
64
|
}
|
|
62
65
|
this.platform.resumeLoopers();
|
|
66
|
+
this.startTimekeeper();
|
|
63
67
|
this.running = true;
|
|
64
68
|
}
|
|
65
69
|
step() {
|
|
66
|
-
|
|
67
|
-
this.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
this.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
70
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
71
|
+
if (this.fps == null || this.platform == null) {
|
|
72
|
+
this.errorTrigger.fire(new Error("Cannot call Runner#step() before initialized"));
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (this.running) {
|
|
76
|
+
this.errorTrigger.fire(new Error("Cannot call Runner#step() in running"));
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
this.timekeeper.advance(1000 / this.fps);
|
|
80
|
+
this.platform.advanceLoopers(Math.ceil(1000 / this.fps));
|
|
81
|
+
yield (0, promises_1.setImmediate)();
|
|
82
|
+
});
|
|
75
83
|
}
|
|
76
84
|
advance(ms) {
|
|
77
85
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -91,14 +99,7 @@ class RunnerV2 extends Runner_1.Runner {
|
|
|
91
99
|
skipThreshold: Math.ceil(ms / this.fps) + 1
|
|
92
100
|
}
|
|
93
101
|
});
|
|
94
|
-
|
|
95
|
-
let progress = 0;
|
|
96
|
-
while (progress <= ms) {
|
|
97
|
-
// NOTE: game-driver の内部実装により Looper 経由で一度に進める時間に制限がある。
|
|
98
|
-
// そのため一度に進める時間を fps に応じて分割する。
|
|
99
|
-
this.platform.advanceLoopers(delta);
|
|
100
|
-
progress += delta;
|
|
101
|
-
}
|
|
102
|
+
this.advancePlatform(ms);
|
|
102
103
|
yield this.changeGameDriverState({
|
|
103
104
|
loopConfiguration: {
|
|
104
105
|
loopMode,
|
|
@@ -146,11 +147,11 @@ class RunnerV2 extends Runner_1.Runner {
|
|
|
146
147
|
}
|
|
147
148
|
_stepMinimal() {
|
|
148
149
|
if (this.fps == null || this.platform == null) {
|
|
149
|
-
this.errorTrigger.fire(new Error("RunnerV2#
|
|
150
|
+
this.errorTrigger.fire(new Error("RunnerV2#_stepMinimal(): Cannot call Runner#step() before initialized"));
|
|
150
151
|
return;
|
|
151
152
|
}
|
|
152
153
|
if (this.running) {
|
|
153
|
-
this.errorTrigger.fire(new Error("RunnerV2#
|
|
154
|
+
this.errorTrigger.fire(new Error("RunnerV2#_stepMinimal(): Cannot call Runner#step() in running"));
|
|
154
155
|
return;
|
|
155
156
|
}
|
|
156
157
|
// NOTE: 現状 PDI の API 仕様により this.step() では厳密なフレーム更新ができない。そこで、一フレームの 1/2 の時間で進行することでフレームが飛んでしまうことを防止する。
|
|
@@ -4,9 +4,9 @@ exports.NullAudioAsset = void 0;
|
|
|
4
4
|
const engine_files_v2_1 = require("engine-files-v2");
|
|
5
5
|
class NullAudioAsset extends engine_files_v2_1.akashicEngine.AudioAsset {
|
|
6
6
|
_load(loader) {
|
|
7
|
-
|
|
7
|
+
setImmediate(() => {
|
|
8
8
|
loader._onAssetLoad(this);
|
|
9
|
-
}
|
|
9
|
+
});
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
exports.NullAudioAsset = NullAudioAsset;
|
|
@@ -9,9 +9,9 @@ class NullImageAsset extends engine_files_v2_1.akashicEngine.ImageAsset {
|
|
|
9
9
|
this._surface = null;
|
|
10
10
|
}
|
|
11
11
|
_load(loader) {
|
|
12
|
-
|
|
12
|
+
setImmediate(() => {
|
|
13
13
|
loader._onAssetLoad(this);
|
|
14
|
-
}
|
|
14
|
+
});
|
|
15
15
|
}
|
|
16
16
|
asSurface() {
|
|
17
17
|
return this._surface || (this._surface = new NullSurface_1.NullSurface(this.width, this.height, null));
|
|
@@ -10,9 +10,9 @@ class NullVideoAsset extends engine_files_v2_1.akashicEngine.VideoAsset {
|
|
|
10
10
|
this._player = new engine_files_v2_1.akashicEngine.VideoPlayer();
|
|
11
11
|
}
|
|
12
12
|
_load(loader) {
|
|
13
|
-
|
|
13
|
+
setImmediate(() => {
|
|
14
14
|
loader._onAssetLoad(this);
|
|
15
|
-
}
|
|
15
|
+
});
|
|
16
16
|
}
|
|
17
17
|
asSurface() {
|
|
18
18
|
return this._surface || (this._surface = new NullSurface_1.NullSurface(this.width, this.height, null));
|
|
@@ -19,7 +19,7 @@ export declare class RunnerV3 extends Runner {
|
|
|
19
19
|
stop(): void;
|
|
20
20
|
pause(): void;
|
|
21
21
|
resume(): void;
|
|
22
|
-
step(): void
|
|
22
|
+
step(): Promise<void>;
|
|
23
23
|
advance(ms: number): Promise<void>;
|
|
24
24
|
changeGameDriverState(param: gdr.GameDriverInitializeParameterObject): Promise<void>;
|
|
25
25
|
firePointEvent(event: RunnerPointEvent): void;
|
|
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.RunnerV3 = void 0;
|
|
13
|
+
const promises_1 = require("node:timers/promises");
|
|
13
14
|
const Runner_1 = require("../Runner");
|
|
14
15
|
const engineFiles_1 = require("./engineFiles");
|
|
15
16
|
const PlatformV3_1 = require("./platform/PlatformV3");
|
|
@@ -44,6 +45,7 @@ class RunnerV3 extends Runner_1.Runner {
|
|
|
44
45
|
this.driver.stopGame();
|
|
45
46
|
this.driver = null;
|
|
46
47
|
}
|
|
48
|
+
this.stopTimekeeper();
|
|
47
49
|
this.running = false;
|
|
48
50
|
}
|
|
49
51
|
pause() {
|
|
@@ -52,6 +54,7 @@ class RunnerV3 extends Runner_1.Runner {
|
|
|
52
54
|
return;
|
|
53
55
|
}
|
|
54
56
|
this.platform.pauseLoopers();
|
|
57
|
+
this.stopTimekeeper();
|
|
55
58
|
this.running = false;
|
|
56
59
|
}
|
|
57
60
|
resume() {
|
|
@@ -60,18 +63,27 @@ class RunnerV3 extends Runner_1.Runner {
|
|
|
60
63
|
return;
|
|
61
64
|
}
|
|
62
65
|
this.platform.resumeLoopers();
|
|
66
|
+
this.startTimekeeper();
|
|
63
67
|
this.running = true;
|
|
64
68
|
}
|
|
65
69
|
step() {
|
|
66
|
-
|
|
67
|
-
this.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
this.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
70
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
71
|
+
if (this.fps == null || this.platform == null) {
|
|
72
|
+
this.errorTrigger.fire(new Error("Cannot call Runner#step() before initialized"));
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (this.running) {
|
|
76
|
+
this.errorTrigger.fire(new Error("Cannot call Runner#step() in running"));
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
this.timekeeper.advance(1000 / this.fps);
|
|
80
|
+
this.platform.stepLoopers();
|
|
81
|
+
// Looper を進行させるとアセット読み込み・AMFlow のコールバックなどの setImmediate() が実行されるが、
|
|
82
|
+
// それらを Runner#step() の完了タイミングで確実に処理するため、Runner#step() の完了を setImmediate() で遅延させている。
|
|
83
|
+
// ここを単純な Promise で返しても microtask queue に積まれるため、macrotask queue に積まれる setImmediate() の処理の完了を待つことはできない。
|
|
84
|
+
// @see https://nodejs.org/en/learn/asynchronous-work/understanding-setimmediate
|
|
85
|
+
yield (0, promises_1.setImmediate)();
|
|
86
|
+
});
|
|
75
87
|
}
|
|
76
88
|
advance(ms) {
|
|
77
89
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -96,14 +108,7 @@ class RunnerV3 extends Runner_1.Runner {
|
|
|
96
108
|
skipThreshold: Math.ceil(ms / this.fps) + 1
|
|
97
109
|
}
|
|
98
110
|
});
|
|
99
|
-
|
|
100
|
-
let progress = 0;
|
|
101
|
-
while (progress <= ms) {
|
|
102
|
-
// NOTE: game-driver の内部実装により Looper 経由で一度に進める時間に制限がある。
|
|
103
|
-
// そのため一度に進める時間を fps に応じて分割する。
|
|
104
|
-
this.platform.advanceLoopers(delta);
|
|
105
|
-
progress += delta;
|
|
106
|
-
}
|
|
111
|
+
this.advancePlatform(ms);
|
|
107
112
|
yield this.changeGameDriverState({
|
|
108
113
|
loopConfiguration: {
|
|
109
114
|
loopMode,
|
|
@@ -170,7 +175,16 @@ class RunnerV3 extends Runner_1.Runner {
|
|
|
170
175
|
return this.getPrimarySurface()._drawable;
|
|
171
176
|
}
|
|
172
177
|
_stepMinimal() {
|
|
173
|
-
this.
|
|
178
|
+
if (this.fps == null || this.platform == null) {
|
|
179
|
+
this.errorTrigger.fire(new Error("RunnerV3#_stepMinimal(): Cannot call Runner#step() before initialized"));
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
if (this.running) {
|
|
183
|
+
this.errorTrigger.fire(new Error("RunnerV3#_stepMinimal(): Cannot call Runner#step() in running"));
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
// NOTE: 現状 PDI の API 仕様により this.step() では厳密なフレーム更新ができない。そこで、一フレームの 1/2 の時間で進行することでフレームが飛んでしまうことを防止する。
|
|
187
|
+
this.platform.advanceLoopers(1000 / this.fps / 2);
|
|
174
188
|
}
|
|
175
189
|
initGameDriver() {
|
|
176
190
|
return new Promise((resolve, reject) => {
|
|
@@ -183,6 +197,7 @@ class RunnerV3 extends Runner_1.Runner {
|
|
|
183
197
|
name: this.player ? this.player.name : undefined
|
|
184
198
|
};
|
|
185
199
|
const executionMode = this.executionMode === "active" ? engineFiles_1.gameDriver.ExecutionMode.Active : engineFiles_1.gameDriver.ExecutionMode.Passive;
|
|
200
|
+
const loopMode = this.loopMode === "replay" ? engineFiles_1.gameDriver.LoopMode.Replay : engineFiles_1.gameDriver.LoopMode.Realtime;
|
|
186
201
|
this.platform = new PlatformV3_1.PlatformV3({
|
|
187
202
|
configurationBaseUrl: this.configurationBaseUrl,
|
|
188
203
|
assetBaseUrl: this.assetBaseUrl,
|
|
@@ -212,7 +227,8 @@ class RunnerV3 extends Runner_1.Runner {
|
|
|
212
227
|
executionMode
|
|
213
228
|
},
|
|
214
229
|
loopConfiguration: {
|
|
215
|
-
loopMode
|
|
230
|
+
loopMode,
|
|
231
|
+
targetTimeFunc: this.timekeeper.now
|
|
216
232
|
},
|
|
217
233
|
gameArgs: this.gameArgs
|
|
218
234
|
}, (e) => {
|
|
@@ -12,9 +12,9 @@ class NullImageAsset extends Asset_1.Asset {
|
|
|
12
12
|
this.height = height;
|
|
13
13
|
}
|
|
14
14
|
_load(loader) {
|
|
15
|
-
|
|
15
|
+
setImmediate(() => {
|
|
16
16
|
loader._onAssetLoad(this);
|
|
17
|
-
}
|
|
17
|
+
});
|
|
18
18
|
}
|
|
19
19
|
asSurface() {
|
|
20
20
|
return this._surface || (this._surface = new NullSurface_1.NullSurface(this.width, this.height));
|
|
@@ -19,9 +19,9 @@ class NullVideoAsset extends Asset_1.Asset {
|
|
|
19
19
|
this._player = new NullVideoPlayer_1.NullVideoPlayer();
|
|
20
20
|
}
|
|
21
21
|
_load(loader) {
|
|
22
|
-
|
|
22
|
+
setImmediate(() => {
|
|
23
23
|
loader._onAssetLoad(this);
|
|
24
|
-
}
|
|
24
|
+
});
|
|
25
25
|
}
|
|
26
26
|
asSurface() {
|
|
27
27
|
return this._surface || (this._surface = new NullSurface_1.NullSurface(this.width, this.height));
|