- 欢迎来到Minecraft插件百科!
- 对百科编辑一脸懵逼?帮助:快速入门带您快速熟悉百科编辑!
- 因近日遭受攻击,百科现已限制编辑,有意编辑请加入插件百科企鹅群:223812289
LuckPerms
外文名 | LuckPerms |
作者 | Luck |
插件类型 | Spigot / CraftBukkit / Sponge |
最新版本 | 4.0.18(Bukkit) / 4.0.60(Sponge) |
兼容服务端 | 1.7, 1.8, 1.9, 1.10, 1.11, 1.12,1.13,1.14,1.15,1.16,1.17,1.18,1.19,1.20 |
源地址 | SpigotMC SpongePowered |
LuckPerms是Minecraft服务端(Bukkit / Spigot,BungeeCord等)的权限插件。它允许服务器管理员通过创建组和分配权限来控制玩家可以使用的功能,由Luck开发。
引言
从何开始?
如果您从未使用过任意权限插件,我推荐你从头开始看。
基础都在[使用教程]页面。
完整的命令使用在[命令使用]页面。
什么也没找到?
如果你有更多的问题是这篇Wiki没有解决的,你可以通过以下几种方式联系我。
- [Discord 服务器] (就算我不在,也有很多人帮助你!)
- 在 irc.esper.net 我是 "Luck",我也在 irc.spi.gt 和 chat.freenode.net
- 在 SpigotMC 和 Sponge 论坛我是 "Luck"
- 在[GitHub]提交一个 issue (如果你要提交一个BUG,这是最好的方式)
一些有用的链接
为什么选择LuckPerms?
这是另外一款全新的权限插件?
是的,我认为LuckPerm相比其他权限插件还有很大的发展空间。
LuckPerm是一款先进、高等的权限插件,仅仅以快速、稳定可靠、灵活多变的特点,
便可以替代现有的许多权限插件,例如PermissionsEX、GroupManagerX、z/bPermissions、BungeePerms等主流权限插件。
LuckPerms这个插件的计划,本来是围绕着两个主要特点来制作的:高性能、强大且广泛的功能,
填补其他同类插件的功能缺陷、并且建立在同类现有功能上更进一步的优化功能。
LuckPerms还包括了非常广泛的API支持,这是为开发人员的添加的,
并且,luckperms还兼容各式各类Minecraft服务器软件&支持多种数据存储的选择。
我已经使用某插件很长一段时间了,它对我的帮助很大,我也很熟悉它了,为什么我要更换它而选择LuckPerm呢?
现在主流的权限插件大多数都是老牌插件了,并且都是在Bukkit早期就被创造出来了。
虽然,这可能意味着它们非常的稳定可靠,但通常也意味着它们被原作者抛弃,并且一般不会再有任何更新、修复,
但LuckPerm却任然是一个需要成长、需要磨砺的插件!
我会尽力及时查看并回复所有的bug报告、问题,以及可实现的新功能建议
你说的不错,但是我更加偏爱某插件,因为仅凭它就完成了我需要的一切
这没关系,我完全理解你的这种心态,我并不是想要说你**必须**用LuckPerm来作为你服务器的权限插件。
当然还有更多适合你服务器权限插件,但是LuckPerm确实是个很棒的选择,不是么?
来吧兄弟,告诉我,我为什么要使用LuckPerm?
LuckPerm能做很多事情,至少单在技术层面,LuckPerm就胜过大部分同类插件。
我认为这不取决于我制作插件的水平,而是取决于我在LuckPerm上面花费的精力与时间。
LuckPerm是我在2016年开始准备编写的插件,但因为Bukkit变得流行起来,许多同一时期的插件都变成了老牌稳定插件,
不过,这也为我编写LuckPerm提供的很好的参考帮助,因为我可以避免其它同类插件的缺陷,
并且明白它们哪些地方做的特别出色,我可以在其基础之上进一步优化,使那部分功能变得更加引人瞩目。
记着,如果你对LuckPerm技术性方面的内容感兴趣,我推荐你从[命令使用]部分开始阅读
或者看看wiki列出的其他部分内容,在本节的其余部分,我会将阅读重点放到LuckPerm一些全新的特色功能上面。
这些内容是你不太可能从其他插件中找到的,专属luckPerm的特色功能!
Verbose(权限查看系统)
LuckPerm有一套完整的权限查看系统,是的,它叫做[verbose]。
他可以实时监视并检测其他插件所需的权限,就像下面示例的动态图那样:【图片过大 请去wiki页面查看】
你也可以把录像上传到网上,方便查看、分析和阅读:
权限树系统
LuckPerm允许你在服务器所有已知权限上建立编写"权限树"。
权限树上的数据是由你所有的插件在服务器注册的权限构成的。
随着你服务器运营时间的增长,因为服务器添加了许多插件,它们都会注册权限,这些数据都会被纳入权限树中。
这是个清真的例子 [https://git.io/vQiti]。 你看到的权限树的颜色,代表了你的玩家是否拥有对应的权限,这一机制很方便的让你查阅到服务器的相应权限。
这还是那个清真的例子 [[1]]
指令界面&TAB补全
LuckPerm的指令系统被我设计的尽可能便捷、易用、人性化,
这样一来,你除了查阅LuckPerm的[大量相关帮助文档],还可以在游戏中查看指令用法、以及指令列表。
LuckPerm的所有指令皆可使用TAB补全功能,这就意味着,你可以通过输入更少的指令来完成你的工作!
这是不是在一定程度极大地提高了你的工作效率呢?就像下面那样:
网站编辑器
除了使用指令来编辑服务器权限相关,LuckPerm还提供了更加便捷的编辑方式,
你可以使用Web网站编辑器来对服务器的权限数据进行快速更改,
任何人都能够使用网站编辑器,不论你使用了哪种存储方式!
网站编辑功能非常容易使用,且易于上手
【图片过大 请去wiki页面查看】
行为记录仪
为了防止服务器中出现心存不轨的管理员,想要私自给自己添加权限,
LuckPerm详细的记录了服务器各类权限的微小变化,
你可以通过行为记录仪来搜索每个人的详细操作。
你也可以查看所有东西的详细历史。
安装
安装
初始设置
1. 下载适合你平台的 `LuckPerms-???-x.x.x.jar` 文件。你可以点这里查看最新的版本。
2. 打开你的 Mod 或插件所在路径,这路径通常要么是 `/server/plugins/` ,要么是 `/server/mods/`。
然后把 LuckPerms 的 jar 文件放入文件夹中。
3. 请完全关闭你的服务器,然后再打开,这会生成默认配置。
4. 完全关闭你的服务器,打开配置文件。配置文件的位置在 `/plugins/LuckPerms/config.yml` 或 `/config/luckperms/luckperms.conf`。
5. 请浏览配置文件,然后根据你的服务器修改设置,尤其是请注意存储相关设置。
6. 再次开启你的服务器。
你可以更改配置文件中的很多内容,文件有很细节化的注释,每个设置的作用注释中都解释的很清楚。
需求
LuckPerms 插件只有一个环境需求。
- Java 8
没错,唯一需求就是你必须使用 Java 8,LuckPerms 插件在旧版本的Java上不会工作。
到目前为止很多服务器提供商都已经升级到Java 8了,但是如果你的服务器提供商没有升级的话,请温和地和他们谈谈,让他们去升级。
如果你是自己租主机开服的话,你应该对你还没有升级Java感到羞愧!
升级的过程是很简单的,如果你想升级的话网上也有大量的教程。
使用过期的软件肯定不是好的:)
Bukkit版本过旧
如果你收到了类似于 "NoSuchMethod" 或 "ClassNotFound" 这类错误的话,十有八九就是你在使用较旧的Bukkit版本。
在将它作为错误报告给我之前,请尝试使用"Development Builds"(构建版本)下载页面的"Bukkit-Legacy"(Bukkit-旧版)版本。
切换存储类型
LuckPerms 插件所使用的默认数据存储类型是 H2 数据库。
所有的数据都会储存在LuckPerms插件目录下的 `luckperms.db.mv.db` 文件之中。
(插件目录为 `/plugins/LuckPerms/` 或 `/luckperms/`)
这个数据格式普通的文本编辑器是**不能读取**的。
如果你想要手动阅读/编辑LuckPerms插件的数据的话,你就需要切换到**YAML或JSON**存储格式,更改 `config.yml` 文件中的配置选项就好了。
更多相关于存储类型的有关信息请阅读[下一节]
选择存储类型
LuckPerms 插件带有很多存储数据的方式,你可以从中选择。
存储类型选项可以在 `config.yml` 或 `luckperms.conf` 文件中修改。
# Which storage method the plugin should use. # Currently supported: mysql, postgresql, sqlite, h2, json, yaml, mongodb # Fill out connection info below if you're using MySQL, PostgreSQL or MongoDB storage-method: h2
请记住如果你想改变存储类型的话,你的数据不会自动转移到新的存储库中。
要想手动在数据存储方式间转移数据的话,请查看这里来获得更多信息。
可用的选项都列在了下面。
H2 / SQLite
默认的存储类型是 H2。
这两种文件类型都是以SQL数据库为基础的。
所有的数据都会存储在LuckPerms插件目录下的一个文件之中。
和YAML和JSON方式的不同之处在于,这个文件不能用文本编辑器打开。
你必须使用插件提供的命令才能编辑或查看数据。
如果你选择使用 H2 数据库的话(默认设置),所有的数据都会储存在 `luckperms-h2.mv.db` 文件中。
SQLite 类型所提供的存储文件是 `luckperms-sqlite.db`。
要想使用这两种类型中的一种,请将配置设置为:
storage-method: h2 # or storage-method: sqlite
JSON / YAML
JSON 和 YAML 存储类型会将数据存储在可读可编辑的文本文件中。YAML 类型所提供的文件扩展名为 `.yml` ,JSON类型所提供的文件扩展名为 `.json`。
这两种类型的存储格式很相似,只是在一些句法上不同。
示例 YAML 文件
uuid: c1d60c50-70b5-4722-8057-87767557e50d name: Luck primary-group: default permissions: - group.default: value: true - test.permission: value: true server: factions - other.test.permission: value: false
示例 JSON 文件
{ "uuid": "c1d60c50-70b5-4722-8057-87767557e50d", "name": "Luck", "primaryGroup": "default", "permissions": [ { "group.default": { "value": true } }, { "test.permission": { "value": true, "server": "factions" } }, { "other.test.permission": { "value": false, "server": "test" } } ] }
要想使用这两种类型中的一种,请将配置设置为:
storage-method: yaml # or storage-method: json
MySQL / PostgreSQL
储存在 MySQL 类型和 PostgreSQL 类型中的数据格式上与上文提及的 H2/SQLite 类型相同,但是数据是储存在远程服务器上的。
这意味着你可以跨服分享相同的数据。
你需要在配置文件中输入你数据库服务器的地址,端口,数据库名,用户名和密码。
这种类型推荐要存储大量数据的用户,或是想要搭建群组服务器的用户所使用。
如果你已经在运行群组服务器,并且想要在子服务器之间同步数据的话,你就必须选择这种类型了。
格式布局示例在这里。
要想使用这两种选项中的一种,请将配置设置为:
storage-method: mysql # or storage-method: postgresql
MongoDB
LuckPerms 也支持 MongoDB 类型的存储,它也是一种远程数据库,在有些方面上和 MySQL 相似。
这种类型也只会被一小部分的用户所使用。
要想使用这种类型的存储,请将配置设置为:
storage-method: mongodb
使用教程
这篇教程是为之前从来没有使用过权限管理插件的人所准备的。
如果你已经很熟悉权限管理等相关概念了的话,我认为你应该就能够理解命令中的东西了。
这样我就推荐你去阅读命令和权限页面,这样更加“直奔主题”,你也能够更容易理解插件的工作方法。
如果你正在努力想弄明白权限管理相关概念的话,这篇教程就是你起步的最佳地方:)
关键术语
权限
在你的服务器上会有大量的**特性,命令和一些新功能**。
这其中的一些特性是服务器自带的,另一些是由“插件”所添加的。
与这些特性相联系的大多数行为都是由权限所控制的,因此你可以控制哪些用户可以使用你指定的特性或权限。
- 权限仅仅是个字符串**,并且使用英文的句号(半角 → . ←)分成几部分。
举个例子, “minecraft.command.ban” 就是原版 /ban 命令所使用的权限。
显然我们不想让所有用户都能执行这个命令,所以我们只给我们信任的玩家这个权限。
代表特定行为的使用许可的字符串,我们就称之为权限,它又名“权限节点”,简称“权限”。
权限组
代替单独为每个用户设置权限,我们可以将**权限捆绑为一组**,然后直接将这一组**给予玩家**。
举个例子,在我设置的“admin”权限组中,我可能会添加使用ban和unban指令的权限,然后将玩家加入admin权限组中。
这意味着他们能够获得“admin”权限组所设置的所有权限和他们自身被设置的权限。
继承
用户和权限组能够**互相继承权限**。
举个例子,默认地,所有的用户都会从“default”权限组继承权限。
你可以为你自己的服务器设置你自己的权限组与继承方式,或是制作你自己独特的系统。
举个例子,我设置了三个权限组, “default”, “moderator” 和 “admin”。
我想让“moderator”权限组从“default”权限组继承所有权限,“admin”权限组从“moderator”权限组继承所有权限。
起步
如果你还没有将LuckPerms插件安装在你的服务器上的话,我们推荐你先阅读安装有关的教程。
然后,请确保你在继续之前已经阅读了选择数据存储类型的有关章节。
虽然你在后期也能实现数据之间的转移,但第一次就将他们弄对位置是更好的。
给予修改权限的全部权限
你想做的第一件事情就是给你本插件的所有权限。
当本插件首次安装后,没有人能够使用LuckPerms插件的有关命令。
要想做到这个的话,你需要在服务器控制台输入 `/luckperms user Luck permission set luckperms.* true` 。
当然,请把我的名字换成你自己的(不用担心,这条命令的使用方法之后会详细讲解)
这应该就是运行的结果:
实际上,这条命令起的效果,就是给了 `Luck` 用户 `luckperms.*` 权限。(或者说,为用户设置权限为 true)
你可能已经注意到了我们刚才在权限字符串的末端使用的 `*` 字符了。
这个字符叫做通配符,它会给玩家**所有**以 "luckperms" 为开头的权限。
创建第一个权限组
我们可以使用创建权限组命令来创建一个新的权限组。
让我们创建一个叫做“admin”的权限组,然后给它附加一条权限吧。
首先,运行 `/luckperms creategroup admin` 命令。
这会创建一个叫做“admin”的空权限组。
接下来,我们想为“admin”权限组增加一条权限。
用来修改权限组的命令是 `/luckperms group <group>`。
如果你执行这条命令的话,它会为你显示所有可用的子命令。
你可能注意到了第一个子命令是“info”命令。它只会列举出一些权限组相关的信息。
我们可以运行 `/luckperms group admin info` 来查看新建立的“admin”权限组的一些信息。
接下来就是“permission”命令。这能够帮助你修改权限组的权限。
再一次,使用 `/luckperms group admin permission` 命令会列出所有可用的子命令。
再一次,我们看到了更多我们可以执行的命令。
第一个就是另一个 "info" 子命令。
因为它是“permission”子命令下的又一子命令,它就会显示某一权限组所拥有的所有权限。
下面的命令是“set”子命令。
你还记得吗,之前我们使用相似的指令来给玩家 "luckperms.*" 权限。这里它也相同
只需要不加参数运行该命令就可以返回该命令的使用方法。举个例子:
举个例子,我想给我的“admin”用户组 "minecraft.command.ban" 权限。
因此我可以输入 `/luckperms group admin permission set minecraft.command.ban true` 。
这条命令就会给予 `admin` 用户组 `minecraft.command.ban permission` 权限。
末端的true控制我们设置的权限的启用与否。
你可以将权限的启用与否设置为 `true` 或 `false` 。
为用户或权限组将权限设置为 true 能够让他们拥有该权限,设置为 false 即该权限无效。(指定他们没有该权限)
如果晚些时候我决定不再让“admin”用户组拥有这个权限了,我可以使用 unset 命令来移除该权限的设定。
输入 `/luckperms group admin permission unset minecraft.command.ban` 。
将玩家加入到权限组中
将用户加入到权限组中需要使用 "parent" 命令。(在我们的命令使用页我们经常用“permission”替换“parent”)
举个例子,把我自己加入“admin”权限组中,我需要使用 `/luckperms user Luck parent add admin` 。
这条命令会将用户 `Luck` 加入到 `admin` 权限组中。
这意味着任何“admin”权限组所拥有的权限我现在也继承下来了。
让一个权限组继承另一个权限组
就像用户能够继承一样,权限组也能够继承另一个权限组。
举个例子,想想下面这种情况的设置方法。(有些权限仅仅是为了演示而编造出来的)
Admin | Mod | Default |
---|---|---|
minecraft.command.ban | minecraft.command.mute | minecraft.command.say |
minecraft.command.pardon | minecraft.command.unmute | minecraft.command.me |
some.cool.admin.perm | some.cool.mod.perm | |
someplugin.vanish | | |
我想让“admin”权限组中的用户拥有“mod”和“default”权限组的权限,同时“mod”权限组中的用户拥有“default”权限组中的权限。要想实现这个的话,我可以设置用户组之间的相互继承。
`/luckperms group admin parent add mod` 命令会让“admin”权限组继承所有“mod”权限组中的权限。
然后要想让“mod”继承“default”,同样的道理,我可以输入 `/luckperms group mod parent add default`。
继承是可递归的,所以这样以后“admin”权限组就不仅仅继承了“mod”权限组,还继承了“default”权限组。
这意味着“admin”权限组中的玩家拥有“mod”**和**“default”两权限组中的权限了。
在“admin”组的一位用户因此拥有 `minecraft.command.ban`,`minecraft.command.mute` *和* `minecraft.command.say` 权限。
移除继承权限组
要想移除权限组间的继承关系只需要输入一个类似的命令就好了。
要想让我自己不再继承“admin”权限组,我只要输入 `/luckperms user Luck parent remove admin` 就好了。
配置
请见子页面:LuckPerms/配置
特性
权限检查系统(Verbose)
你曾经经历过想要找到某条命令或某种特性的使用权限,但找不到作者提供的帮助文档这种情况吗?
可能作者提供的帮助文档过期了,或是内含的信息不正确。可能你想要修复玩家没有正确权限的问题,或是仅仅是对插件所检查的权限感兴趣……
权限检查系统能够让你监视一段时间内的权限检查操作!😄
如何使用本系统
指令的使用方法如下:
/lp verbose <on|record|off|paste> [filter]
第一个参数会启用/禁用本系统,第二个参数设置权限筛选器。
选项 | 描述 |
---|---|
on
|
启用本系统,并且在设置的筛选权限被检查时会发消息提示您。 |
record
|
与“on”的作用相同,但是您的聊天框不会收到提醒。 |
off
|
会禁用本系统,清除内存中所有的存储记忆。 |
paste
|
与“off”的作用相同,但是会将最先的500个结果上传到一个网页上,然后提供给你一个链接。 |
筛选器
筛选器是用来匹配权限节点的工具,它会过滤掉你不需要的权限。它可以筛选玩家名,或更高级的东西。
筛选器输入的字符能够匹配所有带有该字符的权限的开头,或是玩家的全名。
你可以使用 &
(表示 和), |
(表示 或), 和 !
(表示 非)来设置筛选文本,输入时也支持使用小括号 ( )
。
一些使用示例
Luck & (essentials | worldedit)
—— 会匹配玩家“Luck”的所有以“essentials”或“worldedit”开头的权限检查Luck & !anticheat
—— 会匹配玩家“Luck”所有不以“anticheat”为开头的权限检查anticheat & !anticheat.check
—— 会匹配所有玩家以“anticheat”开头,但不是 "anticheat.check" 权限的权限检查
示例
我使用了指令 /lp verbose record Luck & minecraft
,这打开了权限检查系统,然后会检查 "Luck" 玩家所有以 "minecraft" 开头的权限。
然后我使用了 /help
命令(来让服务器对我进行权限检查),然后我输入了 /lp verbose paste
。
然后插件就会将检查的结果上传,然后返回了这个链接。https://git.io/vDUba
如果你点开这个链接看看的话,你会看到检查的结果的。 😄
在Metadata数据信息下面,你会看到一些有关于检查的数据。
你可以注意到 Count: 58 / 72
,这就是说在这段检查期间,共检查了72条权限,其中58条符合你设定的筛选器。
那些满足筛选器的检查结果已经列出来了。
大量编辑
LuckPerms 提供了一个命令来帮助执行大量的权限编辑,这个命令应该小心使用,因为很容易破坏你的所有信息。
在执行这个命令之前做一个备份可能是个明智的选择,或者是给你的数据库做个备份,或者使用 export 命令。
命令的设计基于 SQL 格式,这意味着命令可以直接转换为一条 SQL 查询语句,或者在 YAML 或者 JSON 文本编辑。那些对 SQL 语句有经验的人可能会发现在数据库服务器直接写入查询比使用命令更简单。
这些命令只能在控制台使用。这是因为这些命令可能会对你的服务器造成极大的伤害。在执行之前,你会被要求输入一个确认码,用于防止 "sudo" 来通过这些命令获得权限。
命令用法如下...
/lp bulkupdate <data type> <action> [action field] [action value] [constraint...]
一开始有点令人害怕,我知道,拆开来看...
参数 | 描述 |
---|---|
data type
|
更改的数据 (可以是 "all", "users" 或者 "groups") |
action
|
对数据执行的操作 (可以是 "update" 或者 "delete") |
action field
|
只可用于 update 操作 (可以是 "permission", "server" 或 "world") |
action value
|
替换的值,只可用于 update 操作 |
constraint
|
update 的约束 |
data type
是最简单的,只是简单的告诉了 LuckPerms 这个操作应该影响什么数据。
action
是对数据执行的操作。可以是 "update" 或 "delete"。delete 就是简单的删除满足约束的所有的记录。Update 将会将原来的值替换为新的值。
action field
和 action value
参数是可选的,因为只对 update 有效。field 是用来更新的东西,而 value 是用来替换的东西。
constraints
参数与 update 的限制有关,只有权限(或者条目)匹配约束才会被影响。
约束
约束分为 3 部分,field
, comparison
和 value
。
可用的 fields
是 permission
, server
和 world
。权限就只是存储在文件中的权限节点(记住甚至组的关系和前缀都是存储在前缀的)。server 和 world 与 permission 应用的世界和服务器有关。如果权限没有他们的值,那么就是全局。
value
部分的约束是需要的 field,用于比较。
有四种比较的方式。
比较符号 | 比较的名称 | 描述 |
---|---|---|
==
|
等于 | 两个值相同(忽略大小写) |
!=
|
不等于 | 两个值不相同(忽略大小写) |
~~
|
相似 | 两个值相似,与SQL的 LIKE 关键字相同
|
!~
|
不相似 | 两个值不相似,与SQL的 LIKE 关键字相同
|
基础的大概是这样的: * %
- 百分号代表 0 到多个字符 * _
- 下划线代表一个字符
一些示例
server ~~ hub_
匹配 "hub1", "hub2", "hub3" 等permission !~ group.%
匹配任何不以 group 开头的权限world == nether
匹配世界名为 nether
当在命令中使用约束,必须使用 " "
引号包围。
命令示例
/lp bulkupdate all update permission group.mod "permission == group.moderator"
更新所有的条目,替换所有的 "group.moderator" 为 "group.mod"(效率重命名)。
/lp bulkupdate user delete "server ~~ hub%" "world == nether"
删除任何分配给以 "hub" 开头的服务器,并且世界是 "nether" 的玩家的权限。
/lp bulkupdate all delete "permission == essentials.fly"
删除所有 "essentials.fly" 的权限
/lp bulkupdate all update server global "server == factions"
更改所有服务器 "factions" 条目为 "global"。
希望你理解了这个意思,如果你不确定如何构建一个你想要应用的命令,请随意使用 Wiki 主界面的联系方式联系我。
即时更新权限变更
介绍
如果你在群组服务器上运行LuckPerms的话,有时你会遇到这样的问题——你在一个服务器上做下了更改,但是这更改不会“传播”到你网络中的其他服务器中。
这一页就是教你怎么修复这个问题的。
当然,如果你只有一个服务器运行LuckPerms插件,或是你的服务器不使用普通的储存方法(连接到一个相同的数据库)的话,你不需要看这些。
同步间隔
你能够设置同步间隔,这会执行能够不断重复获得存储系统内的数据的任务。
本选项默认的值是 -1 (也就是说默认是禁用的)
data: ... #此选项控制 LuckPerms 多长时间进行一次同步任务。 #同步任务将会刷新存储中的所有信息,保证插件使用的是最新的数据。 #这个选项默认关闭,因为大多数的用户都是不需要这个功能的,但是如果你使用远程存储,又没有设置信息服务,那么你可能将其设置为像 3 这样的数值。 #设置为 -1 来完全停用这个任务。 sync-minutes: -1
你能够将这个值改成你想要的。
监视文件
如果你使用以文件为基础的存储类型的话(JSON或YAML),LuckPerms能够监视那些数据文件的更改,然后自动检测是否做出了改变。
#当使用基于文件的存储系统,LuckPerms将会监视数据文件的变化,并在文件变化被检测到的时候自动规划更新数据、 #如果不想让这个发生,那么将此选项设置为 false。 watch-files: true
这也就是说你只要更改一个数据文件就好了,然后按下保存按钮,然后你的更改就会被应用到整个群组服中了。
/lp sync
/lp sync
命令能够强制让插件执行一次上述提到的更新任务。
能够从数据库或文件读取最新的数据信息。
这个命令对于使用文件储存来说也是很有用的,因为它能够请求更新。
信息传递服务
在更改设定之后,你可以使用 /lp networksync
命令来让群组服中所有其他服务器应用更改。
当前支持
服务 | 描述 |
---|---|
Bungee | 使用插件所提供的信息传递隧道来在你的BungeeCord网络中传递更改 |
Lilypad | 使用 LilyPad 的连接子服系统来在你的LilyPad网络中传递更改 |
Redis | 使用 Redis Pub Sub 来在所有连接的服务器中传递更改 |
Bungee
messaging-service: bungee
你必须在你的代理服务器上安装LuckPerms插件,然后将上述的设置在所有配置文件中都启用。本选项不支持跨BungeeCord代理服务器传递信息,在这种情况下你应该使用Redis群组服。
LilyPad
messaging-service: lilypad
你需要在你的服务器上安装 LilyPad-Connect
插件。
Redis
messaging-service: redis # Settings for Redis. # Port 6379 is used by default; set address to "host:port" if differs redis: enabled: true address: localhost password: ''
你需要按照你服务器的实际情况来设置你的Redis群组服相关设置,然后在redis小节填写你的服务器的地址和密码。
请确保你的防火墙设置设置地恰当,来防止你的Redis群组服拒绝访问。
切换存储 & 备份
如何做
切换存储是很简单的。
- 第一,运行
/luckperms export <file>
- 接着,完全停止你的服务器
- 编辑你的配置文件,更改存储类型
- 开启你的服务器,等待数据存储的初始化
- 接着,使用
/luckperms import <file>
- 所有的数据已经迁移到新的数据存储中了
<file> 是你想用来存储/加载的文件的名称,文件位于 LuckPerms 的数据文件夹里。你可以任意命名,只要在 import 命令中正确填写。
备份
你可以使用这个特性来备份所有你的 LuckPerms 的数据,只需要运行 export 命令,将文件保存到一个安全的地方。
这是怎么工作的?
export 命令将所有的数据转换为一串命令,处理后将会重建你的安装,import 命令只是将每个命令运行一遍,这意味着你可以只导出/导入一小部分数据,你删掉不需要的一部分就可以了。
权限组路线
虽然其他一些插件也提供了一些相似的功能,LuckPerms 插件拥有它自己独特的权限组路线系统。
请将“权限组路线”试做一种“梯子”或“晋升路线”。
示例 1
我创建了一个叫做“staff”的权限组路线,这权限树包括以下组:
default :arrow_right: helper :arrow_right: mod :arrow_right: admin
然后我就能使用权限组路线来为玩家升级或降级。
例如,玩家“Notch”在helper权限组里,我想将他升到“mod”组,我需要运行
/luckperms user Notch promote staff
示例 2
我又为赞助商新建了一个权限组路线,包括以下组:
default :arrow_right: iron :arrow_right: gold :arrow_right: diamond
当玩家购买了“权限组提升”这类的东西时,我能使用权限组路线为玩家晋升权限等级。
/luckperms user Luck promote donator
要想让玩家在某条权限组路线中降级的话,请使用降级命令。
创建权限组路线
请运行 /luckperms createtrack <name>
命令,然后使用 /luckperms track <name> append <group>
来将权限组加入路线中。
帮助编辑路线的命令也还有几条,你可以在命令使用页面找到。
前缀,后缀与元数据
这教程包括如何使用LuckPerms插件设置和管理玩家的前缀,后缀以及元数据。
如果你已经对这些概念很熟悉了,或是只想查看本插件如何实现更改,你应该阅读命令使用 页面的 “section” 小节。
关键术语
前缀/后缀
Minecraft服务器上的前缀和后缀代指你聊天用户名前后的文本。
举个例子,在下列的聊天中:
[Admin] Luck the great: Hello!
玩家的前缀是"[Admin] "
部分,玩家的后缀是" the great"
部分。
元数据
有时元数据指“选项”或“变量”,元数据是跟权限组有关的额外数据部分。与权限不同的是,元数据分成两部分,一部分是“关键字”,另一部分是“值”。
关键字就是元数据的名字,值就是关键字所代表的数据。
举个例子,我的用户有下列的元数据,这元数据代表我最多能设置5个家,然后我的用户名应该是蓝色的。
max-homes = 5 username-color: blue
是谁提供了对这些的支持?
一般来说,提供服务器管理权限的插件就有能够让你设置,管理和储存玩家的前缀,后缀和元数据的功能,这对于LuckPerms插件来说也一样。、
有时,提供这些设置的权限插件也能够直接在游戏中应用这些值。但是这对于LuckPerms来说不是它能做到的任务,你需要安装另一款额外的插件来在游戏聊天中应用,关于这点我们稍后详述。
前缀/后缀/元数据是怎么存储的
LuckPerms 插件将前缀和后缀转换成权限节点来存储。你可能会注意到当你给一位用户或一个权限组添加权限的恶化,他们的权限信息中会多出一条跟你设置的值相同的权限数据。为什么要这样做呢?好的,从编程的角度来说,让所有东西都储存在一个地方,用相同的格式,这样做更简单。这也意味着你能够简单的更改前缀和后缀,就像你改权限的方式一样。
前缀和后缀分成了两部分 * Weight —— 这是决定着前缀和后缀优先级的数值,较大的数代表着较大的优先级。 * Value —— 这是真正的前缀的值。
例如一个叫做 "[Admin] " 的前缀,优先级设置为100,转换成权限就是: "prefix.100.[Admin] "
。
对于元数据来说所使用的系统也相似,元数据组合 favourite-color = red
,转换成权限就是:"meta.favourite-color.red"
.
前缀和后缀的优先级是怎么工作的
前缀和后缀和权限一样,也能够继承。这意味着LuckPerms插件需要决定,当需要显示前缀或后缀时,真正为玩家显示哪一个。
当另外一款插件请求玩家的前缀或后缀时,LuckPerms插件会: * 收集玩家的所有前缀与后缀,包括继承的 * 根据他们的优先级来进行分类,高的优先级数值代表高的优先级 * 然后决定出最高优先级的前缀或后缀来为玩家展示
如果发现了两个相同优先级的前缀或后缀的话,最接近于用户的那一个会被使用,接近的意思就是插件在搜索继承数据时最先找到的那一个。
我怎么为玩家设置前缀或后缀
举个例子,如果我想让admin权限组的玩家拥有 "&c[Admin] " 前缀,在mod权限组的玩家拥有 "&d[Mod] " 前缀的话,我需要运行:
- /lp creategroup admin
- /lp creategroup mod
- /lp group admin parent add mod
- /lp group admin meta addprefix 100 "&c[Admin] "
- /lp group mod meta addprefix 90 "&d[Mod] "
然后如果我决定想要将admin用户组的称号改为使用 "&4" 这个颜色代码的话,要想删除之前设定的值,我需要运行: * /lp group admin meta removeprefix 100
这会将所有设定给admin权限组的,优先级为100的前缀全部移除,然后我就能重新设置新的前缀值了。
对于临时设定用户前缀或后缀的方法和增加临时权限或临时权限组的方法差不多。
所有的权限使用方法可以在权限使用页面找到。增加和移除元数据的方法也列在了那里。
我怎么查看一位玩家或一个用户组所有的前缀或后缀
解决前缀或后缀相关问题最简单的方式就是使用info命令。
举个例子: /lp user Luck meta info
。这会将用户所有的前缀,后缀和元数据,以及继承的相关信息列举出来。
按照优先级来排序,所以你就能很清楚的看到目前应用的值是哪一个。
另外一条有趣的命令就是玩家的全局信息命令: /lp user Luck info
。
如果玩家在服务器上在线的话,这会直接给你展示所提供给要读取LuckPerms信息的插件的前缀或后缀。
展示前缀和后缀
就像早些时候提到的那样,LuckPerms插件不会为你处理任何的聊天格式相关信息。
你需要安装额外的插件来做到这个。
下面为你列出了一些推荐的聊天管理插件。
Bukkit/Spigot
LuckPerms 目前已经支持所有能够从 Vault 插件读取信息的聊天管理插件了。
你需要在你的服务器上安装Vault来让其工作。
如果你发现某款插件所获取的数据不正确的话,请确保 /vault-info
插件输出的信息展示的数据是从LuckPerms插件处读取的。
一些较为受欢迎的,且支持Vault的聊天管理插件包括: * EssentialsXChat —— 原来的Essentials插件的升级复刻版本。(“X” 是很重要的!) * ChatEx * DeluxeChat —— 你能够使用Vault或LuckPerms所提供的Placeholder变量。 * ChatControl —— 也支持其他选项的设置来帮助管理聊天。
列举出所有可用的插件没有任何意义,再说一遍,所有支持Vault的聊天管理插件都支持LuckPerms!
BungeeCord =
- gChat (我写的 :wink:)
- MultiChat
- BungeeChat
Sponge
前缀与后缀的堆叠
这个功能能做什么?
“元数据堆叠”特性能够让你在玩家聊天中同时展示多个前缀或后缀。
你仍需要安装聊天管理类型的插件。
它怎么工作?
当聊天管理类插件请求要获取玩家的前缀或后缀时,取代返回玩家最高优先级的称号,LuckPerms能够应用一些你设定的规则来一起输出多个前缀或后缀。
默认的设置看起来是这样:
meta-formatting: prefix: format: - "highest" start-spacer: "" middle-spacer: " " end-spacer: "" suffix: format: - "highest" start-spacer: "" middle-spacer: " " end-spacer: ""
这些当前配置意味着,当请求前缀或后缀的时候,会返回最高优先级的那一个。
我怎么增加其他元素?
当前支持以下元素。
元素 | 描述 |
---|---|
highest
|
从玩家拥有或继承的数据中选择最高优先级的值 |
lowest
|
和上面的工作原理相同,但是它会选择最低优先级的值 |
highest_own
|
选择最高优先级的值,但不支持继承来的值 |
lowest_own
|
和上面的工作原理相同,但是它会选择最低优先级的值 |
highest_on_track_<track>
|
选择继承于给予的权限组路线中的权限组所提供的最高优先级的值 |
lowest_on_track_<track>
|
和上面的工作原理相同,但是它会选择最低优先级的值 |
highest_not_on_track_<track>
|
选择不继承于给予的权限组路线中的权限组所提供的最高优先级的值 |
lowest_not_on_track_<track>
|
和上面的工作原理相同,但是它会选择最低优先级的值 |
一个示例
例如,在一个监狱服务器中,你可能有3种类型的权限组,一种是玩家“gameplay”权限组,一种是赞助商权限组,一种是管理员权限组。
如果玩家在三个组中,我想要展示三个前缀,举个例子: [Mine C] [Donor] [Admin] Luck: hi!
.
但是如果玩家不在管理员权限组中,我想展示: [Mine C] [Donor] Luck: hi
.
使用堆叠系统这些都可以实现。每个堆叠中的“元素”都需要添加到格式节内。
prefix: format: - "highest_on_track_prison" - "highest_on_track_donor" - "highest_on_track_staff" start-spacer: "" middle-spacer: " " end-spacer: ""
如果玩家在该元素中没有对应的值的话,它就会被堆叠系统自动无视。
你可以控制每个元素在开头,中间和结尾的分隔符,举个例子:
yml prefix: format: - "highest_on_track_prison" - "highest_on_track_donor" - "highest_on_track_staff" start-spacer: "★ " middle-spacer: " | " end-spacer: " "
... 这样的聊天结果会是: ★ [Mine C] | [Donor] | [Admin] Luck: hi
.
显然你可以使用你的聊天管理插件来改变这些值,那些插件也会提供相似的选项。
高级设置
简介
LuckPerm总体来说虽然是相对简单的.. 你可以利用插件的一些特点与内部规则来制定一个适合你服务器情况的高等权限系统!
分服务器权限&分世界权限
LuckPerm本来是针对群组服的情况来工作的, 但是你可以自定义一些只在特定子服/特定世界才生效的权限。
= 配置中一些重要的选项说明
# The name of the server, used for server specific permissions. Set to 'global' to disable. server: global
该项为设置服务器的名称,如果要想设置特定服务器的权限,则需要通过修改server项来命名服务器。 如果你愿意,同一个群组服是可以一起使用相同的服务器名的。
# If users on this server should have their global permissions/groups applied. include-global: true
include-global选项也是非常重要的。
LuckPerm有两种体现方式,一是特定服务器的权限,二则是直接应用全局权限设置。
如果这个选项被设置为 false,只有指定在此服务器的权限才会被应用。
如果上方的 "server" 选项设置为 global,请不要将其设置为 false。更多的有关服务器指定的权限可以在这里找到。 通过编辑更改这两个选项,你可以灵活的为每个服务器的权限组/权限做出意想不到的配合效果
示例
示例 1
server: global include-global: true
- /luckperms user Luck set minecraft.command.gamemode true 将应用
- /luckperms user Luck set minecraft.command.gamemode true factions 不应用
示例 2
server: lobby include-global: true
- /luckperms user Luck set minecraft.command.gamemode true 将应用
- /luckperms user Luck set minecraft.command.gamemode true lobby 将应用
示例 3
server: bungeecord include-global: false
- /luckperms user Luck set minecraft.command.gamemode true 不应用
- /luckperms user Luck set bungeecord.command.alert true bungeecord 将应用
示例 4
server: global include-global: false
没有任何权限将会应用!
如果没有设置服务器名字(server项设置为global)且全局设置未开启(include-global项设置为flase), 将不会有任何权限可以应用到服务器上!
权限计算
权限是根据优先级进行计算的,如下所示
- 服务器特定的权限是会覆盖通用/全局权限设置的
例如:有一个玩家,我们姑且叫他海螺,他拥有一个全局的“fly.use”(允许飞行)权限, 然后在“factions”这个服务器上,取消了“fly.use”权限,服务器的特定权限设置将会覆盖全局设置。 即,这个海螺在“factions”服务器上是无法使用“fly.use”权限的,他就不能够上天了, 前提是海螺现在正在“factions”服务器上。
- 世界特定的权限也是会覆盖通用/全局权限设置的
例如:上文我们说的玩家“海螺”,他现在任然有一个全局的“fly.use”权限, 然后在“world_nether”(地狱)世界,取消了“fly.use”权限,世界的特定权限设置将会覆盖全局设置。 即,这个海螺在地狱就无法上天了(只要海螺在地狱世界)。
- 临时权限将会覆盖非临时权限
例如:如果玩家海螺本来关闭了一个权限“test.node”, 以此为基础,服务器给海螺设置新的临时权限“test.node”, 海螺的临时权限则会覆盖本身关闭的权限,即海螺会在特定时间(临时权限)获得“test.node”权限。
- 如果同时有两个节点相同、但时长不同的临时权限,时间较长的会覆盖时间较短的
- 更加具体的通配符权限将覆盖不具体的通配符权限
例如:一个用户拥有权限“luckperms.”并且设置为true,但是“luckperms.user.”权限却设置为false, 那么所有玩家的权限都将被设置为false! 因为尽管“luckperm.”有更加通用的通配符,但是他没有“luckperms.user.”具体。
- 继承权限将由对象自己的权限来重写
例如:一个玩家是默认权限组的成员,默认权限组有“some.thing.perm”权限, 但是这个玩家又被以用户形式给予了权限“some.thing.perm”, 继承而来的权限将会被玩家自己的权限给覆盖。
临时权限
临时权限每间隔3s会检查一遍,检查临时权限的时限是否到期, 不论同步间隔设置的怎么样,这个检查都会照常工作,这意味着你可以安全的设置临时权限在几秒后过期, 他们将会在时限到期时被删除。
速记权限
LuckPerms有他自己的速记权限系统,在这一点上,它非常类似PermissionsEx, 它允许你使用速记格式来设置权限。
示例
示例 1
使用LuckPerm的允许节点来作为例子,比如说,你想让一个用户组与用户权限设置/取消允许节点,
如果没有速记,你就必须键入下面四个节点。
luckperms.user.setpermission luckperms.user.unsetpermission luckperms.group.setpermission luckperms.group.unsetpermission
但是,你要是使用速记,你就可以应用以下节点:
luckperms.(user|group).(setpermission|unsetpermission)
你可以使用括号来让一个节点成为一个速记的权限组,然后用 |
来分隔他们
示例 2
你可以使用“-”来创建字符范围,如果没有使用速记,则必须键入以下四个节点:
coolkits.kit.a coolkits.kit.b coolkits.kit.c coolkits.kit.d
然而,使用了速记方法,你只需应用下面的节点:
coolkits.kit.(a-d)
示例 3
你可以使用“-”来创建字符范围,如果没有使用速记,则必须键入以下四个节点:
prisonmines.teleport.1 prisonmines.teleport.2 prisonmines.teleport.3 prisonmines.teleport.4
不过,你只要使用速记方法,这一切都会变得简单许多!你只需要应用下面的节点:
prisonmines.teleport.(1-4)
正则表达式
LuckPerms支持使用正则表达式来定义权限节点与服务器/世界的名字, 当使用正则表达式的时候,必须添加前缀“R=”。 所以LuckPerm才会知道将它是作为正则表达式来输出,而不是作为普通的字符串来输出。
例如:你希望玩家可以创建两个组与权限系(tracks),通常只需要添加两个权限节点。 然而使用正则表达式,你只需要添加一个权限节点 luckperms\.create.*
。 记住,转为任何字符,例如一个点,都将作为一个节点被系统解析。
默认组
我在 LuckPerms 里处理默认和默认组的方法可能是整个插件里最不受喜爱的特性了。最新我做了一些添加/调整,做了一些替代的特性,允许最大程度的控制像其他权限插件的方法,希望这会成为插件最好的方面,而不是最差的方面。
从何开始
这是我的想法。
你的服务器的用户可以分为两种。
- 基础玩家
- 加入不同的组的玩家,或者有他们特别权限的玩家。
你不希望浪费宝贵的硬盘空间来存储第一种玩家,你只希望存储你的职员,或者有特殊等级的玩家。平凡的"成员"就只是平凡,没有必要存储他们的信息。
下一个问题是如何确定一个用户是"平凡的"或不是,想象一下情景。
- 默认的组设置为"默认",当玩家加入,他们被设置为"默认",并被保存。
- 过了一会儿,你想将默认的组更改为"成员"。
- 接着你的老的成员全部在"默认"组里,剩下的人都在"成员",这不好。
甚至我们没有"平凡"的用户,这个问题依然会出现。
- 默认组设置为"默认"
- 你想给 "Notch" 一个特殊的 "essentials.fly" 权限,Notch 的权限被保存,标记为"默认组"的成员,有特殊的飞行权限。
- 接着你编辑了默认的组,所有的"平凡的"成员全部进入了新的组,但是 Notch 还是默认组的。
因为这个原因,我让默认的组不可配置,这让所有对我的事情都简单了 10 倍,这意味着我可以写有效率的存储系统,并且不用担心一些稀有的情况下服务器的管理员更改了默认组,但是,我知道这对一些人很反感。
这对一些等级插件也有问题,如果你想要一个"主"组,并且分离"升级"组,你需要多于一个的默认组。
这里是你的选项。
继续使用默认组,但是只是更改显示名
我非常推荐这个做法,因为你继续使用默认组。
如果你只是想简单的更改默认组的显示名,(比如在 Vault),我推荐你配置一个 group-name-rewrite
规则,通过添加这些到你的 config.yml
/luckperms.conf
来实现。
# Rewrites group names. The underlying name of the group does not change, just the output in commands / placeholders / Vault. group-name-rewrite: default: Member
你也可以使用这个:https://github.com/lucko/LuckPerms/wiki/Primary-Groups
配置继承
这个选项意味着所有的用户都还在"默认"的组里,但是这个默认组作为父组,这样他就可以将配置继承给不同的组。
/luckperms creategroup member /luckperms group default parents add member
配置默认分配
如果你有更多的特殊需要,你可以使用这个选项,但是,这将否定我们在这个页面的第一节讨论的存储空间规划,所有的用户都会被存储,无论是"平凡的"成员还是不是。
注意:查看 Default Assignments 章节
接下来的规则将会创建一个不同的默认的组。
default-assignments: my-defaults-rule: if: has-true: <group.default> take: - group.default give: - group.member set-primary-group: member
放入以后,每次玩家登入时,插件会检测这个玩家是不是"默认"组的成员,如果是,插件将会把玩家从"默认"组移除,将他们添加至"成员"组,将他们的主组也设置为"成员"组。
这个系统非常强力,允许你配置按你自己的需求而定的默认组,记住你可以将玩家添加至不止一个的"默认"组。
开发者
开发者 API
简介
LuckPerms API 允许你更改大量的插件内部编程,并且能够轻松地将 LuckPerms 深度集成到你的插件和系统里。
大多数的其他的权限要么没有 API,要么有很差的 API,或者是有很差的文档的 API,而且里面的方法和类可能随机在不同版本里消失或是移动。Vault 项目就是一个很好的接口,并且是将大量插件一次性集成的很好的方法,可惜他的功能实在是太少了。
LuckPerms 遵循 Semantic 版本控制,也就是意味着一个不向后兼容的新的 API 出现时,主版本会增加这个 API,你可以放心你的集成不会因为版本的不同而崩溃,主要的版本是保持不变的。
如何在项目里使用 API
LuckPerms 的 API 包是 me.lucko.luckperms.api
我的 Nexus 服务器可以在这里找到 https://nexus.lucko.me/,你在你的构建脚本里需要的仓库在 https://repo.lucko.me/
其他有用的链接
Maven
<repositories>
<repository>
<id>luck-repo</id>
<url>https://repo.lucko.me/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>me.lucko.luckperms</groupId>
<artifactId>luckperms-api</artifactId>
<version>3.2</version>
<scope>provided</scope>
</dependency>
</dependencies>
Gradle
repositories { maven { name "luck-repo" url "https://repo.lucko.me/" } } dependencies { compile ("me.lucko.luckperms:luckperms-api:3.2") }
使用指南
使用 API,你需要获得 LuckPermsApi 接口的实例,这可以通过几个方法完成。
// 所有平台 (抛出 IllegalStateException 如果 API 没有被加载)
final LuckPermsApi api = LuckPerms.getApi();
// 或者可选的
Optional<LuckPermsApi> provider = LuckPerms.getApiSafe();
if (provider.isPresent()) {
final LuckPermsApi api = provider.get();
}
// Bukkit/Spigot
ServicesManager manager = Bukkit.getServicesManager();
if (manager.isProvidedFor(LuckPermsApi.class)) {
final LuckPermsApi api = manager.getRegistration(LuckPermsApi.class).getProvider();
}
// Sponge
Optional<LuckPermsApi> provider = Sponge.getServiceManager().provide(LuckPermsApi.class);
if (provider.isPresent()) {
final LuckPermsApi api = provider.get();
}
线程安全的警告
所有 LuckPerms 内部,包括 API 都是线程安全的,你可以在异步线程任意调用 API 而不用担心发生错误。
但是,请注意一些操作,(尤其是存储类)是阻塞的。CompletableFuture 就是用于这种情况:防止由于较差的处理导致的增加的错误,当出现 IO 时主线程等待处理完成。注意在添加 Callback 时指定正确的处理器。
我想将 LuckPerms 作为依赖项
在 Bukkit/Bungee,你需要在你的 plugin.yml 添加以下信息
depend: [LuckPerms]
在 Sponge, 在你的插件声明添加这些。
@Plugin(
id = "myplugin",
dependencies = {
@Dependency(id = "luckperms")
}
)
public class MyPlugin {
...
}
事件
LuckPerms 有一个完整的读写API,也有一个事件监听系统。由于插件的多平台的原因,我们使用了内部的事件系统,而不是每个平台已经使用的事件系统(举个例子,Bukkit Event API)。这意味着简单的注册你的平台的监听器将不会生效。
所有的事件都是异步触发的。这意味着不应该在监听器里交互或者调用任何不是线程安全的方法。
值得注意的是,大多数的 Bukkit/Sponge 都不是线程安全的,并且只应该使用主服务器线程来交互。你应该使用调度器来访问 LuckPerms 的监听器。
我怎样才能监听一个事件
所有的事件接口都可以在 me.lucko.luckperms.api.event 包里找到,它们都继承了 LuckPermsEvent 类。
监听事件应该获得 EventBus 实例,使用 LuckPermsApi#getEventBus即可。
为你的监听器创建另一个类常常是个好想法,这是一个你可以用来参考的类。
package me.lucko.test;
import me.lucko.luckperms.api.event.EventBus;
import me.lucko.luckperms.api.event.log.LogPublishEvent;
import me.lucko.luckperms.api.event.user.UserLoadEvent;
import me.lucko.luckperms.api.event.user.track.UserPromoteEvent;
public class TestListener {
private final MyPlugin plugin;
public TestListener(MyPlugin plugin, LuckPermsApi api) {
this.plugin = plugin;
EventBus eventBus = api.getEventBus();
// use a lambda
eventBus.subscribe(LogPublishEvent.class, e -> e.getCancellationState().set(true));
eventBus.subscribe(UserLoadEvent.class, e -> {
System.out.println("User " + e.getUser().getName() + " was loaded!");
if (e.getUser().hasPermission("some.perm", true)) {
// Do something
}
});
// use a method reference
eventBus.subscribe(UserPromoteEvent.class, this::onUserPromote);
}
private void onUserPromote(UserPromoteEvent event) {
Bukkit.getScheduler().runTask(plugin, () -> {
Bukkit.broadcastMessage(event.getUser().getName() + " was promoted to" + event.getGroupTo().get() + "!");
Player player = Bukkit.getPlayer(event.getUser().getUuid());
if (player != null) {
player.sendMessage("Congrats!");
}
});
}
}
EventBus#subscribe 返回一个 EventHander 实例,可以用来在插件停止的时候取消注册监听器。
示例用法
下面就是一些简短的实例,使用了一些基本的 API 功能。
获得玩家的组
如果你只是想找到一个玩家的组,我非常建议你使用以下的方法(你甚至不需要使用 API)。
public static String getPlayerGroup(Player player, List<String> possibleGroups) {
for (String group : possibleGroups) {
if (player.hasPermission("group." + group)) {
return group;
}
}
return null;
}
记住将你的组排列为优先级的顺序(比如组长在前,成员在后)。
为一个玩家添加权限
LuckPermsApi api = null; // See above for how to get the API instance.
Optional<User> user = api.getUserSafe(uuid);
if (!user.isPresent()) {
return false; // The user isn't loaded in memory.
}
// Build the permission node we want to set
Node node = api.getNodeFactory().newBuilder(permission).setValue(true).build();
// Set the permission, and return true if the user didn't already have it set.
try {
user.get().setPermission(node);
// Now we need to save the user back to the storage
api.getStorage().saveUser(u);
return true;
} catch (ObjectAlreadyHasException e) {
return false;
}
为(可能的)离线玩家添加权限
CompletionStage API 可以用来轻松交互插件的存储,查看这里 和 这里 来查看这两个类的详细信息。
LuckPermsApi api = null; // See above for how to get the API instance.
// load the user in from storage. we can specify "null" for their username,
// since it's unknown to us.
api.getStorage().loadUser(uuid, "null").thenComposeAsync(success -> {
// loading the user failed, return straight away
if (!success) {
return CompletableFuture.completedFuture(false);
}
// get the user instance, they're now loaded in memory.
User user = api.getUser(uuid);
// Build the permission node we want to set
Node node = api.getNodeFactory().newBuilder(permission).setValue(true).build();
// Set the permission, and return true if the user didn't already have it set.
try {
user.setPermission(node);
// now we've set the permission, but still need to save the user data
// back to the storage.
// first save the user
return api.getStorage().saveUser(user)
.thenCompose(b -> {
// then cleanup their user instance so we don't create
// a memory leak.
api.cleanupUser(user);
return CompletableFuture.completedFuture(b);
});
} catch (ObjectAlreadyHasException e) {
return CompletableFuture.completedFuture(false);
}
}, api.getStorage().getAsyncExecutor());
获得玩家的前缀
LuckPerms 有一个(复杂的)缓存系统,用于非常快速的权限/信息查询。这些类都在 API 里,并且可以在可能的地方使用。
LuckPermsApi api = null; // See above for how to get the API instance.
// Get the user, or null if they're not loaded.
User user = api.getUserSafe(uuid).orElse(null);
if (user == null) {
return Optional.empty(); // The user isn't loaded. :(
}
// Now get the users "Contexts". This is basically just data about the players current state.
// Don't worry about it too much, just know we need it to get their cached data.
Contexts contexts = api.getContextForUser(user).orElse(null);
if (contexts == null) {
return Optional.empty();
}
// Ah, now we're making progress. We can use the Contexts to get the users "MetaData". This is their cached meta data.
MetaData metaData = user.getCachedData().getMetaData(contexts);
// MetaData#getPrefix returns null if they have no prefix.
return metaData.getPrefix();
获得玩家请求的权限
我们也可以使用这个缓存系统来获得一个包含用户权限的 Map 实例,包含了基础的权限查询。
// All retrieved in the same way as shown above.
User user;
Contexts contexts;
PermissionData permissionData = user.getCachedData().getPermissionData(contexts);
Map<String, Boolean> data = permissionData.getImmutableBacking();
寻找权限
你可以使用 Java 8 的流轻松过滤并返回一个用户请求的权限
public boolean hasPermissionStartingWith(UUID uuid, String startingWith) {
// Get the user, if they're online.
Optional<User> user = api.getUserSafe(uuid);
// If they're online, perform the check, otherwise, return false.
return user.map(u -> u.getPermissions().stream()
.filter(Node::getValue)
.filter(Node::isPermanent)
.filter(n -> !n.isServerSpecific())
.filter(n -> !n.isWorldSpecific())
.anyMatch(n -> n.getPermission().startsWith(startingWith))
).orElse(false);
}
创建新的组并分配权限
这个方法不是阻塞的,所以可以安全的在主线程调用,一旦操作完成,回调会异步运行。
api.getStorage().createAndLoadGroup("my-new-group").thenAcceptAsync(success -> {
if (!success) {
return;
}
Group group = api.getGroup("my-new-group");
if (group == null) {
return;
}
Node permission = api.buildNode("test.permission").build();
try {
group.setPermission(permission);
} catch (ObjectAlreadyHasException ignored) {}
// Now save the group back to storage
api.getStorage().saveGroup(group);
}, api.getStorage().getAsyncExecutor());
版本控制
在 2.0 版本里,LuckPerms 遵循了 Semantic 版本控制。
唯一不同的是 patch 号不包含在任何地方,除了 pom,并且每次构建都会计算,基于上次提交后的提交数量。(每个新的小版本都会创建新的标签)
这意味着 API 版本不再有 patch 号(在 patch 里没有 API 的变化),API 版本会是 x.y,每个不同的 LuckPerms 构建都会遵循 x.y.z。
变更日志
- 版本 2.x 保持了几个月的稳定,没有任何向后不兼容的变更,但是在之后的版本里很多的方法变为弃用状态,并且事件 API 的确应该重写一遍。
- 版本 3.x 包含了以下的向后不兼容的变化。 https://gist.github.com/PluginsCDTribe/fdf6ae4b2d9e466d8103dd9c68e5db9e
其他
语言文件
LuckPerms 插件中所有的消息(包括颜色和格式代码)都能够修改。(似乎合情合理)
将下面的文件之一下载然后存储到LuckPerms的文件夹中,然后命名为 "lang.yml"。
将文件中的消息文本改成你喜欢的样子,然后重启你的服务器就好了。
语言文件
为翻译做贡献
如果你翻译了语言文件,然后提交回工程的话,我(和其他使用本插件的人)会很高兴的,因为其他使用者会受益。
上面的 "en_US" 语言文件应作为翻译的标准,你只能修改文本消息的值,关键字应保留原样。
附:简体中文语言文件
# LuckPerms Language File # Locale: zh-CN (Simplified Chinese) # Author: EuropeJing prefix: "&7&l[&b&lL&3&lP&7&l] &c" log-info: "&7&l[&bL&3P&7&l] &3{0}" log-warn: "&7&l[&bLuck&3Perms&7&l] &c[警告] {0}" log-error: "&7&l[&bLuck&3Perms&7&l] &4[错误] {0}" empty: "{0}" player-online: "&a在线" player-offline: "&c离线" loading-error: "无法加载权限数据,请稍后再试." op-disabled: "&b此服务器上禁用了vanilla OP系统." op-disabled-sponge: "&2服务器管理员状态在安装权限插件时无效,请直接编辑用户数据." log: "&3日志 &3&l> {0}" export-log: "&3输出 &3&l> &f{0}" export-log-progress: "&3输出 &3&l> &7{0}" migration-log: "&3移动 &7[&3{0}&7] &3&l> &f{1}" migration-log-progress: "&3移动 &7[&3{0}&7] &3&l> &7{1}" command-not-recognised: "命令未被识别." command-no-permission: "你没有权限使用这个命令!" already-haspermission: "{0}已经有这个权限!" does-not-havepermission: "{0}没有这个命令的权限." already-has-temp-permission: "{0}已经设置此临时权限!" does-not-have-temp-permission: "{0}没有设置此临时权限." user-not-found: "&b找不到用户." user-not-online: "&b用户&a{0}&b不在线." user-no-data: "&b没有加载用户&a{0}&b任何数据." user-save-success: "&7(保存用户数据到文件)" user-save-error: "保存用户数据时出错." user-create-fail: "创建新用户时出错." group-not-found: "&b找不到组." group-save-success: "&7(保存组数据到文件)" group-save-error: "保存组数据时出错." track-not-found: "&b无法找到轨道." track-save-success: "&7(保存轨道到文件)" track-save-error: "保存轨道时出错." user-invalid-entry: "&d{0}&c不是有效的用户名/uuid." group-invalid-entry: "组名只能包含字母数字字符." track-invalid-entry: "轨道名称只能包含字母数字字符." server-invalid-entry: "服务器名称只能包含字母数字字符." use-inherit-command: "使用'parent add'和'parent remove'命令,而不是指定节点." verbose-invalid-filter: "&c无效的详细过滤器: &f{0}" verbose-on: "&b所有权限的详细输出设置为&a开&b." verbose-on-query: "&b将匹配过滤器:&f{0}&b的权限详细输出设置为&a开&b." verbose-off: "&b所有权限的详细输出设置为&c关&b." verbose-recording-on: "&b所有权限的详细记录设置为&a开&b." verbose-recording-on-query: "&b将匹配过滤器:&f{0}&b的权限详细记录设置为&a开&b." verbose-recording-upload-start: "&b详细记录被禁用. 正在上传结果..." verbose-recording-url: "&a详细结果的网址:" tree-upload-start: "&b生成权限树..." tree-empty: "&a无法生成树,没有找到结果." tree-url: "&a权限树网址:" search-searching: "&a使用&b{0}&a搜索用户和组..." search-searching-members: "&a正在搜索继承自&b{0}&a的用户和组..." search-result: "&a从&b{1}&a用户和&b{2}&a组找到&b{0}&a个条目." search-showing-users: "&b显示用户条目:" search-showing-groups: "&b显示组条目:" search-showing-users-with-page: "&b显示用户条目: {0}" search-showing-groups-with-page: "&b显示组条目: {0}" check-result: "&a用户&b{0}&a获得允许&b{1}&a权限的检查结果&a: &f{2}" create-success: "&b{0}&a成功创建." delete-success: "&b{0}&a成功删除." rename-success: "&b{0}&a成功被重命名为&b{1}&a." clone-success: "&b{0}&a被成功地复制到了&b{1}&a." already-inherits: "{0}已经继承'{1}'." does-not-inherit: "{0}已不继承'{1}'." already-temp-inherits: "{0}已临时继承'{1}'." does-not-temp-inherit: "{0}不会临时继承'{1}'." track-already-contains: "轨道{0}已经包含组'{1}'." track-does-not-contain: "轨道{0}不包含组'{1}'." track-ambiguous-call: "指定的用户是此轨道上多个组的成员,无法确定他们的位置." group-already-exists: "该组已存在!" group-does-not-exist: "组不存在!" group-load-error: "发生意外错误,组未加载." groups-load-error: "发生意外错误,无法加载所有组." track-already-exists: "轨道已存在!" track-does-not-exist: "轨道不存在!" track-load-error: "发生意外错误. 轨道未加载." tracks-load-error: "出现意外错误,无法加载所有轨道." track-empty: "轨道不能使用,因为它是空的或只包含一个组." update-task-request: "&b更新任务计划." update-task-complete: "&a更新任务完成." update-task-complete-network: "&a更新任务完成,现在尝试推送到其他服务器." update-task-push-success: "&a其他服务器通过&b{0}成功通知." update-task-push-failure: "&c将更改推送到其他服务器时出错." update-task-push-failure-not-setup: "&c将更改推送到其他服务器时出错,未配置消息传递服务." reload-config-success: "&a重新加载配置文件. &7(一些选项将仅在服务器重新启动后才应用.)" info: > {PREFIX}&2运行 &bLuckPerms v{0}&2 by &bLuck&2.\n {PREFIX}&f- &3平台: &f{1}\n {PREFIX}&f- &3存储方式: &f{2}\n {PREFIX}&f- &3服务器名称: &f{3}\n {PREFIX}&f- &3同步间隔: &a{4} &f分钟\n {PREFIX}&f- &3消息服务: &f{5}\n {PREFIX}&f- &b统计:\n {PREFIX}&f- &3在线玩家: &a{6}\n {PREFIX}&f- &3加载用户: &a{7}\n {PREFIX}&f- &3加载组: &a{8}\n {PREFIX}&f- &3加载轨道: &a{9}\n {PREFIX}&f- &3日志大小: &a{10}\n {PREFIX}&f- &3UUID缓存大小: &a{11}\n {PREFIX}&f- &3翻译加载: &a{12}\n {PREFIX}&f- &3预处理环境: &a{13}\n {PREFIX}&f- &3环境计算器: &a{14}\n {PREFIX}&f- &3唯一权限: &a{15}\n {PREFIX}&f- &b配置:\n {PREFIX}&f- &3使用服务器UUIDs: {16}\n {PREFIX}&f- &b权限计算:\n {PREFIX}&f- &3包括全部: {17}\n {PREFIX}&f- &3包括全部世界: {18}\n {PREFIX}&f- &3应用全部组: {19}\n {PREFIX}&f- &3应用全部世界组: {20}\n {PREFIX}&f- &3应用通配符: {21}\n {PREFIX}&f- &3应用正则表达式: {22}\n {PREFIX}&f- &3应用速记: {23} create-group-error: "创建组时出错." delete-group-error: "删除组时出错." delete-group-error-default: "您不能删除默认组." groups-list: "&aGroups: {0}" create-track-error: "创建轨道时出错." delete-track-error: "删除轨道时出错." tracks-list: "&a轨道: {0}" listnodes: "&b{0}的节点:" listnodes-with-page: "&b{0}的节点: {1}" listnodes-temp: > &b{0}的临时节点:\n {1} listparents: > &b{0}的父组:\n {1} listparents-temp: > &b{0}的临时父组:\n {1} listgroups: > &b{0}的组:\n {1} listgroups-temp: > &b{0}的临时组:\n {1} list-tracks: > &b{0}的轨道:\n {1} list-tracks-empty: "{0}不在任何轨道上." context-pair-inline: "&3{0}=&b{1}" context-pair--global-inline: "&e全局" context-pair-end: "&a." context-pair-sep: "&a, " context-pair: "&8(&7{0}=&f{1}&8)" check-permission: "&b在环境&b{3}&b中,&b{0}&b的权限&b{1}&b被设置为&b{2}&b." check-permission-inherited: "&b{0}&a在环境&b{3}&a中的&b{1}&a被设置为&b{2}&a,继承自&b{4}&a." setpermission-success: "&a在&b{3}&a中为&b{2}&a设置&b{0}&a为&b{1}&a." setpermission-temp-success: "&a在环境&b{4}&a将&b{0}&a的&b{2}&a设为&b{1}&a,持续时间&b{3}&a." unsetpermission-success: "&a在环境&b{2}&a中取消&b{1}&a的&b{0}&a." unset-temp-permission-success: "&a在环境&b{2}&a中取消设置&b{1}&a的临时许可&b{0}&a." set-inherit-success: "&b{0}&a现在在环境&b{2}&a中继承&b{1}&a的权限&a." set-temp-inherit-success: "&b{0}&a现在在环境&b{3}&a中继承&b{1}&a的权限,持续时间&b{2}&a." set-parent-success: "&b{0}&a现有的父组被清除,现在只在&b{2}&a中继承&b{1}&a." unset-inherit-success: "&b{0}&a不再继承环境&b{2}&a中的&b{1}&a权限." unset-temp-inherit-success: "&b{0}&a在环境{2}中不再临时从&b{1}&a继承权限." clear-success: "&b{0}&a的权限被清除. (&b{1}&a节点被删除.)" clear-success-singular: "&b{0}&a的权限被清除. (&b{1}&a节点已被删除.)" parent-clear-success: "&b{0}&a的组被清除. (&b{1}&a节点被删除.)" parent-clear-success-singular: "&b{0}&a的组被清除. (&b{1}&a节点已被删除.)" meta-clear-success: "&b{0}&a的父组被清除. (&b{1}&a节点被删除.)" meta-clear-success-singular: "已经清除了这个&b{0}&a的元数据. (&b{1}&a节点已被删除.)" illegal-date-error: "无法解析日期'{0}'." past-date-error: "您不能设定一个过去的日期!" chat-meta-prefix-header: "&b{0}的前缀" chat-meta-suffix-header: "&b{0}的后缀" meta-header: "&b{0}的元信息" chat-meta-entry: "&b-> {0} &f- &f\"{1}&f\" &8(&7继承自&a{2}&8)" chat-meta-entry-with-context: "&b-> {0} &f- &f\"{1}&f\" &8(&7继承自&a{2}&8){3}" meta-entry: "&b-> &a{0} &f= &f\"{1}&f\" &8(&7继承自&a{2}&8)" meta-entry-with-context: "&b-> &a{0} &f= &f\"{1}&f\" &8(&7继承自&a{2}&8){3}" chat-meta-prefix-none: "&b{0}没有前缀." chat-meta-suffix-none: "&b{0}没有后缀." meta-none: "&b{0}没有元信息." meta-invalid-priority: "优先级'{0}'无效. 应该是一个数字." already-has-chat-meta: "{0}已经设置了{1}." does-not-have-chat-meta: "{0}没有设置{1}." add-chatmeta-success: "&b{0}&a在环境&b{4}&a中将优先级&b{3}&a设置为 {1} &f\"{2}&f\"." add-temp-chatmeta-success: "&b{0}&a在环境&b{5}&a中,设置为优先级&b{3}&a的{1} &f\"{2}&f\"&a,持续时间为&b{4}&a." remove-chatmeta-success: "&b{0}&a在&b{3}&a中删除了优先级&b{3}&a的{1} &f\"{2}&f\"&a." bulk-remove-chatmeta-success: "&b{0}&a had all {1}es at priority &b{3}&a removed in context {4}&a." remove-temp-chatmeta-success: "&b{0}&a在环境&b{4}&a中删除了优先级&b{3}&a的临时{1} &f\"{2}&f\"&a." bulk-remove-temp-chatmeta-success: "&b{0}&a在环境&b{4}&a中移除了优先级&b{3}&a的所有临时&b{1}&a.." already-has-meta: "{0}已经有了这个元信息集." set-meta-success: "将环境&b{3}&a中的&b{2}&a的键&f\"{0}&f\"&a的元信息设置为&f\"{1}&f\"&a." set-meta-temp-success: "&a在环境&b{4}&a中将&b{2}&a的键&f\"{0}&f\"&a的值设置为&f\"{1}&f\"&a,持续时间为&b{3}&a." unset-meta-success: "&a在环境{2}中取消设置&b{1}&a的键&f\"{0}&f\"&a的元信息." unset-meta-temp-success: "&a在环境{2}中取消设置&b{1}&a的键&f\"{0}&f\"&a的临时元信息." bulk-update-invalid-data-type: "Invalid type. Was expecting 'all', 'users' or 'groups'." bulk-update-invalid-constraint: "无效的约束&4{0}&c.约束的格式应该是'&f<field> <comparison operator> <value>&c'." bulk-update-invalid-comparison: "比较运算符无效'&4{0}&c'. 应该以下之一: &f== != ~~ ~!" bulk-update-queued: "&a批量更新操作已排队.&7(&f{0}&7)" bulk-update-confirm: "&a运行&b/{0} bulkupdate &a确认{1}执行更新." bulk-update-unknown-id: "&a使用id&b{0}&a的操作不存在或已过期." bulk-update-starting: "&a运行批量更新." bulk-update-success: "&b量更新已成功完成." bulk-update-failure: "&cBulk update failed. Check the console for errors." bulk-change-type-error: "类型无效. 应该是 'server' 或 'world'." bulk-change-success: "&a应用批量更改成功. {0}记录已更改." user-info-general: > {PREFIX}&b&l> &bUser Info: &f{0}\n {PREFIX}&f- &3UUID: &f{1}\n {PREFIX}&f- &3状态: {2}\n {PREFIX}&f- &3主组: &f{3}\n {PREFIX}&f- &a统计:\n {PREFIX}&f- &3权限: &a{4}\n {PREFIX}&f- &3临时权限: &a{5}\n {PREFIX}&f- &3前缀: &a{6}\n {PREFIX}&f- &3后缀: &a{7}\n {PREFIX}&f- &3元信息: &a{8} user-info-data: > {PREFIX}&f- &aCached Data:\n {PREFIX}&f- &3具有环境数据: {0}\n {PREFIX}&f- &3当前环境: {1}\n {PREFIX}&f- &3当前前缀: {2}\n {PREFIX}&f- &3当前后缀: {3} info-parent-header: "&f- &a父组:" info-temp-parent-header: "&f- &a临时父组:" user-getuuid: "&b{0}&b的UUID是&b{1}&b." user-removegroup-error-primary: "您不能从其主组中删除用户." user-primarygroup-success: "&b{0}&的主组已设为&b{1}&a." user-primarygroup-warn-option: "&c警告:此服务器&7({0})&c使用的主组计算方法可能无法反映此更改." user-primarygroup-error-alreadyhas: "用户已将此组设置为其主组." user-primarygroup-error-notmember: "&b{0}&a已经不是&b{1}&a的成员,现在添加它们." user-track-error-not-contain-group: "指定的用户尚未在此轨道上的任何组中." user-track-added-to-first: "&b{0}&a不在此轨道上的任何组中, 因此在环境&b{2}&a中将其添加到第一组&b{2}&a." user-promote-success: "&a在环境&b{3}&a中将用户沿轨道&b{0}&a从&b{1}&a提升到&b{2}&a." user-promote-error-endoftrack: "已达到轨道&4{0}&c的结尾,所以无法提升用户." user-promote-error-malformed: > {PREFIX}轨道上的下一个组{0}不存在. 无法提升用户.\n {PREFIX}创建组,或将其从轨道中删除,然后重试. user-demote-success: "&a在环境&b{3}&a中将用户沿轨道&b{0}&a从&b{1}&a转移到&b{2}&a." user-demote-endoftrack: "已达到轨道&4{0}&c的结尾,所以&4{1}&c已从&4{2}&c中移除." user-demote-error-malformed: > {PREFIX}轨道上的上一组{0}不存在.无法降级用户.\n {PREFIX}创建组,或将其从轨道中删除,然后重试. user-showpos: > &a显示&b{0}&a在轨道&b{1}&a的位置.\n {2} group-info-general: > {PREFIX}&b&l> &b组信息: &f{0}\n {PREFIX}&f- &3显示名称: &f{1}\n {PREFIX}&f- &3权重: &f{2}\n {PREFIX}&f- &a统计:\n {PREFIX}&f- &3权限: &a{3}\n {PREFIX}&f- &3临时权限: &a{4}\n {PREFIX}&f- &3前缀: &a{5}\n {PREFIX}&f- &3后缀: &a{6}\n {PREFIX}&f- &3元信息: &a{7} group-set-weight: "&a将组&b{1}&a的权重设置为&b{0}&a." track-info: > {PREFIX}&b&l> &b显示轨道: &f{0}\n {PREFIX}&f- &7路径: &f{1} track-clear: "&b{0}&a's groups track was cleared." track-append-success: "&a组&b{0}&a已成功添加到轨道&b{1}&a." track-insert-success: "&a组&b{0}&a已成功插入轨道&b{1}&a的&b{2}&a位置." track-insert-error-number: "没有预期的数量,而是收到: {0}" track-insert-error-invalid-pos: "无法插入位置{0}. 索引超出范围." track-remove-success: "&aGroup &b{0}&a已成功从轨道&b{1}&a移除." log-load-error: "日志无法加载." log-invalid-page: "页码无效." log-invalid-page-range: "页码无效,请输入1和{0}之间的值." log-no-entries: "&b没有日志条目显示." log-entry: "&b#{0} -> &8(&7{1} ago&8) {2}" log-notify-toggle-on: "&a启用&b记录输出." log-notify-toggle-off: "&c禁用&b记录输出." log-notify-already-on: "您已经收到通知." log-notify-already-off: "您目前没有收到通知." log-notify-unknown: "状态未知.输入 \"on\" 或者 \"off\"." log-search-header: "&a显示最近的查询操作&b{0} &a(page &f{1}&a of &f{2}&a)" log-recent-header: "&a显示最近操作 (page &f{0}&a of &f{1}&a)" log-recent-by-header: "&a显示&b{0}&a的最近操作 (page &f{1}&a of &f{2}&a)" log-history-user-header: "&a显示用户的历史记录&b{0} &a(page &f{1}&a of &f{2}&a)" log-history-group-header: "&a显示组的历史记录 &b{0} &a(page &f{1}&a of &f{2}&a)" log-history-track-header: "&a显示轨道的历史记录 &b{0} &a(page &f{1}&a of &f{2}&a)" log-export-already-exists: "错误: 文件{0}已经存在." log-export-not-writable: "错误: 文件{0}不可写." log-export-empty: "日志为空,因此无法导出." log-export-failure: "写入文件时出现意外错误." log-export-success: "&a成功导出日志&b{0}&a." import-already-running: "另一个导入过程已经在运行,请等待完成,然后重试." export-already-running: "另一个导出过程已经在运行,请等待完成,然后重试." import-log-doesnt-exist: "错误: 文件{0}不存在." import-log-not-readable: "错误: 文件{0}不可读." import-log-failure: "从日志文件读取时发生意外错误." import-progress: "&b(导入) &b-> &f百分之{0}完成 &7- &b{1}&f/&b{2} &f完成 &c{3}&f错误." import-progress-sin: "&b(导入) &b-> &f百分之{0}完成 &7- &b{1}&f/&b{2} &f完成 &c{3}&f错误." import-start: "&b(导入) &b-> &f开始导入过程." import-end-complete: "&b(导入) &a&l已完成 &7- 用了 &b{0} &7秒 - &7没有错误." import-end-complete-err: "&b(导入) &a&l已完成 &7- 用了 &b{0} &7秒 - &c{1}错误." import-end-complete-err-sin: "&b(导入) &a&l已完成 &7- 用了 &b{0} &7秒 - &c{1}错误." import-end-error-header: > {PREFIX}&b(导入) &7------------> &f显示错误 #&b{0} &7<------------\n {PREFIX}&b(导入) &f执行时: &3Command #{1}\n {PREFIX}&b(导入) &f命令: &7{2}\n {PREFIX}&b(导入) &f类型: &3{3}\n {PREFIX}&b(导入) &f输出: import-end-error-content: "&b(导入) &b-> &c{0}" import-end-error-footer: "&b(导入) &7<------------------------------------------>"
PlaceholderAPI
在 extended_clip 的 PlaceholderAPI 插件中,LuckPerms 也注册了一些变量(Placeholders)。
LuckPerms 插件所使用的标识符是 luckperms。
使用
要想使用变量的话,你需要运行下列命令。 这些命令的作用就是安装 LuckPerms 的变量扩展,安装后你就可以使用下面列举出的变量了。
/papi ecloud download LuckPerms
/papi reload
请记住使用这些指令你需要OP权限(或者你也可以选择在控制台中运行这些指令)
同时请注意,如果你想得到玩家的前缀或后缀数据,——如果你在服务器上安装了Vault插件和Vault的变量扩展的话,你也可以使用 Vault 插件所提供的变量。
Placeholders
%luckperms_group_name%
使用说明: 返回玩家当前所在组的名字
使用示例: n/a
%luckperms_context_<context key>%
使用说明: 返回给定内容关键字的值,如果内容没有值的话会返回空 使用示例: %luckperms_context_server%
%luckperms_groups%
使用说明: 返回服务器上的权限组列表,用逗号分割 使用示例: n/a
%luckperms_has_permission_<permission>%
使用说明: 检查玩家是否直接拥有该权限,不会检查通配符或继承的权限 使用示例: %luckperms_has_permission_essentials.ban%
%luckperms_check_permission_<permission>%
使用说明: 检查玩家是否拥有指定权限,这个变量工作的方式和正常插件的检查方式没有区别 使用示例: %luckperms_check_permission_some.cool.permission%
%luckperms_in_group_<group>%
使用说明: 返回玩家是否为给定组的成员,不包括继承组 使用示例: %luckperms_in_group_admin%
%luckperms_inherits_group_<group>%
使用说明: 返回玩家是否在给定组或继承给定组 使用示例: %luckperms_inherits_group_vip%
%luckperms_on_track_<track>%
使用说明: 返回玩家的权限组是否在给定权限组树上 使用示例: %luckperms_on_track_staff%
%luckperms_has_groups_on_track_<track>%
使用说明: 检查玩家是否继承给定权限组树中的任何一个组 使用示例: %luckperms_on_track_donor%
%luckperms_highest_group_by_weight%
使用说明: 返回玩家所在权限组树种的最高级权限组 使用示例: n/a
%luckperms_lowest_group_by_weight%
使用说明: 返回玩家所在权限组树种的最低级权限组 使用示例: n/a
%luckperms_first_group_on_tracks_<tracks>%
使用说明: 返回玩家在给定权限组树上所在的第一个组,权限组树会返回一组用逗号分隔的权限组名,权限组树中的每一个权限组都正序排列。 使用示例: %luckperms_first_group_on_tracks_staff,donor%
%luckperms_last_group_on_tracks_<tracks>%
使用说明: 返回玩家在给定权限组树上所在的最后一个组,权限组树会返回一组用逗号分隔的权限组名,权限组树中的每一个权限组都倒序排列。 使用示例: %luckperms_last_group_on_tracks_staff,donor%
%luckperms_expiry_time_<permission>%
使用说明: 获得玩家拥有的临时权限剩余的时间,如果玩家没有该权限的话会返回空 使用示例: %luckperms_expiry_time_essentials.fly%
%luckperms_group_expiry_time_<group name>%
使用说明: 获得玩家拥有的临时权限组所剩余的时间,如果玩家不在该权限组的话会返回空 使用示例: %luckperms_group_expiry_time_vip%
%luckperms_prefix%
使用说明: 返回玩家的前缀,使用Vault所提供的变量所输出的结果可能会更精确,这一项不会被Vault的配置设置影响 使用示例: n/a
%luckperms_suffix%
使用说明: 返回玩家的后缀,使用Vault所提供的变量所输出的结果可能会更精确,这一项不会被Vault的配置设置影响 使用示例: n/a
%luckperms_meta_<meta key>%
使用说明: 返回与指定Meta关键字联系的值 使用示例: %luckperms_meta_some-key%