diff --git a/dev.md b/dev.md index ac11cd8..25f8975 100644 --- a/dev.md +++ b/dev.md @@ -33,6 +33,13 @@ | `pnpm type` | 对仓库执行类型检查 | | `pnpm check:circular` | 对仓库执行循环引用检查 | +## 术语统一 + +- 方法:一般指挂载到接口 `interface` 或类 `class` 上的函数。 +- 函数:一般指在文件顶层定义的函数,有时也会指方法,需要根据语境判断。 +- 接口:有时指 `interface`,有时也会指方法、成员等内容,需要根据语境判断。 +- 成员/属性:一般指接口 `interface`、类 `class`、对象 `object` 上的字段。 + ## 开发原则 ### 模块原则 @@ -97,11 +104,29 @@ - **数据端**:可在 `node` 环境中单独运行,可直接用于录像验证,不负责任何渲染逻辑。 - **渲染端**:仅负责向数据端发送消息,不负责任何逻辑运算。 -| 包 | 层级 | 说明 | -| ---------------------- | ------------ | ------------------------------------ | -| `@user/data-base` | 数据端系统层 | 负责数据端核心系统 | -| `@user/data-state` | 数据端实现层 | 依赖系统层实现完整的游戏实例 | -| `@user/client-base` | 渲染端系统层 | 负责渲染端核心系统 | -| `@user/client-modules` | 渲染端实现层 | 依赖系统层实现客户端的渲染与用户交互 | - 数据端允许调用渲染端代码,但必须使用全局接口 `Mota.r(() => {})` 包裹。除非必要,否则不建议在数据端调用渲染端代码。 + +### 渲染端 + +渲染端目前已基本制作完成,分为两层: + +| 包 | 层级 | 说明 | +| ---------------------- | ------ | ------------------------------------ | +| `@user/client-base` | 系统层 | 负责渲染端核心系统 | +| `@user/client-modules` | 实现层 | 依赖系统层实现客户端的渲染与用户交互 | + +### 数据端 + +数据端目前正在从旧引擎进行彻底性重构,分为三层: + +**Layer 0 — 公共层**:包含公共接口、工具函数等内容,不依赖任何外部游戏逻辑,可被任意高层直接引用。内容较少,与 Layer 1 共同放在 `@user/data-base` 中,不单独开包。 + +**Layer 1 — 数据层**:包含所有会影响游戏存档与流程的数据内容,如地图、怪物、玩家属性等。本层通过统一接口 `IStateBase` 对外暴露数据访问能力,各类数据模块均以此接口为核心组织。 + +**Layer 2 — 执行层**:直接引用 Layer 1,负责产生影响游戏进程的动作,如玩家控制、战斗计算等。本层内容不会进入存档,仅通过修改 Layer 1 的数据来影响游戏状态,并通过统一接口 `ICoreState` 对外暴露执行能力。 + +| 包 | 层级 | 说明 | +| ------------------- | ----------------- | ------------------------------------------------------------------------------- | +| `@user/data-base` | Layer 0 / Layer 1 | 公共层与数据层,定义 `IStateBase` 及各类游戏数据(地图、怪物、玩家属性等) | +| `@user/data-state` | — | 数据端的顶层模块,指导 Layer 2 的执行行为,不直接参与执行 | +| `@user/data-system` | Layer 2 | 执行层,定义 `ICoreState`,依赖数据层实现玩家控制、战斗计算等影响游戏进程的动作 | diff --git a/packages-user/data-base/src/common/index.ts b/packages-user/data-base/src/common/index.ts index c528977..f989da9 100644 --- a/packages-user/data-base/src/common/index.ts +++ b/packages-user/data-base/src/common/index.ts @@ -1,5 +1,6 @@ export * from './face'; export * from './faceManager'; +export * from './indexer'; export * from './mover'; export * from './types'; export * from './utils'; diff --git a/packages-user/data-base/src/index.ts b/packages-user/data-base/src/index.ts index f71b3b5..0be7276 100644 --- a/packages-user/data-base/src/index.ts +++ b/packages-user/data-base/src/index.ts @@ -1,4 +1,3 @@ -export * from './combat'; export * from './common'; export * from './enemy'; export * from './flag'; diff --git a/packages-user/data-state/package.json b/packages-user/data-state/package.json index 0ff5c79..eca262b 100644 --- a/packages-user/data-state/package.json +++ b/packages-user/data-state/package.json @@ -4,6 +4,7 @@ "@motajs/types": "workspace:*", "@motajs/common": "workspace:*", "@user/data-base": "workspace:*", + "@user/data-system": "workspace:*", "@user/data-utils": "workspace:*" } } diff --git a/packages-user/data-state/src/enemy/aura.ts b/packages-user/data-state/src/enemy/aura.ts index 1220ba0..eae1149 100644 --- a/packages-user/data-state/src/enemy/aura.ts +++ b/packages-user/data-state/src/enemy/aura.ts @@ -14,10 +14,9 @@ import { IEnemyContext, IEnemySpecialModifier, IEnemyView, - IReadonlyEnemyHandler, - IReadonlyEnemy, - ISpecial -} from '@user/data-base'; + IReadonlyEnemyHandler +} from '@user/data-system'; +import { IReadonlyEnemy, ISpecial } from '@user/data-base'; import { IHaloValue } from './special'; import { IEnemyAttr } from './types'; import { IHeroAttr } from '../hero'; diff --git a/packages-user/data-state/src/enemy/calculator.ts b/packages-user/data-state/src/enemy/calculator.ts index 4831ba6..3d67f08 100644 --- a/packages-user/data-state/src/enemy/calculator.ts +++ b/packages-user/data-state/src/enemy/calculator.ts @@ -3,7 +3,7 @@ import { IDamageCalculator, IEnemyDamageInfo, IReadonlyEnemyHandler -} from '@user/data-base'; +} from '@user/data-system'; import { IEnemyAttr } from './types'; import { IVampireValue } from './special'; import { IHeroAttr } from '../hero'; @@ -90,7 +90,8 @@ export class MainDamageCalculator implements IDamageCalculator< const extraInfo = this.calculate({ enemy: guard.getComputedEnemy(), locator, - hero + hero, + data: handler.data }); turn += extraInfo.turn; damage += extraInfo.damage; diff --git a/packages-user/data-state/src/enemy/final.ts b/packages-user/data-state/src/enemy/final.ts index 0c722e7..dbd3e01 100644 --- a/packages-user/data-state/src/enemy/final.ts +++ b/packages-user/data-state/src/enemy/final.ts @@ -1,4 +1,4 @@ -import { IEnemyFinalEffect, IEnemyHandler } from '@user/data-base'; +import { IEnemyFinalEffect, IEnemyHandler } from '@user/data-system'; import { IEnemyAttr } from './types'; import { IHeroAttr } from '../hero'; diff --git a/packages-user/data-state/src/enemy/mapDamage.ts b/packages-user/data-state/src/enemy/mapDamage.ts index bea8256..6bff8e7 100644 --- a/packages-user/data-state/src/enemy/mapDamage.ts +++ b/packages-user/data-state/src/enemy/mapDamage.ts @@ -16,11 +16,13 @@ import { IMapDamageInfoExtra, IMapDamageReducer, IReadonlyEnemyHandler, + IMapDamageView +} from '@user/data-system'; +import { + IFaceHandler, ISpecial, - IMapDamageView, IReadonlyHeroAttribute, IReadonlyEnemy, - IFaceHandler, InternalFaceGroup } from '@user/data-base'; import { IZoneValue } from './special'; diff --git a/packages-user/data-state/src/enemy/types.ts b/packages-user/data-state/src/enemy/types.ts index e008ebe..59a2d32 100644 --- a/packages-user/data-state/src/enemy/types.ts +++ b/packages-user/data-state/src/enemy/types.ts @@ -1,4 +1,4 @@ -import { IEnemyView } from '@user/data-base'; +import { IEnemyView } from '@user/data-system'; export interface IEnemyAttr { /** 怪物生命值 */ diff --git a/packages-user/data-system/package.json b/packages-user/data-system/package.json new file mode 100644 index 0000000..be999dd --- /dev/null +++ b/packages-user/data-system/package.json @@ -0,0 +1,7 @@ +{ + "name": "@user/data-system", + "dependencies": { + "@motajs/common": "workspace:*", + "@user/data-base": "workspace:*" + } +} diff --git a/packages-user/data-base/src/combat/context.ts b/packages-user/data-system/src/combat/context.ts similarity index 99% rename from packages-user/data-base/src/combat/context.ts rename to packages-user/data-system/src/combat/context.ts index 2a6287f..ca7e8db 100644 --- a/packages-user/data-base/src/combat/context.ts +++ b/packages-user/data-system/src/combat/context.ts @@ -14,11 +14,16 @@ import { IMapDamage, IReadonlyEnemyHandler } from './types'; -import { IReadonlyHeroAttribute } from '../hero'; -import { IEnemy, IReadonlyEnemy, ISpecial } from '../enemy'; +import { + IReadonlyHeroAttribute, + IEnemy, + IReadonlyEnemy, + ISpecial, + IStateBase, + ILocationIndexer, + MapLocIndexer +} from '@user/data-base'; import { EnemyView } from './enemy'; -import { ILocationIndexer, MapLocIndexer } from '../common/indexer'; -import { IStateBase } from '../types'; export class EnemyContext implements IEnemyContext< TEnemy, diff --git a/packages-user/data-base/src/combat/damage.ts b/packages-user/data-system/src/combat/damage.ts similarity index 98% rename from packages-user/data-base/src/combat/damage.ts rename to packages-user/data-system/src/combat/damage.ts index ce70711..2b83a7e 100644 --- a/packages-user/data-base/src/combat/damage.ts +++ b/packages-user/data-system/src/combat/damage.ts @@ -11,9 +11,12 @@ import { IReadonlyEnemyHandler, IEnemyView } from './types'; -import { IHeroAttribute, IReadonlyHeroAttribute } from '../hero'; -import { IReadonlyEnemy } from '../enemy'; -import { IStateBase } from '../types'; +import { + IHeroAttribute, + IReadonlyHeroAttribute, + IReadonlyEnemy, + IStateBase +} from '@user/data-base'; interface ICriticalSearchResult { /** 此临界点的属性值 */ diff --git a/packages-user/data-base/src/combat/enemy.ts b/packages-user/data-system/src/combat/enemy.ts similarity index 94% rename from packages-user/data-base/src/combat/enemy.ts rename to packages-user/data-system/src/combat/enemy.ts index 94a8a60..b28cc53 100644 --- a/packages-user/data-base/src/combat/enemy.ts +++ b/packages-user/data-system/src/combat/enemy.ts @@ -1,4 +1,4 @@ -import { IEnemy, IReadonlyEnemy } from '../enemy'; +import { IEnemy, IReadonlyEnemy } from '@user/data-base'; import { IEnemyView, IEnemyContext } from './types'; export class EnemyView implements IEnemyView { diff --git a/packages-user/data-base/src/combat/index.ts b/packages-user/data-system/src/combat/index.ts similarity index 100% rename from packages-user/data-base/src/combat/index.ts rename to packages-user/data-system/src/combat/index.ts diff --git a/packages-user/data-base/src/combat/mapDamage.ts b/packages-user/data-system/src/combat/mapDamage.ts similarity index 99% rename from packages-user/data-base/src/combat/mapDamage.ts rename to packages-user/data-system/src/combat/mapDamage.ts index 2fd36e3..200fa3b 100644 --- a/packages-user/data-base/src/combat/mapDamage.ts +++ b/packages-user/data-system/src/combat/mapDamage.ts @@ -9,8 +9,7 @@ import { IMapDamageReducer, IMapDamageView } from './types'; -import { ILocationHelper } from '../common/indexer'; -import { IStateBase } from '../types'; +import { ILocationHelper, IStateBase } from '@user/data-base'; interface IPointInfo { /** 该点所有的地图伤害 */ diff --git a/packages-user/data-base/src/combat/types.ts b/packages-user/data-system/src/combat/types.ts similarity index 98% rename from packages-user/data-base/src/combat/types.ts rename to packages-user/data-system/src/combat/types.ts index 28d84cc..cc6ab59 100644 --- a/packages-user/data-base/src/combat/types.ts +++ b/packages-user/data-system/src/combat/types.ts @@ -1,8 +1,13 @@ import { ITileLocator, IRange } from '@motajs/common'; -import { IEnemy, IReadonlyEnemy, ISpecial } from '../enemy'; -import { IReadonlyHeroAttribute, IHeroAttribute } from '../hero'; -import { ILocationHelper } from '../common/indexer'; -import { IStateBase } from '../types'; +import { + IEnemy, + IReadonlyEnemy, + ISpecial, + IReadonlyHeroAttribute, + IHeroAttribute, + IStateBase, + ILocationHelper +} from '@user/data-base'; //#region 辅助接口 diff --git a/packages-user/data-system/src/index.ts b/packages-user/data-system/src/index.ts new file mode 100644 index 0000000..7fd3ec0 --- /dev/null +++ b/packages-user/data-system/src/index.ts @@ -0,0 +1 @@ +export * from './combat'; diff --git a/packages-user/data-utils/src/utils.ts b/packages-user/data-utils/src/utils.ts index 8102333..1e1df0d 100644 --- a/packages-user/data-utils/src/utils.ts +++ b/packages-user/data-utils/src/utils.ts @@ -1,22 +1,3 @@ -/** - * 滑动数组 - * @param arr - * @param delta - */ -export function slide(arr: T[], delta: number): T[] { - if (delta === 0) return arr; - delta %= arr.length; - if (delta > 0) { - arr.unshift(...arr.splice(arr.length - delta, delta)); - return arr; - } - if (delta < 0) { - arr.push(...arr.splice(0, -delta)); - return arr; - } - return arr; -} - const backDirMap: Record = { up: 'down', down: 'up', @@ -38,23 +19,8 @@ export function has(v: T): v is NonNullable { return v !== null && v !== void 0; } -export function maxGameScale(n: number = 0) { - const index = core.domStyle.availableScale.indexOf(core.domStyle.scale); - core.control.setDisplayScale( - core.domStyle.availableScale.length - 1 - index - n - ); - if (!core.isPlaying() && core.flags.enableHDCanvas) { - // @ts-ignore - core.domStyle.ratio = Math.max( - window.devicePixelRatio || 1, - core.domStyle.scale - ); - core.resize(); - } -} - export function ensureArray(arr: T): T extends any[] ? T : T[] { - // @ts-ignore + // @ts-expect-error 需要弃用 return arr instanceof Array ? arr : [arr]; } @@ -70,23 +36,6 @@ export function manhattan(x1: number, y1: number, x2: number, y2: number) { return Math.abs(x1 - x2) + Math.abs(y1 - y2); } -/** - * 检查一个点是否在当前超大地图 v2 优化范围内 - */ -export function checkV2(x?: number, y?: number) { - return ( - has(x) && - has(y) && - !( - core.bigmap.v2 && - (x < core.bigmap.posX - core.bigmap.extend || - x > core.bigmap.posX + core._WIDTH_ + core.bigmap.extend || - y < core.bigmap.posY - core.bigmap.extend || - y > core.bigmap.posY + core._HEIGHT_ + core.bigmap.extend) - ) - ); -} - export function formatDamage(damage: number): DamageString { let dam = ''; let color = ''; @@ -105,64 +54,6 @@ export function formatDamage(damage: number): DamageString { return { damage: dam, color: color as Color }; } -/** - * 判断一个数组的数值是否全部相等 - * @param arr 要判断的数组 - */ -export function equal(arr: number[]): boolean; -/** - * 判断一个数组的元素的某个属性的数值是否全部相等 - * @param arr 要判断的数组 - * @param key 要判断的属性名 - */ -export function equal(arr: T[], key: keyof T): boolean; -export function equal(arr: any, key?: any) { - if (has(key)) { - for (let i = 1; i < arr.length; i++) { - if (arr[i][key] !== arr[0][key]) return false; - } - return true; - } else { - for (let i = 1; i < arr.length; i++) { - if (arr[i] !== arr[0]) return false; - } - return true; - } -} - -/** - * 获得一个数组的数值的最大值和最小值 - * @param arr 要获得的数组 - */ -export function boundary(arr: number[]): [number, number]; -/** - * 获得一个数组的元素的某个属性的数值的最大值和最小值 - * @param arr 要获得的数组 - * @param key 要获得的属性名 - */ -export function boundary(arr: T[], key: keyof T): [number, number]; -export function boundary(arr: any, key?: any) { - if (has(key)) { - let min = arr[0][key]; - let max = arr[0][key]; - for (let i = 1; i < arr.length; i++) { - const ele = arr[i][key]; - if (ele < min) min = ele; - if (ele > max) max = ele; - } - return [min, max]; - } else { - let min = arr[0]; - let max = arr[0]; - for (let i = 1; i < arr.length; i++) { - const ele = arr[i]; - if (ele < min) min = ele; - if (ele > max) max = ele; - } - return [min, max]; - } -} - /** * 获取两个坐标的相对方向 * @param from 初始坐标 diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1bb304c..16fe420 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -315,10 +315,22 @@ importers: '@user/data-base': specifier: workspace:* version: link:../data-base + '@user/data-system': + specifier: workspace:* + version: link:../data-system '@user/data-utils': specifier: workspace:* version: link:../data-utils + packages-user/data-system: + dependencies: + '@motajs/common': + specifier: workspace:* + version: link:../../packages/common + '@user/data-base': + specifier: workspace:* + version: link:../data-base + packages-user/data-utils: dependencies: '@user/data-base': @@ -409,8 +421,6 @@ importers: specifier: workspace:* version: link:../data-utils - packages-user/types: {} - packages/animate: {} packages/audio: @@ -447,12 +457,6 @@ importers: specifier: workspace:* version: link:../common - packages/legacy-data: - dependencies: - '@motajs/common': - specifier: workspace:* - version: link:../common - packages/legacy-system: dependencies: '@motajs/system': diff --git a/prompt.md b/prompt.md index 240cbfe..5dd82ae 100644 --- a/prompt.md +++ b/prompt.md @@ -38,7 +38,23 @@ ```md # 需求综述 -描述清楚需求的内容与目的。 +描述清楚需求的内容、动机与目的。 + +# 接口设计与预期 + +这是相当重要的一章。需要按接口逐一列出其方法与成员,分析每个成员和方法的预期使用频率(高 / 中 / 低)并说明判断依据;对于中频和高频成员,还需列出至少一个典型使用场景。 + +**命名长度原则**:频率越高,成员名应越短。高频成员以一个单词为宜,最多不超过两个单词;中频成员不超过三个单词;低频成员可以稍长,但不宜过长。 + +**频率的定义**:此处频率指**用户编写此调用的可能性或频率**,而非运行时的调用频率。例如某成员每秒被调用千次,但整个游戏中只在一处出现过,仍属低频。 + +示例如下: + +## IObjectMover + +- `IObjectMover.forward()`:预期频率**高频**。向前移动一格是地图行走、动画演出等场景的核心需求,在逻辑与演出中都会频繁出现,故为高频。典型使用场景:演出中玩家或 NPC 沿某方向连续移动。 +- `IObjectMover.speed()`:预期频率**中频**。移动中修改移速有一定使用场景,但远不及 `forward`、`step` 等移动接口的频率,通常只在特殊演出或逻辑中出现,故为中频。典型使用场景:NPC 逃离怪物时先定在原地,随后逐渐加速逃跑。 +- `IObjectMover.stepFace()`:预期频率**低频**。移动方向与朝向不同的常见场景(后退)已由 `backward` 覆盖,只有极特殊情况才需要此接口(如角色朝向固定但沿垂直方向平移),相当罕见,故为低频。 # 实现思路 @@ -52,10 +68,6 @@ ... -# 接口预期 - -这里列出每个接口,然后分析它们的预期使用频率(高中低),对于中频率和高频率,列出至少一个可能的使用场景。需要注意,使用频率越高,其接口名长度理应越短,对于高频接口,应该尽量不超过两个单词,以一个单词为宜;对于中频接口,应该尽量不超过三个单词;低频接口长度可以长一些,但不宜过长。 - # 涉及文件 ## 需要引用的文件