Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
096885d91f | ||
|
|
368700156c | ||
|
|
81cf50520b | ||
|
|
649748c2d3 | ||
|
|
bf7a708440 | ||
|
|
8faa4d137b | ||
|
|
479bd91b74 | ||
|
|
6bc7f1fca2 | ||
|
|
dadd8e2c50 | ||
|
|
03f342a21c | ||
|
|
7fe5397e21 | ||
|
|
b6e1fd179e | ||
|
|
754c7d8e3b | ||
|
|
925d3ccd1b | ||
|
|
d60d0ac9c5 | ||
|
|
e1b51dd6af | ||
|
|
fbe9d9f128 | ||
|
|
509826949d | ||
|
|
39aaa8a292 | ||
|
|
069c76c53a | ||
|
|
f45c0caa45 | ||
|
|
41b0e10709 | ||
|
|
8e8da20c13 | ||
|
|
269aa39378 | ||
|
|
ae8be97db7 | ||
|
|
f0ad40825b | ||
|
|
36d292747a | ||
|
|
b65d2262bf | ||
|
|
a7ab0c6b36 | ||
|
|
c02fcb6508 | ||
|
|
07c38de44b | ||
|
|
188d62c99b | ||
|
|
76b203ad10 | ||
|
|
909844aef5 | ||
|
|
046202719a | ||
|
|
ed15e2838d |
No files matched your search
+24
-36
@@ -26,13 +26,10 @@ already-has-temp-permission: "{0} already has this permission set temporarily!"
|
||||
does-not-have-temp-permission: "{0} does not have this permission set temporarily."
|
||||
user-not-found: "&bUser could not be found."
|
||||
user-not-online: "&bUser &a{0}&b is not online."
|
||||
user-save-success: "&7(User data was saved to storage)"
|
||||
user-save-error: "There was an error whilst saving the user."
|
||||
group-not-found: "&bGroup could not be found."
|
||||
group-save-success: "&7(Group data was saved to storage)"
|
||||
group-save-error: "There was an error whilst saving the group."
|
||||
track-not-found: "&bTrack could not be found."
|
||||
track-save-success: "&7(Track data was saved to storage)"
|
||||
track-save-error: "There was an error whilst saving the track."
|
||||
user-invalid-entry: "&d{0}&c is not a valid username/uuid."
|
||||
group-invalid-entry: "Group names can only contain alphanumeric characters."
|
||||
@@ -95,34 +92,22 @@ update-task-push-success: "&aOther servers were notified via &b{0} Messaging &as
|
||||
update-task-push-failure: "&cError whilst pushing changes to other servers."
|
||||
update-task-push-failure-not-setup: "&cError whilst pushing changes to other servers. A messaging service has not been configured."
|
||||
reload-config-success: "&aThe configuration file was reloaded. &7(some options will only apply after the server has restarted.)"
|
||||
info: >
|
||||
info-top: >
|
||||
{PREFIX}&2Running &bLuckPerms v{0}&2 by &bLuck&2.\n
|
||||
{PREFIX}&f- &3Platform: &f{1}\n
|
||||
{PREFIX}&f- &3Storage Method: &f{2}\n
|
||||
{PREFIX}&f- &3Server Name: &f{3}\n
|
||||
{PREFIX}&f- &3Sync Interval: &a{4} &fminutes\n
|
||||
{PREFIX}&f- &3Messaging Service: &f{5}\n
|
||||
{PREFIX}&f- &bCounts:\n
|
||||
{PREFIX}&f- &3Online Players: &a{6}\n
|
||||
{PREFIX}&f- &3Loaded Users: &a{7}\n
|
||||
{PREFIX}&f- &3Loaded Groups: &a{8}\n
|
||||
{PREFIX}&f- &3Loaded Tracks: &a{9}\n
|
||||
{PREFIX}&f- &3Log size: &a{10}\n
|
||||
{PREFIX}&f- &3UUID Cache size: &a{11}\n
|
||||
{PREFIX}&f- &3Translations loaded: &a{12}\n
|
||||
{PREFIX}&f- &3Pre-process contexts: &a{13}\n
|
||||
{PREFIX}&f- &3Context Calculators: &a{14}\n
|
||||
{PREFIX}&f- &3Unique permissions: &a{15}\n
|
||||
{PREFIX}&f- &bConfiguration:\n
|
||||
{PREFIX}&f- &3Use Server UUIDs: {16}\n
|
||||
{PREFIX}&f- &bPermission Calculation:\n
|
||||
{PREFIX}&f- &3Including Global: {17}\n
|
||||
{PREFIX}&f- &3Including Global World: {18}\n
|
||||
{PREFIX}&f- &3Applying Global Groups: {19}\n
|
||||
{PREFIX}&f- &3Applying Global World Groups: {20}\n
|
||||
{PREFIX}&f- &3Applying Wildcards: {21}\n
|
||||
{PREFIX}&f- &3Applying Regex: {22}\n
|
||||
{PREFIX}&f- &3Applying Shorthand: {23}
|
||||
{PREFIX}&f- &3Server Brand: &f{2}\n
|
||||
{PREFIX}&f- &3Server Version: &f{3}
|
||||
info-middle: >
|
||||
{PREFIX}&f- &bMessaging Type: &f{0}\n
|
||||
{PREFIX}&f- &bInstance:\n
|
||||
{PREFIX}&f- &3Server Name: &f{1}\n
|
||||
{PREFIX}&f- &3Online Players: &a{2}\n
|
||||
{PREFIX}&f- &3Unique Connections: &a{3}\n
|
||||
{PREFIX}&f- &3Uptime: &7{4}\n
|
||||
{PREFIX}&f- &3Local Data: &a{5} &7users, &a{6} &7groups, &a{7} &7tracks\n
|
||||
{PREFIX}&f- &3Context Calculators: &a{8}\n
|
||||
{PREFIX}&f- &3Known permissions: &a{9}\n
|
||||
{PREFIX}&f- &3Active processors: &7{10}
|
||||
create-group-error: "There was an error whilst creating the group."
|
||||
delete-group-error: "There was an error whilst deleting the group."
|
||||
delete-group-error-default: "You cannot delete the default group."
|
||||
@@ -147,6 +132,7 @@ context-pair--global-inline: "&eglobal"
|
||||
context-pair-sep: "&a, "
|
||||
context-pair: "&8(&7{0}=&f{1}&8)"
|
||||
check-permission: "&b{0}&a has permission &b{1}&a set to {2}&a in context {3}&a."
|
||||
check-inherits-permission: "&b{0}&a has permission &b{1}&a set to {2}&a in context {3}&a. &7(inherited from &a{4}&7)"
|
||||
setpermission-success: "&aSet &b{0}&a to &b{1}&a for &b{2}&a in context {3}&a."
|
||||
setpermission-temp-success: "&aSet &b{0}&a to &b{1}&a for &b{2}&a for a duration of &b{3}&a in context {4}&a."
|
||||
unsetpermission-success: "&aUnset &b{0}&a for &b{1}&a in context {2}&a."
|
||||
@@ -159,12 +145,12 @@ unset-inherit-success: "&b{0}&a no longer inherits permissions from &b{1}&a in c
|
||||
unset-temp-inherit-success: "&b{0}&a no longer temporarily inherits permissions from &b{1}&a in context {2}&a."
|
||||
clear-success: "&b{0}&a's permissions were cleared in context {1}&a. (&b{2}&a nodes were removed.)"
|
||||
clear-success-singular: "&b{0}&a's permissions were cleared in context {1}&a. (&b{2}&a node was removed.)"
|
||||
parent-clear-success: "&b{0}&a's parents were cleared in context {1}&a. &b{2}&a nodes were removed.)"
|
||||
parent-clear-success-singular: "&b{0}&a's parents were cleared in context {1}&a. &b{2}&a node was removed.)"
|
||||
parent-clear-track-success: "&b{0}&a's parents on track &b{1}&a were cleared in context {2}&a. &b{3}&a nodes were removed.)"
|
||||
parent-clear-track-success-singular: "&b{0}&a's parents on track &b{1}&a were cleared in context {2}&a. &b{3}&a node was removed.)"
|
||||
meta-clear-success: "&b{0}&a's meta was cleared in context {1}&a. &b{2}&a nodes were removed.)"
|
||||
meta-clear-success-singular: "&b{0}&a's meta was cleared in context {1}&a. &b{2}&a node was removed.)"
|
||||
parent-clear-success: "&b{0}&a's parents were cleared in context {1}&a. (&b{2}&a nodes were removed.)"
|
||||
parent-clear-success-singular: "&b{0}&a's parents were cleared in context {1}&a. (&b{2}&a node was removed.)"
|
||||
parent-clear-track-success: "&b{0}&a's parents on track &b{1}&a were cleared in context {2}&a. (&b{3}&a nodes were removed.)"
|
||||
parent-clear-track-success-singular: "&b{0}&a's parents on track &b{1}&a were cleared in context {2}&a. (&b{3}&a node was removed.)"
|
||||
meta-clear-success: "&b{0}&a's meta matching type &b{1}&a was cleared in context {2}&a. (&b{3}&a nodes were removed.)"
|
||||
meta-clear-success-singular: "&b{0}&a's meta matching type &b{1}&a was cleared in context {2}&a. (&b{3}&a node was removed.)"
|
||||
illegal-date-error: "Could not parse date '{0}'."
|
||||
past-date-error: "You cannot set a date in the past!"
|
||||
chat-meta-prefix-header: "&b{0}'s Prefixes"
|
||||
@@ -261,6 +247,7 @@ log-invalid-page: "Invalid page number."
|
||||
log-invalid-page-range: "Invalid page number. Please enter a value between 1 and {0}."
|
||||
log-no-entries: "&bNo log entries to show."
|
||||
log-entry: "&b#{0} -> &8(&7{1} ago&8) {2}"
|
||||
log-notify-console: "&cCannot toggle notifications for console."
|
||||
log-notify-toggle-on: "&aEnabled&b logging output."
|
||||
log-notify-toggle-off: "&cDisabled&b logging output."
|
||||
log-notify-already-on: "You are already receiving notifications."
|
||||
@@ -606,8 +593,9 @@ command-specs:
|
||||
"suffix": "the suffix string"
|
||||
"context...": "the contexts to remove the suffix in"
|
||||
meta-clear:
|
||||
description: "Clears all chat meta"
|
||||
description: "Clears all meta"
|
||||
args:
|
||||
"type": "the type of meta to remove"
|
||||
"context...": "the contexts to filter by"
|
||||
track-info:
|
||||
description: "Gives info about the track"
|
||||
|
||||
+625
-190
@@ -9,85 +9,94 @@ 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服务器管理员状态在安装权限插件时无效,请直接编辑用户数据."
|
||||
loading-error: "无法加载权限数据,请稍后再试。"
|
||||
op-disabled: "&b此服务器上禁用了vanilla OP系统。"
|
||||
op-disabled-sponge: "&2安装了权限插件时,服务器OP状态无效,请直接编辑用户数据。"
|
||||
log: "&3日志 &3&l> {0}"
|
||||
verbose-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-not-recognised: "命令未被识别。"
|
||||
command-no-permission: "你没有权限使用这个命令!"
|
||||
already-haspermission: "{0}已经有这个权限!"
|
||||
does-not-havepermission: "{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任何数据."
|
||||
does-not-have-temp-permission: "{0}没有设置此临时权限。"
|
||||
user-not-found: "&b找不到用户。"
|
||||
user-not-online: "&b用户&a{0}&b不在线。"
|
||||
user-save-success: "&7(保存用户数据到文件)"
|
||||
user-save-error: "保存用户数据时出错."
|
||||
user-create-fail: "创建新用户时出错."
|
||||
group-not-found: "&b找不到组."
|
||||
user-save-error: "保存用户数据时出错。"
|
||||
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'命令,而不是指定节点."
|
||||
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-world-invalid-entry: "服务器/世界名称只能包含字母数字字符,长度不能超过36个字符。"
|
||||
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-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-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-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}"
|
||||
apply-edits-invalid-code: "&a无效的代码。&7({0})"
|
||||
apply-edits-unable-to-read: "&a无法使用给定代码读取数据。&7({0})"
|
||||
apply-edits-no-target: "&a无法解析编辑的目标。请提供它作为一个额外的参数。"
|
||||
apply-edits-target-group-not-exists: "&a目标组&b{0}&a不存在。"
|
||||
apply-edits-target-user-not-uuid: "&a目标用户&b{0}&a不是一个有效的uuid。"
|
||||
apply-edits-target-user-unable-to-load: "&a无法加载目标用户&b{0}&a。"
|
||||
apply-edits-target-unknown: "&a目标无效。&7({0})"
|
||||
apply-edits-success: "&a成功应用&b{0}&a节点到&b{1}&a。"
|
||||
editor-upload-failure: "&c无法将权限数据上传到编辑器。"
|
||||
editor-url: "&a编辑器URL:"
|
||||
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: "指定的用户是此轨道上多个组的成员,无法确定他们的位置."
|
||||
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(一些选项将仅在服务器重新启动后才应用.)"
|
||||
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}&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
|
||||
@@ -97,7 +106,7 @@ info: >
|
||||
{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{9}\n
|
||||
{PREFIX}&f- &3日志大小: &a{10}\n
|
||||
{PREFIX}&f- &3UUID缓存大小: &a{11}\n
|
||||
{PREFIX}&f- &3翻译加载: &a{12}\n
|
||||
@@ -114,57 +123,49 @@ info: >
|
||||
{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}"
|
||||
create-group-error: "创建组时出错。"
|
||||
delete-group-error: "删除组时出错。"
|
||||
delete-group-error-default: "您不能删除默认组。"
|
||||
groups-list: "&a组: &7(名字,权重,权限组轨道)"
|
||||
groups-list-entry: "&f- &3{0} &7- &b{1}"
|
||||
groups-list-entry-with-tracks: "&f- &3{0} &7- &b{1} &7- [&3{2}&7]"
|
||||
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}
|
||||
listnodes-temp: "&b{0}的临时节点:"
|
||||
listnodes-temp-with-page: "&b{0}的临时节点: {1}"
|
||||
listparents: "&b{0}的父组"
|
||||
listparents-temp: "&b{0}的临时父组:"
|
||||
list-tracks: >
|
||||
&b{0}的轨道:\n
|
||||
&b{0}的权限组轨道:\n
|
||||
{1}
|
||||
list-tracks-empty: "{0}不在任何轨道上."
|
||||
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-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}'."
|
||||
check-permission: "&b在环境&b{3}&b中,&b{0}&b的权限&b{1}&b被设置为&b{2}&b。"
|
||||
setpermission-success: "&a在环境&b{3}&a中将&b{2}&a的&b{0}&a权限设置为&b{1}&a。"
|
||||
setpermission-temp-success: "&a在环境&b{4}&a中将&b{2}&a的&b{0}&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。"
|
||||
set-track-parent-success: "在权限组轨道&b{1}&a上&b{0}&a现有的父组被清除,现在只在&b{3}&a中继承&b{2}&a。"
|
||||
unset-inherit-success: "&b{0}&a不再继承环境&b{2}&a中&b{1}&a的权限。"
|
||||
unset-temp-inherit-success: "&b{0}&a在环境&b{2}&a中不再继承临时权限&b{1}&a。"
|
||||
clear-success: "&b{0}&a的权限在环境&b{1}&a中被清除。(&b{2}&a节点已被删除。)"
|
||||
clear-success-singular: "&b{0}&a的权限在环境&b{1}&a中被清除。(&b{2}&a节点已被删除。)"
|
||||
parent-clear-success: "&b{0}&a的父组在环境&b{1}&a中被清除。&b{2}&a节点被删除。)"
|
||||
parent-clear-success-singular: "&b{0}&a的父组在环境&b{1}&a中被清除。&b{2}&a节点被删除。)"
|
||||
parent-clear-track-success: "在权限组轨道&b{1}&a上,&b{0}&a的父组在环境&b{2}&a中被清除。&b{3}&a节点被删除。)"
|
||||
parent-clear-track-success-singular: "在权限组轨道&b{1}&a上,&b{0}&a的父组在环境&b{2}&a中被清除。&b{3}&a节点被删除。)"
|
||||
meta-clear-success: "&b{0}&a的元数据在环境&b{1}&a中被清除。&b{2}&a节点已被删除。)"
|
||||
meta-clear-success-singular: "&b{0}&a的元数据在环境&b{1}&a中被清除。&b{2}&a节点已被删除。)"
|
||||
illegal-date-error: "无法解析日期'{0}'。"
|
||||
past-date-error: "您不能设定一个过去的日期!"
|
||||
chat-meta-prefix-header: "&b{0}的前缀"
|
||||
chat-meta-suffix-header: "&b{0}的后缀"
|
||||
@@ -173,36 +174,34 @@ 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}记录已更改."
|
||||
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{4}&a中将&b{0}&a的{1}设置为&f\"{2}&f\",优先级&b{3}&a。"
|
||||
add-temp-chatmeta-success: "在环境&b{5}&a中将&b{0}&a的{1}设置为&f\"{2}&f\"&a,优先级&b{3}&a,持续时间为&b{4}&a。"
|
||||
remove-chatmeta-success: "在环境&b{3}&a中删除了&b{0}&a优先级为&b{3}&a的{1} &f\"{2}&f\"&a。"
|
||||
bulk-remove-chatmeta-success: "在环境&b{3}&a中删除了&b{0}&a优先级&b{2}&a的所有&b{1}&a。"
|
||||
remove-temp-chatmeta-success: "在环境&b{4}&a中删除了&b{0}&a优先级&b{3}&a的临时{1} &f\"{2}&f\"&a。"
|
||||
bulk-remove-temp-chatmeta-success: "在环境&b{3}&a中删除了&b{0}&a优先级&b{2}&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: "类型无效。期望类型是'全部'、'用户'或'组'。"
|
||||
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: "&c批量更新失败。检查控制台是否有错误。"
|
||||
user-info-general: >
|
||||
{PREFIX}&b&l> &bUser Info: &f{0}\n
|
||||
{PREFIX}&b&l> &b用户信息: &f{0}\n
|
||||
{PREFIX}&f- &3UUID: &f{1}\n
|
||||
{PREFIX}&f- &3状态: {2}\n
|
||||
{PREFIX}&f- &3主组: &f{3}\n
|
||||
@@ -213,34 +212,30 @@ user-info-general: >
|
||||
{PREFIX}&f- &3后缀: &a{7}\n
|
||||
{PREFIX}&f- &3元信息: &a{8}
|
||||
user-info-data: >
|
||||
{PREFIX}&f- &aCached Data:\n
|
||||
{PREFIX}&f- &a缓存数据:\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-removegroup-error-primary: "您不能从其主组中删除用户。"
|
||||
user-primarygroup-success: "&b{0}&a的主组已设为&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中移除."
|
||||
{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}
|
||||
{PREFIX}权限组轨道上的上一组{0}不存在。无法降级用户。\n
|
||||
{PREFIX}创建组,或将其从权限组轨道中删除,然后重试。
|
||||
group-info-general: >
|
||||
{PREFIX}&b&l> &b组信息: &f{0}\n
|
||||
{PREFIX}&f- &3显示名称: &f{1}\n
|
||||
@@ -251,53 +246,493 @@ group-info-general: >
|
||||
{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."
|
||||
group-set-weight: "&a将组&b{1}&a的权重设置为&b{0}&a。"
|
||||
track-info: >
|
||||
{PREFIX}&b&l> &b显示轨道: &f{0}\n
|
||||
{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没有日志条目显示."
|
||||
track-clear: "&b{0}&a的权限组轨道已被清除。"
|
||||
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: "&a组&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}错误."
|
||||
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(&f{1}&a/&f{2}&a)"
|
||||
log-recent-header: "&a显示最近操作 (&f{0}&a/&f{1}&a)"
|
||||
log-recent-by-header: "&a显示&b{0}&a的最近操作 (&f{1}&a/&f{2}&a)"
|
||||
log-history-user-header: "&a显示用户的历史记录&b{0} &a(&f{1}&a/&f{2}&a)"
|
||||
log-history-group-header: "&a显示组的历史记录 &b{0} &a(&f{1}&a/&f{2}&a)"
|
||||
log-history-track-header: "&a显示权限组轨道的历史记录 &b{0} &a(&f{1}&a/&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执行: &3命令 #{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<------------------------------------------>"
|
||||
import-end-error-footer: "&b(导入) &7<------------------------------------------>"
|
||||
|
||||
command-specs:
|
||||
user:
|
||||
description: "用户命令"
|
||||
usage: "/%s user <用户>"
|
||||
group:
|
||||
description: "组命令"
|
||||
usage: "/%s group <组>"
|
||||
track:
|
||||
description: "权限组轨道指令"
|
||||
usage: "/%s track <权限组轨道>"
|
||||
log:
|
||||
description: "日志命令"
|
||||
usage: "/%s log"
|
||||
sync:
|
||||
description: "与存储同步更改"
|
||||
usage: "/%s sync"
|
||||
info:
|
||||
description: "打印通用插件信息"
|
||||
usage: "/%s info"
|
||||
verbose:
|
||||
description: "管理详细权限检查"
|
||||
usage: "/%s verbose <true|false> [filter]"
|
||||
args:
|
||||
"on|record|off|paste": "是否启用/禁用日志记录,或粘贴记录的输出"
|
||||
"filter": "过滤器匹配项"
|
||||
tree:
|
||||
description: "生成权限的树视图"
|
||||
usage: "/%s tree [selection] [max level] [player]"
|
||||
args:
|
||||
"selection": "树的根,指定\".\"包括所有权限"
|
||||
"max level": "应该返回多少分支级别"
|
||||
"player": "要检查的在线玩家的名称"
|
||||
search:
|
||||
description: "搜索具有特定权限的用户/组"
|
||||
usage: "/%s search <permission>"
|
||||
args:
|
||||
"permission": "权限搜索"
|
||||
"page": "页面查看"
|
||||
check:
|
||||
description: "对用户执行标准的权限检查"
|
||||
usage: "/%s check <user> <permission>"
|
||||
args:
|
||||
"user": "检查用户"
|
||||
"permission": "允许检查"
|
||||
network-sync:
|
||||
description: "与存储同步更改并请求网络上所有其他服务器都同步"
|
||||
usage: "/%s networksync"
|
||||
import:
|
||||
description: "从文件导入数据"
|
||||
usage: "/%s import <file>"
|
||||
args:
|
||||
"file": "要导入的文件"
|
||||
export:
|
||||
description: "将数据导出到文件"
|
||||
usage: "/%s export <file>"
|
||||
args:
|
||||
"file": "要导出的文件"
|
||||
reload-config:
|
||||
description: "重新加载部分配置选项"
|
||||
usage: "/%s reloadconfig"
|
||||
bulk-update:
|
||||
description: "对所有数据执行批量更改查询"
|
||||
usage: "/%s bulkupdate"
|
||||
args:
|
||||
"data type": "正在更改的数据类型。('all'、'users'、'groups')"
|
||||
"action": "对数据执行的操作。('update' or 'delete')"
|
||||
"action field": "要采取行动的领域。只需要'update'。('permission'、'server'、'world')"
|
||||
"action value": "替换的值。只需要'update'。"
|
||||
"constraint...": "更新所需的限制"
|
||||
migration:
|
||||
description: "迁移命令"
|
||||
usage: "/%s migration"
|
||||
apply-edits:
|
||||
description: "应用从Web编辑器进行的权限更改"
|
||||
usage: "/%s applyedits <code> [target]"
|
||||
args:
|
||||
"code": "数据的唯一代码"
|
||||
"target": "应用数据到谁"
|
||||
create-group:
|
||||
description: "创建新组"
|
||||
usage: "/%s creategroup <group>"
|
||||
args:
|
||||
"name": "组的名称"
|
||||
delete-group:
|
||||
description: "删除组"
|
||||
usage: "/%s deletegroup <group>"
|
||||
args:
|
||||
"name": "组的名称"
|
||||
list-groups:
|
||||
description: "列出平台上的所有组"
|
||||
usage: "/%s listgroups"
|
||||
create-track:
|
||||
description: "创建新权限组轨道"
|
||||
usage: "/%s createtrack <track>"
|
||||
args:
|
||||
"name": "权限组轨道的名称"
|
||||
delete-track:
|
||||
description: "删除权限组轨道"
|
||||
usage: "/%s deletetrack <track>"
|
||||
args:
|
||||
"name": "权限组轨道的名称"
|
||||
list-tracks:
|
||||
description: "列出平台上的所有权限组轨道"
|
||||
usage: "/%s listtracks"
|
||||
user-info:
|
||||
description: "显示有关用户的信息"
|
||||
user-switchprimarygroup:
|
||||
description: "切换用户的主组"
|
||||
args:
|
||||
"group": "组切换到"
|
||||
user-promote:
|
||||
description: "在权限组轨道提升用户"
|
||||
args:
|
||||
"track": "提升用户的权限组轨道"
|
||||
"context...": "提升用户使用的环境"
|
||||
user-demote:
|
||||
description: "在权限组轨道降低用户"
|
||||
args:
|
||||
"track": "降低用户的权限组轨道"
|
||||
"context...": "降低用户使用的环境"
|
||||
group-info:
|
||||
description: "提供有关组的信息"
|
||||
group-listmembers:
|
||||
description: "显示从该组继承的用户/组"
|
||||
args:
|
||||
"page": "页面查看"
|
||||
group-setweight:
|
||||
description: "设置组权重"
|
||||
args:
|
||||
"weight": "设定权重"
|
||||
group-rename:
|
||||
description: "重命名组"
|
||||
args:
|
||||
"name": "新名字"
|
||||
group-clone:
|
||||
description: "克隆组"
|
||||
args:
|
||||
"name": "要克隆到的组的名称"
|
||||
holder-editor:
|
||||
description: "打开网页权限编辑器"
|
||||
holder-showtracks:
|
||||
description: "列出对象所在的权限组轨道"
|
||||
holder-clear:
|
||||
description: "删除所有权限,父组和元"
|
||||
args:
|
||||
"context...": "过滤的环境"
|
||||
permission:
|
||||
description: "编辑权限"
|
||||
parent:
|
||||
description: "编辑继承"
|
||||
meta:
|
||||
description: "编辑元数据值"
|
||||
permission-info:
|
||||
description: "列出对象拥有的权限节点"
|
||||
args:
|
||||
"page": "页面查看"
|
||||
"filter": "要过滤的字符串"
|
||||
permission-set:
|
||||
description: "设置对象的权限"
|
||||
args:
|
||||
"node": "要添加的权限"
|
||||
"true|false": "节点的值"
|
||||
"context...": "添加权限的环境"
|
||||
permission-unset:
|
||||
description: "取消对象的权限"
|
||||
args:
|
||||
"node": "取消的权限节点"
|
||||
"context...": "删除权限的环境"
|
||||
permission-settemp:
|
||||
description: "设置对象的临时权限"
|
||||
args:
|
||||
"node": "要添加的权限"
|
||||
"true|false": "节点的值"
|
||||
"duration": "到期时间"
|
||||
"context...": "权限的环境"
|
||||
permission-unsettemp:
|
||||
description: "取消对对象的临时权限"
|
||||
args:
|
||||
"node": "要取消的权限"
|
||||
"context...": "权限的环境"
|
||||
permission-check:
|
||||
description: "检查对象是否具有某个权限节点"
|
||||
args:
|
||||
"node": "要检查的权限"
|
||||
"context...": "权限的环境"
|
||||
permission-check-inherits:
|
||||
description: "检查对象是否继承某个权限节点"
|
||||
args:
|
||||
"node": "要检查的权限"
|
||||
"context...": "权限的环境"
|
||||
parent-info:
|
||||
description: "列出此对象从哪里继承的组"
|
||||
parent-set:
|
||||
description: "删除对象已经继承的所有其他组,并将其添加到给定的对象组中。"
|
||||
args:
|
||||
"group": "组设为"
|
||||
"context...": "设置组的环境"
|
||||
parent-add:
|
||||
description: "为该对象设置另一个组来继承权限"
|
||||
args:
|
||||
"group": "要继承的组"
|
||||
"context...": "继承该组的环境"
|
||||
parent-remove:
|
||||
description: "删除先前设置的继承规则"
|
||||
args:
|
||||
"group": "删除的组"
|
||||
"context...": "删除组的环境"
|
||||
parent-set-track:
|
||||
description: "删除对象在给定权限组轨道上继承的所有其他组,并将其添加到给定的权限组轨道上。"
|
||||
args:
|
||||
"track": "设置的权限组轨道"
|
||||
"group": "组中设置的组,或与组中在给定权限组轨道上的位置相关的数字"
|
||||
"context...": "设置组的环境"
|
||||
parent-add-temp:
|
||||
description: "为对象设置另一个组,以便从临时继承权限"
|
||||
args:
|
||||
"group": "要继承的组"
|
||||
"duration": "持续时间"
|
||||
"context...": "继承该组的环境"
|
||||
parent-remove-temp:
|
||||
description: "删除以前设置的临时继承规则"
|
||||
args:
|
||||
"group": "组删除"
|
||||
"context...": "删除组的环境"
|
||||
parent-clear:
|
||||
description: "清除所有的父组"
|
||||
args:
|
||||
"context...": "过滤的环境"
|
||||
parent-clear-track:
|
||||
description: "清除给定权限组轨道上的所有父组"
|
||||
args:
|
||||
"track": "删除的权限组轨道"
|
||||
"contexts...": "选择的环境"
|
||||
meta-info:
|
||||
description: "显示所有聊天元"
|
||||
meta-set:
|
||||
description: "设置元值"
|
||||
args:
|
||||
"key": "设定的键"
|
||||
"value": "要设置的值"
|
||||
"context...": "将元添加到"
|
||||
meta-unset:
|
||||
description: "取消设定元值"
|
||||
args:
|
||||
"key": "要取消的键"
|
||||
"context...": "删除元的环境"
|
||||
meta-settemp:
|
||||
description: "暂时设置一个元值"
|
||||
args:
|
||||
"key": "设定的键"
|
||||
"value": "要设置的值"
|
||||
"duration": "持续时间"
|
||||
"context...": "将元组添加到"
|
||||
meta-unsettemp:
|
||||
description: "取消设置临时元值"
|
||||
args:
|
||||
"key": "要取消的键"
|
||||
"context...": "删除元的环境"
|
||||
meta-addprefix:
|
||||
description: "添加前缀"
|
||||
args:
|
||||
"priority": "添加的前缀优先级"
|
||||
"prefix": "前缀字符串"
|
||||
"context...": "添加前缀的环境"
|
||||
meta-addsuffix:
|
||||
description: "添加后缀"
|
||||
args:
|
||||
"priority": "添加的后缀优先级"
|
||||
"suffix": "后缀字符串"
|
||||
"context...": "添加后缀的环境"
|
||||
meta-removeprefix:
|
||||
description: "删除前缀"
|
||||
args:
|
||||
"priority": "删除的前缀优先级"
|
||||
"prefix": "前缀字符串"
|
||||
"context...": "删除前缀的环境"
|
||||
meta-removesuffix:
|
||||
description: "删除后缀"
|
||||
args:
|
||||
"priority": "删除的后缀优先级"
|
||||
"suffix": "后缀字符串"
|
||||
"context...": "删除后缀的环境"
|
||||
meta-addtemp-prefix:
|
||||
description: "添加临时前缀"
|
||||
args:
|
||||
"priority": "删除的前缀优先级"
|
||||
"prefix": "前缀字符串"
|
||||
"duration": "持续时间"
|
||||
"context...": "添加前缀的环境"
|
||||
meta-addtemp-suffix:
|
||||
description: "添加临时后缀"
|
||||
args:
|
||||
"priority": "添加的后缀优先级"
|
||||
"suffix": "后缀字符串"
|
||||
"duration": "持续时间"
|
||||
"context...": "添加后缀的环境"
|
||||
meta-removetemp-prefix:
|
||||
description: "删除临时前缀"
|
||||
args:
|
||||
"priority": "删除的前缀优先级"
|
||||
"prefix": "前缀字符串"
|
||||
"context...": "删除前缀的环境"
|
||||
meta-removetemp-suffix:
|
||||
description: "删除临时后缀"
|
||||
args:
|
||||
"priority": "删除的后缀优先级"
|
||||
"suffix": "后缀字符串"
|
||||
"context...": "删除后缀的环境"
|
||||
meta-clear:
|
||||
description: "清除所有聊天元"
|
||||
args:
|
||||
"context...": "过滤的环境"
|
||||
track-info:
|
||||
description: "提供有关权限组轨道的信息"
|
||||
track-append:
|
||||
description: "追加一个组到权限组轨道的最后"
|
||||
args:
|
||||
"group": "追加的组"
|
||||
track-insert:
|
||||
description: "在权限组轨道上的给定位置插入一个组"
|
||||
args:
|
||||
"group": "插入的组"
|
||||
"position": "插入组的位置(权限组轨道上的第一个位置为1)"
|
||||
track-remove:
|
||||
description: "从权限组轨道中删除一个组"
|
||||
args:
|
||||
"group": "删除的组"
|
||||
track-clear:
|
||||
description: "清除权限组轨道上的组"
|
||||
track-rename:
|
||||
description: "重命名权限组轨道"
|
||||
args:
|
||||
"name": "新名字"
|
||||
track-clone:
|
||||
description: "克隆权限组轨道"
|
||||
args:
|
||||
"name": "要克隆的权限组轨道的名称"
|
||||
log-recent:
|
||||
description: "查看最近的登陆"
|
||||
args:
|
||||
"user": "用户的名称/uuid"
|
||||
"page": "要查看的页码"
|
||||
log-search:
|
||||
description: "搜索日志中的条目"
|
||||
args:
|
||||
"query": "搜索的查询"
|
||||
"page": "要查看的页码"
|
||||
log-notify:
|
||||
description: "切换日志通知"
|
||||
args:
|
||||
"on|off": "是否打开或关闭"
|
||||
log-user-history:
|
||||
description: "查看用户的历史记录"
|
||||
args:
|
||||
"user": "用户名/ uuid"
|
||||
"page": "要查看的页码"
|
||||
log-group-history:
|
||||
description: "查看组的历史"
|
||||
args:
|
||||
"group": "组名"
|
||||
"page": "要查看的页码"
|
||||
log-track-history:
|
||||
description: "查看权限组轨道的历史"
|
||||
args:
|
||||
"track": "权限组轨道的名称"
|
||||
"page": "要查看的页码"
|
||||
sponge:
|
||||
description: "编辑额外的Sponge数据"
|
||||
usage: "/%s sponge <collection> <subject>"
|
||||
args:
|
||||
"collection": "要查询的集合"
|
||||
"subject": "修改的主题"
|
||||
sponge-permission-info:
|
||||
description: "显示有关主题权限的信息"
|
||||
args:
|
||||
"contexts...": "选择的环境"
|
||||
sponge-permission-set:
|
||||
description: "设置一个主题的权限"
|
||||
args:
|
||||
"node": "要设置的权限节点"
|
||||
"tristate": "设置允许值"
|
||||
"contexts...": "选择的环境"
|
||||
sponge-permission-clear:
|
||||
description: "清除一个主题的权限"
|
||||
args:
|
||||
"contexts...": "清除的环境"
|
||||
sponge-parent-info:
|
||||
description: "显示关于该主题父项的信息"
|
||||
args:
|
||||
"contexts...": "选择的环境"
|
||||
sponge-parent-add:
|
||||
description: "向主题添加父项"
|
||||
args:
|
||||
"collection": "父主题的主题集合"
|
||||
"subject": "父主题的名称"
|
||||
"contexts...": "添加父项的环境"
|
||||
sponge-parent-remove:
|
||||
description: "从主题中删除父项"
|
||||
args:
|
||||
"collection": "父主题的主题集合"
|
||||
"subject": "父主题的名称"
|
||||
"contexts...": "删除父项的环境"
|
||||
sponge-parent-clear:
|
||||
description: "清除主题父项"
|
||||
args:
|
||||
"contexts...": "清除父项的主题"
|
||||
sponge-option-info:
|
||||
description: "显示有关主题选项的信息"
|
||||
args:
|
||||
"contexts...": "选择的环境"
|
||||
sponge-option-set:
|
||||
description: "为主题设置一个选项"
|
||||
args:
|
||||
"key": "设定键"
|
||||
"value": "设置的键"
|
||||
"contexts...": "设置选项的环境"
|
||||
sponge-option-unset:
|
||||
description: "取消主题一个选项"
|
||||
args:
|
||||
"key": "取消的键"
|
||||
"contexts...": "取消选项的环境"
|
||||
sponge-option-clear:
|
||||
description: "清除对象的选择"
|
||||
args:
|
||||
"contexts...": "清除选项的环境"
|
||||
migration-command:
|
||||
description: "迁移命令"
|
||||
migration-groupmanager:
|
||||
description: "迁移命令"
|
||||
args:
|
||||
"migrate as global": "如果世界权限应该被忽略,并且刚刚迁移为全局"
|
||||
migration-powerfulperms:
|
||||
description: "迁移命令"
|
||||
args:
|
||||
"address": "PP数据库的地址"
|
||||
"database": "PP数据库的名称"
|
||||
"username": "登录DB的用户名"
|
||||
"password": "登录DB的用密码"
|
||||
"db table": "存储用户数据的PP表的名称"
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>luckperms</artifactId>
|
||||
<groupId>me.lucko.luckperms</groupId>
|
||||
<version>3.3-SNAPSHOT</version>
|
||||
<version>3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -32,49 +32,59 @@ import java.util.Optional;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Singleton for the {@link LuckPermsApi}.
|
||||
* Provides static access to the {@link LuckPermsApi}.
|
||||
*
|
||||
* <p>Ideally, the ServiceManager for the platform should be used to obtain and cache an instance, however, this can be
|
||||
* used if you need static access.</p>
|
||||
* <p>Ideally, the ServiceManager for the platform should be used to obtain an instance,
|
||||
* however, this provider can be used if you need static access.</p>
|
||||
*/
|
||||
public final class LuckPerms {
|
||||
private static LuckPermsApi api = null;
|
||||
private static LuckPermsApi instance = null;
|
||||
|
||||
/**
|
||||
* Gets an instance of {@link LuckPermsApi}, throwing {@link IllegalStateException} if the API is not loaded.
|
||||
* Gets an instance of the {@link LuckPermsApi},
|
||||
* throwing {@link IllegalStateException} if an instance is not yet loaded.
|
||||
*
|
||||
* <p>Will never return null.</p>
|
||||
*
|
||||
* @return an api instance
|
||||
* @throws IllegalStateException if the api is not loaded
|
||||
*/
|
||||
@Nonnull
|
||||
public static LuckPermsApi getApi() {
|
||||
if (api == null) {
|
||||
if (instance == null) {
|
||||
throw new IllegalStateException("API is not loaded.");
|
||||
}
|
||||
return api;
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an instance of {@link LuckPermsApi}, if it is loaded.
|
||||
*
|
||||
* <p> Unlike {@link LuckPerms#getApi}, this method will not throw an {@link IllegalStateException} if the API is
|
||||
* not loaded, rather return an empty {@link Optional}.
|
||||
* <p>Unlike {@link LuckPerms#getApi}, this method will not throw an
|
||||
* {@link IllegalStateException} if an instance is not yet loaded, rather return
|
||||
* an empty {@link Optional}.
|
||||
*
|
||||
* @return an optional api instance
|
||||
*/
|
||||
@Nonnull
|
||||
public static Optional<LuckPermsApi> getApiSafe() {
|
||||
return Optional.ofNullable(api);
|
||||
return Optional.ofNullable(instance);
|
||||
}
|
||||
|
||||
/* method used by the implementation to set the singleton instance */
|
||||
static void registerProvider(LuckPermsApi luckPermsApi) {
|
||||
api = luckPermsApi;
|
||||
/**
|
||||
* Registers an instance of the {@link LuckPermsApi} with this provider.
|
||||
*
|
||||
* @param instance the instance
|
||||
*/
|
||||
static void registerProvider(LuckPermsApi instance) {
|
||||
LuckPerms.instance = instance;
|
||||
}
|
||||
|
||||
/* method used by the implementation to remove any previous instance */
|
||||
/**
|
||||
* Removes the current instance from this provider.
|
||||
*/
|
||||
static void unregisterProvider() {
|
||||
api = null;
|
||||
LuckPerms.instance = null;
|
||||
}
|
||||
|
||||
private LuckPerms() {
|
||||
|
||||
@@ -28,6 +28,7 @@ package me.lucko.luckperms.api;
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
@@ -104,4 +105,22 @@ public enum ChatMetaType {
|
||||
@Nonnull
|
||||
public abstract Map.Entry<Integer, String> getEntry(@Nonnull Node node);
|
||||
|
||||
/**
|
||||
* Parses a ChatMetaType from the given node.
|
||||
*
|
||||
* @param node the node
|
||||
* @return the parsed chat meta type
|
||||
* @since 3.4
|
||||
*/
|
||||
@Nonnull
|
||||
public static Optional<ChatMetaType> ofNode(@Nonnull Node node) {
|
||||
if (node.isPrefix()) {
|
||||
return Optional.of(PREFIX);
|
||||
} else if (node.isSuffix()) {
|
||||
return Optional.of(SUFFIX);
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,11 +30,29 @@ import me.lucko.luckperms.exceptions.ObjectLacksException;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Represents the result of a mutation call.
|
||||
*/
|
||||
public enum DataMutateResult {
|
||||
|
||||
/**
|
||||
* Indicates the mutation was a success
|
||||
*/
|
||||
SUCCESS(true, null),
|
||||
|
||||
/**
|
||||
* Indicates the mutation failed because the subject already has something
|
||||
*/
|
||||
ALREADY_HAS(false, ObjectAlreadyHasException::new),
|
||||
|
||||
/**
|
||||
* Indicates the mutation failed because the subject lacks something
|
||||
*/
|
||||
LACKS(false, ObjectLacksException::new),
|
||||
|
||||
/**
|
||||
* Indicates the mutation failed
|
||||
*/
|
||||
FAIL(false, RuntimeException::new);
|
||||
|
||||
private boolean value;
|
||||
@@ -51,10 +69,35 @@ public enum DataMutateResult {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a boolean representation of the result.
|
||||
*
|
||||
* @return a boolean representation
|
||||
*/
|
||||
public boolean asBoolean() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets if the result indicates a success
|
||||
*
|
||||
* @return if the result indicates a success
|
||||
* @since 3.4
|
||||
*/
|
||||
public boolean wasSuccess() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets if the result indicates a failure
|
||||
*
|
||||
* @return if the result indicates a failure
|
||||
* @since 3.4
|
||||
*/
|
||||
public boolean wasFailure() {
|
||||
return !value;
|
||||
}
|
||||
|
||||
// allows us to throw checked exceptions without declaring it, as #throwException throws a number of
|
||||
// exception types.
|
||||
private static void sneakyThrow(Throwable t) {
|
||||
|
||||
@@ -1,3 +1,28 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.api;
|
||||
|
||||
import me.lucko.luckperms.api.caching.MetaContexts;
|
||||
@@ -9,13 +34,14 @@ import javax.annotation.Nonnull;
|
||||
/**
|
||||
* A special instance of {@link Contexts}, which when passed to:
|
||||
*
|
||||
* <p><ul>
|
||||
* <li>{@link UserData#getPermissionData(Contexts)}</li>
|
||||
* <li>{@link UserData#getMetaData(Contexts)}</li>
|
||||
* <li>{@link UserData#getMetaData(MetaContexts)}</li>
|
||||
* </ul></p>
|
||||
* <p></p>
|
||||
* <ul>
|
||||
* <li>{@link UserData#getPermissionData(Contexts)}</li>
|
||||
* <li>{@link UserData#getMetaData(Contexts)}</li>
|
||||
* <li>{@link UserData#getMetaData(MetaContexts)}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>will always satisfy all contextual requirements.</p>
|
||||
* <p>... will always satisfy all contextual requirements.</p>
|
||||
*
|
||||
* <p>This effectively allows you to do lookups which ignore context.</p>
|
||||
*
|
||||
|
||||
@@ -35,7 +35,7 @@ import java.util.OptionalInt;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* A group which holds permission data.
|
||||
* An inheritable holder of permission data.
|
||||
*/
|
||||
public interface Group extends PermissionHolder {
|
||||
|
||||
|
||||
@@ -27,13 +27,15 @@ package me.lucko.luckperms.api;
|
||||
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalLong;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* A relationship between a Holder and a permission
|
||||
* A relationship between a PermissionHolder and a permission
|
||||
*
|
||||
* @param <T> the identifier type of the holder
|
||||
* @since 2.17
|
||||
@@ -90,10 +92,19 @@ public interface HeldPermission<T> {
|
||||
* Gets the context for the permission.
|
||||
*
|
||||
* @return the context
|
||||
* @deprecated in favour of {@link #getContexts()}.
|
||||
*/
|
||||
@Nonnull
|
||||
@Deprecated
|
||||
Multimap<String, String> getContext();
|
||||
|
||||
/**
|
||||
* Gets the extra context for the permission.
|
||||
*
|
||||
* @return the extra context
|
||||
*/
|
||||
ContextSet getContexts();
|
||||
|
||||
/**
|
||||
* Converts this permission into a Node
|
||||
*
|
||||
|
||||
@@ -32,104 +32,119 @@ import java.util.Map;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Read-only access to the LuckPerms configuration settings
|
||||
* Wrapper around parts of the LuckPerms configuration file
|
||||
*/
|
||||
public interface LPConfiguration {
|
||||
|
||||
/**
|
||||
* Returns the name of this server
|
||||
* Gets the name of this server
|
||||
*
|
||||
* @return the name of this server
|
||||
*/
|
||||
@Nonnull
|
||||
String getServer();
|
||||
|
||||
/**
|
||||
* Returns how often a sync task will run in minutes
|
||||
* Gets how often a sync task will run in minutes
|
||||
*
|
||||
* @return how often a sync task will run in minutes
|
||||
*/
|
||||
int getSyncTime();
|
||||
|
||||
/**
|
||||
* Returns if the users on this server will have their global permissions applied
|
||||
* Gets if the users on this server will have their global permissions applied
|
||||
*
|
||||
* @return if the users on this server will have their global permissions applied
|
||||
*/
|
||||
boolean getIncludeGlobalPerms();
|
||||
|
||||
/**
|
||||
* Returns if the users on this server will have their global world permissions applied
|
||||
* Gets if the users on this server will have their global world permissions applied
|
||||
*
|
||||
* @return if the users on this server will have their global world permissions applied
|
||||
* @since 2.9
|
||||
*/
|
||||
boolean getIncludeGlobalWorldPerms();
|
||||
|
||||
/**
|
||||
* Returns true if the platform is applying global groups
|
||||
* Gets if the platform is applying global groups
|
||||
*
|
||||
* @return true if the platform is applying global groups
|
||||
* @since 2.9
|
||||
*/
|
||||
boolean getApplyGlobalGroups();
|
||||
|
||||
/**
|
||||
* Returns true if the platform is applying global world groups
|
||||
* Gets if the platform is applying global world groups
|
||||
*
|
||||
* @return true if the platform is applying global world groups
|
||||
* @since 2.9
|
||||
*/
|
||||
boolean getApplyGlobalWorldGroups();
|
||||
|
||||
/**
|
||||
* Returns the online mode setting
|
||||
* Gets the online mode setting
|
||||
*
|
||||
* @return the online mode setting
|
||||
*/
|
||||
boolean getOnlineMode();
|
||||
|
||||
/**
|
||||
* Returns if LuckPerms is applying wildcard permissions
|
||||
* Gets if LuckPerms is applying wildcard permissions
|
||||
*
|
||||
* @return if LuckPerms is applying wildcard permissions
|
||||
*/
|
||||
boolean getApplyWildcards();
|
||||
|
||||
/**
|
||||
* Returns if LuckPerms is resolving and applying regex permissions
|
||||
*
|
||||
* @return if LuckPerms is resolving and applying regex permissions
|
||||
*/
|
||||
boolean getApplyRegex();
|
||||
|
||||
/**
|
||||
* Returns if LuckPerms is expanding shorthand permissions
|
||||
* Gets if LuckPerms is expanding shorthand permissions
|
||||
*
|
||||
* @return if LuckPerms is expanding shorthand permissions
|
||||
*/
|
||||
boolean getApplyShorthand();
|
||||
|
||||
/**
|
||||
* Returns if LuckPerms will send notifications to users when permissions are modified
|
||||
* Gets if LuckPerms will send notifications to users when permissions are modified
|
||||
*
|
||||
* @return if LuckPerms will send notifications to users when permissions are modified
|
||||
* @since 2.7
|
||||
*/
|
||||
boolean getLogNotify();
|
||||
|
||||
/**
|
||||
* Returns true if the vanilla op system is enabled
|
||||
* Gets if the vanilla op system is enabled
|
||||
*
|
||||
* @return true if the vanilla op system is enabled
|
||||
* @since 2.8
|
||||
*/
|
||||
boolean getEnableOps();
|
||||
|
||||
/**
|
||||
* Returns true if opped players are allowed to use LuckPerms commands
|
||||
* Gets if opped players are allowed to use LuckPerms commands
|
||||
*
|
||||
* @return true if opped players are allowed to use LuckPerms commands
|
||||
* @since 2.8
|
||||
*/
|
||||
boolean getCommandsAllowOp();
|
||||
|
||||
/**
|
||||
* Returns true if auto op is enabled
|
||||
* Gets if auto op is enabled
|
||||
*
|
||||
* @return true if auto op is enabled
|
||||
* @since 2.9
|
||||
*/
|
||||
boolean getAutoOp();
|
||||
|
||||
/**
|
||||
* Returns the name of the server used within Vault operations
|
||||
* Gets the name of the server used within Vault operations
|
||||
*
|
||||
* @return the name of the server used within Vault operations
|
||||
* @since 2.7
|
||||
*/
|
||||
@@ -137,35 +152,40 @@ public interface LPConfiguration {
|
||||
String getVaultServer();
|
||||
|
||||
/**
|
||||
* Returns true if global permissions should be considered when retrieving meta or player groups
|
||||
* Gets if global permissions should be considered when retrieving meta or player groups
|
||||
*
|
||||
* @return true if global permissions should be considered when retrieving meta or player groups
|
||||
* @since 2.7
|
||||
*/
|
||||
boolean getVaultIncludeGlobal();
|
||||
|
||||
/**
|
||||
* Returns the values set for data storage in the configuration
|
||||
* Gets the values set for data storage in the configuration
|
||||
*
|
||||
* @return the values set for data storage in the configuration
|
||||
*/
|
||||
@Nonnull
|
||||
DatastoreConfiguration getDatastoreConfig();
|
||||
|
||||
/**
|
||||
* Returns the storage method string from the configuration
|
||||
* Gets the storage method string from the configuration
|
||||
*
|
||||
* @return the storage method string from the configuration
|
||||
*/
|
||||
@Nonnull
|
||||
String getStorageMethod();
|
||||
|
||||
/**
|
||||
* Returns true if split storage is enabled
|
||||
* Gets true if split storage is enabled
|
||||
*
|
||||
* @return true if split storage is enabled
|
||||
* @since 2.7
|
||||
*/
|
||||
boolean getSplitStorage();
|
||||
|
||||
/**
|
||||
* Returns a map of split storage options
|
||||
* Gets a map of split storage options
|
||||
*
|
||||
* @return a map of split storage options, where the key is the storage section, and the value is the storage
|
||||
* method. For example: key = user, value = json
|
||||
* @since 2.7
|
||||
|
||||
@@ -34,18 +34,26 @@ import javax.annotation.Nonnull;
|
||||
/**
|
||||
* Represents the internal LuckPerms log.
|
||||
*
|
||||
* <p>The returned instance provides a copy of the data at the time of retrieval. Any changes made to log entries will
|
||||
* only apply to this instance of the log. You can add to the log using the {@link Storage}, and then request an updated copy.</p>
|
||||
* <p>The returned instance provides a copy of the data at the time of retrieval.</p>
|
||||
*
|
||||
* <p>Any changes made to log entries will only apply to this instance of the log.
|
||||
* You can add to the log using the {@link Storage}, and then request an updated copy.</p>
|
||||
*
|
||||
* <p>All methods are thread safe, and return immutable & thread safe collections.</p>
|
||||
*/
|
||||
public interface Log {
|
||||
|
||||
/**
|
||||
* Get the content of the log
|
||||
*
|
||||
* @return a {@link SortedSet} of all of the {@link LogEntry} objects in this {@link Log}
|
||||
*/
|
||||
@Nonnull
|
||||
SortedSet<LogEntry> getContent();
|
||||
|
||||
/**
|
||||
* Get the content of the log
|
||||
*
|
||||
* @return all content in this log
|
||||
*/
|
||||
@Nonnull
|
||||
@@ -57,18 +65,22 @@ public interface Log {
|
||||
* @param pageNo the page number
|
||||
* @return the page content
|
||||
* @throws IllegalArgumentException if the pageNo is less than 1
|
||||
* @throws IllegalStateException if the log doesn't contain enough entries to populate the page. See {@link #getRecentMaxPages()}}
|
||||
* @throws IllegalStateException if the log doesn't contain enough entries to populate the page. See {@link #getRecentMaxPages()}
|
||||
*/
|
||||
@Nonnull
|
||||
SortedMap<Integer, LogEntry> getRecent(int pageNo);
|
||||
|
||||
/**
|
||||
* Gets the max page number for the recent pages.
|
||||
*
|
||||
* @return the max page number allowed in the {@link #getRecent(int)} method
|
||||
*/
|
||||
int getRecentMaxPages();
|
||||
|
||||
|
||||
/**
|
||||
* Gets the recent content for a given actor
|
||||
*
|
||||
* @param actor the uuid of the actor to filter by
|
||||
* @return all content in this log where is actor = uuid
|
||||
*/
|
||||
@@ -76,18 +88,20 @@ public interface Log {
|
||||
SortedSet<LogEntry> getRecent(@Nonnull UUID actor);
|
||||
|
||||
/**
|
||||
* Gets the recent content for the uuid, separated into pages
|
||||
* Gets the recent content for a given actor, separated by page
|
||||
*
|
||||
* @param pageNo the page number
|
||||
* @param actor the uuid of the actor to filter by
|
||||
* @return the page content
|
||||
* @throws IllegalArgumentException if the pageNo is less than 1
|
||||
* @throws IllegalStateException if the log doesn't contain enough entries to populate the page. See {@link #getRecentMaxPages(UUID)}}
|
||||
* @throws IllegalStateException if the log doesn't contain enough entries to populate the page. See {@link #getRecentMaxPages(UUID)}
|
||||
*/
|
||||
@Nonnull
|
||||
SortedMap<Integer, LogEntry> getRecent(int pageNo, @Nonnull UUID actor);
|
||||
|
||||
/**
|
||||
* Gets the max page number for the recent pages.
|
||||
*
|
||||
* @param actor the actor to filter by
|
||||
* @return the max page number allowed in the {@link #getRecent(int, UUID)} method
|
||||
*/
|
||||
@@ -95,6 +109,8 @@ public interface Log {
|
||||
|
||||
|
||||
/**
|
||||
* Gets the log content for a given user
|
||||
*
|
||||
* @param uuid the uuid to filter by
|
||||
* @return all content in this log where the user = uuid
|
||||
*/
|
||||
@@ -102,18 +118,20 @@ public interface Log {
|
||||
SortedSet<LogEntry> getUserHistory(@Nonnull UUID uuid);
|
||||
|
||||
/**
|
||||
* Gets the user history content, separated by pages
|
||||
* Gets the log content for a given user, separated by page
|
||||
*
|
||||
* @param pageNo the page number
|
||||
* @param uuid the uuid of the acted user to filter by
|
||||
* @return the page content
|
||||
* @throws IllegalArgumentException if the pageNo is less than 1
|
||||
* @throws IllegalStateException if the log doesn't contain enough entries to populate the page. See {@link #getUserHistoryMaxPages(UUID)}}
|
||||
* @throws IllegalStateException if the log doesn't contain enough entries to populate the page. See {@link #getUserHistoryMaxPages(UUID)}
|
||||
*/
|
||||
@Nonnull
|
||||
SortedMap<Integer, LogEntry> getUserHistory(int pageNo, @Nonnull UUID uuid);
|
||||
|
||||
/**
|
||||
* Gets the max page number for the user history pages.
|
||||
*
|
||||
* @param uuid the uuid to filter by
|
||||
* @return the max page number allowed in the {@link #getUserHistory(int, UUID)} method
|
||||
*/
|
||||
@@ -121,6 +139,8 @@ public interface Log {
|
||||
|
||||
|
||||
/**
|
||||
* Gets the log content for a given group
|
||||
*
|
||||
* @param name the name to filter by
|
||||
* @return all content in this log where the group = name
|
||||
*/
|
||||
@@ -128,18 +148,20 @@ public interface Log {
|
||||
SortedSet<LogEntry> getGroupHistory(@Nonnull String name);
|
||||
|
||||
/**
|
||||
* Gets the group history content, separated by pages
|
||||
* Gets the log content for a given group, separated by page
|
||||
*
|
||||
* @param pageNo the page number
|
||||
* @param name the name of the acted group to filter by
|
||||
* @return the page content
|
||||
* @throws IllegalArgumentException if the pageNo is less than 1
|
||||
* @throws IllegalStateException if the log doesn't contain enough entries to populate the page. See {@link #getGroupHistoryMaxPages(String)}}
|
||||
* @throws IllegalStateException if the log doesn't contain enough entries to populate the page. See {@link #getGroupHistoryMaxPages(String)}
|
||||
*/
|
||||
@Nonnull
|
||||
SortedMap<Integer, LogEntry> getGroupHistory(int pageNo, @Nonnull String name);
|
||||
|
||||
/**
|
||||
* Gets the max page number for the group history pages.
|
||||
*
|
||||
* @param name the name to filter by
|
||||
* @return the max page number allowed in the {@link #getGroupHistory(int, String)} method
|
||||
*/
|
||||
@@ -147,6 +169,8 @@ public interface Log {
|
||||
|
||||
|
||||
/**
|
||||
* Gets the log content for a given track
|
||||
*
|
||||
* @param name the name to filter by
|
||||
* @return all content in this log where the track = name
|
||||
*/
|
||||
@@ -154,25 +178,29 @@ public interface Log {
|
||||
SortedSet<LogEntry> getTrackHistory(@Nonnull String name);
|
||||
|
||||
/**
|
||||
* Gets the track history content, separated by pages
|
||||
* Gets the log content for a given track, separated by page
|
||||
*
|
||||
* @param pageNo the page number
|
||||
* @param name the name of the acted track to filter by
|
||||
* @return the page content
|
||||
* @throws IllegalArgumentException if the pageNo is less than 1
|
||||
* @throws IllegalStateException if the log doesn't contain enough entries to populate the page. See {@link #getTrackHistoryMaxPages(String)}
|
||||
*/
|
||||
@Nonnull
|
||||
SortedMap<Integer, LogEntry> getTrackHistory(int pageNo, @Nonnull String name);
|
||||
|
||||
/**
|
||||
* Gets the max page number for the track history pages.
|
||||
*
|
||||
* @param name the name to filter by
|
||||
* @return the max page number allowed in the {@link #getTrackHistory(int, String)} method
|
||||
* @throws IllegalArgumentException if the pageNo is less than 1
|
||||
* @throws IllegalStateException if the log doesn't contain enough entries to populate the page. See {@link #getTrackHistoryMaxPages(String)}}
|
||||
*/
|
||||
int getTrackHistoryMaxPages(@Nonnull String name);
|
||||
|
||||
|
||||
/**
|
||||
* Gets the log content for a given search query
|
||||
*
|
||||
* @param query the query to filter by
|
||||
* @return all content in this log where the content matches query
|
||||
*/
|
||||
@@ -180,7 +208,7 @@ public interface Log {
|
||||
SortedSet<LogEntry> getSearch(@Nonnull String query);
|
||||
|
||||
/**
|
||||
* Gets the search content, separated by pages
|
||||
* Gets the log content for a given search query, separated by page
|
||||
*
|
||||
* @param pageNo the page number
|
||||
* @param query the query to filter by
|
||||
@@ -192,8 +220,11 @@ public interface Log {
|
||||
SortedMap<Integer, LogEntry> getSearch(int pageNo, @Nonnull String query);
|
||||
|
||||
/**
|
||||
* Gets the max page number for the search query pages.
|
||||
*
|
||||
* @param query the query to filter by
|
||||
* @return the max page number allowed in the {@link #getSearch(int, String)} method
|
||||
*/
|
||||
int getSearchMaxPages(@Nonnull String query);
|
||||
|
||||
}
|
||||
@@ -25,45 +25,115 @@
|
||||
|
||||
package me.lucko.luckperms.api;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* A single entry in the log
|
||||
*
|
||||
* <p>Implements {@link Comparable} ordering based upon the timestamp of the entry.</p>
|
||||
* A single entry in the log.
|
||||
*/
|
||||
public class LogEntry implements Comparable<LogEntry> {
|
||||
|
||||
/**
|
||||
* Compares two LogEntries
|
||||
*
|
||||
* @since 3.3
|
||||
*/
|
||||
public static final Comparator<LogEntry> COMPARATOR = Comparator
|
||||
.comparingLong(LogEntry::getTimestamp)
|
||||
.thenComparing(LogEntry::getActor)
|
||||
.thenComparing(LogEntry::getActorName, String.CASE_INSENSITIVE_ORDER)
|
||||
.thenComparing(LogEntry::getEntryType)
|
||||
.thenComparing(e -> {
|
||||
UUID u = e.getActed();
|
||||
return u == null ? "" : u.toString();
|
||||
})
|
||||
.thenComparing(LogEntry::getActedName, String.CASE_INSENSITIVE_ORDER)
|
||||
.thenComparing(LogEntry::getAction);
|
||||
|
||||
/**
|
||||
* Compares two LogEntries in reverse order
|
||||
*
|
||||
* @since 3.3
|
||||
* @see #COMPARATOR
|
||||
*/
|
||||
public static final Comparator<LogEntry> REVERSE_ORDER = COMPARATOR.reversed();
|
||||
|
||||
private static final String FORMAT = "&8(&e%s&8) [&a%s&8] (&b%s&8) &7--> &f%s";
|
||||
|
||||
/**
|
||||
* Creates a new LogEntry builder
|
||||
*
|
||||
* @return a new builder
|
||||
*/
|
||||
@Nonnull
|
||||
public static LogEntryBuilder builder() {
|
||||
return new LogEntryBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* The time when the log event occurred in unix seconds.
|
||||
*/
|
||||
private long timestamp;
|
||||
|
||||
/**
|
||||
* The player who enacted the change
|
||||
*/
|
||||
@Nonnull
|
||||
private UUID actor;
|
||||
|
||||
/**
|
||||
* The name of the player who enacted the change
|
||||
*/
|
||||
@Nonnull
|
||||
private String actorName;
|
||||
private char type;
|
||||
|
||||
/**
|
||||
* The entry type.
|
||||
*/
|
||||
@Nonnull
|
||||
private Type type;
|
||||
|
||||
/**
|
||||
* The user who was acted upon
|
||||
*/
|
||||
@Nullable
|
||||
private UUID acted;
|
||||
|
||||
/**
|
||||
* The name of the object who was acted upon
|
||||
*/
|
||||
@Nonnull
|
||||
private String actedName;
|
||||
|
||||
/**
|
||||
* A description of the action
|
||||
*/
|
||||
@Nonnull
|
||||
private String action;
|
||||
|
||||
public LogEntry(long timestamp, @Nonnull UUID actor, @Nonnull String actorName, char type, @Nullable UUID acted, @Nonnull String actedName, @Nonnull String action) {
|
||||
if (actor == null) {
|
||||
throw new NullPointerException("actor");
|
||||
}
|
||||
if (actorName == null) {
|
||||
throw new NullPointerException("actorName");
|
||||
}
|
||||
if (actedName == null) {
|
||||
throw new NullPointerException("actedName");
|
||||
}
|
||||
if (action == null) {
|
||||
throw new NullPointerException("action");
|
||||
}
|
||||
/**
|
||||
* Creates a new log entry
|
||||
*
|
||||
* @param timestamp the timestamp
|
||||
* @param actor the actor
|
||||
* @param actorName the actorName
|
||||
* @param type the type
|
||||
* @param acted the acted object, or null
|
||||
* @param actedName the acted object name
|
||||
* @param action the action
|
||||
* @since 3.3
|
||||
*/
|
||||
public LogEntry(long timestamp, @Nonnull UUID actor, @Nonnull String actorName, @Nonnull Type type, @Nullable UUID acted, @Nonnull String actedName, @Nonnull String action) {
|
||||
Preconditions.checkNotNull(actor, "actor");
|
||||
Preconditions.checkNotNull(actorName, "actorName");
|
||||
Preconditions.checkNotNull(type, "type");
|
||||
Preconditions.checkNotNull(actedName, "actedName");
|
||||
Preconditions.checkNotNull(action, "action");
|
||||
|
||||
this.timestamp = timestamp;
|
||||
this.actor = actor;
|
||||
@@ -74,35 +144,72 @@ public class LogEntry implements Comparable<LogEntry> {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new log entry
|
||||
*
|
||||
* @param timestamp the timestamp
|
||||
* @param actor the actor
|
||||
* @param actorName the actorName
|
||||
* @param type the type code
|
||||
* @param acted the acted object, or null
|
||||
* @param actedName the acted object name
|
||||
* @param action the action
|
||||
*/
|
||||
public LogEntry(long timestamp, @Nonnull UUID actor, @Nonnull String actorName, char type, @Nullable UUID acted, @Nonnull String actedName, @Nonnull String action) {
|
||||
Preconditions.checkNotNull(actor, "actor");
|
||||
Preconditions.checkNotNull(actorName, "actorName");
|
||||
Preconditions.checkNotNull(actedName, "actedName");
|
||||
Preconditions.checkNotNull(action, "action");
|
||||
|
||||
this.timestamp = timestamp;
|
||||
this.actor = actor;
|
||||
this.actorName = actorName;
|
||||
this.type = Type.valueOf(type);
|
||||
this.acted = acted;
|
||||
this.actedName = actedName;
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new LogEntry and copies the values from another
|
||||
*
|
||||
* @param other the entry to copy values from
|
||||
* @since 3.3
|
||||
*/
|
||||
protected LogEntry(@Nonnull LogEntry other) {
|
||||
this.timestamp = other.timestamp;
|
||||
this.actor = other.actor;
|
||||
this.actorName = other.actorName;
|
||||
this.type = other.type;
|
||||
this.acted = other.acted;
|
||||
this.actedName = other.actedName;
|
||||
this.action = other.action;
|
||||
}
|
||||
|
||||
protected LogEntry() {
|
||||
this.timestamp = 0L;
|
||||
this.actor = null;
|
||||
this.actorName = null;
|
||||
this.type = Character.MIN_VALUE;
|
||||
this.type = null;
|
||||
this.acted = null;
|
||||
this.actedName = null;
|
||||
this.action = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(LogEntry o) {
|
||||
return equals(o) ? 0 : (Long.compare(timestamp, o.getTimestamp()) == 0 ? 1 : Long.compare(timestamp, o.getTimestamp()));
|
||||
public int compareTo(@Nonnull LogEntry other) {
|
||||
Preconditions.checkNotNull(other, "other");
|
||||
return COMPARATOR.compare(this, other);
|
||||
}
|
||||
|
||||
public boolean matchesSearch(@Nonnull String query) {
|
||||
query = query.toLowerCase();
|
||||
return actorName.toLowerCase().contains(query) || actedName.toLowerCase().contains(query)
|
||||
|| action.toLowerCase().contains(query);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getFormatted() {
|
||||
return String.format(FORMAT,
|
||||
String.valueOf(actorName).equals("null") ? actor.toString() : actorName,
|
||||
Character.toString(type),
|
||||
String.valueOf(actedName).equals("null") && acted != null ? acted.toString() : actedName,
|
||||
action
|
||||
);
|
||||
/**
|
||||
* Creates a copy of this log entry
|
||||
*
|
||||
* @return a copy of this log entry
|
||||
* @since 3.3
|
||||
*/
|
||||
public LogEntry copy() {
|
||||
return new LogEntry(this);
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
@@ -115,28 +222,63 @@ public class LogEntry implements Comparable<LogEntry> {
|
||||
|
||||
@Nonnull
|
||||
public UUID getActor() {
|
||||
return actor;
|
||||
return Preconditions.checkNotNull(actor, "actor");
|
||||
}
|
||||
|
||||
void setActor(@Nonnull UUID actor) {
|
||||
this.actor = actor;
|
||||
this.actor = Preconditions.checkNotNull(actor, "actor");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getActorName() {
|
||||
return actorName;
|
||||
return Preconditions.checkNotNull(actorName, "actorName");
|
||||
}
|
||||
|
||||
void setActorName(@Nonnull String actorName) {
|
||||
this.actorName = actorName;
|
||||
this.actorName = Preconditions.checkNotNull(actorName, "actorName");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of this entry
|
||||
*
|
||||
* @return the type of this entry
|
||||
* @since 3.3
|
||||
*/
|
||||
@Nonnull
|
||||
public Type getEntryType() {
|
||||
return Preconditions.checkNotNull(type, "type");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the type of this entry
|
||||
*
|
||||
* @param type the new type
|
||||
* @since 3.3
|
||||
*/
|
||||
public void setEntryType(@Nonnull Type type) {
|
||||
this.type = Preconditions.checkNotNull(type, "type");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the code representing this entry type
|
||||
*
|
||||
* @return the code representing this entry type
|
||||
* @deprecated in favour of {@link #getEntryType()}
|
||||
*/
|
||||
@Deprecated
|
||||
public char getType() {
|
||||
return type;
|
||||
return getEntryType().getCode();
|
||||
}
|
||||
|
||||
void setType(char type) {
|
||||
this.type = type;
|
||||
/**
|
||||
* Sets the type of this entry by code
|
||||
*
|
||||
* @param code the code type
|
||||
* @deprecated in favour of {@link #setEntryType(Type)}
|
||||
*/
|
||||
@Deprecated
|
||||
void setType(char code) {
|
||||
setEntryType(Type.valueOf(code));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -150,20 +292,37 @@ public class LogEntry implements Comparable<LogEntry> {
|
||||
|
||||
@Nonnull
|
||||
public String getActedName() {
|
||||
return actedName;
|
||||
return Preconditions.checkNotNull(actedName, "actedName");
|
||||
}
|
||||
|
||||
void setActedName(@Nonnull String actedName) {
|
||||
this.actedName = actedName;
|
||||
this.actedName = Preconditions.checkNotNull(actedName, "actedName");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getAction() {
|
||||
return action;
|
||||
return Preconditions.checkNotNull(action, "action");
|
||||
}
|
||||
|
||||
void setAction(@Nonnull String action) {
|
||||
this.action = action;
|
||||
this.action = Preconditions.checkNotNull(action, "action");
|
||||
}
|
||||
|
||||
public boolean matchesSearch(@Nonnull String query) {
|
||||
query = Preconditions.checkNotNull(query, "query").toLowerCase();
|
||||
return actorName.toLowerCase().contains(query) ||
|
||||
actedName.toLowerCase().contains(query) ||
|
||||
action.toLowerCase().contains(query);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getFormatted() {
|
||||
return String.format(FORMAT,
|
||||
String.valueOf(actorName).equals("null") ? actor.toString() : actorName,
|
||||
Character.toString(type.getCode()),
|
||||
String.valueOf(actedName).equals("null") && acted != null ? acted.toString() : actedName,
|
||||
action
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -172,11 +331,10 @@ public class LogEntry implements Comparable<LogEntry> {
|
||||
"timestamp=" + this.getTimestamp() + ", " +
|
||||
"actor=" + this.getActor() + ", " +
|
||||
"actorName=" + this.getActorName() + ", " +
|
||||
"type=" + this.getType() + ", " +
|
||||
"type=" + this.getEntryType() + ", " +
|
||||
"acted=" + this.getActed() + ", " +
|
||||
"actedName=" + this.getActedName() + ", " +
|
||||
"action=" + this.getAction() +
|
||||
")";
|
||||
"action=" + this.getAction() + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -184,13 +342,14 @@ public class LogEntry implements Comparable<LogEntry> {
|
||||
if (o == this) return true;
|
||||
if (!(o instanceof LogEntry)) return false;
|
||||
final LogEntry other = (LogEntry) o;
|
||||
|
||||
return this.getTimestamp() == other.getTimestamp() &&
|
||||
(this.getActor() == null ? other.getActor() == null : this.getActor().equals(other.getActor())) &&
|
||||
(this.getActorName() == null ? other.getActorName() == null : this.getActorName().equals(other.getActorName())) &&
|
||||
this.getType() == other.getType() &&
|
||||
this.getActor().equals(other.getActor()) &&
|
||||
this.getActorName().equals(other.getActorName()) &&
|
||||
this.getEntryType() == other.getEntryType() &&
|
||||
(this.getActed() == null ? other.getActed() == null : this.getActed().equals(other.getActed())) &&
|
||||
(this.getActedName() == null ? other.getActedName() == null : this.getActedName().equals(other.getActedName())) &&
|
||||
(this.getAction() == null ? other.getAction() == null : this.getAction().equals(other.getAction()));
|
||||
this.getActedName().equals(other.getActedName()) &&
|
||||
this.getAction().equals(other.getAction());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -198,118 +357,183 @@ public class LogEntry implements Comparable<LogEntry> {
|
||||
final int PRIME = 59;
|
||||
int result = 1;
|
||||
result = result * PRIME + (int) (this.getTimestamp() >>> 32 ^ this.getTimestamp());
|
||||
result = result * PRIME + (this.getActor() == null ? 43 : this.getActor().hashCode());
|
||||
result = result * PRIME + (this.getActorName() == null ? 43 : this.getActorName().hashCode());
|
||||
result = result * PRIME + this.getType();
|
||||
result = result * PRIME + this.getActor().hashCode();
|
||||
result = result * PRIME + this.getActorName().hashCode();
|
||||
result = result * PRIME + this.getEntryType().hashCode();
|
||||
result = result * PRIME + (this.getActed() == null ? 43 : this.getActed().hashCode());
|
||||
result = result * PRIME + (this.getActedName() == null ? 43 : this.getActedName().hashCode());
|
||||
result = result * PRIME + (this.getAction() == null ? 43 : this.getAction().hashCode());
|
||||
result = result * PRIME + this.getActedName().hashCode();
|
||||
result = result * PRIME + this.getAction().hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* The LogEntry type
|
||||
* @since 3.3
|
||||
*/
|
||||
public enum Type {
|
||||
USER('U'),
|
||||
GROUP('G'),
|
||||
TRACK('T');
|
||||
|
||||
private final char code;
|
||||
|
||||
Type(char code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public char getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
public static Type valueOf(char code) {
|
||||
switch (code) {
|
||||
case 'U':
|
||||
case 'u':
|
||||
return USER;
|
||||
case 'G':
|
||||
case 'g':
|
||||
return GROUP;
|
||||
case 'T':
|
||||
case 't':
|
||||
return TRACK;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown code: " + code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds LogEntry instances
|
||||
*/
|
||||
public static class LogEntryBuilder extends AbstractLogEntryBuilder<LogEntry, LogEntry.LogEntryBuilder> {
|
||||
|
||||
@Override
|
||||
protected LogEntry createObj() {
|
||||
protected LogEntry createEmptyLog() {
|
||||
return new LogEntry();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LogEntryBuilder getThis() {
|
||||
protected LogEntryBuilder getThisBuilder() {
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* An abstract log entry builder
|
||||
*
|
||||
* @param <T> the log type
|
||||
* @param <B> the log builder type
|
||||
*/
|
||||
public static abstract class AbstractLogEntryBuilder<T extends LogEntry, B extends AbstractLogEntryBuilder<T, B>> {
|
||||
private T obj;
|
||||
private B thisObj;
|
||||
|
||||
public AbstractLogEntryBuilder() {
|
||||
obj = createObj();
|
||||
thisObj = getThis();
|
||||
obj = createEmptyLog();
|
||||
thisObj = getThisBuilder();
|
||||
}
|
||||
|
||||
protected abstract T createObj();
|
||||
protected abstract T createEmptyLog();
|
||||
|
||||
protected abstract B getThis();
|
||||
protected abstract B getThisBuilder();
|
||||
|
||||
public long getTimestamp() {
|
||||
return obj.getTimestamp();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public UUID getActor() {
|
||||
return obj.getActor();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getActorName() {
|
||||
return obj.getActorName();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Type getEntryType() {
|
||||
return obj.getEntryType();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Deprecated
|
||||
public char getType() {
|
||||
return obj.getType();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public UUID getActed() {
|
||||
return obj.getActed();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getActedName() {
|
||||
return obj.getActedName();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getAction() {
|
||||
return obj.getAction();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public B timestamp(long timestamp) {
|
||||
obj.setTimestamp(timestamp);
|
||||
return thisObj;
|
||||
}
|
||||
|
||||
public B actor(UUID actor) {
|
||||
@Nonnull
|
||||
public B actor(@Nonnull UUID actor) {
|
||||
obj.setActor(actor);
|
||||
return thisObj;
|
||||
}
|
||||
|
||||
public B actorName(String actorName) {
|
||||
@Nonnull
|
||||
public B actorName(@Nonnull String actorName) {
|
||||
obj.setActorName(actorName);
|
||||
return thisObj;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public B entryType(@Nonnull Type type) {
|
||||
obj.setEntryType(type);
|
||||
return thisObj;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Deprecated
|
||||
public B type(char type) {
|
||||
obj.setType(type);
|
||||
return thisObj;
|
||||
}
|
||||
|
||||
public B acted(UUID acted) {
|
||||
@Nonnull
|
||||
public B acted(@Nullable UUID acted) {
|
||||
obj.setActed(acted);
|
||||
return thisObj;
|
||||
}
|
||||
|
||||
public B actedName(String actedName) {
|
||||
@Nonnull
|
||||
public B actedName(@Nonnull String actedName) {
|
||||
obj.setActedName(actedName);
|
||||
return thisObj;
|
||||
}
|
||||
|
||||
public B action(String action) {
|
||||
@Nonnull
|
||||
public B action(@Nonnull String action) {
|
||||
obj.setAction(action);
|
||||
return thisObj;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public T build() {
|
||||
if (getActor() == null) {
|
||||
throw new NullPointerException("actor");
|
||||
}
|
||||
if (getActorName() == null) {
|
||||
throw new NullPointerException("actorName");
|
||||
}
|
||||
if (getActedName() == null) {
|
||||
throw new NullPointerException("actedName");
|
||||
}
|
||||
if (getAction() == null) {
|
||||
throw new NullPointerException("action");
|
||||
}
|
||||
Preconditions.checkNotNull(getActor(), "actor");
|
||||
Preconditions.checkNotNull(getActorName(), "actorName");
|
||||
Preconditions.checkNotNull(getEntryType(), "type");
|
||||
Preconditions.checkNotNull(getActedName(), "actedName");
|
||||
Preconditions.checkNotNull(getAction(), "action");
|
||||
|
||||
return obj;
|
||||
}
|
||||
@@ -320,11 +544,10 @@ public class LogEntry implements Comparable<LogEntry> {
|
||||
"timestamp=" + this.getTimestamp() + ", " +
|
||||
"actor=" + this.getActor() + ", " +
|
||||
"actorName=" + this.getActorName() + ", " +
|
||||
"type=" + this.getType() + ", " +
|
||||
"type=" + this.getEntryType() + ", " +
|
||||
"acted=" + this.getActed() + ", " +
|
||||
"actedName=" + this.getActedName() + ", " +
|
||||
"action=" + this.getAction() +
|
||||
")";
|
||||
"action=" + this.getAction() + ")";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
package me.lucko.luckperms.api;
|
||||
|
||||
import me.lucko.luckperms.LuckPerms;
|
||||
import me.lucko.luckperms.api.context.ContextCalculator;
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
import me.lucko.luckperms.api.event.EventBus;
|
||||
@@ -38,7 +39,13 @@ import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The root API interface for LuckPerms
|
||||
* The LuckPerms API.
|
||||
*
|
||||
* <p>This interface is the base of the entire API package. All API functions
|
||||
* are accessed via this interface.</p>
|
||||
*
|
||||
* <p>An instance can be obtained via {@link LuckPerms#getApi()}, or the platforms
|
||||
* Services Manager.</p>
|
||||
*/
|
||||
public interface LuckPermsApi {
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ import java.util.Set;
|
||||
*/
|
||||
@Deprecated
|
||||
public class MetaUtils {
|
||||
private static final String[] DELIMS = new String[]{".", "/", "-", "$"};
|
||||
|
||||
private static String escapeDelimiters(String s, String... delims) {
|
||||
for (String delim : delims) {
|
||||
@@ -68,7 +69,7 @@ public class MetaUtils {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
return escapeDelimiters(s, ".", "/", "-", "$");
|
||||
return escapeDelimiters(s, DELIMS);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,7 +87,7 @@ public class MetaUtils {
|
||||
s = s.replace("{SEP}", ".");
|
||||
s = s.replace("{FSEP}", "/");
|
||||
s = s.replace("{DSEP}", "$");
|
||||
s = unescapeDelimiters(s, ".", "/", "-", "$");
|
||||
s = unescapeDelimiters(s, DELIMS);
|
||||
|
||||
return s;
|
||||
}
|
||||
@@ -161,7 +162,7 @@ public class MetaUtils {
|
||||
node = escapeCharacters(node);
|
||||
|
||||
for (Node n : holder.getPermissions()) {
|
||||
if (!n.getValue() || !n.isMeta()) continue;
|
||||
if (!n.getValuePrimitive() || !n.isMeta()) continue;
|
||||
|
||||
if (!n.shouldApplyOnServer(server, includeGlobal, false)) continue;
|
||||
if (!n.shouldApplyOnWorld(world, includeGlobal, false)) continue;
|
||||
@@ -233,7 +234,7 @@ public class MetaUtils {
|
||||
int priority = Integer.MIN_VALUE;
|
||||
String meta = null;
|
||||
for (Node n : holder.getAllNodes(Contexts.allowAll())) {
|
||||
if (!n.getValue()) continue;
|
||||
if (!n.getValuePrimitive()) continue;
|
||||
|
||||
if (!n.shouldApplyOnServer(server, includeGlobal, false)) continue;
|
||||
if (!n.shouldApplyOnWorld(world, includeGlobal, false)) continue;
|
||||
|
||||
@@ -37,16 +37,18 @@ import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* An immutable permission node
|
||||
* Represents a permission node.
|
||||
*
|
||||
* <p>Use {@link LuckPermsApi#buildNode(String)} to get an instance.</p>
|
||||
* <p>All implementations of this interface must be immutable.</p>
|
||||
*
|
||||
* <p>Use the {@link NodeFactory} to obtain and construct instances.</p>
|
||||
*
|
||||
* @since 2.6
|
||||
*/
|
||||
public interface Node extends Map.Entry<String, Boolean> {
|
||||
|
||||
/**
|
||||
* Returns the actual permission string
|
||||
* Gets the permission string
|
||||
*
|
||||
* @return the actual permission node
|
||||
*/
|
||||
@@ -54,36 +56,50 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
String getPermission();
|
||||
|
||||
/**
|
||||
* Gets what value the permission is set to. A negated node would return <code>false</code>.
|
||||
* Gets the value.
|
||||
*
|
||||
* <p>A negated node would return a value of <code>false</code>.</p>
|
||||
*
|
||||
* @return the permission's value
|
||||
*/
|
||||
@Override
|
||||
@Nonnull
|
||||
Boolean getValue();
|
||||
default Boolean getValue() {
|
||||
return getValuePrimitive();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this node as a tristate
|
||||
* Gets the value.
|
||||
*
|
||||
* <p>A negated node would return a value of <code>false</code>.</p>
|
||||
*
|
||||
* @return the permission's value
|
||||
*/
|
||||
boolean getValuePrimitive();
|
||||
|
||||
/**
|
||||
* Gets the value of this node as a {@link Tristate}
|
||||
*
|
||||
* @return the value of this node as a Tristate
|
||||
*/
|
||||
@Nonnull
|
||||
default Tristate getTristate() {
|
||||
return Tristate.fromBoolean(getValue());
|
||||
return Tristate.fromBoolean(getValuePrimitive());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the node is negated
|
||||
* Gets if the node is negated
|
||||
*
|
||||
* @return true if the node is negated
|
||||
*/
|
||||
default boolean isNegated() {
|
||||
return !getValue();
|
||||
return !getValuePrimitive();
|
||||
}
|
||||
|
||||
/**
|
||||
* If this node is set to override explicitly.
|
||||
* This value does not persist across saves, and is therefore only useful for transient nodes
|
||||
* Gets if this node is set to override explicitly.
|
||||
*
|
||||
* <p>This value does not persist across saves, and is therefore only useful for transient nodes</p>
|
||||
*
|
||||
* @return true if this node is set to override explicitly
|
||||
*/
|
||||
@@ -106,21 +122,21 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
Optional<String> getWorld();
|
||||
|
||||
/**
|
||||
* Returns if this node is server specific
|
||||
* Gets if this node is server specific
|
||||
*
|
||||
* @return true if this node is server specific
|
||||
*/
|
||||
boolean isServerSpecific();
|
||||
|
||||
/**
|
||||
* Returns if this node is server specific
|
||||
* Gets if this node is server specific
|
||||
*
|
||||
* @return true if this node is server specific
|
||||
*/
|
||||
boolean isWorldSpecific();
|
||||
|
||||
/**
|
||||
* Returns if this node applies globally, and has no specific context
|
||||
* Gets if this node applies globally, and therefore has no specific context
|
||||
*
|
||||
* @return true if this node applies globally, and has no specific context
|
||||
* @since 3.1
|
||||
@@ -128,7 +144,7 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
boolean appliesGlobally();
|
||||
|
||||
/**
|
||||
* Returns if this node has any specific context in order to apply.
|
||||
* Gets if this node has any specific context in order for it to apply
|
||||
*
|
||||
* @return true if this node has specific context
|
||||
* @since 3.1
|
||||
@@ -136,7 +152,7 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
boolean hasSpecificContext();
|
||||
|
||||
/**
|
||||
* Returns if this node is able to apply in the given context
|
||||
* Gets if this node is able to apply in the given context
|
||||
*
|
||||
* @param includeGlobal if global server values should apply
|
||||
* @param includeGlobalWorld if global world values should apply
|
||||
@@ -150,7 +166,7 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
boolean shouldApply(boolean includeGlobal, boolean includeGlobalWorld, @Nullable String server, @Nullable String world, @Nullable ContextSet context, boolean applyRegex);
|
||||
|
||||
/**
|
||||
* If this node should apply on a specific server
|
||||
* Gets if this node should apply on a specific server
|
||||
*
|
||||
* @param server the name of the server
|
||||
* @param includeGlobal if global permissions should apply
|
||||
@@ -160,7 +176,7 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
boolean shouldApplyOnServer(@Nullable String server, boolean includeGlobal, boolean applyRegex);
|
||||
|
||||
/**
|
||||
* If this node should apply on a specific world
|
||||
* Gets if this node should apply on a specific world
|
||||
*
|
||||
* @param world the name of the world
|
||||
* @param includeGlobal if global permissions should apply
|
||||
@@ -170,7 +186,7 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
boolean shouldApplyOnWorld(@Nullable String world, boolean includeGlobal, boolean applyRegex);
|
||||
|
||||
/**
|
||||
* If this node should apply in the given context
|
||||
* Gets if this node should apply in the given context
|
||||
*
|
||||
* @param context the context key value pairs
|
||||
* @param worldAndServer if world and server contexts should be checked
|
||||
@@ -180,7 +196,7 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
boolean shouldApplyWithContext(@Nonnull ContextSet context, boolean worldAndServer);
|
||||
|
||||
/**
|
||||
* If this node should apply in the given context
|
||||
* Gets if this node should apply in the given context
|
||||
*
|
||||
* @param context the context key value pairs
|
||||
* @return true if the node should apply
|
||||
@@ -211,8 +227,10 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
*
|
||||
* @param possibleNodes a list of possible permission nodes
|
||||
* @return a list of permissions that match this wildcard
|
||||
* @deprecated as this is no longer used internally to resolve wildcards
|
||||
*/
|
||||
@Nonnull
|
||||
@Deprecated
|
||||
List<String> resolveWildcard(@Nonnull List<String> possibleNodes);
|
||||
|
||||
/**
|
||||
@@ -224,14 +242,14 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
List<String> resolveShorthand();
|
||||
|
||||
/**
|
||||
* Returns if this node will expire in the future
|
||||
* Gets if this node will expire in the future
|
||||
*
|
||||
* @return true if this node will expire in the future
|
||||
*/
|
||||
boolean isTemporary();
|
||||
|
||||
/**
|
||||
* Returns if this node will not expire
|
||||
* Gets if this node will not expire
|
||||
*
|
||||
* @return true if this node will not expire
|
||||
*/
|
||||
@@ -240,7 +258,7 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unix timestamp in seconds when this node will expire
|
||||
* Gets a unix timestamp in seconds when this node will expire
|
||||
*
|
||||
* @return the time in Unix time when this node will expire
|
||||
* @throws IllegalStateException if the node is not temporary
|
||||
@@ -248,7 +266,7 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
long getExpiryUnixTime() throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Returns the date when this node will expire
|
||||
* Gets the date when this node will expire
|
||||
*
|
||||
* @return the {@link Date} when this node will expire
|
||||
* @throws IllegalStateException if the node is not temporary
|
||||
@@ -257,7 +275,7 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
Date getExpiry() throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Return the number of seconds until this permission will expire
|
||||
* Gets the number of seconds until this permission will expire
|
||||
*
|
||||
* @return the number of seconds until this permission will expire
|
||||
* @throws IllegalStateException if the node is not temporary
|
||||
@@ -265,8 +283,9 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
long getSecondsTilExpiry() throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Return true if the node has expired.
|
||||
* This also returns false if the node is not temporary
|
||||
* Gets if the node has expired.
|
||||
*
|
||||
* <p>This also returns false if the node is not temporary.</p>
|
||||
*
|
||||
* @return true if this node has expired
|
||||
*/
|
||||
@@ -301,14 +320,14 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
String toSerializedNode();
|
||||
|
||||
/**
|
||||
* Returns if this is a group node
|
||||
* Gets if this is a group node
|
||||
*
|
||||
* @return true if this is a group node
|
||||
*/
|
||||
boolean isGroupNode();
|
||||
|
||||
/**
|
||||
* Returns the name of the group
|
||||
* Gets the name of the group, if this is a group node.
|
||||
*
|
||||
* @return the name of the group
|
||||
* @throws IllegalStateException if this is not a group node. See {@link #isGroupNode()}
|
||||
@@ -317,7 +336,7 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
String getGroupName() throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Returns if this node is a wildcard node
|
||||
* Gets if this node is a wildcard node
|
||||
*
|
||||
* @return true if this node is a wildcard node
|
||||
*/
|
||||
@@ -332,7 +351,7 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
int getWildcardLevel() throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Returns if this node is a meta node
|
||||
* Gets if this node is a meta node
|
||||
*
|
||||
* @return true if this node is a meta node
|
||||
*/
|
||||
@@ -348,7 +367,7 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
Map.Entry<String, String> getMeta() throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Returns if this node is a prefix node
|
||||
* Gets if this node is a prefix node
|
||||
*
|
||||
* @return true if this node is a prefix node
|
||||
*/
|
||||
@@ -364,7 +383,7 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
Map.Entry<Integer, String> getPrefix() throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Returns if this node is a suffix node
|
||||
* Gets if this node is a suffix node
|
||||
*
|
||||
* @return true if this node is a suffix node
|
||||
*/
|
||||
|
||||
@@ -28,27 +28,12 @@ package me.lucko.luckperms.api;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Builds {@link Node} instances
|
||||
* Assists with constructing {@link Node} instances.
|
||||
*
|
||||
* @since 2.17
|
||||
*/
|
||||
public interface NodeFactory {
|
||||
|
||||
/**
|
||||
* Creates a node from a serialised node string
|
||||
*
|
||||
* @param serialisedPermission the serialised permission string
|
||||
* @param value the value of the node
|
||||
* @return a node instance
|
||||
* @throws NullPointerException if the permission is null
|
||||
* @deprecated since this format isn't used internally for permissions anymore
|
||||
* @see Node#toSerializedNode()
|
||||
*/
|
||||
@Deprecated
|
||||
@Nonnull
|
||||
Node fromSerialisedNode(@Nonnull String serialisedPermission, boolean value);
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new node builder from a given base permission string
|
||||
*
|
||||
@@ -69,20 +54,6 @@ public interface NodeFactory {
|
||||
@Nonnull
|
||||
Node.Builder newBuilderFromExisting(@Nonnull Node other);
|
||||
|
||||
/**
|
||||
* Creates a node builder from a serialised node string
|
||||
*
|
||||
* @param serialisedPermission the serialised permission string
|
||||
* @param value the value of the node
|
||||
* @return a node builder instance
|
||||
* @throws NullPointerException if the permission is null
|
||||
* @deprecated since this format isn't used internally for permissions anymore
|
||||
* @see Node#toSerializedNode()
|
||||
*/
|
||||
@Deprecated
|
||||
@Nonnull
|
||||
Node.Builder newBuilderFromSerialisedNode(@Nonnull String serialisedPermission, boolean value);
|
||||
|
||||
|
||||
/**
|
||||
* Creates a node builder from a group
|
||||
@@ -141,4 +112,35 @@ public interface NodeFactory {
|
||||
@Nonnull
|
||||
Node.Builder makeSuffixNode(int priority, @Nonnull String suffix);
|
||||
|
||||
|
||||
/**
|
||||
* Creates a node from a serialised node string
|
||||
*
|
||||
* <p>This format is what was previously used in YAML/JSON storage files.</p>
|
||||
*
|
||||
* @param serialisedPermission the serialised permission string
|
||||
* @param value the value of the node
|
||||
* @return a node instance
|
||||
* @throws NullPointerException if the permission is null
|
||||
* @deprecated since this format isn't used internally for permissions anymore
|
||||
* @see Node#toSerializedNode()
|
||||
*/
|
||||
@Deprecated
|
||||
@Nonnull
|
||||
Node fromSerialisedNode(@Nonnull String serialisedPermission, boolean value);
|
||||
|
||||
/**
|
||||
* Creates a node builder from a serialised node string
|
||||
*
|
||||
* @param serialisedPermission the serialised permission string
|
||||
* @param value the value of the node
|
||||
* @return a node builder instance
|
||||
* @throws NullPointerException if the permission is null
|
||||
* @deprecated since this format isn't used internally for permissions anymore
|
||||
* @see Node#toSerializedNode()
|
||||
*/
|
||||
@Deprecated
|
||||
@Nonnull
|
||||
Node.Builder newBuilderFromSerialisedNode(@Nonnull String serialisedPermission, boolean value);
|
||||
|
||||
}
|
||||
@@ -43,14 +43,15 @@ import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* An object capable of holding permissions
|
||||
* An object which holds permissions.
|
||||
*
|
||||
* <p>Any changes made will be lost unless the instance is saved back to the {@link Storage}.</p>
|
||||
* <p>Any changes made to permission holding objects will be lost unless the
|
||||
* instance is saved back to the {@link Storage}.</p>
|
||||
*/
|
||||
public interface PermissionHolder {
|
||||
|
||||
/**
|
||||
* Gets the objects name
|
||||
* Gets the objects name.
|
||||
*
|
||||
* <p>{@link User#getUuid()}, {@link User#getName()} or {@link Group#getName()} should normally be used instead of
|
||||
* this method.</p>
|
||||
@@ -123,7 +124,7 @@ public interface PermissionHolder {
|
||||
SortedSet<? extends Node> getPermissions();
|
||||
|
||||
/**
|
||||
* Similar to {@link #getPermissions()}, except without transient permissions
|
||||
* Similar to {@link #getPermissions()}, except without transient permissions.
|
||||
*
|
||||
* <p>Unlike transient permissions, enduring permissions will be saved to storage, and exist after the session.</p>
|
||||
*
|
||||
@@ -134,7 +135,7 @@ public interface PermissionHolder {
|
||||
Set<? extends Node> getEnduringPermissions();
|
||||
|
||||
/**
|
||||
* Similar to {@link #getPermissions()}, except without enduring permissions
|
||||
* Similar to {@link #getPermissions()}, except without enduring permissions.
|
||||
*
|
||||
* <p>Transient permissions only exist for the duration of the session.</p>
|
||||
*
|
||||
|
||||
@@ -28,7 +28,7 @@ package me.lucko.luckperms.api;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* The platforms which LuckPerms can run on
|
||||
* Represents a type of platform which LuckPerms can run on.
|
||||
*
|
||||
* @since 2.7
|
||||
*/
|
||||
@@ -44,6 +44,11 @@ public enum PlatformType {
|
||||
this.friendlyName = friendlyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a readable name for the platform type.
|
||||
*
|
||||
* @return a readable name
|
||||
*/
|
||||
@Nonnull
|
||||
public String getFriendlyName() {
|
||||
return friendlyName;
|
||||
|
||||
@@ -36,14 +36,14 @@ import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* A means of loading and saving data to/from the Storage provider.
|
||||
* A means of loading and saving permission data to/from the backend.
|
||||
*
|
||||
* <p>All methods return {@link CompletableFuture}s, which will be populated with the result once the data has been
|
||||
* loaded asynchronously. Care should be taken when using the methods to ensure that the main server thread is not
|
||||
* <p>All blocking methods return {@link CompletableFuture}s, which will be populated with the result once the data has been
|
||||
* loaded/saved asynchronously. Care should be taken when using such methods to ensure that the main server thread is not
|
||||
* blocked.</p>
|
||||
*
|
||||
* <p>Methods such as {@link CompletableFuture#get()} and equivalent should <strong>not</strong> be called on the main
|
||||
* server thread. If you need to use the result of these operations on the main server thread, please register a
|
||||
* server thread. If you need to use the result of these operations on the main server thread, register a
|
||||
* callback using {@link CompletableFuture#thenAcceptAsync(Consumer, Executor)} and {@link #getSyncExecutor()}.</p>
|
||||
*
|
||||
* @since 2.14
|
||||
@@ -59,7 +59,7 @@ public interface Storage {
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Return whether the storage instance is allowing logins on the platform.
|
||||
* Gets whether the storage instance is allowing logins on the platform.
|
||||
*
|
||||
* @return true if logins are enabled
|
||||
*/
|
||||
@@ -144,7 +144,8 @@ public interface Storage {
|
||||
|
||||
/**
|
||||
* Gets a set all "unique" user UUIDs.
|
||||
* "Unique" meaning the user isn't just a member of the "default" group.
|
||||
*
|
||||
* <p>"Unique" meaning the user isn't just a member of the "default" group.</p>
|
||||
*
|
||||
* @return a set of uuids, or null if the operation failed.
|
||||
*/
|
||||
|
||||
@@ -34,21 +34,24 @@ import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* An ordered collection of groups for easy promotions and demotions
|
||||
* An ordered chain of {@link Group}s.
|
||||
*/
|
||||
public interface Track {
|
||||
|
||||
/**
|
||||
* Gets the name of this track
|
||||
*
|
||||
* @return the name of this track
|
||||
*/
|
||||
@Nonnull
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Gets an ordered list of the groups on this track
|
||||
* Gets a list of the groups on this track
|
||||
*
|
||||
* <p>Index 0 is the first/lowest group in (or start of) the track</p>
|
||||
* <p>Index 0 is the first/lowest group in (or start of) the track.</p>
|
||||
*
|
||||
* <p>The returned collection is immutable, and cannot be modified.</p>
|
||||
*
|
||||
* @return an ordered {@link List} of the groups on this track
|
||||
*/
|
||||
|
||||
@@ -28,37 +28,42 @@ package me.lucko.luckperms.api;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Represents a permission setting.
|
||||
* Represents three different states of a setting.
|
||||
*
|
||||
* <p>Consider a value of {@link #TRUE} to be a positive setting, {@link #FALSE} to be a "negated" setting,
|
||||
* and a value of {@link #UNDEFINED} to be a non-existent value.</p>
|
||||
* <p>Possible values:</p>
|
||||
* <p></p>
|
||||
* <ul>
|
||||
* <li>{@link #TRUE} - a positive setting</li>
|
||||
* <li>{@link #FALSE} - a negative (negated) setting</li>
|
||||
* <li>{@link #UNDEFINED} - a non-existent setting</li>
|
||||
* </ul>
|
||||
*/
|
||||
public enum Tristate {
|
||||
|
||||
/**
|
||||
* A value indicating a holder has a permission set.
|
||||
* A value indicating a positive setting
|
||||
*/
|
||||
TRUE(true),
|
||||
|
||||
/**
|
||||
* A value indicating a holder has a negated value for a permission.
|
||||
* A value indicating a negative (negated) setting
|
||||
*/
|
||||
FALSE(false),
|
||||
|
||||
/**
|
||||
* A value indicating a holder doesn't have a value for a permission set.
|
||||
* A value indicating a non-existent setting
|
||||
*/
|
||||
UNDEFINED(false);
|
||||
|
||||
/**
|
||||
* Converts from {@link Boolean} a boolean
|
||||
* Returns a {@link Tristate} from a boolean
|
||||
*
|
||||
* @param b the boolean
|
||||
* @param val the boolean value
|
||||
* @return {@link #TRUE} or {@link #FALSE}, depending on the value of the boolean.
|
||||
*/
|
||||
@Nonnull
|
||||
public static Tristate fromBoolean(boolean b) {
|
||||
return b ? TRUE : FALSE;
|
||||
public static Tristate fromBoolean(boolean val) {
|
||||
return val ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
private final boolean booleanValue;
|
||||
|
||||
@@ -38,7 +38,7 @@ import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* A player holding permission data
|
||||
* A player which holds permission data.
|
||||
*/
|
||||
public interface User extends PermissionHolder {
|
||||
|
||||
@@ -51,7 +51,9 @@ public interface User extends PermissionHolder {
|
||||
UUID getUuid();
|
||||
|
||||
/**
|
||||
* Gets the users username, or null if no username is associated with this user
|
||||
* Gets the users username
|
||||
*
|
||||
* <p>Returns null if no username is associated with this user.</p>
|
||||
*
|
||||
* @return the users username
|
||||
*/
|
||||
@@ -96,6 +98,16 @@ public interface User extends PermissionHolder {
|
||||
@Nonnull
|
||||
UserData getCachedData();
|
||||
|
||||
/**
|
||||
* Pre-calculates some values in the user's data cache.
|
||||
*
|
||||
* <p>Is it <b>not</b> necessary to call this method before
|
||||
* using {@link #getCachedData()}.</p>
|
||||
*
|
||||
* @since 2.17
|
||||
*/
|
||||
void setupDataCache();
|
||||
|
||||
/**
|
||||
* Check to see if the user is a direct member of a group
|
||||
*
|
||||
@@ -128,16 +140,6 @@ public interface User extends PermissionHolder {
|
||||
@Nonnull
|
||||
Optional<UserData> getUserDataCache();
|
||||
|
||||
/**
|
||||
* Pre-calculates some values in the user's data cache.
|
||||
*
|
||||
* <p>Is it <b>not</b> necessary to call this method before
|
||||
* using {@link #getCachedData()}.</p>
|
||||
*
|
||||
* @since 2.17
|
||||
*/
|
||||
void setupDataCache();
|
||||
|
||||
/**
|
||||
* Check to see if a user is a member of a group on a specific server
|
||||
*
|
||||
|
||||
@@ -32,34 +32,34 @@ import javax.annotation.Nonnull;
|
||||
/**
|
||||
* A UUID cache for online users, between external Mojang UUIDs, and internal LuckPerms UUIDs.
|
||||
*
|
||||
* <p>This UuidCache is a means of allowing users to have the same internal UUID across a network of offline mode
|
||||
* servers or mixed offline mode and online mode servers. Platforms running in offline mode generate a UUID for a
|
||||
* user when they first join the server, but this UUID will then not be consistent across the network. LuckPerms will
|
||||
* instead check the datastore cache, to get a UUID for a user that is consistent across an entire network.</p>
|
||||
* <p>A user's internal LuckPerms UUID is always the same as their Mojang one,
|
||||
* unless <code>use-server-uuids</code> is disabled.</p>
|
||||
*
|
||||
* <p>If you want to get a user object from the Storage using the api on a server in offline mode, you will need to use
|
||||
* this cache, OR use Storage#getUUID, for users that are not online.</p>
|
||||
* <p>When this setting is disabled, this cache becomes active, and allows you to convert
|
||||
* between 'internal' and 'server provided' uuids.</p>
|
||||
*
|
||||
* <p><strong>This is only effective for online players. Use {@link Storage#getUUID(String)} for offline players.</strong></p>
|
||||
*/
|
||||
public interface UuidCache {
|
||||
|
||||
/**
|
||||
* Gets a users internal "LuckPerms" UUID, from the one given by the server.
|
||||
* Gets a users "internal" LuckPerms UUID, from the one given by the server.
|
||||
*
|
||||
* @param external the UUID assigned by the server, through Player#getUniqueId or ProxiedPlayer#getUniqueId
|
||||
* <p>When <code>use-server-uuids</code> is true, this returns the same UUID instance.</p>
|
||||
*
|
||||
* @param mojangUuid the UUID assigned by the server, through <code>Player#getUniqueId</code> or <code>ProxiedPlayer#getUniqueId</code>
|
||||
* @return the corresponding internal UUID
|
||||
*/
|
||||
@Nonnull
|
||||
UUID getUUID(@Nonnull UUID external);
|
||||
UUID getUUID(@Nonnull UUID mojangUuid);
|
||||
|
||||
/**
|
||||
* Gets a users external, server assigned or Mojang assigned unique id, from the internal one used within LuckPerms.
|
||||
* Gets a users "external", server assigned unique id, from the internal one used within LuckPerms.
|
||||
*
|
||||
* @param internal the UUID used within LuckPerms, through User#getUuid
|
||||
* @param internalUuid the UUID used within LuckPerms, through <code>User#getUuid</code>
|
||||
* @return the corresponding external UUID
|
||||
*/
|
||||
@Nonnull
|
||||
UUID getExternalUUID(@Nonnull UUID internal);
|
||||
UUID getExternalUUID(@Nonnull UUID internalUuid);
|
||||
|
||||
}
|
||||
@@ -33,8 +33,10 @@ import me.lucko.luckperms.api.metastacking.MetaStackDefinition;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Represents the context for a meta lookup, consisting of a standard {@link Contexts} element, plus options to define how
|
||||
* the meta stack should be constructed.
|
||||
* Represents the context for a meta lookup.
|
||||
*
|
||||
* <p>Consisting of a standard {@link Contexts} element, plus options to define how
|
||||
* the meta stack should be constructed.</p>
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
|
||||
@@ -35,7 +35,13 @@ import java.util.Set;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Holder of contexts.
|
||||
* A set of context pairs.
|
||||
*
|
||||
* <p>You can think of ContextSets as a wrapped <code>Multimap<String, String></code>.
|
||||
* Each key can be mapped to multiple values.</p>
|
||||
*
|
||||
* <p>Keys are automatically converted to lowercase when added, and are therefore
|
||||
* case-insensitive. Values however are not.</p>
|
||||
*
|
||||
* <p>Implementations may be either mutable or immutable.</p>
|
||||
*
|
||||
@@ -72,18 +78,6 @@ public interface ContextSet {
|
||||
return ImmutableContextSet.of(key1, value1, key2, value2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ImmutableContextSet from an existing map
|
||||
*
|
||||
* @param map the map to copy from
|
||||
* @return a new ImmutableContextSet representing the pairs from the map
|
||||
* @throws NullPointerException if the map is null
|
||||
*/
|
||||
@Nonnull
|
||||
static ImmutableContextSet fromMap(@Nonnull Map<String, String> map) {
|
||||
return ImmutableContextSet.fromMap(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ImmutableContextSet from an existing iterable of Map Entries
|
||||
*
|
||||
@@ -96,6 +90,18 @@ public interface ContextSet {
|
||||
return ImmutableContextSet.fromEntries(iterable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ImmutableContextSet from an existing map
|
||||
*
|
||||
* @param map the map to copy from
|
||||
* @return a new ImmutableContextSet representing the pairs from the map
|
||||
* @throws NullPointerException if the map is null
|
||||
*/
|
||||
@Nonnull
|
||||
static ImmutableContextSet fromMap(@Nonnull Map<String, String> map) {
|
||||
return ImmutableContextSet.fromMap(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ImmutableContextSet from an existing multimap
|
||||
*
|
||||
@@ -133,7 +139,7 @@ public interface ContextSet {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if this set is in an immutable form
|
||||
* Gets if this set is in an immutable form
|
||||
*
|
||||
* @return true if the set is immutable
|
||||
*/
|
||||
@@ -167,12 +173,14 @@ public interface ContextSet {
|
||||
/**
|
||||
* Converts this ContextSet to an immutable {@link Map}
|
||||
*
|
||||
* <b>NOTE: Use of this method may result in data being lost. ContextSets can contain lots of different values for
|
||||
* <b>IMPORTANT: Use of this method may result in data being lost. ContextSets can contain lots of different values for
|
||||
* one key.</b>
|
||||
*
|
||||
* @return an immutable map
|
||||
* @deprecated because the resultant map may not contain all data in the ContextSet
|
||||
*/
|
||||
@Nonnull
|
||||
@Deprecated
|
||||
Map<String, String> toMap();
|
||||
|
||||
/**
|
||||
@@ -225,6 +233,19 @@ public interface ContextSet {
|
||||
*/
|
||||
boolean has(@Nonnull String key, @Nonnull String value);
|
||||
|
||||
/**
|
||||
* Check if thr set contains a given key mapped to a given value
|
||||
*
|
||||
* @param entry the entry to look for
|
||||
* @return true if the set contains the KV pair
|
||||
* @throws NullPointerException if the key or value is null
|
||||
* @since 3.4
|
||||
*/
|
||||
default boolean has(@Nonnull Map.Entry<String, String> entry) {
|
||||
Preconditions.checkNotNull(entry, "entry");
|
||||
return has(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #has(String, String)}, except ignores the case of the value.
|
||||
*
|
||||
@@ -235,6 +256,19 @@ public interface ContextSet {
|
||||
*/
|
||||
boolean hasIgnoreCase(@Nonnull String key, @Nonnull String value);
|
||||
|
||||
/**
|
||||
* Same as {@link #has(Map.Entry)}, except ignores the case of the value.
|
||||
*
|
||||
* @param entry the entry to look for
|
||||
* @return true if the set contains the KV pair
|
||||
* @throws NullPointerException if the key or value is null
|
||||
* @since 3.4
|
||||
*/
|
||||
default boolean hasIgnoreCase(@Nonnull Map.Entry<String, String> entry) {
|
||||
Preconditions.checkNotNull(entry, "entry");
|
||||
return hasIgnoreCase(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if all entries in this context set are also included in another set.
|
||||
*
|
||||
@@ -243,6 +277,18 @@ public interface ContextSet {
|
||||
* @since 3.1
|
||||
*/
|
||||
default boolean isSatisfiedBy(@Nonnull ContextSet other) {
|
||||
return isSatisfiedBy(other, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if all entries in this context set are also included in another set.
|
||||
*
|
||||
* @param other the other set to check
|
||||
* @param caseSensitive if the lookup should be case sensitive. see {@link #has(Map.Entry)} and {@link #hasIgnoreCase(Map.Entry)}.
|
||||
* @return true if all entries in this set are also in the other set
|
||||
* @since 3.4
|
||||
*/
|
||||
default boolean isSatisfiedBy(@Nonnull ContextSet other, boolean caseSensitive) {
|
||||
Preconditions.checkNotNull(other, "other");
|
||||
if (this.isEmpty()) {
|
||||
// this is empty, so is therefore always satisfied.
|
||||
@@ -256,8 +302,14 @@ public interface ContextSet {
|
||||
} else {
|
||||
// neither are empty, we need to compare the individual entries
|
||||
for (Map.Entry<String, String> pair : toSet()) {
|
||||
if (!other.has(pair.getKey(), pair.getValue())) {
|
||||
return false;
|
||||
if (caseSensitive) {
|
||||
if (!other.has(pair)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!other.hasIgnoreCase(pair)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,12 +25,10 @@
|
||||
|
||||
package me.lucko.luckperms.api.context;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSetMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.SetMultimap;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
@@ -38,9 +36,14 @@ import java.util.Set;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* An immutable implementation of {@link ContextSet}.
|
||||
*
|
||||
* <p>On construction, all keys/values are {@link String#intern()}ed, in order to increase
|
||||
* comparison speed.</p>
|
||||
*
|
||||
* @since 2.16
|
||||
*/
|
||||
public final class ImmutableContextSet implements ContextSet {
|
||||
@@ -56,9 +59,10 @@ public final class ImmutableContextSet implements ContextSet {
|
||||
*/
|
||||
@Nonnull
|
||||
public static ImmutableContextSet singleton(@Nonnull String key, @Nonnull String value) {
|
||||
Preconditions.checkNotNull(key, "key");
|
||||
Preconditions.checkNotNull(value, "value");
|
||||
return new ImmutableContextSet(ImmutableSetMultimap.of(key.toLowerCase(), value));
|
||||
return new ImmutableContextSet(ImmutableSetMultimap.of(
|
||||
checkNotNull(key, "key").toLowerCase().intern(),
|
||||
checkNotNull(value, "value").intern()
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,30 +78,12 @@ public final class ImmutableContextSet implements ContextSet {
|
||||
*/
|
||||
@Nonnull
|
||||
public static ImmutableContextSet of(@Nonnull String key1, @Nonnull String value1, @Nonnull String key2, @Nonnull String value2) {
|
||||
Preconditions.checkNotNull(key1, "key1");
|
||||
Preconditions.checkNotNull(value1, "value1");
|
||||
Preconditions.checkNotNull(key2, "key2");
|
||||
Preconditions.checkNotNull(value2, "value2");
|
||||
return new ImmutableContextSet(ImmutableSetMultimap.of(key1.toLowerCase(), value1, key2.toLowerCase(), value2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ImmutableContextSet from an existing map
|
||||
*
|
||||
* @param map the map to copy from
|
||||
* @return a new ImmutableContextSet representing the pairs from the map
|
||||
* @throws NullPointerException if the map is null
|
||||
*/
|
||||
@Nonnull
|
||||
public static ImmutableContextSet fromMap(@Nonnull Map<String, String> map) {
|
||||
Preconditions.checkNotNull(map, "map");
|
||||
|
||||
ImmutableSetMultimap.Builder<String, String> b = ImmutableSetMultimap.builder();
|
||||
for (Map.Entry<String, String> e : map.entrySet()) {
|
||||
b.put(e.getKey().toLowerCase(), e.getValue());
|
||||
}
|
||||
|
||||
return new ImmutableContextSet(b.build());
|
||||
return new ImmutableContextSet(ImmutableSetMultimap.of(
|
||||
checkNotNull(key1, "key1").toLowerCase().intern(),
|
||||
checkNotNull(value1, "value1").intern(),
|
||||
checkNotNull(key2, "key2").toLowerCase().intern(),
|
||||
checkNotNull(value2, "value2").intern()
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,8 +95,26 @@ public final class ImmutableContextSet implements ContextSet {
|
||||
*/
|
||||
@Nonnull
|
||||
public static ImmutableContextSet fromEntries(@Nonnull Iterable<? extends Map.Entry<String, String>> iterable) {
|
||||
Preconditions.checkNotNull(iterable, "iterable");
|
||||
return MutableContextSet.fromEntries(iterable).makeImmutable();
|
||||
checkNotNull(iterable, "iterable");
|
||||
|
||||
ImmutableSetMultimap.Builder<String, String> b = ImmutableSetMultimap.builder();
|
||||
for (Map.Entry<String, String> e : iterable) {
|
||||
b.put(checkNotNull(e.getKey()).toLowerCase().intern(), checkNotNull(e.getValue()).intern());
|
||||
}
|
||||
|
||||
return new ImmutableContextSet(b.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ImmutableContextSet from an existing map
|
||||
*
|
||||
* @param map the map to copy from
|
||||
* @return a new ImmutableContextSet representing the pairs from the map
|
||||
* @throws NullPointerException if the map is null
|
||||
*/
|
||||
@Nonnull
|
||||
public static ImmutableContextSet fromMap(@Nonnull Map<String, String> map) {
|
||||
return fromEntries(checkNotNull(map, "map").entrySet());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,8 +126,7 @@ public final class ImmutableContextSet implements ContextSet {
|
||||
*/
|
||||
@Nonnull
|
||||
public static ImmutableContextSet fromMultimap(@Nonnull Multimap<String, String> multimap) {
|
||||
Preconditions.checkNotNull(multimap, "multimap");
|
||||
return MutableContextSet.fromMultimap(multimap).makeImmutable();
|
||||
return fromEntries(checkNotNull(multimap, "multimap").entries());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,7 +139,7 @@ public final class ImmutableContextSet implements ContextSet {
|
||||
*/
|
||||
@Nonnull
|
||||
public static ImmutableContextSet fromSet(@Nonnull ContextSet contextSet) {
|
||||
return Preconditions.checkNotNull(contextSet, "contextSet").makeImmutable();
|
||||
return checkNotNull(contextSet, "contextSet").makeImmutable();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -149,10 +152,10 @@ public final class ImmutableContextSet implements ContextSet {
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
private final SetMultimap<String, String> map;
|
||||
private final ImmutableSetMultimap<String, String> map;
|
||||
|
||||
ImmutableContextSet(Multimap<String, String> contexts) {
|
||||
this.map = ImmutableSetMultimap.copyOf(contexts);
|
||||
ImmutableContextSet(ImmutableSetMultimap<String, String> contexts) {
|
||||
this.map = contexts;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -176,7 +179,7 @@ public final class ImmutableContextSet implements ContextSet {
|
||||
@Override
|
||||
@Nonnull
|
||||
public Set<Map.Entry<String, String>> toSet() {
|
||||
return ImmutableSet.copyOf(map.entries());
|
||||
return map.entries();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -197,36 +200,35 @@ public final class ImmutableContextSet implements ContextSet {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public boolean containsKey(@Nonnull String key) {
|
||||
Preconditions.checkNotNull(key, "key");
|
||||
return map.containsKey(key);
|
||||
return map.containsKey(checkNotNull(key, "key").toLowerCase().intern());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public Set<String> getValues(@Nonnull String key) {
|
||||
Preconditions.checkNotNull(key, "key");
|
||||
Collection<String> c = map.get(key);
|
||||
return c != null && !c.isEmpty() ? ImmutableSet.copyOf(c) : ImmutableSet.of();
|
||||
Collection<String> values = map.get(checkNotNull(key, "key").toLowerCase().intern());
|
||||
return values != null ? ImmutableSet.copyOf(values) : ImmutableSet.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public boolean has(@Nonnull String key, @Nonnull String value) {
|
||||
Preconditions.checkNotNull(key, "key");
|
||||
Preconditions.checkNotNull(value, "value");
|
||||
return map.containsEntry(key, value);
|
||||
return map.containsEntry(checkNotNull(key, "key").toLowerCase().intern(), checkNotNull(value, "value").intern());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public boolean hasIgnoreCase(@Nonnull String key, @Nonnull String value) {
|
||||
Preconditions.checkNotNull(key, "key");
|
||||
Preconditions.checkNotNull(value, "value");
|
||||
value = checkNotNull(value, "value").intern();
|
||||
Collection<String> values = map.get(checkNotNull(key, "key").toLowerCase().intern());
|
||||
|
||||
Collection<String> c = map.get(key);
|
||||
if (c == null || c.isEmpty()) {
|
||||
if (values == null || values.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (String val : c) {
|
||||
for (String val : values) {
|
||||
if (val.equalsIgnoreCase(value)) {
|
||||
return true;
|
||||
}
|
||||
@@ -250,6 +252,11 @@ public final class ImmutableContextSet implements ContextSet {
|
||||
if (!(o instanceof ContextSet)) return false;
|
||||
final ContextSet other = (ContextSet) o;
|
||||
|
||||
// saves on copying the multimap
|
||||
if (other instanceof MutableContextSet) {
|
||||
return other.equals(this);
|
||||
}
|
||||
|
||||
final Multimap<String, String> thisContexts = this.toMultimap();
|
||||
final Multimap<String, String> otherContexts = other.toMultimap();
|
||||
return thisContexts.equals(otherContexts);
|
||||
@@ -257,7 +264,7 @@ public final class ImmutableContextSet implements ContextSet {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 59 + (this.map == null ? 43 : this.map.hashCode());
|
||||
return map.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -40,9 +40,14 @@ import java.util.Set;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* A mutable implementation of {@link ContextSet}.
|
||||
*
|
||||
* <p>On construction, all keys/values are {@link String#intern()}ed, in order to increase
|
||||
* comparison speed.</p>
|
||||
*
|
||||
* @since 2.16
|
||||
*/
|
||||
public final class MutableContextSet implements ContextSet {
|
||||
@@ -57,9 +62,9 @@ public final class MutableContextSet implements ContextSet {
|
||||
*/
|
||||
@Nonnull
|
||||
public static MutableContextSet singleton(@Nonnull String key, @Nonnull String value) {
|
||||
Preconditions.checkNotNull(key, "key");
|
||||
Preconditions.checkNotNull(value, "value");
|
||||
MutableContextSet set = new MutableContextSet();
|
||||
checkNotNull(key, "key");
|
||||
checkNotNull(value, "value");
|
||||
MutableContextSet set = MutableContextSet.create();
|
||||
set.add(key, value);
|
||||
return set;
|
||||
}
|
||||
@@ -77,27 +82,13 @@ public final class MutableContextSet implements ContextSet {
|
||||
*/
|
||||
@Nonnull
|
||||
public static MutableContextSet of(@Nonnull String key1, @Nonnull String value1, @Nonnull String key2, @Nonnull String value2) {
|
||||
Preconditions.checkNotNull(key1, "key1");
|
||||
Preconditions.checkNotNull(value1, "value1");
|
||||
Preconditions.checkNotNull(key2, "key2");
|
||||
Preconditions.checkNotNull(value2, "value2");
|
||||
MutableContextSet ret = singleton(key1, value1);
|
||||
ret.add(key2, value2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a MutableContextSet from an existing map
|
||||
*
|
||||
* @param map the map to copy from
|
||||
* @return a new MutableContextSet representing the pairs from the map
|
||||
* @throws NullPointerException if the map is null
|
||||
*/
|
||||
@Nonnull
|
||||
public static MutableContextSet fromMap(@Nonnull Map<String, String> map) {
|
||||
Preconditions.checkNotNull(map, "map");
|
||||
MutableContextSet set = new MutableContextSet();
|
||||
set.addAll(map);
|
||||
checkNotNull(key1, "key1");
|
||||
checkNotNull(value1, "value1");
|
||||
checkNotNull(key2, "key2");
|
||||
checkNotNull(value2, "value2");
|
||||
MutableContextSet set = MutableContextSet.create();
|
||||
set.add(key1, value1);
|
||||
set.add(key2, value2);
|
||||
return set;
|
||||
}
|
||||
|
||||
@@ -110,12 +101,27 @@ public final class MutableContextSet implements ContextSet {
|
||||
*/
|
||||
@Nonnull
|
||||
public static MutableContextSet fromEntries(@Nonnull Iterable<? extends Map.Entry<String, String>> iterable) {
|
||||
Preconditions.checkNotNull(iterable, "iterable");
|
||||
MutableContextSet set = new MutableContextSet();
|
||||
checkNotNull(iterable, "iterable");
|
||||
MutableContextSet set = MutableContextSet.create();
|
||||
set.addAll(iterable);
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a MutableContextSet from an existing map
|
||||
*
|
||||
* @param map the map to copy from
|
||||
* @return a new MutableContextSet representing the pairs from the map
|
||||
* @throws NullPointerException if the map is null
|
||||
*/
|
||||
@Nonnull
|
||||
public static MutableContextSet fromMap(@Nonnull Map<String, String> map) {
|
||||
checkNotNull(map, "map");
|
||||
MutableContextSet set = MutableContextSet.create();
|
||||
set.addAll(map);
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a MutableContextSet from an existing multimap
|
||||
*
|
||||
@@ -125,8 +131,10 @@ public final class MutableContextSet implements ContextSet {
|
||||
*/
|
||||
@Nonnull
|
||||
public static MutableContextSet fromMultimap(@Nonnull Multimap<String, String> multimap) {
|
||||
Preconditions.checkNotNull(multimap, "multimap");
|
||||
return fromEntries(multimap.entries());
|
||||
checkNotNull(multimap, "multimap");
|
||||
MutableContextSet set = MutableContextSet.create();
|
||||
set.addAll(multimap);
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -161,8 +169,8 @@ public final class MutableContextSet implements ContextSet {
|
||||
this.map = Multimaps.synchronizedSetMultimap(HashMultimap.create());
|
||||
}
|
||||
|
||||
private MutableContextSet(Multimap<String, String> contexts) {
|
||||
this.map = Multimaps.synchronizedSetMultimap(HashMultimap.create(contexts));
|
||||
private MutableContextSet(MutableContextSet other) {
|
||||
this.map = Multimaps.synchronizedSetMultimap(HashMultimap.create(other.map));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -170,21 +178,25 @@ public final class MutableContextSet implements ContextSet {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ImmutableContextSet makeImmutable() {
|
||||
return new ImmutableContextSet(map);
|
||||
return new ImmutableContextSet(ImmutableSetMultimap.copyOf(map));
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public MutableContextSet mutableCopy() {
|
||||
return new MutableContextSet(map);
|
||||
return new MutableContextSet(this);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Set<Map.Entry<String, String>> toSet() {
|
||||
return ImmutableSet.copyOf(map.entries());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Map<String, String> toMap() {
|
||||
ImmutableMap.Builder<String, String> m = ImmutableMap.builder();
|
||||
@@ -195,57 +207,42 @@ public final class MutableContextSet implements ContextSet {
|
||||
return m.build();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Multimap<String, String> toMultimap() {
|
||||
return ImmutableSetMultimap.copyOf(map);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public boolean containsKey(String key) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("key");
|
||||
}
|
||||
|
||||
return map.containsKey(key);
|
||||
public boolean containsKey(@Nonnull String key) {
|
||||
return map.containsKey(checkNotNull(key, "key").toLowerCase().intern());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Set<String> getValues(String key) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("key");
|
||||
}
|
||||
|
||||
Collection<String> c = map.get(key);
|
||||
return c != null && !c.isEmpty() ? ImmutableSet.copyOf(c) : ImmutableSet.of();
|
||||
public Set<String> getValues(@Nonnull String key) {
|
||||
Collection<String> values = map.get(checkNotNull(key, "key").toLowerCase().intern());
|
||||
return values != null ? ImmutableSet.copyOf(values) : ImmutableSet.of();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public boolean has(String key, String value) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("key");
|
||||
}
|
||||
if (value == null) {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
|
||||
return map.containsEntry(key, value);
|
||||
public boolean has(@Nonnull String key, @Nonnull String value) {
|
||||
return map.containsEntry(checkNotNull(key, "key").toLowerCase().intern(), checkNotNull(value, "value").intern());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public boolean hasIgnoreCase(String key, String value) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("key");
|
||||
}
|
||||
if (value == null) {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
public boolean hasIgnoreCase(@Nonnull String key, @Nonnull String value) {
|
||||
value = checkNotNull(value, "value").intern();
|
||||
Collection<String> values = map.get(checkNotNull(key, "key").toLowerCase().intern());
|
||||
|
||||
Collection<String> c = map.get(key);
|
||||
if (c == null || c.isEmpty()) {
|
||||
if (values == null || values.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (String val : c) {
|
||||
for (String val : values) {
|
||||
if (val.equalsIgnoreCase(value)) {
|
||||
return true;
|
||||
}
|
||||
@@ -270,15 +267,8 @@ public final class MutableContextSet implements ContextSet {
|
||||
* @param value the value to add
|
||||
* @throws NullPointerException if the key or value is null
|
||||
*/
|
||||
public void add(String key, String value) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("key");
|
||||
}
|
||||
if (value == null) {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
|
||||
map.put(key.toLowerCase(), value);
|
||||
public void add(@Nonnull String key, @Nonnull String value) {
|
||||
map.put(checkNotNull(key, "key").toLowerCase().intern(), checkNotNull(value, "value").intern());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -287,12 +277,9 @@ public final class MutableContextSet implements ContextSet {
|
||||
* @param entry the entry to add
|
||||
* @throws NullPointerException if the entry is null
|
||||
*/
|
||||
public void add(Map.Entry<String, String> entry) {
|
||||
if (entry == null) {
|
||||
throw new NullPointerException("context");
|
||||
}
|
||||
|
||||
map.put(entry.getKey().toLowerCase(), entry.getValue());
|
||||
public void add(@Nonnull Map.Entry<String, String> entry) {
|
||||
checkNotNull(entry, "entry");
|
||||
add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -301,13 +288,9 @@ public final class MutableContextSet implements ContextSet {
|
||||
* @param iterable an iterable of key value context pairs
|
||||
* @throws NullPointerException if iterable is null
|
||||
*/
|
||||
public void addAll(Iterable<? extends Map.Entry<String, String>> iterable) {
|
||||
if (iterable == null) {
|
||||
throw new NullPointerException("iterable");
|
||||
}
|
||||
|
||||
for (Map.Entry<String, String> e : iterable) {
|
||||
this.map.put(e.getKey().toLowerCase(), e.getValue());
|
||||
public void addAll(@Nonnull Iterable<? extends Map.Entry<String, String>> iterable) {
|
||||
for (Map.Entry<String, String> e : checkNotNull(iterable, "iterable")) {
|
||||
add(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,11 +300,19 @@ public final class MutableContextSet implements ContextSet {
|
||||
* @param map the map to add from
|
||||
* @throws NullPointerException if the map is null
|
||||
*/
|
||||
public void addAll(Map<String, String> map) {
|
||||
if (map == null) {
|
||||
throw new NullPointerException("map");
|
||||
}
|
||||
addAll(map.entrySet());
|
||||
public void addAll(@Nonnull Map<String, String> map) {
|
||||
addAll(checkNotNull(map, "map").entrySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the entries of a multimap to the set
|
||||
*
|
||||
* @param multimap the multimap to add from
|
||||
* @throws NullPointerException if the map is null
|
||||
* @since 3.4
|
||||
*/
|
||||
public void addAll(@Nonnull Multimap<String, String> multimap) {
|
||||
addAll(checkNotNull(multimap, "multimap").entries());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -330,12 +321,14 @@ public final class MutableContextSet implements ContextSet {
|
||||
* @param contextSet the set to add from
|
||||
* @throws NullPointerException if the contextSet is null
|
||||
*/
|
||||
public void addAll(ContextSet contextSet) {
|
||||
if (contextSet == null) {
|
||||
throw new NullPointerException("contextSet");
|
||||
public void addAll(@Nonnull ContextSet contextSet) {
|
||||
checkNotNull(contextSet, "contextSet");
|
||||
if (contextSet instanceof MutableContextSet) {
|
||||
MutableContextSet other = ((MutableContextSet) contextSet);
|
||||
this.map.putAll(other.map);
|
||||
} else {
|
||||
addAll(contextSet.toMultimap());
|
||||
}
|
||||
|
||||
this.map.putAll(contextSet.toMultimap());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -345,15 +338,12 @@ public final class MutableContextSet implements ContextSet {
|
||||
* @param value the value to remove (case sensitive)
|
||||
* @throws NullPointerException if the key or value is null
|
||||
*/
|
||||
public void remove(String key, String value) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("key");
|
||||
}
|
||||
if (value == null) {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
public void remove(@Nonnull String key, @Nonnull String value) {
|
||||
String k = checkNotNull(key, "key").toLowerCase().intern();
|
||||
String v = checkNotNull(value, "value").intern();
|
||||
|
||||
map.entries().removeIf(entry -> entry.getKey().equals(key) && entry.getValue().equals(value));
|
||||
//noinspection StringEquality
|
||||
map.entries().removeIf(entry -> entry.getKey() == k && entry.getValue() == v);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -363,15 +353,12 @@ public final class MutableContextSet implements ContextSet {
|
||||
* @param value the value to remove
|
||||
* @throws NullPointerException if the key or value is null
|
||||
*/
|
||||
public void removeIgnoreCase(String key, String value) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("key");
|
||||
}
|
||||
if (value == null) {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
public void removeIgnoreCase(@Nonnull String key, @Nonnull String value) {
|
||||
String k = checkNotNull(key, "key").toLowerCase().intern();
|
||||
String v = checkNotNull(value, "value").intern();
|
||||
|
||||
map.entries().removeIf(e -> e.getKey().equalsIgnoreCase(key) && e.getValue().equalsIgnoreCase(value));
|
||||
//noinspection StringEquality
|
||||
map.entries().removeIf(e -> e.getKey() == k && e.getValue().equalsIgnoreCase(v));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -380,12 +367,8 @@ public final class MutableContextSet implements ContextSet {
|
||||
* @param key the key to remove
|
||||
* @throws NullPointerException if the key is null
|
||||
*/
|
||||
public void removeAll(String key) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("key");
|
||||
}
|
||||
|
||||
map.removeAll(key.toLowerCase());
|
||||
public void removeAll(@Nonnull String key) {
|
||||
map.removeAll(checkNotNull(key, "key").toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -401,14 +384,20 @@ public final class MutableContextSet implements ContextSet {
|
||||
if (!(o instanceof ContextSet)) return false;
|
||||
final ContextSet other = (ContextSet) o;
|
||||
|
||||
final Multimap<String, String> thisContexts = this.toMultimap();
|
||||
final Multimap<String, String> otherContexts = other.toMultimap();
|
||||
return thisContexts == null ? otherContexts == null : thisContexts.equals(otherContexts);
|
||||
final Multimap<String, String> otherContexts;
|
||||
|
||||
if (other instanceof MutableContextSet) {
|
||||
otherContexts = ((MutableContextSet) other).map;
|
||||
} else {
|
||||
otherContexts = other.toMultimap();
|
||||
}
|
||||
|
||||
return this.map.equals(otherContexts);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 59 + (this.map == null ? 43 : this.map.hashCode());
|
||||
return map.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -44,4 +44,31 @@ public interface LogBroadcastEvent extends LuckPermsEvent, Cancellable {
|
||||
@Nonnull
|
||||
LogEntry getEntry();
|
||||
|
||||
/**
|
||||
* Gets where the log entry originated from.
|
||||
*
|
||||
* @return the origin of the log
|
||||
* @since 3.3
|
||||
*/
|
||||
@Nonnull
|
||||
Origin getOrigin();
|
||||
|
||||
/**
|
||||
* Represents where a log entry is from
|
||||
*
|
||||
* @since 3.3
|
||||
*/
|
||||
enum Origin {
|
||||
|
||||
/**
|
||||
* Represents a log entry which originated from the current server instance
|
||||
*/
|
||||
LOCAL,
|
||||
|
||||
/**
|
||||
* Represents a log entry which was sent to this server via the messaging service
|
||||
*/
|
||||
REMOTE
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.api.event.log;
|
||||
|
||||
import me.lucko.luckperms.api.LogEntry;
|
||||
import me.lucko.luckperms.api.event.Cancellable;
|
||||
import me.lucko.luckperms.api.event.LuckPermsEvent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Called when a log is about to be published to the network via the MessagingService
|
||||
*
|
||||
* @since 3.3
|
||||
*/
|
||||
public interface LogNetworkPublishEvent extends LuckPermsEvent, Cancellable {
|
||||
|
||||
/**
|
||||
* Gets the ID of the log entry being published
|
||||
*
|
||||
* @return the id of the log entry being published
|
||||
*/
|
||||
@Nonnull
|
||||
UUID getLogId();
|
||||
|
||||
/**
|
||||
* Gets the log entry to be published
|
||||
*
|
||||
* @return the log entry to be published
|
||||
*/
|
||||
@Nonnull
|
||||
LogEntry getEntry();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.api.event.log;
|
||||
|
||||
import me.lucko.luckperms.api.LogEntry;
|
||||
import me.lucko.luckperms.api.event.LuckPermsEvent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Called when a log entry is received via the MessagingService
|
||||
*
|
||||
* @since 3.3
|
||||
*/
|
||||
public interface LogReceiveEvent extends LuckPermsEvent {
|
||||
|
||||
/**
|
||||
* Gets the ID of the log entry being received
|
||||
*
|
||||
* @return the id of the log entry being received
|
||||
*/
|
||||
@Nonnull
|
||||
UUID getLogId();
|
||||
|
||||
/**
|
||||
* Gets the log entry being received
|
||||
*
|
||||
* @return the log entry being received
|
||||
*/
|
||||
@Nonnull
|
||||
LogEntry getEntry();
|
||||
|
||||
}
|
||||
@@ -33,7 +33,7 @@ import java.util.UUID;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Called before a network sync task runs
|
||||
* Called before a received network sync task runs
|
||||
*/
|
||||
public interface PreNetworkSyncEvent extends LuckPermsEvent, Cancellable {
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.api.event.user;
|
||||
|
||||
import me.lucko.luckperms.api.User;
|
||||
import me.lucko.luckperms.api.event.LuckPermsEvent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Called when LuckPerms has finished processing a certain Player's connection.
|
||||
*
|
||||
* <p>This event will always execute during the platforms async login/auth event.
|
||||
* All handlers will be called instantly.</p>
|
||||
*
|
||||
* <p>This, among other things, allows you to wait until permission data is loaded
|
||||
* for a User during the BungeeCord 'LoginEvent', as event priorities are ignored
|
||||
* by the current implementation.</p>
|
||||
*
|
||||
* @since 3.4
|
||||
*/
|
||||
public interface UserLoginProcessEvent extends LuckPermsEvent {
|
||||
|
||||
/**
|
||||
* Gets the UUID of the connection which was processed
|
||||
*
|
||||
* @return the uuid of the connection which was processed
|
||||
*/
|
||||
@Nonnull
|
||||
UUID getUuid();
|
||||
|
||||
/**
|
||||
* Gets the username of the connection which was processed
|
||||
*
|
||||
* @return the username of the connection which was processed
|
||||
*/
|
||||
@Nonnull
|
||||
String getUsername();
|
||||
|
||||
/**
|
||||
* Gets the resultant User instance which was loaded.
|
||||
*
|
||||
* @return the user instance
|
||||
*/
|
||||
User getUser();
|
||||
|
||||
}
|
||||
@@ -26,8 +26,16 @@
|
||||
package me.lucko.luckperms.exceptions;
|
||||
|
||||
/**
|
||||
* Thrown when a permission holding object doesn't / already has a permission or isn't / is already is a member of a
|
||||
* group
|
||||
* Thrown when a certain membership state is / isn't met.
|
||||
*
|
||||
* For example, when:
|
||||
* <p></p>
|
||||
* <ul>
|
||||
* <li>a permission holding object doesn't have a permission</li>
|
||||
* <li>a permission holding object already has a permission</li>
|
||||
* <li>a permission holding object is already a member of a group</li>
|
||||
* <li>a permission holding object isn't already a member of a group</li>
|
||||
* </ul>
|
||||
*
|
||||
* @since 2.7
|
||||
*/
|
||||
|
||||
@@ -26,8 +26,15 @@
|
||||
package me.lucko.luckperms.exceptions;
|
||||
|
||||
/**
|
||||
* Thrown when a permission holding object already has a permission, is already a member of a group, or when a track
|
||||
* already contains a group.
|
||||
* Thrown when an object already has something.
|
||||
*
|
||||
* <p>For example, when:</p>
|
||||
* <p></p>
|
||||
* <ul>
|
||||
* <li>a permission holding object already has a permission</li>
|
||||
* <li>a permission holding object is already a member of a group</li>
|
||||
* <li>a track already contains a group</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class ObjectAlreadyHasException extends MembershipException {
|
||||
}
|
||||
@@ -26,8 +26,15 @@
|
||||
package me.lucko.luckperms.exceptions;
|
||||
|
||||
/**
|
||||
* Thrown when a permission holding object does not already have a permission, is not already a member of a group,
|
||||
* or when a track doesn't contain a group.
|
||||
* Thrown when an object lacks something.
|
||||
*
|
||||
* <p>For example, when:</p>
|
||||
* <p></p>
|
||||
* <ul>
|
||||
* <li>a permission holding object doesn't have a permission</li>
|
||||
* <li>a permission holding object isn't already a member of a group</li>
|
||||
* <li>a track doesn't contain a group</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class ObjectLacksException extends MembershipException {
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>luckperms</artifactId>
|
||||
<groupId>me.lucko.luckperms</groupId>
|
||||
<version>3.3-SNAPSHOT</version>
|
||||
<version>3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>luckperms</artifactId>
|
||||
<groupId>me.lucko.luckperms</groupId>
|
||||
<version>3.3-SNAPSHOT</version>
|
||||
<version>3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -71,6 +71,10 @@ public class BukkitListener implements Listener {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
if (plugin.getConfiguration().get(ConfigKeys.DEBUG_LOGINS)) {
|
||||
plugin.getLog().info("Processing pre-login for " + e.getUniqueId() + " - " + e.getName());
|
||||
}
|
||||
|
||||
/* there was an issue connecting to the DB, performing file i/o, etc.
|
||||
we don't let players join in this case, because it means they can connect to the server without their permissions data.
|
||||
some server admins rely on negating perms to stop users from causing damage etc, so it's really important that
|
||||
@@ -98,7 +102,8 @@ public class BukkitListener implements Listener {
|
||||
- creating a user instance in the UserManager for this connection.
|
||||
- setting up cached data. */
|
||||
try {
|
||||
LoginHelper.loadUser(plugin, e.getUniqueId(), e.getName(), false);
|
||||
User user = LoginHelper.loadUser(plugin, e.getUniqueId(), e.getName(), false);
|
||||
plugin.getApiProvider().getEventFactory().handleUserLoginProcess(e.getUniqueId(), e.getName(), user);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
|
||||
@@ -139,6 +144,11 @@ public class BukkitListener implements Listener {
|
||||
At this point, the users data should be present and loaded. */
|
||||
|
||||
final Player player = e.getPlayer();
|
||||
|
||||
if (plugin.getConfiguration().get(ConfigKeys.DEBUG_LOGINS)) {
|
||||
plugin.getLog().info("Processing login for " + player.getUniqueId() + " - " + player.getName());
|
||||
}
|
||||
|
||||
final User user = plugin.getUserManager().getIfLoaded(plugin.getUuidCache().getUUID(player.getUniqueId()));
|
||||
|
||||
/* User instance is null for whatever reason. Could be that it was unloaded between asyncpre and now. */
|
||||
|
||||
@@ -32,20 +32,21 @@ import me.lucko.luckperms.api.Logger;
|
||||
import me.lucko.luckperms.api.LuckPermsApi;
|
||||
import me.lucko.luckperms.api.PlatformType;
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.bukkit.calculators.BukkitCalculatorFactory;
|
||||
import me.lucko.luckperms.bukkit.contexts.BukkitContextManager;
|
||||
import me.lucko.luckperms.bukkit.contexts.WorldCalculator;
|
||||
import me.lucko.luckperms.bukkit.messaging.BungeeMessagingService;
|
||||
import me.lucko.luckperms.bukkit.messaging.LilyPadMessagingService;
|
||||
import me.lucko.luckperms.bukkit.messaging.BukkitMessagingFactory;
|
||||
import me.lucko.luckperms.bukkit.model.Injector;
|
||||
import me.lucko.luckperms.bukkit.model.LPPermissible;
|
||||
import me.lucko.luckperms.bukkit.processors.ChildPermissionProvider;
|
||||
import me.lucko.luckperms.bukkit.processors.DefaultsProvider;
|
||||
import me.lucko.luckperms.bukkit.vault.VaultHookManager;
|
||||
import me.lucko.luckperms.common.actionlog.LogDispatcher;
|
||||
import me.lucko.luckperms.common.api.ApiHandler;
|
||||
import me.lucko.luckperms.common.api.ApiProvider;
|
||||
import me.lucko.luckperms.common.buffers.BufferedRequest;
|
||||
import me.lucko.luckperms.common.buffers.UpdateTaskBuffer;
|
||||
import me.lucko.luckperms.common.caching.handlers.CachedStateManager;
|
||||
import me.lucko.luckperms.common.calculators.CalculatorFactory;
|
||||
import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
@@ -67,8 +68,6 @@ import me.lucko.luckperms.common.managers.GroupManager;
|
||||
import me.lucko.luckperms.common.managers.TrackManager;
|
||||
import me.lucko.luckperms.common.managers.UserManager;
|
||||
import me.lucko.luckperms.common.messaging.InternalMessagingService;
|
||||
import me.lucko.luckperms.common.messaging.NoopMessagingService;
|
||||
import me.lucko.luckperms.common.messaging.RedisMessagingService;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.storage.Storage;
|
||||
@@ -77,7 +76,6 @@ import me.lucko.luckperms.common.storage.StorageType;
|
||||
import me.lucko.luckperms.common.storage.backing.file.FileWatcher;
|
||||
import me.lucko.luckperms.common.tasks.CacheHousekeepingTask;
|
||||
import me.lucko.luckperms.common.tasks.ExpireTemporaryTask;
|
||||
import me.lucko.luckperms.common.tasks.UpdateTask;
|
||||
import me.lucko.luckperms.common.treeview.PermissionVault;
|
||||
import me.lucko.luckperms.common.utils.LoginHelper;
|
||||
import me.lucko.luckperms.common.utils.UuidCache;
|
||||
@@ -109,8 +107,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
@Getter
|
||||
public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
private Set<UUID> ignoringLogs;
|
||||
private Set<UUID> uniqueConnections;
|
||||
|
||||
private long startTime;
|
||||
private LPBukkitScheduler scheduler;
|
||||
private BukkitCommand commandManager;
|
||||
@@ -131,7 +128,6 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
private LocaleManager localeManager;
|
||||
private CachedStateManager cachedStateManager;
|
||||
private ContextManager<Player> contextManager;
|
||||
private WorldCalculator worldCalculator;
|
||||
private CalculatorFactory calculatorFactory;
|
||||
private BufferedRequest<Void> updateTaskBuffer;
|
||||
private boolean started = false;
|
||||
@@ -139,9 +135,15 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
private VerboseHandler verboseHandler;
|
||||
private BukkitSenderFactory senderFactory;
|
||||
private PermissionVault permissionVault;
|
||||
private LogDispatcher logDispatcher;
|
||||
private Set<UUID> uniqueConnections = ConcurrentHashMap.newKeySet();
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
if (checkInvalidVersion()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// setup minimal functionality in order to load initial dependencies
|
||||
scheduler = new LPBukkitScheduler(this);
|
||||
localeManager = new NoopLocaleManager();
|
||||
@@ -153,6 +155,18 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
if (checkInvalidVersion()) {
|
||||
getLogger().severe("----------------------------------------------------------------------");
|
||||
getLogger().severe("Your server version is not compatible with this build of LuckPerms. :(");
|
||||
getLogger().severe("");
|
||||
getLogger().severe("If your server is running 1.8, please update to 1.8.8 or higher.");
|
||||
getLogger().severe("If your server is running 1.7.10, please download the Bukkit-Legacy version of LuckPerms from here:");
|
||||
getLogger().severe("==> https://ci.lucko.me/job/LuckPerms/");
|
||||
getLogger().severe("----------------------------------------------------------------------");
|
||||
getServer().getPluginManager().disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
enable();
|
||||
started = true;
|
||||
@@ -166,11 +180,9 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
private void enable() {
|
||||
startTime = System.currentTimeMillis();
|
||||
LuckPermsPlugin.sendStartupBanner(getConsoleSender(), this);
|
||||
|
||||
ignoringLogs = ConcurrentHashMap.newKeySet();
|
||||
uniqueConnections = ConcurrentHashMap.newKeySet();
|
||||
verboseHandler = new VerboseHandler(scheduler.getAsyncBukkitExecutor(), getVersion());
|
||||
permissionVault = new PermissionVault(scheduler.getAsyncBukkitExecutor());
|
||||
verboseHandler = new VerboseHandler(scheduler.asyncBukkit(), getVersion());
|
||||
permissionVault = new PermissionVault(scheduler.asyncBukkit());
|
||||
logDispatcher = new LogDispatcher(this);
|
||||
|
||||
getLog().info("Loading configuration...");
|
||||
configuration = new BukkitConfig(this);
|
||||
@@ -211,68 +223,14 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
storage = StorageFactory.getInstance(this, StorageType.H2);
|
||||
|
||||
// initialise messaging
|
||||
String messagingType = getConfiguration().get(ConfigKeys.MESSAGING_SERVICE).toLowerCase();
|
||||
if (messagingType.equals("none") && getConfiguration().get(ConfigKeys.REDIS_ENABLED)) {
|
||||
messagingType = "redis";
|
||||
}
|
||||
|
||||
if (!messagingType.equals("none")) {
|
||||
getLog().info("Loading messaging service... [" + messagingType.toUpperCase() + "]");
|
||||
}
|
||||
|
||||
if (messagingType.equals("redis")) {
|
||||
if (getConfiguration().get(ConfigKeys.REDIS_ENABLED)) {
|
||||
RedisMessagingService redis = new RedisMessagingService(this);
|
||||
try {
|
||||
redis.init(getConfiguration().get(ConfigKeys.REDIS_ADDRESS), getConfiguration().get(ConfigKeys.REDIS_PASSWORD));
|
||||
messagingService = redis;
|
||||
} catch (Exception e) {
|
||||
getLog().warn("Couldn't load redis...");
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
getLog().warn("Messaging Service was set to redis, but redis is not enabled!");
|
||||
}
|
||||
} else if (messagingType.equals("bungee")) {
|
||||
BungeeMessagingService bungeeMessaging = new BungeeMessagingService(this);
|
||||
bungeeMessaging.init();
|
||||
messagingService = bungeeMessaging;
|
||||
} else if (messagingType.equals("lilypad")) {
|
||||
if (getServer().getPluginManager().getPlugin("LilyPad-Connect") == null) {
|
||||
getLog().warn("LilyPad-Connect plugin not present.");
|
||||
} else {
|
||||
LilyPadMessagingService lilyPadMessaging = new LilyPadMessagingService(this);
|
||||
lilyPadMessaging.init();
|
||||
messagingService = lilyPadMessaging;
|
||||
}
|
||||
} else if (!messagingType.equals("none")) {
|
||||
getLog().warn("Messaging service '" + messagingType + "' not recognised.");
|
||||
}
|
||||
|
||||
if (messagingService == null) {
|
||||
messagingService = new NoopMessagingService();
|
||||
}
|
||||
messagingService = new BukkitMessagingFactory(this).getInstance();
|
||||
|
||||
// setup the update task buffer
|
||||
updateTaskBuffer = new BufferedRequest<Void>(1000L, this::doAsync) {
|
||||
@Override
|
||||
protected Void perform() {
|
||||
new UpdateTask(LPBukkitPlugin.this).run();
|
||||
return null;
|
||||
}
|
||||
};
|
||||
updateTaskBuffer = new UpdateTaskBuffer(this);
|
||||
|
||||
// load locale
|
||||
localeManager = new SimpleLocaleManager();
|
||||
File locale = new File(getDataFolder(), "lang.yml");
|
||||
if (locale.exists()) {
|
||||
getLog().info("Found lang.yml - loading messages...");
|
||||
try {
|
||||
localeManager.loadFromFile(locale);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
localeManager.tryLoad(this, new File(getDataFolder(), "lang.yml"));
|
||||
|
||||
// register commands
|
||||
commandManager = new BukkitCommand(this);
|
||||
@@ -291,26 +249,10 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
calculatorFactory = new BukkitCalculatorFactory(this);
|
||||
cachedStateManager = new CachedStateManager();
|
||||
|
||||
contextManager = new ContextManager<Player>() {
|
||||
@Override
|
||||
public Contexts formContexts(Player player, ImmutableContextSet contextSet) {
|
||||
return new Contexts(
|
||||
contextSet,
|
||||
getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_PERMS),
|
||||
getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_WORLD_PERMS),
|
||||
true,
|
||||
getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_GROUPS),
|
||||
getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_WORLD_GROUPS),
|
||||
player.isOp()
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
worldCalculator = new WorldCalculator(this);
|
||||
contextManager.registerCalculator(worldCalculator);
|
||||
|
||||
LuckPermsCalculator<Player> staticCalculator = new LuckPermsCalculator<>(getConfiguration());
|
||||
contextManager.registerCalculator(staticCalculator, true);
|
||||
// setup context manager
|
||||
contextManager = new BukkitContextManager(this);
|
||||
contextManager.registerCalculator(new WorldCalculator(this));
|
||||
contextManager.registerCalculator(new LuckPermsCalculator<>(getConfiguration()), true);
|
||||
|
||||
// Provide vault support
|
||||
tryVaultHook(false);
|
||||
@@ -374,6 +316,10 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
if (checkInvalidVersion()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Switch back to the LP executor, the bukkit one won't allow new tasks
|
||||
scheduler.setUseBukkitAsync(false);
|
||||
|
||||
@@ -428,7 +374,6 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
HandlerList.unregisterAll(this);
|
||||
|
||||
// Null everything
|
||||
ignoringLogs = null;
|
||||
vaultHookManager = null;
|
||||
configuration = null;
|
||||
userManager = null;
|
||||
@@ -446,12 +391,12 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
localeManager = null;
|
||||
cachedStateManager = null;
|
||||
contextManager = null;
|
||||
worldCalculator = null;
|
||||
calculatorFactory = null;
|
||||
updateTaskBuffer = null;
|
||||
verboseHandler = null;
|
||||
senderFactory = null;
|
||||
permissionVault = null;
|
||||
logDispatcher = null;
|
||||
}
|
||||
|
||||
public void tryVaultHook(boolean force) {
|
||||
@@ -671,4 +616,13 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
pm.addPermission(new org.bukkit.permissions.Permission(p.getPermission(), def));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean checkInvalidVersion() {
|
||||
try {
|
||||
Class.forName("com.google.gson.JsonElement");
|
||||
return false;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ package me.lucko.luckperms.bukkit;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsScheduler;
|
||||
|
||||
@@ -43,10 +44,16 @@ public class LPBukkitScheduler implements LuckPermsScheduler {
|
||||
private final LPBukkitPlugin plugin;
|
||||
|
||||
@Getter
|
||||
private ExecutorService asyncLpExecutor;
|
||||
@Accessors(fluent = true)
|
||||
private ExecutorService asyncLp;
|
||||
|
||||
@Getter
|
||||
private Executor asyncBukkitExecutor;
|
||||
private Executor syncExecutor;
|
||||
@Accessors(fluent = true)
|
||||
private Executor asyncBukkit;
|
||||
|
||||
@Getter
|
||||
@Accessors(fluent = true)
|
||||
private Executor sync;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@@ -57,19 +64,14 @@ public class LPBukkitScheduler implements LuckPermsScheduler {
|
||||
public LPBukkitScheduler(LPBukkitPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
|
||||
this.asyncLpExecutor = Executors.newCachedThreadPool();
|
||||
this.asyncBukkitExecutor = r -> plugin.getServer().getScheduler().runTaskAsynchronously(plugin, r);
|
||||
this.syncExecutor = r -> plugin.getServer().getScheduler().runTask(plugin, r);
|
||||
this.asyncLp = Executors.newCachedThreadPool();
|
||||
this.asyncBukkit = r -> plugin.getServer().getScheduler().runTaskAsynchronously(plugin, r);
|
||||
this.sync = r -> plugin.getServer().getScheduler().runTask(plugin, r);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor async() {
|
||||
return useBukkitAsync ? asyncBukkitExecutor : asyncLpExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor sync() {
|
||||
return syncExecutor;
|
||||
return useBukkitAsync ? asyncBukkit : asyncLp;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -108,9 +110,9 @@ public class LPBukkitScheduler implements LuckPermsScheduler {
|
||||
public void shutdown() {
|
||||
tasks.forEach(BukkitTask::cancel);
|
||||
// wait for executor
|
||||
asyncLpExecutor.shutdown();
|
||||
asyncLp.shutdown();
|
||||
try {
|
||||
asyncLpExecutor.awaitTermination(30, TimeUnit.SECONDS);
|
||||
asyncLp.awaitTermination(30, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
+6
-1
@@ -38,6 +38,7 @@ import me.lucko.luckperms.bukkit.processors.ChildProcessor;
|
||||
import me.lucko.luckperms.bukkit.processors.DefaultsProcessor;
|
||||
import me.lucko.luckperms.common.calculators.AbstractCalculatorFactory;
|
||||
import me.lucko.luckperms.common.calculators.PermissionCalculator;
|
||||
import me.lucko.luckperms.common.calculators.PermissionCalculatorMetadata;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.processors.MapProcessor;
|
||||
@@ -82,7 +83,11 @@ public class BukkitCalculatorFactory extends AbstractCalculatorFactory {
|
||||
processors.add(new DefaultsProcessor(contexts.isOp(), plugin.getDefaultsProvider()));
|
||||
}
|
||||
|
||||
return registerCalculator(new PermissionCalculator(plugin, user.getFriendlyName(), processors.build()));
|
||||
return registerCalculator(new PermissionCalculator(
|
||||
plugin,
|
||||
PermissionCalculatorMetadata.of(user.getFriendlyName(), contexts.getContexts()),
|
||||
processors.build()
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -91,7 +91,7 @@ public class BukkitJsonMessageHandler {
|
||||
setup(player);
|
||||
setup = true;
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
triedAndFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -25,10 +25,10 @@
|
||||
|
||||
package me.lucko.luckperms.bukkit.compat;
|
||||
|
||||
import me.lucko.luckperms.common.constants.Constants;
|
||||
import me.lucko.luckperms.common.utils.TextUtils;
|
||||
|
||||
import net.kyori.text.Component;
|
||||
import net.kyori.text.serializer.ComponentSerializer;
|
||||
import net.kyori.text.serializer.ComponentSerializers;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -48,7 +48,7 @@ public class MessageHandler {
|
||||
public void sendJsonMessage(CommandSender sender, Component message) {
|
||||
if (ReflectionUtil.isChatCompatible() && sender instanceof Player) {
|
||||
Player player = (Player) sender;
|
||||
String json = ComponentSerializer.serialize(message);
|
||||
String json = ComponentSerializers.JSON.serialize(message);
|
||||
|
||||
// Try Bukkit.
|
||||
if (bukkitHandler.sendJsonMessage(player, json)) {
|
||||
@@ -62,7 +62,7 @@ public class MessageHandler {
|
||||
}
|
||||
|
||||
// Fallback to Bukkit
|
||||
sender.sendMessage(ComponentSerializer.toLegacy(message, Constants.COLOR_CHAR));
|
||||
sender.sendMessage(TextUtils.toLegacy(message));
|
||||
}
|
||||
|
||||
private static boolean isSpigot() {
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.contexts;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.contexts.ContextManager;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class BukkitContextManager extends ContextManager<Player> {
|
||||
private final LPBukkitPlugin plugin;
|
||||
|
||||
@Override
|
||||
public Contexts formContexts(Player subject, ImmutableContextSet contextSet) {
|
||||
return new Contexts(
|
||||
contextSet,
|
||||
plugin.getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_PERMS),
|
||||
plugin.getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_WORLD_PERMS),
|
||||
true,
|
||||
plugin.getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_GROUPS),
|
||||
plugin.getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_WORLD_GROUPS),
|
||||
subject.isOp()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.messaging;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.messaging.InternalMessagingService;
|
||||
import me.lucko.luckperms.common.messaging.MessagingFactory;
|
||||
|
||||
public class BukkitMessagingFactory extends MessagingFactory<LPBukkitPlugin> {
|
||||
public BukkitMessagingFactory(LPBukkitPlugin plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InternalMessagingService getServiceFor(String messagingType) {
|
||||
if (messagingType.equals("bungee")) {
|
||||
BungeeMessagingService bungeeMessaging = new BungeeMessagingService(getPlugin());
|
||||
bungeeMessaging.init();
|
||||
return bungeeMessaging;
|
||||
} else if (messagingType.equals("lilypad")) {
|
||||
if (getPlugin().getServer().getPluginManager().getPlugin("LilyPad-Connect") == null) {
|
||||
getPlugin().getLog().warn("LilyPad-Connect plugin not present.");
|
||||
} else {
|
||||
LilyPadMessagingService lilyPadMessaging = new LilyPadMessagingService(getPlugin());
|
||||
lilyPadMessaging.init();
|
||||
return lilyPadMessaging;
|
||||
}
|
||||
}
|
||||
|
||||
return super.getServiceFor(messagingType);
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,7 @@ import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.caching.UserCache;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.verbose.CheckOrigin;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -110,13 +111,13 @@ public class LPPermissible extends PermissibleBase {
|
||||
|
||||
@Override
|
||||
public boolean isPermissionSet(@NonNull String permission) {
|
||||
Tristate ts = user.getUserData().getPermissionData(calculateContexts()).getPermissionValue(permission);
|
||||
Tristate ts = user.getUserData().getPermissionData(calculateContexts()).getPermissionValue(permission, CheckOrigin.PLATFORM_LOOKUP_CHECK);
|
||||
return ts != Tristate.UNDEFINED || Permission.DEFAULT_PERMISSION.getValue(isOp());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPermissionSet(@NonNull Permission permission) {
|
||||
Tristate ts = user.getUserData().getPermissionData(calculateContexts()).getPermissionValue(permission.getName());
|
||||
Tristate ts = user.getUserData().getPermissionData(calculateContexts()).getPermissionValue(permission.getName(), CheckOrigin.PLATFORM_LOOKUP_CHECK);
|
||||
if (ts != Tristate.UNDEFINED) {
|
||||
return true;
|
||||
}
|
||||
@@ -130,13 +131,13 @@ public class LPPermissible extends PermissibleBase {
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(@NonNull String permission) {
|
||||
Tristate ts = user.getUserData().getPermissionData(calculateContexts()).getPermissionValue(permission);
|
||||
Tristate ts = user.getUserData().getPermissionData(calculateContexts()).getPermissionValue(permission, CheckOrigin.PLATFORM_PERMISSION_CHECK);
|
||||
return ts != Tristate.UNDEFINED ? ts.asBoolean() : Permission.DEFAULT_PERMISSION.getValue(isOp());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(@NonNull Permission permission) {
|
||||
Tristate ts = user.getUserData().getPermissionData(calculateContexts()).getPermissionValue(permission.getName());
|
||||
Tristate ts = user.getUserData().getPermissionData(calculateContexts()).getPermissionValue(permission.getName(), CheckOrigin.PLATFORM_PERMISSION_CHECK);
|
||||
if (ts != Tristate.UNDEFINED) {
|
||||
return ts.asBoolean();
|
||||
}
|
||||
|
||||
@@ -331,7 +331,7 @@ public class VaultChatHook extends Chat {
|
||||
perms.log("Getting meta: '" + node + "' for group " + group.getName() + " on world " + world + ", server " + perms.getServer());
|
||||
|
||||
for (Node n : group.getOwnNodes()) {
|
||||
if (!n.getValue()) continue;
|
||||
if (!n.getValuePrimitive()) continue;
|
||||
if (!n.isMeta()) continue;
|
||||
if (!n.shouldApplyWithContext(perms.createContextForWorldLookup(world).getContexts())) continue;
|
||||
|
||||
@@ -357,7 +357,7 @@ public class VaultChatHook extends Chat {
|
||||
|
||||
ExtractedContexts ec = ExtractedContexts.generate(Contexts.of(perms.createContextForWorldLookup(world).getContexts(), perms.isIncludeGlobal(), true, true, true, true, false));
|
||||
for (Node n : group.getAllNodes(ec)) {
|
||||
if (!n.getValue()) continue;
|
||||
if (!n.getValuePrimitive()) continue;
|
||||
if (type.shouldIgnore(n)) continue;
|
||||
if (!n.shouldApplyWithContext(perms.createContextForWorldLookup(world).getContexts())) continue;
|
||||
|
||||
|
||||
@@ -32,16 +32,17 @@ import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.DataMutateResult;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.api.caching.PermissionData;
|
||||
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.caching.PermissionCache;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.contexts.ExtractedContexts;
|
||||
import me.lucko.luckperms.common.model.Group;
|
||||
import me.lucko.luckperms.common.model.PermissionHolder;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.node.NodeFactory;
|
||||
import me.lucko.luckperms.common.verbose.CheckOrigin;
|
||||
|
||||
import net.milkbowl.vault.permission.Permission;
|
||||
|
||||
@@ -147,7 +148,7 @@ public class VaultPermissionHook extends Permission {
|
||||
}
|
||||
|
||||
// Effectively fallback to the standard Bukkit #hasPermission check.
|
||||
return user.getUserData().getPermissionData(createContextForWorldLookup(player, world)).getPermissionValue(permission).asBoolean();
|
||||
return user.getUserData().getPermissionData(createContextForWorldLookup(player, world)).getPermissionValue(permission, CheckOrigin.INTERNAL).asBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -396,7 +397,7 @@ public class VaultPermissionHook extends Permission {
|
||||
// we need to do the complex PGO checking. (it's been enabled in the config.)
|
||||
if (isPgoCheckInherited()) {
|
||||
// we can just check the cached data
|
||||
PermissionData data = user.getUserData().getPermissionData(createContextForWorldLookup(plugin.getPlayer(user), world));
|
||||
PermissionCache data = user.getUserData().getPermissionData(createContextForWorldLookup(plugin.getPlayer(user), world));
|
||||
for (Map.Entry<String, Boolean> e : data.getImmutableBacking().entrySet()) {
|
||||
if (!e.getValue()) continue;
|
||||
if (!e.getKey().toLowerCase().startsWith("vault.primarygroup.")) continue;
|
||||
@@ -409,7 +410,7 @@ public class VaultPermissionHook extends Permission {
|
||||
}
|
||||
|
||||
if (isPgoCheckMemberOf()) {
|
||||
if (data.getPermissionValue("group." + group) != Tristate.TRUE) {
|
||||
if (data.getPermissionValue("group." + group, CheckOrigin.INTERNAL) != Tristate.TRUE) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -419,7 +420,7 @@ public class VaultPermissionHook extends Permission {
|
||||
} else {
|
||||
// we need to check the users permissions only
|
||||
for (Node node : user.getOwnNodes()) {
|
||||
if (!node.getValue()) continue;
|
||||
if (!node.getValuePrimitive()) continue;
|
||||
if (!node.getPermission().toLowerCase().startsWith("vault.primarygroup.")) continue;
|
||||
if (!node.shouldApplyOnServer(getServer(), isIncludeGlobal(), false)) continue;
|
||||
if (!node.shouldApplyOnWorld(world, true, false)) continue;
|
||||
|
||||
@@ -70,6 +70,10 @@ use-server-uuids: true
|
||||
# in the LuckPerms cache.
|
||||
use-server-uuid-cache: false
|
||||
|
||||
# If LuckPerms should produce extra logging output when it handles logins.
|
||||
# Useful if you're having issues with UUID forwarding or data not being loaded.
|
||||
debug-logins: false
|
||||
|
||||
# If the plugin should send log notifications to users whenever permissions are modified.
|
||||
log-notify: true
|
||||
|
||||
@@ -101,6 +105,10 @@ temporary-add-behaviour: deny
|
||||
# directly and indirectly
|
||||
primary-group-calculation: stored
|
||||
|
||||
# If set to false, the plugin will allow a Users primary group to be removed with the
|
||||
# 'parent remove' command, and will set their primary group back to default.
|
||||
prevent-primary-group-removal: false
|
||||
|
||||
# If the plugin should check for "extra" permissions with users run LP commands.
|
||||
#
|
||||
# These extra permissions allow finer control over what users can do with each command, and
|
||||
@@ -328,6 +336,16 @@ messaging-service: none
|
||||
# If LuckPerms should automatically push updates after a change has been made with a command.
|
||||
auto-push-updates: true
|
||||
|
||||
# If LuckPerms should push logging entries to connected servers via the messaging service.
|
||||
push-log-entries: true
|
||||
|
||||
# If LuckPerms should broadcast received logging entries to players on this platform.
|
||||
#
|
||||
# If you have LuckPerms installed on your backend servers as well as a BungeeCord proxy, you should
|
||||
# set this option to false on either your backends or your proxies, to avoid players being messaged
|
||||
# twice about log entries.
|
||||
broadcast-received-log-entries: true
|
||||
|
||||
# Settings for Redis.
|
||||
# Port 6379 is used by default; set address to "host:port" if differs
|
||||
redis:
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>luckperms</artifactId>
|
||||
<groupId>me.lucko.luckperms</groupId>
|
||||
<version>3.3-SNAPSHOT</version>
|
||||
<version>3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.utils.LoginHelper;
|
||||
import me.lucko.luckperms.common.verbose.CheckOrigin;
|
||||
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.connection.PendingConnection;
|
||||
@@ -70,6 +71,10 @@ public class BungeeListener implements Listener {
|
||||
|
||||
final PendingConnection c = e.getConnection();
|
||||
|
||||
if (plugin.getConfiguration().get(ConfigKeys.DEBUG_LOGINS)) {
|
||||
plugin.getLog().info("Processing pre-login for " + c.getUniqueId() + " - " + c.getName());
|
||||
}
|
||||
|
||||
/* there was an issue connecting to the DB, performing file i/o, etc.
|
||||
as this is bungeecord, we will still allow the login, as players can't really do much harm without permissions data.
|
||||
the proxy will just fallback to using the config file perms. */
|
||||
@@ -96,7 +101,8 @@ public class BungeeListener implements Listener {
|
||||
- creating a user instance in the UserManager for this connection.
|
||||
- setting up cached data. */
|
||||
try {
|
||||
LoginHelper.loadUser(plugin, c.getUniqueId(), c.getName(), true);
|
||||
User user = LoginHelper.loadUser(plugin, c.getUniqueId(), c.getName(), true);
|
||||
plugin.getApiProvider().getEventFactory().handleUserLoginProcess(c.getUniqueId(), c.getName(), user);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
|
||||
@@ -118,6 +124,10 @@ public class BungeeListener implements Listener {
|
||||
final ProxiedPlayer player = e.getPlayer();
|
||||
final User user = plugin.getUserManager().getIfLoaded(plugin.getUuidCache().getUUID(e.getPlayer().getUniqueId()));
|
||||
|
||||
if (plugin.getConfiguration().get(ConfigKeys.DEBUG_LOGINS)) {
|
||||
plugin.getLog().info("Processing post-login for " + player.getUniqueId() + " - " + player.getName());
|
||||
}
|
||||
|
||||
if (user == null) {
|
||||
plugin.getProxy().getScheduler().schedule(plugin, () -> {
|
||||
if (!player.isConnected()) {
|
||||
@@ -151,7 +161,7 @@ public class BungeeListener implements Listener {
|
||||
}
|
||||
|
||||
Contexts contexts = plugin.getContextManager().getApplicableContexts(player);
|
||||
Tristate result = user.getUserData().getPermissionData(contexts).getPermissionValue(e.getPermission());
|
||||
Tristate result = user.getUserData().getPermissionData(contexts).getPermissionValue(e.getPermission(), CheckOrigin.PLATFORM_PERMISSION_CHECK);
|
||||
if (result == Tristate.UNDEFINED && plugin.getConfiguration().get(ConfigKeys.APPLY_BUNGEE_CONFIG_PERMISSIONS)) {
|
||||
return; // just use the result provided by the proxy when the event was created
|
||||
}
|
||||
@@ -174,7 +184,7 @@ public class BungeeListener implements Listener {
|
||||
}
|
||||
|
||||
Contexts contexts = plugin.getContextManager().getApplicableContexts(player);
|
||||
Tristate result = user.getUserData().getPermissionData(contexts).getPermissionValue(e.getPermission());
|
||||
Tristate result = user.getUserData().getPermissionData(contexts).getPermissionValue(e.getPermission(), CheckOrigin.PLATFORM_LOOKUP_CHECK);
|
||||
if (result == Tristate.UNDEFINED && plugin.getConfiguration().get(ConfigKeys.APPLY_BUNGEE_CONFIG_PERMISSIONS)) {
|
||||
return; // just use the result provided by the proxy when the event was created
|
||||
}
|
||||
|
||||
@@ -30,9 +30,10 @@ import me.lucko.luckperms.bungee.event.TristateCheckEvent;
|
||||
import me.lucko.luckperms.common.commands.sender.SenderFactory;
|
||||
import me.lucko.luckperms.common.constants.Constants;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.utils.TextUtils;
|
||||
|
||||
import net.kyori.text.Component;
|
||||
import net.kyori.text.serializer.ComponentSerializer;
|
||||
import net.kyori.text.serializer.ComponentSerializers;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
@@ -68,9 +69,10 @@ public class BungeeSenderFactory extends SenderFactory<CommandSender> {
|
||||
@Override
|
||||
protected void sendMessage(CommandSender sender, Component message) {
|
||||
try {
|
||||
sender.sendMessage(net.md_5.bungee.chat.ComponentSerializer.parse(ComponentSerializer.serialize(message)));
|
||||
sender.sendMessage(net.md_5.bungee.chat.ComponentSerializer.parse(ComponentSerializers.JSON.serialize(message)));
|
||||
} catch (Exception e) {
|
||||
sendMessage(sender, ComponentSerializer.toLegacy(message, Constants.COLOR_CHAR));
|
||||
//noinspection deprecation
|
||||
sendMessage(sender, TextUtils.toLegacy(message));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,12 +34,14 @@ import me.lucko.luckperms.api.context.ContextSet;
|
||||
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
||||
import me.lucko.luckperms.bungee.calculators.BungeeCalculatorFactory;
|
||||
import me.lucko.luckperms.bungee.contexts.BackendServerCalculator;
|
||||
import me.lucko.luckperms.bungee.messaging.BungeeMessagingService;
|
||||
import me.lucko.luckperms.bungee.messaging.RedisBungeeMessagingService;
|
||||
import me.lucko.luckperms.bungee.contexts.BungeeContextManager;
|
||||
import me.lucko.luckperms.bungee.messaging.BungeeMessagingFactory;
|
||||
import me.lucko.luckperms.bungee.util.RedisBungeeUtil;
|
||||
import me.lucko.luckperms.common.actionlog.LogDispatcher;
|
||||
import me.lucko.luckperms.common.api.ApiHandler;
|
||||
import me.lucko.luckperms.common.api.ApiProvider;
|
||||
import me.lucko.luckperms.common.buffers.BufferedRequest;
|
||||
import me.lucko.luckperms.common.buffers.UpdateTaskBuffer;
|
||||
import me.lucko.luckperms.common.caching.handlers.CachedStateManager;
|
||||
import me.lucko.luckperms.common.calculators.CalculatorFactory;
|
||||
import me.lucko.luckperms.common.commands.CommandManager;
|
||||
@@ -61,8 +63,6 @@ import me.lucko.luckperms.common.managers.GroupManager;
|
||||
import me.lucko.luckperms.common.managers.TrackManager;
|
||||
import me.lucko.luckperms.common.managers.UserManager;
|
||||
import me.lucko.luckperms.common.messaging.InternalMessagingService;
|
||||
import me.lucko.luckperms.common.messaging.NoopMessagingService;
|
||||
import me.lucko.luckperms.common.messaging.RedisMessagingService;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsScheduler;
|
||||
@@ -72,7 +72,6 @@ import me.lucko.luckperms.common.storage.StorageType;
|
||||
import me.lucko.luckperms.common.storage.backing.file.FileWatcher;
|
||||
import me.lucko.luckperms.common.tasks.CacheHousekeepingTask;
|
||||
import me.lucko.luckperms.common.tasks.ExpireTemporaryTask;
|
||||
import me.lucko.luckperms.common.tasks.UpdateTask;
|
||||
import me.lucko.luckperms.common.treeview.PermissionVault;
|
||||
import me.lucko.luckperms.common.utils.UuidCache;
|
||||
import me.lucko.luckperms.common.verbose.VerboseHandler;
|
||||
@@ -93,8 +92,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
@Getter
|
||||
public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
private final Set<UUID> ignoringLogs = ConcurrentHashMap.newKeySet();
|
||||
private Set<UUID> uniqueConnections = ConcurrentHashMap.newKeySet();
|
||||
|
||||
private long startTime;
|
||||
private LuckPermsScheduler scheduler;
|
||||
private CommandManager commandManager;
|
||||
@@ -116,6 +114,8 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
private VerboseHandler verboseHandler;
|
||||
private BungeeSenderFactory senderFactory;
|
||||
private PermissionVault permissionVault;
|
||||
private LogDispatcher logDispatcher;
|
||||
private Set<UUID> uniqueConnections = ConcurrentHashMap.newKeySet();
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
@@ -134,6 +134,7 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
LuckPermsPlugin.sendStartupBanner(getConsoleSender(), this);
|
||||
verboseHandler = new VerboseHandler(scheduler.async(), getVersion());
|
||||
permissionVault = new PermissionVault(scheduler.async());
|
||||
logDispatcher = new LogDispatcher(this);
|
||||
|
||||
getLog().info("Loading configuration...");
|
||||
configuration = new BungeeConfig(this);
|
||||
@@ -155,68 +156,14 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
storage = StorageFactory.getInstance(this, StorageType.H2);
|
||||
|
||||
// initialise messaging
|
||||
String messagingType = getConfiguration().get(ConfigKeys.MESSAGING_SERVICE).toLowerCase();
|
||||
if (messagingType.equals("none") && getConfiguration().get(ConfigKeys.REDIS_ENABLED)) {
|
||||
messagingType = "redis";
|
||||
}
|
||||
|
||||
if (!messagingType.equals("none")) {
|
||||
getLog().info("Loading messaging service... [" + messagingType.toUpperCase() + "]");
|
||||
}
|
||||
|
||||
if (messagingType.equals("redis")) {
|
||||
if (getConfiguration().get(ConfigKeys.REDIS_ENABLED)) {
|
||||
RedisMessagingService redis = new RedisMessagingService(this);
|
||||
try {
|
||||
redis.init(getConfiguration().get(ConfigKeys.REDIS_ADDRESS), getConfiguration().get(ConfigKeys.REDIS_PASSWORD));
|
||||
messagingService = redis;
|
||||
} catch (Exception e) {
|
||||
getLog().warn("Couldn't load redis...");
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
getLog().warn("Messaging Service was set to redis, but redis is not enabled!");
|
||||
}
|
||||
} else if (messagingType.equals("bungee")) {
|
||||
BungeeMessagingService bungeeMessaging = new BungeeMessagingService(this);
|
||||
bungeeMessaging.init();
|
||||
messagingService = bungeeMessaging;
|
||||
} else if (messagingType.equals("redisbungee")) {
|
||||
if (getProxy().getPluginManager().getPlugin("RedisBungee") == null) {
|
||||
getLog().warn("RedisBungee plugin not present.");
|
||||
} else {
|
||||
RedisBungeeMessagingService redisBungeeMessaging = new RedisBungeeMessagingService(this);
|
||||
redisBungeeMessaging.init();
|
||||
messagingService = redisBungeeMessaging;
|
||||
}
|
||||
} else if (!messagingType.equals("none")) {
|
||||
getLog().warn("Messaging service '" + messagingType + "' not recognised.");
|
||||
}
|
||||
|
||||
if (messagingService == null) {
|
||||
messagingService = new NoopMessagingService();
|
||||
}
|
||||
messagingService = new BungeeMessagingFactory(this).getInstance();
|
||||
|
||||
// setup the update task buffer
|
||||
updateTaskBuffer = new BufferedRequest<Void>(1000L, this::doAsync) {
|
||||
@Override
|
||||
protected Void perform() {
|
||||
new UpdateTask(LPBungeePlugin.this).run();
|
||||
return null;
|
||||
}
|
||||
};
|
||||
updateTaskBuffer = new UpdateTaskBuffer(this);
|
||||
|
||||
// load locale
|
||||
localeManager = new SimpleLocaleManager();
|
||||
File locale = new File(getDataFolder(), "lang.yml");
|
||||
if (locale.exists()) {
|
||||
getLog().info("Found lang.yml - loading messages...");
|
||||
try {
|
||||
localeManager.loadFromFile(locale);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
localeManager.tryLoad(this, new File(getDataFolder(), "lang.yml"));
|
||||
|
||||
// register commands
|
||||
commandManager = new CommandManager(this);
|
||||
@@ -234,26 +181,10 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
calculatorFactory = new BungeeCalculatorFactory(this);
|
||||
cachedStateManager = new CachedStateManager();
|
||||
|
||||
contextManager = new ContextManager<ProxiedPlayer>() {
|
||||
@Override
|
||||
public Contexts formContexts(ProxiedPlayer player, ImmutableContextSet contextSet) {
|
||||
return new Contexts(
|
||||
contextSet,
|
||||
getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_PERMS),
|
||||
getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_WORLD_PERMS),
|
||||
true,
|
||||
getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_GROUPS),
|
||||
getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_WORLD_GROUPS),
|
||||
false
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
BackendServerCalculator serverCalculator = new BackendServerCalculator(this);
|
||||
contextManager.registerCalculator(serverCalculator);
|
||||
|
||||
LuckPermsCalculator<ProxiedPlayer> staticCalculator = new LuckPermsCalculator<>(getConfiguration());
|
||||
contextManager.registerCalculator(staticCalculator, true);
|
||||
// setup context manager
|
||||
contextManager = new BungeeContextManager(this);
|
||||
contextManager.registerCalculator(new BackendServerCalculator(this));
|
||||
contextManager.registerCalculator(new LuckPermsCalculator<>(getConfiguration()), true);
|
||||
|
||||
// register with the LP API
|
||||
apiProvider = new ApiProvider(this);
|
||||
|
||||
+6
-1
@@ -33,6 +33,7 @@ import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.bungee.LPBungeePlugin;
|
||||
import me.lucko.luckperms.common.calculators.AbstractCalculatorFactory;
|
||||
import me.lucko.luckperms.common.calculators.PermissionCalculator;
|
||||
import me.lucko.luckperms.common.calculators.PermissionCalculatorMetadata;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.processors.MapProcessor;
|
||||
@@ -60,7 +61,11 @@ public class BungeeCalculatorFactory extends AbstractCalculatorFactory {
|
||||
processors.add(new WildcardProcessor());
|
||||
}
|
||||
|
||||
return registerCalculator(new PermissionCalculator(plugin, user.getFriendlyName(), processors.build()));
|
||||
return registerCalculator(new PermissionCalculator(
|
||||
plugin,
|
||||
PermissionCalculatorMetadata.of(user.getFriendlyName(), contexts.getContexts()),
|
||||
processors.build()
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bungee.contexts;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
||||
import me.lucko.luckperms.bungee.LPBungeePlugin;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.contexts.ContextManager;
|
||||
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class BungeeContextManager extends ContextManager<ProxiedPlayer> {
|
||||
private final LPBungeePlugin plugin;
|
||||
|
||||
@Override
|
||||
public Contexts formContexts(ProxiedPlayer subject, ImmutableContextSet contextSet) {
|
||||
return new Contexts(
|
||||
contextSet,
|
||||
plugin.getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_PERMS),
|
||||
plugin.getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_WORLD_PERMS),
|
||||
true,
|
||||
plugin.getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_GROUPS),
|
||||
plugin.getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_WORLD_GROUPS),
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bungee.messaging;
|
||||
|
||||
import me.lucko.luckperms.bungee.LPBungeePlugin;
|
||||
import me.lucko.luckperms.common.messaging.InternalMessagingService;
|
||||
import me.lucko.luckperms.common.messaging.MessagingFactory;
|
||||
|
||||
public class BungeeMessagingFactory extends MessagingFactory<LPBungeePlugin> {
|
||||
public BungeeMessagingFactory(LPBungeePlugin plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InternalMessagingService getServiceFor(String messagingType) {
|
||||
if (messagingType.equals("bungee")) {
|
||||
BungeeMessagingService bungeeMessaging = new BungeeMessagingService(getPlugin());
|
||||
bungeeMessaging.init();
|
||||
return bungeeMessaging;
|
||||
} else if (messagingType.equals("redisbungee")) {
|
||||
if (getPlugin().getProxy().getPluginManager().getPlugin("RedisBungee") == null) {
|
||||
getPlugin().getLog().warn("RedisBungee plugin not present.");
|
||||
} else {
|
||||
RedisBungeeMessagingService redisBungeeMessaging = new RedisBungeeMessagingService(getPlugin());
|
||||
redisBungeeMessaging.init();
|
||||
return redisBungeeMessaging;
|
||||
}
|
||||
}
|
||||
|
||||
return super.getServiceFor(messagingType);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -89,7 +89,7 @@ public class BungeeMessagingService extends AbstractMessagingService implements
|
||||
|
||||
onMessage(e.getTag(), msg, u -> {
|
||||
// Forward to other servers
|
||||
plugin.doAsync(() -> sendMessage(CHANNEL, "update:" + u.toString()));
|
||||
plugin.doAsync(() -> sendMessage(CHANNEL, u));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -73,6 +73,10 @@ use-server-uuids: true
|
||||
# try to find a uuid for a username using RedisBungee, if installed.
|
||||
use-server-uuid-cache: false
|
||||
|
||||
# If LuckPerms should produce extra logging output when it handles logins.
|
||||
# Useful if you're having issues with UUID forwarding or data not being loaded.
|
||||
debug-logins: false
|
||||
|
||||
# If the plugin should send log notifications to users whenever permissions are modified.
|
||||
log-notify: true
|
||||
|
||||
@@ -104,6 +108,10 @@ temporary-add-behaviour: deny
|
||||
# directly and indirectly
|
||||
primary-group-calculation: stored
|
||||
|
||||
# If set to false, the plugin will allow a Users primary group to be removed with the
|
||||
# 'parent remove' command, and will set their primary group back to default.
|
||||
prevent-primary-group-removal: false
|
||||
|
||||
# If the plugin should check for "extra" permissions with users run LP commands.
|
||||
#
|
||||
# These extra permissions allow finer control over what users can do with each command, and
|
||||
@@ -263,6 +271,16 @@ messaging-service: none
|
||||
# If LuckPerms should automatically push updates after a change has been made with a command.
|
||||
auto-push-updates: true
|
||||
|
||||
# If LuckPerms should push logging entries to connected servers via the messaging service.
|
||||
push-log-entries: true
|
||||
|
||||
# If LuckPerms should broadcast received logging entries to players on this platform.
|
||||
#
|
||||
# If you have LuckPerms installed on your backend servers as well as a BungeeCord proxy, you should
|
||||
# set this option to false on either your backends or your proxies, to avoid players being messaged
|
||||
# twice about log entries.
|
||||
broadcast-received-log-entries: false
|
||||
|
||||
# Settings for Redis.
|
||||
# Port 6379 is used by default; set address to "host:port" if differs
|
||||
redis:
|
||||
|
||||
+18
-4
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>luckperms</artifactId>
|
||||
<groupId>me.lucko.luckperms</groupId>
|
||||
<version>3.3-SNAPSHOT</version>
|
||||
<version>3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -39,14 +39,28 @@
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>text</artifactId>
|
||||
<version>1.12-SNAPSHOT</version>
|
||||
<version>1.11-1.0.0</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>jsr305</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!-- HikariCP -->
|
||||
<dependency>
|
||||
<groupId>com.zaxxer</groupId>
|
||||
<artifactId>HikariCP</artifactId>
|
||||
<version>2.6.3</version>
|
||||
<version>2.7.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Jedis -->
|
||||
@@ -88,7 +102,7 @@
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
<version>2.5.2</version>
|
||||
<version>2.5.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Lombok -->
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.actionlog;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
|
||||
import me.lucko.luckperms.api.LogEntry;
|
||||
import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.model.Group;
|
||||
import me.lucko.luckperms.common.model.PermissionHolder;
|
||||
import me.lucko.luckperms.common.model.Track;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.utils.DateUtil;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* An extended version of {@link LogEntry}, with helper methods for
|
||||
* populating and using the entry using internal LuckPerms classes.
|
||||
*/
|
||||
public class ExtendedLogEntry extends LogEntry {
|
||||
public static ExtendedLogEntryBuilder build() {
|
||||
return new ExtendedLogEntryBuilder();
|
||||
}
|
||||
|
||||
public ExtendedLogEntry copy() {
|
||||
return (ExtendedLogEntry) super.copy();
|
||||
}
|
||||
|
||||
public void submit(LuckPermsPlugin plugin, Sender sender) {
|
||||
plugin.getLogDispatcher().dispatch(this, sender);
|
||||
}
|
||||
|
||||
public static JsonObject serializeWithId(UUID id, LogEntry entry) {
|
||||
JsonObject data = new JsonObject();
|
||||
|
||||
data.add("id", new JsonPrimitive(id.toString()));
|
||||
data.add("actor", new JsonPrimitive(entry.getActor().toString()));
|
||||
data.add("actorName", new JsonPrimitive(entry.getActorName()));
|
||||
data.add("type", new JsonPrimitive(entry.getEntryType().name()));
|
||||
if (entry.getActed() != null) {
|
||||
data.add("acted", new JsonPrimitive(entry.getActed().toString()));
|
||||
}
|
||||
data.add("actedName", new JsonPrimitive(entry.getActedName()));
|
||||
data.add("action", new JsonPrimitive(entry.getAction()));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public static Map.Entry<UUID, LogEntry> deserialize(JsonObject object) {
|
||||
LogEntry.LogEntryBuilder builder = LogEntry.builder();
|
||||
|
||||
UUID id = UUID.fromString(object.get("id").getAsString());
|
||||
|
||||
builder.actor(UUID.fromString(object.get("actor").getAsString()));
|
||||
builder.actorName(object.get("actorName").getAsString());
|
||||
builder.entryType(Type.valueOf(object.get("type").getAsString()));
|
||||
if (object.has("acted")) {
|
||||
builder.actor(UUID.fromString(object.get("acted").getAsString()));
|
||||
}
|
||||
builder.actedName(object.get("actedName").getAsString());
|
||||
builder.action(object.get("action").getAsString());
|
||||
|
||||
return Maps.immutableEntry(id, builder.build());
|
||||
}
|
||||
|
||||
public static class ExtendedLogEntryBuilder extends AbstractLogEntryBuilder<ExtendedLogEntry, ExtendedLogEntryBuilder> {
|
||||
|
||||
@Override
|
||||
protected ExtendedLogEntry createEmptyLog() {
|
||||
return new ExtendedLogEntry();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExtendedLogEntryBuilder getThisBuilder() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public ExtendedLogEntryBuilder actor(Sender actor) {
|
||||
super.actorName(actor.getName());
|
||||
super.actor(actor.getUuid());
|
||||
return this;
|
||||
}
|
||||
|
||||
public ExtendedLogEntryBuilder acted(PermissionHolder acted) {
|
||||
if (acted instanceof User) {
|
||||
super.actedName(((User) acted).getName().orElse("null"));
|
||||
super.acted(((User) acted).getUuid());
|
||||
super.entryType(Type.USER);
|
||||
} else if (acted instanceof Group) {
|
||||
super.actedName(((Group) acted).getName());
|
||||
super.entryType(Type.GROUP);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public ExtendedLogEntryBuilder acted(Track track) {
|
||||
super.actedName(track.getName());
|
||||
super.entryType(Type.TRACK);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExtendedLogEntry build() {
|
||||
if (getTimestamp() == 0L) {
|
||||
super.timestamp(DateUtil.unixSecondsNow());
|
||||
}
|
||||
|
||||
return super.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-7
@@ -23,7 +23,7 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.data;
|
||||
package me.lucko.luckperms.common.actionlog;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@@ -119,7 +119,8 @@ public class Log {
|
||||
|
||||
public SortedSet<LogEntry> getUserHistory(UUID uuid) {
|
||||
return content.stream()
|
||||
.filter(e -> e.getType() == 'U')
|
||||
.filter(e -> e.getEntryType() == LogEntry.Type.USER)
|
||||
.filter(e -> e.getActed() != null)
|
||||
.filter(e -> e.getActed().equals(uuid))
|
||||
.collect(Collectors.toCollection(TreeSet::new));
|
||||
}
|
||||
@@ -130,14 +131,15 @@ public class Log {
|
||||
|
||||
public int getUserHistoryMaxPages(UUID uuid) {
|
||||
return getMaxPages(content.stream()
|
||||
.filter(e -> e.getType() == 'U')
|
||||
.filter(e -> e.getEntryType() == LogEntry.Type.USER)
|
||||
.filter(e -> e.getActed() != null)
|
||||
.filter(e -> e.getActed().equals(uuid))
|
||||
.count(), PAGE_ENTRIES);
|
||||
}
|
||||
|
||||
public SortedSet<LogEntry> getGroupHistory(String name) {
|
||||
return content.stream()
|
||||
.filter(e -> e.getType() == 'G')
|
||||
.filter(e -> e.getEntryType() == LogEntry.Type.GROUP)
|
||||
.filter(e -> e.getActedName().equals(name))
|
||||
.collect(Collectors.toCollection(TreeSet::new));
|
||||
}
|
||||
@@ -148,14 +150,14 @@ public class Log {
|
||||
|
||||
public int getGroupHistoryMaxPages(String name) {
|
||||
return getMaxPages(content.stream()
|
||||
.filter(e -> e.getType() == 'G')
|
||||
.filter(e -> e.getEntryType() == LogEntry.Type.GROUP)
|
||||
.filter(e -> e.getActedName().equals(name))
|
||||
.count(), PAGE_ENTRIES);
|
||||
}
|
||||
|
||||
public SortedSet<LogEntry> getTrackHistory(String name) {
|
||||
return content.stream()
|
||||
.filter(e -> e.getType() == 'T')
|
||||
.filter(e -> e.getEntryType() == LogEntry.Type.TRACK)
|
||||
.filter(e -> e.getActedName().equals(name))
|
||||
.collect(Collectors.toCollection(TreeSet::new));
|
||||
}
|
||||
@@ -166,7 +168,7 @@ public class Log {
|
||||
|
||||
public int getTrackHistoryMaxPages(String name) {
|
||||
return getMaxPages(content.stream()
|
||||
.filter(e -> e.getType() == 'T')
|
||||
.filter(e -> e.getEntryType() == LogEntry.Type.TRACK)
|
||||
.filter(e -> e.getActedName().equals(name))
|
||||
.count(), PAGE_ENTRIES);
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.actionlog;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import me.lucko.luckperms.api.LogEntry;
|
||||
import me.lucko.luckperms.api.event.log.LogBroadcastEvent;
|
||||
import me.lucko.luckperms.common.commands.impl.log.LogNotify;
|
||||
import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.constants.CommandPermission;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
import me.lucko.luckperms.common.messaging.InternalMessagingService;
|
||||
import me.lucko.luckperms.common.messaging.NoopMessagingService;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class LogDispatcher {
|
||||
private final LuckPermsPlugin plugin;
|
||||
|
||||
public void dispatch(LogEntry entry, Sender sender) {
|
||||
// set the event to cancelled if the sender is import
|
||||
if (!plugin.getApiProvider().getEventFactory().handleLogPublish(sender.isImport(), entry)) {
|
||||
plugin.getStorage().logAction(entry);
|
||||
}
|
||||
|
||||
// don't dispatch log entries sent by an import process
|
||||
if (sender.isImport()) {
|
||||
return;
|
||||
}
|
||||
|
||||
InternalMessagingService messagingService = plugin.getMessagingService();
|
||||
if (!sender.isImport() && !(messagingService instanceof NoopMessagingService)) {
|
||||
messagingService.pushLog(entry);
|
||||
}
|
||||
|
||||
if (!plugin.getApiProvider().getEventFactory().handleLogBroadcast(!plugin.getConfiguration().get(ConfigKeys.LOG_NOTIFY), entry, LogBroadcastEvent.Origin.LOCAL)) {
|
||||
final String msg = entry.getFormatted();
|
||||
|
||||
List<Sender> senders = plugin.getOnlineSenders();
|
||||
senders.add(plugin.getConsoleSender());
|
||||
|
||||
senders.stream()
|
||||
.filter(CommandPermission.LOG_NOTIFY::isAuthorized)
|
||||
.filter(s -> !LogNotify.isIgnoring(plugin, s.getUuid()))
|
||||
.filter(s -> !s.getUuid().equals(sender.getUuid()))
|
||||
.forEach(s -> Message.LOG.send(s, msg));
|
||||
}
|
||||
}
|
||||
|
||||
public void dispatchFromRemote(LogEntry entry) {
|
||||
if (!plugin.getConfiguration().get(ConfigKeys.BROADCAST_RECEIVED_LOG_ENTRIES)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!plugin.getApiProvider().getEventFactory().handleLogBroadcast(!plugin.getConfiguration().get(ConfigKeys.LOG_NOTIFY), entry, LogBroadcastEvent.Origin.REMOTE)) {
|
||||
final String msg = entry.getFormatted();
|
||||
|
||||
List<Sender> senders = plugin.getOnlineSenders();
|
||||
senders.add(plugin.getConsoleSender());
|
||||
|
||||
senders.stream()
|
||||
.filter(CommandPermission.LOG_NOTIFY::isAuthorized)
|
||||
.filter(s -> !LogNotify.isIgnoring(plugin, s.getUuid()))
|
||||
.forEach(s -> Message.LOG.send(s, msg));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,18 +31,23 @@ import me.lucko.luckperms.api.LuckPermsApi;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class ApiHandler {
|
||||
private static Method REGISTER;
|
||||
private static Method UNREGISTER;
|
||||
private static final Method REGISTER;
|
||||
private static final Method UNREGISTER;
|
||||
static {
|
||||
Method register = null;
|
||||
Method unregister = null;
|
||||
try {
|
||||
REGISTER = LuckPerms.class.getDeclaredMethod("registerProvider", LuckPermsApi.class);
|
||||
REGISTER.setAccessible(true);
|
||||
register = LuckPerms.class.getDeclaredMethod("registerProvider", LuckPermsApi.class);
|
||||
register.setAccessible(true);
|
||||
|
||||
UNREGISTER = LuckPerms.class.getDeclaredMethod("unregisterProvider");
|
||||
UNREGISTER.setAccessible(true);
|
||||
unregister = LuckPerms.class.getDeclaredMethod("unregisterProvider");
|
||||
unregister.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
REGISTER = register;
|
||||
UNREGISTER = unregister;
|
||||
}
|
||||
|
||||
public static void registerProvider(LuckPermsApi luckPermsApi) {
|
||||
|
||||
@@ -88,7 +88,7 @@ public class ApiProvider implements LuckPermsApi {
|
||||
|
||||
@Override
|
||||
public double getApiVersion() {
|
||||
return 3.3;
|
||||
return 3.4;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -38,11 +38,11 @@ import java.util.UUID;
|
||||
import static me.lucko.luckperms.common.api.ApiUtils.checkName;
|
||||
|
||||
/**
|
||||
* Provides a link between {@link Log} and {@link me.lucko.luckperms.common.data.Log}
|
||||
* Provides a link between {@link Log} and {@link me.lucko.luckperms.common.actionlog.Log}
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
public class LogDelegate implements Log {
|
||||
private final me.lucko.luckperms.common.data.Log handle;
|
||||
private final me.lucko.luckperms.common.actionlog.Log handle;
|
||||
|
||||
@Override
|
||||
public SortedSet<LogEntry> getContent() {
|
||||
|
||||
+2
-2
@@ -33,8 +33,8 @@ import com.google.common.collect.ImmutableList;
|
||||
import me.lucko.luckperms.api.metastacking.MetaStackDefinition;
|
||||
import me.lucko.luckperms.api.metastacking.MetaStackElement;
|
||||
import me.lucko.luckperms.api.metastacking.MetaStackFactory;
|
||||
import me.lucko.luckperms.common.metastacking.definition.SimpleMetaStackDefinition;
|
||||
import me.lucko.luckperms.common.metastacking.definition.StandardStackElements;
|
||||
import me.lucko.luckperms.common.metastacking.SimpleMetaStackDefinition;
|
||||
import me.lucko.luckperms.common.metastacking.StandardStackElements;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
+5
-4
@@ -43,6 +43,7 @@ import me.lucko.luckperms.api.context.ImmutableContextSet;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.common.contexts.ExtractedContexts;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.node.MetaType;
|
||||
import me.lucko.luckperms.common.node.NodeFactory;
|
||||
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
|
||||
import me.lucko.luckperms.exceptions.ObjectLacksException;
|
||||
@@ -381,12 +382,12 @@ public class PermissionHolderDelegate implements PermissionHolder {
|
||||
|
||||
@Override
|
||||
public void clearMeta() {
|
||||
handle.clearMeta();
|
||||
handle.clearMeta(MetaType.ANY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearMeta(@NonNull ContextSet contextSet) {
|
||||
handle.clearMeta(contextSet);
|
||||
handle.clearMeta(MetaType.ANY, contextSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -396,7 +397,7 @@ public class PermissionHolderDelegate implements PermissionHolder {
|
||||
set.add("server", server);
|
||||
}
|
||||
|
||||
handle.clearMeta(set);
|
||||
handle.clearMeta(MetaType.ANY, set);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -409,7 +410,7 @@ public class PermissionHolderDelegate implements PermissionHolder {
|
||||
set.add("world", world);
|
||||
}
|
||||
|
||||
handle.clearMeta(set);
|
||||
handle.clearMeta(MetaType.ANY, set);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -79,57 +79,57 @@ public class StorageDelegate implements Storage {
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> logAction(@NonNull LogEntry entry) {
|
||||
return handle.force().logAction(entry);
|
||||
return handle.noBuffer().logAction(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Log> getLog() {
|
||||
return handle.force().getLog().thenApply(log -> log == null ? null : new LogDelegate(log));
|
||||
return handle.noBuffer().getLog().thenApply(log -> log == null ? null : new LogDelegate(log));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> loadUser(@NonNull UUID uuid, String username) {
|
||||
return handle.force().loadUser(uuid, username == null ? null : checkUsername(username));
|
||||
return handle.noBuffer().loadUser(uuid, username == null ? null : checkUsername(username));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> saveUser(@NonNull User user) {
|
||||
return handle.force().saveUser(UserDelegate.cast(user));
|
||||
return handle.noBuffer().saveUser(UserDelegate.cast(user));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> cleanupUsers() {
|
||||
return handle.force().cleanupUsers();
|
||||
return handle.noBuffer().cleanupUsers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Set<UUID>> getUniqueUsers() {
|
||||
return handle.force().getUniqueUsers();
|
||||
return handle.noBuffer().getUniqueUsers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<List<HeldPermission<UUID>>> getUsersWithPermission(@NonNull String permission) {
|
||||
return handle.force().getUsersWithPermission(permission);
|
||||
return handle.noBuffer().getUsersWithPermission(permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> createAndLoadGroup(@NonNull String name) {
|
||||
return handle.force().createAndLoadGroup(checkName(name), CreationCause.API);
|
||||
return handle.noBuffer().createAndLoadGroup(checkName(name), CreationCause.API);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> loadGroup(@NonNull String name) {
|
||||
return handle.force().loadGroup(checkName(name));
|
||||
return handle.noBuffer().loadGroup(checkName(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> loadAllGroups() {
|
||||
return handle.force().loadAllGroups();
|
||||
return handle.noBuffer().loadAllGroups();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> saveGroup(@NonNull Group group) {
|
||||
return handle.force().saveGroup(GroupDelegate.cast(group));
|
||||
return handle.noBuffer().saveGroup(GroupDelegate.cast(group));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -137,51 +137,51 @@ public class StorageDelegate implements Storage {
|
||||
if (group.getName().equalsIgnoreCase(plugin.getConfiguration().get(ConfigKeys.DEFAULT_GROUP_NAME))) {
|
||||
throw new IllegalArgumentException("Cannot delete the default group.");
|
||||
}
|
||||
return handle.force().deleteGroup(GroupDelegate.cast(group), DeletionCause.API);
|
||||
return handle.noBuffer().deleteGroup(GroupDelegate.cast(group), DeletionCause.API);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<List<HeldPermission<String>>> getGroupsWithPermission(@NonNull String permission) {
|
||||
return handle.force().getGroupsWithPermission(permission);
|
||||
return handle.noBuffer().getGroupsWithPermission(permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> createAndLoadTrack(@NonNull String name) {
|
||||
return handle.force().createAndLoadTrack(checkName(name), CreationCause.API);
|
||||
return handle.noBuffer().createAndLoadTrack(checkName(name), CreationCause.API);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> loadTrack(@NonNull String name) {
|
||||
return handle.force().loadTrack(checkName(name));
|
||||
return handle.noBuffer().loadTrack(checkName(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> loadAllTracks() {
|
||||
return handle.force().loadAllTracks();
|
||||
return handle.noBuffer().loadAllTracks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> saveTrack(@NonNull Track track) {
|
||||
return handle.force().saveTrack(TrackDelegate.cast(track));
|
||||
return handle.noBuffer().saveTrack(TrackDelegate.cast(track));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> deleteTrack(@NonNull Track track) {
|
||||
return handle.force().deleteTrack(TrackDelegate.cast(track), DeletionCause.API);
|
||||
return handle.noBuffer().deleteTrack(TrackDelegate.cast(track), DeletionCause.API);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> saveUUIDData(@NonNull String username, @NonNull UUID uuid) {
|
||||
return handle.force().saveUUIDData(checkUsername(username), uuid);
|
||||
return handle.noBuffer().saveUUIDData(checkUsername(username), uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<UUID> getUUID(@NonNull String username) {
|
||||
return handle.force().getUUID(checkUsername(username));
|
||||
return handle.noBuffer().getUUID(checkUsername(username));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<String> getName(@NonNull UUID uuid) {
|
||||
return handle.force().getName(uuid);
|
||||
return handle.noBuffer().getName(uuid);
|
||||
}
|
||||
}
|
||||
+35
-45
@@ -23,18 +23,20 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.data;
|
||||
package me.lucko.luckperms.common.backup;
|
||||
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.commands.utils.Util;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
import me.lucko.luckperms.common.logging.ProgressLogger;
|
||||
import me.lucko.luckperms.common.model.Group;
|
||||
import me.lucko.luckperms.common.model.Track;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.node.NodeFactory;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.storage.Storage;
|
||||
import me.lucko.luckperms.common.utils.Cycle;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
@@ -44,7 +46,6 @@ import java.nio.file.Path;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -54,7 +55,7 @@ import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Handles export operations
|
||||
@@ -62,15 +63,6 @@ import java.util.function.Function;
|
||||
public class Exporter implements Runnable {
|
||||
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
|
||||
|
||||
// number of users --> the value to divide the list by. base value of 1000 per thread, with a max of 10 threads. so, 3000 = 3 threads, 10000+ = 10 threads
|
||||
private static final Function<Integer, Integer> THREAD_COUNT_FUNCTION = usersCount -> {
|
||||
// how many threads to make. must be 1 <= x <= 15
|
||||
int i = Math.max(1, Math.min(15, usersCount / 1000));
|
||||
|
||||
// then work out the value to split at. e.g. if we have 1,000 users to export and 2 threads, we should split at every 500 users.
|
||||
return Math.max(1, usersCount / i);
|
||||
};
|
||||
|
||||
private static void write(BufferedWriter writer, String s) {
|
||||
try {
|
||||
writer.write(s);
|
||||
@@ -109,34 +101,34 @@ public class Exporter implements Runnable {
|
||||
|
||||
// Create the actual groups first
|
||||
write(writer, "# Create groups");
|
||||
plugin.getGroupManager().getAll().values().stream()
|
||||
.sorted((o1, o2) -> {
|
||||
int i = Integer.compare(o2.getWeight().orElse(0), o1.getWeight().orElse(0));
|
||||
return i != 0 ? i : o1.getName().compareToIgnoreCase(o2.getName());
|
||||
})
|
||||
.filter(g -> !g.getName().equals("default"))
|
||||
.forEach(group -> {
|
||||
write(writer, "/luckperms creategroup " + group.getName());
|
||||
});
|
||||
|
||||
write(writer, "");
|
||||
|
||||
AtomicInteger groupCount = new AtomicInteger(0);
|
||||
|
||||
// export groups in order of weight
|
||||
plugin.getGroupManager().getAll().values().stream()
|
||||
List<? extends Group> groups = plugin.getGroupManager().getAll().values().stream()
|
||||
// export groups in order of weight
|
||||
.sorted((o1, o2) -> {
|
||||
int i = Integer.compare(o2.getWeight().orElse(0), o1.getWeight().orElse(0));
|
||||
return i != 0 ? i : o1.getName().compareToIgnoreCase(o2.getName());
|
||||
})
|
||||
.forEach(group -> {
|
||||
write(writer, "# Export group: " + group.getName());
|
||||
for (Node node : group.getEnduringNodes().values()) {
|
||||
write(writer, NodeFactory.nodeAsCommand(node, group.getName(), true, true));
|
||||
}
|
||||
write(writer, "");
|
||||
log.logAllProgress("Exported {} groups so far.", groupCount.incrementAndGet());
|
||||
});
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
for (Group group : groups) {
|
||||
if (!group.getName().equals("default")) {
|
||||
write(writer, "/luckperms creategroup " + group.getName());
|
||||
}
|
||||
}
|
||||
|
||||
for (Group group : groups) {
|
||||
if (groupCount.get() == 0) {
|
||||
write(writer, "");
|
||||
}
|
||||
|
||||
write(writer, "# Export group: " + group.getName());
|
||||
for (Node node : group.getEnduringNodes().values()) {
|
||||
write(writer, NodeFactory.nodeAsCommand(node, group.getName(), true, true));
|
||||
}
|
||||
write(writer, "");
|
||||
log.logAllProgress("Exported {} groups so far.", groupCount.incrementAndGet());
|
||||
}
|
||||
|
||||
log.log("Exported " + groupCount.get() + " groups.");
|
||||
|
||||
@@ -187,17 +179,13 @@ public class Exporter implements Runnable {
|
||||
|
||||
write(writer, "# Export users");
|
||||
|
||||
List<List<UUID>> subUsers;
|
||||
AtomicInteger userCount = new AtomicInteger(0);
|
||||
|
||||
// not really that many users, so it's not really worth spreading the load.
|
||||
if (users.size() < 1500) {
|
||||
subUsers = Collections.singletonList(new ArrayList<>(users));
|
||||
} else {
|
||||
subUsers = Util.divideList(users, THREAD_COUNT_FUNCTION.apply(users.size()));
|
||||
// divide into 16 pools.
|
||||
Cycle<List<UUID>> userPools = new Cycle<>(Util.nInstances(32, ArrayList::new));
|
||||
for (UUID uuid : users) {
|
||||
userPools.next().add(uuid);
|
||||
}
|
||||
|
||||
log.log("Split users into " + subUsers.size() + " threads for export.");
|
||||
log.log("Split users into " + userPools.getBacking().size() + " threads for export.");
|
||||
|
||||
// Setup a file writing lock. We don't want multiple threads writing at the same time.
|
||||
// The write function accepts a list of strings, as we want a user's data to be grouped together.
|
||||
@@ -217,8 +205,10 @@ public class Exporter implements Runnable {
|
||||
// A set of futures, which are really just the threads we need to wait for.
|
||||
Set<CompletableFuture<Void>> futures = new HashSet<>();
|
||||
|
||||
AtomicInteger userCount = new AtomicInteger(0);
|
||||
|
||||
// iterate through each user sublist.
|
||||
for (List<UUID> subList : subUsers) {
|
||||
for (List<UUID> subList : userPools.getBacking()) {
|
||||
|
||||
// register and start a new thread to process the sublist
|
||||
futures.add(CompletableFuture.runAsync(() -> {
|
||||
@@ -229,7 +219,7 @@ public class Exporter implements Runnable {
|
||||
// actually export the user. this output will be fed to the writing function when we have all of the user's data.
|
||||
List<String> output = new ArrayList<>();
|
||||
|
||||
plugin.getStorage().loadUser(uuid, "null").join();
|
||||
plugin.getStorage().loadUser(uuid, null).join();
|
||||
User user = plugin.getUserManager().getIfLoaded(uuid);
|
||||
output.add("# Export user: " + user.getUuid().toString() + " - " + user.getName().orElse("unknown username"));
|
||||
|
||||
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.backup;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import me.lucko.luckperms.common.commands.CommandManager;
|
||||
import me.lucko.luckperms.common.commands.CommandResult;
|
||||
import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.commands.utils.Util;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
import me.lucko.luckperms.common.utils.Cycle;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Handles import operations
|
||||
*/
|
||||
public class Importer implements Runnable {
|
||||
|
||||
private final CommandManager commandManager;
|
||||
private final Set<Sender> notify;
|
||||
private final List<String> commands;
|
||||
private final List<ImportCommand> toExecute;
|
||||
|
||||
public Importer(CommandManager commandManager, Sender executor, List<String> commands) {
|
||||
this.commandManager = commandManager;
|
||||
|
||||
if (executor.isConsole()) {
|
||||
this.notify = ImmutableSet.of(executor);
|
||||
} else {
|
||||
this.notify = ImmutableSet.of(executor, commandManager.getPlugin().getConsoleSender());
|
||||
}
|
||||
this.commands = commands.stream()
|
||||
.map(String::trim)
|
||||
.filter(s -> !s.isEmpty())
|
||||
.filter(s -> !s.startsWith("#"))
|
||||
.filter(s -> !s.startsWith("//"))
|
||||
.map(s -> s.startsWith("/") ? s.substring("/".length()) : s)
|
||||
.map(s -> s.startsWith("perms ") ? s.substring("perms ".length()) : s)
|
||||
.map(s -> s.startsWith("lp ") ? s.substring("lp ".length()) : s)
|
||||
.map(s -> s.startsWith("luckperms ") ? s.substring("luckperms ".length()) : s)
|
||||
.collect(Collectors.toList());
|
||||
this.toExecute = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
long startTime = System.currentTimeMillis();
|
||||
notify.forEach(s -> Message.IMPORT_START.send(s));
|
||||
|
||||
// form instances for all commands, and register them
|
||||
int index = 1;
|
||||
for (String command : commands) {
|
||||
ImportCommand cmd = new ImportCommand(commandManager, index, command);
|
||||
toExecute.add(cmd);
|
||||
|
||||
if (cmd.getCommand().startsWith("creategroup ") || cmd.getCommand().startsWith("createtrack")) {
|
||||
cmd.process(); // process immediately
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
// divide commands up into pools
|
||||
Cycle<List<ImportCommand>> commandPools = new Cycle<>(Util.nInstances(128, ArrayList::new));
|
||||
|
||||
String lastTarget = null;
|
||||
for (ImportCommand cmd : toExecute) {
|
||||
// if the last target isn't the same, skip to a new pool
|
||||
if (lastTarget == null || !lastTarget.equals(cmd.getTarget())) {
|
||||
commandPools.next();
|
||||
}
|
||||
|
||||
commandPools.current().add(cmd);
|
||||
lastTarget = cmd.getTarget();
|
||||
}
|
||||
|
||||
// A set of futures, which are really just the threads we need to wait for.
|
||||
Set<CompletableFuture<Void>> futures = new HashSet<>();
|
||||
|
||||
AtomicInteger processedCount = new AtomicInteger(0);
|
||||
|
||||
// iterate through each user sublist.
|
||||
for (List<ImportCommand> subList : commandPools.getBacking()) {
|
||||
|
||||
// register and start a new thread to process the sublist
|
||||
futures.add(CompletableFuture.runAsync(() -> {
|
||||
|
||||
// iterate through each user in the sublist, and grab their data.
|
||||
for (ImportCommand cmd : subList) {
|
||||
cmd.process();
|
||||
processedCount.incrementAndGet();
|
||||
}
|
||||
}, commandManager.getPlugin().getScheduler().async()));
|
||||
}
|
||||
|
||||
// all of the threads have been scheduled now and are running. we just need to wait for them all to complete
|
||||
CompletableFuture<Void> overallFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]));
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
overallFuture.get(10, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
// abnormal error - just break
|
||||
e.printStackTrace();
|
||||
break;
|
||||
} catch (TimeoutException e) {
|
||||
// still executing - send a progress report and continue waiting
|
||||
sendProgress(processedCount.get());
|
||||
continue;
|
||||
}
|
||||
|
||||
// process is complete
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
long endTime = System.currentTimeMillis();
|
||||
double seconds = (endTime - startTime) / 1000;
|
||||
|
||||
int errors = (int) toExecute.stream().filter(v -> !v.getResult().asBoolean()).count();
|
||||
|
||||
if (errors == 0) {
|
||||
notify.forEach(s -> Message.IMPORT_END_COMPLETE.send(s, seconds));
|
||||
} else if (errors == 1) {
|
||||
notify.forEach(s -> Message.IMPORT_END_COMPLETE_ERR_SIN.send(s, seconds, errors));
|
||||
} else {
|
||||
notify.forEach(s -> Message.IMPORT_END_COMPLETE_ERR.send(s, seconds, errors));
|
||||
}
|
||||
|
||||
AtomicInteger errIndex = new AtomicInteger(1);
|
||||
for (ImportCommand e : toExecute) {
|
||||
if (e.getResult() != null && !e.getResult().asBoolean()) {
|
||||
notify.forEach(s -> {
|
||||
Message.IMPORT_END_ERROR_HEADER.send(s, errIndex.get(), e.getId(), e.getCommand(), e.getResult().toString());
|
||||
for (String out : e.getOutput()) {
|
||||
Message.IMPORT_END_ERROR_CONTENT.send(s, out);
|
||||
}
|
||||
Message.IMPORT_END_ERROR_FOOTER.send(s);
|
||||
});
|
||||
|
||||
errIndex.incrementAndGet();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendProgress(int processedCount) {
|
||||
int percent = (processedCount * 100) / commands.size();
|
||||
int errors = (int) toExecute.stream().filter(v -> v.isCompleted() && !v.getResult().asBoolean()).count();
|
||||
|
||||
if (errors == 1) {
|
||||
notify.forEach(s -> Message.IMPORT_PROGRESS_SIN.send(s, percent, processedCount, commands.size(), errors));
|
||||
} else {
|
||||
notify.forEach(s -> Message.IMPORT_PROGRESS.send(s, percent, processedCount, commands.size(), errors));
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
private static class ImportCommand extends ImporterSender {
|
||||
private static final Splitter SPACE_SPLIT = Splitter.on(" ");
|
||||
|
||||
private final CommandManager commandManager;
|
||||
private final int id;
|
||||
private final String command;
|
||||
|
||||
private final String target;
|
||||
|
||||
@Setter
|
||||
private boolean completed = false;
|
||||
|
||||
private final List<String> output = new ArrayList<>();
|
||||
|
||||
@Setter
|
||||
private CommandResult result = CommandResult.FAILURE;
|
||||
|
||||
ImportCommand(CommandManager commandManager, int id, String command) {
|
||||
super(commandManager.getPlugin());
|
||||
this.commandManager = commandManager;
|
||||
this.id = id;
|
||||
this.command = command;
|
||||
this.target = determineTarget(command);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void consumeMessage(String s) {
|
||||
output.add(s);
|
||||
}
|
||||
|
||||
public void process() {
|
||||
if (isCompleted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
CommandResult result = commandManager.onCommand(
|
||||
this,
|
||||
"lp",
|
||||
Util.stripQuotes(Splitter.on(CommandManager.COMMAND_SEPARATOR_PATTERN).omitEmptyStrings().splitToList(getCommand()))
|
||||
).get();
|
||||
setResult(result);
|
||||
|
||||
} catch (Exception e) {
|
||||
setResult(CommandResult.FAILURE);
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
setCompleted(true);
|
||||
}
|
||||
|
||||
private static String determineTarget(String command) {
|
||||
if (command.startsWith("user ") && command.length() > "user ".length()) {
|
||||
String subCmd = command.substring("user ".length());
|
||||
if (!subCmd.contains(" ")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String targetUser = SPACE_SPLIT.split(subCmd).iterator().next();
|
||||
return "u:" + targetUser;
|
||||
}
|
||||
|
||||
if (command.startsWith("group ") && command.length() > "group ".length()) {
|
||||
String subCmd = command.substring("group ".length());
|
||||
if (!subCmd.contains(" ")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String targetGroup = SPACE_SPLIT.split(subCmd).iterator().next();
|
||||
return "g:" + targetGroup;
|
||||
}
|
||||
|
||||
if (command.startsWith("track ") && command.length() > "track ".length()) {
|
||||
String subCmd = command.substring("track ".length());
|
||||
if (!subCmd.contains(" ")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String targetTrack = SPACE_SPLIT.split(subCmd).iterator().next();
|
||||
return "t:" + targetTrack;
|
||||
}
|
||||
|
||||
if (command.startsWith("creategroup ") && command.length() > "creategroup ".length()) {
|
||||
String targetGroup = command.substring("creategroup ".length());
|
||||
return "g:" + targetGroup;
|
||||
}
|
||||
|
||||
if (command.startsWith("createtrack ") && command.length() > "createtrack ".length()) {
|
||||
String targetTrack = command.substring("createtrack ".length());
|
||||
return "t:" + targetTrack;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+8
-7
@@ -23,7 +23,7 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.data;
|
||||
package me.lucko.luckperms.common.backup;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
@@ -32,17 +32,17 @@ import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.constants.CommandPermission;
|
||||
import me.lucko.luckperms.common.constants.Constants;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.utils.TextUtils;
|
||||
|
||||
import net.kyori.text.Component;
|
||||
import net.kyori.text.serializer.ComponentSerializer;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class ImporterSender implements Sender {
|
||||
public abstract class ImporterSender implements Sender {
|
||||
private final LuckPermsPlugin plugin;
|
||||
private final Consumer<String> messageConsumer;
|
||||
|
||||
protected abstract void consumeMessage(String s);
|
||||
|
||||
@Override
|
||||
public LuckPermsPlugin getPlatform() {
|
||||
@@ -61,12 +61,13 @@ public class ImporterSender implements Sender {
|
||||
|
||||
@Override
|
||||
public void sendMessage(String s) {
|
||||
messageConsumer.accept(s);
|
||||
consumeMessage(s);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void sendMessage(Component message) {
|
||||
messageConsumer.accept(ComponentSerializer.toLegacy(message, Constants.COLOR_CHAR));
|
||||
consumeMessage(TextUtils.toLegacy(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -45,6 +45,7 @@ import java.util.function.Supplier;
|
||||
@RequiredArgsConstructor
|
||||
public abstract class BufferedRequest<T> {
|
||||
private final long bufferTimeMillis;
|
||||
private final long sleepInterval;
|
||||
private final Executor executor;
|
||||
|
||||
private WeakReference<Processor<T>> processor = null;
|
||||
@@ -60,7 +61,7 @@ public abstract class BufferedRequest<T> {
|
||||
}
|
||||
}
|
||||
|
||||
Processor<T> p = new Processor<>(bufferTimeMillis, this::perform);
|
||||
Processor<T> p = new Processor<>(bufferTimeMillis, sleepInterval, this::perform);
|
||||
executor.execute(p);
|
||||
processor = new WeakReference<>(p);
|
||||
return p.get();
|
||||
@@ -79,6 +80,7 @@ public abstract class BufferedRequest<T> {
|
||||
@RequiredArgsConstructor
|
||||
private static class Processor<R> implements Runnable {
|
||||
private final long delayMillis;
|
||||
private final long sleepMillis;
|
||||
private final Supplier<R> supplier;
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
private final CompletableFuture<R> future = new CompletableFuture<>();
|
||||
@@ -108,7 +110,7 @@ public abstract class BufferedRequest<T> {
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
Thread.sleep(sleepMillis);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.buffers;
|
||||
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.tasks.UpdateTask;
|
||||
|
||||
public class UpdateTaskBuffer extends BufferedRequest<Void> {
|
||||
private final LuckPermsPlugin plugin;
|
||||
|
||||
public UpdateTaskBuffer(LuckPermsPlugin plugin) {
|
||||
super(250L, 50L, plugin::doAsync);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void perform() {
|
||||
new UpdateTask(plugin).run();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -36,8 +36,8 @@ import com.google.common.collect.ListMultimap;
|
||||
import me.lucko.luckperms.api.ChatMetaType;
|
||||
import me.lucko.luckperms.api.LocalizedNode;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.metastacking.GenericMetaStack;
|
||||
import me.lucko.luckperms.common.metastacking.MetaStack;
|
||||
import me.lucko.luckperms.common.metastacking.SimpleMetaStack;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
|
||||
import java.util.Comparator;
|
||||
@@ -46,15 +46,16 @@ import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* Holds temporary mutable meta whilst this object is passed up the inheritance tree to accumulate meta from parents
|
||||
* Holds temporary mutable meta whilst this object is passed up the
|
||||
* inheritance tree to accumulate meta from parents
|
||||
*/
|
||||
@Getter
|
||||
@ToString
|
||||
public class MetaAccumulator {
|
||||
public static MetaAccumulator makeFromConfig(LuckPermsPlugin plugin) {
|
||||
return new MetaAccumulator(
|
||||
new GenericMetaStack(plugin.getConfiguration().get(ConfigKeys.PREFIX_FORMATTING_OPTIONS), ChatMetaType.PREFIX),
|
||||
new GenericMetaStack(plugin.getConfiguration().get(ConfigKeys.SUFFIX_FORMATTING_OPTIONS), ChatMetaType.SUFFIX)
|
||||
new SimpleMetaStack(plugin.getConfiguration().get(ConfigKeys.PREFIX_FORMATTING_OPTIONS), ChatMetaType.PREFIX),
|
||||
new SimpleMetaStack(plugin.getConfiguration().get(ConfigKeys.SUFFIX_FORMATTING_OPTIONS), ChatMetaType.SUFFIX)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -104,7 +105,8 @@ public class MetaAccumulator {
|
||||
this.weight = Math.max(this.weight, weight);
|
||||
}
|
||||
|
||||
// We can assume that if this method is being called, this holder is effectively finalized. (it's not going to accumulate more nodes)
|
||||
// We can assume that if this method is being called, this holder is effectively finalized.
|
||||
// (it's not going to accumulate more nodes)
|
||||
// Therefore, it should be ok to set the weight meta key, if not already present.
|
||||
public ListMultimap<String, String> getMeta() {
|
||||
if (!this.meta.containsKey("weight") && this.weight != 0) {
|
||||
|
||||
@@ -33,6 +33,7 @@ import me.lucko.luckperms.api.caching.PermissionData;
|
||||
import me.lucko.luckperms.common.calculators.CalculatorFactory;
|
||||
import me.lucko.luckperms.common.calculators.PermissionCalculator;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.verbose.CheckOrigin;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
@@ -93,6 +94,10 @@ public class PermissionCache implements PermissionData {
|
||||
|
||||
@Override
|
||||
public Tristate getPermissionValue(@NonNull String permission) {
|
||||
return calculator.getPermissionValue(permission);
|
||||
return calculator.getPermissionValue(permission, CheckOrigin.API);
|
||||
}
|
||||
|
||||
public Tristate getPermissionValue(@NonNull String permission, CheckOrigin origin) {
|
||||
return calculator.getPermissionValue(permission, origin);
|
||||
}
|
||||
}
|
||||
@@ -36,12 +36,11 @@ import com.google.common.collect.ImmutableSet;
|
||||
import me.lucko.luckperms.api.ChatMetaType;
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.caching.MetaContexts;
|
||||
import me.lucko.luckperms.api.caching.MetaData;
|
||||
import me.lucko.luckperms.api.caching.PermissionData;
|
||||
import me.lucko.luckperms.api.caching.UserData;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.contexts.ExtractedContexts;
|
||||
import me.lucko.luckperms.common.metastacking.GenericMetaStack;
|
||||
import me.lucko.luckperms.common.metastacking.SimpleMetaStack;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
|
||||
@@ -68,17 +67,17 @@ public class UserCache implements UserData {
|
||||
.build(new MetaCacheLoader());
|
||||
|
||||
@Override
|
||||
public PermissionData getPermissionData(@NonNull Contexts contexts) {
|
||||
public PermissionCache getPermissionData(@NonNull Contexts contexts) {
|
||||
return permission.get(contexts);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetaData getMetaData(@NonNull MetaContexts contexts) {
|
||||
public MetaCache getMetaData(@NonNull MetaContexts contexts) {
|
||||
return meta.get(contexts);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetaData getMetaData(@NonNull Contexts contexts) {
|
||||
public MetaCache getMetaData(@NonNull Contexts contexts) {
|
||||
// just create a MetaContexts instance using the values in the config
|
||||
return getMetaData(makeFromMetaContextsConfig(contexts, user.getPlugin()));
|
||||
}
|
||||
@@ -219,8 +218,8 @@ public class UserCache implements UserData {
|
||||
|
||||
private static MetaAccumulator newAccumulator(MetaContexts contexts) {
|
||||
return new MetaAccumulator(
|
||||
new GenericMetaStack(contexts.getPrefixStackDefinition(), ChatMetaType.PREFIX),
|
||||
new GenericMetaStack(contexts.getSuffixStackDefinition(), ChatMetaType.SUFFIX)
|
||||
new SimpleMetaStack(contexts.getPrefixStackDefinition(), ChatMetaType.PREFIX),
|
||||
new SimpleMetaStack(contexts.getSuffixStackDefinition(), ChatMetaType.SUFFIX)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+4
-3
@@ -33,6 +33,7 @@ import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.processors.PermissionProcessor;
|
||||
import me.lucko.luckperms.common.verbose.CheckOrigin;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -43,7 +44,7 @@ import java.util.Map;
|
||||
@RequiredArgsConstructor
|
||||
public class PermissionCalculator {
|
||||
private final LuckPermsPlugin plugin;
|
||||
private final String objectName;
|
||||
private final PermissionCalculatorMetadata metadata;
|
||||
private final List<PermissionProcessor> processors;
|
||||
|
||||
// caches lookup calls.
|
||||
@@ -54,7 +55,7 @@ public class PermissionCalculator {
|
||||
lookupCache.invalidateAll();
|
||||
}
|
||||
|
||||
public Tristate getPermissionValue(String permission) {
|
||||
public Tristate getPermissionValue(String permission, CheckOrigin origin) {
|
||||
|
||||
// convert the permission to lowercase, as all values in the backing map are also lowercase.
|
||||
// this allows fast case insensitive lookups
|
||||
@@ -64,7 +65,7 @@ public class PermissionCalculator {
|
||||
Tristate result = lookupCache.get(permission);
|
||||
|
||||
// log this permission lookup to the verbose handler
|
||||
plugin.getVerboseHandler().offerCheckData(objectName, permission, result);
|
||||
plugin.getVerboseHandler().offerCheckData(origin, metadata.getObjectName(), metadata.getContext(), permission, result);
|
||||
|
||||
// return the result
|
||||
return result;
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.calculators;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor(staticName = "of")
|
||||
public class PermissionCalculatorMetadata {
|
||||
|
||||
/**
|
||||
* The name of the object which owns the permission calculator
|
||||
*/
|
||||
private final String objectName;
|
||||
|
||||
/**
|
||||
* The context the permission calculator works with
|
||||
*/
|
||||
private final ContextSet context;
|
||||
|
||||
}
|
||||
@@ -63,18 +63,15 @@ import me.lucko.luckperms.common.locale.Message;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.utils.TextUtils;
|
||||
|
||||
import net.kyori.text.Component;
|
||||
import net.kyori.text.TextComponent;
|
||||
import net.kyori.text.event.ClickEvent;
|
||||
import net.kyori.text.event.HoverEvent;
|
||||
import net.kyori.text.serializer.ComponentSerializer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -84,14 +81,11 @@ public class CommandManager {
|
||||
@Getter
|
||||
private final LuckPermsPlugin plugin;
|
||||
|
||||
private final ExecutorService executor;
|
||||
|
||||
@Getter
|
||||
private final List<Command> mainCommands;
|
||||
|
||||
public CommandManager(LuckPermsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.executor = Executors.newSingleThreadExecutor();
|
||||
|
||||
LocaleManager locale = plugin.getLocaleManager();
|
||||
|
||||
@@ -130,8 +124,8 @@ public class CommandManager {
|
||||
* @param label the command label used
|
||||
* @param args the arguments provided
|
||||
*/
|
||||
public Future<CommandResult> onCommand(Sender sender, String label, List<String> args) {
|
||||
return executor.submit(() -> {
|
||||
public CompletableFuture<CommandResult> onCommand(Sender sender, String label, List<String> args) {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
return execute(sender, label, args);
|
||||
} catch (Throwable e) {
|
||||
@@ -139,7 +133,7 @@ public class CommandManager {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}, plugin.getScheduler().async());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -255,18 +249,18 @@ public class CommandManager {
|
||||
@SuppressWarnings("unchecked")
|
||||
String permission = (String) c.getPermission().map(p -> ((CommandPermission) p).getPermission()).orElse("None");
|
||||
|
||||
Component component = ComponentSerializer.parseFromLegacy("&3> &a" + String.format(c.getUsage(), label), Constants.FORMAT_CHAR)
|
||||
.applyRecursively(comp -> {
|
||||
comp.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, ComponentSerializer.parseFromLegacy(TextUtils.joinNewline(
|
||||
TextComponent component = TextUtils.fromLegacy("&3> &a" + String.format(c.getUsage(), label), Constants.FORMAT_CHAR)
|
||||
.toBuilder().applyDeep(comp -> {
|
||||
comp.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(TextUtils.joinNewline(
|
||||
"&bCommand: &2" + c.getName(),
|
||||
"&bDescription: &2" + c.getDescription(),
|
||||
"&bUsage: &2" + String.format(c.getUsage(), label),
|
||||
"&bPermission: &2" + permission,
|
||||
" ",
|
||||
"&7Click to auto-complete."
|
||||
), Constants.FORMAT_CHAR)));
|
||||
), Constants.FORMAT_CHAR)));
|
||||
comp.clickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, String.format(c.getUsage(), label)));
|
||||
});
|
||||
}).build();
|
||||
sender.sendMessage(component);
|
||||
});
|
||||
}
|
||||
@@ -310,6 +304,7 @@ public class CommandManager {
|
||||
}
|
||||
|
||||
private static void handleRewrites(List<String> args) {
|
||||
// Provide aliases
|
||||
if (args.size() >= 1) {
|
||||
if (args.get(0).equalsIgnoreCase("u")) {
|
||||
args.remove(0);
|
||||
@@ -319,6 +314,14 @@ public class CommandManager {
|
||||
args.remove(0);
|
||||
args.add(0, "group");
|
||||
}
|
||||
if (args.get(0).equalsIgnoreCase("t")) {
|
||||
args.remove(0);
|
||||
args.add(0, "track");
|
||||
}
|
||||
if (args.get(0).equalsIgnoreCase("i")) {
|
||||
args.remove(0);
|
||||
args.add(0, "info");
|
||||
}
|
||||
}
|
||||
|
||||
if (args.size() >= 3) {
|
||||
@@ -342,7 +345,6 @@ public class CommandManager {
|
||||
break;
|
||||
case "i":
|
||||
case "about":
|
||||
case "list":
|
||||
args.remove(2);
|
||||
args.add(2, "info");
|
||||
break;
|
||||
@@ -350,6 +352,7 @@ public class CommandManager {
|
||||
case "inheritances":
|
||||
case "group":
|
||||
case "groups":
|
||||
case "g":
|
||||
case "rank":
|
||||
case "ranks":
|
||||
case "parents":
|
||||
@@ -440,7 +443,7 @@ public class CommandManager {
|
||||
boolean lazyInfo = (
|
||||
args.size() >= 4 &&
|
||||
(args.get(2).equalsIgnoreCase("permission") || args.get(2).equalsIgnoreCase("parent") || args.get(2).equalsIgnoreCase("meta")) &&
|
||||
(args.get(3).equalsIgnoreCase("i") || args.get(3).equalsIgnoreCase("about") || args.get(3).equalsIgnoreCase("list"))
|
||||
(args.get(3).equalsIgnoreCase("i") || args.get(3).equalsIgnoreCase("about"))
|
||||
);
|
||||
|
||||
if (lazyInfo) {
|
||||
|
||||
+31
-13
@@ -39,11 +39,14 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public abstract class MainCommand<T> extends Command<Void, T> {
|
||||
public abstract class MainCommand<T, I> extends Command<Void, T> {
|
||||
|
||||
private final int minArgs; // equals 1 if the command doesn't take a mid argument, e.g. /lp user <USER> sub-command....
|
||||
// equals 1 if the command doesn't take a mid argument, e.g. /lp log sub-command....
|
||||
// equals 2 if the command does take a mid argument, e.g. /lp user <USER> sub-command....
|
||||
private final int minArgs;
|
||||
|
||||
public MainCommand(LocalizedSpec spec, String name, int minArgs, List<Command<T, ?>> children) {
|
||||
super(spec, name, null, Predicates.alwaysFalse(), children);
|
||||
@@ -84,17 +87,28 @@ public abstract class MainCommand<T> extends Command<Void, T> {
|
||||
}
|
||||
|
||||
final String name = args.get(0);
|
||||
T t = getTarget(name, plugin, sender);
|
||||
if (t != null) {
|
||||
CommandResult result;
|
||||
try {
|
||||
result = sub.execute(plugin, sender, t, strippedArgs, label);
|
||||
} catch (CommandException e) {
|
||||
result = CommandManager.handleException(e, sender, label, sub);
|
||||
}
|
||||
I targetId = parseTarget(name, plugin, sender);
|
||||
if (targetId == null) {
|
||||
return CommandResult.LOADING_ERROR;
|
||||
}
|
||||
|
||||
cleanup(t, plugin);
|
||||
return result;
|
||||
ReentrantLock lock = getLockForTarget(targetId);
|
||||
lock.lock();
|
||||
try {
|
||||
T target = getTarget(targetId, plugin, sender);
|
||||
if (target != null) {
|
||||
CommandResult result;
|
||||
try {
|
||||
result = sub.execute(plugin, sender, target, strippedArgs, label);
|
||||
} catch (CommandException e) {
|
||||
result = CommandManager.handleException(e, sender, label, sub);
|
||||
}
|
||||
|
||||
cleanup(target, plugin);
|
||||
return result;
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
return CommandResult.LOADING_ERROR;
|
||||
@@ -145,7 +159,11 @@ public abstract class MainCommand<T> extends Command<Void, T> {
|
||||
|
||||
protected abstract List<String> getTargets(LuckPermsPlugin plugin);
|
||||
|
||||
protected abstract T getTarget(String target, LuckPermsPlugin plugin, Sender sender);
|
||||
protected abstract I parseTarget(String target, LuckPermsPlugin plugin, Sender sender);
|
||||
|
||||
protected abstract ReentrantLock getLockForTarget(I target);
|
||||
|
||||
protected abstract T getTarget(I target, LuckPermsPlugin plugin, Sender sender);
|
||||
|
||||
protected abstract void cleanup(T t, LuckPermsPlugin plugin);
|
||||
|
||||
|
||||
+21
-21
@@ -173,7 +173,7 @@ public abstract class SubCommand<T> extends Command<T, Void> {
|
||||
}
|
||||
|
||||
public static void save(User user, Sender sender, LuckPermsPlugin plugin) {
|
||||
boolean success = plugin.getStorage().force().saveUser(user).join();
|
||||
boolean success = plugin.getStorage().noBuffer().saveUser(user).join();
|
||||
|
||||
if (sender.isImport()) {
|
||||
user.getRefreshBuffer().request();
|
||||
@@ -181,20 +181,20 @@ public abstract class SubCommand<T> extends Command<T, Void> {
|
||||
user.getRefreshBuffer().requestDirectly();
|
||||
}
|
||||
|
||||
InternalMessagingService messagingService = plugin.getMessagingService();
|
||||
if (!sender.isImport() && !(messagingService instanceof NoopMessagingService) && plugin.getConfiguration().get(ConfigKeys.AUTO_PUSH_UPDATES)) {
|
||||
messagingService.getUpdateBuffer().request();
|
||||
if (!sender.isImport()) {
|
||||
InternalMessagingService messagingService = plugin.getMessagingService();
|
||||
if (!(messagingService instanceof NoopMessagingService) && plugin.getConfiguration().get(ConfigKeys.AUTO_PUSH_UPDATES)) {
|
||||
messagingService.getUpdateBuffer().request();
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
Message.USER_SAVE_SUCCESS.send(sender);
|
||||
} else {
|
||||
if (!success) {
|
||||
Message.USER_SAVE_ERROR.send(sender);
|
||||
}
|
||||
}
|
||||
|
||||
public static void save(Group group, Sender sender, LuckPermsPlugin plugin) {
|
||||
boolean success = plugin.getStorage().force().saveGroup(group).join();
|
||||
boolean success = plugin.getStorage().noBuffer().saveGroup(group).join();
|
||||
|
||||
if (sender.isImport()) {
|
||||
plugin.getUpdateTaskBuffer().request();
|
||||
@@ -202,20 +202,20 @@ public abstract class SubCommand<T> extends Command<T, Void> {
|
||||
plugin.getUpdateTaskBuffer().requestDirectly();
|
||||
}
|
||||
|
||||
InternalMessagingService messagingService = plugin.getMessagingService();
|
||||
if (!sender.isImport() && !(messagingService instanceof NoopMessagingService) && plugin.getConfiguration().get(ConfigKeys.AUTO_PUSH_UPDATES)) {
|
||||
messagingService.getUpdateBuffer().request();
|
||||
if (!sender.isImport()) {
|
||||
InternalMessagingService messagingService = plugin.getMessagingService();
|
||||
if (!(messagingService instanceof NoopMessagingService) && plugin.getConfiguration().get(ConfigKeys.AUTO_PUSH_UPDATES)) {
|
||||
messagingService.getUpdateBuffer().request();
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
Message.GROUP_SAVE_SUCCESS.send(sender);
|
||||
} else {
|
||||
if (!success) {
|
||||
Message.GROUP_SAVE_ERROR.send(sender);
|
||||
}
|
||||
}
|
||||
|
||||
public static void save(Track track, Sender sender, LuckPermsPlugin plugin) {
|
||||
boolean success = plugin.getStorage().force().saveTrack(track).join();
|
||||
boolean success = plugin.getStorage().noBuffer().saveTrack(track).join();
|
||||
|
||||
if (sender.isImport()) {
|
||||
plugin.getUpdateTaskBuffer().request();
|
||||
@@ -223,14 +223,14 @@ public abstract class SubCommand<T> extends Command<T, Void> {
|
||||
plugin.getUpdateTaskBuffer().requestDirectly();
|
||||
}
|
||||
|
||||
InternalMessagingService messagingService = plugin.getMessagingService();
|
||||
if (!sender.isImport() && !(messagingService instanceof NoopMessagingService) && plugin.getConfiguration().get(ConfigKeys.AUTO_PUSH_UPDATES)) {
|
||||
messagingService.getUpdateBuffer().request();
|
||||
if (!sender.isImport()) {
|
||||
InternalMessagingService messagingService = plugin.getMessagingService();
|
||||
if (!(messagingService instanceof NoopMessagingService) && plugin.getConfiguration().get(ConfigKeys.AUTO_PUSH_UPDATES)) {
|
||||
messagingService.getUpdateBuffer().request();
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
Message.TRACK_SAVE_SUCCESS.send(sender);
|
||||
} else {
|
||||
if (!success) {
|
||||
Message.TRACK_SAVE_ERROR.send(sender);
|
||||
}
|
||||
}
|
||||
|
||||
+8
-8
@@ -28,6 +28,7 @@ package me.lucko.luckperms.common.commands.impl.generic.meta;
|
||||
import me.lucko.luckperms.api.ChatMetaType;
|
||||
import me.lucko.luckperms.api.DataMutateResult;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.common.actionlog.ExtendedLogEntry;
|
||||
import me.lucko.luckperms.common.commands.ArgumentPermissions;
|
||||
import me.lucko.luckperms.common.commands.CommandException;
|
||||
import me.lucko.luckperms.common.commands.CommandResult;
|
||||
@@ -37,7 +38,6 @@ import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
|
||||
import me.lucko.luckperms.common.commands.utils.Util;
|
||||
import me.lucko.luckperms.common.constants.CommandPermission;
|
||||
import me.lucko.luckperms.common.constants.Constants;
|
||||
import me.lucko.luckperms.common.data.LogEntry;
|
||||
import me.lucko.luckperms.common.locale.CommandSpec;
|
||||
import me.lucko.luckperms.common.locale.LocaleManager;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
@@ -45,10 +45,10 @@ import me.lucko.luckperms.common.model.PermissionHolder;
|
||||
import me.lucko.luckperms.common.node.NodeFactory;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.utils.Predicates;
|
||||
import me.lucko.luckperms.common.utils.TextUtils;
|
||||
|
||||
import net.kyori.text.Component;
|
||||
import net.kyori.text.TextComponent;
|
||||
import net.kyori.text.event.HoverEvent;
|
||||
import net.kyori.text.serializer.ComponentSerializer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -85,15 +85,15 @@ public class MetaAddChatMeta extends SharedSubCommand {
|
||||
|
||||
DataMutateResult result = holder.setPermission(NodeFactory.makeChatMetaNode(type, priority, meta).withExtraContext(context).build());
|
||||
if (result.asBoolean()) {
|
||||
Component component = ComponentSerializer.parseFromLegacy(Message.ADD_CHATMETA_SUCCESS.asString(plugin.getLocaleManager(), holder.getFriendlyName(), type.name().toLowerCase(), meta, priority, Util.contextSetToString(context)), Constants.COLOR_CHAR);
|
||||
HoverEvent event = new HoverEvent(HoverEvent.Action.SHOW_TEXT, ComponentSerializer.parseFromLegacy(
|
||||
TextComponent.Builder builder = TextUtils.fromLegacy(Message.ADD_CHATMETA_SUCCESS.asString(plugin.getLocaleManager(), holder.getFriendlyName(), type.name().toLowerCase(), meta, priority, Util.contextSetToString(context)), Constants.COLOR_CHAR).toBuilder();
|
||||
HoverEvent event = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(
|
||||
"¥3Raw " + type.name().toLowerCase() + ": ¥r" + meta,
|
||||
'¥'
|
||||
));
|
||||
component.applyRecursively(c -> c.hoverEvent(event));
|
||||
sender.sendMessage(component);
|
||||
builder.applyDeep(c -> c.hoverEvent(event));
|
||||
sender.sendMessage(builder.build());
|
||||
|
||||
LogEntry.build().actor(sender).acted(holder)
|
||||
ExtendedLogEntry.build().actor(sender).acted(holder)
|
||||
.action("meta add" + type.name().toLowerCase() + " " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
|
||||
.build().submit(plugin, sender);
|
||||
|
||||
|
||||
+8
-8
@@ -29,6 +29,7 @@ import me.lucko.luckperms.api.ChatMetaType;
|
||||
import me.lucko.luckperms.api.DataMutateResult;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.common.actionlog.ExtendedLogEntry;
|
||||
import me.lucko.luckperms.common.commands.ArgumentPermissions;
|
||||
import me.lucko.luckperms.common.commands.CommandException;
|
||||
import me.lucko.luckperms.common.commands.CommandResult;
|
||||
@@ -39,7 +40,6 @@ import me.lucko.luckperms.common.commands.utils.Util;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.constants.CommandPermission;
|
||||
import me.lucko.luckperms.common.constants.Constants;
|
||||
import me.lucko.luckperms.common.data.LogEntry;
|
||||
import me.lucko.luckperms.common.locale.CommandSpec;
|
||||
import me.lucko.luckperms.common.locale.LocaleManager;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
@@ -49,10 +49,10 @@ import me.lucko.luckperms.common.node.NodeFactory;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.utils.DateUtil;
|
||||
import me.lucko.luckperms.common.utils.Predicates;
|
||||
import me.lucko.luckperms.common.utils.TextUtils;
|
||||
|
||||
import net.kyori.text.Component;
|
||||
import net.kyori.text.TextComponent;
|
||||
import net.kyori.text.event.HoverEvent;
|
||||
import net.kyori.text.serializer.ComponentSerializer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -95,15 +95,15 @@ public class MetaAddTempChatMeta extends SharedSubCommand {
|
||||
if (ret.getKey().asBoolean()) {
|
||||
duration = ret.getValue().getExpiryUnixTime();
|
||||
|
||||
Component component = ComponentSerializer.parseFromLegacy(Message.ADD_TEMP_CHATMETA_SUCCESS.asString(plugin.getLocaleManager(), holder.getFriendlyName(), type.name().toLowerCase(), meta, priority, DateUtil.formatDateDiff(duration), Util.contextSetToString(context)), Constants.COLOR_CHAR);
|
||||
HoverEvent event = new HoverEvent(HoverEvent.Action.SHOW_TEXT, ComponentSerializer.parseFromLegacy(
|
||||
TextComponent.Builder builder = TextUtils.fromLegacy(Message.ADD_TEMP_CHATMETA_SUCCESS.asString(plugin.getLocaleManager(), holder.getFriendlyName(), type.name().toLowerCase(), meta, priority, DateUtil.formatDateDiff(duration), Util.contextSetToString(context)), Constants.COLOR_CHAR).toBuilder();
|
||||
HoverEvent event = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(
|
||||
"¥3Raw " + type.name().toLowerCase() + ": ¥r" + meta,
|
||||
'¥'
|
||||
));
|
||||
component.applyRecursively(c -> c.hoverEvent(event));
|
||||
sender.sendMessage(component);
|
||||
builder.applyDeep(c -> c.hoverEvent(event));
|
||||
sender.sendMessage(builder.build());
|
||||
|
||||
LogEntry.build().actor(sender).acted(holder)
|
||||
ExtendedLogEntry.build().actor(sender).acted(holder)
|
||||
.action("meta addtemp" + type.name().toLowerCase() + " " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
|
||||
.build().submit(plugin, sender);
|
||||
|
||||
|
||||
+35
-6
@@ -26,6 +26,7 @@
|
||||
package me.lucko.luckperms.common.commands.impl.generic.meta;
|
||||
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.common.actionlog.ExtendedLogEntry;
|
||||
import me.lucko.luckperms.common.commands.ArgumentPermissions;
|
||||
import me.lucko.luckperms.common.commands.CommandException;
|
||||
import me.lucko.luckperms.common.commands.CommandResult;
|
||||
@@ -34,11 +35,11 @@ import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
|
||||
import me.lucko.luckperms.common.commands.utils.Util;
|
||||
import me.lucko.luckperms.common.constants.CommandPermission;
|
||||
import me.lucko.luckperms.common.data.LogEntry;
|
||||
import me.lucko.luckperms.common.locale.CommandSpec;
|
||||
import me.lucko.luckperms.common.locale.LocaleManager;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
import me.lucko.luckperms.common.model.PermissionHolder;
|
||||
import me.lucko.luckperms.common.node.MetaType;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.utils.Predicates;
|
||||
|
||||
@@ -57,6 +58,34 @@ public class MetaClear extends SharedSubCommand {
|
||||
return CommandResult.NO_PERMISSION;
|
||||
}
|
||||
|
||||
MetaType type = null;
|
||||
if (args.size() > 0) {
|
||||
String typeId = args.get(0).toLowerCase();
|
||||
if (typeId.equals("any") || typeId.equals("all") || typeId.equals("*")) {
|
||||
type = MetaType.ANY;
|
||||
}
|
||||
if (typeId.equals("chat") || typeId.equals("chatmeta")) {
|
||||
type = MetaType.CHAT;
|
||||
}
|
||||
if (typeId.equals("meta")) {
|
||||
type = MetaType.META;
|
||||
}
|
||||
if (typeId.equals("prefix") || typeId.equals("prefixes")) {
|
||||
type = MetaType.PREFIX;
|
||||
}
|
||||
if (typeId.equals("suffix") || typeId.equals("suffixes")) {
|
||||
type = MetaType.SUFFIX;
|
||||
}
|
||||
|
||||
if (type != null) {
|
||||
args.remove(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (type == null) {
|
||||
type = MetaType.ANY;
|
||||
}
|
||||
|
||||
int before = holder.getEnduringNodes().size();
|
||||
|
||||
MutableContextSet context = ArgumentUtils.handleContext(0, args, plugin);
|
||||
@@ -67,19 +96,19 @@ public class MetaClear extends SharedSubCommand {
|
||||
}
|
||||
|
||||
if (context.isEmpty()) {
|
||||
holder.clearMeta();
|
||||
holder.clearMeta(type);
|
||||
} else {
|
||||
holder.clearMeta(context);
|
||||
holder.clearMeta(type, context);
|
||||
}
|
||||
|
||||
int changed = before - holder.getEnduringNodes().size();
|
||||
if (changed == 1) {
|
||||
Message.META_CLEAR_SUCCESS_SINGULAR.send(sender, holder.getFriendlyName(), Util.contextSetToString(context), changed);
|
||||
Message.META_CLEAR_SUCCESS_SINGULAR.send(sender, holder.getFriendlyName(), type.name().toLowerCase(), Util.contextSetToString(context), changed);
|
||||
} else {
|
||||
Message.META_CLEAR_SUCCESS.send(sender, holder.getFriendlyName(), Util.contextSetToString(context), changed);
|
||||
Message.META_CLEAR_SUCCESS.send(sender, holder.getFriendlyName(), type.name().toLowerCase(), Util.contextSetToString(context), changed);
|
||||
}
|
||||
|
||||
LogEntry.build().actor(sender).acted(holder)
|
||||
ExtendedLogEntry.build().actor(sender).acted(holder)
|
||||
.action("meta clear " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
|
||||
.build().submit(plugin, sender);
|
||||
|
||||
|
||||
+18
-18
@@ -49,10 +49,10 @@ import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.utils.Predicates;
|
||||
import me.lucko.luckperms.common.utils.TextUtils;
|
||||
|
||||
import net.kyori.text.Component;
|
||||
import net.kyori.text.BuildableComponent;
|
||||
import net.kyori.text.TextComponent;
|
||||
import net.kyori.text.event.ClickEvent;
|
||||
import net.kyori.text.event.HoverEvent;
|
||||
import net.kyori.text.serializer.ComponentSerializer;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -126,13 +126,13 @@ public class MetaInfo extends SharedSubCommand {
|
||||
String location = processLocation(m, holder);
|
||||
if (m.hasSpecificContext()) {
|
||||
String context = Util.getAppendableNodeContextString(m);
|
||||
Component component = ComponentSerializer.parseFromLegacy(Message.META_ENTRY_WITH_CONTEXT.asString(sender.getPlatform().getLocaleManager(), m.getMeta().getKey(), m.getMeta().getValue(), location, context), Constants.COLOR_CHAR);
|
||||
component.applyRecursively(makeFancy(holder, label, m));
|
||||
sender.sendMessage(component);
|
||||
TextComponent.Builder builder = TextUtils.fromLegacy(Message.META_ENTRY_WITH_CONTEXT.asString(sender.getPlatform().getLocaleManager(), m.getMeta().getKey(), m.getMeta().getValue(), location, context), Constants.COLOR_CHAR).toBuilder();
|
||||
builder.applyDeep(makeFancy(holder, label, m));
|
||||
sender.sendMessage(builder.build());
|
||||
} else {
|
||||
Component component = ComponentSerializer.parseFromLegacy(Message.META_ENTRY.asString(sender.getPlatform().getLocaleManager(), m.getMeta().getKey(), m.getMeta().getValue(), location), Constants.COLOR_CHAR);
|
||||
component.applyRecursively(makeFancy(holder, label, m));
|
||||
sender.sendMessage(component);
|
||||
TextComponent.Builder builder = TextUtils.fromLegacy(Message.META_ENTRY.asString(sender.getPlatform().getLocaleManager(), m.getMeta().getKey(), m.getMeta().getValue(), location), Constants.COLOR_CHAR).toBuilder();
|
||||
builder.applyDeep(makeFancy(holder, label, m));
|
||||
sender.sendMessage(builder.build());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -142,18 +142,18 @@ public class MetaInfo extends SharedSubCommand {
|
||||
String location = processLocation(e.getValue(), holder);
|
||||
if (e.getValue().hasSpecificContext()) {
|
||||
String context = Util.getAppendableNodeContextString(e.getValue());
|
||||
Component component = ComponentSerializer.parseFromLegacy(Message.CHAT_META_ENTRY_WITH_CONTEXT.asString(sender.getPlatform().getLocaleManager(), e.getKey(), type.getEntry(e.getValue()).getValue(), location, context), Constants.COLOR_CHAR);
|
||||
component.applyRecursively(makeFancy(type, holder, label, e.getValue()));
|
||||
sender.sendMessage(component);
|
||||
TextComponent.Builder builder = TextUtils.fromLegacy(Message.CHAT_META_ENTRY_WITH_CONTEXT.asString(sender.getPlatform().getLocaleManager(), e.getKey(), type.getEntry(e.getValue()).getValue(), location, context), Constants.COLOR_CHAR).toBuilder();
|
||||
builder.applyDeep(makeFancy(type, holder, label, e.getValue()));
|
||||
sender.sendMessage(builder.build());
|
||||
} else {
|
||||
Component component = ComponentSerializer.parseFromLegacy(Message.CHAT_META_ENTRY.asString(sender.getPlatform().getLocaleManager(), e.getKey(), type.getEntry(e.getValue()).getValue(), location), Constants.COLOR_CHAR);
|
||||
component.applyRecursively(makeFancy(type, holder, label, e.getValue()));
|
||||
sender.sendMessage(component);
|
||||
TextComponent.Builder builder = TextUtils.fromLegacy(Message.CHAT_META_ENTRY.asString(sender.getPlatform().getLocaleManager(), e.getKey(), type.getEntry(e.getValue()).getValue(), location), Constants.COLOR_CHAR).toBuilder();
|
||||
builder.applyDeep(makeFancy(type, holder, label, e.getValue()));
|
||||
sender.sendMessage(builder.build());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Consumer<Component> makeFancy(ChatMetaType type, PermissionHolder holder, String label, LocalizedNode node) {
|
||||
private static Consumer<BuildableComponent.Builder<?, ?>> makeFancy(ChatMetaType type, PermissionHolder holder, String label, LocalizedNode node) {
|
||||
if (!node.getLocation().equals(holder.getObjectName())) {
|
||||
// inherited.
|
||||
Group group = holder.getPlugin().getGroupManager().getIfLoaded(node.getLocation());
|
||||
@@ -162,7 +162,7 @@ public class MetaInfo extends SharedSubCommand {
|
||||
}
|
||||
}
|
||||
|
||||
HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, ComponentSerializer.parseFromLegacy(TextUtils.joinNewline(
|
||||
HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(TextUtils.joinNewline(
|
||||
"¥3> ¥a" + type.getEntry(node).getKey() + " ¥7- ¥r" + type.getEntry(node).getValue(),
|
||||
" ",
|
||||
"¥7Click to remove this " + type.name().toLowerCase() + " from " + holder.getFriendlyName()
|
||||
@@ -178,7 +178,7 @@ public class MetaInfo extends SharedSubCommand {
|
||||
};
|
||||
}
|
||||
|
||||
private static Consumer<Component> makeFancy(PermissionHolder holder, String label, LocalizedNode node) {
|
||||
private static Consumer<BuildableComponent.Builder<?, ?>> makeFancy(PermissionHolder holder, String label, LocalizedNode node) {
|
||||
if (!node.getLocation().equals(holder.getObjectName())) {
|
||||
// inherited.
|
||||
Group group = holder.getPlugin().getGroupManager().getIfLoaded(node.getLocation());
|
||||
@@ -187,7 +187,7 @@ public class MetaInfo extends SharedSubCommand {
|
||||
}
|
||||
}
|
||||
|
||||
HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, ComponentSerializer.parseFromLegacy(TextUtils.joinNewline(
|
||||
HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(TextUtils.joinNewline(
|
||||
"¥3> ¥r" + node.getMeta().getKey() + " ¥7- ¥r" + node.getMeta().getValue(),
|
||||
" ",
|
||||
"¥7Click to remove this meta pair from " + holder.getFriendlyName()
|
||||
|
||||
+8
-8
@@ -28,6 +28,7 @@ package me.lucko.luckperms.common.commands.impl.generic.meta;
|
||||
import me.lucko.luckperms.api.ChatMetaType;
|
||||
import me.lucko.luckperms.api.DataMutateResult;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.common.actionlog.ExtendedLogEntry;
|
||||
import me.lucko.luckperms.common.commands.ArgumentPermissions;
|
||||
import me.lucko.luckperms.common.commands.CommandException;
|
||||
import me.lucko.luckperms.common.commands.CommandResult;
|
||||
@@ -37,7 +38,6 @@ import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
|
||||
import me.lucko.luckperms.common.commands.utils.Util;
|
||||
import me.lucko.luckperms.common.constants.CommandPermission;
|
||||
import me.lucko.luckperms.common.constants.Constants;
|
||||
import me.lucko.luckperms.common.data.LogEntry;
|
||||
import me.lucko.luckperms.common.locale.CommandSpec;
|
||||
import me.lucko.luckperms.common.locale.LocaleManager;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
@@ -45,10 +45,10 @@ import me.lucko.luckperms.common.model.PermissionHolder;
|
||||
import me.lucko.luckperms.common.node.NodeFactory;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.utils.Predicates;
|
||||
import me.lucko.luckperms.common.utils.TextUtils;
|
||||
|
||||
import net.kyori.text.Component;
|
||||
import net.kyori.text.TextComponent;
|
||||
import net.kyori.text.event.HoverEvent;
|
||||
import net.kyori.text.serializer.ComponentSerializer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -99,15 +99,15 @@ public class MetaRemoveChatMeta extends SharedSubCommand {
|
||||
DataMutateResult result = holder.unsetPermission(NodeFactory.makeChatMetaNode(type, priority, meta).withExtraContext(context).build());
|
||||
|
||||
if (result.asBoolean()) {
|
||||
Component component = ComponentSerializer.parseFromLegacy(Message.REMOVE_CHATMETA_SUCCESS.asString(plugin.getLocaleManager(), holder.getFriendlyName(), type.name().toLowerCase(), meta, priority, Util.contextSetToString(context)), Constants.COLOR_CHAR);
|
||||
HoverEvent event = new HoverEvent(HoverEvent.Action.SHOW_TEXT, ComponentSerializer.parseFromLegacy(
|
||||
TextComponent.Builder builder = TextUtils.fromLegacy(Message.REMOVE_CHATMETA_SUCCESS.asString(plugin.getLocaleManager(), holder.getFriendlyName(), type.name().toLowerCase(), meta, priority, Util.contextSetToString(context)), Constants.COLOR_CHAR).toBuilder();
|
||||
HoverEvent event = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(
|
||||
"¥3Raw " + type.name().toLowerCase() + ": ¥r" + meta,
|
||||
'¥'
|
||||
));
|
||||
component.applyRecursively(c -> c.hoverEvent(event));
|
||||
sender.sendMessage(component);
|
||||
builder.applyDeep(c -> c.hoverEvent(event));
|
||||
sender.sendMessage(builder.build());
|
||||
|
||||
LogEntry.build().actor(sender).acted(holder)
|
||||
ExtendedLogEntry.build().actor(sender).acted(holder)
|
||||
.action("meta remove" + type.name().toLowerCase() + " " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
|
||||
.build().submit(plugin, sender);
|
||||
|
||||
|
||||
+8
-8
@@ -28,6 +28,7 @@ package me.lucko.luckperms.common.commands.impl.generic.meta;
|
||||
import me.lucko.luckperms.api.ChatMetaType;
|
||||
import me.lucko.luckperms.api.DataMutateResult;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.common.actionlog.ExtendedLogEntry;
|
||||
import me.lucko.luckperms.common.commands.ArgumentPermissions;
|
||||
import me.lucko.luckperms.common.commands.CommandException;
|
||||
import me.lucko.luckperms.common.commands.CommandResult;
|
||||
@@ -37,7 +38,6 @@ import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
|
||||
import me.lucko.luckperms.common.commands.utils.Util;
|
||||
import me.lucko.luckperms.common.constants.CommandPermission;
|
||||
import me.lucko.luckperms.common.constants.Constants;
|
||||
import me.lucko.luckperms.common.data.LogEntry;
|
||||
import me.lucko.luckperms.common.locale.CommandSpec;
|
||||
import me.lucko.luckperms.common.locale.LocaleManager;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
@@ -45,10 +45,10 @@ import me.lucko.luckperms.common.model.PermissionHolder;
|
||||
import me.lucko.luckperms.common.node.NodeFactory;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.utils.Predicates;
|
||||
import me.lucko.luckperms.common.utils.TextUtils;
|
||||
|
||||
import net.kyori.text.Component;
|
||||
import net.kyori.text.TextComponent;
|
||||
import net.kyori.text.event.HoverEvent;
|
||||
import net.kyori.text.serializer.ComponentSerializer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -99,15 +99,15 @@ public class MetaRemoveTempChatMeta extends SharedSubCommand {
|
||||
DataMutateResult result = holder.unsetPermission(NodeFactory.makeChatMetaNode(type, priority, meta).setExpiry(10L).withExtraContext(context).build());
|
||||
|
||||
if (result.asBoolean()) {
|
||||
Component component = ComponentSerializer.parseFromLegacy(Message.REMOVE_TEMP_CHATMETA_SUCCESS.asString(plugin.getLocaleManager(), holder.getFriendlyName(), type.name().toLowerCase(), meta, priority, Util.contextSetToString(context)), Constants.COLOR_CHAR);
|
||||
HoverEvent event = new HoverEvent(HoverEvent.Action.SHOW_TEXT, ComponentSerializer.parseFromLegacy(
|
||||
TextComponent.Builder builder = TextUtils.fromLegacy(Message.REMOVE_TEMP_CHATMETA_SUCCESS.asString(plugin.getLocaleManager(), holder.getFriendlyName(), type.name().toLowerCase(), meta, priority, Util.contextSetToString(context)), Constants.COLOR_CHAR).toBuilder();
|
||||
HoverEvent event = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(
|
||||
"¥3Raw " + type.name().toLowerCase() + ": ¥r" + meta,
|
||||
'¥'
|
||||
));
|
||||
component.applyRecursively(c -> c.hoverEvent(event));
|
||||
sender.sendMessage(component);
|
||||
builder.applyDeep(c -> c.hoverEvent(event));
|
||||
sender.sendMessage(builder.build());
|
||||
|
||||
LogEntry.build().actor(sender).acted(holder)
|
||||
ExtendedLogEntry.build().actor(sender).acted(holder)
|
||||
.action("meta removetemp" + type.name().toLowerCase() + " " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
|
||||
.build().submit(plugin, sender);
|
||||
|
||||
|
||||
+7
-9
@@ -27,6 +27,7 @@ package me.lucko.luckperms.common.commands.impl.generic.meta;
|
||||
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.common.actionlog.ExtendedLogEntry;
|
||||
import me.lucko.luckperms.common.commands.ArgumentPermissions;
|
||||
import me.lucko.luckperms.common.commands.CommandException;
|
||||
import me.lucko.luckperms.common.commands.CommandResult;
|
||||
@@ -35,8 +36,6 @@ import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
|
||||
import me.lucko.luckperms.common.commands.utils.Util;
|
||||
import me.lucko.luckperms.common.constants.CommandPermission;
|
||||
import me.lucko.luckperms.common.constants.Constants;
|
||||
import me.lucko.luckperms.common.data.LogEntry;
|
||||
import me.lucko.luckperms.common.locale.CommandSpec;
|
||||
import me.lucko.luckperms.common.locale.LocaleManager;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
@@ -46,9 +45,8 @@ import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.utils.Predicates;
|
||||
import me.lucko.luckperms.common.utils.TextUtils;
|
||||
|
||||
import net.kyori.text.Component;
|
||||
import net.kyori.text.TextComponent;
|
||||
import net.kyori.text.event.HoverEvent;
|
||||
import net.kyori.text.serializer.ComponentSerializer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -89,15 +87,15 @@ public class MetaSet extends SharedSubCommand {
|
||||
holder.clearMetaKeys(key, context, false);
|
||||
holder.setPermission(n);
|
||||
|
||||
Component component = ComponentSerializer.parseFromLegacy(Message.SET_META_SUCCESS.asString(plugin.getLocaleManager(), key, value, holder.getFriendlyName(), Util.contextSetToString(context)), Constants.COLOR_CHAR);
|
||||
HoverEvent event = new HoverEvent(HoverEvent.Action.SHOW_TEXT, ComponentSerializer.parseFromLegacy(
|
||||
TextComponent.Builder builder = TextUtils.fromLegacy(Message.SET_META_SUCCESS.asString(plugin.getLocaleManager(), key, value, holder.getFriendlyName(), Util.contextSetToString(context))).toBuilder();
|
||||
HoverEvent event = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(
|
||||
TextUtils.joinNewline("¥3Raw key: ¥r" + key, "¥3Raw value: ¥r" + value),
|
||||
'¥'
|
||||
));
|
||||
component.applyRecursively(c -> c.hoverEvent(event));
|
||||
sender.sendMessage(component);
|
||||
builder.applyDeep(c -> c.hoverEvent(event));
|
||||
sender.sendMessage(builder.build());
|
||||
|
||||
LogEntry.build().actor(sender).acted(holder)
|
||||
ExtendedLogEntry.build().actor(sender).acted(holder)
|
||||
.action("meta set " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
|
||||
.build().submit(plugin, sender);
|
||||
|
||||
|
||||
+7
-8
@@ -27,6 +27,7 @@ package me.lucko.luckperms.common.commands.impl.generic.meta;
|
||||
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.common.actionlog.ExtendedLogEntry;
|
||||
import me.lucko.luckperms.common.commands.ArgumentPermissions;
|
||||
import me.lucko.luckperms.common.commands.CommandException;
|
||||
import me.lucko.luckperms.common.commands.CommandResult;
|
||||
@@ -37,7 +38,6 @@ import me.lucko.luckperms.common.commands.utils.Util;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.constants.CommandPermission;
|
||||
import me.lucko.luckperms.common.constants.Constants;
|
||||
import me.lucko.luckperms.common.data.LogEntry;
|
||||
import me.lucko.luckperms.common.locale.CommandSpec;
|
||||
import me.lucko.luckperms.common.locale.LocaleManager;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
@@ -49,9 +49,8 @@ import me.lucko.luckperms.common.utils.DateUtil;
|
||||
import me.lucko.luckperms.common.utils.Predicates;
|
||||
import me.lucko.luckperms.common.utils.TextUtils;
|
||||
|
||||
import net.kyori.text.Component;
|
||||
import net.kyori.text.TextComponent;
|
||||
import net.kyori.text.event.HoverEvent;
|
||||
import net.kyori.text.serializer.ComponentSerializer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -94,15 +93,15 @@ public class MetaSetTemp extends SharedSubCommand {
|
||||
holder.clearMetaKeys(key, context, true);
|
||||
duration = holder.setPermission(n, modifier).getValue().getExpiryUnixTime();
|
||||
|
||||
Component component = ComponentSerializer.parseFromLegacy(Message.SET_META_TEMP_SUCCESS.asString(plugin.getLocaleManager(), key, value, holder.getFriendlyName(), DateUtil.formatDateDiff(duration), Util.contextSetToString(context)), Constants.COLOR_CHAR);
|
||||
HoverEvent event = new HoverEvent(HoverEvent.Action.SHOW_TEXT, ComponentSerializer.parseFromLegacy(
|
||||
TextComponent.Builder builder = TextUtils.fromLegacy(Message.SET_META_TEMP_SUCCESS.asString(plugin.getLocaleManager(), key, value, holder.getFriendlyName(), DateUtil.formatDateDiff(duration), Util.contextSetToString(context)), Constants.COLOR_CHAR).toBuilder();
|
||||
HoverEvent event = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(
|
||||
TextUtils.joinNewline("¥3Raw key: ¥r" + key, "¥3Raw value: ¥r" + value),
|
||||
'¥'
|
||||
));
|
||||
component.applyRecursively(c -> c.hoverEvent(event));
|
||||
sender.sendMessage(component);
|
||||
builder.applyDeep(c -> c.hoverEvent(event));
|
||||
sender.sendMessage(builder.build());
|
||||
|
||||
LogEntry.build().actor(sender).acted(holder)
|
||||
ExtendedLogEntry.build().actor(sender).acted(holder)
|
||||
.action("meta settemp " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
|
||||
.build().submit(plugin, sender);
|
||||
|
||||
|
||||
+12
-8
@@ -26,6 +26,7 @@
|
||||
package me.lucko.luckperms.common.commands.impl.generic.meta;
|
||||
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.common.actionlog.ExtendedLogEntry;
|
||||
import me.lucko.luckperms.common.commands.ArgumentPermissions;
|
||||
import me.lucko.luckperms.common.commands.CommandException;
|
||||
import me.lucko.luckperms.common.commands.CommandResult;
|
||||
@@ -34,7 +35,6 @@ import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
|
||||
import me.lucko.luckperms.common.commands.utils.Util;
|
||||
import me.lucko.luckperms.common.constants.CommandPermission;
|
||||
import me.lucko.luckperms.common.data.LogEntry;
|
||||
import me.lucko.luckperms.common.locale.CommandSpec;
|
||||
import me.lucko.luckperms.common.locale.LocaleManager;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
@@ -70,14 +70,18 @@ public class MetaUnset extends SharedSubCommand {
|
||||
return CommandResult.NO_PERMISSION;
|
||||
}
|
||||
|
||||
holder.clearMetaKeys(key, context, false);
|
||||
Message.UNSET_META_SUCCESS.send(sender, key, holder.getFriendlyName(), Util.contextSetToString(context));
|
||||
if (holder.clearMetaKeys(key, context, false)) {
|
||||
Message.UNSET_META_SUCCESS.send(sender, key, holder.getFriendlyName(), Util.contextSetToString(context));
|
||||
|
||||
LogEntry.build().actor(sender).acted(holder)
|
||||
.action("meta unset " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
|
||||
.build().submit(plugin, sender);
|
||||
ExtendedLogEntry.build().actor(sender).acted(holder)
|
||||
.action("meta unset " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
|
||||
.build().submit(plugin, sender);
|
||||
|
||||
save(holder, sender, plugin);
|
||||
return CommandResult.SUCCESS;
|
||||
save(holder, sender, plugin);
|
||||
return CommandResult.SUCCESS;
|
||||
} else {
|
||||
Message.DOESNT_HAVE_META.send(sender, holder.getFriendlyName());
|
||||
return CommandResult.STATE_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
-8
@@ -26,6 +26,7 @@
|
||||
package me.lucko.luckperms.common.commands.impl.generic.meta;
|
||||
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.common.actionlog.ExtendedLogEntry;
|
||||
import me.lucko.luckperms.common.commands.ArgumentPermissions;
|
||||
import me.lucko.luckperms.common.commands.CommandException;
|
||||
import me.lucko.luckperms.common.commands.CommandResult;
|
||||
@@ -34,7 +35,6 @@ import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
|
||||
import me.lucko.luckperms.common.commands.utils.Util;
|
||||
import me.lucko.luckperms.common.constants.CommandPermission;
|
||||
import me.lucko.luckperms.common.data.LogEntry;
|
||||
import me.lucko.luckperms.common.locale.CommandSpec;
|
||||
import me.lucko.luckperms.common.locale.LocaleManager;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
@@ -70,14 +70,18 @@ public class MetaUnsetTemp extends SharedSubCommand {
|
||||
return CommandResult.NO_PERMISSION;
|
||||
}
|
||||
|
||||
holder.clearMetaKeys(key, context, true);
|
||||
Message.UNSET_META_TEMP_SUCCESS.send(sender, key, holder.getFriendlyName(), Util.contextSetToString(context));
|
||||
if (holder.clearMetaKeys(key, context, true)) {
|
||||
Message.UNSET_META_TEMP_SUCCESS.send(sender, key, holder.getFriendlyName(), Util.contextSetToString(context));
|
||||
|
||||
LogEntry.build().actor(sender).acted(holder)
|
||||
.action("meta unsettemp " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
|
||||
.build().submit(plugin, sender);
|
||||
ExtendedLogEntry.build().actor(sender).acted(holder)
|
||||
.action("meta unsettemp " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
|
||||
.build().submit(plugin, sender);
|
||||
|
||||
save(holder, sender, plugin);
|
||||
return CommandResult.SUCCESS;
|
||||
save(holder, sender, plugin);
|
||||
return CommandResult.SUCCESS;
|
||||
} else {
|
||||
Message.DOESNT_HAVE_META.send(sender, holder.getFriendlyName());
|
||||
return CommandResult.STATE_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -26,6 +26,7 @@
|
||||
package me.lucko.luckperms.common.commands.impl.generic.other;
|
||||
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.common.actionlog.ExtendedLogEntry;
|
||||
import me.lucko.luckperms.common.commands.ArgumentPermissions;
|
||||
import me.lucko.luckperms.common.commands.CommandException;
|
||||
import me.lucko.luckperms.common.commands.CommandResult;
|
||||
@@ -34,7 +35,6 @@ import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
|
||||
import me.lucko.luckperms.common.commands.utils.Util;
|
||||
import me.lucko.luckperms.common.constants.CommandPermission;
|
||||
import me.lucko.luckperms.common.data.LogEntry;
|
||||
import me.lucko.luckperms.common.locale.CommandSpec;
|
||||
import me.lucko.luckperms.common.locale.LocaleManager;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
@@ -81,7 +81,7 @@ public class HolderClear<T extends PermissionHolder> extends SubCommand<T> {
|
||||
Message.CLEAR_SUCCESS.send(sender, holder.getFriendlyName(), Util.contextSetToString(context), changed);
|
||||
}
|
||||
|
||||
LogEntry.build().actor(sender).acted(holder)
|
||||
ExtendedLogEntry.build().actor(sender).acted(holder)
|
||||
.action("clear " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
|
||||
.build().submit(plugin, sender);
|
||||
|
||||
|
||||
+8
-3
@@ -53,6 +53,7 @@ import net.kyori.text.Component;
|
||||
import net.kyori.text.TextComponent;
|
||||
import net.kyori.text.event.ClickEvent;
|
||||
import net.kyori.text.event.HoverEvent;
|
||||
import net.kyori.text.format.TextColor;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
@@ -84,8 +85,11 @@ public class HolderEditor<T extends PermissionHolder> extends SubCommand<T> {
|
||||
|
||||
JsonObject data = new JsonObject();
|
||||
Set<NodeModel> nodes = holder.getEnduringNodes().values().stream().map(NodeModel::fromNode).collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
data.add("nodes", serializePermissions(nodes));
|
||||
data.addProperty("who", id(holder));
|
||||
data.addProperty("cmdAlias", label);
|
||||
data.addProperty("uploadedBy", sender.getName());
|
||||
data.addProperty("time", System.currentTimeMillis());
|
||||
data.add("nodes", serializePermissions(nodes));
|
||||
|
||||
String dataUrl = paste(new GsonBuilder().setPrettyPrinting().create().toJson(data));
|
||||
if (dataUrl == null) {
|
||||
@@ -99,9 +103,10 @@ public class HolderEditor<T extends PermissionHolder> extends SubCommand<T> {
|
||||
|
||||
Message.EDITOR_URL.send(sender);
|
||||
|
||||
Component message = new TextComponent(url).color('b')
|
||||
Component message = TextComponent.builder(url).color(TextColor.AQUA)
|
||||
.clickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url))
|
||||
.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponent("Click to open the editor.").color('7')));
|
||||
.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to open the editor.").color(TextColor.GRAY)))
|
||||
.build();
|
||||
|
||||
sender.sendMessage(message);
|
||||
return CommandResult.SUCCESS;
|
||||
|
||||
+2
-2
@@ -27,6 +27,7 @@ package me.lucko.luckperms.common.commands.impl.generic.parent;
|
||||
|
||||
import me.lucko.luckperms.api.DataMutateResult;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.common.actionlog.ExtendedLogEntry;
|
||||
import me.lucko.luckperms.common.commands.ArgumentPermissions;
|
||||
import me.lucko.luckperms.common.commands.CommandException;
|
||||
import me.lucko.luckperms.common.commands.CommandResult;
|
||||
@@ -35,7 +36,6 @@ import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
|
||||
import me.lucko.luckperms.common.commands.utils.Util;
|
||||
import me.lucko.luckperms.common.constants.CommandPermission;
|
||||
import me.lucko.luckperms.common.data.LogEntry;
|
||||
import me.lucko.luckperms.common.locale.CommandSpec;
|
||||
import me.lucko.luckperms.common.locale.LocaleManager;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
@@ -90,7 +90,7 @@ public class ParentAdd extends SharedSubCommand {
|
||||
if (result.asBoolean()) {
|
||||
Message.SET_INHERIT_SUCCESS.send(sender, holder.getFriendlyName(), group.getDisplayName(), Util.contextSetToString(context));
|
||||
|
||||
LogEntry.build().actor(sender).acted(holder)
|
||||
ExtendedLogEntry.build().actor(sender).acted(holder)
|
||||
.action("parent add " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
|
||||
.build().submit(plugin, sender);
|
||||
|
||||
|
||||
+2
-2
@@ -28,6 +28,7 @@ package me.lucko.luckperms.common.commands.impl.generic.parent;
|
||||
import me.lucko.luckperms.api.DataMutateResult;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.common.actionlog.ExtendedLogEntry;
|
||||
import me.lucko.luckperms.common.commands.ArgumentPermissions;
|
||||
import me.lucko.luckperms.common.commands.CommandException;
|
||||
import me.lucko.luckperms.common.commands.CommandResult;
|
||||
@@ -37,7 +38,6 @@ import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
|
||||
import me.lucko.luckperms.common.commands.utils.Util;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.constants.CommandPermission;
|
||||
import me.lucko.luckperms.common.data.LogEntry;
|
||||
import me.lucko.luckperms.common.locale.CommandSpec;
|
||||
import me.lucko.luckperms.common.locale.LocaleManager;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
@@ -104,7 +104,7 @@ public class ParentAddTemp extends SharedSubCommand {
|
||||
duration = ret.getValue().getExpiryUnixTime();
|
||||
Message.SET_TEMP_INHERIT_SUCCESS.send(sender, holder.getFriendlyName(), group.getDisplayName(), DateUtil.formatDateDiff(duration), Util.contextSetToString(context));
|
||||
|
||||
LogEntry.build().actor(sender).acted(holder)
|
||||
ExtendedLogEntry.build().actor(sender).acted(holder)
|
||||
.action("parent addtemp " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
|
||||
.build().submit(plugin, sender);
|
||||
|
||||
|
||||
+2
-2
@@ -26,6 +26,7 @@
|
||||
package me.lucko.luckperms.common.commands.impl.generic.parent;
|
||||
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.common.actionlog.ExtendedLogEntry;
|
||||
import me.lucko.luckperms.common.commands.ArgumentPermissions;
|
||||
import me.lucko.luckperms.common.commands.CommandException;
|
||||
import me.lucko.luckperms.common.commands.CommandResult;
|
||||
@@ -34,7 +35,6 @@ import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
|
||||
import me.lucko.luckperms.common.commands.utils.Util;
|
||||
import me.lucko.luckperms.common.constants.CommandPermission;
|
||||
import me.lucko.luckperms.common.data.LogEntry;
|
||||
import me.lucko.luckperms.common.locale.CommandSpec;
|
||||
import me.lucko.luckperms.common.locale.LocaleManager;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
@@ -79,7 +79,7 @@ public class ParentClear extends SharedSubCommand {
|
||||
Message.PARENT_CLEAR_SUCCESS.send(sender, holder.getFriendlyName(), Util.contextSetToString(context), changed);
|
||||
}
|
||||
|
||||
LogEntry.build().actor(sender).acted(holder)
|
||||
ExtendedLogEntry.build().actor(sender).acted(holder)
|
||||
.action("parent clear " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
|
||||
.build().submit(plugin, sender);
|
||||
|
||||
|
||||
+2
-2
@@ -26,6 +26,7 @@
|
||||
package me.lucko.luckperms.common.commands.impl.generic.parent;
|
||||
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.common.actionlog.ExtendedLogEntry;
|
||||
import me.lucko.luckperms.common.commands.ArgumentPermissions;
|
||||
import me.lucko.luckperms.common.commands.CommandException;
|
||||
import me.lucko.luckperms.common.commands.CommandResult;
|
||||
@@ -35,7 +36,6 @@ import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
|
||||
import me.lucko.luckperms.common.commands.utils.Util;
|
||||
import me.lucko.luckperms.common.constants.CommandPermission;
|
||||
import me.lucko.luckperms.common.constants.DataConstraints;
|
||||
import me.lucko.luckperms.common.data.LogEntry;
|
||||
import me.lucko.luckperms.common.locale.CommandSpec;
|
||||
import me.lucko.luckperms.common.locale.LocaleManager;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
@@ -116,7 +116,7 @@ public class ParentClearTrack extends SharedSubCommand {
|
||||
Message.PARENT_CLEAR_TRACK_SUCCESS.send(sender, holder.getFriendlyName(), track.getName(), Util.contextSetToString(context), changed);
|
||||
}
|
||||
|
||||
LogEntry.build().actor(sender).acted(holder)
|
||||
ExtendedLogEntry.build().actor(sender).acted(holder)
|
||||
.action("parent cleartrack " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
|
||||
.build().submit(plugin, sender);
|
||||
|
||||
|
||||
+12
-11
@@ -46,11 +46,12 @@ import me.lucko.luckperms.common.utils.DateUtil;
|
||||
import me.lucko.luckperms.common.utils.Predicates;
|
||||
import me.lucko.luckperms.common.utils.TextUtils;
|
||||
|
||||
import net.kyori.text.BuildableComponent;
|
||||
import net.kyori.text.Component;
|
||||
import net.kyori.text.TextComponent;
|
||||
import net.kyori.text.event.ClickEvent;
|
||||
import net.kyori.text.event.HoverEvent;
|
||||
import net.kyori.text.serializer.ComponentSerializer;
|
||||
import net.kyori.text.format.TextColor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -89,15 +90,15 @@ public class ParentInfo extends SharedSubCommand {
|
||||
}
|
||||
|
||||
if (page.isEmpty()) {
|
||||
return new TextComponent("None").color('3');
|
||||
return TextComponent.builder("None").color(TextColor.DARK_AQUA).build();
|
||||
}
|
||||
|
||||
TextComponent message = new TextComponent("");
|
||||
TextComponent.Builder message = TextComponent.builder("");
|
||||
for (Node node : page) {
|
||||
String s = "&3> &a" + node.getGroupName() + Util.getAppendableNodeContextString(node) + "\n";
|
||||
message.append(ComponentSerializer.parseFromLegacy(s, Constants.FORMAT_CHAR).applyRecursively(makeFancy(holder, label, node)));
|
||||
message.append(TextUtils.fromLegacy(s, Constants.FORMAT_CHAR).toBuilder().applyDeep(makeFancy(holder, label, node)).build());
|
||||
}
|
||||
return message;
|
||||
return message.build();
|
||||
}
|
||||
|
||||
private static Component tempGroupsToMessage(SortedSet<LocalizedNode> nodes, PermissionHolder holder, String label) {
|
||||
@@ -109,19 +110,19 @@ public class ParentInfo extends SharedSubCommand {
|
||||
}
|
||||
|
||||
if (page.isEmpty()) {
|
||||
return new TextComponent("None").color('3');
|
||||
return TextComponent.builder("None").color(TextColor.DARK_AQUA).build();
|
||||
}
|
||||
|
||||
TextComponent message = new TextComponent("");
|
||||
TextComponent.Builder message = TextComponent.builder("");
|
||||
for (Node node : page) {
|
||||
String s = "&3> &a" + node.getPermission() + Util.getAppendableNodeContextString(node) + "\n&2- expires in " + DateUtil.formatDateDiff(node.getExpiryUnixTime()) + "\n";
|
||||
message.append(ComponentSerializer.parseFromLegacy(s, Constants.FORMAT_CHAR).applyRecursively(makeFancy(holder, label, node)));
|
||||
message.append(TextUtils.fromLegacy(s, Constants.FORMAT_CHAR).toBuilder().applyDeep(makeFancy(holder, label, node)).build());
|
||||
}
|
||||
return message;
|
||||
return message.build();
|
||||
}
|
||||
|
||||
private static Consumer<Component> makeFancy(PermissionHolder holder, String label, Node node) {
|
||||
HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, ComponentSerializer.parseFromLegacy(TextUtils.joinNewline(
|
||||
private static Consumer<BuildableComponent.Builder<? ,?>> makeFancy(PermissionHolder holder, String label, Node node) {
|
||||
HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(TextUtils.joinNewline(
|
||||
"&3> &f" + node.getGroupName(),
|
||||
" ",
|
||||
"&7Click to remove this parent from " + holder.getFriendlyName()
|
||||
|
||||
+4
-3
@@ -27,6 +27,7 @@ package me.lucko.luckperms.common.commands.impl.generic.parent;
|
||||
|
||||
import me.lucko.luckperms.api.DataMutateResult;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.common.actionlog.ExtendedLogEntry;
|
||||
import me.lucko.luckperms.common.commands.ArgumentPermissions;
|
||||
import me.lucko.luckperms.common.commands.CommandException;
|
||||
import me.lucko.luckperms.common.commands.CommandResult;
|
||||
@@ -36,7 +37,6 @@ import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
|
||||
import me.lucko.luckperms.common.commands.utils.Util;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.constants.CommandPermission;
|
||||
import me.lucko.luckperms.common.data.LogEntry;
|
||||
import me.lucko.luckperms.common.locale.CommandSpec;
|
||||
import me.lucko.luckperms.common.locale.LocaleManager;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
@@ -79,7 +79,8 @@ public class ParentRemove extends SharedSubCommand {
|
||||
if (holder instanceof User) {
|
||||
User user = (User) holder;
|
||||
|
||||
boolean shouldPrevent = (context.isEmpty() || context.has("server", "global")) &&
|
||||
boolean shouldPrevent = plugin.getConfiguration().get(ConfigKeys.PREVENT_PRIMARY_GROUP_REMOVAL) &&
|
||||
context.isEmpty() &&
|
||||
plugin.getConfiguration().get(ConfigKeys.PRIMARY_GROUP_CALCULATION_METHOD).equals("stored") &&
|
||||
user.getPrimaryGroup().getStoredValue().equalsIgnoreCase(groupName);
|
||||
|
||||
@@ -93,7 +94,7 @@ public class ParentRemove extends SharedSubCommand {
|
||||
if (result.asBoolean()) {
|
||||
Message.UNSET_INHERIT_SUCCESS.send(sender, holder.getFriendlyName(), groupName, Util.contextSetToString(context));
|
||||
|
||||
LogEntry.build().actor(sender).acted(holder)
|
||||
ExtendedLogEntry.build().actor(sender).acted(holder)
|
||||
.action("parent remove " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
|
||||
.build().submit(plugin, sender);
|
||||
|
||||
|
||||
+2
-2
@@ -27,6 +27,7 @@ package me.lucko.luckperms.common.commands.impl.generic.parent;
|
||||
|
||||
import me.lucko.luckperms.api.DataMutateResult;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.common.actionlog.ExtendedLogEntry;
|
||||
import me.lucko.luckperms.common.commands.ArgumentPermissions;
|
||||
import me.lucko.luckperms.common.commands.CommandException;
|
||||
import me.lucko.luckperms.common.commands.CommandResult;
|
||||
@@ -35,7 +36,6 @@ import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
|
||||
import me.lucko.luckperms.common.commands.utils.Util;
|
||||
import me.lucko.luckperms.common.constants.CommandPermission;
|
||||
import me.lucko.luckperms.common.data.LogEntry;
|
||||
import me.lucko.luckperms.common.locale.CommandSpec;
|
||||
import me.lucko.luckperms.common.locale.LocaleManager;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
@@ -79,7 +79,7 @@ public class ParentRemoveTemp extends SharedSubCommand {
|
||||
if (result.asBoolean()) {
|
||||
Message.UNSET_TEMP_INHERIT_SUCCESS.send(sender, holder.getFriendlyName(), groupName, Util.contextSetToString(context));
|
||||
|
||||
LogEntry.build().actor(sender).acted(holder)
|
||||
ExtendedLogEntry.build().actor(sender).acted(holder)
|
||||
.action("parent removetemp " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
|
||||
.build().submit(plugin, sender);
|
||||
|
||||
|
||||
Loaded 100 of 225 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user