Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
175a21c0e4 | ||
|
|
a2801bff7c | ||
|
|
f1a50f433f | ||
|
|
76bfde4d77 | ||
|
|
d393a4c9ca | ||
|
|
9ea6b0b8bb | ||
|
|
c20b91d5ea | ||
|
|
fad8a38bdf | ||
|
|
2440a38e82 | ||
|
|
b7541c43c8 | ||
|
|
0f10bb0bc9 | ||
|
|
357717886e | ||
|
|
94a4051d29 | ||
|
|
0e581cbcf3 | ||
|
|
230d9725e8 | ||
|
|
dee41b315f | ||
|
|
72e6c75433 | ||
|
|
ebe12f838c | ||
|
|
7279fdc25f | ||
|
|
af5c859385 | ||
|
|
e8896fbdf7 | ||
|
|
54695b8046 | ||
|
|
c573c755d2 | ||
|
|
b299301b69 | ||
|
|
a3a7198777 | ||
|
|
ca8cc91f37 | ||
|
|
26c813c07b | ||
|
|
f109cb684a | ||
|
|
1baefaade4 | ||
|
|
5ac0f93214 | ||
|
|
ecfbed00b1 | ||
|
|
6e429d6c78 | ||
|
|
fa4bb0447a | ||
|
|
aa0be40124 | ||
|
|
04d5310c04 | ||
|
|
74069af309 | ||
|
|
6bfeec6d16 | ||
|
|
0f4c057395 | ||
|
|
2fd74f3b7e | ||
|
|
fb171a57c2 | ||
|
|
b26fc69e73 | ||
|
|
28961b1cfa | ||
|
|
597f2f7b1b | ||
|
|
00cd8bb3f3 | ||
|
|
5732e60510 | ||
|
|
7b271e21e3 | ||
|
|
1a5f9683c2 | ||
|
|
3b74d55442 | ||
|
|
8920396360 | ||
|
|
9c505e4402 | ||
|
|
de4c6b384c | ||
|
|
6dec1ba8af | ||
|
|
9e6788de2f | ||
|
|
1bd7e5c9c4 | ||
|
|
ec75fdddb5 | ||
|
|
f98aafb97c | ||
|
|
f4d2a0daf9 | ||
|
|
de8fb8de90 | ||
|
|
44d137b8f9 | ||
|
|
777c972bdc | ||
|
|
f9efa15781 | ||
|
|
1d1cd679dd | ||
|
|
a9ed4686dd | ||
|
|
5b742eb5b2 | ||
|
|
a3d78f4d0e | ||
|
|
214929e5e5 | ||
|
|
67602b8d85 | ||
|
|
2412edaa3a | ||
|
|
b1584aa2c3 | ||
|
|
a14a416193 | ||
|
|
f3251e9407 | ||
|
|
096885d91f | ||
|
|
368700156c | ||
|
|
81cf50520b | ||
|
|
649748c2d3 | ||
|
|
bf7a708440 | ||
|
|
8faa4d137b | ||
|
|
479bd91b74 | ||
|
|
6bc7f1fca2 | ||
|
|
dadd8e2c50 | ||
|
|
03f342a21c | ||
|
|
7fe5397e21 | ||
|
|
b6e1fd179e | ||
|
|
754c7d8e3b | ||
|
|
925d3ccd1b | ||
|
|
d60d0ac9c5 | ||
|
|
e1b51dd6af | ||
|
|
fbe9d9f128 | ||
|
|
509826949d | ||
|
|
39aaa8a292 | ||
|
|
069c76c53a | ||
|
|
f45c0caa45 | ||
|
|
41b0e10709 | ||
|
|
8e8da20c13 | ||
|
|
269aa39378 | ||
|
|
ae8be97db7 | ||
|
|
f0ad40825b | ||
|
|
36d292747a | ||
|
|
b65d2262bf | ||
|
|
a7ab0c6b36 | ||
|
|
c02fcb6508 | ||
|
|
07c38de44b | ||
|
|
188d62c99b | ||
|
|
76b203ad10 | ||
|
|
909844aef5 | ||
|
|
046202719a | ||
|
|
ed15e2838d |
No files matched your search
+157
-167
@@ -3,53 +3,46 @@
|
||||
# Author: Luck
|
||||
|
||||
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: "&aOnline"
|
||||
player-offline: "&cOffline"
|
||||
loading-error: "Permissions data could not be loaded. Please try again later."
|
||||
loading-error: "&cPermissions 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."
|
||||
op-disabled-sponge: "&2Please note that Server Operator status has no effect on Sponge permission checks when a permission plugin is installed. Please edit user data directly."
|
||||
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}"
|
||||
log: "&3LOG &3&l> {0}"
|
||||
verbose-log: "&3VERBOSE &3&l> {0}"
|
||||
verbose-log: "&3VB &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-save-success: "&7(User data was saved to storage)"
|
||||
user-save-error: "There was an error whilst saving the user."
|
||||
group-not-found: "&bGroup could not be found."
|
||||
group-save-success: "&7(Group data was saved to storage)"
|
||||
group-save-error: "There was an error whilst saving the group."
|
||||
track-not-found: "&bTrack could not be found."
|
||||
track-save-success: "&7(Track data was saved to storage)"
|
||||
track-save-error: "There was an error whilst saving the track."
|
||||
user-invalid-entry: "&d{0}&c is not a valid username/uuid."
|
||||
group-invalid-entry: "Group names can only contain alphanumeric characters."
|
||||
track-invalid-entry: "Track names can only contain alphanumeric characters."
|
||||
server-world-invalid-entry: "Server/world names can only contain alphanumeric characters and cannot exceed 36 characters in length."
|
||||
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 filter: &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 filter: &f{0}"
|
||||
verbose-recording-upload-start: "&bVerbose recording was disabled. Uploading results..."
|
||||
verbose-recording-url: "&aVerbose results URL:"
|
||||
command-not-recognised: "&cCommand not recognised."
|
||||
command-no-permission: "&cYou do not have permission to use this command!"
|
||||
user-not-found: "&cA user for &4{0}&c could not be found."
|
||||
user-not-online: "&aUser &b{0}&a is not online."
|
||||
user-save-error: "&cThere was an error whilst saving user data for &4{0}&c."
|
||||
group-not-found: "&cA group named &4{0}&c could not be found."
|
||||
group-save-error: "&cThere was an error whilst saving group data for &4{0}&c."
|
||||
track-not-found: "&cA track named &4{0}&c could not be found."
|
||||
track-save-error: "&cThere was an error whilst saving track data for &4{0}&c."
|
||||
user-invalid-entry: "&4{0}&c is not a valid username/uuid."
|
||||
group-invalid-entry: "&4{0}&c is not a valid group name."
|
||||
track-invalid-entry: "&4{0}&c is not a valid track name."
|
||||
server-world-invalid-entry: "&cServer/world names can only contain alphanumeric characters and cannot exceed 36 characters in length."
|
||||
use-inherit-command: "&cUse the 'parent add' and 'parent remove' commands instead of specifying the node."
|
||||
verbose-invalid-filter: "&4{0}&c is not a valid verbose filter."
|
||||
verbose-on: "&bVerbose logging &aenabled &bfor checks matching &aANY&b."
|
||||
verbose-on-query: "&bVerbose logging &aenabled &bfor checks matching &a{0}&b."
|
||||
verbose-off: "&bVerbose logging &cdisabled&b."
|
||||
verbose-recording-on: "&bVerbose recording &aenabled &bfor checks matching &aANY&b."
|
||||
verbose-recording-on-query: "&bVerbose recording &aenabled &bfor checks matching &a{0}&b."
|
||||
verbose-upload-start: "&bVerbose logging &cdisabled&b. Uploading results..."
|
||||
verbose-results-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:"
|
||||
tree-empty: "&cUnable to generate tree. No results were found."
|
||||
tree-url: "&aPermission tree URL:"
|
||||
search-searching: "&aSearching for users and groups with &b{0}&a..."
|
||||
search-searching-members: "&aSearching for users and groups who inherit from &b{0}&a..."
|
||||
search-result: "&aFound &b{0}&a entries from &b{1}&a users and &b{2}&a groups."
|
||||
@@ -57,13 +50,13 @@ 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}"
|
||||
apply-edits-invalid-code: "&aInvalid code. &7({0})"
|
||||
apply-edits-unable-to-read: "&aUnable to read data using the given code. &7({0})"
|
||||
apply-edits-no-target: "&aUnable to parse the target of the edit. Please supply it as an extra argument."
|
||||
apply-edits-target-group-not-exists: "&aTarget group &b{0}&a does not exist."
|
||||
apply-edits-target-user-not-uuid: "&aTarget user &b{0}&a is not a valid uuid."
|
||||
apply-edits-target-user-unable-to-load: "&aUnable to load target user &b{0}&a."
|
||||
apply-edits-target-unknown: "&aInvalid target. &7({0})"
|
||||
apply-edits-invalid-code: "&cInvalid code. &7({0})"
|
||||
apply-edits-unable-to-read: "&cUnable to read data using the given code. &7({0})"
|
||||
apply-edits-no-target: "&cUnable to parse the target of the edit. Please supply it as an extra argument."
|
||||
apply-edits-target-group-not-exists: "&cTarget group &4{0}&c does not exist."
|
||||
apply-edits-target-user-not-uuid: "&cTarget user &4{0}&c is not a valid uuid."
|
||||
apply-edits-target-user-unable-to-load: "&cUnable to load target user &4{0}&c."
|
||||
apply-edits-target-unknown: "&cInvalid target. &7({0})"
|
||||
apply-edits-success: "&aSuccessfully applied &b{0}&a nodes to &b{1}&a."
|
||||
editor-upload-failure: "&cUnable to upload permission data to the editor."
|
||||
editor-url: "&aEditor URL:"
|
||||
@@ -72,85 +65,74 @@ 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 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."
|
||||
groups-load-error: "An unexpected error occurred. Unable to load all groups."
|
||||
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."
|
||||
already-inherits: "&b{0}&a already inherits from &b{1}&a in context {2}&a."
|
||||
does-not-inherit: "&b{0}&a does not inherit from &b{1}&a in context {2}&a."
|
||||
already-temp-inherits: "&b{0}&a already temporarily inherits from &b{1}&a in context {2}&a."
|
||||
does-not-temp-inherit: "&b{0}&a does not temporarily inherit from &b{1}&a in context {2}&a."
|
||||
track-already-contains: "&b{0}&a already contains &b{1}&a."
|
||||
track-does-not-contain: "&b{0}&a doesn't contain &b{1}&a."
|
||||
track-ambiguous-call: "&4{0}&c is a member of multiple groups on this track. Unable to determine their location."
|
||||
already-exists: "&4{0}&c already exists!"
|
||||
does-not-exist: "&4{0}&c does not exist!"
|
||||
group-load-error: "&cAn unexpected error occurred. Group not loaded."
|
||||
groups-load-error: "&cAn unexpected error occurred. Unable to load all groups."
|
||||
track-load-error: "&cAn unexpected error occurred. Track not loaded."
|
||||
tracks-load-error: "&cAn unexpected error occurred. Unable to load all tracks."
|
||||
track-empty: "&4{0}&c cannot be used as it is empty or contains only one group."
|
||||
update-task-request: "&bAn update task has been requested. Please wait..."
|
||||
update-task-complete: "&aUpdate task complete."
|
||||
update-task-complete-network: "&aUpdate task complete. Now attempting to push to other servers."
|
||||
update-task-push-success: "&aOther servers were notified via &b{0} Messaging &asuccessfully."
|
||||
update-task-push-failure: "&cError whilst pushing changes to other servers."
|
||||
update-task-push-failure-not-setup: "&cError whilst pushing changes to other servers. A messaging service has not been configured."
|
||||
reload-config-success: "&aThe configuration file was reloaded. &7(some options will only apply after the server has restarted.)"
|
||||
info: >
|
||||
update-task-push-failure-not-setup: "&cError whilst pushing changes to other servers. &7(a messaging service has not been configured)"
|
||||
reload-config-success: "&aThe configuration file was reloaded. &7(some options will only apply after the server has restarted)"
|
||||
info-top: >
|
||||
{PREFIX}&2Running &bLuckPerms v{0}&2 by &bLuck&2.\n
|
||||
{PREFIX}&f- &3Platform: &f{1}\n
|
||||
{PREFIX}&f- &3Storage Method: &f{2}\n
|
||||
{PREFIX}&f- &3Server Name: &f{3}\n
|
||||
{PREFIX}&f- &3Sync Interval: &a{4} &fminutes\n
|
||||
{PREFIX}&f- &3Messaging Service: &f{5}\n
|
||||
{PREFIX}&f- &bCounts:\n
|
||||
{PREFIX}&f- &3Online Players: &a{6}\n
|
||||
{PREFIX}&f- &3Loaded Users: &a{7}\n
|
||||
{PREFIX}&f- &3Loaded Groups: &a{8}\n
|
||||
{PREFIX}&f- &3Loaded Tracks: &a{9}\n
|
||||
{PREFIX}&f- &3Log size: &a{10}\n
|
||||
{PREFIX}&f- &3UUID Cache size: &a{11}\n
|
||||
{PREFIX}&f- &3Translations loaded: &a{12}\n
|
||||
{PREFIX}&f- &3Pre-process contexts: &a{13}\n
|
||||
{PREFIX}&f- &3Context Calculators: &a{14}\n
|
||||
{PREFIX}&f- &3Unique permissions: &a{15}\n
|
||||
{PREFIX}&f- &bConfiguration:\n
|
||||
{PREFIX}&f- &3Use Server UUIDs: {16}\n
|
||||
{PREFIX}&f- &bPermission Calculation:\n
|
||||
{PREFIX}&f- &3Including Global: {17}\n
|
||||
{PREFIX}&f- &3Including Global World: {18}\n
|
||||
{PREFIX}&f- &3Applying Global Groups: {19}\n
|
||||
{PREFIX}&f- &3Applying Global World Groups: {20}\n
|
||||
{PREFIX}&f- &3Applying Wildcards: {21}\n
|
||||
{PREFIX}&f- &3Applying Regex: {22}\n
|
||||
{PREFIX}&f- &3Applying Shorthand: {23}
|
||||
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."
|
||||
{PREFIX}&f- &3Server Brand: &f{2}\n
|
||||
{PREFIX}&f- &3Server Version: &f{3}
|
||||
info-middle: >
|
||||
{PREFIX}&f- &bMessaging Type: &f{0}\n
|
||||
{PREFIX}&f- &bInstance:\n
|
||||
{PREFIX}&f- &3Server Name: &f{1}\n
|
||||
{PREFIX}&f- &3Online Players: &a{2}\n
|
||||
{PREFIX}&f- &3Unique Connections: &a{3}\n
|
||||
{PREFIX}&f- &3Uptime: &7{4}\n
|
||||
{PREFIX}&f- &3Local Data: &a{5} &7users, &a{6} &7groups, &a{7} &7tracks\n
|
||||
{PREFIX}&f- &3Context Calculators: &a{8}\n
|
||||
{PREFIX}&f- &3Known permissions: &a{9}\n
|
||||
{PREFIX}&f- &3Active processors: &7{10}
|
||||
create-error: "&cThere was an error whilst creating &4{0}&c."
|
||||
delete-error: "&cThere was an error whilst deleting &4{0}&c."
|
||||
delete-group-error-default: "&cYou cannot delete the default group."
|
||||
groups-list: "&aGroups: &7(name, weight, tracks)"
|
||||
groups-list-entry: "&f- &3{0} &7- &b{1}"
|
||||
groups-list-entry-with-tracks: "&f- &3{0} &7- &b{1} &7- [&3{2}&7]"
|
||||
create-track-error: "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:"
|
||||
listnodes-temp-with-page: "&b{0}'s Temporary Nodes: {1}"
|
||||
listnodes: "&b{0}'s Permissions:"
|
||||
listnodes-with-page: "&b{0}'s Permissions: {1}"
|
||||
listnodes-temp: "&b{0}'s Temporary Permissions:"
|
||||
listnodes-temp-with-page: "&b{0}'s Temporary Permissions: {1}"
|
||||
listparents: "&b{0}'s Parent Groups:"
|
||||
listparents-temp: "&b{0}'s Temporary Parent Groups:"
|
||||
list-tracks: >
|
||||
&b{0}'s Tracks:\n
|
||||
{1}
|
||||
list-tracks-empty: "{0} is not on any tracks."
|
||||
list-tracks-empty: "&b{0}&a is not on any tracks."
|
||||
context-pair-inline: "&3{0}=&b{1}"
|
||||
context-pair--global-inline: "&eglobal"
|
||||
context-pair-sep: "&a, "
|
||||
context-pair: "&8(&7{0}=&f{1}&8)"
|
||||
check-permission: "&b{0}&a has permission &b{1}&a set to {2}&a in context {3}&a."
|
||||
check-inherits-permission: "&b{0}&a has permission &b{1}&a set to {2}&a in context {3}&a. &7(inherited from &a{4}&7)"
|
||||
setpermission-success: "&aSet &b{0}&a to &b{1}&a for &b{2}&a in context {3}&a."
|
||||
already-haspermission: "&b{0}&a already has &b{1}&a set in context {2}&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."
|
||||
already-has-temp-permission: "&b{0}&a already has &b{1}&a set temporarily in context {2}&a."
|
||||
unsetpermission-success: "&aUnset &b{0}&a for &b{1}&a in context {2}&a."
|
||||
does-not-have-permission: "&b{0}&a does not have &b{1}&a set in context {2}&a."
|
||||
unset-temp-permission-success: "&aUnset temporary permission &b{0}&a for &b{1}&a in context {2}&a."
|
||||
does-not-have-temp-permission: "&b{0}&a does not have &b{1}&a set temporarily 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."
|
||||
@@ -159,41 +141,46 @@ unset-inherit-success: "&b{0}&a no longer inherits permissions from &b{1}&a in c
|
||||
unset-temp-inherit-success: "&b{0}&a no longer temporarily inherits permissions from &b{1}&a in context {2}&a."
|
||||
clear-success: "&b{0}&a's permissions were cleared in context {1}&a. (&b{2}&a nodes were removed.)"
|
||||
clear-success-singular: "&b{0}&a's permissions were cleared in context {1}&a. (&b{2}&a node was removed.)"
|
||||
parent-clear-success: "&b{0}&a's parents were cleared in context {1}&a. &b{2}&a nodes were removed.)"
|
||||
parent-clear-success-singular: "&b{0}&a's parents were cleared in context {1}&a. &b{2}&a node was removed.)"
|
||||
parent-clear-track-success: "&b{0}&a's parents on track &b{1}&a were cleared in context {2}&a. &b{3}&a nodes were removed.)"
|
||||
parent-clear-track-success-singular: "&b{0}&a's parents on track &b{1}&a were cleared in context {2}&a. &b{3}&a node was removed.)"
|
||||
meta-clear-success: "&b{0}&a's meta was cleared in context {1}&a. &b{2}&a nodes were removed.)"
|
||||
meta-clear-success-singular: "&b{0}&a's meta was cleared in context {1}&a. &b{2}&a node was removed.)"
|
||||
illegal-date-error: "Could not parse date '{0}'."
|
||||
past-date-error: "You cannot set a date in the past!"
|
||||
parent-clear-success: "&b{0}&a's parents were cleared in context {1}&a. (&b{2}&a nodes were removed.)"
|
||||
parent-clear-success-singular: "&b{0}&a's parents were cleared in context {1}&a. (&b{2}&a node was removed.)"
|
||||
parent-clear-track-success: "&b{0}&a's parents on track &b{1}&a were cleared in context {2}&a. (&b{3}&a nodes were removed.)"
|
||||
parent-clear-track-success-singular: "&b{0}&a's parents on track &b{1}&a were cleared in context {2}&a. (&b{3}&a node was removed.)"
|
||||
meta-clear-success: "&b{0}&a's meta matching type &b{1}&a was cleared in context {2}&a. (&b{3}&a nodes were removed.)"
|
||||
meta-clear-success-singular: "&b{0}&a's meta matching type &b{1}&a was cleared in context {2}&a. (&b{3}&a node was removed.)"
|
||||
illegal-date-error: "&cCould not parse date &4{0}&c."
|
||||
past-date-error: "&cYou 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"
|
||||
chat-meta-entry: "&b-> {0} &f- &f\"{1}&f\" &8(&7inherited from &a{2}&8)"
|
||||
chat-meta-entry-with-context: "&b-> {0} &f- &f\"{1}&f\" &8(&7inherited from &a{2}&8){3}"
|
||||
meta-entry: "&b-> &a{0} &f= &f\"{1}&f\" &8(&7inherited from &a{2}&8)"
|
||||
meta-entry-with-context: "&b-> &a{0} &f= &f\"{1}&f\" &8(&7inherited from &a{2}&8){3}"
|
||||
chat-meta-entry: "&b-> {0} &f- &f'{1}&f' &8(&7inherited from &a{2}&8)"
|
||||
chat-meta-entry-with-context: "&b-> {0} &f- &f'{1}&f' &8(&7inherited from &a{2}&8){3}"
|
||||
meta-entry: "&b-> &a{0} &f= &f'{1}&f' &8(&7inherited from &a{2}&8)"
|
||||
meta-entry-with-context: "&b-> &a{0} &f= &f'{1}&f' &8(&7inherited from &a{2}&8){3}"
|
||||
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-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."
|
||||
meta-invalid-priority: "&cInvalid priority &4{0}&c. Expected a number."
|
||||
already-has-chat-meta: "&b{0}&a already has {1} &f'{2}&f'&a set at a priority of &b{3}&a in context {4}&a."
|
||||
already-has-temp-chat-meta: "&b{0}&a already has {1} &f'{2}&f'&a set temporarily at a priority of &b{3}&a in context {4}&a."
|
||||
does-not-have-chat-meta: "&b{0}&a doesn't have {1} &f'{2}&f'&a set at a priority of &b{3}&a in context {4}&a."
|
||||
does-not-have-temp-chat-meta: "&b{0}&a doesn't have {1} &f'{2}&f'&a set temporarily at a priority of &b{3}&a in context {4}&a."
|
||||
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{2}&a removed in context {3}&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."
|
||||
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{2}&a removed in context {3}&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 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-update-invalid-data-type: "Invalid type. Was expecting 'all', 'users' or 'groups'."
|
||||
bulk-update-invalid-constraint: "Invalid constraint &4{0}&c. Constraints should be in the format '&f<field> <comparison operator> <value>&c'."
|
||||
bulk-update-invalid-comparison: "Invalid comparison operator '&4{0}&c'. Expected one of the following: &f== != ~~ ~!"
|
||||
already-has-meta: "&b{0}&a already has meta key &f'{1}&f'&a set to &f'{2}&f'&a in context {3}&a."
|
||||
already-has-temp-meta: "&b{0}&a already has meta key &f'{1}&f'&a temporarily set to &f'{2}&f'&a in context {3}&a."
|
||||
doesnt-have-meta: "&b{0}&a doesn't have meta key &f'{1}&f'&a set in context {2}&a."
|
||||
doesnt-have-temp-meta: "&b{0}&a doesn't have meta key &f'{1}&f'&a set temporarily in context {2}&a."
|
||||
set-meta-success: "&aSet meta key &f'{0}&f'&a to &f'{1}&f'&a for &b{2}&a in context {3}&a."
|
||||
set-meta-temp-success: "&aSet meta 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 key &f'{0}&f'&a for &b{1}&a in context {2}&a."
|
||||
unset-meta-temp-success: "&aUnset temporary meta key &f'{0}&f'&a for &b{1}&a in context {2}&a."
|
||||
bulk-update-invalid-data-type: "&cInvalid type. Was expecting 'all', 'users' or 'groups'."
|
||||
bulk-update-invalid-constraint: "&cInvalid constraint &4{0}&c. Constraints should be in the format '&f<field> <comparison operator> <value>&c'."
|
||||
bulk-update-invalid-comparison: "&cInvalid comparison operator '&4{0}&c'. Expected one of the following: &f== != ~~ ~!"
|
||||
bulk-update-queued: "&aBulk update operation was queued. &7(&f{0}&7)"
|
||||
bulk-update-confirm: "&aRun &b/{0} bulkupdate confirm {1} &ato execute the update."
|
||||
bulk-update-unknown-id: "&aOperation with id &b{0}&a does not exist or has expired."
|
||||
@@ -206,8 +193,8 @@ user-info-general: >
|
||||
{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- &3Nodes: &a{4}\n
|
||||
{PREFIX}&f- &3Permissions: &a{5}\n
|
||||
{PREFIX}&f- &3Prefixes: &a{6}\n
|
||||
{PREFIX}&f- &3Suffixes: &a{7}\n
|
||||
{PREFIX}&f- &3Meta: &a{8}
|
||||
@@ -219,30 +206,30 @@ user-info-data: >
|
||||
{PREFIX}&f- &3Current Suffix: {3}
|
||||
info-parent-header: "&f- &aParent Groups:"
|
||||
info-temp-parent-header: "&f- &aTemporary Parent Groups:"
|
||||
user-removegroup-error-primary: "You cannot remove a user from their primary group."
|
||||
user-removegroup-error-primary: "&aYou 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-warn-option: "&aWarning: The primary group calculation method being used by this server &7({0}) &amay not reflect this change."
|
||||
user-primarygroup-error-alreadyhas: "&b{0}&a already has &b{1}&a 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."
|
||||
user-track-error-not-contain-group: "&b{0}&a isn't already in any groups on &b{1}&a."
|
||||
user-track-added-to-first: "&b{0}&a isn't in any groups on this track, so they were added to the first group, &b{1}&a in context {2}&a."
|
||||
user-promote-success: "&aPromoting user along track &b{0}&a from &b{1}&a to &b{2}&a in context {3}&a."
|
||||
user-promote-error-endoftrack: "The end of track &4{0}&c was reached. Unable to promote user."
|
||||
user-promote-success: "&aPromoting &b{0}&a along track &b{1}&a from &b{2}&a to &b{3}&a in context {4}&a."
|
||||
user-promote-error-endoftrack: "&aThe end of track &b{0}&a was reached. Unable to promote &b{1}&a."
|
||||
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: "&aDemoting user along track &b{0}&a from &b{1}&a to &b{2}&a in context {3}&a."
|
||||
user-demote-endoftrack: "The end of track &4{0}&c was reached, so &4{1}&c was removed from &4{2}&c."
|
||||
{PREFIX}&aThe next group on the track, &b{0}&a, no longer exists. Unable to promote user.\n
|
||||
{PREFIX}&aEither create the group, or remove it from the track and try again.
|
||||
user-demote-success: "&aDemoting &b{0}&a along track &b{1}&a from &b{2}&a to &b{3}&a in context {4}&a."
|
||||
user-demote-endoftrack: "&aThe end of track &b{0}&a was reached, so &b{1}&a was removed from &b{2}&a."
|
||||
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.
|
||||
{PREFIX}&aThe previous group on the track, &b{0}&a, no longer exists. Unable to demote user.\n
|
||||
{PREFIX}&aEither create the group, or remove it from the track and try again.
|
||||
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- &3Nodes: &a{3}\n
|
||||
{PREFIX}&f- &3Permissions: &a{4}\n
|
||||
{PREFIX}&f- &3Prefixes: &a{5}\n
|
||||
{PREFIX}&f- &3Suffixes: &a{6}\n
|
||||
{PREFIX}&f- &3Meta: &a{7}
|
||||
@@ -251,39 +238,40 @@ track-info: >
|
||||
{PREFIX}&b&l> &bShowing Track: &f{0}\n
|
||||
{PREFIX}&f- &7Path: &f{1}
|
||||
track-clear: "&b{0}&a's groups track was cleared."
|
||||
track-append-success: "&aGroup &b{0}&a was successfully appended to track &b{1}&a."
|
||||
track-insert-success: "&aGroup &b{0}&a was successfully inserted into track &b{1}&a at position &b{2}&a."
|
||||
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}."
|
||||
track-append-success: "&aGroup &b{0}&a was appended to track &b{1}&a."
|
||||
track-insert-success: "&aGroup &b{0}&a was inserted into track &b{1}&a at position &b{2}&a."
|
||||
track-insert-error-number: "&cExpected number but instead received: {0}"
|
||||
track-insert-error-invalid-pos: "&cUnable to insert at position &4{0}&c. &7(invalid position)"
|
||||
track-remove-success: "&aGroup &b{0}&a was removed from track &b{1}&a."
|
||||
log-load-error: "&cThe log could not be loaded."
|
||||
log-invalid-page: "&cInvalid page number."
|
||||
log-invalid-page-range: "&cInvalid page number. Please enter a value between &41&c and &4{0}&c."
|
||||
log-no-entries: "&bNo log entries to show."
|
||||
log-entry: "&b#{0} -> &8(&7{1} ago&8) {2}"
|
||||
log-notify-console: "&cCannot toggle notifications for console."
|
||||
log-notify-toggle-on: "&aEnabled&b logging output."
|
||||
log-notify-toggle-off: "&cDisabled&b logging output."
|
||||
log-notify-already-on: "You are already receiving notifications."
|
||||
log-notify-already-off: "You aren't currently receiving notifications."
|
||||
log-notify-unknown: "State unknown. Expecting \"on\" or \"off\"."
|
||||
log-notify-already-on: "&cYou are already receiving notifications."
|
||||
log-notify-already-off: "&cYou aren't currently receiving notifications."
|
||||
log-notify-unknown: "&cState 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-already-exists: "&cError: File &4{0}&c already exists."
|
||||
log-export-not-writable: "&cError: File &4{0}&c is not writable."
|
||||
log-export-empty: "&cThe log is empty and therefore cannot be exported."
|
||||
log-export-failure: "&cAn 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-already-running: "&cAnother import process is already running. Please wait for it to finish and try again."
|
||||
export-already-running: "&cAnother export process is already running. Please wait for it to finish and try again."
|
||||
import-log-doesnt-exist: "&cError: File &4{0}&c does not exist."
|
||||
import-log-not-readable: "&cError: File &4{0}&c is not readable."
|
||||
import-log-failure: "&cAn unexpected error occured whilst reading from the log file."
|
||||
import-progress: "&b(Import) &b-> &f{0}&f% complete &7- &b{1}&f/&b{2} &foperations complete with &c{3} &ferrors."
|
||||
import-progress-sin: "&b(Import) &b-> &f{0}&f% 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."
|
||||
@@ -322,6 +310,7 @@ command-specs:
|
||||
args:
|
||||
"on|record|off|paste": "whether to enable/disable logging, or to paste the logged output"
|
||||
"filter": "the filter to match entries against"
|
||||
"--slim": "add \"--slim\" to exclude trace data from the pasted output"
|
||||
tree:
|
||||
description: "Generate a tree view of permissions"
|
||||
usage: "/%s tree [selection] [max level] [player]"
|
||||
@@ -606,8 +595,9 @@ command-specs:
|
||||
"suffix": "the suffix string"
|
||||
"context...": "the contexts to remove the suffix in"
|
||||
meta-clear:
|
||||
description: "Clears all chat meta"
|
||||
description: "Clears all meta"
|
||||
args:
|
||||
"type": "the type of meta to remove"
|
||||
"context...": "the contexts to filter by"
|
||||
track-info:
|
||||
description: "Gives info about the track"
|
||||
|
||||
@@ -0,0 +1,728 @@
|
||||
# LuckPerms Language File
|
||||
# Locale: hu_HU (Hungarian)
|
||||
# Author: montlikadani
|
||||
|
||||
prefix: "&7&l[&b&lL&3&lP&7&l] &c"
|
||||
empty: "{0}"
|
||||
player-online: "&aOnline"
|
||||
player-offline: "&cOffline"
|
||||
loading-error: "&cNem sikerült betölteni az engedélyezési adatokat. Kérlek, próbáld újra később."
|
||||
op-disabled: "&bA vanilla OP rendszer le van tiltva ezen a szerveren."
|
||||
op-disabled-sponge: "&2Kérjük, vegye figyelembe, hogy a kiszolgálói operátor állapota nem befolyásolja a Sponge engedély-ellenőrzéseket, ha engedélyezési bővítmény van telepítve. Kérjük, közvetlenül módosítsa a felhasználói adatokat."
|
||||
log-info: "&7&l[&bL&3P&7&l] &3{0}"
|
||||
log-warn: "&7&l[&bLuck&3Perms&7&l] &c[FIGYELEM] {0}"
|
||||
log-error: "&7&l[&bLuck&3Perms&7&l] &4[HIBA] {0}"
|
||||
log: "&3LOG &3&l> {0}"
|
||||
verbose-log: "&3VB &3&l> {0}"
|
||||
export-log: "&3EXPORT &3&l> &f{0}"
|
||||
export-log-progress: "&3EXPORT &3&l> &7{0}"
|
||||
migration-log: "&3VÁNDORLÁS &7[&3{0}&7] &3&l> &f{1}"
|
||||
migration-log-progress: "&3VÁNDORLÁS &7[&3{0}&7] &3&l> &7{1}"
|
||||
command-not-recognised: "&cA parancs nem ismeretes."
|
||||
command-no-permission: "&cNincs jogosultságod a használatára!"
|
||||
user-not-found: "&cEgy felhasználó számára &4{0}&c nem található."
|
||||
user-not-online: "&b{0}&a felhasználó nem elérhető."
|
||||
user-save-error: "&cHiba történt a felhasználói adatok mentése közben &4{0}&c."
|
||||
group-not-found: "&cEgy nevű csoport &4{0}&c nem található."
|
||||
group-save-error: "&cHiba történt a csoportadatok mentése közben &4{0}&c."
|
||||
track-not-found: "&cEgy nevű sáv &4{0}&c nem található."
|
||||
track-save-error: "&cHiba történt a track adatok mentése közben &4{0}&c."
|
||||
user-invalid-entry: "&4{0}&c nem érvényes felhasználónév/uuid."
|
||||
group-invalid-entry: "&4{0}&c nem érvényes csoportnév."
|
||||
track-invalid-entry: "&4{0}&c nem érvényes track név."
|
||||
server-world-invalid-entry: "&cA szerver/világnév csak alfanumerikus karaktereket tartalmazhat, és nem haladhatja meg a 36 karakter hosszúságú karaktereket."
|
||||
use-inherit-command: "&cHasználd a 'parent add' és a 'parent remove' parancsokat ahelyett, hogy meghatározta volna a csomópontot."
|
||||
verbose-invalid-filter: "&4{0}&c nem érvényes kiterjedt szűrő."
|
||||
verbose-on: "&bRészletes naplózás &aengedélyezve &ba megfelelő ellenőrzésekhez &aBÁRMILYEN&b."
|
||||
verbose-on-query: "&bRészletes naplózás &aengedélyezve &ba megfelelő ellenőrzésekhez &a{0}&b."
|
||||
verbose-off: "&bRészletes naplózás &cletiltva&b."
|
||||
verbose-recording-on: "&bRészletes felvétel &aengedélyezve &ba megfelelő ellenőrzésekhez &aBÁRMILYEN&b."
|
||||
verbose-recording-on-query: "&bRészletes felvétel &aengedélyezve &ba megfelelő ellenőrzésekhez &a{0}&b."
|
||||
verbose-upload-start: "&bRészletes naplózás &cletiltva&b. Eredmények feltöltése..."
|
||||
verbose-results-url: "&aRészletes eredmények URL-je:"
|
||||
tree-upload-start: "&bEngedélyezési fa létrehozása..."
|
||||
tree-empty: "&cNem lehet létrehozni a fát. Nincs találat."
|
||||
tree-url: "&aEngedélyezési fa URL:"
|
||||
search-searching: "&aFelhasználók és csoportok keresése a következővel: &b{0}&a..."
|
||||
search-searching-members: "&aFelhasználók és csoportok keresése, akik örökölnek &b{0}&a..."
|
||||
search-result: "&aTalál &b{0}&a bejegyzéseket a &b{1}&a felhasználók és &b{2}&a csoportok."
|
||||
search-showing-users: "&bFelhasználói bejegyzések megjelenítése:"
|
||||
search-showing-groups: "&bCsoportbejegyzések megjelenítése:"
|
||||
search-showing-users-with-page: "&bFelhasználói bejegyzések megjelenítése: {0}"
|
||||
search-showing-groups-with-page: "&bCsoportbejegyzések megjelenítése: {0}"
|
||||
apply-edits-invalid-code: "&cÉrvénytelen kód. &7({0})"
|
||||
apply-edits-unable-to-read: "&cA megadott kóddal nem lehet adatokat olvasni. &7({0})"
|
||||
apply-edits-no-target: "&cNem lehet elemezni a szerkesztés célját. Kérjük, nyújtsa be, mint egy extra érv."
|
||||
apply-edits-target-group-not-exists: "&cCélcsoport &4{0}&c nem létezik."
|
||||
apply-edits-target-user-not-uuid: "&cCélcsoport &4{0}&c nem érvényes uuid."
|
||||
apply-edits-target-user-unable-to-load: "&cA célfelhasználó nem tölthető be &4{0}&c."
|
||||
apply-edits-target-unknown: "&cÉrvénytelen cél. &7({0})"
|
||||
apply-edits-success: "&aSikeresen alkalmazott &b{0}&a csomópontok &b{1}&a."
|
||||
editor-upload-failure: "&cNem sikerült feltölteni az engedélyezési adatokat a szerkesztőhöz."
|
||||
editor-url: "&aSzerkesztő URL:"
|
||||
check-result: "&aEngedély-ellenőrzés eredmény a felhasználó számára &b{0}&a engedélyért &b{1}&a: &f{2}"
|
||||
create-success: "&b{0}&a sikeresen létrehozva."
|
||||
delete-success: "&b{0}&a sikeresen törölve."
|
||||
rename-success: "&b{0}&a sikeresen átnevezve &b{1}&a."
|
||||
clone-success: "&b{0}&a sikeresen klónozva &b{1}&a."
|
||||
already-inherits: "&b{0}&a már örökli &b{1}&a a szövegkörnyezetben {2}&a."
|
||||
does-not-inherit: "&b{0}&a nem örököl &b{1}&a a szövegkörnyezetben {2}&a."
|
||||
already-temp-inherits: "&b{0}&a már átmenetileg örökli &b{1}&a a szövegkörnyezetben {2}&a."
|
||||
does-not-temp-inherit: "&b{0}&a nem átmenetileg örökli &b{1}&a a szövegkörnyezetben {2}&a."
|
||||
track-already-contains: "&b{0}&a már tartalmazza &b{1}&a."
|
||||
track-does-not-contain: "&b{0}&a nem tartalmaz &b{1}&a."
|
||||
track-ambiguous-call: "&4{0}&c ezen a pályán több csoport tagja. Nem tudják meghatározni a helyüket."
|
||||
already-exists: "&4{0}&c már létezik!"
|
||||
does-not-exist: "&4{0}&c nem létezik!"
|
||||
group-load-error: "&cVáratlan hiba történt. A csoport nincs betöltve."
|
||||
groups-load-error: "&cVáratlan hiba történt. Nem sikerült betölteni az összes csoportot."
|
||||
track-load-error: "&cVáratlan hiba történt. A nyomvonal nincs betöltve."
|
||||
tracks-load-error: "&cVáratlan hiba történt. Nem sikerült betölteni az összes számot."
|
||||
track-empty: "&4{0}&c nem használható, mivel üres vagy csak egy csoportot tartalmaz."
|
||||
update-task-request: "&bFrissítési feladatot kértek. Kérlek, várj..."
|
||||
update-task-complete: "&aA feladat frissítése befejeződött."
|
||||
update-task-complete-network: "&aA feladat frissítése befejeződött. Most más szerverekre próbálkozni."
|
||||
update-task-push-success: "&aMás szervereket értesítettek &b{0} Üzenetek &asikeresen."
|
||||
update-task-push-failure: "&cHiba történt a többi kiszolgálóra történő változtatás közben."
|
||||
update-task-push-failure-not-setup: "&cHiba történt a többi kiszolgálóra történő változtatás közben. &7(egy üzenetkezelő szolgáltatást nem konfigurált)"
|
||||
reload-config-success: "&aA konfigurációs fájl újratöltve. &7(néhány opció csak a szerver újraindítása után fog működni)"
|
||||
info-top: >
|
||||
{PREFIX}&2Running &bLuckPerms v{0}&2 by &bLuck&2.\n
|
||||
{PREFIX}&f- &3Emelvény: &f{1}\n
|
||||
{PREFIX}&f- &3Szerver márka: &f{2}\n
|
||||
{PREFIX}&f- &3Szerver verzió: &f{3}
|
||||
info-middle: >
|
||||
{PREFIX}&f- &bÜzenet típusa: &f{0}\n
|
||||
{PREFIX}&f- &bPélda:\n
|
||||
{PREFIX}&f- &3Szerver név: &f{1}\n
|
||||
{PREFIX}&f- &3Elérhető játékosok: &a{2}\n
|
||||
{PREFIX}&f- &3Egyedi kapcsolatok: &a{3}\n
|
||||
{PREFIX}&f- &3Üzemidő: &7{4}\n
|
||||
{PREFIX}&f- &3Helyi adatok: &a{5} &7felhasználó, &a{6} &7csoport, &a{7} &7pályák\n
|
||||
{PREFIX}&f- &3Kontextus számológépek: &a{8}\n
|
||||
{PREFIX}&f- &3Ismert engedélyek: &a{9}\n
|
||||
{PREFIX}&f- &3Aktív processzorok: &7{10}
|
||||
create-error: "&cHiba történt a létrehozás során &4{0}&c."
|
||||
delete-error: "&cTörlés közben hiba történt &4{0}&c."
|
||||
delete-group-error-default: "&cAz alapértelmezett csoportot nem törölheti."
|
||||
groups-list: "&aCsoportok: &7(név, súly, pályák)"
|
||||
groups-list-entry: "&f- &3{0} &7- &b{1}"
|
||||
groups-list-entry-with-tracks: "&f- &3{0} &7- &b{1} &7- [&3{2}&7]"
|
||||
tracks-list: "&aPályák: {0}"
|
||||
listnodes: "&b{0}'s Jogok:"
|
||||
listnodes-with-page: "&b{0} Jogai: {1}"
|
||||
listnodes-temp: "&b{0} Ideiglenes engedélyei:"
|
||||
listnodes-temp-with-page: "&b{0} Ideiglenes engedélyei: {1}"
|
||||
listparents: "&b{0} Szülői csoportok:"
|
||||
listparents-temp: "&b{0} Ideiglenes szülői csoportok:"
|
||||
list-tracks: >
|
||||
&b{0} Pályái:\n
|
||||
{1}
|
||||
list-tracks-empty: "&b{0}&a nincs rajta."
|
||||
context-pair-inline: "&3{0}=&b{1}"
|
||||
context-pair--global-inline: "&eglobális"
|
||||
context-pair-sep: "&a, "
|
||||
context-pair: "&8(&7{0}=&f{1}&8)"
|
||||
check-permission: "&b{0}&a engedéllyel rendelkezik &b{1}&a állítva {2}&a a szövegkörnyezetben {3}&a."
|
||||
check-inherits-permission: "&b{0}&a engedéllyel rendelkezik &b{1}&a állítva {2}&a a szövegkörnyezetben {3}&a. &7(örökölt &a{4}&7)"
|
||||
setpermission-success: "&aBeállítva &b{0}&a-nak/-nek &b{1}&a, mert &b{2}&a a szövegkörnyezetben {3}&a."
|
||||
already-haspermission: "&b{0}&a már van &b{1}&a összefüggésben {2}&a."
|
||||
setpermission-temp-success: "&aBeállítva &b{0}&a-nak/-nek &b{1}&a, mert &b{2}&a egy ideig &b{3}&a a szövegkörnyezetben {4}&a."
|
||||
already-has-temp-permission: "&b{0}&a már van &b{1}&a ideiglenesen környezetben {2}&a."
|
||||
unsetpermission-success: "&aVisszaállítva &b{0}&a, mert &b{1}&a a szövegkörnyezetben {2}&a."
|
||||
does-not-have-permission: "&b{0}&a nem rendelkezik &b{1}&a összefüggésben {2}&a."
|
||||
unset-temp-permission-success: "&aIdeiglenes engedély érvénytelenítése &b{0}&a, mert &b{1}&a a szövegkörnyezetben {2}&a."
|
||||
does-not-have-temp-permission: "&b{0}&a nem rendelkezik &b{1}&a ideiglenesen környezetben {2}&a."
|
||||
set-inherit-success: "&b{0}&a most örökli az engedélyeket &b{1}&a a szövegkörnyezetben {2}&a."
|
||||
set-temp-inherit-success: "&b{0}&a most örökli az engedélyeket &b{1}&a egy ideig &b{2}&a a szövegkörnyezetben {3}&a."
|
||||
set-parent-success: "&b{0}&a meglévő szüloi csoportjaik tiszták, és most csak örökölnek &b{1}&a a szövegkörnyezetben {2}&a."
|
||||
set-track-parent-success: "&b{0}&a meglévő szülői csoportjaik voltak a pályán &b{1}&a törölni, és most csak örökli &b{2}&a a szövegkörnyezetben {3}&a."
|
||||
unset-inherit-success: "&b{0}&a többé nem örökli az engedélyeket &b{1}&a a szövegkörnyezetben {2}&a."
|
||||
unset-temp-inherit-success: "&b{0}&a már nem ideiglenesen örökli az engedélyeket &b{1}&a a szövegkörnyezetben {2}&a."
|
||||
clear-success: "&b{0}&a a jogosultságokat a kontextusban törölték {1}&a. (&b{2}&a a csomópontokat eltávolítottuk.)"
|
||||
clear-success-singular: "&b{0}&a a jogosultságokat a kontextusban törölték {1}&a. (&b{2}&a csomópontot eltávolítottuk.)"
|
||||
parent-clear-success: "&b{0}&a a szülei a kontextusban megszűntek {1}&a. (&b{2}&a a csomópontokat eltávolítottuk.)"
|
||||
parent-clear-success-singular: "&b{0}&a a szülei a kontextusban megszűntek {1}&a. (&b{2}&a a csomópontokat eltávolítottuk.)"
|
||||
parent-clear-track-success: "&b{0}&a szülők a pályán &b{1}&a összefüggésben {2}&a. (&b{3}&a a csomópontokat eltávolítottuk.)"
|
||||
parent-clear-track-success-singular: "&b{0}&a szülők a pályán &b{1}&a összefüggésben {2}&a. (&b{3}&a csomópontot eltávolítottuk.)"
|
||||
meta-clear-success: "&b{0}&a meta egyezéstípusa &b{1}&a összefüggésben {2}&a. (&b{3}&a a csomópontokat eltávolítottuk.)"
|
||||
meta-clear-success-singular: "&b{0}&a meta egyezéstípusa &b{1}&a összefüggésben {2}&a. (&b{3}&a csomópontot eltávolítottuk.)"
|
||||
illegal-date-error: "&cNem sikerült elemezni a dátumot &4{0}&c."
|
||||
past-date-error: "&cNem állíthat be dátumot a múltban!"
|
||||
chat-meta-prefix-header: "&b{0} Előtagjai"
|
||||
chat-meta-suffix-header: "&b{0} Utótagja"
|
||||
meta-header: "&b{0} Metája"
|
||||
chat-meta-entry: "&b-> {0} &f- &f'{1}&f' &8(&7örökölt &a{2}&8)"
|
||||
chat-meta-entry-with-context: "&b-> {0} &f- &f'{1}&f' &8(&7örökölt &a{2}&8){3}"
|
||||
meta-entry: "&b-> &a{0} &f= &f'{1}&f' &8(&7örökölt &a{2}&8)"
|
||||
meta-entry-with-context: "&b-> &a{0} &f= &f'{1}&f' &8(&7örökölt &a{2}&8){3}"
|
||||
chat-meta-prefix-none: "&b{0} nincsenek előtagjai."
|
||||
chat-meta-suffix-none: "&b{0} nincs utótagja."
|
||||
meta-none: "&b{0} nincs meta."
|
||||
meta-invalid-priority: "&cÉrvénytelen prioritás &4{0}&c. Várható szám."
|
||||
already-has-chat-meta: "&b{0}&a már van {1} &f'{2}&f'&a elsőbbséget élvez &b{3}&a a szövegkörnyezetben {4}&a."
|
||||
already-has-temp-chat-meta: "&b{0}&a már van {1} &f'{2}&f'&a ideiglenesen &b{3}&a a szövegkörnyezetben {4}&a."
|
||||
does-not-have-chat-meta: "&b{0}&a nincs {1} &f'{2}&f'&a elsőbbséget élvez &b{3}&a a szövegkörnyezetben {4}&a."
|
||||
does-not-have-temp-chat-meta: "&b{0}&a nincs {1} &f'{2}&f'&a ideiglenesen &b{3}&a a szövegkörnyezetben {4}&a."
|
||||
add-chatmeta-success: "&b{0}&a volt {1} &f'{2}&f'&a elsőbbséget élvez &b{3}&a a szövegkörnyezetben {4}&a."
|
||||
add-temp-chatmeta-success: "&b{0}&a volt {1} &f'{2}&f'&a elsőbbséget élvez &b{3}&a egy ideig &b{4}&a a szövegkörnyezetben {5}&a."
|
||||
remove-chatmeta-success: "&b{0}&a volt {1} &f'{2}&f'&a prioritásként &b{3}&a eltávolítva a kontextusban {4}&a."
|
||||
bulk-remove-chatmeta-success: "&b{0}&a minden volt {1}es a prioritás &b{2}&a eltávolítva a kontextusban {3}&a."
|
||||
remove-temp-chatmeta-success: "&b{0}&a ideiglenes volt {1} &f'{2}&f'&a prioritásként &b{3}&a eltávolítva a kontextusban {4}&a."
|
||||
bulk-remove-temp-chatmeta-success: "&b{0}&a minden ideiglenes volt {1}es prioritásként &b{2}&a eltávolítva a kontextusban {3}&a."
|
||||
already-has-meta: "&b{0}&a már van meta kulcs &f'{1}&f'&a állítva &f'{2}&f'&a a szövegkörnyezetben {3}&a."
|
||||
already-has-temp-meta: "&b{0}&a már van meta kulcs &f'{1}&f'&a átmenetileg beállítva &f'{2}&f'&a a szövegkörnyezetben {3}&a."
|
||||
doesnt-have-meta: "&b{0}&a nincs meta kulcs &f'{1}&f'&a összefüggésben {2}&a."
|
||||
doesnt-have-temp-meta: "&b{0}&a nincs meta kulcs &f'{1}&f'&a ideiglenesen a környezetben {2}&a."
|
||||
set-meta-success: "&aÁllítva a meta kulcsot &f'{0}&f'&a-nak/-nek &f'{1}&f'&a, mert &b{2}&a a szövegkörnyezetben {3}&a."
|
||||
set-meta-temp-success: "&aÁllítva a meta kulcsot &f'{0}&f'&a-nak/-nek &f'{1}&f'&a, mert &b{2}&a egy ideig &b{3}&a a szövegkörnyezetben {4}&a."
|
||||
unset-meta-success: "&aLeválasztva a meta kulcsot &f'{0}&f'&a, mert &b{1}&a a szövegkörnyezetben {2}&a."
|
||||
unset-meta-temp-success: "&aIdeiglenes meta kulcs kikapcsolása &f'{0}&f'&a, mert &b{1}&a a szövegkörnyezetben {2}&a."
|
||||
bulk-update-invalid-data-type: "&cÉrvénytelen típus. Típusok 'all', 'users' vagy 'groups'."
|
||||
bulk-update-invalid-constraint: "&cÉrvénytelen kényszer &4{0}&c. A korlátozásoknak formátumban kell lenniük '&f<mező> <összehasonlító operátor> <érték>&c'."
|
||||
bulk-update-invalid-comparison: "&cÉrvénytelen összehasonlító operátor '&4{0}&c'. Várható az alábbiak közül: &f== != ~~ ~!"
|
||||
bulk-update-queued: "&aA tömeges frissítés sorba állt. &7(&f{0}&7)"
|
||||
bulk-update-confirm: "&aA futtatáshoz &b/{0} a tömeges frissítés megerősítéséhez {1} &aa frissítés végrehajtásához."
|
||||
bulk-update-unknown-id: "&aMűködési id &b{0}&a nem létezik, vagy lejárt."
|
||||
bulk-update-starting: "&aFolyamatos frissítés futtatása."
|
||||
bulk-update-success: "&bA tömeges frissítés sikeresen befejeződött."
|
||||
bulk-update-failure: "&cA tömeges frissítés sikertelen. Ellenőrizze a konzolt hiba esetén."
|
||||
user-info-general: >
|
||||
{PREFIX}&b&l> &bFelhasználói adatok: &f{0}\n
|
||||
{PREFIX}&f- &3UUID: &f{1}\n
|
||||
{PREFIX}&f- &3Állapot: {2}\n
|
||||
{PREFIX}&f- &3Elsődleges csoport: &f{3}\n
|
||||
{PREFIX}&f- &aGrófok:\n
|
||||
{PREFIX}&f- &3Csomópontok: &a{4}\n
|
||||
{PREFIX}&f- &3Jogok: &a{5}\n
|
||||
{PREFIX}&f- &3Előtagok: &a{6}\n
|
||||
{PREFIX}&f- &3Utótagok: &a{7}\n
|
||||
{PREFIX}&f- &3Meta: &a{8}
|
||||
user-info-data: >
|
||||
{PREFIX}&f- &aGyorsítótár adat:\n
|
||||
{PREFIX}&f- &3Kontextuális adatok vannak: {0}\n
|
||||
{PREFIX}&f- &3Jelenlegi kontextusok: {1}\n
|
||||
{PREFIX}&f- &3Jelenlegi előtag: {2}\n
|
||||
{PREFIX}&f- &3Jelenlegi utótag: {3}
|
||||
info-parent-header: "&f- &aSzülői csoportok:"
|
||||
info-temp-parent-header: "&f- &aIdeiglenes szülői csoportok:"
|
||||
user-removegroup-error-primary: "&aNem lehet eltávolítani egy felhasználót az elsődleges csoportból."
|
||||
user-primarygroup-success: "&b{0}&a az elsődleges csoportot &b{1}&a."
|
||||
user-primarygroup-warn-option: "&aFigyelmeztetés: A kiszolgáló által használt elsődleges csoportszámítási módszer &7({0}) &anem tükrözheti ezt a változást."
|
||||
user-primarygroup-error-alreadyhas: "&b{0}&a már van &b{1}&a mint elsődleges csoportjuk."
|
||||
user-primarygroup-error-notmember: "&b{0}&a már nem tagja &b{1}&a, hozzátéve őket."
|
||||
user-track-error-not-contain-group: "&b{0}&a már nincsenek benne &b{1}&a."
|
||||
user-track-added-to-first: "&b{0}&a nincsenek ezen a pályán egyetlen csoportban sem, így az első csoportba kerültek, &b{1}&a a szövegkörnyezetben {2}&a."
|
||||
user-promote-success: "&aElőmozdítása &b{0}&a a pályán &b{1}&a-tól/-től &b{2}&a-nak/-nek &b{3}&a a szövegkörnyezetben {4}&a."
|
||||
user-promote-error-endoftrack: "&aA pálya vége &b{0}&a elérte. Nem lehetett népszerűsíteni &b{1}&a."
|
||||
user-promote-error-malformed: >
|
||||
{PREFIX}&aA következő csoport a pályán, &b{0}&a, nem létezik többé. Nem sikerült népszerűsíteni a felhasználót.\n
|
||||
{PREFIX}&aVagy hozzon létre egy csoportot, vagy távolítsa el a zeneszámból, és próbálkozzon újra.
|
||||
user-demote-success: "&aLefokozandó &b{0}&a a pályán &b{1}&a-tól/-től &b{2}&a-nak/-nek &b{3}&a a szövegkörnyezetben {4}&a."
|
||||
user-demote-endoftrack: "&aA pálya vége &b{0}&a, így elérte &b{1}&a eltávolították &b{2}&a."
|
||||
user-demote-error-malformed: >
|
||||
{PREFIX}&aAz előző csoport a pályán, &b{0}&a, nem létezik többé. Nem lehet lecsökkenteni a felhasználót.\n
|
||||
{PREFIX}&aVagy hozzon létre egy csoportot, vagy távolítsa el a zeneszámból, és próbálkozzon újra.
|
||||
group-info-general: >
|
||||
{PREFIX}&b&l> &bCsoport info: &f{0}\n
|
||||
{PREFIX}&f- &3Megjelenítendő név: &f{1}\n
|
||||
{PREFIX}&f- &3Súly: &f{2}\n
|
||||
{PREFIX}&f- &aGrófok:\n
|
||||
{PREFIX}&f- &3Csomópontok: &a{3}\n
|
||||
{PREFIX}&f- &3Jogok: &a{4}\n
|
||||
{PREFIX}&f- &3Előtagok: &a{5}\n
|
||||
{PREFIX}&f- &3Utótagok: &a{6}\n
|
||||
{PREFIX}&f- &3Meta: &a{7}
|
||||
group-set-weight: "&aA súly beállítása &b{0} &b{1}&a csoporthoz."
|
||||
track-info: >
|
||||
{PREFIX}&b&l> &bPálya megjelenítése: &f{0}\n
|
||||
{PREFIX}&f- &7Pálya: &f{1}
|
||||
track-clear: "&b{0}&a csoportok nyomvonalát törölték."
|
||||
track-append-success: "&aCsoport &b{0}&a csatolták a követéshez &b{1}&a."
|
||||
track-insert-success: "&aCsoport &b{0}&a beillesztésre került a pályára &b{1}&a helyzetben &b{2}&a."
|
||||
track-insert-error-number: "&cVárható szám, de helyette beérkezett: {0}"
|
||||
track-insert-error-invalid-pos: "&cNem helyezhető be a pozícióba &4{0}&c. &7(érvénytelen pozíció)"
|
||||
track-remove-success: "&aCsoport &b{0}&a eltávolították a pályáról &b{1}&a."
|
||||
log-load-error: "&cA napló nem tölthető be."
|
||||
log-invalid-page: "&cÉrvénytelen oldalszám."
|
||||
log-invalid-page-range: "&cÉrvénytelen oldalszám. Kérjük, adjon meg egy értéket &41&c és &4{0}&c."
|
||||
log-no-entries: "&bNincs megjeleníthető naplóbejegyzés."
|
||||
log-entry: "&b#{0} -> &8(&7{1} ezelőtt&8) {2}"
|
||||
log-notify-console: "&cA konzolra vonatkozó értesítések átváltása nem lehetséges."
|
||||
log-notify-toggle-on: "&aEngedélyezve a&b naplózási kimenet."
|
||||
log-notify-toggle-off: "&cLetiltva a&b naplózási kimenet."
|
||||
log-notify-already-on: "&cMár értesítést kapsz."
|
||||
log-notify-already-off: "&cJelenleg nem kap értesítést."
|
||||
log-notify-unknown: "&cÁllam ismeretlen. Várandós \"on\" vagy \"off\"."
|
||||
log-search-header: "&aA lekérdezés legutóbbi műveleteinek megjelenítése &b{0} &a(oldal &f{1} &f{2}&a-ból/-ből)"
|
||||
log-recent-header: "&aA legutóbbi műveletek megjelenítése (oldal &f{0} &f{1}&a-ból/-ből)"
|
||||
log-recent-by-header: "&aLegutóbbi fellépések megjelenítése a következővel: &b{0} &a(oldal &f{1} &f{2}&a-ból/-ből)"
|
||||
log-history-user-header: "&aA felhasználó előzményeinek megjelenítése &b{0} &a(oldal &f{1} &f{2}&a-ból/-ből)"
|
||||
log-history-group-header: "&aA csoport előzményeinek megjelenítése &b{0} &a(oldal &f{1} &f{2}&a-ból/-ből)"
|
||||
log-history-track-header: "&aA sáv előzményeinek megjelenítése &b{0} &a(oldal &f{1} &f{2}&a-ból/-ből)"
|
||||
log-export-already-exists: "&cHiba: A fájl &4{0}&c már létezik."
|
||||
log-export-not-writable: "&cHiba: A fájl &4{0}&c nem írható."
|
||||
log-export-empty: "&cA napló üres, ezért nem exportálható."
|
||||
log-export-failure: "&cVáratlan hiba történt a fájl írása közben."
|
||||
log-export-success: "&aSikeresen exportálta a naplót &b{0}&a."
|
||||
import-already-running: "&cEgy másik behozatali folyamat már fut. Kérjük, várjon, amíg befejeződik, és próbálkozzon újra."
|
||||
export-already-running: "&cEgy másik exportfolyamat már fut. Kérjük, várjon, amíg befejeződik, és próbálkozzon újra."
|
||||
import-log-doesnt-exist: "&cHiba: A fájl &4{0}&c nem létezik."
|
||||
import-log-not-readable: "&cHiba: A fájl &4{0}&c nem olvasható."
|
||||
import-log-failure: "&cA naplófájl olvasása közben váratlan hiba történt."
|
||||
import-progress: "&b(Import) &b-> &f{0}&f% sikeres &7- &b{1}&f/&b{2} &fműveletekkel kiegészítve &c{3} &fhibák."
|
||||
import-progress-sin: "&b(Import) &b-> &f{0}&f% sikeres &7- &b{1}&f/&b{2} &fműveletekkel kiegészítve &c{3} &fhiba."
|
||||
import-start: "&b(Import) &b-> &fImportálás indítása."
|
||||
import-end-complete: "&b(Import) &a&lSIKERES &7- vett &b{0} &7másodperc - &7Nincs hibák."
|
||||
import-end-complete-err: "&b(Import) &a&lSIKERES &7- vett &b{0} &7másodperc - &c{1} hibák."
|
||||
import-end-complete-err-sin: "&b(Import) &a&lSIKERES &7- vett &b{0} &7másodperc - &c{1} hiba."
|
||||
import-end-error-header: >
|
||||
{PREFIX}&b(Import) &7------------> &fHiba megjelenítése #&b{0} &7<------------\n
|
||||
{PREFIX}&b(Import) &fFuttatás közben: &3Parancs #{1}\n
|
||||
{PREFIX}&b(Import) &fParancs: &7{2}\n
|
||||
{PREFIX}&b(Import) &fTípus: &3{3}\n
|
||||
{PREFIX}&b(Import) &fKibocsátás:
|
||||
import-end-error-content: "&b(Import) &b-> &c{0}"
|
||||
import-end-error-footer: "&b(Import) &7<------------------------------------------>"
|
||||
|
||||
command-specs:
|
||||
user:
|
||||
description: "Felhasználói parancsok"
|
||||
usage: "/%s user <felhasználó>"
|
||||
group:
|
||||
description: "Csoport parancsok"
|
||||
usage: "/%s group <csoport>"
|
||||
track:
|
||||
description: "Sávparancsok"
|
||||
usage: "/%s track <track>"
|
||||
log:
|
||||
description: "Napló parancsok"
|
||||
usage: "/%s log"
|
||||
sync:
|
||||
description: "A szinkronizálás megváltozik a tárolóval"
|
||||
usage: "/%s sync"
|
||||
info:
|
||||
description: "Általános plugin info nyomtatása"
|
||||
usage: "/%s info"
|
||||
verbose:
|
||||
description: "Rendszeres engedély ellenőrzése"
|
||||
usage: "/%s verbose <true|false> [szűrő]"
|
||||
args:
|
||||
"on|record|off|paste": "hogy bekapcsolják/kikapcsolják a naplózást, vagy beillesztik-e a naplózott kimenetet"
|
||||
"filter": "a szűrő a bejegyzések ellen"
|
||||
"--slim": "hozzáad \"--slim\" a nyomkövetési adatok kizárása a beillesztett kimenetből"
|
||||
tree:
|
||||
description: "Hozzon létre egy fa nézetet az engedélyekről"
|
||||
usage: "/%s tree [kiválasztás] [max. szint] [játékos]"
|
||||
args:
|
||||
"selection": "a fa gyökere. Meghatározza \".\", hogy az összes engedélyt tartalmazza"
|
||||
"max level": "hány fiókszintet kell visszaküldeni"
|
||||
"player": "az elérhető játékos nevét ellenőrizni"
|
||||
search:
|
||||
description: "Keressen olyan felhasználókat/csoportokat, akiknek engedélye van"
|
||||
usage: "/%s search <jog>"
|
||||
args:
|
||||
"permission": "a keresési engedély"
|
||||
"page": "a megtekinteni kívánt oldalt"
|
||||
check:
|
||||
description: "Végezzen el egy szabványos engedélyt egy elérhető játékoson"
|
||||
usage: "/%s check <felhasználó> <jog>"
|
||||
args:
|
||||
"user": "a felhasználó ellenőrizni"
|
||||
"permission": "az ellenőrzés engedélye"
|
||||
network-sync:
|
||||
description: "A szinkronizálás a tárhely módosításával történik, és kérni fogja, hogy a hálózaton lévő összes többi szerver ugyanezt tegye"
|
||||
usage: "/%s networksync"
|
||||
import:
|
||||
description: "Adatok importálása fájlból"
|
||||
usage: "/%s import <fájl>"
|
||||
args:
|
||||
"file": "az importálni kívánt fájl"
|
||||
export:
|
||||
description: "Adatok exportálása egy fájlba"
|
||||
usage: "/%s export <fájl>"
|
||||
args:
|
||||
"file": "az exportálni kívánt fájl"
|
||||
reload-config:
|
||||
description: "Betölt néhány konfigurációs beállítást"
|
||||
usage: "/%s reloadconfig"
|
||||
bulk-update:
|
||||
description: "Végezzen ömlesztett változás lekérdezéseket az összes adaton"
|
||||
usage: "/%s bulkupdate"
|
||||
args:
|
||||
"data type": "a megváltoztatott adatok típusa. ('all', 'users' vagy 'groups')"
|
||||
"action": "az elvégzendő művelet az adatokon. ('update' vagy 'delete')"
|
||||
"action field": "a cselekvési terület. Csak a szükséges 'update'. ('permission', 'server' vagy 'world')"
|
||||
"action value": "a cserélendő érték. Csak a szükséges 'update'."
|
||||
"constraint...": "a frissítéshez szükséges korlátokat"
|
||||
migration:
|
||||
description: "Migrációs parancsok"
|
||||
usage: "/%s migration"
|
||||
apply-edits:
|
||||
description: "A webszerkesztő által végrehajtott engedély módosításokat alkalmazza"
|
||||
usage: "/%s applyedits <kód> [cél]"
|
||||
args:
|
||||
"code": "az adatok egyedi kódja"
|
||||
"target": "aki az adatokat alkalmazza"
|
||||
create-group:
|
||||
description: "Létrehoz egy új csoportot"
|
||||
usage: "/%s creategroup <csoport>"
|
||||
args:
|
||||
"name": "a csoport neve"
|
||||
delete-group:
|
||||
description: "Csoport eltávolítása"
|
||||
usage: "/%s deletegroup <csoport>"
|
||||
args:
|
||||
"name": "a csoport neve"
|
||||
list-groups:
|
||||
description: "Felsorolja az összes csoportot a platformon"
|
||||
usage: "/%s listgroups"
|
||||
create-track:
|
||||
description: "Hozzon létre egy új számot"
|
||||
usage: "/%s createtrack <track>"
|
||||
args:
|
||||
"name": "a pálya neve"
|
||||
delete-track:
|
||||
description: "Egy szám törlése"
|
||||
usage: "/%s deletetrack <track>"
|
||||
args:
|
||||
"name": "a pálya neve"
|
||||
list-tracks:
|
||||
description: "Felsorolja az összes zeneszámot a platformon"
|
||||
usage: "/%s listtracks"
|
||||
user-info:
|
||||
description: "Információkat jelenít meg a felhasználóról"
|
||||
user-switchprimarygroup:
|
||||
description: "A felhasználó elsődleges csoportjának átváltása"
|
||||
args:
|
||||
"group": "a csoport, amelyre váltani"
|
||||
user-promote:
|
||||
description: "Segít a felhasználónak egy számot feltölteni"
|
||||
args:
|
||||
"track": "a pálya, hogy elősegítse a felhasználó fel"
|
||||
"context...": "a felhasználót elősegítő kontextusok"
|
||||
user-demote:
|
||||
description: "Megszünteti a felhasználót egy pályán"
|
||||
args:
|
||||
"track": "a sáv, amely leállítja a felhasználót"
|
||||
"context...": "a felhasználókat lecsökkentő kontextusok"
|
||||
group-info:
|
||||
description: "Információkat ad a csoportról"
|
||||
group-listmembers:
|
||||
description: "Mutassa be a csoportból öröklődő felhasználókat/csoportokat"
|
||||
args:
|
||||
"page": "a megtekinteni kívánt oldal"
|
||||
group-setweight:
|
||||
description: "Beállítja a csoportok súlyát"
|
||||
args:
|
||||
"weight": "a beállítani kívánt súly"
|
||||
group-rename:
|
||||
description: "Átnevezi a csoportot"
|
||||
args:
|
||||
"name": "az új név"
|
||||
group-clone:
|
||||
description: "Klónozza a csoportot"
|
||||
args:
|
||||
"name": "a klónozni kívánt csoport neve"
|
||||
holder-editor:
|
||||
description: "Megnyitja a webes engedély-szerkesztőt"
|
||||
holder-showtracks:
|
||||
description: "Megadja az objektum sávjait"
|
||||
holder-clear:
|
||||
description: "Eltávolítja az összes jogosultságot, szülőt és meta-t"
|
||||
args:
|
||||
"context...": "a szövegszűrés körülményei"
|
||||
permission:
|
||||
description: "Jogok szerkesztése"
|
||||
parent:
|
||||
description: "Örökletek szerkesztése"
|
||||
meta:
|
||||
description: "Metaadatértékek szerkesztése"
|
||||
permission-info:
|
||||
description: "Megadja az objektum engedélyezési csomópontjait"
|
||||
args:
|
||||
"page": "a megtekinteni a kívánt oldalt"
|
||||
"filter": "a string szűrni"
|
||||
permission-set:
|
||||
description: "Beállítja az objektum engedélyét"
|
||||
args:
|
||||
"node": "a beállítandó jog csomópont"
|
||||
"true|false": "a csomópont értéke"
|
||||
"context...": "az engedéllyel rendelkező szövegkörnyezetek"
|
||||
permission-unset:
|
||||
description: "Megadja az objektum engedélyét"
|
||||
args:
|
||||
"node": "az engedéllyel rendelkező csomópont kiiktatásához"
|
||||
"context...": "az engedélyek eltávolításának kontextusai"
|
||||
permission-settemp:
|
||||
description: "Beállítja az objektum ideiglenes engedélyét"
|
||||
args:
|
||||
"node": "a beállítandó engedély csomópont"
|
||||
"true|false": "a csomópont értéke"
|
||||
"duration": "amíg az engedély csomópontja lejárt"
|
||||
"context...": "az engedéllyel rendelkező szövegkörnyezetek"
|
||||
permission-unsettemp:
|
||||
description: "Megadja az ideiglenes engedélyt az objektumhoz"
|
||||
args:
|
||||
"node": "az engedéllyel rendelkező csomópont kiiktatásához"
|
||||
"context...": "az engedélyek eltávolításának kontextusai"
|
||||
permission-check:
|
||||
description: "Ellenőrzi, hogy az objektumnak van-e engedélyezési csomópontja"
|
||||
args:
|
||||
"node": "az engedéllyel rendelkező csomópontot"
|
||||
"context...": "a bejelentkezés körülményei"
|
||||
permission-check-inherits:
|
||||
description: "Ellenőrzi, hogy az objektum örökli-e az engedélyezési csomópontot"
|
||||
args:
|
||||
"node": "az engedéllyel rendelkező csomópontot"
|
||||
"context...": "a bejelentkezés körülményei"
|
||||
parent-info:
|
||||
description: "Megadja azokat a csoportokat, amelyeket ez az objektum örököl"
|
||||
parent-set:
|
||||
description: "Eltávolítja az összes többi csoportot, amelyet az objektum már örököl, és hozzáadja azokat az adott objektumhoz"
|
||||
args:
|
||||
"group": "a csoport, amelyre állít"
|
||||
"context...": "a csoport beállításához szükséges kontextusok"
|
||||
parent-add:
|
||||
description: "Beállít egy másik csoportot az objektumhoz, hogy örökli a jogokat"
|
||||
args:
|
||||
"group": "a csoport örökölni"
|
||||
"context...": "a csoportot örökli a szövegkörnyezetben"
|
||||
parent-remove:
|
||||
description: "Eltávolítja a korábban beállított öröklési szabályt"
|
||||
args:
|
||||
"group": "a csoport eltávolítani"
|
||||
"context...": "a csoport eltávolításának kontextusai"
|
||||
parent-set-track:
|
||||
description: "Eltávolítja az összes többi olyan csoportot, amelyet az adott objektum már örököl az adott sávon, és hozzáadja azokat az adott sávhoz"
|
||||
args:
|
||||
"track": "a pálya bekapcsolásához"
|
||||
"group": "a beállítani kívánt csoportot, vagy a csoport helyzetét az adott sávon"
|
||||
"context...": "a csoport beállításához szükséges kontextusok"
|
||||
parent-add-temp:
|
||||
description: "Egy másik csoportot állít be, hogy az objektum átmenetileg átengedi az engedélyeket"
|
||||
args:
|
||||
"group": "a csoport örökölni"
|
||||
"duration": "a csoporttagság időtartamát"
|
||||
"context...": "a csoportot örökli a szövegkörnyezetben"
|
||||
parent-remove-temp:
|
||||
description: "Eltávolítja a korábban beállított ideiglenes öröklési szabályt"
|
||||
args:
|
||||
"group": "a csoport eltávolítani"
|
||||
"context...": "a csoport eltávolításának kontextusai"
|
||||
parent-clear:
|
||||
description: "Törli az összes szülőt"
|
||||
args:
|
||||
"context...": "a szövegszűrés körülményei"
|
||||
parent-clear-track:
|
||||
description: "Törli az összes szülőt egy adott pályán"
|
||||
args:
|
||||
"track": "az eltávolítandó sáv"
|
||||
"context...": "a szövegszűrés körülményei"
|
||||
meta-info:
|
||||
description: "Az összes csevegési meta megjelenítése"
|
||||
meta-set:
|
||||
description: "Meta értéket állít be"
|
||||
args:
|
||||
"key": "a beállítani kívánt kulcs"
|
||||
"value": "a beállítani kívánt érték"
|
||||
"context...": "a meta-pár beillesztésének kontextusai"
|
||||
meta-unset:
|
||||
description: "Megszünteti a meta értéket"
|
||||
args:
|
||||
"key": "a kiiktatás kulcsa"
|
||||
"context...": "a meta-pár eltávolításának kontextusai"
|
||||
meta-settemp:
|
||||
description: "Átmenetileg beállítja a metaértéket"
|
||||
args:
|
||||
"key": "a beállítani kívánt kulcs"
|
||||
"value": "a beállítani kívánt érték"
|
||||
"duration": "amíg a meta érték lejár"
|
||||
"context...": "a meta-pár beillesztésének kontextusai"
|
||||
meta-unsettemp:
|
||||
description: "Megszünteti az ideiglenes metaértéket"
|
||||
args:
|
||||
"key": "a kiiktatás kulcsa"
|
||||
"context...": "a metapár eltávolításának kontextusai"
|
||||
meta-addprefix:
|
||||
description: "Hozzáad egy előtagot"
|
||||
args:
|
||||
"priority": "az elsőbbséget az előtag hozzáadásához"
|
||||
"prefix": "az előtag karaktersorozat"
|
||||
"context...": "az előtag beillesztésének kontextusai"
|
||||
meta-addsuffix:
|
||||
description: "Hozzáad egy utótagot"
|
||||
args:
|
||||
"priority": "elsőbbséget kell adni az utótagnak a következőhöz:"
|
||||
"suffix": "az utótagsor"
|
||||
"context...": "azok a kontextusok, amelyekhez hozzá kell adni az utótagot"
|
||||
meta-removeprefix:
|
||||
description: "Eltávolít egy előtagot"
|
||||
args:
|
||||
"priority": "az elsőbbség eltávolítása az előtagon"
|
||||
"prefix": "az előtag karaktersorozat"
|
||||
"context...": "az előtagot eltávolító szövegkörnyezetek"
|
||||
meta-removesuffix:
|
||||
description: "Eltávolít egy utótagot"
|
||||
args:
|
||||
"priority": "az elsőbbség, hogy eltávolítsák az utótagot"
|
||||
"suffix": "az utótagsor"
|
||||
"context...": "azok a kontextusok, amelyek eltávolítják az utótagot"
|
||||
meta-addtemp-prefix:
|
||||
description: "Privát előtagot ad át ideiglenesen"
|
||||
args:
|
||||
"priority": "az elsőbbséget az előtag hozzáadásához"
|
||||
"prefix": "az előtag karaktersorozat"
|
||||
"duration": "az időtartam, amíg az előtag lejár"
|
||||
"context...": "az előtag beillesztésének kontextusai"
|
||||
meta-addtemp-suffix:
|
||||
description: "Egy ideiglenes utótagot ad hozzá"
|
||||
args:
|
||||
"priority": "elsőbbséget kell adni az utótagnak a következőhöz:"
|
||||
"suffix": "az utótagsor"
|
||||
"duration": "az időtartam, amíg az utótag lejár"
|
||||
"context...": "azok a kontextusok, amelyekhez hozzá kell adni az utótagot"
|
||||
meta-removetemp-prefix:
|
||||
description: "Eltávolít ideiglenes előtagot"
|
||||
args:
|
||||
"priority": "az elsőbbség eltávolítása az előtagon"
|
||||
"prefix": "az előtag karaktersorozat"
|
||||
"context...": "az előtagot eltávolító szövegkörnyezetek"
|
||||
meta-removetemp-suffix:
|
||||
description: "Eltávolítja az ideiglenes utótagot"
|
||||
args:
|
||||
"priority": "az elsőbbség, hogy eltávolítsák az utótagot"
|
||||
"suffix": "az utótagsor"
|
||||
"context...": "azok a kontextusok, amelyek eltávolítják az utótagot"
|
||||
meta-clear:
|
||||
description: "Törli az összes metódust"
|
||||
args:
|
||||
"type": "a eltávolítandó meta típusa"
|
||||
"context...": "a szövegszűrés körülményei"
|
||||
track-info:
|
||||
description: "Ad információt a pályáról"
|
||||
track-append:
|
||||
description: "Csatol egy csoportot a pálya végére"
|
||||
args:
|
||||
"group": "a csoport hozzáfűzése"
|
||||
track-insert:
|
||||
description: "Beilleszti a csoportot egy adott pozícióban a pálya mentén"
|
||||
args:
|
||||
"group": "beszúrni a kívánt csoport"
|
||||
"position": "a helyzet a csoport beillesztésére (az első pozíció a pályán 1)"
|
||||
track-remove:
|
||||
description: "Eltávolít egy csoportot a sávról"
|
||||
args:
|
||||
"group": "a csoport eltávolítani"
|
||||
track-clear:
|
||||
description: "Törli a csoportokat a pályán"
|
||||
track-rename:
|
||||
description: "Nevezze át a sávot"
|
||||
args:
|
||||
"name": "az új név"
|
||||
track-clone:
|
||||
description: "Klónozza a sávot"
|
||||
args:
|
||||
"name": "a pálya neve, hogy klónozzanak"
|
||||
log-recent:
|
||||
description: "A legutóbbi műveletek megtekintése"
|
||||
args:
|
||||
"user": "a felhasználó neve/uuid-je, hogy kiszűrje"
|
||||
"page": "a megtekinteni kívánt oldalszám"
|
||||
log-search:
|
||||
description: "Keressen egy bejegyzés naplót"
|
||||
args:
|
||||
"query": "keresési lekérdezés"
|
||||
"page": "a megtekinteni kívánt oldalszám"
|
||||
log-notify:
|
||||
description: "A naplóbejelentések módosítása"
|
||||
args:
|
||||
"on|off": "hogy be vagy ki van kapcsolva"
|
||||
log-user-history:
|
||||
description: "A felhasználó előzményeinek megtekintése"
|
||||
args:
|
||||
"user": "a felhasználó neve/uuid-je"
|
||||
"page": "a megtekinteni kívánt oldalszám"
|
||||
log-group-history:
|
||||
description: "A csoport előzményeinek megtekintése"
|
||||
args:
|
||||
"group": "a csoport neve"
|
||||
"page": "a megtekinteni kívánt oldalszám"
|
||||
log-track-history:
|
||||
description: "A sáv előzményeinek megtekintése"
|
||||
args:
|
||||
"track": "a pálya neve"
|
||||
"page": "a megtekinteni kívánt oldalszám"
|
||||
sponge:
|
||||
description: "Extra Szivacs adatok szerkesztése"
|
||||
usage: "/%s sponge <gyűjtemény> <tárgy>"
|
||||
args:
|
||||
"collection": "a lekérdezésre kerülő gyűjtemény"
|
||||
"subject": "módosítani a tárgyat"
|
||||
sponge-permission-info:
|
||||
description: "A tárgyhoz tartozó jogokkal kapcsolatos információkat jeleníti meg"
|
||||
args:
|
||||
"contexts...": "a szövegszűrés körülményei"
|
||||
sponge-permission-set:
|
||||
description: "Engedélyt ad a Tárgyhoz"
|
||||
args:
|
||||
"node": "a beállítandó engedély csomópont"
|
||||
"tristate": "az engedélyhez szükséges érték megadása"
|
||||
"contexts...": "az engedéllyel rendelkező szövegkörnyezetek"
|
||||
sponge-permission-clear:
|
||||
description: "Törli a Tárgy engedélyeit"
|
||||
args:
|
||||
"contexts...": "a szövegkörnyezetek engedélyeinek törlése"
|
||||
sponge-parent-info:
|
||||
description: "Megjeleníti a tárgy szüleinek adatait"
|
||||
args:
|
||||
"contexts...": "a szövegszűrés körülményei"
|
||||
sponge-parent-add:
|
||||
description: "Szülő hozzáadása a tárgyhoz"
|
||||
args:
|
||||
"collection": "az a tárgyi gyűjtemény, ahol a szülő Tárgy"
|
||||
"subject": "a szülő Tárgy neve"
|
||||
"contexts...": "a szülő hozzáadásának összefüggései"
|
||||
sponge-parent-remove:
|
||||
description: "Eltávolít egy szülőt a tárgytól"
|
||||
args:
|
||||
"collection": "az a tárgyi gyűjtemény, ahol a szülő Tárgy"
|
||||
"subject": "a szülő Tárgy neve"
|
||||
"contexts...": "a szülő eltávolításának összefüggései"
|
||||
sponge-parent-clear:
|
||||
description: "Törli a Tárgyi szülőket"
|
||||
args:
|
||||
"contexts...": "a szülők egyértelművé tételének összefüggései"
|
||||
sponge-option-info:
|
||||
description: "Megmutatja a tárggyal kapcsolatos információkat"
|
||||
args:
|
||||
"contexts...": "a szövegszűrés körülményei"
|
||||
sponge-option-set:
|
||||
description: "Beállít egy opciót a Tárgyhoz"
|
||||
args:
|
||||
"key": "a beállítani kívánt kulcs"
|
||||
"value": "a kulcs beállításához"
|
||||
"contexts...": "az opció beállításához szükséges kontextusok"
|
||||
sponge-option-unset:
|
||||
description: "Lefuttat egy opciót a Tárgyhoz"
|
||||
args:
|
||||
"key": "a kiiktatás kulcsa"
|
||||
"contexts...": "a kulcshoz való hozzáférés megszüntetésének kontextusai"
|
||||
sponge-option-clear:
|
||||
description: "Törli a Tárgy opciókat"
|
||||
args:
|
||||
"contexts...": "a szövegkörnyezetek egyértelművé tételének lehetőségei"
|
||||
migration-command:
|
||||
description: "Migrációs parancs"
|
||||
migration-groupmanager:
|
||||
description: "Migrációs parancs"
|
||||
args:
|
||||
"migrate as global": "ha a világi engedélyeket figyelmen kívül kell hagyni, és csak globális áttérést kell alkalmazni"
|
||||
migration-powerfulperms:
|
||||
description: "Migrációs parancs"
|
||||
args:
|
||||
"address": "a PP adatbázis címe"
|
||||
"database": "a PP adatbázis neve"
|
||||
"username": "a DB-be való bejelentkezéshez használt felhasználónév"
|
||||
"password": "a DB-be való bejelentkezéshez használt jelszó"
|
||||
"db table": "a PP tábla neve, ahol a játékos adatait tárolják"
|
||||
+662
-237
@@ -3,301 +3,726 @@
|
||||
# Author: EuropeJing
|
||||
|
||||
prefix: "&7&l[&b&lL&3&lP&7&l] &c"
|
||||
log-info: "&7&l[&bL&3P&7&l] &3{0}"
|
||||
log-warn: "&7&l[&bLuck&3Perms&7&l] &c[警告] {0}"
|
||||
log-error: "&7&l[&bLuck&3Perms&7&l] &4[错误] {0}"
|
||||
empty: "{0}"
|
||||
player-online: "&a在线"
|
||||
player-offline: "&c离线"
|
||||
loading-error: "无法加载权限数据,请稍后再试."
|
||||
op-disabled: "&b此服务器上禁用了vanilla OP系统."
|
||||
op-disabled-sponge: "&2服务器管理员状态在安装权限插件时无效,请直接编辑用户数据."
|
||||
loading-error: "&c权限数据无法加载,请稍后再试。"
|
||||
op-disabled: "&b此服务器上禁用了vanilla OP系统。"
|
||||
op-disabled-sponge: "&2请注意,当安装权限插件时,服务器OP状态无效。请直接编辑用户数据。"
|
||||
log-info: "&7&l[&bL&3P&7&l] &3{0}"
|
||||
log-warn: "&7&l[&bLuck&3Perms&7&l] &c[警告] {0}"
|
||||
log-error: "&7&l[&bLuck&3Perms&7&l] &4[错误] {0}"
|
||||
log: "&3日志 &3&l> {0}"
|
||||
verbose-log: "&3详细 &3&l> {0}"
|
||||
export-log: "&3输出 &3&l> &f{0}"
|
||||
export-log-progress: "&3输出 &3&l> &7{0}"
|
||||
migration-log: "&3移动 &7[&3{0}&7] &3&l> &f{1}"
|
||||
migration-log-progress: "&3移动 &7[&3{0}&7] &3&l> &7{1}"
|
||||
command-not-recognised: "命令未被识别."
|
||||
command-no-permission: "你没有权限使用这个命令!"
|
||||
already-haspermission: "{0}已经有这个权限!"
|
||||
does-not-havepermission: "{0}没有这个命令的权限."
|
||||
already-has-temp-permission: "{0}已经设置此临时权限!"
|
||||
does-not-have-temp-permission: "{0}没有设置此临时权限."
|
||||
user-not-found: "&b找不到用户."
|
||||
user-not-online: "&b用户&a{0}&b不在线."
|
||||
user-no-data: "&b没有加载用户&a{0}&b任何数据."
|
||||
user-save-success: "&7(保存用户数据到文件)"
|
||||
user-save-error: "保存用户数据时出错."
|
||||
user-create-fail: "创建新用户时出错."
|
||||
group-not-found: "&b找不到组."
|
||||
group-save-success: "&7(保存组数据到文件)"
|
||||
group-save-error: "保存组数据时出错."
|
||||
track-not-found: "&b无法找到轨道."
|
||||
track-save-success: "&7(保存轨道到文件)"
|
||||
track-save-error: "保存轨道时出错."
|
||||
user-invalid-entry: "&d{0}&c不是有效的用户名/uuid."
|
||||
group-invalid-entry: "组名只能包含字母数字字符."
|
||||
track-invalid-entry: "轨道名称只能包含字母数字字符."
|
||||
server-invalid-entry: "服务器名称只能包含字母数字字符."
|
||||
use-inherit-command: "使用'parent add'和'parent remove'命令,而不是指定节点."
|
||||
verbose-invalid-filter: "&c无效的详细过滤器: &f{0}"
|
||||
verbose-on: "&b所有权限的详细输出设置为&a开&b."
|
||||
verbose-on-query: "&b将匹配过滤器:&f{0}&b的权限详细输出设置为&a开&b."
|
||||
verbose-off: "&b所有权限的详细输出设置为&c关&b."
|
||||
verbose-recording-on: "&b所有权限的详细记录设置为&a开&b."
|
||||
verbose-recording-on-query: "&b将匹配过滤器:&f{0}&b的权限详细记录设置为&a开&b."
|
||||
verbose-recording-upload-start: "&b详细记录被禁用. 正在上传结果..."
|
||||
verbose-recording-url: "&a详细结果的网址:"
|
||||
command-not-recognised: "&c命令未被识别。"
|
||||
command-no-permission: "&c你没有权限使用这个命令!"
|
||||
user-not-found: "&c找不到用户&4{0}&c。"
|
||||
user-not-online: "&a用户&b{0}&a不在线。"
|
||||
user-save-error: "&c保存用户&4{0}&c数据时出错。"
|
||||
group-not-found: "&b找不到名为&4{0}&c的组。"
|
||||
group-save-error: "&c保存组&4{0}&c数据时出错。"
|
||||
track-not-found: "&b无法找到为&4{0}&c的权限组轨道。"
|
||||
track-save-error: "&c保存权限组轨道&4{0}&c时出错。"
|
||||
user-invalid-entry: "&4{0}&c不是有效的用户名/uuid。"
|
||||
group-invalid-entry: "&4{0}&c不是有效的组名称。"
|
||||
track-invalid-entry: "&4{0}&c不是有效的权限组轨道名称。"
|
||||
server-world-invalid-entry: "&c服务器/世界名称只能包含字母数字字符,长度不能超过36个字符。"
|
||||
use-inherit-command: "&c使用'parent add'和'parent remove'命令,而不是指定节点。"
|
||||
verbose-invalid-filter: "&4{0}&c不是有效的详细过滤器"
|
||||
verbose-on: "&b将匹配过滤器:&aANY&b的权限详细输出设置为&a开&b。"
|
||||
verbose-on-query: "&b将匹配过滤器:&a{0}&b的权限详细输出设置为&a开&b。"
|
||||
verbose-off: "&b详细输出设置为&c关&b。"
|
||||
verbose-recording-on: "&b将匹配过滤器:&aANY&b的权限详细记录设置为&a开&b。"
|
||||
verbose-recording-on-query: "&b将匹配过滤器:&a{0}&b的权限详细记录设置为&a开&b。"
|
||||
verbose-upload-start: "&b详细记录被禁用。正在上传结果..."
|
||||
verbose-results-url: "&a详细结果的网址:"
|
||||
tree-upload-start: "&b生成权限树..."
|
||||
tree-empty: "&a无法生成树,没有找到结果."
|
||||
tree-empty: "&c无法生成树,没有找到结果。"
|
||||
tree-url: "&a权限树网址:"
|
||||
search-searching: "&a使用&b{0}&a搜索用户和组..."
|
||||
search-searching-members: "&a正在搜索继承自&b{0}&a的用户和组..."
|
||||
search-result: "&a从&b{1}&a用户和&b{2}&a组找到&b{0}&a个条目."
|
||||
search-result: "&a从&b{1}&a用户和&b{2}&a组找到&b{0}&a个条目。"
|
||||
search-showing-users: "&b显示用户条目:"
|
||||
search-showing-groups: "&b显示组条目:"
|
||||
search-showing-users-with-page: "&b显示用户条目: {0}"
|
||||
search-showing-groups-with-page: "&b显示组条目: {0}"
|
||||
apply-edits-invalid-code: "&c无效的代码。&7({0})"
|
||||
apply-edits-unable-to-read: "&c无法使用给定代码读取数据。&7({0})"
|
||||
apply-edits-no-target: "&c无法解析编辑的目标。请提供它作为一个额外的参数。"
|
||||
apply-edits-target-group-not-exists: "&c目标组&4{0}&c不存在。"
|
||||
apply-edits-target-user-not-uuid: "&c目标用户&4{0}&c不是一个有效的uuid。"
|
||||
apply-edits-target-user-unable-to-load: "&c无法加载目标用户&4{0}&c。"
|
||||
apply-edits-target-unknown: "&c目标无效。&7({0})"
|
||||
apply-edits-success: "&a成功应用&b{0}&a节点到&b{1}&a。"
|
||||
editor-upload-failure: "&c无法将权限数据上传到编辑器。"
|
||||
editor-url: "&a编辑器URL:"
|
||||
check-result: "&a用户&b{0}&a获得允许&b{1}&a权限的检查结果&a: &f{2}"
|
||||
create-success: "&b{0}&a成功创建."
|
||||
delete-success: "&b{0}&a成功删除."
|
||||
rename-success: "&b{0}&a成功被重命名为&b{1}&a."
|
||||
clone-success: "&b{0}&a被成功地复制到了&b{1}&a."
|
||||
already-inherits: "{0}已经继承'{1}'."
|
||||
does-not-inherit: "{0}已不继承'{1}'."
|
||||
already-temp-inherits: "{0}已临时继承'{1}'."
|
||||
does-not-temp-inherit: "{0}不会临时继承'{1}'."
|
||||
track-already-contains: "轨道{0}已经包含组'{1}'."
|
||||
track-does-not-contain: "轨道{0}不包含组'{1}'."
|
||||
track-ambiguous-call: "指定的用户是此轨道上多个组的成员,无法确定他们的位置."
|
||||
group-already-exists: "该组已存在!"
|
||||
group-does-not-exist: "组不存在!"
|
||||
group-load-error: "发生意外错误,组未加载."
|
||||
groups-load-error: "发生意外错误,无法加载所有组."
|
||||
track-already-exists: "轨道已存在!"
|
||||
track-does-not-exist: "轨道不存在!"
|
||||
track-load-error: "发生意外错误. 轨道未加载."
|
||||
tracks-load-error: "出现意外错误,无法加载所有轨道."
|
||||
track-empty: "轨道不能使用,因为它是空的或只包含一个组."
|
||||
update-task-request: "&b更新任务计划."
|
||||
update-task-complete: "&a更新任务完成."
|
||||
update-task-complete-network: "&a更新任务完成,现在尝试推送到其他服务器."
|
||||
update-task-push-success: "&a其他服务器通过&b{0}成功通知."
|
||||
update-task-push-failure: "&c将更改推送到其他服务器时出错."
|
||||
update-task-push-failure-not-setup: "&c将更改推送到其他服务器时出错,未配置消息传递服务."
|
||||
reload-config-success: "&a重新加载配置文件. &7(一些选项将仅在服务器重新启动后才应用.)"
|
||||
info: >
|
||||
{PREFIX}&2运行 &bLuckPerms v{0}&2 by &bLuck&2.\n
|
||||
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: "&b{0}&a已经从环境&b{2}&a中继承&b{1}&a。"
|
||||
does-not-inherit: "&b{0}&a不再从环境&b{2}&a中继承&b{1}&a。"
|
||||
already-temp-inherits: "&b{0}&a已经从环境&b{2}&a中临时继承&b{1}&a。"
|
||||
does-not-temp-inherit: "&b{0}&a不再从环境&b{2}&a中临时继承&b{1}&a。"
|
||||
track-already-contains: "&a权限组轨道&b{0}&a已经包含组&b{1}&a。"
|
||||
track-does-not-contain: "&a权限组轨道&b{0}&a不包含组&b{1}&a。"
|
||||
track-ambiguous-call: "&c用户&4{0}&c是此权限组轨道上多个组的成员,无法确定他们的位置。"
|
||||
already-exists: "&4{0}&c已存在!"
|
||||
does-not-exist: "&4{0}&c不存在!"
|
||||
group-load-error: "&c发生意外错误,组未加载。"
|
||||
groups-load-error: "&c发生意外错误,无法加载所有组。"
|
||||
track-load-error: "&c发生意外错误。权限组轨道未加载。"
|
||||
tracks-load-error: "&c发生意外错误,无法加载所有权限组轨道。"
|
||||
track-empty: "&c权限组轨道&4{0}&c不能使用,因为它是空的或只包含一个组。"
|
||||
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将更改推送到其他服务器时出错。&7(未配置消息传递服务)"
|
||||
reload-config-success: "&a重新加载配置文件。&7(一些选项将仅在服务器重新启动后才应用)"
|
||||
info-top: >
|
||||
{PREFIX}&2运行 &bLuckPerms v{0}&2 by &bLuck&2。\n
|
||||
{PREFIX}&f- &3平台: &f{1}\n
|
||||
{PREFIX}&f- &3存储方式: &f{2}\n
|
||||
{PREFIX}&f- &3服务器名称: &f{3}\n
|
||||
{PREFIX}&f- &3同步间隔: &a{4} &f分钟\n
|
||||
{PREFIX}&f- &3消息服务: &f{5}\n
|
||||
{PREFIX}&f- &b统计:\n
|
||||
{PREFIX}&f- &3在线玩家: &a{6}\n
|
||||
{PREFIX}&f- &3加载用户: &a{7}\n
|
||||
{PREFIX}&f- &3加载组: &a{8}\n
|
||||
{PREFIX}&f- &3加载轨道: &a{9}\n
|
||||
{PREFIX}&f- &3日志大小: &a{10}\n
|
||||
{PREFIX}&f- &3UUID缓存大小: &a{11}\n
|
||||
{PREFIX}&f- &3翻译加载: &a{12}\n
|
||||
{PREFIX}&f- &3预处理环境: &a{13}\n
|
||||
{PREFIX}&f- &3环境计算器: &a{14}\n
|
||||
{PREFIX}&f- &3唯一权限: &a{15}\n
|
||||
{PREFIX}&f- &b配置:\n
|
||||
{PREFIX}&f- &3使用服务器UUIDs: {16}\n
|
||||
{PREFIX}&f- &b权限计算:\n
|
||||
{PREFIX}&f- &3包括全部: {17}\n
|
||||
{PREFIX}&f- &3包括全部世界: {18}\n
|
||||
{PREFIX}&f- &3应用全部组: {19}\n
|
||||
{PREFIX}&f- &3应用全部世界组: {20}\n
|
||||
{PREFIX}&f- &3应用通配符: {21}\n
|
||||
{PREFIX}&f- &3应用正则表达式: {22}\n
|
||||
{PREFIX}&f- &3应用速记: {23}
|
||||
create-group-error: "创建组时出错."
|
||||
delete-group-error: "删除组时出错."
|
||||
delete-group-error-default: "您不能删除默认组."
|
||||
groups-list: "&aGroups: {0}"
|
||||
create-track-error: "创建轨道时出错."
|
||||
delete-track-error: "删除轨道时出错."
|
||||
tracks-list: "&a轨道: {0}"
|
||||
listnodes: "&b{0}的节点:"
|
||||
listnodes-with-page: "&b{0}的节点: {1}"
|
||||
listnodes-temp: >
|
||||
&b{0}的临时节点:\n
|
||||
{1}
|
||||
listparents: >
|
||||
&b{0}的父组:\n
|
||||
{1}
|
||||
listparents-temp: >
|
||||
&b{0}的临时父组:\n
|
||||
{1}
|
||||
listgroups: >
|
||||
&b{0}的组:\n
|
||||
{1}
|
||||
listgroups-temp: >
|
||||
&b{0}的临时组:\n
|
||||
{1}
|
||||
{PREFIX}&f- &3服务器型号: &f{2}\n
|
||||
{PREFIX}&f- &3服务器版本: &f{3}
|
||||
info-middle: >
|
||||
{PREFIX}&f- &3消息类型: &f{0}\n
|
||||
{PREFIX}&f- &b详情:\n
|
||||
{PREFIX}&f- &3服务器名称: &f{1}\n
|
||||
{PREFIX}&f- &3在线玩家: &a{2}\n
|
||||
{PREFIX}&f- &3唯一连接: &a{3}\n
|
||||
{PREFIX}&f- &3正常运行时间: &7{4}\n
|
||||
{PREFIX}&f- &3本地数据: &a{5}&7用户,&a{6}&7组,&a{7}&7权限组轨道\n
|
||||
{PREFIX}&f- &3环境统计: &a{8}\n
|
||||
{PREFIX}&f- &3已知权限: &a{9}\n
|
||||
{PREFIX}&f- &3活动处理器: &7{10}
|
||||
create-group-error: "&c创建组&4{0}&c时出错。"
|
||||
delete-group-error: "&c删除组&4{0}&c时出错。"
|
||||
delete-group-error-default: "&c你不能删除默认组。"
|
||||
groups-list: "&a组: &7(名字,权重,权限组轨道)"
|
||||
groups-list-entry: "&f- &3{0} &7- &b{1}"
|
||||
groups-list-entry-with-tracks: "&f- &3{0} &7- &b{1} &7- [&3{2}&7]"
|
||||
tracks-list: "&a权限组轨道: {0}"
|
||||
listnodes: "&b{0}的权限:"
|
||||
listnodes-with-page: "&b{0}的权限: {1}"
|
||||
listnodes-temp: "&b{0}的临时权限:"
|
||||
listnodes-temp-with-page: "&b{0}的临时权限: {1}"
|
||||
listparents: "&b{0}的父组"
|
||||
listparents-temp: "&b{0}的临时父组:"
|
||||
list-tracks: >
|
||||
&b{0}的轨道:\n
|
||||
&b{0}的权限组轨道:\n
|
||||
{1}
|
||||
list-tracks-empty: "{0}不在任何轨道上."
|
||||
list-tracks-empty: "&b{0}&a不在任何权限组轨道上。"
|
||||
context-pair-inline: "&3{0}=&b{1}"
|
||||
context-pair--global-inline: "&e全局"
|
||||
context-pair-end: "&a."
|
||||
context-pair-sep: "&a, "
|
||||
context-pair-sep: "&a,"
|
||||
context-pair: "&8(&7{0}=&f{1}&8)"
|
||||
check-permission: "&b在环境&b{3}&b中,&b{0}&b的权限&b{1}&b被设置为&b{2}&b."
|
||||
check-permission-inherited: "&b{0}&a在环境&b{3}&a中的&b{1}&a被设置为&b{2}&a,继承自&b{4}&a."
|
||||
setpermission-success: "&a在&b{3}&a中为&b{2}&a设置&b{0}&a为&b{1}&a."
|
||||
setpermission-temp-success: "&a在环境&b{4}&a将&b{0}&a的&b{2}&a设为&b{1}&a,持续时间&b{3}&a."
|
||||
unsetpermission-success: "&a在环境&b{2}&a中取消&b{1}&a的&b{0}&a."
|
||||
unset-temp-permission-success: "&a在环境&b{2}&a中取消设置&b{1}&a的临时许可&b{0}&a."
|
||||
set-inherit-success: "&b{0}&a现在在环境&b{2}&a中继承&b{1}&a的权限&a."
|
||||
set-temp-inherit-success: "&b{0}&a现在在环境&b{3}&a中继承&b{1}&a的权限,持续时间&b{2}&a."
|
||||
set-parent-success: "&b{0}&a现有的父组被清除,现在只在&b{2}&a中继承&b{1}&a."
|
||||
unset-inherit-success: "&b{0}&a不再继承环境&b{2}&a中的&b{1}&a权限."
|
||||
unset-temp-inherit-success: "&b{0}&a在环境{2}中不再临时从&b{1}&a继承权限."
|
||||
clear-success: "&b{0}&a的权限被清除. (&b{1}&a节点被删除.)"
|
||||
clear-success-singular: "&b{0}&a的权限被清除. (&b{1}&a节点已被删除.)"
|
||||
parent-clear-success: "&b{0}&a的组被清除. (&b{1}&a节点被删除.)"
|
||||
parent-clear-success-singular: "&b{0}&a的组被清除. (&b{1}&a节点已被删除.)"
|
||||
meta-clear-success: "&b{0}&a的父组被清除. (&b{1}&a节点被删除.)"
|
||||
meta-clear-success-singular: "已经清除了这个&b{0}&a的元数据. (&b{1}&a节点已被删除.)"
|
||||
illegal-date-error: "无法解析日期'{0}'."
|
||||
past-date-error: "您不能设定一个过去的日期!"
|
||||
check-permission: "&b在环境&b{3}&b中,&b{0}&b的权限&b{1}&b被设置为&b{2}&b。"
|
||||
check-inherits-permission: "&a在环境&b{3}&a中将&b{0}&a的&b{1}&a权限设置为&b{2}&a。&7(从&a{4}&7继承)"
|
||||
setpermission-success: "&a在环境&b{3}&a中将&b{2}&a的&b{0}&a权限设置为&b{1}&a。"
|
||||
already-haspermission: "&a在环境&b{2}&a中&b{0}&a已经设置权限&b{1}&a。"
|
||||
setpermission-temp-success: "&a在环境&b{4}&a中将&b{2}&a的&b{0}&a临时权限设为&b{1}&a,持续时间&b{3}&a。"
|
||||
already-has-temp-permission: "&a在环境&b{2}&a中&b{0}&a已经设置临时权限&b{1}&a。"
|
||||
unsetpermission-success: "&a在环境&b{2}&a中取消&b{1}&a的&b{0}&a权限。"
|
||||
does-not-have-permission: "&a在环境&b{2}&a中&b{0}&a没有设置权限&b{1}&a。"
|
||||
unset-temp-permission-success: "&a在环境&b{2}&a中取消&b{1}&a的临时权限&b{0}&a。"
|
||||
does-not-have-temp-permission: "&a在环境&b{2}&a中&b{0}&a没有设置临时权限&b{1}&a。"
|
||||
set-inherit-success: "&b{0}&a现在在环境&b{2}&a中继承&b{1}&a的权限&a。"
|
||||
set-temp-inherit-success: "&b{0}&a现在在环境&b{3}&a中继承&b{1}&a的权限,持续时间&b{2}&a。"
|
||||
set-parent-success: "&b{0}&a现有的父组被清除,现在只在&b{2}&a中继承&b{1}&a。"
|
||||
set-track-parent-success: "在权限组轨道&b{1}&a上&b{0}&a现有的父组被清除,现在只在&b{3}&a中继承&b{2}&a。"
|
||||
unset-inherit-success: "&b{0}&a不再继承环境&b{2}&a中&b{1}&a的权限。"
|
||||
unset-temp-inherit-success: "&b{0}&a在环境&b{2}&a中不再继承临时权限&b{1}&a。"
|
||||
clear-success: "&b{0}&a的权限在环境&b{1}&a中被清除。(&b{2}&a节点已被删除。)"
|
||||
clear-success-singular: "&b{0}&a的权限在环境&b{1}&a中被清除。(&b{2}&a节点已被删除。)"
|
||||
parent-clear-success: "&b{0}&a的父组在环境&b{1}&a中被清除。(&b{2}&a节点被删除。)"
|
||||
parent-clear-success-singular: "&b{0}&a的父组在环境&b{1}&a中被清除。(&b{2}&a节点被删除。)"
|
||||
parent-clear-track-success: "在权限组轨道&b{1}&a上,&b{0}&a的父组在环境&b{2}&a中被清除。(&b{3}&a节点被删除。)"
|
||||
parent-clear-track-success-singular: "在权限组轨道&b{1}&a上,&b{0}&a的父组在环境&b{2}&a中被清除。(&b{3}&a节点被删除。)"
|
||||
meta-clear-success: "&b{0}&a的元数据匹配类型&b{1}&a在环境&b{2}&a中被清除。(&b{3}&a节点已被删除。)"
|
||||
meta-clear-success-singular: "&b{0}&a的元数据匹配类型&b{1}&a在环境&b{2}&a中被清除。(&b{3}&a节点已被删除。)"
|
||||
illegal-date-error: "&c无法解析日期'{0}'。"
|
||||
past-date-error: "&c你不能设定一个过去的日期!"
|
||||
chat-meta-prefix-header: "&b{0}的前缀"
|
||||
chat-meta-suffix-header: "&b{0}的后缀"
|
||||
meta-header: "&b{0}的元信息"
|
||||
chat-meta-entry: "&b-> {0} &f- &f\"{1}&f\" &8(&7继承自&a{2}&8)"
|
||||
chat-meta-entry-with-context: "&b-> {0} &f- &f\"{1}&f\" &8(&7继承自&a{2}&8){3}"
|
||||
meta-entry: "&b-> &a{0} &f= &f\"{1}&f\" &8(&7继承自&a{2}&8)"
|
||||
meta-entry-with-context: "&b-> &a{0} &f= &f\"{1}&f\" &8(&7继承自&a{2}&8){3}"
|
||||
chat-meta-prefix-none: "&b{0}没有前缀."
|
||||
chat-meta-suffix-none: "&b{0}没有后缀."
|
||||
meta-none: "&b{0}没有元信息."
|
||||
meta-invalid-priority: "优先级'{0}'无效. 应该是一个数字."
|
||||
already-has-chat-meta: "{0}已经设置了{1}."
|
||||
does-not-have-chat-meta: "{0}没有设置{1}."
|
||||
add-chatmeta-success: "&b{0}&a在环境&b{4}&a中将优先级&b{3}&a设置为 {1} &f\"{2}&f\"."
|
||||
add-temp-chatmeta-success: "&b{0}&a在环境&b{5}&a中,设置为优先级&b{3}&a的{1} &f\"{2}&f\"&a,持续时间为&b{4}&a."
|
||||
remove-chatmeta-success: "&b{0}&a在&b{3}&a中删除了优先级&b{3}&a的{1} &f\"{2}&f\"&a."
|
||||
bulk-remove-chatmeta-success: "&b{0}&a had all {1}es at priority &b{3}&a removed in context {4}&a."
|
||||
remove-temp-chatmeta-success: "&b{0}&a在环境&b{4}&a中删除了优先级&b{3}&a的临时{1} &f\"{2}&f\"&a."
|
||||
bulk-remove-temp-chatmeta-success: "&b{0}&a在环境&b{4}&a中移除了优先级&b{3}&a的所有临时&b{1}&a.."
|
||||
already-has-meta: "{0}已经有了这个元信息集."
|
||||
set-meta-success: "将环境&b{3}&a中的&b{2}&a的键&f\"{0}&f\"&a的元信息设置为&f\"{1}&f\"&a."
|
||||
set-meta-temp-success: "&a在环境&b{4}&a中将&b{2}&a的键&f\"{0}&f\"&a的值设置为&f\"{1}&f\"&a,持续时间为&b{3}&a."
|
||||
unset-meta-success: "&a在环境{2}中取消设置&b{1}&a的键&f\"{0}&f\"&a的元信息."
|
||||
unset-meta-temp-success: "&a在环境{2}中取消设置&b{1}&a的键&f\"{0}&f\"&a的临时元信息."
|
||||
bulk-update-invalid-data-type: "Invalid type. Was expecting 'all', 'users' or 'groups'."
|
||||
bulk-update-invalid-constraint: "无效的约束&4{0}&c.约束的格式应该是'&f<field> <comparison operator> <value>&c'."
|
||||
bulk-update-invalid-comparison: "比较运算符无效'&4{0}&c'. 应该以下之一: &f== != ~~ ~!"
|
||||
bulk-update-queued: "&a批量更新操作已排队.&7(&f{0}&7)"
|
||||
bulk-update-confirm: "&a运行&b/{0} bulkupdate &a确认{1}执行更新."
|
||||
bulk-update-unknown-id: "&a使用id&b{0}&a的操作不存在或已过期."
|
||||
bulk-update-starting: "&a运行批量更新."
|
||||
bulk-update-success: "&b量更新已成功完成."
|
||||
bulk-update-failure: "&cBulk update failed. Check the console for errors."
|
||||
bulk-change-type-error: "类型无效. 应该是 'server' 或 'world'."
|
||||
bulk-change-success: "&a应用批量更改成功. {0}记录已更改."
|
||||
chat-meta-entry: "&b-> {0} &f- &f'{1}&f' &8(&7继承自&a{2}&8)"
|
||||
chat-meta-entry-with-context: "&b-> {0} &f- &f'{1}&f' &8(&7继承自&a{2}&8){3}"
|
||||
meta-entry: "&b-> &a{0} &f= &f'{1}&f' &8(&7继承自&a{2}&8)"
|
||||
meta-entry-with-context: "&b-> &a{0} &f= &f'{1}&f' &8(&7继承自&a{2}&8){3}"
|
||||
chat-meta-prefix-none: "&b{0}没有前缀。"
|
||||
chat-meta-suffix-none: "&b{0}没有后缀。"
|
||||
meta-none: "&b{0}没有元信息。"
|
||||
meta-invalid-priority: "&c优先级&4{0}&c无效。应该是一个数字。"
|
||||
already-has-chat-meta: "在环境&b{4}&a中设置&b{0}&a的元信息{1}&f'{2}&f'&a优先级为&b{3}&a。"
|
||||
already-has-temp-chat-meta: "在环境&b{4}&a中设置&b{0}&a的元信息{1}&f'{2}&f'&a临时优先级为&b{3}&a。"
|
||||
does-not-have-chat-meta: "在环境&b{4}&a中没有设置&b{0}&a的元信息{1}&f'{2}&f'&a优先级为&b{3}&a。"
|
||||
does-not-have-temp-chat-meta: "在环境&b{4}&a中没有设置&b{0}&a的元信息{1}&f'{2}&f'&a临时优先级为&b{3}&a。"
|
||||
add-chatmeta-success: "在环境&b{4}&a中将&b{0}&a的{1}设置为&f'{2}&f',优先级&b{3}&a。"
|
||||
add-temp-chatmeta-success: "在环境&b{5}&a中将&b{0}&a的{1}设置为&f'{2}&f'&a,优先级&b{3}&a,持续时间为&b{4}&a。"
|
||||
remove-chatmeta-success: "在环境&b{4}&a中删除了&b{0}&a优先级为&b{3}&a的{1} &f'{2}&f'&a。"
|
||||
bulk-remove-chatmeta-success: "在环境&b{3}&a中删除了&b{0}&a优先级&b{2}&a的所有&b{1}&a。"
|
||||
remove-temp-chatmeta-success: "在环境&b{4}&a中删除了&b{0}&a优先级&b{3}&a的临时{1} &f'{2}&f'&a。"
|
||||
bulk-remove-temp-chatmeta-success: "在环境&b{3}&a中删除了&b{0}&a优先级&b{2}&a的所有临时&b{1}&a。"
|
||||
already-has-meta: "&b{0}&a在环境&b{3}&a中设置了元信息&f'{1}&f'&a为&b&f'{2}&f'&a。"
|
||||
already-has-temp-meta: "&b{0}&a在环境&b{3}&a中设置了临时元信息&f'{1}&f'&a为&b&f'{2}&f'&a。"
|
||||
doesnt-have-meta: "&b{0}&a在环境&b{2}&a中没有设置元信息&f'{1}&f'&a。"
|
||||
doesnt-have-temp-meta: "&b{0}&a在环境&b{2}&a中没有设置临时元信息&f'{1}&f'&a。"
|
||||
set-meta-success: "&a在环境&b{3}&a中将&b{2}&a的元信息&f'{0}&f'&a设置为&f'{1}&f'&a。"
|
||||
set-meta-temp-success: "&a在环境&b{4}&a中将&b{2}&a的元信息&f'{0}&f'&a设置为&f'{1}&f'&a,持续时间为&b{3}&a。"
|
||||
unset-meta-success: "&a在环境{2}中取消设置&b{1}&a的元信息&f'{0}&f'&a。"
|
||||
unset-meta-temp-success: "&a在环境{2}中取消设置&b{1}&a的临时元信息&f'{0}&f'&a。"
|
||||
bulk-update-invalid-data-type: "&c类型无效。期望类型是'全部'、'用户'或'组'。"
|
||||
bulk-update-invalid-constraint: "&c无效的约束&4{0}&c。约束的格式应该是'&f<field> <comparison operator> <value>&c'。"
|
||||
bulk-update-invalid-comparison: "&c比较运算符无效'&4{0}&c'。应该以下之一: &f== != ~~ ~!"
|
||||
bulk-update-queued: "&a批量更新操作已排队。&7(&f{0}&7)"
|
||||
bulk-update-confirm: "&a运行&b/{0} bulkupdate &a确认{1}执行更新。"
|
||||
bulk-update-unknown-id: "&a使用id&b{0}&a的操作不存在或已过期。"
|
||||
bulk-update-starting: "&a运行批量更新。"
|
||||
bulk-update-success: "&b批量更新已成功完成。"
|
||||
bulk-update-failure: "&c批量更新失败。检查控制台是否有错误。"
|
||||
user-info-general: >
|
||||
{PREFIX}&b&l> &bUser Info: &f{0}\n
|
||||
{PREFIX}&b&l> &b用户信息: &f{0}\n
|
||||
{PREFIX}&f- &3UUID: &f{1}\n
|
||||
{PREFIX}&f- &3状态: {2}\n
|
||||
{PREFIX}&f- &3主组: &f{3}\n
|
||||
{PREFIX}&f- &a统计:\n
|
||||
{PREFIX}&f- &3权限: &a{4}\n
|
||||
{PREFIX}&f- &3临时权限: &a{5}\n
|
||||
{PREFIX}&f- &3节点: &a{4}\n
|
||||
{PREFIX}&f- &3权限: &a{5}\n
|
||||
{PREFIX}&f- &3前缀: &a{6}\n
|
||||
{PREFIX}&f- &3后缀: &a{7}\n
|
||||
{PREFIX}&f- &3元信息: &a{8}
|
||||
user-info-data: >
|
||||
{PREFIX}&f- &aCached Data:\n
|
||||
{PREFIX}&f- &a缓存数据:\n
|
||||
{PREFIX}&f- &3具有环境数据: {0}\n
|
||||
{PREFIX}&f- &3当前环境: {1}\n
|
||||
{PREFIX}&f- &3当前前缀: {2}\n
|
||||
{PREFIX}&f- &3当前后缀: {3}
|
||||
info-parent-header: "&f- &a父组:"
|
||||
info-temp-parent-header: "&f- &a临时父组:"
|
||||
user-getuuid: "&b{0}&b的UUID是&b{1}&b."
|
||||
user-removegroup-error-primary: "您不能从其主组中删除用户."
|
||||
user-primarygroup-success: "&b{0}&的主组已设为&b{1}&a."
|
||||
user-primarygroup-warn-option: "&c警告:此服务器&7({0})&c使用的主组计算方法可能无法反映此更改."
|
||||
user-primarygroup-error-alreadyhas: "用户已将此组设置为其主组."
|
||||
user-primarygroup-error-notmember: "&b{0}&a已经不是&b{1}&a的成员,现在添加它们."
|
||||
user-track-error-not-contain-group: "指定的用户尚未在此轨道上的任何组中."
|
||||
user-track-added-to-first: "&b{0}&a不在此轨道上的任何组中, 因此在环境&b{2}&a中将其添加到第一组&b{2}&a."
|
||||
user-promote-success: "&a在环境&b{3}&a中将用户沿轨道&b{0}&a从&b{1}&a提升到&b{2}&a."
|
||||
user-promote-error-endoftrack: "已达到轨道&4{0}&c的结尾,所以无法提升用户."
|
||||
user-removegroup-error-primary: "&a你不能从其主组中删除用户。"
|
||||
user-primarygroup-success: "&b{0}&a的主组已设为&b{1}&a。"
|
||||
user-primarygroup-warn-option: "&a警告:此服务器&7({0})&a使用的主组计算方法可能无法反映此更改。"
|
||||
user-primarygroup-error-alreadyhas: "&a已将&b{1}&a设置为用户&b{0}&a的主组。"
|
||||
user-primarygroup-error-notmember: "&b{0}&a不是&b{1}&a的成员,现在添加它们。"
|
||||
user-track-error-not-contain-group: "&a用户&b{0}&a尚未在权限组轨道&b{1}&a上的任何组中。"
|
||||
user-track-added-to-first: "&b{0}&a不在此权限组轨道上的任何组中,因此在环境&b{2}&a中将其添加到第一组&b{2}&a。"
|
||||
user-promote-success: "&a在环境&b{4}&a中将用户&b{0}&a沿权限组轨道&b{1}&a从&b{2}&a提升到&b{3}&a。"
|
||||
user-promote-error-endoftrack: "&a已达到权限组轨道&b{0}&a的结尾,所以无法提升用户&b{1}&a。"
|
||||
user-promote-error-malformed: >
|
||||
{PREFIX}轨道上的下一个组{0}不存在. 无法提升用户.\n
|
||||
{PREFIX}创建组,或将其从轨道中删除,然后重试.
|
||||
user-demote-success: "&a在环境&b{3}&a中将用户沿轨道&b{0}&a从&b{1}&a转移到&b{2}&a."
|
||||
user-demote-endoftrack: "已达到轨道&4{0}&c的结尾,所以&4{1}&c已从&4{2}&c中移除."
|
||||
{PREFIX}&a权限组轨道上的下一个组&b{0}&a不存在。无法提升用户。\n
|
||||
{PREFIX}&a创建组,或将其从权限组轨道中删除,然后重试。
|
||||
user-demote-success: "&a在环境&b{4}&a中将&b{0}&a沿权限组轨道&b{1}&a从&b{2}&a下降到&b{3}&a。"
|
||||
user-demote-endoftrack: "&a已达到权限组轨道&b{0}&a的结尾,所以&b{1}&a已从&b{2}&a中移除。"
|
||||
user-demote-error-malformed: >
|
||||
{PREFIX}轨道上的上一组{0}不存在.无法降级用户.\n
|
||||
{PREFIX}创建组,或将其从轨道中删除,然后重试.
|
||||
user-showpos: >
|
||||
&a显示&b{0}&a在轨道&b{1}&a的位置.\n
|
||||
{2}
|
||||
{PREFIX}&a权限组轨道上的上一组&b{0}&a不存在。无法降级用户。\n
|
||||
{PREFIX}&a创建组,或将其从权限组轨道中删除,然后重试。
|
||||
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{3}\n
|
||||
{PREFIX}&f- &3临时权限: &a{4}\n
|
||||
{PREFIX}&f- &3前缀: &a{5}\n
|
||||
{PREFIX}&f- &3后缀: &a{6}\n
|
||||
{PREFIX}&f- &3元信息: &a{7}
|
||||
group-set-weight: "&a将组&b{1}&a的权重设置为&b{0}&a."
|
||||
group-set-weight: "&a将组&b{1}&a的权重设置为&b{0}&a。"
|
||||
track-info: >
|
||||
{PREFIX}&b&l> &b显示轨道: &f{0}\n
|
||||
{PREFIX}&b&l> &b显示权限组轨道: &f{0}\n
|
||||
{PREFIX}&f- &7路径: &f{1}
|
||||
track-clear: "&b{0}&a's groups track was cleared."
|
||||
track-append-success: "&a组&b{0}&a已成功添加到轨道&b{1}&a."
|
||||
track-insert-success: "&a组&b{0}&a已成功插入轨道&b{1}&a的&b{2}&a位置."
|
||||
track-insert-error-number: "没有预期的数量,而是收到: {0}"
|
||||
track-insert-error-invalid-pos: "无法插入位置{0}. 索引超出范围."
|
||||
track-remove-success: "&aGroup &b{0}&a已成功从轨道&b{1}&a移除."
|
||||
log-load-error: "日志无法加载."
|
||||
log-invalid-page: "页码无效."
|
||||
log-invalid-page-range: "页码无效,请输入1和{0}之间的值."
|
||||
log-no-entries: "&b没有日志条目显示."
|
||||
track-clear: "&b{0}&a的权限组轨道已被清除。"
|
||||
track-append-success: "&a组&b{0}&a已成功添加到权限组轨道&b{1}&a。"
|
||||
track-insert-success: "&a组&b{0}&a已成功插入权限组轨道&b{1}&a的&b{2}&a位置。"
|
||||
track-insert-error-number: "&c没有预期的数量,而是收到: {0}"
|
||||
track-insert-error-invalid-pos: "&c无法插入位置&4{0}&c。&7(无效位置)"
|
||||
track-remove-success: "&a组&b{0}&a已成功从权限组轨道&b{1}&a移除。"
|
||||
log-load-error: "&c日志无法加载。"
|
||||
log-invalid-page: "&c页码无效。"
|
||||
log-invalid-page-range: "&c页码无效,请输入&41&c和&4{0}&c之间的值。"
|
||||
log-no-entries: "&b没有日志条目显示。"
|
||||
log-entry: "&b#{0} -> &8(&7{1} ago&8) {2}"
|
||||
log-notify-toggle-on: "&a启用&b记录输出."
|
||||
log-notify-toggle-off: "&c禁用&b记录输出."
|
||||
log-notify-already-on: "您已经收到通知."
|
||||
log-notify-already-off: "您目前没有收到通知."
|
||||
log-notify-unknown: "状态未知.输入 \"on\" 或者 \"off\"."
|
||||
log-search-header: "&a显示最近的查询操作&b{0} &a(page &f{1}&a of &f{2}&a)"
|
||||
log-recent-header: "&a显示最近操作 (page &f{0}&a of &f{1}&a)"
|
||||
log-recent-by-header: "&a显示&b{0}&a的最近操作 (page &f{1}&a of &f{2}&a)"
|
||||
log-history-user-header: "&a显示用户的历史记录&b{0} &a(page &f{1}&a of &f{2}&a)"
|
||||
log-history-group-header: "&a显示组的历史记录 &b{0} &a(page &f{1}&a of &f{2}&a)"
|
||||
log-history-track-header: "&a显示轨道的历史记录 &b{0} &a(page &f{1}&a of &f{2}&a)"
|
||||
log-export-already-exists: "错误: 文件{0}已经存在."
|
||||
log-export-not-writable: "错误: 文件{0}不可写."
|
||||
log-export-empty: "日志为空,因此无法导出."
|
||||
log-export-failure: "写入文件时出现意外错误."
|
||||
log-export-success: "&a成功导出日志&b{0}&a."
|
||||
import-already-running: "另一个导入过程已经在运行,请等待完成,然后重试."
|
||||
export-already-running: "另一个导出过程已经在运行,请等待完成,然后重试."
|
||||
import-log-doesnt-exist: "错误: 文件{0}不存在."
|
||||
import-log-not-readable: "错误: 文件{0}不可读."
|
||||
import-log-failure: "从日志文件读取时发生意外错误."
|
||||
import-progress: "&b(导入) &b-> &f百分之{0}完成 &7- &b{1}&f/&b{2} &f完成 &c{3}&f错误."
|
||||
import-progress-sin: "&b(导入) &b-> &f百分之{0}完成 &7- &b{1}&f/&b{2} &f完成 &c{3}&f错误."
|
||||
import-start: "&b(导入) &b-> &f开始导入过程."
|
||||
import-end-complete: "&b(导入) &a&l已完成 &7- 用了 &b{0} &7秒 - &7没有错误."
|
||||
import-end-complete-err: "&b(导入) &a&l已完成 &7- 用了 &b{0} &7秒 - &c{1}错误."
|
||||
import-end-complete-err-sin: "&b(导入) &a&l已完成 &7- 用了 &b{0} &7秒 - &c{1}错误."
|
||||
log-notify-console: "&c无法切换控制台通知。"
|
||||
log-notify-toggle-on: "&a启用&b记录输出。"
|
||||
log-notify-toggle-off: "&c禁用&b记录输出。"
|
||||
log-notify-already-on: "&c你已经收到通知。"
|
||||
log-notify-already-off: "&c你目前没有收到通知。"
|
||||
log-notify-unknown: "&c状态未知。输入 \"on\" 或者 \"off\"。"
|
||||
log-search-header: "&a显示最近的查询操作&b{0} &a(&f{1}&a/&f{2}&a)"
|
||||
log-recent-header: "&a显示最近操作 (&f{0}&a/&f{1}&a)"
|
||||
log-recent-by-header: "&a显示&b{0}&a的最近操作 (&f{1}&a/&f{2}&a)"
|
||||
log-history-user-header: "&a显示用户的历史记录&b{0} &a(&f{1}&a/&f{2}&a)"
|
||||
log-history-group-header: "&a显示组的历史记录 &b{0} &a(&f{1}&a/&f{2}&a)"
|
||||
log-history-track-header: "&a显示权限组轨道的历史记录 &b{0} &a(&f{1}&a/&f{2}&a)"
|
||||
log-export-already-exists: "&c错误: 文件&4{0}&c已经存在。"
|
||||
log-export-not-writable: "&c错误: 文件&4{0}&c不可写。"
|
||||
log-export-empty: "&c日志为空,因此无法导出。"
|
||||
log-export-failure: "&c写入文件时出现意外错误。"
|
||||
log-export-success: "&a成功导出日志&b{0}&a。"
|
||||
import-already-running: "&c另一个导入过程已经在运行,请等待完成,然后重试。"
|
||||
export-already-running: "&c另一个导出过程已经在运行,请等待完成,然后重试。"
|
||||
import-log-doesnt-exist: "&c错误: 文件&4{0}&c不存在。"
|
||||
import-log-not-readable: "&c错误: 文件&4{0}&c不可读。"
|
||||
import-log-failure: "&c从日志文件读取时发生意外错误。"
|
||||
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(导入) &7------------> &f显示错误 #&b{0} &7<------------\n
|
||||
{PREFIX}&b(导入) &f执行时: &3Command #{1}\n
|
||||
{PREFIX}&b(导入) &f执行: &3命令 #{1}\n
|
||||
{PREFIX}&b(导入) &f命令: &7{2}\n
|
||||
{PREFIX}&b(导入) &f类型: &3{3}\n
|
||||
{PREFIX}&b(导入) &f输出:
|
||||
import-end-error-content: "&b(导入) &b-> &c{0}"
|
||||
import-end-error-footer: "&b(导入) &7<------------------------------------------>"
|
||||
import-end-error-footer: "&b(导入) &7<------------------------------------------>"
|
||||
|
||||
command-specs:
|
||||
user:
|
||||
description: "用户命令"
|
||||
usage: "/%s user <用户>"
|
||||
group:
|
||||
description: "组命令"
|
||||
usage: "/%s group <组>"
|
||||
track:
|
||||
description: "权限组轨道指令"
|
||||
usage: "/%s track <权限组轨道>"
|
||||
log:
|
||||
description: "日志命令"
|
||||
usage: "/%s log"
|
||||
sync:
|
||||
description: "与存储同步更改"
|
||||
usage: "/%s sync"
|
||||
info:
|
||||
description: "打印通用插件信息"
|
||||
usage: "/%s info"
|
||||
verbose:
|
||||
description: "管理详细权限检查"
|
||||
usage: "/%s verbose <true|false> [filter]"
|
||||
args:
|
||||
"on|record|off|paste": "是否启用/禁用日志记录,或粘贴记录的输出"
|
||||
"filter": "过滤器匹配项"
|
||||
"--slim": "添加\"--slim\"从粘贴的输出中排除跟踪数据"
|
||||
tree:
|
||||
description: "生成权限的树视图"
|
||||
usage: "/%s tree [selection] [max level] [player]"
|
||||
args:
|
||||
"selection": "树的根,指定\".\"包括所有权限"
|
||||
"max level": "应该返回多少分支级别"
|
||||
"player": "要检查的在线玩家的名称"
|
||||
search:
|
||||
description: "搜索具有特定权限的用户/组"
|
||||
usage: "/%s search <permission>"
|
||||
args:
|
||||
"permission": "权限搜索"
|
||||
"page": "页面查看"
|
||||
check:
|
||||
description: "对用户执行标准的权限检查"
|
||||
usage: "/%s check <user> <permission>"
|
||||
args:
|
||||
"user": "检查用户"
|
||||
"permission": "允许检查"
|
||||
network-sync:
|
||||
description: "与存储同步更改并请求网络上所有其他服务器都同步"
|
||||
usage: "/%s networksync"
|
||||
import:
|
||||
description: "从文件导入数据"
|
||||
usage: "/%s import <file>"
|
||||
args:
|
||||
"file": "要导入的文件"
|
||||
export:
|
||||
description: "将数据导出到文件"
|
||||
usage: "/%s export <file>"
|
||||
args:
|
||||
"file": "要导出的文件"
|
||||
reload-config:
|
||||
description: "重新加载部分配置选项"
|
||||
usage: "/%s reloadconfig"
|
||||
bulk-update:
|
||||
description: "对所有数据执行批量更改查询"
|
||||
usage: "/%s bulkupdate"
|
||||
args:
|
||||
"data type": "正在更改的数据类型。('all'、'users'、'groups')"
|
||||
"action": "对数据执行的操作。('update' or 'delete')"
|
||||
"action field": "要采取行动的领域。只需要'update'。('permission'、'server'、'world')"
|
||||
"action value": "替换的值。只需要'update'。"
|
||||
"constraint...": "更新所需的限制"
|
||||
migration:
|
||||
description: "迁移命令"
|
||||
usage: "/%s migration"
|
||||
apply-edits:
|
||||
description: "应用从Web编辑器进行的权限更改"
|
||||
usage: "/%s applyedits <code> [target]"
|
||||
args:
|
||||
"code": "数据的唯一代码"
|
||||
"target": "应用数据到谁"
|
||||
create-group:
|
||||
description: "创建新组"
|
||||
usage: "/%s creategroup <group>"
|
||||
args:
|
||||
"name": "组的名称"
|
||||
delete-group:
|
||||
description: "删除组"
|
||||
usage: "/%s deletegroup <group>"
|
||||
args:
|
||||
"name": "组的名称"
|
||||
list-groups:
|
||||
description: "列出平台上的所有组"
|
||||
usage: "/%s listgroups"
|
||||
create-track:
|
||||
description: "创建新权限组轨道"
|
||||
usage: "/%s createtrack <track>"
|
||||
args:
|
||||
"name": "权限组轨道的名称"
|
||||
delete-track:
|
||||
description: "删除权限组轨道"
|
||||
usage: "/%s deletetrack <track>"
|
||||
args:
|
||||
"name": "权限组轨道的名称"
|
||||
list-tracks:
|
||||
description: "列出平台上的所有权限组轨道"
|
||||
usage: "/%s listtracks"
|
||||
user-info:
|
||||
description: "显示有关用户的信息"
|
||||
user-switchprimarygroup:
|
||||
description: "切换用户的主组"
|
||||
args:
|
||||
"group": "组切换到"
|
||||
user-promote:
|
||||
description: "在权限组轨道提升用户"
|
||||
args:
|
||||
"track": "提升用户的权限组轨道"
|
||||
"context...": "提升用户使用的环境"
|
||||
user-demote:
|
||||
description: "在权限组轨道降低用户"
|
||||
args:
|
||||
"track": "降低用户的权限组轨道"
|
||||
"context...": "降低用户使用的环境"
|
||||
group-info:
|
||||
description: "提供有关组的信息"
|
||||
group-listmembers:
|
||||
description: "显示从该组继承的用户/组"
|
||||
args:
|
||||
"page": "页面查看"
|
||||
group-setweight:
|
||||
description: "设置组权重"
|
||||
args:
|
||||
"weight": "设定权重"
|
||||
group-rename:
|
||||
description: "重命名组"
|
||||
args:
|
||||
"name": "新名字"
|
||||
group-clone:
|
||||
description: "克隆组"
|
||||
args:
|
||||
"name": "要克隆到的组的名称"
|
||||
holder-editor:
|
||||
description: "打开网页权限编辑器"
|
||||
holder-showtracks:
|
||||
description: "列出对象所在的权限组轨道"
|
||||
holder-clear:
|
||||
description: "删除所有权限,父组和元"
|
||||
args:
|
||||
"context...": "过滤的环境"
|
||||
permission:
|
||||
description: "编辑权限"
|
||||
parent:
|
||||
description: "编辑继承"
|
||||
meta:
|
||||
description: "编辑元数据值"
|
||||
permission-info:
|
||||
description: "列出对象拥有的权限节点"
|
||||
args:
|
||||
"page": "页面查看"
|
||||
"filter": "要过滤的字符串"
|
||||
permission-set:
|
||||
description: "设置对象的权限"
|
||||
args:
|
||||
"node": "要添加的权限"
|
||||
"true|false": "节点的值"
|
||||
"context...": "添加权限的环境"
|
||||
permission-unset:
|
||||
description: "取消对象的权限"
|
||||
args:
|
||||
"node": "取消的权限节点"
|
||||
"context...": "删除权限的环境"
|
||||
permission-settemp:
|
||||
description: "设置对象的临时权限"
|
||||
args:
|
||||
"node": "要添加的权限"
|
||||
"true|false": "节点的值"
|
||||
"duration": "到期时间"
|
||||
"context...": "权限的环境"
|
||||
permission-unsettemp:
|
||||
description: "取消对对象的临时权限"
|
||||
args:
|
||||
"node": "要取消的权限"
|
||||
"context...": "权限的环境"
|
||||
permission-check:
|
||||
description: "检查对象是否具有某个权限节点"
|
||||
args:
|
||||
"node": "要检查的权限"
|
||||
"context...": "权限的环境"
|
||||
permission-check-inherits:
|
||||
description: "检查对象是否继承某个权限节点"
|
||||
args:
|
||||
"node": "要检查的权限"
|
||||
"context...": "权限的环境"
|
||||
parent-info:
|
||||
description: "列出此对象从哪里继承的组"
|
||||
parent-set:
|
||||
description: "删除对象已经继承的所有其他组,并将其添加到给定的对象组中。"
|
||||
args:
|
||||
"group": "组设为"
|
||||
"context...": "设置组的环境"
|
||||
parent-add:
|
||||
description: "为该对象设置另一个组来继承权限"
|
||||
args:
|
||||
"group": "要继承的组"
|
||||
"context...": "继承该组的环境"
|
||||
parent-remove:
|
||||
description: "删除先前设置的继承规则"
|
||||
args:
|
||||
"group": "删除的组"
|
||||
"context...": "删除组的环境"
|
||||
parent-set-track:
|
||||
description: "删除对象在给定权限组轨道上继承的所有其他组,并将其添加到给定的权限组轨道上。"
|
||||
args:
|
||||
"track": "设置的权限组轨道"
|
||||
"group": "组中设置的组,或与组中在给定权限组轨道上的位置相关的数字"
|
||||
"context...": "设置组的环境"
|
||||
parent-add-temp:
|
||||
description: "为对象设置另一个组,以便从临时继承权限"
|
||||
args:
|
||||
"group": "要继承的组"
|
||||
"duration": "持续时间"
|
||||
"context...": "继承该组的环境"
|
||||
parent-remove-temp:
|
||||
description: "删除以前设置的临时继承规则"
|
||||
args:
|
||||
"group": "组删除"
|
||||
"context...": "删除组的环境"
|
||||
parent-clear:
|
||||
description: "清除所有的父组"
|
||||
args:
|
||||
"context...": "过滤的环境"
|
||||
parent-clear-track:
|
||||
description: "清除给定权限组轨道上的所有父组"
|
||||
args:
|
||||
"track": "删除的权限组轨道"
|
||||
"contexts...": "选择的环境"
|
||||
meta-info:
|
||||
description: "显示所有聊天元"
|
||||
meta-set:
|
||||
description: "设置元值"
|
||||
args:
|
||||
"key": "设定的键"
|
||||
"value": "要设置的值"
|
||||
"context...": "将元添加到"
|
||||
meta-unset:
|
||||
description: "取消设定元值"
|
||||
args:
|
||||
"key": "要取消的键"
|
||||
"context...": "删除元的环境"
|
||||
meta-settemp:
|
||||
description: "暂时设置一个元值"
|
||||
args:
|
||||
"key": "设定的键"
|
||||
"value": "要设置的值"
|
||||
"duration": "持续时间"
|
||||
"context...": "将元组添加到"
|
||||
meta-unsettemp:
|
||||
description: "取消设置临时元值"
|
||||
args:
|
||||
"key": "要取消的键"
|
||||
"context...": "删除元的环境"
|
||||
meta-addprefix:
|
||||
description: "添加前缀"
|
||||
args:
|
||||
"priority": "添加的前缀优先级"
|
||||
"prefix": "前缀字符串"
|
||||
"context...": "添加前缀的环境"
|
||||
meta-addsuffix:
|
||||
description: "添加后缀"
|
||||
args:
|
||||
"priority": "添加的后缀优先级"
|
||||
"suffix": "后缀字符串"
|
||||
"context...": "添加后缀的环境"
|
||||
meta-removeprefix:
|
||||
description: "删除前缀"
|
||||
args:
|
||||
"priority": "删除的前缀优先级"
|
||||
"prefix": "前缀字符串"
|
||||
"context...": "删除前缀的环境"
|
||||
meta-removesuffix:
|
||||
description: "删除后缀"
|
||||
args:
|
||||
"priority": "删除的后缀优先级"
|
||||
"suffix": "后缀字符串"
|
||||
"context...": "删除后缀的环境"
|
||||
meta-addtemp-prefix:
|
||||
description: "添加临时前缀"
|
||||
args:
|
||||
"priority": "删除的前缀优先级"
|
||||
"prefix": "前缀字符串"
|
||||
"duration": "持续时间"
|
||||
"context...": "添加前缀的环境"
|
||||
meta-addtemp-suffix:
|
||||
description: "添加临时后缀"
|
||||
args:
|
||||
"priority": "添加的后缀优先级"
|
||||
"suffix": "后缀字符串"
|
||||
"duration": "持续时间"
|
||||
"context...": "添加后缀的环境"
|
||||
meta-removetemp-prefix:
|
||||
description: "删除临时前缀"
|
||||
args:
|
||||
"priority": "删除的前缀优先级"
|
||||
"prefix": "前缀字符串"
|
||||
"context...": "删除前缀的环境"
|
||||
meta-removetemp-suffix:
|
||||
description: "删除临时后缀"
|
||||
args:
|
||||
"priority": "删除的后缀优先级"
|
||||
"suffix": "后缀字符串"
|
||||
"context...": "删除后缀的环境"
|
||||
meta-clear:
|
||||
description: "清除所有元"
|
||||
args:
|
||||
"type": "要删除的元数据类型"
|
||||
"context...": "过滤的环境"
|
||||
track-info:
|
||||
description: "提供有关权限组轨道的信息"
|
||||
track-append:
|
||||
description: "追加一个组到权限组轨道的最后"
|
||||
args:
|
||||
"group": "追加的组"
|
||||
track-insert:
|
||||
description: "在权限组轨道上的给定位置插入一个组"
|
||||
args:
|
||||
"group": "插入的组"
|
||||
"position": "插入组的位置(权限组轨道上的第一个位置为1)"
|
||||
track-remove:
|
||||
description: "从权限组轨道中删除一个组"
|
||||
args:
|
||||
"group": "删除的组"
|
||||
track-clear:
|
||||
description: "清除权限组轨道上的组"
|
||||
track-rename:
|
||||
description: "重命名权限组轨道"
|
||||
args:
|
||||
"name": "新名字"
|
||||
track-clone:
|
||||
description: "克隆权限组轨道"
|
||||
args:
|
||||
"name": "要克隆的权限组轨道的名称"
|
||||
log-recent:
|
||||
description: "查看最近的登陆"
|
||||
args:
|
||||
"user": "用户的名称/uuid"
|
||||
"page": "要查看的页码"
|
||||
log-search:
|
||||
description: "搜索日志中的条目"
|
||||
args:
|
||||
"query": "搜索的查询"
|
||||
"page": "要查看的页码"
|
||||
log-notify:
|
||||
description: "切换日志通知"
|
||||
args:
|
||||
"on|off": "是否打开或关闭"
|
||||
log-user-history:
|
||||
description: "查看用户的历史记录"
|
||||
args:
|
||||
"user": "用户名/ uuid"
|
||||
"page": "要查看的页码"
|
||||
log-group-history:
|
||||
description: "查看组的历史"
|
||||
args:
|
||||
"group": "组名"
|
||||
"page": "要查看的页码"
|
||||
log-track-history:
|
||||
description: "查看权限组轨道的历史"
|
||||
args:
|
||||
"track": "权限组轨道的名称"
|
||||
"page": "要查看的页码"
|
||||
sponge:
|
||||
description: "编辑额外的Sponge数据"
|
||||
usage: "/%s sponge <collection> <subject>"
|
||||
args:
|
||||
"collection": "要查询的集合"
|
||||
"subject": "修改的主题"
|
||||
sponge-permission-info:
|
||||
description: "显示有关主题权限的信息"
|
||||
args:
|
||||
"contexts...": "选择的环境"
|
||||
sponge-permission-set:
|
||||
description: "设置一个主题的权限"
|
||||
args:
|
||||
"node": "要设置的权限节点"
|
||||
"tristate": "设置允许值"
|
||||
"contexts...": "选择的环境"
|
||||
sponge-permission-clear:
|
||||
description: "清除一个主题的权限"
|
||||
args:
|
||||
"contexts...": "清除的环境"
|
||||
sponge-parent-info:
|
||||
description: "显示关于该主题父项的信息"
|
||||
args:
|
||||
"contexts...": "选择的环境"
|
||||
sponge-parent-add:
|
||||
description: "向主题添加父项"
|
||||
args:
|
||||
"collection": "父主题的主题集合"
|
||||
"subject": "父主题的名称"
|
||||
"contexts...": "添加父项的环境"
|
||||
sponge-parent-remove:
|
||||
description: "从主题中删除父项"
|
||||
args:
|
||||
"collection": "父主题的主题集合"
|
||||
"subject": "父主题的名称"
|
||||
"contexts...": "删除父项的环境"
|
||||
sponge-parent-clear:
|
||||
description: "清除主题父项"
|
||||
args:
|
||||
"contexts...": "清除父项的主题"
|
||||
sponge-option-info:
|
||||
description: "显示有关主题选项的信息"
|
||||
args:
|
||||
"contexts...": "选择的环境"
|
||||
sponge-option-set:
|
||||
description: "为主题设置一个选项"
|
||||
args:
|
||||
"key": "设定键"
|
||||
"value": "设置的键"
|
||||
"contexts...": "设置选项的环境"
|
||||
sponge-option-unset:
|
||||
description: "取消主题一个选项"
|
||||
args:
|
||||
"key": "取消的键"
|
||||
"contexts...": "取消选项的环境"
|
||||
sponge-option-clear:
|
||||
description: "清除对象的选择"
|
||||
args:
|
||||
"contexts...": "清除选项的环境"
|
||||
migration-command:
|
||||
description: "迁移命令"
|
||||
migration-groupmanager:
|
||||
description: "迁移命令"
|
||||
args:
|
||||
"migrate as global": "如果世界权限应该被忽略,并且刚刚迁移为全局"
|
||||
migration-powerfulperms:
|
||||
description: "迁移命令"
|
||||
args:
|
||||
"address": "PP数据库的地址"
|
||||
"database": "PP数据库的名称"
|
||||
"username": "登录DB的用户名"
|
||||
"password": "登录DB的用密码"
|
||||
"db table": "存储用户数据的PP表的名称"
|
||||
@@ -49,15 +49,15 @@ The project is split up into 5 seperate modules.
|
||||
## License
|
||||
LuckPerms is licensed under the permissive MIT license. Please see [`LICENSE.txt`](https://github.com/lucko/LuckPerms/blob/master/LICENSE.txt) for more info.
|
||||
|
||||
## LuckPerms vs Other Plugins
|
||||
## Why use LuckPerms?
|
||||
The main features of LuckPerms are detailed on this wiki page: [Why LuckPerms?](https://github.com/lucko/LuckPerms/wiki/Why-LuckPerms)
|
||||
|
||||
### Bukkit
|
||||

|
||||
See [here](https://luckperms.lucko.me/assets/bukkit-compare.png) for a comparison chart showing the differences between LuckPerms and other permission plugins for Bukkit.
|
||||
|
||||
### Sponge
|
||||

|
||||
LuckPerms is currently the only maintained and 'working' permissions plugin for Sponge servers.
|
||||
|
||||
|
||||
## 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").
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>luckperms</artifactId>
|
||||
<groupId>me.lucko.luckperms</groupId>
|
||||
<version>3.3-SNAPSHOT</version>
|
||||
<version>4.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -32,49 +32,59 @@ import java.util.Optional;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Singleton for the {@link LuckPermsApi}.
|
||||
* Provides static access to the {@link LuckPermsApi}.
|
||||
*
|
||||
* <p>Ideally, the ServiceManager for the platform should be used to obtain and cache an instance, however, this can be
|
||||
* used if you need static access.</p>
|
||||
* <p>Ideally, the ServiceManager for the platform should be used to obtain an instance,
|
||||
* however, this provider can be used if you need static access.</p>
|
||||
*/
|
||||
public final class LuckPerms {
|
||||
private static LuckPermsApi api = null;
|
||||
private static LuckPermsApi instance = null;
|
||||
|
||||
/**
|
||||
* Gets an instance of {@link LuckPermsApi}, throwing {@link IllegalStateException} if the API is not loaded.
|
||||
* Gets an instance of the {@link LuckPermsApi},
|
||||
* throwing {@link IllegalStateException} if an instance is not yet loaded.
|
||||
*
|
||||
* <p>Will never return null.</p>
|
||||
*
|
||||
* @return an api instance
|
||||
* @throws IllegalStateException if the api is not loaded
|
||||
*/
|
||||
@Nonnull
|
||||
public static LuckPermsApi getApi() {
|
||||
if (api == null) {
|
||||
if (instance == null) {
|
||||
throw new IllegalStateException("API is not loaded.");
|
||||
}
|
||||
return api;
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an instance of {@link LuckPermsApi}, if it is loaded.
|
||||
*
|
||||
* <p> Unlike {@link LuckPerms#getApi}, this method will not throw an {@link IllegalStateException} if the API is
|
||||
* not loaded, rather return an empty {@link Optional}.
|
||||
* <p>Unlike {@link LuckPerms#getApi}, this method will not throw an
|
||||
* {@link IllegalStateException} if an instance is not yet loaded, rather return
|
||||
* an empty {@link Optional}.
|
||||
*
|
||||
* @return an optional api instance
|
||||
*/
|
||||
@Nonnull
|
||||
public static Optional<LuckPermsApi> getApiSafe() {
|
||||
return Optional.ofNullable(api);
|
||||
return Optional.ofNullable(instance);
|
||||
}
|
||||
|
||||
/* method used by the implementation to set the singleton instance */
|
||||
static void registerProvider(LuckPermsApi luckPermsApi) {
|
||||
api = luckPermsApi;
|
||||
/**
|
||||
* Registers an instance of the {@link LuckPermsApi} with this provider.
|
||||
*
|
||||
* @param instance the instance
|
||||
*/
|
||||
static void registerProvider(LuckPermsApi instance) {
|
||||
LuckPerms.instance = instance;
|
||||
}
|
||||
|
||||
/* method used by the implementation to remove any previous instance */
|
||||
/**
|
||||
* Removes the current instance from this provider.
|
||||
*/
|
||||
static void unregisterProvider() {
|
||||
api = null;
|
||||
LuckPerms.instance = null;
|
||||
}
|
||||
|
||||
private LuckPerms() {
|
||||
|
||||
@@ -28,6 +28,7 @@ package me.lucko.luckperms.api;
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
@@ -104,4 +105,22 @@ public enum ChatMetaType {
|
||||
@Nonnull
|
||||
public abstract Map.Entry<Integer, String> getEntry(@Nonnull Node node);
|
||||
|
||||
/**
|
||||
* Parses a ChatMetaType from the given node.
|
||||
*
|
||||
* @param node the node
|
||||
* @return the parsed chat meta type
|
||||
* @since 3.4
|
||||
*/
|
||||
@Nonnull
|
||||
public static Optional<ChatMetaType> ofNode(@Nonnull Node node) {
|
||||
if (node.isPrefix()) {
|
||||
return Optional.of(PREFIX);
|
||||
} else if (node.isSuffix()) {
|
||||
return Optional.of(SUFFIX);
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,22 +25,46 @@
|
||||
|
||||
package me.lucko.luckperms.api;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Context and options for a permission lookup.
|
||||
* Encapsulates the options and settings for a permission lookup.
|
||||
*
|
||||
* <p>All values are immutable.</p>
|
||||
* <p>This class is immutable.</p>
|
||||
*
|
||||
* @since 2.11
|
||||
*/
|
||||
public class Contexts {
|
||||
|
||||
/**
|
||||
* The context key used to denote the subjects server
|
||||
*/
|
||||
public static final String SERVER_KEY = "server";
|
||||
|
||||
/**
|
||||
* The context key used to denote the subjects world
|
||||
*/
|
||||
public static final String WORLD_KEY = "world";
|
||||
|
||||
private static final Contexts GLOBAL = new Contexts(ContextSet.empty(), true, true, true, true, true, false);
|
||||
/**
|
||||
* A 'global' or default contexts instance.
|
||||
*
|
||||
* Simply passes an empty context set, with all accumulation settings set to true.
|
||||
*/
|
||||
private static final Contexts GLOBAL = new Contexts(
|
||||
ContextSet.empty(),
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets the {@link FullySatisfiedContexts} instance.
|
||||
@@ -69,12 +93,12 @@ public class Contexts {
|
||||
|
||||
/**
|
||||
* The contexts that apply for this lookup
|
||||
* The keys for servers and worlds are defined as static values.
|
||||
*/
|
||||
private final ContextSet context;
|
||||
private final ImmutableContextSet context;
|
||||
|
||||
/**
|
||||
* The mode to parse defaults on Bukkit
|
||||
* If the target subject is OP. This is used to parse defaults on Bukkit,
|
||||
* and is ignored on all other platforms.
|
||||
*
|
||||
* @since 2.12
|
||||
*/
|
||||
@@ -105,18 +129,18 @@ public class Contexts {
|
||||
*/
|
||||
private final boolean applyGlobalWorldGroups;
|
||||
|
||||
public Contexts(@Nonnull ContextSet context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups, boolean op) {
|
||||
if (context == null) {
|
||||
throw new NullPointerException("context");
|
||||
}
|
||||
// cache hashcode - this class is immutable, and is used as an index in the permission cache.
|
||||
private final int hashCode;
|
||||
|
||||
this.context = context.makeImmutable();
|
||||
public Contexts(@Nonnull ContextSet context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups, boolean op) {
|
||||
this.context = Preconditions.checkNotNull(context, "context").makeImmutable();
|
||||
this.includeGlobal = includeGlobal;
|
||||
this.includeGlobalWorld = includeGlobalWorld;
|
||||
this.applyGroups = applyGroups;
|
||||
this.applyGlobalGroups = applyGlobalGroups;
|
||||
this.applyGlobalWorldGroups = applyGlobalWorldGroups;
|
||||
this.op = op;
|
||||
this.hashCode = calculateHashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,7 +155,8 @@ public class Contexts {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets if OP defaults should be included
|
||||
* Gets if the target subject is OP. This is used to parse defaults on Bukkit,
|
||||
* and is ignored on all other platforms.
|
||||
*
|
||||
* @return true if op defaults should be included
|
||||
*/
|
||||
@@ -198,10 +223,6 @@ public class Contexts {
|
||||
")";
|
||||
}
|
||||
|
||||
/*
|
||||
* Ugly auto-generated lombok code
|
||||
*/
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) return true;
|
||||
@@ -218,8 +239,7 @@ public class Contexts {
|
||||
this.isApplyGlobalWorldGroups() == other.isApplyGlobalWorldGroups();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
private int calculateHashCode() {
|
||||
final int PRIME = 59;
|
||||
int result = 1;
|
||||
final Object contexts = this.getContexts();
|
||||
@@ -233,4 +253,8 @@ public class Contexts {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
@@ -25,44 +25,64 @@
|
||||
|
||||
package me.lucko.luckperms.api;
|
||||
|
||||
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
|
||||
import me.lucko.luckperms.exceptions.ObjectLacksException;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Represents the result of a mutation call.
|
||||
*/
|
||||
public enum DataMutateResult {
|
||||
|
||||
SUCCESS(true, null),
|
||||
ALREADY_HAS(false, ObjectAlreadyHasException::new),
|
||||
LACKS(false, ObjectLacksException::new),
|
||||
FAIL(false, RuntimeException::new);
|
||||
/**
|
||||
* Indicates the mutation was a success
|
||||
*/
|
||||
SUCCESS(true),
|
||||
|
||||
private boolean value;
|
||||
private final Supplier<? extends Exception> exceptionSupplier;
|
||||
/**
|
||||
* Indicates the mutation failed because the subject already has something
|
||||
*/
|
||||
ALREADY_HAS(false),
|
||||
|
||||
DataMutateResult(boolean value, Supplier<? extends Exception> exceptionSupplier) {
|
||||
/**
|
||||
* Indicates the mutation failed because the subject lacks something
|
||||
*/
|
||||
LACKS(false),
|
||||
|
||||
/**
|
||||
* Indicates the mutation failed
|
||||
*/
|
||||
FAIL(false);
|
||||
|
||||
private final boolean value;
|
||||
|
||||
DataMutateResult(boolean value) {
|
||||
this.value = value;
|
||||
this.exceptionSupplier = exceptionSupplier;
|
||||
}
|
||||
|
||||
public void throwException() {
|
||||
if (exceptionSupplier != null) {
|
||||
sneakyThrow(exceptionSupplier.get());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a boolean representation of the result.
|
||||
*
|
||||
* @return a boolean representation
|
||||
*/
|
||||
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);
|
||||
/**
|
||||
* Gets if the result indicates a success
|
||||
*
|
||||
* @return if the result indicates a success
|
||||
* @since 3.4
|
||||
*/
|
||||
public boolean wasSuccess() {
|
||||
return value;
|
||||
}
|
||||
|
||||
private static <T extends Throwable> void sneakyThrow0(Throwable t) throws T {
|
||||
throw (T) t;
|
||||
/**
|
||||
* Gets if the result indicates a failure
|
||||
*
|
||||
* @return if the result indicates a failure
|
||||
* @since 3.4
|
||||
*/
|
||||
public boolean wasFailure() {
|
||||
return !value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,3 +1,28 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.api;
|
||||
|
||||
import me.lucko.luckperms.api.caching.MetaContexts;
|
||||
@@ -9,19 +34,22 @@ import javax.annotation.Nonnull;
|
||||
/**
|
||||
* A special instance of {@link Contexts}, which when passed to:
|
||||
*
|
||||
* <p><ul>
|
||||
* <li>{@link UserData#getPermissionData(Contexts)}</li>
|
||||
* <li>{@link UserData#getMetaData(Contexts)}</li>
|
||||
* <li>{@link UserData#getMetaData(MetaContexts)}</li>
|
||||
* </ul></p>
|
||||
* <p></p>
|
||||
* <ul>
|
||||
* <li>{@link UserData#getPermissionData(Contexts)}</li>
|
||||
* <li>{@link UserData#getMetaData(Contexts)}</li>
|
||||
* <li>{@link UserData#getMetaData(MetaContexts)}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>will always satisfy all contextual requirements.</p>
|
||||
* <p>... will always satisfy all contextual requirements.</p>
|
||||
*
|
||||
* <p>This effectively allows you to do lookups which ignore context.</p>
|
||||
*
|
||||
* @since 3.3
|
||||
*/
|
||||
public final class FullySatisfiedContexts extends Contexts {
|
||||
|
||||
// singleton
|
||||
private static final FullySatisfiedContexts INSTANCE = new FullySatisfiedContexts();
|
||||
|
||||
@Nonnull
|
||||
@@ -36,16 +64,18 @@ public final class FullySatisfiedContexts extends Contexts {
|
||||
@Nonnull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FullySatisfiedContexts";
|
||||
return "FullySatisfiedContexts()";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
// this class is a singleton, so we can use object comparison to check equality.
|
||||
return o == this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
// just use the system hashcode - we need to override the hashcode impl in super
|
||||
return System.identityHashCode(this);
|
||||
}
|
||||
}
|
||||
@@ -26,16 +26,13 @@
|
||||
package me.lucko.luckperms.api;
|
||||
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
|
||||
import me.lucko.luckperms.exceptions.ObjectLacksException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.OptionalInt;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* A group which holds permission data.
|
||||
* An inheritable holder of permission data.
|
||||
*/
|
||||
public interface Group extends PermissionHolder {
|
||||
|
||||
@@ -78,242 +75,4 @@ public interface Group extends PermissionHolder {
|
||||
@Nonnull
|
||||
OptionalInt getWeight();
|
||||
|
||||
/**
|
||||
* Check to see if the group inherits a group on a specific server
|
||||
*
|
||||
* @param group The group to check membership of
|
||||
* @param server The server to check on
|
||||
* @return true if the group inherits the group on the server
|
||||
* @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 #inheritsGroup(Group, ContextSet)}
|
||||
*/
|
||||
@Deprecated
|
||||
boolean inheritsGroup(@Nonnull Group group, @Nonnull String server);
|
||||
|
||||
/**
|
||||
* Check to see if the group inherits a group on a specific server and world
|
||||
*
|
||||
* @param group The group to check membership of
|
||||
* @param server The server to check on
|
||||
* @param world The world to check on
|
||||
* @return true if the group inherits the group on the server and world
|
||||
* @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 #inheritsGroup(Group, ContextSet)}
|
||||
*/
|
||||
@Deprecated
|
||||
boolean inheritsGroup(@Nonnull Group group, @Nonnull String server, @Nonnull String world);
|
||||
|
||||
/**
|
||||
* Make this group inherit another group
|
||||
*
|
||||
* @param group the group to be inherited
|
||||
* @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(@Nonnull Group group) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
* Make this group inherit another group on a specific server
|
||||
*
|
||||
* @param group the group to be inherited
|
||||
* @param server The server to inherit the group on
|
||||
* @throws ObjectAlreadyHasException if the group already inherits the group on that server
|
||||
* @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(@Nonnull Group group, @Nonnull String server) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
* Make this group inherit another group on a specific server and world
|
||||
*
|
||||
* @param group the group to be inherited
|
||||
* @param server The server to inherit the group on
|
||||
* @param world The world to inherit the group on
|
||||
* @throws ObjectAlreadyHasException if the group already inherits the group on that server and world
|
||||
* @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(@Nonnull Group group, @Nonnull String server, @Nonnull String world) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
* Make this group inherit another group temporarily
|
||||
*
|
||||
* @param group the group to be inherited
|
||||
* @param expireAt the unix time when the group should expire
|
||||
* @throws ObjectAlreadyHasException if the group already inherits the group temporarily
|
||||
* @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(@Nonnull Group group, long expireAt) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
* Make this group inherit another group on a specific server temporarily
|
||||
*
|
||||
* @param group the group to be inherited
|
||||
* @param server The server inherit add the group on
|
||||
* @param expireAt when the group should expire
|
||||
* @throws ObjectAlreadyHasException if the group already inherits the group on that server temporarily
|
||||
* @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(@Nonnull Group group, @Nonnull String server, long expireAt) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
* Make this group inherit another group on a specific server and world temporarily
|
||||
*
|
||||
* @param group the group to be inherited
|
||||
* @param server The server to inherit the group on
|
||||
* @param world The world to inherit the group on
|
||||
* @param expireAt when the group should expire
|
||||
* @throws ObjectAlreadyHasException if the group already inherits the group on that server and world temporarily
|
||||
* @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(@Nonnull Group group, @Nonnull String server, @Nonnull String world, long expireAt) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
* Remove a previously set inheritance rule
|
||||
*
|
||||
* @param group the group to uninherit
|
||||
* @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(@Nonnull Group group) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
* Remove a previously set inheritance rule
|
||||
*
|
||||
* @param group the group to uninherit
|
||||
* @param temporary if the group being removed is temporary
|
||||
* @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(@Nonnull Group group, boolean temporary) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
* Remove a previously set inheritance rule on a specific server
|
||||
*
|
||||
* @param group the group to uninherit
|
||||
* @param server The server to remove the group on
|
||||
* @throws ObjectLacksException if the group does not already inherit the group on that server
|
||||
* @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(@Nonnull Group group, @Nonnull String server) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
* Remove a previously set inheritance rule on a specific server and world
|
||||
*
|
||||
* @param group the group to uninherit
|
||||
* @param server The server to remove the group on
|
||||
* @param world The world to remove the group on
|
||||
* @throws ObjectLacksException if the group does not already inherit the group
|
||||
* @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(@Nonnull Group group, @Nonnull String server, @Nonnull String world) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
* Remove a previously set inheritance rule on a specific server
|
||||
*
|
||||
* @param group the group to uninherit
|
||||
* @param server The server to remove the group on
|
||||
* @param temporary if the group being removed is temporary
|
||||
* @throws ObjectLacksException if the group does not already inherit the group
|
||||
* @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(@Nonnull Group group, @Nonnull String server, boolean temporary) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
* Remove a previously set inheritance rule on a specific server and world
|
||||
*
|
||||
* @param group the group to uninherit
|
||||
* @param server The server to remove the group on
|
||||
* @param world The world to remove the group on
|
||||
* @param temporary if the group being removed was set temporarily
|
||||
* @throws ObjectLacksException if the group does not already inherit the group
|
||||
* @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(@Nonnull Group group, @Nonnull String server, @Nonnull String world, boolean temporary) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
* Get a {@link List} of all of the groups the group inherits, on all servers
|
||||
*
|
||||
* @return a {@link List} of group names
|
||||
* @deprecated in favour of just querying a users permissions
|
||||
*/
|
||||
@Deprecated
|
||||
@Nonnull
|
||||
List<String> getGroupNames();
|
||||
|
||||
/**
|
||||
* Get a {@link List} of the groups the group inherits on a specific server
|
||||
*
|
||||
* @param server the server to check
|
||||
* @return a {@link List} of group names
|
||||
* @throws NullPointerException if the server is null
|
||||
* @throws IllegalArgumentException if the server is invalid
|
||||
* @deprecated in favour of just querying a users permissions
|
||||
*/
|
||||
@Deprecated
|
||||
@Nonnull
|
||||
List<String> getLocalGroups(@Nonnull String server);
|
||||
|
||||
|
||||
/**
|
||||
* Get a {@link List} of the groups the group inherits on a specific server and world
|
||||
*
|
||||
* @param server the server to check
|
||||
* @param world the world to check
|
||||
* @return a {@link List} of group names
|
||||
* @throws NullPointerException if the server or world is null
|
||||
* @throws IllegalArgumentException if the server or world is invalid
|
||||
* @deprecated in favour of just querying a users permissions
|
||||
*/
|
||||
@Deprecated
|
||||
@Nonnull
|
||||
List<String> getLocalGroups(@Nonnull String server, @Nonnull String world);
|
||||
|
||||
}
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
package me.lucko.luckperms.api;
|
||||
|
||||
import com.google.common.collect.Multimap;
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalLong;
|
||||
@@ -33,7 +33,7 @@ import java.util.OptionalLong;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* A relationship between a Holder and a permission
|
||||
* A relationship between a PermissionHolder and a permission
|
||||
*
|
||||
* @param <T> the identifier type of the holder
|
||||
* @since 2.17
|
||||
@@ -87,12 +87,11 @@ public interface HeldPermission<T> {
|
||||
OptionalLong getExpiry();
|
||||
|
||||
/**
|
||||
* Gets the context for the permission.
|
||||
* Gets the extra context for the permission.
|
||||
*
|
||||
* @return the context
|
||||
* @return the extra context
|
||||
*/
|
||||
@Nonnull
|
||||
Multimap<String, String> getContext();
|
||||
ContextSet getContexts();
|
||||
|
||||
/**
|
||||
* Converts this permission into a Node
|
||||
|
||||
@@ -25,147 +25,73 @@
|
||||
|
||||
package me.lucko.luckperms.api;
|
||||
|
||||
import me.lucko.luckperms.api.data.DatastoreConfiguration;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Read-only access to the LuckPerms configuration settings
|
||||
* Wrapper around parts of the LuckPerms configuration file
|
||||
*/
|
||||
public interface LPConfiguration {
|
||||
|
||||
/**
|
||||
* Returns the name of this server
|
||||
* Gets the name of this server
|
||||
*
|
||||
* @return the name of this server
|
||||
*/
|
||||
@Nonnull
|
||||
String getServer();
|
||||
|
||||
/**
|
||||
* Returns how often a sync task will run in minutes
|
||||
* @return how often a sync task will run in minutes
|
||||
*/
|
||||
int getSyncTime();
|
||||
|
||||
/**
|
||||
* Returns if the users on this server will have their global permissions applied
|
||||
* Gets if the users on this server will have their global permissions applied
|
||||
*
|
||||
* @return if the users on this server will have their global permissions applied
|
||||
*/
|
||||
boolean getIncludeGlobalPerms();
|
||||
|
||||
/**
|
||||
* Returns if the users on this server will have their global world permissions applied
|
||||
* Gets if the users on this server will have their global world permissions applied
|
||||
*
|
||||
* @return if the users on this server will have their global world permissions applied
|
||||
* @since 2.9
|
||||
*/
|
||||
boolean getIncludeGlobalWorldPerms();
|
||||
|
||||
/**
|
||||
* Returns true if the platform is applying global groups
|
||||
* Gets if the platform is applying global groups
|
||||
*
|
||||
* @return true if the platform is applying global groups
|
||||
* @since 2.9
|
||||
*/
|
||||
boolean getApplyGlobalGroups();
|
||||
|
||||
/**
|
||||
* Returns true if the platform is applying global world groups
|
||||
* Gets if the platform is applying global world groups
|
||||
*
|
||||
* @return true if the platform is applying global world groups
|
||||
* @since 2.9
|
||||
*/
|
||||
boolean getApplyGlobalWorldGroups();
|
||||
|
||||
/**
|
||||
* Returns the online mode setting
|
||||
* @return the online mode setting
|
||||
*/
|
||||
boolean getOnlineMode();
|
||||
|
||||
/**
|
||||
* Returns if LuckPerms is applying wildcard permissions
|
||||
* @return if LuckPerms is applying wildcard permissions
|
||||
*/
|
||||
boolean getApplyWildcards();
|
||||
|
||||
/**
|
||||
* Returns if LuckPerms is resolving and applying regex permissions
|
||||
* @return if LuckPerms is resolving and applying regex permissions
|
||||
*/
|
||||
boolean getApplyRegex();
|
||||
|
||||
/**
|
||||
* Returns if LuckPerms is expanding shorthand permissions
|
||||
* @return if LuckPerms is expanding shorthand permissions
|
||||
*/
|
||||
boolean getApplyShorthand();
|
||||
|
||||
/**
|
||||
* Returns if LuckPerms will send notifications to users when permissions are modified
|
||||
* @return if LuckPerms will send notifications to users when permissions are modified
|
||||
* @since 2.7
|
||||
*/
|
||||
boolean getLogNotify();
|
||||
|
||||
/**
|
||||
* Returns true if the vanilla op system is enabled
|
||||
* @return true if the vanilla op system is enabled
|
||||
* @since 2.8
|
||||
*/
|
||||
boolean getEnableOps();
|
||||
|
||||
/**
|
||||
* Returns true if opped players are allowed to use LuckPerms commands
|
||||
* @return true if opped players are allowed to use LuckPerms commands
|
||||
* @since 2.8
|
||||
*/
|
||||
boolean getCommandsAllowOp();
|
||||
|
||||
/**
|
||||
* Returns true if auto op is enabled
|
||||
* @return true if auto op is enabled
|
||||
* @since 2.9
|
||||
*/
|
||||
boolean getAutoOp();
|
||||
|
||||
/**
|
||||
* Returns the name of the server used within Vault operations
|
||||
* @return the name of the server used within Vault operations
|
||||
* @since 2.7
|
||||
*/
|
||||
@Nonnull
|
||||
String getVaultServer();
|
||||
|
||||
/**
|
||||
* Returns true if global permissions should be considered when retrieving meta or player groups
|
||||
* @return true if global permissions should be considered when retrieving meta or player groups
|
||||
* @since 2.7
|
||||
*/
|
||||
boolean getVaultIncludeGlobal();
|
||||
|
||||
/**
|
||||
* Returns the values set for data storage in the configuration
|
||||
* @return the values set for data storage in the configuration
|
||||
*/
|
||||
@Nonnull
|
||||
DatastoreConfiguration getDatastoreConfig();
|
||||
|
||||
/**
|
||||
* Returns the storage method string from the configuration
|
||||
* Gets the storage method string from the configuration
|
||||
*
|
||||
* @return the storage method string from the configuration
|
||||
*/
|
||||
@Nonnull
|
||||
String getStorageMethod();
|
||||
|
||||
/**
|
||||
* Returns true if split storage is enabled
|
||||
* Gets true if split storage is enabled
|
||||
*
|
||||
* @return true if split storage is enabled
|
||||
* @since 2.7
|
||||
*/
|
||||
boolean getSplitStorage();
|
||||
|
||||
/**
|
||||
* Returns a map of split storage options
|
||||
* Gets a map of split storage options
|
||||
*
|
||||
* @return a map of split storage options, where the key is the storage section, and the value is the storage
|
||||
* method. For example: key = user, value = json
|
||||
* @since 2.7
|
||||
@@ -184,7 +110,7 @@ public interface LPConfiguration {
|
||||
* <p>This method is nested under {@link Unsafe} because the keys
|
||||
* and return types may change between versions without warning.</p>
|
||||
*
|
||||
* @param key the key, as defined as a parameter name in
|
||||
* @param key the key, as defined as a field name in
|
||||
* the "ConfigKeys" class.
|
||||
* @return the corresponding object, if one is present
|
||||
* @throws IllegalArgumentException if the key isn't known
|
||||
|
||||
@@ -34,18 +34,26 @@ import javax.annotation.Nonnull;
|
||||
/**
|
||||
* Represents the internal LuckPerms log.
|
||||
*
|
||||
* <p>The returned instance provides a copy of the data at the time of retrieval. Any changes made to log entries will
|
||||
* only apply to this instance of the log. You can add to the log using the {@link Storage}, and then request an updated copy.</p>
|
||||
* <p>The returned instance provides a copy of the data at the time of retrieval.</p>
|
||||
*
|
||||
* <p>Any changes made to log entries will only apply to this instance of the log.
|
||||
* You can add to the log using the {@link Storage}, and then request an updated copy.</p>
|
||||
*
|
||||
* <p>All methods are thread safe, and return immutable and thread safe collections.</p>
|
||||
*/
|
||||
public interface Log {
|
||||
|
||||
/**
|
||||
* Get the content of the log
|
||||
*
|
||||
* @return a {@link SortedSet} of all of the {@link LogEntry} objects in this {@link Log}
|
||||
*/
|
||||
@Nonnull
|
||||
SortedSet<LogEntry> getContent();
|
||||
|
||||
/**
|
||||
* Get the content of the log
|
||||
*
|
||||
* @return all content in this log
|
||||
*/
|
||||
@Nonnull
|
||||
@@ -57,18 +65,22 @@ public interface Log {
|
||||
* @param pageNo the page number
|
||||
* @return the page content
|
||||
* @throws IllegalArgumentException if the pageNo is less than 1
|
||||
* @throws IllegalStateException if the log doesn't contain enough entries to populate the page. See {@link #getRecentMaxPages()}}
|
||||
* @throws IllegalStateException if the log doesn't contain enough entries to populate the page. See {@link #getRecentMaxPages()}
|
||||
*/
|
||||
@Nonnull
|
||||
SortedMap<Integer, LogEntry> getRecent(int pageNo);
|
||||
|
||||
/**
|
||||
* Gets the max page number for the recent pages.
|
||||
*
|
||||
* @return the max page number allowed in the {@link #getRecent(int)} method
|
||||
*/
|
||||
int getRecentMaxPages();
|
||||
|
||||
|
||||
/**
|
||||
* Gets the recent content for a given actor
|
||||
*
|
||||
* @param actor the uuid of the actor to filter by
|
||||
* @return all content in this log where is actor = uuid
|
||||
*/
|
||||
@@ -76,18 +88,20 @@ public interface Log {
|
||||
SortedSet<LogEntry> getRecent(@Nonnull UUID actor);
|
||||
|
||||
/**
|
||||
* Gets the recent content for the uuid, separated into pages
|
||||
* Gets the recent content for a given actor, separated by page
|
||||
*
|
||||
* @param pageNo the page number
|
||||
* @param actor the uuid of the actor to filter by
|
||||
* @return the page content
|
||||
* @throws IllegalArgumentException if the pageNo is less than 1
|
||||
* @throws IllegalStateException if the log doesn't contain enough entries to populate the page. See {@link #getRecentMaxPages(UUID)}}
|
||||
* @throws IllegalStateException if the log doesn't contain enough entries to populate the page. See {@link #getRecentMaxPages(UUID)}
|
||||
*/
|
||||
@Nonnull
|
||||
SortedMap<Integer, LogEntry> getRecent(int pageNo, @Nonnull UUID actor);
|
||||
|
||||
/**
|
||||
* Gets the max page number for the recent pages.
|
||||
*
|
||||
* @param actor the actor to filter by
|
||||
* @return the max page number allowed in the {@link #getRecent(int, UUID)} method
|
||||
*/
|
||||
@@ -95,6 +109,8 @@ public interface Log {
|
||||
|
||||
|
||||
/**
|
||||
* Gets the log content for a given user
|
||||
*
|
||||
* @param uuid the uuid to filter by
|
||||
* @return all content in this log where the user = uuid
|
||||
*/
|
||||
@@ -102,18 +118,20 @@ public interface Log {
|
||||
SortedSet<LogEntry> getUserHistory(@Nonnull UUID uuid);
|
||||
|
||||
/**
|
||||
* Gets the user history content, separated by pages
|
||||
* Gets the log content for a given user, separated by page
|
||||
*
|
||||
* @param pageNo the page number
|
||||
* @param uuid the uuid of the acted user to filter by
|
||||
* @return the page content
|
||||
* @throws IllegalArgumentException if the pageNo is less than 1
|
||||
* @throws IllegalStateException if the log doesn't contain enough entries to populate the page. See {@link #getUserHistoryMaxPages(UUID)}}
|
||||
* @throws IllegalStateException if the log doesn't contain enough entries to populate the page. See {@link #getUserHistoryMaxPages(UUID)}
|
||||
*/
|
||||
@Nonnull
|
||||
SortedMap<Integer, LogEntry> getUserHistory(int pageNo, @Nonnull UUID uuid);
|
||||
|
||||
/**
|
||||
* Gets the max page number for the user history pages.
|
||||
*
|
||||
* @param uuid the uuid to filter by
|
||||
* @return the max page number allowed in the {@link #getUserHistory(int, UUID)} method
|
||||
*/
|
||||
@@ -121,6 +139,8 @@ public interface Log {
|
||||
|
||||
|
||||
/**
|
||||
* Gets the log content for a given group
|
||||
*
|
||||
* @param name the name to filter by
|
||||
* @return all content in this log where the group = name
|
||||
*/
|
||||
@@ -128,18 +148,20 @@ public interface Log {
|
||||
SortedSet<LogEntry> getGroupHistory(@Nonnull String name);
|
||||
|
||||
/**
|
||||
* Gets the group history content, separated by pages
|
||||
* Gets the log content for a given group, separated by page
|
||||
*
|
||||
* @param pageNo the page number
|
||||
* @param name the name of the acted group to filter by
|
||||
* @return the page content
|
||||
* @throws IllegalArgumentException if the pageNo is less than 1
|
||||
* @throws IllegalStateException if the log doesn't contain enough entries to populate the page. See {@link #getGroupHistoryMaxPages(String)}}
|
||||
* @throws IllegalStateException if the log doesn't contain enough entries to populate the page. See {@link #getGroupHistoryMaxPages(String)}
|
||||
*/
|
||||
@Nonnull
|
||||
SortedMap<Integer, LogEntry> getGroupHistory(int pageNo, @Nonnull String name);
|
||||
|
||||
/**
|
||||
* Gets the max page number for the group history pages.
|
||||
*
|
||||
* @param name the name to filter by
|
||||
* @return the max page number allowed in the {@link #getGroupHistory(int, String)} method
|
||||
*/
|
||||
@@ -147,6 +169,8 @@ public interface Log {
|
||||
|
||||
|
||||
/**
|
||||
* Gets the log content for a given track
|
||||
*
|
||||
* @param name the name to filter by
|
||||
* @return all content in this log where the track = name
|
||||
*/
|
||||
@@ -154,25 +178,29 @@ public interface Log {
|
||||
SortedSet<LogEntry> getTrackHistory(@Nonnull String name);
|
||||
|
||||
/**
|
||||
* Gets the track history content, separated by pages
|
||||
* Gets the log content for a given track, separated by page
|
||||
*
|
||||
* @param pageNo the page number
|
||||
* @param name the name of the acted track to filter by
|
||||
* @return the page content
|
||||
* @throws IllegalArgumentException if the pageNo is less than 1
|
||||
* @throws IllegalStateException if the log doesn't contain enough entries to populate the page. See {@link #getTrackHistoryMaxPages(String)}
|
||||
*/
|
||||
@Nonnull
|
||||
SortedMap<Integer, LogEntry> getTrackHistory(int pageNo, @Nonnull String name);
|
||||
|
||||
/**
|
||||
* Gets the max page number for the track history pages.
|
||||
*
|
||||
* @param name the name to filter by
|
||||
* @return the max page number allowed in the {@link #getTrackHistory(int, String)} method
|
||||
* @throws IllegalArgumentException if the pageNo is less than 1
|
||||
* @throws IllegalStateException if the log doesn't contain enough entries to populate the page. See {@link #getTrackHistoryMaxPages(String)}}
|
||||
*/
|
||||
int getTrackHistoryMaxPages(@Nonnull String name);
|
||||
|
||||
|
||||
/**
|
||||
* Gets the log content for a given search query
|
||||
*
|
||||
* @param query the query to filter by
|
||||
* @return all content in this log where the content matches query
|
||||
*/
|
||||
@@ -180,7 +208,7 @@ public interface Log {
|
||||
SortedSet<LogEntry> getSearch(@Nonnull String query);
|
||||
|
||||
/**
|
||||
* Gets the search content, separated by pages
|
||||
* Gets the log content for a given search query, separated by page
|
||||
*
|
||||
* @param pageNo the page number
|
||||
* @param query the query to filter by
|
||||
@@ -192,8 +220,11 @@ public interface Log {
|
||||
SortedMap<Integer, LogEntry> getSearch(int pageNo, @Nonnull String query);
|
||||
|
||||
/**
|
||||
* Gets the max page number for the search query pages.
|
||||
*
|
||||
* @param query the query to filter by
|
||||
* @return the max page number allowed in the {@link #getSearch(int, String)} method
|
||||
*/
|
||||
int getSearchMaxPages(@Nonnull String query);
|
||||
|
||||
}
|
||||
@@ -25,307 +25,139 @@
|
||||
|
||||
package me.lucko.luckperms.api;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* A single entry in the log
|
||||
*
|
||||
* <p>Implements {@link Comparable} ordering based upon the timestamp of the entry.</p>
|
||||
* Represents a logged action.
|
||||
*/
|
||||
public class LogEntry implements Comparable<LogEntry> {
|
||||
private static final String FORMAT = "&8(&e%s&8) [&a%s&8] (&b%s&8) &7--> &f%s";
|
||||
public interface LogEntry extends Comparable<LogEntry> {
|
||||
|
||||
@Nonnull
|
||||
public static LogEntryBuilder builder() {
|
||||
return new LogEntryBuilder();
|
||||
}
|
||||
/**
|
||||
* Gets the time in unix seconds when the action occurred.
|
||||
*
|
||||
* @return the timestamp
|
||||
*/
|
||||
long getTimestamp();
|
||||
|
||||
private long timestamp;
|
||||
private UUID actor;
|
||||
private String actorName;
|
||||
private char type;
|
||||
private UUID acted;
|
||||
private String actedName;
|
||||
private String action;
|
||||
/**
|
||||
* Gets the id of the object which performed the action.
|
||||
*
|
||||
* <p>This is the players uuid in most cases.</p>
|
||||
*
|
||||
* @return the actor id
|
||||
*/
|
||||
UUID getActor();
|
||||
|
||||
public LogEntry(long timestamp, @Nonnull UUID actor, @Nonnull String actorName, char type, @Nullable UUID acted, @Nonnull String actedName, @Nonnull String action) {
|
||||
if (actor == null) {
|
||||
throw new NullPointerException("actor");
|
||||
}
|
||||
if (actorName == null) {
|
||||
throw new NullPointerException("actorName");
|
||||
}
|
||||
if (actedName == null) {
|
||||
throw new NullPointerException("actedName");
|
||||
}
|
||||
if (action == null) {
|
||||
throw new NullPointerException("action");
|
||||
/**
|
||||
* Gets the name describing the actor.
|
||||
*
|
||||
* @return the name of the actor
|
||||
*/
|
||||
String getActorName();
|
||||
|
||||
/**
|
||||
* Gets the type of action.
|
||||
*
|
||||
* @return the action type
|
||||
*/
|
||||
Type getType();
|
||||
|
||||
/**
|
||||
* Gets the uuid of the object which was acted upon.
|
||||
*
|
||||
* <p>Will only return a value for {@link Type#USER} entries.</p>
|
||||
*
|
||||
* @return the uuid of acted object
|
||||
*/
|
||||
Optional<UUID> getActed();
|
||||
|
||||
/**
|
||||
* Gets the name describing the object which was acted upon
|
||||
*
|
||||
* @return the name of the acted object
|
||||
*/
|
||||
String getActedName();
|
||||
|
||||
/**
|
||||
* Returns a string describing the action which took place.
|
||||
*
|
||||
* <p>In most instances, this returns a variation of the command string which caused
|
||||
* the change.</p>
|
||||
*
|
||||
* @return the action
|
||||
*/
|
||||
String getAction();
|
||||
|
||||
/**
|
||||
* Represents the type of a {@link LogEntry}.
|
||||
*
|
||||
* @since 3.3
|
||||
*/
|
||||
enum Type {
|
||||
USER('U'),
|
||||
GROUP('G'),
|
||||
TRACK('T');
|
||||
|
||||
private final char code;
|
||||
|
||||
Type(char code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
this.timestamp = timestamp;
|
||||
this.actor = actor;
|
||||
this.actorName = actorName;
|
||||
this.type = type;
|
||||
this.acted = acted;
|
||||
this.actedName = actedName;
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
protected LogEntry() {
|
||||
this.timestamp = 0L;
|
||||
this.actor = null;
|
||||
this.actorName = null;
|
||||
this.type = Character.MIN_VALUE;
|
||||
this.acted = null;
|
||||
this.actedName = null;
|
||||
this.action = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(LogEntry o) {
|
||||
return equals(o) ? 0 : (Long.compare(timestamp, o.getTimestamp()) == 0 ? 1 : Long.compare(timestamp, o.getTimestamp()));
|
||||
}
|
||||
|
||||
public boolean matchesSearch(@Nonnull String query) {
|
||||
query = query.toLowerCase();
|
||||
return actorName.toLowerCase().contains(query) || actedName.toLowerCase().contains(query)
|
||||
|| action.toLowerCase().contains(query);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getFormatted() {
|
||||
return String.format(FORMAT,
|
||||
String.valueOf(actorName).equals("null") ? actor.toString() : actorName,
|
||||
Character.toString(type),
|
||||
String.valueOf(actedName).equals("null") && acted != null ? acted.toString() : actedName,
|
||||
action
|
||||
);
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public UUID getActor() {
|
||||
return actor;
|
||||
}
|
||||
|
||||
void setActor(@Nonnull UUID actor) {
|
||||
this.actor = actor;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getActorName() {
|
||||
return actorName;
|
||||
}
|
||||
|
||||
void setActorName(@Nonnull String actorName) {
|
||||
this.actorName = actorName;
|
||||
}
|
||||
|
||||
public char getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
void setType(char type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public UUID getActed() {
|
||||
return acted;
|
||||
}
|
||||
|
||||
void setActed(@Nullable UUID acted) {
|
||||
this.acted = acted;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getActedName() {
|
||||
return actedName;
|
||||
}
|
||||
|
||||
void setActedName(@Nonnull String actedName) {
|
||||
this.actedName = actedName;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
void setAction(@Nonnull String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LogEntry(" +
|
||||
"timestamp=" + this.getTimestamp() + ", " +
|
||||
"actor=" + this.getActor() + ", " +
|
||||
"actorName=" + this.getActorName() + ", " +
|
||||
"type=" + this.getType() + ", " +
|
||||
"acted=" + this.getActed() + ", " +
|
||||
"actedName=" + this.getActedName() + ", " +
|
||||
"action=" + this.getAction() +
|
||||
")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) return true;
|
||||
if (!(o instanceof LogEntry)) return false;
|
||||
final LogEntry other = (LogEntry) o;
|
||||
return this.getTimestamp() == other.getTimestamp() &&
|
||||
(this.getActor() == null ? other.getActor() == null : this.getActor().equals(other.getActor())) &&
|
||||
(this.getActorName() == null ? other.getActorName() == null : this.getActorName().equals(other.getActorName())) &&
|
||||
this.getType() == other.getType() &&
|
||||
(this.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
|
||||
public int hashCode() {
|
||||
final int PRIME = 59;
|
||||
int result = 1;
|
||||
result = result * PRIME + (int) (this.getTimestamp() >>> 32 ^ this.getTimestamp());
|
||||
result = result * PRIME + (this.getActor() == null ? 43 : this.getActor().hashCode());
|
||||
result = result * PRIME + (this.getActorName() == null ? 43 : this.getActorName().hashCode());
|
||||
result = result * PRIME + this.getType();
|
||||
result = result * PRIME + (this.getActed() == null ? 43 : this.getActed().hashCode());
|
||||
result = result * PRIME + (this.getActedName() == null ? 43 : this.getActedName().hashCode());
|
||||
result = result * PRIME + (this.getAction() == null ? 43 : this.getAction().hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
public static class LogEntryBuilder extends AbstractLogEntryBuilder<LogEntry, LogEntry.LogEntryBuilder> {
|
||||
|
||||
@Override
|
||||
protected LogEntry createObj() {
|
||||
return new LogEntry();
|
||||
public char getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LogEntryBuilder getThis() {
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static abstract class AbstractLogEntryBuilder<T extends LogEntry, B extends AbstractLogEntryBuilder<T, B>> {
|
||||
private T obj;
|
||||
private B thisObj;
|
||||
|
||||
public AbstractLogEntryBuilder() {
|
||||
obj = createObj();
|
||||
thisObj = getThis();
|
||||
}
|
||||
|
||||
protected abstract T createObj();
|
||||
|
||||
protected abstract B getThis();
|
||||
|
||||
public long getTimestamp() {
|
||||
return obj.getTimestamp();
|
||||
}
|
||||
|
||||
public UUID getActor() {
|
||||
return obj.getActor();
|
||||
}
|
||||
|
||||
public String getActorName() {
|
||||
return obj.getActorName();
|
||||
}
|
||||
|
||||
public char getType() {
|
||||
return obj.getType();
|
||||
}
|
||||
|
||||
public UUID getActed() {
|
||||
return obj.getActed();
|
||||
}
|
||||
|
||||
public String getActedName() {
|
||||
return obj.getActedName();
|
||||
}
|
||||
|
||||
public String getAction() {
|
||||
return obj.getAction();
|
||||
}
|
||||
|
||||
public B timestamp(long timestamp) {
|
||||
obj.setTimestamp(timestamp);
|
||||
return thisObj;
|
||||
}
|
||||
|
||||
public B actor(UUID actor) {
|
||||
obj.setActor(actor);
|
||||
return thisObj;
|
||||
}
|
||||
|
||||
public B actorName(String actorName) {
|
||||
obj.setActorName(actorName);
|
||||
return thisObj;
|
||||
}
|
||||
|
||||
public B type(char type) {
|
||||
obj.setType(type);
|
||||
return thisObj;
|
||||
}
|
||||
|
||||
public B acted(UUID acted) {
|
||||
obj.setActed(acted);
|
||||
return thisObj;
|
||||
}
|
||||
|
||||
public B actedName(String actedName) {
|
||||
obj.setActedName(actedName);
|
||||
return thisObj;
|
||||
}
|
||||
|
||||
public B action(String action) {
|
||||
obj.setAction(action);
|
||||
return thisObj;
|
||||
}
|
||||
|
||||
public T build() {
|
||||
if (getActor() == null) {
|
||||
throw new NullPointerException("actor");
|
||||
public static Type valueOf(char code) {
|
||||
switch (code) {
|
||||
case 'U':
|
||||
case 'u':
|
||||
return USER;
|
||||
case 'G':
|
||||
case 'g':
|
||||
return GROUP;
|
||||
case 'T':
|
||||
case 't':
|
||||
return TRACK;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown code: " + code);
|
||||
}
|
||||
if (getActorName() == null) {
|
||||
throw new NullPointerException("actorName");
|
||||
}
|
||||
if (getActedName() == null) {
|
||||
throw new NullPointerException("actedName");
|
||||
}
|
||||
if (getAction() == null) {
|
||||
throw new NullPointerException("action");
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a LogEntry instance
|
||||
*/
|
||||
interface Builder {
|
||||
|
||||
@Nonnull
|
||||
Builder setTimestamp(long timestamp);
|
||||
|
||||
@Nonnull
|
||||
Builder setActor(@Nonnull UUID actor);
|
||||
|
||||
@Nonnull
|
||||
Builder setActorName(@Nonnull String actorName);
|
||||
|
||||
@Nonnull
|
||||
Builder setType(@Nonnull Type type);
|
||||
|
||||
@Nonnull
|
||||
Builder setActed(@Nullable UUID acted);
|
||||
|
||||
@Nonnull
|
||||
Builder setActedName(@Nonnull String actedName);
|
||||
|
||||
@Nonnull
|
||||
Builder setAction(@Nonnull String action);
|
||||
|
||||
@Nonnull
|
||||
LogEntry build();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LogEntry.LogEntryBuilder(" +
|
||||
"timestamp=" + this.getTimestamp() + ", " +
|
||||
"actor=" + this.getActor() + ", " +
|
||||
"actorName=" + this.getActorName() + ", " +
|
||||
"type=" + this.getType() + ", " +
|
||||
"acted=" + this.getActed() + ", " +
|
||||
"actedName=" + this.getActedName() + ", " +
|
||||
"action=" + this.getAction() +
|
||||
")";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,52 +25,79 @@
|
||||
|
||||
package me.lucko.luckperms.api;
|
||||
|
||||
import me.lucko.luckperms.LuckPerms;
|
||||
import me.lucko.luckperms.api.context.ContextCalculator;
|
||||
import me.lucko.luckperms.api.context.ContextManager;
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
import me.lucko.luckperms.api.event.EventBus;
|
||||
import me.lucko.luckperms.api.manager.GroupManager;
|
||||
import me.lucko.luckperms.api.manager.TrackManager;
|
||||
import me.lucko.luckperms.api.manager.UserManager;
|
||||
import me.lucko.luckperms.api.metastacking.MetaStackFactory;
|
||||
import me.lucko.luckperms.api.platform.PlatformInfo;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The root API interface for LuckPerms
|
||||
* The LuckPerms API.
|
||||
*
|
||||
* <p>This interface is the base of the entire API package. All API functions
|
||||
* are accessed via this interface.</p>
|
||||
*
|
||||
* <p>An instance can be obtained via {@link LuckPerms#getApi()}, or the platforms
|
||||
* Services Manager.</p>
|
||||
*/
|
||||
public interface LuckPermsApi {
|
||||
|
||||
/**
|
||||
* Gets information about the platform LuckPerms is running on.
|
||||
*
|
||||
* @return the platform info
|
||||
* @since 4.0
|
||||
*/
|
||||
@Nonnull
|
||||
PlatformInfo getPlatformInfo();
|
||||
|
||||
/**
|
||||
* Gets the user manager
|
||||
*
|
||||
* @return the user manager
|
||||
* @since 4.0
|
||||
*/
|
||||
@Nonnull
|
||||
UserManager getUserManager();
|
||||
|
||||
/**
|
||||
* Gets the group manager
|
||||
*
|
||||
* @return the group manager
|
||||
* @since 4.0
|
||||
*/
|
||||
@Nonnull
|
||||
GroupManager getGroupManager();
|
||||
|
||||
/**
|
||||
* Gets the track manager
|
||||
*
|
||||
* @return the track manager
|
||||
* @since 4.0
|
||||
*/
|
||||
@Nonnull
|
||||
TrackManager getTrackManager();
|
||||
|
||||
/**
|
||||
* Schedules an update task to run
|
||||
*/
|
||||
void runUpdateTask();
|
||||
|
||||
/**
|
||||
* Gets the API version
|
||||
*
|
||||
* @return the version of the API running on the platform
|
||||
* @since 2.6
|
||||
*/
|
||||
double getApiVersion();
|
||||
|
||||
/**
|
||||
* Gets the plugin version
|
||||
*
|
||||
* @return the version of the plugin running on the platform
|
||||
* @since 4.0
|
||||
*/
|
||||
@Nonnull
|
||||
String getVersion();
|
||||
|
||||
/**
|
||||
* Gets the platform LuckPerms is running on
|
||||
*
|
||||
* @return the platform LuckPerms is running on
|
||||
* @since 2.7
|
||||
*/
|
||||
@Nonnull
|
||||
PlatformType getPlatformType();
|
||||
CompletableFuture<Void> runUpdateTask();
|
||||
|
||||
/**
|
||||
* Gets the event bus, used for subscribing to events
|
||||
@@ -82,7 +109,7 @@ public interface LuckPermsApi {
|
||||
EventBus getEventBus();
|
||||
|
||||
/**
|
||||
* Gets a wrapped {@link LPConfiguration} instance, with read only access
|
||||
* Gets the configuration
|
||||
*
|
||||
* @return a configuration instance
|
||||
*/
|
||||
@@ -90,7 +117,7 @@ public interface LuckPermsApi {
|
||||
LPConfiguration getConfiguration();
|
||||
|
||||
/**
|
||||
* Gets a wrapped {@link Storage} instance.
|
||||
* Gets the backend storage dao
|
||||
*
|
||||
* @return a storage instance
|
||||
* @since 2.14
|
||||
@@ -99,7 +126,7 @@ public interface LuckPermsApi {
|
||||
Storage getStorage();
|
||||
|
||||
/**
|
||||
* Gets the messaging service in use on the platform, if present.
|
||||
* Gets the messaging service
|
||||
*
|
||||
* @return an optional that may contain a messaging service instance.
|
||||
*/
|
||||
@@ -107,21 +134,41 @@ public interface LuckPermsApi {
|
||||
Optional<MessagingService> getMessagingService();
|
||||
|
||||
/**
|
||||
* Gets the {@link Logger} wrapping used by the platform
|
||||
*
|
||||
* @return the logger instance
|
||||
*/
|
||||
@Nonnull
|
||||
Logger getLogger();
|
||||
|
||||
/**
|
||||
* Gets a wrapped {@link UuidCache} instance, providing read access to the LuckPerms internal uuid caching system
|
||||
* Gets a {@link UuidCache} instance, providing read access to the LuckPerms
|
||||
* internal uuid caching system
|
||||
*
|
||||
* @return a uuid cache instance
|
||||
*/
|
||||
@Nonnull
|
||||
UuidCache getUuidCache();
|
||||
|
||||
/**
|
||||
* Gets the context manager
|
||||
*
|
||||
* @return the context manager
|
||||
* @since 4.0
|
||||
*/
|
||||
ContextManager getContextManager();
|
||||
|
||||
/**
|
||||
* Gets the node factory
|
||||
*
|
||||
* @return the node factory
|
||||
*/
|
||||
@Nonnull
|
||||
NodeFactory getNodeFactory();
|
||||
|
||||
/**
|
||||
* Gets the MetaStackFactory
|
||||
*
|
||||
* @return the meta stack factory
|
||||
* @since 3.2
|
||||
*/
|
||||
@Nonnull
|
||||
MetaStackFactory getMetaStackFactory();
|
||||
|
||||
// convenience methods
|
||||
|
||||
/**
|
||||
* Gets a wrapped user object from the user storage
|
||||
*
|
||||
@@ -130,19 +177,21 @@ public interface LuckPermsApi {
|
||||
* @throws NullPointerException if the uuid is null
|
||||
*/
|
||||
@Nullable
|
||||
User getUser(@Nonnull UUID uuid);
|
||||
default User getUser(@Nonnull UUID uuid) {
|
||||
return getUserManager().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
|
||||
* @throws NullPointerException if the uuid is null
|
||||
*/
|
||||
@Nonnull
|
||||
Optional<User> getUserSafe(@Nonnull UUID uuid);
|
||||
default Optional<User> getUserSafe(@Nonnull UUID uuid) {
|
||||
return getUserManager().getUserOpt(uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a wrapped user object from the user storage
|
||||
@@ -152,19 +201,21 @@ public interface LuckPermsApi {
|
||||
* @throws NullPointerException if the name is null
|
||||
*/
|
||||
@Nullable
|
||||
User getUser(@Nonnull String name);
|
||||
default User getUser(@Nonnull String name) {
|
||||
return getUserManager().getUser(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @throws NullPointerException if the name is null
|
||||
*/
|
||||
@Nonnull
|
||||
Optional<User> getUserSafe(@Nonnull String name);
|
||||
default Optional<User> getUserSafe(@Nonnull String name) {
|
||||
return getUserManager().getUserOpt(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a set of all loaded users.
|
||||
@@ -172,7 +223,9 @@ public interface LuckPermsApi {
|
||||
* @return a {@link Set} of {@link User} objects
|
||||
*/
|
||||
@Nonnull
|
||||
Set<User> getUsers();
|
||||
default Set<User> getUsers() {
|
||||
return getUserManager().getLoadedUsers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a user is loaded in memory
|
||||
@@ -181,16 +234,19 @@ public interface LuckPermsApi {
|
||||
* @return true if the user is loaded
|
||||
* @throws NullPointerException if the uuid is null
|
||||
*/
|
||||
boolean isUserLoaded(@Nonnull UUID uuid);
|
||||
default boolean isUserLoaded(@Nonnull UUID uuid) {
|
||||
return getUserManager().isLoaded(uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unload a user from the internal storage, if they're not currently online.
|
||||
*
|
||||
* @param user the user to unload
|
||||
* @throws NullPointerException if the user is null
|
||||
* @since 2.6
|
||||
*/
|
||||
void cleanupUser(@Nonnull User user);
|
||||
default void cleanupUser(@Nonnull User user) {
|
||||
getUserManager().cleanupUser(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a wrapped group object from the group storage
|
||||
@@ -200,7 +256,9 @@ public interface LuckPermsApi {
|
||||
* @throws NullPointerException if the name is null
|
||||
*/
|
||||
@Nullable
|
||||
Group getGroup(@Nonnull String name);
|
||||
default Group getGroup(@Nonnull String name) {
|
||||
return getGroupManager().getGroup(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a wrapped group object from the group storage.
|
||||
@@ -212,7 +270,9 @@ public interface LuckPermsApi {
|
||||
* @throws NullPointerException if the name is null
|
||||
*/
|
||||
@Nonnull
|
||||
Optional<Group> getGroupSafe(@Nonnull String name);
|
||||
default Optional<Group> getGroupSafe(@Nonnull String name) {
|
||||
return getGroupManager().getGroupOpt(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a set of all loaded groups.
|
||||
@@ -220,7 +280,9 @@ public interface LuckPermsApi {
|
||||
* @return a {@link Set} of {@link Group} objects
|
||||
*/
|
||||
@Nonnull
|
||||
Set<Group> getGroups();
|
||||
default Set<Group> getGroups() {
|
||||
return getGroupManager().getLoadedGroups();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a group is loaded in memory
|
||||
@@ -229,17 +291,22 @@ public interface LuckPermsApi {
|
||||
* @return true if the group is loaded
|
||||
* @throws NullPointerException if the name is null
|
||||
*/
|
||||
boolean isGroupLoaded(@Nonnull String name);
|
||||
default boolean isGroupLoaded(@Nonnull String name) {
|
||||
return getGroupManager().isLoaded(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a wrapped track object from the track storage
|
||||
*
|
||||
* @param name the name of the track to get
|
||||
* @return a {@link Track} object, if one matching the name exists, or null if not
|
||||
* @return a {@link Track} object, if one matching the name exists, or null
|
||||
* if not
|
||||
* @throws NullPointerException if the name is null
|
||||
*/
|
||||
@Nullable
|
||||
Track getTrack(@Nonnull String name);
|
||||
default Track getTrack(@Nonnull String name) {
|
||||
return getTrackManager().getTrack(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a wrapped track object from the track storage.
|
||||
@@ -251,7 +318,9 @@ public interface LuckPermsApi {
|
||||
* @throws NullPointerException if the name is null
|
||||
*/
|
||||
@Nonnull
|
||||
Optional<Track> getTrackSafe(@Nonnull String name);
|
||||
default Optional<Track> getTrackSafe(@Nonnull String name) {
|
||||
return getTrackManager().getTrackOpt(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a set of all loaded tracks.
|
||||
@@ -259,7 +328,9 @@ public interface LuckPermsApi {
|
||||
* @return a {@link Set} of {@link Track} objects
|
||||
*/
|
||||
@Nonnull
|
||||
Set<Track> getTracks();
|
||||
default Set<Track> getTracks() {
|
||||
return getTrackManager().getLoadedTracks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a track is loaded in memory
|
||||
@@ -268,24 +339,17 @@ public interface LuckPermsApi {
|
||||
* @return true if the track is loaded
|
||||
* @throws NullPointerException if the name is null
|
||||
*/
|
||||
boolean isTrackLoaded(@Nonnull String name);
|
||||
default boolean isTrackLoaded(@Nonnull String name) {
|
||||
return getTrackManager().isLoaded(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the node factory instance for the platform
|
||||
* Returns a new LogEntry Builder instance
|
||||
*
|
||||
* @return the node factory
|
||||
* @return a new builder
|
||||
* @since 4.0
|
||||
*/
|
||||
@Nonnull
|
||||
NodeFactory getNodeFactory();
|
||||
|
||||
/**
|
||||
* Gets the MetaStackFactory, used for creating MetaStacks.
|
||||
*
|
||||
* @return the meta stack factory
|
||||
* @since 3.2
|
||||
*/
|
||||
@Nonnull
|
||||
MetaStackFactory getMetaStackFactory();
|
||||
LogEntry.Builder newLogEntryBuilder();
|
||||
|
||||
/**
|
||||
* Returns a permission builder instance
|
||||
@@ -297,15 +361,19 @@ public interface LuckPermsApi {
|
||||
* @since 2.6
|
||||
*/
|
||||
@Nonnull
|
||||
Node.Builder buildNode(@Nonnull String permission) throws IllegalArgumentException;
|
||||
default Node.Builder buildNode(@Nonnull String permission) throws IllegalArgumentException {
|
||||
return getNodeFactory().newBuilder(permission);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a custom context calculator to the server
|
||||
*
|
||||
* @param contextCalculator the context calculator to register. The type MUST be the player class of the platform.
|
||||
* @param calculator the context calculator to register. The type MUST be the player class of the platform.
|
||||
* @throws ClassCastException if the type is not the player class of the platform.
|
||||
*/
|
||||
void registerContextCalculator(@Nonnull ContextCalculator<?> contextCalculator);
|
||||
default void registerContextCalculator(@Nonnull ContextCalculator<?> calculator) {
|
||||
getContextManager().registerCalculator(calculator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a calculated context instance for the user using the rules of the platform.
|
||||
@@ -316,7 +384,9 @@ public interface LuckPermsApi {
|
||||
* @return an optional containing contexts. Will return empty if the user is not online.
|
||||
*/
|
||||
@Nonnull
|
||||
Optional<Contexts> getContextForUser(@Nonnull User user);
|
||||
default Optional<Contexts> getContextForUser(@Nonnull User user) {
|
||||
return getContextManager().lookupApplicableContexts(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets set of contexts applicable to a player using the platforms {@link ContextCalculator}s.
|
||||
@@ -326,7 +396,9 @@ public interface LuckPermsApi {
|
||||
* @since 2.17
|
||||
*/
|
||||
@Nonnull
|
||||
ContextSet getContextForPlayer(@Nonnull Object player);
|
||||
default ContextSet getContextForPlayer(@Nonnull Object player) {
|
||||
return getContextManager().getApplicableContext(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a Contexts instance for the player using the platforms {@link ContextCalculator}s.
|
||||
@@ -336,23 +408,8 @@ public interface LuckPermsApi {
|
||||
* @since 3.3
|
||||
*/
|
||||
@Nonnull
|
||||
Contexts getContextsForPlayer(@Nonnull Object player);
|
||||
|
||||
/**
|
||||
* Gets the unique players which have connected to the server since it started.
|
||||
*
|
||||
* @return the unique connections
|
||||
* @since 3.3
|
||||
*/
|
||||
@Nonnull
|
||||
Set<UUID> getUniqueConnections();
|
||||
|
||||
/**
|
||||
* Gets the time when the plugin first started in milliseconds.
|
||||
*
|
||||
* @return the enable time
|
||||
* @since 3.3
|
||||
*/
|
||||
long getStartTime();
|
||||
default Contexts getContextsForPlayer(@Nonnull Object player) {
|
||||
return getContextManager().getApplicableContexts(player);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,286 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.api;
|
||||
|
||||
import me.lucko.luckperms.LuckPerms;
|
||||
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
|
||||
import me.lucko.luckperms.exceptions.ObjectLacksException;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
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) {
|
||||
for (String delim : delims) {
|
||||
s = s.replace(delim, "\\" + delim);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
private static String unescapeDelimiters(String s, String... delims) {
|
||||
for (String delim : delims) {
|
||||
s = s.replace("\\" + delim, delim);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes special characters used within LuckPerms, so the string can be saved without issues
|
||||
*
|
||||
* @param s the string to escape
|
||||
* @return an escaped string
|
||||
* @throws NullPointerException if the string is null
|
||||
*/
|
||||
public static String escapeCharacters(String s) {
|
||||
if (s == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
return escapeDelimiters(s, ".", "/", "-", "$");
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescapes special characters used within LuckPerms, the inverse of {@link #escapeCharacters(String)}
|
||||
*
|
||||
* @param s the string to unescape
|
||||
* @return an unescaped string
|
||||
* @throws NullPointerException if the string is null
|
||||
*/
|
||||
public static String unescapeCharacters(String s) {
|
||||
if (s == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
s = s.replace("{SEP}", ".");
|
||||
s = s.replace("{FSEP}", "/");
|
||||
s = s.replace("{DSEP}", "$");
|
||||
s = unescapeDelimiters(s, ".", "/", "-", "$");
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a meta value on a holder
|
||||
*
|
||||
* @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 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 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");
|
||||
|
||||
key = escapeCharacters(key);
|
||||
value = escapeCharacters(value);
|
||||
|
||||
Set<Node> toRemove = new HashSet<>();
|
||||
for (Node n : holder.getEnduringPermissions()) {
|
||||
if (n.isMeta() && n.getMeta().getKey().equals(key)) {
|
||||
toRemove.add(n);
|
||||
}
|
||||
}
|
||||
|
||||
for (Node n : toRemove) {
|
||||
try {
|
||||
holder.unsetPermission(n);
|
||||
} catch (ObjectLacksException ignored) {}
|
||||
}
|
||||
|
||||
Node.Builder metaNode = LuckPerms.getApi().buildNode("meta." + key + "." + value).setValue(true);
|
||||
if (server != null) {
|
||||
metaNode.setServer(server);
|
||||
}
|
||||
if (world != null) {
|
||||
metaNode.setWorld(world);
|
||||
}
|
||||
|
||||
try {
|
||||
holder.setPermission(metaNode.build());
|
||||
} catch (ObjectAlreadyHasException ignored) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a meta value for the holder
|
||||
*
|
||||
* @param holder the holder to get the meta from
|
||||
* @param server the server to retrieve the meta on, can be null
|
||||
* @param world the world to retrieve the meta on, can be null
|
||||
* @param node the node to get
|
||||
* @param defaultValue the default value to return if the node is not set
|
||||
* @param includeGlobal if global nodes should be considered when retrieving the meta
|
||||
* @return a meta string, or the default value if the user does not have the meta node
|
||||
* @throws NullPointerException if the holder or node is null
|
||||
* @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 (node == null) throw new NullPointerException("node");
|
||||
if (node.equals("")) {
|
||||
throw new IllegalArgumentException("node is empty");
|
||||
}
|
||||
|
||||
node = escapeCharacters(node);
|
||||
|
||||
for (Node n : holder.getPermissions()) {
|
||||
if (!n.getValue() || !n.isMeta()) 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)) {
|
||||
return unescapeCharacters(meta.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
private static void setChatMeta(boolean prefix, PermissionHolder holder, String value, int priority, String server, String world) {
|
||||
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 != null) {
|
||||
node.setServer(server);
|
||||
}
|
||||
if (world != null) {
|
||||
node.setWorld(world);
|
||||
}
|
||||
|
||||
try {
|
||||
holder.setPermission(node.build());
|
||||
} catch (ObjectAlreadyHasException ignored) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a prefix to a holder on a specific server and world
|
||||
*
|
||||
* @param holder the holder to set the prefix for
|
||||
* @param prefix the prefix value
|
||||
* @param priority the priority to set the prefix at
|
||||
* @param server the server to set the prefix on, can be null
|
||||
* @param world the world to set the prefix on, can be null
|
||||
* @throws NullPointerException if the holder is null
|
||||
* @throws IllegalArgumentException if the prefix is null or empty
|
||||
*/
|
||||
public static void setPrefix(PermissionHolder holder, String prefix, int priority, String server, String world) {
|
||||
setChatMeta(true, holder, prefix, priority, server, world);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a suffix to a holder on a specific server and world
|
||||
*
|
||||
* @param holder the holder to set the suffix for
|
||||
* @param suffix the suffix value
|
||||
* @param priority the priority to set the suffix at
|
||||
* @param server the server to set the suffix on, can be null
|
||||
* @param world the world to set the suffix on, can be null
|
||||
* @throws NullPointerException if the holder is null
|
||||
* @throws IllegalArgumentException if the suffix is null or empty
|
||||
*/
|
||||
public static void setSuffix(PermissionHolder holder, String suffix, int priority, String server, String world) {
|
||||
setChatMeta(false, holder, suffix, priority, server, world);
|
||||
}
|
||||
|
||||
private static String getChatMeta(boolean prefix, PermissionHolder holder, String server, String world, boolean includeGlobal) {
|
||||
if (holder == null) {
|
||||
throw new NullPointerException("holder");
|
||||
}
|
||||
|
||||
int priority = Integer.MIN_VALUE;
|
||||
String meta = null;
|
||||
for (Node n : holder.getAllNodes(Contexts.allowAll())) {
|
||||
if (!n.getValue()) continue;
|
||||
|
||||
if (!n.shouldApplyOnServer(server, includeGlobal, false)) continue;
|
||||
if (!n.shouldApplyOnWorld(world, includeGlobal, false)) continue;
|
||||
|
||||
if (prefix ? !n.isPrefix() : !n.isSuffix()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Map.Entry<Integer, String> value = prefix ? n.getPrefix() : n.getSuffix();
|
||||
if (value.getKey() > priority) {
|
||||
meta = value.getValue();
|
||||
priority = value.getKey();
|
||||
}
|
||||
}
|
||||
|
||||
return meta == null ? "" : unescapeCharacters(meta);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a holders highest priority prefix, if they have one
|
||||
*
|
||||
* @param holder the holder
|
||||
* @param server the server to retrieve the prefix on
|
||||
* @param world the world to retrieve the prefix on
|
||||
* @param includeGlobal if global nodes should be considered when retrieving the prefix
|
||||
* @return a prefix string, if the holder has one, or an empty string if not.
|
||||
* @throws NullPointerException if the holder is null
|
||||
*/
|
||||
public static String getPrefix(PermissionHolder holder, String server, String world, boolean includeGlobal) {
|
||||
return getChatMeta(true, holder, server, world, includeGlobal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a holders highest priority suffix, if they have one
|
||||
*
|
||||
* @param holder the holder
|
||||
* @param server the server to retrieve the suffix on
|
||||
* @param world the world to retrieve the suffix on
|
||||
* @param includeGlobal if global nodes should be considered when retrieving the suffix
|
||||
* @return a suffix string, if the holder has one, or an empty string if not.
|
||||
* @throws NullPointerException if the holder is null
|
||||
*/
|
||||
public static String getSuffix(PermissionHolder holder, String server, String world, boolean includeGlobal) {
|
||||
return getChatMeta(false, holder, server, world, includeGlobal);
|
||||
}
|
||||
|
||||
private MetaUtils() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -34,19 +34,20 @@ import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* An immutable permission node
|
||||
* Represents a permission node.
|
||||
*
|
||||
* <p>Use {@link LuckPermsApi#buildNode(String)} to get an instance.</p>
|
||||
* <p>All implementations of this interface must be immutable.</p>
|
||||
*
|
||||
* <p>Use the {@link NodeFactory} to obtain and construct instances.</p>
|
||||
*
|
||||
* @since 2.6
|
||||
*/
|
||||
public interface Node extends Map.Entry<String, Boolean> {
|
||||
|
||||
/**
|
||||
* Returns the actual permission string
|
||||
* Gets the permission string
|
||||
*
|
||||
* @return the actual permission node
|
||||
*/
|
||||
@@ -54,36 +55,50 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
String getPermission();
|
||||
|
||||
/**
|
||||
* Gets what value the permission is set to. A negated node would return <code>false</code>.
|
||||
* Gets the value.
|
||||
*
|
||||
* <p>A negated node would return a value of <code>false</code>.</p>
|
||||
*
|
||||
* @return the permission's value
|
||||
*/
|
||||
@Override
|
||||
@Nonnull
|
||||
Boolean getValue();
|
||||
default Boolean getValue() {
|
||||
return getValuePrimitive();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this node as a tristate
|
||||
* Gets the value.
|
||||
*
|
||||
* <p>A negated node would return a value of <code>false</code>.</p>
|
||||
*
|
||||
* @return the permission's value
|
||||
*/
|
||||
boolean getValuePrimitive();
|
||||
|
||||
/**
|
||||
* Gets the value of this node as a {@link Tristate}
|
||||
*
|
||||
* @return the value of this node as a Tristate
|
||||
*/
|
||||
@Nonnull
|
||||
default Tristate getTristate() {
|
||||
return Tristate.fromBoolean(getValue());
|
||||
return Tristate.fromBoolean(getValuePrimitive());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the node is negated
|
||||
* Gets if the node is negated
|
||||
*
|
||||
* @return true if the node is negated
|
||||
*/
|
||||
default boolean isNegated() {
|
||||
return !getValue();
|
||||
return !getValuePrimitive();
|
||||
}
|
||||
|
||||
/**
|
||||
* If this node is set to override explicitly.
|
||||
* This value does not persist across saves, and is therefore only useful for transient nodes
|
||||
* Gets if this node is set to override explicitly.
|
||||
*
|
||||
* <p>This value does not persist across saves, and is therefore only useful for transient nodes</p>
|
||||
*
|
||||
* @return true if this node is set to override explicitly
|
||||
*/
|
||||
@@ -106,21 +121,21 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
Optional<String> getWorld();
|
||||
|
||||
/**
|
||||
* Returns if this node is server specific
|
||||
* Gets if this node is server specific
|
||||
*
|
||||
* @return true if this node is server specific
|
||||
*/
|
||||
boolean isServerSpecific();
|
||||
|
||||
/**
|
||||
* Returns if this node is server specific
|
||||
* Gets if this node is server specific
|
||||
*
|
||||
* @return true if this node is server specific
|
||||
*/
|
||||
boolean isWorldSpecific();
|
||||
|
||||
/**
|
||||
* Returns if this node applies globally, and has no specific context
|
||||
* Gets if this node applies globally, and therefore has no specific context
|
||||
*
|
||||
* @return true if this node applies globally, and has no specific context
|
||||
* @since 3.1
|
||||
@@ -128,7 +143,7 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
boolean appliesGlobally();
|
||||
|
||||
/**
|
||||
* Returns if this node has any specific context in order to apply.
|
||||
* Gets if this node has any specific context in order for it to apply
|
||||
*
|
||||
* @return true if this node has specific context
|
||||
* @since 3.1
|
||||
@@ -136,51 +151,7 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
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, @Nullable String server, @Nullable String world, @Nullable ContextSet context, boolean applyRegex);
|
||||
|
||||
/**
|
||||
* If this node should apply on a specific server
|
||||
*
|
||||
* @param server the name of the server
|
||||
* @param includeGlobal if global permissions should apply
|
||||
* @param applyRegex if regex should be applied
|
||||
* @return true if the node should apply
|
||||
*/
|
||||
boolean shouldApplyOnServer(@Nullable String server, boolean includeGlobal, boolean applyRegex);
|
||||
|
||||
/**
|
||||
* If this node should apply on a specific world
|
||||
*
|
||||
* @param world the name of the world
|
||||
* @param includeGlobal if global permissions should apply
|
||||
* @param applyRegex if regex should be applied
|
||||
* @return true if the node should apply
|
||||
*/
|
||||
boolean shouldApplyOnWorld(@Nullable String world, boolean includeGlobal, boolean applyRegex);
|
||||
|
||||
/**
|
||||
* If this node should apply in the given context
|
||||
*
|
||||
* @param context the context key value pairs
|
||||
* @param worldAndServer if world and server contexts should be checked
|
||||
* @return true if the node should apply
|
||||
* @since 2.13
|
||||
*/
|
||||
boolean shouldApplyWithContext(@Nonnull ContextSet context, boolean worldAndServer);
|
||||
|
||||
/**
|
||||
* If this node should apply in the given context
|
||||
* Gets if this node should apply in the given context
|
||||
*
|
||||
* @param context the context key value pairs
|
||||
* @return true if the node should apply
|
||||
@@ -188,33 +159,6 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
*/
|
||||
boolean shouldApplyWithContext(@Nonnull ContextSet context);
|
||||
|
||||
/**
|
||||
* Similar to {@link #shouldApplyOnServer(String, boolean, boolean)}, except this method accepts a List
|
||||
*
|
||||
* @param servers the list of servers
|
||||
* @param includeGlobal if global permissions should apply
|
||||
* @return true if the node should apply
|
||||
*/
|
||||
boolean shouldApplyOnAnyServers(@Nonnull List<String> servers, boolean includeGlobal);
|
||||
|
||||
/**
|
||||
* Similar to {@link #shouldApplyOnWorld(String, boolean, boolean)}, except this method accepts a List
|
||||
*
|
||||
* @param worlds the list of world
|
||||
* @param includeGlobal if global permissions should apply
|
||||
* @return true if the node should apply
|
||||
*/
|
||||
boolean shouldApplyOnAnyWorlds(@Nonnull List<String> worlds, boolean includeGlobal);
|
||||
|
||||
/**
|
||||
* Resolves a list of wildcards that match this node
|
||||
*
|
||||
* @param possibleNodes a list of possible permission nodes
|
||||
* @return a list of permissions that match this wildcard
|
||||
*/
|
||||
@Nonnull
|
||||
List<String> resolveWildcard(@Nonnull List<String> possibleNodes);
|
||||
|
||||
/**
|
||||
* Resolves any shorthand parts of this node and returns the full list
|
||||
*
|
||||
@@ -224,14 +168,14 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
List<String> resolveShorthand();
|
||||
|
||||
/**
|
||||
* Returns if this node will expire in the future
|
||||
* Gets if this node will expire in the future
|
||||
*
|
||||
* @return true if this node will expire in the future
|
||||
*/
|
||||
boolean isTemporary();
|
||||
|
||||
/**
|
||||
* Returns if this node will not expire
|
||||
* Gets if this node will not expire
|
||||
*
|
||||
* @return true if this node will not expire
|
||||
*/
|
||||
@@ -240,7 +184,7 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unix timestamp in seconds when this node will expire
|
||||
* Gets a unix timestamp in seconds when this node will expire
|
||||
*
|
||||
* @return the time in Unix time when this node will expire
|
||||
* @throws IllegalStateException if the node is not temporary
|
||||
@@ -248,7 +192,7 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
long getExpiryUnixTime() throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Returns the date when this node will expire
|
||||
* Gets the date when this node will expire
|
||||
*
|
||||
* @return the {@link Date} when this node will expire
|
||||
* @throws IllegalStateException if the node is not temporary
|
||||
@@ -257,7 +201,7 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
Date getExpiry() throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Return the number of seconds until this permission will expire
|
||||
* Gets the number of seconds until this permission will expire
|
||||
*
|
||||
* @return the number of seconds until this permission will expire
|
||||
* @throws IllegalStateException if the node is not temporary
|
||||
@@ -265,8 +209,9 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
long getSecondsTilExpiry() throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Return true if the node has expired.
|
||||
* This also returns false if the node is not temporary
|
||||
* Gets if the node has expired.
|
||||
*
|
||||
* <p>This also returns false if the node is not temporary.</p>
|
||||
*
|
||||
* @return true if this node has expired
|
||||
*/
|
||||
@@ -291,24 +236,14 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
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
|
||||
@Nonnull
|
||||
String toSerializedNode();
|
||||
|
||||
/**
|
||||
* Returns if this is a group node
|
||||
* Gets if this is a group node
|
||||
*
|
||||
* @return true if this is a group node
|
||||
*/
|
||||
boolean isGroupNode();
|
||||
|
||||
/**
|
||||
* Returns the name of the group
|
||||
* Gets the name of the group, if this is a group node.
|
||||
*
|
||||
* @return the name of the group
|
||||
* @throws IllegalStateException if this is not a group node. See {@link #isGroupNode()}
|
||||
@@ -317,7 +252,7 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
String getGroupName() throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Returns if this node is a wildcard node
|
||||
* Gets if this node is a wildcard node
|
||||
*
|
||||
* @return true if this node is a wildcard node
|
||||
*/
|
||||
@@ -332,7 +267,7 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
int getWildcardLevel() throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Returns if this node is a meta node
|
||||
* Gets if this node is a meta node
|
||||
*
|
||||
* @return true if this node is a meta node
|
||||
*/
|
||||
@@ -348,7 +283,7 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
Map.Entry<String, String> getMeta() throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Returns if this node is a prefix node
|
||||
* Gets if this node is a prefix node
|
||||
*
|
||||
* @return true if this node is a prefix node
|
||||
*/
|
||||
@@ -364,7 +299,7 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
Map.Entry<Integer, String> getPrefix() throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Returns if this node is a suffix node
|
||||
* Gets if this node is a suffix node
|
||||
*
|
||||
* @return true if this node is a suffix node
|
||||
*/
|
||||
|
||||
@@ -28,27 +28,12 @@ package me.lucko.luckperms.api;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Builds {@link Node} instances
|
||||
* Assists with constructing {@link Node} instances.
|
||||
*
|
||||
* @since 2.17
|
||||
*/
|
||||
public interface NodeFactory {
|
||||
|
||||
/**
|
||||
* Creates a node from a serialised node string
|
||||
*
|
||||
* @param serialisedPermission the serialised permission string
|
||||
* @param value the value of the node
|
||||
* @return a node instance
|
||||
* @throws NullPointerException if the permission is null
|
||||
* @deprecated since this format isn't used internally for permissions anymore
|
||||
* @see Node#toSerializedNode()
|
||||
*/
|
||||
@Deprecated
|
||||
@Nonnull
|
||||
Node fromSerialisedNode(@Nonnull String serialisedPermission, boolean value);
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new node builder from a given base permission string
|
||||
*
|
||||
@@ -69,20 +54,6 @@ public interface NodeFactory {
|
||||
@Nonnull
|
||||
Node.Builder newBuilderFromExisting(@Nonnull Node other);
|
||||
|
||||
/**
|
||||
* Creates a node builder from a serialised node string
|
||||
*
|
||||
* @param serialisedPermission the serialised permission string
|
||||
* @param value the value of the node
|
||||
* @return a node builder instance
|
||||
* @throws NullPointerException if the permission is null
|
||||
* @deprecated since this format isn't used internally for permissions anymore
|
||||
* @see Node#toSerializedNode()
|
||||
*/
|
||||
@Deprecated
|
||||
@Nonnull
|
||||
Node.Builder newBuilderFromSerialisedNode(@Nonnull String serialisedPermission, boolean value);
|
||||
|
||||
|
||||
/**
|
||||
* Creates a node builder from a group
|
||||
@@ -96,6 +67,17 @@ public interface NodeFactory {
|
||||
@Nonnull
|
||||
Node.Builder makeGroupNode(@Nonnull Group group);
|
||||
|
||||
/**
|
||||
* Creates a node builder from a group
|
||||
*
|
||||
* @param groupName the name of the group
|
||||
* @return a node builder instance
|
||||
* @throws NullPointerException if the groupName is null
|
||||
* @since 4.0
|
||||
*/
|
||||
@Nonnull
|
||||
Node.Builder makeGroupNode(@Nonnull String groupName);
|
||||
|
||||
/**
|
||||
* Creates a node builder from a key value pair
|
||||
*
|
||||
|
||||
@@ -30,8 +30,6 @@ import com.google.common.collect.Multimap;
|
||||
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
||||
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
|
||||
import me.lucko.luckperms.exceptions.ObjectLacksException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -40,17 +38,17 @@ import java.util.SortedSet;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* An object capable of holding permissions
|
||||
* An object which holds permissions.
|
||||
*
|
||||
* <p>Any changes made will be lost unless the instance is saved back to the {@link Storage}.</p>
|
||||
* <p>Any changes made to permission holding objects will be lost unless the
|
||||
* instance is saved back to the {@link Storage}.</p>
|
||||
*/
|
||||
public interface PermissionHolder {
|
||||
|
||||
/**
|
||||
* Gets the objects name
|
||||
* Gets the objects name.
|
||||
*
|
||||
* <p>{@link User#getUuid()}, {@link User#getName()} or {@link Group#getName()} should normally be used instead of
|
||||
* this method.</p>
|
||||
@@ -123,7 +121,7 @@ public interface PermissionHolder {
|
||||
SortedSet<? extends Node> getPermissions();
|
||||
|
||||
/**
|
||||
* Similar to {@link #getPermissions()}, except without transient permissions
|
||||
* Similar to {@link #getPermissions()}, except without transient permissions.
|
||||
*
|
||||
* <p>Unlike transient permissions, enduring permissions will be saved to storage, and exist after the session.</p>
|
||||
*
|
||||
@@ -134,7 +132,7 @@ public interface PermissionHolder {
|
||||
Set<? extends Node> getEnduringPermissions();
|
||||
|
||||
/**
|
||||
* Similar to {@link #getPermissions()}, except without enduring permissions
|
||||
* Similar to {@link #getPermissions()}, except without enduring permissions.
|
||||
*
|
||||
* <p>Transient permissions only exist for the duration of the session.</p>
|
||||
*
|
||||
@@ -290,22 +288,12 @@ public interface PermissionHolder {
|
||||
* Sets a permission for the object
|
||||
*
|
||||
* @param node The node to be set
|
||||
* @throws ObjectAlreadyHasException if the object already has the permission
|
||||
* @throws NullPointerException if the node is null
|
||||
* @since 2.6
|
||||
*/
|
||||
void setPermission(@Nonnull 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
|
||||
* @throws NullPointerException if the node is null
|
||||
* @since 4.0
|
||||
*/
|
||||
@Nonnull
|
||||
DataMutateResult setPermissionUnchecked(@Nonnull Node node);
|
||||
DataMutateResult setPermission(@Nonnull Node node);
|
||||
|
||||
/**
|
||||
* Sets a transient permission for the object
|
||||
@@ -320,73 +308,34 @@ public interface PermissionHolder {
|
||||
* <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
|
||||
* @throws NullPointerException if the node is null
|
||||
* @since 2.6
|
||||
*/
|
||||
void setTransientPermission(@Nonnull 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
|
||||
* @throws NullPointerException if the node is null
|
||||
* @since 4.0
|
||||
*/
|
||||
@Nonnull
|
||||
DataMutateResult setTransientPermissionUnchecked(@Nonnull Node node);
|
||||
DataMutateResult setTransientPermission(@Nonnull Node node);
|
||||
|
||||
/**
|
||||
* Unsets a permission for the object
|
||||
*
|
||||
* @param node The node to be unset
|
||||
* @throws ObjectLacksException if the node wasn't already set
|
||||
* @throws NullPointerException if the node is null
|
||||
* @since 2.6
|
||||
*/
|
||||
void unsetPermission(@Nonnull 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
|
||||
* @throws NullPointerException if the node is null
|
||||
* @since 4.0
|
||||
*/
|
||||
@Nonnull
|
||||
DataMutateResult unsetPermissionUnchecked(@Nonnull Node node);
|
||||
DataMutateResult unsetPermission(@Nonnull Node node);
|
||||
|
||||
/**
|
||||
* Unsets a transient permission for the object
|
||||
*
|
||||
* @param node The node to be unset
|
||||
* @throws ObjectLacksException if the node wasn't already set
|
||||
* @throws NullPointerException if the node is null
|
||||
* @since 2.6
|
||||
*/
|
||||
void unsetTransientPermission(@Nonnull 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
|
||||
* @throws NullPointerException if the node is null
|
||||
* @since 4.0
|
||||
*/
|
||||
@Nonnull
|
||||
DataMutateResult unsetTransientPermissionUnchecked(@Nonnull Node node);
|
||||
DataMutateResult unsetTransientPermission(@Nonnull Node node);
|
||||
|
||||
/**
|
||||
* Clears any nodes from the holder which pass the predicate
|
||||
@@ -454,421 +403,64 @@ public interface PermissionHolder {
|
||||
*/
|
||||
void clearTransientNodes();
|
||||
|
||||
/**
|
||||
* Checks to see if the object has a certain permission
|
||||
*
|
||||
* @param node The permission node
|
||||
* @param b If the node is true/false(negated)
|
||||
* @return true if the object has the permission
|
||||
* @throws NullPointerException if the node is null
|
||||
* @throws IllegalArgumentException if the node is invalid
|
||||
* @deprecated in favour of {@link #hasPermission(Node)}
|
||||
*/
|
||||
@Deprecated
|
||||
boolean hasPermission(@Nonnull String node, boolean b);
|
||||
|
||||
/**
|
||||
* Checks to see the the object has a permission on a certain server
|
||||
*
|
||||
* @param node The permission node
|
||||
* @param b If the node is true/false(negated)
|
||||
* @param server The server
|
||||
* @return true if the object has the permission
|
||||
* @throws NullPointerException if the node or server is null
|
||||
* @throws IllegalArgumentException if the node or server is invalid
|
||||
* @deprecated in favour of {@link #hasPermission(Node)}
|
||||
*/
|
||||
@Deprecated
|
||||
boolean hasPermission(@Nonnull String node, boolean b, @Nonnull String server);
|
||||
|
||||
/**
|
||||
* Checks to see the the object has a permission on a certain server and world
|
||||
*
|
||||
* @param node The permission node
|
||||
* @param b If the node is true/false(negated)
|
||||
* @param server The server
|
||||
* @param world The world
|
||||
* @return true if the object has the permission
|
||||
* @throws NullPointerException if the node, server or world is null
|
||||
* @throws IllegalArgumentException if the node, server or world is invalid
|
||||
* @deprecated in favour of {@link #hasPermission(Node)}
|
||||
*/
|
||||
@Deprecated
|
||||
boolean hasPermission(@Nonnull String node, boolean b, @Nonnull String server, @Nonnull String world);
|
||||
|
||||
/**
|
||||
* Checks to see the the object has a permission
|
||||
*
|
||||
* @param node The permission node
|
||||
* @param b If the node is true/false(negated)
|
||||
* @param temporary if the permission is temporary
|
||||
* @return true if the object has the permission
|
||||
* @throws NullPointerException if the node is null
|
||||
* @throws IllegalArgumentException if the node is invalid
|
||||
* @deprecated in favour of {@link #hasPermission(Node)}
|
||||
*/
|
||||
@Deprecated
|
||||
boolean hasPermission(@Nonnull String node, boolean b, boolean temporary);
|
||||
|
||||
/**
|
||||
* Checks to see the the object has a permission on a certain server
|
||||
*
|
||||
* @param node The permission node
|
||||
* @param b If the node is true/false(negated)
|
||||
* @param server The server to check on
|
||||
* @param temporary if the permission is temporary
|
||||
* @return true if the object has the permission
|
||||
* @throws NullPointerException if the node or server is null
|
||||
* @throws IllegalArgumentException if the node or server is invalid
|
||||
* @deprecated in favour of {@link #hasPermission(Node)}
|
||||
*/
|
||||
@Deprecated
|
||||
boolean hasPermission(@Nonnull String node, boolean b, @Nonnull String server, boolean temporary);
|
||||
|
||||
/**
|
||||
* Checks to see the the object has a permission on a certain server and world
|
||||
*
|
||||
* @param node The permission node
|
||||
* @param b If the node is true/false(negated)
|
||||
* @param server The server to check on
|
||||
* @param world The world to check on
|
||||
* @param temporary if the permission is temporary
|
||||
* @return true if the object has the permission
|
||||
* @throws NullPointerException if the node, server or world is null
|
||||
* @throws IllegalArgumentException if the node, server or world is invalid
|
||||
* @deprecated in favour of {@link #hasPermission(Node)}
|
||||
*/
|
||||
@Deprecated
|
||||
boolean hasPermission(@Nonnull String node, boolean b, @Nonnull String server, @Nonnull String world, boolean temporary);
|
||||
|
||||
/**
|
||||
* Checks to see if the object inherits a certain permission
|
||||
*
|
||||
* @param node The permission node
|
||||
* @param b If the node is true/false(negated)
|
||||
* @return true if the object inherits the permission
|
||||
* @throws NullPointerException if the node is null
|
||||
* @throws IllegalArgumentException if the node is invalid
|
||||
* @deprecated in favour of {@link #hasPermission(Node)}
|
||||
*/
|
||||
@Deprecated
|
||||
boolean inheritsPermission(@Nonnull String node, boolean b);
|
||||
|
||||
/**
|
||||
* Checks to see the the object inherits a permission on a certain server
|
||||
*
|
||||
* @param node The permission node
|
||||
* @param b If the node is true/false(negated)
|
||||
* @param server The server
|
||||
* @return true if the object inherits the permission
|
||||
* @throws NullPointerException if the node or server is null
|
||||
* @throws IllegalArgumentException if the node or server is invalid
|
||||
* @deprecated in favour of {@link #hasPermission(Node)}
|
||||
*/
|
||||
@Deprecated
|
||||
boolean inheritsPermission(@Nonnull String node, boolean b, @Nonnull String server);
|
||||
|
||||
/**
|
||||
* Checks to see the the object inherits a permission on a certain server and world
|
||||
*
|
||||
* @param node The permission node
|
||||
* @param b If the node is true/false(negated)
|
||||
* @param server The server
|
||||
* @param world The world
|
||||
* @return true if the object inherits the permission
|
||||
* @throws NullPointerException if the node, server or world is null
|
||||
* @throws IllegalArgumentException if the node server or world is invalid
|
||||
* @deprecated in favour of {@link #hasPermission(Node)}
|
||||
*/
|
||||
@Deprecated
|
||||
boolean inheritsPermission(@Nonnull String node, boolean b, @Nonnull String server, @Nonnull String world);
|
||||
|
||||
/**
|
||||
* Checks to see if the object inherits a permission
|
||||
*
|
||||
* @param node The permission node
|
||||
* @param b If the node is true/false(negated)
|
||||
* @param temporary if the permission is temporary
|
||||
* @return true if the object inherits the permission
|
||||
* @throws NullPointerException if the node is null
|
||||
* @throws IllegalArgumentException if the node is invalid
|
||||
* @deprecated in favour of {@link #hasPermission(Node)}
|
||||
*/
|
||||
@Deprecated
|
||||
boolean inheritsPermission(@Nonnull String node, boolean b, boolean temporary);
|
||||
|
||||
/**
|
||||
* Checks to see if the object inherits a permission on a certain server
|
||||
*
|
||||
* @param node The permission node
|
||||
* @param b If the node is true/false(negated)
|
||||
* @param server The server
|
||||
* @param temporary if the permission is temporary
|
||||
* @return true if the object inherits the permission
|
||||
* @throws NullPointerException if the node or server is null
|
||||
* @throws IllegalArgumentException if the node or server is invalid
|
||||
* @deprecated in favour of {@link #hasPermission(Node)}
|
||||
*/
|
||||
@Deprecated
|
||||
boolean inheritsPermission(@Nonnull String node, boolean b, @Nonnull String server, boolean temporary);
|
||||
|
||||
/**
|
||||
* Checks to see if the object inherits a permission on a certain server and world
|
||||
*
|
||||
* @param node The permission node
|
||||
* @param b If the node is true/false(negated)
|
||||
* @param server The server
|
||||
* @param world The world
|
||||
* @param temporary if the permission is temporary
|
||||
* @return true if the object inherits the permission
|
||||
* @throws NullPointerException if the node, server or world is null
|
||||
* @throws IllegalArgumentException if the node, server or world if invalid
|
||||
* @deprecated in favour of {@link #hasPermission(Node)}
|
||||
*/
|
||||
@Deprecated
|
||||
boolean inheritsPermission(@Nonnull String node, boolean b, @Nonnull String server, @Nonnull String world, boolean temporary);
|
||||
|
||||
/**
|
||||
* Sets a permission for the object
|
||||
*
|
||||
* @param node The node to be set
|
||||
* @param value What to set the node to - true/false(negated)
|
||||
* @throws ObjectAlreadyHasException if the object already has the permission
|
||||
* @throws NullPointerException if the node is null
|
||||
* @throws IllegalArgumentException if the node is invalid
|
||||
* @deprecated in favour of {@link #setPermission(Node)}
|
||||
* @param node The node to be set
|
||||
* @return the result of the operation
|
||||
* @throws NullPointerException if the node is null
|
||||
* @since 3.1
|
||||
* @deprecated now forwards to {@link #setPermission(Node)}.
|
||||
*/
|
||||
@Nonnull
|
||||
@Deprecated
|
||||
void setPermission(@Nonnull String node, boolean value) throws ObjectAlreadyHasException;
|
||||
default DataMutateResult setPermissionUnchecked(@Nonnull Node node) {
|
||||
return setPermission(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a permission for the object on a specific server
|
||||
* Sets a transient permission for the object
|
||||
*
|
||||
* @param node The node to set
|
||||
* @param value What to set the node to - true/false(negated)
|
||||
* @param server The server to set the permission on
|
||||
* @throws ObjectAlreadyHasException if the object already has the permission
|
||||
* @throws NullPointerException if the node or server is null
|
||||
* @throws IllegalArgumentException if the node or server is invalid
|
||||
* @deprecated in favour of {@link #setPermission(Node)}
|
||||
* @param node The node to be set
|
||||
* @return the result of the operation
|
||||
* @throws NullPointerException if the node is null
|
||||
* @since 3.1
|
||||
* @deprecated now forwards to {@link #setTransientPermission(Node)}
|
||||
*/
|
||||
@Nonnull
|
||||
@Deprecated
|
||||
void setPermission(@Nonnull String node, boolean value, @Nonnull String server) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
* Sets a permission for the object on a specific server and world
|
||||
*
|
||||
* @param node The node to set
|
||||
* @param value What to set the node to - true/false(negated)
|
||||
* @param server The server to set the permission on
|
||||
* @param world The world to set the permission on
|
||||
* @throws ObjectAlreadyHasException if the object already has the permission
|
||||
* @throws NullPointerException if the node, server or world is null
|
||||
* @throws IllegalArgumentException if the node, server or world is invalid
|
||||
* @deprecated in favour of {@link #setPermission(Node)}
|
||||
*/
|
||||
@Deprecated
|
||||
void setPermission(@Nonnull String node, boolean value, @Nonnull String server, @Nonnull String world) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
* Sets a temporary permission for the object
|
||||
*
|
||||
* @param node The node to set
|
||||
* @param value What to set the node to - true/false(negated)
|
||||
* @param expireAt The time in unixtime when the permission will expire
|
||||
* @throws ObjectAlreadyHasException if the object already has the permission
|
||||
* @throws NullPointerException if the node is null
|
||||
* @throws IllegalArgumentException if the node is invalid or if the expiry time is in the past
|
||||
* @deprecated in favour of {@link #setPermission(Node)}
|
||||
*/
|
||||
@Deprecated
|
||||
void setPermission(@Nonnull String node, boolean value, long expireAt) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
* Sets a temporary permission for the object on a specific server
|
||||
*
|
||||
* @param node The node to set
|
||||
* @param value What to set the node to - true/false(negated)
|
||||
* @param server The server to set the permission on
|
||||
* @param expireAt The time in unixtime when the permission will expire
|
||||
* @throws ObjectAlreadyHasException if the object already has the permission
|
||||
* @throws NullPointerException if the node or server is null
|
||||
* @throws IllegalArgumentException if the node/server is invalid or if the expiry time is in the past
|
||||
* @deprecated in favour of {@link #setPermission(Node)}
|
||||
*/
|
||||
@Deprecated
|
||||
void setPermission(@Nonnull String node, boolean value, @Nonnull String server, long expireAt) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
* Sets a temporary permission for the object on a specific server and world
|
||||
*
|
||||
* @param node The node to set
|
||||
* @param value What to set the node to - true/false(negated)
|
||||
* @param server The server to set the permission on
|
||||
* @param world The world to set the permission on
|
||||
* @param expireAt The time in unixtime when the permission will expire
|
||||
* @throws ObjectAlreadyHasException if the object already has the permission
|
||||
* @throws NullPointerException if the node, server or world is null
|
||||
* @throws IllegalArgumentException if the node/server/world is invalid, or if the expiry time is in the past
|
||||
* @deprecated in favour of {@link #setPermission(Node)}
|
||||
*/
|
||||
@Deprecated
|
||||
void setPermission(String node, boolean value, @Nonnull String server, @Nonnull String world, long expireAt) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
* Unsets a permission for the object
|
||||
*
|
||||
* @param node The node to be unset
|
||||
* @param temporary if the permission being removed is temporary
|
||||
* @throws ObjectLacksException if the node wasn't already set
|
||||
* @throws NullPointerException if the node is null
|
||||
* @throws IllegalArgumentException if the node is invalid
|
||||
* @deprecated in favour of {@link #unsetPermission(Node)}
|
||||
*/
|
||||
@Deprecated
|
||||
void unsetPermission(@Nonnull String node, boolean temporary) throws ObjectLacksException;
|
||||
default DataMutateResult setTransientPermissionUnchecked(@Nonnull Node node) {
|
||||
return setTransientPermission(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsets a permission for the object
|
||||
*
|
||||
* @param node The node to be unset
|
||||
* @throws ObjectLacksException if the node wasn't already set
|
||||
* @throws NullPointerException if the node is null
|
||||
* @throws IllegalArgumentException if the node is invalid
|
||||
* @deprecated in favour of {@link #unsetPermission(Node)}
|
||||
* @throws NullPointerException if the node is null
|
||||
* @return the result of the operation
|
||||
* @since 3.1
|
||||
* @deprecated now forwards to {@link #unsetPermission(Node)}
|
||||
*/
|
||||
@Nonnull
|
||||
@Deprecated
|
||||
void unsetPermission(@Nonnull String node) throws ObjectLacksException;
|
||||
default DataMutateResult unsetPermissionUnchecked(@Nonnull Node node) {
|
||||
return unsetPermission(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsets a permission for the object on a specific server
|
||||
* Unsets a transient permission for the object
|
||||
*
|
||||
* @param node The node to be unset
|
||||
* @param server The server to unset the node on
|
||||
* @throws ObjectLacksException if the node wasn't already set
|
||||
* @throws NullPointerException if the node or server is null
|
||||
* @throws IllegalArgumentException if the node or server is invalid
|
||||
* @deprecated in favour of {@link #unsetPermission(Node)}
|
||||
* @param node The node to be unset
|
||||
* @throws NullPointerException if the node is null
|
||||
* @return the result of the operation
|
||||
* @since 3.1
|
||||
* @deprecated now forwards to {@link #unsetTransientPermission(Node)}
|
||||
*/
|
||||
@Nonnull
|
||||
@Deprecated
|
||||
void unsetPermission(@Nonnull String node, @Nonnull String server) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
* Unsets a permission for the object on a specific server and world
|
||||
*
|
||||
* @param node The node to be unset
|
||||
* @param server The server to unset the node on
|
||||
* @param world The world to unset the node on
|
||||
* @throws ObjectLacksException if the node wasn't already set
|
||||
* @throws NullPointerException if the node, server or world is null
|
||||
* @throws IllegalArgumentException if the node, server or world is invalid
|
||||
* @deprecated in favour of {@link #unsetPermission(Node)}
|
||||
*/
|
||||
@Deprecated
|
||||
void unsetPermission(@Nonnull String node, @Nonnull String server, @Nonnull String world) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
* Unsets a permission for the object on a specific server
|
||||
*
|
||||
* @param node The node to be unset
|
||||
* @param server The server to unset the node on
|
||||
* @param temporary if the permission being unset is temporary
|
||||
* @throws ObjectLacksException if the node wasn't already set
|
||||
* @throws NullPointerException if the node or server is null
|
||||
* @throws IllegalArgumentException if the node or server is invalid
|
||||
* @deprecated in favour of {@link #unsetPermission(Node)}
|
||||
*/
|
||||
@Deprecated
|
||||
void unsetPermission(@Nonnull String node, @Nonnull String server, boolean temporary) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
* Unsets a permission for the object on a specific server and world
|
||||
*
|
||||
* @param node The node to be unset
|
||||
* @param server The server to unset the node on
|
||||
* @param world The world to unset the node on
|
||||
* @param temporary if the permission being unset is temporary
|
||||
* @throws ObjectLacksException if the node wasn't already set
|
||||
* @throws NullPointerException if the node, server or world is null
|
||||
* @throws IllegalArgumentException if the node, server or world is invalid
|
||||
* @deprecated in favour of {@link #unsetPermission(Node)}
|
||||
*/
|
||||
@Deprecated
|
||||
void unsetPermission(@Nonnull String node, @Nonnull String server, @Nonnull String world, boolean temporary) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
* Clears all nodes held by the object on a specific server
|
||||
*
|
||||
* @param server the server to filter by, can be null
|
||||
* @since 2.17
|
||||
* @deprecated in favour of {@link #clearNodes(ContextSet)}
|
||||
*/
|
||||
@Deprecated
|
||||
void clearNodes(@Nullable String server);
|
||||
|
||||
/**
|
||||
* Clears all nodes held by the object on a specific server and world
|
||||
*
|
||||
* @param server the server to filter by, can be null
|
||||
* @param world the world to filter by, can be null
|
||||
* @since 2.17
|
||||
* @deprecated in favour of {@link #clearNodes(ContextSet)}
|
||||
*/
|
||||
@Deprecated
|
||||
void clearNodes(@Nullable String server, @Nullable String world);
|
||||
|
||||
/**
|
||||
* Clears all parents on a specific server
|
||||
*
|
||||
* @param server the server to filter by, can be null
|
||||
* @since 2.17
|
||||
* @deprecated in favour of {@link #clearParents(ContextSet)}
|
||||
*/
|
||||
@Deprecated
|
||||
void clearParents(@Nullable String server);
|
||||
|
||||
/**
|
||||
* Clears all parents on a specific server and world
|
||||
*
|
||||
* @param server the server to filter by, can be null
|
||||
* @param world the world to filter by, can be null
|
||||
* @since 2.17
|
||||
* @deprecated in favour of {@link #clearParents(ContextSet)}
|
||||
*/
|
||||
@Deprecated
|
||||
void clearParents(@Nullable String server, @Nullable String world);
|
||||
|
||||
/**
|
||||
* Clears all meta held by the object on a specific server
|
||||
*
|
||||
* @param server the server to filter by, can be null
|
||||
* @since 2.17
|
||||
* @deprecated in favour of {@link #clearMeta(ContextSet)}
|
||||
*/
|
||||
@Deprecated
|
||||
void clearMeta(@Nullable String server);
|
||||
|
||||
/**
|
||||
* Clears all meta held by the object on a specific server and world
|
||||
*
|
||||
* @param server the server to filter by, can be null
|
||||
* @param world the world to filter by, can be null
|
||||
* @since 2.17
|
||||
* @deprecated in favour of {@link #clearMeta(ContextSet)}
|
||||
*/
|
||||
@Deprecated
|
||||
void clearMeta(@Nullable String server, @Nullable String world);
|
||||
|
||||
/**
|
||||
* Clears all meta for a given key.
|
||||
*
|
||||
* @param key the meta key
|
||||
* @param server the server to filter by, can be null
|
||||
* @param world the world to filter by, can be null
|
||||
* @param temporary whether the query is for temporary nodes or not.
|
||||
* @deprecated in favour of {@link #clearMatching(Predicate)}
|
||||
*/
|
||||
@Deprecated
|
||||
void clearMetaKeys(@Nonnull String key, @Nullable String server, @Nullable String world, boolean temporary);
|
||||
default DataMutateResult unsetTransientPermissionUnchecked(@Nonnull Node node) {
|
||||
return unsetTransientPermission(node);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,14 +36,14 @@ import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* A means of loading and saving data to/from the Storage provider.
|
||||
* A means of loading and saving permission data to/from the backend.
|
||||
*
|
||||
* <p>All methods return {@link CompletableFuture}s, which will be populated with the result once the data has been
|
||||
* loaded asynchronously. Care should be taken when using the methods to ensure that the main server thread is not
|
||||
* <p>All blocking methods return {@link CompletableFuture}s, which will be populated with the result once the data has been
|
||||
* loaded/saved asynchronously. Care should be taken when using such methods to ensure that the main server thread is not
|
||||
* blocked.</p>
|
||||
*
|
||||
* <p>Methods such as {@link CompletableFuture#get()} and equivalent should <strong>not</strong> be called on the main
|
||||
* server thread. If you need to use the result of these operations on the main server thread, please register a
|
||||
* server thread. If you need to use the result of these operations on the main server thread, register a
|
||||
* callback using {@link CompletableFuture#thenAcceptAsync(Consumer, Executor)} and {@link #getSyncExecutor()}.</p>
|
||||
*
|
||||
* @since 2.14
|
||||
@@ -59,7 +59,7 @@ public interface Storage {
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Return whether the storage instance is allowing logins on the platform.
|
||||
* Gets whether the storage instance is allowing logins on the platform.
|
||||
*
|
||||
* @return true if logins are enabled
|
||||
*/
|
||||
@@ -134,17 +134,10 @@ public interface Storage {
|
||||
@Nonnull
|
||||
CompletableFuture<Boolean> saveUser(@Nonnull User user);
|
||||
|
||||
/**
|
||||
* Removes users from the main storage who are "default". This is called every time the plugin loads.
|
||||
*
|
||||
* @return true if the operation completed successfully
|
||||
*/
|
||||
@Nonnull
|
||||
CompletableFuture<Boolean> cleanupUsers();
|
||||
|
||||
/**
|
||||
* Gets a set all "unique" user UUIDs.
|
||||
* "Unique" meaning the user isn't just a member of the "default" group.
|
||||
*
|
||||
* <p>"Unique" meaning the user isn't just a member of the "default" group.</p>
|
||||
*
|
||||
* @return a set of uuids, or null if the operation failed.
|
||||
*/
|
||||
|
||||
@@ -25,30 +25,30 @@
|
||||
|
||||
package me.lucko.luckperms.api;
|
||||
|
||||
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
|
||||
import me.lucko.luckperms.exceptions.ObjectLacksException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* An ordered collection of groups for easy promotions and demotions
|
||||
* An ordered chain of {@link Group}s.
|
||||
*/
|
||||
public interface Track {
|
||||
|
||||
/**
|
||||
* Gets the name of this track
|
||||
*
|
||||
* @return the name of this track
|
||||
*/
|
||||
@Nonnull
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Gets an ordered list of the groups on this track
|
||||
* Gets a list of the groups on this track
|
||||
*
|
||||
* <p>Index 0 is the first/lowest group in (or start of) the track</p>
|
||||
* <p>Index 0 is the first/lowest group in (or start of) the track.</p>
|
||||
*
|
||||
* <p>The returned collection is immutable, and cannot be modified.</p>
|
||||
*
|
||||
* @return an ordered {@link List} of the groups on this track
|
||||
*/
|
||||
@@ -65,67 +65,69 @@ public interface Track {
|
||||
/**
|
||||
* Gets the next group on the track, after the one provided
|
||||
*
|
||||
* <p>{@code null} is returned if the group is not on the track.</p>
|
||||
*
|
||||
* @param current the group before the group being requested
|
||||
* @return the group name, or null if the end of the track has been reached
|
||||
* @throws ObjectLacksException if the track does not contain the group given
|
||||
* @throws NullPointerException if the group is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
*/
|
||||
@Nullable
|
||||
String getNext(@Nonnull Group current) throws ObjectLacksException;
|
||||
String getNext(@Nonnull Group current);
|
||||
|
||||
/**
|
||||
* Gets the previous group on the track, before the one provided
|
||||
*
|
||||
* <p>{@code null} is returned if the group is not on the track.</p>
|
||||
*
|
||||
* @param current the group after the group being requested
|
||||
* @return the group name, or null if the start of the track has been reached
|
||||
* @throws ObjectLacksException if the track does not contain the group given
|
||||
* @throws NullPointerException if the group is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
*/
|
||||
@Nullable
|
||||
String getPrevious(@Nonnull Group current) throws ObjectLacksException;
|
||||
String getPrevious(@Nonnull Group current);
|
||||
|
||||
/**
|
||||
* Appends a group to the end of this track
|
||||
*
|
||||
* @param group the group to append
|
||||
* @throws ObjectAlreadyHasException if the group is already on this track somewhere
|
||||
* @return the result of the operation
|
||||
* @throws NullPointerException if the group is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
*/
|
||||
void appendGroup(@Nonnull Group group) throws ObjectAlreadyHasException;
|
||||
DataMutateResult appendGroup(@Nonnull Group group);
|
||||
|
||||
/**
|
||||
* Inserts a group at a certain position on this track
|
||||
*
|
||||
* @param group the group to be inserted
|
||||
* @param position the index position (a value of 0 inserts at the start)
|
||||
* @throws ObjectAlreadyHasException if the group is already on this track somewhere
|
||||
* @return the result of the operation
|
||||
* @throws IndexOutOfBoundsException if the position is less than 0 or greater than the size of the track
|
||||
* @throws NullPointerException if the group is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
*/
|
||||
void insertGroup(@Nonnull Group group, int position) throws ObjectAlreadyHasException, IndexOutOfBoundsException;
|
||||
DataMutateResult insertGroup(@Nonnull Group group, int position) throws IndexOutOfBoundsException;
|
||||
|
||||
/**
|
||||
* Removes a group from this track
|
||||
*
|
||||
* @param group the group to remove
|
||||
* @throws ObjectLacksException if the group is not on this track
|
||||
* @return the result of the operation
|
||||
* @throws NullPointerException if the group is null
|
||||
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
|
||||
*/
|
||||
void removeGroup(@Nonnull Group group) throws ObjectLacksException;
|
||||
DataMutateResult removeGroup(@Nonnull Group group);
|
||||
|
||||
/**
|
||||
* Removes a group from this track
|
||||
*
|
||||
* @param group the group to remove
|
||||
* @throws ObjectLacksException if the group is not on this track
|
||||
* @return the result of the operation
|
||||
* @throws NullPointerException if the group is null
|
||||
*/
|
||||
void removeGroup(@Nonnull String group) throws ObjectLacksException;
|
||||
DataMutateResult removeGroup(@Nonnull String group);
|
||||
|
||||
/**
|
||||
* Checks if a group features on this track
|
||||
|
||||
@@ -28,37 +28,42 @@ package me.lucko.luckperms.api;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Represents a permission setting.
|
||||
* Represents three different states of a setting.
|
||||
*
|
||||
* <p>Consider a value of {@link #TRUE} to be a positive setting, {@link #FALSE} to be a "negated" setting,
|
||||
* and a value of {@link #UNDEFINED} to be a non-existent value.</p>
|
||||
* <p>Possible values:</p>
|
||||
* <p></p>
|
||||
* <ul>
|
||||
* <li>{@link #TRUE} - a positive setting</li>
|
||||
* <li>{@link #FALSE} - a negative (negated) setting</li>
|
||||
* <li>{@link #UNDEFINED} - a non-existent setting</li>
|
||||
* </ul>
|
||||
*/
|
||||
public enum Tristate {
|
||||
|
||||
/**
|
||||
* A value indicating a holder has a permission set.
|
||||
* A value indicating a positive setting
|
||||
*/
|
||||
TRUE(true),
|
||||
|
||||
/**
|
||||
* A value indicating a holder has a negated value for a permission.
|
||||
* A value indicating a negative (negated) setting
|
||||
*/
|
||||
FALSE(false),
|
||||
|
||||
/**
|
||||
* A value indicating a holder doesn't have a value for a permission set.
|
||||
* A value indicating a non-existent setting
|
||||
*/
|
||||
UNDEFINED(false);
|
||||
|
||||
/**
|
||||
* Converts from {@link Boolean} a boolean
|
||||
* Returns a {@link Tristate} from a boolean
|
||||
*
|
||||
* @param b the boolean
|
||||
* @param val the boolean value
|
||||
* @return {@link #TRUE} or {@link #FALSE}, depending on the value of the boolean.
|
||||
*/
|
||||
@Nonnull
|
||||
public static Tristate fromBoolean(boolean b) {
|
||||
return b ? TRUE : FALSE;
|
||||
public static Tristate fromBoolean(boolean val) {
|
||||
return val ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
private final boolean booleanValue;
|
||||
|
||||
@@ -27,18 +27,15 @@ package me.lucko.luckperms.api;
|
||||
|
||||
import me.lucko.luckperms.api.caching.UserData;
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
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.concurrent.CompletableFuture;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* A player holding permission data
|
||||
* A player which holds permission data.
|
||||
*/
|
||||
public interface User extends PermissionHolder {
|
||||
|
||||
@@ -51,7 +48,9 @@ public interface User extends PermissionHolder {
|
||||
UUID getUuid();
|
||||
|
||||
/**
|
||||
* Gets the users username, or null if no username is associated with this user
|
||||
* Gets the users username
|
||||
*
|
||||
* <p>Returns null if no username is associated with this user.</p>
|
||||
*
|
||||
* @return the users username
|
||||
*/
|
||||
@@ -73,19 +72,11 @@ public interface User extends PermissionHolder {
|
||||
* Sets a users primary group. This will only take effect if platform is using stored primary groups.
|
||||
*
|
||||
* @param group the new primary group
|
||||
* @throws ObjectAlreadyHasException if the user already has this set as their primary group
|
||||
* @return if the change was applied successfully
|
||||
* @throws IllegalStateException if the user is not a member of that group
|
||||
* @throws NullPointerException if the group is null
|
||||
*/
|
||||
void setPrimaryGroup(@Nonnull String group) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
* Refresh and re-assign the users permissions.
|
||||
*
|
||||
* <p>This request is not buffered, and the refresh call will be ran directly. This should be called on an
|
||||
* asynchronous thread.</p>
|
||||
*/
|
||||
void refreshPermissions();
|
||||
DataMutateResult setPrimaryGroup(@Nonnull String group);
|
||||
|
||||
/**
|
||||
* Gets the user's {@link UserData} cache.
|
||||
@@ -96,6 +87,15 @@ public interface User extends PermissionHolder {
|
||||
@Nonnull
|
||||
UserData getCachedData();
|
||||
|
||||
/**
|
||||
* Refreshes and applies any changes to the cached user data.
|
||||
*
|
||||
* @return the task future
|
||||
* @since 4.0
|
||||
*/
|
||||
@Nonnull
|
||||
CompletableFuture<Void> refreshCachedData();
|
||||
|
||||
/**
|
||||
* Check to see if the user is a direct member of a group
|
||||
*
|
||||
@@ -118,15 +118,15 @@ public interface User extends PermissionHolder {
|
||||
boolean isInGroup(@Nonnull Group group, @Nonnull ContextSet contextSet);
|
||||
|
||||
/**
|
||||
* Gets the user's {@link UserData} cache, if they have one setup.
|
||||
* Refresh and re-assign the users permissions.
|
||||
*
|
||||
* @return an optional, possibly containing the user's cached lookup data.
|
||||
* @since 2.13
|
||||
* @deprecated in version 3.2, as this cache is now always loaded
|
||||
* <p>This request is not buffered, and the refresh call will be ran directly. This should be called on an
|
||||
* asynchronous thread.</p>
|
||||
*
|
||||
* @deprecated in favour of {@link #refreshCachedData()}.
|
||||
*/
|
||||
@Deprecated
|
||||
@Nonnull
|
||||
Optional<UserData> getUserDataCache();
|
||||
void refreshPermissions();
|
||||
|
||||
/**
|
||||
* Pre-calculates some values in the user's data cache.
|
||||
@@ -135,242 +135,9 @@ public interface User extends PermissionHolder {
|
||||
* using {@link #getCachedData()}.</p>
|
||||
*
|
||||
* @since 2.17
|
||||
* @deprecated because use of this method is no longer necessary.
|
||||
*/
|
||||
@Deprecated
|
||||
void setupDataCache();
|
||||
|
||||
/**
|
||||
* Check to see if a user is a member of a group on a specific server
|
||||
*
|
||||
* @param group The group to check membership of
|
||||
* @param server The server to check on
|
||||
* @return true if the user is a member of the group
|
||||
* @throws NullPointerException if the group or server is null
|
||||
* @throws IllegalArgumentException if the server is invalid
|
||||
* @deprecated in favour of {@link #isInGroup(Group, ContextSet)}
|
||||
*/
|
||||
@Deprecated
|
||||
boolean isInGroup(@Nonnull Group group, @Nonnull String server);
|
||||
|
||||
/**
|
||||
* Check to see if a user is a member of a group on a specific server and world
|
||||
*
|
||||
* @param group The group to check membership of
|
||||
* @param server The server to check on
|
||||
* @param world The world to check on
|
||||
* @return true if the user is a member of the group
|
||||
* @throws NullPointerException if the group, server or world is null
|
||||
* @throws IllegalArgumentException if the server or world is invalid
|
||||
* @deprecated in favour of {@link #isInGroup(Group, ContextSet)}
|
||||
*/
|
||||
@Deprecated
|
||||
boolean isInGroup(@Nonnull Group group, @Nonnull String server, @Nonnull String world);
|
||||
|
||||
/**
|
||||
* Add a user to a group
|
||||
*
|
||||
* @param group The group to add the user to
|
||||
* @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(@Nonnull Group group) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
* Add a user to a group on a specific server
|
||||
*
|
||||
* @param group The group to add the user to
|
||||
* @param server The server to add the group on
|
||||
* @throws ObjectAlreadyHasException if the user is already a member of the group on that server
|
||||
* @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(@Nonnull Group group, @Nonnull String server) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
* Add a user to a group on a specific server and world
|
||||
*
|
||||
* @param group The group to add the user to
|
||||
* @param server The server to add the group on
|
||||
* @param world The world to add the group on
|
||||
* @throws ObjectAlreadyHasException if the user is already a member of the group on that server
|
||||
* @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(@Nonnull Group group, @Nonnull String server, @Nonnull String world) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
* Add a user to a group temporarily on a specific server
|
||||
*
|
||||
* @param group The group to add the user to
|
||||
* @param expireAt when the group should expire
|
||||
* @throws ObjectAlreadyHasException if the user is already a member of the group on that server
|
||||
* @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(@Nonnull Group group, long expireAt) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
* Add a user to a group temporarily on a specific server
|
||||
*
|
||||
* @param group The group to add the user to
|
||||
* @param server The server to add the group on
|
||||
* @param expireAt when the group should expire
|
||||
* @throws ObjectAlreadyHasException if the user is already a member of the group on that server
|
||||
* @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(@Nonnull Group group, @Nonnull String server, long expireAt) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
* Add a user to a group temporarily on a specific server and world
|
||||
*
|
||||
* @param group The group to add the user to
|
||||
* @param server The server to add the group on
|
||||
* @param world The world to add the group on
|
||||
* @param expireAt when the group should expire
|
||||
* @throws ObjectAlreadyHasException if the user is already a member of the group on that server
|
||||
* @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(@Nonnull Group group, @Nonnull String server, @Nonnull String world, long expireAt) throws ObjectAlreadyHasException;
|
||||
|
||||
/**
|
||||
* Remove the user from a group
|
||||
*
|
||||
* @param group the group to remove the user from
|
||||
* @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(@Nonnull Group group) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
* Remove the user from a group
|
||||
*
|
||||
* @param group the group to remove the user from
|
||||
* @param temporary if the group being removed is temporary
|
||||
* @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(@Nonnull Group group, boolean temporary) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
* Remove the user from a group on a specific server
|
||||
*
|
||||
* @param group The group to remove the user from
|
||||
* @param server The server to remove the group on
|
||||
* @throws ObjectLacksException if the user isn't a member of the group
|
||||
* @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(@Nonnull Group group, @Nonnull String server) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
* Remove the user from a group on a specific server and world
|
||||
*
|
||||
* @param group The group to remove the user from
|
||||
* @param server The server to remove the group on
|
||||
* @param world The world to remove the group on
|
||||
* @throws ObjectLacksException if the user isn't a member of the group
|
||||
* @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(@Nonnull Group group, @Nonnull String server, @Nonnull String world) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
* Remove the user from a group on a specific server
|
||||
*
|
||||
* @param group The group to remove the user from
|
||||
* @param server The server to remove the group on
|
||||
* @param temporary if the group being removed is temporary
|
||||
* @throws ObjectLacksException if the user isn't a member of the group
|
||||
* @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(@Nonnull Group group, @Nonnull String server, boolean temporary) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
* Remove the user from a group on a specific server and world
|
||||
*
|
||||
* @param group The group to remove the user from
|
||||
* @param server The server to remove the group on
|
||||
* @param world The world to remove the group on
|
||||
* @param temporary if the group being removed is temporary
|
||||
* @throws ObjectLacksException if the user isn't a member of the group
|
||||
* @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(@Nonnull Group group, @Nonnull String server, @Nonnull String world, boolean temporary) throws ObjectLacksException;
|
||||
|
||||
/**
|
||||
* Get a {@link List} of all of the groups the user is a member of, on all servers
|
||||
*
|
||||
* @return a {@link List} of group names
|
||||
* @deprecated in favour of just querying a users permissions
|
||||
*/
|
||||
@Deprecated
|
||||
@Nonnull
|
||||
List<String> getGroupNames();
|
||||
|
||||
/**
|
||||
* Get a {@link List} of the groups the user is a member of on a specific server
|
||||
*
|
||||
* @param server the server to check
|
||||
* @param world the world to check
|
||||
* @return a {@link List} of group names
|
||||
* @throws NullPointerException if the server or world is null
|
||||
* @throws IllegalArgumentException if the server or world is invalid
|
||||
* @deprecated in favour of just querying a users permissions
|
||||
*/
|
||||
@Deprecated
|
||||
@Nonnull
|
||||
List<String> getLocalGroups(@Nonnull String server, @Nonnull String world);
|
||||
|
||||
/**
|
||||
* Get a {@link List} of the groups the user is a member of on a specific server
|
||||
*
|
||||
* @param server the server to check
|
||||
* @return a {@link List} of group names
|
||||
* @throws NullPointerException if the server is null
|
||||
* @throws IllegalArgumentException if the server is invalid
|
||||
* @deprecated in favour of just querying a users permissions
|
||||
*/
|
||||
@Deprecated
|
||||
@Nonnull
|
||||
List<String> getLocalGroups(@Nonnull String server);
|
||||
|
||||
}
|
||||
@@ -32,34 +32,34 @@ import javax.annotation.Nonnull;
|
||||
/**
|
||||
* A UUID cache for online users, between external Mojang UUIDs, and internal LuckPerms UUIDs.
|
||||
*
|
||||
* <p>This UuidCache is a means of allowing users to have the same internal UUID across a network of offline mode
|
||||
* servers or mixed offline mode and online mode servers. Platforms running in offline mode generate a UUID for a
|
||||
* user when they first join the server, but this UUID will then not be consistent across the network. LuckPerms will
|
||||
* instead check the datastore cache, to get a UUID for a user that is consistent across an entire network.</p>
|
||||
* <p>A user's internal LuckPerms UUID is always the same as their Mojang one,
|
||||
* unless <code>use-server-uuids</code> is disabled.</p>
|
||||
*
|
||||
* <p>If you want to get a user object from the Storage using the api on a server in offline mode, you will need to use
|
||||
* this cache, OR use Storage#getUUID, for users that are not online.</p>
|
||||
* <p>When this setting is disabled, this cache becomes active, and allows you to convert
|
||||
* between 'internal' and 'server provided' uuids.</p>
|
||||
*
|
||||
* <p><strong>This is only effective for online players. Use {@link Storage#getUUID(String)} for offline players.</strong></p>
|
||||
*/
|
||||
public interface UuidCache {
|
||||
|
||||
/**
|
||||
* Gets a users internal "LuckPerms" UUID, from the one given by the server.
|
||||
* Gets a users "internal" LuckPerms UUID, from the one given by the server.
|
||||
*
|
||||
* @param external the UUID assigned by the server, through Player#getUniqueId or ProxiedPlayer#getUniqueId
|
||||
* <p>When <code>use-server-uuids</code> is true, this returns the same UUID instance.</p>
|
||||
*
|
||||
* @param mojangUuid the UUID assigned by the server, through <code>Player#getUniqueId</code> or <code>ProxiedPlayer#getUniqueId</code>
|
||||
* @return the corresponding internal UUID
|
||||
*/
|
||||
@Nonnull
|
||||
UUID getUUID(@Nonnull UUID external);
|
||||
UUID getUUID(@Nonnull UUID mojangUuid);
|
||||
|
||||
/**
|
||||
* Gets a users external, server assigned or Mojang assigned unique id, from the internal one used within LuckPerms.
|
||||
* Gets a users "external", server assigned unique id, from the internal one used within LuckPerms.
|
||||
*
|
||||
* @param internal the UUID used within LuckPerms, through User#getUuid
|
||||
* @param internalUuid the UUID used within LuckPerms, through <code>User#getUuid</code>
|
||||
* @return the corresponding external UUID
|
||||
*/
|
||||
@Nonnull
|
||||
UUID getExternalUUID(@Nonnull UUID internal);
|
||||
UUID getExternalUUID(@Nonnull UUID internalUuid);
|
||||
|
||||
}
|
||||
@@ -33,8 +33,10 @@ import me.lucko.luckperms.api.metastacking.MetaStackDefinition;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Represents the context for a meta lookup, consisting of a standard {@link Contexts} element, plus options to define how
|
||||
* the meta stack should be constructed.
|
||||
* Represents the context for a meta lookup.
|
||||
*
|
||||
* <p>Consisting of a standard {@link Contexts} element, plus options to define how
|
||||
* the meta stack should be constructed.</p>
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
@@ -56,6 +58,9 @@ public final class MetaContexts {
|
||||
private final MetaStackDefinition prefixStackDefinition;
|
||||
private final MetaStackDefinition suffixStackDefinition;
|
||||
|
||||
// cache hashcode - this class is immutable, and is used as an index in the permission cache.
|
||||
private final int hashCode;
|
||||
|
||||
/**
|
||||
* Creates a new meta contexts instance
|
||||
*
|
||||
@@ -67,6 +72,7 @@ public final class MetaContexts {
|
||||
this.contexts = Preconditions.checkNotNull(contexts, "contexts");
|
||||
this.prefixStackDefinition = Preconditions.checkNotNull(prefixStackDefinition, "prefixStackDefinition");
|
||||
this.suffixStackDefinition = Preconditions.checkNotNull(suffixStackDefinition, "suffixStackDefinition");
|
||||
this.hashCode = calculateHashCode();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@@ -104,8 +110,7 @@ public final class MetaContexts {
|
||||
this.getSuffixStackDefinition().equals(other.getSuffixStackDefinition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
private int calculateHashCode() {
|
||||
final int PRIME = 59;
|
||||
int result = 1;
|
||||
result = result * PRIME + this.getContexts().hashCode();
|
||||
@@ -113,4 +118,9 @@ public final class MetaContexts {
|
||||
result = result * PRIME + this.getSuffixStackDefinition().hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ import javax.annotation.Nonnull;
|
||||
* @param <T> the subject type. Is ALWAYS the player class of the platform.
|
||||
* @since 2.13
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ContextCalculator<T> {
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.api.context;
|
||||
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.User;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Manages {@link ContextCalculator}s, and calculates applicable contexts for a
|
||||
* given type.
|
||||
*
|
||||
* This interface accepts {@link Object} types as a parameter to avoid having to depend
|
||||
* on specific server implementations. In all cases, the "player" or "subject" type for
|
||||
* the platform must be used.
|
||||
*
|
||||
* Specifically, {@code org.bukkit.entity.Player},
|
||||
* {@code net.md_5.bungee.api.connection.ProxiedPlayer} and
|
||||
* {@code org.spongepowered.api.service.permission.Subject}.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public interface ContextManager {
|
||||
|
||||
/**
|
||||
* Queries the ContextManager for current context values for the subject.
|
||||
*
|
||||
* @param subject the subject
|
||||
* @return the applicable context for the subject
|
||||
*/
|
||||
@Nonnull
|
||||
ImmutableContextSet getApplicableContext(@Nonnull Object subject);
|
||||
|
||||
/**
|
||||
* Queries the ContextManager for current context values for the subject.
|
||||
*
|
||||
* @param subject the subject
|
||||
* @return the applicable context for the subject
|
||||
*/
|
||||
@Nonnull
|
||||
Contexts getApplicableContexts(@Nonnull Object subject);
|
||||
|
||||
/**
|
||||
* Queries the ContextManager for current context values for the given User.
|
||||
*
|
||||
* <p>This will only return a value if the player corresponding to the
|
||||
* {@link User} is online.</p>
|
||||
*
|
||||
* <p>If you need to be a {@link Contexts} instance regardless, you should
|
||||
* initially try this method, and then fallback on {@link #getStaticContext()}.</p>
|
||||
*
|
||||
* @param user the user
|
||||
* @return the applicable context for the subject
|
||||
*/
|
||||
@Nonnull
|
||||
Optional<ImmutableContextSet> lookupApplicableContext(@Nonnull User user);
|
||||
|
||||
/**
|
||||
* Queries the ContextManager for current context values for the given User.
|
||||
*
|
||||
* <p>This will only return a value if the player corresponding to the
|
||||
* {@link User} is online.</p>
|
||||
*
|
||||
* <p>If you need to be a {@link Contexts} instance regardless, you should
|
||||
* initially try this method, and then fallback on {@link #getStaticContexts()}.</p>
|
||||
*
|
||||
* @param user the user
|
||||
* @return the applicable context for the subject
|
||||
*/
|
||||
@Nonnull
|
||||
Optional<Contexts> lookupApplicableContexts(@Nonnull User user);
|
||||
|
||||
/**
|
||||
* Gets the contexts from the static calculators in this manager.
|
||||
*
|
||||
* <p>Static calculators provide the same context for all subjects, and are
|
||||
* marked as such when registered.</p>
|
||||
*
|
||||
* @return the current active static contexts
|
||||
*/
|
||||
@Nonnull
|
||||
ImmutableContextSet getStaticContext();
|
||||
|
||||
/**
|
||||
* Gets the contexts from the static calculators in this manager.
|
||||
*
|
||||
* <p>Static calculators provide the same context for all subjects, and are
|
||||
* marked as such when registered.</p>
|
||||
*
|
||||
* @return the current active static contexts
|
||||
*/
|
||||
@Nonnull
|
||||
Contexts getStaticContexts();
|
||||
|
||||
/**
|
||||
* Forms a {@link Contexts} instance from an {@link ImmutableContextSet}.
|
||||
*
|
||||
* <p>This method relies on the plugins configuration to form the
|
||||
* {@link Contexts} instance.</p>
|
||||
*
|
||||
* @param subject the reference subject
|
||||
* @param contextSet the context set
|
||||
* @return a contexts instance
|
||||
*/
|
||||
@Nonnull
|
||||
Contexts formContexts(@Nonnull Object subject, @Nonnull ImmutableContextSet contextSet);
|
||||
|
||||
/**
|
||||
* Forms a {@link Contexts} instance from an {@link ImmutableContextSet}.
|
||||
*
|
||||
* <p>This method relies on the plugins configuration to form the
|
||||
* {@link Contexts} instance.</p>
|
||||
*
|
||||
* @param contextSet the context set
|
||||
* @return a contexts instance
|
||||
*/
|
||||
@Nonnull
|
||||
Contexts formContexts(@Nonnull ImmutableContextSet contextSet);
|
||||
|
||||
/**
|
||||
* Registers a context calculator with the manager.
|
||||
*
|
||||
* @param calculator the calculator
|
||||
*/
|
||||
@Nonnull
|
||||
void registerCalculator(@Nonnull ContextCalculator<?> calculator);
|
||||
|
||||
/**
|
||||
* Registers a static context calculator with the manager.
|
||||
*
|
||||
* <p>Static calculators provide the same context for all subjects.</p>
|
||||
*
|
||||
* @param calculator the calculator
|
||||
*/
|
||||
@Nonnull
|
||||
void registerStaticCalculator(@Nonnull StaticContextCalculator calculator);
|
||||
|
||||
/**
|
||||
* Invalidates the lookup cache for a given subject
|
||||
*
|
||||
* @param subject the subject
|
||||
*/
|
||||
@Nonnull
|
||||
void invalidateCache(@Nonnull Object subject);
|
||||
|
||||
}
|
||||
@@ -35,7 +35,13 @@ import java.util.Set;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Holder of contexts.
|
||||
* A set of context pairs.
|
||||
*
|
||||
* <p>You can think of ContextSets as a wrapped <code>Multimap<String, String></code>.
|
||||
* Each key can be mapped to multiple values.</p>
|
||||
*
|
||||
* <p>Keys are automatically converted to lowercase when added, and are therefore
|
||||
* case-insensitive. Values however are not.</p>
|
||||
*
|
||||
* <p>Implementations may be either mutable or immutable.</p>
|
||||
*
|
||||
@@ -72,18 +78,6 @@ public interface ContextSet {
|
||||
return ImmutableContextSet.of(key1, value1, key2, value2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ImmutableContextSet from an existing map
|
||||
*
|
||||
* @param map the map to copy from
|
||||
* @return a new ImmutableContextSet representing the pairs from the map
|
||||
* @throws NullPointerException if the map is null
|
||||
*/
|
||||
@Nonnull
|
||||
static ImmutableContextSet fromMap(@Nonnull Map<String, String> map) {
|
||||
return ImmutableContextSet.fromMap(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ImmutableContextSet from an existing iterable of Map Entries
|
||||
*
|
||||
@@ -96,6 +90,18 @@ public interface ContextSet {
|
||||
return ImmutableContextSet.fromEntries(iterable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ImmutableContextSet from an existing map
|
||||
*
|
||||
* @param map the map to copy from
|
||||
* @return a new ImmutableContextSet representing the pairs from the map
|
||||
* @throws NullPointerException if the map is null
|
||||
*/
|
||||
@Nonnull
|
||||
static ImmutableContextSet fromMap(@Nonnull Map<String, String> map) {
|
||||
return ImmutableContextSet.fromMap(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ImmutableContextSet from an existing multimap
|
||||
*
|
||||
@@ -133,7 +139,7 @@ public interface ContextSet {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if this set is in an immutable form
|
||||
* Gets if this set is in an immutable form
|
||||
*
|
||||
* @return true if the set is immutable
|
||||
*/
|
||||
@@ -167,12 +173,14 @@ public interface ContextSet {
|
||||
/**
|
||||
* Converts this ContextSet to an immutable {@link Map}
|
||||
*
|
||||
* <b>NOTE: Use of this method may result in data being lost. ContextSets can contain lots of different values for
|
||||
* <b>IMPORTANT: Use of this method may result in data being lost. ContextSets can contain lots of different values for
|
||||
* one key.</b>
|
||||
*
|
||||
* @return an immutable map
|
||||
* @deprecated because the resultant map may not contain all data in the ContextSet
|
||||
*/
|
||||
@Nonnull
|
||||
@Deprecated
|
||||
Map<String, String> toMap();
|
||||
|
||||
/**
|
||||
@@ -225,6 +233,19 @@ public interface ContextSet {
|
||||
*/
|
||||
boolean has(@Nonnull String key, @Nonnull String value);
|
||||
|
||||
/**
|
||||
* Check if thr set contains a given key mapped to a given value
|
||||
*
|
||||
* @param entry the entry to look for
|
||||
* @return true if the set contains the KV pair
|
||||
* @throws NullPointerException if the key or value is null
|
||||
* @since 3.4
|
||||
*/
|
||||
default boolean has(@Nonnull Map.Entry<String, String> entry) {
|
||||
Preconditions.checkNotNull(entry, "entry");
|
||||
return has(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #has(String, String)}, except ignores the case of the value.
|
||||
*
|
||||
@@ -235,6 +256,19 @@ public interface ContextSet {
|
||||
*/
|
||||
boolean hasIgnoreCase(@Nonnull String key, @Nonnull String value);
|
||||
|
||||
/**
|
||||
* Same as {@link #has(Map.Entry)}, except ignores the case of the value.
|
||||
*
|
||||
* @param entry the entry to look for
|
||||
* @return true if the set contains the KV pair
|
||||
* @throws NullPointerException if the key or value is null
|
||||
* @since 3.4
|
||||
*/
|
||||
default boolean hasIgnoreCase(@Nonnull Map.Entry<String, String> entry) {
|
||||
Preconditions.checkNotNull(entry, "entry");
|
||||
return hasIgnoreCase(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if all entries in this context set are also included in another set.
|
||||
*
|
||||
@@ -243,6 +277,18 @@ public interface ContextSet {
|
||||
* @since 3.1
|
||||
*/
|
||||
default boolean isSatisfiedBy(@Nonnull ContextSet other) {
|
||||
return isSatisfiedBy(other, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if all entries in this context set are also included in another set.
|
||||
*
|
||||
* @param other the other set to check
|
||||
* @param caseSensitive if the lookup should be case sensitive. see {@link #has(Map.Entry)} and {@link #hasIgnoreCase(Map.Entry)}.
|
||||
* @return true if all entries in this set are also in the other set
|
||||
* @since 3.4
|
||||
*/
|
||||
default boolean isSatisfiedBy(@Nonnull ContextSet other, boolean caseSensitive) {
|
||||
Preconditions.checkNotNull(other, "other");
|
||||
if (this.isEmpty()) {
|
||||
// this is empty, so is therefore always satisfied.
|
||||
@@ -256,8 +302,14 @@ public interface ContextSet {
|
||||
} else {
|
||||
// neither are empty, we need to compare the individual entries
|
||||
for (Map.Entry<String, String> pair : toSet()) {
|
||||
if (!other.has(pair.getKey(), pair.getValue())) {
|
||||
return false;
|
||||
if (caseSensitive) {
|
||||
if (!other.has(pair)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!other.hasIgnoreCase(pair)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,12 +25,10 @@
|
||||
|
||||
package me.lucko.luckperms.api.context;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSetMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.SetMultimap;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
@@ -38,9 +36,14 @@ import java.util.Set;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* An immutable implementation of {@link ContextSet}.
|
||||
*
|
||||
* <p>On construction, all keys/values are {@link String#intern()}ed, in order to increase
|
||||
* comparison speed.</p>
|
||||
*
|
||||
* @since 2.16
|
||||
*/
|
||||
public final class ImmutableContextSet implements ContextSet {
|
||||
@@ -56,9 +59,10 @@ public final class ImmutableContextSet implements ContextSet {
|
||||
*/
|
||||
@Nonnull
|
||||
public static ImmutableContextSet singleton(@Nonnull String key, @Nonnull String value) {
|
||||
Preconditions.checkNotNull(key, "key");
|
||||
Preconditions.checkNotNull(value, "value");
|
||||
return new ImmutableContextSet(ImmutableSetMultimap.of(key.toLowerCase(), value));
|
||||
return new ImmutableContextSet(ImmutableSetMultimap.of(
|
||||
checkNotNull(key, "key").toLowerCase().intern(),
|
||||
checkNotNull(value, "value").intern()
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,30 +78,12 @@ public final class ImmutableContextSet implements ContextSet {
|
||||
*/
|
||||
@Nonnull
|
||||
public static ImmutableContextSet of(@Nonnull String key1, @Nonnull String value1, @Nonnull String key2, @Nonnull String value2) {
|
||||
Preconditions.checkNotNull(key1, "key1");
|
||||
Preconditions.checkNotNull(value1, "value1");
|
||||
Preconditions.checkNotNull(key2, "key2");
|
||||
Preconditions.checkNotNull(value2, "value2");
|
||||
return new ImmutableContextSet(ImmutableSetMultimap.of(key1.toLowerCase(), value1, key2.toLowerCase(), value2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ImmutableContextSet from an existing map
|
||||
*
|
||||
* @param map the map to copy from
|
||||
* @return a new ImmutableContextSet representing the pairs from the map
|
||||
* @throws NullPointerException if the map is null
|
||||
*/
|
||||
@Nonnull
|
||||
public static ImmutableContextSet fromMap(@Nonnull Map<String, String> map) {
|
||||
Preconditions.checkNotNull(map, "map");
|
||||
|
||||
ImmutableSetMultimap.Builder<String, String> b = ImmutableSetMultimap.builder();
|
||||
for (Map.Entry<String, String> e : map.entrySet()) {
|
||||
b.put(e.getKey().toLowerCase(), e.getValue());
|
||||
}
|
||||
|
||||
return new ImmutableContextSet(b.build());
|
||||
return new ImmutableContextSet(ImmutableSetMultimap.of(
|
||||
checkNotNull(key1, "key1").toLowerCase().intern(),
|
||||
checkNotNull(value1, "value1").intern(),
|
||||
checkNotNull(key2, "key2").toLowerCase().intern(),
|
||||
checkNotNull(value2, "value2").intern()
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,8 +95,26 @@ public final class ImmutableContextSet implements ContextSet {
|
||||
*/
|
||||
@Nonnull
|
||||
public static ImmutableContextSet fromEntries(@Nonnull Iterable<? extends Map.Entry<String, String>> iterable) {
|
||||
Preconditions.checkNotNull(iterable, "iterable");
|
||||
return MutableContextSet.fromEntries(iterable).makeImmutable();
|
||||
checkNotNull(iterable, "iterable");
|
||||
|
||||
ImmutableSetMultimap.Builder<String, String> b = ImmutableSetMultimap.builder();
|
||||
for (Map.Entry<String, String> e : iterable) {
|
||||
b.put(checkNotNull(e.getKey()).toLowerCase().intern(), checkNotNull(e.getValue()).intern());
|
||||
}
|
||||
|
||||
return new ImmutableContextSet(b.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ImmutableContextSet from an existing map
|
||||
*
|
||||
* @param map the map to copy from
|
||||
* @return a new ImmutableContextSet representing the pairs from the map
|
||||
* @throws NullPointerException if the map is null
|
||||
*/
|
||||
@Nonnull
|
||||
public static ImmutableContextSet fromMap(@Nonnull Map<String, String> map) {
|
||||
return fromEntries(checkNotNull(map, "map").entrySet());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,8 +126,7 @@ public final class ImmutableContextSet implements ContextSet {
|
||||
*/
|
||||
@Nonnull
|
||||
public static ImmutableContextSet fromMultimap(@Nonnull Multimap<String, String> multimap) {
|
||||
Preconditions.checkNotNull(multimap, "multimap");
|
||||
return MutableContextSet.fromMultimap(multimap).makeImmutable();
|
||||
return fromEntries(checkNotNull(multimap, "multimap").entries());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,7 +139,7 @@ public final class ImmutableContextSet implements ContextSet {
|
||||
*/
|
||||
@Nonnull
|
||||
public static ImmutableContextSet fromSet(@Nonnull ContextSet contextSet) {
|
||||
return Preconditions.checkNotNull(contextSet, "contextSet").makeImmutable();
|
||||
return checkNotNull(contextSet, "contextSet").makeImmutable();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -149,10 +152,10 @@ public final class ImmutableContextSet implements ContextSet {
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
private final SetMultimap<String, String> map;
|
||||
private final ImmutableSetMultimap<String, String> map;
|
||||
|
||||
ImmutableContextSet(Multimap<String, String> contexts) {
|
||||
this.map = ImmutableSetMultimap.copyOf(contexts);
|
||||
ImmutableContextSet(ImmutableSetMultimap<String, String> contexts) {
|
||||
this.map = contexts;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -176,7 +179,7 @@ public final class ImmutableContextSet implements ContextSet {
|
||||
@Override
|
||||
@Nonnull
|
||||
public Set<Map.Entry<String, String>> toSet() {
|
||||
return ImmutableSet.copyOf(map.entries());
|
||||
return map.entries();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -197,36 +200,35 @@ public final class ImmutableContextSet implements ContextSet {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public boolean containsKey(@Nonnull String key) {
|
||||
Preconditions.checkNotNull(key, "key");
|
||||
return map.containsKey(key);
|
||||
return map.containsKey(checkNotNull(key, "key").toLowerCase().intern());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public Set<String> getValues(@Nonnull String key) {
|
||||
Preconditions.checkNotNull(key, "key");
|
||||
Collection<String> c = map.get(key);
|
||||
return c != null && !c.isEmpty() ? ImmutableSet.copyOf(c) : ImmutableSet.of();
|
||||
Collection<String> values = map.get(checkNotNull(key, "key").toLowerCase().intern());
|
||||
return values != null ? ImmutableSet.copyOf(values) : ImmutableSet.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public boolean has(@Nonnull String key, @Nonnull String value) {
|
||||
Preconditions.checkNotNull(key, "key");
|
||||
Preconditions.checkNotNull(value, "value");
|
||||
return map.containsEntry(key, value);
|
||||
return map.containsEntry(checkNotNull(key, "key").toLowerCase().intern(), checkNotNull(value, "value").intern());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public boolean hasIgnoreCase(@Nonnull String key, @Nonnull String value) {
|
||||
Preconditions.checkNotNull(key, "key");
|
||||
Preconditions.checkNotNull(value, "value");
|
||||
value = checkNotNull(value, "value").intern();
|
||||
Collection<String> values = map.get(checkNotNull(key, "key").toLowerCase().intern());
|
||||
|
||||
Collection<String> c = map.get(key);
|
||||
if (c == null || c.isEmpty()) {
|
||||
if (values == null || values.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (String val : c) {
|
||||
for (String val : values) {
|
||||
if (val.equalsIgnoreCase(value)) {
|
||||
return true;
|
||||
}
|
||||
@@ -250,6 +252,11 @@ public final class ImmutableContextSet implements ContextSet {
|
||||
if (!(o instanceof ContextSet)) return false;
|
||||
final ContextSet other = (ContextSet) o;
|
||||
|
||||
// saves on copying the multimap
|
||||
if (other instanceof MutableContextSet) {
|
||||
return other.equals(this);
|
||||
}
|
||||
|
||||
final Multimap<String, String> thisContexts = this.toMultimap();
|
||||
final Multimap<String, String> otherContexts = other.toMultimap();
|
||||
return thisContexts.equals(otherContexts);
|
||||
@@ -257,7 +264,7 @@ public final class ImmutableContextSet implements ContextSet {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 59 + (this.map == null ? 43 : this.map.hashCode());
|
||||
return map.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -40,9 +40,14 @@ import java.util.Set;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* A mutable implementation of {@link ContextSet}.
|
||||
*
|
||||
* <p>On construction, all keys/values are {@link String#intern()}ed, in order to increase
|
||||
* comparison speed.</p>
|
||||
*
|
||||
* @since 2.16
|
||||
*/
|
||||
public final class MutableContextSet implements ContextSet {
|
||||
@@ -57,9 +62,9 @@ public final class MutableContextSet implements ContextSet {
|
||||
*/
|
||||
@Nonnull
|
||||
public static MutableContextSet singleton(@Nonnull String key, @Nonnull String value) {
|
||||
Preconditions.checkNotNull(key, "key");
|
||||
Preconditions.checkNotNull(value, "value");
|
||||
MutableContextSet set = new MutableContextSet();
|
||||
checkNotNull(key, "key");
|
||||
checkNotNull(value, "value");
|
||||
MutableContextSet set = MutableContextSet.create();
|
||||
set.add(key, value);
|
||||
return set;
|
||||
}
|
||||
@@ -77,27 +82,13 @@ public final class MutableContextSet implements ContextSet {
|
||||
*/
|
||||
@Nonnull
|
||||
public static MutableContextSet of(@Nonnull String key1, @Nonnull String value1, @Nonnull String key2, @Nonnull String value2) {
|
||||
Preconditions.checkNotNull(key1, "key1");
|
||||
Preconditions.checkNotNull(value1, "value1");
|
||||
Preconditions.checkNotNull(key2, "key2");
|
||||
Preconditions.checkNotNull(value2, "value2");
|
||||
MutableContextSet ret = singleton(key1, value1);
|
||||
ret.add(key2, value2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a MutableContextSet from an existing map
|
||||
*
|
||||
* @param map the map to copy from
|
||||
* @return a new MutableContextSet representing the pairs from the map
|
||||
* @throws NullPointerException if the map is null
|
||||
*/
|
||||
@Nonnull
|
||||
public static MutableContextSet fromMap(@Nonnull Map<String, String> map) {
|
||||
Preconditions.checkNotNull(map, "map");
|
||||
MutableContextSet set = new MutableContextSet();
|
||||
set.addAll(map);
|
||||
checkNotNull(key1, "key1");
|
||||
checkNotNull(value1, "value1");
|
||||
checkNotNull(key2, "key2");
|
||||
checkNotNull(value2, "value2");
|
||||
MutableContextSet set = MutableContextSet.create();
|
||||
set.add(key1, value1);
|
||||
set.add(key2, value2);
|
||||
return set;
|
||||
}
|
||||
|
||||
@@ -110,12 +101,27 @@ public final class MutableContextSet implements ContextSet {
|
||||
*/
|
||||
@Nonnull
|
||||
public static MutableContextSet fromEntries(@Nonnull Iterable<? extends Map.Entry<String, String>> iterable) {
|
||||
Preconditions.checkNotNull(iterable, "iterable");
|
||||
MutableContextSet set = new MutableContextSet();
|
||||
checkNotNull(iterable, "iterable");
|
||||
MutableContextSet set = MutableContextSet.create();
|
||||
set.addAll(iterable);
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a MutableContextSet from an existing map
|
||||
*
|
||||
* @param map the map to copy from
|
||||
* @return a new MutableContextSet representing the pairs from the map
|
||||
* @throws NullPointerException if the map is null
|
||||
*/
|
||||
@Nonnull
|
||||
public static MutableContextSet fromMap(@Nonnull Map<String, String> map) {
|
||||
checkNotNull(map, "map");
|
||||
MutableContextSet set = MutableContextSet.create();
|
||||
set.addAll(map);
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a MutableContextSet from an existing multimap
|
||||
*
|
||||
@@ -125,8 +131,10 @@ public final class MutableContextSet implements ContextSet {
|
||||
*/
|
||||
@Nonnull
|
||||
public static MutableContextSet fromMultimap(@Nonnull Multimap<String, String> multimap) {
|
||||
Preconditions.checkNotNull(multimap, "multimap");
|
||||
return fromEntries(multimap.entries());
|
||||
checkNotNull(multimap, "multimap");
|
||||
MutableContextSet set = MutableContextSet.create();
|
||||
set.addAll(multimap);
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -161,8 +169,8 @@ public final class MutableContextSet implements ContextSet {
|
||||
this.map = Multimaps.synchronizedSetMultimap(HashMultimap.create());
|
||||
}
|
||||
|
||||
private MutableContextSet(Multimap<String, String> contexts) {
|
||||
this.map = Multimaps.synchronizedSetMultimap(HashMultimap.create(contexts));
|
||||
private MutableContextSet(MutableContextSet other) {
|
||||
this.map = Multimaps.synchronizedSetMultimap(HashMultimap.create(other.map));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -170,21 +178,25 @@ public final class MutableContextSet implements ContextSet {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ImmutableContextSet makeImmutable() {
|
||||
return new ImmutableContextSet(map);
|
||||
return new ImmutableContextSet(ImmutableSetMultimap.copyOf(map));
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public MutableContextSet mutableCopy() {
|
||||
return new MutableContextSet(map);
|
||||
return new MutableContextSet(this);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Set<Map.Entry<String, String>> toSet() {
|
||||
return ImmutableSet.copyOf(map.entries());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Map<String, String> toMap() {
|
||||
ImmutableMap.Builder<String, String> m = ImmutableMap.builder();
|
||||
@@ -195,57 +207,42 @@ public final class MutableContextSet implements ContextSet {
|
||||
return m.build();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Multimap<String, String> toMultimap() {
|
||||
return ImmutableSetMultimap.copyOf(map);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public boolean containsKey(String key) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("key");
|
||||
}
|
||||
|
||||
return map.containsKey(key);
|
||||
public boolean containsKey(@Nonnull String key) {
|
||||
return map.containsKey(checkNotNull(key, "key").toLowerCase().intern());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Set<String> getValues(String key) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("key");
|
||||
}
|
||||
|
||||
Collection<String> c = map.get(key);
|
||||
return c != null && !c.isEmpty() ? ImmutableSet.copyOf(c) : ImmutableSet.of();
|
||||
public Set<String> getValues(@Nonnull String key) {
|
||||
Collection<String> values = map.get(checkNotNull(key, "key").toLowerCase().intern());
|
||||
return values != null ? ImmutableSet.copyOf(values) : ImmutableSet.of();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public boolean has(String key, String value) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("key");
|
||||
}
|
||||
if (value == null) {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
|
||||
return map.containsEntry(key, value);
|
||||
public boolean has(@Nonnull String key, @Nonnull String value) {
|
||||
return map.containsEntry(checkNotNull(key, "key").toLowerCase().intern(), checkNotNull(value, "value").intern());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public boolean hasIgnoreCase(String key, String value) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("key");
|
||||
}
|
||||
if (value == null) {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
public boolean hasIgnoreCase(@Nonnull String key, @Nonnull String value) {
|
||||
value = checkNotNull(value, "value").intern();
|
||||
Collection<String> values = map.get(checkNotNull(key, "key").toLowerCase().intern());
|
||||
|
||||
Collection<String> c = map.get(key);
|
||||
if (c == null || c.isEmpty()) {
|
||||
if (values == null || values.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (String val : c) {
|
||||
for (String val : values) {
|
||||
if (val.equalsIgnoreCase(value)) {
|
||||
return true;
|
||||
}
|
||||
@@ -270,15 +267,8 @@ public final class MutableContextSet implements ContextSet {
|
||||
* @param value the value to add
|
||||
* @throws NullPointerException if the key or value is null
|
||||
*/
|
||||
public void add(String key, String value) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("key");
|
||||
}
|
||||
if (value == null) {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
|
||||
map.put(key.toLowerCase(), value);
|
||||
public void add(@Nonnull String key, @Nonnull String value) {
|
||||
map.put(checkNotNull(key, "key").toLowerCase().intern(), checkNotNull(value, "value").intern());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -287,12 +277,9 @@ public final class MutableContextSet implements ContextSet {
|
||||
* @param entry the entry to add
|
||||
* @throws NullPointerException if the entry is null
|
||||
*/
|
||||
public void add(Map.Entry<String, String> entry) {
|
||||
if (entry == null) {
|
||||
throw new NullPointerException("context");
|
||||
}
|
||||
|
||||
map.put(entry.getKey().toLowerCase(), entry.getValue());
|
||||
public void add(@Nonnull Map.Entry<String, String> entry) {
|
||||
checkNotNull(entry, "entry");
|
||||
add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -301,13 +288,9 @@ public final class MutableContextSet implements ContextSet {
|
||||
* @param iterable an iterable of key value context pairs
|
||||
* @throws NullPointerException if iterable is null
|
||||
*/
|
||||
public void addAll(Iterable<? extends Map.Entry<String, String>> iterable) {
|
||||
if (iterable == null) {
|
||||
throw new NullPointerException("iterable");
|
||||
}
|
||||
|
||||
for (Map.Entry<String, String> e : iterable) {
|
||||
this.map.put(e.getKey().toLowerCase(), e.getValue());
|
||||
public void addAll(@Nonnull Iterable<? extends Map.Entry<String, String>> iterable) {
|
||||
for (Map.Entry<String, String> e : checkNotNull(iterable, "iterable")) {
|
||||
add(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,11 +300,19 @@ public final class MutableContextSet implements ContextSet {
|
||||
* @param map the map to add from
|
||||
* @throws NullPointerException if the map is null
|
||||
*/
|
||||
public void addAll(Map<String, String> map) {
|
||||
if (map == null) {
|
||||
throw new NullPointerException("map");
|
||||
}
|
||||
addAll(map.entrySet());
|
||||
public void addAll(@Nonnull Map<String, String> map) {
|
||||
addAll(checkNotNull(map, "map").entrySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the entries of a multimap to the set
|
||||
*
|
||||
* @param multimap the multimap to add from
|
||||
* @throws NullPointerException if the map is null
|
||||
* @since 3.4
|
||||
*/
|
||||
public void addAll(@Nonnull Multimap<String, String> multimap) {
|
||||
addAll(checkNotNull(multimap, "multimap").entries());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -330,12 +321,14 @@ public final class MutableContextSet implements ContextSet {
|
||||
* @param contextSet the set to add from
|
||||
* @throws NullPointerException if the contextSet is null
|
||||
*/
|
||||
public void addAll(ContextSet contextSet) {
|
||||
if (contextSet == null) {
|
||||
throw new NullPointerException("contextSet");
|
||||
public void addAll(@Nonnull ContextSet contextSet) {
|
||||
checkNotNull(contextSet, "contextSet");
|
||||
if (contextSet instanceof MutableContextSet) {
|
||||
MutableContextSet other = ((MutableContextSet) contextSet);
|
||||
this.map.putAll(other.map);
|
||||
} else {
|
||||
addAll(contextSet.toMultimap());
|
||||
}
|
||||
|
||||
this.map.putAll(contextSet.toMultimap());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -345,15 +338,12 @@ public final class MutableContextSet implements ContextSet {
|
||||
* @param value the value to remove (case sensitive)
|
||||
* @throws NullPointerException if the key or value is null
|
||||
*/
|
||||
public void remove(String key, String value) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("key");
|
||||
}
|
||||
if (value == null) {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
public void remove(@Nonnull String key, @Nonnull String value) {
|
||||
String k = checkNotNull(key, "key").toLowerCase().intern();
|
||||
String v = checkNotNull(value, "value").intern();
|
||||
|
||||
map.entries().removeIf(entry -> entry.getKey().equals(key) && entry.getValue().equals(value));
|
||||
//noinspection StringEquality
|
||||
map.entries().removeIf(entry -> entry.getKey() == k && entry.getValue() == v);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -363,15 +353,12 @@ public final class MutableContextSet implements ContextSet {
|
||||
* @param value the value to remove
|
||||
* @throws NullPointerException if the key or value is null
|
||||
*/
|
||||
public void removeIgnoreCase(String key, String value) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("key");
|
||||
}
|
||||
if (value == null) {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
public void removeIgnoreCase(@Nonnull String key, @Nonnull String value) {
|
||||
String k = checkNotNull(key, "key").toLowerCase().intern();
|
||||
String v = checkNotNull(value, "value").intern();
|
||||
|
||||
map.entries().removeIf(e -> e.getKey().equalsIgnoreCase(key) && e.getValue().equalsIgnoreCase(value));
|
||||
//noinspection StringEquality
|
||||
map.entries().removeIf(e -> e.getKey() == k && e.getValue().equalsIgnoreCase(v));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -380,12 +367,8 @@ public final class MutableContextSet implements ContextSet {
|
||||
* @param key the key to remove
|
||||
* @throws NullPointerException if the key is null
|
||||
*/
|
||||
public void removeAll(String key) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("key");
|
||||
}
|
||||
|
||||
map.removeAll(key.toLowerCase());
|
||||
public void removeAll(@Nonnull String key) {
|
||||
map.removeAll(checkNotNull(key, "key").toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -401,14 +384,20 @@ public final class MutableContextSet implements ContextSet {
|
||||
if (!(o instanceof ContextSet)) return false;
|
||||
final ContextSet other = (ContextSet) o;
|
||||
|
||||
final Multimap<String, String> thisContexts = this.toMultimap();
|
||||
final Multimap<String, String> otherContexts = other.toMultimap();
|
||||
return thisContexts == null ? otherContexts == null : thisContexts.equals(otherContexts);
|
||||
final Multimap<String, String> otherContexts;
|
||||
|
||||
if (other instanceof MutableContextSet) {
|
||||
otherContexts = ((MutableContextSet) other).map;
|
||||
} else {
|
||||
otherContexts = other.toMultimap();
|
||||
}
|
||||
|
||||
return this.map.equals(otherContexts);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 59 + (this.map == null ? 43 : this.map.hashCode());
|
||||
return map.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.api.context;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Extension of {@link ContextCalculator} which provides the same context
|
||||
* regardless of the subject.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface StaticContextCalculator extends ContextCalculator<Object> {
|
||||
|
||||
/**
|
||||
* Adds this calculators context to the given accumulator.
|
||||
*
|
||||
* @param accumulator a map of contexts to add to
|
||||
* @return the map
|
||||
*/
|
||||
@Nonnull
|
||||
MutableContextSet giveApplicableContext(@Nonnull MutableContextSet accumulator);
|
||||
|
||||
/**
|
||||
* Gives the subject all of the applicable contexts they meet
|
||||
*
|
||||
* @param subject the subject to add contexts to
|
||||
* @param accumulator a map of contexts to add to
|
||||
* @return the map
|
||||
*/
|
||||
@Nonnull
|
||||
@Override
|
||||
@Deprecated
|
||||
default MutableContextSet giveApplicableContext(@Nullable Object subject, @Nonnull MutableContextSet accumulator) {
|
||||
return giveApplicableContext(accumulator);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -44,4 +44,31 @@ public interface LogBroadcastEvent extends LuckPermsEvent, Cancellable {
|
||||
@Nonnull
|
||||
LogEntry getEntry();
|
||||
|
||||
/**
|
||||
* Gets where the log entry originated from.
|
||||
*
|
||||
* @return the origin of the log
|
||||
* @since 3.3
|
||||
*/
|
||||
@Nonnull
|
||||
Origin getOrigin();
|
||||
|
||||
/**
|
||||
* Represents where a log entry is from
|
||||
*
|
||||
* @since 3.3
|
||||
*/
|
||||
enum Origin {
|
||||
|
||||
/**
|
||||
* Represents a log entry which originated from the current server instance
|
||||
*/
|
||||
LOCAL,
|
||||
|
||||
/**
|
||||
* Represents a log entry which was sent to this server via the messaging service
|
||||
*/
|
||||
REMOTE
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.api.event.log;
|
||||
|
||||
import me.lucko.luckperms.api.LogEntry;
|
||||
import me.lucko.luckperms.api.event.Cancellable;
|
||||
import me.lucko.luckperms.api.event.LuckPermsEvent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Called when a log is about to be published to the network via the MessagingService
|
||||
*
|
||||
* @since 3.3
|
||||
*/
|
||||
public interface LogNetworkPublishEvent extends LuckPermsEvent, Cancellable {
|
||||
|
||||
/**
|
||||
* Gets the ID of the log entry being published
|
||||
*
|
||||
* @return the id of the log entry being published
|
||||
*/
|
||||
@Nonnull
|
||||
UUID getLogId();
|
||||
|
||||
/**
|
||||
* Gets the log entry to be published
|
||||
*
|
||||
* @return the log entry to be published
|
||||
*/
|
||||
@Nonnull
|
||||
LogEntry getEntry();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.api.event.log;
|
||||
|
||||
import me.lucko.luckperms.api.LogEntry;
|
||||
import me.lucko.luckperms.api.event.LuckPermsEvent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Called when a log entry is received via the MessagingService
|
||||
*
|
||||
* @since 3.3
|
||||
*/
|
||||
public interface LogReceiveEvent extends LuckPermsEvent {
|
||||
|
||||
/**
|
||||
* Gets the ID of the log entry being received
|
||||
*
|
||||
* @return the id of the log entry being received
|
||||
*/
|
||||
@Nonnull
|
||||
UUID getLogId();
|
||||
|
||||
/**
|
||||
* Gets the log entry being received
|
||||
*
|
||||
* @return the log entry being received
|
||||
*/
|
||||
@Nonnull
|
||||
LogEntry getEntry();
|
||||
|
||||
}
|
||||
@@ -33,7 +33,7 @@ import java.util.UUID;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Called before a network sync task runs
|
||||
* Called before a received network sync task runs
|
||||
*/
|
||||
public interface PreNetworkSyncEvent extends LuckPermsEvent, Cancellable {
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.api.event.user;
|
||||
|
||||
import me.lucko.luckperms.api.User;
|
||||
import me.lucko.luckperms.api.event.LuckPermsEvent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Called when LuckPerms has finished processing a certain Player's connection.
|
||||
*
|
||||
* <p>This event will always execute during the platforms async login/auth event.
|
||||
* All handlers will be called instantly.</p>
|
||||
*
|
||||
* <p>This, among other things, allows you to wait until permission data is loaded
|
||||
* for a User during the BungeeCord 'LoginEvent', as event priorities are ignored
|
||||
* by the current implementation.</p>
|
||||
*
|
||||
* @since 3.4
|
||||
*/
|
||||
public interface UserLoginProcessEvent extends LuckPermsEvent {
|
||||
|
||||
/**
|
||||
* Gets the UUID of the connection which was processed
|
||||
*
|
||||
* @return the uuid of the connection which was processed
|
||||
*/
|
||||
@Nonnull
|
||||
UUID getUuid();
|
||||
|
||||
/**
|
||||
* Gets the username of the connection which was processed
|
||||
*
|
||||
* @return the username of the connection which was processed
|
||||
*/
|
||||
@Nonnull
|
||||
String getUsername();
|
||||
|
||||
/**
|
||||
* Gets the resultant User instance which was loaded.
|
||||
*
|
||||
* @return the user instance
|
||||
*/
|
||||
User getUser();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.api.manager;
|
||||
|
||||
import me.lucko.luckperms.api.Group;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Represents the object responsible for managing {@link Group} instances.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public interface GroupManager {
|
||||
|
||||
/**
|
||||
* Gets a wrapped group object from the group storage
|
||||
*
|
||||
* @param name the name of the group to get
|
||||
* @return a {@link Group} object, if one matching the name exists, or null if not
|
||||
* @throws NullPointerException if the name is null
|
||||
*/
|
||||
@Nullable
|
||||
Group getGroup(@Nonnull String name);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @throws NullPointerException if the name is null
|
||||
*/
|
||||
@Nonnull
|
||||
default Optional<Group> getGroupOpt(@Nonnull String name) {
|
||||
return Optional.ofNullable(getGroup(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a set of all loaded groups.
|
||||
*
|
||||
* @return a {@link Set} of {@link Group} objects
|
||||
*/
|
||||
@Nonnull
|
||||
Set<Group> getLoadedGroups();
|
||||
|
||||
/**
|
||||
* Check if a group is loaded in memory
|
||||
*
|
||||
* @param name the name to check for
|
||||
* @return true if the group is loaded
|
||||
* @throws NullPointerException if the name is null
|
||||
*/
|
||||
boolean isLoaded(@Nonnull String name);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.api.manager;
|
||||
|
||||
import me.lucko.luckperms.api.Track;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Represents the object responsible for managing {@link Track} instances.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public interface TrackManager {
|
||||
|
||||
/**
|
||||
* Gets a wrapped track object from the track storage
|
||||
*
|
||||
* @param name the name of the track to get
|
||||
* @return a {@link Track} object, if one matching the name exists, or null if not
|
||||
* @throws NullPointerException if the name is null
|
||||
*/
|
||||
@Nullable
|
||||
Track getTrack(@Nonnull String name);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @throws NullPointerException if the name is null
|
||||
*/
|
||||
@Nonnull
|
||||
default Optional<Track> getTrackOpt(@Nonnull String name) {
|
||||
return Optional.ofNullable(getTrack(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a set of all loaded tracks.
|
||||
*
|
||||
* @return a {@link Set} of {@link Track} objects
|
||||
*/
|
||||
@Nonnull
|
||||
Set<Track> getLoadedTracks();
|
||||
|
||||
/**
|
||||
* Check if a track is loaded in memory
|
||||
*
|
||||
* @param name the name to check for
|
||||
* @return true if the track is loaded
|
||||
* @throws NullPointerException if the name is null
|
||||
*/
|
||||
boolean isLoaded(@Nonnull String name);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.api.manager;
|
||||
|
||||
import me.lucko.luckperms.api.User;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Represents the object responsible for managing {@link User} instances.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public interface UserManager {
|
||||
|
||||
/**
|
||||
* Gets a wrapped user object from the user storage
|
||||
*
|
||||
* @param uuid the uuid of the user to get
|
||||
* @return a {@link User} object, if one matching the uuid is loaded, or null if not
|
||||
* @throws NullPointerException if the uuid is null
|
||||
*/
|
||||
@Nullable
|
||||
User getUser(@Nonnull UUID uuid);
|
||||
|
||||
/**
|
||||
* Gets a wrapped user object from the user storage.
|
||||
*
|
||||
* @param uuid the uuid of the user to get
|
||||
* @return an optional {@link User} object
|
||||
* @throws NullPointerException if the uuid is null
|
||||
*/
|
||||
@Nonnull
|
||||
default Optional<User> getUserOpt(@Nonnull UUID uuid) {
|
||||
return Optional.ofNullable(getUser(uuid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a wrapped user object from the user storage
|
||||
*
|
||||
* @param name the username of the user to get
|
||||
* @return a {@link User} object, if one matching the uuid is loaded, or null if not
|
||||
* @throws NullPointerException if the name is null
|
||||
*/
|
||||
@Nullable
|
||||
User getUser(@Nonnull String name);
|
||||
|
||||
/**
|
||||
* Gets a wrapped user object from the user storage.
|
||||
*
|
||||
* @param name the username of the user to get
|
||||
* @return an optional {@link User} object
|
||||
* @throws NullPointerException if the name is null
|
||||
*/
|
||||
@Nonnull
|
||||
default Optional<User> getUserOpt(@Nonnull String name) {
|
||||
return Optional.ofNullable(getUser(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a set of all loaded users.
|
||||
*
|
||||
* @return a {@link Set} of {@link User} objects
|
||||
*/
|
||||
@Nonnull
|
||||
Set<User> getLoadedUsers();
|
||||
|
||||
/**
|
||||
* Check if a user is loaded in memory
|
||||
*
|
||||
* @param uuid the uuid to check for
|
||||
* @return true if the user is loaded
|
||||
* @throws NullPointerException if the uuid is null
|
||||
*/
|
||||
boolean isLoaded(@Nonnull UUID uuid);
|
||||
|
||||
/**
|
||||
* Unload a user from the internal storage, if they're not currently online.
|
||||
*
|
||||
* @param user the user to unload
|
||||
* @throws NullPointerException if the user is null
|
||||
*/
|
||||
void cleanupUser(@Nonnull User user);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.api.platform;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Provides information about the platform LuckPerms is running on.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public interface PlatformInfo {
|
||||
|
||||
/**
|
||||
* Gets the plugin version
|
||||
*
|
||||
* @return the version of the plugin running on the platform
|
||||
*/
|
||||
@Nonnull
|
||||
String getVersion();
|
||||
|
||||
/**
|
||||
* Gets the API version
|
||||
*
|
||||
* @return the version of the API running on the platform
|
||||
*/
|
||||
double getApiVersion();
|
||||
|
||||
/**
|
||||
* Gets the type of platform LuckPerms is running on
|
||||
*
|
||||
* @return the type of platform LuckPerms is running on
|
||||
*/
|
||||
@Nonnull
|
||||
PlatformType getType();
|
||||
|
||||
/**
|
||||
* Gets the unique players which have connected to the server since it started.
|
||||
*
|
||||
* @return the unique connections
|
||||
*/
|
||||
@Nonnull
|
||||
Set<UUID> getUniqueConnections();
|
||||
|
||||
/**
|
||||
* Gets the time when the plugin first started in milliseconds.
|
||||
*
|
||||
* @return the enable time
|
||||
*/
|
||||
long getStartTime();
|
||||
|
||||
}
|
||||
+7
-2
@@ -23,12 +23,12 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.api;
|
||||
package me.lucko.luckperms.api.platform;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* The platforms which LuckPerms can run on
|
||||
* Represents a type of platform which LuckPerms can run on.
|
||||
*
|
||||
* @since 2.7
|
||||
*/
|
||||
@@ -44,6 +44,11 @@ public enum PlatformType {
|
||||
this.friendlyName = friendlyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a readable name for the platform type.
|
||||
*
|
||||
* @return a readable name
|
||||
*/
|
||||
@Nonnull
|
||||
public String getFriendlyName() {
|
||||
return friendlyName;
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>luckperms</artifactId>
|
||||
<groupId>me.lucko.luckperms</groupId>
|
||||
<version>3.3-SNAPSHOT</version>
|
||||
<version>4.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>luckperms</artifactId>
|
||||
<groupId>me.lucko.luckperms</groupId>
|
||||
<version>3.3-SNAPSHOT</version>
|
||||
<version>4.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
+14
-9
@@ -29,6 +29,7 @@ import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Splitter;
|
||||
|
||||
import me.lucko.luckperms.common.commands.CommandManager;
|
||||
import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.commands.utils.Util;
|
||||
|
||||
import org.bukkit.command.Command;
|
||||
@@ -36,29 +37,33 @@ import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabExecutor;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class BukkitCommand extends CommandManager implements CommandExecutor, TabExecutor {
|
||||
public class BukkitCommandExecutor extends CommandManager implements CommandExecutor, TabExecutor {
|
||||
private static final Splitter ARGUMENT_SPLITTER = Splitter.on(COMMAND_SEPARATOR_PATTERN).omitEmptyStrings();
|
||||
private static final Joiner ARGUMENT_JOINER = Joiner.on(' ');
|
||||
|
||||
private final LPBukkitPlugin plugin;
|
||||
|
||||
BukkitCommand(LPBukkitPlugin plugin) {
|
||||
BukkitCommandExecutor(LPBukkitPlugin plugin) {
|
||||
super(plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
onCommand(
|
||||
plugin.getSenderFactory().wrap(sender),
|
||||
label,
|
||||
Util.stripQuotes(Splitter.on(COMMAND_SEPARATOR_PATTERN).omitEmptyStrings().splitToList(Joiner.on(' ').join(args)))
|
||||
);
|
||||
Sender lpSender = plugin.getSenderFactory().wrap(sender);
|
||||
List<String> arguments = Util.stripQuotes(ARGUMENT_SPLITTER.splitToList(ARGUMENT_JOINER.join(args)));
|
||||
|
||||
onCommand(lpSender, label, arguments);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> onTabComplete(CommandSender sender, Command command, String label, String[] args) {
|
||||
return onTabComplete(plugin.getSenderFactory().wrap(sender), Arrays.asList(args));
|
||||
Sender lpSender = plugin.getSenderFactory().wrap(sender);
|
||||
List<String> arguments = Util.stripQuotes(ARGUMENT_SPLITTER.splitToList(ARGUMENT_JOINER.join(args)));
|
||||
|
||||
return onTabComplete(lpSender, arguments);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -28,7 +28,7 @@ package me.lucko.luckperms.bukkit;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import me.lucko.luckperms.common.config.AbstractConfiguration;
|
||||
import me.lucko.luckperms.common.config.ConfigurationAdapter;
|
||||
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
@@ -41,7 +41,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class BukkitConfig extends AbstractConfiguration {
|
||||
public class BukkitConfigAdapter implements ConfigurationAdapter {
|
||||
|
||||
@Getter
|
||||
private final LPBukkitPlugin plugin;
|
||||
+24
-22
@@ -27,8 +27,9 @@ package me.lucko.luckperms.bukkit;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsScheduler;
|
||||
import me.lucko.luckperms.common.plugin.SchedulerAdapter;
|
||||
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
@@ -39,37 +40,38 @@ import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class LPBukkitScheduler implements LuckPermsScheduler {
|
||||
public class BukkitSchedulerAdapter implements SchedulerAdapter {
|
||||
private final LPBukkitPlugin plugin;
|
||||
|
||||
@Getter
|
||||
private ExecutorService asyncLpExecutor;
|
||||
@Accessors(fluent = true)
|
||||
private ExecutorService asyncLp;
|
||||
|
||||
@Getter
|
||||
private Executor asyncBukkitExecutor;
|
||||
private Executor syncExecutor;
|
||||
@Accessors(fluent = true)
|
||||
private Executor asyncBukkit;
|
||||
|
||||
@Getter
|
||||
@Accessors(fluent = true)
|
||||
private Executor sync;
|
||||
|
||||
@Getter
|
||||
@Accessors(fluent = true)
|
||||
private Executor async;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean useBukkitAsync = false;
|
||||
|
||||
private Set<BukkitTask> tasks = ConcurrentHashMap.newKeySet();
|
||||
private final Set<BukkitTask> tasks = ConcurrentHashMap.newKeySet();
|
||||
|
||||
public LPBukkitScheduler(LPBukkitPlugin plugin) {
|
||||
public BukkitSchedulerAdapter(LPBukkitPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
|
||||
this.asyncLpExecutor = Executors.newCachedThreadPool();
|
||||
this.asyncBukkitExecutor = r -> plugin.getServer().getScheduler().runTaskAsynchronously(plugin, r);
|
||||
this.syncExecutor = r -> plugin.getServer().getScheduler().runTask(plugin, r);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor async() {
|
||||
return useBukkitAsync ? asyncBukkitExecutor : asyncLpExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor sync() {
|
||||
return syncExecutor;
|
||||
this.asyncLp = Executors.newCachedThreadPool();
|
||||
this.asyncBukkit = r -> plugin.getServer().getScheduler().runTaskAsynchronously(plugin, r);
|
||||
this.sync = r -> plugin.getServer().getScheduler().runTask(plugin, r);
|
||||
this.async = r -> (useBukkitAsync ? asyncBukkit : asyncLp).execute(r);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -108,9 +110,9 @@ public class LPBukkitScheduler implements LuckPermsScheduler {
|
||||
public void shutdown() {
|
||||
tasks.forEach(BukkitTask::cancel);
|
||||
// wait for executor
|
||||
asyncLpExecutor.shutdown();
|
||||
asyncLp.shutdown();
|
||||
try {
|
||||
asyncLpExecutor.awaitTermination(30, TimeUnit.SECONDS);
|
||||
asyncLp.awaitTermination(30, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
package me.lucko.luckperms.bukkit;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.bukkit.compat.MessageHandler;
|
||||
import me.lucko.luckperms.common.commands.sender.SenderFactory;
|
||||
@@ -68,7 +70,7 @@ public class BukkitSenderFactory extends SenderFactory<CommandSender> {
|
||||
|
||||
// send sync if command block
|
||||
if (sender instanceof BlockCommandSender) {
|
||||
getPlugin().getScheduler().doSync(() -> sender.sendMessage(s));
|
||||
getPlugin().getScheduler().doSync(new BlockMessageAgent(((BlockCommandSender) sender), s));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -92,4 +94,16 @@ public class BukkitSenderFactory extends SenderFactory<CommandSender> {
|
||||
protected boolean hasPermission(CommandSender sender, String node) {
|
||||
return sender.hasPermission(node);
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
private static final class BlockMessageAgent implements Runnable {
|
||||
private final BlockCommandSender block;
|
||||
private final String message;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
block.sendMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -28,27 +28,30 @@ package me.lucko.luckperms.bukkit;
|
||||
import lombok.Getter;
|
||||
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.Logger;
|
||||
import me.lucko.luckperms.api.LuckPermsApi;
|
||||
import me.lucko.luckperms.api.PlatformType;
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.api.platform.PlatformType;
|
||||
import me.lucko.luckperms.bukkit.calculators.BukkitCalculatorFactory;
|
||||
import me.lucko.luckperms.bukkit.contexts.BukkitContextManager;
|
||||
import me.lucko.luckperms.bukkit.contexts.WorldCalculator;
|
||||
import me.lucko.luckperms.bukkit.messaging.BungeeMessagingService;
|
||||
import me.lucko.luckperms.bukkit.messaging.LilyPadMessagingService;
|
||||
import me.lucko.luckperms.bukkit.listeners.BukkitConnectionListener;
|
||||
import me.lucko.luckperms.bukkit.listeners.BukkitPlatformListener;
|
||||
import me.lucko.luckperms.bukkit.messaging.BukkitMessagingFactory;
|
||||
import me.lucko.luckperms.bukkit.model.Injector;
|
||||
import me.lucko.luckperms.bukkit.model.LPPermissible;
|
||||
import me.lucko.luckperms.bukkit.model.SubscriptionMapInjector;
|
||||
import me.lucko.luckperms.bukkit.processors.BukkitProcessorsSetupTask;
|
||||
import me.lucko.luckperms.bukkit.processors.ChildPermissionProvider;
|
||||
import me.lucko.luckperms.bukkit.processors.DefaultsProvider;
|
||||
import me.lucko.luckperms.bukkit.vault.VaultHookManager;
|
||||
import me.lucko.luckperms.common.api.ApiHandler;
|
||||
import me.lucko.luckperms.common.actionlog.LogDispatcher;
|
||||
import me.lucko.luckperms.common.api.ApiProvider;
|
||||
import me.lucko.luckperms.common.api.ApiSingletonUtils;
|
||||
import me.lucko.luckperms.common.buffers.BufferedRequest;
|
||||
import me.lucko.luckperms.common.buffers.UpdateTaskBuffer;
|
||||
import me.lucko.luckperms.common.caching.handlers.CachedStateManager;
|
||||
import me.lucko.luckperms.common.calculators.CalculatorFactory;
|
||||
import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.config.AbstractConfiguration;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.config.LuckPermsConfiguration;
|
||||
import me.lucko.luckperms.common.constants.CommandPermission;
|
||||
@@ -59,6 +62,7 @@ import me.lucko.luckperms.common.dependencies.DependencyManager;
|
||||
import me.lucko.luckperms.common.locale.LocaleManager;
|
||||
import me.lucko.luckperms.common.locale.NoopLocaleManager;
|
||||
import me.lucko.luckperms.common.locale.SimpleLocaleManager;
|
||||
import me.lucko.luckperms.common.logging.Logger;
|
||||
import me.lucko.luckperms.common.logging.SenderLogger;
|
||||
import me.lucko.luckperms.common.managers.GenericGroupManager;
|
||||
import me.lucko.luckperms.common.managers.GenericTrackManager;
|
||||
@@ -66,15 +70,13 @@ import me.lucko.luckperms.common.managers.GenericUserManager;
|
||||
import me.lucko.luckperms.common.managers.GroupManager;
|
||||
import me.lucko.luckperms.common.managers.TrackManager;
|
||||
import me.lucko.luckperms.common.managers.UserManager;
|
||||
import me.lucko.luckperms.common.messaging.InternalMessagingService;
|
||||
import me.lucko.luckperms.common.messaging.NoopMessagingService;
|
||||
import me.lucko.luckperms.common.messaging.RedisMessagingService;
|
||||
import me.lucko.luckperms.common.messaging.ExtendedMessagingService;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.storage.Storage;
|
||||
import me.lucko.luckperms.common.storage.StorageFactory;
|
||||
import me.lucko.luckperms.common.storage.StorageType;
|
||||
import me.lucko.luckperms.common.storage.backing.file.FileWatcher;
|
||||
import me.lucko.luckperms.common.storage.dao.file.FileWatcher;
|
||||
import me.lucko.luckperms.common.tasks.CacheHousekeepingTask;
|
||||
import me.lucko.luckperms.common.tasks.ExpireTemporaryTask;
|
||||
import me.lucko.luckperms.common.tasks.UpdateTask;
|
||||
@@ -83,7 +85,6 @@ import me.lucko.luckperms.common.utils.LoginHelper;
|
||||
import me.lucko.luckperms.common.utils.UuidCache;
|
||||
import me.lucko.luckperms.common.verbose.VerboseHandler;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.HandlerList;
|
||||
@@ -96,24 +97,24 @@ 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;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* LuckPerms implementation for the Bukkit API.
|
||||
*/
|
||||
@Getter
|
||||
public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
private Set<UUID> ignoringLogs;
|
||||
private Set<UUID> uniqueConnections;
|
||||
|
||||
private long startTime;
|
||||
private LPBukkitScheduler scheduler;
|
||||
private BukkitCommand commandManager;
|
||||
private BukkitSchedulerAdapter scheduler;
|
||||
private BukkitCommandExecutor commandManager;
|
||||
private VaultHookManager vaultHookManager = null;
|
||||
private LuckPermsConfiguration configuration;
|
||||
private UserManager userManager;
|
||||
@@ -121,9 +122,8 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
private TrackManager trackManager;
|
||||
private Storage storage;
|
||||
private FileWatcher fileWatcher = null;
|
||||
private InternalMessagingService messagingService = null;
|
||||
private ExtendedMessagingService messagingService = null;
|
||||
private UuidCache uuidCache;
|
||||
private BukkitListener listener;
|
||||
private ApiProvider apiProvider;
|
||||
private Logger log;
|
||||
private DefaultsProvider defaultsProvider;
|
||||
@@ -131,7 +131,6 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
private LocaleManager localeManager;
|
||||
private CachedStateManager cachedStateManager;
|
||||
private ContextManager<Player> contextManager;
|
||||
private WorldCalculator worldCalculator;
|
||||
private CalculatorFactory calculatorFactory;
|
||||
private BufferedRequest<Void> updateTaskBuffer;
|
||||
private boolean started = false;
|
||||
@@ -139,20 +138,38 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
private VerboseHandler verboseHandler;
|
||||
private BukkitSenderFactory senderFactory;
|
||||
private PermissionVault permissionVault;
|
||||
private LogDispatcher logDispatcher;
|
||||
private Set<UUID> uniqueConnections = ConcurrentHashMap.newKeySet();
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
if (checkInvalidVersion()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// setup minimal functionality in order to load initial dependencies
|
||||
scheduler = new LPBukkitScheduler(this);
|
||||
scheduler = new BukkitSchedulerAdapter(this);
|
||||
localeManager = new NoopLocaleManager();
|
||||
senderFactory = new BukkitSenderFactory(this);
|
||||
log = new SenderLogger(this, getConsoleSender());
|
||||
|
||||
DependencyManager.loadDependencies(this, Collections.singletonList(Dependency.CAFFEINE));
|
||||
DependencyManager.loadDependencies(this, Collections.singleton(Dependency.CAFFEINE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
if (checkInvalidVersion()) {
|
||||
getLogger().severe("----------------------------------------------------------------------");
|
||||
getLogger().severe("Your server version is not compatible with this build of LuckPerms. :(");
|
||||
getLogger().severe("");
|
||||
getLogger().severe("If your server is running 1.8, please update to 1.8.8 or higher.");
|
||||
getLogger().severe("If your server is running 1.7.10, please download the Bukkit-Legacy version of LuckPerms from here:");
|
||||
getLogger().severe("==> https://ci.lucko.me/job/LuckPerms/");
|
||||
getLogger().severe("----------------------------------------------------------------------");
|
||||
getServer().getPluginManager().disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
enable();
|
||||
started = true;
|
||||
@@ -166,41 +183,27 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
private void enable() {
|
||||
startTime = System.currentTimeMillis();
|
||||
LuckPermsPlugin.sendStartupBanner(getConsoleSender(), this);
|
||||
|
||||
ignoringLogs = ConcurrentHashMap.newKeySet();
|
||||
uniqueConnections = ConcurrentHashMap.newKeySet();
|
||||
verboseHandler = new VerboseHandler(scheduler.getAsyncBukkitExecutor(), getVersion());
|
||||
permissionVault = new PermissionVault(scheduler.getAsyncBukkitExecutor());
|
||||
verboseHandler = new VerboseHandler(scheduler.asyncBukkit(), getVersion());
|
||||
permissionVault = new PermissionVault(scheduler.asyncBukkit());
|
||||
logDispatcher = new LogDispatcher(this);
|
||||
|
||||
getLog().info("Loading configuration...");
|
||||
configuration = new BukkitConfig(this);
|
||||
configuration = new AbstractConfiguration(this, new BukkitConfigAdapter(this));
|
||||
configuration.init();
|
||||
configuration.loadAll();
|
||||
|
||||
Set<StorageType> storageTypes = StorageFactory.getRequiredTypes(this, StorageType.H2);
|
||||
DependencyManager.loadDependencies(this, storageTypes);
|
||||
DependencyManager.loadStorageDependencies(this, storageTypes);
|
||||
|
||||
// setup the Bukkit defaults hook
|
||||
defaultsProvider = new DefaultsProvider();
|
||||
childPermissionProvider = new ChildPermissionProvider();
|
||||
|
||||
// give all plugins a chance to load their permissions, then refresh.
|
||||
scheduler.syncLater(() -> {
|
||||
defaultsProvider.refresh();
|
||||
childPermissionProvider.setup();
|
||||
|
||||
Set<String> perms = new HashSet<>();
|
||||
getServer().getPluginManager().getPermissions().forEach(p -> {
|
||||
perms.add(p.getName());
|
||||
perms.addAll(p.getChildren().keySet());
|
||||
});
|
||||
|
||||
perms.forEach(p -> permissionVault.offer(p));
|
||||
}, 1L);
|
||||
scheduler.syncLater(new BukkitProcessorsSetupTask(this), 1L);
|
||||
|
||||
// register events
|
||||
listener = new BukkitListener(this);
|
||||
getServer().getPluginManager().registerEvents(listener, this);
|
||||
getServer().getPluginManager().registerEvents(new BukkitConnectionListener(this), this);
|
||||
getServer().getPluginManager().registerEvents(new BukkitPlatformListener(this), this);
|
||||
|
||||
if (getConfiguration().get(ConfigKeys.WATCH_FILES)) {
|
||||
fileWatcher = new FileWatcher(this);
|
||||
@@ -211,71 +214,17 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
storage = StorageFactory.getInstance(this, StorageType.H2);
|
||||
|
||||
// initialise messaging
|
||||
String messagingType = getConfiguration().get(ConfigKeys.MESSAGING_SERVICE).toLowerCase();
|
||||
if (messagingType.equals("none") && getConfiguration().get(ConfigKeys.REDIS_ENABLED)) {
|
||||
messagingType = "redis";
|
||||
}
|
||||
|
||||
if (!messagingType.equals("none")) {
|
||||
getLog().info("Loading messaging service... [" + messagingType.toUpperCase() + "]");
|
||||
}
|
||||
|
||||
if (messagingType.equals("redis")) {
|
||||
if (getConfiguration().get(ConfigKeys.REDIS_ENABLED)) {
|
||||
RedisMessagingService redis = new RedisMessagingService(this);
|
||||
try {
|
||||
redis.init(getConfiguration().get(ConfigKeys.REDIS_ADDRESS), getConfiguration().get(ConfigKeys.REDIS_PASSWORD));
|
||||
messagingService = redis;
|
||||
} catch (Exception e) {
|
||||
getLog().warn("Couldn't load redis...");
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
getLog().warn("Messaging Service was set to redis, but redis is not enabled!");
|
||||
}
|
||||
} else if (messagingType.equals("bungee")) {
|
||||
BungeeMessagingService bungeeMessaging = new BungeeMessagingService(this);
|
||||
bungeeMessaging.init();
|
||||
messagingService = bungeeMessaging;
|
||||
} else if (messagingType.equals("lilypad")) {
|
||||
if (getServer().getPluginManager().getPlugin("LilyPad-Connect") == null) {
|
||||
getLog().warn("LilyPad-Connect plugin not present.");
|
||||
} else {
|
||||
LilyPadMessagingService lilyPadMessaging = new LilyPadMessagingService(this);
|
||||
lilyPadMessaging.init();
|
||||
messagingService = lilyPadMessaging;
|
||||
}
|
||||
} else if (!messagingType.equals("none")) {
|
||||
getLog().warn("Messaging service '" + messagingType + "' not recognised.");
|
||||
}
|
||||
|
||||
if (messagingService == null) {
|
||||
messagingService = new NoopMessagingService();
|
||||
}
|
||||
messagingService = new BukkitMessagingFactory(this).getInstance();
|
||||
|
||||
// setup the update task buffer
|
||||
updateTaskBuffer = new BufferedRequest<Void>(1000L, this::doAsync) {
|
||||
@Override
|
||||
protected Void perform() {
|
||||
new UpdateTask(LPBukkitPlugin.this).run();
|
||||
return null;
|
||||
}
|
||||
};
|
||||
updateTaskBuffer = new UpdateTaskBuffer(this);
|
||||
|
||||
// load locale
|
||||
localeManager = new SimpleLocaleManager();
|
||||
File locale = new File(getDataFolder(), "lang.yml");
|
||||
if (locale.exists()) {
|
||||
getLog().info("Found lang.yml - loading messages...");
|
||||
try {
|
||||
localeManager.loadFromFile(locale);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
localeManager.tryLoad(this, new File(getDataFolder(), "lang.yml"));
|
||||
|
||||
// register commands
|
||||
commandManager = new BukkitCommand(this);
|
||||
commandManager = new BukkitCommandExecutor(this);
|
||||
PluginCommand main = getServer().getPluginCommand("luckperms");
|
||||
main.setExecutor(commandManager);
|
||||
main.setTabCompleter(commandManager);
|
||||
@@ -291,33 +240,24 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
calculatorFactory = new BukkitCalculatorFactory(this);
|
||||
cachedStateManager = new CachedStateManager();
|
||||
|
||||
contextManager = new ContextManager<Player>() {
|
||||
@Override
|
||||
public Contexts formContexts(Player player, ImmutableContextSet contextSet) {
|
||||
return new Contexts(
|
||||
contextSet,
|
||||
getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_PERMS),
|
||||
getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_WORLD_PERMS),
|
||||
true,
|
||||
getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_GROUPS),
|
||||
getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_WORLD_GROUPS),
|
||||
player.isOp()
|
||||
);
|
||||
}
|
||||
};
|
||||
// setup context manager
|
||||
contextManager = new BukkitContextManager(this);
|
||||
contextManager.registerCalculator(new WorldCalculator(this));
|
||||
contextManager.registerStaticCalculator(new LuckPermsCalculator(getConfiguration()));
|
||||
|
||||
worldCalculator = new WorldCalculator(this);
|
||||
contextManager.registerCalculator(worldCalculator);
|
||||
// inject our own subscription map
|
||||
new SubscriptionMapInjector(this).run();
|
||||
|
||||
LuckPermsCalculator<Player> staticCalculator = new LuckPermsCalculator<>(getConfiguration());
|
||||
contextManager.registerCalculator(staticCalculator, true);
|
||||
// schedule another injection after all plugins have loaded - the entire pluginmanager instance
|
||||
// is replaced by some plugins :(
|
||||
scheduler.asyncLater(new SubscriptionMapInjector(this), 2L);
|
||||
|
||||
// Provide vault support
|
||||
tryVaultHook(false);
|
||||
|
||||
// register with the LP API
|
||||
apiProvider = new ApiProvider(this);
|
||||
ApiHandler.registerProvider(apiProvider);
|
||||
ApiSingletonUtils.registerProvider(apiProvider);
|
||||
getServer().getServicesManager().register(LuckPermsApi.class, apiProvider, this, ServicePriority.Normal);
|
||||
|
||||
|
||||
@@ -331,7 +271,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
|
||||
// run an update instantly.
|
||||
getLog().info("Performing initial data load...");
|
||||
updateTaskBuffer.requestDirectly();
|
||||
new UpdateTask(this, true).run();
|
||||
|
||||
// register tasks
|
||||
scheduler.asyncRepeating(new ExpireTemporaryTask(this), 60L);
|
||||
@@ -339,7 +279,12 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
|
||||
// register permissions
|
||||
try {
|
||||
registerPermissions(getConfiguration().get(ConfigKeys.COMMANDS_ALLOW_OP) ? PermissionDefault.OP : PermissionDefault.FALSE);
|
||||
PluginManager pm = getServer().getPluginManager();
|
||||
PermissionDefault permDefault = getConfiguration().get(ConfigKeys.COMMANDS_ALLOW_OP) ? PermissionDefault.OP : PermissionDefault.FALSE;
|
||||
|
||||
for (CommandPermission p : CommandPermission.values()) {
|
||||
pm.addPermission(new org.bukkit.permissions.Permission(p.getPermission(), permDefault));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// this throws an exception if the plugin is /reloaded, grr
|
||||
}
|
||||
@@ -374,18 +319,23 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
if (checkInvalidVersion()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Switch back to the LP executor, the bukkit one won't allow new tasks
|
||||
scheduler.setUseBukkitAsync(false);
|
||||
|
||||
started = false;
|
||||
|
||||
defaultsProvider.close();
|
||||
permissionVault.setShutdown(true);
|
||||
verboseHandler.setShutdown(true);
|
||||
permissionVault.shutdown();
|
||||
verboseHandler.shutdown();
|
||||
|
||||
// uninject from players
|
||||
for (Player player : getServer().getOnlinePlayers()) {
|
||||
try {
|
||||
Injector.unInject(player, false, false);
|
||||
Injector.unInject(player, false);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -396,11 +346,14 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
|
||||
final User user = getUserManager().getIfLoaded(getUuidCache().getUUID(player.getUniqueId()));
|
||||
if (user != null) {
|
||||
user.unregisterData();
|
||||
user.getUserData().invalidateCaches();
|
||||
getUserManager().unload(user);
|
||||
}
|
||||
}
|
||||
|
||||
// uninject subscription map
|
||||
SubscriptionMapInjector.uninject();
|
||||
|
||||
getLog().info("Closing storage...");
|
||||
storage.shutdown();
|
||||
|
||||
@@ -413,7 +366,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
messagingService.close();
|
||||
}
|
||||
|
||||
ApiHandler.unregisterProvider();
|
||||
ApiSingletonUtils.unregisterProvider();
|
||||
getServer().getServicesManager().unregisterAll(this);
|
||||
|
||||
if (vaultHookManager != null) {
|
||||
@@ -426,32 +379,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
// Bukkit will do this again when #onDisable completes, but we do it early to prevent NPEs elsewhere.
|
||||
getServer().getScheduler().cancelTasks(this);
|
||||
HandlerList.unregisterAll(this);
|
||||
|
||||
// Null everything
|
||||
ignoringLogs = null;
|
||||
vaultHookManager = null;
|
||||
configuration = null;
|
||||
userManager = null;
|
||||
groupManager = null;
|
||||
trackManager = null;
|
||||
storage = null;
|
||||
fileWatcher = null;
|
||||
messagingService = null;
|
||||
uuidCache = null;
|
||||
listener = null;
|
||||
apiProvider = null;
|
||||
log = null;
|
||||
defaultsProvider = null;
|
||||
childPermissionProvider = null;
|
||||
localeManager = null;
|
||||
cachedStateManager = null;
|
||||
contextManager = null;
|
||||
worldCalculator = null;
|
||||
calculatorFactory = null;
|
||||
updateTaskBuffer = null;
|
||||
verboseHandler = null;
|
||||
senderFactory = null;
|
||||
permissionVault = null;
|
||||
getLog().info("Goodbye!");
|
||||
}
|
||||
|
||||
public void tryVaultHook(boolean force) {
|
||||
@@ -472,32 +400,25 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserRefresh(User user) {
|
||||
LPPermissible lpp = Injector.getPermissible(uuidCache.getExternalUUID(user.getUuid()));
|
||||
if (lpp != null) {
|
||||
lpp.updateSubscriptions();
|
||||
public void refreshAutoOp(User user, Player player) {
|
||||
if (user == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (getConfiguration().get(ConfigKeys.AUTO_OP)) {
|
||||
Map<String, Boolean> backing = user.getUserData().getPermissionData(contextManager.getApplicableContexts(player)).getImmutableBacking();
|
||||
boolean op = Optional.ofNullable(backing.get("luckperms.autoop")).orElse(false);
|
||||
player.setOp(op);
|
||||
}
|
||||
}
|
||||
|
||||
public void refreshAutoOp(Player player) {
|
||||
if (getConfiguration().get(ConfigKeys.AUTO_OP)) {
|
||||
try {
|
||||
LPPermissible permissible = Injector.getPermissible(player.getUniqueId());
|
||||
if (permissible == null || !permissible.getActive().get()) {
|
||||
return;
|
||||
}
|
||||
@Override
|
||||
public Optional<ExtendedMessagingService> getMessagingService() {
|
||||
return Optional.ofNullable(messagingService);
|
||||
}
|
||||
|
||||
User user = permissible.getUser();
|
||||
if (user == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Boolean> backing = user.getUserData().getPermissionData(permissible.calculateContexts()).getImmutableBacking();
|
||||
boolean op = Optional.ofNullable(backing.get("luckperms.autoop")).orElse(false);
|
||||
player.setOp(op);
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
public Optional<FileWatcher> getFileWatcher() {
|
||||
return Optional.ofNullable(fileWatcher);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -561,13 +482,13 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getPlayerList() {
|
||||
return getServer().getOnlinePlayers().stream().map(Player::getName).collect(Collectors.toList());
|
||||
public Stream<String> getPlayerList() {
|
||||
return getServer().getOnlinePlayers().stream().map(Player::getName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> getOnlinePlayers() {
|
||||
return getServer().getOnlinePlayers().stream().map(Player::getUniqueId).collect(Collectors.toSet());
|
||||
public Stream<UUID> getOnlinePlayers() {
|
||||
return getServer().getOnlinePlayers().stream().map(Player::getUniqueId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -577,10 +498,11 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Sender> getOnlineSenders() {
|
||||
return getServer().getOnlinePlayers().stream()
|
||||
.map(p -> getSenderFactory().wrap(p))
|
||||
.collect(Collectors.toList());
|
||||
public Stream<Sender> getOnlineSenders() {
|
||||
return Stream.concat(
|
||||
Stream.of(getConsoleSender()),
|
||||
getServer().getOnlinePlayers().stream().map(p -> getSenderFactory().wrap(p))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -589,86 +511,20 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Contexts> getPreProcessContexts(boolean op) {
|
||||
Set<ContextSet> c = new HashSet<>();
|
||||
c.add(ContextSet.empty());
|
||||
c.add(ContextSet.singleton("server", getConfiguration().get(ConfigKeys.SERVER)));
|
||||
|
||||
// Pre process all worlds
|
||||
c.addAll(getServer().getWorlds().stream()
|
||||
.map(World::getName)
|
||||
.map(s -> {
|
||||
MutableContextSet set = MutableContextSet.create();
|
||||
set.add("server", getConfiguration().get(ConfigKeys.SERVER));
|
||||
set.add("world", s);
|
||||
set.addAll(configuration.getContextsFile().getStaticContexts());
|
||||
return set.makeImmutable();
|
||||
})
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
|
||||
// Pre process the separate Vault server, if any
|
||||
if (!getConfiguration().get(ConfigKeys.SERVER).equals(getConfiguration().get(ConfigKeys.VAULT_SERVER))) {
|
||||
c.add(ContextSet.singleton("server", getConfiguration().get(ConfigKeys.VAULT_SERVER)));
|
||||
c.addAll(getServer().getWorlds().stream()
|
||||
.map(World::getName)
|
||||
.map(s -> {
|
||||
MutableContextSet set = MutableContextSet.create();
|
||||
set.add("server", getConfiguration().get(ConfigKeys.VAULT_SERVER));
|
||||
set.add("world", s);
|
||||
set.addAll(configuration.getContextsFile().getStaticContexts());
|
||||
return set.makeImmutable();
|
||||
})
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
|
||||
Set<Contexts> contexts = new HashSet<>();
|
||||
|
||||
// Convert to full Contexts
|
||||
contexts.addAll(c.stream()
|
||||
.map(set -> new Contexts(
|
||||
set,
|
||||
getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_PERMS),
|
||||
getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_WORLD_PERMS),
|
||||
true,
|
||||
getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_GROUPS),
|
||||
getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_WORLD_GROUPS),
|
||||
op
|
||||
))
|
||||
.collect(Collectors.toSet())
|
||||
);
|
||||
|
||||
// Check for and include varying Vault config options
|
||||
boolean vaultDiff = getConfiguration().get(ConfigKeys.VAULT_INCLUDING_GLOBAL) != getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_PERMS) ||
|
||||
!getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_WORLD_PERMS) ||
|
||||
!getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_GROUPS) ||
|
||||
!getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_WORLD_GROUPS);
|
||||
|
||||
if (vaultDiff) {
|
||||
contexts.addAll(c.stream()
|
||||
.map(map -> new Contexts(map, getConfiguration().get(ConfigKeys.VAULT_INCLUDING_GLOBAL), true, true, true, true, op))
|
||||
.collect(Collectors.toSet())
|
||||
);
|
||||
}
|
||||
|
||||
return contexts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LinkedHashMap<String, Object> getExtraInfo() {
|
||||
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
|
||||
public Map<String, Object> getExtraInfo() {
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
map.put("Vault Enabled", vaultHookManager != null);
|
||||
map.put("Bukkit Defaults count", defaultsProvider.size());
|
||||
map.put("Bukkit Child Permissions count", childPermissionProvider.getPermissions().size());
|
||||
return map;
|
||||
}
|
||||
|
||||
private void registerPermissions(PermissionDefault def) {
|
||||
PluginManager pm = getServer().getPluginManager();
|
||||
|
||||
for (CommandPermission p : CommandPermission.values()) {
|
||||
pm.addPermission(new org.bukkit.permissions.Permission(p.getPermission(), def));
|
||||
private static boolean checkInvalidVersion() {
|
||||
try {
|
||||
Class.forName("com.google.gson.JsonElement");
|
||||
return false;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-13
@@ -31,13 +31,11 @@ import com.google.common.collect.ImmutableList;
|
||||
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.bukkit.model.Injector;
|
||||
import me.lucko.luckperms.bukkit.model.LPPermissible;
|
||||
import me.lucko.luckperms.bukkit.processors.AttachmentProcessor;
|
||||
import me.lucko.luckperms.bukkit.processors.ChildProcessor;
|
||||
import me.lucko.luckperms.bukkit.processors.DefaultsProcessor;
|
||||
import me.lucko.luckperms.common.calculators.AbstractCalculatorFactory;
|
||||
import me.lucko.luckperms.common.calculators.PermissionCalculator;
|
||||
import me.lucko.luckperms.common.calculators.PermissionCalculatorMetadata;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.processors.MapProcessor;
|
||||
@@ -46,7 +44,6 @@ import me.lucko.luckperms.common.processors.RegexProcessor;
|
||||
import me.lucko.luckperms.common.processors.WildcardProcessor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class BukkitCalculatorFactory extends AbstractCalculatorFactory {
|
||||
@@ -62,14 +59,6 @@ public class BukkitCalculatorFactory extends AbstractCalculatorFactory {
|
||||
processors.add(new ChildProcessor(plugin.getChildPermissionProvider()));
|
||||
}
|
||||
|
||||
if (plugin.getConfiguration().get(ConfigKeys.APPLY_BUKKIT_ATTACHMENT_PERMISSIONS)) {
|
||||
final UUID uuid = plugin.getUuidCache().getExternalUUID(user.getUuid());
|
||||
processors.add(new AttachmentProcessor(() -> {
|
||||
LPPermissible permissible = Injector.getPermissible(uuid);
|
||||
return permissible == null ? null : permissible.getAttachmentPermissions();
|
||||
}));
|
||||
}
|
||||
|
||||
if (plugin.getConfiguration().get(ConfigKeys.APPLYING_REGEX)) {
|
||||
processors.add(new RegexProcessor());
|
||||
}
|
||||
@@ -82,7 +71,8 @@ public class BukkitCalculatorFactory extends AbstractCalculatorFactory {
|
||||
processors.add(new DefaultsProcessor(contexts.isOp(), plugin.getDefaultsProvider()));
|
||||
}
|
||||
|
||||
return registerCalculator(new PermissionCalculator(plugin, user.getFriendlyName(), processors.build()));
|
||||
PermissionCalculatorMetadata meta = PermissionCalculatorMetadata.of(user.getFriendlyName(), contexts.getContexts());
|
||||
return registerCalculator(new PermissionCalculator(plugin, meta, processors.build()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -91,7 +91,7 @@ public class BukkitJsonMessageHandler {
|
||||
setup(player);
|
||||
setup = true;
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
triedAndFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -25,10 +25,10 @@
|
||||
|
||||
package me.lucko.luckperms.bukkit.compat;
|
||||
|
||||
import me.lucko.luckperms.common.constants.Constants;
|
||||
import me.lucko.luckperms.common.utils.TextUtils;
|
||||
|
||||
import net.kyori.text.Component;
|
||||
import net.kyori.text.serializer.ComponentSerializer;
|
||||
import net.kyori.text.serializer.ComponentSerializers;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -48,7 +48,7 @@ public class MessageHandler {
|
||||
public void sendJsonMessage(CommandSender sender, Component message) {
|
||||
if (ReflectionUtil.isChatCompatible() && sender instanceof Player) {
|
||||
Player player = (Player) sender;
|
||||
String json = ComponentSerializer.serialize(message);
|
||||
String json = ComponentSerializers.JSON.serialize(message);
|
||||
|
||||
// Try Bukkit.
|
||||
if (bukkitHandler.sendJsonMessage(player, json)) {
|
||||
@@ -62,7 +62,7 @@ public class MessageHandler {
|
||||
}
|
||||
|
||||
// Fallback to Bukkit
|
||||
sender.sendMessage(ComponentSerializer.toLegacy(message, Constants.COLOR_CHAR));
|
||||
sender.sendMessage(TextUtils.toLegacy(message));
|
||||
}
|
||||
|
||||
private static boolean isSpigot() {
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.contexts;
|
||||
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.contexts.AbstractContextManager;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class BukkitContextManager extends AbstractContextManager<Player> {
|
||||
public BukkitContextManager(LPBukkitPlugin plugin) {
|
||||
super(plugin, Player.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Contexts formContexts(Player subject, ImmutableContextSet contextSet) {
|
||||
return new Contexts(
|
||||
contextSet,
|
||||
plugin.getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_PERMS),
|
||||
plugin.getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_WORLD_PERMS),
|
||||
true,
|
||||
plugin.getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_GROUPS),
|
||||
plugin.getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_WORLD_GROUPS),
|
||||
subject.isOp()
|
||||
);
|
||||
}
|
||||
}
|
||||
+17
-43
@@ -23,10 +23,11 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit;
|
||||
package me.lucko.luckperms.bukkit.listeners;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.bukkit.model.Injector;
|
||||
import me.lucko.luckperms.bukkit.model.LPPermissible;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
@@ -39,11 +40,8 @@ import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
|
||||
import org.bukkit.event.player.PlayerChangedWorldEvent;
|
||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
import org.bukkit.event.player.PlayerLoginEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.event.server.PluginEnableEvent;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
@@ -52,7 +50,7 @@ import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class BukkitListener implements Listener {
|
||||
public class BukkitConnectionListener implements Listener {
|
||||
private final LPBukkitPlugin plugin;
|
||||
|
||||
private final Set<UUID> deniedAsyncLogin = Collections.synchronizedSet(new HashSet<>());
|
||||
@@ -71,6 +69,10 @@ public class BukkitListener implements Listener {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
if (plugin.getConfiguration().get(ConfigKeys.DEBUG_LOGINS)) {
|
||||
plugin.getLog().info("Processing pre-login for " + e.getUniqueId() + " - " + e.getName());
|
||||
}
|
||||
|
||||
/* there was an issue connecting to the DB, performing file i/o, etc.
|
||||
we don't let players join in this case, because it means they can connect to the server without their permissions data.
|
||||
some server admins rely on negating perms to stop users from causing damage etc, so it's really important that
|
||||
@@ -98,7 +100,8 @@ public class BukkitListener implements Listener {
|
||||
- creating a user instance in the UserManager for this connection.
|
||||
- setting up cached data. */
|
||||
try {
|
||||
LoginHelper.loadUser(plugin, e.getUniqueId(), e.getName(), false);
|
||||
User user = LoginHelper.loadUser(plugin, e.getUniqueId(), e.getName(), false);
|
||||
plugin.getApiProvider().getEventFactory().handleUserLoginProcess(e.getUniqueId(), e.getName(), user);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
|
||||
@@ -139,6 +142,11 @@ public class BukkitListener implements Listener {
|
||||
At this point, the users data should be present and loaded. */
|
||||
|
||||
final Player player = e.getPlayer();
|
||||
|
||||
if (plugin.getConfiguration().get(ConfigKeys.DEBUG_LOGINS)) {
|
||||
plugin.getLog().info("Processing login for " + player.getUniqueId() + " - " + player.getName());
|
||||
}
|
||||
|
||||
final User user = plugin.getUserManager().getIfLoaded(plugin.getUuidCache().getUUID(player.getUniqueId()));
|
||||
|
||||
/* User instance is null for whatever reason. Could be that it was unloaded between asyncpre and now. */
|
||||
@@ -163,12 +171,7 @@ public class BukkitListener implements Listener {
|
||||
t.printStackTrace();
|
||||
}
|
||||
|
||||
plugin.refreshAutoOp(player);
|
||||
|
||||
// We assume all users are not op, but those who are need extra calculation.
|
||||
if (player.isOp()) {
|
||||
plugin.doAsync(() -> user.getUserData().preCalculate(plugin.getPreProcessContexts(true)));
|
||||
}
|
||||
plugin.refreshAutoOp(user, player);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
@@ -196,7 +199,7 @@ public class BukkitListener implements Listener {
|
||||
}
|
||||
|
||||
// everything is going well. login was processed ok, this is just to refresh auto-op status.
|
||||
plugin.refreshAutoOp(e.getPlayer());
|
||||
plugin.refreshAutoOp(plugin.getUserManager().getIfLoaded(e.getPlayer().getUniqueId()), e.getPlayer());
|
||||
}
|
||||
|
||||
// Wait until the last priority to unload, so plugins can still perform permission checks on this event
|
||||
@@ -206,7 +209,7 @@ public class BukkitListener implements Listener {
|
||||
|
||||
// Remove the custom permissible
|
||||
try {
|
||||
Injector.unInject(player, true, true);
|
||||
Injector.unInject(player, true);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
@@ -220,33 +223,4 @@ public class BukkitListener implements Listener {
|
||||
plugin.getUserManager().scheduleUnload(player.getUniqueId());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerCommand(PlayerCommandPreprocessEvent e) {
|
||||
if (plugin.getConfiguration().get(ConfigKeys.OPS_ENABLED)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String s = e.getMessage().substring(1).toLowerCase()
|
||||
.replace("bukkit:", "")
|
||||
.replace("spigot:", "")
|
||||
.replace("minecraft:", "");
|
||||
|
||||
if (s.equals("op") || s.startsWith("op ") || s.equals("deop") || s.startsWith("deop ")) {
|
||||
e.setCancelled(true);
|
||||
e.getPlayer().sendMessage(Message.OP_DISABLED.asString(plugin.getLocaleManager()));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPluginEnable(PluginEnableEvent e) {
|
||||
if (e.getPlugin().getName().equalsIgnoreCase("Vault")) {
|
||||
plugin.tryVaultHook(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onWorldChange(PlayerChangedWorldEvent e) {
|
||||
plugin.getContextManager().invalidateCache(e.getPlayer());
|
||||
plugin.refreshAutoOp(e.getPlayer());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.listeners;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerChangedWorldEvent;
|
||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
import org.bukkit.event.server.PluginEnableEvent;
|
||||
import org.bukkit.event.server.RemoteServerCommandEvent;
|
||||
import org.bukkit.event.server.ServerCommandEvent;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class BukkitPlatformListener implements Listener {
|
||||
private final LPBukkitPlugin plugin;
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerCommand(PlayerCommandPreprocessEvent e) {
|
||||
handleCommand(e.getPlayer(), e.getMessage().toLowerCase(), e);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onServerCommand(ServerCommandEvent e) {
|
||||
handleCommand(e.getSender(), e.getCommand().toLowerCase(), e);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onRemoteServerCommand(RemoteServerCommandEvent e) {
|
||||
handleCommand(e.getSender(), e.getCommand().toLowerCase(), e);
|
||||
}
|
||||
|
||||
private void handleCommand(CommandSender sender, String s, Cancellable event) {
|
||||
if (s.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (plugin.getConfiguration().get(ConfigKeys.OPS_ENABLED)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (s.charAt(0) == '/') {
|
||||
s = s.substring(1);
|
||||
}
|
||||
|
||||
if (s.startsWith("minecraft:")) {
|
||||
s = s.substring("minecraft:".length());
|
||||
}
|
||||
|
||||
if (s.equals("op") || s.startsWith("op ") || s.equals("deop") || s.startsWith("deop ")) {
|
||||
event.setCancelled(true);
|
||||
sender.sendMessage(Message.OP_DISABLED.asString(plugin.getLocaleManager()));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPluginEnable(PluginEnableEvent e) {
|
||||
if (e.getPlugin().getName().equalsIgnoreCase("Vault")) {
|
||||
plugin.tryVaultHook(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onWorldChange(PlayerChangedWorldEvent e) {
|
||||
plugin.getContextManager().invalidateCache(e.getPlayer());
|
||||
plugin.refreshAutoOp(plugin.getUserManager().getIfLoaded(e.getPlayer().getUniqueId()), e.getPlayer());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.messaging;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.messaging.ExtendedMessagingService;
|
||||
import me.lucko.luckperms.common.messaging.MessagingFactory;
|
||||
|
||||
public class BukkitMessagingFactory extends MessagingFactory<LPBukkitPlugin> {
|
||||
public BukkitMessagingFactory(LPBukkitPlugin plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExtendedMessagingService getServiceFor(String messagingType) {
|
||||
if (messagingType.equals("bungee")) {
|
||||
BungeeMessagingService bungeeMessaging = new BungeeMessagingService(getPlugin());
|
||||
bungeeMessaging.init();
|
||||
return bungeeMessaging;
|
||||
} else if (messagingType.equals("lilypad")) {
|
||||
if (getPlugin().getServer().getPluginManager().getPlugin("LilyPad-Connect") == null) {
|
||||
getPlugin().getLog().warn("LilyPad-Connect plugin not present.");
|
||||
} else {
|
||||
LilyPadMessagingService lilyPadMessaging = new LilyPadMessagingService(getPlugin());
|
||||
lilyPadMessaging.init();
|
||||
return lilyPadMessaging;
|
||||
}
|
||||
}
|
||||
|
||||
return super.getServiceFor(messagingType);
|
||||
}
|
||||
}
|
||||
+5
-4
@@ -32,6 +32,7 @@ import com.google.common.io.ByteStreams;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.messaging.AbstractMessagingService;
|
||||
import me.lucko.luckperms.common.messaging.ExtendedMessagingService;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
||||
@@ -40,7 +41,7 @@ import org.bukkit.scheduler.BukkitRunnable;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* An implementation of {@link me.lucko.luckperms.api.MessagingService} using the plugin messaging channels.
|
||||
* An implementation of {@link ExtendedMessagingService} using the plugin messaging channels.
|
||||
*/
|
||||
public class BungeeMessagingService extends AbstractMessagingService implements PluginMessageListener {
|
||||
private final LPBukkitPlugin plugin;
|
||||
@@ -62,7 +63,7 @@ public class BungeeMessagingService extends AbstractMessagingService implements
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendMessage(String channel, String message) {
|
||||
protected void sendMessage(String message) {
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -77,7 +78,7 @@ public class BungeeMessagingService extends AbstractMessagingService implements
|
||||
|
||||
byte[] data = out.toByteArray();
|
||||
|
||||
p.sendPluginMessage(plugin, channel, data);
|
||||
p.sendPluginMessage(plugin, CHANNEL, data);
|
||||
cancel();
|
||||
}
|
||||
}.runTaskTimer(plugin, 1L, 100L);
|
||||
@@ -92,6 +93,6 @@ public class BungeeMessagingService extends AbstractMessagingService implements
|
||||
ByteArrayDataInput in = ByteStreams.newDataInput(bytes);
|
||||
String msg = in.readUTF();
|
||||
|
||||
onMessage(s, msg, null);
|
||||
onMessage(msg, null);
|
||||
}
|
||||
}
|
||||
+11
-5
@@ -27,6 +27,7 @@ package me.lucko.luckperms.bukkit.messaging;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.messaging.AbstractMessagingService;
|
||||
import me.lucko.luckperms.common.messaging.ExtendedMessagingService;
|
||||
|
||||
import lilypad.client.connect.api.Connect;
|
||||
import lilypad.client.connect.api.event.EventListener;
|
||||
@@ -38,7 +39,7 @@ import java.io.UnsupportedEncodingException;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* An implementation of {@link me.lucko.luckperms.api.MessagingService} using LilyPad.
|
||||
* An implementation of {@link ExtendedMessagingService} using LilyPad.
|
||||
*/
|
||||
public class LilyPadMessagingService extends AbstractMessagingService {
|
||||
private final LPBukkitPlugin plugin;
|
||||
@@ -60,11 +61,11 @@ public class LilyPadMessagingService extends AbstractMessagingService {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendMessage(String channel, String message) {
|
||||
protected void sendMessage(String message) {
|
||||
MessageRequest request;
|
||||
|
||||
try {
|
||||
request = new MessageRequest(Collections.emptyList(), channel, message);
|
||||
request = new MessageRequest(Collections.emptyList(), CHANNEL, message);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
@@ -79,12 +80,17 @@ public class LilyPadMessagingService extends AbstractMessagingService {
|
||||
|
||||
@EventListener
|
||||
public void onMessage(MessageEvent event) {
|
||||
plugin.doAsync(() -> {
|
||||
plugin.getScheduler().doAsync(() -> {
|
||||
try {
|
||||
String channel = event.getChannel();
|
||||
|
||||
if (!channel.equals(CHANNEL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String message = event.getMessageAsString();
|
||||
|
||||
onMessage(channel, message, null);
|
||||
onMessage(message, null);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ public class MigrationBPermissions extends SubCommand<Object> {
|
||||
}
|
||||
|
||||
// Make a LuckPerms user for the one being migrated.
|
||||
plugin.getStorage().loadUser(uuid, "null").join();
|
||||
plugin.getStorage().loadUser(uuid, null).join();
|
||||
User lpUser = plugin.getUserManager().getIfLoaded(uuid);
|
||||
|
||||
migrateHolder(world, user, lpUser);
|
||||
|
||||
@@ -262,7 +262,7 @@ public class MigrationGroupManager extends SubCommand<Object> {
|
||||
log.log("Starting user migration.");
|
||||
AtomicInteger userCount = new AtomicInteger(0);
|
||||
for (Map.Entry<UUID, Set<Node>> e : users.entrySet()) {
|
||||
plugin.getStorage().loadUser(e.getKey(), "null").join();
|
||||
plugin.getStorage().loadUser(e.getKey(), null).join();
|
||||
me.lucko.luckperms.common.model.User user = plugin.getUserManager().getIfLoaded(e.getKey());
|
||||
|
||||
for (Node node : e.getValue()) {
|
||||
|
||||
@@ -143,6 +143,7 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
|
||||
continue;
|
||||
}
|
||||
|
||||
// load in a user instance
|
||||
plugin.getStorage().loadUser(u, user.getName()).join();
|
||||
User lpUser = plugin.getUserManager().getIfLoaded(u);
|
||||
|
||||
|
||||
+10
-6
@@ -32,6 +32,7 @@ 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.google.common.collect.ImmutableSet;
|
||||
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.api.event.cause.CreationCause;
|
||||
@@ -94,7 +95,7 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
|
||||
|
||||
if (type == null || type != StorageType.MYSQL) {
|
||||
// We need to load the Hikari/MySQL stuff.
|
||||
DependencyManager.loadDependencies(plugin, DependencyManager.STORAGE_DEPENDENCIES.get(StorageType.MYSQL));
|
||||
DependencyManager.loadStorageDependencies(plugin, ImmutableSet.of(StorageType.MYSQL));
|
||||
}
|
||||
|
||||
String address = args.get(0);
|
||||
@@ -230,7 +231,7 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
|
||||
for (UUID uuid : uuids) {
|
||||
|
||||
// Create a LuckPerms user for the UUID
|
||||
plugin.getStorage().loadUser(uuid, "null").join();
|
||||
plugin.getStorage().loadUser(uuid, null).join();
|
||||
User user = plugin.getUserManager().getIfLoaded(uuid);
|
||||
|
||||
List<Permission> permissions = joinFuture(pm.getPlayerOwnPermissions(uuid));
|
||||
@@ -263,10 +264,13 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
|
||||
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);
|
||||
Group primaryGroup = joinFuture(pm.getPlayerPrimaryGroup(uuid));
|
||||
if (primaryGroup != null && primaryGroup.getName() != null) {
|
||||
String primary = primaryGroup.getName().toLowerCase();
|
||||
if (!primary.equals("default")) {
|
||||
user.setPermission(NodeFactory.make("group." + primary));
|
||||
user.getPrimaryGroup().setStoredValue(primary);
|
||||
}
|
||||
}
|
||||
|
||||
plugin.getUserManager().cleanup(user);
|
||||
|
||||
@@ -45,63 +45,17 @@ public class DummyPermissible implements Permissible {
|
||||
onRefresh.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<PermissionAttachmentInfo> getEffectivePermissions() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
@Override public Set<PermissionAttachmentInfo> getEffectivePermissions() { return Collections.emptySet(); }
|
||||
@Override public boolean isPermissionSet(String name) { return false; }
|
||||
@Override public boolean isPermissionSet(Permission perm) { return false; }
|
||||
@Override public boolean hasPermission(String name) { return false; }
|
||||
@Override public boolean hasPermission(Permission perm) { return false; }
|
||||
@Override public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value) { return null; }
|
||||
@Override public PermissionAttachment addAttachment(Plugin plugin) { return null; }
|
||||
@Override public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks) { return null; }
|
||||
@Override public PermissionAttachment addAttachment(Plugin plugin, int ticks) { return null; }
|
||||
@Override public void removeAttachment(PermissionAttachment attachment) {}
|
||||
@Override public boolean isOp() { return false; }
|
||||
@Override public void setOp(boolean value) {}
|
||||
|
||||
@Override
|
||||
public boolean isPermissionSet(String name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPermissionSet(Permission perm) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(Permission perm) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(Plugin plugin) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(Plugin plugin, int ticks) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttachment(PermissionAttachment attachment) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOp() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOp(boolean value) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -35,77 +35,25 @@ import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
public class DummyPermissibleBase extends PermissibleBase {
|
||||
public DummyPermissibleBase() {
|
||||
public static final DummyPermissibleBase INSTANCE = new DummyPermissibleBase();
|
||||
|
||||
private DummyPermissibleBase() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOp() {
|
||||
return false;
|
||||
}
|
||||
@Override public boolean isOp() { return false; }
|
||||
@Override public void setOp(boolean value) {}
|
||||
@Override public boolean isPermissionSet(String name) { return false; }
|
||||
@Override public boolean isPermissionSet(Permission perm) { return false; }
|
||||
@Override public boolean hasPermission(String inName) { return false; }
|
||||
@Override public boolean hasPermission(Permission perm) { return false; }
|
||||
@Override public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value) { return null; }
|
||||
@Override public PermissionAttachment addAttachment(Plugin plugin) { return null; }
|
||||
@Override public void removeAttachment(PermissionAttachment attachment) {}
|
||||
@Override public void recalculatePermissions() {}
|
||||
@Override public void clearPermissions() {}
|
||||
@Override public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks) { return null; }
|
||||
@Override public PermissionAttachment addAttachment(Plugin plugin, int ticks) { return null; }
|
||||
@Override public Set<PermissionAttachmentInfo> getEffectivePermissions() { return Collections.emptySet(); }
|
||||
|
||||
@Override
|
||||
public void setOp(boolean value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPermissionSet(String name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPermissionSet(Permission perm) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String inName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(Permission perm) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(Plugin plugin) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttachment(PermissionAttachment attachment) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recalculatePermissions() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void clearPermissions() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(Plugin plugin, int ticks) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<PermissionAttachmentInfo> getEffectivePermissions() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.model;
|
||||
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.plugin.PluginLoader;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Dummy plugin instance
|
||||
*/
|
||||
public class DummyPlugin implements Plugin {
|
||||
public static final DummyPlugin INSTANCE = new DummyPlugin();
|
||||
|
||||
private DummyPlugin() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public File getDataFolder() { return null; }
|
||||
@Override public PluginDescriptionFile getDescription() { return null; }
|
||||
@Override public FileConfiguration getConfig() { return null; }
|
||||
@Override public InputStream getResource(String s) { return null; }
|
||||
@Override public void saveConfig() {}
|
||||
@Override public void saveDefaultConfig() {}
|
||||
@Override public void saveResource(String s, boolean b) {}
|
||||
@Override public void reloadConfig() {}
|
||||
@Override public PluginLoader getPluginLoader() { return null; }
|
||||
@Override public Server getServer() { return null; }
|
||||
@Override public void onDisable() {}
|
||||
@Override public void onLoad() {}
|
||||
@Override public void onEnable() {}
|
||||
@Override public boolean isNaggable() { return false; }
|
||||
@Override public void setNaggable(boolean b) {}
|
||||
@Override public ChunkGenerator getDefaultWorldGenerator(String s, String s1) { return null; }
|
||||
@Override public Logger getLogger() { return null; }
|
||||
@Override public String getName() { return null; }
|
||||
@Override public boolean onCommand(CommandSender commandSender, Command command, String s, String[] strings) { return false; }
|
||||
@Override public List<String> onTabComplete(CommandSender commandSender, Command command, String s, String[] strings) { return null; }
|
||||
|
||||
}
|
||||
@@ -35,9 +35,6 @@ import org.bukkit.permissions.PermissionAttachment;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Injects a {@link LPPermissible} into a {@link Player}.
|
||||
@@ -47,7 +44,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
*/
|
||||
@UtilityClass
|
||||
public class Injector {
|
||||
private static final Map<UUID, LPPermissible> INJECTED_PERMISSIBLES = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* All permission checks made on standard Bukkit objects are effectively proxied to a
|
||||
@@ -55,15 +51,17 @@ public class Injector {
|
||||
*
|
||||
* This field is where the permissible is stored on a HumanEntity.
|
||||
*/
|
||||
private static Field humanEntityPermissibleField;
|
||||
private static final Field HUMAN_ENTITY_PERMISSIBLE_FIELD;
|
||||
|
||||
/**
|
||||
* The field where attachments are stored on a permissible base.
|
||||
*/
|
||||
private static Field permissibleBaseAttachmentsField;
|
||||
private static final Field PERMISSIBLE_BASE_ATTACHMENTS_FIELD;
|
||||
|
||||
private static Throwable cachedThrowable = null;
|
||||
static {
|
||||
Field humanEntityPermissibleField;
|
||||
Field permissibleBaseAttachmentsField;
|
||||
|
||||
try {
|
||||
// Catch all. If this setup doesn't fully complete without
|
||||
// exceptions, then the Injector will not work.
|
||||
@@ -85,9 +83,11 @@ public class Injector {
|
||||
permissibleBaseAttachmentsField.setAccessible(true);
|
||||
|
||||
} catch (Throwable t) {
|
||||
cachedThrowable = t;
|
||||
t.printStackTrace();
|
||||
throw new RuntimeException("Injector did not init successfully.", t);
|
||||
}
|
||||
|
||||
HUMAN_ENTITY_PERMISSIBLE_FIELD = humanEntityPermissibleField;
|
||||
PERMISSIBLE_BASE_ATTACHMENTS_FIELD = permissibleBaseAttachmentsField;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,13 +99,8 @@ public class Injector {
|
||||
*/
|
||||
public static void inject(Player player, LPPermissible newPermissible) throws Exception {
|
||||
|
||||
// make sure the class inited without errors, otherwise, print a trace
|
||||
if (cachedThrowable != null) {
|
||||
throw new RuntimeException("Injector did not init successfully.", cachedThrowable);
|
||||
}
|
||||
|
||||
// get the existing PermissibleBase held by the player
|
||||
PermissibleBase oldPermissible = (PermissibleBase) humanEntityPermissibleField.get(player);
|
||||
PermissibleBase oldPermissible = (PermissibleBase) HUMAN_ENTITY_PERMISSIBLE_FIELD.get(player);
|
||||
|
||||
// seems we have already injected into this player.
|
||||
if (oldPermissible instanceof LPPermissible) {
|
||||
@@ -115,23 +110,18 @@ public class Injector {
|
||||
// Move attachments over from the old permissible
|
||||
|
||||
//noinspection unchecked
|
||||
List<PermissionAttachment> attachments = (List<PermissionAttachment>) permissibleBaseAttachmentsField.get(oldPermissible);
|
||||
List<PermissionAttachment> attachments = (List<PermissionAttachment>) PERMISSIBLE_BASE_ATTACHMENTS_FIELD.get(oldPermissible);
|
||||
|
||||
newPermissible.addAttachments(attachments);
|
||||
newPermissible.convertAndAddAttachments(attachments);
|
||||
attachments.clear();
|
||||
oldPermissible.clearPermissions();
|
||||
|
||||
// Setup the new permissible
|
||||
newPermissible.getActive().set(true);
|
||||
newPermissible.recalculatePermissions(false);
|
||||
newPermissible.setOldPermissible(oldPermissible);
|
||||
newPermissible.updateSubscriptionsAsync();
|
||||
|
||||
// inject the new instance
|
||||
humanEntityPermissibleField.set(player, newPermissible);
|
||||
|
||||
// register the injection with the map
|
||||
INJECTED_PERMISSIBLES.put(player.getUniqueId(), newPermissible);
|
||||
HUMAN_ENTITY_PERMISSIBLE_FIELD.set(player, newPermissible);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,17 +129,12 @@ public class Injector {
|
||||
*
|
||||
* @param player the player to uninject from
|
||||
* @param dummy if the replacement permissible should be a dummy.
|
||||
* @param unsubscribe if the extracted permissible should unsubscribe itself. see {@link SubscriptionManager}.
|
||||
* @throws Exception propagates any exceptions which were thrown during uninjection
|
||||
*/
|
||||
public static void unInject(Player player, boolean dummy, boolean unsubscribe) throws Exception {
|
||||
// make sure the class inited without errors, otherwise, print a trace
|
||||
if (cachedThrowable != null) {
|
||||
throw new RuntimeException("Injector did not init successfully.", cachedThrowable);
|
||||
}
|
||||
public static void unInject(Player player, boolean dummy) throws Exception {
|
||||
|
||||
// gets the players current permissible.
|
||||
PermissibleBase permissible = (PermissibleBase) humanEntityPermissibleField.get(player);
|
||||
PermissibleBase permissible = (PermissibleBase) HUMAN_ENTITY_PERMISSIBLE_FIELD.get(player);
|
||||
|
||||
// only uninject if the permissible was a luckperms one.
|
||||
if (permissible instanceof LPPermissible) {
|
||||
@@ -158,43 +143,23 @@ public class Injector {
|
||||
// clear all permissions
|
||||
lpPermissible.clearPermissions();
|
||||
|
||||
// try to unsubscribe
|
||||
if (unsubscribe) {
|
||||
lpPermissible.unsubscribeFromAllAsync();
|
||||
}
|
||||
|
||||
// set to inactive
|
||||
lpPermissible.getActive().set(false);
|
||||
|
||||
// handle the replacement permissible.
|
||||
if (dummy) {
|
||||
// just inject a dummy class. this is used when we know the player is about to quit the server.
|
||||
humanEntityPermissibleField.set(player, new DummyPermissibleBase());
|
||||
HUMAN_ENTITY_PERMISSIBLE_FIELD.set(player, DummyPermissibleBase.INSTANCE);
|
||||
|
||||
} else {
|
||||
// otherwise, inject the permissible they had when we first injected.
|
||||
|
||||
List<PermissionAttachment> lpAttachments = lpPermissible.getAttachments();
|
||||
|
||||
PermissibleBase newPb = lpPermissible.getOldPermissible();
|
||||
if (newPb == null) {
|
||||
newPb = new PermissibleBase(player);
|
||||
}
|
||||
|
||||
//noinspection unchecked
|
||||
List<PermissionAttachment> newPbAttachments = (List<PermissionAttachment>) permissibleBaseAttachmentsField.get(newPb);
|
||||
newPbAttachments.addAll(lpAttachments);
|
||||
lpAttachments.clear();
|
||||
|
||||
humanEntityPermissibleField.set(player, newPb);
|
||||
HUMAN_ENTITY_PERMISSIBLE_FIELD.set(player, newPb);
|
||||
}
|
||||
}
|
||||
|
||||
INJECTED_PERMISSIBLES.remove(player.getUniqueId());
|
||||
}
|
||||
|
||||
public static LPPermissible getPermissible(UUID uuid) {
|
||||
return INJECTED_PERMISSIBLES.get(uuid);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,29 +32,22 @@ import lombok.Setter;
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.caching.UserCache;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.verbose.CheckOrigin;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.permissions.PermissibleBase;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.permissions.PermissionAttachment;
|
||||
import org.bukkit.permissions.PermissionAttachmentInfo;
|
||||
import org.bukkit.permissions.PermissionRemovedExecutor;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
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;
|
||||
|
||||
/**
|
||||
@@ -78,14 +71,11 @@ public class LPPermissible extends PermissibleBase {
|
||||
private final User user;
|
||||
|
||||
// the player this permissible is injected into.
|
||||
private final Player parent;
|
||||
private final Player player;
|
||||
|
||||
// the luckperms plugin instance
|
||||
private final LPBukkitPlugin plugin;
|
||||
|
||||
// the subscription manager, handling the players permission subscriptions.
|
||||
private final SubscriptionManager subscriptions;
|
||||
|
||||
// the players previous permissible. (the one they had before this one was injected)
|
||||
@Setter
|
||||
private PermissibleBase oldPermissible = null;
|
||||
@@ -93,30 +83,26 @@ public class LPPermissible extends PermissibleBase {
|
||||
// if the permissible is currently active.
|
||||
private final AtomicBoolean active = new AtomicBoolean(false);
|
||||
|
||||
// the permissions registered by PermissionAttachments.
|
||||
// stored in this format, as that's what is used by #getEffectivePermissions
|
||||
private final Map<String, PermissionAttachmentInfo> attachmentPermissions = new ConcurrentHashMap<>();
|
||||
|
||||
// the attachments hooked onto the permissible.
|
||||
private final List<PermissionAttachment> attachments = Collections.synchronizedList(new ArrayList<>());
|
||||
// this collection is only modified by the attachments themselves
|
||||
final Set<LPPermissionAttachment> attachments = ConcurrentHashMap.newKeySet();
|
||||
|
||||
public LPPermissible(@NonNull Player parent, @NonNull User user, @NonNull LPBukkitPlugin plugin) {
|
||||
super(parent);
|
||||
public LPPermissible(@NonNull Player player, @NonNull User user, @NonNull LPBukkitPlugin plugin) {
|
||||
super(player);
|
||||
this.user = user;
|
||||
this.parent = parent;
|
||||
this.player = player;
|
||||
this.plugin = plugin;
|
||||
this.subscriptions = new SubscriptionManager(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPermissionSet(@NonNull String permission) {
|
||||
Tristate ts = user.getUserData().getPermissionData(calculateContexts()).getPermissionValue(permission);
|
||||
Tristate ts = user.getUserData().getPermissionData(calculateContexts()).getPermissionValue(permission, CheckOrigin.PLATFORM_LOOKUP_CHECK);
|
||||
return ts != Tristate.UNDEFINED || Permission.DEFAULT_PERMISSION.getValue(isOp());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPermissionSet(@NonNull Permission permission) {
|
||||
Tristate ts = user.getUserData().getPermissionData(calculateContexts()).getPermissionValue(permission.getName());
|
||||
Tristate ts = user.getUserData().getPermissionData(calculateContexts()).getPermissionValue(permission.getName(), CheckOrigin.PLATFORM_LOOKUP_CHECK);
|
||||
if (ts != Tristate.UNDEFINED) {
|
||||
return true;
|
||||
}
|
||||
@@ -130,13 +116,13 @@ public class LPPermissible extends PermissibleBase {
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(@NonNull String permission) {
|
||||
Tristate ts = user.getUserData().getPermissionData(calculateContexts()).getPermissionValue(permission);
|
||||
Tristate ts = user.getUserData().getPermissionData(calculateContexts()).getPermissionValue(permission, CheckOrigin.PLATFORM_PERMISSION_CHECK);
|
||||
return ts != Tristate.UNDEFINED ? ts.asBoolean() : Permission.DEFAULT_PERMISSION.getValue(isOp());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(@NonNull Permission permission) {
|
||||
Tristate ts = user.getUserData().getPermissionData(calculateContexts()).getPermissionValue(permission.getName());
|
||||
Tristate ts = user.getUserData().getPermissionData(calculateContexts()).getPermissionValue(permission.getName(), CheckOrigin.PLATFORM_PERMISSION_CHECK);
|
||||
if (ts != Tristate.UNDEFINED) {
|
||||
return ts.asBoolean();
|
||||
}
|
||||
@@ -148,63 +134,15 @@ public class LPPermissible extends PermissibleBase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the players subscriptions asynchronously
|
||||
*/
|
||||
public void updateSubscriptionsAsync() {
|
||||
if (!active.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
plugin.doAsync(this::updateSubscriptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the players subscriptions
|
||||
*/
|
||||
public void updateSubscriptions() {
|
||||
if (!active.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
UserCache cache = user.getUserData();
|
||||
|
||||
// calculate their "active" permissions
|
||||
Set<String> ent = new HashSet<>(cache.getPermissionData(calculateContexts()).getImmutableBacking().keySet());
|
||||
|
||||
// include defaults, if enabled.
|
||||
if (plugin.getConfiguration().get(ConfigKeys.APPLY_BUKKIT_DEFAULT_PERMISSIONS)) {
|
||||
if (parent.isOp()) {
|
||||
ent.addAll(plugin.getDefaultsProvider().getOpDefaults().keySet());
|
||||
} else {
|
||||
ent.addAll(plugin.getDefaultsProvider().getNonOpDefaults().keySet());
|
||||
}
|
||||
}
|
||||
|
||||
subscriptions.subscribe(ent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribes from all permissions asynchronously
|
||||
*/
|
||||
public void unsubscribeFromAllAsync() {
|
||||
plugin.doAsync(this::unsubscribeFromAll);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribes from all permissions
|
||||
*/
|
||||
public void unsubscribeFromAll() {
|
||||
subscriptions.subscribe(Collections.emptySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds attachments to this permissible.
|
||||
*
|
||||
* @param attachments the attachments to add
|
||||
*/
|
||||
public void addAttachments(Collection<PermissionAttachment> attachments) {
|
||||
this.attachments.addAll(attachments);
|
||||
public void convertAndAddAttachments(Collection<PermissionAttachment> attachments) {
|
||||
for (PermissionAttachment attachment : attachments) {
|
||||
new LPPermissionAttachment(this, attachment).hook();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,147 +151,82 @@ public class LPPermissible extends PermissibleBase {
|
||||
*
|
||||
* @return the calculated contexts for the player.
|
||||
*/
|
||||
public Contexts calculateContexts() {
|
||||
return plugin.getContextManager().getApplicableContexts(parent);
|
||||
private Contexts calculateContexts() {
|
||||
return plugin.getContextManager().getApplicableContexts(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOp(boolean value) {
|
||||
parent.setOp(value);
|
||||
player.setOp(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<PermissionAttachmentInfo> getEffectivePermissions() {
|
||||
Set<PermissionAttachmentInfo> perms = new HashSet<>();
|
||||
perms.addAll(attachmentPermissions.values());
|
||||
|
||||
perms.addAll(
|
||||
user.getUserData().getPermissionData(calculateContexts()).getImmutableBacking().entrySet().stream()
|
||||
.map(e -> new PermissionAttachmentInfo(parent, e.getKey(), null, e.getValue()))
|
||||
.map(e -> new PermissionAttachmentInfo(player, e.getKey(), null, e.getValue()))
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
|
||||
return perms;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(@NonNull Plugin plugin, @NonNull String name, boolean value) {
|
||||
if (!plugin.isEnabled()) {
|
||||
throw new IllegalArgumentException("Plugin " + plugin.getDescription().getFullName() + " is not enabled");
|
||||
}
|
||||
|
||||
PermissionAttachment result = addAttachment(plugin);
|
||||
result.setPermission(name, value);
|
||||
|
||||
recalculatePermissions();
|
||||
|
||||
return result;
|
||||
public LPPermissionAttachment addAttachment(Plugin plugin) {
|
||||
LPPermissionAttachment ret = new LPPermissionAttachment(this, plugin);
|
||||
ret.hook();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(@NonNull Plugin plugin) {
|
||||
if (!plugin.isEnabled()) {
|
||||
throw new IllegalArgumentException("Plugin " + plugin.getDescription().getFullName() + " is not enabled");
|
||||
}
|
||||
|
||||
PermissionAttachment result = new PermissionAttachment(plugin, parent);
|
||||
|
||||
attachments.add(result);
|
||||
recalculatePermissions();
|
||||
|
||||
return result;
|
||||
public PermissionAttachment addAttachment(Plugin plugin, @NonNull String name, boolean value) {
|
||||
PermissionAttachment ret = addAttachment(plugin);
|
||||
ret.setPermission(name, value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(@NonNull Plugin plugin, @NonNull String name, boolean value, int ticks) {
|
||||
public LPPermissionAttachment addAttachment(@NonNull Plugin plugin, int ticks) {
|
||||
if (!plugin.isEnabled()) {
|
||||
throw new IllegalArgumentException("Plugin " + plugin.getDescription().getFullName() + " is not enabled");
|
||||
}
|
||||
|
||||
PermissionAttachment result = addAttachment(plugin, ticks);
|
||||
if (result != null) {
|
||||
result.setPermission(name, value);
|
||||
LPPermissionAttachment ret = addAttachment(plugin);
|
||||
if (getPlugin().getServer().getScheduler().scheduleSyncDelayedTask(plugin, ret::remove, ticks) == -1) {
|
||||
ret.remove();
|
||||
throw new RuntimeException("Could not add PermissionAttachment to " + player + " for plugin " + plugin.getDescription().getFullName() + ": Scheduler returned -1");
|
||||
}
|
||||
|
||||
return result;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(@NonNull Plugin plugin, int ticks) {
|
||||
if (!plugin.isEnabled()) {
|
||||
throw new IllegalArgumentException("Plugin " + plugin.getDescription().getFullName() + " is not enabled");
|
||||
}
|
||||
|
||||
PermissionAttachment result = addAttachment(plugin);
|
||||
if (Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, result::remove, ticks) == -1) {
|
||||
Bukkit.getServer().getLogger().log(Level.WARNING, "Could not add PermissionAttachment to " + parent + " for plugin " + plugin.getDescription().getFullName() + ": Scheduler returned -1");
|
||||
result.remove();
|
||||
return null;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
public LPPermissionAttachment addAttachment(Plugin plugin, @NonNull String name, boolean value, int ticks) {
|
||||
LPPermissionAttachment ret = addAttachment(plugin, ticks);
|
||||
ret.setPermission(name, value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttachment(@NonNull PermissionAttachment attachment) {
|
||||
if (attachments.contains(attachment)) {
|
||||
attachments.remove(attachment);
|
||||
PermissionRemovedExecutor ex = attachment.getRemovalCallback();
|
||||
|
||||
if (ex != null) {
|
||||
ex.attachmentRemoved(attachment);
|
||||
}
|
||||
|
||||
recalculatePermissions();
|
||||
} else {
|
||||
throw new IllegalArgumentException("Given attachment is not part of Permissible object " + parent);
|
||||
if (!(attachment instanceof LPPermissionAttachment)) {
|
||||
throw new IllegalArgumentException("Given attachment is not a LPPermissionAttachment.");
|
||||
}
|
||||
|
||||
LPPermissionAttachment a = ((LPPermissionAttachment) attachment);
|
||||
if (a.getPermissible() != this) {
|
||||
throw new IllegalArgumentException("Attachment does not belong to this permissible.");
|
||||
}
|
||||
|
||||
a.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recalculatePermissions() {
|
||||
recalculatePermissions(true);
|
||||
}
|
||||
|
||||
public void recalculatePermissions(boolean invalidate) {
|
||||
if (attachmentPermissions == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
attachmentPermissions.clear();
|
||||
|
||||
for (PermissionAttachment attachment : attachments) {
|
||||
calculateChildPermissions(attachment.getPermissions(), false, attachment);
|
||||
}
|
||||
|
||||
if (invalidate) {
|
||||
user.getUserData().invalidatePermissionCalculators();
|
||||
}
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void clearPermissions() {
|
||||
Set<String> perms = attachmentPermissions.keySet();
|
||||
|
||||
for (String name : perms) {
|
||||
Bukkit.getServer().getPluginManager().unsubscribeFromPermission(name, parent);
|
||||
}
|
||||
|
||||
attachmentPermissions.clear();
|
||||
}
|
||||
|
||||
private void calculateChildPermissions(Map<String, Boolean> children, boolean invert, PermissionAttachment attachment) {
|
||||
for (Map.Entry<String, Boolean> e : children.entrySet()) {
|
||||
Permission perm = Bukkit.getServer().getPluginManager().getPermission(e.getKey());
|
||||
boolean value = e.getValue() ^ invert;
|
||||
String name = e.getKey().toLowerCase();
|
||||
|
||||
attachmentPermissions.put(name, new PermissionAttachmentInfo(parent, name, attachment, value));
|
||||
Bukkit.getServer().getPluginManager().subscribeToPermission(name, parent);
|
||||
|
||||
if (perm != null) {
|
||||
calculateChildPermissions(perm.getChildren(), !value, attachment);
|
||||
}
|
||||
}
|
||||
public void clearPermissions() {
|
||||
attachments.forEach(LPPermissionAttachment::remove);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,396 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.node.ImmutableTransientNode;
|
||||
import me.lucko.luckperms.common.node.NodeFactory;
|
||||
|
||||
import org.bukkit.permissions.PermissibleBase;
|
||||
import org.bukkit.permissions.PermissionAttachment;
|
||||
import org.bukkit.permissions.PermissionRemovedExecutor;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* PermissionAttachment for LuckPerms.
|
||||
*
|
||||
* Applies all permissions directly to the backing user instance via transient nodes.
|
||||
*/
|
||||
public class LPPermissionAttachment extends PermissionAttachment {
|
||||
|
||||
/**
|
||||
* The field in PermissionAttachment where the attachments applied permissions
|
||||
* are *usually* held.
|
||||
*/
|
||||
private static final Field PERMISSION_ATTACHMENT_PERMISSIONS_FIELD;
|
||||
|
||||
static {
|
||||
Field permissionAttachmentPermissionsField;
|
||||
try {
|
||||
permissionAttachmentPermissionsField = PermissibleBase.class.getDeclaredField("permissions");
|
||||
permissionAttachmentPermissionsField.setAccessible(true);
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
PERMISSION_ATTACHMENT_PERMISSIONS_FIELD = permissionAttachmentPermissionsField;
|
||||
}
|
||||
|
||||
/**
|
||||
* The parent LPPermissible
|
||||
*/
|
||||
@Getter
|
||||
private final LPPermissible permissible;
|
||||
|
||||
/**
|
||||
* The plugin which "owns" this attachment, may be null
|
||||
*/
|
||||
private final Plugin owner;
|
||||
|
||||
/**
|
||||
* The permissions being applied by this attachment
|
||||
*/
|
||||
private final Map<String, Boolean> perms = Collections.synchronizedMap(new HashMap<>());
|
||||
|
||||
/**
|
||||
* If the attachment has been applied to the user
|
||||
*/
|
||||
private boolean hooked = false;
|
||||
|
||||
/**
|
||||
* Callback to run when the attachment is removed
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private PermissionRemovedExecutor removalCallback = null;
|
||||
|
||||
public LPPermissionAttachment(LPPermissible permissible, Plugin owner) {
|
||||
super(DummyPlugin.INSTANCE, null);
|
||||
this.permissible = permissible;
|
||||
this.owner = owner;
|
||||
|
||||
injectFakeMap();
|
||||
}
|
||||
|
||||
public LPPermissionAttachment(LPPermissible permissible, PermissionAttachment bukkit) {
|
||||
super(DummyPlugin.INSTANCE, null);
|
||||
this.permissible = permissible;
|
||||
this.owner = null;
|
||||
|
||||
// copy
|
||||
perms.putAll(bukkit.getPermissions());
|
||||
|
||||
injectFakeMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects a fake 'permissions' map into the superclass, for (clever/dumb??) plugins
|
||||
* which attempt to modify attachment permissions using reflection to get around the slow bukkit
|
||||
* behaviour in the base PermissionAttachment implementation.
|
||||
*
|
||||
* The fake map proxies calls back to the methods on this attachment
|
||||
*/
|
||||
private void injectFakeMap() {
|
||||
// inner class - this proxies calls back to us
|
||||
FakeBackingMap fakeMap = new FakeBackingMap();
|
||||
|
||||
try {
|
||||
// what's this doing, ay?
|
||||
// the field we need to modify is in the superclass - it's set to private
|
||||
// so we have to use reflection to modify it.
|
||||
PERMISSION_ATTACHMENT_PERMISSIONS_FIELD.set(this, fakeMap);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooks this attachment with the parent {@link User} instance.
|
||||
*/
|
||||
public void hook() {
|
||||
hooked = true;
|
||||
permissible.attachments.add(this);
|
||||
for (Map.Entry<String, Boolean> entry : perms.entrySet()) {
|
||||
if (entry.getKey() == null || entry.getKey().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
setPermissionInternal(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private void setPermissionInternal(String name, boolean value) {
|
||||
if (!permissible.getPlugin().getConfiguration().get(ConfigKeys.APPLY_BUKKIT_ATTACHMENT_PERMISSIONS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// construct a node for the permission being set
|
||||
// we use the servers static context to *try* to ensure that the node will apply
|
||||
Node node = NodeFactory.newBuilder(name)
|
||||
.setValue(value)
|
||||
.withExtraContext(permissible.getPlugin().getContextManager().getStaticContext())
|
||||
.build();
|
||||
|
||||
// convert the constructed node to a transient node instance to refer back to this attachment
|
||||
ImmutableTransientNode transientNode = ImmutableTransientNode.of(node, this);
|
||||
|
||||
// set the transient node
|
||||
User user = permissible.getUser();
|
||||
if (user.setTransientPermission(transientNode).asBoolean()) {
|
||||
user.getRefreshBuffer().request();
|
||||
}
|
||||
}
|
||||
|
||||
private void unsetPermissionInternal(String name) {
|
||||
if (!permissible.getPlugin().getConfiguration().get(ConfigKeys.APPLY_BUKKIT_ATTACHMENT_PERMISSIONS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// remove transient permissions from the holder which were added by this attachment & equal the permission
|
||||
User user = permissible.getUser();
|
||||
if (user.removeIfTransient(n -> n instanceof ImmutableTransientNode && ((ImmutableTransientNode) n).getOwner() == this && n.getPermission().equals(name))) {
|
||||
user.getRefreshBuffer().request();
|
||||
}
|
||||
}
|
||||
|
||||
private void clearInternal() {
|
||||
// remove all transient permissions added by this attachment
|
||||
User user = permissible.getUser();
|
||||
if (user.removeIfTransient(n -> n instanceof ImmutableTransientNode && ((ImmutableTransientNode) n).getOwner() == this)) {
|
||||
user.getRefreshBuffer().request();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove() {
|
||||
if (!hooked) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// clear the internal permissions
|
||||
clearInternal();
|
||||
|
||||
// run the callback
|
||||
if (removalCallback != null) {
|
||||
removalCallback.attachmentRemoved(this);
|
||||
}
|
||||
|
||||
// unhook from the permissible
|
||||
hooked = false;
|
||||
permissible.attachments.remove(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPermission(String name, boolean value) {
|
||||
Preconditions.checkNotNull(name, "name is null");
|
||||
Preconditions.checkArgument(!name.isEmpty(), "name is empty");
|
||||
|
||||
String permission = name.toLowerCase();
|
||||
|
||||
Boolean previous = perms.put(permission, value);
|
||||
if (previous != null && previous == value) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if we're not hooked, thn don't actually apply the change
|
||||
// it will get applied on hook - if that ever happens
|
||||
if (!hooked) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (previous != null) {
|
||||
unsetPermissionInternal(permission);
|
||||
}
|
||||
|
||||
setPermissionInternal(permission, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetPermission(String name) {
|
||||
Preconditions.checkNotNull(name, "name is null");
|
||||
Preconditions.checkArgument(!name.isEmpty(), "name is empty");
|
||||
|
||||
String permission = name.toLowerCase();
|
||||
|
||||
Boolean previous = perms.remove(permission);
|
||||
if (previous == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if we're not hooked, thn don't actually apply the change
|
||||
// it will get applied on hook - if that ever happens
|
||||
if (!hooked) {
|
||||
return;
|
||||
}
|
||||
|
||||
unsetPermissionInternal(permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Boolean> getPermissions() {
|
||||
return perms;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Plugin getPlugin() {
|
||||
return owner != null ? owner : permissible.getPlugin();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return this == obj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return System.identityHashCode(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* A fake map to be injected into the superclass. This implementation simply
|
||||
* proxies calls back to this attachment instance.
|
||||
*
|
||||
* Some (clever/dumb??) plugins attempt to modify attachment permissions using reflection
|
||||
* to get around the slow bukkit behaviour in the base PermissionAttachment implementation.
|
||||
*
|
||||
* An instance of this map is injected into the super instance so these plugins continue
|
||||
* to work with LuckPerms.
|
||||
*/
|
||||
private final class FakeBackingMap implements Map<String, Boolean> {
|
||||
|
||||
@Override
|
||||
public Boolean put(String key, Boolean value) {
|
||||
|
||||
// grab the previous result, so we can still satisfy the method signature of Map
|
||||
Boolean previous = perms.get(key);
|
||||
|
||||
// proxy the call back through the PermissionAttachment instance
|
||||
setPermission(key, value);
|
||||
|
||||
// return the previous value
|
||||
return previous;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean remove(Object key) {
|
||||
// we only accept string keys
|
||||
if (!(key instanceof String)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String permission = ((String) key);
|
||||
|
||||
// grab the previous result, so we can still satisfy the method signature of Map
|
||||
Boolean previous = perms.get(permission);
|
||||
|
||||
// proxy the call back through the PermissionAttachment instance
|
||||
unsetPermission(permission);
|
||||
|
||||
// return the previous value
|
||||
return previous;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends String, ? extends Boolean> m) {
|
||||
for (Map.Entry<? extends String, ? extends Boolean> entry : m.entrySet()) {
|
||||
put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
// remove the permissions which have already been applied
|
||||
if (hooked) {
|
||||
clearInternal();
|
||||
}
|
||||
|
||||
// clear the backing map
|
||||
perms.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
// return the size of the permissions map - probably the most accurate value we have
|
||||
return perms.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
// return if the permissions map is empty - again probably the most accurate thing
|
||||
// we can return
|
||||
return perms.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
// just proxy
|
||||
return perms.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
// just proxy
|
||||
return perms.containsValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean get(Object key) {
|
||||
// just proxy
|
||||
return perms.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> keySet() {
|
||||
// just proxy
|
||||
return perms.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Boolean> values() {
|
||||
// just proxy
|
||||
return perms.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<String, Boolean>> entrySet() {
|
||||
// just proxy
|
||||
return perms.entrySet();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.model;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.utils.ImmutableCollectors;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.permissions.Permissible;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* A replacement map for the 'permSubs' instance in Bukkit's SimplePluginManager.
|
||||
*
|
||||
* This instance allows LuckPerms to intercept calls to
|
||||
* {@link PluginManager#subscribeToPermission(String, Permissible)},
|
||||
* {@link PluginManager#unsubscribeFromPermission(String, Permissible)} and
|
||||
* {@link PluginManager#getPermissionSubscriptions(String)}.
|
||||
*
|
||||
* Bukkit for some reason sometimes uses subscription status to determine whether
|
||||
* a permissible has a given node, instead of checking directly with
|
||||
* {@link Permissible#hasPermission(Permission)}.
|
||||
*
|
||||
* {@link org.bukkit.Server#broadcast(String, String)} is a good example of this.
|
||||
*
|
||||
* In order to implement predicable Bukkit behaviour, LP has two options:
|
||||
* 1) register subscriptions for all players as normal, or
|
||||
* 2) inject it's own map instance to proxy calls to {@link PluginManager#getPermissionSubscriptions(String)} back to LuckPerms.
|
||||
*
|
||||
* This class implements option 2 above. It is preferred because it is faster & uses less memory
|
||||
*/
|
||||
public class LPSubscriptionMap extends HashMap<String, Map<Permissible, Boolean>> {
|
||||
|
||||
// the plugin instance
|
||||
private final LPBukkitPlugin plugin;
|
||||
|
||||
public LPSubscriptionMap(LPBukkitPlugin plugin, Map<String, Map<Permissible, Boolean>> existingData) {
|
||||
super(existingData);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
/* The get method is the only one which is actually used by SimplePluginManager
|
||||
* we override it to always return a value - which means the null check in
|
||||
* subscribeToDefaultPerms always fails - soo, we don't have to worry too much
|
||||
* about implementing #put.
|
||||
*
|
||||
* we also ensure all returns are LPSubscriptionValueMaps. this extension
|
||||
* will also delegate checks to online players - meaning we don't ever
|
||||
* have to register their subscriptions with the plugin manager.
|
||||
*/
|
||||
@Override
|
||||
public Map<Permissible, Boolean> get(Object key) {
|
||||
if (key == null || !(key instanceof String)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String permission = ((String) key);
|
||||
|
||||
Map<Permissible, Boolean> result = super.get(key);
|
||||
|
||||
if (result == null) {
|
||||
// calculate a new map - always!
|
||||
result = new LPSubscriptionValueMap(permission);
|
||||
super.put(permission, result);
|
||||
} else if (!(result instanceof LPSubscriptionValueMap)) {
|
||||
// ensure return type is a LPSubscriptionMap
|
||||
result = new LPSubscriptionValueMap(permission, result);
|
||||
super.put(permission, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Permissible, Boolean> put(String key, Map<Permissible, Boolean> value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException("Map value cannot be null");
|
||||
}
|
||||
|
||||
// ensure values are LP subscription maps
|
||||
if (!(value instanceof LPSubscriptionValueMap)) {
|
||||
value = new LPSubscriptionValueMap(key, value);
|
||||
}
|
||||
return super.put(key, value);
|
||||
}
|
||||
|
||||
// if the key isn't null and is a string, #get will always return a value for it
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return key != null && key instanceof String;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this map back to a standard HashMap
|
||||
*
|
||||
* @return a standard representation of this map
|
||||
*/
|
||||
public Map<String, Map<Permissible, Boolean>> detach() {
|
||||
Map<String, Map<Permissible, Boolean>> ret = new HashMap<>();
|
||||
|
||||
for (Map.Entry<String, Map<Permissible, Boolean>> ent : entrySet()) {
|
||||
if (ent.getValue() instanceof LPSubscriptionValueMap) {
|
||||
ret.put(ent.getKey(), ((LPSubscriptionValueMap) ent.getValue()).backing);
|
||||
} else {
|
||||
ret.put(ent.getKey(), ent.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Value map extension which includes LP objects in Permissible related queries.
|
||||
*/
|
||||
public class LPSubscriptionValueMap implements Map<Permissible, Boolean> {
|
||||
|
||||
// the permission being mapped to this value map
|
||||
private final String permission;
|
||||
|
||||
// the backing map
|
||||
private final Map<Permissible, Boolean> backing;
|
||||
|
||||
public LPSubscriptionValueMap(String permission, Map<Permissible, Boolean> backing) {
|
||||
this.permission = permission;
|
||||
this.backing = backing;
|
||||
}
|
||||
|
||||
public LPSubscriptionValueMap(String permission) {
|
||||
this(permission, new WeakHashMap<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean get(Object key) {
|
||||
boolean isPlayer = key instanceof Player;
|
||||
|
||||
// if the key is a player, check their LPPermissible first
|
||||
if (isPlayer) {
|
||||
Permissible p = (Permissible) key;
|
||||
if (p.isPermissionSet(permission)) {
|
||||
return p.hasPermission(permission);
|
||||
}
|
||||
}
|
||||
|
||||
// then try the map
|
||||
Boolean result = backing.get(key);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// then try the map, if we haven't already
|
||||
if (!isPlayer && key instanceof Permissible) {
|
||||
Permissible p = (Permissible) key;
|
||||
if (p.isPermissionSet(permission)) {
|
||||
return p.hasPermission(permission);
|
||||
}
|
||||
}
|
||||
|
||||
// no result
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
// check the backing map, as well as if the permissible has the perm set
|
||||
return backing.containsKey(key) || (key instanceof Permissible && ((Permissible) key).isPermissionSet(permission));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Permissible> keySet() {
|
||||
// gather players (LPPermissibles)
|
||||
Set<Permissible> players = plugin.getServer().getOnlinePlayers().stream()
|
||||
.filter(player -> player.isPermissionSet(permission))
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// then combine the players with the backing map
|
||||
return Sets.union(players, backing.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<Permissible, Boolean>> entrySet() {
|
||||
return keySet().stream()
|
||||
.map(p -> {
|
||||
Boolean ret = get(p);
|
||||
return ret != null ? Maps.immutableEntry(p, ret) : null;
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(ImmutableCollectors.toImmutableSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
// we never want to remove this map from the parent - since it just gets recreated
|
||||
// on subsequent calls
|
||||
return false;
|
||||
}
|
||||
|
||||
// just delegate to the backing map
|
||||
|
||||
@Override
|
||||
public Boolean put(Permissible key, Boolean value) {
|
||||
return backing.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean remove(Object key) {
|
||||
return backing.remove(key);
|
||||
}
|
||||
|
||||
// the following methods are not used in the current impls of PluginManager, but just delegate them for now
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return backing.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return backing.containsValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends Permissible, ? extends Boolean> m) {
|
||||
backing.putAll(m);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
backing.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Boolean> values() {
|
||||
return backing.values();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.model;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import org.bukkit.permissions.Permission;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Handles permission subscriptions with Bukkits plugin manager, for a given LPPermissible.
|
||||
*
|
||||
* Bukkit for some reason sometimes uses subscription status to determine whether a permissible has a given node, instead
|
||||
* of checking directly with {@link org.bukkit.permissions.Permissible#hasPermission(Permission)}.
|
||||
*
|
||||
* {@link org.bukkit.Bukkit#broadcast(String, String)} is a good example of this.
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class SubscriptionManager {
|
||||
|
||||
private final LPPermissible permissible;
|
||||
private Set<String> currentSubscriptions = ImmutableSet.of();
|
||||
|
||||
public synchronized void subscribe(Set<String> perms) {
|
||||
Set<String> newPerms = ImmutableSet.copyOf(perms);
|
||||
|
||||
// we compare changes to avoid unnecessary time wasted on the main thread mutating this data.
|
||||
// the changes can be calculated here async, and then only the needed changes can be applied.
|
||||
Map.Entry<Set<String>, Set<String>> changes = compareSets(newPerms, currentSubscriptions);
|
||||
|
||||
Set<String> toAdd = changes.getKey();
|
||||
Set<String> toRemove = changes.getValue();
|
||||
|
||||
permissible.getPlugin().doSync(() -> {
|
||||
for (String s : toAdd) {
|
||||
permissible.getPlugin().getServer().getPluginManager().subscribeToPermission(s, permissible.getParent());
|
||||
}
|
||||
for (String s : toRemove) {
|
||||
permissible.getPlugin().getServer().getPluginManager().unsubscribeFromPermission(s, permissible.getParent());
|
||||
}
|
||||
});
|
||||
|
||||
this.currentSubscriptions = newPerms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two sets
|
||||
* @param local the local set
|
||||
* @param remote the remote set
|
||||
* @return the entries to add to remote, and the entries to remove from remote
|
||||
*/
|
||||
private static Map.Entry<Set<String>, Set<String>> compareSets(Set<String> local, Set<String> remote) {
|
||||
// entries in local but not remote need to be added
|
||||
// entries in remote but not local need to be removed
|
||||
|
||||
Set<String> toAdd = new HashSet<>(local);
|
||||
toAdd.removeAll(remote);
|
||||
|
||||
Set<String> toRemove = new HashSet<>(remote);
|
||||
toRemove.removeAll(local);
|
||||
|
||||
return Maps.immutableEntry(toAdd, toRemove);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.model;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.permissions.Permissible;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.SimplePluginManager;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Map;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class SubscriptionMapInjector implements Runnable {
|
||||
private static final Field PERM_SUBS_FIELD;
|
||||
|
||||
static {
|
||||
Field permSubsField;
|
||||
try {
|
||||
permSubsField = SimplePluginManager.class.getDeclaredField("permSubs");
|
||||
permSubsField.setAccessible(true);
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
PERM_SUBS_FIELD = permSubsField;
|
||||
}
|
||||
|
||||
private final LPBukkitPlugin plugin;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
inject();
|
||||
} catch (Exception e) {
|
||||
plugin.getLog().severe("Exception occurred whilst injecting LuckPerms Permission Subscription map.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void inject() throws Exception {
|
||||
PluginManager pluginManager = plugin.getServer().getPluginManager();
|
||||
|
||||
if (!(pluginManager instanceof SimplePluginManager)) {
|
||||
plugin.getLog().severe("PluginManager instance is not a 'SimplePluginManager', instead: " + pluginManager.getClass());
|
||||
plugin.getLog().severe("Unable to inject LuckPerms Permission Subscription map.");
|
||||
return;
|
||||
}
|
||||
|
||||
Object map = PERM_SUBS_FIELD.get(pluginManager);
|
||||
if (map instanceof LPSubscriptionMap) {
|
||||
return; // already injected
|
||||
}
|
||||
|
||||
//noinspection unchecked
|
||||
Map<String, Map<Permissible, Boolean>> castedMap = (Map<String, Map<Permissible, Boolean>>) map;
|
||||
|
||||
// make a new subscription map
|
||||
LPSubscriptionMap newMap = new LPSubscriptionMap(plugin, castedMap);
|
||||
|
||||
// inject it
|
||||
PERM_SUBS_FIELD.set(pluginManager, newMap);
|
||||
}
|
||||
|
||||
public static void uninject() {
|
||||
try {
|
||||
PluginManager pluginManager = Bukkit.getServer().getPluginManager();
|
||||
if (!(pluginManager instanceof SimplePluginManager)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object map = PERM_SUBS_FIELD.get(pluginManager);
|
||||
if (map instanceof LPSubscriptionMap) {
|
||||
LPSubscriptionMap lpMap = (LPSubscriptionMap) map;
|
||||
PERM_SUBS_FIELD.set(pluginManager, lpMap.detach());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.processors;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Performs the initial setup for Bukkit permission processors
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class BukkitProcessorsSetupTask implements Runnable {
|
||||
private final LPBukkitPlugin plugin;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
plugin.getDefaultsProvider().refresh();
|
||||
plugin.getChildPermissionProvider().setup();
|
||||
|
||||
Set<String> perms = new HashSet<>();
|
||||
plugin.getServer().getPluginManager().getPermissions().forEach(p -> {
|
||||
perms.add(p.getName());
|
||||
perms.addAll(p.getChildren().keySet());
|
||||
});
|
||||
|
||||
perms.forEach(p -> plugin.getPermissionVault().offer(p));
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
@RequiredArgsConstructor
|
||||
public class ChildProcessor implements PermissionProcessor {
|
||||
private final ChildPermissionProvider provider;
|
||||
private Map<String, Boolean> childPermissions = new ConcurrentHashMap<>();
|
||||
private final Map<String, Boolean> childPermissions = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public Tristate hasPermission(String permission) {
|
||||
|
||||
@@ -45,7 +45,7 @@ public class DefaultsProcessor implements PermissionProcessor {
|
||||
|
||||
@Override
|
||||
public Tristate hasPermission(String permission) {
|
||||
Tristate t = defaultsProvider.hasDefault(permission, isOp);
|
||||
Tristate t = defaultsProvider.lookup(permission, isOp);
|
||||
if (t != Tristate.UNDEFINED) {
|
||||
return t;
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ public class DefaultsProvider {
|
||||
* @param isOp if the player is op
|
||||
* @return a tristate result
|
||||
*/
|
||||
public Tristate hasDefault(String permission, boolean isOp) {
|
||||
public Tristate lookup(String permission, boolean isOp) {
|
||||
Map<String, Boolean> map = isOp ? opDefaults : nonOpDefaults;
|
||||
|
||||
Boolean b = map.get(permission);
|
||||
@@ -126,6 +126,10 @@ public class DefaultsProvider {
|
||||
unregisterDefaults(nonOpDefaults, nonOpDummy, false);
|
||||
}
|
||||
|
||||
private static PluginManager pm() {
|
||||
return Bukkit.getServer().getPluginManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters defaults for a given permissible.
|
||||
*
|
||||
@@ -136,21 +140,21 @@ public class DefaultsProvider {
|
||||
Set<String> perms = map.keySet();
|
||||
|
||||
for (String name : perms) {
|
||||
Bukkit.getServer().getPluginManager().unsubscribeFromPermission(name, p);
|
||||
pm().unsubscribeFromPermission(name, p);
|
||||
}
|
||||
|
||||
Bukkit.getServer().getPluginManager().unsubscribeFromDefaultPerms(op, p);
|
||||
pm().unsubscribeFromDefaultPerms(op, p);
|
||||
}
|
||||
|
||||
private static void calculateDefaults(Map<String, Boolean> map, DummyPermissible p, boolean op) {
|
||||
Bukkit.getServer().getPluginManager().subscribeToDefaultPerms(op, p);
|
||||
pm().subscribeToDefaultPerms(op, p);
|
||||
|
||||
Set<Permission> defaults = Bukkit.getServer().getPluginManager().getDefaultPermissions(op);
|
||||
Set<Permission> defaults = pm().getDefaultPermissions(op);
|
||||
for (Permission perm : defaults) {
|
||||
String name = perm.getName().toLowerCase();
|
||||
|
||||
map.put(name, true);
|
||||
Bukkit.getServer().getPluginManager().subscribeToPermission(name, p);
|
||||
pm().subscribeToPermission(name, p);
|
||||
|
||||
// register defaults for any children too
|
||||
calculateChildPermissions(map, p, perm.getChildren(), false);
|
||||
@@ -167,10 +171,10 @@ public class DefaultsProvider {
|
||||
boolean value = e.getValue() ^ invert;
|
||||
|
||||
accumulator.put(e.getKey().toLowerCase(), value);
|
||||
Bukkit.getServer().getPluginManager().subscribeToPermission(e.getKey(), p);
|
||||
pm().subscribeToPermission(e.getKey(), p);
|
||||
|
||||
// lookup any deeper children & resolve if present
|
||||
Permission perm = Bukkit.getServer().getPluginManager().getPermission(e.getKey());
|
||||
Permission perm = pm().getPermission(e.getKey());
|
||||
if (perm != null) {
|
||||
calculateChildPermissions(accumulator, p, perm.getChildren(), !value);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.api.caching.MetaData;
|
||||
import me.lucko.luckperms.common.caching.MetaAccumulator;
|
||||
import me.lucko.luckperms.common.contexts.ExtractedContexts;
|
||||
import me.lucko.luckperms.common.model.Group;
|
||||
import me.lucko.luckperms.common.model.PermissionHolder;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
@@ -109,25 +108,25 @@ public class VaultChatHook extends Chat {
|
||||
|
||||
@Override
|
||||
public String getGroupPrefix(String world, @NonNull String group) {
|
||||
final Group g = perms.getPlugin().getGroupManager().getIfLoaded(group);
|
||||
final Group g = perms.getPlugin().getGroupManager().getByDisplayName(group);
|
||||
return getGroupChatMeta(g, ChatMetaType.PREFIX, world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroupPrefix(String world, @NonNull String group, @NonNull String prefix) {
|
||||
final Group g = perms.getPlugin().getGroupManager().getIfLoaded(group);
|
||||
final Group g = perms.getPlugin().getGroupManager().getByDisplayName(group);
|
||||
setChatMeta(g, ChatMetaType.PREFIX, prefix, world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroupSuffix(String world, @NonNull String group) {
|
||||
final Group g = perms.getPlugin().getGroupManager().getIfLoaded(group);
|
||||
final Group g = perms.getPlugin().getGroupManager().getByDisplayName(group);
|
||||
return getGroupChatMeta(g, ChatMetaType.SUFFIX, world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroupSuffix(String world, @NonNull String group, @NonNull String suffix) {
|
||||
final Group g = perms.getPlugin().getGroupManager().getIfLoaded(group);
|
||||
final Group g = perms.getPlugin().getGroupManager().getByDisplayName(group);
|
||||
setChatMeta(g, ChatMetaType.SUFFIX, suffix, world);
|
||||
}
|
||||
|
||||
@@ -149,7 +148,7 @@ public class VaultChatHook extends Chat {
|
||||
|
||||
@Override
|
||||
public int getGroupInfoInteger(String world, @NonNull String group, @NonNull String node, int defaultValue) {
|
||||
final Group g = perms.getPlugin().getGroupManager().getIfLoaded(group);
|
||||
final Group g = perms.getPlugin().getGroupManager().getByDisplayName(group);
|
||||
try {
|
||||
return Integer.parseInt(getGroupMeta(g, node, world, String.valueOf(defaultValue)));
|
||||
} catch (NumberFormatException e) {
|
||||
@@ -159,7 +158,7 @@ public class VaultChatHook extends Chat {
|
||||
|
||||
@Override
|
||||
public void setGroupInfoInteger(String world, @NonNull String group, @NonNull String node, int value) {
|
||||
final Group g = perms.getPlugin().getGroupManager().getIfLoaded(group);
|
||||
final Group g = perms.getPlugin().getGroupManager().getByDisplayName(group);
|
||||
setMeta(g, node, String.valueOf(value), world);
|
||||
}
|
||||
|
||||
@@ -181,7 +180,7 @@ public class VaultChatHook extends Chat {
|
||||
|
||||
@Override
|
||||
public double getGroupInfoDouble(String world, @NonNull String group, @NonNull String node, double defaultValue) {
|
||||
final Group g = perms.getPlugin().getGroupManager().getIfLoaded(group);
|
||||
final Group g = perms.getPlugin().getGroupManager().getByDisplayName(group);
|
||||
try {
|
||||
return Double.parseDouble(getGroupMeta(g, node, world, String.valueOf(defaultValue)));
|
||||
} catch (NumberFormatException e) {
|
||||
@@ -191,7 +190,7 @@ public class VaultChatHook extends Chat {
|
||||
|
||||
@Override
|
||||
public void setGroupInfoDouble(String world, @NonNull String group, @NonNull String node, double value) {
|
||||
final Group g = perms.getPlugin().getGroupManager().getIfLoaded(group);
|
||||
final Group g = perms.getPlugin().getGroupManager().getByDisplayName(group);
|
||||
setMeta(g, node, String.valueOf(value), world);
|
||||
}
|
||||
|
||||
@@ -213,7 +212,7 @@ public class VaultChatHook extends Chat {
|
||||
|
||||
@Override
|
||||
public boolean getGroupInfoBoolean(String world, @NonNull String group, @NonNull String node, boolean defaultValue) {
|
||||
final Group g = perms.getPlugin().getGroupManager().getIfLoaded(group);
|
||||
final Group g = perms.getPlugin().getGroupManager().getByDisplayName(group);
|
||||
String s = getGroupMeta(g, node, world, String.valueOf(defaultValue));
|
||||
if (!s.equalsIgnoreCase("true") && !s.equalsIgnoreCase("false")) {
|
||||
return defaultValue;
|
||||
@@ -223,7 +222,7 @@ public class VaultChatHook extends Chat {
|
||||
|
||||
@Override
|
||||
public void setGroupInfoBoolean(String world, @NonNull String group, @NonNull String node, boolean value) {
|
||||
final Group g = perms.getPlugin().getGroupManager().getIfLoaded(group);
|
||||
final Group g = perms.getPlugin().getGroupManager().getByDisplayName(group);
|
||||
setMeta(g, node, String.valueOf(value), world);
|
||||
}
|
||||
|
||||
@@ -241,13 +240,13 @@ public class VaultChatHook extends Chat {
|
||||
|
||||
@Override
|
||||
public String getGroupInfoString(String world, @NonNull String group, @NonNull String node, String defaultValue) {
|
||||
final Group g = perms.getPlugin().getGroupManager().getIfLoaded(group);
|
||||
final Group g = perms.getPlugin().getGroupManager().getByDisplayName(group);
|
||||
return getGroupMeta(g, node, world, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroupInfoString(String world, @NonNull String group, @NonNull String node, String value) {
|
||||
final Group g = perms.getPlugin().getGroupManager().getIfLoaded(group);
|
||||
final Group g = perms.getPlugin().getGroupManager().getByDisplayName(group);
|
||||
setMeta(g, node, value, world);
|
||||
}
|
||||
|
||||
@@ -284,7 +283,7 @@ public class VaultChatHook extends Chat {
|
||||
holder.removeIf(type::matches);
|
||||
|
||||
// find the max inherited priority & add 10
|
||||
MetaAccumulator metaAccumulator = holder.accumulateMeta(null, null, ExtractedContexts.generate(perms.createContextForWorldSet(finalWorld)));
|
||||
MetaAccumulator metaAccumulator = holder.accumulateMeta(null, null, perms.createContextForWorldSet(finalWorld));
|
||||
int priority = (type == ChatMetaType.PREFIX ? metaAccumulator.getPrefixes() : metaAccumulator.getSuffixes()).keySet().stream()
|
||||
.mapToInt(e -> e).max().orElse(0) + 10;
|
||||
|
||||
@@ -331,7 +330,7 @@ public class VaultChatHook extends Chat {
|
||||
perms.log("Getting meta: '" + node + "' for group " + group.getName() + " on world " + world + ", server " + perms.getServer());
|
||||
|
||||
for (Node n : group.getOwnNodes()) {
|
||||
if (!n.getValue()) continue;
|
||||
if (!n.getValuePrimitive()) continue;
|
||||
if (!n.isMeta()) continue;
|
||||
if (!n.shouldApplyWithContext(perms.createContextForWorldLookup(world).getContexts())) continue;
|
||||
|
||||
@@ -355,9 +354,9 @@ public class VaultChatHook extends Chat {
|
||||
int priority = Integer.MIN_VALUE;
|
||||
String meta = null;
|
||||
|
||||
ExtractedContexts ec = ExtractedContexts.generate(Contexts.of(perms.createContextForWorldLookup(world).getContexts(), perms.isIncludeGlobal(), true, true, true, true, false));
|
||||
for (Node n : group.getAllNodes(ec)) {
|
||||
if (!n.getValue()) continue;
|
||||
Contexts contexts = Contexts.of(perms.createContextForWorldLookup(world).getContexts(), perms.isIncludeGlobal(), true, true, true, true, false);
|
||||
for (Node n : group.getAllNodes(contexts)) {
|
||||
if (!n.getValuePrimitive()) continue;
|
||||
if (type.shouldIgnore(n)) continue;
|
||||
if (!n.shouldApplyWithContext(perms.createContextForWorldLookup(world).getContexts())) continue;
|
||||
|
||||
|
||||
@@ -28,20 +28,19 @@ package me.lucko.luckperms.bukkit.vault;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.DataMutateResult;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.api.caching.PermissionData;
|
||||
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.contexts.ExtractedContexts;
|
||||
import me.lucko.luckperms.common.model.Group;
|
||||
import me.lucko.luckperms.common.model.PermissionHolder;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.node.NodeFactory;
|
||||
import me.lucko.luckperms.common.verbose.CheckOrigin;
|
||||
|
||||
import net.milkbowl.vault.permission.Permission;
|
||||
|
||||
@@ -52,9 +51,7 @@ import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* An implementation of the Vault {@link Permission} API using LuckPerms.
|
||||
@@ -110,7 +107,7 @@ public class VaultPermissionHook extends Permission {
|
||||
|
||||
@Override
|
||||
public String[] getGroups() {
|
||||
return plugin.getGroupManager().getAll().keySet().toArray(new String[0]);
|
||||
return plugin.getGroupManager().getAll().values().stream().map(g -> g.getDisplayName().orElse(g.getName())).toArray(String[]::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -147,7 +144,7 @@ public class VaultPermissionHook extends Permission {
|
||||
}
|
||||
|
||||
// Effectively fallback to the standard Bukkit #hasPermission check.
|
||||
return user.getUserData().getPermissionData(createContextForWorldLookup(player, world)).getPermissionValue(permission).asBoolean();
|
||||
return user.getUserData().getPermissionData(createContextForWorldLookup(player, world)).getPermissionValue(permission, CheckOrigin.INTERNAL).asBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -221,11 +218,11 @@ public class VaultPermissionHook extends Permission {
|
||||
world = correctWorld(world);
|
||||
log("Checking if group " + groupName + " has permission: " + permission + " on world " + world + ", server " + getServer());
|
||||
|
||||
final Group group = plugin.getGroupManager().getIfLoaded(groupName);
|
||||
final Group group = plugin.getGroupManager().getByDisplayName(groupName);
|
||||
if (group == null) return false;
|
||||
|
||||
// This is a nasty call. Groups aren't cached. :(
|
||||
Map<String, Boolean> permissions = group.exportNodesAndShorthand(ExtractedContexts.generate(createContextForWorldLookup(world)), true);
|
||||
Map<String, Boolean> permissions = group.exportNodesAndShorthand(createContextForWorldLookup(world), true);
|
||||
return permissions.containsKey(permission.toLowerCase()) && permissions.get(permission.toLowerCase());
|
||||
}
|
||||
|
||||
@@ -234,7 +231,7 @@ public class VaultPermissionHook extends Permission {
|
||||
world = correctWorld(world);
|
||||
log("Adding permission to group " + groupName + ": '" + permission + "' on world " + world + ", server " + getServer());
|
||||
|
||||
final Group group = plugin.getGroupManager().getIfLoaded(groupName);
|
||||
final Group group = plugin.getGroupManager().getByDisplayName(groupName);
|
||||
if (group == null) return false;
|
||||
|
||||
holderAddPermission(group, permission, world);
|
||||
@@ -246,7 +243,7 @@ public class VaultPermissionHook extends Permission {
|
||||
world = correctWorld(world);
|
||||
log("Removing permission from group " + groupName + ": '" + permission + "' on world " + world + ", server " + getServer());
|
||||
|
||||
final Group group = plugin.getGroupManager().getIfLoaded(groupName);
|
||||
final Group group = plugin.getGroupManager().getByDisplayName(groupName);
|
||||
if (group == null) return false;
|
||||
|
||||
holderRemovePermission(group, permission, world);
|
||||
@@ -255,69 +252,77 @@ public class VaultPermissionHook extends Permission {
|
||||
|
||||
@Override
|
||||
public boolean playerInGroup(String world, String player, @NonNull String group) {
|
||||
return playerHas(world, player, "group." + group);
|
||||
return playerHas(world, player, "group." + rewriteGroupName(group));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public boolean playerInGroup(World world, String player, @NonNull String group) {
|
||||
return playerHas(world, player, "group." + group);
|
||||
return playerHas(world, player, "group." + rewriteGroupName(group));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean playerInGroup(String world, OfflinePlayer player, @NonNull String group) {
|
||||
return playerHas(world, player, "group." + group);
|
||||
return playerHas(world, player, "group." + rewriteGroupName(group));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean playerInGroup(Player player, @NonNull String group) {
|
||||
return playerHas(player, "group." + group);
|
||||
return playerHas(player, "group." + rewriteGroupName(group));
|
||||
}
|
||||
|
||||
private boolean checkGroupExists(String group) {
|
||||
return plugin.getGroupManager().isLoaded(group);
|
||||
return plugin.getGroupManager().getByDisplayName(group) != null;
|
||||
}
|
||||
|
||||
private String rewriteGroupName(String name) {
|
||||
Group group = plugin.getGroupManager().getByDisplayName(name);
|
||||
if (group != null) {
|
||||
return group.getName();
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean playerAddGroup(String world, String player, @NonNull String group) {
|
||||
return checkGroupExists(group) && playerAdd(world, player, "group." + group);
|
||||
return checkGroupExists(group) && playerAdd(world, player, "group." + rewriteGroupName(group));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public boolean playerAddGroup(World world, String player, @NonNull String group) {
|
||||
return checkGroupExists(group) && playerAdd(world, player, "group." + group);
|
||||
return checkGroupExists(group) && playerAdd(world, player, "group." + rewriteGroupName(group));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean playerAddGroup(String world, OfflinePlayer player, @NonNull String group) {
|
||||
return checkGroupExists(group) && playerAdd(world, player, "group." + group);
|
||||
return checkGroupExists(group) && playerAdd(world, player, "group." + rewriteGroupName(group));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean playerAddGroup(Player player, @NonNull String group) {
|
||||
return checkGroupExists(group) && playerAdd(player, "group." + group);
|
||||
return checkGroupExists(group) && playerAdd(player, "group." + rewriteGroupName(group));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean playerRemoveGroup(String world, String player, @NonNull String group) {
|
||||
return checkGroupExists(group) && playerRemove(world, player, "group." + group);
|
||||
return checkGroupExists(group) && playerRemove(world, player, "group." + rewriteGroupName(group));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public boolean playerRemoveGroup(World world, String player, @NonNull String group) {
|
||||
return checkGroupExists(group) && playerRemove(world, player, "group." + group);
|
||||
return checkGroupExists(group) && playerRemove(world, player, "group." + rewriteGroupName(group));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean playerRemoveGroup(String world, OfflinePlayer player, @NonNull String group) {
|
||||
return checkGroupExists(group) && playerRemove(world, player, "group." + group);
|
||||
return checkGroupExists(group) && playerRemove(world, player, "group." + rewriteGroupName(group));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean playerRemoveGroup(Player player, @NonNull String group) {
|
||||
return checkGroupExists(group) && playerRemove(player, "group." + group);
|
||||
return checkGroupExists(group) && playerRemove(player, "group." + rewriteGroupName(group));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -353,28 +358,34 @@ public class VaultPermissionHook extends Permission {
|
||||
return user.getEnduringNodes().values().stream()
|
||||
.filter(Node::isGroupNode)
|
||||
.filter(n -> n.shouldApplyWithContext(createContextForWorldLookup(player, w).getContexts()))
|
||||
.map(Node::getGroupName)
|
||||
.map(n -> {
|
||||
Group group = plugin.getGroupManager().getIfLoaded(n.getGroupName());
|
||||
if (group != null) {
|
||||
return group.getDisplayName().orElse(group.getName());
|
||||
}
|
||||
return n.getGroupName();
|
||||
})
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrimaryGroup(String world, @NonNull String player) {
|
||||
return getPrimaryGroup(world, Bukkit.getPlayerExact(player));
|
||||
return getPrimaryGroup(Bukkit.getPlayerExact(player));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public String getPrimaryGroup(World world, @NonNull String player) {
|
||||
return getPrimaryGroup(world == null ? null : world.getName(), Bukkit.getPlayerExact(player));
|
||||
return getPrimaryGroup(Bukkit.getPlayerExact(player));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrimaryGroup(String world, @NonNull OfflinePlayer player) {
|
||||
return getPrimaryGroup(world, player.getPlayer());
|
||||
return getPrimaryGroup(player.getPlayer());
|
||||
}
|
||||
|
||||
private String getPrimaryGroup(String world, Player player) {
|
||||
world = correctWorld(world);
|
||||
@Override
|
||||
public String getPrimaryGroup(Player player) {
|
||||
log("Getting primary group of player: " + player);
|
||||
|
||||
if (player == null) {
|
||||
@@ -387,71 +398,13 @@ public class VaultPermissionHook extends Permission {
|
||||
return null;
|
||||
}
|
||||
|
||||
// nothing special, just return the value.
|
||||
if (!isPgo()) {
|
||||
String g = user.getPrimaryGroup().getValue();
|
||||
return plugin.getConfiguration().get(ConfigKeys.GROUP_NAME_REWRITES).getOrDefault(g, g);
|
||||
}
|
||||
|
||||
// we need to do the complex PGO checking. (it's been enabled in the config.)
|
||||
if (isPgoCheckInherited()) {
|
||||
// we can just check the cached data
|
||||
PermissionData data = user.getUserData().getPermissionData(createContextForWorldLookup(plugin.getPlayer(user), world));
|
||||
for (Map.Entry<String, Boolean> e : data.getImmutableBacking().entrySet()) {
|
||||
if (!e.getValue()) continue;
|
||||
if (!e.getKey().toLowerCase().startsWith("vault.primarygroup.")) continue;
|
||||
|
||||
String group = e.getKey().substring("vault.primarygroup.".length());
|
||||
if (isPgoCheckExists()) {
|
||||
if (!plugin.getGroupManager().isLoaded(group)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (isPgoCheckMemberOf()) {
|
||||
if (data.getPermissionValue("group." + group) != Tristate.TRUE) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
} else {
|
||||
// we need to check the users permissions only
|
||||
for (Node node : user.getOwnNodes()) {
|
||||
if (!node.getValue()) continue;
|
||||
if (!node.getPermission().toLowerCase().startsWith("vault.primarygroup.")) continue;
|
||||
if (!node.shouldApplyOnServer(getServer(), isIncludeGlobal(), false)) continue;
|
||||
if (!node.shouldApplyOnWorld(world, true, false)) continue;
|
||||
|
||||
String group = node.getPermission().substring("vault.primarygroup.".length());
|
||||
if (isPgoCheckExists()) {
|
||||
if (!plugin.getGroupManager().isLoaded(group)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (isPgoCheckMemberOf()) {
|
||||
String finalWorld = world;
|
||||
List<String> localGroups = user.getOwnNodes().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;
|
||||
}
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback
|
||||
String g = user.getPrimaryGroup().getValue();
|
||||
return plugin.getConfiguration().get(ConfigKeys.GROUP_NAME_REWRITES).getOrDefault(g, g);
|
||||
Group group = plugin.getGroupManager().getByDisplayName(g);
|
||||
if (group != null) {
|
||||
return group.getDisplayName().orElse(group.getName());
|
||||
}
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
public void log(String s) {
|
||||
@@ -467,36 +420,26 @@ public class VaultPermissionHook extends Permission {
|
||||
// utility methods for modifying the state of PermissionHolders
|
||||
|
||||
private void holderAddPermission(PermissionHolder holder, String permission, String world) {
|
||||
Preconditions.checkNotNull(permission, "permission is null");
|
||||
Preconditions.checkArgument(!permission.isEmpty(), "permission is an empty string");
|
||||
executor.execute(() -> {
|
||||
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()) {
|
||||
if (holder.setPermission(NodeFactory.make(permission, true, getServer(), world)).asBoolean()) {
|
||||
holderSave(holder);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void holderRemovePermission(PermissionHolder holder, String permission, String world) {
|
||||
Preconditions.checkNotNull(permission, "permission is null");
|
||||
Preconditions.checkArgument(!permission.isEmpty(), "permission is an empty string");
|
||||
executor.execute(() -> {
|
||||
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()) {
|
||||
if (holder.unsetPermission(NodeFactory.make(permission, getServer(), world)).asBoolean()) {
|
||||
holderSave(holder);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void holderSave(PermissionHolder holder) {
|
||||
void holderSave(PermissionHolder holder) {
|
||||
if (holder instanceof User) {
|
||||
User u = (User) holder;
|
||||
plugin.getStorage().saveUser(u).thenRunAsync(() -> u.getRefreshBuffer().request(), plugin.getScheduler().async());
|
||||
@@ -561,20 +504,4 @@ public class VaultPermissionHook extends Permission {
|
||||
boolean isIgnoreWorld() {
|
||||
return plugin.getConfiguration().get(ConfigKeys.VAULT_IGNORE_WORLD);
|
||||
}
|
||||
|
||||
private boolean isPgo() {
|
||||
return plugin.getConfiguration().get(ConfigKeys.VAULT_PRIMARY_GROUP_OVERRIDES);
|
||||
}
|
||||
|
||||
private boolean isPgoCheckInherited() {
|
||||
return plugin.getConfiguration().get(ConfigKeys.VAULT_PRIMARY_GROUP_OVERRIDES_CHECK_INHERITED);
|
||||
}
|
||||
|
||||
private boolean isPgoCheckExists() {
|
||||
return plugin.getConfiguration().get(ConfigKeys.VAULT_PRIMARY_GROUP_OVERRIDES_CHECK_EXISTS);
|
||||
}
|
||||
|
||||
private boolean isPgoCheckMemberOf() {
|
||||
return plugin.getConfiguration().get(ConfigKeys.VAULT_PRIMARY_GROUP_OVERRIDES_CHECK_MEMBER_OF);
|
||||
}
|
||||
}
|
||||
@@ -70,6 +70,16 @@ use-server-uuids: true
|
||||
# in the LuckPerms cache.
|
||||
use-server-uuid-cache: false
|
||||
|
||||
# If set to true, LuckPerms will allow usernames with non alphanumeric characters.
|
||||
#
|
||||
# Note that due to the design of the storage implementation, usernames must still be
|
||||
# 16 characters or less.
|
||||
allow-invalid-usernames: false
|
||||
|
||||
# If LuckPerms should produce extra logging output when it handles logins.
|
||||
# Useful if you're having issues with UUID forwarding or data not being loaded.
|
||||
debug-logins: false
|
||||
|
||||
# If the plugin should send log notifications to users whenever permissions are modified.
|
||||
log-notify: true
|
||||
|
||||
@@ -79,11 +89,6 @@ 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"
|
||||
@@ -99,7 +104,11 @@ temporary-add-behaviour: deny
|
||||
# -> parents-by-weight just use the users most highly weighted parent
|
||||
# -> all-parents-by-weight same as above, but calculates based upon all parents inherited from both
|
||||
# directly and indirectly
|
||||
primary-group-calculation: stored
|
||||
primary-group-calculation: parents-by-weight
|
||||
|
||||
# If set to false, the plugin will allow a Users primary group to be removed with the
|
||||
# 'parent remove' command, and will set their primary group back to default.
|
||||
prevent-primary-group-removal: false
|
||||
|
||||
# If the plugin should check for "extra" permissions with users run LP commands.
|
||||
#
|
||||
@@ -168,6 +177,8 @@ group-weight:
|
||||
# - lowest
|
||||
# - highest_own
|
||||
# - lowest_own
|
||||
# - highest_inherited
|
||||
# - lowest_inherited
|
||||
# - highest_on_track_<track>
|
||||
# - lowest_on_track_<track>
|
||||
# - highest_not_on_track_<track>
|
||||
@@ -253,7 +264,7 @@ vault-debug: false
|
||||
# Which storage method the plugin should use.
|
||||
#
|
||||
# See: https://github.com/lucko/LuckPerms/wiki/Choosing-a-Storage-type
|
||||
# Currently supported: mysql, mariadb, postgresql, sqlite, h2, json, yaml, mongodb
|
||||
# Currently supported: mysql, mariadb, postgresql, sqlite, h2, json, yaml, hocon, 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".
|
||||
@@ -328,6 +339,16 @@ messaging-service: none
|
||||
# If LuckPerms should automatically push updates after a change has been made with a command.
|
||||
auto-push-updates: true
|
||||
|
||||
# If LuckPerms should push logging entries to connected servers via the messaging service.
|
||||
push-log-entries: true
|
||||
|
||||
# If LuckPerms should broadcast received logging entries to players on this platform.
|
||||
#
|
||||
# If you have LuckPerms installed on your backend servers as well as a BungeeCord proxy, you should
|
||||
# set this option to false on either your backends or your proxies, to avoid players being messaged
|
||||
# twice about log entries.
|
||||
broadcast-received-log-entries: true
|
||||
|
||||
# Settings for Redis.
|
||||
# Port 6379 is used by default; set address to "host:port" if differs
|
||||
redis:
|
||||
|
||||
+5
-1
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>luckperms</artifactId>
|
||||
<groupId>me.lucko.luckperms</groupId>
|
||||
<version>3.3-SNAPSHOT</version>
|
||||
<version>4.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -150,6 +150,10 @@
|
||||
<groupId>net.ess3</groupId>
|
||||
<artifactId>Essentials</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>net.ess3</groupId>
|
||||
<artifactId>EssentialsX</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
+15
-9
@@ -29,19 +29,23 @@ import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Splitter;
|
||||
|
||||
import me.lucko.luckperms.common.commands.CommandManager;
|
||||
import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.commands.utils.Util;
|
||||
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
import net.md_5.bungee.api.plugin.TabExecutor;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class BungeeCommandExecutor extends Command implements TabExecutor {
|
||||
private static final Splitter ARGUMENT_SPLITTER = Splitter.on(CommandManager.COMMAND_SEPARATOR_PATTERN).omitEmptyStrings();
|
||||
private static final Joiner ARGUMENT_JOINER = Joiner.on(' ');
|
||||
|
||||
class BungeeCommand extends Command implements TabExecutor {
|
||||
private final LPBungeePlugin plugin;
|
||||
private final CommandManager manager;
|
||||
|
||||
BungeeCommand(LPBungeePlugin plugin, CommandManager manager) {
|
||||
BungeeCommandExecutor(LPBungeePlugin plugin, CommandManager manager) {
|
||||
super("luckpermsbungee", null, "lpb", "bperm", "bperms", "bpermission", "bpermissions");
|
||||
this.plugin = plugin;
|
||||
this.manager = manager;
|
||||
@@ -49,15 +53,17 @@ class BungeeCommand extends Command implements TabExecutor {
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender, String[] args) {
|
||||
manager.onCommand(
|
||||
plugin.getSenderFactory().wrap(sender),
|
||||
"lpb",
|
||||
Util.stripQuotes(Splitter.on(CommandManager.COMMAND_SEPARATOR_PATTERN).omitEmptyStrings().splitToList(Joiner.on(' ').join(args)))
|
||||
);
|
||||
Sender lpSender = plugin.getSenderFactory().wrap(sender);
|
||||
List<String> arguments = Util.stripQuotes(ARGUMENT_SPLITTER.splitToList(ARGUMENT_JOINER.join(args)));
|
||||
|
||||
manager.onCommand(lpSender, "lpb", arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<String> onTabComplete(CommandSender sender, String[] args) {
|
||||
return manager.onTabComplete(plugin.getSenderFactory().wrap(sender), Arrays.asList(args));
|
||||
Sender lpSender = plugin.getSenderFactory().wrap(sender);
|
||||
List<String> arguments = Util.stripQuotes(ARGUMENT_SPLITTER.splitToList(ARGUMENT_JOINER.join(args)));
|
||||
|
||||
return manager.onTabComplete(lpSender, arguments);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -28,7 +28,7 @@ package me.lucko.luckperms.bungee;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import me.lucko.luckperms.common.config.AbstractConfiguration;
|
||||
import me.lucko.luckperms.common.config.ConfigurationAdapter;
|
||||
|
||||
import net.md_5.bungee.config.Configuration;
|
||||
import net.md_5.bungee.config.ConfigurationProvider;
|
||||
@@ -45,7 +45,7 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class BungeeConfig extends AbstractConfiguration {
|
||||
public class BungeeConfigAdapter implements ConfigurationAdapter {
|
||||
|
||||
@Getter
|
||||
private final LPBungeePlugin plugin;
|
||||
+5
-5
@@ -25,7 +25,7 @@
|
||||
|
||||
package me.lucko.luckperms.bungee;
|
||||
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsScheduler;
|
||||
import me.lucko.luckperms.common.plugin.SchedulerAdapter;
|
||||
|
||||
import net.md_5.bungee.api.scheduler.ScheduledTask;
|
||||
|
||||
@@ -34,13 +34,13 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class LPBungeeScheduler implements LuckPermsScheduler {
|
||||
public class BungeeSchedulerAdapter implements SchedulerAdapter {
|
||||
private final LPBungeePlugin plugin;
|
||||
|
||||
private Executor asyncExecutor;
|
||||
private Set<ScheduledTask> tasks = ConcurrentHashMap.newKeySet();
|
||||
private final Executor asyncExecutor;
|
||||
private final Set<ScheduledTask> tasks = ConcurrentHashMap.newKeySet();
|
||||
|
||||
public LPBungeeScheduler(LPBungeePlugin plugin) {
|
||||
public BungeeSchedulerAdapter(LPBungeePlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.asyncExecutor = r -> plugin.getProxy().getScheduler().runAsync(plugin, r);
|
||||
}
|
||||
@@ -30,9 +30,10 @@ import me.lucko.luckperms.bungee.event.TristateCheckEvent;
|
||||
import me.lucko.luckperms.common.commands.sender.SenderFactory;
|
||||
import me.lucko.luckperms.common.constants.Constants;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.utils.TextUtils;
|
||||
|
||||
import net.kyori.text.Component;
|
||||
import net.kyori.text.serializer.ComponentSerializer;
|
||||
import net.kyori.text.serializer.ComponentSerializers;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
@@ -68,9 +69,10 @@ public class BungeeSenderFactory extends SenderFactory<CommandSender> {
|
||||
@Override
|
||||
protected void sendMessage(CommandSender sender, Component message) {
|
||||
try {
|
||||
sender.sendMessage(net.md_5.bungee.chat.ComponentSerializer.parse(ComponentSerializer.serialize(message)));
|
||||
sender.sendMessage(net.md_5.bungee.chat.ComponentSerializer.parse(ComponentSerializers.JSON.serialize(message)));
|
||||
} catch (Exception e) {
|
||||
sendMessage(sender, ComponentSerializer.toLegacy(message, Constants.COLOR_CHAR));
|
||||
//noinspection deprecation
|
||||
sendMessage(sender, TextUtils.toLegacy(message));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,22 +28,25 @@ package me.lucko.luckperms.bungee;
|
||||
import lombok.Getter;
|
||||
|
||||
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.ImmutableContextSet;
|
||||
import me.lucko.luckperms.api.platform.PlatformType;
|
||||
import me.lucko.luckperms.bungee.calculators.BungeeCalculatorFactory;
|
||||
import me.lucko.luckperms.bungee.contexts.BackendServerCalculator;
|
||||
import me.lucko.luckperms.bungee.messaging.BungeeMessagingService;
|
||||
import me.lucko.luckperms.bungee.messaging.RedisBungeeMessagingService;
|
||||
import me.lucko.luckperms.bungee.contexts.BungeeContextManager;
|
||||
import me.lucko.luckperms.bungee.contexts.RedisBungeeCalculator;
|
||||
import me.lucko.luckperms.bungee.listeners.BungeeConnectionListener;
|
||||
import me.lucko.luckperms.bungee.listeners.BungeePermissionCheckListener;
|
||||
import me.lucko.luckperms.bungee.messaging.BungeeMessagingFactory;
|
||||
import me.lucko.luckperms.bungee.util.RedisBungeeUtil;
|
||||
import me.lucko.luckperms.common.api.ApiHandler;
|
||||
import me.lucko.luckperms.common.actionlog.LogDispatcher;
|
||||
import me.lucko.luckperms.common.api.ApiProvider;
|
||||
import me.lucko.luckperms.common.api.ApiSingletonUtils;
|
||||
import me.lucko.luckperms.common.buffers.BufferedRequest;
|
||||
import me.lucko.luckperms.common.buffers.UpdateTaskBuffer;
|
||||
import me.lucko.luckperms.common.caching.handlers.CachedStateManager;
|
||||
import me.lucko.luckperms.common.calculators.CalculatorFactory;
|
||||
import me.lucko.luckperms.common.commands.CommandManager;
|
||||
import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.config.AbstractConfiguration;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.config.LuckPermsConfiguration;
|
||||
import me.lucko.luckperms.common.contexts.ContextManager;
|
||||
@@ -53,6 +56,7 @@ import me.lucko.luckperms.common.dependencies.DependencyManager;
|
||||
import me.lucko.luckperms.common.locale.LocaleManager;
|
||||
import me.lucko.luckperms.common.locale.NoopLocaleManager;
|
||||
import me.lucko.luckperms.common.locale.SimpleLocaleManager;
|
||||
import me.lucko.luckperms.common.logging.Logger;
|
||||
import me.lucko.luckperms.common.logging.SenderLogger;
|
||||
import me.lucko.luckperms.common.managers.GenericGroupManager;
|
||||
import me.lucko.luckperms.common.managers.GenericTrackManager;
|
||||
@@ -60,16 +64,14 @@ import me.lucko.luckperms.common.managers.GenericUserManager;
|
||||
import me.lucko.luckperms.common.managers.GroupManager;
|
||||
import me.lucko.luckperms.common.managers.TrackManager;
|
||||
import me.lucko.luckperms.common.managers.UserManager;
|
||||
import me.lucko.luckperms.common.messaging.InternalMessagingService;
|
||||
import me.lucko.luckperms.common.messaging.NoopMessagingService;
|
||||
import me.lucko.luckperms.common.messaging.RedisMessagingService;
|
||||
import me.lucko.luckperms.common.messaging.ExtendedMessagingService;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsScheduler;
|
||||
import me.lucko.luckperms.common.plugin.SchedulerAdapter;
|
||||
import me.lucko.luckperms.common.storage.Storage;
|
||||
import me.lucko.luckperms.common.storage.StorageFactory;
|
||||
import me.lucko.luckperms.common.storage.StorageType;
|
||||
import me.lucko.luckperms.common.storage.backing.file.FileWatcher;
|
||||
import me.lucko.luckperms.common.storage.dao.file.FileWatcher;
|
||||
import me.lucko.luckperms.common.tasks.CacheHousekeepingTask;
|
||||
import me.lucko.luckperms.common.tasks.ExpireTemporaryTask;
|
||||
import me.lucko.luckperms.common.tasks.UpdateTask;
|
||||
@@ -83,20 +85,20 @@ 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.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* LuckPerms implementation for the BungeeCord API.
|
||||
*/
|
||||
@Getter
|
||||
public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
private final Set<UUID> ignoringLogs = ConcurrentHashMap.newKeySet();
|
||||
private Set<UUID> uniqueConnections = ConcurrentHashMap.newKeySet();
|
||||
|
||||
private long startTime;
|
||||
private LuckPermsScheduler scheduler;
|
||||
private SchedulerAdapter scheduler;
|
||||
private CommandManager commandManager;
|
||||
private LuckPermsConfiguration configuration;
|
||||
private UserManager userManager;
|
||||
@@ -104,7 +106,7 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
private TrackManager trackManager;
|
||||
private Storage storage;
|
||||
private FileWatcher fileWatcher = null;
|
||||
private InternalMessagingService messagingService = null;
|
||||
private ExtendedMessagingService messagingService = null;
|
||||
private UuidCache uuidCache;
|
||||
private ApiProvider apiProvider;
|
||||
private Logger log;
|
||||
@@ -116,16 +118,18 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
private VerboseHandler verboseHandler;
|
||||
private BungeeSenderFactory senderFactory;
|
||||
private PermissionVault permissionVault;
|
||||
private LogDispatcher logDispatcher;
|
||||
private Set<UUID> uniqueConnections = ConcurrentHashMap.newKeySet();
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
// setup minimal functionality in order to load initial dependencies
|
||||
scheduler = new LPBungeeScheduler(this);
|
||||
scheduler = new BungeeSchedulerAdapter(this);
|
||||
localeManager = new NoopLocaleManager();
|
||||
senderFactory = new BungeeSenderFactory(this);
|
||||
log = new SenderLogger(this, getConsoleSender());
|
||||
|
||||
DependencyManager.loadDependencies(this, Collections.singletonList(Dependency.CAFFEINE));
|
||||
DependencyManager.loadDependencies(this, Collections.singleton(Dependency.CAFFEINE));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -134,17 +138,18 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
LuckPermsPlugin.sendStartupBanner(getConsoleSender(), this);
|
||||
verboseHandler = new VerboseHandler(scheduler.async(), getVersion());
|
||||
permissionVault = new PermissionVault(scheduler.async());
|
||||
logDispatcher = new LogDispatcher(this);
|
||||
|
||||
getLog().info("Loading configuration...");
|
||||
configuration = new BungeeConfig(this);
|
||||
configuration = new AbstractConfiguration(this, new BungeeConfigAdapter(this));
|
||||
configuration.init();
|
||||
configuration.loadAll();
|
||||
|
||||
Set<StorageType> storageTypes = StorageFactory.getRequiredTypes(this, StorageType.H2);
|
||||
DependencyManager.loadDependencies(this, storageTypes);
|
||||
DependencyManager.loadStorageDependencies(this, storageTypes);
|
||||
|
||||
// register events
|
||||
getProxy().getPluginManager().registerListener(this, new BungeeListener(this));
|
||||
getProxy().getPluginManager().registerListener(this, new BungeeConnectionListener(this));
|
||||
getProxy().getPluginManager().registerListener(this, new BungeePermissionCheckListener(this));
|
||||
|
||||
if (getConfiguration().get(ConfigKeys.WATCH_FILES)) {
|
||||
fileWatcher = new FileWatcher(this);
|
||||
@@ -155,72 +160,18 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
storage = StorageFactory.getInstance(this, StorageType.H2);
|
||||
|
||||
// initialise messaging
|
||||
String messagingType = getConfiguration().get(ConfigKeys.MESSAGING_SERVICE).toLowerCase();
|
||||
if (messagingType.equals("none") && getConfiguration().get(ConfigKeys.REDIS_ENABLED)) {
|
||||
messagingType = "redis";
|
||||
}
|
||||
|
||||
if (!messagingType.equals("none")) {
|
||||
getLog().info("Loading messaging service... [" + messagingType.toUpperCase() + "]");
|
||||
}
|
||||
|
||||
if (messagingType.equals("redis")) {
|
||||
if (getConfiguration().get(ConfigKeys.REDIS_ENABLED)) {
|
||||
RedisMessagingService redis = new RedisMessagingService(this);
|
||||
try {
|
||||
redis.init(getConfiguration().get(ConfigKeys.REDIS_ADDRESS), getConfiguration().get(ConfigKeys.REDIS_PASSWORD));
|
||||
messagingService = redis;
|
||||
} catch (Exception e) {
|
||||
getLog().warn("Couldn't load redis...");
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
getLog().warn("Messaging Service was set to redis, but redis is not enabled!");
|
||||
}
|
||||
} else if (messagingType.equals("bungee")) {
|
||||
BungeeMessagingService bungeeMessaging = new BungeeMessagingService(this);
|
||||
bungeeMessaging.init();
|
||||
messagingService = bungeeMessaging;
|
||||
} else if (messagingType.equals("redisbungee")) {
|
||||
if (getProxy().getPluginManager().getPlugin("RedisBungee") == null) {
|
||||
getLog().warn("RedisBungee plugin not present.");
|
||||
} else {
|
||||
RedisBungeeMessagingService redisBungeeMessaging = new RedisBungeeMessagingService(this);
|
||||
redisBungeeMessaging.init();
|
||||
messagingService = redisBungeeMessaging;
|
||||
}
|
||||
} else if (!messagingType.equals("none")) {
|
||||
getLog().warn("Messaging service '" + messagingType + "' not recognised.");
|
||||
}
|
||||
|
||||
if (messagingService == null) {
|
||||
messagingService = new NoopMessagingService();
|
||||
}
|
||||
messagingService = new BungeeMessagingFactory(this).getInstance();
|
||||
|
||||
// setup the update task buffer
|
||||
updateTaskBuffer = new BufferedRequest<Void>(1000L, this::doAsync) {
|
||||
@Override
|
||||
protected Void perform() {
|
||||
new UpdateTask(LPBungeePlugin.this).run();
|
||||
return null;
|
||||
}
|
||||
};
|
||||
updateTaskBuffer = new UpdateTaskBuffer(this);
|
||||
|
||||
// load locale
|
||||
localeManager = new SimpleLocaleManager();
|
||||
File locale = new File(getDataFolder(), "lang.yml");
|
||||
if (locale.exists()) {
|
||||
getLog().info("Found lang.yml - loading messages...");
|
||||
try {
|
||||
localeManager.loadFromFile(locale);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
localeManager.tryLoad(this, new File(getDataFolder(), "lang.yml"));
|
||||
|
||||
// register commands
|
||||
commandManager = new CommandManager(this);
|
||||
getProxy().getPluginManager().registerCommand(this, new BungeeCommand(this, commandManager));
|
||||
getProxy().getPluginManager().registerCommand(this, new BungeeCommandExecutor(this, commandManager));
|
||||
|
||||
// disable the default Bungee /perms command so it gets handled by the Bukkit plugin
|
||||
getProxy().getDisabledCommands().add("perms");
|
||||
@@ -234,30 +185,18 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
calculatorFactory = new BungeeCalculatorFactory(this);
|
||||
cachedStateManager = new CachedStateManager();
|
||||
|
||||
contextManager = new ContextManager<ProxiedPlayer>() {
|
||||
@Override
|
||||
public Contexts formContexts(ProxiedPlayer player, ImmutableContextSet contextSet) {
|
||||
return new Contexts(
|
||||
contextSet,
|
||||
getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_PERMS),
|
||||
getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_WORLD_PERMS),
|
||||
true,
|
||||
getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_GROUPS),
|
||||
getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_WORLD_GROUPS),
|
||||
false
|
||||
);
|
||||
}
|
||||
};
|
||||
// setup context manager
|
||||
contextManager = new BungeeContextManager(this);
|
||||
contextManager.registerCalculator(new BackendServerCalculator(this));
|
||||
contextManager.registerStaticCalculator(new LuckPermsCalculator(getConfiguration()));
|
||||
|
||||
BackendServerCalculator serverCalculator = new BackendServerCalculator(this);
|
||||
contextManager.registerCalculator(serverCalculator);
|
||||
|
||||
LuckPermsCalculator<ProxiedPlayer> staticCalculator = new LuckPermsCalculator<>(getConfiguration());
|
||||
contextManager.registerCalculator(staticCalculator, true);
|
||||
if (getProxy().getPluginManager().getPlugin("RedisBungee") != null) {
|
||||
contextManager.registerStaticCalculator(new RedisBungeeCalculator());
|
||||
}
|
||||
|
||||
// register with the LP API
|
||||
apiProvider = new ApiProvider(this);
|
||||
ApiHandler.registerProvider(apiProvider);
|
||||
ApiSingletonUtils.registerProvider(apiProvider);
|
||||
|
||||
// schedule update tasks
|
||||
int mins = getConfiguration().get(ConfigKeys.SYNC_TIME);
|
||||
@@ -269,7 +208,7 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
|
||||
// run an update instantly.
|
||||
getLog().info("Performing initial data load...");
|
||||
updateTaskBuffer.requestDirectly();
|
||||
new UpdateTask(this, true).run();
|
||||
|
||||
// register tasks
|
||||
scheduler.asyncRepeating(new ExpireTemporaryTask(this), 60L);
|
||||
@@ -280,6 +219,9 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
permissionVault.shutdown();
|
||||
verboseHandler.shutdown();
|
||||
|
||||
getLog().info("Closing storage...");
|
||||
storage.shutdown();
|
||||
|
||||
@@ -292,12 +234,23 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
messagingService.close();
|
||||
}
|
||||
|
||||
ApiHandler.unregisterProvider();
|
||||
ApiSingletonUtils.unregisterProvider();
|
||||
|
||||
getLog().info("Shutting down internal scheduler...");
|
||||
scheduler.shutdown();
|
||||
|
||||
getProxy().getScheduler().cancel(this);
|
||||
getProxy().getPluginManager().unregisterListeners(this);
|
||||
getLog().info("Goodbye!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ExtendedMessagingService> getMessagingService() {
|
||||
return Optional.ofNullable(messagingService);
|
||||
}
|
||||
|
||||
public Optional<FileWatcher> getFileWatcher() {
|
||||
return Optional.ofNullable(fileWatcher);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -363,13 +316,13 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getPlayerList() {
|
||||
return getProxy().getPlayers().stream().map(ProxiedPlayer::getName).collect(Collectors.toList());
|
||||
public Stream<String> getPlayerList() {
|
||||
return getProxy().getPlayers().stream().map(ProxiedPlayer::getName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> getOnlinePlayers() {
|
||||
return getProxy().getPlayers().stream().map(ProxiedPlayer::getUniqueId).collect(Collectors.toSet());
|
||||
public Stream<UUID> getOnlinePlayers() {
|
||||
return getProxy().getPlayers().stream().map(ProxiedPlayer::getUniqueId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -379,24 +332,15 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Sender> getOnlineSenders() {
|
||||
return getProxy().getPlayers().stream()
|
||||
.map(p -> getSenderFactory().wrap(p))
|
||||
.collect(Collectors.toList());
|
||||
public Stream<Sender> getOnlineSenders() {
|
||||
return Stream.concat(
|
||||
Stream.of(getConsoleSender()),
|
||||
getProxy().getPlayers().stream().map(p -> getSenderFactory().wrap(p))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sender getConsoleSender() {
|
||||
return getSenderFactory().wrap(getProxy().getConsole());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Contexts> getPreProcessContexts(boolean op) {
|
||||
Set<ImmutableContextSet> c = new HashSet<>();
|
||||
c.add(ContextSet.empty());
|
||||
c.add(ContextSet.singleton("server", getConfiguration().get(ConfigKeys.SERVER)));
|
||||
return c.stream()
|
||||
.map(set -> contextManager.formContexts(null, set))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -33,6 +33,7 @@ import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.bungee.LPBungeePlugin;
|
||||
import me.lucko.luckperms.common.calculators.AbstractCalculatorFactory;
|
||||
import me.lucko.luckperms.common.calculators.PermissionCalculator;
|
||||
import me.lucko.luckperms.common.calculators.PermissionCalculatorMetadata;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.processors.MapProcessor;
|
||||
@@ -60,7 +61,8 @@ public class BungeeCalculatorFactory extends AbstractCalculatorFactory {
|
||||
processors.add(new WildcardProcessor());
|
||||
}
|
||||
|
||||
return registerCalculator(new PermissionCalculator(plugin, user.getFriendlyName(), processors.build()));
|
||||
PermissionCalculatorMetadata meta = PermissionCalculatorMetadata.of(user.getFriendlyName(), contexts.getContexts());
|
||||
return registerCalculator(new PermissionCalculator(plugin, meta, processors.build()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-2
@@ -39,7 +39,7 @@ public class BackendServerCalculator implements ContextCalculator<ProxiedPlayer>
|
||||
private static final String WORLD_KEY = "world";
|
||||
|
||||
private static String getServer(ProxiedPlayer player) {
|
||||
return player.getServer() == null ? null : (player.getServer().getInfo() == null ? null : player.getServer().getInfo().getName());
|
||||
return player.getServer() == null ? null : (player.getServer().getInfo() == null ? null : player.getServer().getInfo().getName().toLowerCase());
|
||||
}
|
||||
|
||||
private final LuckPermsPlugin plugin;
|
||||
@@ -49,7 +49,7 @@ public class BackendServerCalculator implements ContextCalculator<ProxiedPlayer>
|
||||
String server = getServer(subject);
|
||||
while (server != null && !accumulator.has(WORLD_KEY, server)) {
|
||||
accumulator.add(WORLD_KEY, server);
|
||||
server = plugin.getConfiguration().get(ConfigKeys.WORLD_REWRITES).getOrDefault(server, server);
|
||||
server = plugin.getConfiguration().get(ConfigKeys.WORLD_REWRITES).getOrDefault(server, server).toLowerCase();
|
||||
}
|
||||
|
||||
return accumulator;
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bungee.contexts;
|
||||
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
||||
import me.lucko.luckperms.bungee.LPBungeePlugin;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.contexts.AbstractContextManager;
|
||||
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
|
||||
public class BungeeContextManager extends AbstractContextManager<ProxiedPlayer> {
|
||||
public BungeeContextManager(LPBungeePlugin plugin) {
|
||||
super(plugin, ProxiedPlayer.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Contexts formContexts(ProxiedPlayer subject, ImmutableContextSet contextSet) {
|
||||
return new Contexts(
|
||||
contextSet,
|
||||
plugin.getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_PERMS),
|
||||
plugin.getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_WORLD_PERMS),
|
||||
true,
|
||||
plugin.getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_GROUPS),
|
||||
plugin.getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_WORLD_GROUPS),
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bungee.contexts;
|
||||
|
||||
import com.imaginarycode.minecraft.redisbungee.RedisBungee;
|
||||
import com.imaginarycode.minecraft.redisbungee.RedisBungeeAPI;
|
||||
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.api.context.StaticContextCalculator;
|
||||
|
||||
public class RedisBungeeCalculator implements StaticContextCalculator {
|
||||
private static final String PROXY_KEY = "proxy";
|
||||
|
||||
@Override
|
||||
public MutableContextSet giveApplicableContext(MutableContextSet accumulator) {
|
||||
RedisBungeeAPI redisBungee = RedisBungee.getApi();
|
||||
if (redisBungee != null) {
|
||||
accumulator.add(PROXY_KEY, redisBungee.getServerId());
|
||||
}
|
||||
return accumulator;
|
||||
}
|
||||
}
|
||||
+44
-87
@@ -23,14 +23,11 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bungee;
|
||||
package me.lucko.luckperms.bungee.listeners;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.bungee.event.TristateCheckEvent;
|
||||
import me.lucko.luckperms.bungee.LPBungeePlugin;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
@@ -40,19 +37,16 @@ import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.connection.PendingConnection;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
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.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class BungeeListener implements Listener {
|
||||
public class BungeeConnectionListener implements Listener {
|
||||
private final LPBungeePlugin plugin;
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW)
|
||||
@@ -70,20 +64,30 @@ public class BungeeListener implements Listener {
|
||||
|
||||
final PendingConnection c = e.getConnection();
|
||||
|
||||
if (plugin.getConfiguration().get(ConfigKeys.DEBUG_LOGINS)) {
|
||||
plugin.getLog().info("Processing pre-login for " + c.getUniqueId() + " - " + c.getName());
|
||||
}
|
||||
|
||||
/* there was an issue connecting to the DB, performing file i/o, etc.
|
||||
as this is bungeecord, we will still allow the login, as players can't really do much harm without permissions data.
|
||||
the proxy will just fallback to using the config file perms. */
|
||||
if (!plugin.getStorage().isAcceptingLogins()) {
|
||||
|
||||
// log that the user tried to login, but was denied at this stage.
|
||||
plugin.getLog().warn("Permissions storage is not loaded. No permissions data will be loaded for: " + c.getUniqueId() + " - " + c.getName());
|
||||
if (plugin.getConfiguration().get(ConfigKeys.CANCEL_FAILED_LOGINS)) {
|
||||
// cancel the login attempt
|
||||
e.setCancelReason(TextComponent.fromLegacyText(Message.LOADING_ERROR.asString(plugin.getLocaleManager())));
|
||||
e.setCancelled(true);
|
||||
} else {
|
||||
// log that the user tried to login, but was denied at this stage.
|
||||
plugin.getLog().warn("Permissions storage is not loaded. No permissions data will be loaded for: " + c.getUniqueId() + " - " + c.getName());
|
||||
}
|
||||
|
||||
e.completeIntent(plugin);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
plugin.doAsync(() -> {
|
||||
plugin.getScheduler().doAsync(() -> {
|
||||
plugin.getUniqueConnections().add(c.getUniqueId());
|
||||
|
||||
/* Actually process the login for the connection.
|
||||
@@ -96,12 +100,20 @@ public class BungeeListener implements Listener {
|
||||
- creating a user instance in the UserManager for this connection.
|
||||
- setting up cached data. */
|
||||
try {
|
||||
LoginHelper.loadUser(plugin, c.getUniqueId(), c.getName(), true);
|
||||
User user = LoginHelper.loadUser(plugin, c.getUniqueId(), c.getName(), true);
|
||||
plugin.getApiProvider().getEventFactory().handleUserLoginProcess(c.getUniqueId(), c.getName(), user);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
|
||||
// there was some error loading
|
||||
plugin.getLog().warn("Error loading data. No permissions data will be loaded for: " + c.getUniqueId() + " - " + c.getName());
|
||||
if (plugin.getConfiguration().get(ConfigKeys.CANCEL_FAILED_LOGINS)) {
|
||||
// cancel the login attempt
|
||||
e.setCancelReason(TextComponent.fromLegacyText(Message.LOADING_ERROR.asString(plugin.getLocaleManager())));
|
||||
e.setCancelled(true);
|
||||
} else {
|
||||
plugin.getLog().warn("Error loading data. No permissions data will be loaded for: " + c.getUniqueId() + " - " + c.getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// finally, complete our intent to modify state, so the proxy can continue handling the connection.
|
||||
@@ -118,14 +130,25 @@ public class BungeeListener implements Listener {
|
||||
final ProxiedPlayer player = e.getPlayer();
|
||||
final User user = plugin.getUserManager().getIfLoaded(plugin.getUuidCache().getUUID(e.getPlayer().getUniqueId()));
|
||||
|
||||
if (user == null) {
|
||||
plugin.getProxy().getScheduler().schedule(plugin, () -> {
|
||||
if (!player.isConnected()) {
|
||||
return;
|
||||
}
|
||||
if (plugin.getConfiguration().get(ConfigKeys.DEBUG_LOGINS)) {
|
||||
plugin.getLog().info("Processing post-login for " + player.getUniqueId() + " - " + player.getName());
|
||||
}
|
||||
|
||||
player.sendMessage(new TextComponent(Message.LOADING_ERROR.asString(plugin.getLocaleManager())));
|
||||
}, 3, TimeUnit.SECONDS);
|
||||
if (user == null) {
|
||||
if (plugin.getConfiguration().get(ConfigKeys.CANCEL_FAILED_LOGINS)) {
|
||||
// disconnect the user
|
||||
plugin.getLog().warn("User " + player.getUniqueId() + " - " + player.getName() + " doesn't have data pre-loaded - cancelling login.");
|
||||
e.getPlayer().disconnect(TextComponent.fromLegacyText(Message.LOADING_ERROR.asString(plugin.getLocaleManager())));
|
||||
} else {
|
||||
// just send a message
|
||||
plugin.getProxy().getScheduler().schedule(plugin, () -> {
|
||||
if (!player.isConnected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
player.sendMessage(TextComponent.fromLegacyText(Message.LOADING_ERROR.asString(plugin.getLocaleManager())));
|
||||
}, 1, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,70 +159,4 @@ public class BungeeListener implements Listener {
|
||||
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().getIfLoaded(plugin.getUuidCache().getUUID(player.getUniqueId()));
|
||||
if (user == null) {
|
||||
e.setHasPermission(false);
|
||||
return;
|
||||
}
|
||||
|
||||
Contexts contexts = plugin.getContextManager().getApplicableContexts(player);
|
||||
Tristate result = user.getUserData().getPermissionData(contexts).getPermissionValue(e.getPermission());
|
||||
if (result == Tristate.UNDEFINED && plugin.getConfiguration().get(ConfigKeys.APPLY_BUNGEE_CONFIG_PERMISSIONS)) {
|
||||
return; // just use the result provided by the proxy when the event was created
|
||||
}
|
||||
|
||||
e.setHasPermission(result.asBoolean());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onPlayerTristateCheck(TristateCheckEvent e) {
|
||||
if (!(e.getSender() instanceof ProxiedPlayer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ProxiedPlayer player = ((ProxiedPlayer) e.getSender());
|
||||
|
||||
User user = plugin.getUserManager().getIfLoaded(plugin.getUuidCache().getUUID(player.getUniqueId()));
|
||||
if (user == null) {
|
||||
e.setResult(Tristate.UNDEFINED);
|
||||
return;
|
||||
}
|
||||
|
||||
Contexts contexts = plugin.getContextManager().getApplicableContexts(player);
|
||||
Tristate result = user.getUserData().getPermissionData(contexts).getPermissionValue(e.getPermission());
|
||||
if (result == Tristate.UNDEFINED && plugin.getConfiguration().get(ConfigKeys.APPLY_BUNGEE_CONFIG_PERMISSIONS)) {
|
||||
return; // just use the result provided by the proxy when the event was created
|
||||
}
|
||||
|
||||
e.setResult(result);
|
||||
}
|
||||
|
||||
// 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().getIfLoaded(plugin.getUuidCache().getUUID(uuid));
|
||||
if (user == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Contexts contexts = plugin.getContextManager().formContexts(e.getPlayer(), set.makeImmutable());
|
||||
user.getUserData().preCalculate(contexts);
|
||||
});
|
||||
}
|
||||
}
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bungee.listeners;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.bungee.LPBungeePlugin;
|
||||
import me.lucko.luckperms.bungee.event.TristateCheckEvent;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.verbose.CheckOrigin;
|
||||
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.PermissionCheckEvent;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
import net.md_5.bungee.event.EventPriority;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class BungeePermissionCheckListener implements Listener {
|
||||
private final LPBungeePlugin plugin;
|
||||
|
||||
@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().getIfLoaded(plugin.getUuidCache().getUUID(player.getUniqueId()));
|
||||
if (user == null) {
|
||||
e.setHasPermission(false);
|
||||
return;
|
||||
}
|
||||
|
||||
Contexts contexts = plugin.getContextManager().getApplicableContexts(player);
|
||||
Tristate result = user.getUserData().getPermissionData(contexts).getPermissionValue(e.getPermission(), CheckOrigin.PLATFORM_PERMISSION_CHECK);
|
||||
if (result == Tristate.UNDEFINED && plugin.getConfiguration().get(ConfigKeys.APPLY_BUNGEE_CONFIG_PERMISSIONS)) {
|
||||
return; // just use the result provided by the proxy when the event was created
|
||||
}
|
||||
|
||||
e.setHasPermission(result.asBoolean());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onPlayerTristateCheck(TristateCheckEvent e) {
|
||||
if (!(e.getSender() instanceof ProxiedPlayer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ProxiedPlayer player = ((ProxiedPlayer) e.getSender());
|
||||
|
||||
User user = plugin.getUserManager().getIfLoaded(plugin.getUuidCache().getUUID(player.getUniqueId()));
|
||||
if (user == null) {
|
||||
e.setResult(Tristate.UNDEFINED);
|
||||
return;
|
||||
}
|
||||
|
||||
Contexts contexts = plugin.getContextManager().getApplicableContexts(player);
|
||||
Tristate result = user.getUserData().getPermissionData(contexts).getPermissionValue(e.getPermission(), CheckOrigin.PLATFORM_LOOKUP_CHECK);
|
||||
if (result == Tristate.UNDEFINED && plugin.getConfiguration().get(ConfigKeys.APPLY_BUNGEE_CONFIG_PERMISSIONS)) {
|
||||
return; // just use the result provided by the proxy when the event was created
|
||||
}
|
||||
|
||||
e.setResult(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bungee.messaging;
|
||||
|
||||
import me.lucko.luckperms.bungee.LPBungeePlugin;
|
||||
import me.lucko.luckperms.common.messaging.ExtendedMessagingService;
|
||||
import me.lucko.luckperms.common.messaging.MessagingFactory;
|
||||
|
||||
public class BungeeMessagingFactory extends MessagingFactory<LPBungeePlugin> {
|
||||
public BungeeMessagingFactory(LPBungeePlugin plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExtendedMessagingService getServiceFor(String messagingType) {
|
||||
if (messagingType.equals("bungee")) {
|
||||
BungeeMessagingService bungeeMessaging = new BungeeMessagingService(getPlugin());
|
||||
bungeeMessaging.init();
|
||||
return bungeeMessaging;
|
||||
} else if (messagingType.equals("redisbungee")) {
|
||||
if (getPlugin().getProxy().getPluginManager().getPlugin("RedisBungee") == null) {
|
||||
getPlugin().getLog().warn("RedisBungee plugin not present.");
|
||||
} else {
|
||||
RedisBungeeMessagingService redisBungeeMessaging = new RedisBungeeMessagingService(getPlugin());
|
||||
redisBungeeMessaging.init();
|
||||
return redisBungeeMessaging;
|
||||
}
|
||||
}
|
||||
|
||||
return super.getServiceFor(messagingType);
|
||||
}
|
||||
}
|
||||
+6
-5
@@ -31,6 +31,7 @@ import com.google.common.io.ByteStreams;
|
||||
|
||||
import me.lucko.luckperms.bungee.LPBungeePlugin;
|
||||
import me.lucko.luckperms.common.messaging.AbstractMessagingService;
|
||||
import me.lucko.luckperms.common.messaging.ExtendedMessagingService;
|
||||
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
@@ -39,7 +40,7 @@ import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
|
||||
/**
|
||||
* An implementation of {@link me.lucko.luckperms.api.MessagingService} using the plugin messaging channels.
|
||||
* An implementation of {@link ExtendedMessagingService} using the plugin messaging channels.
|
||||
*/
|
||||
public class BungeeMessagingService extends AbstractMessagingService implements Listener {
|
||||
private final LPBungeePlugin plugin;
|
||||
@@ -60,7 +61,7 @@ public class BungeeMessagingService extends AbstractMessagingService implements
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendMessage(String channel, String message) {
|
||||
protected void sendMessage(String message) {
|
||||
|
||||
ByteArrayDataOutput out = ByteStreams.newDataOutput();
|
||||
out.writeUTF(message);
|
||||
@@ -68,7 +69,7 @@ public class BungeeMessagingService extends AbstractMessagingService implements
|
||||
byte[] data = out.toByteArray();
|
||||
|
||||
for (ServerInfo server : plugin.getProxy().getServers().values()) {
|
||||
server.sendData(channel, data, true);
|
||||
server.sendData(CHANNEL, data, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,9 +88,9 @@ public class BungeeMessagingService extends AbstractMessagingService implements
|
||||
ByteArrayDataInput in = ByteStreams.newDataInput(e.getData());
|
||||
String msg = in.readUTF();
|
||||
|
||||
onMessage(e.getTag(), msg, u -> {
|
||||
onMessage(msg, u -> {
|
||||
// Forward to other servers
|
||||
plugin.doAsync(() -> sendMessage(CHANNEL, "update:" + u.toString()));
|
||||
plugin.getScheduler().doAsync(() -> sendMessage(u));
|
||||
});
|
||||
}
|
||||
}
|
||||
+9
-4
@@ -31,12 +31,13 @@ import com.imaginarycode.minecraft.redisbungee.events.PubSubMessageEvent;
|
||||
|
||||
import me.lucko.luckperms.bungee.LPBungeePlugin;
|
||||
import me.lucko.luckperms.common.messaging.AbstractMessagingService;
|
||||
import me.lucko.luckperms.common.messaging.ExtendedMessagingService;
|
||||
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
|
||||
/**
|
||||
* An implementation of {@link me.lucko.luckperms.api.MessagingService} using Redis, via RedisBungee's API.
|
||||
* An implementation of {@link ExtendedMessagingService} using Redis, via RedisBungee's API.
|
||||
*/
|
||||
public class RedisBungeeMessagingService extends AbstractMessagingService implements Listener {
|
||||
private final LPBungeePlugin plugin;
|
||||
@@ -63,12 +64,16 @@ public class RedisBungeeMessagingService extends AbstractMessagingService implem
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendMessage(String channel, String message) {
|
||||
redisBungee.sendChannelMessage(channel, message);
|
||||
protected void sendMessage(String message) {
|
||||
redisBungee.sendChannelMessage(CHANNEL, message);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onMessage(PubSubMessageEvent e) {
|
||||
onMessage(e.getChannel(), e.getMessage(), null);
|
||||
if (!e.getChannel().equals(CHANNEL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
onMessage(e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
@@ -73,6 +73,28 @@ use-server-uuids: true
|
||||
# try to find a uuid for a username using RedisBungee, if installed.
|
||||
use-server-uuid-cache: false
|
||||
|
||||
# If set to true, LuckPerms will allow usernames with non alphanumeric characters.
|
||||
#
|
||||
# Note that due to the design of the storage implementation, usernames must still be
|
||||
# 16 characters or less.
|
||||
allow-invalid-usernames: false
|
||||
|
||||
# If LuckPerms should produce extra logging output when it handles logins.
|
||||
# Useful if you're having issues with UUID forwarding or data not being loaded.
|
||||
debug-logins: false
|
||||
|
||||
# If LuckPerms should ensure all players have permission data when they connect to the server.
|
||||
#
|
||||
# When set to true, LuckPerms will cancel login attempts if it is unable to load permissions data
|
||||
# for a user, of if the storage provider is unavailable.
|
||||
#
|
||||
# When set to false, LuckPerms will allow a player to connect regardless of whether their
|
||||
# permissions data could be loaded.
|
||||
#
|
||||
# This option does not exist on other platforms, and effectively defaults to true - however,
|
||||
# the option is provided on BungeeCord, as it is less likely to be so dependant on permissions.
|
||||
cancel-failed-logins: false
|
||||
|
||||
# If the plugin should send log notifications to users whenever permissions are modified.
|
||||
log-notify: true
|
||||
|
||||
@@ -82,11 +104,6 @@ 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"
|
||||
@@ -102,7 +119,11 @@ temporary-add-behaviour: deny
|
||||
# -> parents-by-weight just use the users most highly weighted parent
|
||||
# -> all-parents-by-weight same as above, but calculates based upon all parents inherited from both
|
||||
# directly and indirectly
|
||||
primary-group-calculation: stored
|
||||
primary-group-calculation: parents-by-weight
|
||||
|
||||
# If set to false, the plugin will allow a Users primary group to be removed with the
|
||||
# 'parent remove' command, and will set their primary group back to default.
|
||||
prevent-primary-group-removal: false
|
||||
|
||||
# If the plugin should check for "extra" permissions with users run LP commands.
|
||||
#
|
||||
@@ -157,6 +178,8 @@ group-weight:
|
||||
# - lowest
|
||||
# - highest_own
|
||||
# - lowest_own
|
||||
# - highest_inherited
|
||||
# - lowest_inherited
|
||||
# - highest_on_track_<track>
|
||||
# - lowest_on_track_<track>
|
||||
# - highest_not_on_track_<track>
|
||||
@@ -187,7 +210,7 @@ meta-formatting:
|
||||
# Which storage method the plugin should use.
|
||||
#
|
||||
# See: https://github.com/lucko/LuckPerms/wiki/Choosing-a-Storage-type
|
||||
# Currently supported: mysql, mariadb, postgresql, sqlite, h2, json, yaml, mongodb
|
||||
# Currently supported: mysql, mariadb, postgresql, sqlite, h2, json, yaml, hocon, 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".
|
||||
@@ -263,6 +286,16 @@ messaging-service: none
|
||||
# If LuckPerms should automatically push updates after a change has been made with a command.
|
||||
auto-push-updates: true
|
||||
|
||||
# If LuckPerms should push logging entries to connected servers via the messaging service.
|
||||
push-log-entries: true
|
||||
|
||||
# If LuckPerms should broadcast received logging entries to players on this platform.
|
||||
#
|
||||
# If you have LuckPerms installed on your backend servers as well as a BungeeCord proxy, you should
|
||||
# set this option to false on either your backends or your proxies, to avoid players being messaged
|
||||
# twice about log entries.
|
||||
broadcast-received-log-entries: false
|
||||
|
||||
# Settings for Redis.
|
||||
# Port 6379 is used by default; set address to "host:port" if differs
|
||||
redis:
|
||||
|
||||
+63
-5
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>luckperms</artifactId>
|
||||
<groupId>me.lucko.luckperms</groupId>
|
||||
<version>3.3-SNAPSHOT</version>
|
||||
<version>4.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -39,14 +39,72 @@
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>text</artifactId>
|
||||
<version>1.12-SNAPSHOT</version>
|
||||
<version>1.11-1.2.0</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>jsr305</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!-- configurate -->
|
||||
<dependency>
|
||||
<groupId>ninja.leaping.configurate</groupId>
|
||||
<artifactId>configurate-core</artifactId>
|
||||
<version>3.3</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ninja.leaping.configurate</groupId>
|
||||
<artifactId>configurate-yaml</artifactId>
|
||||
<version>3.3</version>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ninja.leaping.configurate</groupId>
|
||||
<artifactId>configurate-gson</artifactId>
|
||||
<version>3.3</version>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ninja.leaping.configurate</groupId>
|
||||
<artifactId>configurate-hocon</artifactId>
|
||||
<version>3.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- HikariCP -->
|
||||
<dependency>
|
||||
<groupId>com.zaxxer</groupId>
|
||||
<artifactId>HikariCP</artifactId>
|
||||
<version>2.6.3</version>
|
||||
<version>2.7.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Jedis -->
|
||||
@@ -60,7 +118,7 @@
|
||||
<dependency>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>mongo-java-driver</artifactId>
|
||||
<version>3.4.2</version>
|
||||
<version>3.5.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- SnakeYAML -->
|
||||
@@ -88,7 +146,7 @@
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
<version>2.5.2</version>
|
||||
<version>2.5.6</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Lombok -->
|
||||
|
||||
@@ -0,0 +1,393 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.actionlog;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.ToString;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
|
||||
import me.lucko.luckperms.api.LogEntry;
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.model.Group;
|
||||
import me.lucko.luckperms.common.model.PermissionHolder;
|
||||
import me.lucko.luckperms.common.model.Track;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.utils.DateUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* An implementation of {@link LogEntry} and {@link LogEntry.Builder},
|
||||
* with helper methods for populating and using the entry using internal
|
||||
* LuckPerms classes.
|
||||
*/
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class ExtendedLogEntry implements LogEntry {
|
||||
|
||||
private static final String FORMAT = "&8(&e%s&8) [&a%s&8] (&b%s&8) &7--> &f%s";
|
||||
|
||||
/**
|
||||
* Compares two LogEntries
|
||||
*
|
||||
* @since 3.3
|
||||
*/
|
||||
public static final Comparator<LogEntry> COMPARATOR = Comparator
|
||||
.comparingLong(LogEntry::getTimestamp)
|
||||
.thenComparing(LogEntry::getActor)
|
||||
.thenComparing(LogEntry::getActorName, String.CASE_INSENSITIVE_ORDER)
|
||||
.thenComparing(LogEntry::getType)
|
||||
.thenComparing(e -> {
|
||||
UUID u = e.getActed().orElse(null);
|
||||
return u == null ? "" : u.toString();
|
||||
})
|
||||
.thenComparing(LogEntry::getActedName, String.CASE_INSENSITIVE_ORDER)
|
||||
.thenComparing(LogEntry::getAction);
|
||||
|
||||
/**
|
||||
* Compares two LogEntries in reverse order
|
||||
*
|
||||
* @since 3.3
|
||||
* @see #COMPARATOR
|
||||
*/
|
||||
public static final Comparator<LogEntry> REVERSE_ORDER = COMPARATOR.reversed();
|
||||
|
||||
/**
|
||||
* Creates a new log entry builder
|
||||
*
|
||||
* @return a new builder
|
||||
*/
|
||||
public static ExtendedLogEntryBuilder build() {
|
||||
return new ExtendedLogEntryBuilder();
|
||||
}
|
||||
|
||||
private final long timestamp;
|
||||
private final UUID actor;
|
||||
private final String actorName;
|
||||
private final Type type;
|
||||
private final UUID acted;
|
||||
private final String actedName;
|
||||
private final String action;
|
||||
|
||||
@Override
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getActor() {
|
||||
return actor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActorName() {
|
||||
return actorName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<UUID> getActed() {
|
||||
return Optional.ofNullable(acted);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActedName() {
|
||||
return actedName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(LogEntry other) {
|
||||
Preconditions.checkNotNull(other, "other");
|
||||
return COMPARATOR.compare(this, other);
|
||||
}
|
||||
|
||||
public boolean matchesSearch(String query) {
|
||||
query = Preconditions.checkNotNull(query, "query").toLowerCase();
|
||||
return actorName.toLowerCase().contains(query) ||
|
||||
actedName.toLowerCase().contains(query) ||
|
||||
action.toLowerCase().contains(query);
|
||||
}
|
||||
|
||||
public String getFormatted() {
|
||||
return String.format(FORMAT,
|
||||
String.valueOf(actorName).equals("null") ? actor.toString() : actorName,
|
||||
Character.toString(type.getCode()),
|
||||
String.valueOf(actedName).equals("null") && acted != null ? acted.toString() : actedName,
|
||||
action
|
||||
);
|
||||
}
|
||||
|
||||
public void submit(LuckPermsPlugin plugin, Sender sender) {
|
||||
plugin.getLogDispatcher().dispatch(this, sender);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LogEntry(" +
|
||||
"timestamp=" + this.getTimestamp() + ", " +
|
||||
"actor=" + this.getActor() + ", " +
|
||||
"actorName=" + this.getActorName() + ", " +
|
||||
"type=" + this.getType() + ", " +
|
||||
"acted=" + this.getActed() + ", " +
|
||||
"actedName=" + this.getActedName() + ", " +
|
||||
"action=" + this.getAction() + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) return true;
|
||||
if (!(o instanceof LogEntry)) return false;
|
||||
final LogEntry other = (LogEntry) o;
|
||||
|
||||
return this.getTimestamp() == other.getTimestamp() &&
|
||||
this.getActor().equals(other.getActor()) &&
|
||||
this.getActorName().equals(other.getActorName()) &&
|
||||
this.getType() == other.getType() &&
|
||||
(this.getActed() == null ? other.getActed() == null : this.getActed().equals(other.getActed())) &&
|
||||
this.getActedName().equals(other.getActedName()) &&
|
||||
this.getAction().equals(other.getAction());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int PRIME = 59;
|
||||
int result = 1;
|
||||
result = result * PRIME + (int) (this.getTimestamp() >>> 32 ^ this.getTimestamp());
|
||||
result = result * PRIME + this.getActor().hashCode();
|
||||
result = result * PRIME + this.getActorName().hashCode();
|
||||
result = result * PRIME + this.getType().hashCode();
|
||||
result = result * PRIME + (this.getActed() == null ? 43 : this.getActed().hashCode());
|
||||
result = result * PRIME + this.getActedName().hashCode();
|
||||
result = result * PRIME + this.getAction().hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
@ToString
|
||||
public static class ExtendedLogEntryBuilder implements LogEntry.Builder {
|
||||
|
||||
private long timestamp = 0L;
|
||||
private UUID actor = null;
|
||||
private String actorName = null;
|
||||
private Type type = null;
|
||||
private UUID acted = null;
|
||||
private String actedName = null;
|
||||
private String action = null;
|
||||
|
||||
@Override
|
||||
public ExtendedLogEntryBuilder setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExtendedLogEntryBuilder setActor(UUID actor) {
|
||||
this.actor = Preconditions.checkNotNull(actor, "actor");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExtendedLogEntryBuilder setActorName(String actorName) {
|
||||
this.actorName = Preconditions.checkNotNull(actorName, "actorName");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExtendedLogEntryBuilder setType(Type type) {
|
||||
this.type = Preconditions.checkNotNull(type, "type");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExtendedLogEntryBuilder setActed(UUID acted) {
|
||||
this.acted = acted; // nullable
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExtendedLogEntryBuilder setActedName(String actedName) {
|
||||
this.actedName = Preconditions.checkNotNull(actedName, "actedName");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExtendedLogEntryBuilder setAction(String action) {
|
||||
this.action = Preconditions.checkNotNull(action, "action");
|
||||
return this;
|
||||
}
|
||||
|
||||
public ExtendedLogEntryBuilder timestamp(long timestamp) {
|
||||
return setTimestamp(timestamp);
|
||||
}
|
||||
|
||||
public ExtendedLogEntryBuilder actor(UUID actor) {
|
||||
return setActor(actor);
|
||||
}
|
||||
|
||||
public ExtendedLogEntryBuilder actorName(String actorName) {
|
||||
return setActorName(actorName);
|
||||
}
|
||||
|
||||
public ExtendedLogEntryBuilder type(Type type) {
|
||||
return setType(type);
|
||||
}
|
||||
|
||||
public ExtendedLogEntryBuilder acted(UUID acted) {
|
||||
return setActed(acted);
|
||||
}
|
||||
|
||||
public ExtendedLogEntryBuilder actedName(String actedName) {
|
||||
return setActedName(actedName);
|
||||
}
|
||||
|
||||
public ExtendedLogEntryBuilder action(String action) {
|
||||
return setAction(action);
|
||||
}
|
||||
|
||||
public ExtendedLogEntryBuilder actor(Sender actor) {
|
||||
actorName(actor.getNameWithLocation());
|
||||
actor(actor.getUuid());
|
||||
return this;
|
||||
}
|
||||
|
||||
public ExtendedLogEntryBuilder acted(PermissionHolder acted) {
|
||||
if (acted instanceof User) {
|
||||
actedName(((User) acted).getName().orElse("null"));
|
||||
acted(((User) acted).getUuid());
|
||||
type(Type.USER);
|
||||
} else if (acted instanceof Group) {
|
||||
actedName(((Group) acted).getName());
|
||||
type(Type.GROUP);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public ExtendedLogEntryBuilder acted(Track track) {
|
||||
actedName(track.getName());
|
||||
type(Type.TRACK);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ExtendedLogEntryBuilder action(Object... args) {
|
||||
List<String> parts = new ArrayList<>();
|
||||
|
||||
for (Object o : args) {
|
||||
|
||||
// special formatting for ContextSets instead of just #toString
|
||||
if (o instanceof ContextSet) {
|
||||
ContextSet set = (ContextSet) o;
|
||||
|
||||
for (String value : set.getValues("server")) {
|
||||
parts.add("server=" + value);
|
||||
}
|
||||
for (String value : set.getValues("world")) {
|
||||
parts.add("world=" + value);
|
||||
}
|
||||
|
||||
for (Map.Entry<String, String> context : set.toSet()) {
|
||||
if (context.getKey().equals("server") || context.getKey().equals("world")) {
|
||||
continue;
|
||||
}
|
||||
parts.add(context.getKey() + "=" + context.getValue());
|
||||
}
|
||||
} else {
|
||||
parts.add(String.valueOf(o));
|
||||
}
|
||||
}
|
||||
|
||||
action(parts.stream().collect(Collectors.joining(" ")));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExtendedLogEntry build() {
|
||||
if (timestamp == 0L) {
|
||||
timestamp(DateUtil.unixSecondsNow());
|
||||
}
|
||||
|
||||
Preconditions.checkNotNull(actor, "actor");
|
||||
Preconditions.checkNotNull(actorName, "actorName");
|
||||
Preconditions.checkNotNull(type, "type");
|
||||
Preconditions.checkNotNull(actedName, "actedName");
|
||||
Preconditions.checkNotNull(action, "action");
|
||||
|
||||
return new ExtendedLogEntry(timestamp, actor, actorName, type, acted, actedName, action);
|
||||
}
|
||||
}
|
||||
|
||||
public static JsonObject serializeWithId(UUID id, LogEntry entry) {
|
||||
JsonObject data = new JsonObject();
|
||||
|
||||
data.add("id", new JsonPrimitive(id.toString()));
|
||||
data.add("actor", new JsonPrimitive(entry.getActor().toString()));
|
||||
data.add("actorName", new JsonPrimitive(entry.getActorName()));
|
||||
data.add("type", new JsonPrimitive(entry.getType().name()));
|
||||
if (entry.getActed() != null) {
|
||||
data.add("acted", new JsonPrimitive(entry.getActed().toString()));
|
||||
}
|
||||
data.add("actedName", new JsonPrimitive(entry.getActedName()));
|
||||
data.add("action", new JsonPrimitive(entry.getAction()));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public static Map.Entry<UUID, ExtendedLogEntry> deserialize(JsonObject object) {
|
||||
ExtendedLogEntryBuilder builder = build();
|
||||
|
||||
UUID id = UUID.fromString(object.get("id").getAsString());
|
||||
|
||||
builder.actor(UUID.fromString(object.get("actor").getAsString()));
|
||||
builder.actorName(object.get("actorName").getAsString());
|
||||
builder.type(Type.valueOf(object.get("type").getAsString()));
|
||||
if (object.has("acted")) {
|
||||
builder.actor(UUID.fromString(object.get("acted").getAsString()));
|
||||
}
|
||||
builder.actedName(object.get("actedName").getAsString());
|
||||
builder.action(object.get("action").getAsString());
|
||||
|
||||
return Maps.immutableEntry(id, builder.build());
|
||||
}
|
||||
}
|
||||
+28
-26
@@ -23,7 +23,7 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.data;
|
||||
package me.lucko.luckperms.common.actionlog;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@@ -46,7 +46,7 @@ public class Log {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
private static SortedMap<Integer, LogEntry> getPage(Set<LogEntry> set, int pageNo, int entries) {
|
||||
private static SortedMap<Integer, ExtendedLogEntry> getPage(Set<ExtendedLogEntry> set, int pageNo, int entries) {
|
||||
if (pageNo < 1) {
|
||||
throw new IllegalArgumentException("pageNo cannot be less than 1: " + pageNo);
|
||||
}
|
||||
@@ -57,11 +57,11 @@ public class Log {
|
||||
"Requested: " + minimumEntries + ", Log Count: " + set.size());
|
||||
}
|
||||
|
||||
final SortedMap<Integer, LogEntry> out = new TreeMap<>();
|
||||
final SortedMap<Integer, ExtendedLogEntry> out = new TreeMap<>();
|
||||
|
||||
final int max = minimumEntries + entries - 1;
|
||||
int index = 0;
|
||||
for (LogEntry e : set) {
|
||||
for (ExtendedLogEntry e : set) {
|
||||
index++;
|
||||
if (index >= minimumEntries) {
|
||||
out.put(index, e);
|
||||
@@ -83,17 +83,17 @@ public class Log {
|
||||
}
|
||||
|
||||
@Getter
|
||||
private final SortedSet<LogEntry> content;
|
||||
private final SortedSet<ExtendedLogEntry> content;
|
||||
|
||||
public Log(SortedSet<LogEntry> content) {
|
||||
public Log(SortedSet<ExtendedLogEntry> content) {
|
||||
this.content = ImmutableSortedSet.copyOfSorted(content);
|
||||
}
|
||||
|
||||
public SortedSet<LogEntry> getRecent() {
|
||||
public SortedSet<ExtendedLogEntry> getRecent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public SortedMap<Integer, LogEntry> getRecent(int pageNo) {
|
||||
public SortedMap<Integer, ExtendedLogEntry> getRecent(int pageNo) {
|
||||
return getPage(content, pageNo, PAGE_ENTRIES);
|
||||
}
|
||||
|
||||
@@ -101,13 +101,13 @@ public class Log {
|
||||
return getMaxPages(content.size(), PAGE_ENTRIES);
|
||||
}
|
||||
|
||||
public SortedSet<LogEntry> getRecent(UUID actor) {
|
||||
public SortedSet<ExtendedLogEntry> getRecent(UUID actor) {
|
||||
return content.stream()
|
||||
.filter(e -> e.getActor().equals(actor))
|
||||
.collect(Collectors.toCollection(TreeSet::new));
|
||||
}
|
||||
|
||||
public SortedMap<Integer, LogEntry> getRecent(int pageNo, UUID actor) {
|
||||
public SortedMap<Integer, ExtendedLogEntry> getRecent(int pageNo, UUID actor) {
|
||||
return getPage(getRecent(actor), pageNo, PAGE_ENTRIES);
|
||||
}
|
||||
|
||||
@@ -117,67 +117,69 @@ public class Log {
|
||||
.count(), PAGE_ENTRIES);
|
||||
}
|
||||
|
||||
public SortedSet<LogEntry> getUserHistory(UUID uuid) {
|
||||
public SortedSet<ExtendedLogEntry> getUserHistory(UUID uuid) {
|
||||
return content.stream()
|
||||
.filter(e -> e.getType() == 'U')
|
||||
.filter(e -> e.getType() == LogEntry.Type.USER)
|
||||
.filter(e -> e.getActed() != null)
|
||||
.filter(e -> e.getActed().equals(uuid))
|
||||
.collect(Collectors.toCollection(TreeSet::new));
|
||||
}
|
||||
|
||||
public SortedMap<Integer, LogEntry> getUserHistory(int pageNo, UUID uuid) {
|
||||
public SortedMap<Integer, ExtendedLogEntry> getUserHistory(int pageNo, UUID uuid) {
|
||||
return getPage(getUserHistory(uuid), pageNo, PAGE_ENTRIES);
|
||||
}
|
||||
|
||||
public int getUserHistoryMaxPages(UUID uuid) {
|
||||
return getMaxPages(content.stream()
|
||||
.filter(e -> e.getType() == 'U')
|
||||
.filter(e -> e.getType() == LogEntry.Type.USER)
|
||||
.filter(e -> e.getActed() != null)
|
||||
.filter(e -> e.getActed().equals(uuid))
|
||||
.count(), PAGE_ENTRIES);
|
||||
}
|
||||
|
||||
public SortedSet<LogEntry> getGroupHistory(String name) {
|
||||
public SortedSet<ExtendedLogEntry> getGroupHistory(String name) {
|
||||
return content.stream()
|
||||
.filter(e -> e.getType() == 'G')
|
||||
.filter(e -> e.getType() == LogEntry.Type.GROUP)
|
||||
.filter(e -> e.getActedName().equals(name))
|
||||
.collect(Collectors.toCollection(TreeSet::new));
|
||||
}
|
||||
|
||||
public SortedMap<Integer, LogEntry> getGroupHistory(int pageNo, String name) {
|
||||
public SortedMap<Integer, ExtendedLogEntry> getGroupHistory(int pageNo, String name) {
|
||||
return getPage(getGroupHistory(name), pageNo, PAGE_ENTRIES);
|
||||
}
|
||||
|
||||
public int getGroupHistoryMaxPages(String name) {
|
||||
return getMaxPages(content.stream()
|
||||
.filter(e -> e.getType() == 'G')
|
||||
.filter(e -> e.getType() == LogEntry.Type.GROUP)
|
||||
.filter(e -> e.getActedName().equals(name))
|
||||
.count(), PAGE_ENTRIES);
|
||||
}
|
||||
|
||||
public SortedSet<LogEntry> getTrackHistory(String name) {
|
||||
public SortedSet<ExtendedLogEntry> getTrackHistory(String name) {
|
||||
return content.stream()
|
||||
.filter(e -> e.getType() == 'T')
|
||||
.filter(e -> e.getType() == LogEntry.Type.TRACK)
|
||||
.filter(e -> e.getActedName().equals(name))
|
||||
.collect(Collectors.toCollection(TreeSet::new));
|
||||
}
|
||||
|
||||
public SortedMap<Integer, LogEntry> getTrackHistory(int pageNo, String name) {
|
||||
public SortedMap<Integer, ExtendedLogEntry> getTrackHistory(int pageNo, String name) {
|
||||
return getPage(getTrackHistory(name), pageNo, PAGE_ENTRIES);
|
||||
}
|
||||
|
||||
public int getTrackHistoryMaxPages(String name) {
|
||||
return getMaxPages(content.stream()
|
||||
.filter(e -> e.getType() == 'T')
|
||||
.filter(e -> e.getType() == LogEntry.Type.TRACK)
|
||||
.filter(e -> e.getActedName().equals(name))
|
||||
.count(), PAGE_ENTRIES);
|
||||
}
|
||||
|
||||
public SortedSet<LogEntry> getSearch(String query) {
|
||||
public SortedSet<ExtendedLogEntry> getSearch(String query) {
|
||||
return content.stream()
|
||||
.filter(e -> e.matchesSearch(query))
|
||||
.collect(Collectors.toCollection(TreeSet::new));
|
||||
}
|
||||
|
||||
public SortedMap<Integer, LogEntry> getSearch(int pageNo, String query) {
|
||||
public SortedMap<Integer, ExtendedLogEntry> getSearch(int pageNo, String query) {
|
||||
return getPage(getSearch(query), pageNo, PAGE_ENTRIES);
|
||||
}
|
||||
|
||||
@@ -189,9 +191,9 @@ public class Log {
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public static class Builder {
|
||||
private final SortedSet<LogEntry> content = new TreeSet<>();
|
||||
private final SortedSet<ExtendedLogEntry> content = new TreeSet<>();
|
||||
|
||||
public Builder add(LogEntry e) {
|
||||
public Builder add(ExtendedLogEntry e) {
|
||||
content.add(e);
|
||||
return this;
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.actionlog;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import me.lucko.luckperms.api.event.log.LogBroadcastEvent;
|
||||
import me.lucko.luckperms.common.commands.impl.log.LogNotify;
|
||||
import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.constants.CommandPermission;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
import me.lucko.luckperms.common.messaging.ExtendedMessagingService;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class LogDispatcher {
|
||||
private final LuckPermsPlugin plugin;
|
||||
|
||||
public void dispatch(ExtendedLogEntry entry, Sender sender) {
|
||||
// set the event to cancelled if the sender is import
|
||||
if (!plugin.getApiProvider().getEventFactory().handleLogPublish(sender.isImport(), entry)) {
|
||||
plugin.getStorage().logAction(entry);
|
||||
}
|
||||
|
||||
// don't dispatch log entries sent by an import process
|
||||
if (sender.isImport()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Optional<ExtendedMessagingService> messagingService = plugin.getMessagingService();
|
||||
if (!sender.isImport() && messagingService.isPresent()) {
|
||||
messagingService.get().pushLog(entry);
|
||||
}
|
||||
|
||||
if (!plugin.getApiProvider().getEventFactory().handleLogBroadcast(!plugin.getConfiguration().get(ConfigKeys.LOG_NOTIFY), entry, LogBroadcastEvent.Origin.LOCAL)) {
|
||||
final String msg = entry.getFormatted();
|
||||
|
||||
plugin.getOnlineSenders()
|
||||
.filter(CommandPermission.LOG_NOTIFY::isAuthorized)
|
||||
.filter(s -> !LogNotify.isIgnoring(plugin, s.getUuid()))
|
||||
.filter(s -> !s.getUuid().equals(sender.getUuid()))
|
||||
.forEach(s -> Message.LOG.send(s, msg));
|
||||
}
|
||||
}
|
||||
|
||||
public void dispatchFromRemote(ExtendedLogEntry entry) {
|
||||
if (!plugin.getConfiguration().get(ConfigKeys.BROADCAST_RECEIVED_LOG_ENTRIES)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!plugin.getApiProvider().getEventFactory().handleLogBroadcast(!plugin.getConfiguration().get(ConfigKeys.LOG_NOTIFY), entry, LogBroadcastEvent.Origin.REMOTE)) {
|
||||
final String msg = entry.getFormatted();
|
||||
|
||||
plugin.getOnlineSenders()
|
||||
.filter(CommandPermission.LOG_NOTIFY::isAuthorized)
|
||||
.filter(s -> !LogNotify.isIgnoring(plugin, s.getUuid()))
|
||||
.forEach(s -> Message.LOG.send(s, msg));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,80 +25,101 @@
|
||||
|
||||
package me.lucko.luckperms.common.api;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.Group;
|
||||
import me.lucko.luckperms.api.LPConfiguration;
|
||||
import me.lucko.luckperms.api.Logger;
|
||||
import me.lucko.luckperms.api.LogEntry;
|
||||
import me.lucko.luckperms.api.LuckPermsApi;
|
||||
import me.lucko.luckperms.api.MessagingService;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.api.NodeFactory;
|
||||
import me.lucko.luckperms.api.PlatformType;
|
||||
import me.lucko.luckperms.api.Storage;
|
||||
import me.lucko.luckperms.api.Track;
|
||||
import me.lucko.luckperms.api.User;
|
||||
import me.lucko.luckperms.api.UuidCache;
|
||||
import me.lucko.luckperms.api.context.ContextCalculator;
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
import me.lucko.luckperms.common.api.delegates.MetaStackFactoryDelegate;
|
||||
import me.lucko.luckperms.common.api.delegates.NodeFactoryDelegate;
|
||||
import me.lucko.luckperms.common.api.delegates.UserDelegate;
|
||||
import me.lucko.luckperms.api.context.ContextManager;
|
||||
import me.lucko.luckperms.api.event.EventBus;
|
||||
import me.lucko.luckperms.api.manager.GroupManager;
|
||||
import me.lucko.luckperms.api.manager.TrackManager;
|
||||
import me.lucko.luckperms.api.manager.UserManager;
|
||||
import me.lucko.luckperms.api.metastacking.MetaStackFactory;
|
||||
import me.lucko.luckperms.api.platform.PlatformInfo;
|
||||
import me.lucko.luckperms.common.actionlog.ExtendedLogEntry;
|
||||
import me.lucko.luckperms.common.api.delegates.manager.ApiContextManager;
|
||||
import me.lucko.luckperms.common.api.delegates.manager.ApiGroupManager;
|
||||
import me.lucko.luckperms.common.api.delegates.manager.ApiTrackManager;
|
||||
import me.lucko.luckperms.common.api.delegates.manager.ApiUserManager;
|
||||
import me.lucko.luckperms.common.api.delegates.misc.ApiMetaStackFactory;
|
||||
import me.lucko.luckperms.common.api.delegates.misc.ApiNodeFactory;
|
||||
import me.lucko.luckperms.common.api.delegates.misc.ApiPlatformInfo;
|
||||
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 me.lucko.luckperms.common.references.UserIdentifier;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Implements the LuckPerms API using the plugin instance
|
||||
*/
|
||||
public class ApiProvider implements LuckPermsApi {
|
||||
|
||||
@Getter(AccessLevel.NONE)
|
||||
private final LuckPermsPlugin plugin;
|
||||
|
||||
@Getter
|
||||
private final PlatformInfo platformInfo;
|
||||
private final UserManager userManager;
|
||||
private final GroupManager groupManager;
|
||||
private final TrackManager trackManager;
|
||||
private final LuckPermsEventBus eventBus;
|
||||
|
||||
@Getter
|
||||
private final ContextManager contextManager;
|
||||
private final MetaStackFactory metaStackFactory;
|
||||
private final EventFactory eventFactory;
|
||||
|
||||
@Getter
|
||||
private final MetaStackFactoryDelegate metaStackFactory;
|
||||
|
||||
public ApiProvider(LuckPermsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
|
||||
this.platformInfo = new ApiPlatformInfo(plugin);
|
||||
this.userManager = new ApiUserManager(plugin, plugin.getUserManager());
|
||||
this.groupManager = new ApiGroupManager(plugin.getGroupManager());
|
||||
this.trackManager = new ApiTrackManager(plugin.getTrackManager());
|
||||
this.eventBus = new LuckPermsEventBus(plugin);
|
||||
this.contextManager = new ApiContextManager(plugin, plugin.getContextManager());
|
||||
this.metaStackFactory = new ApiMetaStackFactory(plugin);
|
||||
this.eventFactory = new EventFactory(eventBus);
|
||||
this.metaStackFactory = new MetaStackFactoryDelegate(plugin);
|
||||
}
|
||||
|
||||
public EventFactory getEventFactory() {
|
||||
return eventFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runUpdateTask() {
|
||||
plugin.getUpdateTaskBuffer().request();
|
||||
public PlatformInfo getPlatformInfo() {
|
||||
return platformInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getApiVersion() {
|
||||
return 3.3;
|
||||
public UserManager getUserManager() {
|
||||
return userManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return plugin.getVersion();
|
||||
public GroupManager getGroupManager() {
|
||||
return groupManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformType getPlatformType() {
|
||||
return plugin.getServerType();
|
||||
public TrackManager getTrackManager() {
|
||||
return trackManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> runUpdateTask() {
|
||||
return plugin.getUpdateTaskBuffer().request();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventBus getEventBus() {
|
||||
return eventBus;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -113,8 +134,7 @@ public class ApiProvider implements LuckPermsApi {
|
||||
|
||||
@Override
|
||||
public Optional<MessagingService> getMessagingService() {
|
||||
InternalMessagingService service = plugin.getMessagingService();
|
||||
return service instanceof NoopMessagingService ? Optional.empty() : Optional.of(service);
|
||||
return plugin.getMessagingService().map(Function.identity());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -123,129 +143,22 @@ public class ApiProvider implements LuckPermsApi {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logger getLogger() {
|
||||
return plugin.getLog();
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getUser(@NonNull UUID uuid) {
|
||||
final me.lucko.luckperms.common.model.User user = plugin.getUserManager().getIfLoaded(uuid);
|
||||
return user == null ? null : user.getDelegate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<User> getUserSafe(@NonNull UUID uuid) {
|
||||
return Optional.ofNullable(getUser(uuid));
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getUser(@NonNull String name) {
|
||||
final me.lucko.luckperms.common.model.User user = plugin.getUserManager().getByUsername(name);
|
||||
return user == null ? null : user.getDelegate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<User> getUserSafe(@NonNull String name) {
|
||||
return Optional.ofNullable(getUser(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<User> getUsers() {
|
||||
return plugin.getUserManager().getAll().values().stream().map(u -> u.getDelegate()).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUserLoaded(@NonNull UUID uuid) {
|
||||
return plugin.getUserManager().isLoaded(UserIdentifier.of(uuid, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanupUser(@NonNull User user) {
|
||||
plugin.getUserManager().cleanup(UserDelegate.cast(user));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Group getGroup(@NonNull String name) {
|
||||
final me.lucko.luckperms.common.model.Group group = plugin.getGroupManager().getIfLoaded(name);
|
||||
return group == null ? null : group.getDelegate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Group> getGroupSafe(@NonNull String name) {
|
||||
return Optional.ofNullable(getGroup(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Group> getGroups() {
|
||||
return plugin.getGroupManager().getAll().values().stream().map(g -> g.getDelegate()).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGroupLoaded(@NonNull String name) {
|
||||
return plugin.getGroupManager().isLoaded(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Track getTrack(@NonNull String name) {
|
||||
final me.lucko.luckperms.common.model.Track track = plugin.getTrackManager().getIfLoaded(name);
|
||||
return track == null ? null : track.getDelegate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Track> getTrackSafe(@NonNull String name) {
|
||||
return Optional.ofNullable(getTrack(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Track> getTracks() {
|
||||
return plugin.getTrackManager().getAll().values().stream().map(t -> t.getDelegate()).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTrackLoaded(@NonNull String name) {
|
||||
return plugin.getTrackManager().isLoaded(name);
|
||||
public ContextManager getContextManager() {
|
||||
return contextManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NodeFactory getNodeFactory() {
|
||||
return NodeFactoryDelegate.INSTANCE;
|
||||
return ApiNodeFactory.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node.Builder buildNode(@NonNull String permission) throws IllegalArgumentException {
|
||||
return me.lucko.luckperms.common.node.NodeFactory.newBuilder(permission);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void registerContextCalculator(@NonNull ContextCalculator<?> contextCalculator) {
|
||||
plugin.getContextManager().registerCalculator(contextCalculator);
|
||||
public MetaStackFactory getMetaStackFactory() {
|
||||
return metaStackFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Contexts> getContextForUser(@NonNull User user) {
|
||||
return Optional.ofNullable(plugin.getContextForUser(UserDelegate.cast(user)));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public ContextSet getContextForPlayer(@NonNull Object player) {
|
||||
return plugin.getContextManager().getApplicableContext(player);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Contexts getContextsForPlayer(@NonNull Object player) {
|
||||
return plugin.getContextManager().getApplicableContexts(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> getUniqueConnections() {
|
||||
return Collections.unmodifiableSet(plugin.getUniqueConnections());
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStartTime() {
|
||||
return plugin.getStartTime();
|
||||
public LogEntry.Builder newLogEntryBuilder() {
|
||||
return ExtendedLogEntry.build();
|
||||
}
|
||||
}
|
||||
+12
-7
@@ -30,19 +30,24 @@ import me.lucko.luckperms.api.LuckPermsApi;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class ApiHandler {
|
||||
private static Method REGISTER;
|
||||
private static Method UNREGISTER;
|
||||
public class ApiSingletonUtils {
|
||||
private static final Method REGISTER;
|
||||
private static final Method UNREGISTER;
|
||||
static {
|
||||
Method register = null;
|
||||
Method unregister = null;
|
||||
try {
|
||||
REGISTER = LuckPerms.class.getDeclaredMethod("registerProvider", LuckPermsApi.class);
|
||||
REGISTER.setAccessible(true);
|
||||
register = LuckPerms.class.getDeclaredMethod("registerProvider", LuckPermsApi.class);
|
||||
register.setAccessible(true);
|
||||
|
||||
UNREGISTER = LuckPerms.class.getDeclaredMethod("unregisterProvider");
|
||||
UNREGISTER.setAccessible(true);
|
||||
unregister = LuckPerms.class.getDeclaredMethod("unregisterProvider");
|
||||
unregister.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
REGISTER = register;
|
||||
UNREGISTER = unregister;
|
||||
}
|
||||
|
||||
public static void registerProvider(LuckPermsApi luckPermsApi) {
|
||||
Loaded 100 of 384 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user