feat: add MavenDependLoader
Signed-off-by: MiaoWoo <admin@yumc.pw>
This commit is contained in:
parent
e2f9bbf587
commit
56152657c8
12
pom.xml
12
pom.xml
@ -2,7 +2,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>pw.yumc</groupId>
|
||||
<artifactId>MiaoScript</artifactId>
|
||||
<version>0.20.0</version>
|
||||
<version>0.21.1</version>
|
||||
<developers>
|
||||
<developer>
|
||||
<id>502647092</id>
|
||||
@ -16,9 +16,6 @@
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<excludes>
|
||||
<exclude>dev-plugins/**</exclude>
|
||||
</excludes>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
@ -230,7 +227,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-websocket</artifactId>
|
||||
<version>5.3.13</version>
|
||||
<version>5.3.18</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@ -239,5 +236,10 @@
|
||||
<version>9.0.35</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.zaxxer</groupId>
|
||||
<artifactId>HikariCP</artifactId>
|
||||
<version>4.0.3</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@ -2,6 +2,7 @@ package pw.yumc.MiaoScript;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import pw.yumc.MiaoScript.api.ScriptEngine;
|
||||
|
||||
/**
|
||||
* 喵式脚本
|
||||
|
@ -2,6 +2,7 @@ package pw.yumc.MiaoScript;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
import pw.yumc.MiaoScript.api.ScriptEngine;
|
||||
|
||||
/**
|
||||
* Created with IntelliJ IDEA
|
||||
|
@ -2,6 +2,7 @@ package pw.yumc.MiaoScript;
|
||||
|
||||
import cn.nukkit.plugin.PluginBase;
|
||||
import lombok.SneakyThrows;
|
||||
import pw.yumc.MiaoScript.api.ScriptEngine;
|
||||
|
||||
/**
|
||||
* @author MiaoWoo
|
||||
|
@ -11,6 +11,7 @@ import org.spongepowered.api.event.game.state.GameStartingServerEvent;
|
||||
import org.spongepowered.api.event.game.state.GameStoppingServerEvent;
|
||||
import org.spongepowered.api.plugin.Plugin;
|
||||
import pw.yumc.MiaoScript.api.MiaoScriptAPI;
|
||||
import pw.yumc.MiaoScript.api.ScriptEngine;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
|
@ -6,6 +6,7 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
|
||||
import pw.yumc.MiaoScript.api.ScriptEngine;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
|
@ -1,6 +1,4 @@
|
||||
package pw.yumc.MiaoScript;
|
||||
|
||||
import pw.yumc.MiaoScript.api.MiaoScriptAPI;
|
||||
package pw.yumc.MiaoScript.api;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@ -16,7 +14,7 @@ import java.nio.file.Paths;
|
||||
* Created on 2017/10/9 12:40.
|
||||
*/
|
||||
public class Base {
|
||||
private Object instance;
|
||||
private final Object instance;
|
||||
|
||||
Base(Object instance) {
|
||||
this.instance = instance;
|
||||
@ -42,6 +40,10 @@ public class Base {
|
||||
return JavaScriptTask.class;
|
||||
}
|
||||
|
||||
public File[] loadMavenDepend(String groupId, String artifactId, String version) {
|
||||
return MiaoScriptAPI.loadMavenDepend(groupId, artifactId, version);
|
||||
}
|
||||
|
||||
public String read(String path) throws IOException {
|
||||
return read(Paths.get(path));
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package pw.yumc.MiaoScript;
|
||||
package pw.yumc.MiaoScript.api;
|
||||
|
||||
import java.util.concurrent.Delayed;
|
||||
import java.util.concurrent.TimeUnit;
|
@ -1,17 +1,48 @@
|
||||
package pw.yumc.MiaoScript.api;
|
||||
|
||||
import pw.yumc.MiaoScript.MiaoScriptEngine;
|
||||
import pw.yumc.MiaoScript.ScriptEngine;
|
||||
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.20.0";
|
||||
public static final String VERSION = "0.21.1";
|
||||
private static String root;
|
||||
private static String libPath;
|
||||
private static ScriptEngine scriptEngine;
|
||||
private static PluginManager pluginManager;
|
||||
|
||||
public static void setEngine(ScriptEngine scriptEngine) {
|
||||
MiaoScriptAPI.scriptEngine = scriptEngine;
|
||||
public static String getRoot() {
|
||||
return root;
|
||||
}
|
||||
|
||||
public static void setRoot(String root) {
|
||||
MiaoScriptAPI.root = root;
|
||||
MiaoScriptAPI.libPath = Paths.get(root, "libs").toString();
|
||||
}
|
||||
|
||||
public static MiaoScriptEngine getEngine() {
|
||||
return MiaoScriptAPI.scriptEngine.getEngine();
|
||||
}
|
||||
|
||||
public static void setEngine(ScriptEngine scriptEngine) {
|
||||
MiaoScriptAPI.scriptEngine = scriptEngine;
|
||||
}
|
||||
|
||||
public static PluginManager getPluginManager() {
|
||||
return pluginManager;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package pw.yumc.MiaoScript;
|
||||
package pw.yumc.MiaoScript.api;
|
||||
|
||||
import javax.script.Bindings;
|
||||
import javax.script.ScriptEngine;
|
@ -1,7 +1,7 @@
|
||||
package pw.yumc.MiaoScript;
|
||||
package pw.yumc.MiaoScript.api;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import pw.yumc.MiaoScript.api.MiaoScriptAPI;
|
||||
import pw.yumc.MiaoScript.engine.MiaoScriptEngine;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
@ -25,6 +25,7 @@ public class ScriptEngine {
|
||||
this.root = root;
|
||||
this.logger = logger;
|
||||
this.base = new Base(instance);
|
||||
MiaoScriptAPI.setRoot(root);
|
||||
MiaoScriptAPI.setEngine(this);
|
||||
}
|
||||
|
@ -7,12 +7,12 @@ import org.bukkit.event.HandlerList;
|
||||
import javax.script.Bindings;
|
||||
|
||||
public class ScriptEvent extends Event implements Cancellable {
|
||||
private final String plugin;
|
||||
private final Bindings plugin;
|
||||
private final String event;
|
||||
private final Bindings data;
|
||||
private boolean cancelled = false;
|
||||
|
||||
public ScriptEvent(String plugin, String event, Bindings data) {
|
||||
public ScriptEvent(Bindings plugin, String event, Bindings data) {
|
||||
this.plugin = plugin;
|
||||
this.event = event;
|
||||
this.data = data;
|
||||
@ -23,7 +23,7 @@ public class ScriptEvent extends Event implements Cancellable {
|
||||
*
|
||||
* @return PluginName
|
||||
*/
|
||||
public String getPlugin() {
|
||||
public Bindings getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
|
48
src/main/java/pw/yumc/MiaoScript/api/loader/JarLoader.java
Normal file
48
src/main/java/pw/yumc/MiaoScript/api/loader/JarLoader.java
Normal file
@ -0,0 +1,48 @@
|
||||
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 Object ucp;
|
||||
private static MethodHandle addURLMethodHandle;
|
||||
|
||||
static {
|
||||
initReflect();
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static File load(File file) {
|
||||
addURLMethodHandle.invoke(ucp, file.toURI().toURL());
|
||||
return file;
|
||||
}
|
||||
|
||||
private static void initReflect() {
|
||||
try {
|
||||
ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
||||
Field theUnsafe = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
|
||||
theUnsafe.setAccessible(true);
|
||||
sun.misc.Unsafe 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");
|
||||
}
|
||||
long offset = unsafe.objectFieldOffset(ucpField);
|
||||
ucp = unsafe.getObject(loader, offset);
|
||||
Method method = ucp.getClass().getDeclaredMethod("addURL", URL.class);
|
||||
addURLMethodHandle = lookup.unreflect(method);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package pw.yumc.MiaoScript.api.loader;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
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 {
|
||||
private 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"))
|
||||
};
|
||||
}
|
||||
|
||||
@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))) {
|
||||
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(30000);
|
||||
connection.setUseCaches(true);
|
||||
Files.copy(connection.getInputStream(), target.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private static String getSha1(File file) {
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-1");
|
||||
FileInputStream in = new FileInputStream(file);
|
||||
FileChannel ch = in.getChannel();
|
||||
MappedByteBuffer byteBuffer = ch.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,10 @@
|
||||
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);
|
||||
}
|
@ -1,19 +1,15 @@
|
||||
package pw.yumc.MiaoScript;
|
||||
package pw.yumc.MiaoScript.engine;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.val;
|
||||
import pw.yumc.MiaoScript.api.loader.JarLoader;
|
||||
import pw.yumc.MiaoScript.api.loader.MavenDependLoader;
|
||||
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.*;
|
||||
import java.io.File;
|
||||
import java.io.Reader;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
@ -23,12 +19,9 @@ import java.util.HashMap;
|
||||
* @since 2016年8月29日 上午7:51:43
|
||||
*/
|
||||
public class MiaoScriptEngine implements ScriptEngine, Invocable {
|
||||
private static String MavenRepo = "https://maven.aliyun.com/repository/public";
|
||||
private static MiaoScriptEngine DEFAULT;
|
||||
private static final ScriptEngineManager manager;
|
||||
|
||||
private Object ucp;
|
||||
private MethodHandle addURLMethodHandle;
|
||||
private ScriptEngine engine;
|
||||
|
||||
static {
|
||||
@ -88,71 +81,26 @@ public class MiaoScriptEngine implements ScriptEngine, Invocable {
|
||||
for (String dir : dirs) {
|
||||
File nashorn = new File(dir, "nashorn.jar");
|
||||
if (nashorn.exists()) {
|
||||
this.loadJar(nashorn);
|
||||
JarLoader.load(nashorn);
|
||||
this.createEngineByName(engineType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initReflect() {
|
||||
try {
|
||||
ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
||||
Field theUnsafe = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
|
||||
theUnsafe.setAccessible(true);
|
||||
sun.misc.Unsafe 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");
|
||||
}
|
||||
long offset = unsafe.objectFieldOffset(ucpField);
|
||||
ucp = unsafe.getObject(loader, offset);
|
||||
Method method = ucp.getClass().getDeclaredMethod("addURL", URL.class);
|
||||
addURLMethodHandle = lookup.unreflect(method);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private void loadNetworkNashorn(String engineRoot) {
|
||||
initReflect();
|
||||
File libRootFile = new File(engineRoot, "lib");
|
||||
File libRootFile = new File(engineRoot, "libs");
|
||||
libRootFile.mkdirs();
|
||||
String libRoot = libRootFile.getCanonicalPath();
|
||||
downloadJar(libRoot, "org.openjdk.nashorn", "nashorn-core", "15.3");
|
||||
downloadJar(libRoot, "org.ow2.asm", "asm", "9.2");
|
||||
downloadJar(libRoot, "org.ow2.asm", "asm-commons", "9.2");
|
||||
downloadJar(libRoot, "org.ow2.asm", "asm-tree", "9.2");
|
||||
downloadJar(libRoot, "org.ow2.asm", "asm-util", "9.2");
|
||||
MavenDependLoader.load(libRoot, "org.openjdk.nashorn", "nashorn-core", "15.3");
|
||||
MavenDependLoader.load(libRoot, "org.ow2.asm", "asm", "9.2");
|
||||
MavenDependLoader.load(libRoot, "org.ow2.asm", "asm-commons", "9.2");
|
||||
MavenDependLoader.load(libRoot, "org.ow2.asm", "asm-tree", "9.2");
|
||||
MavenDependLoader.load(libRoot, "org.ow2.asm", "asm-util", "9.2");
|
||||
Class<?> NashornScriptEngineFactory = Class.forName("org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory");
|
||||
Method getScriptEngine = NashornScriptEngineFactory.getMethod("getScriptEngine", ClassLoader.class);
|
||||
Method getScriptEngine = NashornScriptEngineFactory.getMethod("getScriptEngine");
|
||||
Object factory = NashornScriptEngineFactory.newInstance();
|
||||
engine = (ScriptEngine) getScriptEngine.invoke(factory, ClassLoader.getSystemClassLoader());
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private void loadJar(File file) {
|
||||
addURLMethodHandle.invoke(ucp, file.toURI().toURL());
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private void downloadJar(String engineRoot, String groupId, String artifactId, String version) {
|
||||
File lib = new File(engineRoot, String.format("%s-%s.jar", artifactId, version));
|
||||
if (!lib.exists()) {
|
||||
Files.copy(new URL(MavenRepo +
|
||||
String.format("/%1$s/%2$s/%3$s/%2$s-%3$s.jar",
|
||||
groupId.replace(".", "/"),
|
||||
artifactId,
|
||||
version)
|
||||
).openStream(),
|
||||
lib.toPath(),
|
||||
StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
this.loadJar(lib);
|
||||
engine = (ScriptEngine) getScriptEngine.invoke(factory);
|
||||
}
|
||||
|
||||
private void createEngineByName(String engineType) {
|
@ -16,7 +16,7 @@ var global = this;
|
||||
global.logger = logger
|
||||
// Development Env Detect
|
||||
global.root = root || "src/main/resources"
|
||||
checkDebug()
|
||||
readEnvironment()
|
||||
if (!global.debug) {
|
||||
checkUpgrade()
|
||||
}
|
||||
@ -50,24 +50,24 @@ var global = this;
|
||||
global.engineDisableImpl && global.engineDisableImpl()
|
||||
}
|
||||
|
||||
function checkDebug() {
|
||||
function readEnvironment() {
|
||||
if (__FILE__.indexOf('!') === -1) {
|
||||
logger.info('Loading custom BIOS file ' + __FILE__)
|
||||
logger.info('loading custom BIOS file ' + __FILE__)
|
||||
global.debug = true
|
||||
}
|
||||
if (Files.exists(Paths.get(root, "debug"))) {
|
||||
logger.info('Running in debug mode...')
|
||||
logger.info('running in debug mode...')
|
||||
global.debug = true
|
||||
}
|
||||
if (Files.exists(Paths.get(root, "level"))) {
|
||||
global.level = base.read(Paths.get(root, "level"))
|
||||
logger.info('Set system level to [' + global.level + ']...')
|
||||
logger.info('set system level to [' + global.level + ']...')
|
||||
}
|
||||
}
|
||||
|
||||
function checkUpgrade() {
|
||||
if (Files.exists(Paths.get(root, "upgrade"))) {
|
||||
logger.info('Found upgrade file starting 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"))
|
||||
}
|
||||
|
@ -2,12 +2,30 @@
|
||||
// @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 log() {
|
||||
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
|
||||
*/
|
||||
@ -16,13 +34,23 @@
|
||||
log('[' + prefix + ']', Array.prototype.join.call(arguments, ' '))
|
||||
}
|
||||
}
|
||||
return {
|
||||
var logProxy = {
|
||||
log: log,
|
||||
info: log,
|
||||
ex: log,
|
||||
trace: global.level === "trace" ? _proxy('TRACE') : global.noop,
|
||||
debug: global.debug ? _proxy('DEBUG') : global.noop,
|
||||
debug: global.debug ? logger.debug ? debug : _proxy('DEBUG') : global.noop,
|
||||
warn: _proxy('WARN'),
|
||||
error: _proxy('ERROR')
|
||||
}
|
||||
if (logger.warn) {
|
||||
logProxy.warn = warn
|
||||
}
|
||||
if (logger.warning) {
|
||||
logProxy.warn = warning
|
||||
}
|
||||
if (logger.error) {
|
||||
logProxy.error = error
|
||||
}
|
||||
return logProxy
|
||||
})
|
||||
|
@ -217,7 +217,7 @@
|
||||
var filename = file.name
|
||||
var lastDotIndexOf = filename.lastIndexOf('.')
|
||||
if (lastDotIndexOf == -1) {
|
||||
throw Error('require module must include file ext.')
|
||||
throw Error('require ' + file + ' error: module must include file ext.')
|
||||
}
|
||||
var name = filename.substring(0, lastDotIndexOf)
|
||||
var ext = filename.substring(lastDotIndexOf + 1)
|
||||
@ -268,8 +268,9 @@
|
||||
}
|
||||
// 2019-09-19 使用 扩展函数直接 load 无需保存/删除文件
|
||||
// 2020-02-16 结尾新增换行 防止有注释导致加载失败
|
||||
var wrapperScript = '(function (module, exports, require, __dirname, __filename) {' + script + '\n});'
|
||||
var compiledWrapper = engineLoad({
|
||||
script: '(function (module, exports, require, __dirname, __filename) {' + script + '\n});',
|
||||
script: wrapperScript,
|
||||
name: optional.id
|
||||
})
|
||||
compiledWrapper.apply(module.exports, [
|
||||
@ -306,19 +307,24 @@
|
||||
var module_name = name.startsWith('@') ? name_arr[0] + '/' + name_arr[1] : name_arr[0]
|
||||
var target = MS_NODE_PATH + separatorChar + module_name
|
||||
var _package = new File(target, 'package.json')
|
||||
if (_package.exists()) {
|
||||
return
|
||||
}
|
||||
if (_package.exists()) { return name }
|
||||
// at windows need replace file name java.lang.IllegalArgumentException: Invalid prefix or suffix
|
||||
var info = fetchPackageInfo(module_name)
|
||||
var url = info.versions[ModulesVersionLock[module_name] || info['dist-tags']['latest']].dist.tarball
|
||||
console.log('fetch node_module ' + module_name + ' from ' + url + ' waiting...')
|
||||
var latest_version = info['dist-tags']['latest']
|
||||
var version = ModulesVersionLock[module_name] || latest_version
|
||||
var _version = info.versions[version] || info.versions[latest_version]
|
||||
var url = _version.dist.tarball
|
||||
console.log('fetch node_module ' + module_name + ' version ' + version + ' waiting...')
|
||||
return executor.submit(new Callable(function () {
|
||||
var tis = new TarInputStream(new BufferedInputStream(new GZIPInputStream(new URL(url).openStream())))
|
||||
var entry
|
||||
while ((entry = tis.getNextEntry()) != null) {
|
||||
var targetPath = Paths.get(target + separatorChar + entry.getName().substring(8))
|
||||
targetPath.toFile().getParentFile().mkdirs()
|
||||
var parentFile = targetPath.toFile().getParentFile()
|
||||
if (!parentFile.isDirectory()) {
|
||||
parentFile.delete()
|
||||
parentFile.mkdirs()
|
||||
}
|
||||
Files.copy(tis, targetPath, StandardCopyOption.REPLACE_EXISTING)
|
||||
}
|
||||
return name
|
||||
@ -418,13 +424,8 @@
|
||||
if (optional.local || optional.recursive || notFoundModules[name]) {
|
||||
throw new Error("Can't found module " + name + '(' + JSON.stringify(optional) + ') at local ' + path + ' or network!')
|
||||
}
|
||||
try {
|
||||
optional.recursive = true
|
||||
return _require(download(name), path, optional)
|
||||
} catch (ex) {
|
||||
notFoundModules[name] = true
|
||||
throw new Error("Can't found module " + name + ' in directory ' + path + ' ERROR: ' + ex)
|
||||
}
|
||||
optional.recursive = true
|
||||
return _require(download(name), path, optional)
|
||||
}
|
||||
setCacheModule(file, optional)
|
||||
return _requireFile(file, optional)
|
||||
@ -592,7 +593,8 @@
|
||||
|
||||
function initVersionLock() {
|
||||
try {
|
||||
ModulesVersionLock = JSON.parse(fetchContent('https://ms.yumc.pw/api/plugin/download/name/version_lock', 5))
|
||||
var version_lock_url = 'https://ms.yumc.pw/api/plugin/download/name/version_lock' + (global.debug ? '-debug' : '')
|
||||
ModulesVersionLock = JSON.parse(fetchContent(version_lock_url, 5))
|
||||
try {
|
||||
ModulesVersionLock = __assign(ModulesVersionLock, JSON.parse(base.read(localVersionLockFile)))
|
||||
} catch (e) {
|
||||
|
@ -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
|
||||
|
||||
![](https://dn-coding-net-production-pp.qbox.me/f459067b-7829-45ec-9713-bb559d1e0118.png)
|
||||
|
||||
> 注意: 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
|
||||
};
|
Loading…
Reference in New Issue
Block a user