- Source of resources
- Original
- Copyright link
- #
- Language
- Chinese(Simplified)
- Supported version
- The latest version
开源万岁(允许魔改与商用,但必须注明出处:<首发平台minebbs,作者KING>)
写在前面的话:
1、咳咳,毫不低调的说,这是LXL第一款JS开发框架
2、设计这个框架时一开始仿造了 Vue2 的风格,后面又融入了 Java 的一些风格,他本身是基于面向对象的方式。它支持【继承】【接口式编程】【全局引用】【切面编程】【插件互调】【注解式开发】
3、它的核心思想是把你的插件交它给进行管理,他会对你的插件进行整理。它相当于是一个容器。因此它可以实现原版js无法实现的一些功能。同时如果你 Js 功底和 Java 功底很强,你甚至可以设计出基于反射的插件。(所有的功能都是牺牲了一定性能实现,特别是面向切面编程,也不用担心,没牺牲多少)
3、在 LiteXLoader(简称LXL)的 0.5.12 版本之后,LXL嵌入LiteLoader(简称LL)内,并且改名为LiteLoaderBDS(简称LLBDS),因此如果你不懂什么是 LXL,请先了解什么是 LXL 之后在着手 DoAsVue。 LXL架构url:LXL架构 (某些地区可能无法访问)
======================
下面这里是写给我自己看的,,,,
待解决:
(3)加载辅助插件的方法优化,辅助插件更多的指令
(5)尽量添加对真指令的支持,简化真指令的创建(技术有限)
(6)Math的时间间隔计算有bug,不允许出现 0000-00..格式
======================
【需求描述】
当开发复杂的插件系统时,通常会面临这样的问题:
1、要么将所有功能写入同一个插件,使得插件极其庞大复杂,少则数百行,多则上千行
2、要么将插件拆分为模块,但是非常麻烦,并且插件之间无法共享变量与配置文件
3、后期代码过多不易维护,并且还可能涉及到修改源码,破坏原本的插件
4、很多代码都是重复的,没法复用
5、LXL原版错误信息不准确
6、原版的开发方式低效不易阅读与维护
【DoAsVue优点】
1、插件整合:支持将所编写插件整合到DoAsVue.lxl.js主运行插件内,意味着你可以将大型插件系统拆分为模块进行解耦
2、支持插件之间相互调用,共享变量以及配置文件共享,意味着多个插件之间可以实现数据共享,配置文件共享,方法共享等
3、提供切面编程:支持执行前插入,执行时插入,执行返回前插入,意味着在不修改其他插件情况下对其他插件的method进行非入侵式修改,即:执行前触发执行,执行时修改参数,执行返回前修改执行结果
4、支持继承,因此可以用它实现模板式开发与插件复用,甚至还可以实现接口式开发
5、完全运行于LXL,不使用第三方库与包
6、内部封装了独有的错误栈追踪,可以很精确找到插件错误位置(除了LXL自身引发的错误外)
7、支持注解与反射使得开发更加高效与易维护,可以理解为DoAsVue就是LXL中的低配版Java
8、由于高度的封装,DoAsVue实现了统一接口管理,再结合注解与反射,可以对此轻易实现模板化开发、高低版本兼容开发。
【DoAsVue插件开发前提】
1、掌握LXL(js)插件开发
2、扎实的js基础,最好是掌握 js
3、了解切面编程、了解代理模式
4、熟悉封装与继承
5、熟悉面向对象编程
【DoAsVue执行逻辑】
1、整体执行逻辑:
* a、LXL加载DoAsVue.lxl.js
* b、DoAsVue.lxl.js递归扫描配置文件config.json指定的plugins目录下所有davue插件
* c、DoAsVue.lxl.js加载按照DoAsVue规范编写的js插件
2、DoAsVue的js插件被加载流程:
【DoAsVue说明】
DoAsVue结构简述
除了data()数据域是必要的,其他的可以不必要
当然,在1.10.22版本之后新增了对class的支持,结构也可以如下定义:
需要注意的是,框架使用的是无参构造进行对象创建,因此最好就是不要创建有参构造函数
1、DoAsVue结构插件模板如下:
"template_plugin1.DAVue.js"举例
"template_plugin2.DAVue.js"举例,它将引用上面的"template_plugin1.DAVue.js"
以上两个插件运行结果:
上面这个样例使用的是【aspect】实现,但是由于篇幅原因,这里不详细展开说
################################################
详细说明:
【继承功能】
extends:DoAsVue规范插件允许继承功能,即插件 A 可以继承插件 B 的 date属性 与 methods方法,可以达到继承与复用的逻辑
例如 A.DoAsVue.js 继承了 B.DoAsVue.js ,则 B 会拷贝 data 与 methods 给 A,这是副本拷贝,A 改变不会影响到 B,请放心。
说明:
. 1、如果子插件 A 继承父插件 B,但是又重写了父插件 B 的方法或者属性值,那么不会影响到父插件 B,只会影响到自己,例如 A 继承了 B,B有一个m方法,因此A也会有一个m方法,和B的m方法一模一样。但是如果你重写了该方法,那么只会影响到 A 的 m ,不会影响 B 的 m。
. 2、如果 B 的方法被其他插件切面修改,不会影响到子插件 A 进行继承原版功能。即切面不影响继承。
. 3、如果 B 的 m 方法使用了一个在 B 之外定义的全局变量,会影响到 A 继承的 m 方法,即当 B 的 m 方法修改了这个全局变量,也会影响到 A 的 m 方法内的全局变量数值。
4、私有属性与方法:凡是以"_"开头的属性或方法都属于私有的,不会继承给子插件
5、访问控制(详情查看底下的修饰符前缀)
用法:直接 extends:"父插件名称" 即可
【全局域】
global:
1、DoAsVue规范插件允许定义全局变量,在所有DoAsVue插件内均可直接调用,由于它相当于全局静态变量(也可以是function),因此它不支持将和this相关的变量赋予他,仅允许使用常量或者其他变量;
2、它可以定义全局变量,因为利用的是全局this进行添加,因此它甚至可以重写全局已经存在的,例如log,mc,logger等
3、用法:
然后在任何DAVue插件内直接使用 key1或key2 直接使用该变量
【引用域】
require:
在插件内的require里可以填写引用的其他DAVue插件,例如
之后可以通过this.otherPlugin.xxx来调用被引用对象的methods。
在最新版本中(1.12.25之后)已经屏蔽了直接访问data内的属性值,但是DAVue插件会自动对data内的所有属性值添加set与get方法,例如otherPlugin中如果data里有一个叫做value的属性值,则require使用这个value的方法为:
【修饰符前缀】
修饰符前缀:即在data的属性值或methods方法前面添加前缀可以设置控制访问权限
private__:仅插件自身可直接调用,其他不能调用
protection__:插件自身、继承的子类直接调用,其他不能调用
无前缀:插件自身、继承的子类、其他插件引用均可直接调用
注:
1、在旧版本里有一个规定," _ " 前缀的方法用法与 private__ 一致,但是为了兼容旧版本保留了该规定,但是未来会逐渐删除该规定。
2、注意 private__ 与 protection__ 是两个下划线
【注解annotation与反射reflect】
在1.15.43版本之后,DoAsVue支持注解与反射开发,就像Java的效果一样(只能针对method进行注解)
之后在1.15.48之后支持了元注解,旧版本的注解方式已经被隐藏,感兴趣的小伙伴可以去【plugins\DoAsVue_LXL\KING\DoAsVue\plugins\_Demos\_reflectAndAnnotationDemo】下查看
现在完全采取元注解的方式来实现自定义注解。
由于”自定义注解“功能强大,(与aspect一样,也是采用了代理的方式实现的),因此它可以完全代替aspect与旧版的注解的开发方式了(但是为了兼容旧版本,依旧保留了旧版本的规范,同时需要注意,aspect的优先级大于注解)
如代码:
如何自定义注解一个注解
步骤1、继承“BaseAnnotationOperator”
步骤2、使用 @annotation 对一个 fun(method,methodName,annotationInfo,module,...args) 格式的方法进行标注
步骤3、编写方法内容
步骤4、@fun注解完成
如何使用自定义注解:在任意一个method内使用即可
@argMustBeInteger 注解已经添加到了注解库,现在可以直接使用了,在不久之后,我会逐步完善这个注解库,有兴趣的小伙伴也可以提出建议
当参数不是整数时会直接报错(当然,你也可以根据demo,写一个不一定非得报错的注解,我这里只是举例)
注:
1、所有自定义注解的子插件的必须继承 ” BaseAnnotationOperator ”
2、注解格式为:
【@Bean与@Autowired】
这个是我自己仿造 Spring IOC 做的一个小案例,利用注解实现的自动注入bean
源码在 DoAsVue源码附件
执行结果:
【自动对外暴露接口与davue指令】
DoAsVue会自动对子插件添加对外暴露接口,方便其他非davue的第三方插件进行调用
该暴露接口规则遵循require规则,即被修饰符前缀限制的依旧无法访问,依旧可以通过get、set来访问子插件的data属性
需要注意的是,这些接口仅允许调用,由于LXL与bds的运行机制原因,暂时无法返回调用结果
关于davue命令:
最新指令详情请前往控制台输入 davue
【其他说明】
1、DoAsVue插件内直接使用this.logger(msg,type)即可使用日志;type: info/warning/error/debug/fatal
2、对于 A 继承 C,B 继承 C,则C可以通过this.children获取继承的子类列表,而 A 和 B 可以通过this.super拿到父类。
3、DoAsVue不会扫描带有 _ 开头的文件夹,以及js文件,因为以 _ 开头的 js 文件或者文件夹都表示废弃(可以用来装垃圾。。。。)
4、由于所有插件继承BaseObject,因此可以快速打印信息,使用 this.print(msg) 即可,强烈建议不要使用 log 。另外还提供了 this.printObject(obj)可以打印 object 对象(都会记录到日志文件,供维护查看)
5、所有的DoAsVue子插件均可以通过this.self拿到自身的属性,比如自身文件路径,插件名称,被其他插件require的情况。详情使用this.printObject(this.self)查看
【用法】
1、解压到plugins下,解压之后会得有一个DoAsVue.lxl.js的主运行插件,他是负责整合与运行符合DoAsVue规范的插件,把它放在plugins目录下(解压之后有 DoAsVue.lxl.js文件 以及 KING文件夹)
2、在他被第一次运行时会在/plugins/KING/DoAsVue/下生成config.json,里面默认在/plugins/KING/DoAsVue/plugins/下存放所有的DoAsVue规范插件,因为是递归扫描该文件夹,所以你可以在这个目录下进行插件分类存放,便于后期维护。例如你的库相关插件可以放在该目录下的 lib 下
3、开发符合DoAsVue规范的插件,并放到配置文件所指定的目录下(这个目录不能是/plugins下,切记,因为他不是一个LXL插件),这个目录默认是/plugins/KING/DoAsVue/plugins/
4、开服
简而言之:
1、下载之后解压到plugins下
2、编写好你自己的DoAsVue插件(规范都在上面有说明,不会的可以找我)
3、把你的DoAsVue插件放到 /plugins/KING/DoAsVue/plugins/ 下
4、开服
【附赠的插件说明】
在./plugins/KING/DoAsVue/plugins/lib/内,DoAsVue子插件可以直接调用
1、【Lib_MathCal】
这是一个带有数学公式的库,目前还在扩充
2、【DataBuffer】
这是一个全局数据缓存池,用于运行时存储缓存数据,相当于Map全局变量
3、【ObjectHelper】
这是一个用于js的object操作的常用辅助库插件
4、【StringHelper】
这是一个用于 js 的字符串操作的常用辅助库插件
5、【Nbt_PlayerAbilities】
这是一个操作玩家权限的辅助库插件,相当于修改游戏暂停键内那些权限:1建造权 、2破坏权、3使用开关、4打开容器 、5攻击玩家 、6攻击生物(不支持修改 传送权 与 命令使用权);不同于事件拦截,它基于修改nbt实现的
6、【SidebarHelper】
这是一个可以很方便快且捷定制侧边栏的辅助插件,用法在插件底部有说明
7、【NBTHelper】
这是一个可以快速将nbt/snbt转jsobj并且还能自动还原为nbt/snbt的nbt助手,详情用法在该插件底部
8、【EnchantHelper】
这是一个用于附魔辅助的插件库,具备标准附魔查询,违规附魔检测等功能。详情查看lib下的EnchantHelper.DAVue.js
9、【AnnotationLib】
这是一个注解库,你直接拿来即用,从而减少无用代码的编写。开发就是把你的有限的精力放在重要的业务上,而不是写代码本身。这个注解库在逐步完善中
【写在后面的话】
问:这个到底是什么?
答:这个是一个提供将大型插件拆分为模块的插件框架,即运行插件的插件
问:我为什么非得用他开发插件,之前的开发不好吗?
答:如果是简单的功能性插件,您可以按照自己的开发习惯,但是如果您开发的插件系统功能比较多而杂乱,我推荐您使用它(DoAsVue),我只是提供了另一种开发规范与思路
问:他和一般的插件开发有什么区别?
答:区别就是他提供了插件分割思路,与一般的单个的插件不一样,它仿造VueJs与Java的风格与方式,把各个功能和数据进行拆分与整合,按照LXL提供的接口正常开发,它允许每个被加载的插件相互调用,数据共享,以及配置文件共享(有效保证多个插件的对同一个变量或者配置文件进行正确读写操作)。
设计不易,请多多支持,给自己点个赞
写在前面的话:
1、咳咳,毫不低调的说,这是LXL第一款JS开发框架
2、设计这个框架时一开始仿造了 Vue2 的风格,后面又融入了 Java 的一些风格,他本身是基于面向对象的方式。它支持【继承】【接口式编程】【全局引用】【切面编程】【插件互调】【注解式开发】
3、它的核心思想是把你的插件交它给进行管理,他会对你的插件进行整理。它相当于是一个容器。因此它可以实现原版js无法实现的一些功能。同时如果你 Js 功底和 Java 功底很强,你甚至可以设计出基于反射的插件。(所有的功能都是牺牲了一定性能实现,特别是面向切面编程,也不用担心,没牺牲多少)
3、在 LiteXLoader(简称LXL)的 0.5.12 版本之后,LXL嵌入LiteLoader(简称LL)内,并且改名为LiteLoaderBDS(简称LLBDS),因此如果你不懂什么是 LXL,请先了解什么是 LXL 之后在着手 DoAsVue。 LXL架构url:LXL架构 (某些地区可能无法访问)
======================
下面这里是写给我自己看的,,,,
待解决:
(3)加载辅助插件的方法优化,辅助插件更多的指令
(5)尽量添加对真指令的支持,简化真指令的创建(技术有限)
(6)Math的时间间隔计算有bug,不允许出现 0000-00..格式
======================
【需求描述】
当开发复杂的插件系统时,通常会面临这样的问题:
1、要么将所有功能写入同一个插件,使得插件极其庞大复杂,少则数百行,多则上千行
2、要么将插件拆分为模块,但是非常麻烦,并且插件之间无法共享变量与配置文件
3、后期代码过多不易维护,并且还可能涉及到修改源码,破坏原本的插件
4、很多代码都是重复的,没法复用
5、LXL原版错误信息不准确
6、原版的开发方式低效不易阅读与维护
【DoAsVue优点】
1、插件整合:支持将所编写插件整合到DoAsVue.lxl.js主运行插件内,意味着你可以将大型插件系统拆分为模块进行解耦
2、支持插件之间相互调用,共享变量以及配置文件共享,意味着多个插件之间可以实现数据共享,配置文件共享,方法共享等
3、提供切面编程:支持执行前插入,执行时插入,执行返回前插入,意味着在不修改其他插件情况下对其他插件的method进行非入侵式修改,即:执行前触发执行,执行时修改参数,执行返回前修改执行结果
4、支持继承,因此可以用它实现模板式开发与插件复用,甚至还可以实现接口式开发
5、完全运行于LXL,不使用第三方库与包
6、内部封装了独有的错误栈追踪,可以很精确找到插件错误位置(除了LXL自身引发的错误外)
7、支持注解与反射使得开发更加高效与易维护,可以理解为DoAsVue就是LXL中的低配版Java
8、由于高度的封装,DoAsVue实现了统一接口管理,再结合注解与反射,可以对此轻易实现模板化开发、高低版本兼容开发。
【DoAsVue插件开发前提】
1、掌握LXL(js)插件开发
2、扎实的js基础,最好是掌握 js
3、了解切面编程、了解代理模式
4、熟悉封装与继承
5、熟悉面向对象编程
【DoAsVue执行逻辑】
1、整体执行逻辑:
* a、LXL加载DoAsVue.lxl.js
* b、DoAsVue.lxl.js递归扫描配置文件config.json指定的plugins目录下所有davue插件
* c、DoAsVue.lxl.js加载按照DoAsVue规范编写的js插件
2、DoAsVue的js插件被加载流程:
Code:
执行流程:
0、初始化子插件,进行必要的数据搜集与整理
1、初始化全局域,添加全局变量
2、初始化继承
3、创建data数据域
4、建立require引用
5、建立methods方法域
6、注入注解,执行注解逻辑
7、创建aspect切面,并插入切面
8、建立listen监听事件
9、注册命令
10、执行入口main
DoAsVue结构简述
JavaScript:
var plugin = {
data(){
return{ //数据域、属性域
}
},
global:{
testkey:"testvalue", //所有DoAsVue插件可访问该变量,直接使用,例如log(testkey)
},
extends:null, //继承,可以继承其他DoAsVue插件,只能继承一个 extends:"插件名称"
require:{ //引用域,可以用其他DoAsVue插件
},
methods:{ //方法域,可以定义方法(函数),这里的方法可以被切面修改,带有 _ 前缀的算作私有方法
//这里的方法可以写到methods外边,但是不会被继承,即,写到外边的也算是私有方法
//如果外边的方法与methods内的方法名重复,会被methods内的覆盖
},
MCListen:{ //监听域,就和mc.listen一样
},
MCPlayerCmd:{ //注册玩家命令
},
MCConsoleCmd:{ //注册控制台命令
},
aspect:{ //切面域,可以对引用的插件methods进行切面修改(会影响到被切面的插件的methods正常执行)
},
main(){ //主动执行入口,一般用来初始化
//当main返回一个函数时,例如return ()=>{ /*todo*/ } 它表示是在所有插件执行完毕main之后执行该返回函数;
//有时候会有这种需求,比如在main调用其他插件时,但是其他插件可能这个时候并未初始化完毕,直接调用会出现数据不存在引发的undefined错误,因此需要等待他们都初始化完毕之后再执行。
}
}
module.exports={
name:"template_plugin1", //表示这个插件的名字,用于被其他插件引用时的名字
plugin:plugin//当前导出的创建对象
}
当然,在1.10.22版本之后新增了对class的支持,结构也可以如下定义:
需要注意的是,框架使用的是无参构造进行对象创建,因此最好就是不要创建有参构造函数
JavaScript:
//LiteXLoader Dev Helper
/// <reference path="c:\Users\KING\.vscode\extensions\moxicat.lxldevhelper-0.1.4/Library/JS/Api.js" />
//新增对 class 的支持,目的就是为了更好的使用继承。因此你可以在这里使用 require导入其他的class,然后继承
//就像平常一样使用class
//例如 let yourclass = require (你的class路径),然后继承你的class即可
var plugin = class Plugin{
data(){
return{
}
};
global={
testkey:"testvalue",
};
extends=null;
require={
};
methods={
};
MCListen={
};
MCPlayerCmd={
};
MCConsoleCmd={
};
aspect={
};
main(){
this.print("DoAsVue启动 \\ \\ \\\\q( 'ω' )p// / /")
}
}
//导出规范
module.exports={
name : "classtemp", //表示这个插件的名字,用于被其他插件引用时的名字
plugin : plugin //导出当前的class
}
1、DoAsVue结构插件模板如下:
"template_plugin1.DAVue.js"举例
JavaScript:
//LiteXLoader Dev Helper
/// <reference path="c:\Users\KING\.vscode\extensions\moxicat.lxldevhelper-0.1.4/Library/JS/Api.js" />
/**
执行流程:
1、初始化全局域
2、执行继承初始化
3、创建data数据域
4、建立require引用
5、建立methods方法域
6、创建aspect切面,并插入切面
7、建立listen监听事件
8、注册命令
9、执行入口main
*/
var plugin = {
data(){
return{
name:"template plugin 1",//任意的数据
}
//定义数据域
//用法,直接在以下的每个区域this.XXX即可使用,例如 this.name
},
require:{
//引用域
//引用别的模块
// plugin1:plugin1,
// plugin2:plugin2,
// plugin3:plugin3,
// ....
//用法,直接在以下的每个区域this.plugin1即可使用另一个插件
},
methods:{
//自定义方法域
//fun:(paramater){}
//用法,直接在以下的每个区域this.fun(xxx)即可使用,例如this.add(123,456)
show:function(){
log("这里是 "+this.name+" 的函数show()")
},
add(num1,num2){
return num1+num2;
}
},
MCListen:{
//监听域
//监听事件区,即mc.listen()
//用法:例如:onMove:(player){}
},
MCPlayerCmd:{ //注册玩家命令,详情请查看template_plugin2.DAVue.js
},
MCConsoleCmd:{ //注册控制台命令,详情请查看template_plugin2.DAVue.js
},
aspect:{
//切面域
//如何“切开”其他的plugin请查看template_plugin2.js
//支持:执行前,执行时,执行完毕返回前
// 插件名称:{ //详情查看template_plugin2.DAVue.js
// before:{
// //todo
// },
// beforeRun:{
// //todo
// },
// beforeReturn:{
// //todo
// }
// }
},
main(){
//主动执行的入口,即在当前插件一切准备就绪之后主动执行
//只能执行methods内的方法
log("\n--------"+this.name+" main--------")
this.show()
var result = this.add(1000,2000);
log("1000+2000结果是:"+result);//这里结果是6000,因为被template_plugin2切面修改了
log("--------"+this.name+" main--------\n")
}
}
//导出规范
module.exports={
name:"template_plugin1", //表示这个插件的名字,用于被其他插件引用时的名字
plugin:plugin//当前导出的创建对象
}
//++++++++++++++++++++++++++++++++//
//插件模块之间协调与调用请查看template_plugin2.js
//++++++++++++++++++++++++++++++++//
"template_plugin2.DAVue.js"举例,它将引用上面的"template_plugin1.DAVue.js"
JavaScript:
//LiteXLoader Dev Helper
/// <reference path="c:\Users\KING\.vscode\extensions\moxicat.lxldevhelper-0.1.4/Library/JS/Api.js" />
var plugin = {
data(){
return{
name:"template plugin 2",//自定义数据data
}
},
require:{
plugins1:"template_plugin1" //引用template_plugin1插件
},
methods:{
fun:function(){
log("这里是:"+this.name)
log("在template_plugin 2里执行template_plugin 1的函数")
this.plugins1.show();//使用别的plugins方法
log("获取到 "+this.require.plugins1+" 的data数据:"+this.plugins1.name);//使用别的plugins数据
}
},
MCListen:{
onJump:function(player){
log("当前执行监听跳跃事件的插件是:"+this.name)
log(player.realName+" 跳了一下")
}
},
MCPlayerCmd:{ //注册玩家命令
hello:{ //名称
cmd:"hello",//注册的命令
permission:0, //权限等级
description:"说hello", //命令说明
event:function(player,args){ //执行的函数
player.tell("玩家你好你好")
}
}
},
MCConsoleCmd:{ //注册控制台命令
consoleHello:{
cmd:"console hello",
description:"你好",
event:function(args){
log("控制台你好")
}
}
},
aspect:{
/**
所谓切面,即在不直接修改其他插件的method源码前提下修改这个method
*/
//注:只能对其他插件的methods进行切入与修改
//支持多重切入
//但是至于同一个插件被多个插件进行切面的优先等级,理论上是取决于被DoAsVue.lxl.js加载的顺序(File.getFilesList)
plugins1:{
before:{
//这个表示在plugins1插件模块执行add()方法之前先执行当前方法
add:function(){
log(this.require.plugins1+" 执行add前插入了一个函数")
}
},
beforeRun:{
//这个表示在plugins插件模块执行add()时,拦截他的传入参数,并允许修改
add:function(...args){ //这里也可以换成 add:function(num1,num2),返回时需要返回数组[num1,num2]
//args:传入show的数据
log(this.require.plugins1+" 执行add时,接收到的参数:"+args)
args[1]=5000;
log("现在修改为: "+args)
return args;
//切记要返回参数,否则被切面的函数会得不到参数
}
},
beforeReturn:{
//这个表示在plugins插件模块执行add()完毕之后,即将要返回结果之前,拦截他的返回结果,通过修改result,可以修改返回结果
add:function(result){
//result:执行完毕之后的结果
log(this.require.plugins1+" 执行add返回前,结果应该是"+result+",但是现在修改为6666")
result=6666;
//add返回的数据
return result;
}
}
}
},
main(){
log("\n--------"+this.name+" main--------")
this.fun()
log("--------"+this.name+" main--------\n")
},
}
//导出规范
module.exports={
name:"template_plugin2",
plugin:plugin
}
以上两个插件运行结果:
上面这个样例使用的是【aspect】实现,但是由于篇幅原因,这里不详细展开说
################################################
详细说明:
【继承功能】
extends:DoAsVue规范插件允许继承功能,即插件 A 可以继承插件 B 的 date属性 与 methods方法,可以达到继承与复用的逻辑
例如 A.DoAsVue.js 继承了 B.DoAsVue.js ,则 B 会拷贝 data 与 methods 给 A,这是副本拷贝,A 改变不会影响到 B,请放心。
说明:
. 1、如果子插件 A 继承父插件 B,但是又重写了父插件 B 的方法或者属性值,那么不会影响到父插件 B,只会影响到自己,例如 A 继承了 B,B有一个m方法,因此A也会有一个m方法,和B的m方法一模一样。但是如果你重写了该方法,那么只会影响到 A 的 m ,不会影响 B 的 m。
. 2、如果 B 的方法被其他插件切面修改,不会影响到子插件 A 进行继承原版功能。即切面不影响继承。
. 3、如果 B 的 m 方法使用了一个在 B 之外定义的全局变量,会影响到 A 继承的 m 方法,即当 B 的 m 方法修改了这个全局变量,也会影响到 A 的 m 方法内的全局变量数值。
4、私有属性与方法:凡是以"_"开头的属性或方法都属于私有的,不会继承给子插件
5、访问控制(详情查看底下的修饰符前缀)
用法:直接 extends:"父插件名称" 即可
JavaScript:
var plugin = {
data(){
return{
obj:{
a:1,
b:2
}
}
},
extends:null,
methods:{
m(){
log("这里是父类")
}
},
main(){
this.m();
}
}
//导出规范
module.exports={
name:"B", //表示这个插件的名字,用于被其他插件引用时的名字
plugin:plugin//当前导出的创建对象
}
//-------------------------------------------------------------------------------
var plugin = {
data(){
return{
}
},
extends:"B",
methods:{
},
main(){
log("继承B的obj:")
log(this.obj)
log("执行继承于父插件的m方法:")
this.m();
}
}
//导出规范
module.exports={
name:"A", //表示这个插件的名字,用于被其他插件引用时的名字
plugin:plugin//当前导出的创建对象
}
【全局域】
global:
1、DoAsVue规范插件允许定义全局变量,在所有DoAsVue插件内均可直接调用,由于它相当于全局静态变量(也可以是function),因此它不支持将和this相关的变量赋予他,仅允许使用常量或者其他变量;
2、它可以定义全局变量,因为利用的是全局this进行添加,因此它甚至可以重写全局已经存在的,例如log,mc,logger等
3、用法:
JavaScript:
global:{
key1:value1,
key2:value2,
....
}
【引用域】
require:
在插件内的require里可以填写引用的其他DAVue插件,例如
JavaScript:
require:{
otherPlugin : "otherPlugin"
}
在最新版本中(1.12.25之后)已经屏蔽了直接访问data内的属性值,但是DAVue插件会自动对data内的所有属性值添加set与get方法,例如otherPlugin中如果data里有一个叫做value的属性值,则require使用这个value的方法为:
JavaScript:
this.otherPlugin.getValue();
this.otherPlugin.setValue(newValue);
//需要注意的是,如果otherPlugin本身就存在set与get方法,则不会自动添加
【修饰符前缀】
修饰符前缀:即在data的属性值或methods方法前面添加前缀可以设置控制访问权限
private__:仅插件自身可直接调用,其他不能调用
protection__:插件自身、继承的子类直接调用,其他不能调用
无前缀:插件自身、继承的子类、其他插件引用均可直接调用
注:
1、在旧版本里有一个规定," _ " 前缀的方法用法与 private__ 一致,但是为了兼容旧版本保留了该规定,但是未来会逐渐删除该规定。
2、注意 private__ 与 protection__ 是两个下划线
JavaScript:
var plugin = {
data(){
return{
private__value1:"abc", //仅自身可以访问
protection__value1:"abc", //仅自身和子插件可以访问
}
},
extends:null,
methods:{
private__Fun(){
},
protection__Fun(){
},
},
main(){
}
}
//导出规范
module.exports={
name:"Temp", //表示这个插件的名字,用于被其他插件引用时的名字
plugin:plugin//当前导出的创建对象
}
【注解annotation与反射reflect】
在1.15.43版本之后,DoAsVue支持注解与反射开发,就像Java的效果一样(只能针对method进行注解)
之后在1.15.48之后支持了元注解,旧版本的注解方式已经被隐藏,感兴趣的小伙伴可以去【plugins\DoAsVue_LXL\KING\DoAsVue\plugins\_Demos\_reflectAndAnnotationDemo】下查看
现在完全采取元注解的方式来实现自定义注解。
由于”自定义注解“功能强大,(与aspect一样,也是采用了代理的方式实现的),因此它可以完全代替aspect与旧版的注解的开发方式了(但是为了兼容旧版本,依旧保留了旧版本的规范,同时需要注意,aspect的优先级大于注解)
如代码:
如何自定义注解一个注解
步骤1、继承“BaseAnnotationOperator”
步骤2、使用 @annotation 对一个 fun(method,methodName,annotationInfo,module,...args) 格式的方法进行标注
步骤3、编写方法内容
步骤4、@fun注解完成
JavaScript:
var plugin = {
data(){
return{}
},
global:{},
extends:"BaseAnnotationOperator",
require:{},
methods:{
//参数必须为整数的注解
//用法 @argMustBeInteger(argsIndex)
//argsIndex:参数下标,如果不填,默认所有参数都必须是整数
argMustBeInteger(method,methodName,annotationInfo,module,argIndex){
/**
* @annotation
*/
//使用元注解将 argMustBeInteger 标记为一个注解
/**
* 参数前面 method,methodName,annotationInfo,module 这几个是固定的
* method:是被注解标注的 函数 本身
* methodName:函数 的真实名称
* annotationInfo:函数的所有注解信息
* module:这个函数所在的子插件本身
*
*
* argIndex:这个是注解传入的参数
* 例如 @argMustBeInteger (1) 表示下标为 1 的参数必须是整数
* 注:注解可以传入多个参数,我这里只是传入一个举例而已,
* 它的原型是 (method,methodName,annotationInfo,module,...args)
*/
//返回一个代理方法
return function(...args){
//当不填写参数下标时,默认检查所有参数
if(argIndex == null){
//遍历所有参数
for(let index in args){
if(args[index] == null ||
typeof(args[index]) != "number" ||
Math.round(args[index])!= args[index]){
throw Error(annotationInfo["argsName"][index]+" must be an integer")
}
}
}else if(args!=null && args.length > argIndex){
//如果填写了参数下标,就只检查特定参数
if(args[argIndex] == null ||
typeof(args[argIndex]) != "number" ||
Math.round(args[argIndex])!= args[argIndex]){
throw Error(annotationInfo["argsName"][argIndex]+" must be an integer")
}
}
//执行
return method(...args);
}
}
},
MCListen:{},
MCPlayerCmd:{},
MCConsoleCmd:{},
aspect:{},
main(){}
}
//导出规范
module.exports={
name:"AnnotationLib", //表示这个插件的名字,用于被其他插件引用时的名字
plugin:plugin//当前导出的创建对象
}
如何使用自定义注解:在任意一个method内使用即可
JavaScript:
add(num1,num2,num3){
/**
* @argMustBeInteger (1)
*/
return num1+ num2 + num3;
},
JavaScript:
this.print(this.add(1.2, 2.2 ,5.8)) //会报错,因为注解要求了第二个(下标为1)的参数必须是整数
this.print(this.add(1.2, 2 ,5.8)) //不报错,会正常打印 9
@argMustBeInteger 注解已经添加到了注解库,现在可以直接使用了,在不久之后,我会逐步完善这个注解库,有兴趣的小伙伴也可以提出建议
当参数不是整数时会直接报错(当然,你也可以根据demo,写一个不一定非得报错的注解,我这里只是举例)
注:
1、所有自定义注解的子插件的必须继承 ” BaseAnnotationOperator ”
2、注解格式为:
JavaScript:
fun(){
/**
* @annotation1
* @annotation2()
* @annotation3 ()
* @annotation4("value1",123,new Date())
* @annotation5 ("value1",123,new Date())
* @annotation6 ("value1",null)
*/
//todo 你的代码在必须注解之后
}
//1、注解必须在函数内部的头部
//2、与上面的格式相仿
//3、不支持在注解后面添加解释,例如 * @annotation1 //这是注解1
【@Bean与@Autowired】
这个是我自己仿造 Spring IOC 做的一个小案例,利用注解实现的自动注入bean
源码在 DoAsVue源码附件
JavaScript:
// MyBeanFactory.DAVue.js
var plugin = {
data(){
return{}
},
extends:null,
methods:{
setNumBean(){
/**
* @Bean ("myNum")
*/
return 123;
},
setObjBean(){
/**
* @Bean ("myObj")
*/
return {
a:999,
b:"自动注入"
};
},
},
main(){}
}
//导出规范
module.exports={
name:"MyBeanFactory", //表示这个插件的名字,用于被其他插件引用时的名字
plugin:plugin//当前导出的创建对象
}
JavaScript:
// temp.DAVue.js
var plugin = {
data(){
return{
num : null,
obj : null
}
},
extends:null,
methods:{
setValue(num,obj){
/**
* @Autowired (["myNum","myObj"],true)
*/
this.num = num;
this.obj = obj;
}
},
main(){
this.print(this.value);
this.printObject(this.obj)
}
}
//导出规范
module.exports={
name:"temp", //表示这个插件的名字,用于被其他插件引用时的名字
plugin:plugin//当前导出的创建对象
}
执行结果:
【自动对外暴露接口与davue指令】
DoAsVue会自动对子插件添加对外暴露接口,方便其他非davue的第三方插件进行调用
JavaScript:
var plugin = {
data(){
return{}
},
extends:null,
methods:{
fun(arg1,arg2){
},
},
main(){}
}
//导出规范
module.exports={
name:"Temp", //表示这个插件的名字,用于被其他插件引用时的名字
plugin:plugin//当前导出的创建对象
}
JavaScript:
在其他插件需要调用该子插件的fun(args),只需要执行:
mc.runcmdEx("davue execute Temp fun arg1 arg2")
需要注意的是,这些接口仅允许调用,由于LXL与bds的运行机制原因,暂时无法返回调用结果
关于davue命令:
最新指令详情请前往控制台输入 davue
【其他说明】
1、DoAsVue插件内直接使用this.logger(msg,type)即可使用日志;type: info/warning/error/debug/fatal
2、对于 A 继承 C,B 继承 C,则C可以通过this.children获取继承的子类列表,而 A 和 B 可以通过this.super拿到父类。
3、DoAsVue不会扫描带有 _ 开头的文件夹,以及js文件,因为以 _ 开头的 js 文件或者文件夹都表示废弃(可以用来装垃圾。。。。)
4、由于所有插件继承BaseObject,因此可以快速打印信息,使用 this.print(msg) 即可,强烈建议不要使用 log 。另外还提供了 this.printObject(obj)可以打印 object 对象(都会记录到日志文件,供维护查看)
5、所有的DoAsVue子插件均可以通过this.self拿到自身的属性,比如自身文件路径,插件名称,被其他插件require的情况。详情使用this.printObject(this.self)查看
【用法】
1、解压到plugins下,解压之后会得有一个DoAsVue.lxl.js的主运行插件,他是负责整合与运行符合DoAsVue规范的插件,把它放在plugins目录下(解压之后有 DoAsVue.lxl.js文件 以及 KING文件夹)
2、在他被第一次运行时会在/plugins/KING/DoAsVue/下生成config.json,里面默认在/plugins/KING/DoAsVue/plugins/下存放所有的DoAsVue规范插件,因为是递归扫描该文件夹,所以你可以在这个目录下进行插件分类存放,便于后期维护。例如你的库相关插件可以放在该目录下的 lib 下
3、开发符合DoAsVue规范的插件,并放到配置文件所指定的目录下(这个目录不能是/plugins下,切记,因为他不是一个LXL插件),这个目录默认是/plugins/KING/DoAsVue/plugins/
4、开服
简而言之:
1、下载之后解压到plugins下
2、编写好你自己的DoAsVue插件(规范都在上面有说明,不会的可以找我)
3、把你的DoAsVue插件放到 /plugins/KING/DoAsVue/plugins/ 下
4、开服
【附赠的插件说明】
在./plugins/KING/DoAsVue/plugins/lib/内,DoAsVue子插件可以直接调用
1、【Lib_MathCal】
这是一个带有数学公式的库,目前还在扩充
2、【DataBuffer】
这是一个全局数据缓存池,用于运行时存储缓存数据,相当于Map全局变量
3、【ObjectHelper】
这是一个用于js的object操作的常用辅助库插件
4、【StringHelper】
这是一个用于 js 的字符串操作的常用辅助库插件
5、【Nbt_PlayerAbilities】
这是一个操作玩家权限的辅助库插件,相当于修改游戏暂停键内那些权限:1建造权 、2破坏权、3使用开关、4打开容器 、5攻击玩家 、6攻击生物(不支持修改 传送权 与 命令使用权);不同于事件拦截,它基于修改nbt实现的
6、【SidebarHelper】
这是一个可以很方便快且捷定制侧边栏的辅助插件,用法在插件底部有说明
7、【NBTHelper】
这是一个可以快速将nbt/snbt转jsobj并且还能自动还原为nbt/snbt的nbt助手,详情用法在该插件底部
JavaScript:
//快速修改玩家血量举例:
let playerNbt_jsObjNbt = this.NBTHelper.getJsObjNbt(players[0].getNbt())
let Attributes = playerNbt_jsObjNbt.Attributes;
for(let i in Attributes){
let attribute = Attributes[i];
if(attribute.Name=="minecraft:health"){
playerNbt_jsObjNbt.Attributes[i].Current = 19; //修改血量
players[0].setNbt(playerNbt_jsObjNbt.getNbt()); //写入数据
break;
}
}
//--------------------------------------------//
// 快速制作 锋利32k 钻石剑
let ItemSNBT = `{"Count":1b,"Damage":0s,"Name":"minecraft:diamond_sword","WasPickedUp":0b,"tag":{"Damage":0,"RepairCost":3,"display":{"Name":"钻石剑-自定义名字"},"ench":[{"id":17s,"lvl":3s},{"id":9s,"lvl":5s}]}}`;
let item_jsObjNbt = this.NBTHelper.getJsObjNbt(ItemSNBT)
let item = mc.newItem(item_jsObjNbt.Name,item_jsObjNbt.Count);
item_jsObjNbt.tag.ench[1].lvl=32767; //直接修改为32k
item.setNbt(item_jsObjNbt.getNbt());
//如此便捷的nbt操作,心动了吗?
这是一个用于附魔辅助的插件库,具备标准附魔查询,违规附魔检测等功能。详情查看lib下的EnchantHelper.DAVue.js
9、【AnnotationLib】
这是一个注解库,你直接拿来即用,从而减少无用代码的编写。开发就是把你的有限的精力放在重要的业务上,而不是写代码本身。这个注解库在逐步完善中
【写在后面的话】
问:这个到底是什么?
答:这个是一个提供将大型插件拆分为模块的插件框架,即运行插件的插件
问:我为什么非得用他开发插件,之前的开发不好吗?
答:如果是简单的功能性插件,您可以按照自己的开发习惯,但是如果您开发的插件系统功能比较多而杂乱,我推荐您使用它(DoAsVue),我只是提供了另一种开发规范与思路
问:他和一般的插件开发有什么区别?
答:区别就是他提供了插件分割思路,与一般的单个的插件不一样,它仿造VueJs与Java的风格与方式,把各个功能和数据进行拆分与整合,按照LXL提供的接口正常开发,它允许每个被加载的插件相互调用,数据共享,以及配置文件共享(有效保证多个插件的对同一个变量或者配置文件进行正确读写操作)。
设计不易,请多多支持,给自己点个赞