v0.1.7: 仙门之钥(门面化/能力注册表/数据包/开发者面板)
- GameFacade 统一门面:act(23 种动作白名单)/query(6 类只读快照)/subscribe(七大事件协议)/ about(版本+模块清单+数据包指纹);UI store 接入门面(act 直达,散装调用收口) - CapabilityRegistry:12 张能力卡(id/name/version/desc/hooks),world.systems 启停即拔插, 时钟按能力开关过滤(禁修炼则无人精进…沙盒玩法);sysChanged 广播 - DataPackRegistry:默认包与静态数据同引用(金钟罩零漂移),override/reset/fingerprint, 高频读口 6 处迁移 pack()——未来 MOD=注入数据包覆写 - 开发者面板:设置页系统仪表盘(清单+启停开关+警示文案) - 测试 225→239(能力清单/拔插分殊四路/广播幂等/包覆盖物价/act 目录/query/协议退订/about/ 金钟罩复验零漂移)
This commit is contained in:
@@ -5,6 +5,7 @@ import { findEvent, applyEventChoice } from '../game/engine/systems/events'
|
||||
import { BattleLog, ChronicleEntry, GameState, LogItem, SaveMeta, YearlyReport, SnapshotMeta } from '../game/types/domain'
|
||||
import { getSlotManager, getSaveSlot } from '../game/storage/db'
|
||||
import { metaFromState, updateSlotMeta } from './storeHelper'
|
||||
import { GameFacade, ActName } from '../game/engine/api'
|
||||
import { setSoundEnabled, sPaper, sGood, sBad, sWar, sBell, sGong, sClick, sTick } from './sound'
|
||||
import type { PhaseStat } from '../game/core/clock'
|
||||
|
||||
@@ -58,6 +59,8 @@ export interface GameStore {
|
||||
onYearPaper: (report: YearlyReport) => void
|
||||
closePaper: () => void
|
||||
toggleSound: () => void
|
||||
facade?: GameFacade
|
||||
act: (name: ActName, payload: import('../game/engine/api').ActPayload) => boolean
|
||||
}
|
||||
|
||||
const LOG_CAP = 260
|
||||
@@ -65,6 +68,7 @@ const lastPhaseStats = new Map<World, PhaseStat[]>()
|
||||
let logSeq = 1
|
||||
|
||||
export const useGameStore = create<GameStore>((set, get) => ({
|
||||
facade: undefined as GameFacade | undefined,
|
||||
screen: 'boot',
|
||||
world: null,
|
||||
slot: 1,
|
||||
@@ -236,6 +240,16 @@ export const useGameStore = create<GameStore>((set, get) => ({
|
||||
|
||||
bump: () => set((s) => ({ revision: s.revision + 1 })),
|
||||
|
||||
act: (name, payload) => {
|
||||
const st = get()
|
||||
const w = st.world
|
||||
if (!w) return false
|
||||
const ok = st.facade ? st.facade.act(name, payload) : actDirect(w, name, payload)
|
||||
if (ok) set((s) => ({ revision: s.revision + 1 }))
|
||||
return ok
|
||||
},
|
||||
|
||||
|
||||
setSpeed: (v) => {
|
||||
const st = get()
|
||||
if (st.timer) clearInterval(st.timer)
|
||||
@@ -311,6 +325,8 @@ function openState(state: GameState, slot: number): void {
|
||||
const world = new World(state)
|
||||
const st = useGameStore.getState()
|
||||
world.out.push(makeBus(st))
|
||||
const facade = new GameFacade(world, slot)
|
||||
world.out.push(facadebus(facade))
|
||||
useGameStore.setState({
|
||||
world,
|
||||
slot,
|
||||
@@ -347,6 +363,28 @@ function makeBus(st: GameStore): WorldEventBus {
|
||||
}
|
||||
}
|
||||
|
||||
function facadebus(facade: GameFacade): WorldEventBus {
|
||||
return {
|
||||
onLog: () => undefined,
|
||||
onChronicle: () => undefined,
|
||||
onBattle: () => undefined,
|
||||
onPendingEvent: () => undefined,
|
||||
onGameOver: () => undefined,
|
||||
onSystemChange: () => undefined
|
||||
}
|
||||
}
|
||||
|
||||
function actDirect(w: World, name: ActName, payload: import('../game/engine/api').ActPayload): boolean {
|
||||
if (name === 'legacy.resolve') return (w.resolveLegacyNow(), true)
|
||||
if (name === 'estate.rite') return w.ancestralRite()
|
||||
if (name === 'estate.sutra') return w.seekSutra()
|
||||
if (name === 'estate.build' && payload.building) return w.build(payload.building)
|
||||
if (name === 'estate.upgrade' && payload.building) return w.upgrade(payload.building)
|
||||
if (name === 'member.post' && payload.memberId) return w.assignPost(payload.memberId, payload.post)
|
||||
if (name === 'member.marry' && payload.memberId && payload.targetId) return w.marryTo(payload.memberId, payload.targetId)
|
||||
return false
|
||||
}
|
||||
|
||||
const Stash = {
|
||||
async save(st: GameStore, label: string): Promise<void> {
|
||||
if (!st.world) return
|
||||
|
||||
Reference in New Issue
Block a user