Compare commits
42 Commits
Author | SHA1 | Date | |
---|---|---|---|
6b34566489 | |||
074e6e8a10 | |||
14cc05e923 | |||
ebc03b6164 | |||
9268ce9fee | |||
3e4453a197 | |||
dc66290f97 | |||
56152657c8 | |||
e2f9bbf587 | |||
a9003025ee | |||
91a87ab20e | |||
ce92ae9ec6 | |||
cfd44a6289 | |||
fc7fb67023 | |||
7b171f1546 | |||
389bfd7137 | |||
f8ba885b8c | |||
48306b64c4 | |||
1cb4c05efd | |||
54e40b6768 | |||
51fc4549da | |||
824c440f63 | |||
7f32062dca | |||
12d07bf552 | |||
0506c9e3e6 | |||
40760713ff | |||
7e36b6109d | |||
7f85295eb1 | |||
427aa262f0 | |||
e71bd2a0cb | |||
9bb67410ac | |||
eba0e18285 | |||
219eb6b919 | |||
17d07d6cef | |||
f2b8f6ff26 | |||
9a15a0ab1f | |||
d0de120867 | |||
351183ab3c | |||
87c78f7c6f | |||
28db77333e | |||
ac83acd4c8 | |||
876c9b77f7 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -53,3 +53,6 @@ vendor/
|
|||||||
# Minecraft Data
|
# Minecraft Data
|
||||||
/world
|
/world
|
||||||
**/node_modules/
|
**/node_modules/
|
||||||
|
|
||||||
|
# Gradle
|
||||||
|
.gradle
|
||||||
|
0
CHANGELOG.md
Normal file
0
CHANGELOG.md
Normal file
88
README.md
88
README.md
@ -1,87 +1,11 @@
|
|||||||
# MiaoScript
|
# MiaoScript
|
||||||
|
|
||||||
> 排版什么的 不存在的 这辈子都不会有排版的 除非什么时候论坛支持 `MarkDown` 了
|
> 一个兼容 Spigot Sponge Nukkit BungeeCord 的 脚本插件运行时
|
||||||
|
|
||||||
### 简介
|
## 简介
|
||||||
|
|
||||||
> 这个坑是我自己刨的 但是发现坑太大 需要更多的人一起填
|
## 安装
|
||||||
|
|
||||||
#### 起源
|
- 下载后放入对应服务器目录
|
||||||
|
- Bukkit Nukkit BungeeCord 以及其分支 => `plugins`
|
||||||
- 诞生于 `2016年08月25日` 这是 Git 上的第一个提交 具体啥时候我也忘了
|
- Sponge => `mods`
|
||||||
- 起初 `MiaoScript` 只是用于服务器其他插件的变量执行 并且依赖于PAPI(不知道是啥的自己百度)
|
|
||||||
- 比如 [`MiaoMenu`](http://w.yumc.pw/zc/MiaoMenu.html) 的部分复杂脚本
|
|
||||||
- 比如 [`MiaoChat`](http://mcbbs.net/thread-631240-1-1.html) 的聊天变量
|
|
||||||
- 突然有一天 圈内的大佬 `QSB` @qiu1995 过来找我 说能不能用脚本监听玩家的事件
|
|
||||||
- PS: 这货自从用过 `DeluxeMenu` 之后就喜欢上了用JS写菜单
|
|
||||||
- 当初感觉没啥问题 就出了第一个简易的 `MiaoScript` 版本 还是用 yml 做的配置文件
|
|
||||||
- 但是由于设计 BukkitAPI 等内容 对Java要求太高 后来 邱也弃坑了 我也弃坑了
|
|
||||||
|
|
||||||
#### 刨坑
|
|
||||||
|
|
||||||
- 时隔多年(也就一年) 看到了Sponge的兴起 (估摸着是MCPC系列的MOD端都弃坑了)
|
|
||||||
- 同时 这期间 收到很多腐竹的单子 但是又是非常基础的东西
|
|
||||||
- 比如 开服给玩家发一条消息啦
|
|
||||||
- 比如 修改玩家某些数据啦
|
|
||||||
- 这些东西实际上也就几行代码的事情
|
|
||||||
- 同时 很多想入坑 插件开发 但是又有一些被卡死在环境搭建上
|
|
||||||
- 比如 `Bukkit` 需要 `BukkitAPI`
|
|
||||||
- `Sponge` 需要 `SpongeAPI` 如果涉及 `MOD` 还要 `Forge` 环境
|
|
||||||
- 再或者 BungeeCord 的插件开发 我也是经常懒得搞
|
|
||||||
- 当然 最主要的是 某个 咕咕咕的群 天天有人问我 喵系插件能不能支持 Sponge
|
|
||||||
- 内心当然是拒绝的 现在要上班养老婆孩子(咳咳 不要以为我是大叔 我也才刚毕业而已) 那里还有时间免费给你们写插件
|
|
||||||
- 于是乎 我又想起了当初的 `MiaoScript`
|
|
||||||
- 突发奇想 一个插件的雏形出现在我的脑海中
|
|
||||||
- 可以兼容多种服务器
|
|
||||||
- 不需要开发环境 有记事本就可以开发
|
|
||||||
- 语法要简单 比如 JavaScript
|
|
||||||
- 能够自动搜索安装依赖(毕竟很多人天天问我为何喵系插件跑不起来 都是缺少PAPI)
|
|
||||||
- 能够不重启更新插件(当然得保证代码安全的前提下)
|
|
||||||
- 在 2017年9月14号(距离 第一个版本正式版发布(2016-09-21) 相差一年整)
|
|
||||||
- 一个全新的 `MiaoScript` 诞生了
|
|
||||||
- Java部分代码 只有一个启动类
|
|
||||||
- 核心全部由 JS 编写
|
|
||||||
- 兼容 `CommonJS` 规范
|
|
||||||
- 实时重载
|
|
||||||
- 不兼容 MOD 服 (咳咳 当然现在已经支持了)
|
|
||||||
- 基础结构如下
|
|
||||||
|
|
||||||
```txt
|
|
||||||
└─src
|
|
||||||
└─main
|
|
||||||
├─java 引导类
|
|
||||||
└─resources
|
|
||||||
├─bios.js 核心启动类 用于释放文件和初始化
|
|
||||||
├─api 全平台兼容的接口
|
|
||||||
├─core 核心代码 例如 require 模块
|
|
||||||
│ └─ext 扩展代码 例如 Object.toJson()
|
|
||||||
├─internal 内部实现 用于各个平台实现API
|
|
||||||
│ ├─bukkit BukkitAPI内部实现
|
|
||||||
│ └─sponge SpongeAPI内部实现
|
|
||||||
├─modules JS模块 例如 js-yaml, http 等
|
|
||||||
└─plugins 这里当然是插件啦
|
|
||||||
├─bukkit 只兼容bukkit的插件
|
|
||||||
├─sponge 只兼容Sponge的插件
|
|
||||||
└─ext 插件扩展类库 用于多个插件共用代码 当然最好是是用 `modules` 啦
|
|
||||||
```
|
|
||||||
- 没错 第一个版本只兼容了 BukkitAPI
|
|
||||||
- 我还用 `MiaoScript` 给某位腐竹写了一个抽奖插件
|
|
||||||
- 当时因为没解决 MOD 服兼容问题 所以就退款了 放上[源码](http://paste.yumc.pw/pknd8q6e1)
|
|
||||||
- 由于当时没有封装相关的API所以很多方法是直接调用了 `Bukkit` 原生的代码
|
|
||||||
- 所以不兼容 `Sponge`
|
|
||||||
|
|
||||||
### 进展
|
|
||||||
|
|
||||||
- [项目发布](https://git.yumc.pw/502647092/MiaoScript/releases)
|
|
||||||
- [项目代码](https://git.yumc.pw/502647092/MiaoScript)
|
|
||||||
- [项目脑图](http://naotu.baidu.com/file/293b9a0fc7cef23c69de81c55e3617d5?token=1eee8fd759198eb7)
|
|
||||||
|
|
||||||
### 规划
|
|
||||||
|
|
||||||
- 初期只会支持JS类型的插件开发
|
|
||||||
- 二期会出一个建议版本的MS脚本 可以用简单的语法实现简单的功能
|
|
||||||
- 各个层级会有依赖控制 比如 `MS脚本 => JS脚本 => 调用Java原生API`
|
|
||||||
|
|
||||||
### 填坑
|
|
||||||
|
|
||||||
- 实际上说了那么多 最终希望的就是 有大佬能一起来填坑 毕竟这个坑太大了
|
|
||||||
|
113
pom.xml
113
pom.xml
@ -1,15 +1,14 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>pw.yumc</groupId>
|
<groupId>pw.yumc</groupId>
|
||||||
<artifactId>MiaoScript</artifactId>
|
<artifactId>MiaoScript</artifactId>
|
||||||
<version>0.3.1</version>
|
<version>0.28.0</version>
|
||||||
<developers>
|
<developers>
|
||||||
<developer>
|
<developer>
|
||||||
<id>502647092</id>
|
<id>502647092</id>
|
||||||
<name>喵♂呜</name>
|
<name>MiaoWoo</name>
|
||||||
<email>admin@yumc.pw</email>
|
<email>admin@yumc.pw</email>
|
||||||
<url>http://www.yumc.pw</url>
|
<url>https://www.yumc.pw</url>
|
||||||
</developer>
|
</developer>
|
||||||
</developers>
|
</developers>
|
||||||
<build>
|
<build>
|
||||||
@ -17,35 +16,9 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<resource>
|
<resource>
|
||||||
<directory>src/main/resources</directory>
|
<directory>src/main/resources</directory>
|
||||||
<excludes>
|
|
||||||
<exclude>dev-plugins/**</exclude>
|
|
||||||
</excludes>
|
|
||||||
<filtering>true</filtering>
|
<filtering>true</filtering>
|
||||||
</resource>
|
</resource>
|
||||||
</resources>
|
</resources>
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
|
||||||
<version>3.2.1</version>
|
|
||||||
<configuration>
|
|
||||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
|
||||||
<artifactSet>
|
|
||||||
<includes>
|
|
||||||
<include>org.kamranzafar:jtar</include>
|
|
||||||
</includes>
|
|
||||||
</artifactSet>
|
|
||||||
</configuration>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<phase>package</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>shade</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
</build>
|
||||||
<ciManagement>
|
<ciManagement>
|
||||||
<system>Jenkins</system>
|
<system>Jenkins</system>
|
||||||
@ -54,15 +27,65 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<env.GIT_COMMIT>DEV</env.GIT_COMMIT>
|
<env.GIT_COMMIT>DEV</env.GIT_COMMIT>
|
||||||
<update.changes>
|
<update.changes>
|
||||||
|
§623-10-25 §afeat: 升级 asm 版本;
|
||||||
|
§623-07-30 §afeat: 优化 require 性能;
|
||||||
|
§cfix: 修复 require 加载特殊文件异常;
|
||||||
|
§623-07-22 §afeat: 网络加载 jtar 优化包大小;
|
||||||
|
§aremove: 移除 Spring 相关支持;
|
||||||
|
§adeps: 更新 Nashorn 和 GraalvmJS 引擎版本
|
||||||
|
</update.changes>
|
||||||
|
<update.changelog>
|
||||||
|
§622-11-22 §afeat: 兼容 1.7.10-1.19.2 版本;
|
||||||
|
§afeat: 新增 MiaoScriptAPI 相关方法;
|
||||||
|
§622-06-21 §afeat: 兼容 1.7.10-1.19 版本;
|
||||||
|
§afeat: 兼容 JDK17 BungeeCord;
|
||||||
|
§622-05-25 §afeat: 兼容 1.7.10-1.18.2 版本;
|
||||||
|
§622-05-21 §afeat: 优化 框架加载逻辑;
|
||||||
|
§622-05-20 §afeat: 调整 require 主包逻辑;
|
||||||
|
§622-04-09 §afeat: 优化 引擎初始化逻辑;
|
||||||
|
§afeat: 优化 require 网络加载;
|
||||||
|
§afeat: 新增 JS 类型定义文件;
|
||||||
|
§afeat: 新增 自定义类型加载逻辑;
|
||||||
|
§622-02-16 §afeat: 新增 MiaoScriptAPI;
|
||||||
|
§afeat: 新增 ScriptEvent;
|
||||||
|
§afeat: 新增 .mjs .json 类型加载;
|
||||||
|
§622-02-16 §afeat: 优化 初始化逻辑 加快引擎加载速度;
|
||||||
|
§afeat: 新增 root 目录变更检测 变更后重新生成缓存;
|
||||||
|
§afeat: 添加常用库的软依赖;
|
||||||
|
§622-01-01 §afeat: 兼容JDK17 更新Nashorn;
|
||||||
|
§621-11-04 §afeat: 优化系统模块升级逻辑;
|
||||||
|
§621-07-10 §afeat: 优化网络相关功能;
|
||||||
|
§621-06-25 §afeat: 调整启动逻辑 兼容 Arclight;
|
||||||
|
§621-06-22 §afeat: 新增本地版本锁定功能;
|
||||||
|
§621-06-19 §afeat: 兼容JDK16 反射异常;
|
||||||
|
§621-05-15 §afeat: 兼容JDK15+ 自动下载Nashorn类库;
|
||||||
|
§621-03-25 §afeat: 异步加载 polyfill 并且同步加载 @ccms/core;
|
||||||
|
§621-03-25 §cfix: 修改 ployfill 为 polyfill;
|
||||||
|
§620-12-22 §cfix: 增加 require 效验;
|
||||||
|
§620-12-17 §afeat: JavaScriptTask 新增任务ID 并通过 ID 比较优先级;
|
||||||
|
§620-12-16 §afeat: 新增 require 缓存 优化路径寻找速度;
|
||||||
|
§620-12-15 §cfix: 修复 非主线程重载时发生的异常;
|
||||||
|
§620-12-07 §cfix: 修复 Windows 环境 重载异常;
|
||||||
|
§620-11-19 §afeat: 新增 JavaScriptTask 类;
|
||||||
|
§620-11-11 §afeat: 新增 package 版本锁定逻辑;
|
||||||
|
§620-09-21 §afeat: 完善 upgrade 逻辑;
|
||||||
|
§620-08-27 §afeat: 新增 ProtocolLib 依赖;
|
||||||
|
§620-07-28 §afeat: 新增框架升级功能;
|
||||||
|
§620-06-23 §afeat: 支持自定义参数;
|
||||||
|
§620-06-22 §afeat: 优化 require 加载逻辑;
|
||||||
|
§620-05-28 §afeat: 新增 Spring 的支持;
|
||||||
|
§620-05-02 §afeat: 调整 scope 为 @ccms;
|
||||||
|
§620-04-10 §afeat: 默认从 classpath 加载内建的 js 模块;
|
||||||
|
§620-04-07 §afeat: 默认初始化 内建 nodejs 模块;
|
||||||
|
§620-04-03 §afeat: 优化 框架卸载逻辑;
|
||||||
|
§620-03-31 §afeat: require 新增 内建 nodejs 模块;
|
||||||
§620-03-03 §afeat: require 新增 淘宝镜像源拉取;
|
§620-03-03 §afeat: require 新增 淘宝镜像源拉取;
|
||||||
§620-02-27 §afeat: 异步加载脚本引擎;
|
§620-02-27 §afeat: 异步加载脚本引擎;
|
||||||
§620-02-25 §afeat: 新增 Nukkit 的支持;
|
§620-02-25 §afeat: 新增 Nukkit 的支持;
|
||||||
§620-02-16 §afeat: 新增 Source Map 支持;
|
§620-02-16 §afeat: 新增 Source Map 支持;
|
||||||
§620-02-02 §afeat: 迁移 ployfill 到 @ms/ployfill;
|
§620-02-02 §afeat: 迁移 ployfill 到 @ms/ployfill;
|
||||||
§620-01-14 §afeat: 新增 Bungee 支持;
|
§620-01-14 §afeat: 新增 Bungee 支持;
|
||||||
§afeat: 新增 instance 实例获取
|
§afeat: 新增 instance 实例获取;
|
||||||
</update.changes>
|
|
||||||
<update.changelog>
|
|
||||||
§619-09-24 §cremove: 移除 okhttp3 类库;
|
§619-09-24 §cremove: 移除 okhttp3 类库;
|
||||||
§afeat: 新增require自动下载模块功能;
|
§afeat: 新增require自动下载模块功能;
|
||||||
§619-09-21 §afeat: 新增 okhttp3 类库;
|
§619-09-21 §afeat: 新增 okhttp3 类库;
|
||||||
@ -143,10 +166,6 @@
|
|||||||
<id>yumc-repo</id>
|
<id>yumc-repo</id>
|
||||||
<url>${repo.url}/repository/maven-public/</url>
|
<url>${repo.url}/repository/maven-public/</url>
|
||||||
</repository>
|
</repository>
|
||||||
<repository>
|
|
||||||
<id>sponge</id>
|
|
||||||
<url>https://repo.spongepowered.org/maven/</url>
|
|
||||||
</repository>
|
|
||||||
</repositories>
|
</repositories>
|
||||||
<pluginRepositories>
|
<pluginRepositories>
|
||||||
<pluginRepository>
|
<pluginRepository>
|
||||||
@ -165,32 +184,32 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
<version>1.18.6</version>
|
<version>1.18.24</version>
|
||||||
</dependency>
|
<scope>compile</scope>
|
||||||
<dependency>
|
|
||||||
<groupId>org.kamranzafar</groupId>
|
|
||||||
<artifactId>jtar</artifactId>
|
|
||||||
<version>2.3</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.spigotmc</groupId>
|
<groupId>org.spigotmc</groupId>
|
||||||
<artifactId>spigot-api</artifactId>
|
<artifactId>spigot-api</artifactId>
|
||||||
<version>1.14.4-R0.1-SNAPSHOT</version>
|
<version>1.18.2-R0.1-SNAPSHOT</version>
|
||||||
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.spongepowered</groupId>
|
<groupId>org.spongepowered</groupId>
|
||||||
<artifactId>spongeapi</artifactId>
|
<artifactId>spongeapi</artifactId>
|
||||||
<version>7.1.0</version>
|
<version>7.3.0</version>
|
||||||
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.md-5</groupId>
|
<groupId>net.md-5</groupId>
|
||||||
<artifactId>bungeecord-api</artifactId>
|
<artifactId>bungeecord-api</artifactId>
|
||||||
<version>1.12-SNAPSHOT</version>
|
<version>1.16-R0.4</version>
|
||||||
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.nukkit</groupId>
|
<groupId>cn.nukkit</groupId>
|
||||||
<artifactId>nukkit</artifactId>
|
<artifactId>nukkit</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
@ -1,60 +0,0 @@
|
|||||||
package pw.yumc.MiaoScript;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import lombok.val;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created with IntelliJ IDEA
|
|
||||||
*
|
|
||||||
* @author 喵♂呜
|
|
||||||
* Created on 2017/10/9 12:40.
|
|
||||||
*/
|
|
||||||
public class Base {
|
|
||||||
private Object instance;
|
|
||||||
|
|
||||||
public Base(Object instance) {
|
|
||||||
this.instance = instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Class getClass(String name) throws ClassNotFoundException {
|
|
||||||
return Class.forName(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object getInstance() {
|
|
||||||
return this.instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Class getProxyClass() {
|
|
||||||
return ProxyClass.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String read(String path) throws IOException {
|
|
||||||
return new String(Files.readAllBytes(new File(path).toPath()), "UTF-8");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void save(String path, String content) throws IOException {
|
|
||||||
File file = new File(path);
|
|
||||||
file.getParentFile().mkdirs();
|
|
||||||
Files.write(file.toPath(), content.getBytes("UTF-8"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void delete(String path) throws IOException {
|
|
||||||
delete(new File(path).toPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void delete(Path path) throws IOException {
|
|
||||||
val file = path.toFile();
|
|
||||||
if (!file.exists()) { return; }
|
|
||||||
if (file.isDirectory()) {
|
|
||||||
for (Path f : Files.list(file.toPath()).collect(Collectors.toList())) {
|
|
||||||
delete(f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Files.delete(path);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
package pw.yumc.MiaoScript;
|
|
||||||
|
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
|
||||||
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 喵式脚本
|
|
||||||
*
|
|
||||||
* @author 喵♂呜
|
|
||||||
* @since 2016年8月29日 上午7:50:39
|
|
||||||
*/
|
|
||||||
public class MiaoScript extends JavaPlugin {
|
|
||||||
private ScriptEngine engine;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SneakyThrows
|
|
||||||
public void onEnable() {
|
|
||||||
Thread.currentThread().setContextClassLoader(getClassLoader());
|
|
||||||
engine = new ScriptEngine(getDataFolder().getCanonicalPath(), getLogger(), this);
|
|
||||||
engine.enableEngine();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDisable() {
|
|
||||||
engine.disableEngine();
|
|
||||||
}
|
|
||||||
}
|
|
40
src/main/java/pw/yumc/MiaoScript/MiaoScriptBukkit.java
Normal file
40
src/main/java/pw/yumc/MiaoScript/MiaoScriptBukkit.java
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package pw.yumc.MiaoScript;
|
||||||
|
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
import pw.yumc.MiaoScript.api.MiaoScriptAPI;
|
||||||
|
import pw.yumc.MiaoScript.api.ScriptEngine;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 喵式脚本
|
||||||
|
*
|
||||||
|
* @author 喵♂呜
|
||||||
|
* @since 2016年8月29日 上午7:50:39
|
||||||
|
*/
|
||||||
|
public class MiaoScriptBukkit extends JavaPlugin {
|
||||||
|
private ScriptEngine engine;
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public MiaoScriptBukkit() {
|
||||||
|
ClassLoader origin = Thread.currentThread().getContextClassLoader();
|
||||||
|
Thread.currentThread().setContextClassLoader(getClassLoader());
|
||||||
|
engine = MiaoScriptAPI.createEngine(getDataFolder().getCanonicalPath(), getLogger(), this);
|
||||||
|
Thread.currentThread().setContextClassLoader(origin);
|
||||||
|
engine.loadEngine();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoad() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
engine.enableEngine();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
engine.disableEngine();
|
||||||
|
engine = null;
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,8 @@ package pw.yumc.MiaoScript;
|
|||||||
|
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import net.md_5.bungee.api.plugin.Plugin;
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
|
import pw.yumc.MiaoScript.api.MiaoScriptAPI;
|
||||||
|
import pw.yumc.MiaoScript.api.ScriptEngine;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created with IntelliJ IDEA
|
* Created with IntelliJ IDEA
|
||||||
@ -12,16 +14,25 @@ import net.md_5.bungee.api.plugin.Plugin;
|
|||||||
public class MiaoScriptBungee extends Plugin {
|
public class MiaoScriptBungee extends Plugin {
|
||||||
private ScriptEngine engine;
|
private ScriptEngine engine;
|
||||||
|
|
||||||
@Override
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public void onEnable() {
|
public MiaoScriptBungee() {
|
||||||
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
|
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
|
||||||
engine = new ScriptEngine(getDataFolder().getCanonicalPath(), getLogger(), this);
|
engine = MiaoScriptAPI.createEngine(getDataFolder().getCanonicalPath(), getLogger(), this);
|
||||||
|
engine.loadEngine();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoad() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
engine.enableEngine();
|
engine.enableEngine();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
engine.disableEngine();
|
engine.disableEngine();
|
||||||
|
engine = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,182 +0,0 @@
|
|||||||
package pw.yumc.MiaoScript;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.Reader;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.net.URLClassLoader;
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
import javax.script.Bindings;
|
|
||||||
import javax.script.Invocable;
|
|
||||||
import javax.script.ScriptContext;
|
|
||||||
import javax.script.ScriptEngine;
|
|
||||||
import javax.script.ScriptEngineFactory;
|
|
||||||
import javax.script.ScriptEngineManager;
|
|
||||||
import javax.script.ScriptException;
|
|
||||||
import javax.script.SimpleBindings;
|
|
||||||
|
|
||||||
import lombok.val;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 喵式脚本引擎
|
|
||||||
*
|
|
||||||
* @author 喵♂呜
|
|
||||||
* @since 2016年8月29日 上午7:51:43
|
|
||||||
*/
|
|
||||||
public class MiaoScriptEngine implements ScriptEngine, Invocable {
|
|
||||||
private static MiaoScriptEngine DEFAULT;
|
|
||||||
private static ScriptEngineManager manager;
|
|
||||||
private ScriptEngine engine;
|
|
||||||
|
|
||||||
static {
|
|
||||||
manager = new ScriptEngineManager(ClassLoader.getSystemClassLoader());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setBindings(Bindings bindings) {
|
|
||||||
manager.setBindings(bindings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Bindings getBindings() {
|
|
||||||
return manager.getBindings();
|
|
||||||
}
|
|
||||||
|
|
||||||
public MiaoScriptEngine() {
|
|
||||||
this("js");
|
|
||||||
}
|
|
||||||
|
|
||||||
public MiaoScriptEngine(final String engineType) {
|
|
||||||
this(manager, engineType);
|
|
||||||
}
|
|
||||||
|
|
||||||
public MiaoScriptEngine(ScriptEngineManager engineManager) {
|
|
||||||
this(engineManager, "js");
|
|
||||||
}
|
|
||||||
|
|
||||||
public MiaoScriptEngine(ScriptEngineManager engineManager, final String engineType) {
|
|
||||||
try {
|
|
||||||
engine = engineManager.getEngineByName(engineType);
|
|
||||||
} catch (final NullPointerException ignored) {
|
|
||||||
}
|
|
||||||
if (engine == null) {
|
|
||||||
val dirs = System.getProperty("java.ext.dirs").split(File.pathSeparator);
|
|
||||||
for (String dir : dirs) {
|
|
||||||
File nashorn = new File(dir, "nashorn.jar");
|
|
||||||
if (nashorn.exists()) {
|
|
||||||
try {
|
|
||||||
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
|
|
||||||
// 设置方法的访问权限
|
|
||||||
method.setAccessible(true);
|
|
||||||
// 获取系统类加载器
|
|
||||||
URL url = nashorn.toURI().toURL();
|
|
||||||
method.invoke(Thread.currentThread().getContextClassLoader(), url);
|
|
||||||
engineManager = new ScriptEngineManager();
|
|
||||||
engine = engineManager.getEngineByName(engineType);
|
|
||||||
} catch (NoSuchMethodException | MalformedURLException | IllegalAccessException | InvocationTargetException | NullPointerException ignored) {
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new UnsupportedOperationException("当前环境不支持 " + engineType + " 脚本类型!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MiaoScriptEngine getDefault() {
|
|
||||||
if (DEFAULT == null) {
|
|
||||||
DEFAULT = new MiaoScriptEngine();
|
|
||||||
}
|
|
||||||
return DEFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Bindings createBindings() {
|
|
||||||
return new SimpleBindings(new HashMap<>(engine.getBindings(ScriptContext.GLOBAL_SCOPE)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object eval(final Reader reader) throws ScriptException {
|
|
||||||
return engine.eval(reader);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object eval(final Reader reader, final Bindings n) throws ScriptException {
|
|
||||||
return engine.eval(reader, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object eval(final Reader reader, final ScriptContext context) throws ScriptException {
|
|
||||||
return engine.eval(reader, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object eval(final String script) throws ScriptException {
|
|
||||||
return engine.eval(script);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object eval(final String script, final Bindings n) throws ScriptException {
|
|
||||||
return engine.eval(script, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object eval(final String script, final ScriptContext context) throws ScriptException {
|
|
||||||
return engine.eval(script, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object get(final String key) {
|
|
||||||
return engine.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Bindings getBindings(final int scope) {
|
|
||||||
return engine.getBindings(scope);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ScriptContext getContext() {
|
|
||||||
return engine.getContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ScriptEngineFactory getFactory() {
|
|
||||||
return engine.getFactory();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T getInterface(final Class<T> clasz) {
|
|
||||||
return ((Invocable) engine).getInterface(clasz);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T getInterface(final Object thiz, final Class<T> clasz) {
|
|
||||||
return ((Invocable) engine).getInterface(thiz, clasz);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object invokeFunction(final String name, final Object... args) throws ScriptException, NoSuchMethodException {
|
|
||||||
return ((Invocable) engine).invokeFunction(name, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object invokeMethod(final Object thiz, final String name, final Object... args) throws ScriptException, NoSuchMethodException {
|
|
||||||
return ((Invocable) engine).invokeMethod(thiz, name, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void put(final String key, final Object value) {
|
|
||||||
engine.put(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setBindings(final Bindings bindings, final int scope) {
|
|
||||||
engine.setBindings(bindings, scope);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setContext(final ScriptContext context) {
|
|
||||||
engine.setContext(context);
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,6 +2,8 @@ package pw.yumc.MiaoScript;
|
|||||||
|
|
||||||
import cn.nukkit.plugin.PluginBase;
|
import cn.nukkit.plugin.PluginBase;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
|
import pw.yumc.MiaoScript.api.MiaoScriptAPI;
|
||||||
|
import pw.yumc.MiaoScript.api.ScriptEngine;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author MiaoWoo
|
* @author MiaoWoo
|
||||||
@ -9,16 +11,25 @@ import lombok.SneakyThrows;
|
|||||||
public class MiaoScriptNukkit extends PluginBase {
|
public class MiaoScriptNukkit extends PluginBase {
|
||||||
private ScriptEngine engine;
|
private ScriptEngine engine;
|
||||||
|
|
||||||
@Override
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public void onEnable() {
|
public MiaoScriptNukkit() {
|
||||||
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
|
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
|
||||||
engine = new ScriptEngine(getDataFolder().getCanonicalPath(), getLogger(), this);
|
engine = MiaoScriptAPI.createEngine(getDataFolder().getCanonicalPath(), super.getLogger(), this);
|
||||||
|
engine.loadEngine();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoad() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
engine.enableEngine();
|
engine.enableEngine();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
engine.disableEngine();
|
engine.disableEngine();
|
||||||
|
engine = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
package pw.yumc.MiaoScript;
|
package pw.yumc.MiaoScript;
|
||||||
|
|
||||||
import java.io.File;
|
import com.google.inject.Inject;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.spongepowered.api.config.ConfigDir;
|
import org.spongepowered.api.config.ConfigDir;
|
||||||
import org.spongepowered.api.event.Listener;
|
import org.spongepowered.api.event.Listener;
|
||||||
import org.spongepowered.api.event.game.GameReloadEvent;
|
import org.spongepowered.api.event.game.GameReloadEvent;
|
||||||
|
import org.spongepowered.api.event.game.state.GamePreInitializationEvent;
|
||||||
import org.spongepowered.api.event.game.state.GameStartedServerEvent;
|
import org.spongepowered.api.event.game.state.GameStartedServerEvent;
|
||||||
import org.spongepowered.api.event.game.state.GameStoppingServerEvent;
|
import org.spongepowered.api.event.game.state.GameStoppingServerEvent;
|
||||||
import org.spongepowered.api.plugin.Plugin;
|
import org.spongepowered.api.plugin.Plugin;
|
||||||
|
import pw.yumc.MiaoScript.api.MiaoScriptAPI;
|
||||||
|
import pw.yumc.MiaoScript.api.ScriptEngine;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import java.io.File;
|
||||||
import lombok.SneakyThrows;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created with IntelliJ IDEA
|
* Created with IntelliJ IDEA
|
||||||
@ -19,7 +21,7 @@ import lombok.SneakyThrows;
|
|||||||
* @author 喵♂呜
|
* @author 喵♂呜
|
||||||
* Created on 2017/10/25 20:35.
|
* Created on 2017/10/25 20:35.
|
||||||
*/
|
*/
|
||||||
@Plugin(id = "miaoscript", name = "MiaoScript", version = "1.0", authors = "喵♂呜")
|
@Plugin(id = "miaoscript", name = "MiaoScript", description = "MiaoScript runtime in Sponge", version = MiaoScriptAPI.VERSION, authors = "MiaoWoo")
|
||||||
public class MiaoScriptSponge {
|
public class MiaoScriptSponge {
|
||||||
private ScriptEngine engine;
|
private ScriptEngine engine;
|
||||||
@Inject
|
@Inject
|
||||||
@ -31,8 +33,14 @@ public class MiaoScriptSponge {
|
|||||||
|
|
||||||
@Listener
|
@Listener
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public void onStart(GameStartedServerEvent event) {
|
public void onPreInitialization(GamePreInitializationEvent event) {
|
||||||
engine = new ScriptEngine(pluginConfigDir.getCanonicalPath(), logger, this);
|
engine = MiaoScriptAPI.createEngine(pluginConfigDir.getCanonicalPath(), logger, this);
|
||||||
|
engine.loadEngine();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Listener
|
||||||
|
@SneakyThrows
|
||||||
|
public void onStarted(GameStartedServerEvent event) {
|
||||||
engine.enableEngine();
|
engine.enableEngine();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,13 +48,15 @@ public class MiaoScriptSponge {
|
|||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public void onStop(GameStoppingServerEvent event) {
|
public void onStop(GameStoppingServerEvent event) {
|
||||||
engine.disableEngine();
|
engine.disableEngine();
|
||||||
|
engine = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Listener
|
@Listener
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public void reload(GameReloadEvent event) {
|
public void reload(GameReloadEvent event) {
|
||||||
engine.disableEngine();
|
engine.disableEngine();
|
||||||
engine = new ScriptEngine(pluginConfigDir.getCanonicalPath(), logger, this);
|
System.gc();
|
||||||
|
engine.loadEngine();
|
||||||
engine.enableEngine();
|
engine.enableEngine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,56 +0,0 @@
|
|||||||
package pw.yumc.MiaoScript;
|
|
||||||
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
|
|
||||||
import javax.script.ScriptEngineManager;
|
|
||||||
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created with IntelliJ IDEA
|
|
||||||
*
|
|
||||||
* @author 喵♂呜
|
|
||||||
* Created on 2017/10/25 21:01.
|
|
||||||
*/
|
|
||||||
public class ScriptEngine {
|
|
||||||
private String root;
|
|
||||||
private Object logger;
|
|
||||||
private Base base;
|
|
||||||
private MiaoScriptEngine engine;
|
|
||||||
private ScriptEngineManager manager;
|
|
||||||
|
|
||||||
public ScriptEngine(String root, Object logger, Object instance) {
|
|
||||||
this.root = root;
|
|
||||||
this.logger = logger;
|
|
||||||
this.base = new Base(instance);
|
|
||||||
this.manager = new ScriptEngineManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
public void enableEngine() {
|
|
||||||
this.engine = new MiaoScriptEngine(manager, "nashorn");
|
|
||||||
this.engine.put("base", this.base);
|
|
||||||
this.engine.put("ScriptEngineContextHolder", this);
|
|
||||||
Path bios = Paths.get(root, "bios.js");
|
|
||||||
// 如果存在自定义bios就加载自定义的
|
|
||||||
if (Files.exists(bios)) {
|
|
||||||
this.engine.eval("load('" + bios.toFile().getCanonicalPath() + "')");
|
|
||||||
} else {
|
|
||||||
this.engine.eval(new InputStreamReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("bios.js")));
|
|
||||||
}
|
|
||||||
engine.invokeFunction("boot", root, logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
public void disableEngine() {
|
|
||||||
this.engine.invokeFunction("engineDisable");
|
|
||||||
this.engine = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MiaoScriptEngine getEngine() {
|
|
||||||
return engine;
|
|
||||||
}
|
|
||||||
}
|
|
128
src/main/java/pw/yumc/MiaoScript/api/Base.java
Normal file
128
src/main/java/pw/yumc/MiaoScript/api/Base.java
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
package pw.yumc.MiaoScript.api;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created with IntelliJ IDEA
|
||||||
|
*
|
||||||
|
* @author 喵♂呜
|
||||||
|
* Created on 2017/10/9 12:40.
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public class Base {
|
||||||
|
private final Object instance;
|
||||||
|
|
||||||
|
Base(Object instance) {
|
||||||
|
this.instance = instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVersion() {
|
||||||
|
return MiaoScriptAPI.VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<?> getClass(String name) throws ClassNotFoundException {
|
||||||
|
try {
|
||||||
|
return Class.forName(name);
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return Class.forName(name, true, instance.getClass().getClassLoader());
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
return Class.forName(name, true, instance.getClass().getClassLoader().getParent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<?> getProxyClass() {
|
||||||
|
return ProxyClass.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<?> getJavaScriptTaskClass() {
|
||||||
|
return JavaScriptTask.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File[] loadMavenDepend(String groupId, String artifactId, String version) {
|
||||||
|
return MiaoScriptAPI.loadMavenDepend(groupId, artifactId, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
public File[] loadMavenDepend(String groupId, String artifactId, String version, ClassLoader classLoader) {
|
||||||
|
return MiaoScriptAPI.loadMavenDepend(groupId, artifactId, version, classLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public File[] parentLoadMavenDepend(String groupId, String artifactId, String version) {
|
||||||
|
return MiaoScriptAPI.parentLoadMavenDepend(groupId, artifactId, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String read(String path) throws IOException {
|
||||||
|
return read(Paths.get(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String read(File file) throws IOException {
|
||||||
|
return read(file.toPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String read(Path path) throws IOException {
|
||||||
|
return new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Path save(String path, String content) throws IOException {
|
||||||
|
return save(Paths.get(path), content);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Path save(File file, String content) throws IOException {
|
||||||
|
return save(file.toPath(), content);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Path save(Path path, String content) throws IOException {
|
||||||
|
path.getParent().toFile().mkdirs();
|
||||||
|
return Files.write(path, content.getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean move(String source, String target) {
|
||||||
|
return move(new File(source), new File(target));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean move(File source, File target) {
|
||||||
|
return source.renameTo(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean delete(String path) throws IOException {
|
||||||
|
return delete(new File(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean delete(Path path) throws IOException {
|
||||||
|
return delete(path.toFile());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean delete(File file) throws IOException {
|
||||||
|
if (!file.exists()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (file.isFile()) {
|
||||||
|
return file.delete();
|
||||||
|
}
|
||||||
|
File[] files = file.listFiles();
|
||||||
|
if (files != null) {
|
||||||
|
for (File f : files) {
|
||||||
|
if (f.isFile()) {
|
||||||
|
if (!f.delete()) {
|
||||||
|
f.deleteOnExit();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.delete(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
boolean result = file.delete();
|
||||||
|
if (!result) {
|
||||||
|
file.deleteOnExit();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
41
src/main/java/pw/yumc/MiaoScript/api/JavaScriptTask.java
Normal file
41
src/main/java/pw/yumc/MiaoScript/api/JavaScriptTask.java
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package pw.yumc.MiaoScript.api;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.concurrent.Delayed;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class JavaScriptTask implements Delayed {
|
||||||
|
private final long id;
|
||||||
|
private final Object task;
|
||||||
|
private final long startTime;
|
||||||
|
private final long executeTime;
|
||||||
|
|
||||||
|
public JavaScriptTask(Object task, long ms) {
|
||||||
|
this(0, task, ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JavaScriptTask(long id, Object task, long ms) {
|
||||||
|
this.id = id;
|
||||||
|
this.task = task;
|
||||||
|
this.startTime = System.currentTimeMillis();
|
||||||
|
this.executeTime = ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getDelay(TimeUnit unit) {
|
||||||
|
return unit.convert((this.startTime + this.executeTime) - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Delayed delayed) {
|
||||||
|
JavaScriptTask task = (JavaScriptTask) delayed;
|
||||||
|
int delay = (int) ((this.startTime + this.executeTime) - (task.getStartTime() + task.getExecuteTime()));
|
||||||
|
if (delay != 0) {
|
||||||
|
return delay;
|
||||||
|
} else {
|
||||||
|
return (int) (this.id - task.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
62
src/main/java/pw/yumc/MiaoScript/api/MiaoScriptAPI.java
Normal file
62
src/main/java/pw/yumc/MiaoScript/api/MiaoScriptAPI.java
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package pw.yumc.MiaoScript.api;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import pw.yumc.MiaoScript.api.loader.MavenDependLoader;
|
||||||
|
import pw.yumc.MiaoScript.api.plugin.PluginManager;
|
||||||
|
import pw.yumc.MiaoScript.engine.MiaoScriptEngine;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
|
public class MiaoScriptAPI {
|
||||||
|
public static final String VERSION = "0.28.0";
|
||||||
|
@Getter
|
||||||
|
private static String root;
|
||||||
|
private static String libPath;
|
||||||
|
private static ScriptEngine scriptEngine;
|
||||||
|
@Getter
|
||||||
|
private static PluginManager pluginManager;
|
||||||
|
|
||||||
|
public static ScriptEngine createEngine(String root, Object logger, Object instance) {
|
||||||
|
MiaoScriptAPI.scriptEngine = new ScriptEngine(root, logger, instance);
|
||||||
|
return MiaoScriptAPI.scriptEngine;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setRoot(String root) {
|
||||||
|
MiaoScriptAPI.root = root;
|
||||||
|
MiaoScriptAPI.libPath = Paths.get(root, "libs").toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MiaoScriptEngine getEngine() {
|
||||||
|
return MiaoScriptAPI.scriptEngine.getEngine();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setEngine(ScriptEngine scriptEngine) {
|
||||||
|
MiaoScriptAPI.scriptEngine = scriptEngine;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setPluginManager(Object pluginManager) {
|
||||||
|
MiaoScriptAPI.pluginManager = getEngine().getInterface(pluginManager, PluginManager.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static File[] loadMavenDepend(String groupId, String artifactId, String version) {
|
||||||
|
if (root == null || scriptEngine == null) {
|
||||||
|
throw new IllegalStateException("root can't be null before loadMavenDepend.");
|
||||||
|
}
|
||||||
|
return MavenDependLoader.load(MiaoScriptAPI.libPath, groupId, artifactId, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static File[] loadMavenDepend(String groupId, String artifactId, String version, ClassLoader classLoader) {
|
||||||
|
if (root == null || scriptEngine == null) {
|
||||||
|
throw new IllegalStateException("root can't be null before loadMavenDepend.");
|
||||||
|
}
|
||||||
|
return MavenDependLoader.load(MiaoScriptAPI.libPath, groupId, artifactId, version, classLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static File[] parentLoadMavenDepend(String groupId, String artifactId, String version) {
|
||||||
|
if (root == null || scriptEngine == null) {
|
||||||
|
throw new IllegalStateException("root can't be null before loadMavenDepend.");
|
||||||
|
}
|
||||||
|
return MavenDependLoader.parentLoad(MiaoScriptAPI.libPath, groupId, artifactId, version);
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package pw.yumc.MiaoScript;
|
package pw.yumc.MiaoScript.api;
|
||||||
|
|
||||||
import javax.script.Bindings;
|
import javax.script.Bindings;
|
||||||
import javax.script.ScriptEngine;
|
import javax.script.ScriptEngine;
|
76
src/main/java/pw/yumc/MiaoScript/api/ScriptEngine.java
Normal file
76
src/main/java/pw/yumc/MiaoScript/api/ScriptEngine.java
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
package pw.yumc.MiaoScript.api;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import pw.yumc.MiaoScript.engine.MiaoScriptEngine;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created with IntelliJ IDEA
|
||||||
|
*
|
||||||
|
* @author 喵♂呜 Created on 2017/10/25 21:01.
|
||||||
|
*/
|
||||||
|
public class ScriptEngine {
|
||||||
|
private final ClassLoader loader;
|
||||||
|
private final Object logger;
|
||||||
|
private final String root;
|
||||||
|
private final Base base;
|
||||||
|
@Getter
|
||||||
|
private MiaoScriptEngine engine;
|
||||||
|
private Object future;
|
||||||
|
|
||||||
|
ScriptEngine(String root, Object logger, Object instance) {
|
||||||
|
this.loader = Thread.currentThread().getContextClassLoader();
|
||||||
|
this.root = root;
|
||||||
|
this.logger = logger;
|
||||||
|
this.base = new Base(instance);
|
||||||
|
MiaoScriptAPI.setRoot(root);
|
||||||
|
MiaoScriptAPI.setEngine(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createEngine() {
|
||||||
|
synchronized (logger) {
|
||||||
|
if (this.engine == null) {
|
||||||
|
this.engine = new MiaoScriptEngine(root);
|
||||||
|
this.engine.put("base", this.base);
|
||||||
|
this.engine.put("ScriptEngineContextHolder", this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public void loadEngine() {
|
||||||
|
ClassLoader originLoader = Thread.currentThread().getContextClassLoader();
|
||||||
|
Thread.currentThread().setContextClassLoader(this.loader);
|
||||||
|
createEngine();
|
||||||
|
Path bios = Paths.get(root, "bios.js");
|
||||||
|
// 如果存在自定义bios就加载自定义的
|
||||||
|
if (Files.exists(bios)) {
|
||||||
|
this.engine.eval("load('" + bios.toFile().getCanonicalPath() + "')");
|
||||||
|
} else {
|
||||||
|
this.engine.eval("load('classpath:bios.js')");
|
||||||
|
}
|
||||||
|
future = engine.invokeFunction("boot", root, logger);
|
||||||
|
Thread.currentThread().setContextClassLoader(originLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public void enableEngine() {
|
||||||
|
if (this.engine != null) {
|
||||||
|
engine.invokeFunction("enable", future);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public void disableEngine() {
|
||||||
|
synchronized (logger) {
|
||||||
|
if (this.engine != null) {
|
||||||
|
this.engine.invokeFunction("disable");
|
||||||
|
this.engine = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
39
src/main/java/pw/yumc/MiaoScript/api/bukkit/EngineEvent.java
Normal file
39
src/main/java/pw/yumc/MiaoScript/api/bukkit/EngineEvent.java
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package pw.yumc.MiaoScript.api.bukkit;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.bukkit.event.Cancellable;
|
||||||
|
import org.bukkit.event.Event;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
|
||||||
|
import javax.script.Bindings;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class EngineEvent extends Event implements Cancellable {
|
||||||
|
private final String event;
|
||||||
|
private final Bindings data;
|
||||||
|
|
||||||
|
private boolean cancelled = false;
|
||||||
|
|
||||||
|
public EngineEvent(String event, Bindings data) {
|
||||||
|
this.event = event;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return this.cancelled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCancelled(boolean b) {
|
||||||
|
this.cancelled = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private static final HandlerList handlerList = new HandlerList();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HandlerList getHandlers() {
|
||||||
|
return handlerList;
|
||||||
|
}
|
||||||
|
}
|
41
src/main/java/pw/yumc/MiaoScript/api/bukkit/ScriptEvent.java
Normal file
41
src/main/java/pw/yumc/MiaoScript/api/bukkit/ScriptEvent.java
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package pw.yumc.MiaoScript.api.bukkit;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.bukkit.event.Cancellable;
|
||||||
|
import org.bukkit.event.Event;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
|
||||||
|
import javax.script.Bindings;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class ScriptEvent extends Event implements Cancellable {
|
||||||
|
private final Bindings plugin;
|
||||||
|
private final String event;
|
||||||
|
private final Bindings data;
|
||||||
|
|
||||||
|
private boolean cancelled = false;
|
||||||
|
|
||||||
|
public ScriptEvent(Bindings plugin, String event, Bindings data) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.event = event;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return this.cancelled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCancelled(boolean b) {
|
||||||
|
this.cancelled = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private static final HandlerList handlerList = new HandlerList();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HandlerList getHandlers() {
|
||||||
|
return handlerList;
|
||||||
|
}
|
||||||
|
}
|
67
src/main/java/pw/yumc/MiaoScript/api/loader/JarLoader.java
Normal file
67
src/main/java/pw/yumc/MiaoScript/api/loader/JarLoader.java
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package pw.yumc.MiaoScript.api.loader;
|
||||||
|
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.lang.invoke.MethodHandle;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
public class JarLoader {
|
||||||
|
private static sun.misc.Unsafe unsafe;
|
||||||
|
private static long offset;
|
||||||
|
private static Object parentUcp;
|
||||||
|
private static Object ucp;
|
||||||
|
private static MethodHandle addURLMethodHandle;
|
||||||
|
|
||||||
|
static {
|
||||||
|
initReflect();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public static File load(File file) {
|
||||||
|
addURLMethodHandle.invoke(ucp, file.toURI().toURL());
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public static File parentLoad(File file) {
|
||||||
|
if (parentUcp == null)
|
||||||
|
throw new IllegalStateException("parentUcp is null.");
|
||||||
|
addURLMethodHandle.invoke(parentUcp, file.toURI().toURL());
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public static File load(File file, ClassLoader loader) {
|
||||||
|
addURLMethodHandle.invoke(unsafe.getObject(loader, offset), file.toURI().toURL());
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void initReflect() {
|
||||||
|
try {
|
||||||
|
ClassLoader loader = JarLoader.class.getClassLoader();
|
||||||
|
Field theUnsafe = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
|
||||||
|
theUnsafe.setAccessible(true);
|
||||||
|
unsafe = (sun.misc.Unsafe) theUnsafe.get(null);
|
||||||
|
Field field = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
|
||||||
|
MethodHandles.Lookup lookup = (MethodHandles.Lookup) unsafe.getObject(unsafe.staticFieldBase(field), unsafe.staticFieldOffset(field));
|
||||||
|
Field ucpField;
|
||||||
|
try {
|
||||||
|
ucpField = loader.getClass().getDeclaredField("ucp");
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
ucpField = loader.getClass().getSuperclass().getDeclaredField("ucp");
|
||||||
|
}
|
||||||
|
offset = unsafe.objectFieldOffset(ucpField);
|
||||||
|
ucp = unsafe.getObject(loader, offset);
|
||||||
|
Method method = ucp.getClass().getDeclaredMethod("addURL", URL.class);
|
||||||
|
addURLMethodHandle = lookup.unreflect(method);
|
||||||
|
if (loader.getParent() != null)
|
||||||
|
parentUcp = unsafe.getObject(loader.getParent(), offset);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
package pw.yumc.MiaoScript.api.loader;
|
||||||
|
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
import java.nio.MappedByteBuffer;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.nio.file.StandardCopyOption;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
|
||||||
|
public class MavenDependLoader {
|
||||||
|
public static final String MavenRepo = "https://maven.aliyun.com/repository/public";
|
||||||
|
|
||||||
|
public static File[] load(String libPath, String groupId, String artifactId, String version) {
|
||||||
|
return new File[]{
|
||||||
|
downloadAndCheckSha1(libPath, groupId, artifactId, version, "pom"),
|
||||||
|
JarLoader.load(downloadAndCheckSha1(libPath, groupId, artifactId, version, "jar"))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static File[] parentLoad(String libPath, String groupId, String artifactId, String version) {
|
||||||
|
return new File[]{
|
||||||
|
downloadAndCheckSha1(libPath, groupId, artifactId, version, "pom"),
|
||||||
|
JarLoader.parentLoad(downloadAndCheckSha1(libPath, groupId, artifactId, version, "jar"))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static File[] load(String libPath, String groupId, String artifactId, String version, ClassLoader loader) {
|
||||||
|
return new File[]{
|
||||||
|
downloadAndCheckSha1(libPath, groupId, artifactId, version, "pom"),
|
||||||
|
JarLoader.load(downloadAndCheckSha1(libPath, groupId, artifactId, version, "jar"), loader)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public static File downloadAndCheckSha1(String libPath, String groupId, String artifactId, String version, String ext) {
|
||||||
|
File sha1 = getMavenFile(libPath, groupId, artifactId, version, ext + ".sha1");
|
||||||
|
if (!sha1.exists()) {
|
||||||
|
downloadFile(sha1, groupId, artifactId, version, ext + ".sha1");
|
||||||
|
}
|
||||||
|
File file = getMavenFile(libPath, groupId, artifactId, version, ext);
|
||||||
|
if (!file.exists()) {
|
||||||
|
downloadFile(file, groupId, artifactId, version, ext);
|
||||||
|
}
|
||||||
|
if (!new String(Files.readAllBytes(sha1.toPath())).equals(getSha1(file))) {
|
||||||
|
sha1.delete();
|
||||||
|
file.delete();
|
||||||
|
throw new IllegalStateException("file " + file.getName() + " sha1 not match.");
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static File getMavenFile(String libPath, String groupId, String artifactId, String version, String ext) {
|
||||||
|
return Paths.get(libPath, groupId.replace(".", File.separator), artifactId, version, String.format("%s-%s.%s", artifactId, version, ext)).toFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public static void downloadFile(File target, String groupId, String artifactId, String version, String ext) {
|
||||||
|
target.getParentFile().mkdirs();
|
||||||
|
URLConnection connection = new URL(MavenRepo +
|
||||||
|
String.format("/%1$s/%2$s/%3$s/%2$s-%3$s.%4$s",
|
||||||
|
groupId.replace(".", "/"),
|
||||||
|
artifactId,
|
||||||
|
version,
|
||||||
|
ext)
|
||||||
|
).openConnection();
|
||||||
|
connection.setConnectTimeout(5000);
|
||||||
|
connection.setReadTimeout(120000);
|
||||||
|
connection.setUseCaches(true);
|
||||||
|
try (InputStream inputStream = connection.getInputStream()) {
|
||||||
|
Files.copy(inputStream, target.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private static String getSha1(File file) {
|
||||||
|
MessageDigest digest = MessageDigest.getInstance("SHA-1");
|
||||||
|
try (FileInputStream in = new FileInputStream(file)) {
|
||||||
|
MappedByteBuffer byteBuffer = in.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length());
|
||||||
|
digest.update(byteBuffer);
|
||||||
|
return getHash(digest.digest());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getHash(byte[] bytes) {
|
||||||
|
StringBuilder result = new StringBuilder();
|
||||||
|
for (byte b : bytes) {
|
||||||
|
result.append(String.format("%02x", b));
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package pw.yumc.MiaoScript.api.plugin;
|
||||||
|
|
||||||
|
import javax.script.Bindings;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface PluginManager {
|
||||||
|
Map<String, Bindings> getPlugins();
|
||||||
|
|
||||||
|
Bindings getPlugin(String name);
|
||||||
|
|
||||||
|
boolean has(String name);
|
||||||
|
|
||||||
|
Bindings get(String name);
|
||||||
|
|
||||||
|
boolean enable(String name);
|
||||||
|
|
||||||
|
boolean disable(String name);
|
||||||
|
|
||||||
|
boolean install(String name);
|
||||||
|
|
||||||
|
boolean uninstall(String name);
|
||||||
|
}
|
268
src/main/java/pw/yumc/MiaoScript/engine/MiaoScriptEngine.java
Normal file
268
src/main/java/pw/yumc/MiaoScript/engine/MiaoScriptEngine.java
Normal file
@ -0,0 +1,268 @@
|
|||||||
|
package pw.yumc.MiaoScript.engine;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import pw.yumc.MiaoScript.api.loader.JarLoader;
|
||||||
|
import pw.yumc.MiaoScript.api.loader.MavenDependLoader;
|
||||||
|
|
||||||
|
import javax.script.*;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 喵式脚本引擎
|
||||||
|
*
|
||||||
|
* @author 喵♂呜
|
||||||
|
* @since 2016年8月29日 上午7:51:43
|
||||||
|
*/
|
||||||
|
public class MiaoScriptEngine implements ScriptEngine, Invocable {
|
||||||
|
private final String libsRoot;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private ScriptEngine engine;
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public MiaoScriptEngine(String engineRoot) {
|
||||||
|
File libRootFile = new File(engineRoot, "libs");
|
||||||
|
libRootFile.mkdirs();
|
||||||
|
this.libsRoot = libRootFile.getCanonicalPath();
|
||||||
|
if (new File(engineRoot, "debug").exists()) {
|
||||||
|
System.setProperty("nashorn.debug", "true");
|
||||||
|
}
|
||||||
|
MavenDependLoader.load(this.libsRoot, "org.kamranzafar", "jtar", "2.3");
|
||||||
|
this.loadScriptEngine(engineRoot);
|
||||||
|
if (this.engine == null)
|
||||||
|
throw new UnsupportedOperationException("当前环境不支持 Nashorn 或 GraalJS 脚本引擎.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadScriptEngine(String engineRoot) {
|
||||||
|
if (new File(engineRoot, "graal").exists()) {
|
||||||
|
this.engine = this.loadNetworkGraalJS();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (getJavaVersion() > 15) {
|
||||||
|
this.loadGraalJS();
|
||||||
|
} else {
|
||||||
|
this.loadNashorn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadGraalJS() {
|
||||||
|
try {
|
||||||
|
this.engine = this.parentLoadNetworkNashorn();
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
this.engine = this.loadNetworkNashorn();
|
||||||
|
}
|
||||||
|
if (this.engine == null) {
|
||||||
|
this.engine = this.loadNetworkGraalJS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadNashorn() {
|
||||||
|
try {
|
||||||
|
this.createEngineByName();
|
||||||
|
} catch (final Throwable ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
String extDirs = System.getProperty("java.ext.dirs");
|
||||||
|
if (this.engine == null && extDirs != null) {
|
||||||
|
this.engine = this.loadLocalNashorn(extDirs);
|
||||||
|
}
|
||||||
|
} catch (final Throwable ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (this.engine == null) {
|
||||||
|
this.engine = this.loadNetworkNashorn();
|
||||||
|
}
|
||||||
|
} catch (final Throwable ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
if (this.engine == null)
|
||||||
|
throw new UnsupportedOperationException("当前环境不支持 Nashorn 脚本引擎.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getJavaVersion() {
|
||||||
|
String version = System.getProperty("java.version");
|
||||||
|
if (version.startsWith("1.")) {
|
||||||
|
version = version.substring(2, 3);
|
||||||
|
} else {
|
||||||
|
int dot = version.indexOf(".");
|
||||||
|
if (dot != -1) {
|
||||||
|
version = version.substring(0, dot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Integer.parseInt(version);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ScriptEngine loadLocalNashorn(String extDirs) {
|
||||||
|
String[] dirs = extDirs.split(File.pathSeparator);
|
||||||
|
for (String dir : dirs) {
|
||||||
|
File nashorn = new File(dir, "nashorn.jar");
|
||||||
|
if (nashorn.exists()) {
|
||||||
|
JarLoader.load(nashorn);
|
||||||
|
return this.createEngineByName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String nashornVersion = "15.4";
|
||||||
|
private String asmVersion = "9.6";
|
||||||
|
|
||||||
|
private ScriptEngine loadNetworkNashorn() {
|
||||||
|
MavenDependLoader.load(this.libsRoot, "org.openjdk.nashorn", "nashorn-core", this.nashornVersion);
|
||||||
|
MavenDependLoader.load(this.libsRoot, "org.ow2.asm", "asm", this.asmVersion);
|
||||||
|
MavenDependLoader.load(this.libsRoot, "org.ow2.asm", "asm-commons", this.asmVersion);
|
||||||
|
MavenDependLoader.load(this.libsRoot, "org.ow2.asm", "asm-tree", this.asmVersion);
|
||||||
|
MavenDependLoader.load(this.libsRoot, "org.ow2.asm", "asm-util", this.asmVersion);
|
||||||
|
return createEngineByFactoryClassName("org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ScriptEngine parentLoadNetworkNashorn() {
|
||||||
|
MavenDependLoader.parentLoad(this.libsRoot, "org.openjdk.nashorn", "nashorn-core", this.nashornVersion);
|
||||||
|
MavenDependLoader.parentLoad(this.libsRoot, "org.ow2.asm", "asm", this.asmVersion);
|
||||||
|
MavenDependLoader.parentLoad(this.libsRoot, "org.ow2.asm", "asm-commons", this.asmVersion);
|
||||||
|
MavenDependLoader.parentLoad(this.libsRoot, "org.ow2.asm", "asm-tree", this.asmVersion);
|
||||||
|
MavenDependLoader.parentLoad(this.libsRoot, "org.ow2.asm", "asm-util", this.asmVersion);
|
||||||
|
return createEngineByFactoryClassName("org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String graalVersion = "23.0.2";
|
||||||
|
private String icu4jVersion = "72.1";
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private ScriptEngine loadNetworkGraalJS() {
|
||||||
|
MavenDependLoader.load(this.libsRoot, "org.graalvm.js", "js", this.graalVersion);
|
||||||
|
MavenDependLoader.load(this.libsRoot, "com.ibm.icu", "icu4j", this.icu4jVersion);
|
||||||
|
MavenDependLoader.load(this.libsRoot, "org.graalvm.js", "js-scriptengine", this.graalVersion);
|
||||||
|
MavenDependLoader.load(this.libsRoot, "org.graalvm.regex", "regex", this.graalVersion);
|
||||||
|
MavenDependLoader.load(this.libsRoot, "org.graalvm.sdk", "graal-sdk", this.graalVersion);
|
||||||
|
MavenDependLoader.load(this.libsRoot, "org.graalvm.truffle", "truffle-api", this.graalVersion);
|
||||||
|
System.setProperty("polyglot.engine.AllowExperimentalOptions", "true");
|
||||||
|
System.setProperty("polyglot.engine.WarnInterpreterOnly", "false");
|
||||||
|
System.setProperty("polyglot.js.nashorn-compat", "true");
|
||||||
|
System.setProperty("polyglot.js.scripting", "true");
|
||||||
|
System.setProperty("polyglot.js.ecmascript-version", "5");
|
||||||
|
Class<?> NashornScriptEngineFactory = Class.forName("com.oracle.truffle.js.scriptengine.GraalJSEngineFactory");
|
||||||
|
Method getScriptEngine = NashornScriptEngineFactory.getMethod("getScriptEngine");
|
||||||
|
Object factory = NashornScriptEngineFactory.newInstance();
|
||||||
|
ScriptEngine engine = (ScriptEngine) getScriptEngine.invoke(factory);
|
||||||
|
Bindings bind = engine.getBindings(ScriptContext.ENGINE_SCOPE);
|
||||||
|
bind.put("polyglot.js.allowAllAccess", true);
|
||||||
|
return engine;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private ScriptEngine createEngineByName() {
|
||||||
|
return createEngineByFactoryClassName("jdk.nashorn.api.scripting.NashornScriptEngineFactory", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private ScriptEngine createEngineByFactoryClassName(String factoryClassName, boolean jdk) {
|
||||||
|
Class<?> NashornScriptEngineFactory = Class.forName(factoryClassName);
|
||||||
|
Method getScriptEngine = NashornScriptEngineFactory.getMethod("getScriptEngine", String[].class);
|
||||||
|
Object factory = NashornScriptEngineFactory.newInstance();
|
||||||
|
List<String> engineArgs = new ArrayList<>();
|
||||||
|
engineArgs.add("--language=es5");
|
||||||
|
engineArgs.add("--optimistic-types=false");
|
||||||
|
if (getJavaVersion() >= 11 && jdk) {
|
||||||
|
engineArgs.add("--no-deprecation-warning");
|
||||||
|
}
|
||||||
|
return (ScriptEngine) getScriptEngine.invoke(factory, (Object) engineArgs.toArray(new String[] {}));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bindings createBindings() {
|
||||||
|
return engine.createBindings();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object eval(final Reader reader) throws ScriptException {
|
||||||
|
return engine.eval(reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object eval(final Reader reader, final Bindings n) throws ScriptException {
|
||||||
|
return engine.eval(reader, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object eval(final Reader reader, final ScriptContext context) throws ScriptException {
|
||||||
|
return engine.eval(reader, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object eval(final String script) throws ScriptException {
|
||||||
|
return engine.eval(script);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object eval(final String script, final Bindings n) throws ScriptException {
|
||||||
|
return engine.eval(script, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object eval(final String script, final ScriptContext context) throws ScriptException {
|
||||||
|
return engine.eval(script, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object get(final String key) {
|
||||||
|
return engine.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bindings getBindings(final int scope) {
|
||||||
|
return engine.getBindings(scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ScriptContext getContext() {
|
||||||
|
return engine.getContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ScriptEngineFactory getFactory() {
|
||||||
|
return engine.getFactory();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T getInterface(final Class<T> cls) {
|
||||||
|
return ((Invocable) engine).getInterface(cls);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T getInterface(final Object thiz, final Class<T> cls) {
|
||||||
|
return ((Invocable) engine).getInterface(thiz, cls);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object invokeFunction(final String name, final Object... args) throws ScriptException, NoSuchMethodException {
|
||||||
|
return ((Invocable) engine).invokeFunction(name, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object invokeMethod(final Object thiz, final String name, final Object... args) throws ScriptException, NoSuchMethodException {
|
||||||
|
return ((Invocable) engine).invokeMethod(thiz, name, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void put(final String key, final Object value) {
|
||||||
|
engine.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBindings(final Bindings bindings, final int scope) {
|
||||||
|
engine.setBindings(bindings, scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setContext(final ScriptContext context) {
|
||||||
|
engine.setContext(context);
|
||||||
|
}
|
||||||
|
}
|
@ -1,78 +1,97 @@
|
|||||||
'use strict';
|
'use strict'
|
||||||
var log;
|
|
||||||
var boot;
|
|
||||||
var engineDisable;
|
|
||||||
var global = this;
|
var global = this;
|
||||||
/**
|
/**
|
||||||
* Init MiaoScriptEngine Runtime
|
* Init MiaoScriptEngine Runtime
|
||||||
*/
|
*/
|
||||||
(function() {
|
/*global base ScriptEngineContextHolder*/
|
||||||
var loader;
|
(function () {
|
||||||
boot = function(root, logger) {
|
var Files = Java.type('java.nio.file.Files')
|
||||||
log = logger;
|
var Paths = Java.type('java.nio.file.Paths')
|
||||||
|
var System = Java.type('java.lang.System')
|
||||||
|
var Thread = Java.type('java.lang.Thread')
|
||||||
|
var FutureTask = Java.type('java.util.concurrent.FutureTask')
|
||||||
|
|
||||||
|
global.boot = function (root, logger) {
|
||||||
|
global.scope = System.getenv("MS_NODE_CORE_SCOPE") || "@ccms"
|
||||||
|
global.logger = logger
|
||||||
// Development Env Detect
|
// Development Env Detect
|
||||||
root = root || "src/main/resources";
|
global.root = root || "src/main/resources"
|
||||||
if (__FILE__ !== "<eval>") {
|
readEnvironment()
|
||||||
logger.info('Loading custom BIOS file ' + __FILE__);
|
if (!global.debug) { checkUpgrade() }
|
||||||
global.debug = true;
|
return bootEngineThread(checkClassLoader())
|
||||||
}
|
|
||||||
if (java.nio.file.Files.exists(java.nio.file.Paths.get(root, "debug"))) {
|
|
||||||
logger.info('Running in debug mode...');
|
|
||||||
global.debug = true;
|
|
||||||
}
|
|
||||||
if (java.nio.file.Files.exists(java.nio.file.Paths.get(root, "level"))) {
|
|
||||||
global.level = base.read(java.nio.file.Paths.get(root, "level"))
|
|
||||||
logger.info('Set system level to [' + global.level + ']...');
|
|
||||||
}
|
|
||||||
// Check Class Loader, Sometimes Server will can't find plugin.yml file
|
|
||||||
loader = checkClassLoader();
|
|
||||||
// Force decompression core|node_modules to folder when not debug mode
|
|
||||||
release(root, '(core)+/.*', !global.debug);
|
|
||||||
// Async Loading MiaoScript Engine
|
|
||||||
new java.lang.Thread(function() {
|
|
||||||
load(root + '/core/ployfill.js')(root, logger);
|
|
||||||
engineDisable = require('@ms/core').default;
|
|
||||||
}, "MiaoScript thread").start()
|
|
||||||
};
|
|
||||||
|
|
||||||
var pluginYml;
|
|
||||||
function checkClassLoader() {
|
|
||||||
var classLoader = java.lang.Thread.currentThread().contextClassLoader;
|
|
||||||
pluginYml = classLoader.getResource("plugin.yml");
|
|
||||||
if (pluginYml === null) {
|
|
||||||
throw Error("Error class loader: " + classLoader.class.name + " Please contact the author MiaoWoo!");
|
|
||||||
} else {
|
|
||||||
log.info("Class loader compatible: " + classLoader.class.name);
|
|
||||||
if (classLoader.parent) {
|
|
||||||
log.info("Parent class loader: " + classLoader.parent.class.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return classLoader;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function release(root, regex, replace) {
|
function bootEngineThread(loader) {
|
||||||
var filePath = pluginYml.getFile().substring(pluginYml.getFile().indexOf("/") + 1);
|
logger.info("ScriptEngine: " + ScriptEngineContextHolder.getEngine().getEngine().class.name)
|
||||||
var jarPath = java.net.URLDecoder.decode(filePath.substring(0, filePath.indexOf('!')));
|
var future = new FutureTask(function () {
|
||||||
if (!java.nio.file.Files.exists(java.nio.file.Paths.get(jarPath))) {
|
Thread.currentThread().contextClassLoader = loader
|
||||||
jarPath = "/" + jarPath;
|
load(System.getenv("MS_NODE_CORE_POLYFILL") || 'classpath:core/polyfill.js')(root, logger)
|
||||||
}
|
var core = require(System.getenv("MS_NODE_CORE_MODULE") || (global.scope + '/core'))
|
||||||
var jar = new java.util.jar.JarFile(jarPath);
|
return core.default || core
|
||||||
var r = new RegExp(regex);
|
|
||||||
jar.stream().forEach(function(entry) {
|
|
||||||
try {
|
|
||||||
if (!entry.isDirectory()) {
|
|
||||||
if (r.test(entry.name)) {
|
|
||||||
var path = java.nio.file.Paths.get(root, entry.name);
|
|
||||||
var parentFile = path.toFile().parentFile;
|
|
||||||
if (!parentFile.exists()) { parentFile.mkdirs(); }
|
|
||||||
if (!java.nio.file.Files.exists(path) || replace) {
|
|
||||||
java.nio.file.Files.copy(loader.getResourceAsStream(entry.name), path, java.nio.file.StandardCopyOption['REPLACE_EXISTING']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (ex) {
|
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
// Async Loading MiaoScript Engine
|
||||||
|
new Thread(future, "MiaoScript thread").start()
|
||||||
|
return future
|
||||||
}
|
}
|
||||||
})();
|
|
||||||
|
global.enable = function (future) {
|
||||||
|
// await polyfill loading
|
||||||
|
if (!future.isDone()) { logger.info("MiaoScript booting...") }
|
||||||
|
// faster load core
|
||||||
|
var core = future.get()
|
||||||
|
logger.info("MiaoScript starting...")
|
||||||
|
global.engineDisableImpl = core.enable()
|
||||||
|
}
|
||||||
|
|
||||||
|
global.disable = function () {
|
||||||
|
(global.engineDisableImpl || function () {
|
||||||
|
logger.info('Error: abnormal Initialization MiaoScript Engine. Skip disable step...')
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
|
||||||
|
function readEnvironment() {
|
||||||
|
if (__FILE__.indexOf('!') === -1) {
|
||||||
|
logger.info('loading custom BIOS file ' + __FILE__)
|
||||||
|
global.debug = true
|
||||||
|
}
|
||||||
|
if (Files.exists(Paths.get(root, "debug"))) {
|
||||||
|
logger.info('running in debug mode...')
|
||||||
|
global.debug = true
|
||||||
|
}
|
||||||
|
if (Files.exists(Paths.get(root, "level"))) {
|
||||||
|
global.ScriptEngineLoggerLevel = base.read(Paths.get(root, "level"))
|
||||||
|
logger.info('found level set ScriptEngineLoggerLevel to ' + global.ScriptEngineLoggerLevel + '.')
|
||||||
|
}
|
||||||
|
if (Files.exists(Paths.get(root, "channel"))) {
|
||||||
|
global.ScriptEngineChannel = base.read(Paths.get(root, "channel"))
|
||||||
|
logger.info('found channel set ScriptEngineChannel to ' + global.ScriptEngineChannel + '.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkUpgrade() {
|
||||||
|
if (Files.exists(Paths.get(root, "upgrade"))) {
|
||||||
|
logger.info('found upgrade file starting upgrade...')
|
||||||
|
base.move(Paths.get(root, "node_modules"), Paths.get(root, "old_node_modules"))
|
||||||
|
base.delete(Paths.get(root, "upgrade"))
|
||||||
|
}
|
||||||
|
new Thread(function () {
|
||||||
|
try {
|
||||||
|
base.delete(Paths.get(root, "old_node_modules"))
|
||||||
|
} catch (ex) {
|
||||||
|
}
|
||||||
|
}, "MiaoScript node_modules clean thread").start()
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkClassLoader() {
|
||||||
|
// Check Class Loader, Sometimes Server will can't found plugin.yml file
|
||||||
|
var classLoader = Thread.currentThread().contextClassLoader
|
||||||
|
if (classLoader.getResource("bios.js") === null) {
|
||||||
|
throw Error("Error class loader: " + classLoader.class.name + " Please contact the author MiaoWoo!")
|
||||||
|
}
|
||||||
|
logger.info("Class loader compatible: " + classLoader.class.name)
|
||||||
|
if (classLoader.parent) {
|
||||||
|
logger.info("Parent class loader: " + classLoader.parent.class.name)
|
||||||
|
}
|
||||||
|
return classLoader
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
@ -1,29 +1,56 @@
|
|||||||
|
/// <reference path="./index.d.ts" />
|
||||||
// @ts-check
|
// @ts-check
|
||||||
(
|
(
|
||||||
/**
|
/**
|
||||||
* @param {{ info: (arg0: string) => void; }} logger
|
* @param {{
|
||||||
|
* info: (arg0: string) => void;
|
||||||
|
* warn: (arg0: string) => void;
|
||||||
|
* debug: (arg0: string) => void;
|
||||||
|
* error: (arg0: string) => void;
|
||||||
|
* warning: (arg0: string) => void;
|
||||||
|
* }} logger
|
||||||
*/
|
*/
|
||||||
function(logger) {
|
function (logger) {
|
||||||
function log() {
|
function log() {
|
||||||
logger.info(Array.prototype.join.call(arguments, ' '))
|
logger.info(Array.prototype.join.call(arguments, ' '))
|
||||||
}
|
}
|
||||||
|
function warn() {
|
||||||
|
logger.warn(Array.prototype.join.call(arguments, ' '))
|
||||||
|
}
|
||||||
|
function debug() {
|
||||||
|
logger.debug(Array.prototype.join.call(arguments, ' '))
|
||||||
|
}
|
||||||
|
function error() {
|
||||||
|
logger.error(Array.prototype.join.call(arguments, ' '))
|
||||||
|
}
|
||||||
|
function warning() {
|
||||||
|
logger.warning(Array.prototype.join.call(arguments, ' '))
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* @param {string} prefix
|
* @param {string} prefix
|
||||||
*/
|
*/
|
||||||
function _proxy(prefix) {
|
function _proxy(prefix) {
|
||||||
return function() {
|
return function () {
|
||||||
log('[' + prefix + ']', Array.prototype.join.call(arguments, ' '))
|
log('[' + prefix + ']', Array.prototype.join.call(arguments, ' '))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
var logProxy = {
|
||||||
log: log,
|
log: log,
|
||||||
info: log,
|
info: log,
|
||||||
ex: log,
|
ex: log,
|
||||||
// @ts-ignore
|
trace: global.ScriptEngineLoggerLevel === "trace" ? _proxy('TRACE') : global.noop,
|
||||||
trace: global.level === "trace" ? _proxy('TRACE') : global.noop,
|
debug: global.debug ? logger.debug ? debug : _proxy('DEBUG') : global.noop,
|
||||||
// @ts-ignore
|
|
||||||
debug: global.debug ? _proxy('DEBUG') : global.noop,
|
|
||||||
warn: _proxy('WARN'),
|
warn: _proxy('WARN'),
|
||||||
error: _proxy('ERROR')
|
error: _proxy('ERROR')
|
||||||
};
|
}
|
||||||
|
if (logger.warn) {
|
||||||
|
logProxy.warn = warn
|
||||||
|
}
|
||||||
|
if (logger.warning) {
|
||||||
|
logProxy.warn = warning
|
||||||
|
}
|
||||||
|
if (logger.error) {
|
||||||
|
logProxy.error = error
|
||||||
|
}
|
||||||
|
return logProxy
|
||||||
})
|
})
|
||||||
|
25
src/main/resources/core/index.d.ts
vendored
Normal file
25
src/main/resources/core/index.d.ts
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
declare const global: any
|
||||||
|
declare const root: string
|
||||||
|
declare const base: Core
|
||||||
|
declare function engineLoad(str: string | { script: string, name: string }): any
|
||||||
|
interface Core {
|
||||||
|
version: string
|
||||||
|
getClass(name: String): any
|
||||||
|
getProxyClass(): any
|
||||||
|
getJavaScriptTaskClass(): any
|
||||||
|
getInstance(): any
|
||||||
|
read(path: string): string
|
||||||
|
save(path: string, content: string): void
|
||||||
|
delete(path: string): void
|
||||||
|
}
|
||||||
|
namespace Java {
|
||||||
|
function type<T = any>(clazz: string): T
|
||||||
|
function from<T = any>(javaObj: T[]): T[]
|
||||||
|
function to<T = any>(array: T[], type?: T): T[]
|
||||||
|
function extend(...parentTypes: any[]): any
|
||||||
|
function synchronized(func: () => void, lock: any): Function
|
||||||
|
function isJavaObject(obj: any): boolean
|
||||||
|
function asJSONCompatible<T = any>(obj: T): T
|
||||||
|
//@ts-ignore
|
||||||
|
// function super(type: any);
|
||||||
|
}
|
@ -1,21 +0,0 @@
|
|||||||
(
|
|
||||||
/**
|
|
||||||
* @param {string} root
|
|
||||||
* @param {any} logger
|
|
||||||
*/
|
|
||||||
function(root, logger) {
|
|
||||||
// Init Global Value
|
|
||||||
global.root = root;
|
|
||||||
global.logger = logger;
|
|
||||||
global.NashornEngineStartTime = new Date().getTime()
|
|
||||||
global.engineLoad = load;
|
|
||||||
global.noop = global.engineDisable = engineDisable = function() { };
|
|
||||||
global.load = load = function __PreventGlobalLoadFunction__() { throw new Error('Internal engine system not allow use `load` function!'); }
|
|
||||||
global.setGlobal = function(key, value) { global[key] = value; };
|
|
||||||
// Init console and require
|
|
||||||
global.console = engineLoad(global.root + '/core/console.js')(logger);
|
|
||||||
console.log("Loading Engine at Thread", java.lang.Thread.currentThread().name)
|
|
||||||
global.require = engineLoad(global.root + '/core/require.js')(root);
|
|
||||||
require('@ms/ployfill')
|
|
||||||
}
|
|
||||||
);
|
|
32
src/main/resources/core/polyfill.js
Normal file
32
src/main/resources/core/polyfill.js
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/// <reference path="./index.d.ts" />
|
||||||
|
(
|
||||||
|
/**
|
||||||
|
* @param {string} root
|
||||||
|
* @param {any} logger
|
||||||
|
*/
|
||||||
|
function (root, logger) {
|
||||||
|
var System = Java.type('java.lang.System')
|
||||||
|
var Thread = Java.type('java.lang.Thread')
|
||||||
|
|
||||||
|
// Init Global Value
|
||||||
|
global.root = root
|
||||||
|
global.logger = logger
|
||||||
|
global.ScriptEngineStartTime = new Date().getTime()
|
||||||
|
global.engineLoad = load
|
||||||
|
global.noop = function () { }
|
||||||
|
global.load = load = function __PreventGlobalLoadFunction__() { throw new Error('Internal engine system not allow use `load` function!') }
|
||||||
|
global.setGlobal = function (key, value, config) {
|
||||||
|
if (config) {
|
||||||
|
config.value = value
|
||||||
|
Object.defineProperty(global, key, config)
|
||||||
|
} else {
|
||||||
|
global[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Init console and require
|
||||||
|
global.console = engineLoad(System.getenv("MS_NODE_CORE_CONSOLE") || 'classpath:core/console.js')(logger)
|
||||||
|
console.log("Loading Engine at Thread", Thread.currentThread().name)
|
||||||
|
global.require = engineLoad(System.getenv("MS_NODE_CORE_REQUIRE") || 'classpath:core/require.js')(root)
|
||||||
|
return require(global.scope + '/polyfill')
|
||||||
|
}
|
||||||
|
)
|
@ -24,50 +24,77 @@
|
|||||||
* 3. 如果 xx/index.json 存在 则使用 `xx/index.json` 解析为对象加载 并停止执行
|
* 3. 如果 xx/index.json 存在 则使用 `xx/index.json` 解析为对象加载 并停止执行
|
||||||
* 暂不支持 4. 如果 xx/index.msm 是一个文件 则使用MScript解析器解析 并停止执行
|
* 暂不支持 4. 如果 xx/index.msm 是一个文件 则使用MScript解析器解析 并停止执行
|
||||||
*/
|
*/
|
||||||
|
/// <reference path="./index.d.ts" />
|
||||||
// @ts-check
|
// @ts-check
|
||||||
/// <reference types="@ms/nashorn" />
|
|
||||||
(
|
(
|
||||||
/**
|
/**
|
||||||
* @param {any} parent
|
* @param {string} root
|
||||||
*/
|
*/
|
||||||
function(parent) {
|
function (root) {
|
||||||
'use strict';
|
'use strict'
|
||||||
var File = Java.type('java.io.File');
|
var System = Java.type('java.lang.System')
|
||||||
var Paths = Java.type('java.nio.file.Paths');
|
|
||||||
var Files = Java.type('java.nio.file.Files');
|
|
||||||
var StandardCopyOption = Java.type('java.nio.file.StandardCopyOption');
|
|
||||||
var FileNotFoundException = Java.type('java.io.FileNotFoundException');
|
|
||||||
|
|
||||||
var TarInputStream = Java.type('org.kamranzafar.jtar.TarInputStream');
|
var File = Java.type('java.io.File')
|
||||||
var GZIPInputStream = Java.type('java.util.zip.GZIPInputStream');
|
var Paths = Java.type('java.nio.file.Paths')
|
||||||
var BufferedInputStream = Java.type('java.io.BufferedInputStream');
|
var Files = Java.type('java.nio.file.Files')
|
||||||
|
var StandardCopyOption = Java.type('java.nio.file.StandardCopyOption')
|
||||||
|
|
||||||
|
var TarInputStream = Java.type('org.kamranzafar.jtar.TarInputStream')
|
||||||
|
var GZIPInputStream = Java.type('java.util.zip.GZIPInputStream')
|
||||||
|
var BufferedInputStream = Java.type('java.io.BufferedInputStream')
|
||||||
|
|
||||||
var URL = Java.type('java.net.URL')
|
var URL = Java.type('java.net.URL')
|
||||||
var JavaString = Java.type('java.lang.String')
|
var ByteArrayOutputStream = Java.type("java.io.ByteArrayOutputStream")
|
||||||
var separatorChar = File.separatorChar;
|
var ByteArray = Java.type("byte[]")
|
||||||
|
var Thread = Java.type('java.lang.Thread')
|
||||||
|
var Callable = Java.type('java.util.concurrent.Callable')
|
||||||
|
var Executors = Java.type('java.util.concurrent.Executors')
|
||||||
|
var TimeUnit = Java.type('java.util.concurrent.TimeUnit')
|
||||||
|
var separatorChar = File.separatorChar
|
||||||
|
|
||||||
var CoreModules = ['assert', 'async_hooks', 'child_process', 'cluster', 'crypto', 'dns', 'domain', 'events', 'fs', 'http', 'http2', 'https', 'inspector', 'net', 'os', 'path', 'vm', 'url', 'util', 'zlib', 'worker_threads']
|
var MS_NODE_PATH = System.getenv("MS_NODE_PATH") || root + separatorChar + 'node_modules'
|
||||||
|
var MS_NODE_REGISTRY = System.getenv("MS_NODE_REGISTRY") || 'https://registry.npmmirror.com'
|
||||||
|
var MS_FALLBACK_NODE_REGISTRY = System.getenv("MS_FALLBACK_NODE_REGISTRY") || 'https://repo.yumc.pw/repository/npm'
|
||||||
|
var MS_SCRIPT_PACKAGE_CENTER = System.getenv("MS_SCRIPT_PACKAGE_CENTER") || 'https://mscript.yumc.pw/api/plugin/download'
|
||||||
|
var MS_NETWORK_CONNECT_TIMEOUT = System.getenv("MS_NETWORK_CONNECT_TIMEOUT") || 5000
|
||||||
|
var MS_NETWORK_READ_TIMEOUT = System.getenv("MS_NETWORK_TIMEOUT") || 45000
|
||||||
|
var MS_NETWORK_DOWNLOAD_TIMEOUT = System.getenv("MS_NETWORK_DOWNLOAD_TIMEOUT") || 60000
|
||||||
|
var MS_NETWORK_USE_CACHES = System.getenv("MS_NETWORK_USE_CACHES") || true
|
||||||
|
|
||||||
|
var CoreModules = [
|
||||||
|
"assert", "async_hooks", "Buffer", "child_process", "cluster", "crypto",
|
||||||
|
"dgram", "dns", "domain", "events", "fs", "http", "http2", "https",
|
||||||
|
"inspector", "net", "os", "path", "perf_hooks", "process", "punycode",
|
||||||
|
"querystring", "readline", "repl", "stream", "string_decoder",
|
||||||
|
"timer", "tls", "trace_events", "tty", "url", "util",
|
||||||
|
"v8", "vm", "wasi", "worker_threads", "zlib"
|
||||||
|
]
|
||||||
|
|
||||||
|
var VersionLockModules = {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {...object} t
|
* @param {...object} t
|
||||||
*/
|
*/
|
||||||
function __assign(t) {
|
function __assign(t) {
|
||||||
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
||||||
s = arguments[i];
|
s = arguments[i]
|
||||||
if (s === undefined) { continue; };
|
if (s === undefined) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
||||||
t[p] = s[p];
|
t[p] = s[p]
|
||||||
}
|
}
|
||||||
return t;
|
return t
|
||||||
};
|
}
|
||||||
|
|
||||||
|
// noinspection JSValidateJSDoc
|
||||||
/**
|
/**
|
||||||
* 判断是否为一个文件
|
* 判断是否为一个文件
|
||||||
* @param {any} file
|
* @param {any} file
|
||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
function _isFile(file) {
|
function _isFile(file) {
|
||||||
return file.isFile && file.isFile();
|
return file && file.isFile && file.isFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -76,16 +103,14 @@
|
|||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
function _canonical(file) {
|
function _canonical(file) {
|
||||||
return file.canonicalPath;
|
return file.canonicalPath
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
function __error(message, name) {
|
||||||
* 获得文件绝对路径
|
var error = new Error(message)
|
||||||
* @param {any} file
|
if (name) { error.name = name }
|
||||||
* @returns {*}
|
console.error(message)
|
||||||
*/
|
return error
|
||||||
function _absolute(file) {
|
|
||||||
return file.absolutePath;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -93,48 +118,51 @@
|
|||||||
* 按照下列顺序查找
|
* 按照下列顺序查找
|
||||||
* 当前目录 ./
|
* 当前目录 ./
|
||||||
* 父目录 ../
|
* 父目录 ../
|
||||||
* 模块目录 /node_modules
|
* 递归模块目录 ../node_modules 到root
|
||||||
|
* 寻找 ${NODE_PATH}
|
||||||
* @param {string} name 模块名称
|
* @param {string} name 模块名称
|
||||||
* @param {string} parent 父目录
|
* @param {string} parent 父目录
|
||||||
|
* @param {any} optional 附加参数
|
||||||
*/
|
*/
|
||||||
function resolve(name, parent) {
|
function resolve(name, parent, optional) {
|
||||||
name = _canonical(name) || name;
|
name = _canonical(name) || name
|
||||||
// 解析本地目录
|
// 解析本地目录
|
||||||
if (name.startsWith('./') || name.startsWith('../')) {
|
if (optional.local) {
|
||||||
return resolveAsFile(name, parent) || resolveAsDirectory(name, parent) || undefined;
|
return resolveAsFile(name, parent) || resolveAsDirectory(name, parent) || undefined
|
||||||
} else {
|
} else {
|
||||||
|
// 解析 root 模块目录
|
||||||
|
var rootModule = resolveAsFile(name, MS_NODE_PATH) || resolveAsDirectory(name, MS_NODE_PATH)
|
||||||
|
if (rootModule) { return rootModule }
|
||||||
// 解析Node目录
|
// 解析Node目录
|
||||||
var dir = [parent, 'node_modules'].join(separatorChar);
|
var dir = [parent, 'node_modules'].join(separatorChar)
|
||||||
if (cacheModuleIds[name]) return cacheModuleIds[name]
|
return resolveAsFile(name, dir) || resolveAsDirectory(name, dir) ||
|
||||||
cacheModuleIds[name] = resolveAsFile(name, dir) || resolveAsDirectory(name, dir) ||
|
(parent && parent.toString().startsWith(root) ?
|
||||||
// @ts-ignore
|
resolve(name, new File(parent).getParent(), optional) : undefined)
|
||||||
(parent && parent.toString().startsWith(root) ? resolve(name, new File(parent).getParent()) : undefined);
|
|
||||||
return cacheModuleIds[name];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析文件
|
* 解析文件
|
||||||
* @param {string} file 文件
|
* @param {any} file 文件
|
||||||
* @param {string | undefined} dir 目录
|
* @param {string | undefined} dir 目录
|
||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
function resolveAsFile(file, dir) {
|
function resolveAsFile(file, dir) {
|
||||||
file = dir != undefined ? new File(dir, file) : new File(file);
|
file = dir !== undefined ? new File(dir, file) : new File(file)
|
||||||
// 直接文件
|
// 直接文件
|
||||||
// @ts-ignore
|
// 只解析带后缀的文件 其他文件视为非法文件
|
||||||
if (file.isFile()) {
|
if (file.isFile() && file.name.lastIndexOf('.') != -1) {
|
||||||
return file;
|
return file
|
||||||
}
|
}
|
||||||
// JS文件
|
// JS文件
|
||||||
var js = new File(normalizeName(_absolute(file), '.js'));
|
var js = new File(normalizeName(_canonical(file), '.js'))
|
||||||
if (js.isFile()) {
|
if (js.isFile()) {
|
||||||
return js;
|
return js
|
||||||
}
|
}
|
||||||
// JSON文件
|
// JSON文件
|
||||||
var json = new File(normalizeName(_absolute(file), '.json'));
|
var json = new File(normalizeName(_canonical(file), '.json'))
|
||||||
if (json.isFile()) {
|
if (json.isFile()) {
|
||||||
return json;
|
return json
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,17 +173,20 @@
|
|||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
function resolveAsDirectory(file, dir) {
|
function resolveAsDirectory(file, dir) {
|
||||||
dir = dir != undefined ? new File(dir, file) : new File(file);
|
dir = dir !== undefined ? new File(dir, file) : new File(file)
|
||||||
var _package = new File(dir, 'package.json');
|
var _package = new File(dir, 'package.json')
|
||||||
if (_package.exists()) {
|
if (_package.exists()) {
|
||||||
// @ts-ignore
|
try {
|
||||||
var json = JSON.parse(base.read(_package));
|
var json = JSON.parse(base.read(_package))
|
||||||
if (json.main) {
|
if (json.main) {
|
||||||
return resolveAsFile(json.main, dir);
|
return resolveAsFile(json.main, dir) || resolveAsFile('index.js', new File(dir, json.main))
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
throw __error('resolveAsDirectory ' + dir + ' package.json error ' + error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if no package or package.main exists, look for index.js
|
// if no package or package.main exists, look for index.js
|
||||||
return resolveAsFile('index.js', dir);
|
return resolveAsFile('index.js', dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -165,57 +196,69 @@
|
|||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
function normalizeName(fileName, ext) {
|
function normalizeName(fileName, ext) {
|
||||||
var extension = ext || '.js';
|
var extension = ext || '.js'
|
||||||
if (fileName.endsWith(extension)) {
|
if (fileName.endsWith(extension)) {
|
||||||
return fileName;
|
return fileName
|
||||||
}
|
}
|
||||||
return fileName + extension;
|
return fileName + extension
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查模块缓存
|
* 检查模块缓存
|
||||||
* @param {string} id 模块ID
|
* @param {string} id 模块ID
|
||||||
* @param {string} name 模块名称
|
|
||||||
* @param {any} file 模块文件
|
* @param {any} file 模块文件
|
||||||
* @param {any} optional 附加选项
|
* @param {any} optional 附加选项
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
function getCacheModule(id, name, file, optional) {
|
function getCacheModule(id, file, optional) {
|
||||||
var module = cacheModules[id];
|
var module = cacheModules[id]
|
||||||
if (optional.cache && module) {
|
if (optional.cache && module) {
|
||||||
return module;
|
return module
|
||||||
}
|
}
|
||||||
return createModule(id, name, file, optional)
|
return createModule(id, file, optional)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 编译模块
|
* 编译模块
|
||||||
* @param {string} id 模块ID
|
* @param {string} id 模块ID
|
||||||
* @param {string} name 模块名称
|
|
||||||
* @param {any} file 模块文件
|
* @param {any} file 模块文件
|
||||||
* @param {any} optional 附加选项
|
* @param {any} optional 附加选项
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
function createModule(id, name, file, optional) {
|
function createModule(id, file, optional) {
|
||||||
console.trace('Loading module', name + '(' + id + ')', 'Optional', JSON.stringify(optional));
|
var filename = file.name
|
||||||
|
var lastDotIndexOf = filename.lastIndexOf('.')
|
||||||
|
if (lastDotIndexOf == -1) {
|
||||||
|
throw __error("can't require file " + file + '. error: module must include file ext.')
|
||||||
|
}
|
||||||
|
var name = filename.substring(0, lastDotIndexOf)
|
||||||
|
var ext = filename.substring(lastDotIndexOf + 1)
|
||||||
|
var loader = requireLoaders[ext]
|
||||||
|
if (!loader) {
|
||||||
|
throw __error('Unsupported module ' + filename + '. require loader not found.')
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @type any
|
||||||
|
*/
|
||||||
var module = {
|
var module = {
|
||||||
id: id,
|
id: id,
|
||||||
|
name: name,
|
||||||
|
ext: ext,
|
||||||
|
parent: optional.parent,
|
||||||
exports: {},
|
exports: {},
|
||||||
loaded: false,
|
loaded: false,
|
||||||
require: getRequire(file.parentFile, id)
|
loader: loader,
|
||||||
};
|
path: _canonical(file.parentFile),
|
||||||
cacheModules[id] = module;
|
filename: _canonical(file),
|
||||||
var cfile = _canonical(file);
|
children: []
|
||||||
if (cfile.endsWith('.js')) {
|
|
||||||
compileJs(module, file, optional);
|
|
||||||
} else if (cfile.endsWith('.json')) {
|
|
||||||
compileJson(module, file);
|
|
||||||
} else if (cfile.endsWith('.msm')) {
|
|
||||||
throw Error('Unsupported MiaoScript module!');
|
|
||||||
} else {
|
|
||||||
throw Error('Unknown file type ' + cfile);
|
|
||||||
}
|
}
|
||||||
return module;
|
module.require = getRequire(module)
|
||||||
|
if (module.parent && module.parent.children && module.parent.children.indexOf(module) == -1) {
|
||||||
|
module.parent.children.push(module)
|
||||||
|
}
|
||||||
|
console.trace('Loading module', name + '(' + id + ')', 'Optional', JSON.stringify(__assign(optional, { parent: undefined })))
|
||||||
|
cacheModules[id] = module
|
||||||
|
return loader(module, file, __assign(optional, { id: id }))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -223,79 +266,216 @@
|
|||||||
* @param {any} module JS模块
|
* @param {any} module JS模块
|
||||||
* @param {any} file JS文件
|
* @param {any} file JS文件
|
||||||
* @param {any} optional 附加选项
|
* @param {any} optional 附加选项
|
||||||
* @returns {void}
|
* @returns {any}
|
||||||
*/
|
*/
|
||||||
function compileJs(module, file, optional) {
|
function compileJsFile(module, file, optional) {
|
||||||
// @ts-ignore
|
return compileJs(module, base.read(file), optional)
|
||||||
var origin = base.read(file);
|
}
|
||||||
if (optional.hook) {
|
|
||||||
origin = optional.hook(origin);
|
/**
|
||||||
|
* 预编译JS
|
||||||
|
* @param {any} module JS模块
|
||||||
|
* @param {any} script JS脚本
|
||||||
|
* @param {any} optional 附加选项
|
||||||
|
* @returns {any}
|
||||||
|
*/
|
||||||
|
function compileJs(module, script, optional) {
|
||||||
|
if (optional.beforeCompile) {
|
||||||
|
script = optional.beforeCompile(script)
|
||||||
}
|
}
|
||||||
// 2019-09-19 使用 扩展函数直接 load 无需保存/删除文件
|
// 2019-09-19 使用 扩展函数直接 load 无需保存/删除文件
|
||||||
// 2020-02-16 结尾新增换行 防止有注释导致加载失败
|
// 2020-02-16 结尾新增换行 防止有注释导致加载失败
|
||||||
// @ts-ignore
|
var wrapperScript = '(function (module, exports, require, __dirname, __filename) {' + script + '\n});'
|
||||||
var compiledWrapper = engineLoad({ script: '(function $(module, exports, require, __dirname, __filename) {' + origin + '\n});', name: file });
|
var compiledWrapper = engineLoad({
|
||||||
|
script: wrapperScript,
|
||||||
|
name: optional.id
|
||||||
|
})
|
||||||
compiledWrapper.apply(module.exports, [
|
compiledWrapper.apply(module.exports, [
|
||||||
module, module.exports, module.require, file.parentFile, file
|
module, module.exports, module.require, module.path, module.filename
|
||||||
]);
|
])
|
||||||
module.loaded = true;
|
module.loaded = true
|
||||||
|
if (optional.afterCompile) {
|
||||||
|
module = optional.afterCompile(module) || module
|
||||||
|
}
|
||||||
|
return module
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 预编译Json
|
* 预编译Json
|
||||||
* @param {{ id?: string | null; exports?: {}; loaded: any; require?: any; }} module Json模块
|
* @param {{ id?: string | null; exports?: {}; loaded: any; require?: any; }} module Json模块
|
||||||
* @param {any} file Json 文件
|
* @param {any} file Json 文件
|
||||||
* @returns {void}
|
* @returns {any}
|
||||||
*/
|
*/
|
||||||
function compileJson(module, file) {
|
function compileJson(module, file) {
|
||||||
// @ts-ignore
|
module.exports = JSON.parse(base.read(file))
|
||||||
module.exports = JSON.parse(base.read(file));
|
module.loaded = true
|
||||||
module.loaded = true;
|
return module
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得网络链接
|
||||||
|
* @param {string} url 网址
|
||||||
|
*/
|
||||||
|
function getConnection(url) {
|
||||||
|
var connection = new URL(url).openConnection()
|
||||||
|
connection.setConnectTimeout(MS_NETWORK_CONNECT_TIMEOUT)
|
||||||
|
connection.setReadTimeout(MS_NETWORK_READ_TIMEOUT)
|
||||||
|
connection.setUseCaches(MS_NETWORK_USE_CACHES)
|
||||||
|
return connection
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得网络流
|
||||||
|
* @param {string} url 网址
|
||||||
|
*/
|
||||||
|
function getConnectionStream(url) {
|
||||||
|
var connection = getConnection(url)
|
||||||
|
return connection.getInputStream()
|
||||||
|
}
|
||||||
|
|
||||||
|
function splitVersionFromName(name) {
|
||||||
|
// process package name
|
||||||
|
// es6-map/implement => [es6-map/implement, undefined]
|
||||||
|
// @ccms/common/dist/reflect => [@ccms/common, undefined]
|
||||||
|
var name_arr = name.split('/')
|
||||||
|
var module_name = ''
|
||||||
|
var module_version = ''
|
||||||
|
if (name.startsWith('@')) {
|
||||||
|
var module_version_arr = name_arr[1].split('@')
|
||||||
|
module_name = name_arr[0] + '/' + module_version_arr[0]
|
||||||
|
} else {
|
||||||
|
var module_version_arr = name_arr[0].split('@')
|
||||||
|
module_name = module_version_arr[0]
|
||||||
|
}
|
||||||
|
// handle internal package version
|
||||||
|
if (name.startsWith(global.scope) && global.ScriptEngineChannel) {
|
||||||
|
module_version = global.ScriptEngineChannel
|
||||||
|
} else {
|
||||||
|
module_version = module_version_arr[1]
|
||||||
|
}
|
||||||
|
return [module_name, module_version]
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 尝试从网络下载依赖包
|
* 尝试从网络下载依赖包
|
||||||
* @param {string} name 包名称
|
* @param {string} name 包名称
|
||||||
|
* @param {string} optional 附加选项
|
||||||
|
* @param {number} retry 重试次数
|
||||||
*/
|
*/
|
||||||
function download(name) {
|
function download(name, optional, retry) {
|
||||||
// handle name es6-map/implement => es6-map @ms/common/dist/reflect => @ms/common
|
var name_arr = splitVersionFromName(name)
|
||||||
var name_arr = name.split('/');
|
var module_name = name_arr[0]
|
||||||
var module_name = name.startsWith('@') ? name_arr[0] + '/' + name_arr[1] : name_arr[0];
|
var module_version = name_arr[1]
|
||||||
// at windows need replace file name java.lang.IllegalArgumentException: Invalid prefix or suffix
|
try {
|
||||||
var tempFile = Files.createTempFile(module_name.replace('/', '_'), '.json');
|
var target = MS_NODE_PATH + separatorChar + module_name
|
||||||
var info = fetchPackageInfo(module_name, tempFile);
|
if (new File(target, 'package.json').exists()) { return name }
|
||||||
var url = info.versions[info['dist-tags']['latest']].dist.tarball;
|
var info = fetchPackageInfo(module_name)
|
||||||
console.log('fetch node_module ' + module_name + ' from ' + url + ' waiting...')
|
if (!module_version) {
|
||||||
var tis = new TarInputStream(new BufferedInputStream(new GZIPInputStream(new URL(url).openStream())));
|
// if not special version get from lock or tag
|
||||||
// @ts-ignore
|
module_version = VersionLockModules[module_name]
|
||||||
var entry; var target = root + separatorChar + 'node_modules' + separatorChar + module_name;
|
} else if (!/\d+\.\d+\.\w+/.test(module_version)) {
|
||||||
while ((entry = tis.getNextEntry()) != null) {
|
// maybe module_version = latest if special version not exist then fallback latest
|
||||||
var targetPath = Paths.get(target + separatorChar + entry.getName().substring(8));
|
console.log('try get node_module ' + module_name + ' version from ' + module_version + ' tag waiting...')
|
||||||
targetPath.toFile().getParentFile().mkdirs();
|
module_version = info['dist-tags'][module_version]
|
||||||
Files.copy(tis, targetPath, StandardCopyOption.REPLACE_EXISTING);
|
}
|
||||||
|
if (!module_version) {
|
||||||
|
console.log('try get node_module ' + module_name + ' version from latest tag waiting...')
|
||||||
|
module_version = info['dist-tags']['latest']
|
||||||
|
}
|
||||||
|
if (!module_version) { throw __error('fetch node_module ' + module_name + " failed. can't found version from " + name + ".", 'ModuleNotFoundError') }
|
||||||
|
var _version = info.versions[module_version]
|
||||||
|
if (!_version) { throw __error('fetch node_module ' + module_name + ' version ' + module_version + " failed. can't found tarball from versions.", 'ModuleNotFoundError') }
|
||||||
|
var url = _version.dist.tarball
|
||||||
|
console.log('fetch node_module ' + module_name + ' version ' + module_version + ' waiting...')
|
||||||
|
return executor.submit(new Callable(function () {
|
||||||
|
var tis = new TarInputStream(new BufferedInputStream(new GZIPInputStream(getConnectionStream(url))))
|
||||||
|
var entry
|
||||||
|
while ((entry = tis.getNextEntry()) != null) {
|
||||||
|
var targetPath = Paths.get(target + separatorChar + entry.getName().substring(8))
|
||||||
|
var parentFile = targetPath.toFile().getParentFile()
|
||||||
|
if (!parentFile.isDirectory()) {
|
||||||
|
parentFile.delete()
|
||||||
|
parentFile.mkdirs()
|
||||||
|
}
|
||||||
|
Files.copy(tis, targetPath, StandardCopyOption.REPLACE_EXISTING)
|
||||||
|
}
|
||||||
|
return name
|
||||||
|
})).get(MS_NETWORK_DOWNLOAD_TIMEOUT, TimeUnit.MILLISECONDS)
|
||||||
|
} catch (error) {
|
||||||
|
if (error.name == 'ModuleNotFoundError') { throw error }
|
||||||
|
if (retry > 3) { throw __error('fetch node_module ' + module_name + ' version ' + module_version + ' failed. greater than 3 times stop retry.') }
|
||||||
|
console.log('fetch node_module ' + module_name + ' version ' + module_version + ' failed retrying...')
|
||||||
|
return download(name, optional, ++retry)
|
||||||
}
|
}
|
||||||
return name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function fetchPackageInfo(module_name, tempFile) {
|
/**
|
||||||
|
* 获取包信息
|
||||||
|
* @param {string} module_name
|
||||||
|
*/
|
||||||
|
function fetchPackageInfo(module_name) {
|
||||||
|
var content = ''
|
||||||
try {
|
try {
|
||||||
Files.copy(new URL('https://registry.npm.taobao.org/' + module_name).openStream(), tempFile, StandardCopyOption.REPLACE_EXISTING);
|
content = fetchContent(MS_NODE_REGISTRY + '/' + module_name)
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
console.debug('can\'t fetch package ' + module_name + ' from taobao registry. try fetch from yumc registry...')
|
console.warn("can't fetch package " + module_name + ' from ' + MS_NODE_REGISTRY + ' registry. try fetch from ' + MS_FALLBACK_NODE_REGISTRY + ' registry...')
|
||||||
Files.copy(new URL('https://repo.yumc.pw/repository/npm/' + module_name).openStream(), tempFile, StandardCopyOption.REPLACE_EXISTING);
|
content = fetchContent(MS_FALLBACK_NODE_REGISTRY + '/' + module_name)
|
||||||
}
|
}
|
||||||
tempFile.toFile().deleteOnExit();
|
return JSON.parse(content)
|
||||||
return JSON.parse(new JavaString(Files.readAllBytes(tempFile), 'UTF-8'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取网络内容
|
||||||
|
* @param {string} url 网址
|
||||||
|
* @param {number} [timeout] 超时时间
|
||||||
|
*/
|
||||||
|
function fetchContent(url, timeout) {
|
||||||
|
return executor.submit(new Callable(function fetchContent() {
|
||||||
|
var input = getConnectionStream(url)
|
||||||
|
var output = new ByteArrayOutputStream()
|
||||||
|
var buffer = new ByteArray(1024)
|
||||||
|
try {
|
||||||
|
var n
|
||||||
|
while ((n = input.read(buffer)) !== -1) {
|
||||||
|
output.write(buffer, 0, n)
|
||||||
|
}
|
||||||
|
return output.toString("UTF-8")
|
||||||
|
} finally {
|
||||||
|
input.close()
|
||||||
|
output.close()
|
||||||
|
}
|
||||||
|
})).get(timeout || MS_NETWORK_READ_TIMEOUT, TimeUnit.MILLISECONDS)
|
||||||
|
}
|
||||||
|
|
||||||
|
var lastModule = ''
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查核心模块
|
* 检查核心模块
|
||||||
* @param {string} name
|
* @param {string} name
|
||||||
|
* @param {string} path
|
||||||
*/
|
*/
|
||||||
function checkCoreModule(name) {
|
function checkCoreModule(name, path, optional) {
|
||||||
if (CoreModules.indexOf(name) != -1) {
|
if (name.startsWith('@ms') && lastModule.endsWith('.js')) {
|
||||||
throw new Error("Can't load nodejs core module " + name + " . maybe later will auto replace to @ms/" + name + ' to compatible...')
|
console.warn(lastModule + ' load deprecated module ' + name + ' auto replace to ' + (name = name.replace('@ms', global.scope)) + '...')
|
||||||
|
return name
|
||||||
|
} else {
|
||||||
|
lastModule = name
|
||||||
}
|
}
|
||||||
|
if (CoreModules.indexOf(name) !== -1) {
|
||||||
|
var newName = global.scope + '/nodejs/dist/' + name
|
||||||
|
if (resolve(newName, path, optional) !== undefined) {
|
||||||
|
return newName
|
||||||
|
}
|
||||||
|
throw __error("can't load nodejs core module " + name + " . maybe later will auto replace to " + global.scope + "/nodejs/" + name + ' to compatible...')
|
||||||
|
}
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查缓存模块
|
||||||
|
*/
|
||||||
|
function checkCacheModule(optional) {
|
||||||
|
return optional.local ? cacheModuleIds[optional.parent.id] && cacheModuleIds[optional.parent.id][optional.path] : cacheModuleIds[optional.path]
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -306,89 +486,286 @@
|
|||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
function _require(name, path, optional) {
|
function _require(name, path, optional) {
|
||||||
checkCoreModule(name);
|
// require direct file
|
||||||
var file = new File(name);
|
var file = _isFile(name) ? name : new File(name)
|
||||||
file = _isFile(file) ? file : resolve(name, path);
|
if (_isFile(file) && file.name.lastIndexOf('.') != -1) {
|
||||||
optional = __assign({ cache: true }, optional);
|
return _requireFile(file, optional)
|
||||||
if (file === undefined) {
|
|
||||||
try {
|
|
||||||
// excloud local dir, prevent too many recursive call and cache not found module
|
|
||||||
if (name.startsWith('.') || name.startsWith('/') || optional.recursive || notFoundModules[name]) {
|
|
||||||
console.log(name, path, optional, notFoundModules[name])
|
|
||||||
throw new Error("Can't found module " + name + '(' + JSON.stringify(optional) + ') at local ' + path + ' or network!')
|
|
||||||
}
|
|
||||||
optional.recursive = true;
|
|
||||||
return _require(download(name), path, optional);
|
|
||||||
} catch (ex) {
|
|
||||||
notFoundModules[name] = true;
|
|
||||||
throw new FileNotFoundException("Can't found module " + name + ' in directory ' + path + ' ERROR: ' + ex)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// require cache module
|
||||||
|
var cachePath = checkCacheModule(optional)
|
||||||
|
var cacheFile = new File(cachePath)
|
||||||
|
if (cachePath && cacheFile.exists()) {
|
||||||
|
return _requireFile(cacheFile, optional)
|
||||||
|
}
|
||||||
|
// check core module
|
||||||
|
name = checkCoreModule(name, path, optional)
|
||||||
|
var file = resolve(name, path, optional)
|
||||||
|
// search module
|
||||||
|
if (file === undefined) {
|
||||||
|
// excloud local dir, prevent too many recursive call and cache not found module
|
||||||
|
if (optional.local || optional.recursive || notFoundModules[name]) {
|
||||||
|
delete optional.parent
|
||||||
|
throw __error("can't found module " + name + '(' + JSON.stringify(optional) + ') at local ' + path + ' or network!')
|
||||||
|
}
|
||||||
|
optional.recursive = true
|
||||||
|
return _require(download(name, optional, 1), path, optional)
|
||||||
|
}
|
||||||
|
setCacheModule(file, optional)
|
||||||
|
return _requireFile(file, optional)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置模块缓存
|
||||||
|
* @param {any} file
|
||||||
|
* @param {any} optional
|
||||||
|
*/
|
||||||
|
function setCacheModule(file, optional) {
|
||||||
|
if (optional.local) {
|
||||||
|
var parent = cacheModuleIds[optional.parent.id]
|
||||||
|
if (!parent) {
|
||||||
|
cacheModuleIds[optional.parent.id] = {}
|
||||||
|
}
|
||||||
|
return cacheModuleIds[optional.parent.id][optional.path] = _canonical(file)
|
||||||
|
}
|
||||||
|
return cacheModuleIds[optional.path] = _canonical(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
function _requireFile(file, optional) {
|
||||||
// 重定向文件名称和类型
|
// 重定向文件名称和类型
|
||||||
return getCacheModule(_canonical(file), file.name.split('.')[0], file, optional);
|
return getCacheModule(_canonical(file), file, optional)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 闭包方法
|
* 闭包方法
|
||||||
* @param {string} parent 父目录
|
* @param {any} parent 父模块
|
||||||
* @param {string} parentId
|
|
||||||
* @returns {Function}
|
* @returns {Function}
|
||||||
*/
|
*/
|
||||||
function exports(parent, parentId) {
|
function exports(parent) {
|
||||||
var __DynamicRequire__ =
|
/**
|
||||||
/**
|
* @param {string} path
|
||||||
* @param {string} path
|
* @param {any} optional
|
||||||
* @param {any} optional
|
*/
|
||||||
*/
|
var require = function __DynamicRequire__(path, optional) {
|
||||||
function __DynamicRequire__(path, optional) {
|
if (!path) {
|
||||||
return _require(path, parent, __assign({ parentId: parentId }, optional)).exports;
|
throw __error("require path can't be undefined or empty!")
|
||||||
}
|
}
|
||||||
return __DynamicRequire__
|
var optional = __assign({
|
||||||
|
cache: true,
|
||||||
|
parent: parent,
|
||||||
|
path: path,
|
||||||
|
local: path.startsWith('.') || path.startsWith('/')
|
||||||
|
}, optional)
|
||||||
|
return _require(path, parent.path, optional).exports
|
||||||
|
}
|
||||||
|
require.resolve = function __DynamicResolve__(path, optional) {
|
||||||
|
return _canonical(new File(resolve(path, root, __assign({
|
||||||
|
parent: parent,
|
||||||
|
cache: true,
|
||||||
|
local: path.startsWith('.') || path.startsWith('/')
|
||||||
|
}, optional))))
|
||||||
|
}
|
||||||
|
return require
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} parent
|
* @param {string} name
|
||||||
* @param {string} parentId
|
|
||||||
*/
|
*/
|
||||||
function getRequire(parent, parentId) {
|
function __DynamicClear__(name) {
|
||||||
|
for (var cacheModule in cacheModules) {
|
||||||
|
if (cacheModule.indexOf(name) !== -1) {
|
||||||
|
console.trace('clear module ' + cacheModule + ' ...')
|
||||||
|
delete cacheModules[cacheModule]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function __DynamicDisable__() {
|
||||||
|
base.save(cacheModuleIdsFile, JSON.stringify(upgradeMode ? {} : cacheModuleIds))
|
||||||
|
for (var cacheModule in cacheModules) {
|
||||||
|
delete cacheModules[cacheModule]
|
||||||
|
}
|
||||||
|
cacheModules = {}
|
||||||
|
for (var cacheModuleId in cacheModuleIds) {
|
||||||
|
delete cacheModuleIds[cacheModuleId]
|
||||||
|
}
|
||||||
|
cacheModuleIds = {}
|
||||||
|
notFoundModules = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function __setUpgradeMode__(status) {
|
||||||
|
upgradeMode = status
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {any} parent
|
||||||
|
*/
|
||||||
|
function getRequire(parent) {
|
||||||
/**
|
/**
|
||||||
* @type {any} require
|
* @type {any} require
|
||||||
*/
|
*/
|
||||||
var require = exports(parent, parentId)
|
var require = exports(parent)
|
||||||
require.resolve =
|
require.main = mainRequire
|
||||||
/**
|
require.cache = cacheModules
|
||||||
* @param {string} name
|
require.clear = __DynamicClear__
|
||||||
*/
|
require.disable = __DynamicDisable__
|
||||||
function __DynamicResolve__(name) {
|
require.setUpgradeMode = __setUpgradeMode__
|
||||||
return _canonical(new File(resolve(name, parent)))
|
require.loader = {
|
||||||
|
register: registerLoader,
|
||||||
|
get: getLoader,
|
||||||
|
unregister: unregisterLoader,
|
||||||
|
}
|
||||||
|
require.loaders = requireLoaders
|
||||||
|
require.internal = {
|
||||||
|
coreModules: CoreModules,
|
||||||
|
cacheModules: cacheModules,
|
||||||
|
cacheModuleIds: cacheModuleIds,
|
||||||
|
notFoundModules: notFoundModules,
|
||||||
|
versionLockModules: VersionLockModules
|
||||||
|
}
|
||||||
|
require.loadCoreScript = loadCoreScript
|
||||||
|
return require
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} ext
|
||||||
|
* @param {any} loader
|
||||||
|
*/
|
||||||
|
function registerLoader(ext, loader) {
|
||||||
|
if (requireLoaders[ext]) {
|
||||||
|
return console.error('require loader ' + ext + ' already register ignore. if you want override loader please unregister before register.')
|
||||||
|
}
|
||||||
|
requireExts.push(ext)
|
||||||
|
requireLoaders[ext] = loader
|
||||||
|
console.info('register require loader ' + ext + ' => ' + (loader.name || '<anonymous>') + '.')
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param {*} ext
|
||||||
|
*/
|
||||||
|
function getLoader(ext) {
|
||||||
|
return requireLoaders[ext]
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param {*} ext
|
||||||
|
*/
|
||||||
|
function unregisterLoader(ext) {
|
||||||
|
requireExts.splice(requireExts.indexOf(ext), 1);
|
||||||
|
delete requireLoaders[ext]
|
||||||
|
console.info('unregister require loader ' + ext + '.')
|
||||||
|
}
|
||||||
|
|
||||||
|
function printRequireInfo() {
|
||||||
|
console.info('Initialization require module.')
|
||||||
|
console.info('ParentDir:', root)
|
||||||
|
console.info('Require module env list:')
|
||||||
|
console.info('- JAVA_VERSION:', System.getProperty("java.version"))
|
||||||
|
console.info('- PLUGIN_VERSION:', base.version)
|
||||||
|
console.info('- MS_NODE_PATH:', MS_NODE_PATH.startsWith(root) ? MS_NODE_PATH.split(root)[1] : MS_NODE_PATH)
|
||||||
|
console.info('- MS_NODE_REGISTRY:', MS_NODE_REGISTRY)
|
||||||
|
console.info('- MS_FALLBACK_NODE_REGISTRY:', MS_FALLBACK_NODE_REGISTRY)
|
||||||
|
}
|
||||||
|
|
||||||
|
function initCacheModuleIds() {
|
||||||
|
try {
|
||||||
|
cacheModuleIds = JSON.parse(base.read(cacheModuleIdsFile))
|
||||||
|
if (cacheModuleIds['@ccms-cache-module-root'] != MS_NODE_PATH) {
|
||||||
|
throw __error('canonicalRoot Change ' + cacheModuleIds['@ccms-cache-module-root'] + ' to ' + MS_NODE_PATH + ' Clear Cache!')
|
||||||
}
|
}
|
||||||
require.clear =
|
console.log('Read cacheModuleIds from file', cacheModuleIdsFile.startsWith(root) ? cacheModuleIdsFile.split(root)[1] : cacheModuleIdsFile)
|
||||||
/**
|
} catch (error) {
|
||||||
* @param {string} name
|
cacheModuleIds = {}
|
||||||
*/
|
cacheModuleIds['@ccms-cache-module-root'] = MS_NODE_PATH
|
||||||
function __DynamicClear__(name) {
|
console.log('Initialization new cacheModuleIds: ' + error)
|
||||||
var moduleId = require.resolve(name)
|
}
|
||||||
console.trace('Clear module ' + name + '(' + moduleId + ') ...')
|
}
|
||||||
return delete cacheModules[moduleId]
|
|
||||||
|
function initVersionLock() {
|
||||||
|
try {
|
||||||
|
var version_lock_url = MS_SCRIPT_PACKAGE_CENTER + '?name=version_lock' + (global.debug ? '-debug' : '')
|
||||||
|
VersionLockModules = JSON.parse(fetchContent(version_lock_url, 5000))
|
||||||
|
try {
|
||||||
|
VersionLockModules = __assign(VersionLockModules, JSON.parse(base.read(localVersionLockFile)))
|
||||||
|
} catch (e) {
|
||||||
}
|
}
|
||||||
return require;
|
} catch (error) {
|
||||||
|
console.warn("无法获取到最新的版本锁定信息 使用默认配置.")
|
||||||
|
console.warn("InitVersionLock Error:", error)
|
||||||
|
console.debug(error)
|
||||||
|
VersionLockModules = {
|
||||||
|
"@babel/standalone": "7.12.18",
|
||||||
|
"crypto-js": "3.3.0",
|
||||||
|
"core-js": "3.33.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.info('Lock module version List:')
|
||||||
|
for (var key in VersionLockModules) {
|
||||||
|
console.info('- ' + key + ': ' + VersionLockModules[key])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function initRequireLoader(require) {
|
||||||
|
registerLoader('js', compileJsFile)
|
||||||
|
registerLoader('json', compileJson)
|
||||||
|
try {
|
||||||
|
loadCoreScript('require_loader')(require)
|
||||||
|
} catch (error) {
|
||||||
|
console.warn("无法获取到最新的加载器信息 使用默认配置.")
|
||||||
|
console.warn("InitRequireLoader Error:", error)
|
||||||
|
console.debug(error)
|
||||||
|
registerLoader('ms', compileJsFile)
|
||||||
|
}
|
||||||
|
require.main = mainRequire = require
|
||||||
|
return require
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadCoreScript(name) {
|
||||||
|
return engineLoad({
|
||||||
|
script: fetchContent(MS_SCRIPT_PACKAGE_CENTER + '?name=' + name, 5000),
|
||||||
|
name: 'core/' + name + '.js'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof parent === 'string') {
|
if (typeof parent === 'string') {
|
||||||
parent = new File(parent);
|
parent = new File(parent)
|
||||||
}
|
}
|
||||||
|
var mainRequire = undefined
|
||||||
/**
|
/**
|
||||||
* @type {{[key:string]:any}} cacheModules
|
* require 支持的后缀
|
||||||
|
* @type {string[]} requireExts
|
||||||
*/
|
*/
|
||||||
var cacheModules = {};
|
var requireExts = []
|
||||||
/**
|
/**
|
||||||
* @type {{[key:string]:string}} cacheModules
|
* require加载器
|
||||||
|
* @type {{[key:string]:(module:any, file:string, optional?:any)=>any}} requireLoader
|
||||||
*/
|
*/
|
||||||
var cacheModuleIds = {};
|
var requireLoaders = {}
|
||||||
/**
|
/**
|
||||||
* @type {{[key:string]:boolean}} cacheModules
|
* 已缓存的模块
|
||||||
|
* @type {{[key:string]:any}} [cacheModules]
|
||||||
*/
|
*/
|
||||||
var notFoundModules = {};
|
var cacheModules = {}
|
||||||
console.info('Initialization require module. ParentDir:', _canonical(parent));
|
var cacheModuleIdsFile = _canonical(new File(MS_NODE_PATH, 'cacheModuleIds.json'))
|
||||||
return getRequire(parent, "null");
|
var localVersionLockFile = _canonical(new File(MS_NODE_PATH, 'moduleVersionLock.json'))
|
||||||
});
|
/**
|
||||||
|
* 已缓存的模块ID
|
||||||
|
* @type {{[key:string]:{[key:string]:string}|string}} [cacheModuleIds]
|
||||||
|
*/
|
||||||
|
var cacheModuleIds = {}
|
||||||
|
/**
|
||||||
|
* 未找到的模块
|
||||||
|
* @type {{[key:string]:boolean}}
|
||||||
|
*/
|
||||||
|
var notFoundModules = {}
|
||||||
|
var upgradeMode = false
|
||||||
|
var executor = Executors.newSingleThreadExecutor(function (r) {
|
||||||
|
return new Thread(r, "MiaoScript require thread")
|
||||||
|
})
|
||||||
|
|
||||||
|
printRequireInfo()
|
||||||
|
initCacheModuleIds()
|
||||||
|
initVersionLock()
|
||||||
|
|
||||||
|
return initRequireLoader(getRequire({
|
||||||
|
id: 'main',
|
||||||
|
path: root
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
@ -1,69 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
/**
|
|
||||||
* Hello Wrold 测试插件
|
|
||||||
*/
|
|
||||||
/*global Java, base, module, exports, require*/
|
|
||||||
|
|
||||||
var event = require('api/event');
|
|
||||||
var wrapper = require('api/wrapper');
|
|
||||||
var command = require('api/command');
|
|
||||||
var server = require('api/server');
|
|
||||||
var fs = require('fs');
|
|
||||||
|
|
||||||
var description = {
|
|
||||||
name: 'HelloWorld',
|
|
||||||
version: '1.0',
|
|
||||||
author: 'MiaoWoo',
|
|
||||||
commands: {
|
|
||||||
'hello': {
|
|
||||||
description: 'HelloWorld主命令'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function load() {
|
|
||||||
console.log('载入 Hello Wrold 测试插件!');
|
|
||||||
}
|
|
||||||
|
|
||||||
function enable() {
|
|
||||||
// noinspection JSUnusedLocalSymbols
|
|
||||||
command.on(this, 'hello', {
|
|
||||||
cmd: function(sender, command, args) {
|
|
||||||
engineLoad(fs.file(root, 'test.js'));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
console.log('启用 Hello World 测试插件!');
|
|
||||||
switch (DetectServerType) {
|
|
||||||
case ServerType.Bukkit:
|
|
||||||
event.on(this, 'PlayerLoginEvent', function join(event) {
|
|
||||||
send(event, wrapper.player(event.player));
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case ServerType.Sponge:
|
|
||||||
event.on(this, 'ClientConnectionEvent.Join', function join(event) {
|
|
||||||
send(event, wrapper.player(event.targetEntity));
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function send(event, player) {
|
|
||||||
// noinspection JSUnresolvedVariable
|
|
||||||
console.debug('玩家', player.getName(), "触发事件", event.class.simpleName);
|
|
||||||
setTimeout(function() {
|
|
||||||
// noinspection JSUnresolvedVariable
|
|
||||||
player.sendMessage("§a欢迎来到 §bMiaoScript §a的世界! 当前在线: " + server.players().length)
|
|
||||||
}, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
function disable() {
|
|
||||||
console.log('卸载 Hello World 测试插件!');
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
description: description,
|
|
||||||
load: load,
|
|
||||||
enable: enable,
|
|
||||||
disable: disable
|
|
||||||
};
|
|
@ -1,88 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
/*global Java, base, module, exports, require*/
|
|
||||||
var event = require('api/event');
|
|
||||||
var task = require('api/task');
|
|
||||||
var http = require('http');
|
|
||||||
var fs = require('fs');
|
|
||||||
|
|
||||||
var Keys;
|
|
||||||
|
|
||||||
var description = {
|
|
||||||
name: 'ItemTag',
|
|
||||||
version: '1.0',
|
|
||||||
author: 'MiaoWoo'
|
|
||||||
};
|
|
||||||
|
|
||||||
var itemConfig;
|
|
||||||
|
|
||||||
function load() {
|
|
||||||
var itemFile = self.file('item.yml');
|
|
||||||
task.async(function() {
|
|
||||||
if (!itemFile.exists()) {
|
|
||||||
fs.save(itemFile, http.get('https://data.yumc.pw/config/Item_zh_CN.yml'))
|
|
||||||
}
|
|
||||||
itemConfig = self.getConfig('item.yml')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function enable() {
|
|
||||||
switch (DetectServerType) {
|
|
||||||
case ServerType.Bukkit:
|
|
||||||
var i = require('api/item').create('STONE')
|
|
||||||
if (!i.setCustomName) { return }
|
|
||||||
event.on(self, 'ItemMergeEvent', function(event) {
|
|
||||||
bukkit(event.target, event.entity.itemStack.amount + event.target.itemStack.amount);
|
|
||||||
});
|
|
||||||
event.on(self, 'ItemSpawnEvent', function(event) {
|
|
||||||
if (event.entity.itemStack) {
|
|
||||||
bukkit(event.entity, event.entity.itemStack.amount);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case ServerType.Sponge:
|
|
||||||
Keys = Java.type('org.spongepowered.api.data.key.Keys');
|
|
||||||
event.on(self, 'ItemMergeItemEvent', function(event) {
|
|
||||||
// Sponge 暂未实现当前事件
|
|
||||||
});
|
|
||||||
event.on(self, 'SpawnEntityEvent', function(event) {
|
|
||||||
event.entities.forEach(function(entity) {
|
|
||||||
if (entity.type.name === "item") sponge(entity);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function bukkit(item, amount) {
|
|
||||||
item.setCustomName('§b' + getItemName(item.itemStack.type) + getItemCount(amount));
|
|
||||||
item.setCustomNameVisible(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function sponge(entity) {
|
|
||||||
var itemOptional = entity.get(Keys['REPRESENTED_ITEM']);
|
|
||||||
if (itemOptional.isPresent()) {
|
|
||||||
var item = itemOptional.get();
|
|
||||||
var itemName = '§b' + getItemName(item.type.name.split(':')[1]) + getItemCount(item.count);
|
|
||||||
entity.offer(Keys['DISPLAY_NAME'], org.spongepowered.api.text.Text.of(itemName));
|
|
||||||
entity.offer(Keys['CUSTOM_NAME_VISIBLE'], true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getItemName(name) {
|
|
||||||
return itemConfig[(name + '').toUpperCase()] || name;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getItemCount(amount) {
|
|
||||||
return amount === 1 ? "" : "*" + amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
function disable() {
|
|
||||||
console.log('卸载', description.name, '插件!');
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
description: description,
|
|
||||||
load: load,
|
|
||||||
enable: enable,
|
|
||||||
disable: disable
|
|
||||||
};
|
|
@ -1,70 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
/**
|
|
||||||
* MiaoAuth简易登录系统
|
|
||||||
*/
|
|
||||||
/*global Java, base, module, exports, require*/
|
|
||||||
|
|
||||||
var event = require('api/event');
|
|
||||||
var wrapper = require('api/wrapper');
|
|
||||||
var command = require('api/command');
|
|
||||||
|
|
||||||
var description = {
|
|
||||||
name: 'MiaoAuth',
|
|
||||||
version: '1.0',
|
|
||||||
author: 'MiaoWoo',
|
|
||||||
commands: {
|
|
||||||
'l': {
|
|
||||||
description: 'MiaoAuth登录命令'
|
|
||||||
},
|
|
||||||
'r': {
|
|
||||||
description: 'MiaoAuth注册命令'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function load() {
|
|
||||||
console.log('载入 MiaoAuth 插件!');
|
|
||||||
}
|
|
||||||
|
|
||||||
function enable() {
|
|
||||||
command.on(this, 'l', {
|
|
||||||
cmd: function(sender, command, args) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
command.on(this, 'r', {
|
|
||||||
cmd: function(sender, command, args) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
console.log('启用 MiaoAuth 测试插件!');
|
|
||||||
switch (DetectServerType) {
|
|
||||||
case ServerType.Bukkit:
|
|
||||||
event.on(this, 'playerloginevent', function join(event) {
|
|
||||||
send(wrapper.player(event.player));
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case ServerType.Sponge:
|
|
||||||
event.on(this, 'clientconnectionevent.join', function join(event) {
|
|
||||||
send(wrapper.player(event.targetEntity));
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function send(player) {
|
|
||||||
setTimeout(function sendMessage() {
|
|
||||||
player.sendMessage('§a输入 /l <密码> 以登录!');
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
function disable() {
|
|
||||||
console.log('卸载 MiaoAuth 测试插件!');
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
description: description,
|
|
||||||
load: load,
|
|
||||||
enable: enable,
|
|
||||||
disable: disable
|
|
||||||
};
|
|
@ -1,261 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
/**
|
|
||||||
* MiaoChat 喵式聊天插件
|
|
||||||
*/
|
|
||||||
/*global Java, base, module, exports, require*/
|
|
||||||
|
|
||||||
var event = require('api/event');
|
|
||||||
var command = require('api/command');
|
|
||||||
|
|
||||||
var tellraw = require('tellraw');
|
|
||||||
var papi = require('papi');
|
|
||||||
var utils = require('utils');
|
|
||||||
|
|
||||||
var Player;
|
|
||||||
|
|
||||||
var description = {
|
|
||||||
name: 'MiaoChat',
|
|
||||||
version: '1.0',
|
|
||||||
author: 'MiaoWoo',
|
|
||||||
commands: {
|
|
||||||
'mchat': {
|
|
||||||
description: 'MiaoChat登录命令'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
permissions: {
|
|
||||||
'MiaoChat.default': {
|
|
||||||
default: true,
|
|
||||||
description: '默认权限 赋予玩家'
|
|
||||||
},
|
|
||||||
'MiaoChat.admin': {
|
|
||||||
default: false,
|
|
||||||
description: '管理权限'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
config: {
|
|
||||||
Version: "1.8.5",
|
|
||||||
BungeeCord: true,
|
|
||||||
Server: "生存服",
|
|
||||||
ChatFormats: {
|
|
||||||
"default": {
|
|
||||||
"index": 50,
|
|
||||||
"permission": "MiaoChat.default",
|
|
||||||
"range": 0,
|
|
||||||
"format": "[world][player]&7: ",
|
|
||||||
"item": true,
|
|
||||||
"itemformat": "&6[&b%s&6]&r"
|
|
||||||
},
|
|
||||||
"admin": {
|
|
||||||
"index": 49,
|
|
||||||
"permission": "MiaoChat.admin",
|
|
||||||
"format": "[admin][world][player][help]&7: ",
|
|
||||||
"range": 0,
|
|
||||||
"item": true,
|
|
||||||
"itemformat": "&6[&b%s&6]&r"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
StyleFormats: {
|
|
||||||
"world": {
|
|
||||||
"text": "&6[&a%player_world%&6]",
|
|
||||||
"hover": [
|
|
||||||
"&6当前所在位置:",
|
|
||||||
"&6世界: &d%player_world%",
|
|
||||||
"&6坐标: &aX:%player_x% Y: %player_y% Z: %player_z%",
|
|
||||||
"",
|
|
||||||
"&c点击即可TP我!"
|
|
||||||
],
|
|
||||||
"click": {
|
|
||||||
"type": "COMMAND",
|
|
||||||
"command": "/tpa %player_name%"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"player": {
|
|
||||||
"text": "&b%player_name%",
|
|
||||||
"hover": [
|
|
||||||
"&6玩家名称: &b%player_name%",
|
|
||||||
"&6玩家等级: &a%player_level%",
|
|
||||||
"&6玩家血量: &c%player_health%",
|
|
||||||
"&6玩家饥饿: &d%player_food_level%",
|
|
||||||
"&6游戏模式: &4%player_gamemode%",
|
|
||||||
"",
|
|
||||||
"&c点击与我聊天"
|
|
||||||
],
|
|
||||||
"click": {
|
|
||||||
"type": "SUGGEST",
|
|
||||||
"command": "/tell %player_name%"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"admin": {
|
|
||||||
"text": "&6[&c管理员&6]"
|
|
||||||
},
|
|
||||||
"help": {
|
|
||||||
"text": "&4[求助]",
|
|
||||||
"hover": [
|
|
||||||
"点击求助OP"
|
|
||||||
],
|
|
||||||
"click": {
|
|
||||||
"type": "COMMAND",
|
|
||||||
"command": "管理员@%player_name% 我需要你的帮助!"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var chat_formats;
|
|
||||||
var style_formats;
|
|
||||||
|
|
||||||
function load() {
|
|
||||||
chat_formats = Object.values(self.config.ChatFormats);
|
|
||||||
chat_formats.sort(utils.compare('index'));
|
|
||||||
initFormat(chat_formats);
|
|
||||||
style_formats = self.config.StyleFormats;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 用于匹配 '[xx]' 聊天格式
|
|
||||||
var FORMAT_PATTERN = /[\[]([^\[\]]+)[\]]/ig;
|
|
||||||
|
|
||||||
function initFormat(chat_formats) {
|
|
||||||
chat_formats.forEach(function(chat_format) {
|
|
||||||
var chat_format_str = chat_format.format;
|
|
||||||
var temp = [];
|
|
||||||
var r;
|
|
||||||
while (r = FORMAT_PATTERN.exec(chat_format_str)) {
|
|
||||||
temp.push(r[1]);
|
|
||||||
}
|
|
||||||
var format_list = [];
|
|
||||||
temp.forEach(function splitStyle(t) {
|
|
||||||
var arr = chat_format_str.split('[' + t + ']', 2);
|
|
||||||
if (arr[0]) {
|
|
||||||
format_list.push(arr[0]);
|
|
||||||
}
|
|
||||||
format_list.push(t);
|
|
||||||
chat_format_str = arr[1];
|
|
||||||
});
|
|
||||||
if (chat_format_str) {
|
|
||||||
format_list.push(chat_format_str);
|
|
||||||
}
|
|
||||||
chat_format.format_list = format_list;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function enable() {
|
|
||||||
registerCommand();
|
|
||||||
registerEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
function registerCommand() {
|
|
||||||
command.on(self, 'mchat', {
|
|
||||||
cmd: mainCommand
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// noinspection JSUnusedLocalSymbols
|
|
||||||
function mainCommand(sender, command, args) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function registerEvent() {
|
|
||||||
switch (DetectServerType) {
|
|
||||||
case ServerType.Bukkit:
|
|
||||||
event.on(self, 'AsyncPlayerChatEvent', handlerBukkitChat);
|
|
||||||
break;
|
|
||||||
case ServerType.Sponge:
|
|
||||||
Player = org.spongepowered.api.entity.living.player.Player;
|
|
||||||
event.on(self, 'MessageChannelEvent.Chat', handlerSpongeChat);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handlerBukkitChat(event) {
|
|
||||||
sendChat(event.player, event.message, function() {
|
|
||||||
event.setCancelled(true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function handlerSpongeChat(event) {
|
|
||||||
var player = event.getCause().first(Player.class).orElse(null);
|
|
||||||
if (player == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var plain = event.getRawMessage().toPlain();
|
|
||||||
if (plain.startsWith(tellraw.duplicateChar)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sendChat(player, plain, function() {
|
|
||||||
event.setMessageCancelled(true)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendChat(player, plain, callback) {
|
|
||||||
var chat_format = getChatFormat(player);
|
|
||||||
if (!chat_format) {
|
|
||||||
console.debug('未获得用户', player.name, '的 ChatRule 跳过执行...');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
callback();
|
|
||||||
var tr = tellraw.create();
|
|
||||||
chat_format.format_list.forEach(function setStyle(format) {
|
|
||||||
var style = style_formats[format];
|
|
||||||
if (style) {
|
|
||||||
tr.then(replace(player, style.text));
|
|
||||||
if (style.hover) {
|
|
||||||
tr.tip(replace(player, style.hover));
|
|
||||||
}
|
|
||||||
if (style.click && style.click.type && style.click.command) {
|
|
||||||
var command = replace(player, style.click.command);
|
|
||||||
switch (style.click.type) {
|
|
||||||
case "COMMAND":
|
|
||||||
tr.command(command);
|
|
||||||
break;
|
|
||||||
case "OPENURL":
|
|
||||||
tr.link(command);
|
|
||||||
break;
|
|
||||||
case "SUGGEST":
|
|
||||||
tr.suggest(command);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tr.then(replace(player, format));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
tr.then(replace(player, plain)).sendAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
function getChatFormat(player) {
|
|
||||||
for (var i in chat_formats) {
|
|
||||||
var format = chat_formats[i];
|
|
||||||
if (player.hasPermission(format.permission)) {
|
|
||||||
return format;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function replace(player, target) {
|
|
||||||
if (toString.call(target) === "[object Array]") {
|
|
||||||
for (var i in target) {
|
|
||||||
target[i] = replaceStr(player, target[i]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
target = replaceStr(player, target);
|
|
||||||
}
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
|
|
||||||
function replaceStr(player, target) {
|
|
||||||
return papi.$(player, target);
|
|
||||||
}
|
|
||||||
|
|
||||||
function disable() {
|
|
||||||
console.log('卸载', description.name, '插件!');
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
description: description,
|
|
||||||
load: load,
|
|
||||||
enable: enable,
|
|
||||||
disable: disable
|
|
||||||
};
|
|
@ -1,231 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
/**
|
|
||||||
* Hello Wrold 测试插件
|
|
||||||
*/
|
|
||||||
/*global Java, base, module, exports, require*/
|
|
||||||
|
|
||||||
var event = require('api/event');
|
|
||||||
var command = require('api/command');
|
|
||||||
var bukkit = require('api/server');
|
|
||||||
var item = require('api/item');
|
|
||||||
|
|
||||||
var Arrays = Java.type('java.util.Arrays');
|
|
||||||
var ItemStackArray = Java.type('org.bukkit.inventory.ItemStack[]');
|
|
||||||
|
|
||||||
var PANE = 'STAINED_GLASS_PANE'
|
|
||||||
|
|
||||||
var description = {
|
|
||||||
name: 'Lottery',
|
|
||||||
version: '1.0',
|
|
||||||
author: 'MiaoWoo',
|
|
||||||
commands: {
|
|
||||||
'lottery': {
|
|
||||||
description: 'Lottery主命令'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
config: {
|
|
||||||
title: '§m§s§a幸运抽奖',
|
|
||||||
control: {
|
|
||||||
panel: PANE + ':13',
|
|
||||||
ok: PANE + ':14',
|
|
||||||
no: PANE + ':15',
|
|
||||||
},
|
|
||||||
list: [
|
|
||||||
{
|
|
||||||
box: {
|
|
||||||
id: PANE,
|
|
||||||
damage: 1,
|
|
||||||
name: '§a箱子',
|
|
||||||
lore: [
|
|
||||||
'这是箱子的Lore'
|
|
||||||
]
|
|
||||||
},
|
|
||||||
key: {
|
|
||||||
id: PANE,
|
|
||||||
damage: 2,
|
|
||||||
name: '§b钥匙',
|
|
||||||
lore: [
|
|
||||||
'这是钥匙的Lore'
|
|
||||||
]
|
|
||||||
},
|
|
||||||
result: [
|
|
||||||
{
|
|
||||||
percent: 10,
|
|
||||||
command: 'money give %player% 100',
|
|
||||||
item: {
|
|
||||||
id: PANE,
|
|
||||||
damage: 3,
|
|
||||||
name: '§c奖品1',
|
|
||||||
lore: [
|
|
||||||
'这是奖品1的Lore'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
percent: 20,
|
|
||||||
command: 'money give %player% 200',
|
|
||||||
item: {
|
|
||||||
id: PANE,
|
|
||||||
damage: 4,
|
|
||||||
name: '§c奖品2',
|
|
||||||
lore: [
|
|
||||||
'这是奖品2的Lore'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var panel;
|
|
||||||
var config;
|
|
||||||
var items;
|
|
||||||
|
|
||||||
function load() {
|
|
||||||
config = this.config;
|
|
||||||
panel = newItemFromString(config.control.panel || PANE + ':13')
|
|
||||||
items = new ItemStackArray(54);
|
|
||||||
item.setName(panel, '');
|
|
||||||
var ok = newItemFromString(config.control.ok || PANE + ':14')
|
|
||||||
item.setName(ok, '§a确定抽奖');
|
|
||||||
var no = newItemFromString(config.control.no || PANE + ':15')
|
|
||||||
item.setName(no, '§c取消抽奖');
|
|
||||||
Arrays.fill(items, 0, 10, panel);
|
|
||||||
Arrays.fill(items, 11, 16, panel);
|
|
||||||
Arrays.fill(items, 17, 29, panel);
|
|
||||||
items[29] = no;
|
|
||||||
Arrays.fill(items, 30, 33, panel);
|
|
||||||
items[33] = ok;
|
|
||||||
Arrays.fill(items, 34, 40, panel);
|
|
||||||
Arrays.fill(items, 41, 54, panel);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isTargetItem(item, config) {
|
|
||||||
return item.typeId === config.id &&
|
|
||||||
item.itemMeta &&
|
|
||||||
item.itemMeta.displayName === config.name &&
|
|
||||||
item.itemMeta.lore && Java.from(item.itemMeta.lore).toJson() === config.lore.toJson()
|
|
||||||
}
|
|
||||||
|
|
||||||
function newItem(name, sub) {
|
|
||||||
return item.create(name, 1, sub || 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
function newItemFromString(str) {
|
|
||||||
var arr = str.split(':');
|
|
||||||
if (arr.length === 2) {
|
|
||||||
return newItem(arr[0], arr[1]);
|
|
||||||
} else {
|
|
||||||
return newItem(arr[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function newItemFromConfig(config) {
|
|
||||||
var i = newItem(config.id, config.damage);
|
|
||||||
if (config.name) item.setName(i, config.name);
|
|
||||||
if (config.lore) item.setLore(i, config.lore);
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
function enable() {
|
|
||||||
// noinspection JSUnusedLocalSymbols
|
|
||||||
command.on(this, 'l', {
|
|
||||||
cmd: function(sender, command, args) {
|
|
||||||
sender.inventory.addItem(newItemFromConfig(config.list[0].box))
|
|
||||||
sender.inventory.addItem(newItemFromConfig(config.list[0].key))
|
|
||||||
if (!sender.openInventory) {
|
|
||||||
console.sender(sender, "§4当前用户无法使用该命令!");
|
|
||||||
}
|
|
||||||
var inv = MServer.createInventory(null, 54, config.title);
|
|
||||||
inv.setContents(items);
|
|
||||||
sender.openInventory(inv);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
event.on(this, 'InventoryClick', function click(event) {
|
|
||||||
var inv = event.inventory;
|
|
||||||
if (inv && inv.title !== config.title) return;
|
|
||||||
var player = event.whoClicked;
|
|
||||||
var slot = event.rawSlot;
|
|
||||||
if (slot > 53 || slot < 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
event.cancelled = true;
|
|
||||||
switch (slot) {
|
|
||||||
case 10:
|
|
||||||
case 16:
|
|
||||||
case 40:
|
|
||||||
event.cancelled = false;
|
|
||||||
break;
|
|
||||||
case 29:
|
|
||||||
// TODO 关闭界面
|
|
||||||
player.closeInventory();
|
|
||||||
break;
|
|
||||||
case 33:
|
|
||||||
var temp = inv.getItem(40);
|
|
||||||
if (temp && temp.typeId !== 0) {
|
|
||||||
console.sender(player, '§c请先取走奖品!');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var litem;
|
|
||||||
var box = inv.getItem(10);
|
|
||||||
if (!box) {
|
|
||||||
console.sender(player, '§c请先放入抽奖物品和钥匙!');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var key = inv.getItem(16);
|
|
||||||
if (box && box.typeId !== 0 && key && key.typeId !== 0) {
|
|
||||||
for (var i = 0; i < config.list.length; i++) {
|
|
||||||
var r = config.list[i];
|
|
||||||
if (isTargetItem(box, r.box)) {
|
|
||||||
litem = r;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO 抽奖
|
|
||||||
if (!litem) {
|
|
||||||
console.sender(player, '§c请先放入抽奖物品和钥匙!');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!isTargetItem(key, litem.key)) {
|
|
||||||
console.sender(player, '§c抽奖物品和钥匙不匹配!');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var resultList = [];
|
|
||||||
litem.result.forEach(function(t) {
|
|
||||||
for (var i = 0; i < t.percent; i++) {
|
|
||||||
resultList.push(t);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
var ri = random(resultList.length);
|
|
||||||
var result = resultList[ri];
|
|
||||||
box.amount = box.amount - 1;
|
|
||||||
key.amount = key.amount - 1;
|
|
||||||
inv.setItem(10, box);
|
|
||||||
inv.setItem(16, key);
|
|
||||||
inv.setItem(40, newItemFromConfig(result.item));
|
|
||||||
bukkit.console(result.command.replace('%player%', player.name));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
event.cancelled = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function random(max, min) {
|
|
||||||
min = min === undefined ? 0 : min;
|
|
||||||
return Math.floor(Math.random() * (max - min) + min);
|
|
||||||
};
|
|
||||||
|
|
||||||
function disable() {
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
description: description,
|
|
||||||
load: load,
|
|
||||||
enable: enable,
|
|
||||||
disable: disable
|
|
||||||
};
|
|
@ -1,188 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
/**
|
|
||||||
* MiaoTag
|
|
||||||
* 可兼容任何记分板
|
|
||||||
*/
|
|
||||||
/*global Java, base, module, exports, require*/
|
|
||||||
var event = require('api/event');
|
|
||||||
var bukkit = require('api/server');
|
|
||||||
var command = require('api/command');
|
|
||||||
|
|
||||||
var fakeTag;
|
|
||||||
|
|
||||||
var description = {
|
|
||||||
name: 'MiaoTag',
|
|
||||||
version: '1.1',
|
|
||||||
author: 'MiaoWoo',
|
|
||||||
config: {
|
|
||||||
format: '§4§l❤'
|
|
||||||
},
|
|
||||||
commands: {
|
|
||||||
'mtag': {
|
|
||||||
description: 'MiaoTag主命令',
|
|
||||||
usage: '',
|
|
||||||
permission: 'MiaoTag.admin'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
permissions: {
|
|
||||||
'MiaoTag.default': {
|
|
||||||
default: true,
|
|
||||||
description: '默认权限 赋予玩家'
|
|
||||||
},
|
|
||||||
'MiaoTag.admin': {
|
|
||||||
default: false,
|
|
||||||
description: '管理权限'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var config;
|
|
||||||
|
|
||||||
function load() {
|
|
||||||
config = self.getConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
function enable() {
|
|
||||||
registryCommand()
|
|
||||||
fakeTag = new FakeTag(config.format);
|
|
||||||
registryEvent()
|
|
||||||
}
|
|
||||||
|
|
||||||
function registryCommand() {
|
|
||||||
command.on(self, 'mtag', {
|
|
||||||
cmd: function cmd(sender, command, args) {
|
|
||||||
var subCommand = args[0];
|
|
||||||
switch (subCommand) {
|
|
||||||
case 'reload':
|
|
||||||
self.reloadConfig();
|
|
||||||
fakeTag = new FakeTag(config.format);
|
|
||||||
console.sender(sender, "§a配置文件重载完成!");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
tab: function tab(sender, command, args) {
|
|
||||||
return ['reload'];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function registryEvent() {
|
|
||||||
bukkit.players(function(p) { fakeTag.set(p) });
|
|
||||||
event.on(self, 'PlayerJoin', function(event) { fakeTag.set(event.player) });
|
|
||||||
event.on(self, 'EntityRegainHealth', entityUpdate, false);
|
|
||||||
event.on(self, 'EntityDamage', entityUpdate, false);
|
|
||||||
event.on(self, 'EntityRegainHealth', entityUpdate, false);
|
|
||||||
event.on(self, 'PlayerRespawn', entityUpdate, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function entityUpdate(event) {
|
|
||||||
var player = event.entity || event.player;
|
|
||||||
if (player instanceof org.bukkit.entity.Player) {
|
|
||||||
setTimeout(function() {
|
|
||||||
fakeTag.update(player);
|
|
||||||
}, 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function disable() {
|
|
||||||
if (fakeTag) { fakeTag.disable() };
|
|
||||||
}
|
|
||||||
|
|
||||||
function FakeTag(name) {
|
|
||||||
var ver1_13 = false;
|
|
||||||
// NMS CLASS
|
|
||||||
try {
|
|
||||||
var ScoreboardBaseCriteria = bukkit.nmsCls('ScoreboardBaseCriteria');
|
|
||||||
} catch (ex) {
|
|
||||||
try {
|
|
||||||
var IScoreboardCriteria = bukkit.nmsCls('IScoreboardCriteria');
|
|
||||||
var ScoreboardServer = bukkit.nmsCls("ScoreboardServer");
|
|
||||||
var ChatComponentText = bukkit.nmsCls('ChatComponentText');
|
|
||||||
ver1_13 = true;
|
|
||||||
} catch (ex) {
|
|
||||||
console.log(ex);
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var PacketPlayOutScoreboardScore = bukkit.nmsCls('PacketPlayOutScoreboardScore');
|
|
||||||
var PacketPlayOutScoreboardObjective = bukkit.nmsCls('PacketPlayOutScoreboardObjective');
|
|
||||||
var PacketPlayOutScoreboardDisplayObjective = bukkit.nmsCls('PacketPlayOutScoreboardDisplayObjective');
|
|
||||||
|
|
||||||
var scoreboardManager = bukkit.$.scoreboardManager;
|
|
||||||
var mainScoreboard = scoreboardManager.mainScoreboard.handle;
|
|
||||||
|
|
||||||
// 注销对象
|
|
||||||
var objective = mainScoreboard.getObjective(name);
|
|
||||||
if (objective) {
|
|
||||||
mainScoreboard.unregisterObjective(objective);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (!ver1_13) {
|
|
||||||
// 注册tag对象
|
|
||||||
objective = mainScoreboard.registerObjective(name, new ScoreboardBaseCriteria(name));
|
|
||||||
} else {
|
|
||||||
// 注册tag对象
|
|
||||||
objective = mainScoreboard.registerObjective(name,
|
|
||||||
IScoreboardCriteria.HEALTH,
|
|
||||||
new ChatComponentText(name),
|
|
||||||
IScoreboardCriteria.EnumScoreboardHealthDisplay.HEARTS);
|
|
||||||
}
|
|
||||||
} catch (ex) {
|
|
||||||
throw ex
|
|
||||||
// ignore 忽略创建错误 eg: java.lang.IllegalArgumentException: An objective with the name 'xxxxx' already exists!
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!objective) {
|
|
||||||
throw Error("Error Can't Found MainScoreboard Objective " + name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 缓存虚拟的tag包
|
|
||||||
var cache = {
|
|
||||||
objective: new PacketPlayOutScoreboardObjective(objective, 0),
|
|
||||||
display: new PacketPlayOutScoreboardDisplayObjective(2, objective)
|
|
||||||
};
|
|
||||||
|
|
||||||
function sendPacket(player, p) {
|
|
||||||
player.handle.playerConnection.sendPacket(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.set = function(player) {
|
|
||||||
sendPacket(player, cache.objective);
|
|
||||||
sendPacket(player, cache.display);
|
|
||||||
this.update(player);
|
|
||||||
};
|
|
||||||
|
|
||||||
function createScore(player) {
|
|
||||||
if (!ver1_13) {
|
|
||||||
var score = mainScoreboard.getPlayerScoreForObjective(player.name, objective);
|
|
||||||
score.setScore(player.health);
|
|
||||||
return new PacketPlayOutScoreboardScore(score);
|
|
||||||
} else {
|
|
||||||
return new PacketPlayOutScoreboardScore(ScoreboardServer.Action.CHANGE, name, player.name, player.health)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.update = function update(player) {
|
|
||||||
var scorePack = createScore(player);
|
|
||||||
//把其他玩家缓存的包发给这个玩家
|
|
||||||
bukkit.players(function(t) {
|
|
||||||
sendPacket(t, scorePack);
|
|
||||||
if (t.name !== player.name) {
|
|
||||||
sendPacket(player, createScore(t));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
this.disable = function() {
|
|
||||||
// 注销tag对象
|
|
||||||
mainScoreboard.unregisterObjective(objective);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
description: description,
|
|
||||||
load: load,
|
|
||||||
enable: enable,
|
|
||||||
disable: disable
|
|
||||||
};
|
|
@ -1,48 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
/**
|
|
||||||
* WorldEdit 插件
|
|
||||||
*/
|
|
||||||
/*global Java, base, module, exports, require*/
|
|
||||||
var item = require('/api/item');
|
|
||||||
var command = require('api/command');
|
|
||||||
var Material = Java.type("org.bukkit.Material");
|
|
||||||
|
|
||||||
var description = {
|
|
||||||
name: 'WorldEdit',
|
|
||||||
version: '1.0',
|
|
||||||
author: 'MiaoWoo',
|
|
||||||
commands: {
|
|
||||||
'/up': {
|
|
||||||
description: 'Up Player And Set Block'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function load() {
|
|
||||||
}
|
|
||||||
|
|
||||||
function enable() {
|
|
||||||
command.on(this, '/up', {
|
|
||||||
cmd: function(sender, command, args) {
|
|
||||||
if (!sender.openInventory) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var player = sender;
|
|
||||||
var location = player.location;
|
|
||||||
var type = item.type(args[0], 'STONE');
|
|
||||||
player.velocity = player.velocity.setY(0.5);
|
|
||||||
setTimeout(function() {
|
|
||||||
location.block.type = type
|
|
||||||
}, 6);
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
tab: function(sender, command, args) {
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
description: description,
|
|
||||||
enable: enable
|
|
||||||
};
|
|
@ -1,32 +0,0 @@
|
|||||||
## MiaoChat for MiaoScript
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
> 注意: MiaoScript 在Windows环境下 暂不支持 reload 所以 Windows 环境请重启服务器
|
|
||||||
> 注意: MiaoScript 将不会计划兼容 非 `Sponge` 的MOD端
|
|
||||||
|
|
||||||
- 基于 `MiaoScript` 开发 同时兼容 `Sponge` 和 `Bukkit`
|
|
||||||
- 支持PAPI
|
|
||||||
- `Bukkit` 为 `me.clip.placeholderapi.PlaceholderAPI`
|
|
||||||
- `Sponge` 为 `me.rojo8399.placeholderapi.PlaceholderService`
|
|
||||||
- 支持悬浮提示
|
|
||||||
- 支持点击执行命令
|
|
||||||
- 支持点击命令补全
|
|
||||||
|
|
||||||
### Feature(开发规划)
|
|
||||||
- 悬浮物品提示
|
|
||||||
- 兼容 `BungeeCord` 支持跨服聊天
|
|
||||||
- 兼容其他聊天插件 保护插件
|
|
||||||
|
|
||||||
### 安装教程
|
|
||||||
- 下载 MiaoChat 本体并安装
|
|
||||||
- [下载地址-论坛](http://www.mcbbs.net/thread-774401-1-1.html)
|
|
||||||
- [下载地址-备用](https://git.yumc.pw/502647092/MiaoScript/releases)
|
|
||||||
- 安装到服务端对应的目录
|
|
||||||
- Bukkit => plugins
|
|
||||||
- Sponge => mods
|
|
||||||
- 重启服务器
|
|
||||||
- 下载 安装 `MiaoScriptPackageManager`
|
|
||||||
- [安装教程](http://www.mcbbs.net/thread-774797-1-1.html)
|
|
||||||
- 使用 `MiaoScriptPackageManager` 安装插件
|
|
||||||
- 执行 `mpm install MiaoChat` 即可安装成功
|
|
@ -1,220 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
/**
|
|
||||||
* MiaoBoard 喵式聊天插件
|
|
||||||
*/
|
|
||||||
/*global Java, base, module, exports, require*/
|
|
||||||
var task = require('api/task');
|
|
||||||
var event = require('api/event');
|
|
||||||
var server = require('api/server');
|
|
||||||
var command = require('api/command');
|
|
||||||
|
|
||||||
var papi = require('papi');
|
|
||||||
|
|
||||||
var Player;
|
|
||||||
|
|
||||||
var boards = [];
|
|
||||||
|
|
||||||
var description = {
|
|
||||||
name: 'MiaoBoard',
|
|
||||||
version: '1.0',
|
|
||||||
author: 'MiaoWoo',
|
|
||||||
commands: {
|
|
||||||
'mboard': {
|
|
||||||
description: '喵式记分板主命令'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
permissions: {
|
|
||||||
'mb.default': {
|
|
||||||
default: true,
|
|
||||||
description: '默认权限 赋予玩家'
|
|
||||||
},
|
|
||||||
'mb.admin': {
|
|
||||||
default: false,
|
|
||||||
description: '管理权限'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
config: {
|
|
||||||
"Version": 2,
|
|
||||||
"UpdateTime": 10,
|
|
||||||
"DisableWorld": [
|
|
||||||
"WorldName"
|
|
||||||
],
|
|
||||||
"Boards": {
|
|
||||||
"default": {
|
|
||||||
"index": 50,
|
|
||||||
"time": {
|
|
||||||
"start": "2016-01-01 00:00:00",
|
|
||||||
"end": "2020-01-01 00:00:00"
|
|
||||||
},
|
|
||||||
"title": "玩家信息",
|
|
||||||
"permission": "mb.default",
|
|
||||||
"lines": [
|
|
||||||
"&6名 称: &a%player_displayname%",
|
|
||||||
"&6世 界: &b%player_world%",
|
|
||||||
"&6位 置: &3%player_x%,%player_y%,%player_z%",
|
|
||||||
"&6等 级: &e%player_level%",
|
|
||||||
"&6血 量: &c%player_health%",
|
|
||||||
"&6模 式: &4%player_gamemode%"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"admin": {
|
|
||||||
"index": 49,
|
|
||||||
"title": "服务器信息",
|
|
||||||
"permission": "mb.reload",
|
|
||||||
"lines": [
|
|
||||||
"&6名 称: &aMiaoBoard",
|
|
||||||
"&6版 本: &b1.0.0",
|
|
||||||
"&6作 者: &cMiaoWoo",
|
|
||||||
"&6人 数: &c%server_online%/%server_max%",
|
|
||||||
"&6内 存: &a%server_ram_used%/%server_ram_total%/%server_ram_max%"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var update_task;
|
|
||||||
var board_formats;
|
|
||||||
|
|
||||||
function load() {
|
|
||||||
board_formats = self.config.Boards;
|
|
||||||
}
|
|
||||||
|
|
||||||
function enable() {
|
|
||||||
registerCommand();
|
|
||||||
registerEvent();
|
|
||||||
registerTask();
|
|
||||||
updatePlayers()
|
|
||||||
}
|
|
||||||
|
|
||||||
function registerCommand() {
|
|
||||||
command.on(self, 'mboard', {
|
|
||||||
cmd: mainCommand
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function mainCommand(sender, command, args) {
|
|
||||||
if (!args[0]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switch (args[0]) {
|
|
||||||
case "reload":
|
|
||||||
self.reloadConfig();
|
|
||||||
load();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function registerEvent() {
|
|
||||||
switch (DetectServerType) {
|
|
||||||
case ServerType.Bukkit:
|
|
||||||
//event.on(self, 'PlayerLoginEvent', handlerPlayerJoin);
|
|
||||||
break;
|
|
||||||
case ServerType.Sponge:
|
|
||||||
Player = org.spongepowered.api.entity.living.player.Player;
|
|
||||||
event.on(self, 'ClientConnectionEvent.Join', handlerPlayerJoin);
|
|
||||||
event.on(self, 'ClientConnectionEvent.Disconnect', handlerPlayerQuit);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updatePlayers() {
|
|
||||||
switch (DetectServerType) {
|
|
||||||
case ServerType.Bukkit:
|
|
||||||
//event.on(self, 'PlayerLoginEvent', handlerPlayerJoin);
|
|
||||||
break;
|
|
||||||
case ServerType.Sponge:
|
|
||||||
server.players(function(player) {
|
|
||||||
boards[player.name] = new MiaoBoard(player);
|
|
||||||
})
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handlerPlayerJoin(event) {
|
|
||||||
var player = event.player || event.targetEntity;
|
|
||||||
boards[player.name] = new MiaoBoard(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handlerPlayerQuit(event) {
|
|
||||||
var player = event.player || event.targetEntity;
|
|
||||||
delete boards[player.name];
|
|
||||||
}
|
|
||||||
|
|
||||||
function registerTask() {
|
|
||||||
update_task = task.timerAsync(updateBoard, self.config.UpdateTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateBoard() {
|
|
||||||
for (var i in boards) {
|
|
||||||
var player = server.player(i);
|
|
||||||
if (player.isOnline()) {
|
|
||||||
var format = getBoardFormat(player);
|
|
||||||
if (format) {
|
|
||||||
boards[i].update(papi.$(player, format.title), papi.$(player, format.lines));
|
|
||||||
} else {
|
|
||||||
boards[i].clear();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
delete boards[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getBoardFormat(player) {
|
|
||||||
for (var i in board_formats) {
|
|
||||||
var format = board_formats[i];
|
|
||||||
if (player.hasPermission(format.permission)) {
|
|
||||||
return format;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function disable() {
|
|
||||||
if (update_task) { update_task.cancel(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
function MiaoBoard(player) {
|
|
||||||
var Scoreboard = Java.type('org.spongepowered.api.scoreboard.Scoreboard');
|
|
||||||
var Objective = Java.type('org.spongepowered.api.scoreboard.objective.Objective');
|
|
||||||
var Criteria = Java.type('org.spongepowered.api.scoreboard.critieria.Criteria');
|
|
||||||
var Text = Java.type('org.spongepowered.api.text.Text');
|
|
||||||
var DisplaySlots = Java.type('org.spongepowered.api.scoreboard.displayslot.DisplaySlots');
|
|
||||||
|
|
||||||
var uuid = player.uniqueId;
|
|
||||||
var scoreboard = Scoreboard.builder().build();
|
|
||||||
var sidebar = Objective.builder().criterion(Criteria.DUMMY).displayName(Text.EMPTY).name("Sidebar").build();
|
|
||||||
|
|
||||||
var origin = [];
|
|
||||||
|
|
||||||
scoreboard.addObjective(sidebar);
|
|
||||||
player.setScoreboard(scoreboard);
|
|
||||||
|
|
||||||
this.update = function(title, lines) {
|
|
||||||
this.updateBuffer(title, lines);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.updateBuffer = function(title, lines) {
|
|
||||||
sidebar.scores.values().forEach(function removeScore(score) {
|
|
||||||
sidebar.removeScore(score);
|
|
||||||
})
|
|
||||||
var i = 0;
|
|
||||||
sidebar.setDisplayName(Text.of(title));
|
|
||||||
lines.forEach(function addScore(line) {
|
|
||||||
sidebar.getOrCreateScore(Text.of(line)).setScore(lines.length - i++);
|
|
||||||
})
|
|
||||||
scoreboard.updateDisplaySlot(sidebar, DisplaySlots.SIDEBAR);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.clear = function() {
|
|
||||||
player.setScoreboard(Scoreboard.builder().build());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
description: description,
|
|
||||||
load: load,
|
|
||||||
enable: enable,
|
|
||||||
disable: disable
|
|
||||||
};
|
|
@ -1,10 +1,26 @@
|
|||||||
name: ${project.artifactId}
|
name: ${project.artifactId}
|
||||||
description: ${project.description}
|
description: ${project.description}
|
||||||
main: ${project.groupId}.${project.artifactId}.${project.artifactId}
|
main: ${project.groupId}.${project.artifactId}.${project.artifactId}Bukkit
|
||||||
version: ${project.version}
|
version: ${project.version}
|
||||||
|
api-version: 1.13
|
||||||
author: MiaoWoo
|
author: MiaoWoo
|
||||||
website: ${ciManagement.url}
|
website: ${ciManagement.url}
|
||||||
load: STARTUP
|
|
||||||
softdepend:
|
softdepend:
|
||||||
- PlaceholderAPI
|
- OriginAttribute
|
||||||
- Vault
|
- AttributeSystem
|
||||||
|
- ItemLoreOrigin
|
||||||
|
- PlaceholderAPI
|
||||||
|
- AttributePlus
|
||||||
|
- PlayerPoints
|
||||||
|
- SX-Attribute
|
||||||
|
- CrazyCrates
|
||||||
|
- ProtocolLib
|
||||||
|
- DragonCore
|
||||||
|
- MythicMobs
|
||||||
|
- WorldGuard
|
||||||
|
- Adyeshach
|
||||||
|
- WorldEdit
|
||||||
|
- SkillAPI
|
||||||
|
- TradeMe
|
||||||
|
- Chemdah
|
||||||
|
- Vault
|
||||||
|
Reference in New Issue
Block a user