Skip to content
way-zer edited this page Jun 27, 2020 · 5 revisions

开发总述

本插件脚本基于kts,语法为kotlin,运行环境为jvm。
开发工具使用IDEA,导入本仓库,将具备脚本的语法高亮和代码提示能力
IDEA可以在开发时,检查大部分语法错误,其他IDE对kts支持较差,基本无代码提示能力
能够不依赖IDE,纯手敲的大佬,可以直接上传到服务器,插件加载时会显示编译信息

自行编译

  • ./gradlew buildPlugin 编译插件(加载器)
  • ./gradlew scriptsZip 打包脚本 文件生成在build/libs和build/distributions中

Scripts目录结构

  • cache 下面放置脚本编译缓存,或其他缓存内容
  • data 放置持久化数据(配置文件或数据库文件)
  • main.init.kts 模块定义文件
  • main 模块根目录
    • lib 模块库(内部可放一系列kt源文件,将随模块编译加载)
    • .metadata 模块元数据(供IDE和其他编译器分析编译使用,运行时自动生成)
    • xxxx.content.kts 普通内容脚本(也可放置在子目录下)

脚本结构及关系

本插件定义了两种kts脚本

模块定义脚本 init.kts

代表一个模块

  • 可以集成父模块 @file:DependsModule
  • 同时为子脚本定义一些辅助库 module.lib 包,与模块定义一起编译加载
  • 为子脚本添加默认导入 addDefaultImport
  • 为子脚本导入第三方库 addLibraryByClass addLibrary addLibraryByName
  • 监测子脚本生命周期 onBeforeContentEnable onAfterContentEnable onBeforeContentDisable onAfterContentDisable
  • 生成.metadata辅助IDE开发 generateHelper()

内部实现信息

实现上InitScript->IInitScript->IContentScript->IBaseScript,判定IInitScript即可
继承于IContentScript,因此可以作为内容脚本使用,但请不要滥用,模块应当仅做模块定义相关 模块定义脚本使用自定义的ModuleClassLoader加载,Class与其他模块共享。
模块导入的第三方库,脚本本身,以及辅助库lib中的类,均由ModuleClassLoader加载。
可以使用Class<*>.getContextModule()获取当前模块(IInitScript)。

普通内容脚本 content.kts

用于实现某一特定功能,放置在模块目录下(或除lib以外的子目录)

  • 获取当前模块 this.module
  • 获取当前脚本唯一ID this.id
  • 设定脚本名字 this.name = "xxx" (亦代表模块名)
  • 获取当前源文件 this.sourceFile
  • 生命周期函数 onEnable{} onDisable{}
  • 单独导入第三方库@file:MavenDepends @file:ImportByClass
  • 导入其他kt源代码@file:ImportScript(模块默认导入所有lib)

关于生命周期

根层次下的代码将在Load阶段执行,此时应当做一些定义,设置,声明(例如做模块定义,定义配置项,注册指令,监听事件,暴露接口)
onEnable将在enable阶段调用,在onEnable后,脚本才算真正启用(例如启动Worker,开启Web端口,初始化运行时数据)
onDisale将在disable阶段调用,此时应当做相关资源的回收(协程和父模块提供的接口一般均有自动回收,可不关系)
onDisable也可在onEnable内声明(例如onEnable成功开启Web服务器后,注册onDisable关闭服务器)

内部实现信息

内容脚本也有自己的Classloader,父为ModuleClassLoader。不同内容脚本间不共享Class。
但可以通过父ModuleClassLoader使用所有模块的Class

开发提示

每一次启动的ClassLoader均与旧实例不同,所加载的Class将被视为不同Class,所以请不要将Class传递到给外部接口持有,若已传递,必须在onDisable进行回收(甚至使用反射)
脚本中可以声明object和class,但内部无法直接访问脚本成员,内部没有this对象(IDE提示有误),若想如此,可以使用innner class代替class,使用val变量代替object使用

关于多平台脚本的通用性

  • coreLibrary模块设计为平台无关,所有直接依赖于此的模块,应当做到平台无关
  • coreXXXX(coreMindustry)为对应平台实现,为子脚本通过对应平台接口,与平台有关的模块应当继承于此(或main)
  • main模块,所有平台main模块应当直接继承coreXXXX,并不添加任何额外接口,无模块的内容脚本应当默认放置在该模块下