From 483df57fdff628b023133c0a57a4675e72b705bc Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Sat, 27 Jan 2024 22:45:07 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A4=8D=E5=86=99api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/game/system.ts | 301 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 265 insertions(+), 36 deletions(-) diff --git a/src/game/system.ts b/src/game/system.ts index 1703fb0..1353a2f 100644 --- a/src/game/system.ts +++ b/src/game/system.ts @@ -95,7 +95,14 @@ interface SystemInterfaceMap { type InterfaceType = keyof SystemInterfaceMap; +interface PluginInterface {} + export interface IMota { + rewrite: typeof rewrite; + rewriteSys: typeof rewriteSys; + + Plugin: IPlugin; + /** * 获取一个样板接口 * @param type 要获取的接口类型 @@ -138,6 +145,131 @@ export interface IMota { register(type: InterfaceType, key: string, data: any): void; } +export interface IPlugin { + /** + * 初始化所有插件 + */ + init(): void; + /** + * 初始化指定插件 + * @param plugin 要初始化的插件 + */ + init(plugin: string): void; + + /** + * 获取到一个插件的内容 + * @param plugin 要获取的插件 + */ + require(plugin: K): PluginInterface[K]; + /** + * 获取到一个插件的内容 + * @param plugin 要获取的插件 + */ + require(plugin: string): any; + + /** + * 获取所有插件 + */ + requireAll(): PluginInterface; + + /** + * 注册一个插件 + * @param plugin 要注册的插件名 + * @param data 插件内容 + * @param init 插件的初始化函数,可选,初始化函数接受两个参数,分别是plugin和data,表示插件名称和内容 + */ + register( + plugin: K, + data: PluginInterface[K], + init?: (plugin: K, data: PluginInterface[K]) => void + ): void; + /** + * 注册一个插件 + * @param plugin 要注册的插件名 + * @param init 插件的初始化函数,初始化函数接受一个参数,表示插件名称,要求返回插件内容 + */ + register( + plugin: K, + init: (plugin: K) => PluginInterface[K] + ): void; + /** + * 注册一个插件 + * @param plugin 要注册的插件名 + * @param data 插件内容 + * @param init 插件的初始化函数,可选,初始化函数接受两个参数,分别是plugin和data,表示插件名称和内容 + */ + register( + plugin: K, + data: D, + init?: (plugin: K, data: D) => void + ): void; + /** + * 注册一个插件 + * @param plugin 要注册的插件名 + * @param init 插件的初始化函数,初始化函数接受一个参数,表示插件名称,要求返回插件内容 + */ + register(plugin: K, init: (plugin: K) => any): void; +} + +interface IPluginData { + /** 插件类型,content表示直接注册了内容,function表示注册了初始化函数,内容从其返回值获取 */ + type: 'content' | 'function'; + data: any; + init?: (plugin: string, data?: any) => any; +} + +class MPlugin { + private static plugins: Record = {}; + private static inited = false; + private static pluginData: Record = {}; + + 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; + } + + static requireAll() { + return this.pluginData; + } + + 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 + }; + } + } +} + /** * 样板接口系统,通过 Mota 获取到样板的核心功能,不可实例化 */ @@ -146,25 +278,14 @@ class Mota { private static functions: Record = {}; private static variables: Record = {}; + static rewrite = rewrite; + static rewriteSys = rewriteSys; + static Plugin = MPlugin; + constructor() { throw new Error(`System interface class cannot be constructed.`); } - /** - * 获取一个样板接口 - * @param type 要获取的接口类型 - * @param key 接口名称 - */ - static require< - T extends InterfaceType, - K extends keyof SystemInterfaceMap[T] - >(type: T, key: K): SystemInterfaceMap[T][K]; - /** - * 获取一个样板接口 - * @param type 要获取的接口类型 - * @param key 接口名称 - */ - static require(type: InterfaceType, key: string): any; static require(type: InterfaceType, key: string): any { const data = this.getByType(type)[key]; if (!!data) return data; @@ -175,31 +296,10 @@ class Mota { } } - /** - * 获取一种接口的所有内容 - * @param type 要获取的接口类型 - */ static requireAll(type: T): SystemInterfaceMap[T] { return this.getByType(type) as SystemInterfaceMap[T]; } - /** - * 注册一个样板接口 - * @param type 要注册的接口类型 - * @param key 接口名称 - * @param data 接口内容 - */ - static register< - T extends InterfaceType, - K extends keyof SystemInterfaceMap[T] - >(type: T, key: K, data: SystemInterfaceMap[T][K]): void; - /** - * 注册一个样板接口 - * @param type 要注册的接口类型 - * @param key 接口名称 - * @param data 接口内容 - */ - static register(type: InterfaceType, key: string, data: any): void; static register(type: InterfaceType, key: string, data: any) { const obj = this.getByType(type); if (key in obj) { @@ -219,6 +319,135 @@ class Mota { } } +type RewriteType = 'full' | 'front' | 'add'; +type _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 + */ +function rewrite, T = O>( + base: O, + key: K, + type: 'full' | 'front', + re: (this: T, ...params: [..._F[0], ...any[]]) => _F[1], + bind?: any, + rebind?: T +): (this: T, ...params: [..._F[0], ...any[]]) => _F[1]; +/** + * 在函数后追加内容 + * @param base 函数所在对象 + * @param key 函数名称,即函数在base中叫什么 + * @param type 复写类型,add表示在函数后追加 + * @param re 复写函数,类型为add时表示在原函数后面追加复写函数,会在第一个参数中传入原函数的返回值, + * 并要求复写函数必须有返回值,作为复写的最终返回值。 + * @param bind 原函数的调用对象,默认为base + * @param rebind 复写函数的调用对象,默认为base + */ +function rewrite, T = O>( + base: O, + key: K, + type: 'add', + re: ( + this: T, + ...params: [_F[1], ..._F[0], ...any[]] + ) => _F[1], + bind?: any, + rebind?: T +): (this: T, ...params: [..._F[0], ...any[]]) => _F[1]; +function rewrite, T = O>( + base: O, + key: K, + type: RewriteType, + re: (this: T, ...params: [..._F[0], ...any[]]) => _F[1], + bind?: any, + rebind?: T +): (this: T, ...params: [..._F[0], ...any[]]) => _F[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[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[0], ...any[]]) { + // @ts-ignore + re.call(rebind ?? base, v, ...params); + const ret = (origin as _Func).call(bind ?? base, ...params); + return ret; + } + // @ts-ignore + return (base[key] = res); + } +} + +type _FI = FunctionInterface[K]; + +/** + * 全量复写系统函数或在系统函数函数前添加内容 + * @param key 系统函数名称 + * @param type 复写类型,full表示全量复写,front表示在原函数之前添加内容 + * @param re 复写函数,类型为full时表示将原函数完全覆盖,为front时表示将该函数添加到原函数之前 + * @param bind 原函数的调用对象,默认为base + * @param rebind 复写函数的调用对象,默认为base + */ +function rewriteSys( + key: K, + type: 'full' | 'front', + re: (this: T, ...params: [..._F<_FI>[0], ...any[]]) => _F<_FI>[1], + bind?: any, + rebind?: T +): (this: T, ...params: [..._F<_FI>[0], ...any[]]) => _F<_FI>[1]; +/** + * 在系统函数后追加内容 + * @param key 系统函数名称 + * @param type 复写类型,add表示在函数后追加 + * @param re 复写函数,类型为add时表示在原函数后面追加复写函数,会在第一个参数中传入原函数的返回值, + * 并要求复写函数必须有返回值,作为复写的最终返回值。 + * @param bind 原函数的调用对象,默认为base + * @param rebind 复写函数的调用对象,默认为base + */ +function rewriteSys( + key: K, + type: 'add', + re: ( + this: T, + ...params: [_F<_FI>[1], ..._F<_FI>[0], ...any[]] + ) => _F<_FI>[1], + bind?: any, + rebind?: T +): (this: T, ...params: [..._F<_FI>[0], ...any[]]) => _F<_FI>[1]; +function rewriteSys( + key: K, + type: RewriteType, + re: (this: T, ...params: [..._F<_FI>[0], ...any[]]) => _F<_FI>[1], + bind?: any, + rebind?: T +): (this: T, ...params: [..._F<_FI>[0], ...any[]]) => _F<_FI>[1] { + // @ts-ignore + return rewrite(Mota.requireAll('fn'), key, type, re, bind, rebind); +} + declare global { interface Window { Mota: IMota;