caoli5288
本帖最后由 caoli5288 于 2018-6-29 00:03 编辑

Script
在服务器中用JavaScript来写插件吧!
帖子下方有脚本实例,欢迎大家分享自己写的脚本

插件指令
执行下列权限需要script.admin权限。


注意
初次接触js脚本的童鞋注意,脚本可以正确调用Java中的重载方法,但是脚本无法声明重载函数,请务必注意。

初次上手
一个最简单的有功能的脚本如下例,它将给登陆的玩家发送信息。description对象定义了脚本的基本属性(非必须)。对象中的handle字段定义了脚本监听的事件。
  1. var description = {
  2.     "author":"mengcraft.com",
  3.     "name":"Hello",
  4.     "version":"1.0",
  5.     "handle":"playerjoinevent"
  6. }

  7. var handle = function handle(event) {
  8.     var p = event.player
  9.     p.sendMessage("hello, " + p.name)
  10. }
复制代码


加载脚本
插件在启动时自动加载插件根目录下文件名匹配*.js的脚本,不匹配或位于子目录的脚本请使用指令/script load <文件名>加载。脚本文件名后的字符作为全局变量arg传入脚本中,类型为string[]。自动加载的脚本arg始终为未定义。
  1. if (arg) {
  2.     loader.sendMessage(arg.join(" "));
  3. }
复制代码


单次脚本
如果脚本没有添加指令、事件监听和任务调度等行为,那么该脚本为单次脚本。单次脚本执行后不驻留,因此可以通过指令反复加载。

监听事件
这里有另一种更加灵活的方式监听一个事件,并且你可以随时添加或者去除一个或者多个监听器。事件名默认小写化处理。
  1. var description = {
  2.     "author":"mengcraft.com",
  3.     "name":"Hello",
  4.     "version":"1.0",
  5. }

  6. var listener = plugin.addListener("playerjoinevent", function(event) {...})

  7. listener.remove()
复制代码


对于第三方插件中的事件可能需要在监听前进行注册操作。事件名冲突时请使用插件名作为前置命名空间。
  1. plugin.mapping.init("AnyPlugin")

  2. plugin.addListener("playerjoinevent", function(event) {
  3.     plugin.logger.info("build-in event fire")
  4. })

  5. plugin.addListener("anyplugin:playerjoinevent", function(event) {
  6.     plugin.logger.info("AnyPlugin's event fire")
  7. })
复制代码


你可以按正则过滤事件,注意事件名使用小写字母。
  1. plugin.mapping.filter("any(.*)event").forEach(function (name) {
  2.     plugin.addListener(name, function (evt) {...})
  3. })
复制代码


请注意脚本处理事件继承与插件有所区别。例如,插件中监听EntityDamageEvent会将该类的子类一并监听,而脚本的监听器对此做了额外处理以确保不会监听到子类。

玩家权限
可以在脚本中给予玩家权限。权限仅在玩家本次在线过程中有效。插件卸载不会移除权限。
  1. var p = plugin.addPermission(plugin.getPlayer("md_5"), "script.admin")
  2. // do any here
  3. p.remove()
复制代码


加入指令
你可以添加一个或者多个指令。以下代码同时添加/echo/script:echo指令。回调函数的第一个参数是指令执行者,第二个参数是指令参数,类型为Array
  1. plugin.addExecutor("echo", function(sender, i) {
  2.     if (Array.isArray(i)) sender.sendMessage(i.join(" "))
  3. })
复制代码


可以直接指定执行指令所需的权限。
  1. plugin.addExecutor("echo", "echo.use", function(sender, i) {...})
复制代码


理所当然的,添加的指令随时可以撤销。
  1. var exec = plugin.addExecutor(...)
  2. exec.remove()
复制代码


服务加载
加载服务是可能的,并且比Java插件中的做法更为简单。但是你无法在脚本中提供一个服务。
  1. var economy = plugin.getService("Economy")
  2. var p = plugin.getPlayer("him")
  3. if (economy && p) {
  4.     economy.depositPlayer(p, 100)
  5.     p.sendMessage("you receive 100 dollar")
  6.     plugin.getAll().forEach(function(player) {
  7.         player.sendMessage("lucky! " + p.name + " receive 100 dollar");
  8.     })
  9. }
复制代码


发送广播
广播消息将发送给当前在线的所有玩家。消息支持任意多行,默认将替换&为颜色代码。
  1. plugin.broadcast("&1这是第一行消息",
  2.     "&2这是第二行消息",
  3.     "&3这是第三行消息")
复制代码


插件依赖
脚本加载的时机之于服务器插件加载的时机是不确定的。有些函数的调用必须确保在一些插件加载之后调用,否则可能得到意料之外的结果。
  1. plugin.depend("Vault", function () {
  2.     var eco = plugin.getService("Economy");
  3.     plugin.addListener("playerjoinevent", function () {
  4.         eco.depositPlayer(p, 100);
  5.     })
  6. })
复制代码


在这个用例中,如果Vault插件已经加载那么回调函数将立即执行,否则将推迟到下tick执行,该行为视同任务调度。如果插件仍未加载,回调函数将被抛弃并在控制台输出一个警告信息。

也可以同时依赖多个插件。
  1. plugin.depend(["Vault", "AnyPlugin"], function () {...});
复制代码


你可以给该行为添加一个失败时执行的回调函数。
  1. plugin.depend("Vault", function () {...})
  2.     .onFail(function () {
  3.         plugin.logger.info("Vault NOT found!");
  4.         plugin.unload();
  5.     });
复制代码


交互插件
与其他脚本或者插件进行交互是不安全的,但你仍可以在必要时这么做。使用时请注意脚本或插件加载顺序,必要时使用plugin.depend函数。
  1. var p = plugin.unsafe.getPlugin("PlayerPoints").getApi()
  2. p.give(plugin.getPlayer("Him"), 100)

  3. plugin.unsafe.getScript("other_script").plugin.unload()
复制代码


任务调度
尝试在脚本加载6000tick后执行任务,你可以随时在任务未执行前取消它。
  1. var task = plugin.runTask(function() {...}, 6000)
  2. task.cancel()
复制代码


或者调度一个在下tick执行,并且每1800tick循环执行的任务。
  1. plugin.runTask(function() plugin.logger.info("hello, world"), 1, 1800)
复制代码


或者在下tick执行一个任务。
  1. plugin.runTask(function() plugin.logger.info("hello, world"))
复制代码


异步的任务调度都是可行的,只需要在参数后传入true标识。
  1. plugin.runTask(function() {...}, true)
  2. plugin.runTask(function() {...}, 1, true)
  3. plugin.runTask(function() {...}, 1, 1800, true)
复制代码


后台指令
  1. plugin.runCommand("kill him");
复制代码


引用其他插件类
一些服务端架构方面的限制导致脚本中无法直接使用内置方法引用其他插件类,此时请使用这个方法获取。
  1. var viaversion = plugin.loadType("us.myles.ViaVersion.api.Via");
  2. var api = viaversion.static.getAPI();// 静态方法
复制代码


卸载
脚本卸载时将移除所有的事件监听、指令和未完成的任务,请谨慎操作。
  1. plugin.unload();
复制代码


如果你定义了卸载钩子,卸载钩子将在脚本卸载完成时被执行。钩子中无法执行大部分plugin接口调用。
  1. plugin.setUnloadHook(function() {...});
  2. plugin.setUnloadHook(null);
复制代码


Placeholder
如果服务器安装有PlaceholderAPI,那么可以很方便的注册placeholder以及格式化字符串。
  1. var hook = plugin.addPlaceholder("sp", function (p, input) {
  2.     // sp_any_world -> any|world
  3.     return input[0] + "|" + input[1];
  4. });
  5. hook.remove();// remove it

  6. var jeb = plugin.getPlayer("jeb");
  7. jeb.sendMessage(plugin.format(jeb, "hello, %player_name%"))
复制代码


Boss血条
该API只适用于1.9版本以上的服务端。文字中的%placeholder%将自动替换。
  1. var norch = plugin.getPlayer("norch");
  2. plugin.sendBossBar(norch, "hello, %player_name%", 100);// shown 100 tick(s)
复制代码


亦支持传入任意血条样式描述。
  1. plugin.sendBossBar(norch, "hello, %player_name%", {color: "red", style: 0, flag: ["darken_sky", "play_boss_music", "create_fog"]}, 100);
复制代码

参数color的取值范围为["pink", "blue", "red", "green", "yellow", "purple", "white"],参数style的取值范围为0-4

脚本实例 - 更方便于上手插件
重生后给玩家发送死亡时的坐标:
  1. description = {
  2.         name: "死亡坐标"
  3. }

  4. plugin.addListener("playerdeathevent", function (evt) {
  5.         var p = evt.entity;
  6.         var loc = p.location;
  7.         p.sendMessage("§c你最后的坐标为 §6§l"+loc.blockX+"§7, §6§l"+loc.blockY+"§7, §6§l"+loc.blockZ)
  8. })
复制代码


jiongjionger
给梦梦大佬点赞,真热更新插件。

xziye
mcbbs有你更精彩

Greekssky
前排占位置,为梦梦点赞

背着书包丶
哇!惊现梦梦。梦梦的插件写的也太牛逼了吧

CziSKY
大佬牛逼!希望推出更多范例

爱浪
mcbbs有你更精彩,前排前排~

龌龊大大
活捉一只,梦梦大佬

梅子酒呀
MCBBS有你更精彩~

1255655119
只可惜自己学艺不精,Java插件都还没精通,JavaScript更是差了,真希望哪天能用上

粘兽
用插件写插件,讲究!

Sobo
以后怕不是插件都可以直接用js来写了,那真的要方便很多啊~

MoeWhite19
好东西 ,以后肯定能用上

qq的小辣鸡
这个插件很棒啊

xingtan7815
插件已收藏,感谢楼主的感谢