From 501a598de0026904ea3a4189e06668d077d0c5ba Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Sat, 16 May 2026 23:43:14 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=A7=A6=E5=8F=91=E5=99=A8=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dev.md | 3 + docs/dev/map/trigger.md | 103 +++++++++++++ packages-user/data-base/src/map/layerState.ts | 13 +- packages-user/data-base/src/map/types.ts | 8 + packages-user/data-system/src/index.ts | 1 + .../data-system/src/trigger/collection.ts | 57 +++++++ .../data-system/src/trigger/index.ts | 3 + .../data-system/src/trigger/registry.ts | 49 ++++++ .../data-system/src/trigger/types.ts | 139 ++++++++++++++++++ packages/common/src/logger.json | 2 + prompt.md | 1 + 11 files changed, 378 insertions(+), 1 deletion(-) create mode 100644 docs/dev/map/trigger.md create mode 100644 packages-user/data-system/src/trigger/collection.ts create mode 100644 packages-user/data-system/src/trigger/index.ts create mode 100644 packages-user/data-system/src/trigger/registry.ts create mode 100644 packages-user/data-system/src/trigger/types.ts diff --git a/dev.md b/dev.md index 25f8975..45ec7b8 100644 --- a/dev.md +++ b/dev.md @@ -75,6 +75,7 @@ - 注释合理换行:考虑中文字符较宽,建议每 40–60 个字符在标点符号后换行,不要频繁换行,每行长度应差不多,不允许在句中换行;参数注释换行后保持对齐。 - 单行注释结尾不加句号;较长的多行注释结尾可加句号。 - 一般不建议给接口(`inteface` 本身)、类型别名或类本身写注释(不好看),特殊情况除外。 +- 对于 jsDoc 注释,方法注释必须使用换行风格;对于成员 jsDoc 注释,除非注释较长需要换行,否则使用不换行的风格。 ### 类型规范 @@ -85,6 +86,7 @@ - 合理使用 `readonly`、`protected`、`private` 关键字。 - 可选参数过多时(大于两个),考虑改用对象参数。 - 尽量避免 `as` 类型断言,除非必要。 +- 函数类型单独开一个 `type` 类型别名,除非函数类型本身较短(小于 20 字符,且不会因为此函数类型导致换行) ### 其他要求 @@ -96,6 +98,7 @@ - 只进行必要的非空判断,非必要时直接使用非空断言 `!`。 - 除非参数要求传入函数等情况,不建议在函数内定义局部函数。 - 语句尽量不换行,除非必要,尤其注意三元运算符与 `private readonly` 类成员。 +- 任何时候都不应该写 `getter` 和 `setter`。 ## 双端分离 diff --git a/docs/dev/map/trigger.md b/docs/dev/map/trigger.md new file mode 100644 index 0000000..9583cc4 --- /dev/null +++ b/docs/dev/map/trigger.md @@ -0,0 +1,103 @@ +# 需求综述 + +当前地图系统已完成图层管理与动态图块的构建,但地图上每个格点可能存在的**事件逻辑**(如战斗、对话、商店等)尚无统一抽象。本需求旨在建立一套触发器系统,将地图事件的注册、收集与触发解耦为三个独立接口层,最终可通过统一的方式触发地图上某一点所有匹配的事件。 + +触发器本身不与地图绑定,可独立于地图存在。由于触发的执行依赖 Layer 2 的上下文(`IStateBase` 等),整个触发器系统均归属 Layer 2(`@user/data-system`),地图在 Layer 1 中只存储可序列化的图块数据,不直接持有 `ITrigger`。 + +--- + +# 接口设计与预期 + +## ITrigger + +- `ITrigger.type`:预期频率**低频**,触发器的类型标识符,以数字表示,用于区分不同种类的触发器(如战斗、对话等);一般仅在实例化时通过构造参数传入一次,运行期基本不读写,故为低频。 +- `ITrigger.priority`:预期频率**低频**,仅在创建触发器时设置一次,用于控制同格点多触发器的执行顺序;绝大多数情况下一个格点只会有一个触发器,多触发器仅为少量拓展场景预留,在 `collect` 场景下,同一次收集中的 `priority` 重复会被视为配置冲突,故为低频。 +- `ITrigger.trigger(handler)`:预期频率**中频**,用户在脚本中有时会直接持有某个触发器引用并手动触发,但大多数事件触发都通过 `ITriggerCollection.trigger` 完成,直接调用此方法的场合相对有限,故为中频。接受 `ITriggerHandler` 上下文对象(必选 `state: IStateBase`,可选 `layer?: ILayerState`、`mapLayer?: IMapLayer`、`locator?: ITileLocator`),返回 `Promise`。典型使用场景:脚本中已持有某个战斗触发器引用,希望直接触发而不经过格点收集流程。 +- `ITrigger.collection()`:预期频率**中频**,当用户希望将单个触发器包装为集合并走统一触发流程时使用,场景较为固定但有一定出现概率,故为中频。典型使用场景:脚本中手动构造只含单个触发器的集合,再调用 `collection.trigger(...)` 统一触发。 + +## ITriggerRegistry + +以触发器**类型**(`type: number`)为核心提供注册与查询;`registerString` / `getString` 是触发器自身 id 的字符串别名,与地图图块绑定无关,不参与 `collect` 的自动收集流程。共四个方法,不拆分为子接口。 + +- `ITriggerRegistry.register(type, factory)`:预期频率**低频**,按触发器类型注册触发器工厂函数(`(type: number) => ITrigger`),由注册表在实例化时将当前 `type` 透传给工厂,使 `ITrigger.type` 跟随注册表,`collect` 时每次调用工厂创建独立实例,一种触发器类型只注册一次,故为低频。 +- `ITriggerRegistry.get(type)`:预期频率**低频**,主要供 `ITriggerCollector` 内部调用,用户代码几乎不会直接使用,故为低频。 +- `ITriggerRegistry.registerString(id, factory)`:预期频率**低频**,为触发器注册字符串别名(`() => ITrigger`),仅用于手动按字符串 id 查询,与地图图块收集无关,故为低频。 +- `ITriggerRegistry.getString(id)`:预期频率**低频**,按字符串 id 查询触发器工厂,调用方手动获取后实例化,主要供内部调用,故为低频。 + +## ITriggerCollection + +- `ITriggerCollection.count`:预期频率**低频**,在"当格点无任何触发器时跳过处理"的场景下可快速判断,避免额外迭代,故为低频。 +- `ITriggerCollection.trigger(handler)`:预期频率**高频**,这是触发器系统对用户暴露的最主要入口,凡是需要触发某格事件的地方都会出现此调用,故为高频。接受 `ITriggerHandler` 上下文对象,顺序异步执行所有触发器,返回 `Promise`。典型使用场景:玩家移动到某格后,移动系统调用 `collection.trigger(handler)` 依次执行该格所有已排序的触发器。 +- `ITriggerCollection.triggerIter(handler)`:预期频率**低频**,返回 `AsyncGenerator`,允许调用方逐个手动推进触发器执行,每次 `next(handler)` 可传入新的上下文(传 `null` 则沿用初始 `handler`),故为低频。典型使用场景:需要在两个触发器之间插入额外效果(如战斗结束后立刻播放特效)的进阶场景。 +- `ITriggerCollection.iterate()`:预期频率**低频**,仅在需要检查当前集合包含哪些触发器时使用(如 UI 显示交互提示),多数情况下直接触发而无需遍历,故为低频。 +- `ITriggerCollection.push(trigger)`:预期频率**低频**,在脚本中偶尔需要向已有集合末尾追加一个触发器(如特殊演出追加额外效果),直接插入末尾不重新排序,故为低频。 +- `ITriggerCollection.unshift(trigger)`:预期频率**低频**,与 `push` 对称,向集合头部强制插入触发器,直接插入头部不重新排序,场景更为罕见,故为低频。 +- `ITriggerCollection.concat(...others)`:预期频率**低频**,将当前集合与一个或多个其他集合按自身在前、传入参数依序在后的顺序合并为新集合,不重新排序。此接口需求存疑,先行提供,故为低频。 + +## ITriggerCollector + +`ITriggerCollector` 独立存在于 Layer 2(`@user/data-system`),不附属于 `ILayerState`。调用方持有 collector 引用,调用 `collect(x, y, layer)` 时显式传入目标图层(`IMapLayer`)。收集时会依赖后续由 `IMapLayer.getTileInfo` 暴露的图块信息,其中包含触发器类型。引擎层会利用 `ILayerState.eventLayer` 自动调用 `collect` 实现默认收集行为,该行为不在本接口设计范围内;若需对多个图层收集,调用方自行多次调用并合并结果,合并顺序、跨层排序结果与跨层冲突处理均由调用方自行决定。 + +- `ITriggerCollector.collect(x, y, layer)`:预期频率**中频**,在移动系统或交互系统中需要确认某格事件时调用,使用场景固定且有一定频率,故为中频。`layer` 为必选,调用方显式指定要收集的目标图层(`IMapLayer`)。典型使用场景:玩家向某格移动时,移动系统持有 collector 引用并调用 `collector.collect(x, y, layer)` 获取目标格的 `ITriggerCollection`,再决定是否阻断移动或直接触发。 +- `ITriggerCollector.attachRegistry(registry)`:预期频率**低频**,仅在初始化或切换注册表时调用,故为低频。 + +--- + +# 实现思路 + +## 1. 触发器对象 ITrigger + +`ITrigger` 代表一类事件逻辑(如"战斗触发器"、"对话触发器"),是整个系统的原子单元。`type` 成员以数字标识触发器种类,在常规注册流程下由注册表在实例化时通过构造参数注入;`priority` 控制同格点的执行顺序,并在 `collect` 场景下充当唯一执行位。触发器本身是极其宽泛的东西,一般只有几种类型,比如战斗、触发系统事件、触发自定义事件等,不会每种战斗和每种对话都开一种触发器。触发时接受外部传入的 `ITriggerHandler` 上下文参数,执行对应逻辑。 + +`ITrigger` 提供 `collection()` 方法,将单个触发器包装为 `ITriggerCollection`,供不需要收集步骤的场景直接使用。 + +## 2. 触发器注册接口 ITriggerRegistry + +触发器以类型为单位注册。为保证每个收集场景下的 `ITrigger` 实例相互独立(触发器可在内部保存状态而不互相影响),注册时传入工厂函数 `(type: number) => ITrigger`,由注册表在创建实例时将当前类型透传给工厂,使实例上的 `ITrigger.type` 跟随注册表;`collect` 时按需调用工厂创建新实例。字符串别名注册仍用于手动查询场景,不参与 `collect` 自动收集。`ITriggerRegistry` 直接包含以下四个方法: + +- `register(type: number, factory: (type: number) => ITrigger)`:按触发器类型注册触发器工厂 +- `get(type: number)`:按触发器类型查询触发器工厂 +- `registerString(id: string, factory: () => ITrigger)`:为触发器注册字符串别名(仅用于手动查询,不参与 `collect` 自动收集) +- `getString(id: string)`:按字符串 id 查询触发器工厂 + +每个 key 只对应一个工厂。重复注册同一 key 时,发出警告并以新工厂覆盖旧的。 + +## 3. 触发收集 ITriggerCollector + +`ITriggerCollector` 属于 Layer 2(`@user/data-system`),独立于 `ILayerState` 存在,不挂载到任何 Layer 1 接口上。地图在 Layer 1 中只存储可序列化的图块数据(如图块编号),不持有 `ITrigger` 实例。收集时,调用方显式传入目标图层 `layer`(`IMapLayer`),`ITriggerCollector` 读取该图层中该格点的图块数据——包括静态图块(通过 `IMapLayer.getBlock`)以及动态图块(通过 `IMapLayer.dynamicLayer`)——并结合后续由 `IMapLayer.getTileInfo` 暴露的图块信息读取其中记录的触发器类型,再通过 `ITriggerRegistry` 获取工厂并构造对应的 `ITrigger`,收集后排序,返回 `ITriggerCollection`。注册表通过 `attachRegistry(registry)` 设置。 + +排序规则:按触发器自身 `priority` 降序排列。这里的 `priority` 不仅表示执行顺序,也表示单次收集内的唯一执行位;正常情况下同一坐标只会有一个触发器,多触发器支持仅用于极少数拓展场景。收集阶段若发现两个或以上触发器的 `priority` 相同,则视为配置冲突,发出警告,并将本次结果中所有该优先级的触发器全部剔除,不进入 `ITriggerCollection`。 + +## 4. 触发器集合 ITriggerCollection + +`ITriggerCollection` 是一组已排序的 `ITrigger` 的载体,提供统一的触发入口 `trigger(...)` 与迭代方法 `iterate()`、数量属性 `count`。`push` / `unshift` / `concat` 均不对集合重新排序,语义为"强制指定执行位置",与 `priority` 排序体系完全分离(`ITriggerCollection` 本身与地图无关,不应自行排序)。可由: + +- `ITriggerCollector.collect` 返回; +- `ITrigger.collection()` 方法直接构造(单触发器集合)。 + +触发执行策略:`trigger(handler)` 顺序异步执行(返回 `Promise`),触发器之间串行等待;`triggerIter(handler)` 返回异步生成器,调用方可逐个推进执行并为每一步单独传入上下文,适用于需要在触发器间插入额外逻辑的进阶场景。 + +--- + +# 涉及文件 + +## 需要引用的文件 + +- `@user/data-base`(跨包引用):`@user/data-system/trigger/types.ts` 中的 `ITriggerHandler` 需要引用 `IStateBase`(全局状态)、`ILayerState`(楼层状态)、`IMapLayer`(图层)与 `ITileLocator`;`ITriggerCollector.collect` 同样需要引用 `IMapLayer`,并依赖其后续提供的 `getTileInfo` 读取图块信息中的触发器类型 + +## 需要修改的文件 + +### `@user/data-base` 中的 `ILayerState` + +- [x] 新增 `readonly eventLayer: IMapLayer | null` 属性:表示该楼层的默认事件图层,供引擎默认收集行为使用(引擎默认收集逻辑不在本设计范围内) +- [x] 新增 `setEventLayer(layer: IMapLayer | null): void` 方法:设置默认事件图层 + +## 需要新建的文件 + +### `@user/data-system/trigger/types.ts` + +- [ ] 新增 `ITriggerHandler` 接口:触发时传入的上下文对象,包含必选的 `state: IStateBase` 以及可选的 `layer?: ILayerState`、`mapLayer?: IMapLayer`、`locator?: ITileLocator` +- [ ] 新增 `ITrigger` 接口:触发器原子对象,代表一类事件逻辑;包含 `type: number` 类型标识、`priority` 优先级成员、`trigger(handler: ITriggerHandler): Promise` 触发方法与 `collection()` 方法以便包装为集合 +- [ ] 新增 `ITriggerRegistry` 接口:包含 `register(type, factory: (type: number) => ITrigger)` `get(type)` `registerString(id, factory: () => ITrigger)` `getString(id)` 四个方法;以触发器类型 `type` 为核心管理注册与查询,字符串 id 为触发器自身别名,不参与 `collect` 自动收集;数字注册路径下由注册表透传 `type` 给工厂,保证实例的 `ITrigger.type` 与注册项一致 +- [ ] 新增 `ITriggerCollection` 接口:包含已排序的触发器集合,提供 `trigger(handler)` 顺序异步触发入口(`Promise`)与 `triggerIter(handler)` 异步迭代触发入口(`AsyncGenerator`)、`iterate()` 迭代方法、`count` 数量属性、`push` / `unshift` 向集合末尾或头部插入(不重排序)的方法,以及 `concat(...others)` 按自身在前的顺序合并多个集合(不重排序)的方法 +- [ ] 新增 `ITriggerCollector` 接口:包含 `collect(x: number, y: number, layer: IMapLayer)` 收集方法与 `attachRegistry(registry: ITriggerRegistry | null)` 注册表设置方法 diff --git a/packages-user/data-base/src/map/layerState.ts b/packages-user/data-base/src/map/layerState.ts index 9edb9ed..2e1e345 100644 --- a/packages-user/data-base/src/map/layerState.ts +++ b/packages-user/data-base/src/map/layerState.ts @@ -31,8 +31,8 @@ export class LayerState /** 图层钩子映射 */ private layerHookMap: Map = new Map(); - /** 楼层是否处于激活状态 */ active: boolean = false; + eventLayer: IMapLayer | null = null; /** 楼层级脏标记 */ private dirty: boolean = false; @@ -130,6 +130,17 @@ export class LayerState this.active = active; } + setEventLayer(layer: IMapLayer | null): void { + if (!layer) { + this.eventLayer = null; + } else { + if (!this.layerList.has(layer)) { + return; + } + this.eventLayer = layer; + } + } + isDirty(): boolean { return this.dirty; } diff --git a/packages-user/data-base/src/map/types.ts b/packages-user/data-base/src/map/types.ts index 49e6da5..8e7d9b8 100644 --- a/packages-user/data-base/src/map/types.ts +++ b/packages-user/data-base/src/map/types.ts @@ -231,6 +231,8 @@ export interface ILayerState extends IHookable { readonly width: number; /** 此楼层的地图高度 */ readonly height: number; + /** 当前楼层的默认事件层 */ + readonly eventLayer: IMapLayer | null; /** * 添加图层,使用楼层预设的宽高 @@ -293,6 +295,12 @@ export interface ILayerState extends IHookable { */ setActiveStatus(active: boolean): void; + /** + * 设置本楼层的事件层图层 + * @param layer 图层 + */ + setEventLayer(layer: IMapLayer | null): void; + /** * 楼层是否被修改过(相对于参考基准) */ diff --git a/packages-user/data-system/src/index.ts b/packages-user/data-system/src/index.ts index 7fd3ec0..25a6dfe 100644 --- a/packages-user/data-system/src/index.ts +++ b/packages-user/data-system/src/index.ts @@ -1 +1,2 @@ export * from './combat'; +export * from './trigger'; diff --git a/packages-user/data-system/src/trigger/collection.ts b/packages-user/data-system/src/trigger/collection.ts new file mode 100644 index 0000000..e76f69a --- /dev/null +++ b/packages-user/data-system/src/trigger/collection.ts @@ -0,0 +1,57 @@ +import { ITrigger, ITriggerCollection, ITriggerHandler } from './types'; + +export class TriggerCollection implements ITriggerCollection { + /** 当前集合内部维护的触发器列表 */ + private readonly triggerList: ITrigger[]; + + constructor(triggers: Iterable) { + this.triggerList = Array.from(triggers); + } + + count(): number { + return this.triggerList.length; + } + + async trigger( + handler: ITriggerHandler + ): Promise { + for (const trigger of this.triggerList) { + await trigger.trigger(handler); + } + } + + async *triggerIter( + handler: ITriggerHandler + ): AsyncGenerator | null> { + let currentHandler = handler; + for (const trigger of this.triggerList) { + await trigger.trigger(currentHandler); + const nextHandler = yield trigger; + if (nextHandler) { + currentHandler = nextHandler; + } else { + currentHandler = handler; + } + } + } + + iterate(): Iterable { + return this.triggerList.values(); + } + + push(trigger: ITrigger): void { + this.triggerList.push(trigger); + } + + unshift(trigger: ITrigger): void { + this.triggerList.unshift(trigger); + } + + concat(...others: ITriggerCollection[]): ITriggerCollection { + const merged = [...this.triggerList]; + for (const other of others) { + merged.push(...other.iterate()); + } + return new TriggerCollection(merged); + } +} diff --git a/packages-user/data-system/src/trigger/index.ts b/packages-user/data-system/src/trigger/index.ts new file mode 100644 index 0000000..02077b8 --- /dev/null +++ b/packages-user/data-system/src/trigger/index.ts @@ -0,0 +1,3 @@ +export * from './types'; +export * from './collection'; +export * from './registry'; diff --git a/packages-user/data-system/src/trigger/registry.ts b/packages-user/data-system/src/trigger/registry.ts new file mode 100644 index 0000000..6b2a86a --- /dev/null +++ b/packages-user/data-system/src/trigger/registry.ts @@ -0,0 +1,49 @@ +import { logger } from '@motajs/common'; +import { + ITrigger, + ITriggerRegistry, + TriggerFactory, + TriggerStringFactory +} from './types'; + +export class TriggerRegistry implements ITriggerRegistry { + /** 数字类型到触发器工厂的映射 */ + private readonly typeMap: Map = new Map(); + + /** 字符串 id 到触发器工厂的映射 */ + private readonly stringMap: Map = new Map(); + + register(type: number, factory: TriggerFactory): void { + if (this.typeMap.has(type)) { + logger.warn(132, 'type', type.toString()); + } + this.typeMap.set(type, factory); + } + + get(type: number): TriggerFactory | null { + return this.typeMap.get(type) ?? null; + } + + create(num: number): ITrigger | null { + const factory = this.get(num); + if (!factory) return null; + return factory(num); + } + + registerString(id: string, factory: TriggerStringFactory): void { + if (this.stringMap.has(id)) { + logger.warn(132, 'id', id); + } + this.stringMap.set(id, factory); + } + + getString(id: string): TriggerStringFactory | null { + return this.stringMap.get(id) ?? null; + } + + createByString(id: string): ITrigger | null { + const factory = this.getString(id); + if (!factory) return null; + return factory(); + } +} diff --git a/packages-user/data-system/src/trigger/types.ts b/packages-user/data-system/src/trigger/types.ts new file mode 100644 index 0000000..2e75673 --- /dev/null +++ b/packages-user/data-system/src/trigger/types.ts @@ -0,0 +1,139 @@ +import { ITileLocator } from '@motajs/common'; +import { ILayerState, IMapLayer, IStateBase } from '@user/data-base'; + +export interface ITriggerHandler { + /** 当前全局状态对象 */ + readonly state: IStateBase; + /** 当前楼层状态对象 */ + readonly layer?: ILayerState; + /** 当前参与触发的图层对象 */ + readonly mapLayer?: IMapLayer; + /** 当前触发点定位符 */ + readonly locator?: ITileLocator; +} + +export type TriggerFactory = (type: number) => ITrigger; + +export type TriggerStringFactory = () => ITrigger; + +export interface ITrigger { + /** 触发器类型标识 */ + readonly type: number; + /** 触发器优先级 */ + readonly priority: number; + + /** + * 使用给定上下文触发当前触发器 + * @param handler 触发上下文对象 + */ + trigger( + handler: ITriggerHandler + ): Promise; + + /** + * 将当前触发器包装为单元素触发器集合 + */ + collection(): ITriggerCollection; +} + +export interface ITriggerRegistry { + /** + * 注册一个按类型创建的触发器工厂 + * @param type 触发器类型 + * @param factory 触发器工厂函数 + */ + register(type: number, factory: TriggerFactory): void; + + /** + * 获取指定类型的触发器工厂 + * @param type 触发器类型 + */ + get(type: number): TriggerFactory | null; + + /** + * 根据触发器类型创建一个触发器实例,如果对应工厂不存在则返回 `null` + * @param num 触发器类型 + */ + create(num: number): ITrigger | null; + + /** + * 注册一个按字符串 id 查询的触发器工厂 + * @param id 触发器字符串 id + * @param factory 触发器工厂函数 + */ + registerString(id: string, factory: TriggerStringFactory): void; + + /** + * 获取指定字符串 id 对应的触发器工厂 + * @param id 触发器字符串 id + */ + getString(id: string): TriggerStringFactory | null; + + /** + * 根据字符串 id 创建一个触发器实例,如果对应工厂不存在则返回 `null` + * @param id 触发器字符串 id + */ + createByString(id: string): ITrigger | null; +} + +export interface ITriggerCollection { + /** + * 当前集合中的触发器数量 + */ + count(): number; + + /** + * 顺序触发当前集合中的所有触发器 + * @param handler 初始触发上下文对象 + */ + trigger( + handler: ITriggerHandler + ): Promise; + + /** + * 逐个触发当前集合中的触发器,并允许为下一次推进提供新上下文 + * @param handler 初始触发上下文对象 + */ + triggerIter( + handler: ITriggerHandler + ): AsyncGenerator | null>; + + /** + * 迭代当前集合中的所有触发器 + */ + iterate(): Iterable; + + /** + * 向集合末尾追加一个触发器 + * @param trigger 要追加的触发器 + */ + push(trigger: ITrigger): void; + + /** + * 向集合头部插入一个触发器 + * @param trigger 要插入的触发器 + */ + unshift(trigger: ITrigger): void; + + /** + * 将当前集合与其他集合顺序拼接为一个新集合 + * @param others 要拼接的其他集合 + */ + concat(...others: ITriggerCollection[]): ITriggerCollection; +} + +export interface ITriggerCollector { + /** + * 收集指定图层中某一点的所有触发器 + * @param x 横坐标 + * @param y 纵坐标 + * @param layer 目标图层 + */ + collect(x: number, y: number, layer: IMapLayer): ITriggerCollection; + + /** + * 绑定或清除当前 collector 使用的注册表 + * @param registry 触发器注册表 + */ + attachRegistry(registry: ITriggerRegistry | null): void; +} diff --git a/packages/common/src/logger.json b/packages/common/src/logger.json index 571c3b9..8fde405 100644 --- a/packages/common/src/logger.json +++ b/packages/common/src/logger.json @@ -188,6 +188,8 @@ "128": "Position $1,$2 is out of map bounds, operation cancelled.", "129": "Position $1,$2 is not empty, existing block will be overwritten.", "130": "The given tile is not managed by this dynamic layer.", + "131": "Event layer to set is not belong to current LayerState.", + "132": "Trigger registry entry of $1 '$2' already exists, new factory will override old factory.", "1001": "Item-detail extension needs 'floor-binder' and 'floor-damage' extension as dependency." } } diff --git a/prompt.md b/prompt.md index 5dd82ae..3137c38 100644 --- a/prompt.md +++ b/prompt.md @@ -21,6 +21,7 @@ 3. **发现接口问题时提问**:若认为类型标注中的接口设计有问题,或在实现中发现缺少某些接口,应向我提问是否添加,经我同意后方可添加。 4. **接口设计兼顾合理性与便捷性**:设计接口时不仅要考虑合理性,还要考虑使用便捷性。罕见场景应当被支持,但不应与常见场景共用同一接口——这只会增加常见场景的使用难度。 5. **避免多余的非空判断与类型守卫**:若某个类型已满足目标的类型约束,不应再对其添加任何判断或过滤操作。典型例子:`Promise.all` 对数组元素类型没有任何限制,传入 `(Promise | void)[]` 完全合法,无需多此一举地写成 `Promise.all(arr.filter(v => !!v))`。 +6. **关于整个仓库的类型检查**:一般情况下**不需要**跑全仓库的类型检查,每个需求都是独立的,不会影响外部内容。只有在进行重构的时候才有此需求。 **时刻谨记上述要求,避免一个需求反复修改仍无法满足预期。**