Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4fb07ff181 | ||
|
|
4631dcf857 | ||
|
|
f6f9840eb7 | ||
|
|
4de8165c95 | ||
|
|
242672f49d | ||
|
|
c32c975a71 | ||
|
|
82e759d708 | ||
|
|
9de44d2605 | ||
|
|
132d0cf578 | ||
|
|
029dc9f8d9 | ||
|
|
5567b1dad8 | ||
|
|
ea00ec64af | ||
|
|
7259e6be0a | ||
|
|
2e40557b39 | ||
|
|
e68fc7c558 | ||
|
|
055dfb000d | ||
|
|
b997ab6e3f | ||
|
|
25f31d0bb8 | ||
|
|
4cfd8a7e2c | ||
|
|
0ec19a8fee | ||
|
|
2749563f5d | ||
|
|
e7e2e3f7e0 | ||
|
|
0a33c0aac5 | ||
|
|
24e09fd2d9 | ||
|
|
4d0499a61e | ||
|
|
ae82807139 | ||
|
|
65147e1935 | ||
|
|
8e557d122b | ||
|
|
486b19aa90 | ||
|
|
14cb34ac95 | ||
|
|
abfc23b04d | ||
|
|
ebb24aefa1 | ||
|
|
2573f46f40 | ||
|
|
5dcb8cd73a | ||
|
|
e4bfe09882 | ||
|
|
eecbfe04db | ||
|
|
671e2adc32 | ||
|
|
1137e476dd | ||
|
|
cb63b321d0 | ||
|
|
c36b0d2975 | ||
|
|
f8ad562b95 | ||
|
|
c35ab38f36 | ||
|
|
073b775566 | ||
|
|
85c7a7db8d | ||
|
|
1e134df27d | ||
|
|
bdff84885a | ||
|
|
f1a9c3722c | ||
|
|
8b402f6423 | ||
|
|
a0aec52661 | ||
|
|
407ab43dd1 | ||
|
|
c2165e0196 | ||
|
|
2e75bc3f3b | ||
|
|
e91c2ca427 | ||
|
|
965ff04bcc | ||
|
|
ac4bd418f3 | ||
|
|
e9e844c1f7 | ||
|
|
aa2941fcdb | ||
|
|
dbc909a317 | ||
|
|
11465a4ce9 | ||
|
|
f5007f94dc | ||
|
|
d18ac2e6eb | ||
|
|
b9fc5c39ae | ||
|
|
9dc2278083 | ||
|
|
281060a972 | ||
|
|
91626f079d | ||
|
|
7305c6c54b | ||
|
|
bce7fa871d | ||
|
|
a35fd80763 | ||
|
|
b383f9dfbc | ||
|
|
680ad3c145 | ||
|
|
7b712e7f90 | ||
|
|
2462eac497 | ||
|
|
bb818c8942 | ||
|
|
ddc881af11 | ||
|
|
838fba9173 | ||
|
|
0b6f326c18 | ||
|
|
00895fc7ab | ||
|
|
07f38aa283 | ||
|
|
ecf1d3790c | ||
|
|
53c9e5bb4a | ||
|
|
b20b03113a | ||
|
|
ec8273aa9f | ||
|
|
2862f0dfae | ||
|
|
fd4963c74b | ||
|
|
df99ef4481 | ||
|
|
35d1057673 | ||
|
|
e6a90a18c4 | ||
|
|
26afb69a14 | ||
|
|
e8c0c43e9d | ||
|
|
1707f333bf |
No files matched your search
@@ -1,5 +1,5 @@
|
||||
# LuckPerms Language File
|
||||
# Locale: en_US
|
||||
# Locale: en_US (English)
|
||||
# Author: Luck
|
||||
|
||||
prefix: "&7&l[&b&lL&3&lP&7&l] &c"
|
||||
@@ -9,84 +9,66 @@ log-error: "&7&l[&bLuck&3Perms&7&l] &4[ERROR] {0}"
|
||||
empty: "{0}"
|
||||
player-online: "&aOnline"
|
||||
player-offline: "&cOffline"
|
||||
loading-error: "Permissions data could not be loaded. Please contact an administrator."
|
||||
loading-error: "Permissions data could not be loaded. Please try again later."
|
||||
op-disabled: "&bThe vanilla OP system is disabled on this server."
|
||||
op-disabled-sponge: "&2Server Operator status has no effect when a permission plugin is installed. Please edit user data directly."
|
||||
log: "&3LOG &3&l> {0}"
|
||||
|
||||
export-log: "&3EXPORT &3&l> &f{0}"
|
||||
export-log-progress: "&3EXPORT &3&l> &7{0}"
|
||||
migration-log: "&3MIGRATION &7[&3{0}&7] &3&l> &f{1}"
|
||||
migration-log-progress: "&3MIGRATION &7[&3{0}&7] &3&l> &7{1}"
|
||||
command-not-recognised: "Command not recognised."
|
||||
command-no-permission: "You do not have permission to use this command!"
|
||||
|
||||
already-haspermission: "{0} already has this permission!"
|
||||
does-not-havepermission: "{0} does not have this permission set."
|
||||
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-no-data: "&bUser &a{0}&b does not have any data loaded."
|
||||
user-save-success: "&7(User data was saved to storage)"
|
||||
user-save-error: "There was an error whilst saving the user."
|
||||
user-create-fail: "There was an error whilst creating a new 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."
|
||||
track-invalid-entry: "Track names can only contain alphanumeric characters."
|
||||
server-invalid-entry: "Server names can only contain alphanumeric characters."
|
||||
|
||||
use-inherit-command: "Use the 'parent add' command instead of specifying the node."
|
||||
|
||||
|
||||
|
||||
use-inherit-command: "Use the 'parent add' and 'parent remove' commands instead of specifying the node."
|
||||
verbose-invalid-filter: "&cInvalid verbose filter: &f{0}"
|
||||
verbose-on: "&bVerbose checking output set to &aTRUE &bfor all permissions."
|
||||
verbose-on_query: "&bVerbose checking output set to &aTRUE &bfor permissions matching the following filters: &f{0}"
|
||||
verbose-on-query: "&bVerbose checking output set to &aTRUE &bfor permissions matching the following filters: &f{0}"
|
||||
verbose-off: "&bVerbose checking output set to &cFALSE&b."
|
||||
|
||||
verbose-recording-on: "&bVerbose recording set to &aTRUE &bfor all permissions."
|
||||
verbose-recording-on-query: "&bVerbose recording set to &aTRUE &bfor permissions matching the following filters: &f{0}"
|
||||
verbose-recording-upload-start: "&bVerbose recording was disabled. Uploading results..."
|
||||
verbose-recording-url: "&aVerbose results URL:"
|
||||
|
||||
tree-upload-start: "&bGenerating permission tree..."
|
||||
tree-empty: "&aUnable to generate tree. No results were found."
|
||||
tree-url: "&aPermission Tree URL:"
|
||||
|
||||
search-searching: "&aSearching for users and groups with &b{0}&a..."
|
||||
search-result: "&aFound &b{0}&a entries from &b{1}&a users and &b{2}&a groups."
|
||||
search-showing-users: "&bShowing user entries:"
|
||||
search-showing-groups: "&bShowing group entries:"
|
||||
search-showing-users-with-page: "&bShowing user entries: {0}"
|
||||
search-showing-groups-with-page: "&bShowing group entries: {0}"
|
||||
|
||||
check-result: "&aPermission check result on user &b{0}&a for permission &b{1}&a: &f{2}"
|
||||
|
||||
create-success: "&b{0}&a was successfully created."
|
||||
delete-success: "&b{0}&a was successfully deleted."
|
||||
rename-success: "&b{0}&a was successfully renamed to &b{1}&a."
|
||||
clone-success: "&b{0}&a was successfully cloned to &b{1}&a."
|
||||
|
||||
clone-success: "&b{0}&a was successfully cloned onto &b{1}&a."
|
||||
already-inherits: "{0} already inherits '{1}'."
|
||||
does-not-inherit: "{0} does not inherit '{1}'."
|
||||
already-temp-inherits: "{0} already temporarily inherits '{1}'."
|
||||
does-not-temp-inherit: "{0} does not temporarily inherit '{1}'."
|
||||
|
||||
track-already-contains: "Track {0} already contains the group '{1}'."
|
||||
track-does-not-contain: "Track {0} does not contain the group '{1}'."
|
||||
track-ambiguous-call: "The user specified is a member of multiple groups on this track. Unable to determine their location."
|
||||
|
||||
group-already-exists: "That group already exists!"
|
||||
group-does-not-exist: "That group does not exist!"
|
||||
group-load-error: "An unexpected error occurred. Group not loaded."
|
||||
@@ -95,9 +77,7 @@ track-already-exists: "That track already exists!"
|
||||
track-does-not-exist: "That track does not exist!"
|
||||
track-load-error: "An unexpected error occurred. Track not loaded."
|
||||
tracks-load-error: "An unexpected error occurred. Unable to load all tracks."
|
||||
|
||||
track-empty: "The track cannot be used as it is empty or contains only one group."
|
||||
|
||||
update-task-request: "&bUpdate task scheduled."
|
||||
update-task-complete: "&aUpdate task finished."
|
||||
update-task-complete-network: "&aUpdate task finished. Now attempting to push to other servers."
|
||||
@@ -124,7 +104,7 @@ info: >
|
||||
{PREFIX}&f- &3Context Calculators: &a{14}\n
|
||||
{PREFIX}&f- &3Unique permissions: &a{15}\n
|
||||
{PREFIX}&f- &bConfiguration:\n
|
||||
{PREFIX}&f- &3Online Mode: {16}\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
|
||||
@@ -137,48 +117,46 @@ 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."
|
||||
groups-list: "&aGroups: {0}"
|
||||
|
||||
create-track-error: "There was an error whilst creating the track."
|
||||
delete-track-error: "There was an error whilst deleting the track."
|
||||
tracks-list: "&aTracks: {0}"
|
||||
|
||||
listnodes: "&b{0}'s Nodes:"
|
||||
listnodes-with-page: "&b{0}'s Nodes: {1}"
|
||||
listnodes-temp: "&b{0}'s Temporary Nodes:\n{1}"
|
||||
listparents: "&b{0}'s Parent Groups:\n{1}"
|
||||
listparents-temp: "&b{0}'s Temporary Parent Groups:\n{1}"
|
||||
listgroups: "&b{0}'s Groups:\n{1}"
|
||||
listgroups-temp: "&b{0}'s Temporary Groups:\n{1}"
|
||||
list-tracks: "&b{0}'s Tracks:\n{1}"
|
||||
listnodes-temp: >
|
||||
&b{0}'s Temporary Nodes:\n
|
||||
{1}
|
||||
listparents: >
|
||||
&b{0}'s Parent Groups:\n
|
||||
{1}
|
||||
listparents-temp: >
|
||||
&b{0}'s Temporary Parent Groups:\n
|
||||
{1}
|
||||
listgroups: >
|
||||
&b{0}'s Groups:\n
|
||||
{1}
|
||||
listgroups-temp: >
|
||||
&b{0}'s Temporary Groups:\n
|
||||
{1}
|
||||
list-tracks: >
|
||||
&b{0}'s Tracks:\n
|
||||
{1}
|
||||
list-tracks-empty: "{0} is not on any tracks."
|
||||
|
||||
setpermission-success: "&aSet &b{0}&a to &b{1}&a for &b{2}&a."
|
||||
setpermission-server-success: "&aSet &b{0}&a to &b{1}&a for &b{2}&a on server &b{3}&a."
|
||||
setpermission-server-world-success: "&aSet &b{0}&a to &b{1}&a for &b{2}&a on server &b{3}&a, world &b{4}&a."
|
||||
setpermission-temp-success: "&aSet &b{0}&a to &b{1}&a for &b{2}&a for a duration of &b{3}&a."
|
||||
setpermission-temp-server-success: "&aSet &b{0}&a to &b{1}&a for &b{2}&a on server &b{3}&a for a duration of &b{4}&a."
|
||||
setpermission-temp-server-world-success: "&aSet &b{0}&a to &b{1}&a for &b{2}&a on server &b{3}&a, world &b{4}&a, for a duration of &b{5}&a."
|
||||
unsetpermission-success: "&aUnset &b{0}&a for &b{1}&a."
|
||||
unsetpermission-server-success: "&aUnset &b{0}&a for &b{1}&a on server &b{2}&a."
|
||||
unsetpermission-server-world-success: "&aUnset &b{0}&a for &b{1}&a on server &b{2}&a, world &b{3}&a."
|
||||
unset-temp-permission-success: "&aUnset temporary permission &b{0}&a for &b{1}&a."
|
||||
unset-temp-permission-server-success: "&aUnset temporary permission &b{0}&a for &b{1}&a on server &b{2}&a."
|
||||
unset-temp-permission-server-world-success: "&aUnset temporary permission &b{0}&a for &b{1}&a on server &b{2}&a, world &b{3}&a."
|
||||
set-inherit-success: "&b{0}&a now inherits permissions from &b{1}&a."
|
||||
set-inherit-server-success: "&b{0}&a now inherits permissions from &b{2}&a on server &b{3}&a."
|
||||
set-inherit-server-world-success: "&b{0}&a now inherits permissions from &b{1}&a on server &b{2}&a, world &b{3}&a."
|
||||
set-parent-success: "&b{0}&a had their existing parent groups cleared, and now only inherits &b{1}&a."
|
||||
set-parent-server-success: "&b{0}&a had their existing parent groups cleared, and now only inherits &b{1}&a on server &b{2}&a."
|
||||
set-parent-server-world-success: "&b{0}&a had their existing parent groups cleared, and now only inherits &b{1}&a on server &b{2}&a, world &b{3}&a."
|
||||
set-temp-inherit-success: "&b{0}&a now inherits permissions from &b{1}&a for a duration of &b{2}&a."
|
||||
set-temp-inherit-server-success: "&b{0}&a now inherits permissions from &b{1}&a on server &b{2}&a for a duration of &b{3}&a."
|
||||
set-temp-inherit-server-world-success: "&b{0}&a now inherits permissions from &b{1}&a on server &b{2}&a, world &b{3}&a, for a duration of &b{4}&a."
|
||||
unset-inherit-success: "&b{0}&a no longer inherits permissions from &b{1}&a."
|
||||
unset-inherit-server-success: "&b{0}&a no longer inherits permissions from &b{1}&a on server &b{2}&a."
|
||||
unset-inherit-server-world-success: "&b{0}&a no longer inherits permissions from &b{1}&a on server &b{2}&a, world &b{3}&a."
|
||||
unset-temp-inherit-success: "&b{0}&a no longer temporarily inherits permissions from &b{1}&a."
|
||||
unset-temp-inherit-server-success: "&b{0}&a no longer temporarily inherits permissions from &b{1}&a on server &b{2}&a."
|
||||
unset-temp-inherit-server-world-success: "&b{0}&a no longer temporarily inherits permissions from &b{1}&a on server &b{2}&a, world &b{3}&a."
|
||||
context-pair-inline: "&3{0}=&b{1}"
|
||||
context-pair--global-inline: "&eglobal"
|
||||
context-pair-end: "&a."
|
||||
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-permission-inherited: "&b{0}&a has permission &b{1}&a set to {2}&a in context {3}&a, inherited from &b{4}&a."
|
||||
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."
|
||||
unset-temp-permission-success: "&aUnset temporary permission &b{0}&a for &b{1}&a in context {2}&a."
|
||||
set-inherit-success: "&b{0}&a now inherits permissions from &b{1}&a in context {2}&a."
|
||||
set-temp-inherit-success: "&b{0}&a now inherits permissions from &b{1}&a for a duration of &b{2}&a in context {3}&a."
|
||||
set-parent-success: "&b{0}&a had their existing parent groups cleared, and now only inherits &b{1}&a in context {2}&a."
|
||||
unset-inherit-success: "&b{0}&a no longer inherits permissions from &b{1}&a in context {2}&a."
|
||||
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. (&b{1}&a nodes were removed.)"
|
||||
clear-success-singular: "&b{0}&a's permissions were cleared. (&b{1}&a node was removed.)"
|
||||
parent-clear-success: "&b{0}&a's parents were cleared. (&b{1}&a nodes were removed.)"
|
||||
@@ -187,7 +165,6 @@ meta-clear-success: "&b{0}&a's meta was cleared. (&b{1}&a nodes were removed.)"
|
||||
meta-clear-success-singular: "&b{0}&a's meta was cleared. (&b{1}&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"
|
||||
chat-meta-suffix-header: "&b{0}'s Suffixes"
|
||||
meta-header: "&b{0}'s Meta"
|
||||
@@ -198,59 +175,22 @@ meta-entry-with-context: "&b-> &a{0} &f= &f\"{1}&f\" &8(&7inherited from &a{2}&8
|
||||
chat-meta-prefix-none: "&b{0} has no prefixes."
|
||||
chat-meta-suffix-none: "&b{0} has no suffixes."
|
||||
meta-none: "&b{0} has no meta."
|
||||
|
||||
meta-invalid-priority: "Invalid priority '{0}'. Expected a number."
|
||||
already-has-prefix: "{0} already has that prefix set."
|
||||
already-has-suffix: "{0} already has that suffix set."
|
||||
does-not-have-prefix: "{0} doesn't have that prefix set."
|
||||
does-not-have-suffix: "{0} doesn't have that suffix set."
|
||||
|
||||
addprefix-success: "&b{0}&a had prefix &f\"{1}&f\"&a set at a priority of &b{2}&a."
|
||||
addprefix-server-success: "&b{0}&a had prefix &f\"{1}&f\"&a set at a priority of &b{2}&a on server &b{3}&a."
|
||||
addprefix-server-world-success: "&b{0}&a had prefix &f\"{1}&f\"&a set at a priority of &b{2}&a on server &b{3}&a, world &b{4}&a."
|
||||
removeprefix-success: "&b{0}&a had prefix &f\"{1}&f\"&a at priority &b{2}&a removed."
|
||||
removeprefix-server-success: "&b{0}&a had prefix &f\"{1}&f\"&a at priority &b{2}&a removed on server &b{3}&a."
|
||||
removeprefix-server-world-success: "&b{0}&a had prefix &f\"{1}&f\"&a at priority &b{2}&a removed on server &b{3}&a, world &b{4}&a."
|
||||
|
||||
addsuffix-success: "&b{0}&a had suffix &f\"{1}&f\"&a set at a priority of &b{2}&a."
|
||||
addsuffix-server-success: "&b{0}&a had suffix &f\"{1}&f\"&a set at a priority of &b{2}&a on server &b{3}&a."
|
||||
addsuffix-server-world-success: "&b{0}&a had suffix &f\"{1}&f\"&a set at a priority of &b{2}&a on server &b{3}&a, world &b{4}&a."
|
||||
removesuffix-success: "&b{0}&a had suffix &f\"{1}&f\"&a at priority &b{2}&a removed."
|
||||
removesuffix-server-success: "&b{0}&a had suffix &f\"{1}&f\"&a at priority &b{2}&a removed on server &b{3}&a."
|
||||
removesuffix-server-world-success: "&b{0}&a had suffix &f\"{1}&f\"&a at priority &b{2}&a removed on server &b{3}&a, world &b{4}&a."
|
||||
|
||||
add-temp-prefix-success: "&b{0}&a had prefix &f\"{1}&f\"&a set at a priority of &b{2}&a for a duration of &b{3}&a."
|
||||
add-temp-prefix-server-success: "&b{0}&a had prefix &f\"{1}&f\"&a set at a priority of &b{2}&a on server &b{3}&a, for a duration of &b{4}&a."
|
||||
add-temp-prefix-server-world-success: "&b{0}&a had prefix &f\"{1}&f\"&a set at a priority of &b{2}&a on server &b{3}&a, world &b{4}&a, for a duration of &b{5}&a."
|
||||
remove-temp-prefix-success: "&b{0}&a had temporary prefix &f\"{1}&f\"&a at priority &b{2}&a removed."
|
||||
remove-temp-prefix-server-success: "&b{0}&a had temporary prefix &f\"{1}&f\"&a at priority &b{2}&a removed on server &b{3}&a."
|
||||
remove-temp-prefix-server-world-success: "&b{0}&a had temporary prefix &f\"{1}&f\"&a at priority &b{2}&a removed on server &b{3}&a, world &b{4}&a."
|
||||
|
||||
add-temp-suffix-success: "&b{0}&a had suffix &f\"{1}&f\"&a set at a priority of &b{2}&a for a duration of &b{3}&a."
|
||||
add-temp-suffix-server-success: "&b{0}&a had suffix &f\"{1}&f\"&a set at a priority of &b{2}&a on server &b{3}&a, for a duration of &b{4}&a."
|
||||
add-temp-suffix-server-world-success: "&b{0}&a had suffix &f\"{1}&f\"&a set at a priority of &b{2}&a on server &b{3}&a, world &b{4}&a, for a duration of &b{5}&a."
|
||||
remove-temp-suffix-success: "&b{0}&a had temporary suffix &f\"{1}&f\"&a at priority &b{1}&a removed."
|
||||
remove-temp-suffix-server-success: "&b{0}&a had temporary suffix &f\"{1}&f\"&a at priority &b{2}&a removed on server &b{3}&a."
|
||||
remove-temp-suffix-server-world-success: "&b{0}&a had temporary suffix &f\"{1}&f\"&a at priority &b{2}&a removed on server &b{3}&a, world &b{4}&a."
|
||||
|
||||
already-has-chat-meta: "{0} already has that {1} set."
|
||||
does-not-have-chat-meta: "{0} doesn't have that {1} set."
|
||||
add-chatmeta-success: "&b{0}&a had {1} &f\"{2}&f\"&a set at a priority of &b{3}&a in context {4}&a."
|
||||
add-temp-chatmeta-success: "&b{0}&a had {1} &f\"{2}&f\"&a set at a priority of &b{3}&a for a duration of &b{4}&a in context {5}&a."
|
||||
remove-chatmeta-success: "&b{0}&a had {1} &f\"{2}&f\"&a at priority &b{3}&a removed in context {4}&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 had temporary {1} &f\"{2}&f\"&a at priority &b{3}&a removed in context {4}&a."
|
||||
bulk-remove-temp-chatmeta-success: "&b{0}&a had all temporary {1}es at priority &b{3}&a removed in context {4}&a."
|
||||
already-has-meta: "{0} already has that meta key value pair set."
|
||||
set-meta-success: "&aSet meta value for key &f\"{0}&f\"&a to &f\"{1}&f\"&a for &b{2}&a."
|
||||
set-meta-server-success: "&aSet meta value for key &f\"{0}&f\"&a to &f\"{1}&f\"&a for &b{2}&a on server &b{3}&a."
|
||||
set-meta-server-world-success: "&aSet meta value for key &f\"{0}&f\"&a to &f\"{1}&f\"&a for &b{2}&a on server &b{3}&a, world &b{4}&a."
|
||||
set-meta-temp-success: "&aSet meta value for key &f\"{0}&f\"&a to &f\"{1}&f\"&a for &b{2}&a for a duration of &b{3}&a."
|
||||
set-meta-temp-server-success: "&aSet meta value for key &f\"{0}&f\"&a to &f\"{1}&f\"&a for &b{2}&a on server &b{3}&a for a duration of &b{4}&a."
|
||||
set-meta-temp-server-world-success: "&aSet meta value for key &f\"{0}&f\"&a to &f\"{1}&f\"&a for &b{2}&a on server &b{3}&a, world &b{4}&a, for a duration of &b{5}&a."
|
||||
|
||||
unset-meta-success: "&aUnset meta value with key &f\"{0}&f\"&a for &b{1}&a."
|
||||
unset-meta-server-success: "&aUnset meta value with key &f\"{0}&f\"&a for &b{1}&a on server &b{2}&a."
|
||||
unset-meta-server-world-success: "&aUnset meta value with key &f\"{0}&f\"&a for &b{1}&a on server &b{2}&a, world &b{3}&a."
|
||||
unset-meta-temp-success: "&aUnset temporary meta value with key &f\"{0}&f\"&a for &b{1}&a."
|
||||
unset-meta-temp-server-success: "&aUnset temporary meta value with key &f\"{0}&f\"&a for &b{1}&a on server &b{2}&a."
|
||||
unset-meta-temp-server-world-success: "&aUnset temporary meta value with key &f\"{0}&f\"&a for &b{1}&a on server &b{2}&a, world &b{3}&a."
|
||||
|
||||
set-meta-success: "&aSet meta value for key &f\"{0}&f\"&a to &f\"{1}&f\"&a for &b{2}&a in context {3}&a."
|
||||
set-meta-temp-success: "&aSet meta value for key &f\"{0}&f\"&a to &f\"{1}&f\"&a for &b{2}&a for a duration of &b{3}&a in context {4}&a."
|
||||
unset-meta-success: "&aUnset meta value with key &f\"{0}&f\"&a for &b{1}&a in context {2}&a."
|
||||
unset-meta-temp-success: "&aUnset temporary meta value with key &f\"{0}&f\"&a for &b{1}&a in context {2}&a."
|
||||
bulk-change-type-error: "Invalid type. Was expecting 'server' or 'world'."
|
||||
bulk-change-success: "&aApplied bulk change successfully. {0} records were changed."
|
||||
|
||||
user-info-general: >
|
||||
{PREFIX}&b&l> &bUser Info: &f{0}\n
|
||||
{PREFIX}&f- &3UUID: &f{1}\n
|
||||
@@ -273,6 +213,7 @@ info-temp-parent-header: "&f- &aTemporary Parent Groups:"
|
||||
user-getuuid: "&bThe UUID of &b{0}&b is &b{1}&b."
|
||||
user-removegroup-error-primary: "You cannot remove a user from their primary group."
|
||||
user-primarygroup-success: "&b{0}&a's primary group was set to &b{1}&a."
|
||||
user-primarygroup-warn-option: "&cWarning: The primary group calculation method being used by this server &7({0}) &cmay not reflect this change."
|
||||
user-primarygroup-error-alreadyhas: "The user already has this group set as their primary group."
|
||||
user-primarygroup-error-notmember: "&b{0}&a was not already a member of &b{1}&a, adding them now."
|
||||
user-track-error-not-contain-group: "The user specified isn't already in any groups on this track."
|
||||
@@ -284,7 +225,7 @@ user-promote-success-server: "&aPromoting user along track &b{0}&a from &b{1}&a
|
||||
user-promote-success-server-world: "&aPromoting user along track &b{0}&a from &b{1}&a to &b{2}&a on server &b{3}&a, world &b{4}&a."
|
||||
user-promote-error-endoftrack: "The end of track &4{0}&c was reached. Unable to promote user."
|
||||
user-promote-error-malformed: >
|
||||
{PREFIX}The next group on the track, {0}, no longer exists. Unable to promote user.
|
||||
{PREFIX}The next group on the track, {0}, no longer exists. Unable to promote user.\n
|
||||
{PREFIX}Either create the group, or remove it from the track and try again.
|
||||
user-demote-success: "&aDemoting user along track &b{0}&a from &b{1}&a to &b{2}&a."
|
||||
user-demote-success-server: "&aDemoting user along track &b{0}&a from &b{1}&a to &b{2}&a on server &b{3}&a."
|
||||
@@ -293,9 +234,9 @@ user-demote-endoftrack: "The end of track &4{0}&c was reached, so &4{1}&c was re
|
||||
user-demote-error-malformed: >
|
||||
{PREFIX}The previous group on the track, {0}, no longer exists. Unable to demote user.\n
|
||||
{PREFIX}Either create the group, or remove it from the track and try again.
|
||||
user-demote-error-not-contain-group: "Demotions are done based on primary groups. The users primary group is not on the track specified."
|
||||
user-showpos: "&aShowing &b{0}&a's position on track &b{1}&a.{2}"
|
||||
|
||||
user-showpos: >
|
||||
&aShowing &b{0}&a's position on track &b{1}&a.\n
|
||||
{2}
|
||||
group-info-general: >
|
||||
{PREFIX}&b&l> &bGroup Info: &f{0}\n
|
||||
{PREFIX}&f- &3Display Name: &f{1}\n
|
||||
@@ -307,7 +248,6 @@ group-info-general: >
|
||||
{PREFIX}&f- &3Suffixes: &a{6}\n
|
||||
{PREFIX}&f- &3Meta: &a{7}
|
||||
group-set-weight: "&aSet weight to &b{0}&a for group &b{1}&a."
|
||||
|
||||
track-info: >
|
||||
{PREFIX}&b&l> &bShowing Track: &f{0}\n
|
||||
{PREFIX}&f- &7Path: &f{1}
|
||||
@@ -317,55 +257,43 @@ track-insert-success: "&aGroup &b{0}&a was successfully inserted into track &b{1
|
||||
track-insert-error-number: "Expected number but instead received: {0}"
|
||||
track-insert-error-invalid-pos: "Unable to insert at position {0}. Index out of bounds."
|
||||
track-remove-success: "&aGroup &b{0}&a was successfully removed from track &b{1}&a."
|
||||
|
||||
log-load-error: "The log could not be loaded."
|
||||
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-toggle-on: "&aEnabled&b logging output."
|
||||
log-notify-toggle-off: "&cDisabled&b logging output."
|
||||
log-notify-already-on: "You are already receiving notifications."
|
||||
log-notify-already-off: "You aren't currently receiving notifications."
|
||||
log-notify-unknown: "State unknown. Expecting \"on\" or \"off\"."
|
||||
|
||||
log-search-header: "&aShowing recent actions for query &b{0} &a(page &f{1}&a of &f{2}&a)"
|
||||
|
||||
log-recent-header: "&aShowing recent actions (page &f{0}&a of &f{1}&a)"
|
||||
log-recent-by-header: "&aShowing recent actions by &b{0} &a(page &f{1}&a of &f{2}&a)"
|
||||
|
||||
log-history-user-header: "&aShowing history for user &b{0} &a(page &f{1}&a of &f{2}&a)"
|
||||
log-history-group-header: "&aShowing history for group &b{0} &a(page &f{1}&a of &f{2}&a)"
|
||||
log-history-track-header: "&aShowing history for track &b{0} &a(page &f{1}&a of &f{2}&a)"
|
||||
|
||||
log-export-already-exists: "Error: File {0} already exists."
|
||||
log-export-not-writable: "Error: File {0} is not writable."
|
||||
log-export-empty: "The log is empty and therefore cannot be exported."
|
||||
log-export-failure: "An unexpected error occured whilst writing to the file."
|
||||
log-export-success: "&aSuccessfully exported the log to &b{0}&a."
|
||||
|
||||
import-already-running: "Another import process is already running. Please wait for it to finish and try again."
|
||||
export-already-running: "Another export process is already running. Please wait for it to finish and try again."
|
||||
import-log-doesnt-exist: "Error: File {0} does not exist."
|
||||
import-log-not-readable: "Error: File {0} is not readable."
|
||||
import-log-failure: "An unexpected error occured whilst reading from the log file."
|
||||
|
||||
import-progress: "&b(Import) &b-> &f{0} &fpercent complete &7- &b{1}&f/&b{2} &foperations complete with &c{3} &ferrors."
|
||||
import-progress-sin: "&b(Import) &b-> &f{0} &fpercent complete &7- &b{1}&f/&b{2} &foperations complete with &c{3} &ferror."
|
||||
import-start: "&b(Import) &b-> &fStarting import process."
|
||||
|
||||
import-end-complete: "&b(Import) &a&lCOMPLETED &7- took &b{0} &7seconds - &7No errors."
|
||||
import-end-complete-err: "&b(Import) &a&lCOMPLETED &7- took &b{0} &7seconds - &c{1} errors."
|
||||
import-end-complete-err-sin: "&b(Import) &a&lCOMPLETED &7- took &b{0} &7seconds - &c{1} error."
|
||||
|
||||
import-end-error-header: >
|
||||
{PREFIX}&b(Import) &7------------> &fShowing Error #&b{0} &7<------------\n
|
||||
{PREFIX}&b(Import) &fWhilst executing: &3Command #{1}\n
|
||||
{PREFIX}&b(Import) &fCommand: &7{2}\n
|
||||
{PREFIX}&b(Import) &fType: &3{3}\n
|
||||
{PREFIX}&b(Import) &fOutput:
|
||||
|
||||
import-end-error-content: "&b(Import) &b-> &c{0}"
|
||||
import-end-error-footer: "&b(Import) &7<------------------------------------------>"
|
||||
|
||||
migration-not-console: "Migration must be performed from the Console."
|
||||
@@ -0,0 +1,338 @@
|
||||
# LuckPerms Language File
|
||||
# Locale: es_ES (Spanish)
|
||||
# Author: Jose Chavez (Twitter: @JoCHav3z)
|
||||
|
||||
prefix: "&7&l[&b&lL&3&lP&7&l] &c"
|
||||
log-info: "&7&l[&bL&3P&7&l] &3{0}"
|
||||
log-warn: "&7&l[&bLuck&3Perms&7&l] &c[ADVERTENCIA] {0}"
|
||||
log-error: "&7&l[&bLuck&3Perms&7&l] &4[ERROR] {0}"
|
||||
empty: "{0}"
|
||||
player-online: "&aConectado"
|
||||
player-offline: "&cDesconectado"
|
||||
loading-error: "La Informacion de los permisos no pudo ser cargada. Por favor contacte al administrador."
|
||||
op-disabled: "&bEl sistema OP de Vanilla esta deshabilitado en este servidor."
|
||||
op-disabled-sponge: "&2El estado de operador del servidor no tiene efecto cuando un plugin de permisos esta instalado. Por favor edite la informacion de usuario directamente."
|
||||
log: "&3LOG &3&l> {0}"
|
||||
export-log: "&3EXPORTAR &3&l> &f{0}"
|
||||
export-log-progress: "&3EXPORTADO &3&l> &7{0}"
|
||||
migration-log: "&3MIGRACION &7[&3{0}&7] &3&l> &f{1}"
|
||||
migration-log-progress: "&3MIGRADO &7[&3{0}&7] &3&l> &7{1}"
|
||||
command-not-recognised: "Comando no reconocido."
|
||||
command-no-permission: "¡No tienes permiso de usar este comando!"
|
||||
already-haspermission: "{0} ¡Ya tienes este permiso!"
|
||||
does-not-havepermission: "{0} No tienes este permiso establecido."
|
||||
already-has-temp-permission: "{0} ¡Ya tienes este permiso establecido temporalmente!"
|
||||
does-not-have-temp-permission: "{0} No tienes este permiso establecido temporalmente."
|
||||
user-not-found: "&bNo se pudo encontrar al usuario."
|
||||
user-not-online: "&bUsuario &a{0}&b no esta conectado."
|
||||
user-no-data: "&bUsuario &a{0}&b no tiene ningún dato cargado."
|
||||
user-save-success: "&7(Los datos del usuario se guardaron en el almacenamiento)"
|
||||
user-save-error: "Se ha producido un error al guardar el usuario."
|
||||
user-create-fail: "Se produjo un error al crear un nuevo usuario."
|
||||
group-not-found: "&bEl Grupo no se pudo encontrar."
|
||||
group-save-success: "&7(Los datos del grupo se guardaron en el almacenamiento)"
|
||||
group-save-error: "Se ha producido un error al guardar el grupo."
|
||||
track-not-found: "&bNo se pudo encontrar la pista."
|
||||
track-save-success: "&7(Los datos de la pista se guardaron en el almacenamiento)"
|
||||
track-save-error: "Se ha producido un error al guardar la pista."
|
||||
user-invalid-entry: "&d{0}&c El username/uuid no es valido."
|
||||
group-invalid-entry: "Los nombres de grupo sólo pueden contener caracteres alfanuméricos."
|
||||
track-invalid-entry: "Los nombres de pista sólo pueden contener caracteres alfanuméricos."
|
||||
server-invalid-entry: "Los nombres de servidor sólo pueden contener caracteres alfanuméricos."
|
||||
use-inherit-command: "Usa el comando 'parent add' y 'parent remove' en vez de especificar el nodo."
|
||||
verbose-invalid-filter: "&cFiltro Verbose invalido: &f{0}"
|
||||
verbose-on: "&bEl chequeo Verbose de salida se ha establecido en &aTRUE &bpara todos los permisos."
|
||||
verbose-on-query: "&bEl chequeo Verbose de salida que se establecio en &aTRUE &bpara los permisos se ha pareado con los siguientes filtros: &f{0}"
|
||||
verbose-off: "&bEl chequeo Verbose de salida que se establecio en &cFALSE&b."
|
||||
verbose-recording-on: "&bGrabacion de Verbose establecida en &aTRUE &bpara todos los permisos."
|
||||
verbose-recording-on-query: "&bGrabacion de Verbose establecida en &aTRUE &bpara los permisos se ha pareado con los siguientes filtros: &f{0}"
|
||||
verbose-recording-upload-start: "&bGrabacion de Verbose se ha deshabilitado. Cargando resultados..."
|
||||
verbose-recording-url: "&aURL de resultados de Verbose:"
|
||||
tree-upload-start: "&bGenerando arbol de permisos..."
|
||||
tree-empty: "&aNo se puede generar el árbol. No se encontraron resultados."
|
||||
tree-url: "&aURL de arbol de permisos:"
|
||||
search-searching: "&aBúsqueda de usuarios y grupos con &b{0}&a..."
|
||||
search-result: "&aEncontradas &b{0}&a entradas por parte de &b{1}&a usuarios y &b{2}&a grupos."
|
||||
search-showing-users: "&bMostrando entradas del usuario:"
|
||||
search-showing-groups: "&bMostrando entradas del grupo:"
|
||||
search-showing-users-with-page: "&bMostrando entradas del usuario: {0}"
|
||||
search-showing-groups-with-page: "&bMostrando entradas del grupo: {0}"
|
||||
check-result: "&aResultado de la comprobación del permiso en el usuario &b{0}&a para permiso &b{1}&a: &f{2}"
|
||||
create-success: "&b{0}&a se creó correctamente."
|
||||
delete-success: "&b{0}&a fue eliminado correctamente."
|
||||
rename-success: "&b{0}&a fue exitosamente renombrado a &b{1}&a."
|
||||
clone-success: "&b{0}&a fue clonado con éxito en &b{1}&a."
|
||||
already-inherits: "{0} ya hereda '{1}'."
|
||||
does-not-inherit: "{0} no hereda '{1}'."
|
||||
already-temp-inherits: "{0} ya lo heredo temporalmente a '{1}'."
|
||||
does-not-temp-inherit: "{0} no lo heredo temporalmente a '{1}'."
|
||||
track-already-contains: "La pista {0} ya contiene el grupo '{1}'."
|
||||
track-does-not-contain: "La pista {0} no contiene el grupo '{1}'."
|
||||
track-ambiguous-call: "El usuario especificado es miembro de varios grupos en esta pista. No se puede determinar su ubicación."
|
||||
group-already-exists: "¡Ese grupo ya existe!"
|
||||
group-does-not-exist: "¡Ese grupo no existe!"
|
||||
group-load-error: "Ocurrió un error inesperado. No se pudo cargar el grupo."
|
||||
groups-load-error: "Ocurrió un error inesperado. No se pueden cargar todos los grupos."
|
||||
track-already-exists: "¡La pista ya existe!"
|
||||
track-does-not-exist: "¡La pista no existe!"
|
||||
track-load-error: "Ocurrió un error inesperado. No se pudo cargar la pista."
|
||||
tracks-load-error: "Ocurrió un error inesperado. No se pueden cargar todas las pistas."
|
||||
track-empty: "La pista no se puede utilizar porque está vacía o contiene sólo un grupo."
|
||||
update-task-request: "&bActualizar tarea programada."
|
||||
update-task-complete: "&aLa actualizacion de la tarea a finalizado."
|
||||
update-task-complete-network: "&aLa actualizacion de la tarea a finalizado. Ahora intentando enviar a otros servidores."
|
||||
update-task-push-success: "&aOtros servidores fueron notificados vía &b{0} Mensajería &aexitoxamente."
|
||||
update-task-push-failure: "&cError al empujar cambios a otros servidores."
|
||||
update-task-push-failure-not-setup: "&cError al presionar los cambios a otros servidores. No se ha configurado un servicio de mensajería."
|
||||
reload-config-success: "&aSe ha vuelto a cargar el archivo de configuración. &7(Algunas opciones sólo se aplicarán después de que el servidor se haya reiniciado.)"
|
||||
info: >
|
||||
{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}
|
||||
create-group-error: "Se produjo un error al crear el grupo."
|
||||
delete-group-error: "Se produjo un error al eliminar el grupo."
|
||||
delete-group-error-default: "No puede eliminar el grupo predeterminado."
|
||||
groups-list: "&aGrupos: {0}"
|
||||
create-track-error: "Se produjo un error al crear la pista."
|
||||
delete-track-error: "Se produjo un error al eliminar la pista."
|
||||
tracks-list: "&aPistas: {0}"
|
||||
listnodes: "&b{0}'s Nodos:"
|
||||
listnodes-with-page: "&b{0}'s Nodos: {1}"
|
||||
listnodes-temp: >
|
||||
&b{0}'s Temporary Nodes:\n
|
||||
{1}
|
||||
listparents: >
|
||||
&b{0}'s Parent Groups:\n
|
||||
{1}
|
||||
listparents-temp: >
|
||||
&b{0}'s Temporary Parent Groups:\n
|
||||
{1}
|
||||
listgroups: >
|
||||
&b{0}'s Groups:\n
|
||||
{1}
|
||||
listgroups-temp: >
|
||||
&b{0}'s Temporary Groups:\n
|
||||
{1}
|
||||
list-tracks: >
|
||||
&b{0}'s Tracks:\n
|
||||
{1}
|
||||
list-tracks-empty: "{0} no está en ninguna pista."
|
||||
setpermission-success: "&aEstablecer &b{0}&a a &b{1}&a para &b{2}&a."
|
||||
setpermission-server-success: "&aEstablecer &b{0}&a a &b{1}&a para &b{2}&a en el servidor &b{3}&a."
|
||||
setpermission-server-world-success: "&aEstablecer &b{0}&a a &b{1}&a para &b{2}&a en el servidor &b{3}&a, mundo &b{4}&a."
|
||||
setpermission-temp-success: "&aEstablecer &b{0}&a a &b{1}&a para &b{2}&a por una duracion de &b{3}&a."
|
||||
setpermission-temp-server-success: "&aEstablecer &b{0}&a a &b{1}&a para &b{2}&a en el servidor &b{3}&a por una duracion de &b{4}&a."
|
||||
setpermission-temp-server-world-success: "&aEstablecer &b{0}&a a &b{1}&a para &b{2}&a en el servidor &b{3}&a, mundo &b{4}&a, por una duracion de &b{5}&a."
|
||||
unsetpermission-success: "&aDesestablecer &b{0}&a para &b{1}&a."
|
||||
unsetpermission-server-success: "&aDesestablecer &b{0}&a para &b{1}&a en el servidor &b{2}&a."
|
||||
unsetpermission-server-world-success: "&aDesestablecer &b{0}&a para &b{1}&a en el servidor &b{2}&a, mundo &b{3}&a."
|
||||
unset-temp-permission-success: "&aDesestablecer temporalmente el permiso &b{0}&a para &b{1}&a."
|
||||
unset-temp-permission-server-success: "&aDesestablecer temporalmente el permiso &b{0}&a para &b{1}&a en el servidor &b{2}&a."
|
||||
unset-temp-permission-server-world-success: "&aDesestablecer temporalmente el permiso &b{0}&a para &b{1}&a en el servidor &b{2}&a, mundo &b{3}&a."
|
||||
set-inherit-success: "&b{0}&a ahora hereda los permisos de &b{1}&a."
|
||||
set-inherit-server-success: "&b{0}&a ahora hereda los permisos de &b{1}&a en el servidor &b{2}&a."
|
||||
set-inherit-server-world-success: "&b{0}&a ahora hereda los permisos de &b{1}&a en el servidor &b{2}&a, mundo &b{3}&a."
|
||||
set-parent-success: "&b{0}&a sus grupos parentales existentes han sido borrados, y ahora solo heredan &b{1}&a."
|
||||
set-parent-server-success: "&b{0}&a sus grupos parentales existentes han sido borrados, y ahora solo heredan &b{1}&a en el servidor &b{2}&a."
|
||||
set-parent-server-world-success: "&b{0}&a sus grupos parentales existentes han sido borrados, y ahora solo heredan &b{1}&a en el servidor &b{2}&a, mundo &b{3}&a."
|
||||
set-temp-inherit-success: "&b{0}&a ahora heredan permisos de &b{1}&a por una duracion de &b{2}&a."
|
||||
set-temp-inherit-server-success: "&b{0}&a ahora heredan permisos de &b{1}&a en el servidor &b{2}&a por una duracion de &b{3}&a."
|
||||
set-temp-inherit-server-world-success: "&b{0}&a ahora heredan permisos de &b{1}&a en el servidor &b{2}&a, mundo &b{3}&a, por una duracion de &b{4}&a."
|
||||
unset-inherit-success: "&b{0}&a ya no hereda los permisos de &b{1}&a."
|
||||
unset-inherit-server-success: "&b{0}&a ya no hereda los permisos de &b{1}&a en el servidor &b{2}&a."
|
||||
unset-inherit-server-world-success: "&b{0}&a ya no hereda los permisos de &b{1}&a en el servidor &b{2}&a, mundo &b{3}&a."
|
||||
unset-temp-inherit-success: "&b{0}&a ya no hereda temporalmente los permisos de &b{1}&a."
|
||||
unset-temp-inherit-server-success: "&b{0}&a ya no hereda temporalmente los permisos &b{1}&a en el servidor &b{2}&a."
|
||||
unset-temp-inherit-server-world-success: "&b{0}&a ya no hereda temporalmente los permisos &b{1}&a en el servidor &b{2}&a, mundo &b{3}&a."
|
||||
clear-success: "&b{0}&a's permisos fueron borrados. (&b{1}&a nodos fueron removidos.)"
|
||||
clear-success-singular: "&b{0}&a's permisos fueron borrados. (&b{1}&a nodo fue removido.)"
|
||||
parent-clear-success: "&b{0}&a's los padres fueron eliminados. (&b{1}&a nodos fueron removidos.)"
|
||||
parent-clear-success-singular: "&b{0}&a's los padres fueron eliminados. (&b{1}&a nodo fue removido.)"
|
||||
meta-clear-success: "&b{0}&a's meta fue eliminada. (&b{1}&a nodos fueron removidos.)"
|
||||
meta-clear-success-singular: "&b{0}&a's meta fue eliminada. (&b{1}&a nodo fue removido.)"
|
||||
illegal-date-error: "No se pudo analizar la fecha '{0}'."
|
||||
past-date-error: "¡No puedes fijar una fecha en el pasado!"
|
||||
chat-meta-prefix-header: "&b{0}'s Prefijos"
|
||||
chat-meta-suffix-header: "&b{0}'s Sufijos"
|
||||
meta-header: "&b{0}'s Meta"
|
||||
chat-meta-entry: "&b-> {0} &f- &f\"{1}&f\" &8(&7heredado de &a{2}&8)"
|
||||
chat-meta-entry-with-context: "&b-> {0} &f- &f\"{1}&f\" &8(&7heredado de &a{2}&8){3}"
|
||||
meta-entry: "&b-> &a{0} &f= &f\"{1}&f\" &8(&7heredado de &a{2}&8)"
|
||||
meta-entry-with-context: "&b-> &a{0} &f= &f\"{1}&f\" &8(&7heredado de &a{2}&8){3}"
|
||||
chat-meta-prefix-none: "&b{0} no tiene prefijos."
|
||||
chat-meta-suffix-none: "&b{0} no tiene sufijos."
|
||||
meta-none: "&b{0} no tiene meta."
|
||||
meta-invalid-priority: "Prioridad no válida '{0}'. Se esperaba un número."
|
||||
already-has-prefix: "{0} ya tiene ese prefijo establecido."
|
||||
already-has-suffix: "{0} ya tiene ese sufijo establecido."
|
||||
does-not-have-prefix: "{0} no tiene ese prefijo establecido."
|
||||
does-not-have-suffix: "{0} no tiene ese sufijo establecido."
|
||||
addprefix-success: "&b{0}&a tiene el prefijo &f\"{1}&f\"&a establecido como prioridad de &b{2}&a."
|
||||
addprefix-server-success: "&b{0}&a tiene el prefijo &f\"{1}&f\"&a establecido como prioridad de &b{2}&a en el servidor &b{3}&a."
|
||||
addprefix-server-world-success: "&b{0}&a tiene el prefijo &f\"{1}&f\"&a establecido como prioridad de &b{2}&a en el servidor &b{3}&a, mundo &b{4}&a."
|
||||
removeprefix-success: "&b{0}&a tiene el prefijo &f\"{1}&f\"&a en prioridad de &b{2}&a removido."
|
||||
removeprefix-server-success: "&b{0}&a tiene el prefijo &f\"{1}&f\"&a en prioridad de &b{2}&a removido en el servidor &b{3}&a."
|
||||
removeprefix-server-world-success: "&b{0}&a tiene el prefijo &f\"{1}&f\"&a en prioridad de &b{2}&a removido en el servidor &b{3}&a, mundo &b{4}&a."
|
||||
addsuffix-success: "&b{0}&a tiene el sufijo &f\"{1}&f\"&a establecido en prioridad de &b{2}&a."
|
||||
addsuffix-server-success: "&b{0}&a tiene el sufijo &f\"{1}&f\"&a establecido en prioridad de &b{2}&a en el servidor &b{3}&a."
|
||||
addsuffix-server-world-success: "&b{0}&a tiene el sufijo &f\"{1}&f\"&a establecido en prioridad de &b{2}&a en el servidor &b{3}&a, mundo &b{4}&a."
|
||||
removesuffix-success: "&b{0}&a tiene el sufijo &f\"{1}&f\"&a en prioridad de &b{2}&a removido."
|
||||
removesuffix-server-success: "&b{0}&a tiene el sufijo &f\"{1}&f\"&a en prioridad de &b{2}&a removido en el servidor &b{3}&a."
|
||||
removesuffix-server-world-success: "&b{0}&a tiene el sufijo &f\"{1}&f\"&a en prioridad de &b{2}&a removido en el servidor &b{3}&a, mundo &b{4}&a."
|
||||
add-temp-prefix-success: "&b{0}&a tiene el prefijo &f\"{1}&f\"&a en prioridad de &b{2}&a por una duracion de &b{3}&a."
|
||||
add-temp-prefix-server-success: "&b{0}&a tiene el prefijo &f\"{1}&f\"&a establecido en prioridad de &b{2}&a en el servidor &b{3}&a, por una duracion de &b{4}&a."
|
||||
add-temp-prefix-server-world-success: "&b{0}&a tiene el prefijo &f\"{1}&f\"&a establecido en prioridad de &b{2}&a en el servidor &b{3}&a, mundo &b{4}&a, por una duracion de &b{5}&a."
|
||||
remove-temp-prefix-success: "&b{0}&a tiene temporalmente el prefijo &f\"{1}&f\"&a en prioridad de &b{2}&a removido."
|
||||
remove-temp-prefix-server-success: "&b{0}&a tiene temporalmente el prefijo &f\"{1}&f\"&a en prioridad de &b{2}&a removido en el servidor &b{3}&a."
|
||||
remove-temp-prefix-server-world-success: "&b{0}&a tiene temporalmente el prefijo &f\"{1}&f\"&a en prioridad de &b{2}&a removido en el servidor &b{3}&a, mundo &b{4}&a."
|
||||
add-temp-suffix-success: "&b{0}&a tiene el sufijo &f\"{1}&f\"&a establecido en prioridad de &b{2}&a por una duracion de &b{3}&a."
|
||||
add-temp-suffix-server-success: "&b{0}&a tiene el sufijo &f\"{1}&f\"&a establecido en prioridad de &b{2}&a en el servidor &b{3}&a, por una duracion de &b{4}&a."
|
||||
add-temp-suffix-server-world-success: "&b{0}&a tiene el sufijo &f\"{1}&f\"&a establecido en prioridad de &b{2}&a en el servidor &b{3}&a, mundo &b{4}&a, por una duracion de &b{5}&a."
|
||||
remove-temp-suffix-success: "&b{0}&a tiene temporalmente el sufijo &f\"{1}&f\"&a en prioridad de &b{1}&a removido."
|
||||
remove-temp-suffix-server-success: "&b{0}&a tiene temporalmente el sufijo &f\"{1}&f\"&a en prioridad de &b{2}&a removido en el servidor &b{3}&a."
|
||||
remove-temp-suffix-server-world-success: "&b{0}&a tiene temporalmente el sufijo &f\"{1}&f\"&a en prioridad de &b{2}&a removido en el servidor &b{3}&a, mundo &b{4}&a."
|
||||
already-has-meta: "{0} ya tiene ese par de valores de llave meta establecido."
|
||||
set-meta-success: "&aEstablecer el valor meta para la llave &f\"{0}&f\"&a a &f\"{1}&f\"&a para &b{2}&a."
|
||||
set-meta-server-success: "&aEstablecer el valor meta para la llave &f\"{0}&f\"&a a &f\"{1}&f\"&a para &b{2}&a en el servidor &b{3}&a."
|
||||
set-meta-server-world-success: "&aEstablecer el valor meta para la llave &f\"{0}&f\"&a a &f\"{1}&f\"&a para &b{2}&a en el servidor &b{3}&a, mundo &b{4}&a."
|
||||
set-meta-temp-success: "&aEstablecer el valor meta para la llave &f\"{0}&f\"&a a &f\"{1}&f\"&a para &b{2}&a por una duracion de &b{3}&a."
|
||||
set-meta-temp-server-success: "&aEstablecer el valor meta para la llave &f\"{0}&f\"&a a &f\"{1}&f\"&a para &b{2}&a en el servidor &b{3}&a por una duracion de &b{4}&a."
|
||||
set-meta-temp-server-world-success: "&aEstablecer el valor meta para la llave &f\"{0}&f\"&a a &f\"{1}&f\"&a para &b{2}&a en el servidor &b{3}&a, mundo &b{4}&a, por una duracion de &b{5}&a."
|
||||
unset-meta-success: "&aDesestablecer el valor meta con la llave &f\"{0}&f\"&a para &b{1}&a."
|
||||
unset-meta-server-success: "&aDesestablecer el valor meta con la llave &f\"{0}&f\"&a para &b{1}&a en el servidor &b{2}&a."
|
||||
unset-meta-server-world-success: "&aDesestablecer el valor meta con la llave &f\"{0}&f\"&a for &b{1}&a en el servidor &b{2}&a, mundo &b{3}&a."
|
||||
unset-meta-temp-success: "&aDesestablecer temporalmente el valor meta con la llave &f\"{0}&f\"&a para &b{1}&a."
|
||||
unset-meta-temp-server-success: "&aDesestablecer temporalmente el valor meta con la llave &f\"{0}&f\"&a para &b{1}&a en el servidor &b{2}&a."
|
||||
unset-meta-temp-server-world-success: "&aDesestablecer temporalmente el valor meta con la llave &f\"{0}&f\"&a para &b{1}&a en el servidor &b{2}&a, mundo &b{3}&a."
|
||||
bulk-change-type-error: "Tipo no válido. Se estaba esperando 'server' o 'world'."
|
||||
bulk-change-success: "&aEl cambio masivo fue aplicado correctamente. {0} los registros fueron cambiados."
|
||||
user-info-general: >
|
||||
{PREFIX}&b&l> &bUser Info: &f{0}\n
|
||||
{PREFIX}&f- &3UUID: &f{1}\n
|
||||
{PREFIX}&f- &3Status: {2}\n
|
||||
{PREFIX}&f- &3Primary Group: &f{3}\n
|
||||
{PREFIX}&f- &aCounts:\n
|
||||
{PREFIX}&f- &3Permissions: &a{4}\n
|
||||
{PREFIX}&f- &3Temporary Permissions: &a{5}\n
|
||||
{PREFIX}&f- &3Prefixes: &a{6}\n
|
||||
{PREFIX}&f- &3Suffixes: &a{7}\n
|
||||
{PREFIX}&f- &3Meta: &a{8}
|
||||
user-info-data: >
|
||||
{PREFIX}&f- &aCached Data:\n
|
||||
{PREFIX}&f- &3Is Loaded: {0}\n
|
||||
{PREFIX}&f- &3Current Contexts: {1}\n
|
||||
{PREFIX}&f- &3Current Prefix: {2}\n
|
||||
{PREFIX}&f- &3Current Suffix: {3}
|
||||
info-parent-header: "&f- &aGrupos Parentales:"
|
||||
info-temp-parent-header: "&f- &aGrupos Temporalmente Parentales:"
|
||||
user-getuuid: "&bEl UUID de &b{0}&b es &b{1}&b."
|
||||
user-removegroup-error-primary: "No puede eliminar un usuario de su grupo principal."
|
||||
user-primarygroup-success: "&b{0}&a's grupo primario se estableció &b{1}&a."
|
||||
user-primarygroup-warn-option: "&cAdvertencia: El método de cálculo de grupo primario utilizado por este servidor &7({0}) &cpuede no reflejar este cambio."
|
||||
user-primarygroup-error-alreadyhas: "El usuario ya tiene este grupo configurado como su grupo principal."
|
||||
user-primarygroup-error-notmember: "&b{0}&a ya no era miembro de &b{1}&a, agregándolos ahora."
|
||||
user-track-error-not-contain-group: "El usuario especificado ya no está en ningún grupo de esta pista."
|
||||
user-track-added-to-first: "&b{0}&a no está en ningún grupo en esta pista, por lo que se agregaron al primer grupo, &b{1}&a."
|
||||
user-track-added-to-first-server: "&b{0}&a no está en ningún grupo en esta pista, por lo que se agregaron al primer grupo, &b{1}&a, en el servidor &b{2}&a."
|
||||
user-track-added-to-first-server-world: "&b{0}&a no está en ningún grupo en esta pista, por lo que se agregaron al primer grupo, &b{1}&a, en el servidor &b{2}&a, mundo &b{3}&a."
|
||||
user-promote-success: "&aPromover al usuario a lo largo de la pista &b{0}&a desde &b{1}&a a &b{2}&a."
|
||||
user-promote-success-server: "&aPromover al usuario a lo largo de la pista &b{0}&a desde &b{1}&a a &b{2}&a en el servidor &b{3}&a."
|
||||
user-promote-success-server-world: "&aPromover al usuario a lo largo de la pista &b{0}&a desde &b{1}&a a &b{2}&a en el servidor &b{3}&a, mundo &b{4}&a."
|
||||
user-promote-error-endoftrack: "El final de la pista &4{0}&c fue alcanzado. No se puede promover al usuario."
|
||||
user-promote-error-malformed: >
|
||||
{PREFIX}The next group on the track, {0}, no longer exists. Unable to promote user.\n
|
||||
{PREFIX}Either create the group, or remove it from the track and try again.
|
||||
user-demote-success: "&aDegradando al usuario a lo largo de la pista &b{0}&a desde &b{1}&a a &b{2}&a."
|
||||
user-demote-success-server: "&aDegradando al usuario a lo largo de la pista &b{0}&a desde &b{1}&a a &b{2}&a en el servidor &b{3}&a."
|
||||
user-demote-success-server-world: "&aDegradando al usuario a lo largo de la pista &b{0}&a desde &b{1}&a a &b{2}&a en el servidor &b{3}&a, mundo &b{4}&a."
|
||||
user-demote-endoftrack: "El final de la pista &4{0}&c fue alcanzado, asi que &4{1}&c fue removido de &4{2}&c."
|
||||
user-demote-error-malformed: >
|
||||
{PREFIX}The previous group on the track, {0}, no longer exists. Unable to demote user.\n
|
||||
{PREFIX}Either create the group, or remove it from the track and try again.
|
||||
user-showpos: >
|
||||
&aShowing &b{0}&a's position on track &b{1}&a.\n
|
||||
{2}
|
||||
group-info-general: >
|
||||
{PREFIX}&b&l> &bGroup Info: &f{0}\n
|
||||
{PREFIX}&f- &3Display Name: &f{1}\n
|
||||
{PREFIX}&f- &3Weight: &f{2}\n
|
||||
{PREFIX}&f- &aCounts:\n
|
||||
{PREFIX}&f- &3Permissions: &a{3}\n
|
||||
{PREFIX}&f- &3Temporary Permissions: &a{4}\n
|
||||
{PREFIX}&f- &3Prefixes: &a{5}\n
|
||||
{PREFIX}&f- &3Suffixes: &a{6}\n
|
||||
{PREFIX}&f- &3Meta: &a{7}
|
||||
group-set-weight: "&aEstablesca el peso a &b{0}&a para el grupo &b{1}&a."
|
||||
track-info: >
|
||||
{PREFIX}&b&l> &bShowing Track: &f{0}\n
|
||||
{PREFIX}&f- &7Path: &f{1}
|
||||
track-clear: "&b{0}&a's pista de grupos fue borrada."
|
||||
track-append-success: "&aGrupo &b{0}&a fue añadido con éxito a la pista &b{1}&a."
|
||||
track-insert-success: "&aGrupo &b{0}&a fue insertado con éxito en la pista &b{1}&a en la posicion &b{2}&a."
|
||||
track-insert-error-number: "Numero esperado en lugar de recibido: {0}"
|
||||
track-insert-error-invalid-pos: "No se puede insertar en la posición {0}. Indice fuera de los limites."
|
||||
track-remove-success: "&aGrupo &b{0}&a se eliminó correctamente de la pista &b{1}&a."
|
||||
log-load-error: "No se pudo cargar el registro."
|
||||
log-invalid-page: "Número de página no válido."
|
||||
log-invalid-page-range: "Número de página no válido. Por favor introduzca un valor entre 1 y {0}."
|
||||
log-no-entries: "&bNo hay entradas de registro que mostrar."
|
||||
log-entry: "&b#{0} -> &8(&7{1} hace&8) {2}"
|
||||
log-notify-toggle-on: "&aHabilitada&b salida de registro."
|
||||
log-notify-toggle-off: "&cDeshabilitada&b salida de registro."
|
||||
log-notify-already-on: "Ya está recibiendo notificaciones."
|
||||
log-notify-already-off: "Actualmente no estás recibiendo notificaciones."
|
||||
log-notify-unknown: "Estado desconocido. Esperando \"on\" o \"off\"."
|
||||
log-search-header: "&aMostrar acciones recientes para la consulta &b{0} &a(pagina &f{1}&a de &f{2}&a)"
|
||||
log-recent-header: "&aMostrando acciones recientes (pagina &f{0}&a de &f{1}&a)"
|
||||
log-recent-by-header: "&aMostrando las acciones recientes por &b{0} &a(pagina &f{1}&a de &f{2}&a)"
|
||||
log-history-user-header: "&aMostrando el historial del usuario &b{0} &a(pagina &f{1}&a de &f{2}&a)"
|
||||
log-history-group-header: "&aMostrando la historia del grupo &b{0} &a(pagina &f{1}&a de &f{2}&a)"
|
||||
log-history-track-header: "&aMostrando la historia de la pista &b{0} &a(pagina &f{1}&a de &f{2}&a)"
|
||||
log-export-already-exists: "Error: Archivo {0} ya existe."
|
||||
log-export-not-writable: "Error: Archivo {0} no se puede escribir."
|
||||
log-export-empty: "El registro está vacío y por lo tanto no puede ser exportado."
|
||||
log-export-failure: "Se ha producido un error inesperado al escribir en el archivo."
|
||||
log-export-success: "&aExitosamente exportó el registro a &b{0}&a."
|
||||
import-already-running: "Ya se está ejecutando otro proceso de importación. Por favor espere a que finalice e inténtelo de nuevo."
|
||||
export-already-running: "Ya se está ejecutando otro proceso de exportación. Por favor espere a que finalice e inténtelo de nuevo."
|
||||
import-log-doesnt-exist: "Error: Archivo {0} no existe."
|
||||
import-log-not-readable: "Error: Archivo {0} no es legible."
|
||||
import-log-failure: "Se ha producido un error inesperado al leer del archivo de registro."
|
||||
import-progress: "&b(Import) &b-> &f{0} &fporcentaje completado &7- &b{1}&f/&b{2} &fOperaciones completas con &c{3} &ferrores."
|
||||
import-progress-sin: "&b(Import) &b-> &f{0} &fporcentaje completado &7- &b{1}&f/&b{2} &fOperaciones completas con &c{3} &ferrores."
|
||||
import-start: "&b(Import) &b-> &fInicio del proceso de importación."
|
||||
import-end-complete: "&b(Import) &a&lCOMPLETADO &7- tomo &b{0} &7segundos - &7No errores."
|
||||
import-end-complete-err: "&b(Import) &a&lCOMPLETADO &7- tomo &b{0} &7segundos - &c{1} errores."
|
||||
import-end-complete-err-sin: "&b(Import) &a&lCOMPLETADO &7- tomo &b{0} &7segundos - &c{1} errores."
|
||||
import-end-error-header: >
|
||||
{PREFIX}&b(Import) &7------------> &fShowing Error #&b{0} &7<------------\n
|
||||
{PREFIX}&b(Import) &fWhilst executing: &3Command #{1}\n
|
||||
{PREFIX}&b(Import) &fCommand: &7{2}\n
|
||||
{PREFIX}&b(Import) &fType: &3{3}\n
|
||||
{PREFIX}&b(Import) &fOutput:
|
||||
import-end-error-content: "&b(Import) &b-> &c{0}"
|
||||
import-end-error-footer: "&b(Import) &7<------------------------------------------>"
|
||||
@@ -0,0 +1,338 @@
|
||||
# LuckPerms Language File
|
||||
# Locale: ru_RU
|
||||
# Author: Pixelmon.PRO
|
||||
|
||||
prefix: "&7&l[&b&lL&3&lP&7&l] &c"
|
||||
log-info: "&7&l[&bL&3P&7&l] &3{0}"
|
||||
log-warn: "&7&l[&bLuck&3Perms&7&l] &c[WARN] {0}"
|
||||
log-error: "&7&l[&bLuck&3Perms&7&l] &4[ERROR] {0}"
|
||||
empty: "{0}"
|
||||
player-online: "&aОнлайн"
|
||||
player-offline: "&cОффлайн"
|
||||
loading-error: "Не удалось загрузить данные разрешений (пермов). Пожалуйста обратитесь к администратору."
|
||||
op-disabled: "&bНа этом сервере отключена ванильная система OP."
|
||||
op-disabled-sponge: "&2Статус оператора сервера не влияет на установленный плагин разрешений (пермов). Пожалуйста отредактируйте данные пользователя напрямую."
|
||||
log: "&3LOG &3&l> {0}"
|
||||
export-log: "&3ЭКСПОРТ &3&l> &f{0}"
|
||||
export-log-progress: "&3ЭКСПОРТ &3&l> &7{0}"
|
||||
migration-log: "&3ПЕРЕМЕЩЕНИЕ &7[&3{0}&7] &3&l> &f{1}"
|
||||
migration-log-progress: "&3ПЕРЕМЕЩЕНИЕ &7[&3{0}&7] &3&l> &7{1}"
|
||||
command-not-recognised: "Команда не распознана."
|
||||
command-no-permission: "У вас нет разрешения на использование этой команды!"
|
||||
already-haspermission: "{0} уже имеет такое разрешение (перм)!"
|
||||
does-not-havepermission: "{0} не имеет этого набора разрешений (пермов)."
|
||||
already-has-temp-permission: "{0} уже имеет этот набор временных разрешений (пермов)!"
|
||||
does-not-have-temp-permission: "{0} не имеет этого набора временных разрешений (пермов)."
|
||||
user-not-found: "&bНе удалось найти пользователя."
|
||||
user-not-online: "&bПользователь &a{0}&b не онлайн."
|
||||
user-no-data: "&bПользователь &a{0}&b не имеет загруженных данных."
|
||||
user-save-success: "&7(Пользовательские данные были сохранены на хранение)"
|
||||
user-save-error: "При сохранении пользователя произошла ошибка."
|
||||
user-create-fail: "При создании нового пользователя возникла ошибка."
|
||||
group-not-found: "&bНе удалось найти группу."
|
||||
group-save-success: "&7(Групповые данные были сохранены на хранение)"
|
||||
group-save-error: "При сохранении группы произошла ошибка."
|
||||
track-not-found: "&bНе удалось найти путь (track)."
|
||||
track-save-success: "&7(Данные о путе (track) сохранены на хранение)"
|
||||
track-save-error: "При сохранении пути (track) произошла ошибка."
|
||||
user-invalid-entry: "&d{0}&c не является допустимым именем пользователя/uuid."
|
||||
group-invalid-entry: "Имена групп могут содержать только буквенно-цифровые символы."
|
||||
track-invalid-entry: "Имена путей (track) могут содержать только буквенно-цифровые символы."
|
||||
server-invalid-entry: "Имена серверов могут содержать только буквенно-цифровые символы."
|
||||
use-inherit-command: "Используйте команды «parent add» и «parent remove» вместо указания узла (node)."
|
||||
verbose-invalid-filter: "&cНедопустимый подробный (verbose) фильтр: &f{0}"
|
||||
verbose-on: "&Запись подробной проверки установлена на &aВЕРНЫЙ &bдля всех разрешений (пермов)."
|
||||
verbose-on-query: "&Запись подробной проверки установлена на &aВЕРНЫЙ &bДля разрешений, соответствующих следующим фильтрам: &f{0}"
|
||||
verbose-off: "&Запись подробной проверки установлена на &cНЕВЕРНЫЙ&b."
|
||||
verbose-recording-on: "&Запись подробной записи установлена на &aВЕРНЫЙ &bдля всех разрешений."
|
||||
verbose-recording-on-query: "&Запись подробной записи установлена на &aВЕРНЫЙ &bДля разрешений, соответствующих следующим фильтрам: &f{0}"
|
||||
verbose-recording-upload-start: "&bЗапись подробной информации была отключена. Загрузка результатов..."
|
||||
verbose-recording-url: "&aПодробный URL результатов:"
|
||||
tree-upload-start: "&bСоздание дерева разрешений..."
|
||||
tree-empty: "&aНе удалось создать дерево. Ничего не найдено."
|
||||
tree-url: "&aURL дерева разрешений:"
|
||||
search-searching: "&aПоиск пользователей и групп с помощью &b{0}&a..."
|
||||
search-result: "&aНайдено &b{0}&a записи из &b{1}&a пользователей и &b{2}&a групп."
|
||||
search-showing-users: "&bПросмотр записей пользователя:"
|
||||
search-showing-groups: "&bПросмотр записей в группах:"
|
||||
search-showing-users-with-page: "&bПросмотр записей пользователя: {0}"
|
||||
search-showing-groups-with-page: "&bПросмотр записей в группах: {0}"
|
||||
check-result: "&aРезультат проверки разрешения (перма) на пользователя &b{0}&a на разрешение (перма) &b{1}&a: &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: "Путь (Track) {0} уже содержит группу '{1}'."
|
||||
track-does-not-contain: "Путь (Track) {0} не содержит группу '{1}'."
|
||||
track-ambiguous-call: "Указанный пользователь является членом нескольких групп на этом пути (track). Невозможно определить их местоположение."
|
||||
group-already-exists: "Эта группа уже существует!"
|
||||
group-does-not-exist: "Эта группа не существует!"
|
||||
group-load-error: "Произошла непредвиденная ошибка. Группа не загружена."
|
||||
groups-load-error: "Произошла непредвиденная ошибка. Не удалось загрузить все группы."
|
||||
track-already-exists: "Этот путь (track) уже существует!"
|
||||
track-does-not-exist: "Этот путь (track) не существует!"
|
||||
track-load-error: "Произошла непредвиденная ошибка. Путь (track) не загружен."
|
||||
tracks-load-error: "Произошла непредвиденная ошибка. Не удалось загрузить все пути (tracks)."
|
||||
track-empty: "Путь (track) нельзя использовать, так как он пуст или содержит только одну группу."
|
||||
update-task-request: "&bОбновление задачи запланировано."
|
||||
update-task-complete: "&aОбновление задачи завершено."
|
||||
update-task-complete-network: "&aОбновление задачи завершено. Теперь пытаемся подключиться к другим серверам."
|
||||
update-task-push-success: "&aДругие серверы были уведомлены через &b{0} Сообщения и удаленный доступ."
|
||||
update-task-push-failure: "&cОшибка при нажатии изменений на других серверах."
|
||||
update-task-push-failure-not-setup: "&cОшибка при нажатии изменений на других серверах. Служба обмена сообщениями не настроена."
|
||||
reload-config-success: "&aФайл конфигурации был перезагружен. &7(Некоторые параметры будут применяться только после перезапуска сервера.)"
|
||||
info: >
|
||||
{PREFIX}&2Выполнение &bLuckPerms v{0}&2 by &bLuck&2.\n
|
||||
{PREFIX}&f- &3Платформа: &f{1}\n
|
||||
{PREFIX}&f- &3Способ Хранения: &f{2}\n
|
||||
{PREFIX}&f- &3Имя Сервера: &f{3}\n
|
||||
{PREFIX}&f- &3Интервал Синхронизации: &a{4} &fминут\n
|
||||
{PREFIX}&f- &3Служба обмена сообщениями: &f{5}\n
|
||||
{PREFIX}&f- &bГрафы:\n
|
||||
{PREFIX}&f- &3Игроки Онлайн: &a{6}\n
|
||||
{PREFIX}&f- &3Загруженные пользователи: &a{7}\n
|
||||
{PREFIX}&f- &3Загруженные группы: &a{8}\n
|
||||
{PREFIX}&f- &3Загруженные пути (tracks): &a{9}\n
|
||||
{PREFIX}&f- &3Размер лога: &a{10}\n
|
||||
{PREFIX}&f- &3UUID Размер кеша: &a{11}\n
|
||||
{PREFIX}&f- &3Переводы загружены: &a{12}\n
|
||||
{PREFIX}&f- &3Контексты перед обработкой: &a{13}\n
|
||||
{PREFIX}&f- &3Счетчик контекста: &a{14}\n
|
||||
{PREFIX}&f- &3Уникальные разрешения (пермы): &a{15}\n
|
||||
{PREFIX}&f- &bКонфигурация:\n
|
||||
{PREFIX}&f- &3Использует сервер UUIDs: {16}\n
|
||||
{PREFIX}&f- &bСчетчик разрешений (Пермов):\n
|
||||
{PREFIX}&f- &3Включая глобальные: {17}\n
|
||||
{PREFIX}&f- &3Включая глобальный мир: {18}\n
|
||||
{PREFIX}&f- &3Применения глобальных групп: {19}\n
|
||||
{PREFIX}&f- &3Применения глобальных групп мира: {20}\n
|
||||
{PREFIX}&f- &3Применения подстановочных знаков (Wildcards): {21}\n
|
||||
{PREFIX}&f- &3Применение регулярных выражений: {22}\n
|
||||
{PREFIX}&f- &3Применение стенографии (Shorthand): {23}
|
||||
create-group-error: "При создании группы произошла ошибка."
|
||||
delete-group-error: "При удалении группы произошла ошибка."
|
||||
delete-group-error-default: "Вы не можете удалить группу по умолчанию."
|
||||
groups-list: "&aГруппы: {0}"
|
||||
create-track-error: "При создании пути (track) произошла ошибка."
|
||||
delete-track-error: "При удалении пути (Track) произошла ошибка."
|
||||
tracks-list: "&aGenb (Tracks): {0}"
|
||||
listnodes: "&b{0}'s Узлы:"
|
||||
listnodes-with-page: "&b{0}'s Узлы: {1}"
|
||||
listnodes-temp: >
|
||||
&b{0}'s Временные узлы:\n
|
||||
{1}
|
||||
listparents: >
|
||||
&b{0}'s Родительские группы:\n
|
||||
{1}
|
||||
listparents-temp: >
|
||||
&b{0}'s Временные родительские группы:\n
|
||||
{1}
|
||||
listgroups: >
|
||||
&b{0}'s Группы:\n
|
||||
{1}
|
||||
listgroups-temp: >
|
||||
&b{0}'s Временные группы:\n
|
||||
{1}
|
||||
list-tracks: >
|
||||
&b{0}'s Пути (Tracks):\n
|
||||
{1}
|
||||
list-tracks-empty: "{0} Не на каких-либо путях (tracks)."
|
||||
setpermission-success: "&aУстановить &b{0}&a к &b{1}&a для &b{2}&a."
|
||||
setpermission-server-success: "&aУстановить &b{0}&a к &b{1}&a для &b{2}&a на сервер &b{3}&a."
|
||||
setpermission-server-world-success: "&aУстановить &b{0}&a к &b{1}&a для &b{2}&a на сервер &b{3}&a, мир &b{4}&a."
|
||||
setpermission-temp-success: "&aУстановить &b{0}&a к &b{1}&a для &b{2}&a На срок &b{3}&a."
|
||||
setpermission-temp-server-success: "&aУстановить &b{0}&a к &b{1}&a для &b{2}&a на сервер &b{3}&a на срок &b{4}&a."
|
||||
setpermission-temp-server-world-success: "&aУстановить &b{0}&a к &b{1}&a для &b{2}&a на сервер &b{3}&a, мир &b{4}&a, на срок &b{5}&a."
|
||||
unsetpermission-success: "&aСбросить &b{0}&a для &b{1}&a."
|
||||
unsetpermission-server-success: "&aСбросить &b{0}&a для &b{1}&a on server &b{2}&a."
|
||||
unsetpermission-server-world-success: "&aСбросить &b{0}&a для &b{1}&a on server &b{2}&a, world &b{3}&a."
|
||||
unset-temp-permission-success: "&aСбросить временное разрешение &b{0}&a для &b{1}&a."
|
||||
unset-temp-permission-server-success: "&aСбросить временное разрешение &b{0}&a для &b{1}&a на сервере &b{2}&a."
|
||||
unset-temp-permission-server-world-success: "&aСбросить временное разрешение &b{0}&a для &b{1}&a на сервере &b{2}&a, мире &b{3}&a."
|
||||
set-inherit-success: "&b{0}&a теперь наследует разрешения от &b{1}&a."
|
||||
set-inherit-server-success: "&b{0}&a теперь наследует разрешения от &b{1}&a на сервере &b{2}&a."
|
||||
set-inherit-server-world-success: "&b{0}&a теперь наследует разрешения от &b{1}&a на сервере &b{2}&a, мире &b{3}&a."
|
||||
set-parent-success: "&b{0}&a их существующие родительские группы очищены, и теперь только наследуют &b{1}&a."
|
||||
set-parent-server-success: "&b{0}&a их существующие родительские группы очищены, и теперь только наследуют &b{1}&a на сервере &b{2}&a."
|
||||
set-parent-server-world-success: "&b{0}&a их существующие родительские группы очищены, и теперь только наследуют &b{1}&a на сервере &b{2}&a, мире &b{3}&a."
|
||||
set-temp-inherit-success: "&b{0}&a теперь наследует разрешения (пермы) от &b{1}&a на срок &b{2}&a."
|
||||
set-temp-inherit-server-success: "&b{0}&a теперь наследует разрешения (пермы) от &b{1}&a на сервере &b{2}&a for a duration of &b{3}&a."
|
||||
set-temp-inherit-server-world-success: "&b{0}&a теперь наследует разрешения (пермы) от &b{1}&a на сервере &b{2}&a, мире &b{3}&a, на срок &b{4}&a."
|
||||
unset-inherit-success: "&b{0}&a больше не наследует разрешения (пермы) от &b{1}&a."
|
||||
unset-inherit-server-success: "&b{0}&a больше не наследует разрешения (пермы) &b{1}&a на сервере &b{2}&a."
|
||||
unset-inherit-server-world-success: "&b{0}&a больше не наследует разрешения (пермы) &b{1}&a на сервере &b{2}&a, мире &b{3}&a."
|
||||
unset-temp-inherit-success: "&b{0}&a больше не наследует временные разрешения (пермы) &b{1}&a."
|
||||
unset-temp-inherit-server-success: "&b{0}&a больше не наследует временные разрешения (пермы) &b{1}&a на сервере &b{2}&a."
|
||||
unset-temp-inherit-server-world-success: "&b{0}&a больше не наследует временные разрешения (пермы) &b{1}&a на сервере &b{2}&a, мире &b{3}&a."
|
||||
clear-success: "&b{0}&a's разрешения (пермы) были очищены. (&b{1}&a узлы были удалены.)"
|
||||
clear-success-singular: "&b{0}&a's разрешения (пермы) были очищены. (&b{1}&a узел удален.)"
|
||||
parent-clear-success: "&b{0}&a's родители очищены. (&b{1}&a узлы были удалены.)"
|
||||
parent-clear-success-singular: "&b{0}&a's родители очищены. (&b{1}&a узел удален.)"
|
||||
meta-clear-success: "&b{0}&a's Meta очищена. (&b{1}&a узлы были удалены.)"
|
||||
meta-clear-success-singular: "&b{0}&a's Meta очищена. (&b{1}&a узел удален.)"
|
||||
illegal-date-error: "Не удалось выполнить синтаксический анализ даты '{0}'."
|
||||
past-date-error: "Вы не можете установить дату в прошлом!"
|
||||
chat-meta-prefix-header: "&b{0}'s Префиксы"
|
||||
chat-meta-suffix-header: "&b{0}'s Суффиксы"
|
||||
meta-header: "&b{0}'s Meta"
|
||||
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."
|
||||
meta-invalid-priority: "Недопустимый приоритет '{0}'. Ожидается число."
|
||||
already-has-prefix: "{0} Уже имеет этот набор префиксов."
|
||||
already-has-suffix: "{0} Уже имеет этот набор суффиксов."
|
||||
does-not-have-prefix: "{0} Не имеет этого набора префиксов."
|
||||
does-not-have-suffix: "{0} Не имеет этого набора суффиксов."
|
||||
addprefix-success: "&b{0}&a имеет префикс &f\"{1}&f\"&a установленный в приоритете &b{2}&a."
|
||||
addprefix-server-success: "&b{0}&a имеет префикс &f\"{1}&f\"&a установленный в приоритете &b{2}&a на сервере &b{3}&a."
|
||||
addprefix-server-world-success: "&b{0}&a имеет префикс &f\"{1}&f\"&a установленный в приоритете &b{2}&a на сервере &b{3}&a, мире &b{4}&a."
|
||||
removeprefix-success: "&b{0}&a имеет префикс &f\"{1}&f\"&a в приоритете &b{2}&a удалено."
|
||||
removeprefix-server-success: "&b{0}&a имеет префикс &f\"{1}&f\"&a в приоритете &b{2}&a удалено на сервере &b{3}&a."
|
||||
removeprefix-server-world-success: "&b{0}&a имеет префикс &f\"{1}&f\"&a в приоритете &b{2}&a удалено на сервере &b{3}&a, мире &b{4}&a."
|
||||
addsuffix-success: "&b{0}&a имеет суффикс &f\"{1}&f\"&a установленный в приоритете &b{2}&a."
|
||||
addsuffix-server-success: "&b{0}&a имеет суффикс &f\"{1}&f\"&a установленный в приоритете &b{2}&a на сервере &b{3}&a."
|
||||
addsuffix-server-world-success: "&b{0}&a имеет суффикс &f\"{1}&f\"&a установленный в приоритете &b{2}&a on server &b{3}&a, мире &b{4}&a."
|
||||
removesuffix-success: "&b{0}&a имеет суффикс &f\"{1}&f\"&a в приоритете &b{2}&a удалено."
|
||||
removesuffix-server-success: "&b{0}&a имеет суффикс &f\"{1}&f\"&a в приоритете &b{2}&a удалено на сервере &b{3}&a."
|
||||
removesuffix-server-world-success: "&b{0}&a имеет суффикс &f\"{1}&f\"&a в приоритете &b{2}&a удалено на сервере &b{3}&a, мире &b{4}&a."
|
||||
add-temp-prefix-success: "&b{0}&a имеет префикс &f\"{1}&f\"&a установленный в приоритете &b{2}&a на срок &b{3}&a."
|
||||
add-temp-prefix-server-success: "&b{0}&a имеет префикс &f\"{1}&f\"&a установленный в приоритете of &b{2}&a на сервере &b{3}&a, на срок &b{4}&a."
|
||||
add-temp-prefix-server-world-success: "&b{0}&a имеет префикс &f\"{1}&f\"&a установленный в приоритете of &b{2}&a на сервере &b{3}&a, мире &b{4}&a, на срок &b{5}&a."
|
||||
remove-temp-prefix-success: "&b{0}&a Имел временный префикс &f\"{1}&f\"&a в приоритете &b{2}&a удалено."
|
||||
remove-temp-prefix-server-success: "&b{0}&a Имел временный префикс &f\"{1}&f\"&a в приоритете &b{2}&a удалено на сервере &b{3}&a."
|
||||
remove-temp-prefix-server-world-success: "&b{0}&a Имел временный префикс &f\"{1}&f\"&a в приоритете &b{2}&a удалено на сервере &b{3}&a, мире &b{4}&a."
|
||||
add-temp-suffix-success: "&b{0}&a имел суффикс &f\"{1}&f\"&a установленный в приоритете &b{2}&a на срок &b{3}&a."
|
||||
add-temp-suffix-server-success: "&b{0}&a имел суффикс &f\"{1}&f\"&a установленный в приоритете &b{2}&a на сервере &b{3}&a, на срок &b{4}&a."
|
||||
add-temp-suffix-server-world-success: "&b{0}&a имел суффикс &f\"{1}&f\"&a установленный в приоритете &b{2}&a на сервере &b{3}&a, мире &b{4}&a, на срок &b{5}&a."
|
||||
remove-temp-suffix-success: "&b{0}&a Имел временный суффикс &f\"{1}&f\"&a в приоритете &b{1}&a удалено."
|
||||
remove-temp-suffix-server-success: "&b{0}&a Имел временный суффикс &f\"{1}&f\"&a в приоритете &b{2}&a удалено на сервере &b{3}&a."
|
||||
remove-temp-suffix-server-world-success: "&b{0}&a Имел временный суффикс &f\"{1}&f\"&a в приоритете &b{2}&a удалено на сервере &b{3}&a, мире &b{4}&a."
|
||||
already-has-meta: "{0} Уже установлено, что установлена пара мета-значения ключа."
|
||||
set-meta-success: "&aУстановить метазначение для ключа &f\"{0}&f\"&a к &f\"{1}&f\"&a для &b{2}&a."
|
||||
set-meta-server-success: "&aУстановить метазначение для ключа &f\"{0}&f\"&a к &f\"{1}&f\"&a для &b{2}&a на сервере &b{3}&a."
|
||||
set-meta-server-world-success: "&aУстановить метазначение для ключа &f\"{0}&f\"&a к &f\"{1}&f\"&a для &b{2}&a на сервере &b{3}&a, мире &b{4}&a."
|
||||
set-meta-temp-success: "&aУстановить метазначение для ключа &f\"{0}&f\"&a к &f\"{1}&f\"&a для &b{2}&a на срок &b{3}&a."
|
||||
set-meta-temp-server-success: "&aУстановить метазначение для ключа &f\"{0}&f\"&a к &f\"{1}&f\"&a для &b{2}&a на сервере &b{3}&a на срок &b{4}&a."
|
||||
set-meta-temp-server-world-success: "&aУстановить метазначение для ключа &f\"{0}&f\"&a к &f\"{1}&f\"&a для &b{2}&a на сервере &b{3}&a, мире &b{4}&a, на срок &b{5}&a."
|
||||
unset-meta-success: "&aСбросить метазначение с помощью ключа &f\"{0}&f\"&a для &b{1}&a."
|
||||
unset-meta-server-success: "&aСбросить метазначение с помощью ключа &f\"{0}&f\"&a для &b{1}&a на сервере &b{2}&a."
|
||||
unset-meta-server-world-success: "&aСбросить метазначение с помощью ключа &f\"{0}&f\"&a для &b{1}&a на сервере &b{2}&a, мире &b{3}&a."
|
||||
unset-meta-temp-success: "&aUnset temporary meta value with key &f\"{0}&f\"&a для &b{1}&a."
|
||||
unset-meta-temp-server-success: "&aСбросить временное мета-значение с помощью ключа &f\"{0}&f\"&a для &b{1}&a на сервере &b{2}&a."
|
||||
unset-meta-temp-server-world-success: "&aСбросить временное мета-значение с помощью ключа &f\"{0}&f\"&a для &b{1}&a на сервере &b{2}&a, мире &b{3}&a."
|
||||
bulk-change-type-error: "Недопустимый тип. ожидание 'server' или 'world'."
|
||||
bulk-change-success: "&aПрименение изменения успешно. {0} записей изменено."
|
||||
user-info-general: >
|
||||
{PREFIX}&b&l> &bИнформация о пользователе: &f{0}\n
|
||||
{PREFIX}&f- &3UUID: &f{1}\n
|
||||
{PREFIX}&f- &3Статус: {2}\n
|
||||
{PREFIX}&f- &3Первичная группа: &f{3}\n
|
||||
{PREFIX}&f- &aГрафы:\n
|
||||
{PREFIX}&f- &3Разрешения (пермы): &a{4}\n
|
||||
{PREFIX}&f- &3Временные разрешения (пермы): &a{5}\n
|
||||
{PREFIX}&f- &3Префиксы: &a{6}\n
|
||||
{PREFIX}&f- &3Суффиксы: &a{7}\n
|
||||
{PREFIX}&f- &3Meta: &a{8}
|
||||
user-info-data: >
|
||||
{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: "&bUUID для &b{0}&b это &b{1}&b."
|
||||
user-removegroup-error-primary: "Вы не можете удалить пользователя из своей основной группы."
|
||||
user-primarygroup-success: "&b{0}&a's для основной группы установил значение &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: "Указанный пользователь не находится ни в каких группах на этом пути (track)."
|
||||
user-track-added-to-first: "&b{0}&a Не находится ни в каких группах на этом пути (track), поэтому они были добавлены в первую группу, &b{1}&a."
|
||||
user-track-added-to-first-server: "&b{0}&a Не находится ни в каких группах на этом пути (track), поэтому они были добавлены в первую группу, &b{1}&a, на сервере &b{2}&a."
|
||||
user-track-added-to-first-server-world: "&b{0}&a Не находится ни в каких группах на этом пути (track), поэтому они были добавлены в первую группу, &b{1}&a, на сервере &b{2}&a, мире &b{3}&a."
|
||||
user-promote-success: "&aПродвижение пользователя по пути (track) &b{0}&a от &b{1}&a к &b{2}&a."
|
||||
user-promote-success-server: "&aПродвижение пользователя по пути (track) &b{0}&a от &b{1}&a к &b{2}&a на сервере &b{3}&a."
|
||||
user-promote-success-server-world: "&aПродвижение пользователя по пути (track) &b{0}&a от &b{1}&a к &b{2}&a на сервере &b{3}&a, мире &b{4}&a."
|
||||
user-promote-error-endoftrack: "Конец пути (track) &4{0}&c ,был достигнут. Не удалось продвинуть пользователя."
|
||||
user-promote-error-malformed: >
|
||||
{PREFIX}Следующая группа на пути (track), {0}, более не существует. Не удалось продвинуть пользователя.\n
|
||||
{PREFIX}Создайте группу или удалите ее с пути (track) и повторите попытку.
|
||||
user-demote-success: "&aПонижение пользователя по пути (track) &b{0}&a от &b{1}&a к &b{2}&a."
|
||||
user-demote-success-server: "&aПонижение пользователя по пути (track) &b{0}&a от &b{1}&a к &b{2}&a на сервере &b{3}&a."
|
||||
user-demote-success-server-world: "&aПонижение пользователя по пути (track) &b{0}&a от &b{1}&a к &b{2}&a на сервере &b{3}&a, мире &b{4}&a."
|
||||
user-demote-endoftrack: "Конец пути (track) &4{0}&c был достингут, поэтому &4{1}&c был удален из &4{2}&c."
|
||||
user-demote-error-malformed: >
|
||||
{PREFIX}Предыдущая группа на пути (track), {0}, более не существуют. Невозможно понизить рейтинг пользователя.\n
|
||||
{PREFIX}Создайте группу или удалите ее с пути (track) и повторите попытку.
|
||||
user-showpos: >
|
||||
&aпоказывает &b{0}&a's позицию на пути (track) &b{1}&a.\n
|
||||
{2}
|
||||
group-info-general: >
|
||||
{PREFIX}&b&l> &bИнфо о группе: &f{0}\n
|
||||
{PREFIX}&f- &3Отображаемое имя: &f{1}\n
|
||||
{PREFIX}&f- &3Значение: &f{2}\n
|
||||
{PREFIX}&f- &aГрафы:\n
|
||||
{PREFIX}&f- &3Разрешения (пермы): &a{3}\n
|
||||
{PREFIX}&f- &3Временные разрешения (пермы): &a{4}\n
|
||||
{PREFIX}&f- &3Префиксы: &a{5}\n
|
||||
{PREFIX}&f- &3Суффиксы: &a{6}\n
|
||||
{PREFIX}&f- &3Meta: &a{7}
|
||||
group-set-weight: "&aУстановить значение &b{0}&a для группы &b{1}&a."
|
||||
track-info: >
|
||||
{PREFIX}&b&l> &bпоказать путь (track): &f{0}\n
|
||||
{PREFIX}&f- &7Путь: &f{1}
|
||||
track-clear: "&b{0}&a's путь (track) групп был очищен."
|
||||
track-append-success: "&aГруппа &b{0}&a успешно добавлен в путь (track) &b{1}&a."
|
||||
track-insert-success: "&aГруппа &b{0}&a был успешно добавлен в путь (track) &b{1}&a на позиции &b{2}&a."
|
||||
track-insert-error-number: "Ожидаемое число, но вместо этого получено: {0}"
|
||||
track-insert-error-invalid-pos: "Невозможно вставить в позицию {0}. Индекс вне пределов."
|
||||
track-remove-success: "&aгруппа &b{0}&a Успешно удален с пути (track) &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Отображение истории для пути (track) &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} &fПроцент завершен &7- &b{1}&f/&b{2} &fОперации в комплекте с &c{3} &fошибками."
|
||||
import-progress-sin: "&b(Импортировать) &b-> &f{0} &fПроцент завершен &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(Import) &7------------> &fОтображение ошибки #&b{0} &7<------------\n
|
||||
{PREFIX}&b(Import) &fВыполняя: &3Команду #{1}\n
|
||||
{PREFIX}&b(Import) &fКоманда: &7{2}\n
|
||||
{PREFIX}&b(Import) &fТип: &3{3}\n
|
||||
{PREFIX}&b(Import) &fВывод:
|
||||
import-end-error-content: "&b(Импортировать) &b-> &c{0}"
|
||||
import-end-error-footer: "&b(Импортировать) &7<------------------------------------------>"
|
||||
@@ -11,7 +11,7 @@ LuckPerms also includes an extensive API for developers, and support for a varie
|
||||
|
||||
## Useful Links
|
||||
* **Development Builds** - <https://ci.lucko.me/job/LuckPerms>
|
||||
* **Javadocs** - <https://jd.lucko.me/LuckPerms>
|
||||
* **Javadocs** - <https://luckperms.lucko.me/javadocs/>
|
||||
* **Wiki** - <https://github.com/lucko/LuckPerms/wiki>
|
||||
|
||||
## Building
|
||||
@@ -32,13 +32,13 @@ LuckPerms is licensed under the permissive MIT license. Please see [`LICENSE.txt
|
||||
|
||||
## LuckPerms vs Other Plugins
|
||||
### Bukkit
|
||||

|
||||
###### _Features checked on 23rd Aug 2016. If you find any inaccuracies, please let me know._
|
||||

|
||||
|
||||
### Sponge
|
||||

|
||||
###### _Features checked on 8th Oct 2016. If you find any inaccuracies, please let me know._
|
||||

|
||||
|
||||
|
||||
## Thanks
|
||||
[](http://www.ej-technologies.com/products/jprofiler/overview.html)
|
||||
|
||||
Thanks to ej-technologies for granting LuckPerms an open source licence to their [Java Profiling Software](http://www.ej-technologies.com/products/jprofiler/overview.html "Java Profiler").
|
||||
Thanks to ej-technologies for granting LuckPerms an open source licence to their [Java Profiling Software](http://www.ej-technologies.com/products/jprofiler/overview.html "Java Profiler").
|
||||
+3
-2
@@ -5,17 +5,18 @@
|
||||
<parent>
|
||||
<artifactId>luckperms</artifactId>
|
||||
<groupId>me.lucko.luckperms</groupId>
|
||||
<version>3.0-SNAPSHOT</version>
|
||||
<version>3.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>luckperms-api</artifactId>
|
||||
<build>
|
||||
<finalName>LuckPerms-API-${release.version}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<version>${compiler.version}</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
|
||||
@@ -29,8 +29,8 @@ import java.util.Optional;
|
||||
/**
|
||||
* Singleton for 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>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>
|
||||
*/
|
||||
public final class LuckPerms {
|
||||
private static LuckPermsApi api = null;
|
||||
|
||||
@@ -27,7 +27,7 @@ import me.lucko.luckperms.api.context.ContextSet;
|
||||
/**
|
||||
* Context and options for a permission lookup.
|
||||
*
|
||||
* <p> All values are immutable.
|
||||
* <p>All values are immutable.</p>
|
||||
*
|
||||
* @since 2.11
|
||||
*/
|
||||
@@ -192,16 +192,13 @@ public class Contexts {
|
||||
if (o == this) return true;
|
||||
if (!(o instanceof Contexts)) return false;
|
||||
final Contexts other = (Contexts) o;
|
||||
final Object this$context = this.getContexts();
|
||||
final Object other$context = other.getContexts();
|
||||
if (this$context == null ? other$context != null : !this$context.equals(other$context)) return false;
|
||||
if (this.isOp() != other.isOp()) return false;
|
||||
if (this.isIncludeGlobal() != other.isIncludeGlobal()) return false;
|
||||
if (this.isIncludeGlobalWorld() != other.isIncludeGlobalWorld()) return false;
|
||||
if (this.isApplyGroups() != other.isApplyGroups()) return false;
|
||||
if (this.isApplyGlobalGroups() != other.isApplyGlobalGroups()) return false;
|
||||
if (this.isApplyGlobalWorldGroups() != other.isApplyGlobalWorldGroups()) return false;
|
||||
return true;
|
||||
return (this.getContexts() == null ? other.getContexts() == null : this.getContexts().equals(other.getContexts())) &&
|
||||
this.isOp() == other.isOp() &&
|
||||
this.isIncludeGlobal() == other.isIncludeGlobal() &&
|
||||
this.isIncludeGlobalWorld() == other.isIncludeGlobalWorld() &&
|
||||
this.isApplyGroups() == other.isApplyGroups() &&
|
||||
this.isApplyGlobalGroups() == other.isApplyGlobalGroups() &&
|
||||
this.isApplyGlobalWorldGroups() == other.isApplyGlobalWorldGroups();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,8 +210,8 @@ public class Contexts {
|
||||
public int hashCode() {
|
||||
final int PRIME = 59;
|
||||
int result = 1;
|
||||
final Object $context = this.getContexts();
|
||||
result = result * PRIME + ($context == null ? 43 : $context.hashCode());
|
||||
final Object contexts = this.getContexts();
|
||||
result = result * PRIME + (contexts == null ? 43 : contexts.hashCode());
|
||||
result = result * PRIME + (this.isOp() ? 79 : 97);
|
||||
result = result * PRIME + (this.isIncludeGlobal() ? 79 : 97);
|
||||
result = result * PRIME + (this.isIncludeGlobalWorld() ? 79 : 97);
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* 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.exceptions.ObjectAlreadyHasException;
|
||||
import me.lucko.luckperms.exceptions.ObjectLacksException;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public enum DataMutateResult {
|
||||
|
||||
SUCCESS(true, null),
|
||||
ALREADY_HAS(false, ObjectAlreadyHasException::new),
|
||||
LACKS(false, ObjectLacksException::new),
|
||||
FAIL(false, RuntimeException::new);
|
||||
|
||||
private boolean value;
|
||||
private final Supplier<? extends Exception> exceptionSupplier;
|
||||
|
||||
DataMutateResult(boolean value, Supplier<? extends Exception> exceptionSupplier) {
|
||||
this.value = value;
|
||||
this.exceptionSupplier = exceptionSupplier;
|
||||
}
|
||||
|
||||
public void throwException() {
|
||||
if (exceptionSupplier != null) {
|
||||
sneakyThrow(exceptionSupplier.get());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean asBoolean() {
|
||||
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) {
|
||||
sneakyThrow0(t);
|
||||
}
|
||||
|
||||
private static <T extends Throwable> void sneakyThrow0(Throwable t) throws T {
|
||||
throw (T) t;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -82,7 +82,9 @@ public interface Group extends PermissionHolder {
|
||||
* @throws ObjectAlreadyHasException if the group already inherits the group
|
||||
* @throws NullPointerException if the group is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
|
||||
*/
|
||||
@Deprecated
|
||||
void setInheritGroup(Group group) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
@@ -94,7 +96,9 @@ public interface Group extends PermissionHolder {
|
||||
* @throws NullPointerException if the group or server is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
* @throws IllegalArgumentException if the server is invalid
|
||||
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
|
||||
*/
|
||||
@Deprecated
|
||||
void setInheritGroup(Group group, String server) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
@@ -107,7 +111,9 @@ public interface Group extends PermissionHolder {
|
||||
* @throws NullPointerException if the group, server or world is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
* @throws IllegalArgumentException if the server or world is invalid
|
||||
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
|
||||
*/
|
||||
@Deprecated
|
||||
void setInheritGroup(Group group, String server, String world) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
@@ -119,7 +125,9 @@ public interface Group extends PermissionHolder {
|
||||
* @throws NullPointerException if the group is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
* @throws IllegalArgumentException if the expiry time is in the past
|
||||
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
|
||||
*/
|
||||
@Deprecated
|
||||
void setInheritGroup(Group group, long expireAt) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
@@ -132,7 +140,9 @@ public interface Group extends PermissionHolder {
|
||||
* @throws NullPointerException if the group or server is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
* @throws IllegalArgumentException if the expiry time is in the past or the server is invalid
|
||||
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
|
||||
*/
|
||||
@Deprecated
|
||||
void setInheritGroup(Group group, String server, long expireAt) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
@@ -146,7 +156,9 @@ public interface Group extends PermissionHolder {
|
||||
* @throws NullPointerException if the group, server or world is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
* @throws IllegalArgumentException if the expiry time is in the past or the server/world is invalid
|
||||
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
|
||||
*/
|
||||
@Deprecated
|
||||
void setInheritGroup(Group group, String server, String world, long expireAt) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
@@ -156,7 +168,9 @@ public interface Group extends PermissionHolder {
|
||||
* @throws ObjectLacksException if the group does not already inherit the group
|
||||
* @throws NullPointerException if the group is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
|
||||
*/
|
||||
@Deprecated
|
||||
void unsetInheritGroup(Group group) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
@@ -167,7 +181,9 @@ public interface Group extends PermissionHolder {
|
||||
* @throws ObjectLacksException if the group does not already inherit the group
|
||||
* @throws NullPointerException if the group is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
|
||||
*/
|
||||
@Deprecated
|
||||
void unsetInheritGroup(Group group, boolean temporary) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
@@ -179,7 +195,9 @@ public interface Group extends PermissionHolder {
|
||||
* @throws NullPointerException if the group or server is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
* @throws IllegalArgumentException if the server is invalid
|
||||
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
|
||||
*/
|
||||
@Deprecated
|
||||
void unsetInheritGroup(Group group, String server) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
@@ -192,7 +210,9 @@ public interface Group extends PermissionHolder {
|
||||
* @throws NullPointerException if the group, server or world is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
* @throws IllegalArgumentException if the server or world is invalid
|
||||
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
|
||||
*/
|
||||
@Deprecated
|
||||
void unsetInheritGroup(Group group, String server, String world) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
@@ -205,7 +225,9 @@ public interface Group extends PermissionHolder {
|
||||
* @throws NullPointerException if the group or server is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
* @throws IllegalArgumentException if the expiry time is in the past or the server is invalid
|
||||
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
|
||||
*/
|
||||
@Deprecated
|
||||
void unsetInheritGroup(Group group, String server, boolean temporary) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
@@ -219,7 +241,9 @@ public interface Group extends PermissionHolder {
|
||||
* @throws NullPointerException if the group, server or world is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
* @throws IllegalArgumentException if the expiry time is in the past or the server/world is invalid
|
||||
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
|
||||
*/
|
||||
@Deprecated
|
||||
void unsetInheritGroup(Group group, String server, String world, boolean temporary) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
|
||||
@@ -29,8 +29,8 @@ import java.util.UUID;
|
||||
/**
|
||||
* 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>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>
|
||||
*/
|
||||
public interface Log {
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ import java.util.UUID;
|
||||
/**
|
||||
* A single entry in the log
|
||||
*
|
||||
* <p> Implements {@link Comparable} ordering based upon the timestamp of the entry.
|
||||
* <p>Implements {@link Comparable} ordering based upon the timestamp of the entry.</p>
|
||||
*/
|
||||
public class LogEntry implements Comparable<LogEntry> {
|
||||
private static final String FORMAT = "&8(&e%s&8) [&a%s&8] (&b%s&8) &7--> &f%s";
|
||||
@@ -90,7 +90,7 @@ public class LogEntry implements Comparable<LogEntry> {
|
||||
|
||||
public String getFormatted() {
|
||||
return String.format(FORMAT,
|
||||
actorName,
|
||||
String.valueOf(actorName).equals("null") ? actor.toString() : actorName,
|
||||
Character.toString(type),
|
||||
actedName,
|
||||
action
|
||||
@@ -171,13 +171,13 @@ public class LogEntry implements Comparable<LogEntry> {
|
||||
if (o == this) return true;
|
||||
if (!(o instanceof LogEntry)) return false;
|
||||
final LogEntry other = (LogEntry) o;
|
||||
if (this.getTimestamp() != other.getTimestamp()) return false;
|
||||
if (this.getActor() == null ? other.getActor() != null : !this.getActor().equals(other.getActor())) return false;
|
||||
if (this.getActorName() == null ? other.getActorName() != null : !this.getActorName().equals(other.getActorName())) return false;
|
||||
if (this.getType() != other.getType()) return false;
|
||||
if (this.getActed() == null ? other.getActed() != null : !this.getActed().equals(other.getActed())) return false;
|
||||
if (this.getActedName() == null ? other.getActedName() != null : !this.getActedName().equals(other.getActedName())) return false;
|
||||
return this.getAction() == null ? other.getAction() == null : this.getAction().equals(other.getAction());
|
||||
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.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()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -25,8 +25,8 @@ package me.lucko.luckperms.api;
|
||||
/**
|
||||
* A wrapper interface for platform logger instances
|
||||
*
|
||||
* <p> Bukkit/Bungee both use java.util.logging, and Sponge uses org.slf4j. This class wraps those classes so the
|
||||
* commons module can access a logger.
|
||||
* <p>Bukkit/Bungee both use java.util.logging, and Sponge uses org.slf4j. This class wraps those classes so the
|
||||
* commons module can access a logger.</p>
|
||||
*/
|
||||
public interface Logger {
|
||||
|
||||
|
||||
@@ -113,7 +113,9 @@ public interface LuckPermsApi {
|
||||
User getUser(UUID uuid);
|
||||
|
||||
/**
|
||||
* Gets a wrapped user object from the user storage. This method does not return null, unlike {@link #getUser(UUID)}
|
||||
* Gets a wrapped user object from the user storage.
|
||||
*
|
||||
* <p>This method does not return null, unlike {@link #getUser(UUID)}</p>
|
||||
*
|
||||
* @param uuid the uuid of the user to get
|
||||
* @return an optional {@link User} object
|
||||
@@ -131,8 +133,9 @@ public interface LuckPermsApi {
|
||||
User getUser(String name);
|
||||
|
||||
/**
|
||||
* Gets a wrapped user object from the user storage. This method does not return null, unlike {@link
|
||||
* #getUser(String)}
|
||||
* Gets a wrapped user object from the user storage.
|
||||
*
|
||||
* <p>This method does not return null, unlike {@link #getUser(String)}</p>
|
||||
*
|
||||
* @param name the username of the user to get
|
||||
* @return an optional {@link User} object
|
||||
@@ -175,7 +178,9 @@ public interface LuckPermsApi {
|
||||
Group getGroup(String name);
|
||||
|
||||
/**
|
||||
* Gets a wrapped group object from the group storage. This method does not return null, unlike {@link #getGroup}
|
||||
* Gets a wrapped group object from the group storage.
|
||||
*
|
||||
* <p>This method does not return null, unlike {@link #getGroup}</p>
|
||||
*
|
||||
* @param name the name of the group to get
|
||||
* @return an optional {@link Group} object
|
||||
@@ -209,7 +214,9 @@ public interface LuckPermsApi {
|
||||
Track getTrack(String name);
|
||||
|
||||
/**
|
||||
* Gets a wrapped track object from the track storage. This method does not return null, unlike {@link #getTrack}
|
||||
* Gets a wrapped track object from the track storage.
|
||||
*
|
||||
* <p>This method does not return null, unlike {@link #getTrack}</p>
|
||||
*
|
||||
* @param name the name of the track to get
|
||||
* @return an optional {@link Track} object
|
||||
|
||||
@@ -32,8 +32,8 @@ public interface MessagingService {
|
||||
/**
|
||||
* Uses the messaging service to inform other servers about changes.
|
||||
*
|
||||
* <p> This will push the update asynchronously, and this method will return immediately. Calling this method is
|
||||
* equivalent to running "/lp networksync", except will not sync this server.
|
||||
* <p>This will push the update asynchronously, and this method will return immediately. Calling this method is
|
||||
* equivalent to running "/lp networksync", except will not sync this server.</p>
|
||||
*/
|
||||
void pushUpdate();
|
||||
|
||||
|
||||
@@ -34,7 +34,9 @@ import java.util.Set;
|
||||
* A collection of utilities to help retrieve meta values for {@link PermissionHolder}s
|
||||
*
|
||||
* @since 2.7
|
||||
* @deprecated in favour of using {@link NodeFactory#makeMetaNode(String, String)} or {@link me.lucko.luckperms.api.caching.MetaData}.
|
||||
*/
|
||||
@Deprecated
|
||||
public class MetaUtils {
|
||||
|
||||
private static String escapeDelimiters(String s, String... delims) {
|
||||
@@ -92,42 +94,24 @@ public class MetaUtils {
|
||||
* @param holder the holder to apply the meta node to
|
||||
* @param server the server to apply the meta on, can be null
|
||||
* @param world the world to apply the meta on, can be null
|
||||
* @param node the meta node
|
||||
* @param key the meta key
|
||||
* @param value the meta value
|
||||
* @throws NullPointerException if the holder, node or value is null
|
||||
* @throws IllegalArgumentException if the node or value is empty
|
||||
*/
|
||||
public static void setMeta(PermissionHolder holder, String server, String world, String node, String value) {
|
||||
if (holder == null) {
|
||||
throw new NullPointerException("holder");
|
||||
}
|
||||
public static void setMeta(PermissionHolder holder, String server, String world, String key, String value) {
|
||||
if (holder == null) throw new NullPointerException("holder");
|
||||
if (key == null) throw new NullPointerException("node");
|
||||
if (value == null) throw new NullPointerException("value");
|
||||
if (key.equals("")) throw new IllegalArgumentException("node is empty");
|
||||
if (value.equals("")) throw new IllegalArgumentException("value is empty");
|
||||
|
||||
if (node == null) {
|
||||
throw new NullPointerException("node");
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
|
||||
if (node.equals("")) {
|
||||
throw new IllegalArgumentException("node is empty");
|
||||
}
|
||||
|
||||
if (value.equals("")) {
|
||||
throw new IllegalArgumentException("value is empty");
|
||||
}
|
||||
|
||||
if (server == null || server.equals("")) {
|
||||
server = "global";
|
||||
}
|
||||
|
||||
node = escapeCharacters(node);
|
||||
key = escapeCharacters(key);
|
||||
value = escapeCharacters(value);
|
||||
|
||||
Set<Node> toRemove = new HashSet<>();
|
||||
for (Node n : holder.getEnduringPermissions()) {
|
||||
if (n.isMeta() && n.getMeta().getKey().equals(node)) {
|
||||
if (n.isMeta() && n.getMeta().getKey().equals(key)) {
|
||||
toRemove.add(n);
|
||||
}
|
||||
}
|
||||
@@ -135,22 +119,20 @@ public class MetaUtils {
|
||||
for (Node n : toRemove) {
|
||||
try {
|
||||
holder.unsetPermission(n);
|
||||
} catch (ObjectLacksException ignored) {
|
||||
}
|
||||
} catch (ObjectLacksException ignored) {}
|
||||
}
|
||||
|
||||
Node.Builder metaNode = LuckPerms.getApi().buildNode("meta." + node + "." + value).setValue(true);
|
||||
if (!server.equalsIgnoreCase("global")) {
|
||||
Node.Builder metaNode = LuckPerms.getApi().buildNode("meta." + key + "." + value).setValue(true);
|
||||
if (server != null) {
|
||||
metaNode.setServer(server);
|
||||
}
|
||||
if (world != null && !world.equals("")) {
|
||||
metaNode.setServer(server).setWorld(world);
|
||||
if (world != null) {
|
||||
metaNode.setWorld(world);
|
||||
}
|
||||
|
||||
try {
|
||||
holder.setPermission(metaNode.build());
|
||||
} catch (ObjectAlreadyHasException ignored) {
|
||||
}
|
||||
} catch (ObjectAlreadyHasException ignored) {}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,18 +149,8 @@ public class MetaUtils {
|
||||
* @throws IllegalArgumentException if the node is empty
|
||||
*/
|
||||
public static String getMeta(PermissionHolder holder, String server, String world, String node, String defaultValue, boolean includeGlobal) {
|
||||
if (holder == null) {
|
||||
throw new NullPointerException("holder");
|
||||
}
|
||||
|
||||
if (server == null || server.equals("")) {
|
||||
server = "global";
|
||||
}
|
||||
|
||||
if (node == null) {
|
||||
throw new NullPointerException("node");
|
||||
}
|
||||
|
||||
if (holder == null) throw new NullPointerException("holder");
|
||||
if (node == null) throw new NullPointerException("node");
|
||||
if (node.equals("")) {
|
||||
throw new IllegalArgumentException("node is empty");
|
||||
}
|
||||
@@ -186,23 +158,10 @@ public class MetaUtils {
|
||||
node = escapeCharacters(node);
|
||||
|
||||
for (Node n : holder.getPermissions()) {
|
||||
if (!n.getValue()) {
|
||||
continue;
|
||||
}
|
||||
if (!n.getValue() || !n.isMeta()) continue;
|
||||
|
||||
if (!n.isMeta()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!server.equalsIgnoreCase("global")) {
|
||||
if (!n.shouldApplyOnServer(server, includeGlobal, false)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!n.shouldApplyOnWorld(world, includeGlobal, false)) {
|
||||
continue;
|
||||
}
|
||||
if (!n.shouldApplyOnServer(server, includeGlobal, false)) continue;
|
||||
if (!n.shouldApplyOnWorld(world, includeGlobal, false)) continue;
|
||||
|
||||
Map.Entry<String, String> meta = n.getMeta();
|
||||
if (meta.getKey().equalsIgnoreCase(node)) {
|
||||
@@ -214,27 +173,23 @@ public class MetaUtils {
|
||||
}
|
||||
|
||||
private static void setChatMeta(boolean prefix, PermissionHolder holder, String value, int priority, String server, String world) {
|
||||
if (holder == null) {
|
||||
throw new NullPointerException("holder");
|
||||
}
|
||||
|
||||
if (holder == null) throw new NullPointerException("holder");
|
||||
if (value == null || value.equals("")) {
|
||||
throw new IllegalArgumentException("value is null/empty");
|
||||
}
|
||||
|
||||
Node.Builder node = LuckPerms.getApi().buildNode(prefix ? "prefix" : "suffix" + "." + priority + "." + escapeCharacters(value));
|
||||
node.setValue(true);
|
||||
if (!server.equalsIgnoreCase("global")) {
|
||||
if (server != null) {
|
||||
node.setServer(server);
|
||||
}
|
||||
if (world != null && !world.equals("")) {
|
||||
node.setServer(server).setWorld(world);
|
||||
if (world != null) {
|
||||
node.setWorld(world);
|
||||
}
|
||||
|
||||
try {
|
||||
holder.setPermission(node.build());
|
||||
} catch (ObjectAlreadyHasException ignored) {
|
||||
}
|
||||
} catch (ObjectAlreadyHasException ignored) {}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -271,26 +226,14 @@ public class MetaUtils {
|
||||
if (holder == null) {
|
||||
throw new NullPointerException("holder");
|
||||
}
|
||||
if (server == null) {
|
||||
server = "global";
|
||||
}
|
||||
|
||||
int priority = Integer.MIN_VALUE;
|
||||
String meta = null;
|
||||
for (Node n : holder.getAllNodes(Contexts.allowAll())) {
|
||||
if (!n.getValue()) {
|
||||
continue;
|
||||
}
|
||||
if (!n.getValue()) continue;
|
||||
|
||||
if (!server.equalsIgnoreCase("global")) {
|
||||
if (!n.shouldApplyOnServer(server, includeGlobal, false)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!n.shouldApplyOnWorld(world, includeGlobal, false)) {
|
||||
continue;
|
||||
}
|
||||
if (!n.shouldApplyOnServer(server, includeGlobal, false)) continue;
|
||||
if (!n.shouldApplyOnWorld(world, includeGlobal, false)) continue;
|
||||
|
||||
if (prefix ? !n.isPrefix() : !n.isSuffix()) {
|
||||
continue;
|
||||
|
||||
@@ -33,7 +33,7 @@ import java.util.Set;
|
||||
/**
|
||||
* An immutable permission node
|
||||
*
|
||||
* <p> Use {@link LuckPermsApi#buildNode(String)} to get an instance.
|
||||
* <p>Use {@link LuckPermsApi#buildNode(String)} to get an instance.</p>
|
||||
*
|
||||
* @since 2.6
|
||||
*/
|
||||
@@ -85,15 +85,49 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
Optional<String> getWorld();
|
||||
|
||||
/**
|
||||
* Returns if this node is server specific
|
||||
*
|
||||
* @return true if this node is server specific
|
||||
*/
|
||||
boolean isServerSpecific();
|
||||
|
||||
/**
|
||||
* Returns 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
|
||||
*
|
||||
* @return true if this node applies globally, and has no specific context
|
||||
* @since 3.1
|
||||
*/
|
||||
boolean appliesGlobally();
|
||||
|
||||
/**
|
||||
* Returns if this node has any specific context in order to apply.
|
||||
*
|
||||
* @return true if this node has specific context
|
||||
* @since 3.1
|
||||
*/
|
||||
boolean hasSpecificContext();
|
||||
|
||||
/**
|
||||
* Returns 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
|
||||
* @param server the server being checked against, or null
|
||||
* @param world the world being checked against, or null
|
||||
* @param context the context being checked against, or null
|
||||
* @param applyRegex if regex should be applied
|
||||
* @return true if the node should apply, otherwise false
|
||||
* @since 3.1
|
||||
*/
|
||||
boolean shouldApply(boolean includeGlobal, boolean includeGlobalWorld, String server, String world, ContextSet context, boolean applyRegex);
|
||||
|
||||
/**
|
||||
* If this node should apply on a specific server
|
||||
*
|
||||
@@ -203,31 +237,49 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
boolean hasExpired();
|
||||
|
||||
/**
|
||||
* Gets the extra contexts required for this node to apply
|
||||
*
|
||||
* @return the extra contexts required for this node to apply
|
||||
* @since 2.13
|
||||
*/
|
||||
ContextSet getContexts();
|
||||
|
||||
/**
|
||||
* The same as {@link #getContexts()}, but also includes values for "server" and "world" keys if present.
|
||||
*
|
||||
* @return the full contexts required for this node to apply
|
||||
* @since 3.1
|
||||
*/
|
||||
ContextSet getFullContexts();
|
||||
|
||||
/**
|
||||
* Converts this node into a serialized form
|
||||
*
|
||||
* @return a serialized node string
|
||||
* @deprecated because this serialized form is no longer used by the implementation.
|
||||
*/
|
||||
@Deprecated
|
||||
String toSerializedNode();
|
||||
|
||||
/**
|
||||
* Returns if this is a group node
|
||||
*
|
||||
* @return true if this is a group node
|
||||
*/
|
||||
boolean isGroupNode();
|
||||
|
||||
/**
|
||||
* Returns the name of the group
|
||||
*
|
||||
* @return the name of the group
|
||||
* @throws IllegalStateException if this is not a group node. See {@link #isGroupNode()}
|
||||
*/
|
||||
String getGroupName();
|
||||
|
||||
/**
|
||||
* @return true is this node is a wildcard node
|
||||
* Returns if this node is a wildcard node
|
||||
*
|
||||
* @return true if this node is a wildcard node
|
||||
*/
|
||||
boolean isWildcard();
|
||||
|
||||
@@ -240,6 +292,8 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
int getWildcardLevel();
|
||||
|
||||
/**
|
||||
* Returns if this node is a meta node
|
||||
*
|
||||
* @return true if this node is a meta node
|
||||
*/
|
||||
boolean isMeta();
|
||||
|
||||
@@ -33,7 +33,7 @@ public interface NodeFactory {
|
||||
* Creates a node from a serialised node string
|
||||
*
|
||||
* @param serialisedPermission the serialised permission string
|
||||
* @param value the value of the node
|
||||
* @param value the value of the node
|
||||
* @return a node instance
|
||||
* @throws NullPointerException if the permission is null
|
||||
*/
|
||||
@@ -60,18 +60,30 @@ public interface NodeFactory {
|
||||
|
||||
/**
|
||||
* Creates a node builder from a serialised node string
|
||||
*
|
||||
* @param serialisedPermission the serialised permission string
|
||||
* @param value the value of the node
|
||||
* @param value the value of the node
|
||||
* @return a node builder instance
|
||||
* @throws NullPointerException if the permission is null
|
||||
*/
|
||||
Node.Builder newBuilderFromSerialisedNode(String serialisedPermission, boolean value);
|
||||
|
||||
|
||||
/**
|
||||
* Creates a node builder from a group
|
||||
*
|
||||
* @param group the group
|
||||
* @return a node builder instance
|
||||
* @throws NullPointerException if the group is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
* @since 3.1
|
||||
*/
|
||||
Node.Builder makeGroupNode(Group group);
|
||||
|
||||
/**
|
||||
* Creates a node builder from a key value pair
|
||||
*
|
||||
* @param key the key
|
||||
* @param key the key
|
||||
* @param value the value
|
||||
* @return a node builder instance
|
||||
* @throws NullPointerException if the key or value is null
|
||||
@@ -82,7 +94,7 @@ public interface NodeFactory {
|
||||
* Creates a node builder from a prefix string and priority
|
||||
*
|
||||
* @param priority the priority
|
||||
* @param prefix the prefix string
|
||||
* @param prefix the prefix string
|
||||
* @return a node builder instance
|
||||
* @throws NullPointerException if the prefix is null
|
||||
*/
|
||||
@@ -92,7 +104,7 @@ public interface NodeFactory {
|
||||
* Creates a node builder from a prefix string and priority
|
||||
*
|
||||
* @param priority the priority
|
||||
* @param suffix the suffix string
|
||||
* @param suffix the suffix string
|
||||
* @return a node builder instance
|
||||
* @throws NullPointerException if the suffix is null
|
||||
*/
|
||||
|
||||
@@ -32,15 +32,15 @@ import java.util.SortedSet;
|
||||
/**
|
||||
* An object capable of holding permissions
|
||||
*
|
||||
* <p> Any changes made will be lost unless the instance is saved back to the {@link Storage}.
|
||||
* <p>Any changes made will be lost unless the instance is saved back to the {@link Storage}.</p>
|
||||
*/
|
||||
public interface PermissionHolder {
|
||||
|
||||
/**
|
||||
* Gets the objects name
|
||||
*
|
||||
* <p> {@link User#getUuid()}, {@link User#getName()} or {@link Group#getName()} should normally be used instead of
|
||||
* this method.
|
||||
* <p>{@link User#getUuid()}, {@link User#getName()} or {@link Group#getName()} should normally be used instead of
|
||||
* this method.</p>
|
||||
*
|
||||
* @return the identifier for this object. Either a uuid string or name.
|
||||
*/
|
||||
@@ -74,9 +74,11 @@ public interface PermissionHolder {
|
||||
|
||||
/**
|
||||
* Gets a mutable sorted set of the nodes that this object has and inherits, filtered by context
|
||||
* Unlike {@link #getAllNodesFiltered(Contexts)}, this method will not filter individual nodes. The context is only
|
||||
* used to determine which groups should apply.
|
||||
* Nodes are sorted into priority order.
|
||||
*
|
||||
* <p>Unlike {@link #getAllNodesFiltered(Contexts)}, this method will not filter individual nodes. The context is only
|
||||
* used to determine which groups should apply.</p>
|
||||
*
|
||||
* <p>Nodes are sorted into priority order.</p>
|
||||
*
|
||||
* @param contexts the context for the lookup,
|
||||
* @return a mutable sorted set of permissions
|
||||
@@ -87,8 +89,9 @@ public interface PermissionHolder {
|
||||
|
||||
/**
|
||||
* Gets a mutable set of the nodes that this object has and inherits, filtered by context.
|
||||
* Unlike {@link #getAllNodes(Contexts)}, this method WILL filter individual nodes, and only return ones that fully
|
||||
* meet the context provided.
|
||||
*
|
||||
* <p>Unlike {@link #getAllNodes(Contexts)}, this method WILL filter individual nodes, and only return ones that fully
|
||||
* meet the context provided.</p>
|
||||
*
|
||||
* @param contexts the context for the lookup
|
||||
* @return a mutable set of permissions
|
||||
@@ -99,6 +102,7 @@ public interface PermissionHolder {
|
||||
|
||||
/**
|
||||
* Converts the output of {@link #getAllNodesFiltered(Contexts)}, and expands shorthand permissions.
|
||||
*
|
||||
* @param contexts the context for the lookup
|
||||
* @param lowerCase if the keys should be made lowercase whilst being exported
|
||||
* @return a mutable map of permissions
|
||||
@@ -206,7 +210,7 @@ public interface PermissionHolder {
|
||||
boolean hasPermission(String node, boolean b, String server, String world, boolean temporary);
|
||||
|
||||
/**
|
||||
* Cheks to see if the object inherits a certain permission
|
||||
* Checks to see if the object inherits a certain permission
|
||||
*
|
||||
* @param node the node to check for
|
||||
* @return a Tristate for the holders inheritance status for the node
|
||||
@@ -300,17 +304,27 @@ public interface PermissionHolder {
|
||||
*/
|
||||
void setPermission(Node node) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
* Sets a permission for the object
|
||||
*
|
||||
* @param node The node to be set
|
||||
* @throws NullPointerException if the node is null
|
||||
* @return the result of the operation
|
||||
* @since 3.1
|
||||
*/
|
||||
DataMutateResult setPermissionUnchecked(Node node);
|
||||
|
||||
/**
|
||||
* Sets a transient permission for the object
|
||||
*
|
||||
* <p> A transient node is a permission that does not persist.
|
||||
* <p>A transient node is a permission that does not persist.
|
||||
* Whenever a user logs out of the server, or the server restarts, this permission will disappear.
|
||||
* It is never saved to the datastore, and therefore will not apply on other servers.
|
||||
* It is never saved to the datastore, and therefore will not apply on other servers.</p>
|
||||
*
|
||||
* <p> This is useful if you want to temporarily set a permission for a user while they're online, but don't
|
||||
* want it to persist, and have to worry about removing it when they log out.
|
||||
* <p>This is useful if you want to temporarily set a permission for a user while they're online, but don't
|
||||
* want it to persist, and have to worry about removing it when they log out.</p>
|
||||
*
|
||||
* <p> For unsetting a transient permission, see {@link #unsetTransientPermission(Node)}
|
||||
* <p>For unsetting a transient permission, see {@link #unsetTransientPermission(Node)}</p>
|
||||
*
|
||||
* @param node The node to be set
|
||||
* @throws ObjectAlreadyHasException if the object already has the permission
|
||||
@@ -319,6 +333,25 @@ public interface PermissionHolder {
|
||||
*/
|
||||
void setTransientPermission(Node node) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
* Sets a transient permission for the object
|
||||
*
|
||||
* <p>A transient node is a permission that does not persist.
|
||||
* Whenever a user logs out of the server, or the server restarts, this permission will disappear.
|
||||
* It is never saved to the datastore, and therefore will not apply on other servers.</p>
|
||||
*
|
||||
* <p>This is useful if you want to temporarily set a permission for a user while they're online, but don't
|
||||
* want it to persist, and have to worry about removing it when they log out.</p>
|
||||
*
|
||||
* <p>For unsetting a transient permission, see {@link #unsetTransientPermission(Node)}</p>
|
||||
*
|
||||
* @param node The node to be set
|
||||
* @throws NullPointerException if the node is null
|
||||
* @return the result of the operation
|
||||
* @since 3.1
|
||||
*/
|
||||
DataMutateResult setTransientPermissionUnchecked(Node node);
|
||||
|
||||
/**
|
||||
* Sets a permission for the object
|
||||
*
|
||||
@@ -416,6 +449,16 @@ public interface PermissionHolder {
|
||||
*/
|
||||
void unsetPermission(Node node) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
* Unsets a permission for the object
|
||||
*
|
||||
* @param node The node to be unset
|
||||
* @throws NullPointerException if the node is null
|
||||
* @return the result of the operation
|
||||
* @since 3.1
|
||||
*/
|
||||
DataMutateResult unsetPermissionUnchecked(Node node);
|
||||
|
||||
/**
|
||||
* Unsets a transient permission for the object
|
||||
*
|
||||
@@ -426,6 +469,16 @@ public interface PermissionHolder {
|
||||
*/
|
||||
void unsetTransientPermission(Node node) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
* Unsets a transient permission for the object
|
||||
*
|
||||
* @param node The node to be unset
|
||||
* @throws NullPointerException if the node is null
|
||||
* @return the result of the operation
|
||||
* @since 3.1
|
||||
*/
|
||||
DataMutateResult unsetTransientPermissionUnchecked(Node node);
|
||||
|
||||
/**
|
||||
* Unsets a permission for the object
|
||||
*
|
||||
|
||||
@@ -34,11 +34,11 @@ import java.util.function.Consumer;
|
||||
*
|
||||
* <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
|
||||
* blocked.
|
||||
* 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
|
||||
* callback using {@link CompletableFuture#thenAcceptAsync(Consumer, Executor)} and {@link #getSyncExecutor()}.
|
||||
* callback using {@link CompletableFuture#thenAcceptAsync(Consumer, Executor)} and {@link #getSyncExecutor()}.</p>
|
||||
*
|
||||
* @since 2.14
|
||||
*/
|
||||
|
||||
@@ -41,7 +41,7 @@ public interface Track {
|
||||
/**
|
||||
* Gets an ordered list of the groups on this track
|
||||
*
|
||||
* <p> Index 0 is the first/lowest group in (or start of) the track
|
||||
* <p>Index 0 is the first/lowest group in (or start of) the track</p>
|
||||
*
|
||||
* @return an ordered {@link List} of the groups on this track
|
||||
*/
|
||||
|
||||
@@ -25,8 +25,8 @@ package me.lucko.luckperms.api;
|
||||
/**
|
||||
* Represents a permission setting.
|
||||
*
|
||||
* <p> Consider a value of {@link #FALSE} to be a "negated" setting, and a value of {@link #UNDEFINED} to be a
|
||||
* non-existent value.
|
||||
* <p>Consider a value of {@link #FALSE} to be a "negated" setting, and a value of {@link #UNDEFINED} to be a
|
||||
* non-existent value.</p>
|
||||
*/
|
||||
public enum Tristate {
|
||||
|
||||
@@ -63,7 +63,8 @@ public enum Tristate {
|
||||
|
||||
/**
|
||||
* Returns the value of the Tristate as a boolean.
|
||||
* <p> A value of {@link #UNDEFINED} converts to false.
|
||||
*
|
||||
* <p>A value of {@link #UNDEFINED} converts to false.</p>
|
||||
*
|
||||
* @return a boolean representation of the Tristate.
|
||||
*/
|
||||
|
||||
@@ -69,8 +69,8 @@ public interface User extends PermissionHolder {
|
||||
/**
|
||||
* Refresh and re-assign the users permissions.
|
||||
*
|
||||
* <p> This request is not buffered, and the refresh call will be ran directly. This should ideally be called on
|
||||
* an asynchronous thread.
|
||||
* <p>This request is not buffered, and the refresh call will be ran directly. This should ideally be called on
|
||||
* an asynchronous thread.</p>
|
||||
*/
|
||||
void refreshPermissions();
|
||||
|
||||
@@ -128,7 +128,9 @@ public interface User extends PermissionHolder {
|
||||
* @throws ObjectAlreadyHasException if the user is already a member of the group
|
||||
* @throws NullPointerException if the group is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
|
||||
*/
|
||||
@Deprecated
|
||||
void addGroup(Group group) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
@@ -140,7 +142,9 @@ public interface User extends PermissionHolder {
|
||||
* @throws NullPointerException if the group or server is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
* @throws IllegalArgumentException if the server is invalid
|
||||
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
|
||||
*/
|
||||
@Deprecated
|
||||
void addGroup(Group group, String server) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
@@ -153,7 +157,9 @@ public interface User extends PermissionHolder {
|
||||
* @throws NullPointerException if the group, server or world is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
* @throws IllegalArgumentException if the server or world is invalid
|
||||
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
|
||||
*/
|
||||
@Deprecated
|
||||
void addGroup(Group group, String server, String world) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
@@ -165,7 +171,9 @@ public interface User extends PermissionHolder {
|
||||
* @throws NullPointerException if the group is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
* @throws IllegalArgumentException if the expiry time is in the past
|
||||
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
|
||||
*/
|
||||
@Deprecated
|
||||
void addGroup(Group group, long expireAt) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
@@ -178,7 +186,9 @@ public interface User extends PermissionHolder {
|
||||
* @throws NullPointerException if the group or server is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
* @throws IllegalArgumentException if the expiry time is in the past or the server is invalid
|
||||
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
|
||||
*/
|
||||
@Deprecated
|
||||
void addGroup(Group group, String server, long expireAt) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
@@ -192,7 +202,9 @@ public interface User extends PermissionHolder {
|
||||
* @throws NullPointerException if the group, server or world is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
* @throws IllegalArgumentException if the expiry time is in the past or the server/world is invalid
|
||||
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
|
||||
*/
|
||||
@Deprecated
|
||||
void addGroup(Group group, String server, String world, long expireAt) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
@@ -202,7 +214,9 @@ public interface User extends PermissionHolder {
|
||||
* @throws ObjectLacksException if the user isn't a member of the group
|
||||
* @throws NullPointerException if the group is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
|
||||
*/
|
||||
@Deprecated
|
||||
void removeGroup(Group group) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
@@ -213,7 +227,9 @@ public interface User extends PermissionHolder {
|
||||
* @throws ObjectLacksException if the user isn't a member of the group
|
||||
* @throws NullPointerException if the group is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
|
||||
*/
|
||||
@Deprecated
|
||||
void removeGroup(Group group, boolean temporary) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
@@ -225,7 +241,9 @@ public interface User extends PermissionHolder {
|
||||
* @throws NullPointerException if the group or server is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
* @throws IllegalArgumentException if the server is invalid
|
||||
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
|
||||
*/
|
||||
@Deprecated
|
||||
void removeGroup(Group group, String server) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
@@ -238,7 +256,9 @@ public interface User extends PermissionHolder {
|
||||
* @throws NullPointerException if the group, server or world is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
* @throws IllegalArgumentException if the server or world is invalid
|
||||
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
|
||||
*/
|
||||
@Deprecated
|
||||
void removeGroup(Group group, String server, String world) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
@@ -251,7 +271,9 @@ public interface User extends PermissionHolder {
|
||||
* @throws NullPointerException if the group or server is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
* @throws IllegalArgumentException if the expiry time is in the past or the server is invalid
|
||||
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
|
||||
*/
|
||||
@Deprecated
|
||||
void removeGroup(Group group, String server, boolean temporary) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
@@ -265,7 +287,9 @@ public interface User extends PermissionHolder {
|
||||
* @throws NullPointerException if the group, server or world is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
* @throws IllegalArgumentException if the expiry time is in the past or the server/world is invalid
|
||||
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
|
||||
*/
|
||||
@Deprecated
|
||||
void removeGroup(Group group, String server, String world, boolean temporary) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,15 +27,15 @@ import java.util.UUID;
|
||||
/**
|
||||
* 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
|
||||
* <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> 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
|
||||
* <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> THIS IS ONLY EFFECTIVE FOR ONLINE PLAYERS. USE THE DATASTORE METHODS FOR OFFLINE PLAYERS.
|
||||
* <p><strong>This is only effective for online players. Use {@link Storage#getUUID(String)} for offline players.</strong></p>
|
||||
*/
|
||||
public interface UuidCache {
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ public interface PermissionData {
|
||||
/**
|
||||
* Invalidates the underlying permission calculator cache.
|
||||
*
|
||||
* <p> Can be called to allow for an update in defaults.
|
||||
* <p>Can be called to allow for an update in defaults.</p>
|
||||
*/
|
||||
void invalidateCache();
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ import java.util.Set;
|
||||
* Holds cached permission and meta lookup data for a {@link me.lucko.luckperms.api.User}.
|
||||
*
|
||||
* <p>Data is only likely to be available for online users. All calls will account for inheritance, as well as any
|
||||
* default data provided by the platform. This calls are heavily cached and are therefore fast.
|
||||
* default data provided by the platform. This calls are heavily cached and are therefore fast.</p>
|
||||
*
|
||||
* @since 2.13
|
||||
*/
|
||||
@@ -39,7 +39,7 @@ public interface UserData {
|
||||
/**
|
||||
* Gets PermissionData from the cache, given a specified context.
|
||||
*
|
||||
* <p> If the data is not cached, it is calculated. Therefore, this call could be costly.
|
||||
* <p>If the data is not cached, it is calculated. Therefore, this call could be costly.</p>
|
||||
*
|
||||
* @param contexts the contexts to get the permission data in
|
||||
* @return a permission data instance
|
||||
@@ -50,7 +50,7 @@ public interface UserData {
|
||||
/**
|
||||
* Gets MetaData from the cache, given a specified context.
|
||||
*
|
||||
* <p> If the data is not cached, it is calculated. Therefore, this call could be costly.
|
||||
* <p>If the data is not cached, it is calculated. Therefore, this call could be costly.</p>
|
||||
*
|
||||
* @param contexts the contexts to get the permission data in
|
||||
* @return a meta data instance
|
||||
@@ -79,8 +79,8 @@ public interface UserData {
|
||||
/**
|
||||
* Calculates permission data and stores it in the cache.
|
||||
*
|
||||
* <p> If there is already data cached for the given contexts, and if the resultant output is different,
|
||||
* the cached value is updated.
|
||||
* <p>If there is already data cached for the given contexts, and if the resultant output is different,
|
||||
* the cached value is updated.</p>
|
||||
*
|
||||
* @param contexts the contexts to recalculate in.
|
||||
* @throws NullPointerException if contexts is null
|
||||
@@ -90,8 +90,8 @@ public interface UserData {
|
||||
/**
|
||||
* Calculates meta data and stores it in the cache.
|
||||
*
|
||||
* <p> If there is already data cached for the given contexts, and if the resultant output is different,
|
||||
* the cached value is updated.
|
||||
* <p>If there is already data cached for the given contexts, and if the resultant output is different,
|
||||
* the cached value is updated.</p>
|
||||
*
|
||||
* @param contexts the contexts to recalculate in.
|
||||
* @throws NullPointerException if contexts is null
|
||||
@@ -119,7 +119,7 @@ public interface UserData {
|
||||
/**
|
||||
* Ensures that PermissionData and MetaData is cached for a context.
|
||||
*
|
||||
* <p> If the cache does not contain any data for the context, it will be calculated and saved.
|
||||
* <p>If the cache does not contain any data for the context, it will be calculated and saved.</p>
|
||||
*
|
||||
* @param contexts the contexts to pre-calculate for
|
||||
* @throws NullPointerException if contexts is null
|
||||
@@ -128,7 +128,8 @@ public interface UserData {
|
||||
|
||||
/**
|
||||
* Invalidates all of the underlying Permission calculators.
|
||||
* Can be called to allow for an update in defaults.
|
||||
*
|
||||
* <p>Can be called to allow for an update in defaults.</p>
|
||||
*/
|
||||
void invalidatePermissionCalculators();
|
||||
|
||||
|
||||
@@ -22,14 +22,11 @@
|
||||
|
||||
package me.lucko.luckperms.api.context;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Calculates whether contexts are applicable to {@link T}
|
||||
*
|
||||
* <p>Somewhat inspired by the system used on Sponge.
|
||||
*
|
||||
* @param <T> the subject type. Is ALWAYS the player class of the platform.
|
||||
* @since 2.13
|
||||
*/
|
||||
public interface ContextCalculator<T> {
|
||||
|
||||
@@ -43,13 +40,4 @@ public interface ContextCalculator<T> {
|
||||
*/
|
||||
MutableContextSet giveApplicableContext(T subject, MutableContextSet accumulator);
|
||||
|
||||
/**
|
||||
* Checks to see if a context is applicable to a subject
|
||||
*
|
||||
* @param subject the subject to check against
|
||||
* @param context the context to check for
|
||||
* @return true if met, or false if not. If this calculator does not calculate the given context, return false.
|
||||
*/
|
||||
boolean isContextApplicable(T subject, Map.Entry<String, String> context);
|
||||
|
||||
}
|
||||
@@ -25,18 +25,20 @@ package me.lucko.luckperms.api.context;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Holds contexts.
|
||||
* Implementations may be either mutable or immutable.
|
||||
* Holder of contexts.
|
||||
*
|
||||
* <p>Implementations may be either mutable or immutable.</p>
|
||||
*
|
||||
* @since 2.13
|
||||
*/
|
||||
public interface ContextSet {
|
||||
|
||||
/**
|
||||
* Make a singleton ImmutableContextSet from a context pair
|
||||
* Creates an ImmutableContextSet from a context pair
|
||||
*
|
||||
* @param key the key
|
||||
* @param value the value
|
||||
@@ -48,7 +50,22 @@ public interface ContextSet {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ImmutableContextSet from an existing map
|
||||
* Creates an ImmutableContextSet from two context pairs
|
||||
*
|
||||
* @param key1 the first key
|
||||
* @param value1 the first value
|
||||
* @param key2 the second key
|
||||
* @param value2 the second value
|
||||
* @return a new ImmutableContextSet containing the two pairs
|
||||
* @throws NullPointerException if any of the keys or values are null
|
||||
* @since 3.1
|
||||
*/
|
||||
static ImmutableContextSet of(String key1, String value1, String key2, String value2) {
|
||||
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
|
||||
@@ -59,7 +76,7 @@ public interface ContextSet {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ImmutableContextSet from an existing iterable of Map Entries
|
||||
* Creates an ImmutableContextSet from an existing iterable of Map Entries
|
||||
*
|
||||
* @param iterable the iterable to copy from
|
||||
* @return a new ImmutableContextSet representing the pairs in the iterable
|
||||
@@ -70,7 +87,7 @@ public interface ContextSet {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ImmutableContextSet from an existing multimap
|
||||
* Creates an ImmutableContextSet from an existing multimap
|
||||
*
|
||||
* @param multimap the multimap to copy from
|
||||
* @return a new ImmutableContextSet representing the pairs in the multimap
|
||||
@@ -82,7 +99,7 @@ public interface ContextSet {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ImmutableContextSet from an existing set.
|
||||
* Creates an new ImmutableContextSet from an existing set.
|
||||
* Only really useful for converting between mutable and immutable types.
|
||||
*
|
||||
* @param contextSet the context set to copy from
|
||||
@@ -167,6 +184,17 @@ public interface ContextSet {
|
||||
*/
|
||||
Set<String> getValues(String key);
|
||||
|
||||
/**
|
||||
* Returns any value from this set matching the key, if present.
|
||||
*
|
||||
* @param key the key to find values for
|
||||
* @return an optional containing any match
|
||||
* @since 3.1
|
||||
*/
|
||||
default Optional<String> getAnyValue(String key) {
|
||||
return getValues(key).stream().findAny();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if thr set contains a given key mapped to a given value
|
||||
*
|
||||
@@ -187,6 +215,35 @@ public interface ContextSet {
|
||||
*/
|
||||
boolean hasIgnoreCase(String key, String value);
|
||||
|
||||
/**
|
||||
* Checks to see if all entries in this context set are also included in another set.
|
||||
*
|
||||
* @param other the other set to check
|
||||
* @return true if all entries in this set are also in the other set
|
||||
* @since 3.1
|
||||
*/
|
||||
default boolean isSatisfiedBy(ContextSet other) {
|
||||
if (this.isEmpty()) {
|
||||
// this is empty, so is therefore always satisfied.
|
||||
return true;
|
||||
} else if (other.isEmpty()) {
|
||||
// this set isn't empty, but the other one is
|
||||
return false;
|
||||
} else if (this.size() > other.size()) {
|
||||
// this set has more unique entries than the other set, so there's no way this can be satisfied.
|
||||
return false;
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the set is empty
|
||||
*
|
||||
|
||||
@@ -23,9 +23,10 @@
|
||||
package me.lucko.luckperms.api.context;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
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;
|
||||
@@ -37,10 +38,10 @@ import java.util.Set;
|
||||
* @since 2.16
|
||||
*/
|
||||
public final class ImmutableContextSet implements ContextSet {
|
||||
private static final ImmutableContextSet EMPTY = new ImmutableContextSet(ImmutableMultimap.of());
|
||||
private static final ImmutableContextSet EMPTY = new ImmutableContextSet(ImmutableSetMultimap.of());
|
||||
|
||||
/**
|
||||
* Make a singleton ImmutableContextSet from a context pair
|
||||
* Creates an ImmutableContextSet from a context pair
|
||||
*
|
||||
* @param key the key
|
||||
* @param value the value
|
||||
@@ -55,11 +56,39 @@ public final class ImmutableContextSet implements ContextSet {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
|
||||
return new ImmutableContextSet(ImmutableMultimap.of(key.toLowerCase(), value));
|
||||
return new ImmutableContextSet(ImmutableSetMultimap.of(key.toLowerCase(), value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ImmutableContextSet from an existing map
|
||||
* Creates an ImmutableContextSet from two context pairs
|
||||
*
|
||||
* @param key1 the first key
|
||||
* @param value1 the first value
|
||||
* @param key2 the second key
|
||||
* @param value2 the second value
|
||||
* @return a new ImmutableContextSet containing the two pairs
|
||||
* @throws NullPointerException if any of the keys or values are null
|
||||
* @since 3.1
|
||||
*/
|
||||
public static ImmutableContextSet of(String key1, String value1, String key2, String value2) {
|
||||
if (key1 == null) {
|
||||
throw new NullPointerException("key1");
|
||||
}
|
||||
if (value1 == null) {
|
||||
throw new NullPointerException("value1");
|
||||
}
|
||||
if (key2 == null) {
|
||||
throw new NullPointerException("key2");
|
||||
}
|
||||
if (value2 == null) {
|
||||
throw new NullPointerException("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
|
||||
@@ -70,16 +99,16 @@ public final class ImmutableContextSet implements ContextSet {
|
||||
throw new NullPointerException("map");
|
||||
}
|
||||
|
||||
ImmutableMultimap.Builder<String, String> b = ImmutableMultimap.builder();
|
||||
ImmutableSetMultimap.Builder<String, String> b = ImmutableSetMultimap.builder();
|
||||
for (Map.Entry<String, String> e : map.entrySet()) {
|
||||
b.put(e.getKey(), e.getValue());
|
||||
b.put(e.getKey().toLowerCase(), e.getValue());
|
||||
}
|
||||
|
||||
return new ImmutableContextSet(b.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ImmutableContextSet from an existing iterable of Map Entries
|
||||
* Creates an ImmutableContextSet from an existing iterable of Map Entries
|
||||
*
|
||||
* @param iterable the iterable to copy from
|
||||
* @return a new ImmutableContextSet representing the pairs in the iterable
|
||||
@@ -94,7 +123,7 @@ public final class ImmutableContextSet implements ContextSet {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ImmutableContextSet from an existing multimap
|
||||
* Creates an ImmutableContextSet from an existing multimap
|
||||
*
|
||||
* @param multimap the multimap to copy from
|
||||
* @return a new ImmutableContextSet representing the pairs in the multimap
|
||||
@@ -121,7 +150,7 @@ public final class ImmutableContextSet implements ContextSet {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new empty ContextSet.
|
||||
* Creates an new empty ContextSet.
|
||||
*
|
||||
* @return a new ContextSet
|
||||
*/
|
||||
@@ -129,10 +158,10 @@ public final class ImmutableContextSet implements ContextSet {
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
private final Multimap<String, String> map;
|
||||
private final SetMultimap<String, String> map;
|
||||
|
||||
ImmutableContextSet(Multimap<String, String> contexts) {
|
||||
this.map = ImmutableMultimap.copyOf(contexts);
|
||||
this.map = ImmutableSetMultimap.copyOf(contexts);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -25,8 +25,10 @@ package me.lucko.luckperms.api.context;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
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.Multimaps;
|
||||
import com.google.common.collect.SetMultimap;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
@@ -60,6 +62,36 @@ public final class MutableContextSet implements ContextSet {
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a MutableContextSet from two context pairs
|
||||
*
|
||||
* @param key1 the first key
|
||||
* @param value1 the first value
|
||||
* @param key2 the second key
|
||||
* @param value2 the second value
|
||||
* @return a new MutableContextSet containing the two pairs
|
||||
* @throws NullPointerException if any of the keys or values are null
|
||||
* @since 3.1
|
||||
*/
|
||||
public static MutableContextSet of(String key1, String value1, String key2, String value2) {
|
||||
if (key1 == null) {
|
||||
throw new NullPointerException("key1");
|
||||
}
|
||||
if (value1 == null) {
|
||||
throw new NullPointerException("value1");
|
||||
}
|
||||
if (key2 == null) {
|
||||
throw new NullPointerException("key2");
|
||||
}
|
||||
if (value2 == null) {
|
||||
throw new NullPointerException("value2");
|
||||
}
|
||||
|
||||
MutableContextSet ret = singleton(key1, value1);
|
||||
ret.add(key2, value2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a MutableContextSet from an existing map
|
||||
*
|
||||
@@ -136,14 +168,14 @@ public final class MutableContextSet implements ContextSet {
|
||||
return new MutableContextSet();
|
||||
}
|
||||
|
||||
private final Multimap<String, String> map;
|
||||
private final SetMultimap<String, String> map;
|
||||
|
||||
public MutableContextSet() {
|
||||
this.map = Multimaps.synchronizedMultimap(HashMultimap.create());
|
||||
this.map = Multimaps.synchronizedSetMultimap(HashMultimap.create());
|
||||
}
|
||||
|
||||
private MutableContextSet(Multimap<String, String> contexts) {
|
||||
this.map = Multimaps.synchronizedMultimap(HashMultimap.create(contexts));
|
||||
this.map = Multimaps.synchronizedSetMultimap(HashMultimap.create(contexts));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -178,7 +210,7 @@ public final class MutableContextSet implements ContextSet {
|
||||
|
||||
@Override
|
||||
public Multimap<String, String> toMultimap() {
|
||||
return map;
|
||||
return ImmutableSetMultimap.copyOf(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -284,7 +316,7 @@ public final class MutableContextSet implements ContextSet {
|
||||
*/
|
||||
public void addAll(Iterable<? extends Map.Entry<String, String>> iterable) {
|
||||
if (iterable == null) {
|
||||
throw new NullPointerException("contexts");
|
||||
throw new NullPointerException("iterable");
|
||||
}
|
||||
|
||||
for (Map.Entry<String, String> e : iterable) {
|
||||
@@ -300,7 +332,7 @@ public final class MutableContextSet implements ContextSet {
|
||||
*/
|
||||
public void addAll(Map<String, String> map) {
|
||||
if (map == null) {
|
||||
throw new NullPointerException("contexts");
|
||||
throw new NullPointerException("map");
|
||||
}
|
||||
addAll(map.entrySet());
|
||||
}
|
||||
@@ -334,7 +366,7 @@ public final class MutableContextSet implements ContextSet {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
|
||||
map.entries().removeIf(entry -> entry.getKey().equalsIgnoreCase(key) && entry.getValue().equals(value));
|
||||
map.entries().removeIf(entry -> entry.getKey().equals(key) && entry.getValue().equals(value));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -40,6 +40,6 @@ public enum CreationCause {
|
||||
/**
|
||||
* The creation was caused by a LuckPerms internal
|
||||
*/
|
||||
INTERNAL;
|
||||
INTERNAL
|
||||
|
||||
}
|
||||
@@ -40,6 +40,6 @@ public enum DeletionCause {
|
||||
/**
|
||||
* The deletion was caused by a LuckPerms internal
|
||||
*/
|
||||
INTERNAL;
|
||||
INTERNAL
|
||||
|
||||
}
|
||||
@@ -35,6 +35,6 @@ public enum TrackAction {
|
||||
/**
|
||||
* The user was demoted down a track
|
||||
*/
|
||||
DEMOTION;
|
||||
DEMOTION
|
||||
|
||||
}
|
||||
+13
-7
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>luckperms</artifactId>
|
||||
<groupId>me.lucko.luckperms</groupId>
|
||||
<version>3.0-SNAPSHOT</version>
|
||||
<version>3.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -14,10 +14,6 @@
|
||||
<defaultGoal>clean package</defaultGoal>
|
||||
<finalName>LuckPerms-Bukkit-Legacy-${release.version}.${patch.version}</finalName>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>../</directory>
|
||||
<filtering>false</filtering>
|
||||
@@ -30,7 +26,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<version>${compiler.version}</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
@@ -39,7 +35,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>2.4.3</version>
|
||||
<version>${shade.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
@@ -77,6 +73,16 @@
|
||||
<artifactId>luckperms-bukkit</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>me.lucko.luckperms</groupId>
|
||||
<artifactId>luckperms-common</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>me.lucko.luckperms</groupId>
|
||||
<artifactId>luckperms-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- Shade gson and guava, as they are not included in earlier Bukkit releases -->
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>luckperms</artifactId>
|
||||
<groupId>me.lucko.luckperms</groupId>
|
||||
<version>3.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>luckperms-bukkit-placeholders</artifactId>
|
||||
<build>
|
||||
<finalName>LuckPermsPlaceholderExpansion</finalName>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>../</directory>
|
||||
<filtering>false</filtering>
|
||||
<includes>
|
||||
<include>LICENSE.txt</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<!-- LuckPerms API -->
|
||||
<dependency>
|
||||
<groupId>me.lucko.luckperms</groupId>
|
||||
<artifactId>luckperms-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- BukkitAPI -->
|
||||
<dependency>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>bukkit</artifactId>
|
||||
<version>1.8.8-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- PlaceholderAPI -->
|
||||
<dependency>
|
||||
<groupId>me.clip</groupId>
|
||||
<artifactId>placeholderapi</artifactId>
|
||||
<version>2.2.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
-220
@@ -1,220 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* 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.placeholders;
|
||||
|
||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||
import me.clip.placeholderapi.util.TimeUtil;
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.LuckPermsApi;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.api.Track;
|
||||
import me.lucko.luckperms.api.User;
|
||||
import me.lucko.luckperms.api.caching.UserData;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/*
|
||||
* PlaceholderAPI Expansion for LuckPerms, implemented using the LuckPerms API.
|
||||
*
|
||||
* Placeholders:
|
||||
* - group_name
|
||||
* - groups
|
||||
* - has_permission_<node>
|
||||
* - inherits_permission_<node>
|
||||
* - in_group_<name>
|
||||
* - inherits_group_<name>
|
||||
* - on_track_<track>
|
||||
* - expiry_time_<node>
|
||||
* - group_expiry_time_<group>
|
||||
* - prefix
|
||||
* - suffix
|
||||
* - meta_<node>
|
||||
*/
|
||||
public class LuckPermsPlaceholderExpansion extends PlaceholderExpansion {
|
||||
private static final String IDENTIFIER = "luckperms";
|
||||
private static final String PLUGIN_NAME = "LuckPerms";
|
||||
private static final String AUTHOR = "Luck";
|
||||
|
||||
private static String formatBoolean(boolean b) {
|
||||
return b ? PlaceholderAPIPlugin.booleanTrue() : PlaceholderAPIPlugin.booleanFalse();
|
||||
}
|
||||
|
||||
private LuckPermsApi api = null;
|
||||
|
||||
@Override
|
||||
public boolean canRegister() {
|
||||
return Bukkit.getServicesManager().isProvidedFor(LuckPermsApi.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean register() {
|
||||
if (!canRegister()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
api = Bukkit.getServicesManager().getRegistration(LuckPermsApi.class).getProvider();
|
||||
return super.register();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return "2.13";
|
||||
}
|
||||
|
||||
private Contexts makeContexts(Player player) {
|
||||
MutableContextSet contextSet = new MutableContextSet();
|
||||
contextSet.add("server", api.getConfiguration().getVaultServer());
|
||||
contextSet.add("world", player.getWorld().getName());// ignore world?
|
||||
return Contexts.of(contextSet.makeImmutable(), api.getConfiguration().getVaultIncludeGlobal(), true, true, true, true, player.isOp());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String onPlaceholderRequest(Player player, String identifier) {
|
||||
if (player == null || api == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
Optional<User> u = api.getUserSafe(api.getUuidCache().getUUID(player.getUniqueId()));
|
||||
if (!u.isPresent()) {
|
||||
return "";
|
||||
}
|
||||
final User user = u.get();
|
||||
|
||||
Optional<UserData> d = user.getUserDataCache();
|
||||
if (!d.isPresent()) {
|
||||
return "";
|
||||
}
|
||||
final UserData data = d.get();
|
||||
|
||||
identifier = identifier.toLowerCase();
|
||||
|
||||
if (identifier.equalsIgnoreCase("group_name")) {
|
||||
return user.getPrimaryGroup();
|
||||
}
|
||||
|
||||
if (identifier.equalsIgnoreCase("groups")) {
|
||||
return user.getGroupNames().stream().collect(Collectors.joining(", "));
|
||||
}
|
||||
|
||||
if (identifier.startsWith("has_permission_") && identifier.length() > "has_permission_".length()) {
|
||||
String node = identifier.substring("has_permission_".length());
|
||||
return formatBoolean(user.hasPermission(node, true));
|
||||
}
|
||||
|
||||
if (identifier.startsWith("inherits_permission_") && identifier.length() > "inherits_permission_".length()) {
|
||||
String node = identifier.substring("inherits_permission_".length());
|
||||
return formatBoolean(data.getPermissionData(makeContexts(player)).getPermissionValue(node).asBoolean());
|
||||
}
|
||||
|
||||
if (identifier.startsWith("in_group_") && identifier.length() > "in_group_".length()) {
|
||||
String groupName = identifier.substring("in_group_".length());
|
||||
return formatBoolean(user.getGroupNames().contains(groupName));
|
||||
}
|
||||
|
||||
if (identifier.startsWith("inherits_group_") && identifier.length() > "inherits_group_".length()) {
|
||||
String groupName = identifier.substring("inherits_group_".length());
|
||||
return formatBoolean(data.getPermissionData(makeContexts(player)).getPermissionValue("group." + groupName).asBoolean());
|
||||
}
|
||||
|
||||
if (identifier.startsWith("on_track_") && identifier.length() > "on_track_".length()) {
|
||||
String trackName = identifier.substring("on_track_".length());
|
||||
|
||||
Optional<Track> track = api.getTrackSafe(trackName);
|
||||
if (!track.isPresent()) return "";
|
||||
|
||||
return formatBoolean(track.get().containsGroup(user.getPrimaryGroup()));
|
||||
}
|
||||
|
||||
if (identifier.startsWith("expiry_time_") && identifier.length() > "expiry_time_".length()) {
|
||||
String node = identifier.substring("expiry_time_".length());
|
||||
long currentTime = System.currentTimeMillis() / 1000L;
|
||||
for (Node n : user.getTemporaryPermissionNodes()) {
|
||||
if (n.toSerializedNode().equalsIgnoreCase(node)) {
|
||||
return TimeUtil.getTime((int) (n.getExpiryUnixTime() - currentTime));
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
if (identifier.startsWith("group_expiry_time_") && identifier.length() > "group_expiry_time_".length()) {
|
||||
String node = "group." + identifier.substring("group_expiry_time_".length());
|
||||
long currentTime = System.currentTimeMillis() / 1000L;
|
||||
for (Node n : user.getTemporaryPermissionNodes()) {
|
||||
if (n.getPermission().equalsIgnoreCase(node)) {
|
||||
return TimeUtil.getTime((int) (n.getExpiryUnixTime() - currentTime));
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
if (identifier.equalsIgnoreCase("prefix")) {
|
||||
String prefix = data.calculateMeta(makeContexts(player)).getPrefix();
|
||||
if (prefix == null) {
|
||||
prefix = "";
|
||||
}
|
||||
return prefix;
|
||||
}
|
||||
|
||||
if (identifier.equalsIgnoreCase("suffix")) {
|
||||
String suffix = data.calculateMeta(makeContexts(player)).getSuffix();
|
||||
if (suffix == null) {
|
||||
suffix = "";
|
||||
}
|
||||
return suffix;
|
||||
}
|
||||
|
||||
if (identifier.startsWith("meta_") && identifier.length() > "meta_".length()) {
|
||||
String node = identifier.substring("meta_".length());
|
||||
String meta = data.getMetaData(makeContexts(player)).getMeta().get(node);
|
||||
if (meta == null) {
|
||||
meta = "";
|
||||
}
|
||||
return meta;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdentifier() {
|
||||
return IDENTIFIER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlugin() {
|
||||
return PLUGIN_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthor() {
|
||||
return AUTHOR;
|
||||
}
|
||||
}
|
||||
+13
-20
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>luckperms</artifactId>
|
||||
<groupId>me.lucko.luckperms</groupId>
|
||||
<version>3.0-SNAPSHOT</version>
|
||||
<version>3.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<version>${compiler.version}</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
@@ -42,7 +42,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>2.4.3</version>
|
||||
<version>${shade.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
@@ -66,11 +66,11 @@
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<!-- BukkitAPI -->
|
||||
<!-- Spigot API -->
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.8.8-R0.1-SNAPSHOT</version>
|
||||
<version>1.11.2-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Vault -->
|
||||
@@ -94,6 +94,13 @@
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- Lombok -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- LilyPad - used as a messaging service -->
|
||||
<dependency>
|
||||
<groupId>lilypad.client.connect</groupId>
|
||||
@@ -101,20 +108,6 @@
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- HikariCP - needed as source -->
|
||||
<dependency>
|
||||
<groupId>com.zaxxer</groupId>
|
||||
<artifactId>HikariCP</artifactId>
|
||||
<version>2.5.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Lombok -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.16.10</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- **************Migration Plugins************** -->
|
||||
<dependency>
|
||||
<groupId>org.tyrannyofheaven.bukkit</groupId>
|
||||
@@ -141,7 +134,7 @@
|
||||
<dependency>
|
||||
<groupId>com.github.cheesesoftware</groupId>
|
||||
<artifactId>PowerfulPermsAPI</artifactId>
|
||||
<version>1.0.1</version>
|
||||
<version>1.4.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
@@ -57,6 +57,11 @@ public class BukkitConfig extends AbstractConfiguration {
|
||||
configuration = YamlConfiguration.loadConfiguration(configFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(String path) {
|
||||
return configuration.contains(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString(String path, String def) {
|
||||
return configuration.getString(path, def);
|
||||
|
||||
@@ -22,12 +22,15 @@
|
||||
|
||||
package me.lucko.luckperms.bukkit;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import me.lucko.luckperms.bukkit.model.Injector;
|
||||
import me.lucko.luckperms.bukkit.model.LPPermissible;
|
||||
import me.lucko.luckperms.common.caching.UserCache;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.constants.Message;
|
||||
import me.lucko.luckperms.common.core.model.User;
|
||||
import me.lucko.luckperms.common.utils.AbstractListener;
|
||||
import me.lucko.luckperms.common.utils.LoginHelper;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
@@ -45,52 +48,95 @@ import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
class BukkitListener extends AbstractListener implements Listener {
|
||||
@RequiredArgsConstructor
|
||||
public class BukkitListener implements Listener {
|
||||
private final LPBukkitPlugin plugin;
|
||||
private final Set<UUID> deniedAsyncLogin = Collections.synchronizedSet(new HashSet<>());
|
||||
private final Set<UUID> deniedLogin = new HashSet<>();
|
||||
|
||||
BukkitListener(LPBukkitPlugin plugin) {
|
||||
super(plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
private final Set<UUID> deniedAsyncLogin = Collections.synchronizedSet(new HashSet<>());
|
||||
private final Set<UUID> deniedLogin = Collections.synchronizedSet(new HashSet<>());
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW)
|
||||
public void onPlayerPreLogin(AsyncPlayerPreLoginEvent e) {
|
||||
/* Called when the player first attempts a connection with the server.
|
||||
Listening on LOW priority to allow plugins to modify username / UUID data here. (auth plugins) */
|
||||
|
||||
/* the player was denied entry to the server before this priority.
|
||||
log this, so we can handle appropriately later. */
|
||||
if (e.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) {
|
||||
plugin.getLog().warn("Connection from " + e.getUniqueId() + " was already denied. No permissions data will be loaded.");
|
||||
deniedAsyncLogin.add(e.getUniqueId());
|
||||
return;
|
||||
}
|
||||
|
||||
/* either the plugin hasn't finished starting yet, or 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
|
||||
this data is loaded. */
|
||||
if (!plugin.isStarted() || !plugin.getStorage().isAcceptingLogins()) {
|
||||
|
||||
// log that the user tried to login, but was denied at this stage.
|
||||
deniedAsyncLogin.add(e.getUniqueId());
|
||||
|
||||
// The datastore is disabled, prevent players from joining the server
|
||||
e.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER, Message.LOADING_ERROR.toString());
|
||||
// actually deny the connection.
|
||||
plugin.getLog().warn("Permissions storage is not loaded yet. Denying connection from: " + e.getUniqueId() + " - " + e.getName());
|
||||
e.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER, Message.LOADING_ERROR.asString(plugin.getLocaleManager()));
|
||||
return;
|
||||
}
|
||||
|
||||
// Process login
|
||||
onAsyncLogin(e.getUniqueId(), e.getName());
|
||||
/* Actually process the login for the connection.
|
||||
We do this here to delay the login until the data is ready.
|
||||
If the login gets cancelled later on, then this will be cleaned up.
|
||||
|
||||
This includes:
|
||||
- loading uuid data
|
||||
- loading permissions
|
||||
- creating a user instance in the UserManager for this connection.
|
||||
- setting up cached data. */
|
||||
try {
|
||||
LoginHelper.loadUser(plugin, e.getUniqueId(), e.getName());
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
|
||||
// there was some error loading data. deny the connection
|
||||
deniedAsyncLogin.add(e.getUniqueId());
|
||||
e.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER, Message.LOADING_ERROR.asString(plugin.getLocaleManager()));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerPreLoginMonitor(AsyncPlayerPreLoginEvent e) {
|
||||
// If they were denied before/at LOW, then don't bother handling here.
|
||||
/* Listen to see if the event was cancelled after we initially handled the connection
|
||||
If the connection was cancelled here, we need to do something to clean up the data that was loaded. */
|
||||
|
||||
// Check to see if this connection was denied at LOW.
|
||||
if (deniedAsyncLogin.remove(e.getUniqueId())) {
|
||||
|
||||
// This is a problem, as they were denied at low priority, but are now being allowed.
|
||||
if (e.getLoginResult() == AsyncPlayerPreLoginEvent.Result.ALLOWED) {
|
||||
plugin.getLog().severe("Player connection was re-allowed for " + e.getUniqueId());
|
||||
e.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER, "");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (plugin.isStarted() && plugin.getStorage().isAcceptingLogins() && e.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) {
|
||||
|
||||
// Login event was cancelled by another plugin
|
||||
onLeave(e.getUniqueId());
|
||||
// Login event was cancelled by another plugin
|
||||
if (e.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) {
|
||||
// Schedule cleanup of this user.
|
||||
plugin.getUserManager().scheduleUnload(e.getUniqueId());
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW)
|
||||
public void onPlayerLogin(PlayerLoginEvent e) {
|
||||
/* Called when the player starts logging into the server.
|
||||
At this point, the users data should be present and loaded.
|
||||
Listening on LOW priority to allow plugins to further modify data here. (auth plugins, etc.) */
|
||||
|
||||
/* the player was denied entry to the server before this priority.
|
||||
log this, so we can handle appropriately later. */
|
||||
if (e.getResult() != PlayerLoginEvent.Result.ALLOWED) {
|
||||
plugin.getLog().warn("Login from " + e.getPlayer().getUniqueId() + " was denied before an attachment could be injected.");
|
||||
deniedLogin.add(e.getPlayer().getUniqueId());
|
||||
return;
|
||||
}
|
||||
@@ -98,14 +144,17 @@ class BukkitListener extends AbstractListener implements Listener {
|
||||
final Player player = e.getPlayer();
|
||||
final User user = plugin.getUserManager().get(plugin.getUuidCache().getUUID(player.getUniqueId()));
|
||||
|
||||
/* User instance is null for whatever reason. Could be that it was unloaded between asyncpre and now. */
|
||||
if (user == null) {
|
||||
deniedLogin.add(e.getPlayer().getUniqueId());
|
||||
|
||||
// User wasn't loaded for whatever reason.
|
||||
e.disallow(PlayerLoginEvent.Result.KICK_OTHER, Message.LOADING_ERROR.toString());
|
||||
plugin.getLog().warn("User " + player.getUniqueId() + " - " + player.getName() + " doesn't have data pre-loaded. - denying login.");
|
||||
e.disallow(PlayerLoginEvent.Result.KICK_OTHER, Message.LOADING_ERROR.asString(plugin.getLocaleManager()));
|
||||
return;
|
||||
}
|
||||
|
||||
// User instance is there, now we can inject our custom Permissible into the player.
|
||||
// Care should be taken at this stage to ensure that async tasks which manipulate bukkit data check that the player is still online.
|
||||
try {
|
||||
// Make a new permissible for the user
|
||||
LPPermissible lpPermissible = new LPPermissible(player, user, plugin);
|
||||
@@ -119,30 +168,49 @@ class BukkitListener extends AbstractListener implements Listener {
|
||||
|
||||
plugin.refreshAutoOp(player);
|
||||
|
||||
// We assume all users are not op, but those who are need extra calculation.
|
||||
if (player.isOp()) {
|
||||
plugin.doAsync(() -> {
|
||||
UserCache userData = user.getUserData();
|
||||
if (userData == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We assume all users are not op, but those who are need extra calculation.
|
||||
plugin.doAsync(() -> user.getUserData().preCalculate(plugin.getPreProcessContexts(true)));
|
||||
userData.preCalculate(plugin.getPreProcessContexts(true));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerLoginMonitor(PlayerLoginEvent e) {
|
||||
if (e.getResult() != PlayerLoginEvent.Result.ALLOWED) {
|
||||
/* Listen to see if the event was cancelled after we initially handled the login
|
||||
If the connection was cancelled here, we need to do something to clean up the data that was loaded. */
|
||||
|
||||
// If they were denied before/at LOW, then don't bother handling here.
|
||||
if (deniedLogin.remove(e.getPlayer().getUniqueId())) {
|
||||
return;
|
||||
// Check to see if this connection was denied at LOW.
|
||||
if (deniedLogin.remove(e.getPlayer().getUniqueId())) {
|
||||
|
||||
// This is a problem, as they were denied at low priority, but are now being allowed.
|
||||
if (e.getResult() == PlayerLoginEvent.Result.ALLOWED) {
|
||||
plugin.getLog().severe("Player connection was re-allowed for " + e.getPlayer().getUniqueId());
|
||||
e.disallow(PlayerLoginEvent.Result.KICK_OTHER, "");
|
||||
}
|
||||
|
||||
// The player got denied on sync login.
|
||||
plugin.getServer().getScheduler().runTaskLater(plugin, () -> onLeave(e.getPlayer().getUniqueId()), 20L);
|
||||
} else {
|
||||
plugin.refreshAutoOp(e.getPlayer());
|
||||
return;
|
||||
}
|
||||
|
||||
// Login event was cancelled by another plugin
|
||||
if (e.getResult() != PlayerLoginEvent.Result.ALLOWED) {
|
||||
// Schedule cleanup of this user.
|
||||
plugin.getUserManager().scheduleUnload(e.getPlayer().getUniqueId());
|
||||
return;
|
||||
}
|
||||
|
||||
// everything is going well. login was processed ok, this is just to refresh auto-op status.
|
||||
plugin.refreshAutoOp(e.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR) // Allow other plugins to see data when this event gets called.
|
||||
// Wait until the last priority to unload, so plugins can still perform permission checks on this event
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerQuit(PlayerQuitEvent e) {
|
||||
final Player player = e.getPlayer();
|
||||
|
||||
@@ -154,8 +222,8 @@ class BukkitListener extends AbstractListener implements Listener {
|
||||
player.setOp(false);
|
||||
}
|
||||
|
||||
// Call internal leave handling
|
||||
onLeave(player.getUniqueId());
|
||||
// Request that the users data is unloaded.
|
||||
plugin.getUserManager().scheduleUnload(player.getUniqueId());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@@ -164,7 +232,7 @@ class BukkitListener extends AbstractListener implements Listener {
|
||||
return;
|
||||
}
|
||||
|
||||
String s = e.getMessage()
|
||||
String s = e.getMessage().toLowerCase()
|
||||
.replace("/", "")
|
||||
.replace("bukkit:", "")
|
||||
.replace("spigot:", "")
|
||||
@@ -172,7 +240,7 @@ class BukkitListener extends AbstractListener implements Listener {
|
||||
|
||||
if (s.equals("op") || s.startsWith("op ") || s.equals("deop") || s.startsWith("deop ")) {
|
||||
e.setCancelled(true);
|
||||
e.getPlayer().sendMessage(Message.OP_DISABLED.toString());
|
||||
e.getPlayer().sendMessage(Message.OP_DISABLED.asString(plugin.getLocaleManager()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ import me.lucko.luckperms.bukkit.model.LPPermissible;
|
||||
import me.lucko.luckperms.bukkit.vault.VaultHook;
|
||||
import me.lucko.luckperms.common.api.ApiHandler;
|
||||
import me.lucko.luckperms.common.api.ApiProvider;
|
||||
import me.lucko.luckperms.common.caching.UserCache;
|
||||
import me.lucko.luckperms.common.caching.handlers.CachedStateManager;
|
||||
import me.lucko.luckperms.common.calculators.CalculatorFactory;
|
||||
import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
@@ -46,11 +47,10 @@ import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.config.LuckPermsConfiguration;
|
||||
import me.lucko.luckperms.common.constants.Permission;
|
||||
import me.lucko.luckperms.common.contexts.ContextManager;
|
||||
import me.lucko.luckperms.common.contexts.ServerCalculator;
|
||||
import me.lucko.luckperms.common.contexts.StaticCalculator;
|
||||
import me.lucko.luckperms.common.core.UuidCache;
|
||||
import me.lucko.luckperms.common.core.model.User;
|
||||
import me.lucko.luckperms.common.data.Importer;
|
||||
import me.lucko.luckperms.common.debug.DebugHandler;
|
||||
import me.lucko.luckperms.common.dependencies.Dependency;
|
||||
import me.lucko.luckperms.common.dependencies.DependencyManager;
|
||||
import me.lucko.luckperms.common.locale.LocaleManager;
|
||||
import me.lucko.luckperms.common.locale.NoopLocaleManager;
|
||||
@@ -62,6 +62,7 @@ import me.lucko.luckperms.common.managers.impl.GenericGroupManager;
|
||||
import me.lucko.luckperms.common.managers.impl.GenericTrackManager;
|
||||
import me.lucko.luckperms.common.managers.impl.GenericUserManager;
|
||||
import me.lucko.luckperms.common.messaging.InternalMessagingService;
|
||||
import me.lucko.luckperms.common.messaging.NoopMessagingService;
|
||||
import me.lucko.luckperms.common.messaging.RedisMessaging;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.storage.Storage;
|
||||
@@ -72,7 +73,10 @@ 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.BufferedRequest;
|
||||
import me.lucko.luckperms.common.utils.FileWatcher;
|
||||
import me.lucko.luckperms.common.utils.LoggerImpl;
|
||||
import me.lucko.luckperms.common.utils.LoginHelper;
|
||||
import me.lucko.luckperms.common.verbose.VerboseHandler;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
@@ -86,6 +90,7 @@ import org.bukkit.plugin.java.JavaPlugin;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
@@ -107,12 +112,12 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
private GroupManager groupManager;
|
||||
private TrackManager trackManager;
|
||||
private Storage storage;
|
||||
private FileWatcher fileWatcher = null;
|
||||
private InternalMessagingService messagingService = null;
|
||||
private UuidCache uuidCache;
|
||||
private BukkitListener listener;
|
||||
private ApiProvider apiProvider;
|
||||
private Logger log;
|
||||
private Importer importer;
|
||||
private DefaultsProvider defaultsProvider;
|
||||
private ChildPermissionProvider childPermissionProvider;
|
||||
private LocaleManager localeManager;
|
||||
@@ -122,21 +127,27 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
private CalculatorFactory calculatorFactory;
|
||||
private BufferedRequest<Void> updateTaskBuffer;
|
||||
private boolean started = false;
|
||||
private DebugHandler debugHandler;
|
||||
private VerboseHandler verboseHandler;
|
||||
private BukkitSenderFactory senderFactory;
|
||||
private PermissionVault permissionVault;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
public void onLoad() {
|
||||
// setup minimal functionality in order to load initial dependencies
|
||||
scheduler = new LPBukkitScheduler(this);
|
||||
|
||||
localeManager = new NoopLocaleManager();
|
||||
senderFactory = new BukkitSenderFactory(this);
|
||||
log = new LoggerImpl(getConsoleSender());
|
||||
|
||||
DependencyManager.loadDependencies(this, Collections.singletonList(Dependency.CAFFEINE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
LuckPermsPlugin.sendStartupBanner(getConsoleSender(), this);
|
||||
|
||||
ignoringLogs = ConcurrentHashMap.newKeySet();
|
||||
debugHandler = new DebugHandler(scheduler.getAsyncBukkitExecutor(), getVersion());
|
||||
verboseHandler = new VerboseHandler(scheduler.getAsyncBukkitExecutor(), getVersion());
|
||||
permissionVault = new PermissionVault(scheduler.getAsyncBukkitExecutor());
|
||||
|
||||
getLog().info("Loading configuration...");
|
||||
@@ -170,6 +181,11 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
listener = new BukkitListener(this);
|
||||
pm.registerEvents(listener, this);
|
||||
|
||||
if (getConfiguration().get(ConfigKeys.WATCH_FILES)) {
|
||||
fileWatcher = new FileWatcher(this);
|
||||
getScheduler().doAsyncRepeating(fileWatcher, 30L);
|
||||
}
|
||||
|
||||
// initialise datastore
|
||||
storage = StorageFactory.getInstance(this, StorageType.H2);
|
||||
|
||||
@@ -212,6 +228,10 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
getLog().warn("Messaging service '" + messagingType + "' not recognised.");
|
||||
}
|
||||
|
||||
if (messagingService == null) {
|
||||
messagingService = new NoopMessagingService();
|
||||
}
|
||||
|
||||
// setup the update task buffer
|
||||
updateTaskBuffer = new BufferedRequest<Void>(1000L, this::doAsync) {
|
||||
@Override
|
||||
@@ -247,14 +267,13 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
userManager = new GenericUserManager(this);
|
||||
groupManager = new GenericGroupManager(this);
|
||||
trackManager = new GenericTrackManager(this);
|
||||
importer = new Importer(commandManager);
|
||||
calculatorFactory = new BukkitCalculatorFactory(this);
|
||||
cachedStateManager = new CachedStateManager(this);
|
||||
|
||||
contextManager = new ContextManager<>();
|
||||
worldCalculator = new WorldCalculator(this);
|
||||
contextManager.registerCalculator(worldCalculator);
|
||||
contextManager.registerCalculator(new ServerCalculator<>(getConfiguration()));
|
||||
contextManager.registerCalculator(new StaticCalculator<>(getConfiguration()));
|
||||
|
||||
// Provide vault support
|
||||
tryVaultHook(false);
|
||||
@@ -282,20 +301,23 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
scheduler.doAsyncRepeating(new CacheHousekeepingTask(this), 2400L);
|
||||
|
||||
// register permissions
|
||||
registerPermissions(getConfiguration().get(ConfigKeys.COMMANDS_ALLOW_OP) ? PermissionDefault.OP : PermissionDefault.FALSE);
|
||||
try {
|
||||
registerPermissions(getConfiguration().get(ConfigKeys.COMMANDS_ALLOW_OP) ? PermissionDefault.OP : PermissionDefault.FALSE);
|
||||
} catch (Exception e) {
|
||||
// this throws an exception if the plugin is /reloaded, grr
|
||||
}
|
||||
|
||||
if (!getConfiguration().get(ConfigKeys.OPS_ENABLED)) {
|
||||
scheduler.doSync(() -> getServer().getOperators().forEach(o -> o.setOp(false)));
|
||||
}
|
||||
|
||||
// replace the temporary executor when the Bukkit one starts
|
||||
getServer().getScheduler().runTaskAsynchronously(this, () -> {
|
||||
scheduler.setUseBukkitAsync(true);
|
||||
});
|
||||
getServer().getScheduler().runTaskAsynchronously(this, () -> scheduler.setUseBukkitAsync(true));
|
||||
|
||||
// Load any online users (in the case of a reload)
|
||||
for (Player player : getServer().getOnlinePlayers()) {
|
||||
scheduler.doAsync(() -> {
|
||||
listener.onAsyncLogin(player.getUniqueId(), player.getName());
|
||||
LoginHelper.loadUser(this, player.getUniqueId(), player.getName());
|
||||
User user = getUserManager().get(getUuidCache().getUUID(player.getUniqueId()));
|
||||
if (user != null) {
|
||||
scheduler.doSync(() -> {
|
||||
@@ -323,7 +345,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
|
||||
defaultsProvider.close();
|
||||
permissionVault.setShutdown(true);
|
||||
debugHandler.setShutdown(true);
|
||||
verboseHandler.setShutdown(true);
|
||||
|
||||
for (Player player : getServer().getOnlinePlayers()) {
|
||||
Injector.unInject(player, false, false);
|
||||
@@ -341,6 +363,10 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
getLog().info("Closing datastore...");
|
||||
storage.shutdown();
|
||||
|
||||
if (fileWatcher != null) {
|
||||
fileWatcher.close();
|
||||
}
|
||||
|
||||
if (messagingService != null) {
|
||||
getLog().info("Closing messaging service...");
|
||||
messagingService.close();
|
||||
@@ -368,12 +394,12 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
groupManager = null;
|
||||
trackManager = null;
|
||||
storage = null;
|
||||
fileWatcher = null;
|
||||
messagingService = null;
|
||||
uuidCache = null;
|
||||
listener = null;
|
||||
apiProvider = null;
|
||||
log = null;
|
||||
importer = null;
|
||||
defaultsProvider = null;
|
||||
childPermissionProvider = null;
|
||||
localeManager = null;
|
||||
@@ -382,7 +408,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
worldCalculator = null;
|
||||
calculatorFactory = null;
|
||||
updateTaskBuffer = null;
|
||||
debugHandler = null;
|
||||
verboseHandler = null;
|
||||
senderFactory = null;
|
||||
permissionVault = null;
|
||||
}
|
||||
@@ -420,11 +446,21 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
if (getConfiguration().get(ConfigKeys.AUTO_OP)) {
|
||||
try {
|
||||
LPPermissible permissible = Injector.getPermissible(player.getUniqueId());
|
||||
if (permissible == null) {
|
||||
if (permissible == null || !permissible.getActive().get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Boolean> backing = permissible.getUser().getUserData().getPermissionData(permissible.calculateContexts()).getImmutableBacking();
|
||||
User user = permissible.getUser();
|
||||
if (user == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
UserCache userData = user.getUserData();
|
||||
if (userData == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Boolean> backing = userData.getPermissionData(permissible.calculateContexts()).getImmutableBacking();
|
||||
boolean op = Optional.ofNullable(backing.get("luckperms.autoop")).orElse(false);
|
||||
player.setOp(op);
|
||||
} catch (Exception ignored) {}
|
||||
@@ -448,7 +484,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
|
||||
@Override
|
||||
public String getServerVersion() {
|
||||
return getServer().getVersion();
|
||||
return getServer().getVersion() + " - " + getServer().getBukkitVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -500,7 +536,8 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
|
||||
@Override
|
||||
public boolean isPlayerOnline(UUID external) {
|
||||
return getServer().getPlayer(external) != null;
|
||||
Player player = getServer().getPlayer(external);
|
||||
return player != null && player.isOnline();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -528,6 +565,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
MutableContextSet set = MutableContextSet.create();
|
||||
set.add("server", getConfiguration().get(ConfigKeys.SERVER));
|
||||
set.add("world", s);
|
||||
set.addAll(configuration.getStaticContexts().getContextSet());
|
||||
return set.makeImmutable();
|
||||
})
|
||||
.collect(Collectors.toList())
|
||||
@@ -542,6 +580,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
MutableContextSet set = MutableContextSet.create();
|
||||
set.add("server", getConfiguration().get(ConfigKeys.VAULT_SERVER));
|
||||
set.add("world", s);
|
||||
set.addAll(configuration.getStaticContexts().getContextSet());
|
||||
return set.makeImmutable();
|
||||
})
|
||||
.collect(Collectors.toList())
|
||||
@@ -597,16 +636,6 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
return map;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public UUID getUuidFromUsername(String playerName) {
|
||||
try {
|
||||
return getServer().getOfflinePlayer(playerName).getUniqueId();
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void registerPermissions(PermissionDefault def) {
|
||||
PluginManager pm = getServer().getPluginManager();
|
||||
|
||||
|
||||
@@ -33,8 +33,6 @@ import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class WorldCalculator implements ContextCalculator<Player> {
|
||||
private static final String WORLD_KEY = "world";
|
||||
@@ -43,27 +41,13 @@ public class WorldCalculator implements ContextCalculator<Player> {
|
||||
|
||||
@Override
|
||||
public MutableContextSet giveApplicableContext(Player subject, MutableContextSet accumulator) {
|
||||
String world = getWorld(subject);
|
||||
String world = subject.getWorld().getName();
|
||||
world = plugin.getConfiguration().get(ConfigKeys.WORLD_REWRITES).getOrDefault(world, world);
|
||||
|
||||
if (world != null) {
|
||||
accumulator.add(Maps.immutableEntry(WORLD_KEY, world));
|
||||
accumulator.add(Maps.immutableEntry(WORLD_KEY, world.toLowerCase()));
|
||||
}
|
||||
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isContextApplicable(Player subject, Map.Entry<String, String> context) {
|
||||
if (!context.getKey().equals(WORLD_KEY)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String world = getWorld(subject);
|
||||
return world != null && world.equals(context.getValue());
|
||||
}
|
||||
|
||||
private String getWorld(Player player) {
|
||||
String world = player.getWorld().getName();
|
||||
return plugin.getConfiguration().get(ConfigKeys.WORLD_REWRITES).getOrDefault(world, world);
|
||||
}
|
||||
}
|
||||
+10
-22
@@ -22,7 +22,6 @@
|
||||
|
||||
package me.lucko.luckperms.bukkit.compat;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
@@ -58,7 +57,7 @@ public class BukkitJsonMessageHandler {
|
||||
}
|
||||
}
|
||||
|
||||
Class<?> packetChatClass = Class.forName(getVersionedClassName("PacketPlayOutChat"));
|
||||
Class<?> packetChatClass = ReflectionUtil.nmsClass("PacketPlayOutChat");
|
||||
Constructor[] packetConstructors = packetChatClass.getDeclaredConstructors();
|
||||
for (Constructor c : packetConstructors) {
|
||||
Class<?>[] parameters = c.getParameterTypes();
|
||||
@@ -68,30 +67,19 @@ public class BukkitJsonMessageHandler {
|
||||
}
|
||||
}
|
||||
|
||||
Class<?> baseComponentClass = Class.forName(getVersionedClassName("IChatBaseComponent"));
|
||||
Class<?> chatSerializerClass = baseComponentClass.getClasses()[0];
|
||||
Class<?> baseComponentClass = ReflectionUtil.nmsClass("IChatBaseComponent");
|
||||
Class<?> chatSerializerClass;
|
||||
|
||||
if (baseComponentClass.getClasses().length > 0) {
|
||||
chatSerializerClass = baseComponentClass.getClasses()[0];
|
||||
} else {
|
||||
// 1.7 class is here instead.
|
||||
chatSerializerClass = ReflectionUtil.nmsClass("ChatSerializer");
|
||||
}
|
||||
|
||||
SERIALIZE_METHOD = chatSerializerClass.getDeclaredMethod("a", String.class);
|
||||
}
|
||||
|
||||
private static String getVersionedClassName(String className) {
|
||||
Class server = Bukkit.getServer().getClass();
|
||||
if (!server.getSimpleName().equals("CraftServer")) {
|
||||
throw new RuntimeException("Couldn't reflect into server " + server);
|
||||
}
|
||||
|
||||
String version;
|
||||
if (server.getName().equals("org.bukkit.craftbukkit.CraftServer")) {
|
||||
// Non versioned class
|
||||
version = ".";
|
||||
} else {
|
||||
version = server.getName().substring("org.bukkit.craftbukkit".length());
|
||||
version = version.substring(0, version.length() - "CraftServer".length());
|
||||
}
|
||||
|
||||
return "net.minecraft.server" + version + className;
|
||||
}
|
||||
|
||||
private static synchronized boolean trySetup(Object player) {
|
||||
if (setup) return true;
|
||||
if (triedAndFailed) return false;
|
||||
|
||||
@@ -37,9 +37,9 @@ public class MessageHandler {
|
||||
}
|
||||
|
||||
public void sendJsonMessage(CommandSender sender, FancyMessage message) {
|
||||
if (sender instanceof Player) {
|
||||
if (ReflectionUtil.isChatCompatible() && sender instanceof Player) {
|
||||
Player player = (Player) sender;
|
||||
String json = message.toJSONString();
|
||||
String json = message.exportToJson();
|
||||
|
||||
// Try Bukkit.
|
||||
if (bukkitHandler.sendJsonMessage(player, json)) {
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* 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.compat;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
@UtilityClass
|
||||
public class ReflectionUtil {
|
||||
private static final String SERVER_VERSION = _getServerVersion();
|
||||
private static final boolean CHAT_COMPATIBLE = !SERVER_VERSION.startsWith(".v1_7_");
|
||||
|
||||
private static String _getServerVersion() {
|
||||
Class<?> server = Bukkit.getServer().getClass();
|
||||
if (!server.getSimpleName().equals("CraftServer")) {
|
||||
return ".";
|
||||
}
|
||||
if (server.getName().equals("org.bukkit.craftbukkit.CraftServer")) {
|
||||
// Non versioned class
|
||||
return ".";
|
||||
} else {
|
||||
String version = server.getName().substring("org.bukkit.craftbukkit".length());
|
||||
return version.substring(0, version.length() - "CraftServer".length());
|
||||
}
|
||||
}
|
||||
|
||||
public static String getServerVersion() {
|
||||
return SERVER_VERSION;
|
||||
}
|
||||
|
||||
public static boolean isChatCompatible() {
|
||||
return CHAT_COMPATIBLE;
|
||||
}
|
||||
|
||||
public static String nms(String className) {
|
||||
return "net.minecraft.server" + getServerVersion() + className;
|
||||
}
|
||||
|
||||
public static Class<?> nmsClass(String className) throws ClassNotFoundException {
|
||||
return Class.forName(nms(className));
|
||||
}
|
||||
|
||||
public static String obc(String className) {
|
||||
return "org.bukkit.craftbukkit" + getServerVersion() + className;
|
||||
}
|
||||
|
||||
public static Class<?> obcClass(String className) throws ClassNotFoundException {
|
||||
return Class.forName(obc(className));
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -64,12 +64,11 @@ public class BungeeMessagingService extends AbstractMessagingService implements
|
||||
@Override
|
||||
public void run() {
|
||||
Collection<? extends Player> players = plugin.getServer().getOnlinePlayers();
|
||||
if (players.isEmpty()) {
|
||||
Player p = Iterables.getFirst(players, null);
|
||||
if (p == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player p = Iterables.getFirst(players, null);
|
||||
|
||||
ByteArrayDataOutput out = ByteStreams.newDataOutput();
|
||||
out.writeUTF(message);
|
||||
|
||||
|
||||
+57
-64
@@ -29,21 +29,24 @@ import de.bananaco.bpermissions.api.Permission;
|
||||
import de.bananaco.bpermissions.api.World;
|
||||
import de.bananaco.bpermissions.api.WorldManager;
|
||||
|
||||
import me.lucko.luckperms.api.MetaUtils;
|
||||
import me.lucko.luckperms.api.event.cause.CreationCause;
|
||||
import me.lucko.luckperms.common.commands.CommandException;
|
||||
import me.lucko.luckperms.common.commands.CommandResult;
|
||||
import me.lucko.luckperms.common.commands.SubCommand;
|
||||
import me.lucko.luckperms.common.commands.abstraction.SubCommand;
|
||||
import me.lucko.luckperms.common.commands.impl.migration.MigrationUtils;
|
||||
import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.core.NodeFactory;
|
||||
import me.lucko.luckperms.common.core.model.PermissionHolder;
|
||||
import me.lucko.luckperms.common.core.model.User;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.utils.Predicates;
|
||||
import me.lucko.luckperms.common.utils.ProgressLogger;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -54,9 +57,6 @@ import static me.lucko.luckperms.common.constants.Permission.MIGRATION;
|
||||
|
||||
public class MigrationBPermissions extends SubCommand<Object> {
|
||||
private static Field uConfigField;
|
||||
private static Method getConfigurationSectionMethod = null;
|
||||
private static Method getKeysMethod = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
uConfigField = Class.forName("de.bananaco.bpermissions.imp.YamlWorld").getDeclaredField("uconfig");
|
||||
@@ -87,7 +87,24 @@ public class MigrationBPermissions extends SubCommand<Object> {
|
||||
log.log("Forcing the plugin to load all data. This could take a while.");
|
||||
for (World world : worldManager.getAllWorlds()) {
|
||||
log.log("Loading users in world " + world.getName());
|
||||
Set<String> users = getUsers(world);
|
||||
|
||||
YamlConfiguration yamlWorldUsers = null;
|
||||
try {
|
||||
yamlWorldUsers = (YamlConfiguration) uConfigField.get(world);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
|
||||
if (yamlWorldUsers == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ConfigurationSection configSection = yamlWorldUsers.getConfigurationSection("users");
|
||||
if (configSection == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Set<String> users = configSection.getKeys(false);
|
||||
if (users == null) {
|
||||
log.logErr("Couldn't get a list of users.");
|
||||
return CommandResult.FAILURE;
|
||||
@@ -109,7 +126,7 @@ public class MigrationBPermissions extends SubCommand<Object> {
|
||||
log.log("Starting group migration in world " + world.getName() + ".");
|
||||
AtomicInteger groupCount = new AtomicInteger(0);
|
||||
for (Calculable group : world.getAll(CalculableType.GROUP)) {
|
||||
String groupName = group.getName().toLowerCase();
|
||||
String groupName = MigrationUtils.standardizeName(group.getName());
|
||||
if (group.getName().equalsIgnoreCase(world.getDefaultGroup())) {
|
||||
groupName = "default";
|
||||
}
|
||||
@@ -118,23 +135,31 @@ public class MigrationBPermissions extends SubCommand<Object> {
|
||||
plugin.getStorage().createAndLoadGroup(groupName, CreationCause.INTERNAL).join();
|
||||
me.lucko.luckperms.common.core.model.Group lpGroup = plugin.getGroupManager().getIfLoaded(groupName);
|
||||
|
||||
migrateHolder(log, world, group, lpGroup);
|
||||
MigrationUtils.setGroupWeight(lpGroup, group.getPriority());
|
||||
migrateHolder(world, group, lpGroup);
|
||||
|
||||
plugin.getStorage().saveGroup(lpGroup);
|
||||
|
||||
log.logAllProgress("Migrated {} groups so far.", groupCount.incrementAndGet());
|
||||
}
|
||||
log.log("Migrated " + groupCount.get() + " groups in world " + world.getName() + ".");
|
||||
|
||||
|
||||
// Migrate all users
|
||||
log.log("Starting user migration in world " + world.getName() + ".");
|
||||
AtomicInteger userCount = new AtomicInteger(0);
|
||||
for (Calculable user : world.getAll(CalculableType.USER)) {
|
||||
// There is no mention of UUIDs in the API. I assume that name = uuid. idk?
|
||||
UUID uuid;
|
||||
UUID uuid = null;
|
||||
try {
|
||||
uuid = UUID.fromString(user.getName());
|
||||
} catch (IllegalArgumentException e) {
|
||||
uuid = plugin.getUuidFromUsername(user.getName());
|
||||
try {
|
||||
//noinspection deprecation
|
||||
uuid = Bukkit.getOfflinePlayer(user.getName()).getUniqueId();
|
||||
} catch (Exception ex) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (uuid == null) {
|
||||
@@ -146,7 +171,7 @@ public class MigrationBPermissions extends SubCommand<Object> {
|
||||
plugin.getStorage().loadUser(uuid, "null").join();
|
||||
User lpUser = plugin.getUserManager().get(uuid);
|
||||
|
||||
migrateHolder(log, world, user, lpUser);
|
||||
migrateHolder(world, user, lpUser);
|
||||
|
||||
plugin.getStorage().saveUser(lpUser);
|
||||
plugin.getUserManager().cleanup(lpUser);
|
||||
@@ -161,78 +186,46 @@ public class MigrationBPermissions extends SubCommand<Object> {
|
||||
return CommandResult.SUCCESS;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Set<String> getUsers(World world) {
|
||||
try {
|
||||
Object yamlWorldUsers = uConfigField.get(world);
|
||||
if (getConfigurationSectionMethod == null) {
|
||||
getConfigurationSectionMethod = yamlWorldUsers.getClass().getMethod("getConfigurationSection", String.class);
|
||||
getConfigurationSectionMethod.setAccessible(true);
|
||||
}
|
||||
|
||||
Object configSection = getConfigurationSectionMethod.invoke(yamlWorldUsers, "users");
|
||||
if (configSection == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
if (getKeysMethod == null) {
|
||||
getKeysMethod = configSection.getClass().getMethod("getKeys", boolean.class);
|
||||
getKeysMethod.setAccessible(true);
|
||||
}
|
||||
|
||||
return (Set<String>) getKeysMethod.invoke(configSection, false);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void migrateHolder(ProgressLogger log, World world, Calculable c, PermissionHolder holder) {
|
||||
private static void migrateHolder(World world, Calculable c, PermissionHolder holder) {
|
||||
// Migrate the groups permissions in this world
|
||||
for (Permission p : c.getPermissions()) {
|
||||
try {
|
||||
holder.setPermission(p.name(), p.isTrue(), "global", world.getName());
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
if (p.name().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
holder.setPermission(NodeFactory.make(p.name(), p.isTrue(), "global", world.getName()));
|
||||
|
||||
// Include any child permissions
|
||||
for (Map.Entry<String, Boolean> child : p.getChildren().entrySet()) {
|
||||
try {
|
||||
holder.setPermission(child.getKey(), child.getValue(), "global", world.getName());
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
if (child.getKey().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
holder.setPermission(NodeFactory.make(child.getKey(), child.getValue(), "global", world.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
// Migrate any inherited groups
|
||||
for (Group parent : c.getGroups()) {
|
||||
try {
|
||||
holder.setPermission("group." + parent.getName(), true, "global", world.getName());
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
String parentName = MigrationUtils.standardizeName(parent.getName());
|
||||
if (parent.getName().equalsIgnoreCase(world.getDefaultGroup())) {
|
||||
parentName = "default";
|
||||
}
|
||||
|
||||
holder.setPermission(NodeFactory.make("group." + parentName, true, "global", world.getName()));
|
||||
}
|
||||
|
||||
// Migrate existing meta
|
||||
for (Map.Entry<String, String> meta : c.getMeta().entrySet()) {
|
||||
if (meta.getKey().equalsIgnoreCase("prefix") || meta.getKey().equalsIgnoreCase("suffix")) {
|
||||
String chatMeta = MetaUtils.escapeCharacters(meta.getValue());
|
||||
try {
|
||||
holder.setPermission(meta.getKey().toLowerCase() + "." + c.getPriority() + "." + chatMeta, true);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
if (meta.getKey().isEmpty() || meta.getValue().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
holder.setPermission("meta." + meta.getKey() + "." + meta.getValue(), true, "global", world.getName());
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
if (meta.getKey().equalsIgnoreCase("prefix") || meta.getKey().equalsIgnoreCase("suffix")) {
|
||||
holder.setPermission(NodeFactory.makeChatMetaNode(meta.getKey().equalsIgnoreCase("prefix"), c.getPriority(), meta.getValue()).setWorld(world.getName()).build());
|
||||
continue;
|
||||
}
|
||||
|
||||
holder.setPermission(NodeFactory.makeMetaNode(meta.getKey(), meta.getValue()).setWorld(world.getName()).build());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+99
-98
@@ -22,20 +22,19 @@
|
||||
|
||||
package me.lucko.luckperms.bukkit.migration;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.api.event.cause.CreationCause;
|
||||
import me.lucko.luckperms.common.commands.Arg;
|
||||
import me.lucko.luckperms.common.commands.CommandException;
|
||||
import me.lucko.luckperms.common.commands.CommandResult;
|
||||
import me.lucko.luckperms.common.commands.SubCommand;
|
||||
import me.lucko.luckperms.common.commands.abstraction.SubCommand;
|
||||
import me.lucko.luckperms.common.commands.impl.migration.MigrationUtils;
|
||||
import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.constants.Permission;
|
||||
import me.lucko.luckperms.common.core.NodeFactory;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.utils.Predicates;
|
||||
import me.lucko.luckperms.common.utils.ProgressLogger;
|
||||
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
|
||||
import me.lucko.luckperms.exceptions.ObjectLacksException;
|
||||
|
||||
import org.anjocaido.groupmanager.GlobalGroups;
|
||||
import org.anjocaido.groupmanager.GroupManager;
|
||||
@@ -47,8 +46,10 @@ import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Function;
|
||||
@@ -73,8 +74,8 @@ public class MigrationGroupManager extends SubCommand<Object> {
|
||||
log.logErr("Was expecting true/false, but got " + args.get(0) + " instead.");
|
||||
return CommandResult.STATE_ERROR;
|
||||
}
|
||||
boolean migrateAsGlobal = Boolean.parseBoolean(args.get(0));
|
||||
final Function<String, String> worldMappingFunc = s -> migrateAsGlobal ? "" : s;
|
||||
final boolean migrateAsGlobal = Boolean.parseBoolean(args.get(0));
|
||||
final Function<String, String> worldMappingFunc = s -> migrateAsGlobal ? null : s;
|
||||
|
||||
if (!Bukkit.getPluginManager().isPluginEnabled("GroupManager")) {
|
||||
log.logErr("Plugin not loaded.");
|
||||
@@ -82,7 +83,6 @@ public class MigrationGroupManager extends SubCommand<Object> {
|
||||
}
|
||||
|
||||
List<String> worlds = Bukkit.getWorlds().stream().map(World::getName).map(String::toLowerCase).collect(Collectors.toList());
|
||||
|
||||
GroupManager gm = (GroupManager) Bukkit.getPluginManager().getPlugin("GroupManager");
|
||||
|
||||
// Migrate Global Groups
|
||||
@@ -91,32 +91,25 @@ public class MigrationGroupManager extends SubCommand<Object> {
|
||||
|
||||
AtomicInteger globalGroupCount = new AtomicInteger(0);
|
||||
for (Group g : gg.getGroupList()) {
|
||||
plugin.getStorage().createAndLoadGroup(g.getName().toLowerCase(), CreationCause.INTERNAL).join();
|
||||
me.lucko.luckperms.common.core.model.Group group = plugin.getGroupManager().getIfLoaded(g.getName().toLowerCase());
|
||||
String groupName = MigrationUtils.standardizeName(g.getName());
|
||||
|
||||
plugin.getStorage().createAndLoadGroup(groupName, CreationCause.INTERNAL).join();
|
||||
me.lucko.luckperms.common.core.model.Group group = plugin.getGroupManager().getIfLoaded(groupName);
|
||||
|
||||
for (String node : g.getPermissionList()) {
|
||||
boolean value = true;
|
||||
if (node.startsWith("!") || node.startsWith("-")) {
|
||||
node = node.substring(1);
|
||||
value = false;
|
||||
} else if (node.startsWith("+")) {
|
||||
node = node.substring(1);
|
||||
value = true;
|
||||
if (node.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
group.setPermission(node, value);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
group.setPermission(MigrationUtils.parseNode(node, true).build());
|
||||
}
|
||||
|
||||
for (String s : g.getInherits()) {
|
||||
try {
|
||||
group.setPermission("group." + s.toLowerCase(), true);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
if (s.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
group.setPermission(NodeFactory.make("group." + MigrationUtils.standardizeName(s)));
|
||||
}
|
||||
|
||||
plugin.getStorage().saveGroup(group);
|
||||
@@ -125,14 +118,9 @@ public class MigrationGroupManager extends SubCommand<Object> {
|
||||
log.log("Migrated " + globalGroupCount.get() + " global groups");
|
||||
|
||||
// Collect data
|
||||
|
||||
// UUID --> Map<Entry<String, String>, Boolean> where k=world, v = node
|
||||
Map<UUID, Map<Map.Entry<String, String>, Boolean>> users = new HashMap<>();
|
||||
// UUID --> primary group name
|
||||
Map<UUID, Set<Node>> users = new HashMap<>();
|
||||
Map<UUID, String> primaryGroups = new HashMap<>();
|
||||
|
||||
// String --> Map<Entry<String, String>, Boolean> where k=world, v = node
|
||||
Map<String, Map<Map.Entry<String, String>, Boolean>> groups = new HashMap<>();
|
||||
Map<String, Set<Node>> groups = new HashMap<>();
|
||||
|
||||
WorldsHolder wh = gm.getWorldsHolder();
|
||||
|
||||
@@ -145,25 +133,48 @@ public class MigrationGroupManager extends SubCommand<Object> {
|
||||
WorldDataHolder wdh = wh.getWorldData(world);
|
||||
|
||||
AtomicInteger groupWorldCount = new AtomicInteger(0);
|
||||
for (Group g : wdh.getGroupList()) {
|
||||
groups.putIfAbsent(g.getName().toLowerCase(), new HashMap<>());
|
||||
for (Group group : wdh.getGroupList()) {
|
||||
String groupName = MigrationUtils.standardizeName(group.getName());
|
||||
|
||||
for (String node : g.getPermissionList()) {
|
||||
boolean value = true;
|
||||
if (node.startsWith("!") || node.startsWith("-")) {
|
||||
node = node.substring(1);
|
||||
value = false;
|
||||
} else if (node.startsWith("+")) {
|
||||
node = node.substring(1);
|
||||
value = true;
|
||||
groups.putIfAbsent(groupName, new HashSet<>());
|
||||
|
||||
for (String node : group.getPermissionList()) {
|
||||
if (node.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
groups.get(g.getName().toLowerCase()).put(Maps.immutableEntry(worldMappingFunc.apply(world), node), value);
|
||||
groups.get(groupName).add(MigrationUtils.parseNode(node, true).setWorld(worldMappingFunc.apply(world)).build());
|
||||
}
|
||||
|
||||
for (String s : g.getInherits()) {
|
||||
groups.get(g.getName().toLowerCase()).put(Maps.immutableEntry(worldMappingFunc.apply(world), "group." + s.toLowerCase()), true);
|
||||
for (String s : group.getInherits()) {
|
||||
if (s.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
groups.get(groupName).add(NodeFactory.make("group." + MigrationUtils.standardizeName(s), true, null, worldMappingFunc.apply(world)));
|
||||
}
|
||||
|
||||
|
||||
String[] metaKeys = group.getVariables().getVarKeyList();
|
||||
for (String key : metaKeys) {
|
||||
String value = group.getVariables().getVarString(key);
|
||||
key = key.toLowerCase();
|
||||
|
||||
if (key.isEmpty() || value.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key.equals("build")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key.equals("prefix") || key.equals("suffix")) {
|
||||
groups.get(groupName).add(NodeFactory.makeChatMetaNode(key.equals("prefix"), 50, value).setWorld(worldMappingFunc.apply(world)).build());
|
||||
} else {
|
||||
groups.get(groupName).add(NodeFactory.makeMetaNode(key, value).setWorld(worldMappingFunc.apply(world)).build());
|
||||
}
|
||||
}
|
||||
|
||||
log.logAllProgress("Migrated {} groups so far in world " + world, groupWorldCount.incrementAndGet());
|
||||
}
|
||||
log.log("Migrated " + groupWorldCount.get() + " groups in world " + world);
|
||||
@@ -178,35 +189,51 @@ public class MigrationGroupManager extends SubCommand<Object> {
|
||||
continue;
|
||||
}
|
||||
|
||||
users.putIfAbsent(uuid, new HashMap<>());
|
||||
users.putIfAbsent(uuid, new HashSet<>());
|
||||
|
||||
for (String node : user.getPermissionList()) {
|
||||
boolean value = true;
|
||||
if (node.startsWith("!") || node.startsWith("-")) {
|
||||
node = node.substring(1);
|
||||
value = false;
|
||||
} else if (node.startsWith("+")) {
|
||||
node = node.substring(1);
|
||||
value = true;
|
||||
if (node.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
users.get(uuid).put(Maps.immutableEntry(worldMappingFunc.apply(world), node), value);
|
||||
users.get(uuid).add(MigrationUtils.parseNode(node, true).setWorld(worldMappingFunc.apply(world)).build());
|
||||
}
|
||||
|
||||
String finalWorld = worldMappingFunc.apply(world);
|
||||
|
||||
// Collect sub groups
|
||||
users.get(uuid).putAll(user.subGroupListStringCopy().stream()
|
||||
.map(n -> "group." + n)
|
||||
.map(n -> Maps.immutableEntry(finalWorld, n))
|
||||
.collect(Collectors.toMap(n -> n, n -> true))
|
||||
String finalWorld = worldMappingFunc.apply(world);
|
||||
users.get(uuid).addAll(user.subGroupListStringCopy().stream()
|
||||
.filter(n -> !n.isEmpty())
|
||||
.map(n -> "group." + MigrationUtils.standardizeName(n))
|
||||
.map(n -> NodeFactory.make(n, true, null, finalWorld))
|
||||
.collect(Collectors.toSet())
|
||||
);
|
||||
primaryGroups.put(uuid, user.getGroupName());
|
||||
|
||||
// Get primary group
|
||||
primaryGroups.put(uuid, MigrationUtils.standardizeName(user.getGroupName()));
|
||||
|
||||
String[] metaKeys = user.getVariables().getVarKeyList();
|
||||
for (String key : metaKeys) {
|
||||
String value = user.getVariables().getVarString(key);
|
||||
key = key.toLowerCase();
|
||||
|
||||
if (key.isEmpty() || value.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key.equals("build")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key.equals("prefix") || key.equals("suffix")) {
|
||||
users.get(uuid).add(NodeFactory.makeChatMetaNode(key.equals("prefix"), 100, value).setWorld(worldMappingFunc.apply(world)).build());
|
||||
} else {
|
||||
users.get(uuid).add(NodeFactory.makeMetaNode(key, value).setWorld(worldMappingFunc.apply(world)).build());
|
||||
}
|
||||
}
|
||||
|
||||
log.logProgress("Migrated {} users so far in world " + world, userWorldCount.incrementAndGet());
|
||||
}
|
||||
log.log("Migrated " + userWorldCount.get() + " users in world " + world);
|
||||
|
||||
}
|
||||
|
||||
log.log("All data has now been processed, now starting the import process.");
|
||||
@@ -214,23 +241,12 @@ public class MigrationGroupManager extends SubCommand<Object> {
|
||||
|
||||
log.log("Starting group migration.");
|
||||
AtomicInteger groupCount = new AtomicInteger(0);
|
||||
for (Map.Entry<String, Map<Map.Entry<String, String>, Boolean>> e : groups.entrySet()) {
|
||||
for (Map.Entry<String, Set<Node>> e : groups.entrySet()) {
|
||||
plugin.getStorage().createAndLoadGroup(e.getKey(), CreationCause.INTERNAL).join();
|
||||
me.lucko.luckperms.common.core.model.Group group = plugin.getGroupManager().getIfLoaded(e.getKey());
|
||||
|
||||
for (Map.Entry<Map.Entry<String, String>, Boolean> n : e.getValue().entrySet()) {
|
||||
// n.key.key = world
|
||||
// n.key.value = node
|
||||
// n.value = true/false
|
||||
try {
|
||||
if (n.getKey().getKey().equals("")) {
|
||||
group.setPermission(n.getKey().getValue(), n.getValue());
|
||||
} else {
|
||||
group.setPermission(n.getKey().getValue(), n.getValue(), "global", n.getKey().getKey());
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
for (Node node : e.getValue()) {
|
||||
group.setPermission(node);
|
||||
}
|
||||
|
||||
plugin.getStorage().saveGroup(group);
|
||||
@@ -240,34 +256,19 @@ public class MigrationGroupManager extends SubCommand<Object> {
|
||||
|
||||
log.log("Starting user migration.");
|
||||
AtomicInteger userCount = new AtomicInteger(0);
|
||||
for (Map.Entry<UUID, Map<Map.Entry<String, String>, Boolean>> e : users.entrySet()) {
|
||||
for (Map.Entry<UUID, Set<Node>> e : users.entrySet()) {
|
||||
plugin.getStorage().loadUser(e.getKey(), "null").join();
|
||||
me.lucko.luckperms.common.core.model.User user = plugin.getUserManager().get(e.getKey());
|
||||
|
||||
for (Map.Entry<Map.Entry<String, String>, Boolean> n : e.getValue().entrySet()) {
|
||||
// n.key.key = world
|
||||
// n.key.value = node
|
||||
// n.value = true/false
|
||||
try {
|
||||
if (n.getKey().getKey().equals("")) {
|
||||
user.setPermission(n.getKey().getValue(), n.getValue());
|
||||
} else {
|
||||
user.setPermission(n.getKey().getValue(), n.getValue(), "global", n.getKey().getKey());
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
for (Node node : e.getValue()) {
|
||||
user.setPermission(node);
|
||||
}
|
||||
|
||||
String primaryGroup = primaryGroups.get(e.getKey());
|
||||
if (primaryGroup != null) {
|
||||
try {
|
||||
user.setPermission("group." + primaryGroup, true);
|
||||
} catch (ObjectAlreadyHasException ignored) {}
|
||||
user.setPrimaryGroup(primaryGroup);
|
||||
try {
|
||||
user.unsetPermission("group.default");
|
||||
} catch (ObjectLacksException ignored) {}
|
||||
user.setPermission(NodeFactory.make("group." + primaryGroup));
|
||||
user.getPrimaryGroup().setStoredValue(primaryGroup);
|
||||
user.unsetPermission(NodeFactory.make("group.default"));
|
||||
}
|
||||
|
||||
plugin.getStorage().saveUser(user);
|
||||
|
||||
+60
-95
@@ -22,20 +22,19 @@
|
||||
|
||||
package me.lucko.luckperms.bukkit.migration;
|
||||
|
||||
import me.lucko.luckperms.api.MetaUtils;
|
||||
import me.lucko.luckperms.api.event.cause.CreationCause;
|
||||
import me.lucko.luckperms.common.commands.CommandException;
|
||||
import me.lucko.luckperms.common.commands.CommandResult;
|
||||
import me.lucko.luckperms.common.commands.SubCommand;
|
||||
import me.lucko.luckperms.common.commands.abstraction.SubCommand;
|
||||
import me.lucko.luckperms.common.commands.impl.migration.MigrationUtils;
|
||||
import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.constants.Permission;
|
||||
import me.lucko.luckperms.common.core.NodeFactory;
|
||||
import me.lucko.luckperms.common.core.model.Group;
|
||||
import me.lucko.luckperms.common.core.model.User;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.utils.Predicates;
|
||||
import me.lucko.luckperms.common.utils.ProgressLogger;
|
||||
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
|
||||
import me.lucko.luckperms.exceptions.ObjectLacksException;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
@@ -99,59 +98,49 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
|
||||
for (PermissionGroup group : manager.getGroupList()) {
|
||||
int groupWeight = maxWeight - group.getRank();
|
||||
|
||||
final String name = group.getName().toLowerCase();
|
||||
plugin.getStorage().createAndLoadGroup(name, CreationCause.INTERNAL).join();
|
||||
Group lpGroup = plugin.getGroupManager().getIfLoaded(name);
|
||||
final String groupName = MigrationUtils.standardizeName(group.getName());
|
||||
plugin.getStorage().createAndLoadGroup(groupName, CreationCause.INTERNAL).join();
|
||||
Group lpGroup = plugin.getGroupManager().getIfLoaded(groupName);
|
||||
|
||||
MigrationUtils.setGroupWeight(lpGroup, groupWeight);
|
||||
|
||||
try {
|
||||
for (String node : group.getOwnPermissions(null)) {
|
||||
boolean value = true;
|
||||
if (node.startsWith("-")) {
|
||||
node = node.substring(1);
|
||||
value = false;
|
||||
if (node.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
lpGroup.setPermission(node, value);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
lpGroup.setPermission(MigrationUtils.parseNode(node, true).build());
|
||||
}
|
||||
} catch (NullPointerException ignored) {
|
||||
// No docs on if #getOwnPermissions(null) is ok. Should be fine though.
|
||||
}
|
||||
|
||||
for (String world : worlds) {
|
||||
if (world.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (String node : group.getOwnPermissions(world)) {
|
||||
boolean value = true;
|
||||
if (node.startsWith("-")) {
|
||||
node = node.substring(1);
|
||||
value = false;
|
||||
if (node.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
lpGroup.setPermission(node, value, "global", world.toLowerCase());
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
lpGroup.setPermission(MigrationUtils.parseNode(node, true).setWorld(world.toLowerCase()).build());
|
||||
}
|
||||
}
|
||||
|
||||
for (PermissionGroup g : group.getParents()) {
|
||||
try {
|
||||
lpGroup.setPermission("group." + g.getName().toLowerCase(), true);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
lpGroup.setPermission(NodeFactory.make("group." + MigrationUtils.standardizeName(g.getName())));
|
||||
}
|
||||
|
||||
for (String world : worlds) {
|
||||
if (world.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (PermissionGroup g : group.getParents(world)) {
|
||||
try {
|
||||
lpGroup.setPermission("group." + g.getName().toLowerCase(), true, "global", world.toLowerCase());
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
lpGroup.setPermission(NodeFactory.make("group." + MigrationUtils.standardizeName(g.getName()), true, "global", world.toLowerCase()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,21 +148,11 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
|
||||
String suffix = group.getOwnSuffix();
|
||||
|
||||
if (prefix != null && !prefix.equals("")) {
|
||||
prefix = MetaUtils.escapeCharacters(prefix);
|
||||
try {
|
||||
lpGroup.setPermission("prefix." + groupWeight + "." + prefix, true);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
lpGroup.setPermission(NodeFactory.makePrefixNode(groupWeight, prefix).build());
|
||||
}
|
||||
|
||||
if (suffix != null && !suffix.equals("")) {
|
||||
suffix = MetaUtils.escapeCharacters(suffix);
|
||||
try {
|
||||
lpGroup.setPermission("suffix." + groupWeight + "." + suffix, true);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
lpGroup.setPermission(NodeFactory.makeSuffixNode(groupWeight, suffix).build());
|
||||
}
|
||||
|
||||
plugin.getStorage().saveGroup(lpGroup);
|
||||
@@ -195,7 +174,11 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
|
||||
} catch (IllegalArgumentException e) {
|
||||
u = ni.nameToUUID(user.getIdentifier());
|
||||
if (u == null) {
|
||||
u = plugin.getUuidFromUsername(user.getIdentifier());
|
||||
try {
|
||||
u = Bukkit.getOfflinePlayer(user.getIdentifier()).getUniqueId();
|
||||
} catch (Exception ex) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,53 +192,49 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
|
||||
|
||||
try {
|
||||
for (String node : user.getOwnPermissions(null)) {
|
||||
boolean value = true;
|
||||
if (node.startsWith("-")) {
|
||||
node = node.substring(1);
|
||||
value = false;
|
||||
if (node.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
lpUser.setPermission(node, value);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
lpUser.setPermission(MigrationUtils.parseNode(node, true).build());
|
||||
}
|
||||
} catch (NullPointerException ignored) {
|
||||
// No docs on if #getOwnPermissions(null) is ok. Should be fine though.
|
||||
}
|
||||
|
||||
for (String world : worlds) {
|
||||
if (world.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (String node : user.getOwnPermissions(world)) {
|
||||
boolean value = true;
|
||||
if (node.startsWith("-")) {
|
||||
node = node.substring(1);
|
||||
value = false;
|
||||
if (node.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
lpUser.setPermission(node, value, "global", world.toLowerCase());
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
lpUser.setPermission(MigrationUtils.parseNode(node, true).setWorld(world.toLowerCase()).build());
|
||||
}
|
||||
}
|
||||
|
||||
for (String s : user.getGroupNames()) {
|
||||
try {
|
||||
lpUser.setPermission("group." + s.toLowerCase(), true);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
for (String g : user.getGroupNames()) {
|
||||
if (g.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
lpUser.setPermission(NodeFactory.make("group." + MigrationUtils.standardizeName(g)));
|
||||
}
|
||||
|
||||
for (String world : worlds) {
|
||||
for (String s : user.getGroupNames(world)) {
|
||||
try {
|
||||
lpUser.setPermission("group." + s.toLowerCase(), true, "global", world.toLowerCase());
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
if (world.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (String g : user.getGroupNames(world)) {
|
||||
if (g.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
lpUser.setPermission(NodeFactory.make("group." + MigrationUtils.standardizeName(g), true, "global", world.toLowerCase()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,21 +242,11 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
|
||||
String suffix = user.getOwnSuffix();
|
||||
|
||||
if (prefix != null && !prefix.equals("")) {
|
||||
prefix = MetaUtils.escapeCharacters(prefix);
|
||||
try {
|
||||
lpUser.setPermission("prefix." + maxWeight + "." + prefix, true);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
lpUser.setPermission(NodeFactory.makePrefixNode(maxWeight, prefix).build());
|
||||
}
|
||||
|
||||
if (suffix != null && !suffix.equals("")) {
|
||||
suffix = MetaUtils.escapeCharacters(suffix);
|
||||
try {
|
||||
lpUser.setPermission("suffix." + maxWeight + "." + suffix, true);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
lpUser.setPermission(NodeFactory.makeSuffixNode(maxWeight, suffix).build());
|
||||
}
|
||||
|
||||
// Lowest rank is the highest group #logic
|
||||
@@ -291,13 +260,9 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
|
||||
}
|
||||
|
||||
if (primary != null && !primary.equalsIgnoreCase("default")) {
|
||||
try {
|
||||
lpUser.setPermission("group." + primary.toLowerCase(), true);
|
||||
} catch (ObjectAlreadyHasException ignored) {}
|
||||
lpUser.setPrimaryGroup(primary);
|
||||
try {
|
||||
lpUser.unsetPermission("group.default");
|
||||
} catch (ObjectLacksException ignored) {}
|
||||
lpUser.setPermission(NodeFactory.make("group." + primary.toLowerCase()));
|
||||
lpUser.getPrimaryGroup().setStoredValue(primary);
|
||||
lpUser.unsetPermission(NodeFactory.make("group.default"));
|
||||
}
|
||||
|
||||
plugin.getUserManager().cleanup(lpUser);
|
||||
|
||||
+154
-341
@@ -22,106 +22,52 @@
|
||||
|
||||
package me.lucko.luckperms.bukkit.migration;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import com.github.cheesesoftware.PowerfulPermsAPI.CachedGroup;
|
||||
import com.github.cheesesoftware.PowerfulPermsAPI.Group;
|
||||
import com.github.cheesesoftware.PowerfulPermsAPI.Permission;
|
||||
import com.github.cheesesoftware.PowerfulPermsAPI.PermissionManager;
|
||||
import com.github.cheesesoftware.PowerfulPermsAPI.PowerfulPermsPlugin;
|
||||
import com.github.cheesesoftware.PowerfulPermsAPI.ResultRunnable;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.api.event.cause.CreationCause;
|
||||
import me.lucko.luckperms.bukkit.migration.utils.LPResultRunnable;
|
||||
import me.lucko.luckperms.common.commands.Arg;
|
||||
import me.lucko.luckperms.common.commands.CommandException;
|
||||
import me.lucko.luckperms.common.commands.CommandResult;
|
||||
import me.lucko.luckperms.common.commands.SubCommand;
|
||||
import me.lucko.luckperms.common.commands.abstraction.SubCommand;
|
||||
import me.lucko.luckperms.common.commands.impl.migration.MigrationUtils;
|
||||
import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.core.NodeFactory;
|
||||
import me.lucko.luckperms.common.core.model.PermissionHolder;
|
||||
import me.lucko.luckperms.common.core.model.User;
|
||||
import me.lucko.luckperms.common.dependencies.DependencyManager;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.storage.StorageType;
|
||||
import me.lucko.luckperms.common.utils.HikariSupplier;
|
||||
import me.lucko.luckperms.common.utils.Predicates;
|
||||
import me.lucko.luckperms.common.utils.ProgressLogger;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static me.lucko.luckperms.common.constants.Permission.MIGRATION;
|
||||
|
||||
|
||||
// Only supports the latest versions of the PP API. (it seems to change randomly almost every release)
|
||||
public class MigrationPowerfulPerms extends SubCommand<Object> {
|
||||
private static Method getPlayerPermissionsMethod = null;
|
||||
private static Method getPlayerGroupsMethod = null;
|
||||
private static Method getGroupMethod = null;
|
||||
|
||||
// lol, nice "api"
|
||||
private static boolean superLegacy = false;
|
||||
private static boolean legacy = false;
|
||||
|
||||
static {
|
||||
try {
|
||||
Class.forName("com.github.cheesesoftware.PowerfulPermsAPI.ResponseRunnable");
|
||||
legacy = true;
|
||||
} catch (ClassNotFoundException ignored) {}
|
||||
|
||||
if (legacy) {
|
||||
try {
|
||||
getPlayerPermissionsMethod = PermissionManager.class.getMethod("getPlayerOwnPermissions", UUID.class, ResultRunnable.class);
|
||||
getPlayerPermissionsMethod.setAccessible(true);
|
||||
} catch (NoSuchMethodException ignored) {}
|
||||
} else {
|
||||
try {
|
||||
getPlayerPermissionsMethod = PermissionManager.class.getMethod("getPlayerOwnPermissions", UUID.class);
|
||||
getPlayerPermissionsMethod.setAccessible(true);
|
||||
} catch (NoSuchMethodException ignored) {}
|
||||
}
|
||||
|
||||
try {
|
||||
getGroupMethod = CachedGroup.class.getMethod("getGroup");
|
||||
getGroupMethod.setAccessible(true);
|
||||
superLegacy = true;
|
||||
} catch (NoSuchMethodException ignored) {}
|
||||
|
||||
if (!legacy) {
|
||||
try {
|
||||
getPlayerGroupsMethod = PermissionManager.class.getMethod("getPlayerOwnGroups", UUID.class);
|
||||
getPlayerGroupsMethod.setAccessible(true);
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
getPlayerGroupsMethod = PermissionManager.class.getMethod("getPlayerOwnGroups", UUID.class, ResultRunnable.class);
|
||||
getPlayerGroupsMethod.setAccessible(true);
|
||||
} catch (NoSuchMethodException e) {
|
||||
try {
|
||||
getPlayerGroupsMethod = PermissionManager.class.getMethod("getPlayerGroups", UUID.class, ResultRunnable.class);
|
||||
getPlayerGroupsMethod.setAccessible(true);
|
||||
} catch (NoSuchMethodException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public MigrationPowerfulPerms() {
|
||||
super("powerfulperms", "Migration from PowerfulPerms", MIGRATION, Predicates.not(5),
|
||||
Arg.list(
|
||||
@@ -136,44 +82,37 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
|
||||
|
||||
@Override
|
||||
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object o, List<String> args, String label) throws CommandException {
|
||||
try {
|
||||
return run(plugin, sender, args);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
return CommandResult.FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
private CommandResult run(LuckPermsPlugin plugin, Sender sender, List<String> args) {
|
||||
ProgressLogger log = new ProgressLogger("PowerfulPerms");
|
||||
log.addListener(plugin.getConsoleSender());
|
||||
log.addListener(sender);
|
||||
|
||||
log.log("Starting.");
|
||||
|
||||
|
||||
if (!Bukkit.getPluginManager().isPluginEnabled("PowerfulPerms")) {
|
||||
log.logErr("PowerfulPerms is not loaded.");
|
||||
log.logErr("Plugin not loaded.");
|
||||
return CommandResult.STATE_ERROR;
|
||||
}
|
||||
|
||||
final String address = args.get(0);
|
||||
final String database = args.get(1);
|
||||
final String username = args.get(2);
|
||||
final String password = args.get(3);
|
||||
final String dbTable = args.get(4);
|
||||
String method = plugin.getConfiguration().get(ConfigKeys.STORAGE_METHOD);
|
||||
StorageType type = StorageType.parse(method);
|
||||
|
||||
if (type == null || type != StorageType.MYSQL) {
|
||||
// We need to load the Hikari/MySQL stuff.
|
||||
DependencyManager.loadDependencies(plugin, DependencyManager.STORAGE_DEPENDENCIES.get(StorageType.MYSQL));
|
||||
}
|
||||
|
||||
String address = args.get(0);
|
||||
String database = args.get(1);
|
||||
String username = args.get(2);
|
||||
String password = args.get(3);
|
||||
String dbTable = args.get(4);
|
||||
|
||||
// Find a list of UUIDs
|
||||
log.log("Getting a list of UUIDs to migrate.");
|
||||
Set<UUID> uuids = new HashSet<>();
|
||||
|
||||
try (HikariDataSource hikari = new HikariDataSource()) {
|
||||
hikari.setMaximumPoolSize(2);
|
||||
hikari.setDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlDataSource");
|
||||
hikari.addDataSourceProperty("serverName", address.split(":")[0]);
|
||||
hikari.addDataSourceProperty("port", address.split(":")[1]);
|
||||
hikari.addDataSourceProperty("databaseName", database);
|
||||
hikari.addDataSourceProperty("user", username);
|
||||
hikari.addDataSourceProperty("password", password);
|
||||
try (HikariSupplier hikari = new HikariSupplier(address, database, username, password)) {
|
||||
hikari.setup("powerfulperms-migrator-pool");
|
||||
|
||||
try (Connection c = hikari.getConnection()) {
|
||||
DatabaseMetaData meta = c.getMetaData();
|
||||
@@ -220,23 +159,54 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
|
||||
PowerfulPermsPlugin ppPlugin = (PowerfulPermsPlugin) Bukkit.getPluginManager().getPlugin("PowerfulPerms");
|
||||
PermissionManager pm = ppPlugin.getPermissionManager();
|
||||
|
||||
Collection<Group> groups = pm.getGroups().values();
|
||||
|
||||
int maxWeight = 0;
|
||||
|
||||
// Groups first.
|
||||
log.log("Starting group migration.");
|
||||
AtomicInteger groupCount = new AtomicInteger(0);
|
||||
Map<Integer, Group> groups = pm.getGroups(); // All versions
|
||||
for (Group g : groups.values()) {
|
||||
plugin.getStorage().createAndLoadGroup(g.getName().toLowerCase(), CreationCause.INTERNAL).join();
|
||||
final me.lucko.luckperms.common.core.model.Group group = plugin.getGroupManager().getIfLoaded(g.getName().toLowerCase());
|
||||
for (Group g : groups) {
|
||||
maxWeight = Math.max(maxWeight, g.getRank());
|
||||
|
||||
for (Permission p : g.getOwnPermissions()) { // All versions
|
||||
applyPerm(group, p, log);
|
||||
final String groupName = MigrationUtils.standardizeName(g.getName());
|
||||
plugin.getStorage().createAndLoadGroup(groupName, CreationCause.INTERNAL).join();
|
||||
final me.lucko.luckperms.common.core.model.Group group = plugin.getGroupManager().getIfLoaded(groupName);
|
||||
|
||||
MigrationUtils.setGroupWeight(group, g.getRank());
|
||||
|
||||
for (Permission p : g.getOwnPermissions()) {
|
||||
applyPerm(group, p);
|
||||
}
|
||||
|
||||
for (Group parent : g.getParents()) { // All versions
|
||||
try {
|
||||
group.setPermission("group." + parent.getName().toLowerCase(), true);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
for (Group parent : g.getParents()) {
|
||||
group.setPermission(NodeFactory.make("group." + parent.getName().toLowerCase(), true));
|
||||
}
|
||||
|
||||
// server --> prefix afaik
|
||||
for (Map.Entry<String, String> prefix : g.getPrefixes().entrySet()) {
|
||||
String server = prefix.getKey().toLowerCase();
|
||||
if (prefix.getKey().equals("*") || prefix.getKey().equals("all")) {
|
||||
server = null;
|
||||
}
|
||||
|
||||
if (server != null) {
|
||||
group.setPermission(NodeFactory.makePrefixNode(g.getRank(), prefix.getValue()).setServer(server).build());
|
||||
} else {
|
||||
group.setPermission(NodeFactory.makePrefixNode(g.getRank(), prefix.getValue()).build());
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<String, String> suffix : g.getSuffixes().entrySet()) {
|
||||
String server = suffix.getKey().toLowerCase();
|
||||
if (suffix.getKey().equals("*") || suffix.getKey().equals("all")) {
|
||||
server = null;
|
||||
}
|
||||
|
||||
if (server != null) {
|
||||
group.setPermission(NodeFactory.makeSuffixNode(g.getRank(), suffix.getValue()).setServer(server).build());
|
||||
} else {
|
||||
group.setPermission(NodeFactory.makeSuffixNode(g.getRank(), suffix.getValue()).build());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,291 +215,134 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
|
||||
}
|
||||
log.log("Migrated " + groupCount.get() + " groups");
|
||||
|
||||
// Now users.
|
||||
// Migrate all users
|
||||
log.log("Starting user migration.");
|
||||
final Map<UUID, CountDownLatch> progress = new HashMap<>();
|
||||
AtomicInteger userCount = new AtomicInteger(0);
|
||||
|
||||
// Increment the max weight from the group migrations. All user meta should override.
|
||||
maxWeight += 5;
|
||||
|
||||
// Migrate all users and their groups
|
||||
for (UUID uuid : uuids) {
|
||||
progress.put(uuid, new CountDownLatch(2));
|
||||
|
||||
// Create a LuckPerms user for the UUID
|
||||
plugin.getStorage().loadUser(uuid, "null").join();
|
||||
User user = plugin.getUserManager().get(uuid);
|
||||
|
||||
// Get a list of Permissions held by the user from the PP API.
|
||||
getPlayerPermissions(pm, uuid, perms -> { // Changes each version
|
||||
perms.forEach(p -> applyPerm(user, p, log));
|
||||
List<Permission> permissions = joinFuture(pm.getPlayerOwnPermissions(uuid));
|
||||
|
||||
// Update the progress so the user can be saved and unloaded.
|
||||
synchronized (progress) {
|
||||
progress.get(uuid).countDown();
|
||||
if (progress.get(uuid).getCount() == 0) {
|
||||
plugin.getStorage().saveUser(user);
|
||||
plugin.getUserManager().cleanup(user);
|
||||
}
|
||||
}
|
||||
});
|
||||
for (Permission p : permissions) {
|
||||
applyPerm(user, p);
|
||||
}
|
||||
|
||||
// Migrate the user's groups to LuckPerms from PP.
|
||||
Consumer<Map<String, List<CachedGroup>>> callback = groups1 -> {
|
||||
for (Map.Entry<String, List<CachedGroup>> e : groups1.entrySet()) {
|
||||
final String server;
|
||||
if (e.getKey() != null && (e.getKey().equals("") || e.getKey().equalsIgnoreCase("all"))) {
|
||||
server = null;
|
||||
} else {
|
||||
server = e.getKey();
|
||||
}
|
||||
|
||||
if (superLegacy) {
|
||||
e.getValue().stream()
|
||||
.filter(cg -> !cg.isNegated())
|
||||
.map(cg -> {
|
||||
try {
|
||||
return (Group) getGroupMethod.invoke(cg);
|
||||
} catch (IllegalAccessException | InvocationTargetException e1) {
|
||||
e1.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.forEach(g -> {
|
||||
if (g != null) {
|
||||
if (server == null) {
|
||||
try {
|
||||
user.setPermission("group." + g.getName().toLowerCase(), true);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
user.setPermission("group." + g.getName().toLowerCase(), true, server);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
e.getValue().stream()
|
||||
.filter(g -> !g.hasExpired() && !g.isNegated())
|
||||
.forEach(g -> {
|
||||
final Group group = pm.getGroup(g.getGroupId());
|
||||
if (g.willExpire()) {
|
||||
if (server == null) {
|
||||
try {
|
||||
user.setPermission("group." + group.getName().toLowerCase(), true, g.getExpirationDate().getTime() / 1000L);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
user.setPermission("group." + group.getName().toLowerCase(), true, server, g.getExpirationDate().getTime() / 1000L);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (server == null) {
|
||||
try {
|
||||
user.setPermission("group." + group.getName().toLowerCase(), true);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
user.setPermission("group." + group.getName().toLowerCase(), true, server);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// server --> list of groups
|
||||
Map<String, List<CachedGroup>> parents = joinFuture(pm.getPlayerOwnGroups(uuid));
|
||||
for (Map.Entry<String, List<CachedGroup>> parent : parents.entrySet()) {
|
||||
String server = parent.getKey().toLowerCase();
|
||||
if (parent.getKey().equals("*") || parent.getKey().equals("all")) {
|
||||
server = null;
|
||||
}
|
||||
|
||||
// Update the progress so the user can be saved and unloaded.
|
||||
synchronized (progress) {
|
||||
progress.get(uuid).countDown();
|
||||
if (progress.get(uuid).getCount() == 0) {
|
||||
plugin.getStorage().saveUser(user);
|
||||
plugin.getUserManager().cleanup(user);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (!legacy) {
|
||||
try {
|
||||
ListenableFuture<LinkedHashMap<String, List<CachedGroup>>> future = (ListenableFuture<LinkedHashMap<String, List<CachedGroup>>>) getPlayerGroupsMethod.invoke(pm, uuid);
|
||||
try {
|
||||
if (future.isDone()) {
|
||||
callback.accept(future.get());
|
||||
} else {
|
||||
future.addListener(() -> {
|
||||
try {
|
||||
callback.accept(future.get());
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}, Runnable::run);
|
||||
}
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
getPlayerGroupsMethod.invoke(pm, uuid, new LPResultRunnable<LinkedHashMap<String, List<CachedGroup>>>() {
|
||||
@Override
|
||||
public void run() {
|
||||
callback.accept(getResult());
|
||||
}
|
||||
});
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
for (CachedGroup group : parent.getValue()) {
|
||||
applyGroup(pm, user, group, server);
|
||||
}
|
||||
}
|
||||
|
||||
String prefix = joinFuture(pm.getPlayerOwnPrefix(uuid));
|
||||
String suffix = joinFuture(pm.getPlayerOwnSuffix(uuid));
|
||||
|
||||
if (prefix != null && !prefix.equals("")) {
|
||||
user.setPermission(NodeFactory.makePrefixNode(maxWeight, prefix).build());
|
||||
}
|
||||
|
||||
if (suffix != null && !suffix.equals("")) {
|
||||
user.setPermission(NodeFactory.makeSuffixNode(maxWeight, suffix).build());
|
||||
}
|
||||
|
||||
String primary = joinFuture(pm.getPlayerPrimaryGroup(uuid)).getName().toLowerCase();
|
||||
if (!primary.equals("default")) {
|
||||
user.setPermission(NodeFactory.make("group." + primary));
|
||||
user.getPrimaryGroup().setStoredValue(primary);
|
||||
}
|
||||
|
||||
plugin.getUserManager().cleanup(user);
|
||||
plugin.getStorage().saveUser(user);
|
||||
log.logProgress("Migrated {} users so far.", userCount.incrementAndGet());
|
||||
}
|
||||
|
||||
// All groups are migrated, but there may still be some users being migrated.
|
||||
// This block will wait for all users to be completed.
|
||||
log.log("Waiting for user migration to complete. This may take some time");
|
||||
boolean sleep = true;
|
||||
while (sleep) {
|
||||
sleep = false;
|
||||
|
||||
for (Map.Entry<UUID, CountDownLatch> e : progress.entrySet()) {
|
||||
if (e.getValue().getCount() != 0) {
|
||||
sleep = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sleep) {
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// We done.
|
||||
log.log("Migrated " + userCount.get() + " users.");
|
||||
log.log("Success! Migration complete.");
|
||||
return CommandResult.SUCCESS;
|
||||
}
|
||||
|
||||
private void applyPerm(PermissionHolder holder, Permission p, ProgressLogger log) {
|
||||
private void applyPerm(PermissionHolder holder, Permission p) {
|
||||
String node = p.getPermissionString();
|
||||
boolean value = true;
|
||||
if (node.startsWith("!")) {
|
||||
if (node.startsWith("!") || node.startsWith("-")) {
|
||||
node = node.substring(1);
|
||||
value = false;
|
||||
}
|
||||
|
||||
String server = p.getServer();
|
||||
if (server != null && server.equalsIgnoreCase("all")) {
|
||||
if (server != null && (server.equalsIgnoreCase("all") || server.equalsIgnoreCase("*"))) {
|
||||
server = null;
|
||||
}
|
||||
|
||||
String world = p.getWorld();
|
||||
if (world != null && world.equalsIgnoreCase("all")) {
|
||||
if (world != null && (world.equalsIgnoreCase("all") || world.equalsIgnoreCase("*"))) {
|
||||
world = null;
|
||||
}
|
||||
|
||||
long expireAt = 0L;
|
||||
if (!superLegacy) {
|
||||
if (p.willExpire()) {
|
||||
expireAt = p.getExpirationDate().getTime() / 1000L;
|
||||
}
|
||||
if (p.willExpire()) {
|
||||
expireAt = p.getExpirationDate().getTime() / 1000L;
|
||||
}
|
||||
|
||||
if (world != null && server == null) {
|
||||
server = "global";
|
||||
}
|
||||
|
||||
if (world != null) {
|
||||
if (expireAt == 0L) {
|
||||
try {
|
||||
holder.setPermission(node, value, server, world);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
holder.setPermission(node, value, server, world, expireAt);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
}
|
||||
Node.Builder nb = NodeFactory.newBuilder(node).setValue(value);
|
||||
|
||||
} else if (server != null) {
|
||||
if (expireAt == 0L) {
|
||||
try {
|
||||
holder.setPermission(node, value, server);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
holder.setPermission(node, value, server, expireAt);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (expireAt == 0L) {
|
||||
try {
|
||||
holder.setPermission(node, value);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
holder.setPermission(node, value, expireAt);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
}
|
||||
if (expireAt != 0) {
|
||||
nb.setExpiry(expireAt);
|
||||
}
|
||||
|
||||
if (server != null) {
|
||||
nb.setServer(server);
|
||||
}
|
||||
|
||||
if (world != null) {
|
||||
nb.setWorld(world);
|
||||
}
|
||||
|
||||
holder.setPermission(nb.build());
|
||||
}
|
||||
|
||||
private static void getPlayerPermissions(PermissionManager manager, UUID uuid, Consumer<List<Permission>> callback) {
|
||||
if (legacy) {
|
||||
try {
|
||||
getPlayerPermissionsMethod.invoke(manager, uuid, new LPResultRunnable<List<Permission>>() {
|
||||
@Override
|
||||
public void run() {
|
||||
callback.accept(getResult());
|
||||
}
|
||||
});
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
ListenableFuture<List<Permission>> lf = (ListenableFuture<List<Permission>>) getPlayerPermissionsMethod.invoke(manager, uuid);
|
||||
try {
|
||||
if (lf.isDone()) {
|
||||
callback.accept(lf.get());
|
||||
} else {
|
||||
lf.addListener(() -> {
|
||||
try {
|
||||
callback.accept(lf.get());
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}, Runnable::run);
|
||||
}
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
private void applyGroup(PermissionManager pm, PermissionHolder holder, CachedGroup g, String server) {
|
||||
Group group = pm.getGroup(g.getGroupId());
|
||||
String node = "group." + MigrationUtils.standardizeName(group.getName());
|
||||
|
||||
long expireAt = 0L;
|
||||
if (g.willExpire()) {
|
||||
expireAt = g.getExpirationDate().getTime() / 1000L;
|
||||
}
|
||||
|
||||
Node.Builder nb = NodeFactory.newBuilder(node);
|
||||
|
||||
if (expireAt != 0) {
|
||||
nb.setExpiry(expireAt);
|
||||
}
|
||||
|
||||
if (server != null) {
|
||||
nb.setServer(server);
|
||||
}
|
||||
|
||||
holder.setPermission(nb.build());
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private static <T> T joinFuture(Future<T> future) {
|
||||
return future.get();
|
||||
}
|
||||
}
|
||||
+37
-38
@@ -25,7 +25,8 @@ package me.lucko.luckperms.bukkit.migration;
|
||||
import me.lucko.luckperms.api.event.cause.CreationCause;
|
||||
import me.lucko.luckperms.common.commands.CommandException;
|
||||
import me.lucko.luckperms.common.commands.CommandResult;
|
||||
import me.lucko.luckperms.common.commands.SubCommand;
|
||||
import me.lucko.luckperms.common.commands.abstraction.SubCommand;
|
||||
import me.lucko.luckperms.common.commands.impl.migration.MigrationUtils;
|
||||
import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.constants.Permission;
|
||||
import me.lucko.luckperms.common.core.NodeFactory;
|
||||
@@ -36,7 +37,6 @@ import me.lucko.luckperms.common.core.model.User;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.utils.Predicates;
|
||||
import me.lucko.luckperms.common.utils.ProgressLogger;
|
||||
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsService;
|
||||
@@ -59,19 +59,19 @@ public class MigrationZPermissions extends SubCommand<Object> {
|
||||
|
||||
@Override
|
||||
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object o, List<String> args, String label) throws CommandException {
|
||||
ProgressLogger log = new ProgressLogger("PermissionManager");
|
||||
ProgressLogger log = new ProgressLogger("zPermissions");
|
||||
log.addListener(plugin.getConsoleSender());
|
||||
log.addListener(sender);
|
||||
|
||||
log.log("Starting.");
|
||||
|
||||
if (!Bukkit.getPluginManager().isPluginEnabled("zPermissions")) {
|
||||
log.logErr("zPermissions is not loaded.");
|
||||
log.logErr("Plugin not loaded.");
|
||||
return CommandResult.STATE_ERROR;
|
||||
}
|
||||
|
||||
if (!Bukkit.getServicesManager().isProvidedFor(ZPermissionsService.class)) {
|
||||
log.logErr("zPermissions is not loaded.");
|
||||
log.logErr("Plugin not loaded.");
|
||||
return CommandResult.STATE_ERROR;
|
||||
}
|
||||
|
||||
@@ -91,8 +91,10 @@ public class MigrationZPermissions extends SubCommand<Object> {
|
||||
log.log("Starting group migration.");
|
||||
AtomicInteger groupCount = new AtomicInteger(0);
|
||||
for (String g : service.getAllGroups()) {
|
||||
plugin.getStorage().createAndLoadGroup(g.toLowerCase(), CreationCause.INTERNAL).join();
|
||||
Group group = plugin.getGroupManager().getIfLoaded(g.toLowerCase());
|
||||
String groupName = MigrationUtils.standardizeName(g);
|
||||
|
||||
plugin.getStorage().createAndLoadGroup(groupName, CreationCause.INTERNAL).join();
|
||||
Group group = plugin.getGroupManager().getIfLoaded(groupName);
|
||||
|
||||
PermissionEntity entity = internalService.getEntity(g, null, true);
|
||||
migrateEntity(group, entity, null);
|
||||
@@ -106,10 +108,13 @@ public class MigrationZPermissions extends SubCommand<Object> {
|
||||
log.log("Starting track migration.");
|
||||
AtomicInteger trackCount = new AtomicInteger(0);
|
||||
for (String t : service.getAllTracks()) {
|
||||
plugin.getStorage().createAndLoadTrack(t.toLowerCase(), CreationCause.INTERNAL).join();
|
||||
Track track = plugin.getTrackManager().getIfLoaded(t.toLowerCase());
|
||||
String trackName = MigrationUtils.standardizeName(t);
|
||||
|
||||
plugin.getStorage().createAndLoadTrack(trackName, CreationCause.INTERNAL).join();
|
||||
Track track = plugin.getTrackManager().getIfLoaded(trackName);
|
||||
track.setGroups(service.getTrackGroups(t));
|
||||
plugin.getStorage().saveTrack(track);
|
||||
|
||||
log.logAllProgress("Migrated {} tracks so far.", trackCount.incrementAndGet());
|
||||
}
|
||||
log.log("Migrated " + trackCount.get() + " tracks");
|
||||
@@ -118,18 +123,17 @@ public class MigrationZPermissions extends SubCommand<Object> {
|
||||
log.log("Starting user migration.");
|
||||
AtomicInteger userCount = new AtomicInteger(0);
|
||||
for (UUID u : service.getAllPlayersUUID()) {
|
||||
plugin.getStorage().loadUser(u, "null").join();
|
||||
User user = plugin.getUserManager().get(u);
|
||||
|
||||
PermissionEntity entity = internalService.getEntity(null, u, false);
|
||||
migrateEntity(user, entity, internalService.getGroups(u));
|
||||
|
||||
user.setPrimaryGroup(service.getPlayerPrimaryGroup(u));
|
||||
|
||||
String username = null;
|
||||
if (!entity.isGroup()) {
|
||||
user.setName(entity.getDisplayName());
|
||||
username = entity.getDisplayName();
|
||||
}
|
||||
|
||||
plugin.getStorage().loadUser(u, username).join();
|
||||
User user = plugin.getUserManager().get(u);
|
||||
migrateEntity(user, entity, internalService.getGroups(u));
|
||||
user.getPrimaryGroup().setStoredValue(MigrationUtils.standardizeName(service.getPlayerPrimaryGroup(u)));
|
||||
|
||||
plugin.getUserManager().cleanup(user);
|
||||
plugin.getStorage().saveUser(user);
|
||||
log.logProgress("Migrated {} users so far.", userCount.incrementAndGet());
|
||||
@@ -140,41 +144,36 @@ public class MigrationZPermissions extends SubCommand<Object> {
|
||||
return CommandResult.SUCCESS;
|
||||
}
|
||||
|
||||
private void migrateEntity(PermissionHolder group, PermissionEntity entity, List<Membership> memberships) {
|
||||
private void migrateEntity(PermissionHolder holder, PermissionEntity entity, List<Membership> memberships) {
|
||||
for (Entry e : entity.getPermissions()) {
|
||||
if (e.getWorld() != null) {
|
||||
try {
|
||||
group.setPermission(e.getPermission(), true, "global", e.getWorld().getName());
|
||||
} catch (ObjectAlreadyHasException ignored) {}
|
||||
if (e.getWorld() != null && !e.getWorld().getName().equals("")) {
|
||||
holder.setPermission(MigrationUtils.parseNode(e.getPermission(), true).setWorld(e.getWorld().getName()).build());
|
||||
} else {
|
||||
try {
|
||||
group.setPermission(e.getPermission(), true); // TODO handle negated.
|
||||
} catch (ObjectAlreadyHasException ignored) {}
|
||||
holder.setPermission(MigrationUtils.parseNode(e.getPermission(), true).build());
|
||||
}
|
||||
}
|
||||
|
||||
if (entity.isGroup()) {
|
||||
// entity.getMemberships() doesn't work for groups (always returns 0 records)
|
||||
for (Inheritance inheritance : entity.getInheritancesAsChild()) {
|
||||
try {
|
||||
if (!inheritance.getParent().getName().equals(group.getObjectName())) {
|
||||
group.setPermission("group." + inheritance.getParent().getName(), true);
|
||||
}
|
||||
} catch (ObjectAlreadyHasException ignored) {}
|
||||
if (!inheritance.getParent().getName().equals(holder.getObjectName())) {
|
||||
holder.setPermission(NodeFactory.make("group." + MigrationUtils.standardizeName(inheritance.getParent().getName())));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// entity.getMemberships() doesn't work (always returns 0 records)
|
||||
for (Membership membership : memberships) {
|
||||
try {
|
||||
group.setPermission("group." + membership.getGroup().getDisplayName(), true);
|
||||
} catch (ObjectAlreadyHasException ignored) {}
|
||||
holder.setPermission(NodeFactory.make("group." + MigrationUtils.standardizeName(membership.getGroup().getDisplayName())));
|
||||
}
|
||||
}
|
||||
|
||||
int weight = entity.isGroup() ? 50 : 100;
|
||||
for (EntityMetadata metadata : entity.getMetadata()) {
|
||||
try {
|
||||
group.setPermission(NodeFactory.makeMetaNode(metadata.getName(), metadata.getStringValue()).build());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
String key = metadata.getName().toLowerCase();
|
||||
|
||||
if (key.equals("prefix") || key.equals("suffix")) {
|
||||
holder.setPermission(NodeFactory.makeChatMetaNode(key.equals("prefix"), weight, metadata.getStringValue()).build());
|
||||
} else {
|
||||
holder.setPermission(NodeFactory.makeMetaNode(key, metadata.getStringValue()).build());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
/**
|
||||
* Injects a {@link LPPermissible} into a {@link Player}
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@UtilityClass
|
||||
public class Injector {
|
||||
private static final Map<UUID, LPPermissible> INJECTED_PERMISSIBLES = new ConcurrentHashMap<>();
|
||||
@@ -63,7 +64,7 @@ public class Injector {
|
||||
PermissibleBase existing = (PermissibleBase) HUMAN_ENTITY_FIELD.get(player);
|
||||
if (existing instanceof LPPermissible) {
|
||||
// uh oh
|
||||
throw new IllegalStateException();
|
||||
throw new IllegalStateException("LPPermissible already injected into player " + player.toString());
|
||||
}
|
||||
|
||||
// Move attachments over from the old permissible.
|
||||
@@ -72,7 +73,8 @@ public class Injector {
|
||||
attachments.clear();
|
||||
existing.clearPermissions();
|
||||
|
||||
lpPermissible.recalculatePermissions();
|
||||
lpPermissible.getActive().set(true);
|
||||
lpPermissible.recalculatePermissions(false);
|
||||
lpPermissible.setOldPermissible(existing);
|
||||
|
||||
lpPermissible.updateSubscriptionsAsync();
|
||||
@@ -97,6 +99,8 @@ public class Injector {
|
||||
((LPPermissible) permissible).unsubscribeFromAllAsync();
|
||||
}
|
||||
|
||||
((LPPermissible) permissible).getActive().set(false);
|
||||
|
||||
if (dummy) {
|
||||
HUMAN_ENTITY_FIELD.set(player, new DummyPermissibleBase());
|
||||
} else {
|
||||
|
||||
@@ -49,6 +49,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -66,6 +67,8 @@ public class LPPermissible extends PermissibleBase {
|
||||
@Setter
|
||||
private PermissibleBase oldPermissible = null;
|
||||
|
||||
private final AtomicBoolean active = new AtomicBoolean(false);
|
||||
|
||||
// Attachment stuff.
|
||||
private final Map<String, PermissionAttachmentInfo> attachmentPermissions = new ConcurrentHashMap<>();
|
||||
private final List<PermissionAttachment> attachments = Collections.synchronizedList(new LinkedList<>());
|
||||
@@ -81,10 +84,18 @@ public class LPPermissible extends PermissibleBase {
|
||||
}
|
||||
|
||||
public void updateSubscriptionsAsync() {
|
||||
if (!active.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
plugin.doAsync(this::updateSubscriptions);
|
||||
}
|
||||
|
||||
public void updateSubscriptions() {
|
||||
if (!active.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
UserCache cache = user.getUserData();
|
||||
if (cache == null) {
|
||||
return;
|
||||
@@ -110,9 +121,7 @@ public class LPPermissible extends PermissibleBase {
|
||||
}
|
||||
|
||||
public void addAttachments(List<PermissionAttachment> attachments) {
|
||||
for (PermissionAttachment attachment : attachments) {
|
||||
this.attachments.add(attachment);
|
||||
}
|
||||
this.attachments.addAll(attachments);
|
||||
}
|
||||
|
||||
public Contexts calculateContexts() {
|
||||
@@ -128,7 +137,7 @@ public class LPPermissible extends PermissibleBase {
|
||||
}
|
||||
|
||||
private boolean hasData() {
|
||||
return user.getUserData() != null;
|
||||
return user != null && user.getUserData() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -262,6 +271,10 @@ public class LPPermissible extends PermissibleBase {
|
||||
|
||||
@Override
|
||||
public void recalculatePermissions() {
|
||||
recalculatePermissions(true);
|
||||
}
|
||||
|
||||
public void recalculatePermissions(boolean invalidate) {
|
||||
if (attachmentPermissions == null) {
|
||||
return;
|
||||
}
|
||||
@@ -272,7 +285,7 @@ public class LPPermissible extends PermissibleBase {
|
||||
calculateChildPermissions(attachment.getPermissions(), false, attachment);
|
||||
}
|
||||
|
||||
if (hasData()) {
|
||||
if (hasData() && invalidate) {
|
||||
user.getUserData().invalidatePermissionCalculators();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,21 +28,17 @@ import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.api.caching.MetaData;
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
import me.lucko.luckperms.common.caching.MetaHolder;
|
||||
import me.lucko.luckperms.common.caching.MetaAccumulator;
|
||||
import me.lucko.luckperms.common.core.NodeFactory;
|
||||
import me.lucko.luckperms.common.core.model.Group;
|
||||
import me.lucko.luckperms.common.core.model.PermissionHolder;
|
||||
import me.lucko.luckperms.common.core.model.User;
|
||||
import me.lucko.luckperms.common.utils.ExtractedContexts;
|
||||
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
|
||||
import me.lucko.luckperms.exceptions.ObjectLacksException;
|
||||
|
||||
import net.milkbowl.vault.chat.Chat;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static me.lucko.luckperms.api.MetaUtils.escapeCharacters;
|
||||
import static me.lucko.luckperms.api.MetaUtils.unescapeCharacters;
|
||||
@@ -75,15 +71,7 @@ public class VaultChatHook extends Chat {
|
||||
perms.log("Setting meta: '" + node + "' for " + holder.getObjectName() + " on world " + world + ", server " + perms.getServer());
|
||||
|
||||
perms.getScheduler().execute(() -> {
|
||||
List<Node> toRemove = holder.getNodes().stream()
|
||||
.filter(n -> n.isMeta() && n.getMeta().getKey().equals(node))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
toRemove.forEach(n -> {
|
||||
try {
|
||||
holder.unsetPermission(n);
|
||||
} catch (ObjectLacksException ignored) {}
|
||||
});
|
||||
holder.removeIf(n -> n.isMeta() && n.getMeta().getKey().equals(node));
|
||||
|
||||
Node.Builder metaNode = NodeFactory.makeMetaNode(node, value).setValue(true);
|
||||
if (!perms.getServer().equalsIgnoreCase("global")) {
|
||||
@@ -93,10 +81,7 @@ public class VaultChatHook extends Chat {
|
||||
metaNode.setWorld(finalWorld);
|
||||
}
|
||||
|
||||
try {
|
||||
holder.setPermission(metaNode.build());
|
||||
} catch (ObjectAlreadyHasException ignored) {}
|
||||
|
||||
holder.setPermission(metaNode.build());
|
||||
perms.save(holder);
|
||||
});
|
||||
}
|
||||
@@ -111,19 +96,11 @@ public class VaultChatHook extends Chat {
|
||||
perms.getScheduler().execute(() -> {
|
||||
|
||||
// remove all prefixes/suffixes directly set on the user/group
|
||||
List<Node> toRemove = holder.getNodes().stream()
|
||||
.filter(n -> prefix ? n.isPrefix() : n.isSuffix())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
toRemove.forEach(n -> {
|
||||
try {
|
||||
holder.unsetPermission(n);
|
||||
} catch (ObjectLacksException ignored) {}
|
||||
});
|
||||
holder.removeIf(n -> prefix ? n.isPrefix() : n.isSuffix());
|
||||
|
||||
// find the max inherited priority & add 10
|
||||
MetaHolder metaHolder = holder.accumulateMeta(null, null, ExtractedContexts.generate(perms.createContextForWorld(finalWorld)));
|
||||
int priority = (prefix ? metaHolder.getPrefixes() : metaHolder.getSuffixes()).keySet().stream()
|
||||
MetaAccumulator metaAccumulator = holder.accumulateMeta(null, null, ExtractedContexts.generate(perms.createContextForWorld(finalWorld)));
|
||||
int priority = (prefix ? metaAccumulator.getPrefixes() : metaAccumulator.getSuffixes()).keySet().stream()
|
||||
.mapToInt(e -> e).max().orElse(0) + 10;
|
||||
|
||||
Node.Builder chatMetaNode = NodeFactory.makeChatMetaNode(prefix, priority, value);
|
||||
@@ -134,10 +111,7 @@ public class VaultChatHook extends Chat {
|
||||
chatMetaNode.setWorld(finalWorld);
|
||||
}
|
||||
|
||||
try {
|
||||
holder.setPermission(chatMetaNode.build());
|
||||
} catch (ObjectAlreadyHasException ignored) {}
|
||||
|
||||
holder.setPermission(chatMetaNode.build());
|
||||
perms.save(holder);
|
||||
});
|
||||
}
|
||||
@@ -184,7 +158,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.getPermissions(true)) {
|
||||
for (Node n : group.mergePermissionsToList()) {
|
||||
if (!n.getValue()) continue;
|
||||
if (!n.isMeta()) continue;
|
||||
if (!n.shouldApplyOnServer(perms.getServer(), perms.isIncludeGlobal(), false)) continue;
|
||||
@@ -215,7 +189,7 @@ public class VaultChatHook extends Chat {
|
||||
}
|
||||
|
||||
ExtractedContexts ec = ExtractedContexts.generate(new Contexts(ContextSet.fromMap(context), perms.isIncludeGlobal(), true, true, true, true, false));
|
||||
for (Node n : group.getAllNodes(null, ec)) {
|
||||
for (Node n : group.getAllNodes(ec)) {
|
||||
if (!n.getValue()) continue;
|
||||
if (prefix ? !n.isPrefix() : !n.isSuffix()) continue;
|
||||
if (!n.shouldApplyOnServer(perms.getServer(), perms.isIncludeGlobal(), false)) continue;
|
||||
|
||||
@@ -26,25 +26,28 @@ import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.LocalizedNode;
|
||||
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.ContextSet;
|
||||
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.core.NodeFactory;
|
||||
import me.lucko.luckperms.common.core.model.Group;
|
||||
import me.lucko.luckperms.common.core.model.PermissionHolder;
|
||||
import me.lucko.luckperms.common.core.model.User;
|
||||
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
|
||||
import me.lucko.luckperms.exceptions.ObjectLacksException;
|
||||
import me.lucko.luckperms.common.utils.ExtractedContexts;
|
||||
|
||||
import net.milkbowl.vault.permission.Permission;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* LuckPerms Vault Permission implementation
|
||||
@@ -90,15 +93,16 @@ public class VaultPermissionHook extends Permission {
|
||||
*/
|
||||
private CompletableFuture<Void> add(String world, PermissionHolder holder, String permission) {
|
||||
return CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
if (world != null && !world.equals("") && !world.equalsIgnoreCase("global")) {
|
||||
holder.setPermission(permission, true, getServer(), world);
|
||||
} else {
|
||||
holder.setPermission(permission, true, getServer());
|
||||
}
|
||||
DataMutateResult result;
|
||||
if (world != null && !world.equals("") && !world.equalsIgnoreCase("global")) {
|
||||
result = holder.setPermission(NodeFactory.make(permission, true, getServer(), world));
|
||||
} else {
|
||||
result = holder.setPermission(NodeFactory.make(permission, true, getServer()));
|
||||
}
|
||||
|
||||
if (result.asBoolean()) {
|
||||
save(holder);
|
||||
} catch (ObjectAlreadyHasException ignored) {}
|
||||
}
|
||||
}, scheduler);
|
||||
}
|
||||
|
||||
@@ -111,15 +115,16 @@ public class VaultPermissionHook extends Permission {
|
||||
*/
|
||||
private CompletableFuture<Void> remove(String world, PermissionHolder holder, String permission) {
|
||||
return CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
if (world != null && !world.equals("") && !world.equalsIgnoreCase("global")) {
|
||||
holder.unsetPermission(permission, getServer(), world);
|
||||
} else {
|
||||
holder.unsetPermission(permission, getServer());
|
||||
}
|
||||
DataMutateResult result;
|
||||
if (world != null && !world.equals("") && !world.equalsIgnoreCase("global")) {
|
||||
result = holder.unsetPermission(NodeFactory.make(permission, getServer(), world));
|
||||
} else {
|
||||
result = holder.unsetPermission(NodeFactory.make(permission, getServer()));
|
||||
}
|
||||
|
||||
if (result.asBoolean()) {
|
||||
save(holder);
|
||||
} catch (ObjectLacksException ignored) {}
|
||||
}
|
||||
}, scheduler);
|
||||
}
|
||||
|
||||
@@ -197,7 +202,7 @@ public class VaultPermissionHook extends Permission {
|
||||
if (group == null) return false;
|
||||
|
||||
// This is a nasty call. Groups aren't cached. :(
|
||||
Map<String, Boolean> permissions = group.exportNodes(createContextForWorld(world), true);
|
||||
Map<String, Boolean> permissions = group.exportNodes(ExtractedContexts.generate(createContextForWorld(world)), true);
|
||||
return permissions.containsKey(permission.toLowerCase()) && permissions.get(permission.toLowerCase());
|
||||
}
|
||||
|
||||
@@ -234,7 +239,7 @@ public class VaultPermissionHook extends Permission {
|
||||
if (user == null) return false;
|
||||
|
||||
String w = world; // screw effectively final
|
||||
return user.getNodes().stream()
|
||||
return user.getNodes().values().stream()
|
||||
.filter(Node::isGroupNode)
|
||||
.filter(n -> n.shouldApplyOnServer(getServer(), isIncludeGlobal(), false))
|
||||
.filter(n -> n.shouldApplyOnWorld(w, true, false))
|
||||
@@ -255,15 +260,16 @@ public class VaultPermissionHook extends Permission {
|
||||
|
||||
String w = world;
|
||||
scheduler.execute(() -> {
|
||||
try {
|
||||
if (w != null && !w.equals("") && !w.equalsIgnoreCase("global")) {
|
||||
user.setInheritGroup(group, getServer(), w);
|
||||
} else {
|
||||
user.setInheritGroup(group, getServer());
|
||||
}
|
||||
DataMutateResult result;
|
||||
if (w != null && !w.equals("") && !w.equalsIgnoreCase("global")) {
|
||||
result = user.setInheritGroup(group, ImmutableContextSet.of("server", getServer(), "world", w));
|
||||
} else {
|
||||
result = user.setInheritGroup(group, ImmutableContextSet.singleton("server", getServer()));
|
||||
}
|
||||
|
||||
if (result.asBoolean()) {
|
||||
save(user);
|
||||
} catch (ObjectAlreadyHasException ignored) {}
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
@@ -281,15 +287,16 @@ public class VaultPermissionHook extends Permission {
|
||||
|
||||
String w = world;
|
||||
scheduler.execute(() -> {
|
||||
try {
|
||||
if (w != null && !w.equals("") && !w.equalsIgnoreCase("global")) {
|
||||
user.unsetInheritGroup(group, getServer(), w);
|
||||
} else {
|
||||
user.unsetInheritGroup(group, getServer());
|
||||
}
|
||||
DataMutateResult result;
|
||||
if (w != null && !w.equals("") && !w.equalsIgnoreCase("global")) {
|
||||
result = user.unsetInheritGroup(group, ImmutableContextSet.of("server", getServer(), "world", w));
|
||||
} else {
|
||||
result = user.unsetInheritGroup(group, ImmutableContextSet.singleton("server", getServer()));
|
||||
}
|
||||
|
||||
if (result.asBoolean()) {
|
||||
save(user);
|
||||
} catch (ObjectLacksException ignored) {}
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
@@ -303,7 +310,7 @@ public class VaultPermissionHook extends Permission {
|
||||
if (user == null) return new String[0];
|
||||
|
||||
String w = world; // screw effectively final
|
||||
return user.getNodes().stream()
|
||||
return user.getNodes().values().stream()
|
||||
.filter(Node::isGroupNode)
|
||||
.filter(n -> n.shouldApplyOnServer(getServer(), isIncludeGlobal(), false))
|
||||
.filter(n -> n.shouldApplyOnWorld(w, true, false))
|
||||
@@ -323,7 +330,7 @@ public class VaultPermissionHook extends Permission {
|
||||
|
||||
// nothing special, just return the value.
|
||||
if (!isPgo()) {
|
||||
String g = user.getPrimaryGroup();
|
||||
String g = user.getPrimaryGroup().getValue();
|
||||
return plugin.getConfiguration().get(ConfigKeys.GROUP_NAME_REWRITES).getOrDefault(g, g);
|
||||
}
|
||||
|
||||
@@ -352,7 +359,7 @@ public class VaultPermissionHook extends Permission {
|
||||
}
|
||||
} else {
|
||||
// we need to check the users permissions only
|
||||
for (LocalizedNode node : user.getPermissions(true)) {
|
||||
for (Node node : user.mergePermissionsToList()) {
|
||||
if (!node.getValue()) continue;
|
||||
if (!node.getPermission().toLowerCase().startsWith("vault.primarygroup.")) continue;
|
||||
if (!node.shouldApplyOnServer(getServer(), isIncludeGlobal(), false)) continue;
|
||||
@@ -366,7 +373,15 @@ public class VaultPermissionHook extends Permission {
|
||||
}
|
||||
|
||||
if (isPgoCheckMemberOf()) {
|
||||
if (!user.getLocalGroups(getServer(), world, isIncludeGlobal()).contains(group.toLowerCase())) {
|
||||
String finalWorld = world;
|
||||
List<String> localGroups = user.mergePermissionsToList().stream()
|
||||
.filter(Node::isGroupNode)
|
||||
.filter(n -> n.shouldApplyOnWorld(finalWorld, isIncludeGlobal(), true))
|
||||
.filter(n -> n.shouldApplyOnServer(getServer(), isIncludeGlobal(), true))
|
||||
.map(Node::getGroupName)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!localGroups.contains(group.toLowerCase())) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -376,7 +391,7 @@ public class VaultPermissionHook extends Permission {
|
||||
}
|
||||
|
||||
// Fallback
|
||||
String g = user.getPrimaryGroup();
|
||||
String g = user.getPrimaryGroup().getValue();
|
||||
return plugin.getConfiguration().get(ConfigKeys.GROUP_NAME_REWRITES).getOrDefault(g, g);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,26 +26,38 @@ apply-global-groups: true
|
||||
# If users on this server should have global (non-world specific) groups applied
|
||||
apply-global-world-groups: true
|
||||
|
||||
# If this server is in offline or online mode.
|
||||
# This setting allows a player to have the same UUID across a network of offline mode/mixed servers.
|
||||
# If UUIDs should be pulled from the server, or looked up by username based upon previous connections.
|
||||
#
|
||||
# You should generally reflect the setting in server.properties here. Except when...
|
||||
# This option should be set to true in most cases. When set to false, in order to get a player's UUID, LuckPerms will:
|
||||
# 1. Check if a player with the given username has joined before, if they have, use the UUID they used on their previous login.
|
||||
# 2. Save and return the players "current" uuid.
|
||||
#
|
||||
# 1. You have Spigot servers connected to a BungeeCord proxy, with online-mode set to false, but 'bungeecord' set to true in the spigot.yml
|
||||
# AND 'ip-forward' set to true in the BungeeCord config.yml
|
||||
# In this case, set online-mode in LuckPerms to true, despite the server being in offline mode.
|
||||
# For offline mode (cracked) servers, a players UUID is generated based upon their username.
|
||||
#
|
||||
# 2. You are only running one server instance using LuckPerms, (not a network)
|
||||
# In this case, set online-mode to true no matter what is set in server.properties. (we can just fallback to the servers uuid cache)
|
||||
# IMPORTANT:
|
||||
# If you are using BungeeCord proxy running in online mode, it is important that "online-mode=false" is set in server.properties, but
|
||||
# "bungeecord: true" is set in the spigot.yml. You also need to set "ip_forward: true" in BungeeCord's config.yml.
|
||||
# If for whatever reason you are not able to do this, and do not have ip-forward enabled, then you may need to set "use-server-uuids" to false.
|
||||
#
|
||||
# 3. If your proxy is running in offline mode, and you are using PaperSpigot (https://ci.destroystokyo.com/job/PaperSpigot/),
|
||||
# you should set "bungee-online-mode" to false in the paper.yml, and set "online-mode" to true in all LuckPerms configs.
|
||||
# This approach is thoroughly recommended for offline mode networks.
|
||||
online-mode: true
|
||||
# If your proxy is running in offline mode, you should still be setting up ip-forwarding as described above, but may also find that you need to set
|
||||
# "bungee-online-mode" to false in paper.yml, if you are using PaperSpigot. (https://ci.destroystokyo.com/job/PaperSpigot/)
|
||||
#
|
||||
# This option only really exists for networks who for whatever reason cannot setup proper ip forwarding.
|
||||
use-server-uuids: true
|
||||
|
||||
# If the plugin should send log notifications to users whenever permissions are modified.
|
||||
log-notify: true
|
||||
|
||||
# Mirrors world names. Whenever LuckPerms checks what world a user is in, if the world name is in this list, the value assigned
|
||||
# will be sent forward for permission calculation instead.
|
||||
world-rewrite:
|
||||
# world_nether: world
|
||||
# world_the_end: world
|
||||
|
||||
# Rewrites group names. The underlying name of the group does not change, just the output in commands / placeholders / Vault.
|
||||
group-name-rewrite:
|
||||
# default: Member
|
||||
|
||||
# Controls how temporary permissions/parents/meta should be accumulated
|
||||
#
|
||||
# The default behaviour is "deny"
|
||||
@@ -54,6 +66,14 @@ log-notify: true
|
||||
# If "deny": the command will just fail if you try to add another node with the same expiry
|
||||
temporary-add-behaviour: deny
|
||||
|
||||
# How should LuckPerms determine a users "primary" group.
|
||||
#
|
||||
# Available Options:
|
||||
# -> stored use the value stored against the users record in the file/database
|
||||
# -> parents-by-weight just use the users most highly weighted parent
|
||||
# -> all-parents-by-weight same as above, but calculates based upon all parents inherits from both directly and indirectly
|
||||
primary-group-calculation: stored
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -144,8 +164,14 @@ commands-allow-op: true
|
||||
# | Vault | #
|
||||
# +------------------------------------------------------------------------+ #
|
||||
|
||||
# If the vault-server option below should be used.
|
||||
# When this option is set to false, the server value defined above under "server" is used.
|
||||
use-vault-server: false
|
||||
|
||||
# The name of the server used within Vault operations. If you don't want Vault operations to be server specific, set this
|
||||
# to "global".
|
||||
#
|
||||
# Will only take effect if use-vault-server is set to true above.
|
||||
vault-server: global
|
||||
|
||||
# If global permissions should be considered when retrieving meta or player groups
|
||||
@@ -154,32 +180,9 @@ vault-include-global: true
|
||||
# If Vault operations should ignore any world arguments if supplied.
|
||||
vault-ignore-world: false
|
||||
|
||||
# This block controls the Primary Group override feature
|
||||
# See the wiki for more information.
|
||||
vault-primary-groups-overrides:
|
||||
# If the feature is enabled
|
||||
enabled: false
|
||||
# If the check should query the user's inherited permissions.
|
||||
# (a value of false only checks the permissions they explicitly have)
|
||||
check-inherited-permissions: false
|
||||
# If LuckPerms should check if the group exists
|
||||
check-group-exists: true
|
||||
# If LuckPerms should check if the user is actually a member of the group
|
||||
check-user-member-of: true
|
||||
|
||||
# If LuckPerms should print debugging info to console when a plugin uses a Vault function
|
||||
vault-debug: false
|
||||
|
||||
# Mirrors world names. Whenever LuckPerms checks what world a user is in, if the world name is in this list, the value assigned
|
||||
# will be sent forward for permission calculation instead.
|
||||
world-rewrite:
|
||||
# world_nether: world
|
||||
# world_the_end: world
|
||||
|
||||
# Rewrites group names. The underlying name of the group does not change, just the output in commands / placeholders / Vault.
|
||||
group-name-rewrite:
|
||||
# default: Member
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -188,10 +191,20 @@ group-name-rewrite:
|
||||
# +------------------------------------------------------------------------+ #
|
||||
|
||||
# Which storage method the plugin should use.
|
||||
# Currently supported: mysql, postgresql, sqlite, h2, json, yaml, mongodb
|
||||
# Fill out connection info below if you're using MySQL, PostgreSQL or MongoDB
|
||||
#
|
||||
# See: https://github.com/lucko/LuckPerms/wiki/Choosing-a-Storage-type
|
||||
# Currently supported: mysql, mariadb, postgresql, sqlite, h2, json, yaml, mongodb
|
||||
|
||||
# Fill out connection info below if you're using MySQL, MariaDB, PostgreSQL or MongoDB
|
||||
# If your MySQL server supports it, the "mariadb" option is preferred over "mysql".
|
||||
storage-method: h2
|
||||
|
||||
# When using a file-based storage type, LuckPerms can monitor the data files for changes, and then schedule automatic
|
||||
# updates when changes are detected.
|
||||
#
|
||||
# If you don't want this to happen, set this option to false.
|
||||
watch-files: true
|
||||
|
||||
# This block enables support for split datastores.
|
||||
split-storage:
|
||||
enabled: false
|
||||
@@ -217,9 +230,14 @@ data:
|
||||
# This should *not* be set to "lp_" if you have previously ran LuckPerms v2.16.81 or earlier with this database.
|
||||
table_prefix: 'luckperms_'
|
||||
|
||||
# Set to -1 to disable. If this is the only instance accessing the datastore, you can disable syncing.
|
||||
# e.g. if you're using sqlite or flatfile, this can be set to -1 to save resources.
|
||||
sync-minutes: 3
|
||||
# This option controls how frequently LuckPerms will perform a sync task.
|
||||
# A sync task will refresh all data from the storage, and ensure that the most up-to-date data is being used by the plugin.
|
||||
#
|
||||
# This is disabled by default, as most users will not need it. However, if you're using a remote storage type
|
||||
# without a messaging service setup, you may wish to set this value to something like 3.
|
||||
#
|
||||
# Set to -1 to disable the task completely.
|
||||
sync-minutes: -1
|
||||
|
||||
# Settings for the messaging service
|
||||
#
|
||||
@@ -237,6 +255,9 @@ data:
|
||||
# none ==> nothing
|
||||
messaging-service: none
|
||||
|
||||
# If LuckPerms should automatically push updates after a change has been made with a command.
|
||||
auto-push-updates: true
|
||||
|
||||
# Settings for Redis.
|
||||
# Port 6379 is used by default; set address to "host:port" if differs
|
||||
redis:
|
||||
|
||||
+5
-12
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>luckperms</artifactId>
|
||||
<groupId>me.lucko.luckperms</groupId>
|
||||
<version>3.0-SNAPSHOT</version>
|
||||
<version>3.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<version>${compiler.version}</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
@@ -42,7 +42,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>2.4.3</version>
|
||||
<version>${shade.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
@@ -70,7 +70,7 @@
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>1.9-SNAPSHOT</version>
|
||||
<version>1.11-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- LuckPerms Common -->
|
||||
@@ -87,18 +87,11 @@
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- slf4j library -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
<version>1.7.9</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Lombok -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.16.10</version>
|
||||
<version>${lombok.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- **************Migration Plugins************** -->
|
||||
|
||||
@@ -29,8 +29,6 @@ import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class BackendServerCalculator implements ContextCalculator<ProxiedPlayer> {
|
||||
private static final String WORLD_KEY = "world";
|
||||
|
||||
@@ -43,19 +41,9 @@ public class BackendServerCalculator implements ContextCalculator<ProxiedPlayer>
|
||||
String server = getServer(subject);
|
||||
|
||||
if (server != null) {
|
||||
accumulator.add(Maps.immutableEntry(WORLD_KEY, server));
|
||||
accumulator.add(Maps.immutableEntry(WORLD_KEY, server.toLowerCase()));
|
||||
}
|
||||
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isContextApplicable(ProxiedPlayer subject, Map.Entry<String, String> context) {
|
||||
if (!context.getKey().equals(WORLD_KEY)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String server = getServer(subject);
|
||||
return server != null && server.equals(context.getValue());
|
||||
}
|
||||
}
|
||||
@@ -35,11 +35,11 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class BungeeConfig extends AbstractConfiguration {
|
||||
@@ -72,6 +72,11 @@ public class BungeeConfig extends AbstractConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(String path) {
|
||||
return configuration.contains(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString(String path, String def) {
|
||||
return configuration.getString(path, def);
|
||||
@@ -99,7 +104,7 @@ public class BungeeConfig extends AbstractConfiguration {
|
||||
return def;
|
||||
}
|
||||
|
||||
return Optional.ofNullable(section.getKeys().stream().collect(Collectors.toList())).orElse(def);
|
||||
return Optional.of((List<String>) new ArrayList<>(section.getKeys())).orElse(def);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -22,13 +22,16 @@
|
||||
|
||||
package me.lucko.luckperms.bungee;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.caching.UserData;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.constants.Message;
|
||||
import me.lucko.luckperms.common.core.UuidCache;
|
||||
import me.lucko.luckperms.common.core.model.User;
|
||||
import me.lucko.luckperms.common.defaults.Rule;
|
||||
import me.lucko.luckperms.common.utils.AbstractListener;
|
||||
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.connection.PendingConnection;
|
||||
@@ -37,67 +40,68 @@ import net.md_5.bungee.api.event.LoginEvent;
|
||||
import net.md_5.bungee.api.event.PermissionCheckEvent;
|
||||
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
|
||||
import net.md_5.bungee.api.event.PostLoginEvent;
|
||||
import net.md_5.bungee.api.event.ServerConnectEvent;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
import net.md_5.bungee.event.EventPriority;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public class BungeeListener extends AbstractListener implements Listener {
|
||||
private static final TextComponent WARN_MESSAGE = new TextComponent(Message.LOADING_ERROR.toString());
|
||||
@RequiredArgsConstructor
|
||||
public class BungeeListener implements Listener {
|
||||
private final LPBungeePlugin plugin;
|
||||
|
||||
BungeeListener(LPBungeePlugin plugin) {
|
||||
super(plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
private final Set<UUID> deniedLogin = Collections.synchronizedSet(new HashSet<>());
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerPermissionCheck(PermissionCheckEvent e) {
|
||||
if (!(e.getSender() instanceof ProxiedPlayer)) {
|
||||
e.setHasPermission(true);
|
||||
return;
|
||||
}
|
||||
|
||||
final ProxiedPlayer player = ((ProxiedPlayer) e.getSender());
|
||||
|
||||
User user = plugin.getUserManager().get(plugin.getUuidCache().getUUID(player.getUniqueId()));
|
||||
if (user == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (user.getUserData() == null) {
|
||||
plugin.getLog().warn("Player " + player.getName() + " does not have any user data setup.");
|
||||
return;
|
||||
}
|
||||
|
||||
Contexts contexts = new Contexts(
|
||||
plugin.getContextManager().getApplicableContext(player),
|
||||
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
|
||||
);
|
||||
|
||||
e.setHasPermission(user.getUserData().getPermissionData(contexts).getPermissionValue(e.getPermission()).asBoolean());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
@EventHandler(priority = EventPriority.LOW)
|
||||
public void onPlayerLogin(LoginEvent e) {
|
||||
/* Delay the login here, as we want to cache UUID data before the player is connected to a backend bukkit server.
|
||||
/* Called when the player first attempts a connection with the server.
|
||||
Listening on LOW priority to allow plugins to modify username / UUID data here. (auth plugins)
|
||||
|
||||
Delay the login here, as we want to cache UUID data before the player is connected to a backend bukkit server.
|
||||
This means that a player will have the same UUID across the network, even if parts of the network are running in
|
||||
Offline mode. */
|
||||
e.registerIntent(plugin);
|
||||
plugin.doAsync(() -> {
|
||||
final long startTime = System.currentTimeMillis();
|
||||
final UuidCache cache = plugin.getUuidCache();
|
||||
final PendingConnection c = e.getConnection();
|
||||
|
||||
if (!plugin.getConfiguration().get(ConfigKeys.ONLINE_MODE)) {
|
||||
// registers the plugins intent to modify this events state going forward.
|
||||
// this will prevent the event from completing until we're finished handling.
|
||||
e.registerIntent(plugin);
|
||||
|
||||
final long startTime = System.currentTimeMillis();
|
||||
final PendingConnection c = e.getConnection();
|
||||
|
||||
/* either the plugin hasn't finished starting yet, or 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. */
|
||||
if (!plugin.getStorage().isAcceptingLogins()) {
|
||||
// log that the user tried to login, but was denied at this stage.
|
||||
deniedLogin.add(c.getUniqueId());
|
||||
return;
|
||||
}
|
||||
|
||||
/* another plugin (or the proxy itself) has cancelled this connection already */
|
||||
if (e.isCancelled()) {
|
||||
plugin.getLog().warn("Connection from " + c.getUniqueId() + " was already denied. No permissions data will be loaded.");
|
||||
deniedLogin.add(c.getUniqueId());
|
||||
return;
|
||||
}
|
||||
|
||||
/* Actually process the login for the connection.
|
||||
We do this here to delay the login until the data is ready.
|
||||
If the login gets cancelled later on, then this will be cleaned up.
|
||||
|
||||
This includes:
|
||||
- loading uuid data
|
||||
- loading permissions
|
||||
- creating a user instance in the UserManager for this connection.
|
||||
- setting up cached data. */
|
||||
plugin.doAsync(() -> {
|
||||
final UuidCache cache = plugin.getUuidCache();
|
||||
|
||||
if (!plugin.getConfiguration().get(ConfigKeys.USE_SERVER_UUIDS)) {
|
||||
UUID uuid = plugin.getStorage().getUUID(c.getName()).join();
|
||||
if (uuid != null) {
|
||||
cache.addToCache(c.getUniqueId(), uuid);
|
||||
@@ -105,6 +109,8 @@ public class BungeeListener extends AbstractListener implements Listener {
|
||||
// No previous data for this player
|
||||
plugin.getApiProvider().getEventFactory().handleUserFirstLogin(c.getUniqueId(), c.getName());
|
||||
cache.addToCache(c.getUniqueId(), c.getUniqueId());
|
||||
|
||||
// Join this call, as we want this to be set for when the player connects to the backend.
|
||||
plugin.getStorage().force().saveUUIDData(c.getName(), c.getUniqueId()).join();
|
||||
}
|
||||
} else {
|
||||
@@ -114,12 +120,14 @@ public class BungeeListener extends AbstractListener implements Listener {
|
||||
}
|
||||
|
||||
// Online mode, no cache needed. This is just for name -> uuid lookup.
|
||||
// Again, join this call so the data is available for the backend.
|
||||
plugin.getStorage().force().saveUUIDData(c.getName(), c.getUniqueId()).join();
|
||||
}
|
||||
|
||||
// We have to make a new user on this thread whilst the connection is being held, or we get concurrency issues as the Bukkit server
|
||||
// and the BungeeCord server try to make a new user at the same time.
|
||||
/* We have to make a new user on this thread whilst the connection is being held, or we get concurrency issues
|
||||
as the Bukkit server and the BungeeCord server try to make a new user at the same time. */
|
||||
plugin.getStorage().force().loadUser(cache.getUUID(c.getUniqueId()), c.getName()).join();
|
||||
|
||||
User user = plugin.getUserManager().get(cache.getUUID(c.getUniqueId()));
|
||||
if (user == null) {
|
||||
plugin.getLog().warn("Failed to load user: " + c.getName());
|
||||
@@ -144,7 +152,13 @@ public class BungeeListener extends AbstractListener implements Listener {
|
||||
if (time >= 1000) {
|
||||
plugin.getLog().warn("Processing login for " + c.getName() + " took " + time + "ms.");
|
||||
}
|
||||
|
||||
// finally, complete out intent to modify state, so the proxy can continue handling the connection.
|
||||
e.completeIntent(plugin);
|
||||
|
||||
// schedule a cleanup of the users data in a few seconds.
|
||||
// this should cover the eventuality that the login fails.
|
||||
plugin.getUserManager().scheduleUnload(c.getUniqueId());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -154,12 +168,87 @@ public class BungeeListener extends AbstractListener implements Listener {
|
||||
final User user = plugin.getUserManager().get(plugin.getUuidCache().getUUID(e.getPlayer().getUniqueId()));
|
||||
|
||||
if (user == null) {
|
||||
plugin.getProxy().getScheduler().schedule(plugin, () -> player.sendMessage(WARN_MESSAGE), 3, TimeUnit.SECONDS);
|
||||
plugin.getProxy().getScheduler().schedule(plugin, () -> {
|
||||
if (!player.isConnected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
player.sendMessage(new TextComponent(Message.LOADING_ERROR.asString(plugin.getLocaleManager())));
|
||||
}, 3, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
// Wait until the last priority to unload, so plugins can still perform permission checks on this event
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPlayerQuit(PlayerDisconnectEvent e) {
|
||||
onLeave(e.getPlayer().getUniqueId());
|
||||
// Request that the users data is unloaded.
|
||||
plugin.getUserManager().scheduleUnload(e.getPlayer().getUniqueId());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onPlayerPermissionCheck(PermissionCheckEvent e) {
|
||||
if (!(e.getSender() instanceof ProxiedPlayer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ProxiedPlayer player = ((ProxiedPlayer) e.getSender());
|
||||
|
||||
User user = plugin.getUserManager().get(plugin.getUuidCache().getUUID(player.getUniqueId()));
|
||||
if (user == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
UserData userData = user.getUserData();
|
||||
if (userData == null) {
|
||||
plugin.getLog().warn("Player " + player.getName() + " does not have any user data setup.");
|
||||
plugin.doAsync(() -> user.setupData(false));
|
||||
return;
|
||||
}
|
||||
|
||||
Contexts contexts = new Contexts(
|
||||
plugin.getContextManager().getApplicableContext(player),
|
||||
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
|
||||
);
|
||||
|
||||
e.setHasPermission(userData.getPermissionData(contexts).getPermissionValue(e.getPermission()).asBoolean());
|
||||
}
|
||||
|
||||
// We don't pre-process all servers, so we have to do it here.
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onServerSwitch(ServerConnectEvent e) {
|
||||
String serverName = e.getTarget().getName();
|
||||
UUID uuid = e.getPlayer().getUniqueId();
|
||||
|
||||
plugin.doAsync(() -> {
|
||||
MutableContextSet set = MutableContextSet.create();
|
||||
set.add("server", plugin.getConfiguration().get(ConfigKeys.SERVER));
|
||||
set.add("world", serverName);
|
||||
|
||||
User user = plugin.getUserManager().get(plugin.getUuidCache().getUUID(uuid));
|
||||
if (user == null) {
|
||||
return;
|
||||
}
|
||||
UserData userData = user.getUserData();
|
||||
if (userData == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Contexts contexts = new Contexts(
|
||||
set.makeImmutable(),
|
||||
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
|
||||
);
|
||||
|
||||
userData.preCalculate(contexts);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -64,7 +64,7 @@ public class BungeeSenderFactory extends SenderFactory<CommandSender> {
|
||||
@Override
|
||||
protected void sendMessage(CommandSender sender, FancyMessage message) {
|
||||
try {
|
||||
sender.sendMessage(ComponentSerializer.parse(message.toJSONString()));
|
||||
sender.sendMessage(ComponentSerializer.parse(message.exportToJson()));
|
||||
} catch (Exception e) {
|
||||
sendMessage(sender, message.toOldMessageFormat());
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.Logger;
|
||||
import me.lucko.luckperms.api.PlatformType;
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.bungee.messaging.BungeeMessagingService;
|
||||
import me.lucko.luckperms.common.api.ApiHandler;
|
||||
import me.lucko.luckperms.common.api.ApiProvider;
|
||||
@@ -39,11 +38,10 @@ import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.config.LuckPermsConfiguration;
|
||||
import me.lucko.luckperms.common.contexts.ContextManager;
|
||||
import me.lucko.luckperms.common.contexts.ServerCalculator;
|
||||
import me.lucko.luckperms.common.contexts.StaticCalculator;
|
||||
import me.lucko.luckperms.common.core.UuidCache;
|
||||
import me.lucko.luckperms.common.core.model.User;
|
||||
import me.lucko.luckperms.common.data.Importer;
|
||||
import me.lucko.luckperms.common.debug.DebugHandler;
|
||||
import me.lucko.luckperms.common.dependencies.Dependency;
|
||||
import me.lucko.luckperms.common.dependencies.DependencyManager;
|
||||
import me.lucko.luckperms.common.locale.LocaleManager;
|
||||
import me.lucko.luckperms.common.locale.NoopLocaleManager;
|
||||
@@ -55,6 +53,7 @@ import me.lucko.luckperms.common.managers.impl.GenericGroupManager;
|
||||
import me.lucko.luckperms.common.managers.impl.GenericTrackManager;
|
||||
import me.lucko.luckperms.common.managers.impl.GenericUserManager;
|
||||
import me.lucko.luckperms.common.messaging.InternalMessagingService;
|
||||
import me.lucko.luckperms.common.messaging.NoopMessagingService;
|
||||
import me.lucko.luckperms.common.messaging.RedisMessaging;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsScheduler;
|
||||
@@ -66,14 +65,16 @@ 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.BufferedRequest;
|
||||
import me.lucko.luckperms.common.utils.FileWatcher;
|
||||
import me.lucko.luckperms.common.utils.LoggerImpl;
|
||||
import me.lucko.luckperms.common.verbose.VerboseHandler;
|
||||
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -85,33 +86,41 @@ import java.util.stream.Collectors;
|
||||
public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
private final Set<UUID> ignoringLogs = ConcurrentHashMap.newKeySet();
|
||||
private LuckPermsScheduler scheduler;
|
||||
private CommandManager commandManager;
|
||||
private LuckPermsConfiguration configuration;
|
||||
private UserManager userManager;
|
||||
private GroupManager groupManager;
|
||||
private TrackManager trackManager;
|
||||
private Storage storage;
|
||||
private FileWatcher fileWatcher = null;
|
||||
private InternalMessagingService messagingService = null;
|
||||
private UuidCache uuidCache;
|
||||
private ApiProvider apiProvider;
|
||||
private Logger log;
|
||||
private Importer importer;
|
||||
private LocaleManager localeManager;
|
||||
private CachedStateManager cachedStateManager;
|
||||
private ContextManager<ProxiedPlayer> contextManager;
|
||||
private CalculatorFactory calculatorFactory;
|
||||
private BufferedRequest<Void> updateTaskBuffer;
|
||||
private DebugHandler debugHandler;
|
||||
private VerboseHandler verboseHandler;
|
||||
private BungeeSenderFactory senderFactory;
|
||||
private PermissionVault permissionVault;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
public void onLoad() {
|
||||
// setup minimal functionality in order to load initial dependencies
|
||||
scheduler = new LPBungeeScheduler(this);
|
||||
localeManager = new NoopLocaleManager();
|
||||
senderFactory = new BungeeSenderFactory(this);
|
||||
log = new LoggerImpl(getConsoleSender());
|
||||
|
||||
DependencyManager.loadDependencies(this, Collections.singletonList(Dependency.CAFFEINE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
LuckPermsPlugin.sendStartupBanner(getConsoleSender(), this);
|
||||
debugHandler = new DebugHandler(scheduler.getAsyncExecutor(), getVersion());
|
||||
verboseHandler = new VerboseHandler(scheduler.getAsyncExecutor(), getVersion());
|
||||
permissionVault = new PermissionVault(scheduler.getAsyncExecutor());
|
||||
|
||||
getLog().info("Loading configuration...");
|
||||
@@ -125,6 +134,11 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
// register events
|
||||
getProxy().getPluginManager().registerListener(this, new BungeeListener(this));
|
||||
|
||||
if (getConfiguration().get(ConfigKeys.WATCH_FILES)) {
|
||||
fileWatcher = new FileWatcher(this);
|
||||
getScheduler().doAsyncRepeating(fileWatcher, 30L);
|
||||
}
|
||||
|
||||
// initialise datastore
|
||||
storage = StorageFactory.getInstance(this, StorageType.H2);
|
||||
|
||||
@@ -158,6 +172,10 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
getLog().warn("Messaging service '" + messagingType + "' not recognised.");
|
||||
}
|
||||
|
||||
if (messagingService == null) {
|
||||
messagingService = new NoopMessagingService();
|
||||
}
|
||||
|
||||
// setup the update task buffer
|
||||
updateTaskBuffer = new BufferedRequest<Void>(1000L, this::doAsync) {
|
||||
@Override
|
||||
@@ -181,7 +199,7 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
|
||||
// register commands
|
||||
getLog().info("Registering commands...");
|
||||
CommandManager commandManager = new CommandManager(this);
|
||||
commandManager = new CommandManager(this);
|
||||
getProxy().getPluginManager().registerCommand(this, new BungeeCommand(this, commandManager));
|
||||
|
||||
// disable the default Bungee /perms command so it gets handled by the Bukkit plugin
|
||||
@@ -193,14 +211,13 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
userManager = new GenericUserManager(this);
|
||||
groupManager = new GenericGroupManager(this);
|
||||
trackManager = new GenericTrackManager(this);
|
||||
importer = new Importer(commandManager);
|
||||
calculatorFactory = new BungeeCalculatorFactory(this);
|
||||
cachedStateManager = new CachedStateManager(this);
|
||||
|
||||
contextManager = new ContextManager<>();
|
||||
BackendServerCalculator serverCalculator = new BackendServerCalculator();
|
||||
contextManager.registerCalculator(serverCalculator);
|
||||
contextManager.registerCalculator(new ServerCalculator<>(configuration));
|
||||
contextManager.registerCalculator(new StaticCalculator<>(configuration));
|
||||
|
||||
// register with the LP API
|
||||
getLog().info("Registering API...");
|
||||
@@ -230,6 +247,10 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
getLog().info("Closing datastore...");
|
||||
storage.shutdown();
|
||||
|
||||
if (fileWatcher != null) {
|
||||
fileWatcher.close();
|
||||
}
|
||||
|
||||
if (messagingService != null) {
|
||||
getLog().info("Closing messaging service...");
|
||||
messagingService.close();
|
||||
@@ -311,7 +332,8 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
|
||||
@Override
|
||||
public boolean isPlayerOnline(UUID external) {
|
||||
return getProxy().getPlayer(external) != null;
|
||||
ProxiedPlayer player = getProxy().getPlayer(external);
|
||||
return player != null && player.isConnected();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -331,17 +353,6 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
Set<ContextSet> c = new HashSet<>();
|
||||
c.add(ContextSet.empty());
|
||||
c.add(ContextSet.singleton("server", getConfiguration().get(ConfigKeys.SERVER)));
|
||||
c.addAll(getProxy().getServers().values().stream()
|
||||
.map(ServerInfo::getName)
|
||||
.map(s -> {
|
||||
MutableContextSet set = MutableContextSet.create();
|
||||
set.add("server", getConfiguration().get(ConfigKeys.SERVER));
|
||||
set.add("world", s);
|
||||
return set.makeImmutable();
|
||||
})
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
|
||||
return c.stream()
|
||||
.map(set -> new Contexts(
|
||||
set,
|
||||
@@ -354,9 +365,4 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUuidFromUsername(String playerName) {
|
||||
return null; // Not needed on Bungee
|
||||
}
|
||||
}
|
||||
+60
-65
@@ -22,13 +22,14 @@
|
||||
|
||||
package me.lucko.luckperms.bungee.migration;
|
||||
|
||||
import me.lucko.luckperms.api.MetaUtils;
|
||||
import me.lucko.luckperms.api.event.cause.CreationCause;
|
||||
import me.lucko.luckperms.common.commands.CommandException;
|
||||
import me.lucko.luckperms.common.commands.CommandResult;
|
||||
import me.lucko.luckperms.common.commands.SubCommand;
|
||||
import me.lucko.luckperms.common.commands.abstraction.SubCommand;
|
||||
import me.lucko.luckperms.common.commands.impl.migration.MigrationUtils;
|
||||
import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.constants.Permission;
|
||||
import me.lucko.luckperms.common.core.NodeFactory;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.utils.Predicates;
|
||||
import me.lucko.luckperms.common.utils.ProgressLogger;
|
||||
@@ -63,53 +64,66 @@ public class MigrationBungeePerms extends SubCommand<Object> {
|
||||
return CommandResult.STATE_ERROR;
|
||||
}
|
||||
|
||||
List<Group> groups = bp.getPermissionsManager().getBackEnd().loadGroups();
|
||||
|
||||
log.log("Calculating group weightings.");
|
||||
int maxWeight = 0;
|
||||
for (Group group : groups) {
|
||||
maxWeight = Math.max(maxWeight, group.getRank());
|
||||
}
|
||||
maxWeight += 5;
|
||||
|
||||
// Migrate all groups.
|
||||
log.log("Starting group migration.");
|
||||
AtomicInteger groupCount = new AtomicInteger(0);
|
||||
for (Group g : bp.getPermissionsManager().getBackEnd().loadGroups()) {
|
||||
for (Group g : groups) {
|
||||
int groupWeight = maxWeight - g.getRank();
|
||||
|
||||
// Make a LuckPerms group for the one being migrated
|
||||
plugin.getStorage().createAndLoadGroup(g.getName().toLowerCase(), CreationCause.INTERNAL).join();
|
||||
me.lucko.luckperms.common.core.model.Group group = plugin.getGroupManager().getIfLoaded(g.getName().toLowerCase());
|
||||
String groupName = MigrationUtils.standardizeName(g.getName());
|
||||
plugin.getStorage().createAndLoadGroup(groupName, CreationCause.INTERNAL).join();
|
||||
me.lucko.luckperms.common.core.model.Group group = plugin.getGroupManager().getIfLoaded(groupName);
|
||||
|
||||
MigrationUtils.setGroupWeight(group, groupWeight);
|
||||
|
||||
// Migrate global perms
|
||||
for (String perm : g.getPerms()) {
|
||||
try {
|
||||
group.setPermission(perm, true);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
if (perm.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
group.setPermission(MigrationUtils.parseNode(perm, true).build());
|
||||
}
|
||||
|
||||
// Migrate per-server perms
|
||||
for (Map.Entry<String, Server> e : g.getServers().entrySet()) {
|
||||
for (String perm : e.getValue().getPerms()) {
|
||||
try {
|
||||
group.setPermission(perm, true, e.getKey());
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
if (perm.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
group.setPermission(MigrationUtils.parseNode(perm, true).setWorld(e.getKey()).build());
|
||||
}
|
||||
|
||||
// Migrate per-world perms
|
||||
for (Map.Entry<String, World> we : e.getValue().getWorlds().entrySet()) {
|
||||
for (String perm : we.getValue().getPerms()) {
|
||||
try {
|
||||
group.setPermission(perm, true, e.getKey(), we.getKey());
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
if (perm.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
group.setPermission(MigrationUtils.parseNode(perm, true).setServer(e.getKey()).setWorld(we.getKey()).build());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Migrate any parent groups
|
||||
for (String inherit : g.getInheritances()) {
|
||||
try {
|
||||
group.setPermission("group." + inherit, true);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
if (inherit.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
group.setPermission(NodeFactory.make("group." + MigrationUtils.standardizeName(inherit)));
|
||||
}
|
||||
|
||||
// Migrate prefix and suffix
|
||||
@@ -117,25 +131,13 @@ public class MigrationBungeePerms extends SubCommand<Object> {
|
||||
String suffix = g.getSuffix();
|
||||
|
||||
if (prefix != null && !prefix.equals("")) {
|
||||
prefix = MetaUtils.escapeCharacters(prefix);
|
||||
try {
|
||||
group.setPermission("prefix.50." + prefix, true);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
group.setPermission(NodeFactory.makePrefixNode(groupWeight, prefix).build());
|
||||
}
|
||||
|
||||
if (suffix != null && !suffix.equals("")) {
|
||||
suffix = MetaUtils.escapeCharacters(suffix);
|
||||
try {
|
||||
group.setPermission("suffix.50." + suffix, true);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
group.setPermission(NodeFactory.makeSuffixNode(groupWeight, suffix).build());
|
||||
}
|
||||
|
||||
plugin.getStorage().saveGroup(group);
|
||||
|
||||
log.logAllProgress("Migrated {} groups so far.", groupCount.incrementAndGet());
|
||||
}
|
||||
log.log("Migrated " + groupCount.get() + " groups");
|
||||
@@ -143,6 +145,10 @@ public class MigrationBungeePerms extends SubCommand<Object> {
|
||||
// Migrate all users.
|
||||
log.log("Starting user migration.");
|
||||
AtomicInteger userCount = new AtomicInteger(0);
|
||||
|
||||
// Increment the max weight from the group migrations. All user meta should override.
|
||||
maxWeight += 5;
|
||||
|
||||
for (User u : bp.getPermissionsManager().getBackEnd().loadUsers()) {
|
||||
if (u.getUUID() == null) {
|
||||
log.logErr("Could not parse UUID for user: " + u.getName());
|
||||
@@ -150,47 +156,47 @@ public class MigrationBungeePerms extends SubCommand<Object> {
|
||||
}
|
||||
|
||||
// Make a LuckPerms user for the one being migrated.
|
||||
plugin.getStorage().loadUser(u.getUUID(), "null").join();
|
||||
plugin.getStorage().loadUser(u.getUUID(), u.getName()).join();
|
||||
me.lucko.luckperms.common.core.model.User user = plugin.getUserManager().get(u.getUUID());
|
||||
|
||||
// Migrate global perms
|
||||
for (String perm : u.getPerms()) {
|
||||
try {
|
||||
user.setPermission(perm, true);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
if (perm.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
user.setPermission(MigrationUtils.parseNode(perm, true).build());
|
||||
}
|
||||
|
||||
// Migrate per-server perms
|
||||
for (Map.Entry<String, Server> e : u.getServers().entrySet()) {
|
||||
for (String perm : e.getValue().getPerms()) {
|
||||
try {
|
||||
user.setPermission(perm, true, e.getKey());
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
if (perm.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
user.setPermission(MigrationUtils.parseNode(perm, true).setWorld(e.getKey()).build());
|
||||
}
|
||||
|
||||
// Migrate per-world perms
|
||||
for (Map.Entry<String, World> we : e.getValue().getWorlds().entrySet()) {
|
||||
for (String perm : we.getValue().getPerms()) {
|
||||
try {
|
||||
user.setPermission(perm, true, e.getKey(), we.getKey());
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
if (perm.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
user.setPermission(MigrationUtils.parseNode(perm, true).setServer(e.getKey()).setWorld(we.getKey()).build());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Migrate groups
|
||||
for (String group : u.getGroupsString()) {
|
||||
try {
|
||||
user.setPermission("group." + group, true);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
if (group.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
user.setPermission(NodeFactory.make("group." + MigrationUtils.standardizeName(group)));
|
||||
}
|
||||
|
||||
// Migrate prefix & suffix
|
||||
@@ -198,21 +204,10 @@ public class MigrationBungeePerms extends SubCommand<Object> {
|
||||
String suffix = u.getSuffix();
|
||||
|
||||
if (prefix != null && !prefix.equals("")) {
|
||||
prefix = MetaUtils.escapeCharacters(prefix);
|
||||
try {
|
||||
user.setPermission("prefix.100." + prefix, true);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
user.setPermission(NodeFactory.makePrefixNode(maxWeight, prefix).build());
|
||||
}
|
||||
|
||||
if (suffix != null && !suffix.equals("")) {
|
||||
suffix = MetaUtils.escapeCharacters(suffix);
|
||||
try {
|
||||
user.setPermission("suffix.100." + suffix, true);
|
||||
} catch (Exception ex) {
|
||||
log.handleException(ex);
|
||||
}
|
||||
user.setPermission(NodeFactory.makeSuffixNode(maxWeight, suffix).build());
|
||||
}
|
||||
|
||||
plugin.getStorage().saveUser(user);
|
||||
|
||||
@@ -26,22 +26,24 @@ apply-global-groups: true
|
||||
# If users on this server should have global (non-world specific) groups applied
|
||||
apply-global-world-groups: true
|
||||
|
||||
# If this server is in offline or online mode.
|
||||
# This setting allows a player to have the same UUID across a network of offline mode/mixed servers.
|
||||
# If UUIDs should be pulled from the server, or looked up by username based upon previous connections.
|
||||
#
|
||||
# You should generally reflect the setting in server.properties here. Except when...
|
||||
# This option should be set to true in most cases. When set to false, in order to get a player's UUID, LuckPerms will:
|
||||
# 1. Check if a player with the given username has joined before, if they have, use the UUID they used on their previous login.
|
||||
# 2. Save and return the players "current" uuid.
|
||||
#
|
||||
# 1. You have Spigot servers connected to a BungeeCord proxy, with online-mode set to false, but 'bungeecord' set to true in the spigot.yml
|
||||
# AND 'ip-forward' set to true in the BungeeCord config.yml
|
||||
# In this case, set online-mode in LuckPerms to true, despite the server being in offline mode.
|
||||
# For offline mode (cracked) servers, a players UUID is generated based upon their username.
|
||||
#
|
||||
# 2. You are only running one server instance using LuckPerms, (not a network)
|
||||
# In this case, set online-mode to true no matter what is set in server.properties. (we can just fallback to the servers uuid cache)
|
||||
# IMPORTANT:
|
||||
# If you are using BungeeCord proxy running in online mode, it is important that "online-mode=false" is set all backend server.properties, but
|
||||
# "bungeecord: true" is set in the spigot.yml. You also need to set "ip_forward: true" in BungeeCord's config.yml.
|
||||
# If for whatever reason you are not able to do this, and do not have ip-forward enabled, then you may need to set "use-server-uuids" to false.
|
||||
#
|
||||
# 3. If your proxy is running in offline mode, and you are using PaperSpigot (https://ci.destroystokyo.com/job/PaperSpigot/),
|
||||
# you should set "bungee-online-mode" to false in the paper.yml, and set "online-mode" to true in all LuckPerms configs.
|
||||
# This approach is thoroughly recommended for offline mode networks.
|
||||
online-mode: true
|
||||
# If your proxy is running in offline mode, you should still be setting up ip-forwarding as described above, but may also find that you need to set
|
||||
# "bungee-online-mode" to false in paper.yml, if you are using PaperSpigot. (https://ci.destroystokyo.com/job/PaperSpigot/)
|
||||
#
|
||||
# This option should always be set to true on the BungeeCord side. Don't change unless you're sure you know what you're doing.
|
||||
use-server-uuids: true
|
||||
|
||||
# If the plugin should send log notifications to users whenever permissions are modified.
|
||||
log-notify: true
|
||||
@@ -64,6 +66,14 @@ group-name-rewrite:
|
||||
# If "deny": the command will just fail if you try to add another node with the same expiry
|
||||
temporary-add-behaviour: deny
|
||||
|
||||
# How should LuckPerms determine a users "primary" group.
|
||||
#
|
||||
# Available Options:
|
||||
# -> stored use the value stored against the users record in the file/database
|
||||
# -> parents-by-weight just use the users most highly weighted parent
|
||||
# -> all-parents-by-weight same as above, but calculates based upon all parents inherits from both directly and indirectly
|
||||
primary-group-calculation: stored
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -130,10 +140,20 @@ meta-formatting:
|
||||
# +------------------------------------------------------------------------+ #
|
||||
|
||||
# Which storage method the plugin should use.
|
||||
# Currently supported: mysql, postgresql, sqlite, h2, json, yaml, mongodb
|
||||
# Fill out connection info below if you're using MySQL, PostgreSQL or MongoDB
|
||||
#
|
||||
# See: https://github.com/lucko/LuckPerms/wiki/Choosing-a-Storage-type
|
||||
# Currently supported: mysql, mariadb, postgresql, sqlite, h2, json, yaml, mongodb
|
||||
|
||||
# Fill out connection info below if you're using MySQL, MariaDB, PostgreSQL or MongoDB
|
||||
# If your MySQL server supports it, the "mariadb" option is preferred over "mysql".
|
||||
storage-method: h2
|
||||
|
||||
# When using a file-based storage type, LuckPerms can monitor the data files for changes, and then schedule automatic
|
||||
# updates when changes are detected.
|
||||
#
|
||||
# If you don't want this to happen, set this option to false.
|
||||
watch-files: true
|
||||
|
||||
# This block enables support for split datastores.
|
||||
split-storage:
|
||||
enabled: false
|
||||
@@ -159,9 +179,14 @@ data:
|
||||
# This should *not* be set to "lp_" if you have previously ran LuckPerms v2.16.81 or earlier with this database.
|
||||
table_prefix: 'luckperms_'
|
||||
|
||||
# Set to -1 to disable. If this is the only instance accessing the datastore, you can disable syncing.
|
||||
# e.g. if you're using sqlite or flatfile, this can be set to -1 to save resources.
|
||||
sync-minutes: 3
|
||||
# This option controls how frequently LuckPerms will perform a sync task.
|
||||
# A sync task will refresh all data from the storage, and ensure that the most up-to-date data is being used by the plugin.
|
||||
#
|
||||
# This is disabled by default, as most users will not need it. However, if you're using a remote storage type
|
||||
# without a messaging service setup, you may wish to set this value to something like 3.
|
||||
#
|
||||
# Set to -1 to disable the task completely.
|
||||
sync-minutes: -1
|
||||
|
||||
# Settings for the messaging service
|
||||
#
|
||||
@@ -178,6 +203,9 @@ data:
|
||||
# none ==> nothing
|
||||
messaging-service: none
|
||||
|
||||
# If LuckPerms should automatically push updates after a change has been made with a command.
|
||||
auto-push-updates: true
|
||||
|
||||
# Settings for Redis.
|
||||
# Port 6379 is used by default; set address to "host:port" if differs
|
||||
redis:
|
||||
|
||||
@@ -3,4 +3,3 @@ version: ${release.version}.${patch.version}
|
||||
description: A permissions plugin
|
||||
author: Luck
|
||||
main: me.lucko.luckperms.bungee.LPBungeePlugin
|
||||
softdepends: [PowerfulPerms] # For migration
|
||||
+15
-5
@@ -5,17 +5,20 @@
|
||||
<parent>
|
||||
<artifactId>luckperms</artifactId>
|
||||
<groupId>me.lucko.luckperms</groupId>
|
||||
<version>3.0-SNAPSHOT</version>
|
||||
<version>3.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>luckperms-common</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<build>
|
||||
<finalName>LuckPerms-Common-${release.version}.${patch.version}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<version>${compiler.version}</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
@@ -36,7 +39,7 @@
|
||||
<dependency>
|
||||
<groupId>io.github.mkremins</groupId>
|
||||
<artifactId>fanciful</artifactId>
|
||||
<version>1.2.0</version>
|
||||
<version>1.2.5</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- MySQL -->
|
||||
@@ -50,7 +53,7 @@
|
||||
<dependency>
|
||||
<groupId>com.zaxxer</groupId>
|
||||
<artifactId>HikariCP</artifactId>
|
||||
<version>2.5.1</version>
|
||||
<version>2.6.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Jedis -->
|
||||
@@ -116,11 +119,18 @@
|
||||
<version>19.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- caffeine -->
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
<version>2.4.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Lombok -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.16.10</version>
|
||||
<version>${lombok.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@@ -42,10 +42,11 @@ import me.lucko.luckperms.api.context.ContextCalculator;
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
import me.lucko.luckperms.common.api.delegates.NodeFactoryDelegate;
|
||||
import me.lucko.luckperms.common.api.delegates.UserDelegate;
|
||||
import me.lucko.luckperms.common.core.NodeBuilder;
|
||||
import me.lucko.luckperms.common.core.UserIdentifier;
|
||||
import me.lucko.luckperms.common.event.EventFactory;
|
||||
import me.lucko.luckperms.common.event.LuckPermsEventBus;
|
||||
import me.lucko.luckperms.common.messaging.InternalMessagingService;
|
||||
import me.lucko.luckperms.common.messaging.NoopMessagingService;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
|
||||
import java.util.Optional;
|
||||
@@ -78,7 +79,7 @@ public class ApiProvider implements LuckPermsApi {
|
||||
|
||||
@Override
|
||||
public double getApiVersion() {
|
||||
return 3.0;
|
||||
return 3.1;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -103,7 +104,8 @@ public class ApiProvider implements LuckPermsApi {
|
||||
|
||||
@Override
|
||||
public Optional<MessagingService> getMessagingService() {
|
||||
return Optional.ofNullable(plugin.getMessagingService());
|
||||
InternalMessagingService service = plugin.getMessagingService();
|
||||
return service instanceof NoopMessagingService ? Optional.empty() : Optional.of(service);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -150,8 +152,7 @@ public class ApiProvider implements LuckPermsApi {
|
||||
|
||||
@Override
|
||||
public void cleanupUser(@NonNull User user) {
|
||||
ApiUtils.checkUser(user);
|
||||
plugin.getUserManager().cleanup(((UserDelegate) user).getMaster());
|
||||
plugin.getUserManager().cleanup(UserDelegate.cast(user));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -203,7 +204,7 @@ public class ApiProvider implements LuckPermsApi {
|
||||
|
||||
@Override
|
||||
public Node.Builder buildNode(@NonNull String permission) throws IllegalArgumentException {
|
||||
return new NodeBuilder(permission);
|
||||
return me.lucko.luckperms.common.core.NodeFactory.newBuilder(permission);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -214,8 +215,7 @@ public class ApiProvider implements LuckPermsApi {
|
||||
|
||||
@Override
|
||||
public Optional<Contexts> getContextForUser(User user) {
|
||||
ApiUtils.checkUser(user);
|
||||
return Optional.ofNullable(plugin.getContextForUser(((UserDelegate) user).getMaster()));
|
||||
return Optional.ofNullable(plugin.getContextForUser(UserDelegate.cast(user)));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@@ -26,29 +26,11 @@ import lombok.experimental.UtilityClass;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import me.lucko.luckperms.api.Group;
|
||||
import me.lucko.luckperms.api.Track;
|
||||
import me.lucko.luckperms.api.User;
|
||||
import me.lucko.luckperms.common.api.delegates.GroupDelegate;
|
||||
import me.lucko.luckperms.common.api.delegates.TrackDelegate;
|
||||
import me.lucko.luckperms.common.api.delegates.UserDelegate;
|
||||
import me.lucko.luckperms.common.utils.ArgumentChecker;
|
||||
|
||||
@UtilityClass
|
||||
public class ApiUtils {
|
||||
|
||||
public static void checkUser(User user) {
|
||||
Preconditions.checkState(user instanceof UserDelegate, "User instance cannot be handled by this implementation.");
|
||||
}
|
||||
|
||||
public static void checkGroup(Group group) {
|
||||
Preconditions.checkState(group instanceof GroupDelegate, "Group instance cannot be handled by this implementation.");
|
||||
}
|
||||
|
||||
public static void checkTrack(Track track) {
|
||||
Preconditions.checkState(track instanceof TrackDelegate, "Track instance cannot be handled by this implementation.");
|
||||
}
|
||||
|
||||
public static String checkUsername(String s) {
|
||||
Preconditions.checkArgument(
|
||||
!ArgumentChecker.checkUsername(s),
|
||||
|
||||
@@ -23,150 +23,166 @@
|
||||
package me.lucko.luckperms.common.api.delegates;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import me.lucko.luckperms.api.Group;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.common.core.NodeFactory;
|
||||
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
|
||||
import me.lucko.luckperms.exceptions.ObjectLacksException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static me.lucko.luckperms.common.api.ApiUtils.checkGroup;
|
||||
import static me.lucko.luckperms.common.api.ApiUtils.checkTime;
|
||||
|
||||
/**
|
||||
* Provides a link between {@link Group} and {@link me.lucko.luckperms.common.core.model.Group}
|
||||
*/
|
||||
@EqualsAndHashCode(of = {"name"}, callSuper = false)
|
||||
public class GroupDelegate extends PermissionHolderDelegate implements Group {
|
||||
public final class GroupDelegate extends PermissionHolderDelegate implements Group {
|
||||
public static me.lucko.luckperms.common.core.model.Group cast(Group g) {
|
||||
Preconditions.checkState(g instanceof GroupDelegate, "Illegal instance " + g.getClass() + " cannot be handled by this implementation.");
|
||||
return ((GroupDelegate) g).getHandle();
|
||||
}
|
||||
|
||||
@Getter(AccessLevel.PACKAGE)
|
||||
private final me.lucko.luckperms.common.core.model.Group master;
|
||||
private final me.lucko.luckperms.common.core.model.Group handle;
|
||||
|
||||
@Getter
|
||||
private final String name;
|
||||
public GroupDelegate(@NonNull me.lucko.luckperms.common.core.model.Group handle) {
|
||||
super(handle);
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
public GroupDelegate(@NonNull me.lucko.luckperms.common.core.model.Group master) {
|
||||
super(master);
|
||||
this.master = master;
|
||||
this.name = master.getName();
|
||||
@Override
|
||||
public String getName() {
|
||||
return handle.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inheritsGroup(@NonNull Group group) {
|
||||
checkGroup(group);
|
||||
return master.inheritsGroup(((GroupDelegate) group).getMaster());
|
||||
return handle.inheritsGroup(cast(group));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inheritsGroup(@NonNull Group group, @NonNull String server) {
|
||||
checkGroup(group);
|
||||
return master.inheritsGroup(((GroupDelegate) group).getMaster(), server);
|
||||
return handle.inheritsGroup(((GroupDelegate) group).getHandle(), server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inheritsGroup(@NonNull Group group, @NonNull String server, @NonNull String world) {
|
||||
checkGroup(group);
|
||||
return master.inheritsGroup(((GroupDelegate) group).getMaster(), server, world);
|
||||
return handle.inheritsGroup(cast(group), server, world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInheritGroup(@NonNull Group group) throws ObjectAlreadyHasException {
|
||||
checkGroup(group);
|
||||
master.setInheritGroup(((GroupDelegate) group).getMaster());
|
||||
handle.setPermission(NodeFactory.make(cast(group))).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInheritGroup(@NonNull Group group, @NonNull String server) throws ObjectAlreadyHasException {
|
||||
checkGroup(group);
|
||||
master.setInheritGroup(((GroupDelegate) group).getMaster(), server);
|
||||
handle.setPermission(NodeFactory.make(cast(group), server)).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInheritGroup(@NonNull Group group, @NonNull String server, @NonNull String world) throws ObjectAlreadyHasException {
|
||||
checkGroup(group);
|
||||
master.setInheritGroup(((GroupDelegate) group).getMaster(), server, world);
|
||||
handle.setPermission(NodeFactory.make(cast(group), server, world)).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInheritGroup(@NonNull Group group, @NonNull long expireAt) throws ObjectAlreadyHasException {
|
||||
checkGroup(group);
|
||||
master.setInheritGroup(((GroupDelegate) group).getMaster(), checkTime(expireAt));
|
||||
handle.setPermission(NodeFactory.make(cast(group), checkTime(expireAt))).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInheritGroup(@NonNull Group group, @NonNull String server, @NonNull long expireAt) throws ObjectAlreadyHasException {
|
||||
checkGroup(group);
|
||||
master.setInheritGroup(((GroupDelegate) group).getMaster(), server, checkTime(expireAt));
|
||||
handle.setPermission(NodeFactory.make(cast(group), server, checkTime(expireAt))).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInheritGroup(@NonNull Group group, @NonNull String server, @NonNull String world, @NonNull long expireAt) throws ObjectAlreadyHasException {
|
||||
checkGroup(group);
|
||||
master.setInheritGroup(((GroupDelegate) group).getMaster(), server, world, checkTime(expireAt));
|
||||
handle.setPermission(NodeFactory.make(cast(group), server, world, checkTime(expireAt))).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetInheritGroup(@NonNull Group group) throws ObjectLacksException {
|
||||
checkGroup(group);
|
||||
master.unsetInheritGroup(((GroupDelegate) group).getMaster());
|
||||
handle.unsetPermission(NodeFactory.make(cast(group))).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetInheritGroup(@NonNull Group group, @NonNull boolean temporary) throws ObjectLacksException {
|
||||
checkGroup(group);
|
||||
master.unsetInheritGroup(((GroupDelegate) group).getMaster(), temporary);
|
||||
handle.unsetPermission(NodeFactory.make(cast(group), temporary)).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetInheritGroup(@NonNull Group group, @NonNull String server) throws ObjectLacksException {
|
||||
checkGroup(group);
|
||||
master.unsetInheritGroup(((GroupDelegate) group).getMaster(), server);
|
||||
handle.unsetPermission(NodeFactory.make(cast(group), server)).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetInheritGroup(@NonNull Group group, @NonNull String server, @NonNull String world) throws ObjectLacksException {
|
||||
checkGroup(group);
|
||||
master.unsetInheritGroup(((GroupDelegate) group).getMaster(), server, world);
|
||||
handle.unsetPermission(NodeFactory.make(cast(group), server, world)).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetInheritGroup(@NonNull Group group, @NonNull String server, @NonNull boolean temporary) throws ObjectLacksException {
|
||||
checkGroup(group);
|
||||
master.unsetInheritGroup(((GroupDelegate) group).getMaster(), server, temporary);
|
||||
handle.unsetPermission(NodeFactory.make(cast(group), server, temporary)).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetInheritGroup(@NonNull Group group, @NonNull String server, @NonNull String world, @NonNull boolean temporary) throws ObjectLacksException {
|
||||
checkGroup(group);
|
||||
master.unsetInheritGroup(((GroupDelegate) group).getMaster(), server, world, temporary);
|
||||
handle.unsetPermission(NodeFactory.make(cast(group), server, world, temporary)).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearNodes() {
|
||||
master.clearNodes();
|
||||
handle.clearNodes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getGroupNames() {
|
||||
return master.getGroupNames();
|
||||
return handle.mergePermissionsToList().stream()
|
||||
.filter(Node::isGroupNode)
|
||||
.map(Node::getGroupName)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getLocalGroups(@NonNull String server, @NonNull String world) {
|
||||
return master.getLocalGroups(server, world);
|
||||
return handle.mergePermissionsToList().stream()
|
||||
.filter(Node::isGroupNode)
|
||||
.filter(n -> n.shouldApplyOnWorld(world, false, true))
|
||||
.filter(n -> n.shouldApplyOnServer(server, false, true))
|
||||
.map(Node::getGroupName)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public OptionalInt getWeight() {
|
||||
return master.getWeight();
|
||||
return handle.getWeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getLocalGroups(@NonNull String server) {
|
||||
return master.getLocalGroups(server);
|
||||
return handle.mergePermissionsToList().stream()
|
||||
.filter(Node::isGroupNode)
|
||||
.filter(n -> n.shouldApplyOnServer(server, false, true))
|
||||
.map(Node::getGroupName)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) return true;
|
||||
if (!(o instanceof GroupDelegate)) return false;
|
||||
|
||||
GroupDelegate other = (GroupDelegate) o;
|
||||
return this.getName() == null ? other.getName() == null : this.getName().equals(other.getName());
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.getName().hashCode();
|
||||
}
|
||||
}
|
||||
+21
-21
@@ -36,105 +36,105 @@ import java.util.Map;
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
public class LPConfigurationDelegate implements LPConfiguration {
|
||||
private final LuckPermsConfiguration master;
|
||||
private final LuckPermsConfiguration handle;
|
||||
|
||||
@Override
|
||||
public String getServer() {
|
||||
return master.get(ConfigKeys.SERVER);
|
||||
return handle.get(ConfigKeys.SERVER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSyncTime() {
|
||||
return master.get(ConfigKeys.SYNC_TIME);
|
||||
return handle.get(ConfigKeys.SYNC_TIME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getIncludeGlobalPerms() {
|
||||
return master.get(ConfigKeys.INCLUDING_GLOBAL_PERMS);
|
||||
return handle.get(ConfigKeys.INCLUDING_GLOBAL_PERMS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getIncludeGlobalWorldPerms() {
|
||||
return master.get(ConfigKeys.INCLUDING_GLOBAL_WORLD_PERMS);
|
||||
return handle.get(ConfigKeys.INCLUDING_GLOBAL_WORLD_PERMS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getApplyGlobalGroups() {
|
||||
return master.get(ConfigKeys.APPLYING_GLOBAL_GROUPS);
|
||||
return handle.get(ConfigKeys.APPLYING_GLOBAL_GROUPS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getApplyGlobalWorldGroups() {
|
||||
return master.get(ConfigKeys.APPLYING_GLOBAL_WORLD_GROUPS);
|
||||
return handle.get(ConfigKeys.APPLYING_GLOBAL_WORLD_GROUPS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getOnlineMode() {
|
||||
return master.get(ConfigKeys.ONLINE_MODE);
|
||||
return handle.get(ConfigKeys.USE_SERVER_UUIDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getApplyWildcards() {
|
||||
return master.get(ConfigKeys.APPLYING_WILDCARDS);
|
||||
return handle.get(ConfigKeys.APPLYING_WILDCARDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getApplyRegex() {
|
||||
return master.get(ConfigKeys.APPLYING_REGEX);
|
||||
return handle.get(ConfigKeys.APPLYING_REGEX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getApplyShorthand() {
|
||||
return master.get(ConfigKeys.APPLYING_SHORTHAND);
|
||||
return handle.get(ConfigKeys.APPLYING_SHORTHAND);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getLogNotify() {
|
||||
return master.get(ConfigKeys.LOG_NOTIFY);
|
||||
return handle.get(ConfigKeys.LOG_NOTIFY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getEnableOps() {
|
||||
return master.get(ConfigKeys.OPS_ENABLED);
|
||||
return handle.get(ConfigKeys.OPS_ENABLED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getCommandsAllowOp() {
|
||||
return master.get(ConfigKeys.COMMANDS_ALLOW_OP);
|
||||
return handle.get(ConfigKeys.COMMANDS_ALLOW_OP);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getAutoOp() {
|
||||
return master.get(ConfigKeys.AUTO_OP);
|
||||
return handle.get(ConfigKeys.AUTO_OP);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVaultServer() {
|
||||
return master.get(ConfigKeys.VAULT_SERVER);
|
||||
return handle.get(ConfigKeys.VAULT_SERVER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getVaultIncludeGlobal() {
|
||||
return master.get(ConfigKeys.VAULT_INCLUDING_GLOBAL);
|
||||
return handle.get(ConfigKeys.VAULT_INCLUDING_GLOBAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DatastoreConfiguration getDatastoreConfig() {
|
||||
return master.get(ConfigKeys.DATABASE_VALUES);
|
||||
return handle.get(ConfigKeys.DATABASE_VALUES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStorageMethod() {
|
||||
return master.get(ConfigKeys.STORAGE_METHOD);
|
||||
return handle.get(ConfigKeys.STORAGE_METHOD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getSplitStorage() {
|
||||
return master.get(ConfigKeys.SPLIT_STORAGE);
|
||||
return handle.get(ConfigKeys.SPLIT_STORAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getSplitStorageOptions() {
|
||||
return master.get(ConfigKeys.SPLIT_STORAGE_OPTIONS);
|
||||
return handle.get(ConfigKeys.SPLIT_STORAGE_OPTIONS);
|
||||
}
|
||||
}
|
||||
@@ -39,100 +39,100 @@ import static me.lucko.luckperms.common.api.ApiUtils.checkName;
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
public class LogDelegate implements Log {
|
||||
private final me.lucko.luckperms.common.data.Log master;
|
||||
private final me.lucko.luckperms.common.data.Log handle;
|
||||
|
||||
@Override
|
||||
public SortedSet<LogEntry> getContent() {
|
||||
return master.getContent();
|
||||
return handle.getContent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedSet<LogEntry> getRecent() {
|
||||
return master.getRecent();
|
||||
return handle.getRecent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMap<Integer, LogEntry> getRecent(int pageNo) {
|
||||
return master.getRecent(pageNo);
|
||||
return handle.getRecent(pageNo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRecentMaxPages() {
|
||||
return master.getRecentMaxPages();
|
||||
return handle.getRecentMaxPages();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedSet<LogEntry> getRecent(@NonNull UUID actor) {
|
||||
return master.getRecent(actor);
|
||||
return handle.getRecent(actor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMap<Integer, LogEntry> getRecent(int pageNo, @NonNull UUID actor) {
|
||||
return master.getRecent(pageNo, actor);
|
||||
return handle.getRecent(pageNo, actor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRecentMaxPages(@NonNull UUID actor) {
|
||||
return master.getRecentMaxPages(actor);
|
||||
return handle.getRecentMaxPages(actor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedSet<LogEntry> getUserHistory(@NonNull UUID uuid) {
|
||||
return master.getUserHistory(uuid);
|
||||
return handle.getUserHistory(uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMap<Integer, LogEntry> getUserHistory(int pageNo, @NonNull UUID uuid) {
|
||||
return master.getUserHistory(pageNo, uuid);
|
||||
return handle.getUserHistory(pageNo, uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUserHistoryMaxPages(@NonNull UUID uuid) {
|
||||
return master.getUserHistoryMaxPages(uuid);
|
||||
return handle.getUserHistoryMaxPages(uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedSet<LogEntry> getGroupHistory(@NonNull String name) {
|
||||
return master.getGroupHistory(checkName(name));
|
||||
return handle.getGroupHistory(checkName(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMap<Integer, LogEntry> getGroupHistory(int pageNo, @NonNull String name) {
|
||||
return master.getGroupHistory(pageNo, checkName(name));
|
||||
return handle.getGroupHistory(pageNo, checkName(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGroupHistoryMaxPages(@NonNull String name) {
|
||||
return master.getGroupHistoryMaxPages(checkName(name));
|
||||
return handle.getGroupHistoryMaxPages(checkName(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedSet<LogEntry> getTrackHistory(@NonNull String name) {
|
||||
return master.getTrackHistory(checkName(name));
|
||||
return handle.getTrackHistory(checkName(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMap<Integer, LogEntry> getTrackHistory(int pageNo, @NonNull String name) {
|
||||
return master.getTrackHistory(pageNo, checkName(name));
|
||||
return handle.getTrackHistory(pageNo, checkName(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTrackHistoryMaxPages(@NonNull String name) {
|
||||
return master.getTrackHistoryMaxPages(checkName(name));
|
||||
return handle.getTrackHistoryMaxPages(checkName(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedSet<LogEntry> getSearch(@NonNull String query) {
|
||||
return master.getSearch(query);
|
||||
return handle.getSearch(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMap<Integer, LogEntry> getSearch(int pageNo, @NonNull String query) {
|
||||
return master.getSearch(pageNo, query);
|
||||
return handle.getSearch(pageNo, query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSearchMaxPages(@NonNull String query) {
|
||||
return master.getSearchMaxPages(query);
|
||||
return handle.getSearchMaxPages(query);
|
||||
}
|
||||
}
|
||||
+8
-2
@@ -24,6 +24,7 @@ package me.lucko.luckperms.common.api.delegates;
|
||||
|
||||
import lombok.NonNull;
|
||||
|
||||
import me.lucko.luckperms.api.Group;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.common.core.NodeFactory;
|
||||
|
||||
@@ -32,7 +33,7 @@ public class NodeFactoryDelegate implements me.lucko.luckperms.api.NodeFactory {
|
||||
|
||||
@Override
|
||||
public Node fromSerialisedNode(@NonNull String serialisedPermission, boolean value) {
|
||||
return NodeFactory.fromSerialisedNode(serialisedPermission, value);
|
||||
return NodeFactory.fromSerializedNode(serialisedPermission, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -47,7 +48,12 @@ public class NodeFactoryDelegate implements me.lucko.luckperms.api.NodeFactory {
|
||||
|
||||
@Override
|
||||
public Node.Builder newBuilderFromSerialisedNode(@NonNull String serialisedPermission, boolean value) {
|
||||
return NodeFactory.builderFromSerialisedNode(serialisedPermission, value);
|
||||
return NodeFactory.builderFromSerializedNode(serialisedPermission, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node.Builder makeGroupNode(Group group) {
|
||||
return NodeFactory.newBuilder("group." + GroupDelegate.cast(group).getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+123
-54
@@ -29,10 +29,13 @@ import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.DataMutateResult;
|
||||
import me.lucko.luckperms.api.LocalizedNode;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.api.PermissionHolder;
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.common.core.NodeFactory;
|
||||
import me.lucko.luckperms.common.utils.ExtractedContexts;
|
||||
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
|
||||
import me.lucko.luckperms.exceptions.ObjectLacksException;
|
||||
@@ -49,269 +52,335 @@ import static me.lucko.luckperms.common.api.ApiUtils.checkTime;
|
||||
/**
|
||||
* Provides a link between {@link PermissionHolder} and {@link me.lucko.luckperms.common.core.model.PermissionHolder}
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@AllArgsConstructor
|
||||
public class PermissionHolderDelegate implements PermissionHolder {
|
||||
private final me.lucko.luckperms.common.core.model.PermissionHolder master;
|
||||
private final me.lucko.luckperms.common.core.model.PermissionHolder handle;
|
||||
|
||||
@Override
|
||||
public String getObjectName() {
|
||||
return master.getObjectName();
|
||||
return handle.getObjectName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedSet<? extends Node> getPermissions() {
|
||||
return ImmutableSortedSet.copyOfSorted(master.getPermissions(false));
|
||||
return ImmutableSortedSet.copyOfSorted(handle.mergePermissionsToSortedSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Node> getEnduringPermissions() {
|
||||
return ImmutableSet.copyOf(master.getNodes());
|
||||
return ImmutableSet.copyOf(handle.getNodes().values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Node> getTransientPermissions() {
|
||||
return ImmutableSet.copyOf(master.getTransientNodes());
|
||||
return ImmutableSet.copyOf(handle.getTransientNodes().values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedSet<LocalizedNode> getAllNodes(@NonNull Contexts contexts) {
|
||||
return new TreeSet<>(master.getAllNodes(null, ExtractedContexts.generate(contexts)));
|
||||
return new TreeSet<>(handle.resolveInheritancesAlmostEqual(ExtractedContexts.generate(contexts)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<LocalizedNode> getAllNodesFiltered(@NonNull Contexts contexts) {
|
||||
return new HashSet<>(master.getAllNodesFiltered(ExtractedContexts.generate(contexts)));
|
||||
return new HashSet<>(handle.getAllNodes(ExtractedContexts.generate(contexts)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Boolean> exportNodes(Contexts contexts, boolean lowerCase) {
|
||||
return new HashMap<>(master.exportNodes(contexts, lowerCase));
|
||||
return new HashMap<>(handle.exportNodes(ExtractedContexts.generate(contexts), lowerCase));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tristate hasPermission(@NonNull Node node) {
|
||||
return master.hasPermission(node, false);
|
||||
return handle.hasPermission(node, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tristate hasTransientPermission(@NonNull Node node) {
|
||||
return master.hasPermission(node, true);
|
||||
return handle.hasPermission(node, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(@NonNull String node, @NonNull boolean b) {
|
||||
return master.hasPermission(node, b);
|
||||
return handle.hasPermission(node, b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(@NonNull String node, @NonNull boolean b, @NonNull String server) {
|
||||
return master.hasPermission(node, b, server);
|
||||
return handle.hasPermission(node, b, server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(@NonNull String node, @NonNull boolean b, @NonNull String server, @NonNull String world) {
|
||||
return master.hasPermission(node, b, server, world);
|
||||
return handle.hasPermission(node, b, server, world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(@NonNull String node, @NonNull boolean b, @NonNull boolean temporary) {
|
||||
return master.hasPermission(node, b, temporary);
|
||||
return handle.hasPermission(node, b, temporary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(@NonNull String node, @NonNull boolean b, @NonNull String server, @NonNull boolean temporary) {
|
||||
return master.hasPermission(node, b, server, temporary);
|
||||
return handle.hasPermission(node, b, server, temporary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(@NonNull String node, @NonNull boolean b, @NonNull String server, @NonNull String world, @NonNull boolean temporary) {
|
||||
return master.hasPermission(node, b, server, world, temporary);
|
||||
return handle.hasPermission(node, b, server, world, temporary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tristate inheritsPermission(@NonNull Node node) {
|
||||
return master.inheritsPermission(node);
|
||||
return handle.inheritsPermission(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inheritsPermission(@NonNull String node, @NonNull boolean b) {
|
||||
return master.inheritsPermission(node, b);
|
||||
return handle.inheritsPermission(node, b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inheritsPermission(@NonNull String node, @NonNull boolean b, @NonNull String server) {
|
||||
return master.inheritsPermission(node, b, server);
|
||||
return handle.inheritsPermission(node, b, server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inheritsPermission(@NonNull String node, @NonNull boolean b, @NonNull String server, @NonNull String world) {
|
||||
return master.inheritsPermission(node, b, server, world);
|
||||
return handle.inheritsPermission(node, b, server, world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inheritsPermission(@NonNull String node, @NonNull boolean b, @NonNull boolean temporary) {
|
||||
return master.inheritsPermission(node, b, temporary);
|
||||
return handle.inheritsPermission(node, b, temporary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inheritsPermission(@NonNull String node, @NonNull boolean b, @NonNull String server, @NonNull boolean temporary) {
|
||||
return master.inheritsPermission(node, b, server, temporary);
|
||||
return handle.inheritsPermission(node, b, server, temporary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inheritsPermission(@NonNull String node, @NonNull boolean b, @NonNull String server, @NonNull String world, @NonNull boolean temporary) {
|
||||
return master.inheritsPermission(node, b, server, world, temporary);
|
||||
return handle.inheritsPermission(node, b, server, world, temporary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPermission(@NonNull Node node) throws ObjectAlreadyHasException {
|
||||
master.setPermission(node);
|
||||
handle.setPermission(node).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataMutateResult setPermissionUnchecked(Node node) {
|
||||
return handle.setPermission(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTransientPermission(@NonNull Node node) throws ObjectAlreadyHasException {
|
||||
master.setTransientPermission(node);
|
||||
handle.setTransientPermission(node).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataMutateResult setTransientPermissionUnchecked(Node node) {
|
||||
return handle.setTransientPermission(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPermission(@NonNull String node, @NonNull boolean value) throws ObjectAlreadyHasException {
|
||||
master.setPermission(node, value);
|
||||
handle.setPermission(NodeFactory.make(node, value)).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPermission(@NonNull String node, @NonNull boolean value, @NonNull String server) throws ObjectAlreadyHasException {
|
||||
master.setPermission(node, value, server);
|
||||
handle.setPermission(NodeFactory.make(node, value, server)).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPermission(@NonNull String node, @NonNull boolean value, @NonNull String server, @NonNull String world) throws ObjectAlreadyHasException {
|
||||
master.setPermission(node, value, server, world);
|
||||
handle.setPermission(NodeFactory.make(node, value, server, world)).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPermission(@NonNull String node, @NonNull boolean value, @NonNull long expireAt) throws ObjectAlreadyHasException {
|
||||
master.setPermission(node, value, checkTime(expireAt));
|
||||
handle.setPermission(NodeFactory.make(node, value, checkTime(expireAt))).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPermission(@NonNull String node, @NonNull boolean value, @NonNull String server, @NonNull long expireAt) throws ObjectAlreadyHasException {
|
||||
master.setPermission(node, value, server, checkTime(expireAt));
|
||||
handle.setPermission(NodeFactory.make(node, value, server, checkTime(expireAt))).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPermission(@NonNull String node, @NonNull boolean value, @NonNull String server, @NonNull String world, @NonNull long expireAt) throws ObjectAlreadyHasException {
|
||||
master.setPermission(node, value, server, world, checkTime(expireAt));
|
||||
handle.setPermission(NodeFactory.make(node, value, server, world, checkTime(expireAt))).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetPermission(@NonNull Node node) throws ObjectLacksException {
|
||||
master.unsetPermission(node);
|
||||
handle.unsetPermission(node).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataMutateResult unsetPermissionUnchecked(Node node) {
|
||||
return handle.unsetPermission(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetTransientPermission(@NonNull Node node) throws ObjectLacksException {
|
||||
master.unsetTransientPermission(node);
|
||||
handle.unsetTransientPermission(node).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataMutateResult unsetTransientPermissionUnchecked(Node node) {
|
||||
return handle.unsetTransientPermission(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetPermission(@NonNull String node, @NonNull boolean temporary) throws ObjectLacksException {
|
||||
master.unsetPermission(node, temporary);
|
||||
handle.unsetPermission(NodeFactory.make(node, temporary)).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetPermission(@NonNull String node) throws ObjectLacksException {
|
||||
master.unsetPermission(node);
|
||||
handle.unsetPermission(NodeFactory.make(node)).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetPermission(@NonNull String node, @NonNull String server) throws ObjectLacksException {
|
||||
master.unsetPermission(node, server);
|
||||
handle.unsetPermission(NodeFactory.make(node, server)).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetPermission(@NonNull String node, @NonNull String server, @NonNull String world) throws ObjectLacksException {
|
||||
master.unsetPermission(node, server, world);
|
||||
handle.unsetPermission(NodeFactory.make(node, server, world)).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetPermission(@NonNull String node, @NonNull String server, @NonNull boolean temporary) throws ObjectLacksException {
|
||||
master.unsetPermission(node, server, temporary);
|
||||
handle.unsetPermission(NodeFactory.make(node, server, temporary)).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetPermission(@NonNull String node, @NonNull String server, @NonNull String world, @NonNull boolean temporary) throws ObjectLacksException {
|
||||
master.unsetPermission(node, server, world, temporary);
|
||||
handle.unsetPermission(NodeFactory.make(node, server, world, temporary)).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearNodes() {
|
||||
master.clearNodes();
|
||||
handle.clearNodes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearNodes(String server) {
|
||||
master.clearNodes(server);
|
||||
MutableContextSet set = new MutableContextSet();
|
||||
if (server != null) {
|
||||
set.add("server", server);
|
||||
}
|
||||
|
||||
handle.clearNodes(set);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearNodes(String server, String world) {
|
||||
master.clearNodes(server, world);
|
||||
MutableContextSet set = new MutableContextSet();
|
||||
if (server != null) {
|
||||
set.add("server", server);
|
||||
}
|
||||
if (world != null) {
|
||||
set.add("world", world);
|
||||
}
|
||||
|
||||
handle.clearNodes(set);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearParents() {
|
||||
master.clearParents();
|
||||
handle.clearParents(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearParents(String server) {
|
||||
master.clearParents(server);
|
||||
MutableContextSet set = new MutableContextSet();
|
||||
if (server != null) {
|
||||
set.add("server", server);
|
||||
}
|
||||
|
||||
handle.clearParents(set, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearParents(String server, String world) {
|
||||
master.clearParents(server, world);
|
||||
MutableContextSet set = new MutableContextSet();
|
||||
if (server != null) {
|
||||
set.add("server", server);
|
||||
}
|
||||
if (world != null) {
|
||||
set.add("world", world);
|
||||
}
|
||||
|
||||
handle.clearParents(set, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearMeta() {
|
||||
master.clearMeta();
|
||||
handle.clearMeta();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearMeta(String server) {
|
||||
master.clearMeta(server);
|
||||
MutableContextSet set = new MutableContextSet();
|
||||
if (server != null) {
|
||||
set.add("server", server);
|
||||
}
|
||||
|
||||
handle.clearMeta(set);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearMeta(String server, String world) {
|
||||
master.clearMeta(server, world);
|
||||
MutableContextSet set = new MutableContextSet();
|
||||
if (server != null) {
|
||||
set.add("server", server);
|
||||
}
|
||||
if (world != null) {
|
||||
set.add("world", world);
|
||||
}
|
||||
|
||||
handle.clearMeta(set);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearMetaKeys(String key, String server, String world, boolean temporary) {
|
||||
master.clearMetaKeys(key, server, world, temporary);
|
||||
MutableContextSet set = new MutableContextSet();
|
||||
if (server != null) {
|
||||
set.add("server", server);
|
||||
}
|
||||
if (world != null) {
|
||||
set.add("world", world);
|
||||
}
|
||||
|
||||
handle.clearMetaKeys(key, set, temporary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearTransientNodes() {
|
||||
master.clearTransientNodes();
|
||||
handle.clearTransientNodes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Node> getTemporaryPermissionNodes() {
|
||||
return master.getTemporaryNodes();
|
||||
return handle.getTemporaryNodes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Node> getPermanentPermissionNodes() {
|
||||
return master.getPermanentNodes();
|
||||
return handle.getPermanentNodes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void auditTemporaryPermissions() {
|
||||
master.auditTemporaryPermissions();
|
||||
handle.auditTemporaryPermissions();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -43,10 +43,7 @@ import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import static me.lucko.luckperms.common.api.ApiUtils.checkGroup;
|
||||
import static me.lucko.luckperms.common.api.ApiUtils.checkName;
|
||||
import static me.lucko.luckperms.common.api.ApiUtils.checkTrack;
|
||||
import static me.lucko.luckperms.common.api.ApiUtils.checkUser;
|
||||
import static me.lucko.luckperms.common.api.ApiUtils.checkUsername;
|
||||
|
||||
/**
|
||||
@@ -55,16 +52,16 @@ import static me.lucko.luckperms.common.api.ApiUtils.checkUsername;
|
||||
@AllArgsConstructor
|
||||
public class StorageDelegate implements Storage {
|
||||
private final LuckPermsPlugin plugin;
|
||||
private final me.lucko.luckperms.common.storage.Storage master;
|
||||
private final me.lucko.luckperms.common.storage.Storage handle;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return master.getName();
|
||||
return handle.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAcceptingLogins() {
|
||||
return master.isAcceptingLogins();
|
||||
return handle.isAcceptingLogins();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -79,114 +76,109 @@ public class StorageDelegate implements Storage {
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> logAction(@NonNull LogEntry entry) {
|
||||
return master.force().logAction(entry);
|
||||
return handle.force().logAction(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Log> getLog() {
|
||||
return master.force().getLog().thenApply(log -> log == null ? null : new LogDelegate(log));
|
||||
return handle.force().getLog().thenApply(log -> log == null ? null : new LogDelegate(log));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> loadUser(UUID uuid, String username) {
|
||||
return master.force().loadUser(uuid, checkUsername(username));
|
||||
return handle.force().loadUser(uuid, checkUsername(username));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> saveUser(User user) {
|
||||
checkUser(user);
|
||||
return master.force().saveUser(((UserDelegate) user).getMaster());
|
||||
return handle.force().saveUser(UserDelegate.cast(user));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> cleanupUsers() {
|
||||
return master.force().cleanupUsers();
|
||||
return handle.force().cleanupUsers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Set<UUID>> getUniqueUsers() {
|
||||
return master.force().getUniqueUsers();
|
||||
return handle.force().getUniqueUsers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<List<HeldPermission<UUID>>> getUsersWithPermission(@NonNull String permission) {
|
||||
return master.force().getUsersWithPermission(permission);
|
||||
return handle.force().getUsersWithPermission(permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> createAndLoadGroup(String name) {
|
||||
return master.force().createAndLoadGroup(checkName(name), CreationCause.API);
|
||||
return handle.force().createAndLoadGroup(checkName(name), CreationCause.API);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> loadGroup(String name) {
|
||||
return master.force().loadGroup(checkName(name));
|
||||
return handle.force().loadGroup(checkName(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> loadAllGroups() {
|
||||
return master.force().loadAllGroups();
|
||||
return handle.force().loadAllGroups();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> saveGroup(Group group) {
|
||||
checkGroup(group);
|
||||
return master.force().saveGroup(((GroupDelegate) group).getMaster());
|
||||
return handle.force().saveGroup(GroupDelegate.cast(group));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> deleteGroup(Group group) {
|
||||
checkGroup(group);
|
||||
if (group.getName().equalsIgnoreCase(plugin.getConfiguration().get(ConfigKeys.DEFAULT_GROUP_NAME))) {
|
||||
throw new IllegalArgumentException("Cannot delete the default group.");
|
||||
}
|
||||
return master.force().deleteGroup(((GroupDelegate) group).getMaster(), DeletionCause.API);
|
||||
return handle.force().deleteGroup(GroupDelegate.cast(group), DeletionCause.API);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<List<HeldPermission<String>>> getGroupsWithPermission(@NonNull String permission) {
|
||||
return master.force().getGroupsWithPermission(permission);
|
||||
return handle.force().getGroupsWithPermission(permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> createAndLoadTrack(String name) {
|
||||
return master.force().createAndLoadTrack(checkName(name), CreationCause.API);
|
||||
return handle.force().createAndLoadTrack(checkName(name), CreationCause.API);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> loadTrack(String name) {
|
||||
return master.force().loadTrack(checkName(name));
|
||||
return handle.force().loadTrack(checkName(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> loadAllTracks() {
|
||||
return master.force().loadAllTracks();
|
||||
return handle.force().loadAllTracks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> saveTrack(Track track) {
|
||||
checkTrack(track);
|
||||
return master.force().saveTrack(((TrackDelegate) track).getMaster());
|
||||
return handle.force().saveTrack(TrackDelegate.cast(track));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> deleteTrack(Track track) {
|
||||
checkTrack(track);
|
||||
return master.force().deleteTrack(((TrackDelegate) track).getMaster(), DeletionCause.API);
|
||||
return handle.force().deleteTrack(TrackDelegate.cast(track), DeletionCause.API);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> saveUUIDData(String username, UUID uuid) {
|
||||
return master.force().saveUUIDData(checkUsername(username), uuid);
|
||||
return handle.force().saveUUIDData(checkUsername(username), uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<UUID> getUUID(String username) {
|
||||
return master.force().getUUID(checkUsername(username));
|
||||
return handle.force().getUUID(checkUsername(username));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<String> getName(@NonNull UUID uuid) {
|
||||
return master.force().getName(uuid);
|
||||
return handle.force().getName(uuid);
|
||||
}
|
||||
}
|
||||
@@ -23,10 +23,12 @@
|
||||
package me.lucko.luckperms.common.api.delegates;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import me.lucko.luckperms.api.Group;
|
||||
import me.lucko.luckperms.api.Track;
|
||||
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
|
||||
@@ -34,83 +36,88 @@ import me.lucko.luckperms.exceptions.ObjectLacksException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static me.lucko.luckperms.common.api.ApiUtils.checkGroup;
|
||||
|
||||
/**
|
||||
* Provides a link between {@link Track} and {@link me.lucko.luckperms.common.core.model.Track}
|
||||
*/
|
||||
@EqualsAndHashCode(of = {"name"})
|
||||
public class TrackDelegate implements Track {
|
||||
@AllArgsConstructor
|
||||
public final class TrackDelegate implements Track {
|
||||
public static me.lucko.luckperms.common.core.model.Track cast(Track g) {
|
||||
Preconditions.checkState(g instanceof TrackDelegate, "Illegal instance " + g.getClass() + " cannot be handled by this implementation.");
|
||||
return ((TrackDelegate) g).getHandle();
|
||||
}
|
||||
|
||||
@Getter(AccessLevel.PACKAGE)
|
||||
private final me.lucko.luckperms.common.core.model.Track master;
|
||||
private final me.lucko.luckperms.common.core.model.Track handle;
|
||||
|
||||
@Getter
|
||||
private final String name;
|
||||
|
||||
public TrackDelegate(@NonNull me.lucko.luckperms.common.core.model.Track master) {
|
||||
this.master = master;
|
||||
this.name = master.getName();
|
||||
@Override
|
||||
public String getName() {
|
||||
return handle.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getGroups() {
|
||||
return master.getGroups();
|
||||
return handle.getGroups();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return master.getSize();
|
||||
return handle.getSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNext(@NonNull Group current) throws ObjectLacksException {
|
||||
checkGroup(current);
|
||||
return master.getNext(((GroupDelegate) current).getMaster());
|
||||
return handle.getNext(GroupDelegate.cast(current));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrevious(@NonNull Group current) throws ObjectLacksException {
|
||||
checkGroup(current);
|
||||
return master.getPrevious(((GroupDelegate) current).getMaster());
|
||||
return handle.getPrevious(GroupDelegate.cast(current));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendGroup(@NonNull Group group) throws ObjectAlreadyHasException {
|
||||
checkGroup(group);
|
||||
master.appendGroup(((GroupDelegate) group).getMaster());
|
||||
handle.appendGroup(GroupDelegate.cast(group));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertGroup(@NonNull Group group, @NonNull int position) throws ObjectAlreadyHasException, IndexOutOfBoundsException {
|
||||
checkGroup(group);
|
||||
master.insertGroup(((GroupDelegate) group).getMaster(), position);
|
||||
handle.insertGroup(GroupDelegate.cast(group), position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeGroup(@NonNull Group group) throws ObjectLacksException {
|
||||
checkGroup(group);
|
||||
master.removeGroup(((GroupDelegate) group).getMaster());
|
||||
handle.removeGroup(GroupDelegate.cast(group));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeGroup(@NonNull String group) throws ObjectLacksException {
|
||||
master.removeGroup(group);
|
||||
handle.removeGroup(group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsGroup(@NonNull Group group) {
|
||||
checkGroup(group);
|
||||
return master.containsGroup(((GroupDelegate) group).getMaster());
|
||||
return handle.containsGroup(GroupDelegate.cast(group));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsGroup(@NonNull String group) {
|
||||
return master.containsGroup(group);
|
||||
return handle.containsGroup(group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearGroups() {
|
||||
master.clearGroups();
|
||||
handle.clearGroups();
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) return true;
|
||||
if (!(o instanceof TrackDelegate)) return false;
|
||||
|
||||
TrackDelegate other = (TrackDelegate) o;
|
||||
return this.getName() == null ? other.getName() == null : this.getName().equals(other.getName());
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.getName().hashCode();
|
||||
}
|
||||
}
|
||||
@@ -22,49 +22,56 @@
|
||||
|
||||
package me.lucko.luckperms.common.api.delegates;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import me.lucko.luckperms.api.Group;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.api.User;
|
||||
import me.lucko.luckperms.api.caching.UserData;
|
||||
import me.lucko.luckperms.common.core.NodeFactory;
|
||||
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
|
||||
import me.lucko.luckperms.exceptions.ObjectLacksException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static me.lucko.luckperms.common.api.ApiUtils.checkGroup;
|
||||
import static me.lucko.luckperms.common.api.ApiUtils.checkTime;
|
||||
|
||||
/**
|
||||
* Provides a link between {@link User} and {@link me.lucko.luckperms.common.core.model.User}
|
||||
*/
|
||||
@EqualsAndHashCode(of = {"uuid"}, callSuper = false)
|
||||
public class UserDelegate extends PermissionHolderDelegate implements User {
|
||||
public final class UserDelegate extends PermissionHolderDelegate implements User {
|
||||
public static me.lucko.luckperms.common.core.model.User cast(User g) {
|
||||
Preconditions.checkState(g instanceof UserDelegate, "Illegal instance " + g.getClass() + " cannot be handled by this implementation.");
|
||||
return ((UserDelegate) g).getHandle();
|
||||
}
|
||||
|
||||
@Getter
|
||||
private final me.lucko.luckperms.common.core.model.User master;
|
||||
private final me.lucko.luckperms.common.core.model.User handle;
|
||||
|
||||
@Getter
|
||||
private final UUID uuid;
|
||||
public UserDelegate(@NonNull me.lucko.luckperms.common.core.model.User handle) {
|
||||
super(handle);
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
public UserDelegate(@NonNull me.lucko.luckperms.common.core.model.User master) {
|
||||
super(master);
|
||||
this.master = master;
|
||||
this.uuid = master.getUuid();
|
||||
@Override
|
||||
public UUID getUuid() {
|
||||
return handle.getUuid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return master.getName();
|
||||
return handle.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrimaryGroup() {
|
||||
return master.getPrimaryGroup();
|
||||
return handle.getPrimaryGroup().getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -77,132 +84,140 @@ public class UserDelegate extends PermissionHolderDelegate implements User {
|
||||
throw new IllegalStateException("User is not a member of that group.");
|
||||
}
|
||||
|
||||
master.setPrimaryGroup(s.toLowerCase());
|
||||
handle.getPrimaryGroup().setStoredValue(s.toLowerCase());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshPermissions() {
|
||||
master.getRefreshBuffer().requestDirectly();
|
||||
handle.getRefreshBuffer().requestDirectly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<UserData> getUserDataCache() {
|
||||
return Optional.ofNullable(master.getUserData());
|
||||
return Optional.ofNullable(handle.getUserData());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupDataCache() {
|
||||
master.setupData(false);
|
||||
handle.setupData(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInGroup(@NonNull Group group) {
|
||||
checkGroup(group);
|
||||
return master.inheritsGroup(((GroupDelegate) group).getMaster());
|
||||
return handle.inheritsGroup(GroupDelegate.cast(group));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInGroup(@NonNull Group group, @NonNull String server) {
|
||||
checkGroup(group);
|
||||
return master.inheritsGroup(((GroupDelegate) group).getMaster(), server);
|
||||
return handle.inheritsGroup(((GroupDelegate) group).getHandle(), server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInGroup(@NonNull Group group, @NonNull String server, @NonNull String world) {
|
||||
checkGroup(group);
|
||||
return master.inheritsGroup(((GroupDelegate) group).getMaster(), server, world);
|
||||
return handle.inheritsGroup(((GroupDelegate) group).getHandle(), server, world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addGroup(@NonNull Group group) throws ObjectAlreadyHasException {
|
||||
checkGroup(group);
|
||||
master.setInheritGroup(((GroupDelegate) group).getMaster());
|
||||
handle.setPermission(NodeFactory.make(GroupDelegate.cast(group))).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addGroup(@NonNull Group group, @NonNull String server) throws ObjectAlreadyHasException {
|
||||
checkGroup(group);
|
||||
master.setInheritGroup(((GroupDelegate) group).getMaster(), server);
|
||||
handle.setPermission(NodeFactory.make(GroupDelegate.cast(group), server)).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addGroup(@NonNull Group group, @NonNull String server, @NonNull String world) throws ObjectAlreadyHasException {
|
||||
checkGroup(group);
|
||||
master.setInheritGroup(((GroupDelegate) group).getMaster(), server, world);
|
||||
handle.setPermission(NodeFactory.make(GroupDelegate.cast(group), server, world)).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addGroup(@NonNull Group group, @NonNull long expireAt) throws ObjectAlreadyHasException {
|
||||
checkGroup(group);
|
||||
master.setInheritGroup(((GroupDelegate) group).getMaster(), checkTime(expireAt));
|
||||
handle.setPermission(NodeFactory.make(GroupDelegate.cast(group), checkTime(expireAt))).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addGroup(@NonNull Group group, @NonNull String server, @NonNull long expireAt) throws ObjectAlreadyHasException {
|
||||
checkGroup(group);
|
||||
master.setInheritGroup(((GroupDelegate) group).getMaster(), server, checkTime(expireAt));
|
||||
handle.setPermission(NodeFactory.make(GroupDelegate.cast(group), server, checkTime(expireAt))).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addGroup(@NonNull Group group, @NonNull String server, @NonNull String world, @NonNull long expireAt) throws ObjectAlreadyHasException {
|
||||
checkGroup(group);
|
||||
master.setInheritGroup(((GroupDelegate) group).getMaster(), server, world, checkTime(expireAt));
|
||||
handle.setPermission(NodeFactory.make(GroupDelegate.cast(group), server, world, checkTime(expireAt))).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeGroup(@NonNull Group group) throws ObjectLacksException {
|
||||
checkGroup(group);
|
||||
master.unsetInheritGroup(((GroupDelegate) group).getMaster());
|
||||
handle.unsetPermission(NodeFactory.make(GroupDelegate.cast(group))).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeGroup(@NonNull Group group, @NonNull boolean temporary) throws ObjectLacksException {
|
||||
checkGroup(group);
|
||||
master.unsetInheritGroup(((GroupDelegate) group).getMaster(), temporary);
|
||||
handle.unsetPermission(NodeFactory.make(GroupDelegate.cast(group), temporary)).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeGroup(@NonNull Group group, @NonNull String server) throws ObjectLacksException {
|
||||
checkGroup(group);
|
||||
master.unsetInheritGroup(((GroupDelegate) group).getMaster(), server);
|
||||
handle.unsetPermission(NodeFactory.make(GroupDelegate.cast(group), server)).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeGroup(@NonNull Group group, @NonNull String server, @NonNull String world) throws ObjectLacksException {
|
||||
checkGroup(group);
|
||||
master.unsetInheritGroup(((GroupDelegate) group).getMaster(), server, world);
|
||||
handle.unsetPermission(NodeFactory.make(GroupDelegate.cast(group), server, world)).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeGroup(@NonNull Group group, @NonNull String server, @NonNull boolean temporary) throws ObjectLacksException {
|
||||
checkGroup(group);
|
||||
master.unsetInheritGroup(((GroupDelegate) group).getMaster(), server, temporary);
|
||||
handle.unsetPermission(NodeFactory.make(GroupDelegate.cast(group), server, temporary)).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeGroup(@NonNull Group group, @NonNull String server, @NonNull String world, @NonNull boolean temporary) throws ObjectLacksException {
|
||||
checkGroup(group);
|
||||
master.unsetInheritGroup(((GroupDelegate) group).getMaster(), server, world, temporary);
|
||||
handle.unsetPermission(NodeFactory.make(GroupDelegate.cast(group), server, world, temporary)).throwException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearNodes() {
|
||||
master.clearNodes();
|
||||
handle.clearNodes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getGroupNames() {
|
||||
return master.getGroupNames();
|
||||
return handle.mergePermissionsToList().stream()
|
||||
.filter(Node::isGroupNode)
|
||||
.map(Node::getGroupName)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getLocalGroups(@NonNull String server, @NonNull String world) {
|
||||
return master.getLocalGroups(server, world);
|
||||
return handle.mergePermissionsToList().stream()
|
||||
.filter(Node::isGroupNode)
|
||||
.filter(n -> n.shouldApplyOnWorld(world, false, true))
|
||||
.filter(n -> n.shouldApplyOnServer(server, false, true))
|
||||
.map(Node::getGroupName)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getLocalGroups(@NonNull String server) {
|
||||
return master.getLocalGroups(server);
|
||||
return handle.mergePermissionsToList().stream()
|
||||
.filter(Node::isGroupNode)
|
||||
.filter(n -> n.shouldApplyOnServer(server, false, true))
|
||||
.map(Node::getGroupName)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) return true;
|
||||
if (!(o instanceof UserDelegate)) return false;
|
||||
|
||||
UserDelegate other = (UserDelegate) o;
|
||||
return this.getUuid() == null ? other.getUuid() == null : this.getUuid().equals(other.getUuid());
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.getUuid().hashCode();
|
||||
}
|
||||
}
|
||||
@@ -34,15 +34,15 @@ import java.util.UUID;
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
public class UuidCacheDelegate implements UuidCache {
|
||||
private final me.lucko.luckperms.common.core.UuidCache master;
|
||||
private final me.lucko.luckperms.common.core.UuidCache handle;
|
||||
|
||||
@Override
|
||||
public UUID getUUID(@NonNull UUID external) {
|
||||
return master.getUUID(external);
|
||||
return handle.getUUID(external);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getExternalUUID(@NonNull UUID internal) {
|
||||
return master.getExternalUUID(internal);
|
||||
return handle.getExternalUUID(internal);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* 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.bulkupdate;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
import me.lucko.luckperms.common.bulkupdate.action.Action;
|
||||
import me.lucko.luckperms.common.bulkupdate.constraint.Constraint;
|
||||
import me.lucko.luckperms.common.core.NodeModel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a query to be applied to a set of data.
|
||||
* Queries can either be applied to im-memory sets of data, or converted to SQL syntax to be executed remotely.
|
||||
*/
|
||||
@Getter
|
||||
@ToString
|
||||
@EqualsAndHashCode
|
||||
@AllArgsConstructor
|
||||
public class BulkUpdate {
|
||||
|
||||
// the data types which this query should apply to
|
||||
private final DataType dataType;
|
||||
|
||||
// the action to apply to the data which matches the constraints
|
||||
private final Action action;
|
||||
|
||||
// a set of constraints which data must match to be acted upon
|
||||
private final List<Constraint> constraints;
|
||||
|
||||
/**
|
||||
* Check to see if a Node instance satisfies the constrints of this query
|
||||
*
|
||||
* @param node the node to check
|
||||
* @return true if satisfied
|
||||
*/
|
||||
public boolean satisfiesConstraints(NodeModel node) {
|
||||
for (Constraint constraint : constraints) {
|
||||
if (!constraint.isSatisfiedBy(node)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies this query to the given NodeModel, and returns the result.
|
||||
*
|
||||
* @param from the node to base changes from
|
||||
* @return the new nodemodel instance, or null if the node should be deleted.
|
||||
*/
|
||||
public NodeModel apply(NodeModel from) {
|
||||
if (!satisfiesConstraints(from)) {
|
||||
return from; // make no change
|
||||
}
|
||||
|
||||
return action.apply(from);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this {@link BulkUpdate} to SQL syntax
|
||||
*
|
||||
* @return this query in SQL form
|
||||
*/
|
||||
public String buildAsSql() {
|
||||
// DELETE FROM {table} WHERE ...
|
||||
// UPDATE {table} SET ... WHERE ...
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
// add the action
|
||||
// (DELETE FROM or UPDATE)
|
||||
sb.append(action.getAsSql());
|
||||
|
||||
// if there are no constraints, just return without a WHERE clause
|
||||
if (constraints.isEmpty()) {
|
||||
return sb.append(";").toString();
|
||||
}
|
||||
|
||||
// append constraints
|
||||
sb.append(" WHERE");
|
||||
for (int i = 0; i < constraints.size(); i++) {
|
||||
Constraint constraint = constraints.get(i);
|
||||
|
||||
sb.append(" ");
|
||||
if (i != 0) {
|
||||
sb.append("AND ");
|
||||
}
|
||||
|
||||
sb.append(constraint.getAsSql());
|
||||
}
|
||||
|
||||
return sb.append(";").toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility to appropriately escape a string for use in a query.
|
||||
*
|
||||
* @param s the string to escape
|
||||
* @return an escaped string
|
||||
*/
|
||||
public static String escapeStringForSql(String s) {
|
||||
if (s.equalsIgnoreCase("true") || s.equalsIgnoreCase("false")) {
|
||||
return s.toLowerCase();
|
||||
}
|
||||
|
||||
try {
|
||||
Integer.parseInt(s);
|
||||
return s;
|
||||
} catch (NumberFormatException e) {
|
||||
// ignored
|
||||
}
|
||||
|
||||
return "\"" + s + "\"";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* 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.bulkupdate;
|
||||
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import me.lucko.luckperms.common.bulkupdate.action.Action;
|
||||
import me.lucko.luckperms.common.bulkupdate.constraint.Constraint;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Responsible for building a {@link BulkUpdate}
|
||||
*/
|
||||
@ToString
|
||||
@NoArgsConstructor(staticName = "create")
|
||||
public class BulkUpdateBuilder {
|
||||
|
||||
// the data type this query should affect
|
||||
private DataType dataType = DataType.ALL;
|
||||
|
||||
// the action to apply to the data which matches the constraints
|
||||
private Action action = null;
|
||||
|
||||
// a set of constraints which data must match to be acted upon
|
||||
private Set<Constraint> constraints = new LinkedHashSet<>();
|
||||
|
||||
public BulkUpdateBuilder action(Action action) {
|
||||
this.action = action;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BulkUpdateBuilder dataType(DataType dataType) {
|
||||
this.dataType = dataType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BulkUpdateBuilder constraint(Constraint constraint) {
|
||||
constraints.add(constraint);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BulkUpdate build() {
|
||||
if (action == null) {
|
||||
throw new IllegalStateException("no action specified");
|
||||
}
|
||||
|
||||
return new BulkUpdate(dataType, action, ImmutableList.copyOf(constraints));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* 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.bulkupdate;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Represents the data sets a query should apply to
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum DataType {
|
||||
|
||||
ALL("all", true, true),
|
||||
USERS("users", true, false),
|
||||
GROUPS("groups", false, true);
|
||||
|
||||
private final String name;
|
||||
private final boolean includingUsers;
|
||||
private final boolean includingGroups;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* 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.bulkupdate.action;
|
||||
|
||||
import me.lucko.luckperms.common.core.NodeModel;
|
||||
|
||||
public interface Action {
|
||||
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Applies this action to the given NodeModel, and returns the result.
|
||||
*
|
||||
* @param from the node to base changes from
|
||||
* @return the new nodemodel instance, or null if the node should be deleted.
|
||||
*/
|
||||
NodeModel apply(NodeModel from);
|
||||
|
||||
String getAsSql();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* 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.bulkupdate.action;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
import me.lucko.luckperms.common.core.NodeModel;
|
||||
|
||||
@AllArgsConstructor(staticName = "create")
|
||||
public class DeleteAction implements Action {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "delete";
|
||||
}
|
||||
|
||||
@Override
|
||||
public NodeModel apply(NodeModel from) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAsSql() {
|
||||
return "DELETE FROM {table}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* 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.bulkupdate.action;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
import me.lucko.luckperms.common.bulkupdate.BulkUpdate;
|
||||
import me.lucko.luckperms.common.bulkupdate.constraint.QueryField;
|
||||
import me.lucko.luckperms.common.core.NodeModel;
|
||||
|
||||
@AllArgsConstructor(staticName = "of")
|
||||
public class UpdateAction implements Action {
|
||||
|
||||
private final QueryField field;
|
||||
private final String value;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "update";
|
||||
}
|
||||
|
||||
@Override
|
||||
public NodeModel apply(NodeModel from) {
|
||||
switch (field) {
|
||||
case PERMISSION:
|
||||
return from.setPermission(value);
|
||||
case SERVER:
|
||||
return from.setServer(value);
|
||||
case WORLD:
|
||||
return from.setWorld(value);
|
||||
default:
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAsSql() {
|
||||
return "UPDATE {table} SET " + field.getSqlName() + "=" + BulkUpdate.escapeStringForSql(value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* 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.bulkupdate.comparisons;
|
||||
|
||||
public interface Comparison {
|
||||
|
||||
String getSymbol();
|
||||
|
||||
boolean matches(String str, String expr);
|
||||
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* 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.bulkupdate.comparisons;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
import me.lucko.luckperms.common.bulkupdate.comparisons.impl.ComparisonEqual;
|
||||
import me.lucko.luckperms.common.bulkupdate.comparisons.impl.ComparisonNotEqual;
|
||||
import me.lucko.luckperms.common.bulkupdate.comparisons.impl.ComparisonNotSimilar;
|
||||
import me.lucko.luckperms.common.bulkupdate.comparisons.impl.ComparisonSimilar;
|
||||
|
||||
@AllArgsConstructor
|
||||
public enum ComparisonType {
|
||||
|
||||
EQUAL("==", new ComparisonEqual()),
|
||||
NOT_EQUAL("!=", new ComparisonNotEqual()),
|
||||
SIMILAR("~~", new ComparisonSimilar()),
|
||||
NOT_SIMILAR("!~", new ComparisonNotSimilar());
|
||||
|
||||
private final String symbol;
|
||||
private final Comparison instance;
|
||||
|
||||
public String getSymbol() {
|
||||
return symbol;
|
||||
}
|
||||
|
||||
public Comparison get() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static ComparisonType parseComparison(String s) {
|
||||
for (ComparisonType t : values()) {
|
||||
if (t.getSymbol().equals(s)) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* 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.bulkupdate.comparisons.impl;
|
||||
|
||||
import me.lucko.luckperms.common.bulkupdate.comparisons.Comparison;
|
||||
|
||||
public class ComparisonEqual implements Comparison {
|
||||
|
||||
@Override
|
||||
public String getSymbol() {
|
||||
return "==";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(String str, String expr) {
|
||||
return str.equalsIgnoreCase(expr);
|
||||
}
|
||||
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* 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.bulkupdate.comparisons.impl;
|
||||
|
||||
import me.lucko.luckperms.common.bulkupdate.comparisons.Comparison;
|
||||
|
||||
public class ComparisonNotEqual implements Comparison {
|
||||
|
||||
@Override
|
||||
public String getSymbol() {
|
||||
return "!=";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(String str, String expr) {
|
||||
return !str.equalsIgnoreCase(expr);
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* 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.bulkupdate.comparisons.impl;
|
||||
|
||||
import me.lucko.luckperms.common.bulkupdate.comparisons.Comparison;
|
||||
|
||||
public class ComparisonNotSimilar implements Comparison {
|
||||
|
||||
@Override
|
||||
public String getSymbol() {
|
||||
return "!~";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(String str, String expr) {
|
||||
// form expression
|
||||
expr = expr.toLowerCase();
|
||||
expr = expr.replace(".", "\\.");
|
||||
|
||||
// convert from SQL LIKE syntax to regex
|
||||
expr = expr.replace("_", ".");
|
||||
expr = expr.replace("%", ".*");
|
||||
|
||||
return !str.toLowerCase().matches(expr);
|
||||
}
|
||||
}
|
||||
+17
-16
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) 2017 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -20,25 +20,26 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.utils;
|
||||
package me.lucko.luckperms.common.bulkupdate.comparisons.impl;
|
||||
|
||||
import java.util.Objects;
|
||||
import me.lucko.luckperms.common.bulkupdate.comparisons.Comparison;
|
||||
|
||||
public interface ThrowingFunction<T, R> {
|
||||
|
||||
R apply(T t) throws Exception;
|
||||
|
||||
default <V> ThrowingFunction<V, R> compose(ThrowingFunction<? super V, ? extends T> before) {
|
||||
Objects.requireNonNull(before);
|
||||
return (V v) -> apply(before.apply(v));
|
||||
public class ComparisonSimilar implements Comparison {
|
||||
@Override
|
||||
public String getSymbol() {
|
||||
return "~~";
|
||||
}
|
||||
|
||||
default <V> ThrowingFunction<T, V> andThen(ThrowingFunction<? super R, ? extends V> after) {
|
||||
Objects.requireNonNull(after);
|
||||
return (T t) -> after.apply(apply(t));
|
||||
}
|
||||
@Override
|
||||
public boolean matches(String str, String expr) {
|
||||
// form expression
|
||||
expr = expr.toLowerCase();
|
||||
expr = expr.replace(".", "\\.");
|
||||
|
||||
static <T> ThrowingFunction<T, T> identity() {
|
||||
return t -> t;
|
||||
// convert from SQL LIKE syntax to regex
|
||||
expr = expr.replace("_", ".");
|
||||
expr = expr.replace("%", ".*");
|
||||
|
||||
return str.toLowerCase().matches(expr);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* 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.bulkupdate.constraint;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import me.lucko.luckperms.common.bulkupdate.BulkUpdate;
|
||||
import me.lucko.luckperms.common.bulkupdate.comparisons.ComparisonType;
|
||||
import me.lucko.luckperms.common.core.NodeModel;
|
||||
|
||||
/**
|
||||
* Represents a query constraint
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor(staticName = "of")
|
||||
public class Constraint {
|
||||
|
||||
// the field this constraint is comparing against
|
||||
private final QueryField field;
|
||||
|
||||
// the comparison type being used in this constraint
|
||||
private final ComparisonType comparison;
|
||||
|
||||
// the expression being compared against
|
||||
private final String value;
|
||||
|
||||
/**
|
||||
* Returns if the given node satisfies this constraint
|
||||
*
|
||||
* @param node the node
|
||||
* @return true if satisfied
|
||||
*/
|
||||
public boolean isSatisfiedBy(NodeModel node) {
|
||||
switch (field) {
|
||||
case PERMISSION:
|
||||
return comparison.get().matches(node.getPermission(), value);
|
||||
case SERVER:
|
||||
return comparison.get().matches(node.getServer(), value);
|
||||
case WORLD:
|
||||
return comparison.get().matches(node.getWorld(), value);
|
||||
default:
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
public String getAsSql() {
|
||||
// WHERE permission = "thing"
|
||||
// WHERE permission != ""
|
||||
// WHERE permission LIKE ""
|
||||
// WHERE permission NOT LIKE ""
|
||||
|
||||
switch (comparison) {
|
||||
case EQUAL:
|
||||
return field.getSqlName() + " = " + BulkUpdate.escapeStringForSql(value);
|
||||
case NOT_EQUAL:
|
||||
return field.getSqlName() + " != " + BulkUpdate.escapeStringForSql(value);
|
||||
case SIMILAR:
|
||||
return field.getSqlName() + " LIKE " + BulkUpdate.escapeStringForSql(value);
|
||||
case NOT_SIMILAR:
|
||||
return field.getSqlName() + " NOT LIKE " + BulkUpdate.escapeStringForSql(value);
|
||||
default:
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* 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.bulkupdate.constraint;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Represents a field being used in an update
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum QueryField {
|
||||
|
||||
PERMISSION("permission"),
|
||||
SERVER("server"),
|
||||
WORLD("world");
|
||||
|
||||
private final String sqlName;
|
||||
|
||||
public static QueryField of(String s) {
|
||||
try {
|
||||
return valueOf(s.toUpperCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
-7
@@ -22,12 +22,12 @@
|
||||
|
||||
package me.lucko.luckperms.common.caching;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
import me.lucko.luckperms.api.LocalizedNode;
|
||||
import me.lucko.luckperms.common.caching.stacking.MetaStack;
|
||||
import me.lucko.luckperms.common.caching.stacking.NoopMetaStack;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
@@ -40,16 +40,18 @@ import java.util.TreeMap;
|
||||
*/
|
||||
@Getter
|
||||
@ToString
|
||||
public class MetaHolder {
|
||||
public class MetaAccumulator {
|
||||
|
||||
@Getter(AccessLevel.NONE)
|
||||
private final Map<String, String> meta;
|
||||
private final SortedMap<Integer, String> prefixes;
|
||||
private final SortedMap<Integer, String> suffixes;
|
||||
private int weight = 0;
|
||||
|
||||
private final MetaStack prefixStack;
|
||||
private final MetaStack suffixStack;
|
||||
|
||||
public MetaHolder(MetaStack prefixStack, MetaStack suffixStack) {
|
||||
public MetaAccumulator(MetaStack prefixStack, MetaStack suffixStack) {
|
||||
this.meta = new HashMap<>();
|
||||
this.prefixes = new TreeMap<>(Comparator.reverseOrder());
|
||||
this.suffixes = new TreeMap<>(Comparator.reverseOrder());
|
||||
@@ -57,10 +59,6 @@ public class MetaHolder {
|
||||
this.suffixStack = suffixStack;
|
||||
}
|
||||
|
||||
public MetaHolder() {
|
||||
this(NoopMetaStack.INSTANCE, NoopMetaStack.INSTANCE);
|
||||
}
|
||||
|
||||
public void accumulateNode(LocalizedNode n) {
|
||||
if (n.isMeta()) {
|
||||
Map.Entry<String, String> entry = n.getMeta();
|
||||
@@ -88,4 +86,18 @@ public class MetaHolder {
|
||||
}
|
||||
}
|
||||
|
||||
public void accumulateWeight(int weight) {
|
||||
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)
|
||||
// Therefore, it should be ok to set the weight meta key, if not already present.
|
||||
public Map<String, String> getMeta() {
|
||||
if (!this.meta.containsKey("weight") && this.weight != 0) {
|
||||
this.meta.put("weight", String.valueOf(this.weight));
|
||||
}
|
||||
|
||||
return this.meta;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -59,7 +59,7 @@ public class MetaCache implements MetaData {
|
||||
@Getter
|
||||
private MetaStack suffixStack = NoopMetaStack.INSTANCE;
|
||||
|
||||
public void loadMeta(MetaHolder meta) {
|
||||
public void loadMeta(MetaAccumulator meta) {
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
this.meta = ImmutableMap.copyOf(meta.getMeta());
|
||||
|
||||
@@ -25,12 +25,10 @@ package me.lucko.luckperms.common.caching;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.github.benmanes.caffeine.cache.CacheLoader;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.caching.MetaData;
|
||||
@@ -49,6 +47,7 @@ import java.util.concurrent.TimeUnit;
|
||||
@RequiredArgsConstructor
|
||||
public class UserCache implements UserData {
|
||||
|
||||
|
||||
/**
|
||||
* The user whom this data instance is representing
|
||||
*/
|
||||
@@ -59,7 +58,7 @@ public class UserCache implements UserData {
|
||||
*/
|
||||
private final CalculatorFactory calculatorFactory;
|
||||
|
||||
private final LoadingCache<Contexts, PermissionCache> permission = CacheBuilder.newBuilder()
|
||||
private final LoadingCache<Contexts, PermissionCache> permission = Caffeine.newBuilder()
|
||||
.expireAfterAccess(10, TimeUnit.MINUTES)
|
||||
.build(new CacheLoader<Contexts, PermissionCache>() {
|
||||
@Override
|
||||
@@ -68,13 +67,13 @@ public class UserCache implements UserData {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<PermissionCache> reload(Contexts contexts, PermissionCache oldData) {
|
||||
oldData.comparePermissions(user.exportNodes(contexts, true));
|
||||
return Futures.immediateFuture(oldData);
|
||||
public PermissionCache reload(Contexts contexts, PermissionCache oldData) {
|
||||
oldData.comparePermissions(user.exportNodes(ExtractedContexts.generate(contexts), true));
|
||||
return oldData;
|
||||
}
|
||||
});
|
||||
|
||||
private final LoadingCache<Contexts, MetaCache> meta = CacheBuilder.newBuilder()
|
||||
private final LoadingCache<Contexts, MetaCache> meta = Caffeine.newBuilder()
|
||||
.expireAfterAccess(10, TimeUnit.MINUTES)
|
||||
.build(new CacheLoader<Contexts, MetaCache>() {
|
||||
@Override
|
||||
@@ -83,26 +82,26 @@ public class UserCache implements UserData {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<MetaCache> reload(Contexts contexts, MetaCache oldData) {
|
||||
public MetaCache reload(Contexts contexts, MetaCache oldData) {
|
||||
oldData.loadMeta(user.accumulateMeta(null, null, ExtractedContexts.generate(contexts)));
|
||||
return Futures.immediateFuture(oldData);
|
||||
return oldData;
|
||||
}
|
||||
});
|
||||
|
||||
@Override
|
||||
public PermissionData getPermissionData(@NonNull Contexts contexts) {
|
||||
return permission.getUnchecked(contexts);
|
||||
return permission.get(contexts);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetaData getMetaData(@NonNull Contexts contexts) {
|
||||
return meta.getUnchecked(contexts);
|
||||
return meta.get(contexts);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionCache calculatePermissions(@NonNull Contexts contexts) {
|
||||
PermissionCache data = new PermissionCache(contexts, user, calculatorFactory);
|
||||
data.setPermissions(user.exportNodes(contexts, true));
|
||||
data.setPermissions(user.exportNodes(ExtractedContexts.generate(contexts), true));
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -142,8 +141,8 @@ public class UserCache implements UserData {
|
||||
|
||||
@Override
|
||||
public void preCalculate(@NonNull Contexts contexts) {
|
||||
permission.getUnchecked(contexts);
|
||||
meta.getUnchecked(contexts);
|
||||
permission.get(contexts);
|
||||
meta.get(contexts);
|
||||
}
|
||||
|
||||
public void invalidateCache() {
|
||||
|
||||
+4
-4
@@ -27,24 +27,22 @@ import lombok.RequiredArgsConstructor;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
import me.lucko.luckperms.common.core.model.PermissionHolder;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Manages the cached state of all permission holders
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class CachedStateManager {
|
||||
private static final Consumer<PermissionHolder> INVALIDATE_CONSUMER = PermissionHolder::invalidateInheritanceCaches;
|
||||
// private static final Consumer<PermissionHolder> INVALIDATE_CONSUMER = PermissionHolder::invalidateInheritanceCaches;
|
||||
|
||||
private final LuckPermsPlugin plugin;
|
||||
|
||||
// Group --> Groups that inherit from that group. (reverse relationship)
|
||||
// Group --> Groups/Users that inherit from that group. (reverse relationship)
|
||||
private final Multimap<HolderReference, HolderReference> map = HashMultimap.create();
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
@@ -117,6 +115,7 @@ public class CachedStateManager {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
public void invalidateInheritances(HolderReference holder) {
|
||||
Set<HolderReference> toInvalidate = getInheritances(holder);
|
||||
invalidateInheritances(plugin, toInvalidate);
|
||||
@@ -125,5 +124,6 @@ public class CachedStateManager {
|
||||
public static void invalidateInheritances(LuckPermsPlugin plugin, Set<HolderReference> references) {
|
||||
references.forEach(hr -> hr.apply(plugin, INVALIDATE_CONSUMER));
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
@@ -38,7 +38,7 @@ import java.util.function.Consumer;
|
||||
@ToString
|
||||
@EqualsAndHashCode
|
||||
@AllArgsConstructor(staticName = "of")
|
||||
public class UserReference implements HolderReference<UserIdentifier> {
|
||||
public final class UserReference implements HolderReference<UserIdentifier> {
|
||||
private final UserIdentifier id;
|
||||
|
||||
@Override
|
||||
|
||||
+2
-1
@@ -23,6 +23,7 @@
|
||||
package me.lucko.luckperms.common.caching.stacking;
|
||||
|
||||
import me.lucko.luckperms.api.LocalizedNode;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.common.core.model.Track;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
|
||||
@@ -44,7 +45,7 @@ public interface MetaStackElement {
|
||||
* @param node the node to check
|
||||
* @return true if the accumulation should return
|
||||
*/
|
||||
static boolean checkMetaType(boolean expectingPrefix, LocalizedNode node) {
|
||||
static boolean checkMetaType(boolean expectingPrefix, Node node) {
|
||||
if (expectingPrefix) {
|
||||
if (!node.isPrefix()) {
|
||||
return true;
|
||||
|
||||
+5
-12
@@ -24,9 +24,8 @@ package me.lucko.luckperms.common.calculators;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
@@ -43,13 +42,7 @@ public class PermissionCalculator {
|
||||
private final String objectName;
|
||||
private final List<PermissionProcessor> processors;
|
||||
|
||||
private final LoadingCache<String, Tristate> cache = CacheBuilder.newBuilder()
|
||||
.build(new CacheLoader<String, Tristate>() {
|
||||
@Override
|
||||
public Tristate load(String s) {
|
||||
return lookupPermissionValue(s);
|
||||
}
|
||||
});
|
||||
private final LoadingCache<String, Tristate> cache = Caffeine.newBuilder().build(this::lookupPermissionValue);
|
||||
|
||||
public void invalidateCache() {
|
||||
cache.invalidateAll();
|
||||
@@ -57,8 +50,8 @@ public class PermissionCalculator {
|
||||
|
||||
public Tristate getPermissionValue(String permission) {
|
||||
permission = permission.toLowerCase();
|
||||
Tristate t = cache.getUnchecked(permission);
|
||||
plugin.getDebugHandler().offer(objectName, permission, t);
|
||||
Tristate t = cache.get(permission);
|
||||
plugin.getVerboseHandler().offer(objectName, permission, t);
|
||||
plugin.getPermissionVault().offer(permission);
|
||||
return t;
|
||||
}
|
||||
|
||||
@@ -26,29 +26,30 @@ import lombok.Getter;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import me.lucko.luckperms.common.commands.group.CreateGroup;
|
||||
import me.lucko.luckperms.common.commands.group.DeleteGroup;
|
||||
import me.lucko.luckperms.common.commands.group.GroupMainCommand;
|
||||
import me.lucko.luckperms.common.commands.group.ListGroups;
|
||||
import me.lucko.luckperms.common.commands.log.LogMainCommand;
|
||||
import me.lucko.luckperms.common.commands.migration.MigrationMainCommand;
|
||||
import me.lucko.luckperms.common.commands.misc.CheckCommand;
|
||||
import me.lucko.luckperms.common.commands.misc.ExportCommand;
|
||||
import me.lucko.luckperms.common.commands.misc.ImportCommand;
|
||||
import me.lucko.luckperms.common.commands.misc.InfoCommand;
|
||||
import me.lucko.luckperms.common.commands.misc.NetworkSyncCommand;
|
||||
import me.lucko.luckperms.common.commands.misc.ReloadConfigCommand;
|
||||
import me.lucko.luckperms.common.commands.misc.SearchCommand;
|
||||
import me.lucko.luckperms.common.commands.misc.SyncCommand;
|
||||
import me.lucko.luckperms.common.commands.misc.TreeCommand;
|
||||
import me.lucko.luckperms.common.commands.misc.VerboseCommand;
|
||||
import me.lucko.luckperms.common.commands.abstraction.Command;
|
||||
import me.lucko.luckperms.common.commands.impl.group.CreateGroup;
|
||||
import me.lucko.luckperms.common.commands.impl.group.DeleteGroup;
|
||||
import me.lucko.luckperms.common.commands.impl.group.GroupMainCommand;
|
||||
import me.lucko.luckperms.common.commands.impl.group.ListGroups;
|
||||
import me.lucko.luckperms.common.commands.impl.log.LogMainCommand;
|
||||
import me.lucko.luckperms.common.commands.impl.migration.MigrationMainCommand;
|
||||
import me.lucko.luckperms.common.commands.impl.misc.BulkUpdateCommand;
|
||||
import me.lucko.luckperms.common.commands.impl.misc.CheckCommand;
|
||||
import me.lucko.luckperms.common.commands.impl.misc.ExportCommand;
|
||||
import me.lucko.luckperms.common.commands.impl.misc.ImportCommand;
|
||||
import me.lucko.luckperms.common.commands.impl.misc.InfoCommand;
|
||||
import me.lucko.luckperms.common.commands.impl.misc.NetworkSyncCommand;
|
||||
import me.lucko.luckperms.common.commands.impl.misc.ReloadConfigCommand;
|
||||
import me.lucko.luckperms.common.commands.impl.misc.SearchCommand;
|
||||
import me.lucko.luckperms.common.commands.impl.misc.SyncCommand;
|
||||
import me.lucko.luckperms.common.commands.impl.misc.TreeCommand;
|
||||
import me.lucko.luckperms.common.commands.impl.misc.VerboseCommand;
|
||||
import me.lucko.luckperms.common.commands.impl.track.CreateTrack;
|
||||
import me.lucko.luckperms.common.commands.impl.track.DeleteTrack;
|
||||
import me.lucko.luckperms.common.commands.impl.track.ListTracks;
|
||||
import me.lucko.luckperms.common.commands.impl.track.TrackMainCommand;
|
||||
import me.lucko.luckperms.common.commands.impl.user.UserMainCommand;
|
||||
import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.commands.track.CreateTrack;
|
||||
import me.lucko.luckperms.common.commands.track.DeleteTrack;
|
||||
import me.lucko.luckperms.common.commands.track.ListTracks;
|
||||
import me.lucko.luckperms.common.commands.track.TrackMainCommand;
|
||||
import me.lucko.luckperms.common.commands.user.UserMainCommand;
|
||||
import me.lucko.luckperms.common.commands.usersbulkedit.UsersBulkEditMainCommand;
|
||||
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
|
||||
import me.lucko.luckperms.common.commands.utils.Util;
|
||||
import me.lucko.luckperms.common.constants.Message;
|
||||
@@ -75,14 +76,14 @@ public class CommandManager {
|
||||
private final ExecutorService executor;
|
||||
|
||||
@Getter
|
||||
private final List<BaseCommand> mainCommands;
|
||||
private final List<Command> mainCommands;
|
||||
|
||||
public CommandManager(LuckPermsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.executor = Executors.newSingleThreadExecutor();
|
||||
|
||||
ImmutableList.Builder<BaseCommand> l = ImmutableList.builder();
|
||||
l.add(new UserMainCommand())
|
||||
mainCommands = ImmutableList.<Command>builder()
|
||||
.add(new UserMainCommand())
|
||||
.add(new GroupMainCommand())
|
||||
.add(new TrackMainCommand())
|
||||
.addAll(plugin.getExtraCommands())
|
||||
@@ -97,40 +98,50 @@ public class CommandManager {
|
||||
.add(new ImportCommand())
|
||||
.add(new ExportCommand())
|
||||
.add(new ReloadConfigCommand())
|
||||
.add(new BulkUpdateCommand())
|
||||
.add(new MigrationMainCommand())
|
||||
.add(new UsersBulkEditMainCommand())
|
||||
.add(new CreateGroup())
|
||||
.add(new DeleteGroup())
|
||||
.add(new ListGroups())
|
||||
.add(new CreateTrack())
|
||||
.add(new DeleteTrack())
|
||||
.add(new ListTracks());
|
||||
|
||||
mainCommands = l.build();
|
||||
.add(new ListTracks())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic on command method to be called from the command executor object of the platform
|
||||
* Unlike {@link #onCommand(Sender, String, List)}, this method is called in a new thread
|
||||
* @param sender who sent the command
|
||||
* Unlike {@link #execute(Sender, String, List)}, this method is called in a new thread
|
||||
* @param sender who sent the command
|
||||
* @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(() -> execute(sender, label, args));
|
||||
return executor.submit(() -> {
|
||||
try {
|
||||
return execute(sender, label, args);
|
||||
} catch (Exception e) {
|
||||
plugin.getLog().severe("Exception whilst executing command: " + args.toString());
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private CommandResult execute(Sender sender, String label, List<String> args) {
|
||||
List<String> arguments = new ArrayList<>(args);
|
||||
handleRewrites(arguments);
|
||||
|
||||
// Handle no arguments
|
||||
if (args.size() == 0) {
|
||||
if (arguments.size() == 0) {
|
||||
sendCommandUsage(sender, label);
|
||||
return CommandResult.INVALID_ARGS;
|
||||
}
|
||||
|
||||
// Look for the main command.
|
||||
Optional<BaseCommand> o = mainCommands.stream()
|
||||
.filter(m -> m.getName().equalsIgnoreCase(args.get(0)))
|
||||
Optional<Command> o = mainCommands.stream()
|
||||
.filter(m -> m.getName().equalsIgnoreCase(arguments.get(0)))
|
||||
.limit(1)
|
||||
.findAny();
|
||||
|
||||
@@ -147,13 +158,11 @@ public class CommandManager {
|
||||
return CommandResult.NO_PERMISSION;
|
||||
}
|
||||
|
||||
List<String> arguments = new ArrayList<>(args);
|
||||
handleRewrites(arguments);
|
||||
arguments.remove(0); // remove the main command arg.
|
||||
|
||||
// Check the correct number of args were given for the main command
|
||||
if (main.getArgumentCheck().test(arguments.size())) {
|
||||
main.sendUsage(sender, label);
|
||||
main.sendDetailedUsage(sender, label);
|
||||
return CommandResult.INVALID_ARGS;
|
||||
}
|
||||
|
||||
@@ -180,15 +189,18 @@ public class CommandManager {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<String> onTabComplete(Sender sender, List<String> args) {
|
||||
List<String> arguments = new ArrayList<>(args);
|
||||
handleRewrites(arguments);
|
||||
|
||||
final List<Command> mains = mainCommands.stream()
|
||||
.filter(m -> m.isAuthorized(sender))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// Not yet past the point of entering a main command
|
||||
if (args.size() <= 1) {
|
||||
if (arguments.size() <= 1) {
|
||||
|
||||
// Nothing yet entered
|
||||
if (args.isEmpty() || args.get(0).equalsIgnoreCase("")) {
|
||||
if (arguments.isEmpty() || arguments.get(0).equalsIgnoreCase("")) {
|
||||
return mains.stream()
|
||||
.map(m -> m.getName().toLowerCase())
|
||||
.collect(Collectors.toList());
|
||||
@@ -197,22 +209,24 @@ public class CommandManager {
|
||||
// Started typing a main command
|
||||
return mains.stream()
|
||||
.map(m -> m.getName().toLowerCase())
|
||||
.filter(s -> s.startsWith(args.get(0).toLowerCase()))
|
||||
.filter(s -> s.startsWith(arguments.get(0).toLowerCase()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
// Find a main command matching the first arg
|
||||
Optional<Command> o = mains.stream()
|
||||
.filter(m -> m.getName().equalsIgnoreCase(args.get(0)))
|
||||
.filter(m -> m.getName().equalsIgnoreCase(arguments.get(0)))
|
||||
.limit(1)
|
||||
.findAny();
|
||||
|
||||
arguments.remove(0); // remove the main command arg.
|
||||
|
||||
if (!o.isPresent()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// Pass the processing onto the main command
|
||||
return o.get().tabComplete(plugin, sender, args.subList(1, args.size()));
|
||||
return o.get().tabComplete(plugin, sender, arguments);
|
||||
}
|
||||
|
||||
private void sendCommandUsage(Sender sender, String label) {
|
||||
@@ -226,19 +240,23 @@ public class CommandManager {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
String permission = (String) c.getPermission().map(p -> ((Permission) p).getExample()).orElse("None");
|
||||
FancyMessage msg = new FancyMessage("> ").color(ChatColor.getByChar('3')).then().text(String.format(c.getUsage(), label)).color(ChatColor.getByChar('a'))
|
||||
FancyMessage msg = new FancyMessage("> ").color(c('3')).then().text(String.format(c.getUsage(), label)).color(c('a'))
|
||||
.formattedTooltip(
|
||||
new FancyMessage("Command: ").color(ChatColor.getByChar('b')).then().text(c.getName()).color(ChatColor.getByChar('2')),
|
||||
new FancyMessage("Description: ").color(ChatColor.getByChar('b')).then().text(c.getDescription()).color(ChatColor.getByChar('2')),
|
||||
new FancyMessage("Usage: ").color(ChatColor.getByChar('b')).then().text(String.format(c.getUsage(), label)).color(ChatColor.getByChar('2')),
|
||||
new FancyMessage("Permission: ").color(ChatColor.getByChar('b')).then().text(permission).color(ChatColor.getByChar('2')),
|
||||
new FancyMessage("Command: ").color(c('b')).then().text(c.getName()).color(c('2')),
|
||||
new FancyMessage("Description: ").color(c('b')).then().text(c.getDescription()).color(c('2')),
|
||||
new FancyMessage("Usage: ").color(c('b')).then().text(String.format(c.getUsage(), label)).color(c('2')),
|
||||
new FancyMessage("Permission: ").color(c('b')).then().text(permission).color(c('2')),
|
||||
new FancyMessage(" "),
|
||||
new FancyMessage("Click to auto-complete.").color(ChatColor.getByChar('7'))
|
||||
new FancyMessage("Click to auto-complete.").color(c('7'))
|
||||
)
|
||||
.suggest(String.format(c.getUsage(), label));
|
||||
sender.sendMessage(msg);
|
||||
});
|
||||
}
|
||||
|
||||
private static ChatColor c(char c) {
|
||||
return ChatColor.getByChar(c);
|
||||
}
|
||||
|
||||
public static CommandResult handleException(CommandException e, Sender sender, String label, Command command) {
|
||||
if (e instanceof ArgumentUtils.ArgumentException) {
|
||||
@@ -279,6 +297,17 @@ public class CommandManager {
|
||||
}
|
||||
|
||||
private static void handleRewrites(List<String> args) {
|
||||
if (args.size() >= 1) {
|
||||
if (args.get(0).equalsIgnoreCase("u")) {
|
||||
args.remove(0);
|
||||
args.add(0, "user");
|
||||
}
|
||||
if (args.get(0).equalsIgnoreCase("g")) {
|
||||
args.remove(0);
|
||||
args.add(0, "group");
|
||||
}
|
||||
}
|
||||
|
||||
if (args.size() >= 3) {
|
||||
if (!args.get(0).equalsIgnoreCase("user") && !args.get(0).equalsIgnoreCase("group")) {
|
||||
return;
|
||||
@@ -299,6 +328,11 @@ public class CommandManager {
|
||||
args.add(2, "meta");
|
||||
break;
|
||||
case "i":
|
||||
case "about":
|
||||
case "list":
|
||||
args.remove(2);
|
||||
args.add(2, "info");
|
||||
break;
|
||||
case "inherit":
|
||||
case "inheritances":
|
||||
case "group":
|
||||
@@ -389,12 +423,24 @@ public class CommandManager {
|
||||
break;
|
||||
}
|
||||
|
||||
// provide lazy info
|
||||
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"))
|
||||
);
|
||||
|
||||
if (lazyInfo) {
|
||||
args.remove(3);
|
||||
args.add(3, "info");
|
||||
}
|
||||
|
||||
// Provide lazy set rewrite
|
||||
boolean lazySet = (
|
||||
args.size() >= 6 &&
|
||||
args.get(2).equalsIgnoreCase("permission") &&
|
||||
args.get(3).toLowerCase().startsWith("set") &&
|
||||
(args.get(5).equalsIgnoreCase("none") || args.get(5).equalsIgnoreCase("0"))
|
||||
args.get(2).equalsIgnoreCase("permission") &&
|
||||
args.get(3).toLowerCase().startsWith("set") &&
|
||||
(args.get(5).equalsIgnoreCase("none") || args.get(5).equalsIgnoreCase("0"))
|
||||
);
|
||||
|
||||
if (lazySet) {
|
||||
|
||||
+71
-4
@@ -20,12 +20,15 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.commands;
|
||||
package me.lucko.luckperms.common.commands.abstraction;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import me.lucko.luckperms.common.commands.Arg;
|
||||
import me.lucko.luckperms.common.commands.CommandException;
|
||||
import me.lucko.luckperms.common.commands.CommandResult;
|
||||
import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.constants.Permission;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
@@ -35,24 +38,46 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* An abstract command class
|
||||
*
|
||||
* @param <T> the type required by the {@link #execute(LuckPermsPlugin, Sender, Object, List, String)} method of this command
|
||||
* @param <S> the type of any child commands
|
||||
*/
|
||||
public abstract class Command<T, S> {
|
||||
|
||||
/**
|
||||
* The name of the command. Should be properly capitalised.
|
||||
*/
|
||||
@Getter
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* A brief description of this command
|
||||
*/
|
||||
@Getter
|
||||
private final String description;
|
||||
|
||||
// Could be null
|
||||
/**
|
||||
* The permission required to use this command. Nullable.
|
||||
*/
|
||||
private final Permission permission;
|
||||
|
||||
/**
|
||||
* A predicate used for testing the size of the arguments list passed to this command
|
||||
*/
|
||||
@Getter
|
||||
private final Predicate<Integer> argumentCheck;
|
||||
|
||||
// Could be null
|
||||
/**
|
||||
* A list of arguments required for the command. These are just here for informational purposes, and aren't used
|
||||
* for argument validation.
|
||||
*/
|
||||
private final List<Arg> args;
|
||||
|
||||
// Could be null
|
||||
/**
|
||||
* Child commands. Nullable.
|
||||
*/
|
||||
private final List<Command<S, ?>> children;
|
||||
|
||||
public Command(String name, String description, Permission permission, Predicate<Integer> argumentCheck, List<Arg> args, List<Command<S, ?>> children) {
|
||||
@@ -78,14 +103,56 @@ public abstract class Command<T, S> {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a brief command usage message to the Sender.
|
||||
* If this command has child commands, the children are listed. Otherwise, a basic usage message is sent.
|
||||
*
|
||||
* @param sender the sender to send the usage to
|
||||
* @param label the label used when executing the command
|
||||
*/
|
||||
public abstract void sendUsage(Sender sender, String label);
|
||||
|
||||
/**
|
||||
* Sends a detailed command usage message to the Sender.
|
||||
* If this command has child commands, nothing is sent. Otherwise, a detailed messaging containing a description
|
||||
* and argument usage is sent.
|
||||
*
|
||||
* @param sender the sender to send the usage to
|
||||
* @param label the label used when executing the command
|
||||
*/
|
||||
public abstract void sendDetailedUsage(Sender sender, String label);
|
||||
|
||||
/**
|
||||
* Returns true if the sender is authorised to use this command
|
||||
*
|
||||
* Commands with children are likely to override this method to check for permissions based upon whether
|
||||
* a sender has access to any sub commands.
|
||||
*
|
||||
* @param sender the sender
|
||||
* @return true if the sender has permission to use this command
|
||||
*/
|
||||
public boolean isAuthorized(Sender sender) {
|
||||
return permission == null || permission.isAuthorized(sender);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if this command should be displayed in command listings, or "hidden"
|
||||
*
|
||||
* @return if this command should be displayed in command listings, or "hidden"
|
||||
*/
|
||||
public boolean shouldDisplay() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the usage of this command. Will only return a non empty result for main commands.
|
||||
*
|
||||
* @return the usage of this command.
|
||||
*/
|
||||
public String getUsage() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public Optional<Permission> getPermission() {
|
||||
return Optional.ofNullable(permission);
|
||||
}
|
||||
+10
-14
@@ -20,10 +20,13 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.commands;
|
||||
package me.lucko.luckperms.common.commands.abstraction;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import me.lucko.luckperms.common.commands.CommandException;
|
||||
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.constants.Message;
|
||||
@@ -36,7 +39,7 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public abstract class MainCommand<T> extends BaseCommand<Void, T> {
|
||||
public abstract class MainCommand<T> extends Command<Void, T> {
|
||||
|
||||
@Getter
|
||||
private final String usage;
|
||||
@@ -55,7 +58,7 @@ public abstract class MainCommand<T> extends BaseCommand<Void, T> {
|
||||
return CommandResult.INVALID_ARGS;
|
||||
}
|
||||
|
||||
Optional<Command<T, ?>> o = getSubCommands().stream()
|
||||
Optional<Command<T, ?>> o = getChildren().get().stream()
|
||||
.filter(s -> s.getName().equalsIgnoreCase(args.get(minArgs - 1)))
|
||||
.limit(1)
|
||||
.findAny();
|
||||
@@ -112,7 +115,7 @@ public abstract class MainCommand<T> extends BaseCommand<Void, T> {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
final List<Command<T, ?>> subs = getSubCommands().stream()
|
||||
final List<Command<T, ?>> subs = getChildren().get().stream()
|
||||
.filter(s -> s.isAuthorized(sender))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
@@ -149,7 +152,7 @@ public abstract class MainCommand<T> extends BaseCommand<Void, T> {
|
||||
|
||||
@Override
|
||||
public void sendUsage(Sender sender, String label) {
|
||||
List<Command> subs = getSubCommands().stream()
|
||||
List<Command> subs = getChildren().get().stream()
|
||||
.filter(s -> s.isAuthorized(sender))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
@@ -167,23 +170,16 @@ public abstract class MainCommand<T> extends BaseCommand<Void, T> {
|
||||
|
||||
@Override
|
||||
public void sendDetailedUsage(Sender sender, String label) {
|
||||
|
||||
sendUsage(sender, label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAuthorized(Sender sender) {
|
||||
return getSubCommands().stream().filter(sc -> sc.isAuthorized(sender)).count() != 0;
|
||||
return getChildren().get().stream().filter(sc -> sc.isAuthorized(sender)).count() != 0;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public Optional<List<Command<T, ?>>> getChildren() {
|
||||
return super.getChildren();
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public List<Command<T, ?>> getSubCommands() {
|
||||
return getChildren().get();
|
||||
}
|
||||
}
|
||||
+49
-45
@@ -20,11 +20,10 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.commands.generic;
|
||||
package me.lucko.luckperms.common.commands.abstraction;
|
||||
|
||||
import me.lucko.luckperms.common.commands.CommandException;
|
||||
import me.lucko.luckperms.common.commands.CommandResult;
|
||||
import me.lucko.luckperms.common.commands.SubCommand;
|
||||
import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
|
||||
import me.lucko.luckperms.common.commands.utils.Util;
|
||||
@@ -39,46 +38,18 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* A shared main command. Shared meaning it can apply to both users and groups.
|
||||
* This extends sub command as they're actually sub commands of the main user/group commands.
|
||||
* @param <T>
|
||||
*/
|
||||
public class SharedMainCommand<T extends PermissionHolder> extends SubCommand<T> {
|
||||
private static CommandResult handleException(CommandException e, Sender sender, SharedSubCommand command) {
|
||||
if (e instanceof ArgumentUtils.ArgumentException) {
|
||||
if (e instanceof ArgumentUtils.DetailedUsageException) {
|
||||
command.sendDetailedUsage(sender);
|
||||
return CommandResult.INVALID_ARGS;
|
||||
}
|
||||
|
||||
if (e instanceof ArgumentUtils.UseInheritException) {
|
||||
Message.USE_INHERIT_COMMAND.send(sender);
|
||||
return CommandResult.INVALID_ARGS;
|
||||
}
|
||||
|
||||
if (e instanceof ArgumentUtils.InvalidServerException) {
|
||||
Message.SERVER_INVALID_ENTRY.send(sender);
|
||||
return CommandResult.INVALID_ARGS;
|
||||
}
|
||||
|
||||
if (e instanceof ArgumentUtils.PastDateException) {
|
||||
Message.PAST_DATE_ERROR.send(sender);
|
||||
return CommandResult.INVALID_ARGS;
|
||||
}
|
||||
|
||||
if (e instanceof ArgumentUtils.InvalidDateException) {
|
||||
Message.ILLEGAL_DATE_ERROR.send(sender, ((ArgumentUtils.InvalidDateException) e).getInvalidDate());
|
||||
return CommandResult.INVALID_ARGS;
|
||||
}
|
||||
|
||||
if (e instanceof ArgumentUtils.InvalidPriorityException) {
|
||||
Message.META_INVALID_PRIORITY.send(sender, ((ArgumentUtils.InvalidPriorityException) e).getInvalidPriority());
|
||||
return CommandResult.INVALID_ARGS;
|
||||
}
|
||||
}
|
||||
|
||||
// Not something we can catch.
|
||||
e.printStackTrace();
|
||||
return CommandResult.FAILURE;
|
||||
}
|
||||
|
||||
private final List<SharedSubCommand> secondaryCommands;
|
||||
|
||||
/**
|
||||
* If this instance of the shared command is targeting a user. Otherwise, it targets a group.
|
||||
*/
|
||||
private boolean user;
|
||||
|
||||
public SharedMainCommand(String name, String description, boolean user, List<SharedSubCommand> secondaryCommands) {
|
||||
@@ -162,12 +133,7 @@ public class SharedMainCommand<T extends PermissionHolder> extends SubCommand<T>
|
||||
|
||||
@Override
|
||||
public boolean isAuthorized(Sender sender) {
|
||||
for (SharedSubCommand subCommand : secondaryCommands) {
|
||||
if (subCommand.isAuthorized(sender, user)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return secondaryCommands.stream().filter(sc -> sc.isAuthorized(sender, user)).count() != 0;
|
||||
}
|
||||
|
||||
private void sendUsageDetailed(Sender sender, boolean user, String label) {
|
||||
@@ -190,4 +156,42 @@ public class SharedMainCommand<T extends PermissionHolder> extends SubCommand<T>
|
||||
Message.COMMAND_NO_PERMISSION.send(sender);
|
||||
}
|
||||
}
|
||||
|
||||
private static CommandResult handleException(CommandException e, Sender sender, SharedSubCommand command) {
|
||||
if (e instanceof ArgumentUtils.ArgumentException) {
|
||||
if (e instanceof ArgumentUtils.DetailedUsageException) {
|
||||
command.sendDetailedUsage(sender);
|
||||
return CommandResult.INVALID_ARGS;
|
||||
}
|
||||
|
||||
if (e instanceof ArgumentUtils.UseInheritException) {
|
||||
Message.USE_INHERIT_COMMAND.send(sender);
|
||||
return CommandResult.INVALID_ARGS;
|
||||
}
|
||||
|
||||
if (e instanceof ArgumentUtils.InvalidServerException) {
|
||||
Message.SERVER_INVALID_ENTRY.send(sender);
|
||||
return CommandResult.INVALID_ARGS;
|
||||
}
|
||||
|
||||
if (e instanceof ArgumentUtils.PastDateException) {
|
||||
Message.PAST_DATE_ERROR.send(sender);
|
||||
return CommandResult.INVALID_ARGS;
|
||||
}
|
||||
|
||||
if (e instanceof ArgumentUtils.InvalidDateException) {
|
||||
Message.ILLEGAL_DATE_ERROR.send(sender, ((ArgumentUtils.InvalidDateException) e).getInvalidDate());
|
||||
return CommandResult.INVALID_ARGS;
|
||||
}
|
||||
|
||||
if (e instanceof ArgumentUtils.InvalidPriorityException) {
|
||||
Message.META_INVALID_PRIORITY.send(sender, ((ArgumentUtils.InvalidPriorityException) e).getInvalidPriority());
|
||||
return CommandResult.INVALID_ARGS;
|
||||
}
|
||||
}
|
||||
|
||||
// Not something we can catch.
|
||||
e.printStackTrace();
|
||||
return CommandResult.FAILURE;
|
||||
}
|
||||
}
|
||||
Loaded 100 of 328 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user