@yyyu-star/arcade-kit 0.11.0 → 0.11.1
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/CHANGELOG.md +12 -0
- package/README.md +7 -1
- package/dist/client.d.ts +41 -8
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +119 -43
- package/dist/client.js.map +1 -1
- package/dist/room.d.ts +5 -0
- package/dist/room.d.ts.map +1 -1
- package/dist/room.js +24 -5
- package/dist/room.js.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +119 -41
- package/src/room.ts +28 -4
package/src/room.ts
CHANGED
|
@@ -117,6 +117,8 @@ export const DEFAULT_LIMITS: RoomLimits = {
|
|
|
117
117
|
|
|
118
118
|
/** 闹钟里出错时,过这么久再醒来重试(不用"马上",免得每次都出错时连着计费)。 */
|
|
119
119
|
const ALARM_RETRY_MS = 60_000;
|
|
120
|
+
/** 每个座位记住最近几个做成的 moveId(0.11.1):客户端断线时攒着没确认的操作,重连后原样补发 */
|
|
121
|
+
const RECENT_MOVES = 8;
|
|
120
122
|
|
|
121
123
|
/** 计量说的门槛在内存里记多久(不进新人时用;报数、还名额时顺便更新)。 */
|
|
122
124
|
const LEVEL_TTL_MS = 30_000;
|
|
@@ -148,6 +150,11 @@ interface SeatState {
|
|
|
148
150
|
auto: boolean;
|
|
149
151
|
/** 这个座位最后一次做成的操作的 moveId(重发去重) */
|
|
150
152
|
lastMoveId: string | null;
|
|
153
|
+
/**
|
|
154
|
+
* 最近做成的几个 moveId,新的在后(0.11.1,最多 RECENT_MOVES 个;旧房间的状态里没有,读到时当空的)。
|
|
155
|
+
* 只记最后一个不够:连发 A、B,A 的 ack 丢了,重连后补发 A,lastMoveId 已经是 B,不轮流的操作(free)就会被做第二遍
|
|
156
|
+
*/
|
|
157
|
+
recentMoves?: string[];
|
|
151
158
|
}
|
|
152
159
|
|
|
153
160
|
interface Persist<S> {
|
|
@@ -389,13 +396,14 @@ export abstract class GameRoom<S, A, V, Env = unknown, O = unknown, E extends Ro
|
|
|
389
396
|
this.alarmAt = null;
|
|
390
397
|
await this.entry(() => this.onAlarm());
|
|
391
398
|
// 出错时状态可能没走到"重设闹钟"那一步:房间还在、又没有闹钟,就过一会儿再醒来,不然房间永远没人关
|
|
392
|
-
|
|
399
|
+
// setAlarm 本身失败时 alarmAt 是 undefined(不知道),以存储里读到的为准(0.11.1)
|
|
400
|
+
if (this.lastStepFailed && this.load() && (this.alarmAt === undefined ? await this.ctx.storage.getAlarm() : this.alarmAt) === null) {
|
|
393
401
|
this.alarmAt = Date.now() + ALARM_RETRY_MS;
|
|
394
402
|
this.lastStepWrites++;
|
|
395
403
|
this.totalWrites++;
|
|
396
404
|
this.unmetered++;
|
|
397
405
|
this.maxStepWrites = Math.max(this.maxStepWrites, this.lastStepWrites);
|
|
398
|
-
await this.
|
|
406
|
+
await this.setAlarmSafely(this.alarmAt);
|
|
399
407
|
}
|
|
400
408
|
} catch (e) {
|
|
401
409
|
console.error('room alarm failed', e instanceof Error ? e.message : e);
|
|
@@ -430,11 +438,26 @@ export abstract class GameRoom<S, A, V, Env = unknown, O = unknown, E extends Ro
|
|
|
430
438
|
this.totalWrites += this.writes;
|
|
431
439
|
this.unmetered += this.writes;
|
|
432
440
|
this.maxStepWrites = Math.max(this.maxStepWrites, this.writes);
|
|
433
|
-
if (at !== null
|
|
441
|
+
if (at !== null && !(await this.setAlarmSafely(at))) this.lastStepFailed = true;
|
|
434
442
|
await this.afterStep();
|
|
435
443
|
return out;
|
|
436
444
|
}
|
|
437
445
|
|
|
446
|
+
/**
|
|
447
|
+
* 设闹钟;失败了不往外抛(0.11.1)。planAlarm 已经把 alarmAt 改成了新时间,失败时它就是错的:
|
|
448
|
+
* 留着的话以后 planAlarm 看"已经设了更早的"一直不重设,房间就没人收场。改回"不知道",下一个入口按 getAlarm() 重新读、照常重排
|
|
449
|
+
*/
|
|
450
|
+
private async setAlarmSafely(at: number): Promise<boolean> {
|
|
451
|
+
try {
|
|
452
|
+
await this.ctx.storage.setAlarm(at);
|
|
453
|
+
return true;
|
|
454
|
+
} catch (e) {
|
|
455
|
+
console.error('room setAlarm failed', e instanceof Error ? e.message : e);
|
|
456
|
+
this.alarmAt = undefined;
|
|
457
|
+
return false;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
438
461
|
// ---------- 计量(0.2.0) ----------
|
|
439
462
|
|
|
440
463
|
/**
|
|
@@ -809,7 +832,7 @@ export abstract class GameRoom<S, A, V, Env = unknown, O = unknown, E extends Ro
|
|
|
809
832
|
if (seat === null) return this.reject(ws, 'not_seated', moveId);
|
|
810
833
|
const s = st.seats[seat]!;
|
|
811
834
|
// 重发的同一个操作:不再做一遍,只回 ack 和当前状态
|
|
812
|
-
if (s.lastMoveId === moveId) {
|
|
835
|
+
if (s.lastMoveId === moveId || s.recentMoves?.includes(moveId)) {
|
|
813
836
|
const bound = this.boundOf(attachmentOf(ws)!.userId);
|
|
814
837
|
return this.send(ws, this.stateMsg(seat, bound, [{ state: st.game, delay: 0 }], moveId));
|
|
815
838
|
}
|
|
@@ -828,6 +851,7 @@ export abstract class GameRoom<S, A, V, Env = unknown, O = unknown, E extends Ro
|
|
|
828
851
|
const out = this.step(seat, action, now, free);
|
|
829
852
|
if (out) return this.reject(ws, out, moveId);
|
|
830
853
|
s.lastMoveId = moveId;
|
|
854
|
+
s.recentMoves = [...(s.recentMoves ?? []), moveId].slice(-RECENT_MOVES);
|
|
831
855
|
const auto = this.runAuto(now);
|
|
832
856
|
if (seen !== null && auto.length === 0 && this.othersSee(seat) === seen) return this.commitQuiet(ws, seat, moveId);
|
|
833
857
|
this.commit({ frames: [{ state: st.game, delay: 0 }, ...auto], ack: { ws, moveId } });
|