HumanBreak/src/game/system.ts

561 lines
18 KiB
TypeScript
Raw Normal View History

2024-01-24 21:32:49 +08:00
import type { AudioPlayer } from '@/core/audio/audio';
import type { BgmController } from '@/core/audio/bgm';
import type { SoundController, SoundEffect } from '@/core/audio/sound';
import type { Disposable } from '@/core/common/disposable';
import type {
EventEmitter,
IndexedEventEmitter
} from '@/core/common/eventEmitter';
2024-02-02 17:10:21 +08:00
import type { loading } from './game';
2024-01-24 21:32:49 +08:00
import type {
Resource,
ResourceStore,
ResourceType,
ZippedResource
} from '@/core/loader/resource';
import type { Hotkey } from '@/core/main/custom/hotkey';
import type { Keyboard } from '@/core/main/custom/keyboard';
import type { CustomToolbar } from '@/core/main/custom/toolbar';
import type { Focus, GameUi, UiController } from '@/core/main/custom/ui';
2024-02-02 17:10:21 +08:00
import type { gameListener, hook } from './game';
2024-01-24 21:32:49 +08:00
import type {
MotaSetting,
SettingDisplayer,
SettingStorage
} from '@/core/main/setting';
import type { GameStorage } from '@/core/main/storage';
2024-02-02 17:10:21 +08:00
import type { DamageEnemy, EnemyCollection } from './enemy/damage';
import type { specials } from './enemy/special';
2024-01-24 21:32:49 +08:00
import type { Range } from '@/plugin/game/range';
import type { KeyCode } from '@/plugin/keyCodes';
2024-02-01 19:31:49 +08:00
import type { Ref } from 'vue';
2024-01-24 21:32:49 +08:00
interface ClassInterface {
// 渲染进程与游戏进程通用
EventEmitter: typeof EventEmitter;
IndexedEventEmitter: typeof IndexedEventEmitter;
Disposable: typeof Disposable;
// 定义于渲染进程录像中会进行polyfill但是不执行任何内容
GameStorage: typeof GameStorage;
MotaSetting: typeof MotaSetting;
SettingDisplayer: typeof SettingDisplayer;
Resource: typeof Resource;
ZippedResource: typeof ZippedResource;
ResourceStore: typeof ResourceStore;
Focus: typeof Focus;
GameUi: typeof GameUi;
UiController: typeof UiController;
Hotkey: typeof Hotkey;
Keyboard: typeof Keyboard;
CustomToolbar: typeof CustomToolbar;
AudioPlayer: typeof AudioPlayer;
SoundEffect: typeof SoundEffect;
SoundController: typeof SoundController;
BgmController: typeof BgmController;
// todo: 放到插件 ShaderEffect: typeof ShaderEffect;
// 定义于游戏进程,渲染进程依然可用
Range: typeof Range;
EnemyCollection: typeof EnemyCollection;
DamageEnemy: typeof DamageEnemy;
}
interface FunctionInterface {
// 定义于渲染进程录像中会进行polyfill但是不执行任何内容
readyAllResource(): void;
// 定义于游戏进程,渲染进程依然可用
// todo
}
interface VariableInterface {
// 定义于渲染进程录像中会进行polyfill
loading: typeof loading;
hook: typeof hook;
gameListener: typeof gameListener;
mainSetting: MotaSetting;
gameKey: Hotkey;
mainUi: UiController;
fixedUi: UiController;
KeyCode: typeof KeyCode;
// isMobile: boolean;
bgm: BgmController;
sound: SoundController;
resource: ResourceStore<Exclude<ResourceType, 'zip'>>;
zipResource: ResourceStore<'zip'>;
settingStorage: GameStorage<SettingStorage>;
2024-02-01 19:31:49 +08:00
status: Ref<boolean>;
2024-01-24 21:32:49 +08:00
// 定义于游戏进程,渲染进程依然可用
haloSpecials: number[];
2024-02-01 19:31:49 +08:00
enemySpecials: typeof specials;
2024-01-24 21:32:49 +08:00
}
2024-02-02 17:10:21 +08:00
interface ModuleInterface {}
2024-01-24 21:32:49 +08:00
interface SystemInterfaceMap {
class: ClassInterface;
fn: FunctionInterface;
var: VariableInterface;
2024-02-02 17:10:21 +08:00
module: ModuleInterface;
2024-01-24 21:32:49 +08:00
}
type InterfaceType = keyof SystemInterfaceMap;
2024-02-01 19:31:49 +08:00
interface PluginInterface {
// 渲染进程定义的插件
pop_r: typeof import('../plugin/pop');
use_r: typeof import('../plugin/use');
// animate: typeof import('../plugin/animateController');
// utils: typeof import('../plugin/utils');
// status: typeof import('../plugin/ui/statusBar');
fly_r: typeof import('../plugin/ui/fly');
chase_r: typeof import('../plugin/chase/chase');
// webglUtils: typeof import('../plugin/webgl/utils');
shadow_r: typeof import('../plugin/shadow/shadow');
gameShadow_r: typeof import('../plugin/shadow/gameShadow');
// achievement: typeof import('../plugin/ui/achievement');
completion_r: typeof import('../plugin/completion');
// path: typeof import('../plugin/fx/path');
gameCanvas_r: typeof import('../plugin/fx/gameCanvas');
// noise: typeof import('../plugin/fx/noise');
smooth_r: typeof import('../plugin/fx/smoothView');
frag_r: typeof import('../plugin/fx/frag');
// 游戏进程定义的插件
utils_g: typeof import('../plugin/game/utils');
loopMap_g: typeof import('../plugin/game/loopMap');
shop_g: typeof import('../plugin/game/shop');
replay_g: typeof import('../plugin/game/replay');
skillTree_g: typeof import('../plugin/game/skillTree');
removeMap_g: typeof import('../plugin/game/removeMap');
remainEnemy_g: typeof import('../plugin/game/enemy/remainEnemy');
chase_g: typeof import('../plugin/game/chase');
skill_g: typeof import('../plugin/game/skill');
towerBoss_g: typeof import('../plugin/game/towerBoss');
heroFourFrames_g: typeof import('../plugin/game/fx/heroFourFrames');
rewrite_g: typeof import('../plugin/game/fx/rewrite');
itemDetail_g: typeof import('../plugin/game/fx/itemDetail');
checkBlock_g: typeof import('../plugin/game/enemy/checkblock');
halo_g: typeof import('../plugin/game/fx/halo');
study_g: typeof import('../plugin/game/study');
}
interface PackageInterface {
axios: typeof import('axios');
'chart.js': typeof import('chart.js');
jszip: typeof import('jszip');
lodash: typeof import('lodash-es');
'lz-string': typeof import('lz-string');
'mutate-animate': typeof import('mutate-animate');
vue: typeof import('vue');
}
2024-01-27 22:45:07 +08:00
2024-01-24 21:32:49 +08:00
export interface IMota {
2024-01-27 22:45:07 +08:00
rewrite: typeof rewrite;
2024-02-01 19:31:49 +08:00
r: typeof r;
rf: typeof rf;
2024-01-27 22:45:07 +08:00
2024-02-01 19:31:49 +08:00
/** 样板插件接口 */
2024-01-27 22:45:07 +08:00
Plugin: IPlugin;
2024-02-01 19:31:49 +08:00
/**
* 使
* polyfill使
* 使main.replayChecking进行检查使
*/
Package: IPackage;
2024-01-27 22:45:07 +08:00
2024-01-24 21:32:49 +08:00
/**
*
* @param type
* @param key
*/
require<T extends InterfaceType, K extends keyof SystemInterfaceMap[T]>(
type: T,
key: K
): SystemInterfaceMap[T][K];
/**
*
* @param type
* @param key
*/
require(type: InterfaceType, key: string): any;
/**
*
* @param type
*/
requireAll<T extends InterfaceType>(type: T): SystemInterfaceMap[T];
/**
*
* @param type
* @param key
* @param data
*/
register<T extends InterfaceType, K extends keyof SystemInterfaceMap[T]>(
type: T,
key: K,
data: SystemInterfaceMap[T][K]
): void;
/**
*
* @param type
* @param key
* @param data
*/
register(type: InterfaceType, key: string, data: any): void;
}
2024-01-27 22:45:07 +08:00
export interface IPlugin {
2024-02-01 19:31:49 +08:00
inited: boolean;
2024-01-27 22:45:07 +08:00
/**
*
*/
init(): void;
/**
*
* @param plugin
*/
require<K extends keyof PluginInterface>(plugin: K): PluginInterface[K];
/**
*
* @param plugin
*/
require(plugin: string): any;
/**
*
*/
2024-02-01 19:31:49 +08:00
requireAll(): PluginInterface & { [x: string]: any };
2024-01-27 22:45:07 +08:00
/**
*
* @param plugin
* @param data
* @param init plugin和data
*/
register<K extends keyof PluginInterface>(
plugin: K,
data: PluginInterface[K],
init?: (plugin: K, data: PluginInterface[K]) => void
): void;
/**
*
* @param plugin
* @param init
*/
register<K extends keyof PluginInterface>(
plugin: K,
init: (plugin: K) => PluginInterface[K]
): void;
/**
*
* @param plugin
* @param data
* @param init plugin和data
*/
register<K extends string, D>(
plugin: K,
data: D,
init?: (plugin: K, data: D) => void
): void;
/**
*
* @param plugin
* @param init
*/
register<K extends string>(plugin: K, init: (plugin: K) => any): void;
}
2024-02-01 19:31:49 +08:00
export interface IPackage {
/**
* 使
* @param name
*/
require<K extends keyof PackageInterface>(name: K): PackageInterface[K];
/**
* 使
*/
requireAll(): PackageInterface;
register<K extends keyof PackageInterface>(
name: K,
data: PackageInterface[K]
): void;
}
2024-01-27 22:45:07 +08:00
interface IPluginData {
/** 插件类型content表示直接注册了内容function表示注册了初始化函数内容从其返回值获取 */
type: 'content' | 'function';
data: any;
init?: (plugin: string, data?: any) => any;
}
class MPlugin {
private static plugins: Record<string, IPluginData> = {};
private static pluginData: Record<string, any> = {};
2024-02-01 19:31:49 +08:00
static inited = false;
2024-01-27 22:45:07 +08:00
constructor() {
throw new Error(`System plugin class cannot be constructed.`);
}
static init() {
for (const [key, data] of Object.entries(this.plugins)) {
if (data.type === 'content') {
data.init?.(key, data.data);
} else {
data.data = data.init!(key);
}
this.pluginData[key] = data.data;
}
this.inited = true;
}
static require(key: string) {
if (!this.inited) {
throw new Error(`Cannot access plugin '${key}' before initialize.`);
}
if (!(key in this.plugins)) {
throw new Error(`Cannot resolve plugin require: key='${key}'`);
}
return this.plugins[key].data;
}
2024-02-01 19:31:49 +08:00
static requireAll(): PluginInterface {
return this.pluginData as PluginInterface;
2024-01-27 22:45:07 +08:00
}
static register(key: string, data: any, init?: any) {
if (typeof data === 'function') {
this.plugins[key] = {
type: 'function',
init: data,
data: void 0
};
} else {
this.plugins[key] = {
type: 'content',
data,
init
};
}
}
}
2024-02-01 19:31:49 +08:00
class MPackage {
// @ts-ignore
private static packages: PackageInterface = {};
constructor() {
throw new Error(`System package class cannot be constructed.`);
}
static require<K extends keyof PackageInterface>(
name: K
): PackageInterface[K] {
return this.packages[name];
}
static requireAll() {
return this.packages;
}
static register<K extends keyof PackageInterface>(
name: K,
data: PackageInterface[K]
) {
this.packages[name] = data;
}
}
2024-01-24 21:32:49 +08:00
/**
* Mota
*/
class Mota {
private static classes: Record<string, any> = {};
private static functions: Record<string, any> = {};
private static variables: Record<string, any> = {};
2024-02-02 17:10:21 +08:00
private static modules: Record<string, any> = {};
2024-01-24 21:32:49 +08:00
2024-01-27 22:45:07 +08:00
static rewrite = rewrite;
2024-02-01 19:31:49 +08:00
static r = r;
static rf = rf;
2024-01-27 22:45:07 +08:00
static Plugin = MPlugin;
2024-02-01 19:31:49 +08:00
static Package = MPackage;
2024-01-27 22:45:07 +08:00
2024-01-24 21:32:49 +08:00
constructor() {
throw new Error(`System interface class cannot be constructed.`);
}
static require(type: InterfaceType, key: string): any {
const data = this.getByType(type)[key];
if (!!data) return data;
else {
throw new Error(
`Cannot resolve require: type='${type}',key='${key}'`
);
}
}
static requireAll<T extends InterfaceType>(type: T): SystemInterfaceMap[T] {
return this.getByType(type) as SystemInterfaceMap[T];
}
static register(type: InterfaceType, key: string, data: any) {
const obj = this.getByType(type);
if (key in obj) {
console.warn(
`重复的样板接口注册: type='${type}', key='${key}',已将其覆盖`
);
}
obj[key] = data;
}
private static getByType(type: InterfaceType) {
return type === 'class'
? this.classes
: type === 'fn'
? this.functions
2024-02-02 17:10:21 +08:00
: type === 'var'
? this.variables
: this.modules;
2024-01-24 21:32:49 +08:00
}
}
2024-01-27 22:45:07 +08:00
type RewriteType = 'full' | 'front' | 'add';
type _F<F> = F extends (...params: infer P) => infer R ? [P, R] : never;
type _Func = (...params: any) => any;
/**
*
* @param base
* @param key base中叫什么
* @param type full表示全量复写front表示在原函数之前添加内容
* @param re full时表示将原函数完全覆盖front时表示将该函数添加到原函数之前
* @param bind base
* @param rebind base
*/
2024-02-01 19:31:49 +08:00
function rewrite<
O,
K extends SelectKey<O, _Func>,
R extends 'full' | 'front',
T = O
>(
2024-01-27 22:45:07 +08:00
base: O,
key: K,
2024-02-01 19:31:49 +08:00
type: R,
re: (
this: T,
...params: [..._F<O[K]>[0], ...any[]]
) => R extends 'full' ? _F<O[K]>[1] : void,
2024-01-27 22:45:07 +08:00
bind?: any,
rebind?: T
): (this: T, ...params: [..._F<O[K]>[0], ...any[]]) => _F<O[K]>[1];
/**
*
* @param base
* @param key base中叫什么
* @param type add表示在函数后追加
* @param re add时表示在原函数后面追加复写函数
*
2024-02-01 19:31:49 +08:00
* @param bind `base`
* @param rebind `base`
2024-01-27 22:45:07 +08:00
*/
function rewrite<O, K extends SelectKey<O, _Func>, T = O>(
base: O,
key: K,
type: 'add',
re: (
this: T,
...params: [_F<O[K]>[1], ..._F<O[K]>[0], ...any[]]
) => _F<O[K]>[1],
bind?: any,
rebind?: T
): (this: T, ...params: [..._F<O[K]>[0], ...any[]]) => _F<O[K]>[1];
function rewrite<O, K extends SelectKey<O, _Func>, T = O>(
base: O,
key: K,
type: RewriteType,
re: (this: T, ...params: [..._F<O[K]>[0], ...any[]]) => _F<O[K]>[1],
bind?: any,
rebind?: T
): (this: T, ...params: [..._F<O[K]>[0], ...any[]]) => _F<O[K]>[1] {
const func = base[key];
if (typeof func !== 'function') {
throw new Error(
`Cannot rewrite variable with type of '${typeof func}'.`
);
}
if (type === 'full') {
// @ts-ignore
return (base[key] = re.bind(rebind ?? base));
} else if (type === 'add') {
const origin = base[key];
function res(this: T, ...params: [..._F<O[K]>[0], ...any[]]) {
const v = (origin as _Func).call(bind ?? base, ...params);
// @ts-ignore
const ret = re.call(rebind ?? base, v, ...params);
return ret;
}
// @ts-ignore
return (base[key] = res);
} else {
const origin = base[key];
function res(this: T, ...params: [..._F<O[K]>[0], ...any[]]) {
// @ts-ignore
2024-02-01 19:31:49 +08:00
re.call(rebind ?? base, ...params);
2024-01-27 22:45:07 +08:00
const ret = (origin as _Func).call(bind ?? base, ...params);
return ret;
}
// @ts-ignore
return (base[key] = res);
}
}
2024-02-01 19:31:49 +08:00
/**
*
* ui显示
* @param fn `Mota.Package.requireAll()`
* @param thisArg `this`
*/
function r<T = undefined>(
fn: (this: T, packages: PackageInterface) => void,
thisArg?: T
) {
if (!main.replayChecking) fn.call(thisArg as T, MPackage.requireAll());
}
/**
* {@link r}
* `call``bind`
* ```ts
* const fn = rf((x) => x * x);
* console.log(fn(2)); // 在正常游玩中会输出 4但是录像验证中会输出undefined因为录像验证中不会执行渲染进程函数
* ```
* @param fn
* @param thisArg this指向
* @returns
*/
function rf<F extends (...params: any) => any, T>(
fn: F,
thisArg?: T
): (this: T, ...params: Parameters<F>) => ReturnType<F> | undefined {
// @ts-ignore
if (main.replayChecking) return () => {};
else {
return (...params) => {
return fn.call(thisArg, ...params);
};
}
}
2024-01-24 21:32:49 +08:00
declare global {
interface Window {
Mota: IMota;
}
}
window.Mota = Mota;