From 23a8c0bf3ae02b00b284bccc519a1b3cd8bce960 Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Sun, 9 Mar 2025 19:15:22 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=BF=AE=E5=A4=8D=E6=89=80?= =?UTF-8?q?=E6=9C=89=E7=9A=84=E5=BE=AA=E7=8E=AF=E5=BC=95=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/render/legacy}/fallback.ts | 0 .../src/render/legacy}/gameCanvas.ts | 0 .../src/render/legacy}/halo.ts | 0 .../src/render/legacy}/pop.ts | 0 .../src/render/legacy}/portal.ts | 0 .../client-modules/src/render/ui/main.tsx | 12 +- .../client-modules/src/render/ui/toolbar.tsx | 7 +- packages-user/data-state/src/enemy/damage.ts | 5 +- .../data-state/src/mechanism/index.ts | 1 + .../data-state/src/mechanism/misc.ts | 125 ------ .../data-state/src/mechanism/skillTree.ts | 127 +++++- packages-user/data-state/src/state/hero.ts | 2 +- .../src/boss/palaceBoss.ts | 2 +- .../src/boss/towerBoss.ts | 4 +- .../legacy-plugin-client/src/chase/chase1.ts | 4 +- .../legacy-plugin-client/src/fx/index.ts | 4 - .../legacy-plugin-client/src/index.ts | 3 - packages-user/legacy-plugin-data/src/index.ts | 1 - packages-user/legacy-plugin-data/src/skill.ts | 2 +- packages/legacy-common/src/index.ts | 1 + packages/legacy-common/src/utils.ts | 48 ++ packages/legacy-ui/src/components/box.vue | 17 +- .../legacy-ui/src/components/boxAnimate.vue | 5 +- packages/legacy-ui/src/components/colomn.vue | 12 +- .../legacy-ui/src/components/enemyOne.vue | 4 +- packages/legacy-ui/src/components/minimap.vue | 5 +- packages/legacy-ui/src/components/scroll.vue | 8 +- packages/legacy-ui/src/controller.ts | 8 +- packages/legacy-ui/src/danmaku.ts | 4 +- packages/legacy-ui/src/fx/webgl.ts | 11 +- packages/legacy-ui/src/index.ts | 3 +- packages/legacy-ui/src/interface.ts | 99 +++++ packages/legacy-ui/src/mark.ts | 164 ------- .../legacy-ui/src/panel/enemyCritical.vue | 12 +- packages/legacy-ui/src/panel/enemyTarget.vue | 85 ---- packages/legacy-ui/src/preset/danmaku.ts | 2 +- packages/legacy-ui/src/preset/fixed.ts | 4 +- packages/legacy-ui/src/preset/hotkey.ts | 18 +- packages/legacy-ui/src/preset/index.ts | 2 + packages/legacy-ui/src/preset/settingIns.ts | 3 + packages/legacy-ui/src/preset/settings.tsx | 2 +- packages/legacy-ui/src/preset/ui.ts | 52 +-- packages/legacy-ui/src/preset/uiIns.ts | 38 ++ packages/legacy-ui/src/setting.ts | 13 +- packages/legacy-ui/src/tools/achievement.ts | 120 ----- packages/legacy-ui/src/tools/book.tsx | 6 +- packages/legacy-ui/src/tools/completion.ts | 113 ----- packages/legacy-ui/src/tools/equipbox.tsx | 5 +- packages/legacy-ui/src/tools/fly.ts | 8 +- packages/legacy-ui/src/tools/index.ts | 7 +- packages/legacy-ui/src/ui/achievement.vue | 340 -------------- packages/legacy-ui/src/ui/book.vue | 18 +- packages/legacy-ui/src/ui/bookDetail.vue | 8 +- packages/legacy-ui/src/ui/chapter.vue | 17 +- .../legacy-ui/src/ui/completeAchievement.vue | 113 ----- packages/legacy-ui/src/ui/danmaku.vue | 7 +- packages/legacy-ui/src/ui/danmakuEditor.vue | 14 +- packages/legacy-ui/src/ui/desc.vue | 10 +- packages/legacy-ui/src/ui/equipbox.vue | 32 +- packages/legacy-ui/src/ui/fixed.vue | 2 - packages/legacy-ui/src/ui/fixedDetail.vue | 11 +- packages/legacy-ui/src/ui/fly.vue | 19 +- packages/legacy-ui/src/ui/hotkey.vue | 13 +- packages/legacy-ui/src/ui/index.ts | 2 +- packages/legacy-ui/src/ui/load.vue | 12 +- packages/legacy-ui/src/ui/markedEnemy.vue | 157 ------- packages/legacy-ui/src/ui/settings.vue | 13 +- packages/legacy-ui/src/ui/shop.vue | 14 +- packages/legacy-ui/src/ui/skill.vue | 12 +- packages/legacy-ui/src/ui/skillTree.vue | 17 +- packages/legacy-ui/src/ui/start.vue | 15 +- packages/legacy-ui/src/ui/toolbox.vue | 27 +- packages/legacy-ui/src/uiUtils.ts | 47 ++ packages/legacy-ui/src/use.ts | 21 +- packages/legacy-ui/src/utils.ts | 137 +----- packages/render-elements/src/floor.ts | 415 ------------------ packages/render-elements/src/index.ts | 1 - packages/render-elements/src/layer.ts | 407 ++++++++++++++++- packages/render-elements/src/viewport.ts | 2 +- packages/system-action/src/hotkey.ts | 2 +- packages/system-action/src/keyboard.ts | 8 +- vite.config.ts | 11 +- 82 files changed, 1015 insertions(+), 2087 deletions(-) rename packages-user/{legacy-plugin-client/src => client-modules/src/render/legacy}/fallback.ts (100%) rename packages-user/{legacy-plugin-client/src/fx => client-modules/src/render/legacy}/gameCanvas.ts (100%) rename packages-user/{legacy-plugin-client/src/fx => client-modules/src/render/legacy}/halo.ts (100%) rename packages-user/{legacy-plugin-client/src/fx => client-modules/src/render/legacy}/pop.ts (100%) rename packages-user/{legacy-plugin-client/src/fx => client-modules/src/render/legacy}/portal.ts (100%) create mode 100644 packages/legacy-common/src/utils.ts create mode 100644 packages/legacy-ui/src/interface.ts delete mode 100644 packages/legacy-ui/src/mark.ts delete mode 100644 packages/legacy-ui/src/panel/enemyTarget.vue create mode 100644 packages/legacy-ui/src/preset/settingIns.ts create mode 100644 packages/legacy-ui/src/preset/uiIns.ts delete mode 100644 packages/legacy-ui/src/tools/achievement.ts delete mode 100644 packages/legacy-ui/src/tools/completion.ts delete mode 100644 packages/legacy-ui/src/ui/achievement.vue delete mode 100644 packages/legacy-ui/src/ui/completeAchievement.vue delete mode 100644 packages/legacy-ui/src/ui/markedEnemy.vue create mode 100644 packages/legacy-ui/src/uiUtils.ts delete mode 100644 packages/render-elements/src/floor.ts diff --git a/packages-user/legacy-plugin-client/src/fallback.ts b/packages-user/client-modules/src/render/legacy/fallback.ts similarity index 100% rename from packages-user/legacy-plugin-client/src/fallback.ts rename to packages-user/client-modules/src/render/legacy/fallback.ts diff --git a/packages-user/legacy-plugin-client/src/fx/gameCanvas.ts b/packages-user/client-modules/src/render/legacy/gameCanvas.ts similarity index 100% rename from packages-user/legacy-plugin-client/src/fx/gameCanvas.ts rename to packages-user/client-modules/src/render/legacy/gameCanvas.ts diff --git a/packages-user/legacy-plugin-client/src/fx/halo.ts b/packages-user/client-modules/src/render/legacy/halo.ts similarity index 100% rename from packages-user/legacy-plugin-client/src/fx/halo.ts rename to packages-user/client-modules/src/render/legacy/halo.ts diff --git a/packages-user/legacy-plugin-client/src/fx/pop.ts b/packages-user/client-modules/src/render/legacy/pop.ts similarity index 100% rename from packages-user/legacy-plugin-client/src/fx/pop.ts rename to packages-user/client-modules/src/render/legacy/pop.ts diff --git a/packages-user/legacy-plugin-client/src/fx/portal.ts b/packages-user/client-modules/src/render/legacy/portal.ts similarity index 100% rename from packages-user/legacy-plugin-client/src/fx/portal.ts rename to packages-user/client-modules/src/render/legacy/portal.ts diff --git a/packages-user/client-modules/src/render/ui/main.tsx b/packages-user/client-modules/src/render/ui/main.tsx index 6864c55..737ef73 100644 --- a/packages-user/client-modules/src/render/ui/main.tsx +++ b/packages-user/client-modules/src/render/ui/main.tsx @@ -11,13 +11,6 @@ import { Font } from '@motajs/render'; import { WeatherController } from '../../weather'; -import { - FloorChange, - LayerGroupFilter, - LayerGroupHalo, - LayerGroupPortal, - PopText -} from '@user/legacy-plugin-client'; import { defineComponent, onMounted, reactive, ref } from 'vue'; import { Textbox, Tip } from '../components'; import { GameUI, UIController } from '@motajs/system-ui'; @@ -40,6 +33,11 @@ import { jumpIgnoreFloor } from '@user/legacy-plugin-data'; import { hook } from '@user/data-base'; import { FloorDamageExtends } from '../damage'; import { FloorItemDetail } from '../itemDetail'; +import { LayerGroupPortal } from '../legacy/portal'; +import { LayerGroupFilter } from '../legacy/gameCanvas'; +import { LayerGroupHalo } from '../legacy/halo'; +import { FloorChange } from '../legacy/fallback'; +import { PopText } from '../legacy/pop'; const MainScene = defineComponent(() => { const layerGroupExtends: ILayerGroupRenderExtends[] = [ diff --git a/packages-user/client-modules/src/render/ui/toolbar.tsx b/packages-user/client-modules/src/render/ui/toolbar.tsx index 43c4eaa..af3f3a6 100644 --- a/packages-user/client-modules/src/render/ui/toolbar.tsx +++ b/packages-user/client-modules/src/render/ui/toolbar.tsx @@ -13,17 +13,14 @@ import { StepForward, ViewMapIcon } from '../components/icons'; -import { - generateBinary, - getVitualKeyOnce, - openDanmakuPoster -} from '@motajs/legacy-ui'; +import { getVitualKeyOnce, openDanmakuPoster } from '@motajs/legacy-ui'; import { gameKey } from '@motajs/system-action'; import { generateKeyboardEvent } from '@motajs/system-action'; import { transitioned } from '../use'; import { linear } from 'mutate-animate'; import { KeyCode } from '@motajs/client-base'; import { Progress } from '../components/misc'; +import { generateBinary } from '@motajs/legacy-common'; interface ToolbarProps extends DefaultProps { loc?: ElementLocator; diff --git a/packages-user/data-state/src/enemy/damage.ts b/packages-user/data-state/src/enemy/damage.ts index 5f3d8e2..c6ab52a 100644 --- a/packages-user/data-state/src/enemy/damage.ts +++ b/packages-user/data-state/src/enemy/damage.ts @@ -2,7 +2,7 @@ import { getHeroStatusOf, getHeroStatusOn } from '../state/hero'; import { Range, ensureArray, has, manhattan } from '@user/data-utils'; import EventEmitter from 'eventemitter3'; import { hook } from '@user/data-base'; -import { HeroSkill, NightSpecial } from '../mechanism/misc'; +import { HeroSkill, NightSpecial } from '../mechanism'; import { EnemyInfo, DamageInfo, @@ -16,6 +16,7 @@ import { HaloType, IEnemyCollectionEvent } from '@motajs/types'; +import { isNil } from 'lodash-es'; // todo: 光环划分优先级,从而可以实现光环的多级运算 @@ -293,7 +294,7 @@ export class DamageEnemy implements IDamageEnemy { // 融化,融化不属于怪物光环,因此不能用provide和inject计算,需要在这里计算 const melt = flags[`melt_${floorId}`]; - if (has(melt) && has(this.x) && has(this.y)) { + if (!isNil(melt) && !isNil(this.x) && !isNil(this.y)) { for (const [loc, per] of Object.entries(melt)) { const [mx, my] = loc.split(',').map(v => parseInt(v)); if ( diff --git a/packages-user/data-state/src/mechanism/index.ts b/packages-user/data-state/src/mechanism/index.ts index 587b892..a9adaa7 100644 --- a/packages-user/data-state/src/mechanism/index.ts +++ b/packages-user/data-state/src/mechanism/index.ts @@ -1 +1,2 @@ export * from './misc'; +export * from './skillTree'; diff --git a/packages-user/data-state/src/mechanism/misc.ts b/packages-user/data-state/src/mechanism/misc.ts index ef2108b..7478189 100644 --- a/packages-user/data-state/src/mechanism/misc.ts +++ b/packages-user/data-state/src/mechanism/misc.ts @@ -48,131 +48,6 @@ export namespace NightSpecial { } } -export namespace HeroSkill { - export const enum Skill { - None, - /** 断灭之刃 */ - Blade, - /** 铸剑为盾 */ - Shield, - /** 跳跃 */ - Jump - } - - export const Blade = Skill.Blade; - export const Shield = Skill.Shield; - export const Jump = Skill.Jump; - - const skillNameMap = new Map([ - [Skill.Blade, '断灭之刃'], - [Skill.Shield, '铸剑为盾'], - [Skill.Jump, '跳跃'] - ]); - - const skillDesc = new Map string>([ - [ - Skill.Blade, - level => `攻击上升 ${level * 10}%,防御下降 ${level * 10}%` - ], - [ - Skill.Shield, - level => `防御上升 ${level * 10}%,攻击下降 ${level * 10}%` - ], - [Skill.Jump, () => `跳过前方障碍,或踢走面前的怪物`] - ]); - - interface SkillSave { - autoSkill: boolean; - learned: Skill[]; - } - - const learned = new Set(); - let autoSkill = true; - let enabled: Skill = Skill.None; - - export function getLevel(skill: Skill = getEnabled()) { - switch (skill) { - case Blade: - return getSkillLevel(2); - case Jump: - return learned.has(Jump) ? 1 : 0; - case Shield: - return getSkillLevel(10); - } - return 0; - } - - export function getSkillName(skill: Skill = getEnabled()) { - return skillNameMap.get(skill) ?? '未开启技能'; - } - - export function getSkillDesc( - skill: Skill = getEnabled(), - level: number = getLevel() - ) { - return skillDesc.get(skill)?.(level) ?? ''; - } - - export function setAutoSkill(auto: boolean) { - autoSkill = auto; - } - - export function getAutoSkill() { - return autoSkill; - } - - export function learnedSkill(skill: Skill) { - return learned.has(skill); - } - - export function learnSkill(skill: Skill) { - learned.add(skill); - } - - export function forgetSkill(skill: Skill) { - learned.delete(skill); - } - - export function clearSkill() { - learned.clear(); - } - - export function saveSkill(): SkillSave { - return { autoSkill, learned: [...learned] }; - } - - export function loadSkill(skills: SkillSave) { - learned.clear(); - for (const skill of skills.learned) { - learned.add(skill); - } - autoSkill = skills.autoSkill; - } - - export function getAll() { - return learned; - } - - export function toggleSkill(skill: Skill) { - if (!learned.has(skill)) return; - if (enabled !== skill) enabled = skill; - else enabled = Skill.None; - } - - export function enableSkill(skill: Skill) { - if (!learned.has(skill)) return; - enabled = skill; - } - - export function disableSkill() { - enabled = Skill.None; - } - - export function getEnabled() { - return enabled; - } -} - export namespace BluePalace { type DoorConvertInfo = [id: AllIds, x: number, y: number]; diff --git a/packages-user/data-state/src/mechanism/skillTree.ts b/packages-user/data-state/src/mechanism/skillTree.ts index e2cb043..39d7970 100644 --- a/packages-user/data-state/src/mechanism/skillTree.ts +++ b/packages-user/data-state/src/mechanism/skillTree.ts @@ -1,5 +1,3 @@ -import { HeroSkill } from './misc'; - let levels: number[] = []; export type Chapter = 'chapter1' | 'chapter2'; @@ -314,3 +312,128 @@ export function saveSkillTree() { export function loadSkillTree(data: number[]) { levels = data ?? []; } + +export namespace HeroSkill { + export const enum Skill { + None, + /** 断灭之刃 */ + Blade, + /** 铸剑为盾 */ + Shield, + /** 跳跃 */ + Jump + } + + export const Blade = Skill.Blade; + export const Shield = Skill.Shield; + export const Jump = Skill.Jump; + + const skillNameMap = new Map([ + [Skill.Blade, '断灭之刃'], + [Skill.Shield, '铸剑为盾'], + [Skill.Jump, '跳跃'] + ]); + + const skillDesc = new Map string>([ + [ + Skill.Blade, + level => `攻击上升 ${level * 10}%,防御下降 ${level * 10}%` + ], + [ + Skill.Shield, + level => `防御上升 ${level * 10}%,攻击下降 ${level * 10}%` + ], + [Skill.Jump, () => `跳过前方障碍,或踢走面前的怪物`] + ]); + + interface SkillSave { + autoSkill: boolean; + learned: Skill[]; + } + + const learned = new Set(); + let autoSkill = true; + let enabled: Skill = Skill.None; + + export function getLevel(skill: Skill = getEnabled()) { + switch (skill) { + case Blade: + return getSkillLevel(2); + case Jump: + return learned.has(Jump) ? 1 : 0; + case Shield: + return getSkillLevel(10); + } + return 0; + } + + export function getSkillName(skill: Skill = getEnabled()) { + return skillNameMap.get(skill) ?? '未开启技能'; + } + + export function getSkillDesc( + skill: Skill = getEnabled(), + level: number = getLevel() + ) { + return skillDesc.get(skill)?.(level) ?? ''; + } + + export function setAutoSkill(auto: boolean) { + autoSkill = auto; + } + + export function getAutoSkill() { + return autoSkill; + } + + export function learnedSkill(skill: Skill) { + return learned.has(skill); + } + + export function learnSkill(skill: Skill) { + learned.add(skill); + } + + export function forgetSkill(skill: Skill) { + learned.delete(skill); + } + + export function clearSkill() { + learned.clear(); + } + + export function saveSkill(): SkillSave { + return { autoSkill, learned: [...learned] }; + } + + export function loadSkill(skills: SkillSave) { + learned.clear(); + for (const skill of skills.learned) { + learned.add(skill); + } + autoSkill = skills.autoSkill; + } + + export function getAll() { + return learned; + } + + export function toggleSkill(skill: Skill) { + if (!learned.has(skill)) return; + if (enabled !== skill) enabled = skill; + else enabled = Skill.None; + } + + export function enableSkill(skill: Skill) { + if (!learned.has(skill)) return; + enabled = skill; + } + + export function disableSkill() { + enabled = Skill.None; + } + + export function getEnabled() { + return enabled; + } +} diff --git a/packages-user/data-state/src/state/hero.ts b/packages-user/data-state/src/state/hero.ts index 7fbaf19..5ac9089 100644 --- a/packages-user/data-state/src/state/hero.ts +++ b/packages-user/data-state/src/state/hero.ts @@ -1,7 +1,7 @@ import { logger } from '@motajs/common'; import { EventEmitter } from 'eventemitter3'; import { cloneDeep } from 'lodash-es'; -import { HeroSkill, NightSpecial } from '../mechanism/misc'; +import { HeroSkill, NightSpecial } from '../mechanism'; /** * 获取勇士在某一点的属性 diff --git a/packages-user/legacy-plugin-client/src/boss/palaceBoss.ts b/packages-user/legacy-plugin-client/src/boss/palaceBoss.ts index 92ad16f..9abb2b7 100644 --- a/packages-user/legacy-plugin-client/src/boss/palaceBoss.ts +++ b/packages-user/legacy-plugin-client/src/boss/palaceBoss.ts @@ -9,7 +9,7 @@ import { Transform, MotaOffscreenCanvas2D } from '@motajs/render'; -import { Pop } from '../fx/pop'; +import { Pop } from '../../../client-modules/src/render/legacy/pop'; import { SplittableBall } from './palaceBossProjectile'; import { PointEffect } from '../fx/pointShader'; import { loading } from '@user/data-base'; diff --git a/packages-user/legacy-plugin-client/src/boss/towerBoss.ts b/packages-user/legacy-plugin-client/src/boss/towerBoss.ts index b15390b..dba7cbd 100644 --- a/packages-user/legacy-plugin-client/src/boss/towerBoss.ts +++ b/packages-user/legacy-plugin-client/src/boss/towerBoss.ts @@ -22,10 +22,10 @@ import { ThunderProjectile } from './towerBossProjectile'; import { IStateDamageable } from '@user/data-state'; -import { Pop } from '../fx/pop'; -import { WeatherController } from '@user/client-modules'; +import { Pop } from '../../../client-modules/src/render/legacy/pop'; import { loading } from '@user/data-base'; import { clip } from '@user/legacy-plugin-data'; +import { WeatherController } from '@user/client-modules'; loading.once('coreInit', () => { const shader = new Shader(); diff --git a/packages-user/legacy-plugin-client/src/chase/chase1.ts b/packages-user/legacy-plugin-client/src/chase/chase1.ts index ab9d44b..fbfe652 100644 --- a/packages-user/legacy-plugin-client/src/chase/chase1.ts +++ b/packages-user/legacy-plugin-client/src/chase/chase1.ts @@ -1,6 +1,6 @@ import { Animation, hyper, linear, power, sleep } from 'mutate-animate'; import { Chase, ChaseData, IChaseController } from './chase'; -import { completeAchievement } from '@motajs/legacy-ui'; +// import { completeAchievement } from '@motajs/legacy-ui'; import { Camera, CameraAnimation, @@ -206,7 +206,7 @@ export function initChase(): IChaseController { core.removeFlag('chaseId'); if (success) { - completeAchievement('challenge', 0); + // completeAchievement('challenge', 0); } }); diff --git a/packages-user/legacy-plugin-client/src/fx/index.ts b/packages-user/legacy-plugin-client/src/fx/index.ts index de93f55..35f9314 100644 --- a/packages-user/legacy-plugin-client/src/fx/index.ts +++ b/packages-user/legacy-plugin-client/src/fx/index.ts @@ -1,5 +1 @@ -export * from './gameCanvas'; -export * from './halo'; export * from './pointShader'; -export * from './pop'; -export * from './portal'; diff --git a/packages-user/legacy-plugin-client/src/index.ts b/packages-user/legacy-plugin-client/src/index.ts index 4217111..d55557b 100644 --- a/packages-user/legacy-plugin-client/src/index.ts +++ b/packages-user/legacy-plugin-client/src/index.ts @@ -1,6 +1,3 @@ export * from './boss'; export * from './chase'; export * from './fx'; - -export * from './fallback'; -export * from '../../client-modules/src/render/loopMap'; diff --git a/packages-user/legacy-plugin-data/src/index.ts b/packages-user/legacy-plugin-data/src/index.ts index 9dce77d..c274dc4 100644 --- a/packages-user/legacy-plugin-data/src/index.ts +++ b/packages-user/legacy-plugin-data/src/index.ts @@ -21,5 +21,4 @@ export * from './removeMap'; export * from './replay'; export * from './shop'; export * from './skill'; -export * from '../../data-state/src/mechanism/skillTree'; export * from './ui'; diff --git a/packages-user/legacy-plugin-data/src/skill.ts b/packages-user/legacy-plugin-data/src/skill.ts index cff0dc7..c096eb6 100644 --- a/packages-user/legacy-plugin-data/src/skill.ts +++ b/packages-user/legacy-plugin-data/src/skill.ts @@ -1,6 +1,6 @@ // @ts-nocheck -import { HeroSkill } from '@/game/mechanism/misc'; +import { HeroSkill } from '@user/data-state'; // 所有的主动技能效果 var ignoreInJump = { diff --git a/packages/legacy-common/src/index.ts b/packages/legacy-common/src/index.ts index 3d17abd..6bf076a 100644 --- a/packages/legacy-common/src/index.ts +++ b/packages/legacy-common/src/index.ts @@ -2,3 +2,4 @@ export * from './patch'; export * from './disposable'; export * from './eventEmitter'; export * from './resource'; +export * from './utils'; diff --git a/packages/legacy-common/src/utils.ts b/packages/legacy-common/src/utils.ts new file mode 100644 index 0000000..6582837 --- /dev/null +++ b/packages/legacy-common/src/utils.ts @@ -0,0 +1,48 @@ +import { EVENT_KEY_CODE_MAP } from '@motajs/client-base'; + +export function flipBinary(num: number, col: number) { + const n = 1 << col; + if (num & n) return num & ~n; + else return num | n; +} + +/** + * 根据布尔值数组转换成一个二进制数 + * @param arr 要转换的布尔值数组 + */ +export function generateBinary(arr: boolean[]) { + let num = 0; + arr.forEach((v, i) => { + if (v) { + num |= 1 << i; + } + }); + return num; +} + +/** + * 删除数组内的某个项,返回删除后的数组 + * @param arr 要操作的数组 + * @param ele 要删除的项 + */ +export function deleteWith(arr: T[], ele: T): T[] { + const index = arr.indexOf(ele); + if (index === -1) return arr; + arr.splice(index, 1); + return arr; +} + +export function spliceBy(arr: T[], from: T): T[] { + const index = arr.indexOf(from); + if (index === -1) return arr; + arr.splice(index); + return arr; +} + +/** + * 获取事件中的keycode对应的键 + * @param key 要获取的键 + */ +export function keycode(key: number) { + return EVENT_KEY_CODE_MAP[key]; +} diff --git a/packages/legacy-ui/src/components/box.vue b/packages/legacy-ui/src/components/box.vue index b522c32..318703c 100644 --- a/packages/legacy-ui/src/components/box.vue +++ b/packages/legacy-ui/src/components/box.vue @@ -49,8 +49,13 @@ - - diff --git a/packages/legacy-ui/src/preset/danmaku.ts b/packages/legacy-ui/src/preset/danmaku.ts index f28f1b4..226e329 100644 --- a/packages/legacy-ui/src/preset/danmaku.ts +++ b/packages/legacy-ui/src/preset/danmaku.ts @@ -1,6 +1,6 @@ import { Danmaku } from '../danmaku'; import { Component, h } from 'vue'; -import { mainSetting } from './ui'; +import { mainSetting } from './settingIns'; import { getIconHeight } from '../utils'; import { BoxAnimate } from '../components'; diff --git a/packages/legacy-ui/src/preset/fixed.ts b/packages/legacy-ui/src/preset/fixed.ts index 0a7fb25..a4c4d48 100644 --- a/packages/legacy-ui/src/preset/fixed.ts +++ b/packages/legacy-ui/src/preset/fixed.ts @@ -1,5 +1,4 @@ import { debounce } from 'lodash-es'; -import { fixedUi, mainUi } from './ui'; import { ref } from 'vue'; import { sleep } from 'mutate-animate'; @@ -16,6 +15,7 @@ const showFixed = debounce((block: Block) => { if (!e) return; const enemy = core.status.thisMap.enemy.get(block.x, block.y); if (!enemy) return; + const { fixedUi } = Mota.require('@motajs/legacy-ui'); fixedUi.open( 'fixed', { enemy, close, loc: [cx, cy], hovered }, @@ -29,6 +29,7 @@ const showFixed = debounce((block: Block) => { const closeFixed = () => { close.value = true; sleep(200).then(() => { + const { fixedUi } = Mota.require('@motajs/legacy-ui'); fixedUi.closeByName('fixed'); close.value = false; }); @@ -58,6 +59,7 @@ gameListener.on('mouseMove', e => { }); hook.once('mounted', () => { + const { mainUi } = Mota.require('@motajs/legacy-ui'); mainUi.on('start', () => { showFixed.cancel(); closeFixed(); diff --git a/packages/legacy-ui/src/preset/hotkey.ts b/packages/legacy-ui/src/preset/hotkey.ts index 44b70fb..ec76ba7 100644 --- a/packages/legacy-ui/src/preset/hotkey.ts +++ b/packages/legacy-ui/src/preset/hotkey.ts @@ -1,15 +1,11 @@ import { KeyCode } from '@motajs/client-base'; import { gameKey, HotkeyJSON } from '@motajs/system-action'; -import { - openDanmakuPoster, - tip, - hasMarkedEnemy, - markEnemy, - unmarkEnemy -} from '@motajs/legacy-ui'; import { hovered } from './fixed'; -import { mainUi } from './ui'; +import { mainUi } from './uiIns'; import { GameStorage } from '@motajs/legacy-system'; +// import { hasMarkedEnemy, markEnemy, unmarkEnemy } from '../mark'; +import { openDanmakuPoster } from '../uiUtils'; +import { tip } from '../use'; export const mainScope = Symbol.for('@key_main'); @@ -506,9 +502,9 @@ gameKey .realize('mark', () => { const cls = hovered?.event.cls; if (cls === 'enemys' || cls === 'enemy48') { - const id = hovered!.event.id as EnemyIds; - if (hasMarkedEnemy(id)) unmarkEnemy(id); - else markEnemy(id); + // const id = hovered!.event.id as EnemyIds; + // if (hasMarkedEnemy(id)) unmarkEnemy(id); + // else markEnemy(id); } }) .realize('special', () => { diff --git a/packages/legacy-ui/src/preset/index.ts b/packages/legacy-ui/src/preset/index.ts index 44f0eec..38b8bac 100644 --- a/packages/legacy-ui/src/preset/index.ts +++ b/packages/legacy-ui/src/preset/index.ts @@ -4,3 +4,5 @@ export * from './danmaku'; export * from './fixed'; export * from './hotkey'; export * from './keyboard'; +export * from './uiIns'; +export * from './settingIns'; diff --git a/packages/legacy-ui/src/preset/settingIns.ts b/packages/legacy-ui/src/preset/settingIns.ts new file mode 100644 index 0000000..6ef3be9 --- /dev/null +++ b/packages/legacy-ui/src/preset/settingIns.ts @@ -0,0 +1,3 @@ +import { MotaSetting } from '../setting'; + +export const mainSetting = new MotaSetting(); diff --git a/packages/legacy-ui/src/preset/settings.tsx b/packages/legacy-ui/src/preset/settings.tsx index 6351e96..c7e5b42 100644 --- a/packages/legacy-ui/src/preset/settings.tsx +++ b/packages/legacy-ui/src/preset/settings.tsx @@ -1,6 +1,6 @@ import type { SettingComponent, SettingComponentProps } from '../setting'; import { Button, InputNumber, Radio } from 'ant-design-vue'; -import { mainUi } from './ui'; +import { mainUi } from './uiIns'; import { gameKey } from '@motajs/system-action'; interface Components { diff --git a/packages/legacy-ui/src/preset/ui.ts b/packages/legacy-ui/src/preset/ui.ts index aeea3d7..3c9746f 100644 --- a/packages/legacy-ui/src/preset/ui.ts +++ b/packages/legacy-ui/src/preset/ui.ts @@ -1,50 +1,13 @@ -import { GameStorage, VirtualKey } from '@motajs/legacy-system'; -import { - createSettingComponents, - GameUi, - isMobile, - MotaSetting, - triggerFullscreen, - UI, - UiController -} from '@motajs/legacy-ui'; +import { GameStorage } from '@motajs/legacy-system'; +import { createSettingComponents } from './settings'; +import { isMobile } from '../use'; +import { MotaSetting } from '../setting'; +import { triggerFullscreen } from '../utils'; import settingsText from '../data/settings.json'; +import { fixedUi, mainUi } from './uiIns'; +import { mainSetting } from './settingIns'; //#region legacy-ui -export const mainUi = new UiController(); -mainUi.register( - new GameUi('book', UI.Book), - new GameUi('toolbox', UI.Toolbox), - new GameUi('equipbox', UI.Equipbox), - new GameUi('settings', UI.Settings), - new GameUi('desc', UI.Desc), - new GameUi('skill', UI.Skill), - new GameUi('skillTree', UI.SkillTree), - new GameUi('fly', UI.Fly), - new GameUi('fixedDetail', UI.FixedDetail), - new GameUi('shop', UI.Shop), - new GameUi('achievement', UI.Achievement), - new GameUi('hotkey', UI.Hotkey), - new GameUi('toolEditor', UI.ToolEditor), - new GameUi('virtualKey', VirtualKey) - // todo: 把游戏主 div 加入到 mainUi 里面 -); -mainUi.showAll(); - -export const fixedUi = new UiController(true); -fixedUi.register( - new GameUi('markedEnemy', UI.Marked), - new GameUi('fixed', UI.Fixed), - new GameUi('chapter', UI.Chapter), - new GameUi('completeAchi', UI.CompleteAchi), - new GameUi('start', UI.Start), - new GameUi('toolbar', UI.Toolbar), - new GameUi('load', UI.Load), - new GameUi('danmaku', UI.Danmaku), - new GameUi('danmakuEditor', UI.DanmakuEditor), - new GameUi('tips', UI.Tips) -); -fixedUi.showAll(); const { hook } = Mota.require('@user/data-base'); hook.once('mounted', () => { @@ -84,7 +47,6 @@ hook.once('mounted', () => { const COM = createSettingComponents(); -export const mainSetting = new MotaSetting(); // 添加不参与全局存储的设置 MotaSetting.noStorage.push('action.autoSkill', 'screen.fullscreen'); diff --git a/packages/legacy-ui/src/preset/uiIns.ts b/packages/legacy-ui/src/preset/uiIns.ts new file mode 100644 index 0000000..9f3e25d --- /dev/null +++ b/packages/legacy-ui/src/preset/uiIns.ts @@ -0,0 +1,38 @@ +import { GameUi, UiController } from '../controller'; +import * as UI from '../ui'; +import { VirtualKey } from '@motajs/legacy-system'; + +export const mainUi = new UiController(); +mainUi.register( + new GameUi('book', UI.Book), + new GameUi('toolbox', UI.Toolbox), + new GameUi('equipbox', UI.Equipbox), + new GameUi('settings', UI.Settings), + new GameUi('desc', UI.Desc), + new GameUi('skill', UI.Skill), + new GameUi('skillTree', UI.SkillTree), + new GameUi('fly', UI.Fly), + new GameUi('fixedDetail', UI.FixedDetail), + new GameUi('shop', UI.Shop), + // new GameUi('achievement', UI.Achievement), + new GameUi('hotkey', UI.Hotkey), + new GameUi('toolEditor', UI.ToolEditor), + new GameUi('virtualKey', VirtualKey) + // todo: 把游戏主 div 加入到 mainUi 里面 +); +mainUi.showAll(); + +export const fixedUi = new UiController(true); +fixedUi.register( + new GameUi('markedEnemy', UI.Marked), + new GameUi('fixed', UI.Fixed), + new GameUi('chapter', UI.Chapter), + new GameUi('completeAchi', UI.CompleteAchi), + new GameUi('start', UI.Start), + new GameUi('toolbar', UI.Toolbar), + new GameUi('load', UI.Load), + new GameUi('danmaku', UI.Danmaku), + new GameUi('danmakuEditor', UI.DanmakuEditor), + new GameUi('tips', UI.Tips) +); +fixedUi.showAll(); diff --git a/packages/legacy-ui/src/setting.ts b/packages/legacy-ui/src/setting.ts index 6403598..ddb2916 100644 --- a/packages/legacy-ui/src/setting.ts +++ b/packages/legacy-ui/src/setting.ts @@ -1,9 +1,6 @@ import { FunctionalComponent, reactive } from 'vue'; import { EventEmitter } from '@motajs/legacy-common'; -import { has } from './utils'; -import { createSettingComponents } from './preset'; - -const COM = createSettingComponents(); +import { isNil } from 'lodash-es'; export interface SettingComponentProps { item: MotaSettingItem; @@ -85,7 +82,7 @@ export class MotaSetting extends EventEmitter { key: string, name: string, value: MotaSettingType, - com: SettingComponent = COM.Default, + com: SettingComponent, step: [number, number, number] = [0, 100, 1] ) { const setting: MotaSettingItem = { @@ -162,12 +159,12 @@ export class MotaSetting extends EventEmitter { defaultValue?: T ): T | undefined { const setting = this.getSetting(key); - if (!has(setting) && !has(defaultValue)) return void 0; + if (isNil(setting) && isNil(defaultValue)) return void 0; if (setting instanceof MotaSetting) { - if (has(setting)) return defaultValue; + if (!isNil(setting)) return defaultValue; return void 0; } else { - return has(setting) ? (setting.value as T) : (defaultValue as T); + return !isNil(setting) ? (setting.value as T) : (defaultValue as T); } } diff --git a/packages/legacy-ui/src/tools/achievement.ts b/packages/legacy-ui/src/tools/achievement.ts deleted file mode 100644 index b54372a..0000000 --- a/packages/legacy-ui/src/tools/achievement.ts +++ /dev/null @@ -1,120 +0,0 @@ -import list from '../data/achievement.json'; -import { achiDict, checkCompletionAchievement } from './completion'; -import { changeLocalStorage, has } from '../utils'; -import { fixedUi } from '../preset'; - -type AchievementList = typeof list; -export type AchievementType = keyof AchievementList; - -type AchievementData = Record; - -export interface Achievement { - name: string; - text: string[]; - point: number; - hide?: string; - progress?: string; - percent?: boolean; -} - -export default function init() { - return { completeAchievement, hasCompletedAchievement, addMountSign }; -} - -export const totalPoint = Object.values(list) - .map((v: Achievement[]) => - v.reduce((prev, curr) => { - return curr.point + prev; - }, 0) - ) - .reduce((prev, curr) => prev + curr); - -/** - * 完成一个成就 - * @param type 成就类型 - * @param index 成就索引 - */ -export function completeAchievement(type: AchievementType, index: number) { - if (flags.debug || hasCompletedAchievement(type, index)) return; - changeLocalStorage( - 'achievement', - data => { - data[type][index] = true; - return data; - }, - { - normal: [], - challenge: [], - explore: [] - } - ); - if (type === 'explore' && !Object.values(achiDict).includes(index)) { - checkCompletionAchievement(); - } - fixedUi.open('completeAchi', { - complete: `${type},${index}` - }); -} - -/** - * 是否完成了某个成就 - * @param type 成就类型 - * @param index 成就索引 - */ -export function hasCompletedAchievement(type: AchievementType, index: number) { - let data = core.getLocalStorage('achievement'); - if (!has(data)) { - const d = { - normal: [], - challenge: [], - explore: [] - }; - data = d; - core.setLocalStorage('achievement', d); - } - return data[type][index] ?? false; -} - -/** - * 获取当前成就点数 - */ -export function getNowPoint() { - let res = 0; - for (const [type, achi] of Object.entries(list)) { - achi.forEach((v, i) => { - if (hasCompletedAchievement(type as AchievementType, i)) { - res += v.point; - } - }); - } - return res; -} - -// ----- 各个成就相关的函数 - -/** - * 山路木牌 - * @param id 木牌id - */ -export function addMountSign(id: number) { - if (flags.debug) return; - if ( - !core.getLocalStorage(`mountSign_${id}`, false) && - !hasCompletedAchievement('explore', 1) - ) { - changeLocalStorage( - 'mountSign', - n => { - if (n + 1 >= 5) { - completeAchievement('explore', 1); - for (const i of [1, 2, 3, 4, 5]) { - core.removeLocalStorage(`mountSign_${i}`); - } - } - return n + 1; - }, - 0 - ); - core.setLocalStorage(`mountSign_${id}`, true); - } -} diff --git a/packages/legacy-ui/src/tools/book.tsx b/packages/legacy-ui/src/tools/book.tsx index 5ddef81..a3ed092 100644 --- a/packages/legacy-ui/src/tools/book.tsx +++ b/packages/legacy-ui/src/tools/book.tsx @@ -1,4 +1,4 @@ -import { has } from '../utils'; +import { isNil } from 'lodash-es'; import { IDamageEnemy } from '@motajs/types'; export interface CurrentEnemy { @@ -73,7 +73,7 @@ export function getDefDamage( if (res.length === 0) { origin = dam.damage; - if (has(origin)) { + if (!isNil(origin)) { res.push([addDef + i * ratio, origin]); last = origin; } @@ -113,7 +113,7 @@ export function getCriticalDamage( if (res.length === 0) { origin = dam.damage; - if (has(origin)) { + if (!isNil(origin)) { res.push([addAtk + i * ratio, origin]); last = origin; } diff --git a/packages/legacy-ui/src/tools/completion.ts b/packages/legacy-ui/src/tools/completion.ts deleted file mode 100644 index e107df9..0000000 --- a/packages/legacy-ui/src/tools/completion.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { - AchievementType, - completeAchievement, - hasCompletedAchievement -} from './achievement'; -import { changeLocalStorage } from '../utils'; -import list from '../data/achievement.json'; - -export const floors: Record = { - 1: ['MT0', 'tower7'] -}; -const achis: Record> = { - 1: { - normal: [0, 1], - challenge: [0], - explore: [1] - } -}; - -export const achiDict: Record = { - 1: 0 -}; - -export function init() { - Object.values(floors).forEach((v, i) => { - const from = core.floorIds.indexOf(v[0]); - const to = core.floorIds.indexOf(v[1]); - const all = core.floorIds.slice(from, to + 1); - floors[i + 1] = all; - }); -} - -/** - * 检查所有到达过的楼层,用于成就的计算 - */ -export function checkVisitedFloor() { - changeLocalStorage>>( - 'visitedFloor', - data => { - let needUpdate = false; - core.floorIds.forEach(v => { - if (core.hasVisitedFloor(v)) { - data[v] = true; - needUpdate = true; - } - }); - if (needUpdate) { - checkCompletionAchievement(); - } - - return data; - }, - {} - ); -} - -/** - * 获取一个章节的完成度 - * @param num 章节 - */ -export function getChapterCompletion(num: number) { - if (!achis[num]) return 0; - let res = 0; - const all = floors[num]; - const achiNum = Object.values(achis[num]).reduce( - (pre, cur) => pre + cur.length, - 0 - ); - - // 计算到达过的楼层 - let visitedFloor = 0; - const visited = core.getLocalStorage>>( - 'visitedFloor', - {} - ); - all.forEach(v => { - if (visited[v]) visitedFloor++; - }); - const floorRatio = all.length / (all.length + achiNum); - const floorPoint = (floorRatio * visitedFloor) / all.length; - - let completedPoint = 0; - let totalPoint = 0; - - // 计算成就,占比按成就点走 - for (const [type, achi] of Object.entries(achis[num]) as [ - AchievementType, - number[] - ][]) { - achi.forEach(v => { - totalPoint += list[type][v].point; - if (hasCompletedAchievement(type, v)) { - completedPoint += list[type][v].point; - } - }); - } - const achiPoint = (completedPoint / totalPoint) * (1 - floorRatio); - - res = floorPoint + achiPoint; - - return Math.floor(res * 100); -} - -/** - * 检查完成度成就是否完成 - */ -export function checkCompletionAchievement() { - [1].forEach(v => { - if (getChapterCompletion(v) >= 100) { - completeAchievement('explore', achiDict[v]); - } - }); -} diff --git a/packages/legacy-ui/src/tools/equipbox.tsx b/packages/legacy-ui/src/tools/equipbox.tsx index 7ea3cb1..839fb00 100644 --- a/packages/legacy-ui/src/tools/equipbox.tsx +++ b/packages/legacy-ui/src/tools/equipbox.tsx @@ -1,4 +1,5 @@ -import { getStatusLabel, has } from '../utils'; +import { isNil } from 'lodash-es'; +import { getStatusLabel } from '../utils'; /** * 获取所有装备 @@ -71,7 +72,7 @@ export function getNowStatus(nowEquip?: Equip, onCol: boolean = false) { else status = getHeroStatusOn(v)?.toString(); let add = 0; - if (has(nowEquip)) { + if (!isNil(nowEquip)) { add += Math.floor( (nowEquip.value[v] ?? 0) * core.getBuff(v) ); diff --git a/packages/legacy-ui/src/tools/fly.ts b/packages/legacy-ui/src/tools/fly.ts index 3be5749..e896806 100644 --- a/packages/legacy-ui/src/tools/fly.ts +++ b/packages/legacy-ui/src/tools/fly.ts @@ -1,5 +1,7 @@ -import { mainSetting } from '../preset/ui'; -import { downloadCanvasImage, has, tip } from '../utils'; +import { isNil } from 'lodash-es'; +import { mainSetting } from '../preset/settingIns'; +import { tip } from '../use'; +import { downloadCanvasImage } from '../utils'; type BFSFromString = `${FloorIds},${number},${number},${Dir}`; type BFSToString = `${FloorIds},${number},${number}`; @@ -163,7 +165,7 @@ export function getMapData( noCache: boolean = false ): MapBFSResult { if (!floorId) return { maps: [], link: {} }; - if (has(bfsCache[floorId]) && !noCache) return bfsCache[floorId]!; + if (!isNil(bfsCache[floorId]) && !noCache) return bfsCache[floorId]!; const queue = [floorId]; const used: Partial> = { diff --git a/packages/legacy-ui/src/tools/index.ts b/packages/legacy-ui/src/tools/index.ts index 8dbf1f2..aa0ab0f 100644 --- a/packages/legacy-ui/src/tools/index.ts +++ b/packages/legacy-ui/src/tools/index.ts @@ -1,7 +1,10 @@ -export * from './achievement'; +// import { init } from './achievement'; + +// init(); + +// export * from './achievement'; export * from './book'; export * from './common'; -export * from './completion'; export * from './equipbox'; export * from './fixed'; export * from './fly'; diff --git a/packages/legacy-ui/src/ui/achievement.vue b/packages/legacy-ui/src/ui/achievement.vue deleted file mode 100644 index 2fa4276..0000000 --- a/packages/legacy-ui/src/ui/achievement.vue +++ /dev/null @@ -1,340 +0,0 @@ - - - - - diff --git a/packages/legacy-ui/src/ui/book.vue b/packages/legacy-ui/src/ui/book.vue index 62dd778..9187430 100644 --- a/packages/legacy-ui/src/ui/book.vue +++ b/packages/legacy-ui/src/ui/book.vue @@ -41,21 +41,17 @@ import { onUnmounted, ref } from 'vue'; import EnemyOne from '../components/enemyOne.vue'; import Scroll from '../components/scroll.vue'; -import { has } from '../utils'; import BookDetail from './bookDetail.vue'; import { LeftOutlined } from '@ant-design/icons-vue'; import { ToShowEnemy, detailInfo } from '../tools/book'; import { getDetailedEnemy } from '../tools/fixed'; -import { GameUi } from '../controller'; import { gameKey } from '@motajs/system-action'; -import { mainUi } from '../preset/ui'; -import { mainSetting } from '../preset/ui'; +import { mainSetting } from '../preset/settingIns'; import { isMobile } from '../use'; +import { IMountedVBind } from '../interface'; +import { isNil } from 'lodash-es'; -const props = defineProps<{ - num: number; - ui: GameUi; -}>(); +const props = defineProps(); const floorId = // @ts-ignore @@ -122,12 +118,12 @@ async function show() { * 退出怪物手册 */ async function exit() { - const hold = mainUi.holdOn(); - mainUi.close(props.num); + const hold = props.controller.holdOn(); + props.controller.close(props.num); if (core.events.recoverEvents(core.status.event.interval)) { hold.end(true); return; - } else if (has(core.status.event.ui)) { + } else if (!isNil(core.status.event.ui)) { core.status.boxAnimateObjs = []; // @ts-ignore core.ui._drawViewMaps(core.status.event.ui); diff --git a/packages/legacy-ui/src/ui/bookDetail.vue b/packages/legacy-ui/src/ui/bookDetail.vue index e9cf629..3fdd5bf 100644 --- a/packages/legacy-ui/src/ui/bookDetail.vue +++ b/packages/legacy-ui/src/ui/bookDetail.vue @@ -22,7 +22,7 @@ :from-book="fromBook" v-else-if="panel === 'critical'" > - +
@@ -35,8 +35,8 @@ id="enemy-target" class="button-text more" @click="changePanel($event, 'target')" - > 怪物更多信息 + > +
- {{ chapter }} + {{ props.chapter }}
- - diff --git a/packages/legacy-ui/src/ui/danmaku.vue b/packages/legacy-ui/src/ui/danmaku.vue index 090584a..9743d8e 100644 --- a/packages/legacy-ui/src/ui/danmaku.vue +++ b/packages/legacy-ui/src/ui/danmaku.vue @@ -30,7 +30,7 @@ import { nextTick, onUnmounted, reactive, watch } from 'vue'; import { Danmaku } from '../danmaku'; import { LikeFilled } from '@ant-design/icons-vue'; -import { mainSetting } from '../preset/ui'; +import { mainSetting } from '../preset/settingIns'; import { debounce } from 'lodash-es'; interface ElementMap { @@ -205,10 +205,7 @@ onUnmounted(() => {}); } .danmaku-info { - text-shadow: - 1px 1px 1px black, - 1px -1px 1px black, - -1px 1px 1px black, + text-shadow: 1px 1px 1px black, 1px -1px 1px black, -1px 1px 1px black, -1px -1px 1px black; } diff --git a/packages/legacy-ui/src/ui/danmakuEditor.vue b/packages/legacy-ui/src/ui/danmakuEditor.vue index aa2c006..c27b981 100644 --- a/packages/legacy-ui/src/ui/danmakuEditor.vue +++ b/packages/legacy-ui/src/ui/danmakuEditor.vue @@ -159,21 +159,17 @@ import { UpOutlined } from '@ant-design/icons-vue'; import { Danmaku } from '../danmaku'; -import { GameUi } from '../controller'; import { sleep } from 'mutate-animate'; -import { fixedUi } from '../preset/ui'; -import { calStringSize, tip } from '../utils'; +import { calStringSize, stringifyCSS, parseCss, getIconHeight } from '../utils'; import { gameKey } from '@motajs/system-action'; import { isNil } from 'lodash-es'; -import { stringifyCSS, parseCss, getIconHeight } from '../utils'; import { logger, LogLevel } from '@motajs/common'; import Scroll from '../components/scroll.vue'; import BoxAnimate from '../components/boxAnimate.vue'; +import { IMountedVBind } from '../interface'; +import { tip } from '../use'; -const props = defineProps<{ - num: number; - ui: GameUi; -}>(); +const props = defineProps(); const frequentlyIcon: (AllIds | 'hero' | `X${number}`)[] = [ 'hero', @@ -301,7 +297,7 @@ function close() { mainDiv.classList.remove('danmaku-startup'); mainDiv.classList.add('danmaku-close'); sleep(200).then(() => { - fixedUi.close(props.num); + props.controller.close(props.num); }); } diff --git a/packages/legacy-ui/src/ui/desc.vue b/packages/legacy-ui/src/ui/desc.vue index 60b8bef..0f7e96c 100644 --- a/packages/legacy-ui/src/ui/desc.vue +++ b/packages/legacy-ui/src/ui/desc.vue @@ -22,21 +22,17 @@ import { computed, onUnmounted, ref } from 'vue'; import desc from '../data/desc.json'; import { splitText } from '../utils'; import Colomn from '../components/colomn.vue'; -import { GameUi } from '../controller'; import { gameKey } from '@motajs/system-action'; -import { mainUi } from '../preset/ui'; +import { IMountedVBind } from '../interface'; -const props = defineProps<{ - num: number; - ui: GameUi; -}>(); +const props = defineProps(); type DescKey = keyof typeof desc; const selected = ref(Object.keys(desc)[0] as DescKey); function exit() { - mainUi.close(props.num); + props.controller.close(props.num); } const content = computed(() => { diff --git a/packages/legacy-ui/src/ui/equipbox.vue b/packages/legacy-ui/src/ui/equipbox.vue index 2affed8..61ea9b5 100644 --- a/packages/legacy-ui/src/ui/equipbox.vue +++ b/packages/legacy-ui/src/ui/equipbox.vue @@ -125,8 +125,8 @@ {{ equip.name }} @@ -183,18 +183,14 @@ import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'; import Scroll from '../components/scroll.vue'; import { getAddStatus, getEquips, getNowStatus } from '../tools/equipbox'; import BoxAnimate from '../components/boxAnimate.vue'; -import { has, tip, type } from '../utils'; -import { cancelGlobalDrag, isMobile, useDrag } from '../use'; +import { type, getStatusLabel } from '../utils'; +import { cancelGlobalDrag, isMobile, tip, useDrag } from '../use'; import { hyper } from 'mutate-animate'; -import { GameUi } from '../controller'; import { gameKey } from '@motajs/system-action'; -import { getStatusLabel } from '../utils'; -import { mainUi } from '../preset/ui'; +import { IMountedVBind } from '../interface'; +import { isNil } from 'lodash-es'; -const props = defineProps<{ - num: number; - ui: GameUi; -}>(); +const props = defineProps(); const equips = ref(getEquips()); const col = ref('all'); @@ -242,10 +238,10 @@ const equip = computed(() => { if (isCol.value) { const id = equiped.value[selected.value]; const e = core.material.items[id]; - if (!has(e)) return none; + if (isNil(e)) return none; return e; } - if (!has(index)) return none; + if (isNil(index)) return none; return all[index[0]]; }); @@ -276,7 +272,7 @@ const toShow = computed(() => { const e = all[v[0]].equip!; const t = e.type; if (sortNorm !== 'none') { - if (!has(e[sortBy][sortNorm])) return false; + if (isNil(e[sortBy][sortNorm])) return false; } if (col.value === 'all') return true; if (typeof t === 'string') return t === col.value; @@ -309,7 +305,7 @@ function changeSort() { } function exit() { - mainUi.close(props.num); + props.controller.close(props.num); } function clickList(i: number) { @@ -350,7 +346,7 @@ function canDragin(type: number) { if (type < 0) return false; const et = equip.value.equip?.type; if (!core.canEquip(toShow.value[selected.value]?.[0])) return false; - if (!has(et)) return false; + if (isNil(et)) return false; if (typeof et === 'number') return type === et; return equipCol[type] === et; } @@ -427,10 +423,10 @@ function dragout(e: Event) { } function toTool() { - mainUi.holdOn(); + props.controller.holdOn(); exit(); nextTick(() => { - mainUi.open('toolbox'); + props.controller.open('toolbox'); }); } diff --git a/packages/legacy-ui/src/ui/fixed.vue b/packages/legacy-ui/src/ui/fixed.vue index 180d045..4deea64 100644 --- a/packages/legacy-ui/src/ui/fixed.vue +++ b/packages/legacy-ui/src/ui/fixed.vue @@ -31,13 +31,11 @@ diff --git a/packages/legacy-ui/src/ui/fly.vue b/packages/legacy-ui/src/ui/fly.vue index 2c24c13..0125f61 100644 --- a/packages/legacy-ui/src/ui/fly.vue +++ b/packages/legacy-ui/src/ui/fly.vue @@ -98,18 +98,14 @@ import { DoubleRightOutlined } from '@ant-design/icons-vue'; import { debounce } from 'lodash-es'; -import { tip } from '../utils'; -import { GameUi } from '../controller'; +import { tip } from '../use'; import { gameKey } from '@motajs/system-action'; import { createChangable } from '../tools/common'; -import { mainUi } from '../preset/ui'; -import { mainSetting } from '../preset/ui'; +import { mainSetting } from '../preset/settingIns'; import { GameStorage } from '@motajs/legacy-system'; +import { IMountedVBind } from '../interface'; -const props = defineProps<{ - num: number; - ui: GameUi; -}>(); +const props = defineProps(); type Loc2 = [number, number, number, number]; @@ -162,7 +158,7 @@ let thumb: HTMLCanvasElement; let thumbCtx: CanvasRenderingContext2D; function exit() { - mainUi.close(props.num); + props.controller.close(props.num); } const title = computed(() => { @@ -584,10 +580,7 @@ onUnmounted(() => { max-width: 50%; text-overflow: ellipsis; overflow: hidden; - text-shadow: - 1px 1px 1px black, - 1px -1px 1px black, - -1px 1px 1px black, + text-shadow: 1px 1px 1px black, 1px -1px 1px black, -1px 1px 1px black, -1px -1px 1px black; } diff --git a/packages/legacy-ui/src/ui/hotkey.vue b/packages/legacy-ui/src/ui/hotkey.vue index 14b8d32..9580090 100644 --- a/packages/legacy-ui/src/ui/hotkey.vue +++ b/packages/legacy-ui/src/ui/hotkey.vue @@ -37,14 +37,13 @@ - - diff --git a/packages/legacy-ui/src/ui/settings.vue b/packages/legacy-ui/src/ui/settings.vue index 66e3bd8..f6348c7 100644 --- a/packages/legacy-ui/src/ui/settings.vue +++ b/packages/legacy-ui/src/ui/settings.vue @@ -73,7 +73,7 @@ diff --git a/packages/legacy-ui/src/ui/skillTree.vue b/packages/legacy-ui/src/ui/skillTree.vue index bbc90db..5b165f6 100644 --- a/packages/legacy-ui/src/ui/skillTree.vue +++ b/packages/legacy-ui/src/ui/skillTree.vue @@ -81,17 +81,14 @@ import { computed, onMounted, onUnmounted, ref, watch } from 'vue'; import { LeftOutlined, RightOutlined } from '@ant-design/icons-vue'; import Scroll from '../components/scroll.vue'; -import { has, splitText, tip } from '../utils'; -import { isMobile } from '../use'; +import { splitText } from '../utils'; +import { isMobile, tip } from '../use'; import { sleep } from 'mutate-animate'; import { gameKey } from '@motajs/system-action'; -import { GameUi } from '../controller'; -import { mainUi } from '../preset/ui'; +import { IMountedVBind } from '../interface'; +import { isNil } from 'lodash-es'; -const props = defineProps<{ - num: number; - ui: GameUi; -}>(); +const props = defineProps(); const skillTree = Mota.require('@user/legacy-plugin-data'); @@ -179,7 +176,7 @@ const level = computed(() => { }); function exit() { - mainUi.close(props.num); + props.controller.close(props.num); } function resize() { @@ -298,7 +295,7 @@ function selectChapter(delta: number) { const now = chapterList.indexOf(chapter.value); const to = now + delta; - if (has(chapterList[to]) && flags.chapter > to) { + if (!isNil(chapterList[to]) && flags.chapter > to) { selected.value = s[chapterList[to]][0].index; chapter.value = chapterList[to]; update.value = !update.value; diff --git a/packages/legacy-ui/src/ui/start.vue b/packages/legacy-ui/src/ui/start.vue index 66a5355..d0ccf8e 100644 --- a/packages/legacy-ui/src/ui/start.vue +++ b/packages/legacy-ui/src/ui/start.vue @@ -64,19 +64,14 @@ import { FullscreenExitOutlined } from '@ant-design/icons-vue'; import { sleep } from 'mutate-animate'; -import { doByInterval } from '../utils'; -import { triggerFullscreen } from '../utils'; +import { doByInterval, triggerFullscreen } from '../utils'; import { isMobile } from '../use'; -import { GameUi } from '../controller'; import { gameKey } from '@motajs/system-action'; -import { mainUi } from '../preset/ui'; -import { mainSetting } from '../preset/ui'; +import { mainSetting } from '../preset/settingIns'; import { mat4 } from 'gl-matrix'; +import { IMountedVBind } from '../interface'; -const props = defineProps<{ - num: number; - ui: GameUi; -}>(); +const props = defineProps(); const bg = core.material.images.images['bg.webp']; @@ -158,7 +153,7 @@ async function clickStartButton(id: string) { } if (id === 'replay') core.chooseReplayFile(); if (id === 'achievement') { - mainUi.open('achievement'); + props.controller.open('achievement'); } } diff --git a/packages/legacy-ui/src/ui/toolbox.vue b/packages/legacy-ui/src/ui/toolbox.vue index cb30066..8882df5 100644 --- a/packages/legacy-ui/src/ui/toolbox.vue +++ b/packages/legacy-ui/src/ui/toolbox.vue @@ -85,8 +85,8 @@ {{ selected === 'none' ? '永久道具' - : (getClsName(all[selected].cls as ItemMode) ?? - '永久道具') + : getClsName(all[selected].cls as ItemMode) ?? + '永久道具' }}
@@ -113,17 +113,14 @@ import Scroll from '../components/scroll.vue'; import BoxAnimate from '../components/boxAnimate.vue'; import { getClsName, getItems } from '../tools/toolbox'; import { isMobile } from '../use'; -import { type, has } from '../utils'; +import { type } from '../utils'; import { hyper } from 'mutate-animate'; import { message } from 'ant-design-vue'; -import { GameUi } from '../controller'; import { gameKey } from '@motajs/system-action'; -import { mainUi } from '../preset/ui'; +import { IMountedVBind } from '../interface'; +import { isNil } from 'lodash-es'; -const props = defineProps<{ - num: number; - ui: GameUi; -}>(); +const props = defineProps(); type ItemMode = 'tools' | 'constants'; type ShowItemIds = ItemIdOf<'constants' | 'tools'> | 'none'; @@ -146,7 +143,7 @@ watch(index, n => { }); watch(mode, n => { - if (!has(items[n][index.value])) { + if (isNil(items[n][index.value])) { selected.value = 'none'; return; } @@ -172,17 +169,17 @@ async function select(id: ShowItemIds, nouse: boolean = false) { } function exit() { - mainUi.close(props.num); + props.controller.close(props.num); } function use(id: ShowItemIds) { if (id === 'none') return; if (core.canUseItem(id)) { - const hold = mainUi.holdOn(); + const hold = props.controller.holdOn(); exit(); nextTick(() => { core.tryUseItem(id, false, () => { - if (mainUi.stack.length === 0) { + if (props.controller.stack.length === 0) { hold.end(core.status.event.id !== 'toolbox'); } }); @@ -196,10 +193,10 @@ function use(id: ShowItemIds) { } async function toEquip() { - mainUi.holdOn(); + props.controller.holdOn(); exit(); nextTick(() => { - mainUi.open('equipbox'); + props.controller.open('equipbox'); }); } diff --git a/packages/legacy-ui/src/uiUtils.ts b/packages/legacy-ui/src/uiUtils.ts new file mode 100644 index 0000000..dd94220 --- /dev/null +++ b/packages/legacy-ui/src/uiUtils.ts @@ -0,0 +1,47 @@ +import { KeyCode } from '@motajs/client-base'; +import { KeyboardEmits, Keyboard, isAssist } from '@motajs/system-action'; +import { mainUi, fixedUi } from './preset/uiIns'; + +/** + * 唤起虚拟键盘,并获取到一次按键操作 + * @param emitAssist 是否可以获取辅助按键,为true时,如果按下辅助按键,那么会立刻返回该按键, + * 否则会视为开关辅助按键 + * @param assist 初始化的辅助按键 + */ +export function getVitualKeyOnce( + emitAssist: boolean = false, + assist: number = 0, + emittable: KeyCode[] = [] +): Promise { + // todo: 正确触发后删除监听器 + return new Promise(res => { + const key = Keyboard.get('full')!; + key.withAssist(assist); + const id = mainUi.open('virtualKey', { keyboard: key }); + key.on('emit', (item, assist, _index, ev) => { + ev.preventDefault(); + if (emitAssist) { + if (emittable.length === 0 || emittable.includes(item.key)) { + res({ key: item.key, assist: 0 }); + key.disposeScope(); + mainUi.close(id); + } + } else { + if ( + !isAssist(item.key) && + (emittable.length === 0 || emittable.includes(item.key)) + ) { + res({ key: item.key, assist }); + key.disposeScope(); + mainUi.close(id); + } + } + }); + }); +} + +export function openDanmakuPoster() { + if (!fixedUi.hasName('danmakuEditor')) { + fixedUi.open('danmakuEditor'); + } +} diff --git a/packages/legacy-ui/src/use.ts b/packages/legacy-ui/src/use.ts index 5066ed8..ff52ca7 100644 --- a/packages/legacy-ui/src/use.ts +++ b/packages/legacy-ui/src/use.ts @@ -1,8 +1,23 @@ import { sleep } from 'mutate-animate'; -import { tip } from './utils'; +import { message } from 'ant-design-vue'; +import { MessageApi } from 'ant-design-vue/lib/message'; -export default function init() { - return { useDrag, useWheel, useUp, isMobile }; +message.config({ + maxCount: 3 +}); +export function tip( + type: Exclude, + text: string +) { + message[type]({ + content: text, + class: 'antdv-message' + }); +} + +let num = 0; +export function requireUniqueSymbol() { + return num++; } type DragFn = (x: number, y: number, e: MouseEvent | TouchEvent) => void; diff --git a/packages/legacy-ui/src/utils.ts b/packages/legacy-ui/src/utils.ts index 2aa9017..4e9c235 100644 --- a/packages/legacy-ui/src/utils.ts +++ b/packages/legacy-ui/src/utils.ts @@ -1,13 +1,10 @@ -import { message } from 'ant-design-vue'; -import { MessageApi } from 'ant-design-vue/lib/message'; import { isNil } from 'lodash-es'; import { Animation, sleep, TimingFn } from 'mutate-animate'; import { Ref, ref } from 'vue'; -import { EVENT_KEY_CODE_MAP, KeyCode } from '@motajs/client-base'; +import { KeyCode } from '@motajs/client-base'; import axios from 'axios'; import { decompressFromBase64 } from 'lz-string'; import { Keyboard, KeyboardEmits, isAssist } from '@motajs/system-action'; -import { fixedUi, mainUi } from './preset/ui'; import { logger } from '@motajs/common'; type CanParseCss = keyof { @@ -18,25 +15,6 @@ type CanParseCss = keyof { : never]: CSSStyleDeclaration[P]; }; -export default function init() { - return { - has, - getDamageColor, - parseCss, - tip, - changeLocalStorage, - swapChapter - }; -} - -/** - * 判定一个值是否不是undefined或null - * @param value 要判断的值 - */ -export function has(value: T): value is NonNullable { - return !isNil(value); -} - /** * 根据伤害大小获取颜色 * @param damage 伤害大小 @@ -68,14 +46,6 @@ export function setCanvasSize( canvas.style.height = `${h}px`; } -/** - * 获取事件中的keycode对应的键 - * @param key 要获取的键 - */ -export function keycode(key: number) { - return EVENT_KEY_CODE_MAP[key]; -} - /** * 解析css字符串为CSSStyleDeclaration对象 * @param css 要解析的css字符串 @@ -195,7 +165,7 @@ export function type( const all = toShow.length; const fn = (time: number) => { - if (!has(time)) return; + if (isNil(time)) return; const now = ani.x; content.value = toShow.slice(0, Math.floor(now)); if (Math.floor(now) === all) { @@ -213,19 +183,6 @@ export function type( return content; } -message.config({ - maxCount: 3 -}); -export function tip( - type: Exclude, - text: string -) { - message[type]({ - content: text, - class: 'antdv-message' - }); -} - /** * 设置文字分段换行等 * @param str 文字 @@ -235,7 +192,7 @@ export function splitText(str: string[]) { .map((v, i, a) => { if (/^\d+\./.test(v)) return `${' '.repeat(12)}${v}`; else if ( - (has(a[i - 1]) && v !== '
' && a[i - 1] === '
') || + (!isNil(a[i - 1]) && v !== '
' && a[i - 1] === '
') || i === 0 ) { return `${' '.repeat(8)}${v}`; @@ -339,25 +296,6 @@ export function ensureArray(arr: T): T extends any[] ? T : T[] { return arr instanceof Array ? arr : [arr]; } -/** - * 删除数组内的某个项,返回删除后的数组 - * @param arr 要操作的数组 - * @param ele 要删除的项 - */ -export function deleteWith(arr: T[], ele: T): T[] { - const index = arr.indexOf(ele); - if (index === -1) return arr; - arr.splice(index, 1); - return arr; -} - -export function spliceBy(arr: T[], from: T): T[] { - const index = arr.indexOf(from); - if (index === -1) return arr; - arr.splice(index); - return arr; -} - export async function triggerFullscreen(full: boolean) { const { maxGameScale } = Mota.require('@user/data-utils'); if (!!document.fullscreenElement && !full) { @@ -382,20 +320,6 @@ export async function triggerFullscreen(full: boolean) { } } -/** - * 根据布尔值数组转换成一个二进制数 - * @param arr 要转换的布尔值数组 - */ -export function generateBinary(arr: boolean[]) { - let num = 0; - arr.forEach((v, i) => { - if (v) { - num |= 1 << i; - } - }); - return num; -} - /** * 获得某个状态的中文名 * @param name 要获取的属性名 @@ -423,50 +347,6 @@ export function getStatusLabel(name: string) { ); } -export function flipBinary(num: number, col: number) { - const n = 1 << col; - if (num & n) return num & ~n; - else return num | n; -} - -/** - * 唤起虚拟键盘,并获取到一次按键操作 - * @param emitAssist 是否可以获取辅助按键,为true时,如果按下辅助按键,那么会立刻返回该按键, - * 否则会视为开关辅助按键 - * @param assist 初始化的辅助按键 - */ -export function getVitualKeyOnce( - emitAssist: boolean = false, - assist: number = 0, - emittable: KeyCode[] = [] -): Promise { - // todo: 正确触发后删除监听器 - return new Promise(res => { - const key = Keyboard.get('full')!; - key.withAssist(assist); - const id = mainUi.open('virtualKey', { keyboard: key }); - key.on('emit', (item, assist, _index, ev) => { - ev.preventDefault(); - if (emitAssist) { - if (emittable.length === 0 || emittable.includes(item.key)) { - res({ key: item.key, assist: 0 }); - key.disposeScope(); - mainUi.close(id); - } - } else { - if ( - !isAssist(item.key) && - (emittable.length === 0 || emittable.includes(item.key)) - ) { - res({ key: item.key, assist }); - key.disposeScope(); - mainUi.close(id); - } - } - }); - }); -} - export function formatSize(size: number) { return size < 1 << 10 ? `${size.toFixed(2)}B` @@ -477,17 +357,6 @@ export function formatSize(size: number) { : `${(size / (1 << 30)).toFixed(2)}GB`; } -let num = 0; -export function requireUniqueSymbol() { - return num++; -} - -export function openDanmakuPoster() { - if (!fixedUi.hasName('danmakuEditor')) { - fixedUi.open('danmakuEditor'); - } -} - export function getIconHeight(icon: AllIds | 'hero') { if (icon === 'hero') { if (core.isPlaying()) { diff --git a/packages/render-elements/src/floor.ts b/packages/render-elements/src/floor.ts deleted file mode 100644 index fe99080..0000000 --- a/packages/render-elements/src/floor.ts +++ /dev/null @@ -1,415 +0,0 @@ -import EventEmitter from 'eventemitter3'; -import { - FloorLayer, - ILayerGroupRenderExtends, - ILayerRenderExtends, - Layer, - LayerGroup, - LayerMovingRenderable -} from './layer'; -import { texture } from './cache'; -import { sleep } from 'mutate-animate'; -import { RenderAdapter } from '@motajs/render-core'; - -const { hook } = Mota.require('@user/data-base'); - -hook.on('setBlock', (x, y, floor, block) => { - const isNow = floor === core.status.floorId; - LayerGroupFloorBinder.activedBinder.forEach(v => { - if (floor === v.floor || (isNow && v.bindThisFloor)) { - v.setBlock('event', block, x, y); - } - }); - LayerFloorBinder.listenedBinder.forEach(v => { - if (v.layer.layer === 'event') { - if (v.floor === floor || (isNow && v.bindThisFloor)) { - v.setBlock(block, x, y); - } - } - }); -}); -hook.on('changingFloor', floor => { - // 潜在隐患:如果putRenderData改成异步,那么会变成两帧后才能真正刷新并渲染 - // 考虑到楼层转换一般不会同时执行很多次,因此这里改为立刻更新 - LayerGroupFloorBinder.activedBinder.forEach(v => { - if (v.bindThisFloor) v.updateBindData(); - v.emit('floorChange', floor); - }); - LayerFloorBinder.listenedBinder.forEach(v => { - if (v.bindThisFloor) v.updateBindData(); - }); -}); -hook.on('setBgFgBlock', (name, number, x, y, floor) => { - const isNow = floor === core.status.floorId; - LayerGroupFloorBinder.activedBinder.forEach(v => { - if (floor === v.floor || (isNow && v.bindThisFloor)) { - v.setBlock(name, number, x, y); - } - }); - LayerFloorBinder.listenedBinder.forEach(v => { - if (v.layer.layer === name) { - if (v.floor === floor || (isNow && v.bindThisFloor)) { - v.setBlock(number, x, y); - } - } - }); -}); - -interface LayerGroupBinderEvent { - update: [floor: FloorIds]; - setBlock: [x: number, y: number, floor: FloorIds, block: AllNumbers]; - floorChange: [floor: FloorIds]; -} - -/** - * 楼层绑定拓展,用于LayerGroup,将楼层数据传输到渲染系统。 - * 添加后,会自动在LayerGroup包含的子Layer上添加LayerFloorBinder拓展,用于后续处理。 - * 当移除这个拓展时,其附属的所有子拓展也会一并被移除。 - */ -export class LayerGroupFloorBinder - extends EventEmitter - implements ILayerGroupRenderExtends -{ - id: string = 'floor-binder'; - - bindThisFloor: boolean = true; - floor?: FloorIds; - group!: LayerGroup; - - /** 附属的子LayerFloorBinder拓展 */ - layerBinders: Set = new Set(); - - private needUpdate: boolean = false; - - static activedBinder: Set = new Set(); - - /** - * 绑定楼层为当前楼层,并跟随变化 - */ - bindThis() { - this.floor = void 0; - this.bindThisFloor = true; - this.layerBinders.forEach(v => v.bindThis()); - this.updateBind(); - } - - /** - * 绑定楼层为指定楼层 - * @param floorId 楼层id - */ - bindFloor(floorId: FloorIds) { - this.bindThisFloor = false; - this.floor = floorId; - this.layerBinders.forEach(v => v.bindFloor(floorId)); - this.updateBind(); - } - - /** - * 在下一帧进行绑定数据更新 - */ - updateBind() { - if (this.needUpdate || !this.group) return; - this.needUpdate = true; - this.group.requestBeforeFrame(() => { - this.needUpdate = false; - this.updateBindData(); - }); - } - - /** - * 立刻进行数据绑定更新 - */ - updateBindData() { - this.layerBinders.forEach(v => { - v.updateBindData(); - }); - - const floor = this.getFloor(); - this.emit('update', floor); - } - - getFloor() { - return this.bindThisFloor ? core.status.floorId : this.floor!; - } - - /** - * 设置图块 - */ - setBlock(layer: FloorLayer, block: AllNumbers, x: number, y: number) { - const ex = this.group - .getLayer(layer) - ?.getExtends('floor-binder') as LayerFloorBinder; - if (!ex) return; - ex.setBlock(block, x, y); - - const floor = this.bindThisFloor ? core.status.floorId : this.floor!; - this.emit('setBlock', x, y, floor, block); - } - - checkLayerExtends(layer: Layer) { - const ex = layer.getExtends('floor-binder'); - - if (!ex) { - const extend = new LayerFloorBinder(this); - layer.extends(extend); - this.layerBinders.add(extend); - } else { - if (ex instanceof LayerFloorBinder) { - ex.setParent(this); - this.layerBinders.add(ex); - } - } - } - - awake(group: LayerGroup) { - this.group = group; - - for (const layer of group.layers.values()) { - this.checkLayerExtends(layer); - } - LayerGroupFloorBinder.activedBinder.add(this); - } - - onLayerAdd(_group: LayerGroup, layer: Layer): void { - this.checkLayerExtends(layer); - } - - onDestroy(group: LayerGroup) { - LayerGroupFloorBinder.activedBinder.delete(this); - group.layers.forEach(v => { - v.removeExtends('floor-binder'); - }); - this.removeAllListeners(); - } -} - -/** - * 楼层绑定拓展,用于Layer的楼层渲染。 - * 注意,如果目标Layer是LayerGroup的子元素,那么会自动检测父元素是否包含LayerGroupFloorBinder拓展, - * 如果包含,那么会自动将此拓展附加至父元素的拓展。当父元素的拓展被移除时,此拓展也会一并被移除。 - */ -export class LayerFloorBinder implements ILayerRenderExtends { - id: string = 'floor-binder'; - - parent?: LayerGroupFloorBinder; - layer!: Layer; - bindThisFloor: boolean = true; - floor?: FloorIds; - - static listenedBinder: Set = new Set(); - - private needUpdate: boolean = false; - - constructor(parent?: LayerGroupFloorBinder) { - this.parent = parent; - } - - /** - * 绑定楼层为当前楼层,并跟随变化 - */ - bindThis() { - this.floor = void 0; - this.bindThisFloor = true; - this.updateBind(); - } - - /** - * 绑定楼层为指定楼层 - * @param floorId 楼层id - */ - bindFloor(floorId: FloorIds) { - this.bindThisFloor = false; - this.floor = floorId; - this.updateBind(); - } - - getFloor() { - return this.bindThisFloor ? core.status.floorId : this.floor!; - } - - /** - * 设置这个拓展附属至的父拓展(LayerGroupFloorBinder拓展) - * @param parent 父拓展 - */ - setParent(parent?: LayerGroupFloorBinder) { - this.parent = parent; - this.checkListen(); - } - - private checkListen() { - if (this.parent) LayerFloorBinder.listenedBinder.delete(this); - else LayerFloorBinder.listenedBinder.add(this); - } - - /** - * 在下一帧进行绑定数据更新 - */ - updateBind() { - if (this.needUpdate) return; - this.needUpdate = true; - this.layer.requestBeforeFrame(() => { - this.needUpdate = false; - this.updateBindData(); - }); - } - - /** - * 设置图块 - */ - setBlock(block: AllNumbers, x: number, y: number) { - this.layer.putRenderData([block], 1, x, y); - } - - /** - * 立刻更新绑定数据,而非下一帧 - */ - updateBindData() { - const floor = this.getFloor(); - if (!floor) return; - core.extractBlocks(floor); - const map = core.status.maps[floor]; - this.layer.setMapSize(map.width, map.height); - const image = core.status.maps[this.getFloor()].images; - if (this.layer.layer === 'event') { - const m = map.map; - this.layer.putRenderData(m.flat(), map.width, 0, 0); - } else { - const m = core.maps._getBgFgMapArray(this.layer.layer!, floor); - this.layer.putRenderData(m.flat(), map.width, 0, 0); - } - if (this.layer.layer === 'bg') { - // 别忘了背景图块 - this.layer.setBackground(texture.idNumberMap[map.defaultGround]); - } - const toDraw = image?.filter(v => v.canvas === this.layer.layer); - this.layer.setFloorImage(toDraw ?? []); - } - - awake(layer: Layer) { - this.layer = layer; - if (!this.parent) { - const group = layer.parent; - if (group instanceof LayerGroup) { - const ex = group.getExtends('floor-binder'); - if (ex instanceof LayerGroupFloorBinder) { - ex.checkLayerExtends(layer); - this.parent = ex; - } - } - } - this.checkListen(); - } - - onDestroy(_layer: Layer) { - LayerFloorBinder.listenedBinder.delete(this); - this.parent?.layerBinders.delete(this); - } -} - -interface DoorAnimateRenderable { - renderable: LayerMovingRenderable; - count: number; - perTime: number; -} - -export class LayerDoorAnimate implements ILayerRenderExtends { - id: string = 'door-animate'; - - layer!: Layer; - - private moving: Set = new Set(); - - private getRenderable(block: Block): DoorAnimateRenderable | null { - const { x, y, id } = block; - const renderable = texture.getRenderable(id); - if (!renderable) return null; - const image = renderable.autotile - ? renderable.image[0] - : renderable.image; - const time = block.event.doorInfo?.time ?? 160; - const frame = renderable.render.length; - const perTime = time / frame; - - const data: LayerMovingRenderable = { - x, - y, - zIndex: y, - image, - autotile: false, - animate: 0, - frame, - bigImage: false, - render: renderable.render, - alpha: 1 - }; - return { renderable: data, count: frame, perTime }; - } - - /** - * 开门 - * @param block 图块信息 - */ - async openDoor(block: Block) { - const renderable = this.getRenderable(block); - if (!renderable) return Promise.reject(); - const { renderable: data, count: frame, perTime } = renderable; - data.animate = 0; - this.moving.add(data); - this.layer.requestUpdateMoving(); - - let now = 0; - while (now < frame) { - await sleep(perTime); - data.animate = ++now; - this.layer.update(this.layer); - } - - this.moving.delete(data); - this.layer.requestUpdateMoving(); - return Promise.resolve(); - } - - /** - * 关门 - * @param block 图块信息 - */ - async closeDoor(block: Block) { - const renderable = this.getRenderable(block); - if (!renderable) return Promise.reject(); - const { renderable: data, count: frame, perTime } = renderable; - data.animate = frame - 1; - this.moving.add(data); - this.layer.requestUpdateMoving(); - - let now = 0; - while (now >= 0) { - await sleep(perTime); - data.animate = --now; - this.layer.update(this.layer); - } - this.moving.delete(data); - this.layer.requestUpdateMoving(); - return Promise.resolve(); - } - - awake(layer: Layer) { - this.layer = layer; - doorAdapter.add(this); - } - - onMovingUpdate(_layer: Layer, renderable: LayerMovingRenderable[]): void { - renderable.push(...this.moving); - } - - onDestroy(_layer: Layer): void { - doorAdapter.remove(this); - } -} - -const doorAdapter = new RenderAdapter('door-animate'); -doorAdapter.receive('openDoor', (item, block: Block) => { - return item.openDoor(block); -}); -doorAdapter.receive('closeDoor', (item, block: Block) => { - return item.closeDoor(block); -}); diff --git a/packages/render-elements/src/index.ts b/packages/render-elements/src/index.ts index a9a9930..280f1f5 100644 --- a/packages/render-elements/src/index.ts +++ b/packages/render-elements/src/index.ts @@ -2,7 +2,6 @@ export * from './animate'; export * from './block'; export * from './cache'; export * from './camera'; -export * from './floor'; export * from './frame'; export * from './graphics'; export * from './hero'; diff --git a/packages/render-elements/src/layer.ts b/packages/render-elements/src/layer.ts index fe11d13..9079ce1 100644 --- a/packages/render-elements/src/layer.ts +++ b/packages/render-elements/src/layer.ts @@ -8,11 +8,11 @@ import { RenderAdapter } from '@motajs/render-core'; import { logger } from '@motajs/common'; -import { TimingFn } from 'mutate-animate'; +import { sleep, TimingFn } from 'mutate-animate'; import { RenderableData, texture } from './cache'; import { BlockCacher, CanvasCacheItem, ICanvasCacheItem } from './block'; -import { LayerFloorBinder, LayerGroupFloorBinder } from './floor'; import { IAnimateFrame, renderEmits } from './frame'; +import { EventEmitter } from 'eventemitter3'; export interface ILayerGroupRenderExtends { /** 拓展的唯一标识符 */ @@ -1550,3 +1550,406 @@ export class Layer extends Container { } const layerAdapter = new RenderAdapter('layer'); + +const { hook } = Mota.require('@user/data-base'); + +hook.on('setBlock', (x, y, floor, block) => { + const isNow = floor === core.status.floorId; + LayerGroupFloorBinder.activedBinder.forEach(v => { + if (floor === v.floor || (isNow && v.bindThisFloor)) { + v.setBlock('event', block, x, y); + } + }); + LayerFloorBinder.listenedBinder.forEach(v => { + if (v.layer.layer === 'event') { + if (v.floor === floor || (isNow && v.bindThisFloor)) { + v.setBlock(block, x, y); + } + } + }); +}); +hook.on('changingFloor', floor => { + // 潜在隐患:如果putRenderData改成异步,那么会变成两帧后才能真正刷新并渲染 + // 考虑到楼层转换一般不会同时执行很多次,因此这里改为立刻更新 + LayerGroupFloorBinder.activedBinder.forEach(v => { + if (v.bindThisFloor) v.updateBindData(); + v.emit('floorChange', floor); + }); + LayerFloorBinder.listenedBinder.forEach(v => { + if (v.bindThisFloor) v.updateBindData(); + }); +}); +hook.on('setBgFgBlock', (name, number, x, y, floor) => { + const isNow = floor === core.status.floorId; + LayerGroupFloorBinder.activedBinder.forEach(v => { + if (floor === v.floor || (isNow && v.bindThisFloor)) { + v.setBlock(name, number, x, y); + } + }); + LayerFloorBinder.listenedBinder.forEach(v => { + if (v.layer.layer === name) { + if (v.floor === floor || (isNow && v.bindThisFloor)) { + v.setBlock(number, x, y); + } + } + }); +}); + +interface LayerGroupBinderEvent { + update: [floor: FloorIds]; + setBlock: [x: number, y: number, floor: FloorIds, block: AllNumbers]; + floorChange: [floor: FloorIds]; +} + +/** + * 楼层绑定拓展,用于LayerGroup,将楼层数据传输到渲染系统。 + * 添加后,会自动在LayerGroup包含的子Layer上添加LayerFloorBinder拓展,用于后续处理。 + * 当移除这个拓展时,其附属的所有子拓展也会一并被移除。 + */ +export class LayerGroupFloorBinder + extends EventEmitter + implements ILayerGroupRenderExtends +{ + id: string = 'floor-binder'; + + bindThisFloor: boolean = true; + floor?: FloorIds; + group!: LayerGroup; + + /** 附属的子LayerFloorBinder拓展 */ + layerBinders: Set = new Set(); + + private needUpdate: boolean = false; + + static activedBinder: Set = new Set(); + + /** + * 绑定楼层为当前楼层,并跟随变化 + */ + bindThis() { + this.floor = void 0; + this.bindThisFloor = true; + this.layerBinders.forEach(v => v.bindThis()); + this.updateBind(); + } + + /** + * 绑定楼层为指定楼层 + * @param floorId 楼层id + */ + bindFloor(floorId: FloorIds) { + this.bindThisFloor = false; + this.floor = floorId; + this.layerBinders.forEach(v => v.bindFloor(floorId)); + this.updateBind(); + } + + /** + * 在下一帧进行绑定数据更新 + */ + updateBind() { + if (this.needUpdate || !this.group) return; + this.needUpdate = true; + this.group.requestBeforeFrame(() => { + this.needUpdate = false; + this.updateBindData(); + }); + } + + /** + * 立刻进行数据绑定更新 + */ + updateBindData() { + this.layerBinders.forEach(v => { + v.updateBindData(); + }); + + const floor = this.getFloor(); + this.emit('update', floor); + } + + getFloor() { + return this.bindThisFloor ? core.status.floorId : this.floor!; + } + + /** + * 设置图块 + */ + setBlock(layer: FloorLayer, block: AllNumbers, x: number, y: number) { + const ex = this.group + .getLayer(layer) + ?.getExtends('floor-binder') as LayerFloorBinder; + if (!ex) return; + ex.setBlock(block, x, y); + + const floor = this.bindThisFloor ? core.status.floorId : this.floor!; + this.emit('setBlock', x, y, floor, block); + } + + checkLayerExtends(layer: Layer) { + const ex = layer.getExtends('floor-binder'); + + if (!ex) { + const extend = new LayerFloorBinder(this); + layer.extends(extend); + this.layerBinders.add(extend); + } else { + if (ex instanceof LayerFloorBinder) { + ex.setParent(this); + this.layerBinders.add(ex); + } + } + } + + awake(group: LayerGroup) { + this.group = group; + + for (const layer of group.layers.values()) { + this.checkLayerExtends(layer); + } + LayerGroupFloorBinder.activedBinder.add(this); + } + + onLayerAdd(_group: LayerGroup, layer: Layer): void { + this.checkLayerExtends(layer); + } + + onDestroy(group: LayerGroup) { + LayerGroupFloorBinder.activedBinder.delete(this); + group.layers.forEach(v => { + v.removeExtends('floor-binder'); + }); + this.removeAllListeners(); + } +} + +/** + * 楼层绑定拓展,用于Layer的楼层渲染。 + * 注意,如果目标Layer是LayerGroup的子元素,那么会自动检测父元素是否包含LayerGroupFloorBinder拓展, + * 如果包含,那么会自动将此拓展附加至父元素的拓展。当父元素的拓展被移除时,此拓展也会一并被移除。 + */ +export class LayerFloorBinder implements ILayerRenderExtends { + id: string = 'floor-binder'; + + parent?: LayerGroupFloorBinder; + layer!: Layer; + bindThisFloor: boolean = true; + floor?: FloorIds; + + static listenedBinder: Set = new Set(); + + private needUpdate: boolean = false; + + constructor(parent?: LayerGroupFloorBinder) { + this.parent = parent; + } + + /** + * 绑定楼层为当前楼层,并跟随变化 + */ + bindThis() { + this.floor = void 0; + this.bindThisFloor = true; + this.updateBind(); + } + + /** + * 绑定楼层为指定楼层 + * @param floorId 楼层id + */ + bindFloor(floorId: FloorIds) { + this.bindThisFloor = false; + this.floor = floorId; + this.updateBind(); + } + + getFloor() { + return this.bindThisFloor ? core.status.floorId : this.floor!; + } + + /** + * 设置这个拓展附属至的父拓展(LayerGroupFloorBinder拓展) + * @param parent 父拓展 + */ + setParent(parent?: LayerGroupFloorBinder) { + this.parent = parent; + this.checkListen(); + } + + private checkListen() { + if (this.parent) LayerFloorBinder.listenedBinder.delete(this); + else LayerFloorBinder.listenedBinder.add(this); + } + + /** + * 在下一帧进行绑定数据更新 + */ + updateBind() { + if (this.needUpdate) return; + this.needUpdate = true; + this.layer.requestBeforeFrame(() => { + this.needUpdate = false; + this.updateBindData(); + }); + } + + /** + * 设置图块 + */ + setBlock(block: AllNumbers, x: number, y: number) { + this.layer.putRenderData([block], 1, x, y); + } + + /** + * 立刻更新绑定数据,而非下一帧 + */ + updateBindData() { + const floor = this.getFloor(); + if (!floor) return; + core.extractBlocks(floor); + const map = core.status.maps[floor]; + this.layer.setMapSize(map.width, map.height); + const image = core.status.maps[this.getFloor()].images; + if (this.layer.layer === 'event') { + const m = map.map; + this.layer.putRenderData(m.flat(), map.width, 0, 0); + } else { + const m = core.maps._getBgFgMapArray(this.layer.layer!, floor); + this.layer.putRenderData(m.flat(), map.width, 0, 0); + } + if (this.layer.layer === 'bg') { + // 别忘了背景图块 + this.layer.setBackground(texture.idNumberMap[map.defaultGround]); + } + const toDraw = image?.filter(v => v.canvas === this.layer.layer); + this.layer.setFloorImage(toDraw ?? []); + } + + awake(layer: Layer) { + this.layer = layer; + if (!this.parent) { + const group = layer.parent; + if (group instanceof LayerGroup) { + const ex = group.getExtends('floor-binder'); + if (ex instanceof LayerGroupFloorBinder) { + ex.checkLayerExtends(layer); + this.parent = ex; + } + } + } + this.checkListen(); + } + + onDestroy(_layer: Layer) { + LayerFloorBinder.listenedBinder.delete(this); + this.parent?.layerBinders.delete(this); + } +} + +interface DoorAnimateRenderable { + renderable: LayerMovingRenderable; + count: number; + perTime: number; +} + +export class LayerDoorAnimate implements ILayerRenderExtends { + id: string = 'door-animate'; + + layer!: Layer; + + private moving: Set = new Set(); + + private getRenderable(block: Block): DoorAnimateRenderable | null { + const { x, y, id } = block; + const renderable = texture.getRenderable(id); + if (!renderable) return null; + const image = renderable.autotile + ? renderable.image[0] + : renderable.image; + const time = block.event.doorInfo?.time ?? 160; + const frame = renderable.render.length; + const perTime = time / frame; + + const data: LayerMovingRenderable = { + x, + y, + zIndex: y, + image, + autotile: false, + animate: 0, + frame, + bigImage: false, + render: renderable.render, + alpha: 1 + }; + return { renderable: data, count: frame, perTime }; + } + + /** + * 开门 + * @param block 图块信息 + */ + async openDoor(block: Block) { + const renderable = this.getRenderable(block); + if (!renderable) return Promise.reject(); + const { renderable: data, count: frame, perTime } = renderable; + data.animate = 0; + this.moving.add(data); + this.layer.requestUpdateMoving(); + + let now = 0; + while (now < frame) { + await sleep(perTime); + data.animate = ++now; + this.layer.update(this.layer); + } + + this.moving.delete(data); + this.layer.requestUpdateMoving(); + return Promise.resolve(); + } + + /** + * 关门 + * @param block 图块信息 + */ + async closeDoor(block: Block) { + const renderable = this.getRenderable(block); + if (!renderable) return Promise.reject(); + const { renderable: data, count: frame, perTime } = renderable; + data.animate = frame - 1; + this.moving.add(data); + this.layer.requestUpdateMoving(); + + let now = 0; + while (now >= 0) { + await sleep(perTime); + data.animate = --now; + this.layer.update(this.layer); + } + this.moving.delete(data); + this.layer.requestUpdateMoving(); + return Promise.resolve(); + } + + awake(layer: Layer) { + this.layer = layer; + doorAdapter.add(this); + } + + onMovingUpdate(_layer: Layer, renderable: LayerMovingRenderable[]): void { + renderable.push(...this.moving); + } + + onDestroy(_layer: Layer): void { + doorAdapter.remove(this); + } +} + +const doorAdapter = new RenderAdapter('door-animate'); +doorAdapter.receive('openDoor', (item, block: Block) => { + return item.openDoor(block); +}); +doorAdapter.receive('closeDoor', (item, block: Block) => { + return item.closeDoor(block); +}); diff --git a/packages/render-elements/src/viewport.ts b/packages/render-elements/src/viewport.ts index 3623315..5d3b042 100644 --- a/packages/render-elements/src/viewport.ts +++ b/packages/render-elements/src/viewport.ts @@ -1,7 +1,7 @@ import { RenderAdapter } from '@motajs/render-core'; import { HeroRenderer } from './hero'; import { ILayerGroupRenderExtends, LayerGroup } from './layer'; -import { LayerGroupFloorBinder } from './floor'; +import { LayerGroupFloorBinder } from './layer'; import { hyper, TimingFn } from 'mutate-animate'; export class FloorViewport implements ILayerGroupRenderExtends { diff --git a/packages/system-action/src/hotkey.ts b/packages/system-action/src/hotkey.ts index 61ee69e..2105d0f 100644 --- a/packages/system-action/src/hotkey.ts +++ b/packages/system-action/src/hotkey.ts @@ -4,7 +4,7 @@ import { generateBinary, keycode, spliceBy -} from '@motajs/legacy-ui'; +} from '@motajs/legacy-common'; import { EventEmitter } from 'eventemitter3'; import { isNil } from 'lodash-es'; diff --git a/packages/system-action/src/keyboard.ts b/packages/system-action/src/keyboard.ts index 6acf6ee..8189291 100644 --- a/packages/system-action/src/keyboard.ts +++ b/packages/system-action/src/keyboard.ts @@ -1,8 +1,12 @@ -import { EventEmitter, Listener } from '@motajs/legacy-common'; +import { + EventEmitter, + Listener, + deleteWith, + flipBinary +} from '@motajs/legacy-common'; import { KeyCode } from '@motajs/client-base'; import { gameKey } from './hotkey'; import { unwarpBinary } from './hotkey'; -import { deleteWith, flipBinary } from '@motajs/legacy-ui'; import { cloneDeep } from 'lodash-es'; import { shallowReactive } from 'vue'; diff --git a/vite.config.ts b/vite.config.ts index c55a295..3abb0b9 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -24,6 +24,14 @@ const aliases = glob.sync('packages/*/src').map((srcPath) => { }; }); +const aliasesUser = glob.sync('packages-user/*/src').map((srcPath) => { + const packageName = path.basename(path.dirname(srcPath)); + return { + find: `@user/${packageName}`, + replacement: path.resolve(__dirname, srcPath), + }; +}); + // https://vitejs.dev/config/ export default defineConfig({ plugins: [ @@ -51,7 +59,8 @@ export default defineConfig({ base: `./`, resolve: { alias: [ - ...aliases + ...aliases, + ...aliasesUser ] }, build: {