refactor(0.1.14-P1): 内核归位——game/ 按引擎架构重排(零行为漂移)
结构(旧 game/core+engine → 新 engine/ 域): - engine/kernel/ 时钟/随机/插件协议/fxqueue/timesense/format/urgency/guide/names(原 core) - engine/narrative/ legacy/报告/列传/谱系/年轴(原 core 叙事族) - engine/runtime/ World/creation/pcgen/ApiFacade/capabilities/pluginManager/boot/clocks + Systems/*(12 系统) - engine/sim/ Market(未来 WorldSim 同行) - 旧 game/core、engine/systems、engine/world.ts 等路径全部废弃(无 re-export 兼容层) 验证:35 套件/967 测试全绿(金钟罩三档零漂移=纯搬迁无行为变化) typecheck 0 error
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
export type FxKind = 'spark' | 'mist' | 'ripple' | 'blade' | 'pulse' | 'seasonShift' | 'drift'
|
||||
|
||||
export type FxMode = 'soft' | 'std' | 'full'
|
||||
|
||||
export interface FxEmit {
|
||||
kind: FxKind
|
||||
payload?: Record<string, number | string>
|
||||
at: number
|
||||
}
|
||||
|
||||
export interface FxBus {
|
||||
emit(e: FxEmit): void
|
||||
}
|
||||
|
||||
/** 竞态安全发射闸:单循环、队列不覆盖、档位过滤、reduced-motion 降级 */
|
||||
export class FxGate {
|
||||
private queue: FxEmit[] = []
|
||||
private draining = false
|
||||
mode: FxMode = 'std'
|
||||
preferReduced = false
|
||||
|
||||
constructor(private bus: FxBus) {}
|
||||
|
||||
setMode(m: FxMode): void {
|
||||
this.mode = m
|
||||
}
|
||||
|
||||
setReduced(r: boolean): void {
|
||||
this.preferReduced = r
|
||||
}
|
||||
|
||||
allowed(kind: FxKind): boolean {
|
||||
if (this.mode === 'soft') return kind === 'ripple' || kind === 'pulse' || kind === 'drift'
|
||||
if (this.mode === 'full') return true
|
||||
return kind !== 'blade' // std:火花/雾/涟漪/脉动,刀光仅 full
|
||||
}
|
||||
|
||||
emit(kind: FxKind, payload?: FxEmit['payload']): void {
|
||||
if (!this.allowed(kind) || this.preferReduced || this.draining) return
|
||||
this.queue.push({ kind, payload, at: Date.now() })
|
||||
this.drain()
|
||||
}
|
||||
|
||||
private drain(): void {
|
||||
if (this.draining) return
|
||||
this.draining = true
|
||||
// 单帧集中派发(不逐个 setTimeout,防止栈深+竞态覆盖)
|
||||
const batch = this.queue
|
||||
this.queue = []
|
||||
try {
|
||||
for (const e of batch) this.bus.emit(e)
|
||||
} finally {
|
||||
this.draining = false
|
||||
}
|
||||
}
|
||||
|
||||
pending(): number {
|
||||
return this.queue.length + (this.draining ? 1 : 0)
|
||||
}
|
||||
|
||||
/** 纯逻辑:资源差量(防负值与 NaN,供漂字用) */
|
||||
static deltas(prev: Record<string, number>, next: Record<string, number>): Record<string, number> {
|
||||
const out: Record<string, number> = {}
|
||||
const keys = new Set([...Object.keys(prev), ...Object.keys(next)])
|
||||
for (const k of keys) {
|
||||
const a = prev[k] ?? 0
|
||||
const b = next[k] ?? 0
|
||||
if (Number.isFinite(a) && Number.isFinite(b) && b !== a) out[k] = b - a
|
||||
}
|
||||
return out
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user