Compare commits

...
490 Commits
Author SHA1 Message Date
Luck 64838708ab Release version 4.2.0
blaze it
2018-05-06 17:16:36 +01:00
Luck 91b7af52ac Use the servers uuid cache in the output to /lp search if LP doesn't have data (#974) 2018-05-06 16:20:08 +01:00
Luck d3dded8791 Fix jedis shading (#930) 2018-05-06 15:58:40 +01:00
Luck 022b385c0a Fix /lp search query (#972) 2018-05-05 18:39:13 +01:00
Luck 7ee9b93365 Convert bulkupdate & search functionality to use PreparedStatements (#972) 2018-05-05 18:17:48 +01:00
Luck c4c98aaabf Improve the behaviour of the APIs (now somewhat redundant) holder refresh method 2018-05-04 23:17:06 +01:00
Luck 10c0efaa5d Fix bad caching logic resulting in super high CPU usage 2018-05-04 23:12:46 +01:00
Luck d8a7d8de4a Throw a more detailed error when database connection info is missing 2018-05-04 21:27:57 +01:00
Luck ab8b675bae Add flag to exclude users from an export (#961) 2018-05-04 18:19:52 +01:00
Luck 194b602fd6 Implement different comparison methods for /lp search (#917) 2018-05-04 18:11:11 +01:00
Luck 7da0c58b76 Improve consistency of contextual primary group caching 2018-05-04 17:24:40 +01:00
Luck 2dbbea4993 Remove the locks in NodeMap to ease thread contention when lots of processes are resolving inheritance & refactor the way LocalizedNodes are created (#734) 2018-05-04 16:16:12 +01:00
Luck 55d59bb1c4 Make auto-op changes take effect (almost) immediately (#943)
"almost immediately" is better than "after a relog" ;)
2018-05-03 20:21:52 +01:00
Luck a6facf7492 Refactor the way holder caches are invalidated in order to improve consistency (#734) 2018-05-03 19:36:10 +01:00
Luck b8a1871cf1 Fix guava being accidentally shaded 2018-05-03 13:46:17 +01:00
Luck f556c75d94 Allow display names to be set in specific contexts (#963) 2018-05-02 21:27:21 +01:00
Luck 58bd7de66a Implement equals, hashcode and toString for NodeTypes 2018-05-02 20:35:20 +01:00
Luck 4547b52748 Refactor extended node types, general cleanup 2018-05-02 20:18:57 +01:00
Luck b9acb84119 Optimize WildcardProcessor 2018-05-01 00:20:39 +01:00
Luck e3a783c546 Maybe fix problems with symlinks (#956) 2018-04-30 14:44:09 +01:00
Luck 2e136666be Remove storage buffers 2018-04-29 11:33:51 +01:00
Luck 7d089cb5f0 Refactor configurate deo serialization of permission data, add support for the TOML format 2018-04-28 21:26:59 +01:00
Luck 3784d904fb Some small fixes and changes for ContextSet implementations 2018-04-27 18:50:36 +01:00
Luck fef6ebf793 Context set values should be lowercase'd too 2018-04-26 19:51:05 +01:00
Luck 316e177c1d Exclude temporary file changes from FileWatcher (#945) 2018-04-26 18:44:53 +01:00
Luck 4cdff14c7c Apply improvements to the caches in AbstractContextManager (#929) 2018-04-25 21:14:16 +01:00
Luck 97121bc719 Add some missing null check annotations 2018-04-25 21:02:17 +01:00
Luck 1312aac349 Add promote and demote methods to the API (#938) 2018-04-25 19:58:56 +01:00
Bogdan 8a5c9ddef2 Added explicit column names in INSERT queries. (#939) 2018-04-25 18:27:28 +01:00
Luck 55382519a1 Fix sponge split-storage config section being in the wrong section of the config (#928) 2018-04-25 17:30:56 +01:00
Luck cbb562b603 Fix sponge subject storage 2018-04-25 17:30:02 +01:00
Luck ba51f803ba add more logging to the importer 2018-04-25 17:15:30 +01:00
Luck d73543408e Fix misplaced sponge config options 2018-04-23 21:31:04 +01:00
Luck 7d90dba08b Update some dependency versions 2018-04-21 23:26:34 +01:00
Luck f11ebe6166 Replace file logger with json based system 2018-04-21 18:16:35 +01:00
Luck 1b917f0901 Fix init error in SeparatedConfigurateDao (#924 & #925) 2018-04-21 17:03:59 +01:00
Luck 328353d053 Implement the option to combine yaml/json/hocon storage files into one 2018-04-20 21:59:32 +01:00
Luck 4e87489dc1 Output meta in inheritance order in the 'meta info' command (#908) 2018-04-20 15:04:29 +01:00
Luck 8e5bcdd5ea Move schema files to a namespaced package (#899) 2018-04-20 14:59:06 +01:00
Luck 882a29029e Account for Sponge permission defaults in SpongeSenderFactory#getPermissionValue (fixes #920) 2018-04-20 14:17:29 +01:00
Luck 4704c5c975 Add full diff to the log when webeditor data is applied (#922) 2018-04-20 14:06:35 +01:00
Luck 957365ab91 refactor inheritance graphs slightly 2018-04-20 14:00:50 +01:00
Luck f8d34d7f46 Fix compile 2018-04-09 20:58:52 +01:00
Luck cb185e4827 Minor misc changes 2018-04-08 22:58:15 +01:00
Luck f5c6b9e3d4 Add 'permission clear' command (#893) 2018-04-04 18:46:01 +01:00
Luck 96f0f46b3e Update readme 2018-04-04 17:10:33 +01:00
Luck 6a5b7ce3a1 derp 2018-04-04 15:29:45 +01:00
Luck f33c540efb Register Sponge PermDescriptions to the LP permission registry 2018-04-03 21:56:15 +01:00
Luck 7684ac5d3a Add extra parameter to EventBus#subscribe which allows a handler to be bound to a plugin 2018-04-02 17:26:02 +01:00
Luck c13b01da01 misc cleanup 2018-04-02 16:02:55 +01:00
Luck 3453f05aca Copy usernames in the GroupManager migration (#883) 2018-04-02 13:34:30 +01:00
Luck c8bb85a06b Don't intern strings in permission checking process 2018-03-31 22:13:10 +01:00
Luck 2aabc9902f Rename verbose paste to verbose upload 2018-03-31 22:09:58 +01:00
Luck 6dba778e60 Catch exceptions thrown in repeating tasks to avoid subsequent executions from being cancelled 2018-03-31 11:13:27 +01:00
Luck cbeaaca7af Fix shutdown hang (#881) 2018-03-31 11:11:42 +01:00
Luck 0e69c8902d Revert f63d6cf 2018-03-31 10:26:22 +01:00
Luck f63d6cfced Properly escape sql query for loadTrack (#877) 2018-03-30 21:50:03 +01:00
Luck 72f9de6cc7 Fix resolving data directory on Sponge servers with a custom config dir location (#875) 2018-03-30 21:37:33 +01:00
Luck 509e89b9cf Clarify the showtracks output (#862) 2018-03-30 11:58:32 +01:00
Luck 90cce19baf Make the world-rewrite map case insensitive (#863) 2018-03-30 11:54:17 +01:00
Luck e4e93b1af1 Improve the way player uuid data is saved/stored. Add a warning message to catch ip forwarding issues 2018-03-29 21:46:55 +01:00
funniray 8f30176edd Fixed command arguments for Nukkit (#871) 2018-03-27 16:43:49 +01:00
Luck 4923d10b86 Encode editor payload using UTF-8 (#841) 2018-03-18 20:58:33 +00:00
Luck bd3a4e1ad7 Fix Sql messenger table name & bug which meant entries were only received after a 1 min delay 2018-03-18 18:58:53 +00:00
Luck 0f99a6c5ca Fix recursive proxying in PhasedStorage
ugh
2018-03-18 18:31:30 +00:00
Luck 0150da94a8 Apply table prefix to the SQL messenger 2018-03-18 17:38:52 +00:00
Luck b8da286f64 Replace huge forwarding classes with java Proxy instances 2018-03-18 17:36:07 +00:00
Luck da797f154d Implement Messaging Service using SQL (#534) 2018-03-18 16:02:04 +00:00
Luck 926195efc4 Fix Sponge persisted subject parent serialisation 2018-03-18 11:41:13 +00:00
Luck 8c1c5c820c Fix Sponge subject inheritance 2018-03-18 10:41:27 +00:00
Luck f63f652edb Fix parentadd and parentremove sponge commands 2018-03-18 10:09:21 +00:00
Luck 174ef187e8 Rename role parameter in PermissionDescription.Builder#assign 2018-03-18 10:02:16 +00:00
Luck d1e76f401a Reorganise the default configuration 2018-03-17 21:03:50 +00:00
Luck d52983c5af Fix tristate check event on BungeeCord for console senders 2018-03-17 15:03:40 +00:00
Luck 4773934481 Fix race condition in the import process (#833) 2018-03-14 22:01:52 +00:00
Luck dbfc524180 Fix NPE in Message#asString (fixes #822, #823, #824) 2018-03-13 15:30:35 +00:00
Luck 60aa7c6104 Fix compile 2018-03-12 21:27:23 +00:00
Luck 907d716929 Reorganise commands 2018-03-12 21:25:39 +00:00
Luck 1689a8abe2 Fix adding null json values (#818) 2018-03-12 19:01:38 +00:00
Luck 5db3820df4 A few minor API javadoc changes 2018-03-12 18:58:11 +00:00
Luck f969e2e52b Strip color when sending messages to the fallback logger 2018-03-09 16:43:29 +00:00
Luck cde2306079 Compress editor/verbose/treeview data using gzip before uploading 2018-03-09 16:21:45 +00:00
Luck f6c440c172 Further improvements to the Sponge service design 2018-03-08 21:51:25 +00:00
Luck 1b98667365 Fix IsolatedClassLoader on Java 9 (#815) 2018-03-08 18:36:41 +00:00
Luck bf69d5314e Implement Sponge subject lookup queries using CachedData from LP common 2018-03-07 23:50:23 +00:00
Luck 6d2ea659a4 Fix errors relating to sponge plugin parameter being an illegal argument (#810) 2018-03-03 20:43:41 +00:00
Luck 0d89840179 Reduce the number of entries sent to the verbose viewer, cleanup old hikari try..catches 2018-03-03 20:41:46 +00:00
Luck f93e8fdccd Always fire SubjectDataUpdateEvent async 2018-03-03 16:27:43 +00:00
Luck 68e4d36f40 Extract common plugin behaviour into an abstract class 2018-03-03 16:26:37 +00:00
Luck cd5447de38 Submit users/groups to the editor in weight order 2018-03-01 18:26:32 +00:00
Luck 6c0bb61cb1 Remove sponge migration commands 2018-03-01 11:03:22 +00:00
Luck d9a45b1090 Implement SubjectDataUpdateEvent (#753) 2018-03-01 10:58:08 +00:00
Luck 7549b3eb9e Return a dummy value instead of throwing an exception when an offline player is queried via Vault (#806) 2018-03-01 10:08:09 +00:00
Luck 8f82ef7eb4 Add copyFrom method to Node.Builder 2018-03-01 09:19:26 +00:00
Luck fbe84322b5 Cleanup parts of the sponge service implementation 2018-03-01 08:48:39 +00:00
Luck 98fb9946e4 Refactor Contexts class 2018-02-28 19:13:21 +00:00
Luck 984bc5860f Set allow-invalid-usernames to true by default for Nukkit (#798) 2018-02-26 17:35:34 +00:00
Luck a42d27f056 Don't intern strings in ContextSets (#797) 2018-02-26 17:27:28 +00:00
Luck aa4833ed74 Fix NPEs caused in LPPermissionMap (#794) 2018-02-24 22:59:18 +00:00
Luck 6704ac4b46 Fully relocate the jedis driver 2018-02-24 18:20:56 +00:00
Luck 4e4ec8e608 Bump caffeine & hikari version 2018-02-24 14:15:51 +00:00
Luck 4f4a387f04 Run the permissible monitoring injector twice 2018-02-24 14:08:36 +00:00
Luck d0143f9e54 Fix issue with loading on old CraftBukkit versions 2018-02-24 14:04:22 +00:00
Luck b2175e885f Fix compat with older Gson versions (#791) 2018-02-24 13:50:38 +00:00
Luck 68dd96e563 Properly bump version 2018-02-23 22:16:52 +00:00
Luck 168e712324 Update API to 4.1 2018-02-23 22:13:41 +00:00
Luck 2889c28815 Separate prefix/suffix/meta nodes into their own section within yaml/json/hocon storage files 2018-02-23 15:59:12 +00:00
Luck 966bf8bf51 Replace deprecated method usage in NodeTools 2018-02-23 14:20:30 +00:00
Luck 63ff3c34b3 Fix default assignment expressions checking temporary permissions (#783) 2018-02-22 23:38:26 +00:00
Luck 736105cc12 Add node equality predicates, and provide way to determine hasPermission behaviour using them (#782) 2018-02-22 23:34:35 +00:00
Luck b1fa4263ed Fix illegal argument exception when a proxied Sponge calculator adds an empty context (#780) 2018-02-22 22:24:21 +00:00
Luck 31d435dc2b Update web related functionality to point to new locations and APIs (#770) (#784) 2018-02-22 22:09:37 +00:00
Luck da9977a30f Fix compile and some minor formatting errors 2018-02-20 20:15:48 +00:00
Andrew 9c92522564 MongoDB Replica Set connections cannot resolve (#776 & #777) 2018-02-20 19:59:29 +00:00
Luck 31e436868d Nukkit support (#764) 2018-02-18 15:10:35 +00:00
Luck 794455d728 Refactor bulkupdate comparisons 2018-02-16 22:25:19 +00:00
Luck 0adf85746d Abstract out the process of traversing the inheritance tree, add configurable option to choose which algorithm to use (#719) 2018-02-16 17:46:17 +00:00
Luck f1047df98e Log checks made against non Player command senders in LP bungee 2018-02-16 13:41:21 +00:00
Luck 765f9d2545 Remove old schema migration code, cleanup a bit 2018-02-16 13:19:43 +00:00
Luck 0b5588a7dd Cleanup temporary permission auditing process 2018-02-16 12:35:25 +00:00
Luck 4fda89d5c8 Wrap unimportant sql migrations in try..catch (#755) 2018-02-16 12:13:15 +00:00
Luck b8c5c60ece try to fix null proxySelector issue with okhttp 2018-02-15 22:20:11 +00:00
Luck a3730aceeb i'm a dummy 2018-02-15 22:08:42 +00:00
Luck df5240a67c Lazily initialise Http client 2018-02-15 22:03:53 +00:00
Luck 620b0c898c Add ability to edit multiple users/groups in the same editor session 2018-02-12 22:04:39 +00:00
Luck 02ac4bc48b Allow temporary-add-behaviour to be defined as an argument to the add/set commands (#747) 2018-02-10 22:04:53 +00:00
Luck d14310768c Allow bulkupdates without constraints (#746) 2018-02-10 21:51:57 +00:00
Luck 63f8e8849f extract WeightCache out of PermissionHolder 2018-02-10 21:27:02 +00:00
Luck 7e7268bb5a Filter expired entries from user/group bulk permission search results (#736) 2018-02-07 18:03:25 +00:00
Luck 173286d404 Rebuild default and child permission lookup maps live instead of only once when the plugin first enables 2018-02-04 20:50:35 +00:00
Luck fd937e3209 Refactor permission processors, misc cleanup 2018-02-04 18:39:34 +00:00
Luck 31df29194b Add source to UserPromote & UserDemote events (#722) 2018-02-01 21:33:32 +00:00
Luck a1a2e189b6 Refactor PEX primary group detection to exclude temporary parents 2018-02-01 20:31:54 +00:00
Luck 5799a26cb7 Migrate temporary permissions / parents in PEX migration 2018-02-01 20:03:20 +00:00
Luck fe200ca1ec Add API methods to load users/groups/tracks and return a future encapsulating the resultant object instead of a success flag 2018-01-30 15:55:36 +00:00
Luck 7f7116e1c7 Use OkHttp for web requests 2018-01-30 00:08:00 +00:00
Luck 0cc1c4e5a7 fix build, refactor Bukkit model classes 2018-01-28 14:18:53 +00:00
Luck 2bc56de1c3 Don't store API delegate instances for all users 2018-01-28 00:26:58 +00:00
Luck e28d15456c Update some dependencies 2018-01-25 23:31:31 +00:00
Luck 54dbede130 Add /lp debug command 2018-01-24 19:13:29 +00:00
Luck 982254ff5e Reduce the amount of unnecessary data in info command outputs a bit 2018-01-23 19:55:21 +00:00
Luck e1c60fa70f Only query online players when upgrading usernames --> uuids in Vault hooks 2018-01-23 17:07:26 +00:00
Luck 6923c4e247 Log the name of the calculator when an exception is thrown 2018-01-23 16:52:50 +00:00
Luck 0eba5f1cbc Add a means to provide a custom Storage dao implementation (#590) 2018-01-22 23:21:47 +00:00
Luck 4858e59b70 Don't relocate H2 or SQLite depends in favour of loading into isolated classloaders (fixes #704) 2018-01-22 21:32:31 +00:00
Luck 1f70ad978f Cleanup usages of loadUser/loadGroup/loadTrack - eliminate possibility for unloading race condition (#706) 2018-01-22 17:34:15 +00:00
Luck 40294b10f5 ensure that we always use the shaded JDBC driver 2018-01-21 22:20:00 +00:00
Luck 8d045be0b0 misc cleanup 2018-01-21 21:35:25 +00:00
Luck e24a482deb Don't call events for changes to transient nodes 2018-01-21 20:31:48 +00:00
Luck f18d230ff6 Force a clear of transient nodes when a User quits, don't just rely on their instance being unloaded 2018-01-21 20:25:00 +00:00
Luck 72d4e5cf7a Remove the 'use-server-uuids' option and internal UuidCache system
The feature has stuck around since the early days - and solves a problem which really should never occur.
2018-01-21 20:18:13 +00:00
Luck 4c3e28ba85 Only show enduring nodes in command output, encapsulate the Node multimaps in PermissionHolder into separate class 2018-01-21 19:53:20 +00:00
Luck 821dc4ef56 Expose a means to implement the plugin's MessagingService via the API 2018-01-19 23:35:41 +00:00
Luck 612712f015 fix accidentally marking guava as compile in the previous commit 2018-01-19 19:29:34 +00:00
Luck 03a93b1186 Apply dependency remapping using an isolated classloader
* Fixes the issue which prevented LP from loading on Java 9
* Should also fix #697
2018-01-19 19:27:08 +00:00
Luck 04ffd00c0e fix typo in /lp <u/g> editor message 2018-01-19 16:31:15 +00:00
Luck a74475d4cd serialise -> serialize 2018-01-18 19:21:02 +00:00
Luck 05ac7e6041 refactor the way verbose filters are parsed - tokenize on first init as opposed to on each check 2018-01-17 19:30:05 +00:00
Luck 5ae90f2a4b Log verbose checks for the console, commandblocks & entities when running on Bukkit 2018-01-16 19:20:06 +00:00
Luck b800db03fc Nest the 'switchprimarygroup' command under the 'parent' subcommand 2018-01-15 21:09:42 +00:00
Spanner_Man 662b958a7f Update Jenkins URL for the LuckPermsLegacy build (#686) 2018-01-15 20:48:09 +00:00
Luck 7cd5eea6d3 Display tracks relating to the group itself when the showtracks command is performed on a group 2018-01-15 20:39:18 +00:00
Luck ed223f0e4e Don't allow empty context keys/values (#688) 2018-01-15 20:06:20 +00:00
Luck 8a374aed04 add javadocs to Command class 2018-01-15 19:55:21 +00:00
Luck 9ceacdb739 Refactor some Sponge service details 2018-01-15 18:07:27 +00:00
Luck 39daed23c4 fix ~~minor~~ typo 2018-01-13 23:53:44 +00:00
Luck 19e6d4e4c8 Relocate dependency packages to prevent conflicts with other plugins 2018-01-13 23:27:55 +00:00
Luck 22006617d0 misc refactor for PermissionHolder & DummySender 2018-01-12 23:51:59 +00:00
Luck 3201d10bdd Rewrite the way user instances are cleaned up and unloaded - towards #674 2018-01-10 21:28:33 +00:00
Luck ea94bd8696 move bukkit-legacy module to a separate project, cleanup poms 2018-01-08 20:01:02 +00:00
Luck f646c04d09 Remove lombok from the project 2018-01-07 18:40:23 +00:00
Luck 17ff9ac328 Allow shorthand nodes with single element lists (#665) 2018-01-03 19:25:47 +00:00
Luck 283516614b Create CONTRIBUTING.md 2018-01-02 15:02:25 +00:00
Luck 6c8f04f829 Implement PermissionsBukkit migration 2018-01-01 21:11:50 +00:00
Luck 505a10a8b1 misc refactoring 2018-01-01 19:48:20 +00:00
Luck 4fd89e6a34 fix compile 2017-12-30 19:38:58 +00:00
Luck 7bf666b062 fix abuse of static in SubjectReferenceFactory 2017-12-30 16:11:41 +00:00
Luck 764665cf15 Populate Subject cache when obtaining SubjectReferences for instances which already exist 2017-12-30 15:23:31 +00:00
Luck b9dfd7db54 Execute commands sequentially on a single thread executor 2017-12-30 12:16:34 +00:00
Luck e09c5622f7 Recompile against new powerfulperms namespace (#651) 2017-12-29 22:44:42 +00:00
Luck 717347273d Revert Spigot PluginClassLoader workaround 2017-12-29 20:40:43 +00:00
Luck 9bb1ba12b2 Fix issue with slf4j loading 2017-12-29 16:52:11 +00:00
Luck bff9715e7f Implement nasty workaround for Spigot's changes to the PluginClassLoader (#648) 2017-12-29 15:25:49 +00:00
Luck cfcd896c59 Fix broadcasting log entries 2017-12-29 00:41:45 +00:00
Luck aaa50cacda Allow spaces in world names 2017-12-29 00:39:54 +00:00
Luck 3413adf16f Send a different type of update ping for user changes, and only apply the change if the user is loaded 2017-12-28 13:37:55 +00:00
Luck 3d6aa69ca1 Improve various javadocs, add LogNotifyEvent 2017-12-27 17:00:54 +00:00
Luck ab115c4a6b Fix NodeFactory#nodeAsCommand (closes #639) 2017-12-27 10:30:13 +00:00
Luck e1e7bc8e0d Return empty string instead of null in VaultChatHook 2017-12-24 11:42:40 +00:00
Luck 6602b23f09 misc cleanup 2017-12-23 23:51:42 +00:00
Luck 862fe6e2e3 fix compile 2017-12-23 20:45:28 +00:00
Luck 5a34fa182a rewrite Vault implementation to upgrade requests to uuids instead of downgrade to usernames 2017-12-23 18:25:23 +00:00
Luck 0b72507e2d Correctly close flatfile database connections on disable, catch all exceptions when performing initial data load 2017-12-22 22:35:13 +00:00
Luck cc3ddd51fd fix copyright headers 2017-12-21 11:09:42 +00:00
Luck f793fd5010 pass and account for the holder type when building PermissionCalculators 2017-12-19 22:48:53 +00:00
Luck fb92fd9357 Extract out common constants & magic values into factory classes 2017-12-18 22:19:25 +00:00
Luck a415a2705f Return the loaded objects from storage methods as opposed to success flags 2017-12-18 17:03:59 +00:00
Luck 765f140121 Various fixes for log commands 2017-12-17 21:20:22 +00:00
Luck cb47f9f94b Change log output format, refactor log pagination 2017-12-17 17:47:10 +00:00
Luck d0fb9f6aee Update text version 2017-12-17 17:14:43 +00:00
Luck 9d424f5122 Fix more broken message coloring 2017-12-17 13:41:37 +00:00
Luck f71237ea95 Send more helpful message when /lp is executed without any arguments 2017-12-17 13:31:45 +00:00
Luck fb5925e1e8 Add user clone command (#530) 2017-12-17 12:59:36 +00:00
Luck f86bdb7619 Misc cleanup 2017-12-17 12:17:46 +00:00
Luck ad5299d0cd Send a message when an editor upload begins 2017-12-16 23:29:50 +00:00
Luck 904bb90385 Refactor paginated command output, add flags for ordering 'permission info' entries, fix crashes caused by long messages (#591) 2017-12-16 21:05:43 +00:00
Luck 2e7a08c006 Fix promote / demote command inconsistencies (#609) 2017-12-14 21:43:44 +00:00
Luck 38e75da92f Fix user demote command success message (#609) 2017-12-14 18:31:52 +00:00
Luck 97708c2c80 Update locale files (#604, #601, #602)
#601 by @DarkFort
#602 by @EuropeJing
2017-12-13 16:42:30 +00:00
Luck e5ce64266f Add option to pull server setting from the server.properties file 2017-12-11 19:42:24 +00:00
Luck a765be0a6f Fix compat with older hikari versions (#600) 2017-12-11 19:26:17 +00:00
Luck 0bec93ab1c refactor context sets 2017-12-11 19:02:02 +00:00
Luck dfb1b8f841 Work around message bug when parsing two consecutive color codes 2017-12-11 17:39:35 +00:00
Luck 322b522a52 propagate i/o errors to the futures returned by the dao 2017-12-10 01:47:00 +00:00
Luck 9dd4f71526 Remove the isAcceptingLogins storage state in favour of just throwing exceptions on usage 2017-12-09 19:02:23 +00:00
Luck 94b4e3d366 Validate checksums of downloaded dependencies 2017-12-09 18:36:08 +00:00
Luck bbb2897d20 Fix compatibility with older Gson versions 2017-12-09 11:26:12 +00:00
Luck a5e41e479a Use static empty context set where appropriate, cache reversed comparator instances 2017-12-07 19:49:04 +00:00
Luck 2baea0ce13 Fix MongoDao issue causing unnecessary writes each time a user is loaded (#589) 2017-12-07 16:52:21 +00:00
Foorack 90cbff885f Migrate PermissionsEx ladders (#588) 2017-12-04 23:24:06 +00:00
Luck 0d9034504e Run a sync task after completing a bulk update (#579) 2017-12-01 17:44:57 +00:00
Luck 800749c5ed Update README.md 2017-12-01 00:02:35 +00:00
Luck 30f27f29b4 Update readme 2017-12-01 00:01:50 +00:00
Luck 2985cf7237 Don't run schema migrations for Postgre (#568) 2017-11-30 20:33:15 +00:00
Luck 003ddc51de Rewrite the MongoDB storage impl to use the modern node serialisation format 2017-11-30 20:25:48 +00:00
Luck c369ac6b90 Fix mongodb bulkupdate (#572) 2017-11-29 23:10:32 +00:00
Luck e2b9e37867 Change poms to conform to Sonatype's OSSRH requirements 2017-11-28 22:22:52 +00:00
Luck 1e105b4135 Cleanup sponge service impl 2017-11-25 15:56:02 +00:00
Luck c5c253af4e Fix bug when loading maps from the BungeeConfigAdapter (#563) 2017-11-25 12:45:57 +00:00
Luck 717835e5c1 Add config option for defining extra SQL connection properties (#563) 2017-11-25 11:37:30 +00:00
Mat't e9ba62dbd9 Update pl_PL locale (#556) 2017-11-24 21:12:16 +00:00
montlikadani ad5c22ecdb Update hu_HU locale (#558) 2017-11-24 21:11:50 +00:00
Luck 2e92b97f01 Update ru_RU locale (#560 - thanks @DarkFort) 2017-11-24 21:10:44 +00:00
Luck ae8fe0fe1e Refactor configurate dao 2017-11-23 22:51:05 +00:00
Luck d992d7f77c Fix race condition when saving null config nodes to non-existent files 2017-11-23 20:15:29 +00:00
Luck a7cb7ec1af Remove character constraints on group names, cleanup legacy node (de)serialization system 2017-11-23 20:05:38 +00:00
Luck 3afeb30795 Implement system for shorter editor urls & display diff when changes are applied 2017-11-22 20:54:58 +00:00
Luck 26feeb125e Don't allow user names to be set if the length exceeds 16 characters 2017-11-22 17:17:49 +00:00
Luck 211fb219a7 Catch and ignore exceptions thrown when migrating a specific entity 2017-11-22 16:59:19 +00:00
Luck e71ef834c0 fix issue with the LP Vault impl and servers with more than one server context 2017-11-21 16:44:20 +00:00
Luck 29eba93ee3 Fix zero length prefixes from locale files 2017-11-21 15:44:22 +00:00
Luck 52ebfe9309 Bump SQLite version 2017-11-20 15:16:00 +00:00
Luck b3e78c6dc1 Fix issue with loading tracks with configurate 2017-11-20 15:14:44 +00:00
Luck cd0184970a Don't try to run schema migrations for SQLite 2017-11-19 22:24:39 +00:00
Luck 6401480874 Fix compiling null AssignmentExpressions 2017-11-19 19:09:21 +00:00
Luck 6ca9eb13dd General tidy up 2017-11-18 23:20:48 +00:00
Luck 987ea51264 Expose more connection pool settings in the config file 2017-11-14 19:39:46 +00:00
Luck df37491199 maybe fix some bukkit migration issues when plugins use strange identifier formats, cleanup legacy message conversion on Bungee 2017-11-12 15:05:06 +00:00
Luck 9a420403de Attach extra data to the editor payload object to allow for tab completion 2017-11-11 22:57:25 +00:00
Luck 17da2807cf Bump dependency versions 2017-11-10 20:16:44 +00:00
Luck 22fba0c172 Fix broken usage of LogEntry#getActed 2017-11-09 21:05:06 +00:00
Luck 14005563a3 Move #refreshCachedData up the type hierarchy into PermissionHolder 2017-11-08 22:59:22 +00:00
Luck a115ff8ce2 Final bits of API refactoring, add group data caches, fix issue with LPPermissionAttachment fake map injection 2017-11-08 22:55:05 +00:00
Luck d75b29f51d Move a couple more methods around in the API 2017-11-08 15:48:55 +00:00
Luck 3e8f7911af Fix tab completions not being returned for empty strings (#538) 2017-11-07 22:16:48 +00:00
Luck 175a21c0e4 API 4.0 - this is a breaking change 2017-11-07 22:05:49 +00:00
Luck a2801bff7c Inject a fake map into the super PermissionAttachment instance to fix compat with plugins using reflection to change attachment data (#528) 2017-11-07 17:05:16 +00:00
Luck f1a50f433f Throw exception earlier if an invalid permission is added/removed via Vault (#526) 2017-11-07 15:22:31 +00:00
Luck 76bfde4d77 Don't prevent modification of group.<group name> nodes with permission subcommands 2017-11-04 19:12:46 +00:00
Luck d393a4c9ca Alias /lp player --> /lp user 2017-11-03 16:26:54 +00:00
Luck 9ea6b0b8bb Use "None" instead of "global" when no server name is specified 2017-11-02 19:32:13 +00:00
Luck c20b91d5ea Increase actor_name field length to account for changes to logging 2017-11-02 19:28:49 +00:00
Luck fad8a38bdf Use a string version of the full static context, as opposed to the server name 2017-11-02 19:25:35 +00:00
Luck 2440a38e82 add RedisBungee context calculator for the BungeeCord platform 2017-11-02 19:01:53 +00:00
Luck b7541c43c8 Add Sender#getNameWithLocation 2017-11-02 18:51:59 +00:00
Luck 0f10bb0bc9 Deprecate some unused methods in ImmutableNode, refactor #shouldApplyWithContext 2017-11-02 18:22:42 +00:00
Luck 357717886e Refactor the log creation process 2017-10-30 21:06:45 +00:00
Luck 94a4051d29 Add extra catch for null primary group in powerfulperms migration 2017-10-30 20:03:59 +00:00
Luck 0e581cbcf3 Increase actions actor_name column length (#525) 2017-10-30 20:03:03 +00:00
Luck 230d9725e8 cleanup & fix build 2017-10-29 20:37:29 +00:00
Luck dee41b315f Inject our own subscription map into the plugin manager instead of registering permissions individually for each player 2017-10-29 15:16:48 +00:00
Luck 72e6c75433 Cleanup / tidy up a number of classes 2017-10-29 12:58:49 +00:00
Luck ebe12f838c Fix user exports 2017-10-28 00:15:34 +01:00
Luck 7279fdc25f Fix changes not being saved for flatfile bulkupdate operations 2017-10-27 23:17:57 +01:00
Luck af5c859385 Fix temporary group display format in parent info command (#518) 2017-10-24 13:17:27 +01:00
Luck e8896fbdf7 Fix NPE on startup (#520) 2017-10-24 13:05:06 +01:00
Luck 54695b8046 Form more descriptive console & import usernames 2017-10-23 23:37:55 +01:00
Luck c573c755d2 Add option to cancel failed logins on BungeeCord variant 2017-10-23 16:59:07 +01:00
Luck b299301b69 Cleanup 2017-10-22 21:02:48 +01:00
Luck a3a7198777 More storage refactoring 2017-10-22 20:09:53 +01:00
Luck ca8cc91f37 Add group setdisplayname command (#493) 2017-10-22 16:58:53 +01:00
Luck 26c813c07b Mode storage refactoring - write group nodes into their own section in flatfile types (#502) 2017-10-22 14:22:52 +01:00
Luck f109cb684a Apply PermissionAttachment permissions at a higher priority than normal nodes using the transient system (#515) 2017-10-22 10:24:04 +01:00
Luck 1baefaade4 Try to find the most appropriate primary group before just adding a user to default - closes #506 2017-10-22 09:16:04 +01:00
Luck 5ac0f93214 Fix migrating null / non-existent usernames - reverts parts of 6bfeec6, fixes #514 2017-10-22 09:07:08 +01:00
Luck ecfbed00b1 Add config option to allow invalid usernames (#516) 2017-10-22 09:00:10 +01:00
Luck 6e429d6c78 Throw exception if directories cannot be created 2017-10-22 08:48:00 +01:00
Luck fa4bb0447a Rewrite flatfile storage (YAML & JSON) to use configurate, add HOCON storage method 2017-10-21 23:20:45 +01:00
Luck aa0be40124 Cleanup verbose handler & only send sponge OP command notification if the sender has permission 2017-10-16 18:55:17 +01:00
Luck 04d5310c04 Ensure users are a member of their primary group (#506) 2017-10-16 18:53:02 +01:00
Luck 74069af309 Throw an exception if we're unable to create the lib dir 2017-10-16 15:28:02 +01:00
Luck 6bfeec6d16 Fix updating primary groups for players who've never joined the server with SQL storage types (#500) 2017-10-16 14:43:58 +01:00
Luck 0f4c057395 Add highest_inherited and lowest_inherited meta stack elements 2017-10-15 15:13:23 +01:00
Luck 2fd74f3b7e fix MetaStackElement equality checks 2017-10-15 14:51:42 +01:00
Luck fb171a57c2 Ensure stored primary groups are always lowercase'd 2017-10-15 14:32:57 +01:00
Luck b26fc69e73 Remove usage of the now-redundant ExtractedContexts class, other misc cleanup 2017-10-15 14:23:51 +01:00
Luck 28961b1cfa Primary groups should come first, not last, when ordering groups for inheritance (#500) 2017-10-15 11:22:38 +01:00
Luck 597f2f7b1b Make parents-by-weight the default primary group calculation method 2017-10-14 22:54:54 +01:00
Luck 00cd8bb3f3 Prioritise primary groups when two inherited groups have the same weight (#500) 2017-10-14 22:50:50 +01:00
Luck 5732e60510 Remove cleanupUsers functionality
It was pretty useless (and wasn't implemented on SQL/Mongo storage types.) Data is naturally cleaned up over time as users are loaded/saved.
2017-10-12 20:38:08 +01:00
Luck 7b271e21e3 Update readme 2017-10-12 20:25:51 +01:00
Luck 1a5f9683c2 Fix build (whoops) 2017-10-12 20:21:49 +01:00
Luck 3b74d55442 Remove sponge comparison chart from readme 2017-10-12 20:19:53 +01:00
Luck 8920396360 Remove context pre-processing (mostly)
This approach isn't very effective when contexts are frequently changing, and it is hard to guess in advance which contexts are going to be in-use.

The Sponge version has proven that this whole system isn't really necessary.

Contexts for 'allow all' and 'global' are still pre-processed, however this should be significantly less work for the server. (even if it is being done async)
2017-10-12 20:17:52 +01:00
Luck 9c505e4402 Move Track methods away from checked exceptions, refactor ContextManager & primary group holders 2017-10-12 19:43:42 +01:00
Luck de4c6b384c Export using the /lp alias 2017-10-12 18:47:35 +01:00
Luck 6dec1ba8af Add hu_HU locale - thanks @montlikadani 2017-10-03 19:04:47 +01:00
Luck 9e6788de2f Refactor context manager 2017-10-03 19:02:14 +01:00
Luck 1bd7e5c9c4 Refactor sponge cache invalidation 2017-09-29 23:21:12 +01:00
Luck ec75fdddb5 Make verbose output more readable when a check is made against a lot of contexts 2017-09-27 20:11:17 +01:00
Luck f98aafb97c Fix world content on BungeeCord not being lowercase'd 2017-09-24 23:43:39 +01:00
Luck f4d2a0daf9 Bump dependency versions 2017-09-23 23:36:13 +01:00
Luck de8fb8de90 Only load slf4j if it's not already present on the server 2017-09-23 21:15:45 +01:00
Luck 44d137b8f9 Add project Code of Conduct 2017-09-22 16:09:50 +01:00
Luck 777c972bdc Cache SubjectReference instances, general cleanup 2017-09-21 21:59:27 +01:00
Luck f9efa15781 Re-add 'list' as an alias of 'permission info' - reverts #461, closes #473 2017-09-20 20:31:24 +01:00
Luck 1d1cd679dd Fix tab completion inconsistencies caused by argument rewrites - closes #481 2017-09-20 20:27:46 +01:00
Luck a9ed4686dd Avoid loading slf4j when running on Sponge 2017-09-19 22:13:02 +01:00
Luck 5b742eb5b2 Only schedule a user cleanup when LuckPermsApi#cleanupUser is called 2017-09-18 20:50:50 +01:00
Luck a3d78f4d0e Always load dependencies into the plugin classloader, and not it's parent - fixes #479 2017-09-17 19:30:43 +01:00
Luck 214929e5e5 Fix group expiry time not being exported (#474) 2017-09-14 19:10:18 +01:00
Luck 67602b8d85 Fix startup deadlock 2017-09-13 21:24:35 +01:00
Luck 2412edaa3a Cleanup subscription updates & UserManager#loadAllUsers 2017-09-13 20:18:48 +01:00
EuropeJing b1584aa2c3 Update zh-CN locale (#466) 2017-09-12 08:47:37 +01:00
Luck a14a416193 Make some ingame messages more consistent with the LP theme, general cleanup 2017-09-11 22:21:57 +01:00
Luck f3251e9407 Fix missing depend 2017-09-10 21:45:47 +01:00
Luck 096885d91f Add tracing to /lp verbose, API updates/cleanup, add login process event, and utilise string interning for faster context/node comparisons 2017-09-10 21:25:00 +01:00
Frank Zhang 368700156c Added uranium server support to DependencyManager (#464) 2017-09-08 14:25:49 +01:00
Luck 81cf50520b Fix NodeFactory#nodeAsCommand when unsetting meta nodes, fix meta unset command 2017-09-06 21:56:41 +01:00
Luck 649748c2d3 Bump caffeine and hikari versions (#462) 2017-09-05 23:56:45 +01:00
Luck bf7a708440 Send some extra data to the editor data object 2017-09-05 14:54:22 +01:00
Luck 8faa4d137b Fix some issues with the recent import/export changes 2017-09-04 23:20:21 +01:00
Luck 479bd91b74 Fix build 2017-09-04 22:32:02 +01:00
Luck 6bc7f1fca2 Refactor Importer/Exporter to use multiple threads (#317) 2017-09-04 22:24:07 +01:00
Luck dadd8e2c50 Don't publish/broadcast log entries from the import process - towards #317 2017-09-04 20:47:45 +01:00
Luck 03f342a21c Refactor command execution to use Locks per target instead of (effectively) one for all commands - towards #317 2017-09-04 20:42:21 +01:00
Luck 7fe5397e21 Fix incorrect usage of CompletableFuture#thenCombineAsync 2017-09-04 17:56:01 +01:00
Luck b6e1fd179e Add type argument to 'meta clear' command (#457) 2017-09-04 17:25:59 +01:00
Luck 754c7d8e3b Add config option to prevent primary group removal (#405) 2017-09-04 17:03:17 +01:00
Luck 925d3ccd1b Remove "list" alias for holder info (#461) 2017-09-04 16:55:10 +01:00
Luck d60d0ac9c5 Reduce buffer times, refactor MessagingService init 2017-09-04 16:49:43 +01:00
Luck e1b51dd6af Catch Throwable instead of Exception when setting up BukkitJsonMessageHandler 2017-09-04 13:03:09 +01:00
Luck fbe9d9f128 Run user cleanup task async and not on Storage init 2017-09-03 16:16:21 +01:00
Luck 509826949d Add login debug option 2017-08-27 13:54:26 +01:00
Luck 39aaa8a292 Update for latest Text version 2017-08-22 22:51:49 +01:00
Luck 069c76c53a Fix time test for node expiry times 2017-08-22 16:30:46 +01:00
Luck f45c0caa45 Refactor metastacks & primary group calculation 2017-08-21 15:45:29 +02:00
EuropeJing 41b0e10709 Update zh-CN locale (#450) 2017-08-21 10:38:30 +02:00
EuropeJing 8e8da20c13 Update zh-CN locale (#449) 2017-08-20 19:43:58 +02:00
Luck 269aa39378 Fix comparator and ensure @Nonnull annotated methods never return null in LogEntry 2017-08-20 14:51:46 +02:00
Luck ae8be97db7 Dispatch log entries via the messaging service 2017-08-20 13:32:52 +02:00
Luck f0ad40825b Refactor and cleanup Log classes 2017-08-20 01:35:03 +02:00
Luck 36d292747a Format times in /lp log into a shorter form 2017-08-19 11:38:08 +02:00
Luck b65d2262bf Remove "... data was saved to storage" messages 2017-08-19 11:08:28 +02:00
Luck a7ab0c6b36 Send a more helpful message when the non legacy version of LP is installed on Bukkit 1.7 (#437) 2017-08-18 13:58:41 +02:00
Luck c02fcb6508 Refactor weight lookups 2017-08-18 11:14:03 +02:00
Luck 07c38de44b Allow permission info command to be filtered by context (#442) 2017-08-18 10:44:54 +02:00
Luck 188d62c99b Fix issue with casting UUIDs in MongoDB backing (#443) 2017-08-18 10:35:56 +02:00
Luck 76b203ad10 Fix text dependencies being shaded 2017-08-17 10:12:08 +02:00
Luck 909844aef5 Update KyoriPowered/text dependency 2017-08-16 10:56:35 +02:00
Luck 046202719a Correctly export meta/prefix/suffix nodes to command strings 2017-08-14 18:58:12 +02:00
Luck ed15e2838d Fix checkinherits command not returning the inheritance data 2017-08-14 09:38:08 +02:00
Luck 82466c2e5d Properly implement Contexts#allowAll - bump API to 3.3 2017-08-13 22:21:04 +02:00
Luck c598daf350 Fix negating group permissions to cancel inheritance 2017-08-13 19:40:59 +02:00
Luck a40421fa1f Optimizations to the core PermissionHolder class
- Remove usage of Java 8 streams from frequently called methods
- Use LinkedLists where appropriate to improve Iterator#remove speed
- Cache immutable multimap conversion
- Rename some methods to make the intended use/behaviour clearer
2017-08-13 19:24:00 +02:00
Luck d98b464ce9 Cleanup verbose & treeview packages. Return known permissions from the PermissionVault as Sponge PermissionDescriptions 2017-08-13 12:07:05 +02:00
Luck 1d5e3205ac Refactoring & misc cleanup 2017-08-12 19:34:14 +02:00
Luck 07eb17f5d5 Fix Sponge PermissionDescription lookups (#425) 2017-08-08 10:37:54 +02:00
Luck 3951725852 Fix 'meta settemp' command using duration as the server context (#421) 2017-08-05 23:46:19 +02:00
Luck 77956d69ad Fix NPE with Vault #getPlayerGroups 2017-08-05 17:30:40 +02:00
Luck 5784458d03 Make Sponge's #getFriendlyIdentifier return usernames of Users and display names of Groups (#412) 2017-08-03 18:39:39 +01:00
Luck 3d2115ff3c Remove unnecessary extra cache in ContextManager 2017-08-02 21:48:22 +01:00
Luck 8618a67e2e Fix sponge config loading - closes #407 2017-07-31 22:26:59 +01:00
Luck 234b9cafd7 Give default group if needed after "parent remove" (#405) 2017-07-30 21:08:05 +01:00
Luck 4ecd899bac Fix IndexOutOfBoundsException with 'permission settemp' command (#403) 2017-07-30 15:23:42 +01:00
Luck ce2c943397 Inject bukkit permissible at lowest priority instead of low 2017-07-27 12:58:31 +01:00
Luck 51898abb71 Don't load contexts file twice 2017-07-26 10:31:14 +01:00
Luck e2f800dd63 Throw an NPE if a null delegate sender is passed to SenderFactory#wrap 2017-07-26 10:10:25 +01:00
Luck d9e5bc9345 fix error with null subject in ContextManager removal listener - closes #392 2017-07-24 19:42:35 +01:00
Luck e42cc101cc Cleanup & document a number of Bukkit impl classes 2017-07-24 14:32:10 +01:00
Luck 845367e847 Flush storage buffer more frequently 2017-07-22 20:42:53 +01:00
Luck 90afd3c3ed Cleanup handling of empty permissions when migrating data (closes #387) 2017-07-22 20:04:55 +01:00
Luck b4aeb04d1b Fix possible NPEs when calling API storage events - fixes #384 2017-07-22 00:06:37 +01:00
Luck 65b0d45738 Fix IllegalStateException in meta info command - closes #385 2017-07-22 00:00:58 +01:00
Luck 3c44388883 Update /lp info output 2017-07-19 22:15:12 +01:00
Luck 400f3a9156 Add option to disable colored logging (#382) 2017-07-18 17:58:40 +01:00
creator3 ad6e837aa5 Use single quotes in escapeStringForSql (#379) 2017-07-16 23:53:15 +02:00
Luck cadd7545c5 Use saner class naming 2017-07-16 21:16:08 +01:00
Luck b41dea9ee1 Implement support for futures & other changes in the Sponge Permissions API 2017-07-16 14:12:36 +01:00
Luck 7a6c0ab154 Improve /lp listgroups output - closes #368 2017-07-10 10:09:29 +01:00
Luck 1bb1f5ebb3 Fail silently when the Sponge Server is not available - closes #367 2017-07-10 09:18:58 +01:00
Luck fce5b8430d Use GA MySQL version 2017-07-09 18:05:08 +01:00
Luck 0befa6a491 Fix generating unset commands for temporary nodes 2017-07-07 19:39:31 +01:00
Luck b12ce943f7 Make 'meta info' and 'parent info' clickable (#311) 2017-07-07 19:28:26 +01:00
Luck d23b29aeb1 Update dependency versions 2017-07-07 14:48:42 +01:00
Luck 42d48c8da2 Implement argument based permissions for LP commands - closes #52, #170, #174 2017-07-07 12:43:13 +01:00
Luck 9e83a5e4d9 Add RedisBungee messaging service option for BungeeCord 2017-07-03 16:24:00 +01:00
Luck d2bf940105 Add option to use the servers uuid cache/lookup facility (#354) 2017-07-03 16:07:33 +01:00
Luck 7d4aca68cc Fix jsr being shaded & tweak javadoc generation to link to guava docs correctly 2017-07-02 22:04:37 +01:00
Luck d7094909c0 Change verbose output slightly 2017-07-02 21:29:48 +01:00
Luck 7083d55a9b Fix vault lookups with a specified world 2017-07-02 10:49:07 +01:00
Luck 770db2fee0 Export groups in order of weight, then alphabetically 2017-06-30 19:43:45 +01:00
Luck b8e65c4f26 Fix bukkit defaults still being applied to subscriptions when disabled 2017-06-30 19:32:12 +01:00
Luck 5cd5186092 Don't cancel re-allowed connections unless the cancel was made by LP 2017-06-26 21:39:59 +01:00
Luck fa0b66c2dc Fix lp tree max recursion property 2017-06-26 16:31:30 +01:00
Luck 1b199fd2c7 Fix NPE when loading locale file - closes #338 2017-06-24 17:26:52 +01:00
Luck 2ffbeeef8e Add jsr305 annotations to the API 2017-06-24 17:25:13 +01:00
Chris N 26ce8b8ab7 YAML/JSON batch permission defining (#337) 2017-06-22 10:41:29 +01:00
Luck 8e224c4a27 Don't force cancel Sponge ClientConnection.Join if the cancellation state changes, shuffle event orders slightly - fixes #335 2017-06-20 21:37:38 +01:00
Luck cf5318b92b Make command defintion/usage messages translatable 2017-06-20 20:20:41 +01:00
Luck e50fa17f7c Store all accumulated meta values in MetaCache 2017-06-19 21:48:52 +01:00
Luck 8766e3b408 Add jar signing to build scripts 2017-06-19 20:09:18 +01:00
Luck c4c7f06d83 Fix BungeePerms migration - closes #333 2017-06-19 16:43:00 +01:00
Luck 413e304845 Fix NPE with null context in FileWatcher 2017-06-14 17:32:02 +01:00
Luck 046daf23d0 Deploy source & javadoc jar with the API 2017-06-13 20:17:41 +01:00
Luck c57947949c Don't send messages to command blocks async 2017-06-13 17:30:01 +01:00
Luck 0acefde805 Tidy up configuration file layouts 2017-06-12 21:41:23 +01:00
Luck a9e751b4b8 Replace fanciful with KyoriPowered/text 2017-06-11 14:46:56 +01:00
Luck 3df1ae8ded Fix argument validation for parent settrack command - closes #321 2017-06-11 10:27:26 +01:00
Luck b4a2da0ea8 Add some missing tab completions, remove /lp log export command 2017-06-09 22:19:07 +01:00
Luck 5c5d1e8d0a Fixes some issues with username storage and handling
- Fix the yaml/json UUID cache corrupting username data when performing uuid --> username checks
- Fix handling of usernames when users are loaded

Closes #301
2017-06-09 18:20:12 +01:00
Luck ff0c988a1d Don't store attributes for permissions with only 'value: true' in YAML/JSON storage files 2017-06-07 21:04:14 +01:00
Luck b9fc8f4b5f Add MongoDB collection prefix option 2017-06-05 16:09:02 +01:00
Luck 2ecaa39cb6 Only resolve inheritances for groups which exist already 2017-06-04 16:41:20 +01:00
Luck 7b8654339c Maybe fix usernames not being updated in storage after name changes (#301) 2017-06-03 16:40:16 +01:00
dzegarek 306e252c31 Add pl_PL locale (#306) 2017-06-03 14:47:34 +01:00
Luck 87c3bd6293 Update README.md 2017-05-26 20:48:41 +01:00
Luck 307beebb58 Cleanup Bukkit PEX migration, fix user parents being transferred incorrectly 2017-05-25 22:24:55 +01:00
Luck 4109863aa9 Fix -s flag (#132) 2017-05-25 21:35:47 +01:00
Luck 0febdbe3a4 Update copyright headers in the API module 2017-05-21 09:47:08 +01:00
Luck 139dd5302b Cleanup login handling & reduce the amount of unnecessary logging output on startup 2017-05-18 22:30:01 +01:00
Luck cc907b6530 Don't catch exceptions thrown inside i/o (#291) 2017-05-18 21:16:31 +01:00
Luck ca1dacf2b6 Invalidate active context cache when a player changes world - closes #288 2017-05-16 21:52:46 +01:00
Luck abc1c164cf Expose MetaStacks in the API, general cleanup, release 3.2 2017-05-16 21:41:20 +01:00
Luck dc801464ef Refactor meta stacking to be mapped in MetaCache - towards lucko/LuckPermsPlaceholders#1 2017-05-16 19:13:08 +01:00
Luck 99c6fe20c2 Catch exceptions thrown by context calculators 2017-05-16 13:50:28 +01:00
Luck 9d780ae24a Fix misleading Vault debug message 2017-05-15 21:26:43 +01:00
Luck a44dec0402 Fix typo 2017-05-15 12:07:59 +01:00
Luck a081152baa Fix web editor url 2017-05-15 12:05:54 +01:00
Luck 9b50d48f46 fix compile 2017-05-14 22:41:25 +01:00
Luck 5121fc6b1f Cleanup 2017-05-14 22:15:25 +01:00
Luck d4ac261e85 Cleanup config keys, make editor URL configurable 2017-05-14 21:36:02 +01:00
Luck 2e9561371d Implement initial web editor support 2017-05-13 20:36:05 +01:00
Luck 942fd3c4ce Fix vault lookups with static context 2017-05-11 20:04:11 +01:00
Luck 8cf32752e9 Fix meta info only showing values in global context 2017-05-11 19:46:28 +01:00
Luck b240ca9939 Add parent cleartrack command, cleanup Messages enum 2017-05-09 16:26:55 +01:00
Luck e25d99129c Implement parent settrack command - closes #112 2017-05-09 14:06:16 +01:00
Luck 1fee47e087 Implement default contexts - closes #241 2017-05-09 13:36:43 +01:00
Luck e835b31277 Apply world rewrites on-top of the real world name, and apply recursively (#255) 2017-05-09 13:07:39 +01:00
Luck 6817945e12 Bump sponge API version, cleanup 2017-05-09 12:55:45 +01:00
Luck 030fb1262e Fix being able to negate permissions/parents/meta in specific contexts 2017-05-08 22:27:46 +01:00
Luck fae49096f3 Fix retrieving meta keys from Vault which contain delimited characters - closes #270 2017-05-08 21:43:20 +01:00
EuropeJing afd491ecea Update zh-CN locale (#281) 2017-05-08 20:17:51 +01:00
EuropeJing 09bc100ad9 Add zh-CN locale (#279) 2017-05-08 18:11:29 +01:00
Luck 037f18ac56 Fix zPerms parent group migration for users, and fix migration of temporary memberships 2017-05-08 17:45:17 +01:00
Luck a5746dfa21 Support sponge selector resolution - closes #275 2017-05-07 22:52:45 +01:00
Luck cedc5108fc Refactor Patterns to PatternCache 2017-05-07 13:56:42 +01:00
Luck 65af3d0f54 Add data constraints - closes #256 2017-05-07 13:44:29 +01:00
Luck 6c4fa65f91 Fix migrating weight with zPerms 2017-05-06 23:35:58 +01:00
Luck 4731ad8061 Fix migrating false zPerms nodes 2017-05-06 21:06:22 +01:00
Luck 7dc41e15d3 Fix users being cleaned up too early and then logging back into the server - closes #271 2017-05-06 18:24:44 +01:00
Luck 8326539d40 Refactor LP PermissionService to implement a modified API & add proxied classes 2017-05-03 20:14:31 +01:00
Luck 163e6e0f2a Always load user data caches alongside user instances 2017-05-02 16:55:08 +01:00
Luck f56bb251e9 Cleanup some stuff 2017-05-02 16:36:46 +01:00
Luck 152ca99276 Fix issue with bulk removing suffixes 2017-04-25 16:51:21 +01:00
Luck 7c398d2c67 Split up chat messages sent to console containing new lines 2017-04-23 20:51:24 +01:00
Luck a526c942ca Add config options to allow for finer control over how permissions are calculated, and set include-global to true on BungeeCord by default 2017-04-23 20:30:58 +01:00
Luck af8fd15929 improve speed of NodeTools#removeSamePermission 2017-04-23 11:51:56 +01:00
Luck 7bfd5d4bc8 implement atomic group insertion 2017-04-22 22:53:29 +01:00
Luck 4382d5c56d show uuid in log messages if username is null 2017-04-21 21:28:50 +01:00
Luck f43b9c96de cleanup login handling & add CountdownLatch to ensure the plugin has started before logins are handled 2017-04-21 19:10:25 +01:00
Luck c64f72e394 Fix issue with loading usernames on MongoDB - closes #257 2017-04-21 16:58:07 +01:00
Luck 3d54f832c5 cleanup duplicated method 2017-04-20 19:26:47 +01:00
Luck 867ba24c6c support glowstone (maybe) 2017-04-20 19:15:37 +01:00
Luck 9715c5394c Fix NPE caused by AllParentsByWeight primary group selector - closes #252 2017-04-18 17:11:07 +01:00
Luck 67b5c72520 Cleanup handling of unknown/null usernames for users 2017-04-17 19:31:52 +01:00
Articuno 43450f6cc7 Update RU locale (#250) 2017-04-17 10:12:37 +01:00
Luck a3737d4f35 fix typo 2017-04-16 11:08:54 +01:00
Luck 3314e94a9a Add not_on_track meta stack criteria 2017-04-16 11:06:05 +01:00
Luck a27436b086 Fix getting primary groups for offline users 2017-04-15 20:32:03 +01:00
Luck fe5554ffb1 fix build 2017-04-15 19:53:12 +01:00
Luck f305f8d822 Determine dynamic primary groups using current context 2017-04-15 19:08:04 +01:00
Luck 1f54bc41cc Cleanup poms, update copyright header 2017-04-15 19:01:52 +01:00
Luck c82d028429 fix yaml/json schema migration 2017-04-12 21:33:59 +01:00
Luck be2a8b7b07 Fix incorrect chat meta command usage 2017-04-12 17:59:51 +01:00
Luck 261fc82016 Remove getuuid command
why did that ever exist anyways
2017-04-12 17:25:22 +01:00
Luck 37b940f3a5 Convert promote / demote commands to use new context system, update en locale with latest changes 2017-04-12 17:11:01 +01:00
Luck 0504e904a2 Only perform flatfile schema migration if the new dir doesn't exist 2017-04-12 14:28:39 +01:00
Luck 71bfdd9bfd log the file name when exceptions are thrown during i/o 2017-04-12 14:09:51 +01:00
Articuno c7305f6b06 Update ru_RU locale (#238) 2017-04-11 10:47:43 +01:00
871 changed files with 69879 additions and 37891 deletions

No files matched your search

-299
View File
@@ -1,299 +0,0 @@
# LuckPerms Language File
# Locale: en_US (English)
# 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."
op-disabled: "&bThe vanilla OP system is disabled on this server."
op-disabled-sponge: "&2Server Operator status has no effect when a permission plugin is installed. Please edit user data directly."
log: "&3LOG &3&l> {0}"
export-log: "&3EXPORT &3&l> &f{0}"
export-log-progress: "&3EXPORT &3&l> &7{0}"
migration-log: "&3MIGRATION &7[&3{0}&7] &3&l> &f{1}"
migration-log-progress: "&3MIGRATION &7[&3{0}&7] &3&l> &7{1}"
command-not-recognised: "Command not recognised."
command-no-permission: "You do not have permission to use this command!"
already-haspermission: "{0} already has this permission!"
does-not-havepermission: "{0} does not have this permission set."
already-has-temp-permission: "{0} already has this permission set temporarily!"
does-not-have-temp-permission: "{0} does not have this permission set temporarily."
user-not-found: "&bUser could not be found."
user-not-online: "&bUser &a{0}&b is not online."
user-no-data: "&bUser &a{0}&b does not have any data loaded."
user-save-success: "&7(User data was saved to storage)"
user-save-error: "There was an error whilst saving the user."
user-create-fail: "There was an error whilst creating a new user."
group-not-found: "&bGroup could not be found."
group-save-success: "&7(Group data was saved to storage)"
group-save-error: "There was an error whilst saving the group."
track-not-found: "&bTrack could not be found."
track-save-success: "&7(Track data was saved to storage)"
track-save-error: "There was an error whilst saving the track."
user-invalid-entry: "&d{0}&c is not a valid username/uuid."
group-invalid-entry: "Group names can only contain alphanumeric characters."
track-invalid-entry: "Track names can only contain alphanumeric characters."
server-invalid-entry: "Server names can only contain alphanumeric characters."
use-inherit-command: "Use the 'parent add' and 'parent remove' commands instead of specifying the node."
verbose-invalid-filter: "&cInvalid verbose filter: &f{0}"
verbose-on: "&bVerbose checking output set to &aTRUE &bfor all permissions."
verbose-on-query: "&bVerbose checking output set to &aTRUE &bfor permissions matching the following filters: &f{0}"
verbose-off: "&bVerbose checking output set to &cFALSE&b."
verbose-recording-on: "&bVerbose recording set to &aTRUE &bfor all permissions."
verbose-recording-on-query: "&bVerbose recording set to &aTRUE &bfor permissions matching the following filters: &f{0}"
verbose-recording-upload-start: "&bVerbose recording was disabled. Uploading results..."
verbose-recording-url: "&aVerbose results URL:"
tree-upload-start: "&bGenerating permission tree..."
tree-empty: "&aUnable to generate tree. No results were found."
tree-url: "&aPermission Tree URL:"
search-searching: "&aSearching for users and groups with &b{0}&a..."
search-result: "&aFound &b{0}&a entries from &b{1}&a users and &b{2}&a groups."
search-showing-users: "&bShowing user entries:"
search-showing-groups: "&bShowing group entries:"
search-showing-users-with-page: "&bShowing user entries: {0}"
search-showing-groups-with-page: "&bShowing group entries: {0}"
check-result: "&aPermission check result on user &b{0}&a for permission &b{1}&a: &f{2}"
create-success: "&b{0}&a was successfully created."
delete-success: "&b{0}&a was successfully deleted."
rename-success: "&b{0}&a was successfully renamed to &b{1}&a."
clone-success: "&b{0}&a was successfully cloned 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."
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: >
{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."
groups-list: "&aGroups: {0}"
create-track-error: "There was an error whilst creating the track."
delete-track-error: "There was an error whilst deleting the track."
tracks-list: "&aTracks: {0}"
listnodes: "&b{0}'s Nodes:"
listnodes-with-page: "&b{0}'s Nodes: {1}"
listnodes-temp: >
&b{0}'s Temporary Nodes:\n
{1}
listparents: >
&b{0}'s Parent Groups:\n
{1}
listparents-temp: >
&b{0}'s Temporary Parent Groups:\n
{1}
listgroups: >
&b{0}'s Groups:\n
{1}
listgroups-temp: >
&b{0}'s Temporary Groups:\n
{1}
list-tracks: >
&b{0}'s Tracks:\n
{1}
list-tracks-empty: "{0} is not on any tracks."
context-pair-inline: "&3{0}=&b{1}"
context-pair--global-inline: "&eglobal"
context-pair-end: "&a."
context-pair-sep: "&a, "
context-pair: "&8(&7{0}=&f{1}&8)"
check-permission: "&b{0}&a has permission &b{1}&a set to {2}&a in context {3}&a."
check-permission-inherited: "&b{0}&a has permission &b{1}&a set to {2}&a in context {3}&a, inherited from &b{4}&a."
setpermission-success: "&aSet &b{0}&a to &b{1}&a for &b{2}&a in context {3}&a."
setpermission-temp-success: "&aSet &b{0}&a to &b{1}&a for &b{2}&a for a duration of &b{3}&a in context {4}&a."
unsetpermission-success: "&aUnset &b{0}&a for &b{1}&a in context {2}&a."
unset-temp-permission-success: "&aUnset temporary permission &b{0}&a for &b{1}&a in context {2}&a."
set-inherit-success: "&b{0}&a now inherits permissions from &b{1}&a in context {2}&a."
set-temp-inherit-success: "&b{0}&a now inherits permissions from &b{1}&a for a duration of &b{2}&a in context {3}&a."
set-parent-success: "&b{0}&a had their existing parent groups cleared, and now only inherits &b{1}&a in context {2}&a."
unset-inherit-success: "&b{0}&a no longer inherits permissions from &b{1}&a in context {2}&a."
unset-temp-inherit-success: "&b{0}&a no longer temporarily inherits permissions from &b{1}&a in context {2}&a."
clear-success: "&b{0}&a's permissions were cleared. (&b{1}&a nodes were removed.)"
clear-success-singular: "&b{0}&a's permissions were cleared. (&b{1}&a node was removed.)"
parent-clear-success: "&b{0}&a's parents were cleared. (&b{1}&a nodes were removed.)"
parent-clear-success-singular: "&b{0}&a's parents were cleared. (&b{1}&a node was removed.)"
meta-clear-success: "&b{0}&a's meta was cleared. (&b{1}&a nodes were removed.)"
meta-clear-success-singular: "&b{0}&a's meta was cleared. (&b{1}&a node was removed.)"
illegal-date-error: "Could not parse date '{0}'."
past-date-error: "You cannot set a date in the past!"
chat-meta-prefix-header: "&b{0}'s Prefixes"
chat-meta-suffix-header: "&b{0}'s Suffixes"
meta-header: "&b{0}'s Meta"
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."
bulk-remove-chatmeta-success: "&b{0}&a had all {1}es at priority &b{3}&a removed in context {4}&a."
remove-temp-chatmeta-success: "&b{0}&a had temporary {1} &f\"{2}&f\"&a at priority &b{3}&a removed in context {4}&a."
bulk-remove-temp-chatmeta-success: "&b{0}&a had all temporary {1}es at priority &b{3}&a removed in context {4}&a."
already-has-meta: "{0} already has that meta key value pair set."
set-meta-success: "&aSet meta value for key &f\"{0}&f\"&a to &f\"{1}&f\"&a for &b{2}&a in context {3}&a."
set-meta-temp-success: "&aSet meta value for key &f\"{0}&f\"&a to &f\"{1}&f\"&a for &b{2}&a for a duration of &b{3}&a in context {4}&a."
unset-meta-success: "&aUnset meta value with key &f\"{0}&f\"&a for &b{1}&a in context {2}&a."
unset-meta-temp-success: "&aUnset temporary meta value with key &f\"{0}&f\"&a for &b{1}&a in context {2}&a."
bulk-change-type-error: "Invalid type. Was expecting 'server' or 'world'."
bulk-change-success: "&aApplied bulk change successfully. {0} records were changed."
user-info-general: >
{PREFIX}&b&l> &bUser Info: &f{0}\n
{PREFIX}&f- &3UUID: &f{1}\n
{PREFIX}&f- &3Status: {2}\n
{PREFIX}&f- &3Primary Group: &f{3}\n
{PREFIX}&f- &aCounts:\n
{PREFIX}&f- &3Permissions: &a{4}\n
{PREFIX}&f- &3Temporary Permissions: &a{5}\n
{PREFIX}&f- &3Prefixes: &a{6}\n
{PREFIX}&f- &3Suffixes: &a{7}\n
{PREFIX}&f- &3Meta: &a{8}
user-info-data: >
{PREFIX}&f- &aCached Data:\n
{PREFIX}&f- &3Is Loaded: {0}\n
{PREFIX}&f- &3Current Contexts: {1}\n
{PREFIX}&f- &3Current Prefix: {2}\n
{PREFIX}&f- &3Current Suffix: {3}
info-parent-header: "&f- &aParent Groups:"
info-temp-parent-header: "&f- &aTemporary Parent Groups:"
user-getuuid: "&bThe UUID of &b{0}&b is &b{1}&b."
user-removegroup-error-primary: "You cannot remove a user from their primary group."
user-primarygroup-success: "&b{0}&a's primary group was set to &b{1}&a."
user-primarygroup-warn-option: "&cWarning: The primary group calculation method being used by this server &7({0}) &cmay not reflect this change."
user-primarygroup-error-alreadyhas: "The user already has this group set as their primary group."
user-primarygroup-error-notmember: "&b{0}&a was not already a member of &b{1}&a, adding them now."
user-track-error-not-contain-group: "The user specified isn't already in any groups on this track."
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."
user-track-added-to-first-server: "&b{0}&a isn't in any groups on this track, so they were added to the first group, &b{1}&a, on server &b{2}&a."
user-track-added-to-first-server-world: "&b{0}&a isn't in any groups on this track, so they were added to the first group, &b{1}&a, on server &b{2}&a, world &b{3}&a."
user-promote-success: "&aPromoting user along track &b{0}&a from &b{1}&a to &b{2}&a."
user-promote-success-server: "&aPromoting user along track &b{0}&a from &b{1}&a to &b{2}&a on server &b{3}&a."
user-promote-success-server-world: "&aPromoting user along track &b{0}&a from &b{1}&a to &b{2}&a on server &b{3}&a, world &b{4}&a."
user-promote-error-endoftrack: "The end of track &4{0}&c was reached. Unable to promote user."
user-promote-error-malformed: >
{PREFIX}The next group on the track, {0}, no longer exists. Unable to promote user.\n
{PREFIX}Either create the group, or remove it from the track and try again.
user-demote-success: "&aDemoting user along track &b{0}&a from &b{1}&a to &b{2}&a."
user-demote-success-server: "&aDemoting user along track &b{0}&a from &b{1}&a to &b{2}&a on server &b{3}&a."
user-demote-success-server-world: "&aDemoting user along track &b{0}&a from &b{1}&a to &b{2}&a on server &b{3}&a, world &b{4}&a."
user-demote-endoftrack: "The end of track &4{0}&c was reached, so &4{1}&c was removed from &4{2}&c."
user-demote-error-malformed: >
{PREFIX}The previous group on the track, {0}, no longer exists. Unable to demote user.\n
{PREFIX}Either create the group, or remove it from the track and try again.
user-showpos: >
&aShowing &b{0}&a's position on track &b{1}&a.\n
{2}
group-info-general: >
{PREFIX}&b&l> &bGroup Info: &f{0}\n
{PREFIX}&f- &3Display Name: &f{1}\n
{PREFIX}&f- &3Weight: &f{2}\n
{PREFIX}&f- &aCounts:\n
{PREFIX}&f- &3Permissions: &a{3}\n
{PREFIX}&f- &3Temporary Permissions: &a{4}\n
{PREFIX}&f- &3Prefixes: &a{5}\n
{PREFIX}&f- &3Suffixes: &a{6}\n
{PREFIX}&f- &3Meta: &a{7}
group-set-weight: "&aSet weight to &b{0}&a for group &b{1}&a."
track-info: >
{PREFIX}&b&l> &bShowing Track: &f{0}\n
{PREFIX}&f- &7Path: &f{1}
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}."
log-no-entries: "&bNo log entries to show."
log-entry: "&b#{0} -> &8(&7{1} ago&8) {2}"
log-notify-toggle-on: "&aEnabled&b logging output."
log-notify-toggle-off: "&cDisabled&b logging output."
log-notify-already-on: "You are already receiving notifications."
log-notify-already-off: "You aren't currently receiving notifications."
log-notify-unknown: "State unknown. Expecting \"on\" or \"off\"."
log-search-header: "&aShowing recent actions for query &b{0} &a(page &f{1}&a of &f{2}&a)"
log-recent-header: "&aShowing recent actions (page &f{0}&a of &f{1}&a)"
log-recent-by-header: "&aShowing recent actions by &b{0} &a(page &f{1}&a of &f{2}&a)"
log-history-user-header: "&aShowing history for user &b{0} &a(page &f{1}&a of &f{2}&a)"
log-history-group-header: "&aShowing history for group &b{0} &a(page &f{1}&a of &f{2}&a)"
log-history-track-header: "&aShowing history for track &b{0} &a(page &f{1}&a of &f{2}&a)"
log-export-already-exists: "Error: File {0} already exists."
log-export-not-writable: "Error: File {0} is not writable."
log-export-empty: "The log is empty and therefore cannot be exported."
log-export-failure: "An unexpected error occured whilst writing to the file."
log-export-success: "&aSuccessfully exported the log to &b{0}&a."
import-already-running: "Another import process is already running. Please wait for it to finish and try again."
export-already-running: "Another export process is already running. Please wait for it to finish and try again."
import-log-doesnt-exist: "Error: File {0} does not exist."
import-log-not-readable: "Error: File {0} is not readable."
import-log-failure: "An unexpected error occured whilst reading from the log file."
import-progress: "&b(Import) &b-> &f{0} &fpercent complete &7- &b{1}&f/&b{2} &foperations complete with &c{3} &ferrors."
import-progress-sin: "&b(Import) &b-> &f{0} &fpercent complete &7- &b{1}&f/&b{2} &foperations complete with &c{3} &ferror."
import-start: "&b(Import) &b-> &fStarting import process."
import-end-complete: "&b(Import) &a&lCOMPLETED &7- took &b{0} &7seconds - &7No errors."
import-end-complete-err: "&b(Import) &a&lCOMPLETED &7- took &b{0} &7seconds - &c{1} errors."
import-end-complete-err-sin: "&b(Import) &a&lCOMPLETED &7- took &b{0} &7seconds - &c{1} error."
import-end-error-header: >
{PREFIX}&b(Import) &7------------> &fShowing Error #&b{0} &7<------------\n
{PREFIX}&b(Import) &fWhilst executing: &3Command #{1}\n
{PREFIX}&b(Import) &fCommand: &7{2}\n
{PREFIX}&b(Import) &fType: &3{3}\n
{PREFIX}&b(Import) &fOutput:
import-end-error-content: "&b(Import) &b-> &c{0}"
import-end-error-footer: "&b(Import) &7<------------------------------------------>"
-338
View File
@@ -1,338 +0,0 @@
# LuckPerms Language File
# Locale: es_ES (Spanish)
# Author: Jose Chavez (Twitter: @JoCHav3z)
prefix: "&7&l[&b&lL&3&lP&7&l] &c"
log-info: "&7&l[&bL&3P&7&l] &3{0}"
log-warn: "&7&l[&bLuck&3Perms&7&l] &c[ADVERTENCIA] {0}"
log-error: "&7&l[&bLuck&3Perms&7&l] &4[ERROR] {0}"
empty: "{0}"
player-online: "&aConectado"
player-offline: "&cDesconectado"
loading-error: "La Informacion de los permisos no pudo ser cargada. Por favor contacte al administrador."
op-disabled: "&bEl sistema OP de Vanilla esta deshabilitado en este servidor."
op-disabled-sponge: "&2El estado de operador del servidor no tiene efecto cuando un plugin de permisos esta instalado. Por favor edite la informacion de usuario directamente."
log: "&3LOG &3&l> {0}"
export-log: "&3EXPORTAR &3&l> &f{0}"
export-log-progress: "&3EXPORTADO &3&l> &7{0}"
migration-log: "&3MIGRACION &7[&3{0}&7] &3&l> &f{1}"
migration-log-progress: "&3MIGRADO &7[&3{0}&7] &3&l> &7{1}"
command-not-recognised: "Comando no reconocido."
command-no-permission: "¡No tienes permiso de usar este comando!"
already-haspermission: "{0} ¡Ya tienes este permiso!"
does-not-havepermission: "{0} No tienes este permiso establecido."
already-has-temp-permission: "{0} ¡Ya tienes este permiso establecido temporalmente!"
does-not-have-temp-permission: "{0} No tienes este permiso establecido temporalmente."
user-not-found: "&bNo se pudo encontrar al usuario."
user-not-online: "&bUsuario &a{0}&b no esta conectado."
user-no-data: "&bUsuario &a{0}&b no tiene ningún dato cargado."
user-save-success: "&7(Los datos del usuario se guardaron en el almacenamiento)"
user-save-error: "Se ha producido un error al guardar el usuario."
user-create-fail: "Se produjo un error al crear un nuevo usuario."
group-not-found: "&bEl Grupo no se pudo encontrar."
group-save-success: "&7(Los datos del grupo se guardaron en el almacenamiento)"
group-save-error: "Se ha producido un error al guardar el grupo."
track-not-found: "&bNo se pudo encontrar la pista."
track-save-success: "&7(Los datos de la pista se guardaron en el almacenamiento)"
track-save-error: "Se ha producido un error al guardar la pista."
user-invalid-entry: "&d{0}&c El username/uuid no es valido."
group-invalid-entry: "Los nombres de grupo sólo pueden contener caracteres alfanuméricos."
track-invalid-entry: "Los nombres de pista sólo pueden contener caracteres alfanuméricos."
server-invalid-entry: "Los nombres de servidor sólo pueden contener caracteres alfanuméricos."
use-inherit-command: "Usa el comando 'parent add' y 'parent remove' en vez de especificar el nodo."
verbose-invalid-filter: "&cFiltro Verbose invalido: &f{0}"
verbose-on: "&bEl chequeo Verbose de salida se ha establecido en &aTRUE &bpara todos los permisos."
verbose-on-query: "&bEl chequeo Verbose de salida que se establecio en &aTRUE &bpara los permisos se ha pareado con los siguientes filtros: &f{0}"
verbose-off: "&bEl chequeo Verbose de salida que se establecio en &cFALSE&b."
verbose-recording-on: "&bGrabacion de Verbose establecida en &aTRUE &bpara todos los permisos."
verbose-recording-on-query: "&bGrabacion de Verbose establecida en &aTRUE &bpara los permisos se ha pareado con los siguientes filtros: &f{0}"
verbose-recording-upload-start: "&bGrabacion de Verbose se ha deshabilitado. Cargando resultados..."
verbose-recording-url: "&aURL de resultados de Verbose:"
tree-upload-start: "&bGenerando arbol de permisos..."
tree-empty: "&aNo se puede generar el árbol. No se encontraron resultados."
tree-url: "&aURL de arbol de permisos:"
search-searching: "&aBúsqueda de usuarios y grupos con &b{0}&a..."
search-result: "&aEncontradas &b{0}&a entradas por parte de &b{1}&a usuarios y &b{2}&a grupos."
search-showing-users: "&bMostrando entradas del usuario:"
search-showing-groups: "&bMostrando entradas del grupo:"
search-showing-users-with-page: "&bMostrando entradas del usuario: {0}"
search-showing-groups-with-page: "&bMostrando entradas del grupo: {0}"
check-result: "&aResultado de la comprobación del permiso en el usuario &b{0}&a para permiso &b{1}&a: &f{2}"
create-success: "&b{0}&a se creó correctamente."
delete-success: "&b{0}&a fue eliminado correctamente."
rename-success: "&b{0}&a fue exitosamente renombrado a &b{1}&a."
clone-success: "&b{0}&a fue clonado con éxito en &b{1}&a."
already-inherits: "{0} ya hereda '{1}'."
does-not-inherit: "{0} no hereda '{1}'."
already-temp-inherits: "{0} ya lo heredo temporalmente a '{1}'."
does-not-temp-inherit: "{0} no lo heredo temporalmente a '{1}'."
track-already-contains: "La pista {0} ya contiene el grupo '{1}'."
track-does-not-contain: "La pista {0} no contiene el grupo '{1}'."
track-ambiguous-call: "El usuario especificado es miembro de varios grupos en esta pista. No se puede determinar su ubicación."
group-already-exists: "¡Ese grupo ya existe!"
group-does-not-exist: "¡Ese grupo no existe!"
group-load-error: "Ocurrió un error inesperado. No se pudo cargar el grupo."
groups-load-error: "Ocurrió un error inesperado. No se pueden cargar todos los grupos."
track-already-exists: "¡La pista ya existe!"
track-does-not-exist: "¡La pista no existe!"
track-load-error: "Ocurrió un error inesperado. No se pudo cargar la pista."
tracks-load-error: "Ocurrió un error inesperado. No se pueden cargar todas las pistas."
track-empty: "La pista no se puede utilizar porque está vacía o contiene sólo un grupo."
update-task-request: "&bActualizar tarea programada."
update-task-complete: "&aLa actualizacion de la tarea a finalizado."
update-task-complete-network: "&aLa actualizacion de la tarea a finalizado. Ahora intentando enviar a otros servidores."
update-task-push-success: "&aOtros servidores fueron notificados vía &b{0} Mensajería &aexitoxamente."
update-task-push-failure: "&cError al empujar cambios a otros servidores."
update-task-push-failure-not-setup: "&cError al presionar los cambios a otros servidores. No se ha configurado un servicio de mensajería."
reload-config-success: "&aSe ha vuelto a cargar el archivo de configuración. &7(Algunas opciones sólo se aplicarán después de que el servidor se haya reiniciado.)"
info: >
{PREFIX}&2Running &bLuckPerms v{0}&2 by &bLuck&2.\n
{PREFIX}&f- &3Platform: &f{1}\n
{PREFIX}&f- &3Storage Method: &f{2}\n
{PREFIX}&f- &3Server Name: &f{3}\n
{PREFIX}&f- &3Sync Interval: &a{4} &fminutes\n
{PREFIX}&f- &3Messaging Service: &f{5}\n
{PREFIX}&f- &bCounts:\n
{PREFIX}&f- &3Online Players: &a{6}\n
{PREFIX}&f- &3Loaded Users: &a{7}\n
{PREFIX}&f- &3Loaded Groups: &a{8}\n
{PREFIX}&f- &3Loaded Tracks: &a{9}\n
{PREFIX}&f- &3Log size: &a{10}\n
{PREFIX}&f- &3UUID Cache size: &a{11}\n
{PREFIX}&f- &3Translations loaded: &a{12}\n
{PREFIX}&f- &3Pre-process contexts: &a{13}\n
{PREFIX}&f- &3Context Calculators: &a{14}\n
{PREFIX}&f- &3Unique permissions: &a{15}\n
{PREFIX}&f- &bConfiguration:\n
{PREFIX}&f- &3Use Server UUIDs: {16}\n
{PREFIX}&f- &bPermission Calculation:\n
{PREFIX}&f- &3Including Global: {17}\n
{PREFIX}&f- &3Including Global World: {18}\n
{PREFIX}&f- &3Applying Global Groups: {19}\n
{PREFIX}&f- &3Applying Global World Groups: {20}\n
{PREFIX}&f- &3Applying Wildcards: {21}\n
{PREFIX}&f- &3Applying Regex: {22}\n
{PREFIX}&f- &3Applying Shorthand: {23}
create-group-error: "Se produjo un error al crear el grupo."
delete-group-error: "Se produjo un error al eliminar el grupo."
delete-group-error-default: "No puede eliminar el grupo predeterminado."
groups-list: "&aGrupos: {0}"
create-track-error: "Se produjo un error al crear la pista."
delete-track-error: "Se produjo un error al eliminar la pista."
tracks-list: "&aPistas: {0}"
listnodes: "&b{0}'s Nodos:"
listnodes-with-page: "&b{0}'s Nodos: {1}"
listnodes-temp: >
&b{0}'s Temporary Nodes:\n
{1}
listparents: >
&b{0}'s Parent Groups:\n
{1}
listparents-temp: >
&b{0}'s Temporary Parent Groups:\n
{1}
listgroups: >
&b{0}'s Groups:\n
{1}
listgroups-temp: >
&b{0}'s Temporary Groups:\n
{1}
list-tracks: >
&b{0}'s Tracks:\n
{1}
list-tracks-empty: "{0} no está en ninguna pista."
setpermission-success: "&aEstablecer &b{0}&a a &b{1}&a para &b{2}&a."
setpermission-server-success: "&aEstablecer &b{0}&a a &b{1}&a para &b{2}&a en el servidor &b{3}&a."
setpermission-server-world-success: "&aEstablecer &b{0}&a a &b{1}&a para &b{2}&a en el servidor &b{3}&a, mundo &b{4}&a."
setpermission-temp-success: "&aEstablecer &b{0}&a a &b{1}&a para &b{2}&a por una duracion de &b{3}&a."
setpermission-temp-server-success: "&aEstablecer &b{0}&a a &b{1}&a para &b{2}&a en el servidor &b{3}&a por una duracion de &b{4}&a."
setpermission-temp-server-world-success: "&aEstablecer &b{0}&a a &b{1}&a para &b{2}&a en el servidor &b{3}&a, mundo &b{4}&a, por una duracion de &b{5}&a."
unsetpermission-success: "&aDesestablecer &b{0}&a para &b{1}&a."
unsetpermission-server-success: "&aDesestablecer &b{0}&a para &b{1}&a en el servidor &b{2}&a."
unsetpermission-server-world-success: "&aDesestablecer &b{0}&a para &b{1}&a en el servidor &b{2}&a, mundo &b{3}&a."
unset-temp-permission-success: "&aDesestablecer temporalmente el permiso &b{0}&a para &b{1}&a."
unset-temp-permission-server-success: "&aDesestablecer temporalmente el permiso &b{0}&a para &b{1}&a en el servidor &b{2}&a."
unset-temp-permission-server-world-success: "&aDesestablecer temporalmente el permiso &b{0}&a para &b{1}&a en el servidor &b{2}&a, mundo &b{3}&a."
set-inherit-success: "&b{0}&a ahora hereda los permisos de &b{1}&a."
set-inherit-server-success: "&b{0}&a ahora hereda los permisos de &b{1}&a en el servidor &b{2}&a."
set-inherit-server-world-success: "&b{0}&a ahora hereda los permisos de &b{1}&a en el servidor &b{2}&a, mundo &b{3}&a."
set-parent-success: "&b{0}&a sus grupos parentales existentes han sido borrados, y ahora solo heredan &b{1}&a."
set-parent-server-success: "&b{0}&a sus grupos parentales existentes han sido borrados, y ahora solo heredan &b{1}&a en el servidor &b{2}&a."
set-parent-server-world-success: "&b{0}&a sus grupos parentales existentes han sido borrados, y ahora solo heredan &b{1}&a en el servidor &b{2}&a, mundo &b{3}&a."
set-temp-inherit-success: "&b{0}&a ahora heredan permisos de &b{1}&a por una duracion de &b{2}&a."
set-temp-inherit-server-success: "&b{0}&a ahora heredan permisos de &b{1}&a en el servidor &b{2}&a por una duracion de &b{3}&a."
set-temp-inherit-server-world-success: "&b{0}&a ahora heredan permisos de &b{1}&a en el servidor &b{2}&a, mundo &b{3}&a, por una duracion de &b{4}&a."
unset-inherit-success: "&b{0}&a ya no hereda los permisos de &b{1}&a."
unset-inherit-server-success: "&b{0}&a ya no hereda los permisos de &b{1}&a en el servidor &b{2}&a."
unset-inherit-server-world-success: "&b{0}&a ya no hereda los permisos de &b{1}&a en el servidor &b{2}&a, mundo &b{3}&a."
unset-temp-inherit-success: "&b{0}&a ya no hereda temporalmente los permisos de &b{1}&a."
unset-temp-inherit-server-success: "&b{0}&a ya no hereda temporalmente los permisos &b{1}&a en el servidor &b{2}&a."
unset-temp-inherit-server-world-success: "&b{0}&a ya no hereda temporalmente los permisos &b{1}&a en el servidor &b{2}&a, mundo &b{3}&a."
clear-success: "&b{0}&a's permisos fueron borrados. (&b{1}&a nodos fueron removidos.)"
clear-success-singular: "&b{0}&a's permisos fueron borrados. (&b{1}&a nodo fue removido.)"
parent-clear-success: "&b{0}&a's los padres fueron eliminados. (&b{1}&a nodos fueron removidos.)"
parent-clear-success-singular: "&b{0}&a's los padres fueron eliminados. (&b{1}&a nodo fue removido.)"
meta-clear-success: "&b{0}&a's meta fue eliminada. (&b{1}&a nodos fueron removidos.)"
meta-clear-success-singular: "&b{0}&a's meta fue eliminada. (&b{1}&a nodo fue removido.)"
illegal-date-error: "No se pudo analizar la fecha '{0}'."
past-date-error: "¡No puedes fijar una fecha en el pasado!"
chat-meta-prefix-header: "&b{0}'s Prefijos"
chat-meta-suffix-header: "&b{0}'s Sufijos"
meta-header: "&b{0}'s Meta"
chat-meta-entry: "&b-> {0} &f- &f\"{1}&f\" &8(&7heredado de &a{2}&8)"
chat-meta-entry-with-context: "&b-> {0} &f- &f\"{1}&f\" &8(&7heredado de &a{2}&8){3}"
meta-entry: "&b-> &a{0} &f= &f\"{1}&f\" &8(&7heredado de &a{2}&8)"
meta-entry-with-context: "&b-> &a{0} &f= &f\"{1}&f\" &8(&7heredado de &a{2}&8){3}"
chat-meta-prefix-none: "&b{0} no tiene prefijos."
chat-meta-suffix-none: "&b{0} no tiene sufijos."
meta-none: "&b{0} no tiene meta."
meta-invalid-priority: "Prioridad no válida '{0}'. Se esperaba un número."
already-has-prefix: "{0} ya tiene ese prefijo establecido."
already-has-suffix: "{0} ya tiene ese sufijo establecido."
does-not-have-prefix: "{0} no tiene ese prefijo establecido."
does-not-have-suffix: "{0} no tiene ese sufijo establecido."
addprefix-success: "&b{0}&a tiene el prefijo &f\"{1}&f\"&a establecido como prioridad de &b{2}&a."
addprefix-server-success: "&b{0}&a tiene el prefijo &f\"{1}&f\"&a establecido como prioridad de &b{2}&a en el servidor &b{3}&a."
addprefix-server-world-success: "&b{0}&a tiene el prefijo &f\"{1}&f\"&a establecido como prioridad de &b{2}&a en el servidor &b{3}&a, mundo &b{4}&a."
removeprefix-success: "&b{0}&a tiene el prefijo &f\"{1}&f\"&a en prioridad de &b{2}&a removido."
removeprefix-server-success: "&b{0}&a tiene el prefijo &f\"{1}&f\"&a en prioridad de &b{2}&a removido en el servidor &b{3}&a."
removeprefix-server-world-success: "&b{0}&a tiene el prefijo &f\"{1}&f\"&a en prioridad de &b{2}&a removido en el servidor &b{3}&a, mundo &b{4}&a."
addsuffix-success: "&b{0}&a tiene el sufijo &f\"{1}&f\"&a establecido en prioridad de &b{2}&a."
addsuffix-server-success: "&b{0}&a tiene el sufijo &f\"{1}&f\"&a establecido en prioridad de &b{2}&a en el servidor &b{3}&a."
addsuffix-server-world-success: "&b{0}&a tiene el sufijo &f\"{1}&f\"&a establecido en prioridad de &b{2}&a en el servidor &b{3}&a, mundo &b{4}&a."
removesuffix-success: "&b{0}&a tiene el sufijo &f\"{1}&f\"&a en prioridad de &b{2}&a removido."
removesuffix-server-success: "&b{0}&a tiene el sufijo &f\"{1}&f\"&a en prioridad de &b{2}&a removido en el servidor &b{3}&a."
removesuffix-server-world-success: "&b{0}&a tiene el sufijo &f\"{1}&f\"&a en prioridad de &b{2}&a removido en el servidor &b{3}&a, mundo &b{4}&a."
add-temp-prefix-success: "&b{0}&a tiene el prefijo &f\"{1}&f\"&a en prioridad de &b{2}&a por una duracion de &b{3}&a."
add-temp-prefix-server-success: "&b{0}&a tiene el prefijo &f\"{1}&f\"&a establecido en prioridad de &b{2}&a en el servidor &b{3}&a, por una duracion de &b{4}&a."
add-temp-prefix-server-world-success: "&b{0}&a tiene el prefijo &f\"{1}&f\"&a establecido en prioridad de &b{2}&a en el servidor &b{3}&a, mundo &b{4}&a, por una duracion de &b{5}&a."
remove-temp-prefix-success: "&b{0}&a tiene temporalmente el prefijo &f\"{1}&f\"&a en prioridad de &b{2}&a removido."
remove-temp-prefix-server-success: "&b{0}&a tiene temporalmente el prefijo &f\"{1}&f\"&a en prioridad de &b{2}&a removido en el servidor &b{3}&a."
remove-temp-prefix-server-world-success: "&b{0}&a tiene temporalmente el prefijo &f\"{1}&f\"&a en prioridad de &b{2}&a removido en el servidor &b{3}&a, mundo &b{4}&a."
add-temp-suffix-success: "&b{0}&a tiene el sufijo &f\"{1}&f\"&a establecido en prioridad de &b{2}&a por una duracion de &b{3}&a."
add-temp-suffix-server-success: "&b{0}&a tiene el sufijo &f\"{1}&f\"&a establecido en prioridad de &b{2}&a en el servidor &b{3}&a, por una duracion de &b{4}&a."
add-temp-suffix-server-world-success: "&b{0}&a tiene el sufijo &f\"{1}&f\"&a establecido en prioridad de &b{2}&a en el servidor &b{3}&a, mundo &b{4}&a, por una duracion de &b{5}&a."
remove-temp-suffix-success: "&b{0}&a tiene temporalmente el sufijo &f\"{1}&f\"&a en prioridad de &b{1}&a removido."
remove-temp-suffix-server-success: "&b{0}&a tiene temporalmente el sufijo &f\"{1}&f\"&a en prioridad de &b{2}&a removido en el servidor &b{3}&a."
remove-temp-suffix-server-world-success: "&b{0}&a tiene temporalmente el sufijo &f\"{1}&f\"&a en prioridad de &b{2}&a removido en el servidor &b{3}&a, mundo &b{4}&a."
already-has-meta: "{0} ya tiene ese par de valores de llave meta establecido."
set-meta-success: "&aEstablecer el valor meta para la llave &f\"{0}&f\"&a a &f\"{1}&f\"&a para &b{2}&a."
set-meta-server-success: "&aEstablecer el valor meta para la llave &f\"{0}&f\"&a a &f\"{1}&f\"&a para &b{2}&a en el servidor &b{3}&a."
set-meta-server-world-success: "&aEstablecer el valor meta para la llave &f\"{0}&f\"&a a &f\"{1}&f\"&a para &b{2}&a en el servidor &b{3}&a, mundo &b{4}&a."
set-meta-temp-success: "&aEstablecer el valor meta para la llave &f\"{0}&f\"&a a &f\"{1}&f\"&a para &b{2}&a por una duracion de &b{3}&a."
set-meta-temp-server-success: "&aEstablecer el valor meta para la llave &f\"{0}&f\"&a a &f\"{1}&f\"&a para &b{2}&a en el servidor &b{3}&a por una duracion de &b{4}&a."
set-meta-temp-server-world-success: "&aEstablecer el valor meta para la llave &f\"{0}&f\"&a a &f\"{1}&f\"&a para &b{2}&a en el servidor &b{3}&a, mundo &b{4}&a, por una duracion de &b{5}&a."
unset-meta-success: "&aDesestablecer el valor meta con la llave &f\"{0}&f\"&a para &b{1}&a."
unset-meta-server-success: "&aDesestablecer el valor meta con la llave &f\"{0}&f\"&a para &b{1}&a en el servidor &b{2}&a."
unset-meta-server-world-success: "&aDesestablecer el valor meta con la llave &f\"{0}&f\"&a for &b{1}&a en el servidor &b{2}&a, mundo &b{3}&a."
unset-meta-temp-success: "&aDesestablecer temporalmente el valor meta con la llave &f\"{0}&f\"&a para &b{1}&a."
unset-meta-temp-server-success: "&aDesestablecer temporalmente el valor meta con la llave &f\"{0}&f\"&a para &b{1}&a en el servidor &b{2}&a."
unset-meta-temp-server-world-success: "&aDesestablecer temporalmente el valor meta con la llave &f\"{0}&f\"&a para &b{1}&a en el servidor &b{2}&a, mundo &b{3}&a."
bulk-change-type-error: "Tipo no válido. Se estaba esperando 'server' o 'world'."
bulk-change-success: "&aEl cambio masivo fue aplicado correctamente. {0} los registros fueron cambiados."
user-info-general: >
{PREFIX}&b&l> &bUser Info: &f{0}\n
{PREFIX}&f- &3UUID: &f{1}\n
{PREFIX}&f- &3Status: {2}\n
{PREFIX}&f- &3Primary Group: &f{3}\n
{PREFIX}&f- &aCounts:\n
{PREFIX}&f- &3Permissions: &a{4}\n
{PREFIX}&f- &3Temporary Permissions: &a{5}\n
{PREFIX}&f- &3Prefixes: &a{6}\n
{PREFIX}&f- &3Suffixes: &a{7}\n
{PREFIX}&f- &3Meta: &a{8}
user-info-data: >
{PREFIX}&f- &aCached Data:\n
{PREFIX}&f- &3Is Loaded: {0}\n
{PREFIX}&f- &3Current Contexts: {1}\n
{PREFIX}&f- &3Current Prefix: {2}\n
{PREFIX}&f- &3Current Suffix: {3}
info-parent-header: "&f- &aGrupos Parentales:"
info-temp-parent-header: "&f- &aGrupos Temporalmente Parentales:"
user-getuuid: "&bEl UUID de &b{0}&b es &b{1}&b."
user-removegroup-error-primary: "No puede eliminar un usuario de su grupo principal."
user-primarygroup-success: "&b{0}&a's grupo primario se estableció &b{1}&a."
user-primarygroup-warn-option: "&cAdvertencia: El método de cálculo de grupo primario utilizado por este servidor &7({0}) &cpuede no reflejar este cambio."
user-primarygroup-error-alreadyhas: "El usuario ya tiene este grupo configurado como su grupo principal."
user-primarygroup-error-notmember: "&b{0}&a ya no era miembro de &b{1}&a, agregándolos ahora."
user-track-error-not-contain-group: "El usuario especificado ya no está en ningún grupo de esta pista."
user-track-added-to-first: "&b{0}&a no está en ningún grupo en esta pista, por lo que se agregaron al primer grupo, &b{1}&a."
user-track-added-to-first-server: "&b{0}&a no está en ningún grupo en esta pista, por lo que se agregaron al primer grupo, &b{1}&a, en el servidor &b{2}&a."
user-track-added-to-first-server-world: "&b{0}&a no está en ningún grupo en esta pista, por lo que se agregaron al primer grupo, &b{1}&a, en el servidor &b{2}&a, mundo &b{3}&a."
user-promote-success: "&aPromover al usuario a lo largo de la pista &b{0}&a desde &b{1}&a a &b{2}&a."
user-promote-success-server: "&aPromover al usuario a lo largo de la pista &b{0}&a desde &b{1}&a a &b{2}&a en el servidor &b{3}&a."
user-promote-success-server-world: "&aPromover al usuario a lo largo de la pista &b{0}&a desde &b{1}&a a &b{2}&a en el servidor &b{3}&a, mundo &b{4}&a."
user-promote-error-endoftrack: "El final de la pista &4{0}&c fue alcanzado. No se puede promover al usuario."
user-promote-error-malformed: >
{PREFIX}The next group on the track, {0}, no longer exists. Unable to promote user.\n
{PREFIX}Either create the group, or remove it from the track and try again.
user-demote-success: "&aDegradando al usuario a lo largo de la pista &b{0}&a desde &b{1}&a a &b{2}&a."
user-demote-success-server: "&aDegradando al usuario a lo largo de la pista &b{0}&a desde &b{1}&a a &b{2}&a en el servidor &b{3}&a."
user-demote-success-server-world: "&aDegradando al usuario a lo largo de la pista &b{0}&a desde &b{1}&a a &b{2}&a en el servidor &b{3}&a, mundo &b{4}&a."
user-demote-endoftrack: "El final de la pista &4{0}&c fue alcanzado, asi que &4{1}&c fue removido de &4{2}&c."
user-demote-error-malformed: >
{PREFIX}The previous group on the track, {0}, no longer exists. Unable to demote user.\n
{PREFIX}Either create the group, or remove it from the track and try again.
user-showpos: >
&aShowing &b{0}&a's position on track &b{1}&a.\n
{2}
group-info-general: >
{PREFIX}&b&l> &bGroup Info: &f{0}\n
{PREFIX}&f- &3Display Name: &f{1}\n
{PREFIX}&f- &3Weight: &f{2}\n
{PREFIX}&f- &aCounts:\n
{PREFIX}&f- &3Permissions: &a{3}\n
{PREFIX}&f- &3Temporary Permissions: &a{4}\n
{PREFIX}&f- &3Prefixes: &a{5}\n
{PREFIX}&f- &3Suffixes: &a{6}\n
{PREFIX}&f- &3Meta: &a{7}
group-set-weight: "&aEstablesca el peso a &b{0}&a para el grupo &b{1}&a."
track-info: >
{PREFIX}&b&l> &bShowing Track: &f{0}\n
{PREFIX}&f- &7Path: &f{1}
track-clear: "&b{0}&a's pista de grupos fue borrada."
track-append-success: "&aGrupo &b{0}&a fue añadido con éxito a la pista &b{1}&a."
track-insert-success: "&aGrupo &b{0}&a fue insertado con éxito en la pista &b{1}&a en la posicion &b{2}&a."
track-insert-error-number: "Numero esperado en lugar de recibido: {0}"
track-insert-error-invalid-pos: "No se puede insertar en la posición {0}. Indice fuera de los limites."
track-remove-success: "&aGrupo &b{0}&a se eliminó correctamente de la pista &b{1}&a."
log-load-error: "No se pudo cargar el registro."
log-invalid-page: "Número de página no válido."
log-invalid-page-range: "Número de página no válido. Por favor introduzca un valor entre 1 y {0}."
log-no-entries: "&bNo hay entradas de registro que mostrar."
log-entry: "&b#{0} -> &8(&7{1} hace&8) {2}"
log-notify-toggle-on: "&aHabilitada&b salida de registro."
log-notify-toggle-off: "&cDeshabilitada&b salida de registro."
log-notify-already-on: "Ya está recibiendo notificaciones."
log-notify-already-off: "Actualmente no estás recibiendo notificaciones."
log-notify-unknown: "Estado desconocido. Esperando \"on\" o \"off\"."
log-search-header: "&aMostrar acciones recientes para la consulta &b{0} &a(pagina &f{1}&a de &f{2}&a)"
log-recent-header: "&aMostrando acciones recientes (pagina &f{0}&a de &f{1}&a)"
log-recent-by-header: "&aMostrando las acciones recientes por &b{0} &a(pagina &f{1}&a de &f{2}&a)"
log-history-user-header: "&aMostrando el historial del usuario &b{0} &a(pagina &f{1}&a de &f{2}&a)"
log-history-group-header: "&aMostrando la historia del grupo &b{0} &a(pagina &f{1}&a de &f{2}&a)"
log-history-track-header: "&aMostrando la historia de la pista &b{0} &a(pagina &f{1}&a de &f{2}&a)"
log-export-already-exists: "Error: Archivo {0} ya existe."
log-export-not-writable: "Error: Archivo {0} no se puede escribir."
log-export-empty: "El registro está vacío y por lo tanto no puede ser exportado."
log-export-failure: "Se ha producido un error inesperado al escribir en el archivo."
log-export-success: "&aExitosamente exportó el registro a &b{0}&a."
import-already-running: "Ya se está ejecutando otro proceso de importación. Por favor espere a que finalice e inténtelo de nuevo."
export-already-running: "Ya se está ejecutando otro proceso de exportación. Por favor espere a que finalice e inténtelo de nuevo."
import-log-doesnt-exist: "Error: Archivo {0} no existe."
import-log-not-readable: "Error: Archivo {0} no es legible."
import-log-failure: "Se ha producido un error inesperado al leer del archivo de registro."
import-progress: "&b(Import) &b-> &f{0} &fporcentaje completado &7- &b{1}&f/&b{2} &fOperaciones completas con &c{3} &ferrores."
import-progress-sin: "&b(Import) &b-> &f{0} &fporcentaje completado &7- &b{1}&f/&b{2} &fOperaciones completas con &c{3} &ferrores."
import-start: "&b(Import) &b-> &fInicio del proceso de importación."
import-end-complete: "&b(Import) &a&lCOMPLETADO &7- tomo &b{0} &7segundos - &7No errores."
import-end-complete-err: "&b(Import) &a&lCOMPLETADO &7- tomo &b{0} &7segundos - &c{1} errores."
import-end-complete-err-sin: "&b(Import) &a&lCOMPLETADO &7- tomo &b{0} &7segundos - &c{1} errores."
import-end-error-header: >
{PREFIX}&b(Import) &7------------> &fShowing Error #&b{0} &7<------------\n
{PREFIX}&b(Import) &fWhilst executing: &3Command #{1}\n
{PREFIX}&b(Import) &fCommand: &7{2}\n
{PREFIX}&b(Import) &fType: &3{3}\n
{PREFIX}&b(Import) &fOutput:
import-end-error-content: "&b(Import) &b-> &c{0}"
import-end-error-footer: "&b(Import) &7<------------------------------------------>"
-338
View File
@@ -1,338 +0,0 @@
# LuckPerms Language File
# Locale: ru_RU
# Author: Pixelmon.PRO
prefix: "&7&l[&b&lL&3&lP&7&l] &c"
log-info: "&7&l[&bL&3P&7&l] &3{0}"
log-warn: "&7&l[&bLuck&3Perms&7&l] &c[WARN] {0}"
log-error: "&7&l[&bLuck&3Perms&7&l] &4[ERROR] {0}"
empty: "{0}"
player-online: "&aОнлайн"
player-offline: "&cОффлайн"
loading-error: "Не удалось загрузить данные разрешений (пермов). Пожалуйста обратитесь к администратору."
op-disabled: "&bНа этом сервере отключена ванильная система OP."
op-disabled-sponge: "&2Статус оператора сервера не влияет на установленный плагин разрешений (пермов). Пожалуйста отредактируйте данные пользователя напрямую."
log: "&3LOG &3&l> {0}"
export-log: "&3ЭКСПОРТ &3&l> &f{0}"
export-log-progress: "&3ЭКСПОРТ &3&l> &7{0}"
migration-log: "&3ПЕРЕМЕЩЕНИЕ &7[&3{0}&7] &3&l> &f{1}"
migration-log-progress: "&3ПЕРЕМЕЩЕНИЕ &7[&3{0}&7] &3&l> &7{1}"
command-not-recognised: "Команда не распознана."
command-no-permission: "У вас нет разрешения на использование этой команды!"
already-haspermission: "{0} уже имеет такое разрешение (перм)!"
does-not-havepermission: "{0} не имеет этого набора разрешений (пермов)."
already-has-temp-permission: "{0} уже имеет этот набор временных разрешений (пермов)!"
does-not-have-temp-permission: "{0} не имеет этого набора временных разрешений (пермов)."
user-not-found: "&bНе удалось найти пользователя."
user-not-online: "&bПользователь &a{0}&b не онлайн."
user-no-data: "&bПользователь &a{0}&b не имеет загруженных данных."
user-save-success: "&7(Пользовательские данные были сохранены на хранение)"
user-save-error: "При сохранении пользователя произошла ошибка."
user-create-fail: "При создании нового пользователя возникла ошибка."
group-not-found: "&bНе удалось найти группу."
group-save-success: "&7(Групповые данные были сохранены на хранение)"
group-save-error: "При сохранении группы произошла ошибка."
track-not-found: "&bНе удалось найти путь (track)."
track-save-success: "&7(Данные о путе (track) сохранены на хранение)"
track-save-error: "При сохранении пути (track) произошла ошибка."
user-invalid-entry: "&d{0}&c не является допустимым именем пользователя/uuid."
group-invalid-entry: "Имена групп могут содержать только буквенно-цифровые символы."
track-invalid-entry: "Имена путей (track) могут содержать только буквенно-цифровые символы."
server-invalid-entry: "Имена серверов могут содержать только буквенно-цифровые символы."
use-inherit-command: "Используйте команды «parent add» и «parent remove» вместо указания узла (node)."
verbose-invalid-filter: "&cНедопустимый подробный (verbose) фильтр: &f{0}"
verbose-on: "&Запись подробной проверки установлена на &aВЕРНЫЙ &bдля всех разрешений (пермов)."
verbose-on-query: "&Запись подробной проверки установлена на &aВЕРНЫЙ &bДля разрешений, соответствующих следующим фильтрам: &f{0}"
verbose-off: "&Запись подробной проверки установлена на &cНЕВЕРНЫЙ&b."
verbose-recording-on: "&Запись подробной записи установлена ​​на &aВЕРНЫЙ &bдля всех разрешений."
verbose-recording-on-query: "&Запись подробной записи установлена ​​на &aВЕРНЫЙ &bДля разрешений, соответствующих следующим фильтрам: &f{0}"
verbose-recording-upload-start: "&bЗапись подробной информации была отключена. Загрузка результатов..."
verbose-recording-url: "&aПодробный URL результатов:"
tree-upload-start: "&bСоздание дерева разрешений..."
tree-empty: "&aНе удалось создать дерево. Ничего не найдено."
tree-url: "&aURL дерева разрешений:"
search-searching: "&aПоиск пользователей и групп с помощью &b{0}&a..."
search-result: "&aНайдено &b{0}&a записи из &b{1}&a пользователей и &b{2}&a групп."
search-showing-users: "&bПросмотр записей пользователя:"
search-showing-groups: "&bПросмотр записей в группах:"
search-showing-users-with-page: "&bПросмотр записей пользователя: {0}"
search-showing-groups-with-page: "&bПросмотр записей в группах: {0}"
check-result: "&aРезультат проверки разрешения (перма) на пользователя &b{0}&a на разрешение (перма) &b{1}&a: &f{2}"
create-success: "&b{0}&a было успешно создано."
delete-success: "&b{0}&a успешно удален."
rename-success: "&b{0}&a был успешно переименован в &b{1}&a."
clone-success: "&b{0}&a был успешно клонирован на &b{1}&a."
already-inherits: "{0} уже наследует '{1}'."
does-not-inherit: "{0} не наследует '{1}'."
already-temp-inherits: "{0} уже временно наследует '{1}'."
does-not-temp-inherit: "{0} временно не наследует '{1}'."
track-already-contains: "Путь (Track) {0} уже содержит группу '{1}'."
track-does-not-contain: "Путь (Track) {0} не содержит группу '{1}'."
track-ambiguous-call: "Указанный пользователь является членом нескольких групп на этом пути (track). Невозможно определить их местоположение."
group-already-exists: "Эта группа уже существует!"
group-does-not-exist: "Эта группа не существует!"
group-load-error: "Произошла непредвиденная ошибка. Группа не загружена."
groups-load-error: "Произошла непредвиденная ошибка. Не удалось загрузить все группы."
track-already-exists: "Этот путь (track) уже существует!"
track-does-not-exist: "Этот путь (track) не существует!"
track-load-error: "Произошла непредвиденная ошибка. Путь (track) не загружен."
tracks-load-error: "Произошла непредвиденная ошибка. Не удалось загрузить все пути (tracks)."
track-empty: "Путь (track) нельзя использовать, так как он пуст или содержит только одну группу."
update-task-request: "&bОбновление задачи запланировано."
update-task-complete: "&aОбновление задачи завершено."
update-task-complete-network: "&aОбновление задачи завершено. Теперь пытаемся подключиться к другим серверам."
update-task-push-success: "&aДругие серверы были уведомлены через &b{0} Сообщения и удаленный доступ."
update-task-push-failure: "&cОшибка при нажатии изменений на других серверах."
update-task-push-failure-not-setup: "&cОшибка при нажатии изменений на других серверах. Служба обмена сообщениями не настроена."
reload-config-success: "&aФайл конфигурации был перезагружен. &7(Некоторые параметры будут применяться только после перезапуска сервера.)"
info: >
{PREFIX}&2Выполнение &bLuckPerms v{0}&2 by &bLuck&2.\n
{PREFIX}&f- &3Платформа: &f{1}\n
{PREFIX}&f- &3Способ Хранения: &f{2}\n
{PREFIX}&f- &3Имя Сервера: &f{3}\n
{PREFIX}&f- &3Интервал Синхронизации: &a{4} &fминут\n
{PREFIX}&f- &3Служба обмена сообщениями: &f{5}\n
{PREFIX}&f- &bГрафы:\n
{PREFIX}&f- &3Игроки Онлайн: &a{6}\n
{PREFIX}&f- &3Загруженные пользователи: &a{7}\n
{PREFIX}&f- &3Загруженные группы: &a{8}\n
{PREFIX}&f- &3Загруженные пути (tracks): &a{9}\n
{PREFIX}&f- &3Размер лога: &a{10}\n
{PREFIX}&f- &3UUID Размер кеша: &a{11}\n
{PREFIX}&f- &3Переводы загружены: &a{12}\n
{PREFIX}&f- &3Контексты перед обработкой: &a{13}\n
{PREFIX}&f- &3Счетчик контекста: &a{14}\n
{PREFIX}&f- &3Уникальные разрешения (пермы): &a{15}\n
{PREFIX}&f- &bКонфигурация:\n
{PREFIX}&f- &3Использует сервер UUIDs: {16}\n
{PREFIX}&f- &bСчетчик разрешений (Пермов):\n
{PREFIX}&f- &3Включая глобальные: {17}\n
{PREFIX}&f- &3Включая глобальный мир: {18}\n
{PREFIX}&f- &3Применения глобальных групп: {19}\n
{PREFIX}&f- &3Применения глобальных групп мира: {20}\n
{PREFIX}&f- &3Применения подстановочных знаков (Wildcards): {21}\n
{PREFIX}&f- &3Применение регулярных выражений: {22}\n
{PREFIX}&f- &3Применение стенографии (Shorthand): {23}
create-group-error: "При создании группы произошла ошибка."
delete-group-error: "При удалении группы произошла ошибка."
delete-group-error-default: "Вы не можете удалить группу по умолчанию."
groups-list: "&aГруппы: {0}"
create-track-error: "При создании пути (track) произошла ошибка."
delete-track-error: "При удалении пути (Track) произошла ошибка."
tracks-list: "&aGenb (Tracks): {0}"
listnodes: "&b{0}'s Узлы:"
listnodes-with-page: "&b{0}'s Узлы: {1}"
listnodes-temp: >
&b{0}'s Временные узлы:\n
{1}
listparents: >
&b{0}'s Родительские группы:\n
{1}
listparents-temp: >
&b{0}'s Временные родительские группы:\n
{1}
listgroups: >
&b{0}'s Группы:\n
{1}
listgroups-temp: >
&b{0}'s Временные группы:\n
{1}
list-tracks: >
&b{0}'s Пути (Tracks):\n
{1}
list-tracks-empty: "{0} Не на каких-либо путях (tracks)."
setpermission-success: "&aУстановить &b{0}&a к &b{1}&a для &b{2}&a."
setpermission-server-success: "&aУстановить &b{0}&a к &b{1}&a для &b{2}&a на сервер &b{3}&a."
setpermission-server-world-success: "&aУстановить &b{0}&a к &b{1}&a для &b{2}&a на сервер &b{3}&a, мир &b{4}&a."
setpermission-temp-success: "&aУстановить &b{0}&a к &b{1}&a для &b{2}&a На срок &b{3}&a."
setpermission-temp-server-success: "&aУстановить &b{0}&a к &b{1}&a для &b{2}&a на сервер &b{3}&a на срок &b{4}&a."
setpermission-temp-server-world-success: "&aУстановить &b{0}&a к &b{1}&a для &b{2}&a на сервер &b{3}&a, мир &b{4}&a, на срок &b{5}&a."
unsetpermission-success: "&aСбросить &b{0}&a для &b{1}&a."
unsetpermission-server-success: "&aСбросить &b{0}&a для &b{1}&a on server &b{2}&a."
unsetpermission-server-world-success: "&aСбросить &b{0}&a для &b{1}&a on server &b{2}&a, world &b{3}&a."
unset-temp-permission-success: "&aСбросить временное разрешение &b{0}&a для &b{1}&a."
unset-temp-permission-server-success: "&aСбросить временное разрешение &b{0}&a для &b{1}&a на сервере &b{2}&a."
unset-temp-permission-server-world-success: "&aСбросить временное разрешение &b{0}&a для &b{1}&a на сервере &b{2}&a, мире &b{3}&a."
set-inherit-success: "&b{0}&a теперь наследует разрешения от &b{1}&a."
set-inherit-server-success: "&b{0}&a теперь наследует разрешения от &b{1}&a на сервере &b{2}&a."
set-inherit-server-world-success: "&b{0}&a теперь наследует разрешения от &b{1}&a на сервере &b{2}&a, мире &b{3}&a."
set-parent-success: "&b{0}&a их существующие родительские группы очищены, и теперь только наследуют &b{1}&a."
set-parent-server-success: "&b{0}&a их существующие родительские группы очищены, и теперь только наследуют &b{1}&a на сервере &b{2}&a."
set-parent-server-world-success: "&b{0}&a их существующие родительские группы очищены, и теперь только наследуют &b{1}&a на сервере &b{2}&a, мире &b{3}&a."
set-temp-inherit-success: "&b{0}&a теперь наследует разрешения (пермы) от &b{1}&a на срок &b{2}&a."
set-temp-inherit-server-success: "&b{0}&a теперь наследует разрешения (пермы) от &b{1}&a на сервере &b{2}&a for a duration of &b{3}&a."
set-temp-inherit-server-world-success: "&b{0}&a теперь наследует разрешения (пермы) от &b{1}&a на сервере &b{2}&a, мире &b{3}&a, на срок &b{4}&a."
unset-inherit-success: "&b{0}&a больше не наследует разрешения (пермы) от &b{1}&a."
unset-inherit-server-success: "&b{0}&a больше не наследует разрешения (пермы) &b{1}&a на сервере &b{2}&a."
unset-inherit-server-world-success: "&b{0}&a больше не наследует разрешения (пермы) &b{1}&a на сервере &b{2}&a, мире &b{3}&a."
unset-temp-inherit-success: "&b{0}&a больше не наследует временные разрешения (пермы) &b{1}&a."
unset-temp-inherit-server-success: "&b{0}&a больше не наследует временные разрешения (пермы) &b{1}&a на сервере &b{2}&a."
unset-temp-inherit-server-world-success: "&b{0}&a больше не наследует временные разрешения (пермы) &b{1}&a на сервере &b{2}&a, мире &b{3}&a."
clear-success: "&b{0}&a's разрешения (пермы) были очищены. (&b{1}&a узлы были удалены.)"
clear-success-singular: "&b{0}&a's разрешения (пермы) были очищены. (&b{1}&a узел удален.)"
parent-clear-success: "&b{0}&a's родители очищены. (&b{1}&a узлы были удалены.)"
parent-clear-success-singular: "&b{0}&a's родители очищены. (&b{1}&a узел удален.)"
meta-clear-success: "&b{0}&a's Meta очищена. (&b{1}&a узлы были удалены.)"
meta-clear-success-singular: "&b{0}&a's Meta очищена. (&b{1}&a узел удален.)"
illegal-date-error: "Не удалось выполнить синтаксический анализ даты '{0}'."
past-date-error: "Вы не можете установить дату в прошлом!"
chat-meta-prefix-header: "&b{0}'s Префиксы"
chat-meta-suffix-header: "&b{0}'s Суффиксы"
meta-header: "&b{0}'s Meta"
chat-meta-entry: "&b-> {0} &f- &f\"{1}&f\" &8(&7унаследованный от &a{2}&8)"
chat-meta-entry-with-context: "&b-> {0} &f- &f\"{1}&f\" &8(&7унаследованный от &a{2}&8){3}"
meta-entry: "&b-> &a{0} &f= &f\"{1}&f\" &8(&7унаследованный от &a{2}&8)"
meta-entry-with-context: "&b-> &a{0} &f= &f\"{1}&f\" &8(&7унаследованный от &a{2}&8){3}"
chat-meta-prefix-none: "&b{0} не имеет префиксов."
chat-meta-suffix-none: "&b{0} не имеет суффиксов."
meta-none: "&b{0} не имеет meta."
meta-invalid-priority: "Недопустимый приоритет '{0}'. Ожидается число."
already-has-prefix: "{0} Уже имеет этот набор префиксов."
already-has-suffix: "{0} Уже имеет этот набор суффиксов."
does-not-have-prefix: "{0} Не имеет этого набора префиксов."
does-not-have-suffix: "{0} Не имеет этого набора суффиксов."
addprefix-success: "&b{0}&a имеет префикс &f\"{1}&f\"&a установленный в приоритете &b{2}&a."
addprefix-server-success: "&b{0}&a имеет префикс &f\"{1}&f\"&a установленный в приоритете &b{2}&a на сервере &b{3}&a."
addprefix-server-world-success: "&b{0}&a имеет префикс &f\"{1}&f\"&a установленный в приоритете &b{2}&a на сервере &b{3}&a, мире &b{4}&a."
removeprefix-success: "&b{0}&a имеет префикс &f\"{1}&f\"&a в приоритете &b{2}&a удалено."
removeprefix-server-success: "&b{0}&a имеет префикс &f\"{1}&f\"&a в приоритете &b{2}&a удалено на сервере &b{3}&a."
removeprefix-server-world-success: "&b{0}&a имеет префикс &f\"{1}&f\"&a в приоритете &b{2}&a удалено на сервере &b{3}&a, мире &b{4}&a."
addsuffix-success: "&b{0}&a имеет суффикс &f\"{1}&f\"&a установленный в приоритете &b{2}&a."
addsuffix-server-success: "&b{0}&a имеет суффикс &f\"{1}&f\"&a установленный в приоритете &b{2}&a на сервере &b{3}&a."
addsuffix-server-world-success: "&b{0}&a имеет суффикс &f\"{1}&f\"&a установленный в приоритете &b{2}&a on server &b{3}&a, мире &b{4}&a."
removesuffix-success: "&b{0}&a имеет суффикс &f\"{1}&f\"&a в приоритете &b{2}&a удалено."
removesuffix-server-success: "&b{0}&a имеет суффикс &f\"{1}&f\"&a в приоритете &b{2}&a удалено на сервере &b{3}&a."
removesuffix-server-world-success: "&b{0}&a имеет суффикс &f\"{1}&f\"&a в приоритете &b{2}&a удалено на сервере &b{3}&a, мире &b{4}&a."
add-temp-prefix-success: "&b{0}&a имеет префикс &f\"{1}&f\"&a установленный в приоритете &b{2}&a на срок &b{3}&a."
add-temp-prefix-server-success: "&b{0}&a имеет префикс &f\"{1}&f\"&a установленный в приоритете of &b{2}&a на сервере &b{3}&a, на срок &b{4}&a."
add-temp-prefix-server-world-success: "&b{0}&a имеет префикс &f\"{1}&f\"&a установленный в приоритете of &b{2}&a на сервере &b{3}&a, мире &b{4}&a, на срок &b{5}&a."
remove-temp-prefix-success: "&b{0}&a Имел временный префикс &f\"{1}&f\"&a в приоритете &b{2}&a удалено."
remove-temp-prefix-server-success: "&b{0}&a Имел временный префикс &f\"{1}&f\"&a в приоритете &b{2}&a удалено на сервере &b{3}&a."
remove-temp-prefix-server-world-success: "&b{0}&a Имел временный префикс &f\"{1}&f\"&a в приоритете &b{2}&a удалено на сервере &b{3}&a, мире &b{4}&a."
add-temp-suffix-success: "&b{0}&a имел суффикс &f\"{1}&f\"&a установленный в приоритете &b{2}&a на срок &b{3}&a."
add-temp-suffix-server-success: "&b{0}&a имел суффикс &f\"{1}&f\"&a установленный в приоритете &b{2}&a на сервере &b{3}&a, на срок &b{4}&a."
add-temp-suffix-server-world-success: "&b{0}&a имел суффикс &f\"{1}&f\"&a установленный в приоритете &b{2}&a на сервере &b{3}&a, мире &b{4}&a, на срок &b{5}&a."
remove-temp-suffix-success: "&b{0}&a Имел временный суффикс &f\"{1}&f\"&a в приоритете &b{1}&a удалено."
remove-temp-suffix-server-success: "&b{0}&a Имел временный суффикс &f\"{1}&f\"&a в приоритете &b{2}&a удалено на сервере &b{3}&a."
remove-temp-suffix-server-world-success: "&b{0}&a Имел временный суффикс &f\"{1}&f\"&a в приоритете &b{2}&a удалено на сервере &b{3}&a, мире &b{4}&a."
already-has-meta: "{0} Уже установлено, что установлена ​​пара мета-значения ключа."
set-meta-success: "&aУстановить метазначение для ключа &f\"{0}&f\"&a к &f\"{1}&f\"&a для &b{2}&a."
set-meta-server-success: "&aУстановить метазначение для ключа &f\"{0}&f\"&a к &f\"{1}&f\"&a для &b{2}&a на сервере &b{3}&a."
set-meta-server-world-success: "&aУстановить метазначение для ключа &f\"{0}&f\"&a к &f\"{1}&f\"&a для &b{2}&a на сервере &b{3}&a, мире &b{4}&a."
set-meta-temp-success: "&aУстановить метазначение для ключа &f\"{0}&f\"&a к &f\"{1}&f\"&a для &b{2}&a на срок &b{3}&a."
set-meta-temp-server-success: "&aУстановить метазначение для ключа &f\"{0}&f\"&a к &f\"{1}&f\"&a для &b{2}&a на сервере &b{3}&a на срок &b{4}&a."
set-meta-temp-server-world-success: "&aУстановить метазначение для ключа &f\"{0}&f\"&a к &f\"{1}&f\"&a для &b{2}&a на сервере &b{3}&a, мире &b{4}&a, на срок &b{5}&a."
unset-meta-success: "&aСбросить метазначение с помощью ключа &f\"{0}&f\"&a для &b{1}&a."
unset-meta-server-success: "&aСбросить метазначение с помощью ключа &f\"{0}&f\"&a для &b{1}&a на сервере &b{2}&a."
unset-meta-server-world-success: "&aСбросить метазначение с помощью ключа &f\"{0}&f\"&a для &b{1}&a на сервере &b{2}&a, мире &b{3}&a."
unset-meta-temp-success: "&aUnset temporary meta value with key &f\"{0}&f\"&a для &b{1}&a."
unset-meta-temp-server-success: "&aСбросить временное мета-значение с помощью ключа &f\"{0}&f\"&a для &b{1}&a на сервере &b{2}&a."
unset-meta-temp-server-world-success: "&aСбросить временное мета-значение с помощью ключа &f\"{0}&f\"&a для &b{1}&a на сервере &b{2}&a, мире &b{3}&a."
bulk-change-type-error: "Недопустимый тип. ожидание 'server' или 'world'."
bulk-change-success: "&aПрименение изменения успешно. {0} записей изменено."
user-info-general: >
{PREFIX}&b&l> &bИнформация о пользователе: &f{0}\n
{PREFIX}&f- &3UUID: &f{1}\n
{PREFIX}&f- &3Статус: {2}\n
{PREFIX}&f- &3Первичная группа: &f{3}\n
{PREFIX}&f- &aГрафы:\n
{PREFIX}&f- &3Разрешения (пермы): &a{4}\n
{PREFIX}&f- &3Временные разрешения (пермы): &a{5}\n
{PREFIX}&f- &3Префиксы: &a{6}\n
{PREFIX}&f- &3Суффиксы: &a{7}\n
{PREFIX}&f- &3Meta: &a{8}
user-info-data: >
{PREFIX}&f- &aКэшированные данные:\n
{PREFIX}&f- &3Загружается: {0}\n
{PREFIX}&f- &3Текущие контексты: {1}\n
{PREFIX}&f- &3Текущие префиксы: {2}\n
{PREFIX}&f- &3Текущие суффиксы: {3}
info-parent-header: "&f- &aРодительские группы:"
info-temp-parent-header: "&f- &aВременные родительские группы:"
user-getuuid: "&bUUID для &b{0}&b это &b{1}&b."
user-removegroup-error-primary: "Вы не можете удалить пользователя из своей основной группы."
user-primarygroup-success: "&b{0}&a's для основной группы установил значение &b{1}&a."
user-primarygroup-warn-option: "&cВнимание: метод расчета основной группы, используемый этим сервером &7({0}) &cМожет не отражать это изменение."
user-primarygroup-error-alreadyhas: "Пользователь уже установил эту группу в качестве основной группы."
user-primarygroup-error-notmember: "&b{0}&a еще не был членом &b{1}&a, Добавить его сейчас."
user-track-error-not-contain-group: "Указанный пользователь не находится ни в каких группах на этом пути (track)."
user-track-added-to-first: "&b{0}&a Не находится ни в каких группах на этом пути (track), поэтому они были добавлены в первую группу, &b{1}&a."
user-track-added-to-first-server: "&b{0}&a Не находится ни в каких группах на этом пути (track), поэтому они были добавлены в первую группу, &b{1}&a, на сервере &b{2}&a."
user-track-added-to-first-server-world: "&b{0}&a Не находится ни в каких группах на этом пути (track), поэтому они были добавлены в первую группу, &b{1}&a, на сервере &b{2}&a, мире &b{3}&a."
user-promote-success: "&aПродвижение пользователя по пути (track) &b{0}&a от &b{1}&a к &b{2}&a."
user-promote-success-server: "&aПродвижение пользователя по пути (track) &b{0}&a от &b{1}&a к &b{2}&a на сервере &b{3}&a."
user-promote-success-server-world: "&aПродвижение пользователя по пути (track) &b{0}&a от &b{1}&a к &b{2}&a на сервере &b{3}&a, мире &b{4}&a."
user-promote-error-endoftrack: "Конец пути (track) &4{0}&c ,был достигнут. Не удалось продвинуть пользователя."
user-promote-error-malformed: >
{PREFIX}Следующая группа на пути (track), {0}, более не существует. Не удалось продвинуть пользователя.\n
{PREFIX}Создайте группу или удалите ее с пути (track) и повторите попытку.
user-demote-success: "&aПонижение пользователя по пути (track) &b{0}&a от &b{1}&a к &b{2}&a."
user-demote-success-server: "&aПонижение пользователя по пути (track) &b{0}&a от &b{1}&a к &b{2}&a на сервере &b{3}&a."
user-demote-success-server-world: "&aПонижение пользователя по пути (track) &b{0}&a от &b{1}&a к &b{2}&a на сервере &b{3}&a, мире &b{4}&a."
user-demote-endoftrack: "Конец пути (track) &4{0}&c был достингут, поэтому &4{1}&c был удален из &4{2}&c."
user-demote-error-malformed: >
{PREFIX}Предыдущая группа на пути (track), {0}, более не существуют. Невозможно понизить рейтинг пользователя.\n
{PREFIX}Создайте группу или удалите ее с пути (track) и повторите попытку.
user-showpos: >
&aпоказывает &b{0}&a's позицию на пути (track) &b{1}&a.\n
{2}
group-info-general: >
{PREFIX}&b&l> &bИнфо о группе: &f{0}\n
{PREFIX}&f- &3Отображаемое имя: &f{1}\n
{PREFIX}&f- &3Значение: &f{2}\n
{PREFIX}&f- &aГрафы:\n
{PREFIX}&f- &3Разрешения (пермы): &a{3}\n
{PREFIX}&f- &3Временные разрешения (пермы): &a{4}\n
{PREFIX}&f- &3Префиксы: &a{5}\n
{PREFIX}&f- &3Суффиксы: &a{6}\n
{PREFIX}&f- &3Meta: &a{7}
group-set-weight: "&aУстановить значение &b{0}&a для группы &b{1}&a."
track-info: >
{PREFIX}&b&l> &bпоказать путь (track): &f{0}\n
{PREFIX}&f- &7Путь: &f{1}
track-clear: "&b{0}&a's путь (track) групп был очищен."
track-append-success: "&aГруппа &b{0}&a успешно добавлен в путь (track) &b{1}&a."
track-insert-success: "&aГруппа &b{0}&a был успешно добавлен в путь (track) &b{1}&a на позиции &b{2}&a."
track-insert-error-number: "Ожидаемое число, но вместо этого получено: {0}"
track-insert-error-invalid-pos: "Невозможно вставить в позицию {0}. Индекс вне пределов."
track-remove-success: "&aгруппа &b{0}&a Успешно удален с пути (track) &b{1}&a."
log-load-error: "Не удалось загрузить лог."
log-invalid-page: "Недействительный номер страницы."
log-invalid-page-range: "Недопустимый номер страницы. Введите значение от 1 до {0}."
log-no-entries: "&bНет логов для отображения."
log-entry: "&b#{0} -> &8(&7{1} ago&8) {2}"
log-notify-toggle-on: "&aВключен&b вывод лога."
log-notify-toggle-off: "&cОтключен&b вывод лога."
log-notify-already-on: "Вы уже получаете оповещения."
log-notify-already-off: "Вы не получаете оповещений."
log-notify-unknown: "Состояние неизвестно. Ожидание \"on\" или \"off\"."
log-search-header: "&aПросмотр недавних действий для запроса &b{0} &a(page &f{1}&a of &f{2}&a)"
log-recent-header: "&aПоследние действия (page &f{0}&a of &f{1}&a)"
log-recent-by-header: "&aПоказывать последние действия &b{0} &a(page &f{1}&a of &f{2}&a)"
log-history-user-header: "&aОтображение истории для пользователя &b{0} &a(page &f{1}&a of &f{2}&a)"
log-history-group-header: "&aОтображение истории для группы &b{0} &a(page &f{1}&a of &f{2}&a)"
log-history-track-header: "&aОтображение истории для пути (track) &b{0} &a(page &f{1}&a of &f{2}&a)"
log-export-already-exists: "Ошибка: файл {0} уже существует."
log-export-not-writable: "Ошибка: файл {0} недоступен для записи."
log-export-empty: "Журнал пуст и поэтому не может быть экспортирован."
log-export-failure: "Произошла непредвиденная ошибка во время записи в файл."
log-export-success: "&aФайл журнала успешно экспортирован в &b{0}&a."
import-already-running: "Другой процесс импорта уже запущен. Дождитесь завершения и повторите попытку."
export-already-running: "Еще один процесс экспорта уже запущен. Дождитесь завершения и повторите попытку."
import-log-doesnt-exist: "Ошибка: файл {0} не существует."
import-log-not-readable: "Ошибка: файл {0} не читается."
import-log-failure: "Произошла непредвиденная ошибка при чтении лога."
import-progress: "&b(Импортировать) &b-> &f{0} &fПроцент завершен &7- &b{1}&f/&b{2} &fОперации в комплекте с &c{3} &fошибками."
import-progress-sin: "&b(Импортировать) &b-> &f{0} &fПроцент завершен &7- &b{1}&f/&b{2} &fОперации в комплекте с &c{3} &fошибками."
import-start: "&b(Импортировать) &b-> &fЗапуск процесса импорта."
import-end-complete: "&b(Импортировать) &a&lЗАВЕРШЕНО &7- заняло &b{0} &7секунд - &7Нет ошибок."
import-end-complete-err: "&b(Импортировать) &a&lЗАВЕРШЕНО &7- заняло &b{0} &7секунд - &c{1} ошибок."
import-end-complete-err-sin: "&b(Импортировать) &a&lЗАВЕРШЕНО &7- заняло &b{0} &7секунд - &c{1} ошибок."
import-end-error-header: >
{PREFIX}&b(Import) &7------------> &fОтображение ошибки #&b{0} &7<------------\n
{PREFIX}&b(Import) &fВыполняя: &3Команду #{1}\n
{PREFIX}&b(Import) &fКоманда: &7{2}\n
{PREFIX}&b(Import) &fТип: &3{3}\n
{PREFIX}&b(Import) &fВывод:
import-end-error-content: "&b(Импортировать) &b-> &c{0}"
import-end-error-footer: "&b(Импортировать) &7<------------------------------------------>"
+26
View File
@@ -0,0 +1,26 @@
### :speech_balloon: Looking for support?
Details about support for the project can be found [here, on the Wiki Homepage](https://github.com/lucko/LuckPerms/wiki#support).
### :bug: Reporting bugs?
Before reporting a bug or issue, please make sure that the issue is actually being caused by or related to LuckPerms. We get a lot of reports which are caused by other software - please double check!
If you're unsure, feel free to ask using the above resources BEFORE making a report.
Bugs or issues should be reported using the [GitHub Issues tab](https://github.com/lucko/LuckPerms/issues).
### :pencil: Want to contribute code?
#### Pull Requests
If you make any changes or improvements to the plugin which you think would be beneficial to others, please consider making a pull request to merge your changes back into the upstream project. (especially if your changes are bug fixes!)
LuckPerms loosely follows the [Google Java Style Guide](https://google.github.io/styleguide/javaguide.html). Generally, try to copy the style of code found in the class you're editing.
If you're considering submitting a substantial pull request, please open an issue so we can discuss the change before starting work on the contribution. Most pull requests are happily accepted, but larger changes may have an inpact on the maintainability of the project, and require more consideration.
#### Project Layout
The project is split up into 5 seperate modules.
* **API** - The public, semantically versioned API used by other plugins wishing to integrate with and retrieve data from LuckPerms. This module (for the most part) does not contain any implementation itself, and is provided by the plugin.
* **Common** - The common module contains most of the code which implements the respective LuckPerms plugins. This abstract module reduces duplicated code throughout the project.
* **Bukkit, BungeeCord & Sponge** - Each use the common module to implement plugins on the respective server platforms.
+3 -2
View File
@@ -1,6 +1,7 @@
MIT License
The MIT License.
Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
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
+26 -20
View File
@@ -1,44 +1,50 @@
![alt text](https://i.imgur.com/7TwJZ5e.png "Banner")
# LuckPerms [![Build Status](https://ci.lucko.me/job/LuckPerms/badge/icon)](https://ci.lucko.me/job/LuckPerms/)
# LuckPerms [![Build Status](https://ci.lucko.me/job/LuckPerms/badge/icon)](https://ci.lucko.me/job/LuckPerms/) [![Javadocs](https://javadoc.io/badge/me.lucko.luckperms/luckperms-api.svg)](https://javadoc.io/doc/me.lucko.luckperms/luckperms-api) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/me.lucko.luckperms/luckperms-api/badge.svg)](https://maven-badges.herokuapp.com/maven-central/me.lucko.luckperms/luckperms-api)
LuckPerms is an advanced permissions implementation aiming to be a fast, reliable and flexible alternative to existing permission plugins. The project's main goals are centered around high performance and a wide feature set, filling the gaps of functionality and building upon existing features found in other plugins.
LuckPerms also includes an extensive API for developers, and support for a variety of Minecraft server software & data storage options.
[See the charts below](https://github.com/lucko/LuckPerms#luckperms-vs-other-plugins) for a partial list of features & comparison with other providers.
* [Spigot Plugin Release Page](https://www.spigotmc.org/resources/luckperms-an-advanced-permissions-system.28140/ "Spigot Plugin Page")
* [Sponge Plugin Release Page](https://forums.spongepowered.org/t/luckperms-an-advanced-permissions-system/14274 "Sponge Plugin Page")
Still not convinced? More information can be found on the wiki, under: [Why LuckPerms?](https://github.com/lucko/LuckPerms/wiki/Why-LuckPerms)
## Useful Links
* **Development Builds** - <https://ci.lucko.me/job/LuckPerms>
* **Javadocs** - <https://luckperms.lucko.me/javadocs/>
* **Wiki** - <https://github.com/lucko/LuckPerms/wiki>
The latest **downloads** can be found on the [project's homepage](https://luckperms.github.io/).
More information about the project & how to use the plugin can be found in the [wiki](https://github.com/lucko/LuckPerms/wiki).
## Building
LuckPerms uses Maven to handle dependencies.
#### Requirements
* Maven 3.3.x (the older versions will not work.)
* Java 8 JDK or newer
* Maven 3.3.x or newer (the older versions will not work.)
* Git
#### Then run
#### Compiling from source
```sh
git clone https://github.com/lucko/LuckPerms.git
cd LuckPerms/
mvn clean package
```
You can find the output jars in the `target` directories.
## Contributing
#### Pull Requests
If you make any changes or improvements to the plugin which you think would be beneficial to others, please consider making a pull request to merge your changes back into the upstream project. (especially if your changes are bug fixes!)
LuckPerms loosely follows the [Google Java Style Guide](https://google.github.io/styleguide/javaguide.html). Generally, try to copy the style of code found in the class you're editing.
#### Project Layout
The project is split up into 5 seperate modules.
* **API** - The public, semantically versioned API used by other plugins wishing to integrate with and retrieve data from LuckPerms. This module (for the most part) does not contain any implementation itself, and is provided by the plugin.
* **Common** - The common module contains most of the code which implements the respective LuckPerms plugins. This abstract module reduces duplicated code throughout the project.
* **Bukkit, BungeeCord, Sponge & Nukkit** - Each use the common module to implement plugins on the respective server platforms.
## 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
### Bukkit
![alt text](https://luckperms.lucko.me/assets/bukkit-compare.png "Feature comparison")
### Sponge
![alt text](https://luckperms.lucko.me/assets/sponge-compare.png "Feature comparison")
## Thanks
[![JProfiler](https://www.ej-technologies.com/images/product_banners/jprofiler_large.png)](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").
+59 -1
View File
@@ -5,13 +5,23 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>3.1-SNAPSHOT</version>
<version>4.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>luckperms-api</artifactId>
<build>
<finalName>LuckPerms-API-${release.version}</finalName>
<resources>
<resource>
<directory>../</directory>
<filtering>false</filtering>
<includes>
<include>LICENSE.txt</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@@ -25,6 +35,47 @@
</plugins>
</build>
<profiles>
<profile>
<id>deployment</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
<configuration>
<links>
<link>https://google.github.io/guava/releases/21.0/api/docs/</link>
</links>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<dependencies>
<!-- guava -->
<dependency>
@@ -33,6 +84,13 @@
<version>19.0</version>
<scope>provided</scope>
</dependency>
<!-- jsr305 -->
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>3.0.2</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -26,46 +29,62 @@ import me.lucko.luckperms.api.LuckPermsApi;
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} safely.
* 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);
}
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;
}
/**
* Removes the current instance from this provider.
*/
static void unregisterProvider() {
api = null;
LuckPerms.instance = null;
}
private LuckPerms() {
@@ -0,0 +1,98 @@
/*
* 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 java.util.concurrent.CompletableFuture;
import javax.annotation.Nonnull;
/**
* Represents the object responsible for handling action logging.
*
* @since 4.1
*/
public interface ActionLogger {
/**
* Returns a new {@link LogEntry.Builder} instance
*
* @return a new builder
*/
@Nonnull
LogEntry.Builder newEntryBuilder();
/**
* Gets a {@link Log} instance from the plugin storage.
*
* @return a log instance
* @see Storage#getLog()
*/
@Nonnull
CompletableFuture<Log> getLog();
/**
* Submits a log entry to the plugin to be handled.
*
* <p>This method submits the log to the storage provider and broadcasts
* it.</p>
*
* <p>It is therefore roughly equivalent to calling
* {@link #submitToStorage(LogEntry)} and {@link #broadcastAction(LogEntry)},
* however, using this method is preferred to making the calls individually.</p>
*
* <p>If you want to submit a log entry but don't know which method to pick,
* use this one.</p>
*
* @param entry the entry to submit
* @return a future which will complete when the action is done
*/
@Nonnull
CompletableFuture<Void> submit(@Nonnull LogEntry entry);
/**
* Submits a log entry to the plugins storage handler.
*
* <p>Performs the same action as {@link Storage#logAction(LogEntry)}.</p>
*
* @param entry the entry to submit
* @return a future which will complete when the action is done
*/
@Nonnull
CompletableFuture<Void> submitToStorage(@Nonnull LogEntry entry);
/**
* Submits a log entry to the plugins log broadcasting handler.
*
* <p>If enabled, this method will also dispatch the log entry via the
* plugins {@link MessagingService}.</p>
*
* @param entry the entry to submit
* @return a future which will complete when the action is done
*/
@Nonnull
CompletableFuture<Void> broadcastAction(@Nonnull LogEntry entry);
}
@@ -0,0 +1,130 @@
/*
* 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 java.util.Map;
import java.util.Objects;
import java.util.Optional;
import javax.annotation.Nonnull;
/**
* Represents a type of chat meta
*
* @since 3.2
*/
public enum ChatMetaType {
/**
* Represents a prefix
*/
PREFIX("prefix") {
@Override
public boolean matches(@Nonnull Node node) {
return Objects.requireNonNull(node, "node").isPrefix();
}
@Nonnull
@Override
public Map.Entry<Integer, String> getEntry(@Nonnull Node node) {
return Objects.requireNonNull(node, "node").getPrefix();
}
},
/**
* Represents a suffix
*/
SUFFIX("suffix") {
@Override
public boolean matches(@Nonnull Node node) {
return Objects.requireNonNull(node, "node").isSuffix();
}
@Nonnull
@Override
public Map.Entry<Integer, String> getEntry(@Nonnull Node node) {
return Objects.requireNonNull(node, "node").getSuffix();
}
};
private final String str;
ChatMetaType(String str) {
this.str = str;
}
/**
* Returns if the passed node matches the type
*
* @param node the node to test
* @return true if the node has the same type
*/
public abstract boolean matches(@Nonnull Node node);
/**
* Returns if the passed node should be ignored when searching for meta of this type
*
* @param node the node to test
* @return true if the node does not share the same type
*/
public boolean shouldIgnore(@Nonnull Node node) {
return !matches(node);
}
/**
* Maps the corresponding entry from the given node
*
* @param node the node to retrieve the entry from
* @return the entry
* @throws IllegalStateException if the node does not share the same type
*/
@Nonnull
public abstract Map.Entry<Integer, String> getEntry(@Nonnull Node node);
@Override
public String toString() {
return this.str;
}
/**
* 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();
}
}
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -22,203 +25,329 @@
package me.lucko.luckperms.api;
import com.google.common.collect.ImmutableSet;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import java.util.EnumSet;
import java.util.Objects;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
/**
* Context and options for a permission lookup.
* Encapsulates the {@link ContextSet contexts} and {@link LookupSetting settings} for
* a permission or meta lookup.
*
* <p>All values are immutable.</p>
* <p>This class is immutable.</p>
*
* @since 2.11
*/
@Immutable
public class Contexts {
public static final String SERVER_KEY = "server";
public static final String WORLD_KEY = "world";
private static final Contexts ALLOW_ALL = new Contexts(ContextSet.empty(), true, true, true, true, true, true);
/**
* Gets a context that will allow all nodes
*
* @return a context that will not apply any filters
* 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";
/**
* The default {@link LookupSetting}s.
*/
private static final EnumSet<LookupSetting> DEFAULT_SETTINGS = EnumSet.of(
LookupSetting.INCLUDE_NODES_SET_WITHOUT_SERVER,
LookupSetting.INCLUDE_NODES_SET_WITHOUT_WORLD,
LookupSetting.RESOLVE_INHERITANCE,
LookupSetting.APPLY_PARENTS_SET_WITHOUT_SERVER,
LookupSetting.APPLY_PARENTS_SET_WITHOUT_WORLD
);
/**
* A 'global' or default contexts instance.
*
* <p>Formed of an empty {@link ContextSet} and all inclusion and
* inheritance {@link LookupSetting}s applied.</p>
*/
private static final Contexts GLOBAL = new Contexts(ImmutableContextSet.empty(), ImmutableSet.copyOf(DEFAULT_SETTINGS));
/**
* Gets the {@link FullySatisfiedContexts} instance.
*
* @return a context that will satisfy all contextual requirements.
*/
@Nonnull
public static Contexts allowAll() {
return ALLOW_ALL;
return FullySatisfiedContexts.getInstance();
}
public static Contexts of(ContextSet context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups, boolean op) {
return new Contexts(context, includeGlobal, includeGlobalWorld, applyGroups, applyGlobalGroups, applyGlobalWorldGroups, op);
/**
* Returns a 'global' or default contexts instance.
*
* <p>Formed of an empty {@link ContextSet} and all inclusion and
* inheritance {@link LookupSetting}s applied.</p>
*
* @return the global contexts
* @since 3.3
*/
@Nonnull
public static Contexts global() {
return GLOBAL;
}
/**
* Creates a new {@link Contexts} instance.
*
* @param contextSet the context set
* @param includeNodesSetWithoutServer the value of {@link LookupSetting#INCLUDE_NODES_SET_WITHOUT_SERVER}
* @param includeNodesSetWithoutWorld the value of {@link LookupSetting#INCLUDE_NODES_SET_WITHOUT_WORLD}
* @param resolveInheritance the value of {@link LookupSetting#RESOLVE_INHERITANCE}
* @param applyParentsWithoutServer the value of {@link LookupSetting#APPLY_PARENTS_SET_WITHOUT_SERVER}
* @param applyParentsWithoutWorld the value of {@link LookupSetting#APPLY_PARENTS_SET_WITHOUT_WORLD}
* @param isOp the value of {@link LookupSetting#IS_OP}
* @return a new instance
*/
@Nonnull
public static Contexts of(@Nonnull ContextSet contextSet, boolean includeNodesSetWithoutServer, boolean includeNodesSetWithoutWorld, boolean resolveInheritance, boolean applyParentsWithoutServer, boolean applyParentsWithoutWorld, boolean isOp) {
Objects.requireNonNull(contextSet, "contextSet");
EnumSet<LookupSetting> settings = formSettings(
includeNodesSetWithoutServer,
includeNodesSetWithoutWorld,
resolveInheritance,
applyParentsWithoutServer,
applyParentsWithoutWorld,
isOp
);
if (contextSet.isEmpty() && DEFAULT_SETTINGS.equals(settings)) {
return GLOBAL;
}
return new Contexts(contextSet.makeImmutable(), ImmutableSet.copyOf(settings));
}
/**
* Creates a new {@link Contexts} instance.
*
* @param contextSet the context set
* @param settings the settings
* @return a new instance
*/
public static Contexts of(@Nonnull ContextSet contextSet, @Nonnull Set<LookupSetting> settings) {
Objects.requireNonNull(contextSet, "contextSet");
Objects.requireNonNull(settings, "settings");
EnumSet<LookupSetting> settingsCopy = EnumSet.copyOf(settings);
if (contextSet.isEmpty() && DEFAULT_SETTINGS.equals(settingsCopy)) {
return GLOBAL;
}
return new Contexts(contextSet.makeImmutable(), ImmutableSet.copyOf(settingsCopy));
}
/**
* 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 contextSet;
/**
* The mode to parse defaults on Bukkit
* The settings for this lookup
*/
private final ImmutableSet<LookupSetting> settings;
// cache hashcode - this class is immutable, and is used as an index in the permission cache.
private final int hashCode;
/**
* Creates a new {@link Contexts} instance.
*
* @since 2.12
* @param contextSet the context set
* @param includeNodesSetWithoutServer the value of {@link LookupSetting#INCLUDE_NODES_SET_WITHOUT_SERVER}
* @param includeNodesSetWithoutWorld the value of {@link LookupSetting#INCLUDE_NODES_SET_WITHOUT_WORLD}
* @param resolveInheritance the value of {@link LookupSetting#RESOLVE_INHERITANCE}
* @param applyParentsWithoutServer the value of {@link LookupSetting#APPLY_PARENTS_SET_WITHOUT_SERVER}
* @param applyParentsWithoutWorld the value of {@link LookupSetting#APPLY_PARENTS_SET_WITHOUT_WORLD}
* @param isOp the value of {@link LookupSetting#IS_OP}
* @deprecated in favour of {@link #of(ContextSet, boolean, boolean, boolean, boolean, boolean, boolean)}
*/
private final boolean op;
@Deprecated
public Contexts(@Nonnull ContextSet contextSet, boolean includeNodesSetWithoutServer, boolean includeNodesSetWithoutWorld, boolean resolveInheritance, boolean applyParentsWithoutServer, boolean applyParentsWithoutWorld, boolean isOp) {
this.contextSet = Objects.requireNonNull(contextSet, "contextSet").makeImmutable();
this.settings = ImmutableSet.copyOf(formSettings(
includeNodesSetWithoutServer,
includeNodesSetWithoutWorld,
resolveInheritance,
applyParentsWithoutServer,
applyParentsWithoutWorld,
isOp
));
this.hashCode = calculateHashCode();
}
/**
* If global or non server specific nodes should be applied
*/
private final boolean includeGlobal;
/**
* If global or non world specific nodes should be applied
*/
private final boolean includeGlobalWorld;
/**
* If parent groups should be applied
*/
private final boolean applyGroups;
/**
* If global or non server specific group memberships should be applied
*/
private final boolean applyGlobalGroups;
/**
* If global or non world specific group memberships should be applied
*/
private final boolean applyGlobalWorldGroups;
public Contexts(ContextSet context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups, boolean op) {
if (context == null) {
throw new NullPointerException("context");
}
this.context = context.makeImmutable();
this.includeGlobal = includeGlobal;
this.includeGlobalWorld = includeGlobalWorld;
this.applyGroups = applyGroups;
this.applyGlobalGroups = applyGlobalGroups;
this.applyGlobalWorldGroups = applyGlobalWorldGroups;
this.op = op;
protected Contexts(@Nonnull ImmutableContextSet contextSet, @Nonnull ImmutableSet<LookupSetting> settings) {
this.contextSet = contextSet;
this.settings = settings;
this.hashCode = calculateHashCode();
}
/**
* Gets the contexts that apply for this lookup
* Gets the {@link ContextSet} which represent these {@link Contexts}.
*
* @return an immutable set of context key value pairs
* @return an immutable context from this instance
* @since 2.13
*/
@Nonnull
public ContextSet getContexts() {
return this.context;
return this.contextSet;
}
/**
* Gets if OP defaults should be included
* Gets the set of {@link LookupSetting}s which represent these {@link Contexts}.
*
* @return true if op defaults should be included
* @return the settings
* @since 4.2
*/
@Nonnull
public Set<LookupSetting> getSettings() {
return this.settings;
}
/**
* Gets if the given {@link LookupSetting} is set.
*
* @param setting the setting
* @return the value
* @since 4.2
*/
public boolean hasSetting(@Nonnull LookupSetting setting) {
return this.settings.contains(setting);
}
/**
* Gets the value of {@link LookupSetting#IS_OP}.
*
* @return the value
* @see LookupSetting#IS_OP
* @deprecated in favour of {@link #hasSetting(LookupSetting)}
*/
@Deprecated
public boolean isOp() {
return this.op;
return hasSetting(LookupSetting.IS_OP);
}
/**
* Gets if global or non server specific nodes should be applied
* Gets the value of {@link LookupSetting#INCLUDE_NODES_SET_WITHOUT_SERVER}.
*
* @return true if global or non server specific nodes should be applied
* @return the value
* @see LookupSetting#INCLUDE_NODES_SET_WITHOUT_SERVER
* @deprecated in favour of {@link #hasSetting(LookupSetting)}
*/
@Deprecated
public boolean isIncludeGlobal() {
return this.includeGlobal;
return hasSetting(LookupSetting.INCLUDE_NODES_SET_WITHOUT_SERVER);
}
/**
* Gets if global or non world specific nodes should be applied
* Gets the value of {@link LookupSetting#INCLUDE_NODES_SET_WITHOUT_WORLD}.
*
* @return true if global or non world specific nodes should be applied
* @return the value
* @see LookupSetting#INCLUDE_NODES_SET_WITHOUT_WORLD
* @deprecated in favour of {@link #hasSetting(LookupSetting)}
*/
@Deprecated
public boolean isIncludeGlobalWorld() {
return this.includeGlobalWorld;
return hasSetting(LookupSetting.INCLUDE_NODES_SET_WITHOUT_WORLD);
}
/**
* Gets if parent groups should be applied
* Gets the value of {@link LookupSetting#RESOLVE_INHERITANCE}.
*
* @return true if parent groups should be applied
* @return the value
* @see LookupSetting#RESOLVE_INHERITANCE
* @deprecated in favour of {@link #hasSetting(LookupSetting)}
*/
@Deprecated
public boolean isApplyGroups() {
return this.applyGroups;
return hasSetting(LookupSetting.RESOLVE_INHERITANCE);
}
/**
* Gets if global or non server specific group memberships should be applied
* Gets the value of {@link LookupSetting#APPLY_PARENTS_SET_WITHOUT_SERVER}.
*
* @return true if global or non server specific group memberships should be applied
* @return the value
* @see LookupSetting#APPLY_PARENTS_SET_WITHOUT_SERVER
* @deprecated in favour of {@link #hasSetting(LookupSetting)}
*/
@Deprecated
public boolean isApplyGlobalGroups() {
return this.applyGlobalGroups;
return hasSetting(LookupSetting.APPLY_PARENTS_SET_WITHOUT_SERVER);
}
/**
* Gets if global or non world specific group memberships should be applied
* Gets the value of {@link LookupSetting#APPLY_PARENTS_SET_WITHOUT_WORLD}.
*
* @return true if global or non world specific group memberships should be applied
* @return the value
* @see LookupSetting#APPLY_PARENTS_SET_WITHOUT_WORLD
* @deprecated in favour of {@link #hasSetting(LookupSetting)}
*/
@Deprecated
public boolean isApplyGlobalWorldGroups() {
return this.applyGlobalWorldGroups;
return hasSetting(LookupSetting.APPLY_PARENTS_SET_WITHOUT_WORLD);
}
@Nonnull
@Override
public String toString() {
return "Contexts(" +
"context=" + this.getContexts() + ", " +
"op=" + this.isOp() + ", " +
"includeGlobal=" + this.isIncludeGlobal() + ", " +
"includeGlobalWorld=" + this.isIncludeGlobalWorld() + ", " +
"applyGroups=" + this.isApplyGroups() + ", " +
"applyGlobalGroups=" + this.isApplyGlobalGroups() + ", " +
"applyGlobalWorldGroups=" + this.isApplyGlobalWorldGroups() +
")";
return "Contexts(contextSet=" + this.contextSet + ", settings=" + this.settings + ")";
}
/*
* Ugly auto-generated lombok code
*/
/**
* Check for equality
*
* @param o the other
* @return true if equal
* @since 2.12
*/
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (o == allowAll()) return false;
if (!(o instanceof Contexts)) return false;
final Contexts other = (Contexts) o;
return (this.getContexts() == null ? other.getContexts() == null : this.getContexts().equals(other.getContexts())) &&
this.isOp() == other.isOp() &&
this.isIncludeGlobal() == other.isIncludeGlobal() &&
this.isIncludeGlobalWorld() == other.isIncludeGlobalWorld() &&
this.isApplyGroups() == other.isApplyGroups() &&
this.isApplyGlobalGroups() == other.isApplyGlobalGroups() &&
this.isApplyGlobalWorldGroups() == other.isApplyGlobalWorldGroups();
final Contexts that = (Contexts) o;
return this.contextSet.equals(that.contextSet) && this.settings.equals(that.settings);
}
/**
* Gets the hashcode
*
* @return the hashcode
* @since 2.12
*/
public int hashCode() {
private int calculateHashCode() {
final int PRIME = 59;
int result = 1;
final Object contexts = this.getContexts();
result = result * PRIME + (contexts == null ? 43 : contexts.hashCode());
result = result * PRIME + (this.isOp() ? 79 : 97);
result = result * PRIME + (this.isIncludeGlobal() ? 79 : 97);
result = result * PRIME + (this.isIncludeGlobalWorld() ? 79 : 97);
result = result * PRIME + (this.isApplyGroups() ? 79 : 97);
result = result * PRIME + (this.isApplyGlobalGroups() ? 79 : 97);
result = result * PRIME + (this.isApplyGlobalWorldGroups() ? 79 : 97);
result = result * PRIME + this.contextSet.hashCode();
result = result * PRIME + this.settings.hashCode();
return result;
}
@Override
public int hashCode() {
return this.hashCode;
}
private static EnumSet<LookupSetting> formSettings(boolean includeNodesSetWithoutServer, boolean includeNodesSetWithoutWorld, boolean resolveInheritance, boolean applyParentsWithoutServer, boolean applyParentsWithoutWorld, boolean isOp) {
EnumSet<LookupSetting> settings = EnumSet.noneOf(LookupSetting.class);
if (includeNodesSetWithoutServer) {
settings.add(LookupSetting.INCLUDE_NODES_SET_WITHOUT_SERVER);
}
if (includeNodesSetWithoutWorld) {
settings.add(LookupSetting.INCLUDE_NODES_SET_WITHOUT_WORLD);
}
if (resolveInheritance) {
settings.add(LookupSetting.RESOLVE_INHERITANCE);
}
if (applyParentsWithoutServer) {
settings.add(LookupSetting.APPLY_PARENTS_SET_WITHOUT_SERVER);
}
if (applyParentsWithoutWorld) {
settings.add(LookupSetting.APPLY_PARENTS_SET_WITHOUT_WORLD);
}
if (isOp) {
settings.add(LookupSetting.IS_OP);
}
return settings;
}
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -22,44 +25,41 @@
package me.lucko.luckperms.api;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
/**
* Represents the result of a data mutation call on a LuckPerms object.
*
* <p>Usually as the result to a call on a {@link PermissionHolder} or {@link Track}.</p>
*/
public enum DataMutateResult implements MutateResult {
import java.util.function.Supplier;
/**
* Indicates the mutation was a success
*/
SUCCESS(true),
public enum DataMutateResult {
/**
* Indicates the mutation failed because the subject of the action already has something
*/
ALREADY_HAS(false),
SUCCESS(true, null),
ALREADY_HAS(false, ObjectAlreadyHasException::new),
LACKS(false, ObjectLacksException::new),
FAIL(false, RuntimeException::new);
/**
* Indicates the mutation failed because the subject of the action lacks something
*/
LACKS(false),
private boolean value;
private final Supplier<? extends Exception> exceptionSupplier;
/**
* Indicates the mutation failed
*/
FAIL(false);
DataMutateResult(boolean value, Supplier<? extends Exception> exceptionSupplier) {
this.value = value;
this.exceptionSupplier = exceptionSupplier;
private final boolean success;
DataMutateResult(boolean success) {
this.success = success;
}
public void throwException() {
if (exceptionSupplier != null) {
sneakyThrow(exceptionSupplier.get());
}
@Override
public boolean wasSuccess() {
return this.success;
}
public boolean asBoolean() {
return value;
}
// allows us to throw checked exceptions without declaring it, as #throwException throws a number of
// exception types.
private static void sneakyThrow(Throwable t) {
sneakyThrow0(t);
}
private static <T extends Throwable> void sneakyThrow0(Throwable t) throws T {
throw (T) t;
}
}
@@ -0,0 +1,130 @@
/*
* 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 java.util.Optional;
import javax.annotation.Nonnull;
/**
* Encapsulates the result of {@link User}s demotion along a {@link Track}.
*
* @since 4.2
*/
public interface DemotionResult extends MutateResult {
/**
* Gets the status of the result.
*
* @return the status
*/
@Nonnull
Status getStatus();
@Override
default boolean wasSuccess() {
return getStatus().wasSuccess();
}
/**
* Gets the name of the group the user was demoted from, if applicable.
*
* <p>Will only be present for results with a {@link #getStatus() status} of
* {@link Status#SUCCESS} or {@link Status#REMOVED_FROM_FIRST_GROUP}.</p>
*
* <p>The value will also be set for results with the {@link Status#MALFORMED_TRACK} status,
* with this value marking the group which no longer exists.</p>
*
* @return the group the user was demoted from.
*/
@Nonnull
Optional<String> getGroupFrom();
/**
* Gets the name of the group the user was demoted from, if applicable.
*
* <p>Will only be present for results with a {@link #getStatus() status} of
* {@link Status#SUCCESS}.</p>
*
* @return the group the user was demoted to.
*/
@Nonnull
Optional<String> getGroupTo();
/**
* The result status
*/
enum Status implements MutateResult {
/**
* Indicates that the user was demoted normally.
*/
SUCCESS(true),
/**
* Indicates that the user was removed from the first group in the track.
*
* <p>This usually occurs when the user is currently on the first group, and was demoted
* "over the start" of the track.</p>
*/
REMOVED_FROM_FIRST_GROUP(true),
/**
* Indicates that the previous group in the track no longer exists.
*/
MALFORMED_TRACK(false),
/**
* Indicates that the user isn't a member of any of the groups on this track.
*/
NOT_ON_TRACK(false),
/**
* Indicates that the implementation was unable to determine the users current position on
* this track.
*
* <p>This usually occurs when the user is on more than one group on the track.</p>
*/
AMBIGUOUS_CALL(false),
/**
* An undefined failure occurred.
*/
UNDEFINED_FAILURE(false);
private final boolean success;
Status(boolean success) {
this.success = success;
}
@Override
public boolean wasSuccess() {
return this.success;
}
}
}
@@ -0,0 +1,87 @@
/*
* 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 java.util.UUID;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Represents an entity on the server.
*
* <p>This does not relate directly to a "Minecraft Entity". The closest
* comparison is to a "CommandSender" or "CommandSource" in Bukkit/Sponge.</p>
*
* <p>The various types of {@link Entity} are detailed in {@link Type}.</p>
*
* @since 4.1
*/
public interface Entity {
/**
* Gets the unique id of the entity, if it has one.
*
* <p>For players, this returns their uuid assigned by the server.</p>
*
* @return the uuid of the object, if available
*/
@Nullable
UUID getUniqueId();
/**
* Gets the name of the object
*
* @return the object name
*/
@Nonnull
String getName();
/**
* Gets the entities type.
*
* @return the type
*/
@Nonnull
Type getType();
/**
* The different types of {@link Entity}
*/
enum Type {
/**
* Represents a player connected to the server
*/
PLAYER,
/**
* Represents the server console
*/
CONSOLE
}
}
@@ -0,0 +1,83 @@
/*
* 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 com.google.common.collect.ImmutableSet;
import me.lucko.luckperms.api.caching.CachedData;
import me.lucko.luckperms.api.caching.MetaContexts;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import javax.annotation.Nonnull;
/**
* A special instance of {@link Contexts}, which when passed to:
*
* <p></p>
* <ul>
* <li>{@link CachedData#getPermissionData(Contexts)}</li>
* <li>{@link CachedData#getMetaData(Contexts)}</li>
* <li>{@link CachedData#getMetaData(MetaContexts)}</li>
* </ul>
*
* <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
public static Contexts getInstance() {
return INSTANCE;
}
private FullySatisfiedContexts() {
super(ImmutableContextSet.empty(), ImmutableSet.copyOf(Contexts.global().getSettings()));
}
@Nonnull
@Override
public String toString() {
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);
}
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -22,14 +25,14 @@
package me.lucko.luckperms.api;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import me.lucko.luckperms.api.caching.GroupData;
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 {
@@ -38,249 +41,26 @@ public interface Group extends PermissionHolder {
*
* @return the name of the group
*/
@Nonnull
String getName();
/**
* Check to see if a group inherits a group
*
* @param group The group to check membership of
* @return true if the group inherits the other group
* @throws NullPointerException if the group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
*/
boolean inheritsGroup(Group group);
/**
* 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
*/
boolean inheritsGroup(Group group, 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
*/
boolean inheritsGroup(Group group, String server, 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(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(Group group, 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(Group group, String server, 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(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(Group group, 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(Group group, String server, 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(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(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(Group group, 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(Group group, String server, 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(Group group, 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(Group group, String server, 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
*/
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
*/
List<String> getLocalGroups(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
*/
List<String> getLocalGroups(String server, String world);
/**
* Gets the weight of this group, is present.
* Gets the weight of this group, if present.
*
* @return the group weight
* @since 2.17
*/
@Nonnull
OptionalInt getWeight();
/**
* Gets the groups's {@link GroupData} cache.
*
* @return the groups cached data.
* @since 4.0
*/
@Nonnull
@Override
GroupData getCachedData();
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -22,17 +25,21 @@
package me.lucko.luckperms.api;
import com.google.common.collect.Multimap;
import me.lucko.luckperms.api.context.ContextSet;
import java.util.Optional;
import java.util.OptionalLong;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
/**
* A relationship between a Holder and a permission
* A relationship between a {@link PermissionHolder} and a permission.
*
* @param <T> the identifier type of the holder
* @since 2.17
*/
@Immutable
public interface HeldPermission<T> {
/**
@@ -40,6 +47,7 @@ public interface HeldPermission<T> {
*
* @return the holder
*/
@Nonnull
T getHolder();
/**
@@ -47,6 +55,7 @@ public interface HeldPermission<T> {
*
* @return the permission
*/
@Nonnull
String getPermission();
/**
@@ -61,6 +70,7 @@ public interface HeldPermission<T> {
*
* @return the server
*/
@Nonnull
Optional<String> getServer();
/**
@@ -68,6 +78,7 @@ public interface HeldPermission<T> {
*
* @return the world
*/
@Nonnull
Optional<String> getWorld();
/**
@@ -78,17 +89,18 @@ 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
*/
Multimap<String, String> getContext();
ContextSet getContexts();
/**
* Converts this permission into a Node
*
* @return a Node copy of this permission
*/
@Nonnull
Node asNode();
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -22,145 +25,98 @@
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
*/
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
*/
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
*/
@Nonnull
Map<String, String> getSplitStorageOptions();
@Nonnull
Unsafe unsafe();
interface Unsafe {
/**
* Gets an Object from the config.
*
* <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 field name in
* the "ConfigKeys" class.
* @return the corresponding object, if one is present
* @throws IllegalArgumentException if the key isn't known
*/
@Nonnull
Object getObject(String key);
}
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -22,11 +25,15 @@
package me.lucko.luckperms.api;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
/**
* A node with a traceable origin
*
* @since 2.11
*/
@Immutable
public interface LocalizedNode extends Node {
/**
@@ -34,6 +41,7 @@ public interface LocalizedNode extends Node {
*
* @return the node this instance is representing
*/
@Nonnull
Node getNode();
/**
@@ -42,6 +50,7 @@ public interface LocalizedNode extends Node {
* @return where the node was inherited from. Will not return null.
* @see PermissionHolder#getObjectName()
*/
@Nonnull
String getLocation();
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -26,22 +29,36 @@ import java.util.SortedMap;
import java.util.SortedSet;
import java.util.UUID;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
/**
* 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>
*/
@Immutable
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
SortedSet<LogEntry> getRecent();
/**
@@ -50,120 +67,150 @@ 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
*/
SortedSet<LogEntry> getRecent(UUID actor);
@Nonnull
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)}
*/
SortedMap<Integer, LogEntry> getRecent(int pageNo, UUID actor);
@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
*/
int getRecentMaxPages(UUID actor);
int getRecentMaxPages(@Nonnull UUID actor);
/**
* 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
*/
SortedSet<LogEntry> getUserHistory(UUID uuid);
@Nonnull
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)}
*/
SortedMap<Integer, LogEntry> getUserHistory(int pageNo, UUID 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
*/
int getUserHistoryMaxPages(UUID uuid);
int getUserHistoryMaxPages(@Nonnull UUID uuid);
/**
* 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
*/
SortedSet<LogEntry> getGroupHistory(String name);
@Nonnull
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)}
*/
SortedMap<Integer, LogEntry> getGroupHistory(int pageNo, String name);
@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
*/
int getGroupHistoryMaxPages(String name);
int getGroupHistoryMaxPages(@Nonnull String name);
/**
* 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
*/
SortedSet<LogEntry> getTrackHistory(String name);
@Nonnull
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)}
*/
SortedMap<Integer, LogEntry> getTrackHistory(int pageNo, String name);
@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(String name);
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
*/
SortedSet<LogEntry> getSearch(String query);
@Nonnull
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
@@ -171,11 +218,15 @@ public interface Log {
* @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 #getSearchMaxPages(String)}}
*/
SortedMap<Integer, LogEntry> getSearch(int pageNo, String query);
@Nonnull
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(String query);
int getSearchMaxPages(@Nonnull String query);
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -22,297 +25,204 @@
package me.lucko.luckperms.api;
import java.util.Optional;
import java.util.UUID;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
/**
* A single entry in the log
* Represents a logged action.
*
* <p>Implements {@link Comparable} ordering based upon the timestamp of the entry.</p>
* @see ActionLogger#newEntryBuilder() for creating an instance
*/
public class LogEntry implements Comparable<LogEntry> {
private static final String FORMAT = "&8(&e%s&8) [&a%s&8] (&b%s&8) &7--> &f%s";
@Immutable
public interface LogEntry extends Comparable<LogEntry> {
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
*/
@Nonnull
UUID getActor();
public LogEntry(long timestamp, UUID actor, String actorName, char type, UUID acted, String actedName, 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
*/
@Nonnull
String getActorName();
/**
* Gets the type of action.
*
* @return the action type
*/
@Nonnull
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
*/
@Nonnull
Optional<UUID> getActed();
/**
* Gets the name describing the object which was acted upon
*
* @return the name of the acted object
*/
@Nonnull
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
*/
@Nonnull
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(String query) {
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),
actedName,
action
);
}
public long getTimestamp() {
return timestamp;
}
void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
public UUID getActor() {
return actor;
}
void setActor(UUID actor) {
this.actor = actor;
}
public String getActorName() {
return actorName;
}
void setActorName(String actorName) {
this.actorName = actorName;
}
public char getType() {
return type;
}
void setType(char type) {
this.type = type;
}
public UUID getActed() {
return acted;
}
void setActed(UUID acted) {
this.acted = acted;
}
public String getActedName() {
return actedName;
}
void setActedName(String actedName) {
this.actedName = actedName;
}
public String getAction() {
return action;
}
void setAction(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");
@Nonnull
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 {
/**
* Sets the timestamp of the entry.
*
* @param timestamp the timestamp
* @return the builder
* @see LogEntry#getTimestamp()
*/
@Nonnull
Builder setTimestamp(long timestamp);
/**
* Sets the actor of the entry.
*
* @param actor the actor
* @return the builder
* @see LogEntry#getActor()
*/
@Nonnull
Builder setActor(@Nonnull UUID actor);
/**
* Sets the actor name of the entry.
*
* @param actorName the actor name
* @return the builder
* @see LogEntry#getActorName()
*/
@Nonnull
Builder setActorName(@Nonnull String actorName);
/**
* Sets the type of the entry.
*
* @param type the type
* @return the builder
* @see LogEntry#getType()
*/
@Nonnull
Builder setType(@Nonnull Type type);
/**
* Sets the acted object for the entry.
*
* @param acted the acted object
* @return the builder
* @see LogEntry#getActed()
*/
@Nonnull
Builder setActed(@Nullable UUID acted);
/**
* Sets the acted name for the entry.
*
* @param actedName the acted name
* @return the builder
* @see LogEntry#getActedName()
*/
@Nonnull
Builder setActedName(@Nonnull String actedName);
/**
* Sets the action of the entry.
*
* @param action the action
* @return the builder
* @see LogEntry#getAction()
*/
@Nonnull
Builder setAction(@Nonnull String action);
/**
* Creates a {@link LogEntry} instance from the builder.
*
* @return a new log entry instance
*/
@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() +
")";
}
}
}
@@ -0,0 +1,64 @@
/*
* 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;
/**
* The various lookup setting flags for {@link Contexts}.
*
* @since 4.2
*/
public enum LookupSetting {
/**
* If the target subject is OP
*/
IS_OP,
/**
* If global or non-server-specific nodes should be applied
*/
INCLUDE_NODES_SET_WITHOUT_SERVER,
/**
* If global or non-world-specific nodes should be applied
*/
INCLUDE_NODES_SET_WITHOUT_WORLD,
/**
* If parent groups should be resolved
*/
RESOLVE_INHERITANCE,
/**
* If global or non-server-specific group memberships should be applied
*/
APPLY_PARENTS_SET_WITHOUT_SERVER,
/**
* If global or non-world-specific group memberships should be applied
*/
APPLY_PARENTS_SET_WITHOUT_WORLD
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -22,87 +25,237 @@
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.messenger.MessengerProvider;
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 {
/**
* Schedules an update task to run
* Gets information about the platform LuckPerms is running on.
*
* @return the platform info
* @since 4.0
*/
void runUpdateTask();
@Nonnull
PlatformInfo getPlatformInfo();
/**
* Gets the API version
* @return the version of the API running on the platform
* @since 2.6
* Gets the {@link UserManager}, responsible for managing
* {@link User} instances.
*
* <p>This manager can be used to retrieve instances of {@link User} by uuid
* or name, or query all loaded users.</p>
*
* <p>The {@link #getStorage() storage} instance should be used to
* load/create/save users.</p>
*
* @return the user manager
* @since 4.0
*/
double getApiVersion();
@Nonnull
UserManager getUserManager();
/**
* Gets the plugin version
* @return the version of the plugin running on the platform
* Gets the {@link GroupManager}, responsible for managing
* {@link Group} instances.
*
* <p>This manager can be used to retrieve instances of {@link Group} by
* name, or query all loaded groups.</p>
*
* <p>The {@link #getStorage() storage} instance should be used to
* load/create/save/delete groups.</p>
*
* @return the group manager
* @since 4.0
*/
String getVersion();
@Nonnull
GroupManager getGroupManager();
/**
* Gets the platform LuckPerms is running on
* @return the platform LuckPerms is running on
* @since 2.7
* Gets the {@link TrackManager}, responsible for managing
* {@link Track} instances.
*
* <p>This manager can be used to retrieve instances of {@link Track} by
* name, or query all loaded tracks.</p>
*
* <p>The {@link #getStorage() storage} instance should be used to
* load/create/save/delete tracks.</p>
*
* @return the track manager
* @since 4.0
*/
PlatformType getPlatformType();
@Nonnull
TrackManager getTrackManager();
/**
* Gets the event bus, used for subscribing to events
* Schedules the execution of an update task, and returns an encapsulation
* of the task as a {@link CompletableFuture}.
*
* <p>The exact actions performed in an update task remains an
* implementation detail of the plugin, however, as a minimum, it is
* expected to perform a full reload of user, group and track data, and
* ensure that any changes are fully applied and propagated.</p>
*
* @return a future
* @since 4.0
*/
@Nonnull
CompletableFuture<Void> runUpdateTask();
/**
* Gets the {@link EventBus}, used for subscribing to internal LuckPerms
* events.
*
* @return the event bus
* @since 3.0
*/
@Nonnull
EventBus getEventBus();
/**
* Gets a wrapped {@link LPConfiguration} instance, with read only access
* Gets a representation of the plugins configuration
*
* @return a configuration instance
* @return the configuration
*/
@Nonnull
LPConfiguration getConfiguration();
/**
* Gets a wrapped {@link Storage} instance.
* Gets an object representing the plugins primary {@link Storage} backend.
*
* <p>The instance propagates calls to the internal DAO (Data Access Object),
* and applies any changes to the storage provider.</p>
*
* @return a storage instance
* @since 2.14
*/
@Nonnull
Storage getStorage();
/**
* Gets the messaging service in use on the platform, if present.
* Gets the {@link MessagingService}, if present.
*
* @return an optional that may contain a messaging service instance.
* <p>The MessagingService is used to dispatch updates throughout a network
* of servers running the plugin.</p>
*
* <p>Not all instances of LuckPerms will have a messaging service setup and
* configured, but it is recommended that all users of the API account for
* and make use of this.</p>
*
* @return the messaging service instance, if present.
*/
@Nonnull
Optional<MessagingService> getMessagingService();
/**
* Gets the {@link Logger} wrapping used by the platform
* Registers a {@link MessengerProvider} for use by the platform.
*
* @return the logger instance
* <p>Note that the mere action of registering a provider doesn't
* necessarily mean that it will be used.</p>
*
* @param messengerProvider the messenger provider.
* @since 4.1
*/
Logger getLogger();
void registerMessengerProvider(@Nonnull MessengerProvider messengerProvider);
/**
* Gets a wrapped {@link UuidCache} instance, providing read access to the LuckPerms internal uuid caching system
* Gets the {@link ActionLogger}.
*
* @return a uuid cache instance
* <p>The action logger is responsible for saving and broadcasting defined
* actions occurring on the platform.</p>
*
* @return the action logger
* @since 4.1
*/
ActionLogger getActionLogger();
/**
* Gets a {@link UuidCache}.
*
* <p>The uuid cache provides read access to the internal LuckPerms uuid
* mapping system.</p>
*
* @return the uuid cache
* @deprecated this feature is now handled internally - and the API returns a
* No-op implementation of this class.
*/
@Nonnull
@Deprecated
UuidCache getUuidCache();
/**
* Gets the {@link ContextManager}.
*
* <p>The context manager manages {@link ContextCalculator}s, and calculates
* applicable contexts for a given type.</p>
*
* @return the context manager
* @since 4.0
*/
ContextManager getContextManager();
/**
* Gets the {@link NodeFactory}.
*
* <p>The node factory provides methods for building {@link Node} instances.</p>
*
* @return the node factory
*/
@Nonnull
NodeFactory getNodeFactory();
/**
* Gets the {@link MetaStackFactory}.
*
* <p>The metastack factory provides methods for retrieving
* {@link me.lucko.luckperms.api.metastacking.MetaStackElement}s and constructing
* {@link me.lucko.luckperms.api.metastacking.MetaStackDefinition}s.</p>
*
* @return the meta stack factory
* @since 3.2
*/
@Nonnull
MetaStackFactory getMetaStackFactory();
/*
* The following methods are provided only for convenience, and offer no
* additional functionality.
*
* They are implemented as "default" methods, using the manager and factory
* instances provided by the methods above.
*/
/**
* Gets a wrapped user object from the user storage
*
@@ -110,18 +263,22 @@ public interface LuckPermsApi {
* @return a {@link User} object, if one matching the uuid is loaded, or null if not
* @throws NullPointerException if the uuid is null
*/
User getUser(UUID uuid);
@Nullable
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
*/
Optional<User> getUserSafe(UUID uuid);
@Nonnull
default Optional<User> getUserSafe(@Nonnull UUID uuid) {
return getUserManager().getUserOpt(uuid);
}
/**
* Gets a wrapped user object from the user storage
@@ -130,25 +287,32 @@ public interface LuckPermsApi {
* @return a {@link User} object, if one matching the uuid is loaded, or null if not
* @throws NullPointerException if the name is null
*/
User getUser(String name);
@Nullable
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
*/
Optional<User> getUserSafe(String name);
@Nonnull
default Optional<User> getUserSafe(@Nonnull String name) {
return getUserManager().getUserOpt(name);
}
/**
* Gets a set of all loaded users.
*
* @return a {@link Set} of {@link User} objects
*/
Set<User> getUsers();
@Nonnull
default Set<User> getUsers() {
return getUserManager().getLoadedUsers();
}
/**
* Check if a user is loaded in memory
@@ -157,16 +321,19 @@ public interface LuckPermsApi {
* @return true if the user is loaded
* @throws NullPointerException if the uuid is null
*/
boolean isUserLoaded(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(User user);
default void cleanupUser(@Nonnull User user) {
getUserManager().cleanupUser(user);
}
/**
* Gets a wrapped group object from the group storage
@@ -175,7 +342,10 @@ public interface LuckPermsApi {
* @return a {@link Group} object, if one matching the name exists, or null if not
* @throws NullPointerException if the name is null
*/
Group getGroup(String name);
@Nullable
default Group getGroup(@Nonnull String name) {
return getGroupManager().getGroup(name);
}
/**
* Gets a wrapped group object from the group storage.
@@ -186,14 +356,20 @@ public interface LuckPermsApi {
* @return an optional {@link Group} object
* @throws NullPointerException if the name is null
*/
Optional<Group> getGroupSafe(String name);
@Nonnull
default Optional<Group> getGroupSafe(@Nonnull String name) {
return getGroupManager().getGroupOpt(name);
}
/**
* Gets a set of all loaded groups.
*
* @return a {@link Set} of {@link Group} objects
*/
Set<Group> getGroups();
@Nonnull
default Set<Group> getGroups() {
return getGroupManager().getLoadedGroups();
}
/**
* Check if a group is loaded in memory
@@ -202,16 +378,22 @@ public interface LuckPermsApi {
* @return true if the group is loaded
* @throws NullPointerException if the name is null
*/
boolean isGroupLoaded(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
*/
Track getTrack(String name);
@Nullable
default Track getTrack(@Nonnull String name) {
return getTrackManager().getTrack(name);
}
/**
* Gets a wrapped track object from the track storage.
@@ -222,14 +404,20 @@ public interface LuckPermsApi {
* @return an optional {@link Track} object
* @throws NullPointerException if the name is null
*/
Optional<Track> getTrackSafe(String name);
@Nonnull
default Optional<Track> getTrackSafe(@Nonnull String name) {
return getTrackManager().getTrackOpt(name);
}
/**
* Gets a set of all loaded tracks.
*
* @return a {@link Set} of {@link Track} objects
*/
Set<Track> getTracks();
@Nonnull
default Set<Track> getTracks() {
return getTrackManager().getLoadedTracks();
}
/**
* Check if a track is loaded in memory
@@ -238,14 +426,20 @@ public interface LuckPermsApi {
* @return true if the track is loaded
* @throws NullPointerException if the name is null
*/
boolean isTrackLoaded(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
*/
NodeFactory getNodeFactory();
@Nonnull
default LogEntry.Builder newLogEntryBuilder() {
return getActionLogger().newEntryBuilder();
}
/**
* Returns a permission builder instance
@@ -256,15 +450,20 @@ public interface LuckPermsApi {
* @throws NullPointerException if the permission is null
* @since 2.6
*/
Node.Builder buildNode(String permission) throws IllegalArgumentException;
@Nonnull
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(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.
@@ -274,7 +473,10 @@ public interface LuckPermsApi {
* @param user the user to get contexts for
* @return an optional containing contexts. Will return empty if the user is not online.
*/
Optional<Contexts> getContextForUser(User user);
@Nonnull
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.
@@ -283,6 +485,21 @@ public interface LuckPermsApi {
* @return a set of contexts.
* @since 2.17
*/
ContextSet getContextForPlayer(Object player);
@Nonnull
default ContextSet getContextForPlayer(@Nonnull Object player) {
return getContextManager().getApplicableContext(player);
}
/**
* Gets a Contexts instance for the player using the platforms {@link ContextCalculator}s.
*
* @param player the player to calculate for. Must be the player instance for the platform.
* @return a set of contexts.
* @since 3.3
*/
@Nonnull
default Contexts getContextsForPlayer(@Nonnull Object player) {
return getContextManager().getApplicableContexts(player);
}
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -22,6 +25,8 @@
package me.lucko.luckperms.api;
import javax.annotation.Nonnull;
/**
* A means to push changes to other servers using the platforms networking
*
@@ -30,11 +35,42 @@ package me.lucko.luckperms.api;
public interface MessagingService {
/**
* Uses the messaging service to inform other servers about changes.
* Gets the name of this messaging service
*
* <p>This will push the update asynchronously, and this method will return immediately. Calling this method is
* equivalent to running "/lp networksync", except will not sync this server.</p>
* @return the name of this messaging service
* @since 4.1
*/
String getName();
/**
* Uses the messaging service to inform other servers about a general
* change.
*
* <p>The standard response by other servers will be to execute a overall
* sync of all live data, equivalent to calling
* {@link LuckPermsApi#runUpdateTask()}.</p>
*
* <p>This will push the update asynchronously, and this method will return
* immediately. Note that this method will not cause an update to be
* processed on the local server.</p>
*/
void pushUpdate();
/**
* Uses the messaging service to inform other servers about a change to a
* specific user.
*
* <p>The standard response by other servers is undefined, however the
* current implementation will reload the corresponding users data if they
* are online.</p>
*
* <p>This will push the update asynchronously, and this method will return
* immediately. Note that this method will not cause an update to be
* processed on the local server.</p>
*
* @param user the user to push the update for
* @since 4.1
*/
void pushUserUpdate(@Nonnull User user);
}
@@ -1,283 +0,0 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api;
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() {
}
}
@@ -0,0 +1,74 @@
/*
* 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;
/**
* Represents the result to a "mutation" on an object.
*
* @since 4.2
*/
public interface MutateResult {
/**
* Instance of {@link MutateResult} which always reports success.
*/
MutateResult GENERIC_SUCCESS = () -> true;
/**
* Instance of {@link MutateResult} which always reports failure.
*/
MutateResult GENERIC_FAILURE = () -> false;
/**
* Gets if the operation which produced this result completed successfully.
*
* @return if the result indicates a success
*/
boolean wasSuccess();
/**
* Gets if the operation which produced this result failed.
*
* @return if the result indicates a failure
*/
default boolean wasFailure() {
return !wasSuccess();
}
/**
* Gets a boolean representation of the result.
*
* <p>A value of <code>true</code> marks that the operation {@link #wasSuccess() was a success}
* and a value of <code>false</code> marks that the operation
* {@link #wasFailure() was a failure}.</p>
*
* @return a boolean representation
*/
default boolean asBoolean() {
return wasSuccess();
}
}
+475 -162
View File
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -22,84 +25,171 @@
package me.lucko.luckperms.api;
import com.google.common.base.Preconditions;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.nodetype.NodeType;
import me.lucko.luckperms.api.nodetype.NodeTypeKey;
import me.lucko.luckperms.api.nodetype.types.DisplayNameType;
import me.lucko.luckperms.api.nodetype.types.InheritanceType;
import me.lucko.luckperms.api.nodetype.types.MetaType;
import me.lucko.luckperms.api.nodetype.types.PrefixType;
import me.lucko.luckperms.api.nodetype.types.SuffixType;
import me.lucko.luckperms.api.nodetype.types.WeightType;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
/**
* An immutable permission node
* Represents a LuckPerms "node".
*
* <p>Use {@link LuckPermsApi#buildNode(String)} to get an instance.</p>
* <p>The {@link Node} class encapsulates more than just permission assignments.
* Nodes are used to store data about inherited groups, as well as assigned
* prefixes, suffixes and meta values.</p>
*
* <p>Combining these various states into one object (a "node") means that a
* holder only has to have one type of data set (a set of nodes) in order to
* take on various properties.</p>
*
* <p>It is recommended that users of the API make use of {@link Stream}s
* to manipulate data and obtain the required information.</p>
*
* <p>This interface provides a number of methods to read the attributes of the
* node, as well as methods to query and extract additional state and properties
* from these settings.</p>
*
* <p>Nodes have the following attributes:</p>
* <p></p>
* <ul>
* <li>{@link #getPermission() permission} - the actual permission string</li>
* <li>{@link #getValue() value} - the value of the node (false for negated)</li>
* <li>{@link #isOverride() override} - if the node is marked as having special priority over other nodes</li>
* <li>{@link #getServer() server} - the specific server where this node should apply</li>
* <li>{@link #getWorld() world} - the specific world where this node should apply</li>
* <li>{@link #getContexts() context} - the additional contexts required for this node to apply </li>
* <li>{@link #getExpiry() expiry} - the time when this node should expire</li>
* </ul>
*
* <p>The 'permission' property of a {@link Node} is also used in some cases to represent state
* beyond a granted permission. This state is encapsulated by extra {@link NodeType} data which
* can be obtained from this instance using {@link #getTypeData(NodeTypeKey)}.</p>
*
* <p>Type data is mapped by {@link NodeTypeKey}s, which are usually stored as static members of the
* corresponding {@link NodeType} class under the <code>KEY</code> field.</p>
*
* <p>The current types are:</p>
* <p></p>
* <ul>
* <li>normal - just a regular permission</li>
* <li>{@link InheritanceType} - an "inheritance node" marks that the holder should inherit data from another group</li>
* <li>{@link PrefixType} - represents an assigned prefix</li>
* <li>{@link SuffixType} - represents an assigned suffix</li>
* <li>{@link MetaType} - represents an assigned meta option</li>
* <li>{@link WeightType} - marks the weight of the object holding this node</li>
* <li>{@link DisplayNameType} - marks the display name of the object holding this node</li>
* </ul>
*
* <p>The core node state must be immutable in all implementations.</p>
*
* @see NodeFactory for obtaining and constructing instances.
* @since 2.6
*/
public interface Node extends Map.Entry<String, Boolean> {
@Immutable
public interface Node {
/**
* Gets the permission string this node encapsulates.
*
* <p>The exact value of this string may vary for nodes which aren't regular
* permission settings.</p>
*
* @return the actual permission node
*/
@Nonnull
String getPermission();
/**
* Get what value the permission is set to. A negated node would return <code>false</code>.
* Gets the value of the node.
*
* @return the permission's value
* <p>A negated setting would result in a value of <code>false</code>.</p>
*
* @return the nodes value
*/
@Override
Boolean getValue();
boolean getValue();
/**
* Gets the value of this node as a {@link Tristate}.
*
* @return the value of this node as a Tristate
*/
Tristate getTristate();
@Nonnull
default Tristate getTristate() {
return Tristate.fromBoolean(getValue());
}
/**
* Gets if the node is negated.
*
* <p>This is the inverse of the {@link #getValue() value}.</p>
*
* @return true if the node is negated
*/
boolean isNegated();
default boolean isNegated() {
return !getValue();
}
/**
* 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
*/
boolean isOverride();
/**
* Gets the server this node applies on, if the node is server specific
* Gets the server this node applies on, if the node is server specific.
*
* @return an {@link Optional} containing the server, if one is defined
*/
@Nonnull
Optional<String> getServer();
/**
* Gets the world this node applies on, if the node is world specific
* Gets the world this node applies on, if the node is world specific.
*
* @return an {@link Optional} containing the world, if one is defined
*/
@Nonnull
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
@@ -107,7 +197,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
@@ -115,287 +205,510 @@ public interface Node extends Map.Entry<String, Boolean> {
boolean hasSpecificContext();
/**
* Returns if this node is able to apply in the given context
* Gets if this node should apply in the given context
*
* @param includeGlobal if global server values should apply
* @param includeGlobalWorld if global world values should apply
* @param server the server being checked against, or null
* @param world the world being checked against, or null
* @param context the context being checked against, or null
* @param applyRegex if regex should be applied
* @return true if the node should apply, otherwise false
* @since 3.1
*/
boolean shouldApply(boolean includeGlobal, boolean includeGlobalWorld, String server, String world, ContextSet context, boolean applyRegex);
/**
* If this node should apply on a specific server
*
* @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(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(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
* @param contextSet the context set
* @return true if the node should apply
* @since 2.13
*/
boolean shouldApplyWithContext(ContextSet context, boolean worldAndServer);
boolean shouldApplyWithContext(@Nonnull ContextSet contextSet);
/**
* If this node should apply in the given context
* Resolves any shorthand parts of this node and returns the full list of
* resolved nodes.
*
* @param context the context key value pairs
* @return true if the node should apply
* @since 2.13
*/
boolean shouldApplyWithContext(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(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(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
*/
List<String> resolveWildcard(List<String> possibleNodes);
/**
* Resolves any shorthand parts of this node and returns the full list
* <p>The list will not contain the exact permission itself.</p>
*
* @return a list of full nodes
*/
@Nonnull
List<String> resolveShorthand();
/**
* Gets if this node is assigned temporarily.
*
* @return true if this node will expire in the future
*/
boolean isTemporary();
/**
* Gets if this node is permanent (will not expire).
*
* @return true if this node will not expire
*/
boolean isPermanent();
default boolean isPermanent() {
return !isTemporary();
}
/**
* Gets the 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
*/
long getExpiryUnixTime();
long getExpiryUnixTime() throws IllegalStateException;
/**
* 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
*/
Date getExpiry();
@Nonnull
Date getExpiry() throws IllegalStateException;
/**
* Gets the number of seconds until this permission will expire.
*
* <p>Will return a negative value if the node has already expired.</p>
*
* @return the number of seconds until this permission will expire
* @throws IllegalStateException if the node is not temporary
*/
long getSecondsTilExpiry();
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 returns false if the node is not temporary.</p>
*
* @return true if this node has expired
*/
boolean hasExpired();
/**
* Gets the extra contexts required for this node to apply
* Gets the extra contexts required for this node to apply.
*
* @return the extra contexts required for this node to apply
* @since 2.13
*/
@Nonnull
ContextSet getContexts();
/**
* The same as {@link #getContexts()}, but also includes values for "server" and "world" keys if present.
* The same as {@link #getContexts()}, but also includes context pairs for
* "server" and "world" keys if present.
*
* @return the full contexts required for this node to apply
* @since 3.1
* @see Contexts#SERVER_KEY
* @see Contexts#WORLD_KEY
*/
@Nonnull
ContextSet getFullContexts();
/**
* Converts this node into a serialized form
* Gets if this node is a wildcard permission.
*
* @return a serialized node string
* @deprecated because this serialized form is no longer used by the implementation.
*/
@Deprecated
String toSerializedNode();
/**
* Returns if this is a group node
*
* @return true if this is a group node
*/
boolean isGroupNode();
/**
* Returns the name of the group
*
* @return the name of the group
* @throws IllegalStateException if this is not a group node. See {@link #isGroupNode()}
*/
String getGroupName();
/**
* Returns if this node is a wildcard node
*
* @return true if this node is a wildcard node
* @return true if this node is a wildcard permission
*/
boolean isWildcard();
/**
* Gets the level of this wildcard, higher is more specific
* Gets the level of this wildcard.
*
* <p>The node <code>luckperms.*</code> has a wildcard level of 1.</p>
* <p>The node <code>luckperms.user.permission.*</code> has a wildcard level of 3.</p>
*
* <p>Nodes with a higher wildcard level are more specific and have priority over
* less specific nodes (nodes with a lower wildcard level).</p>
*
* @return the wildcard level
* @throws IllegalStateException if this is not a wildcard
*/
int getWildcardLevel();
int getWildcardLevel() throws IllegalStateException;
/**
* Returns if this node is a meta node
* Gets if this node has any extra {@link NodeType} data attached to it.
*
* @return true if this node is a meta node
* @return if this node has any type data
* @since 4.2
*/
boolean isMeta();
boolean hasTypeData();
/**
* Gets the meta value from this node
* Gets the type data corresponding to the given <code>key</code>, if present.
*
* @return the meta value
* @throws IllegalStateException if this node is not a meta node
* @param key the key
* @param <T> the {@link NodeType} type
* @return the data, if present
* @since 4.2
*/
Map.Entry<String, String> getMeta();
<T extends NodeType> Optional<T> getTypeData(NodeTypeKey<T> key);
/**
* Gets the type data corresponding to the given <code>key</code>, throwing an exception
* if no data is present.
*
* @param key the key
* @param <T> the {@link NodeType} type
* @return the data
* @throws IllegalStateException if data isn't present
* @since 4.2
*/
default <T extends NodeType> T typeData(NodeTypeKey<T> key) throws IllegalStateException {
return getTypeData(key)
.orElseThrow(() ->
new IllegalStateException("Node '" + getPermission() + "' does not have the '" + key.getTypeName() + "' type.")
);
}
/**
* Gets if this node has {@link InheritanceType} type data.
*
* @return true if this is a inheritance (group) node.
*/
default boolean isGroupNode() {
return getTypeData(InheritanceType.KEY).isPresent();
}
/**
* Gets the name of the inherited group if this node has {@link InheritanceType} type data,
* throwing an exception if the data is not present.
*
* @return the name of the group
* @throws IllegalStateException if this node doesn't have {@link InheritanceType} data
*/
@Nonnull
default String getGroupName() throws IllegalStateException {
return typeData(InheritanceType.KEY).getGroupName();
}
/**
* Gets if this node has {@link MetaType} type data.
*
* @return true if this is a meta node.
*/
default boolean isMeta() {
return getTypeData(MetaType.KEY).isPresent();
}
/**
* Gets the meta entry if this node has {@link MetaType} type data,
* throwing an exception if the data is not present.
*
* @return the meta entry
* @throws IllegalStateException if this node doesn't have {@link MetaType} data
*/
@Nonnull
default Map.Entry<String, String> getMeta() throws IllegalStateException {
return typeData(MetaType.KEY);
}
/**
* Gets if this node has {@link PrefixType} type data.
*
* @return true if this node is a prefix node
*/
boolean isPrefix();
default boolean isPrefix() {
return getTypeData(PrefixType.KEY).isPresent();
}
/**
* Gets the prefix value from this node
* Gets the prefix entry if this node has {@link PrefixType} type data,
* throwing an exception if the data is not present.
*
* @return the prefix value
* @throws IllegalStateException if this node is a not a prefix node
* @return the meta entry
* @throws IllegalStateException if this node doesn't have {@link PrefixType} data
*/
Map.Entry<Integer, String> getPrefix();
@Nonnull
default Map.Entry<Integer, String> getPrefix() throws IllegalStateException {
return typeData(PrefixType.KEY).getAsEntry();
}
/**
* Gets if this node has {@link SuffixType} type data.
*
* @return true if this node is a suffix node
*/
boolean isSuffix();
default boolean isSuffix() {
return getTypeData(SuffixType.KEY).isPresent();
}
/**
* Gets the suffix value from this node
* Gets the suffix entry if this node has {@link SuffixType} type data,
* throwing an exception if the data is not present.
*
* @return the suffix value
* @throws IllegalStateException if this node is a not a suffix node
* @return the meta entry
* @throws IllegalStateException if this node doesn't have {@link SuffixType} data
*/
Map.Entry<Integer, String> getSuffix();
@Nonnull
default Map.Entry<Integer, String> getSuffix() throws IllegalStateException {
return typeData(SuffixType.KEY).getAsEntry();
}
/**
* Checks if this Node is equal to another node
* Gets if this Node is equal to another node.
*
* @param obj the other node
* @return true if this node is equal to the other provided
* @see #equalsIgnoringValue(Node) for a less strict implementation of this method
* @see StandardNodeEquality#EXACT
*/
@Override
boolean equals(Object obj);
/**
* Similar to {@link Node#equals(Object)}, except doesn't take note of the value
* Gets if this Node is equal to another node as defined by the given
* {@link StandardNodeEquality} predicate.
*
* @param other the other node
* @param equalityPredicate the predicate
* @return true if this node is considered equal
* @since 4.1
*/
boolean standardEquals(Node other, StandardNodeEquality equalityPredicate);
/**
* Gets if this Node is equal to another node as defined by the given
* {@link NodeEqualityPredicate}.
*
* @param other the other node
* @param equalityPredicate the predicate
* @return true if this node is considered equal
* @since 4.1
*/
default boolean equals(Node other, NodeEqualityPredicate equalityPredicate) {
return equalityPredicate.areEqual(this, other);
}
/**
* Similar to {@link Node#equals(Object)}, except doesn't take note of the
* value.
*
* @param other the other node
* @return true if the two nodes are almost equal
* @deprecated in favour of {@link #equals(Node, NodeEqualityPredicate)}
* @see StandardNodeEquality#IGNORE_VALUE
*/
boolean equalsIgnoringValue(Node other);
@Deprecated
default boolean equalsIgnoringValue(@Nonnull Node other) {
return equals(other, StandardNodeEquality.IGNORE_VALUE);
}
/**
* Similar to {@link Node#equals(Object)}, except doesn't take note of the expiry time or value
* Similar to {@link Node#equals(Object)}, except doesn't take note of the
* expiry time or value.
*
* @param other the other node
* @return true if the two nodes are almost equal
* @deprecated in favour of {@link #equals(Node, NodeEqualityPredicate)}
* @see StandardNodeEquality#IGNORE_EXPIRY_TIME_AND_VALUE
*/
boolean almostEquals(Node other);
@Deprecated
default boolean almostEquals(@Nonnull Node other) {
return equals(other, StandardNodeEquality.IGNORE_EXPIRY_TIME_AND_VALUE);
}
/**
* Similar to {@link Node#equals(Object)}, except doesn't take note of the value or if the node is temporary
* Similar to {@link Node#equals(Object)}, except doesn't take note of the
* value or if the node is temporary.
*
* @param other the other node
* @return true if the two nodes are almost equal
* @since 2.8
* @deprecated in favour of {@link #equals(Node, NodeEqualityPredicate)}
* @see StandardNodeEquality#IGNORE_VALUE_OR_IF_TEMPORARY
*/
boolean equalsIgnoringValueOrTemp(Node other);
@Deprecated
default boolean equalsIgnoringValueOrTemp(@Nonnull Node other) {
return equals(other, StandardNodeEquality.IGNORE_VALUE_OR_IF_TEMPORARY);
}
/**
* Constructs a new builder initially containing the current properties of
* this node.
*
* @return a new builder
* @since 4.1
*/
Builder toBuilder();
/**
* Builds a Node instance
*/
interface Builder {
/**
* Copies the attributes from the given node and applies them to this
* builder.
*
* <p>Note that this copies all attributes <strong>except</strong> the
* permission itself.</p>
*
* @param node the node to copy from
* @return the builder
* @since 4.2
*/
Builder copyFrom(@Nonnull Node node);
/**
* Sets the value of negated for the node.
*
* @param negated the value
* @return the builder
* @see Node#isNegated()
*/
@Nonnull
Builder setNegated(boolean negated);
/**
* Sets the value of the node.
*
* @param value the value
* @return the builder
* @see Node#getValue()
*/
@Nonnull
Builder setValue(boolean value);
/**
* Warning: this value does not persist, and disappears when the holder is re-loaded.
* It is therefore only useful for transient nodes.
* Sets the override property for the node.
*
* <p>Warning: this value does not persist, and disappears when the holder is re-loaded.
* It is therefore only useful for transient nodes.</p>
*
* @param override the override state
* @return the builder
* @see Node#isOverride()
*/
@Nonnull
Builder setOverride(boolean override);
Builder setExpiry(long expireAt);
/**
* Sets the time when the node should expire.
*
* <p>The parameter passed to this method must be the unix timestamp
* (in seconds) when the node should expire.</p>
*
* @param expiryUnixTimestamp the expiry timestamp (unix seconds)
* @return the builder
* @see Node#getExpiryUnixTime()
*/
@Nonnull
Builder setExpiry(long expiryUnixTimestamp);
Builder setWorld(String world);
/**
* Sets the time when the node should expire.
*
* <p>The expiry timestamp is calculated relative to the current
* system time.</p>
*
* @param duration how long the node should be added for
* @param unit the unit <code>duration</code> is measured in
* @return the builder
* @since 4.2
*/
@Nonnull
default Builder setExpiry(long duration, TimeUnit unit) {
Preconditions.checkArgument(duration > 0, "duration must be positive");
long seconds = Objects.requireNonNull(unit, "unit").toSeconds(duration);
long timeNow = System.currentTimeMillis() / 1000L;
return setExpiry(timeNow + seconds);
}
Builder setServer(String server) throws IllegalArgumentException;
/**
* Marks that the node being built should never expire.
*
* @return the builder
* @since 4.2
*/
@Nonnull
Builder clearExpiry();
Builder withExtraContext(String key, String value);
/**
* Sets the world value for the node.
*
* @param world the world value
* @return the builder
* @see Node#getWorld()
*/
@Nonnull
Builder setWorld(@Nullable String world);
Builder withExtraContext(Map<String, String> map);
/**
* Sets the server value for the node.
*
* @param server the world value
* @return the builder
* @see Node#getServer()
*/
@Nonnull
Builder setServer(@Nullable String server);
Builder withExtraContext(Set<Map.Entry<String, String>> context);
/**
* Appends an extra context onto the node.
*
* @param key the context key
* @param value the context value
* @return the builder
* @see ContextSet
* @see Node#getContexts()
*/
@Nonnull
Builder withExtraContext(@Nonnull String key, @Nonnull String value);
Builder withExtraContext(Map.Entry<String, String> entry);
/**
* Appends extra contexts onto the node.
*
* @param map a map of contexts
* @return the builder
* @see ContextSet
* @see Node#getContexts()
*/
@Nonnull
Builder withExtraContext(@Nonnull Map<String, String> map);
Builder withExtraContext(ContextSet set);
/**
* Appends extra contexts onto the node.
*
* @param context a set of contexts
* @return the builder
* @see ContextSet
* @see Node#getContexts()
*/
@Nonnull
Builder withExtraContext(@Nonnull Set<Map.Entry<String, String>> context);
/**
* Appends an extra context onto the node.
*
* @param entry the context
* @return the builder
* @see ContextSet
* @see Node#getContexts()
*/
@Nonnull
Builder withExtraContext(@Nonnull Map.Entry<String, String> entry);
/**
* Appends extra contexts onto the node.
*
* @param contextSet a context set
* @return the builder
* @see ContextSet
* @see Node#getContexts()
*/
@Nonnull
Builder withExtraContext(@Nonnull ContextSet contextSet);
/**
* Sets the extra contexts for the node.
*
* @param contextSet a context set
* @return the builder
* @see ContextSet
* @see Node#getContexts()
* @since 4.2
*/
@Nonnull
Builder setExtraContext(@Nonnull ContextSet contextSet);
/**
* Creates a {@link Node} instance from the builder.
*
* @return a new node instance
*/
@Nonnull
Node build();
}
@@ -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.api;
import javax.annotation.Nonnull;
/**
* A rule for determining if two nodes are equal.
*
* <p>Generally, individual instances of this interface should fulfil the same
* requirements as the {@link Object#equals(Object)} contract.</p>
*
* <p>Some standard implementations are provided by
* {@link StandardNodeEquality}.</p>
*
* @since 4.1
*/
@FunctionalInterface
public interface NodeEqualityPredicate {
/**
* Returns if the two nodes are equal
*
* @param o1 the first node
* @param o2 the second node
* @return true if equal
*/
boolean areEqual(@Nonnull Node o1, @Nonnull Node o2);
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -22,24 +25,15 @@
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
*/
Node fromSerialisedNode(String serialisedPermission, boolean value);
/**
* Creates a new node builder from a given base permission string
*
@@ -47,7 +41,8 @@ public interface NodeFactory {
* @return a node builder instance
* @throws NullPointerException if the permission is null
*/
Node.Builder newBuilder(String permission);
@Nonnull
Node.Builder newBuilder(@Nonnull String permission);
/**
* Creates a node builder instance from an existing node
@@ -56,17 +51,8 @@ public interface NodeFactory {
* @return a node builder instance
* @throws NullPointerException if the other node is null
*/
Node.Builder newBuilderFromExisting(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
*/
Node.Builder newBuilderFromSerialisedNode(String serialisedPermission, boolean value);
@Nonnull
Node.Builder newBuilderFromExisting(@Nonnull Node other);
/**
@@ -78,7 +64,19 @@ public interface NodeFactory {
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @since 3.1
*/
Node.Builder makeGroupNode(Group group);
@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
@@ -88,7 +86,21 @@ public interface NodeFactory {
* @return a node builder instance
* @throws NullPointerException if the key or value is null
*/
Node.Builder makeMetaNode(String key, String value);
@Nonnull
Node.Builder makeMetaNode(@Nonnull String key, @Nonnull String value);
/**
* Creates a node builder for the given chat meta type
*
* @param type the type
* @param priority the priority
* @param value the value for the prefix/suffix
* @return a node builder instance
* @throws NullPointerException if the type or value is null
* @since 3.2
*/
@Nonnull
Node.Builder makeChatMetaNode(@Nonnull ChatMetaType type, int priority, @Nonnull String value);
/**
* Creates a node builder from a prefix string and priority
@@ -98,7 +110,8 @@ public interface NodeFactory {
* @return a node builder instance
* @throws NullPointerException if the prefix is null
*/
Node.Builder makePrefixNode(int priority, String prefix);
@Nonnull
Node.Builder makePrefixNode(int priority, @Nonnull String prefix);
/**
* Creates a node builder from a prefix string and priority
@@ -108,6 +121,7 @@ public interface NodeFactory {
* @return a node builder instance
* @throws NullPointerException if the suffix is null
*/
Node.Builder makeSuffixNode(int priority, String suffix);
@Nonnull
Node.Builder makeSuffixNode(int priority, @Nonnull String suffix);
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -22,56 +25,196 @@
package me.lucko.luckperms.api;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Multimap;
import me.lucko.luckperms.api.caching.CachedData;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate;
import javax.annotation.Nonnull;
/**
* 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>
*
* @return the identifier for this object. Either a uuid string or name.
*/
@Nonnull
String getObjectName();
/**
* Gets a friendly name for this holder, to be displayed in command output, etc.
*
* <p>This will <strong>always</strong> return a value, eventually falling back to {@link #getObjectName()} if no
* other "friendlier" identifiers are present.</p>
*
* @return a friendly identifier for this holder
* @since 3.2
*/
@Nonnull
String getFriendlyName();
/**
* Gets the holders {@link CachedData} cache.
*
* @return the holders cached data.
* @since 3.2
*/
@Nonnull
CachedData getCachedData();
/**
* Refreshes and applies any changes to the cached holder data.
*
* <p>Calling this method is unnecessary in most cases. Cache updates are handled
* behind the scenes by the implementation.</p>
*
* @return the task future
* @since 4.0
*/
@Nonnull
CompletableFuture<Void> refreshCachedData();
/**
* Gets the backing multimap containing every permission this holder has.
*
* <p>This method <b>does not</b> resolve inheritance rules, and returns a
* view of what's 'in the file'.</p>
*
* @return the holders own permissions
* @since 3.3
*/
@Nonnull
ImmutableSetMultimap<ImmutableContextSet, Node> getNodes();
/**
* Gets the backing multimap containing every transient permission this holder has.
*
* <p>This method <b>does not</b> resolve inheritance rules.</p>
*
* <p>Transient permissions only exist for the duration of the session.</p>
*
* @return the holders own permissions
* @since 3.3
*/
@Nonnull
ImmutableSetMultimap<ImmutableContextSet, Node> getTransientNodes();
/**
* Gets a flattened/squashed view of the holders permissions.
*
* <p>This list is constructed using the {@link Multimap#values()} method
* of both the transient and enduring backing multimaps.</p>
*
* <p>This means that it <b>may contain</b> duplicate entries.</p>
*
* <p>Use {@link #getPermissions()} for a view without duplicates.</p>
*
* @return a list of the holders own nodes.
* @since 3.3
*/
@Nonnull
List<Node> getOwnNodes();
/**
* Gets a sorted set of all held permissions.
*
* @return an immutable set of permissions in priority order
* @since 2.6
*/
@Nonnull
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>
*
* @return a set of nodes
* @since 2.6
*/
@Nonnull
Set<? extends Node> getEnduringPermissions();
/**
* Gets an immutable set of all transiently held permissions.
* Similar to {@link #getPermissions()}, except without enduring permissions.
*
* <p> Transient permissions only exist for the duration of the session.
* <p>Transient permissions only exist for the duration of the session.</p>
*
* @return a set of nodes
* @since 2.6
*/
@Nonnull
Set<? extends Node> getTransientPermissions();
/**
* Processes the nodes and returns the non-temporary ones.
*
* @return a set of permanent nodes
* @since 2.6
*/
@Nonnull
Set<Node> getPermanentPermissionNodes();
/**
* Processes the nodes and returns the temporary ones.
*
* @return a set of temporary nodes
* @since 2.6
*/
@Nonnull
Set<Node> getTemporaryPermissionNodes();
/**
* Recursively resolves this holders permissions.
*
* <p>The returned list will contain every inherited
* node the holder has, in the order that they were inherited in.</p>
*
* <p>This means the list will contain duplicates.</p>
*
* @param contexts the contexts for the lookup
* @return a list of nodes
* @since 3.3
*/
@Nonnull
List<LocalizedNode> resolveInheritances(Contexts contexts);
/**
* Recursively resolves this holders permissions.
*
* <p>The returned list will contain every inherited
* node the holder has, in the order that they were inherited in.</p>
*
* <p>This means the list will contain duplicates.</p>
*
* <p>Unlike {@link #resolveInheritances(Contexts)}, this method does not
* filter by context, at all.</p>
*
* @return a list of nodes
* @since 3.3
*/
@Nonnull
List<LocalizedNode> resolveInheritances();
/**
* Gets a mutable sorted set of the nodes that this object has and inherits, filtered by context
*
@@ -80,12 +223,27 @@ public interface PermissionHolder {
*
* <p>Nodes are sorted into priority order.</p>
*
* @param contexts the context for the lookup,
* @param contexts the context for the lookup
* @return a mutable sorted set of permissions
* @throws NullPointerException if the context is null
* @since 2.11
*/
SortedSet<LocalizedNode> getAllNodes(Contexts contexts);
@Nonnull
SortedSet<LocalizedNode> getAllNodes(@Nonnull Contexts contexts);
/**
* Gets a mutable sorted set of the nodes that this object has and inherits.
*
* <p>Unlike {@link #getAllNodes(Contexts)}, this method does not filter by context, at all.</p>
*
* <p>Nodes are sorted into priority order.</p>
*
* @return a mutable sorted set of permissions
* @throws NullPointerException if the context is null
* @since 3.3
*/
@Nonnull
SortedSet<LocalizedNode> getAllNodes();
/**
* Gets a mutable set of the nodes that this object has and inherits, filtered by context.
@@ -98,7 +256,8 @@ public interface PermissionHolder {
* @throws NullPointerException if the context is null
* @since 2.11
*/
Set<LocalizedNode> getAllNodesFiltered(Contexts contexts);
@Nonnull
Set<LocalizedNode> getAllNodesFiltered(@Nonnull Contexts contexts);
/**
* Converts the output of {@link #getAllNodesFiltered(Contexts)}, and expands shorthand permissions.
@@ -107,7 +266,8 @@ public interface PermissionHolder {
* @param lowerCase if the keys should be made lowercase whilst being exported
* @return a mutable map of permissions
*/
Map<String, Boolean> exportNodes(Contexts contexts, boolean lowerCase);
@Nonnull
Map<String, Boolean> exportNodes(@Nonnull Contexts contexts, boolean lowerCase);
/**
* Removes temporary permissions that have expired
@@ -118,11 +278,37 @@ public interface PermissionHolder {
* Checks to see if the object has a certain permission
*
* @param node the node to check for
* @param equalityPredicate how to determine if a node matches
* @return a Tristate for the holders permission status for the node
* @throws NullPointerException if the node is null
* @since 2.6
* @since 4.1
*/
Tristate hasPermission(Node node);
@Nonnull
Tristate hasPermission(@Nonnull Node node, @Nonnull NodeEqualityPredicate equalityPredicate);
/**
* Checks to see if the object has a certain permission
*
* @param node the node to check for
* @param equalityPredicate how to determine if a node matches
* @return a Tristate for the holders permission status for the node
* @throws NullPointerException if the node is null
* @since 4.1
*/
@Nonnull
Tristate hasTransientPermission(@Nonnull Node node, @Nonnull NodeEqualityPredicate equalityPredicate);
/**
* Checks to see if the object inherits a certain permission
*
* @param node the node to check for
* @param equalityPredicate how to determine if a node matches
* @return a Tristate for the holders inheritance status for the node
* @throws NullPointerException if the node is null
* @since 4.1
*/
@Nonnull
Tristate inheritsPermission(@Nonnull Node node, @Nonnull NodeEqualityPredicate equalityPredicate);
/**
* Checks to see if the object has a certain permission
@@ -132,82 +318,19 @@ public interface PermissionHolder {
* @throws NullPointerException if the node is null
* @since 2.6
*/
Tristate hasTransientPermission(Node node);
@Nonnull
Tristate hasPermission(@Nonnull Node node);
/**
* 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
* @param node the node to check for
* @return a Tristate for the holders permission status for the node
* @throws NullPointerException if the node is null
* @since 2.6
*/
boolean hasPermission(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
*/
boolean hasPermission(String node, boolean b, 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
*/
boolean hasPermission(String node, boolean b, String server, 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
*/
boolean hasPermission(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
*/
boolean hasPermission(String node, boolean b, 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
*/
boolean hasPermission(String node, boolean b, String server, String world, boolean temporary);
@Nonnull
Tristate hasTransientPermission(@Nonnull Node node);
/**
* Checks to see if the object inherits a certain permission
@@ -217,102 +340,42 @@ public interface PermissionHolder {
* @throws NullPointerException if the node is null
* @since 2.6
*/
Tristate inheritsPermission(Node node);
@Nonnull
Tristate inheritsPermission(@Nonnull Node node);
/**
* Checks to see if the object inherits a certain permission
* Check to see if this holder inherits another group directly
*
* @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
* @param group The group to check membership of
* @return true if the group inherits the other group
* @throws NullPointerException if the group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @since 4.0
*/
boolean inheritsPermission(String node, boolean b);
boolean inheritsGroup(@Nonnull Group group);
/**
* Checks to see the the object inherits a permission on a certain server
* Check to see if this holder inherits another group directly
*
* @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
* @param group The group to check membership of
* @param contextSet the context set to filter by
* @return true if the group inherits the other group
* @throws NullPointerException if the group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @since 4.0
*/
boolean inheritsPermission(String node, boolean b, 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
*/
boolean inheritsPermission(String node, boolean b, String server, 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
*/
boolean inheritsPermission(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
*/
boolean inheritsPermission(String node, boolean b, 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
*/
boolean inheritsPermission(String node, boolean b, String server, String world, boolean temporary);
boolean inheritsGroup(@Nonnull Group group, @Nonnull ContextSet contextSet);
/**
* 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(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
*/
DataMutateResult setPermissionUnchecked(Node node);
@Nonnull
DataMutateResult setPermission(@Nonnull Node node);
/**
* Sets a transient permission for the object
@@ -327,238 +390,50 @@ 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(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
*/
DataMutateResult setTransientPermissionUnchecked(Node node);
/**
* 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)}
*/
@Deprecated
void setPermission(String node, boolean value) throws ObjectAlreadyHasException;
/**
* Sets a 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
* @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)}
*/
@Deprecated
void setPermission(String node, boolean value, 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(String node, boolean value, String server, 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(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(String node, boolean value, 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, String server, String world, long expireAt) throws ObjectAlreadyHasException;
@Nonnull
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(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
*/
DataMutateResult unsetPermissionUnchecked(Node node);
@Nonnull
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(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
*/
DataMutateResult unsetTransientPermissionUnchecked(Node node);
@Nonnull
DataMutateResult unsetTransientPermission(@Nonnull Node node);
/**
* Unsets a permission for the object
* Clears any nodes from the holder which pass the predicate
*
* @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)}
* @param test the predicate to test for nodes which should be removed
* @since 3.2
*/
@Deprecated
void unsetPermission(String node, boolean temporary) throws ObjectLacksException;
void clearMatching(@Nonnull Predicate<Node> test);
/**
* Unsets a permission for the object
* Clears any transient nodes from the holder which pass the predicate
*
* @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)}
* @param test the predicate to test for nodes which should be removed
* @since 3.2
*/
@Deprecated
void unsetPermission(String node) 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
* @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(String node, 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(String node, String server, 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(String node, 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(String node, String server, String world, boolean temporary) throws ObjectLacksException;
void clearMatchingTransient(@Nonnull Predicate<Node> test);
/**
* Clears all nodes held by the object
@@ -568,21 +443,12 @@ public interface PermissionHolder {
void clearNodes();
/**
* Clears all nodes held by the object on a specific server
* Clears all nodes held by the object in a specific context
*
* @param server the server to filter by, can be null
* @since 2.17
* @param contextSet the contexts to filter by
* @since 3.2
*/
void clearNodes(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
*/
void clearNodes(String server, String world);
void clearNodes(@Nonnull ContextSet contextSet);
/**
* Clears all parent groups
@@ -592,21 +458,12 @@ public interface PermissionHolder {
void clearParents();
/**
* Clears all parents on a specific server
* Clears all parent groups in a specific context
*
* @param server the server to filter by, can be null
* @since 2.17
* @param contextSet the contexts to filter by
* @since 3.2
*/
void clearParents(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
*/
void clearParents(String server, String world);
void clearParents(@Nonnull ContextSet contextSet);
/**
* Clears all meta held by the object
@@ -616,31 +473,12 @@ public interface PermissionHolder {
void clearMeta();
/**
* Clears all meta held by the object on a specific server
* Clears all meta held by the object in a specific context
*
* @param server the server to filter by, can be null
* @since 2.17
* @param contextSet the contexts to filter by
* @since 3.2
*/
void clearMeta(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
*/
void clearMeta(String server, 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.
*/
void clearMetaKeys(String key, String server, String world, boolean temporary);
void clearMeta(@Nonnull ContextSet contextSet);
/**
* Clears all transient permissions the holder has.
@@ -648,19 +486,63 @@ public interface PermissionHolder {
void clearTransientNodes();
/**
* Processes the nodes and returns the non-temporary ones.
* Sets a permission for the object
*
* @return a set of permanent nodes
* @since 2.6
* @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)}.
*/
Set<Node> getPermanentPermissionNodes();
@Nonnull
@Deprecated
default DataMutateResult setPermissionUnchecked(@Nonnull Node node) {
return setPermission(node);
}
/**
* Processes the nodes and returns the temporary ones.
* Sets a transient permission for the object
*
* @return a set of temporary nodes
* @since 2.6
* @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)}
*/
Set<Node> getTemporaryPermissionNodes();
@Nonnull
@Deprecated
default DataMutateResult setTransientPermissionUnchecked(@Nonnull Node node) {
return setTransientPermission(node);
}
/**
* 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
* @deprecated now forwards to {@link #unsetPermission(Node)}
*/
@Nonnull
@Deprecated
default DataMutateResult unsetPermissionUnchecked(@Nonnull Node node) {
return unsetPermission(node);
}
/**
* 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
* @deprecated now forwards to {@link #unsetTransientPermission(Node)}
*/
@Nonnull
@Deprecated
default DataMutateResult unsetTransientPermissionUnchecked(@Nonnull Node node) {
return unsetTransientPermission(node);
}
}
@@ -0,0 +1,112 @@
/*
* 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 java.util.Set;
import java.util.UUID;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Encapsulates the result of an operation to save uuid data about a player.
*
* @since 4.2
*/
public interface PlayerSaveResult {
/**
* Gets the status returned by the operation
*
* @return the status
*/
@Nonnull
Set<Status> getStatus();
/**
* Gets if the result includes a certain status code.
*
* @param status the status to check for
* @return if the result includes the status
*/
boolean includes(@Nonnull Status status);
/**
* Gets the old username involved in the result
*
* @return the old username
* @see Status#USERNAME_UPDATED
*/
@Nullable
String getOldUsername();
/**
* Gets the other uuids involved in the result
*
* @return the other uuids
* @see Status#OTHER_UUIDS_PRESENT_FOR_USERNAME
*/
@Nullable
Set<UUID> getOtherUuids();
/**
* The various states the result can take
*/
enum Status {
/**
* There was no existing data saved for either the uuid or username
*/
CLEAN_INSERT,
/**
* There was existing data for the player, no change was needed.
*/
NO_CHANGE,
/**
* There was already a record for the UUID saved, but it was for a different username.
*
* <p>This is normal, players are able to change their usernames.</p>
*/
USERNAME_UPDATED,
/**
* There was already a record for the username saved, but it was under a different uuid.
*
* <p>This is a bit of a cause for concern. It's possible that "player1" has changed
* their username to "player2", and "player3" has changed their username to "player1".
* If the original "player1" doesn't join after changing their name, this conflict could
* occur.</p>
*
* <p>However, what's more likely is that the server is not setup to authenticate
* correctly. Usually this is a problem with BungeeCord "ip-forwarding", but could be
* that the user of the plugin is running a network off a shared database with one
* server in online mode and another in offline mode.</p>
*/
OTHER_UUIDS_PRESENT_FOR_USERNAME,
}
}
@@ -0,0 +1,130 @@
/*
* 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 java.util.Optional;
import javax.annotation.Nonnull;
/**
* Encapsulates the result of {@link User}s promotion along a {@link Track}.
*
* @since 4.2
*/
public interface PromotionResult extends MutateResult {
/**
* Gets the status of the result.
*
* @return the status
*/
@Nonnull
Status getStatus();
@Override
default boolean wasSuccess() {
return getStatus().wasSuccess();
}
/**
* Gets the name of the group the user was promoted from, if applicable.
*
* <p>Will only be present for results with a {@link #getStatus() status} of
* {@link Status#SUCCESS}.</p>
*
* @return the group the user was promoted from.
*/
@Nonnull
Optional<String> getGroupFrom();
/**
* Gets the name of the group the user was promoted from, if applicable.
*
* <p>Will only be present for results with a {@link #getStatus() status} of
* {@link Status#SUCCESS} or {@link Status#ADDED_TO_FIRST_GROUP}.</p>
*
* <p>The value will also be set for results with the {@link Status#MALFORMED_TRACK} status,
* with this value marking the group which no longer exists.</p>
*
* @return the group the user was promoted to.
*/
@Nonnull
Optional<String> getGroupTo();
/**
* The result status
*/
enum Status implements MutateResult {
/**
* Indicates that the user was promoted normally.
*/
SUCCESS(true),
/**
* Indicates that the user was added to the first group in the track.
*
* <p>This usually occurs when the user isn't already on any of the groups in the track.</p>
*/
ADDED_TO_FIRST_GROUP(true),
/**
* Indicates that the next group in the track no longer exists.
*/
MALFORMED_TRACK(false),
/**
* Indicates that the user is already a member of the group at the end of the track,
* and as such cannot be promoted any further.
*/
END_OF_TRACK(false),
/**
* Indicates that the implementation was unable to determine the users current position on
* this track.
*
* <p>This usually occurs when the user is on more than one group on the track.</p>
*/
AMBIGUOUS_CALL(false),
/**
* An undefined failure occurred.
*/
UNDEFINED_FAILURE(false);
private final boolean success;
Status(boolean success) {
this.success = success;
}
@Override
public boolean wasSuccess() {
return this.success;
}
}
}
@@ -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;
import javax.annotation.Nonnull;
/**
* Standard {@link NodeEqualityPredicate}s.
*
* @since 4.1
*/
public enum StandardNodeEquality implements NodeEqualityPredicate {
/**
* Represents an exact match.
*
* <p>All attributes of the nodes must match for them to be considered
* equal.</p>
*/
EXACT,
/**
* All attributes must match, except for
* {@link Node#getValue() value}, which is ignored.
*/
IGNORE_VALUE,
/**
* All attributes must match, except for the
* {@link Node#getExpiry() expiry time}, which is ignored.
*
* <p>Note that with this setting, whether a node is temporary or not is
* still considered.</p>
*/
IGNORE_EXPIRY_TIME,
/**
* All attributes must match, except for
* {@link Node#getValue() value} and the
* {@link Node#getExpiry() expiry time}, which are ignored.
*/
IGNORE_EXPIRY_TIME_AND_VALUE,
/**
* All attributes must match, except for
* {@link Node#getValue() value} and the if the node is
* {@link Node#isTemporary() temporary}, which are ignored.
*/
IGNORE_VALUE_OR_IF_TEMPORARY;
@Override
public boolean areEqual(@Nonnull Node o1, @Nonnull Node o2) {
return o1.standardEquals(o2, this);
}
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -22,23 +25,21 @@
package me.lucko.luckperms.api;
import me.lucko.luckperms.api.manager.GroupManager;
import me.lucko.luckperms.api.manager.TrackManager;
import me.lucko.luckperms.api.manager.UserManager;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* A means of loading and saving data to/from the Storage provider.
*
* <p>All methods return {@link CompletableFuture}s, which will be populated with the result once the data has been
* loaded asynchronously. Care should be taken when using the methods to ensure that the main server thread is not
* blocked.</p>
*
* <p>Methods such as {@link CompletableFuture#get()} and equivalent should <strong>not</strong> be called on the main
* server thread. If you need to use the result of these operations on the main server thread, please register a
* callback using {@link CompletableFuture#thenAcceptAsync(Consumer, Executor)} and {@link #getSyncExecutor()}.</p>
* A means of loading and saving permission data to/from the backend.
*
* @since 2.14
*/
@@ -49,80 +50,92 @@ public interface Storage {
*
* @return the name of the implementation
*/
@Nonnull
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
* @deprecated as this method always returns true.
*/
@Deprecated
boolean isAcceptingLogins();
/**
* Returns an executor which will run all passed runnables on the main server thread.
*
* @return an executor instance
*/
Executor getSyncExecutor();
/**
* Returns an executor which will run all passed runnables asynchronously using the platforms scheduler and thread
* pools.
*
* @return an executor instance
*/
Executor getAsyncExecutor();
/**
* Saves an action to storage
*
* @param entry the log entry to be saved
* @return true if the operation completed successfully.
* @throws NullPointerException if entry is null
* @deprecated in favour of {@link ActionLogger#submit(LogEntry)}.
*/
CompletableFuture<Boolean> logAction(LogEntry entry);
@Nonnull
@Deprecated
CompletableFuture<Boolean> logAction(@Nonnull LogEntry entry);
/**
* Loads and returns the entire log from storage
*
* @return a log instance, could be null if loading failed
* @deprecated in favour of {@link ActionLogger#getLog()}
*/
@Nonnull
@Deprecated
CompletableFuture<Log> getLog();
/**
* Loads a user's data from the main storage into the plugins local storage.
*
* @param uuid the uuid of the user to load
* @param username the users username. (if you want to specify <code>null</code> here, just input "null" as a
* string.)
* @param username the users username, or null if it is not known.
* @return if the operation completed successfully
* @throws NullPointerException if uuid or username is null
* @throws NullPointerException if uuid is null
* @deprecated in favour of {@link UserManager#loadUser(UUID, String)}
*/
CompletableFuture<Boolean> loadUser(UUID uuid, String username);
@Nonnull
@Deprecated
CompletableFuture<Boolean> loadUser(@Nonnull UUID uuid, @Nullable String username);
/**
* Saves a user object back to storage. You should call this after you make any changes to a user.
* Loads a user's data from the main storage into the plugins local storage.
*
* @param uuid the uuid of the user to load
* @return if the operation completed successfully
* @throws NullPointerException if uuid is null
* @deprecated in favour of {@link UserManager#loadUser(UUID)}
*/
@Nonnull
@Deprecated
default CompletableFuture<Boolean> loadUser(@Nonnull UUID uuid) {
return loadUser(uuid, null);
}
/**
* Saves a user object back to storage.
*
* <p>You should call this after you make any changes to a user.</p>
*
* @param user the user to save
* @return true if the operation completed successfully.
* @throws NullPointerException if user is null
* @throws IllegalStateException if the user instance was not obtained from LuckPerms.
* @deprecated in favour of {@link UserManager#saveUser(User)}
*/
CompletableFuture<Boolean> saveUser(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
*/
CompletableFuture<Boolean> cleanupUsers();
@Nonnull
@Deprecated
CompletableFuture<Boolean> saveUser(@Nonnull User user);
/**
* 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.
* @deprecated in favour of {@link UserManager#getUniqueUsers()}
*/
@Nonnull
@Deprecated
CompletableFuture<Set<UUID>> getUniqueUsers();
/**
@@ -132,8 +145,11 @@ public interface Storage {
* @return a list of held permissions, or null if the operation failed
* @throws NullPointerException if the permission is null
* @since 2.17
* @deprecated in favour of {@link UserManager#getWithPermission(String)}
*/
CompletableFuture<List<HeldPermission<UUID>>> getUsersWithPermission(String permission);
@Nonnull
@Deprecated
CompletableFuture<List<HeldPermission<UUID>>> getUsersWithPermission(@Nonnull String permission);
/**
* Creates and loads a group into the plugins local storage
@@ -142,8 +158,11 @@ public interface Storage {
* @return true if the operation completed successfully
* @throws NullPointerException if name is null
* @throws IllegalArgumentException if the name is invalid
* @deprecated in favour of {@link GroupManager#createAndLoadGroup(String)}
*/
CompletableFuture<Boolean> createAndLoadGroup(String name);
@Nonnull
@Deprecated
CompletableFuture<Boolean> createAndLoadGroup(@Nonnull String name);
/**
* Loads a group into the plugins local storage.
@@ -152,25 +171,36 @@ public interface Storage {
* @return true if the operation completed successfully
* @throws NullPointerException if name is null
* @throws IllegalArgumentException if the name is invalid
* @deprecated in favour of {@link GroupManager#loadGroup(String)}
*/
CompletableFuture<Boolean> loadGroup(String name);
@Nonnull
@Deprecated
CompletableFuture<Boolean> loadGroup(@Nonnull String name);
/**
* Loads all groups from the storage into memory
*
* @return true if the operation completed successfully.
* @deprecated in favour of {@link GroupManager#loadAllGroups()}
*/
@Nonnull
@Deprecated
CompletableFuture<Boolean> loadAllGroups();
/**
* Saves a group back to storage. You should call this after you make any changes to a group.
* Saves a group back to storage.
*
* <p>You should call this after you make any changes to a group.</p>
*
* @param group the group to save
* @return true if the operation completed successfully.
* @throws NullPointerException if group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @deprecated in favour of {@link GroupManager#saveGroup(Group)}
*/
CompletableFuture<Boolean> saveGroup(Group group);
@Nonnull
@Deprecated
CompletableFuture<Boolean> saveGroup(@Nonnull Group group);
/**
* Permanently deletes a group from storage.
@@ -179,8 +209,11 @@ public interface Storage {
* @return true if the operation completed successfully.
* @throws NullPointerException if group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @deprecated in favour of {@link GroupManager#deleteGroup(Group)}
*/
CompletableFuture<Boolean> deleteGroup(Group group);
@Nonnull
@Deprecated
CompletableFuture<Boolean> deleteGroup(@Nonnull Group group);
/**
* Searches for a list of groups with a given permission.
@@ -189,8 +222,11 @@ public interface Storage {
* @return a list of held permissions, or null if the operation failed
* @throws NullPointerException if the permission is null
* @since 2.17
* @deprecated in favour of {@link GroupManager#getWithPermission(String)}
*/
CompletableFuture<List<HeldPermission<String>>> getGroupsWithPermission(String permission);
@Nonnull
@Deprecated
CompletableFuture<List<HeldPermission<String>>> getGroupsWithPermission(@Nonnull String permission);
/**
* Creates and loads a track into the plugins local storage
@@ -199,8 +235,11 @@ public interface Storage {
* @return true if the operation completed successfully
* @throws NullPointerException if name is null
* @throws IllegalArgumentException if the name is invalid
* @deprecated in favour of {@link TrackManager#createAndLoadTrack(String)}
*/
CompletableFuture<Boolean> createAndLoadTrack(String name);
@Nonnull
@Deprecated
CompletableFuture<Boolean> createAndLoadTrack(@Nonnull String name);
/**
* Loads a track into the plugins local storage.
@@ -209,14 +248,20 @@ public interface Storage {
* @return true if the operation completed successfully
* @throws NullPointerException if name is null
* @throws IllegalArgumentException if the name is invalid
* @deprecated in favour of {@link TrackManager#loadTrack(String)}
*/
CompletableFuture<Boolean> loadTrack(String name);
@Nonnull
@Deprecated
CompletableFuture<Boolean> loadTrack(@Nonnull String name);
/**
* Loads all tracks from the storage into memory
*
* @return true if the operation completed successfully.
* @deprecated in favour of {@link TrackManager#loadAllTracks()}
*/
@Nonnull
@Deprecated
CompletableFuture<Boolean> loadAllTracks();
/**
@@ -226,8 +271,11 @@ public interface Storage {
* @return true if the operation completed successfully.
* @throws NullPointerException if track is null
* @throws IllegalStateException if the track instance was not obtained from LuckPerms.
* @deprecated in favour of {@link TrackManager#saveTrack(Track)}
*/
CompletableFuture<Boolean> saveTrack(Track track);
@Nonnull
@Deprecated
CompletableFuture<Boolean> saveTrack(@Nonnull Track track);
/**
* Permanently deletes a track from storage
@@ -236,8 +284,11 @@ public interface Storage {
* @return true if the operation completed successfully.
* @throws NullPointerException if track is null
* @throws IllegalStateException if the track instance was not obtained from LuckPerms.
* @deprecated in favour of {@link TrackManager#deleteTrack(Track)}
*/
CompletableFuture<Boolean> deleteTrack(Track track);
@Nonnull
@Deprecated
CompletableFuture<Boolean> deleteTrack(@Nonnull Track track);
/**
* Saves UUID caching data to the global cache
@@ -247,8 +298,10 @@ public interface Storage {
* @return true if the operation completed successfully.
* @throws NullPointerException if either parameters are null
* @throws IllegalArgumentException if the username is invalid
* @deprecated in favour of {@link UserManager#savePlayerData(UUID, String)}
*/
CompletableFuture<Boolean> saveUUIDData(String username, UUID uuid);
@Nonnull
CompletableFuture<Boolean> saveUUIDData(@Nonnull String username, @Nonnull UUID uuid);
/**
* Gets a UUID from a username
@@ -257,8 +310,10 @@ public interface Storage {
* @return a uuid object, could be null
* @throws NullPointerException if either parameters are null
* @throws IllegalArgumentException if the username is invalid
* @deprecated in favour of {@link UserManager#lookupUuid(String)}
*/
CompletableFuture<UUID> getUUID(String username);
@Nonnull
CompletableFuture<UUID> getUUID(@Nonnull String username);
/**
* Gets a username from a UUID
@@ -267,7 +322,38 @@ public interface Storage {
* @return a name string, could be null
* @throws NullPointerException if either parameters are null
* @since 2.17
* @deprecated in favour of {@link UserManager#lookupUsername(UUID)}
*/
CompletableFuture<String> getName(UUID uuid);
@Nonnull
@Deprecated
CompletableFuture<String> getName(@Nonnull UUID uuid);
/**
* Returns an executor which will run all passed runnables on the
* main server thread.
*
* <p>This method is deprecated as plugins should create and use their own
* executor instances.</p>
*
* @return an executor instance
* @deprecated as plugins should create their own executors
*/
@Nonnull
@Deprecated
Executor getSyncExecutor();
/**
* Returns an executor which will run all passed runnables asynchronously
* using the platforms scheduler and thread pools.
*
* <p>This method is deprecated as plugins should create and use their own
* executor instances.</p>
*
* @return an executor instance
* @deprecated as plugins should create their own executors
*/
@Nonnull
@Deprecated
Executor getAsyncExecutor();
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -22,29 +25,36 @@
package me.lucko.luckperms.api;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import me.lucko.luckperms.api.context.ContextSet;
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
*/
@Nonnull
List<String> getGroups();
/**
@@ -57,65 +67,95 @@ 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.
*/
String getNext(Group current) throws ObjectLacksException;
@Nullable
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.
*/
String getPrevious(Group current) throws ObjectLacksException;
@Nullable
String getPrevious(@Nonnull Group current);
/**
* Promotes the given user along this track.
*
* @param user the user to promote
* @param contextSet the contexts to promote the user in
* @return the result of the action
* @since 4.2
*/
@Nonnull
PromotionResult promote(@Nonnull User user, @Nonnull ContextSet contextSet);
/**
* Demotes the given user along this track.
*
* @param user the user to demote
* @param contextSet the contexts to demote the user in
* @return the result of the action
* @since 4.2
*/
@Nonnull
DemotionResult demote(@Nonnull User user, @Nonnull ContextSet contextSet);
/**
* 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(Group group) throws ObjectAlreadyHasException;
@Nonnull
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(Group group, int position) throws ObjectAlreadyHasException, IndexOutOfBoundsException;
@Nonnull
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(Group group) throws ObjectLacksException;
@Nonnull
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(String group) throws ObjectLacksException;
@Nonnull
DataMutateResult removeGroup(@Nonnull String group);
/**
* Checks if a group features on this track
@@ -125,7 +165,7 @@ public interface Track {
* @throws NullPointerException if the group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
*/
boolean containsGroup(Group group);
boolean containsGroup(@Nonnull Group group);
/**
* Checks if a group features on this track
@@ -134,7 +174,7 @@ public interface Track {
* @return true if the group is on this track
* @throws NullPointerException if the group is null
*/
boolean containsGroup(String group);
boolean containsGroup(@Nonnull String group);
/**
* Clear all of the groups from this track
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -22,37 +25,61 @@
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 #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
* @return {@link #TRUE} or {@link #FALSE}, depending on the value of the boolean.
* @param val the boolean value
* @return {@link #TRUE} or {@link #FALSE}, if the value is <code>true</code> or <code>false</code>, respectively.
*/
public static Tristate fromBoolean(boolean b) {
return b ? TRUE : FALSE;
@Nonnull
public static Tristate fromBoolean(boolean val) {
return val ? TRUE : FALSE;
}
/**
* Returns a {@link Tristate} from a nullable boolean.
*
* <p>Unlike {@link #fromBoolean(boolean)}, this method returns {@link #UNDEFINED}
* if the value is null.</p>
*
* @param val the boolean value
* @return {@link #UNDEFINED}, {@link #TRUE} or {@link #FALSE}, if the value
* is <code>null</code>, <code>true</code> or <code>false</code>, respectively.
* @since 4.1
*/
@Nonnull
public static Tristate fromNullableBoolean(Boolean val) {
return val == null ? UNDEFINED : val ? TRUE : FALSE;
}
private final boolean booleanValue;
@@ -69,6 +96,6 @@ public enum Tristate {
* @return a boolean representation of the Tristate.
*/
public boolean asBoolean() {
return booleanValue;
return this.booleanValue;
}
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -23,15 +26,14 @@
package me.lucko.luckperms.api;
import me.lucko.luckperms.api.caching.UserData;
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 javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* A player holding permission data
* A player which holds permission data.
*/
public interface User extends PermissionHolder {
@@ -40,284 +42,72 @@ public interface User extends PermissionHolder {
*
* @return the users Mojang assigned unique id
*/
@Nonnull
UUID getUuid();
/**
* Gets the users username
*
* @return the Users Username
* <p>Returns null if no username is associated with this user.</p>
*
* @return the users username
*/
@Nullable
String getName();
/**
* Gets the users primary group
* Gets the users current primary group.
*
* <p>The result of this method depends on which method is configured for primary group calculation. It may not
* be the same as any value set through {@link #setPrimaryGroup(String)}.</p>
*
* @return the users primary group
*/
@Nonnull
String getPrimaryGroup();
/**
* Sets a users primary group
* 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(String group) throws ObjectAlreadyHasException;
@Nonnull
DataMutateResult setPrimaryGroup(@Nonnull String group);
/**
* Gets the user's {@link UserData} cache.
*
* @return the users cached data.
* @since 3.2
*/
@Nonnull
@Override
UserData getCachedData();
/**
* Refresh and re-assign the users permissions.
*
* <p>This request is not buffered, and the refresh call will be ran directly. This should ideally be called on
* an asynchronous thread.</p>
* <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
void refreshPermissions();
/**
* Gets the user's {@link UserData} cache, if they have one setup.
* Pre-calculates some values in the user's data cache.
*
* @return an optional, possibly containing the user's cached lookup data.
* @since 2.13
*/
Optional<UserData> getUserDataCache();
/**
* Sets up the users data cache, if the don't have one setup already.
* <p>Is it <b>not</b> necessary to call this method before
* using {@link #getCachedData()}.</p>
*
* @since 2.17
* @deprecated because use of this method is no longer necessary.
*/
@Deprecated
void setupDataCache();
/**
* Check to see if the user is a member of a group
*
* @param group The group to check membership of
* @return true if the user is a member of the group
* @throws NullPointerException if the group is null
*/
boolean isInGroup(Group group);
/**
* 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
*/
boolean isInGroup(Group group, 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
*/
boolean isInGroup(Group group, String server, 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(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(Group group, 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(Group group, String server, 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(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(Group group, 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(Group group, String server, 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(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(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(Group group, 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(Group group, String server, 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(Group group, 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(Group group, String server, 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
*/
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
*/
List<String> getLocalGroups(String server, 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
*/
List<String> getLocalGroups(String server);
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -24,35 +27,43 @@ package me.lucko.luckperms.api;
import java.util.UUID;
import javax.annotation.Nonnull;
/**
* A UUID cache for online users, between external Mojang UUIDs, and internal LuckPerms UUIDs.
* 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>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><strong>This is only effective for online players. Use {@link Storage#getUUID(String)} for offline players.</strong></p>
* @deprecated this feature is now handled internally - and the API returns a
* No-op implementation of this class.
*/
@Deprecated
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
*/
UUID getUUID(UUID external);
@Nonnull
@Deprecated
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
*/
UUID getExternalUUID(UUID internal);
@Nonnull
@Deprecated
UUID getExternalUUID(@Nonnull UUID internalUuid);
}
@@ -0,0 +1,425 @@
/*
* 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.caching;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.PermissionHolder;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import javax.annotation.Nonnull;
/**
* Holds cached permission and meta lookup data for a {@link PermissionHolder}.
*
* <p>All calls will account for inheritance, as well as any default data
* provided by the platform. This calls are heavily cached and are therefore
* fast.</p>
*
* <p>For meta, both methods accepting {@link Contexts} and {@link MetaContexts}
* are provided. The only difference is that the latter allows you to define
* how the meta stack should be structured internally. Where {@link Contexts}
* are passed, the values from the configuration are used.</p>
*
* @since 4.0
*/
public interface CachedData {
/**
* Gets PermissionData from the cache, given a specified context.
*
* @param contexts the contexts to get the permission data in
* @return a permission data instance
* @throws NullPointerException if contexts is null
*/
@Nonnull
PermissionData getPermissionData(@Nonnull Contexts contexts);
/**
* Gets MetaData from the cache, given a specified context.
*
* @param contexts the contexts to get the permission data in
* @return a meta data instance
* @throws NullPointerException if contexts is null
* @since 3.2
*/
@Nonnull
MetaData getMetaData(@Nonnull MetaContexts contexts);
/**
* Gets MetaData from the cache, given a specified context.
*
* @param contexts the contexts to get the permission data in
* @return a meta data instance
* @throws NullPointerException if contexts is null
*/
@Nonnull
MetaData getMetaData(@Nonnull Contexts contexts);
/**
* Calculates permission data, bypassing the cache.
*
* <p>The result of this operation is calculated each time the method is called.
* The result is not added to the internal cache.</p>
*
* <p>It is therefore highly recommended to use {@link #getPermissionData(Contexts)} instead.</p>
*
* <p>The use cases of this method are more around constructing one-time
* instances of {@link PermissionData}, without adding the result to the cache.</p>
*
* @param contexts the contexts to get permission data in
* @return a permission data instance
* @throws NullPointerException if contexts is null
*/
@Nonnull
PermissionData calculatePermissions(@Nonnull Contexts contexts);
/**
* Calculates meta data, bypassing the cache.
*
* <p>The result of this operation is calculated each time the method is called.
* The result is not added to the internal cache.</p>
*
* <p>It is therefore highly recommended to use {@link #getMetaData(MetaContexts)} instead.</p>
*
* <p>The use cases of this method are more around constructing one-time
* instances of {@link MetaData}, without adding the result to the cache.</p>
*
* @param contexts the contexts to get meta data in
* @return a meta data instance
* @throws NullPointerException if contexts is null
* @since 3.2
*/
@Nonnull
MetaData calculateMeta(@Nonnull MetaContexts contexts);
/**
* Calculates meta data, bypassing the cache.
*
* <p>The result of this operation is calculated each time the method is called.
* The result is not added to the internal cache.</p>
*
* <p>It is therefore highly recommended to use {@link #getMetaData(Contexts)} instead.</p>
*
* <p>The use cases of this method are more around constructing one-time
* instances of {@link MetaData}, without adding the result to the cache.</p>
*
* @param contexts the contexts to get meta data in
* @return a meta data instance
* @throws NullPointerException if contexts is null
*/
@Nonnull
MetaData calculateMeta(@Nonnull Contexts contexts);
/**
* (Re)calculates permission data for a given context.
*
* <p>This method returns immediately in all cases. The (re)calculation is
* performed asynchronously and applied to the cache in the background.</p>
*
* <p>If there was a previous {@link PermissionData} instance associated with
* the given {@link Contexts}, then that instance will continue to be returned by
* {@link #getPermissionData(Contexts)} until the recalculation is completed.</p>
*
* <p>If there was no value calculated and cached prior to the call of this
* method, then one will be calculated.</p>
*
* @param contexts the contexts to recalculate in.
* @throws NullPointerException if contexts is null
*/
void recalculatePermissions(@Nonnull Contexts contexts);
/**
* (Re)calculates meta data for a given context.
*
* <p>This method returns immediately in all cases. The (re)calculation is
* performed asynchronously and applied to the cache in the background.</p>
*
* <p>If there was a previous {@link MetaData} instance associated with
* the given {@link MetaContexts}, then that instance will continue to be returned by
* {@link #getMetaData(MetaContexts)} until the recalculation is completed.</p>
*
* <p>If there was no value calculated and cached prior to the call of this
* method, then one will be calculated.</p>
*
* @param contexts the contexts to recalculate in.
* @throws NullPointerException if contexts is null
* @since 3.2
*/
void recalculateMeta(@Nonnull MetaContexts contexts);
/**
* (Re)calculates meta data for a given context.
*
* <p>This method returns immediately in all cases. The (re)calculation is
* performed asynchronously and applied to the cache in the background.</p>
*
* <p>If there was a previous {@link MetaData} instance associated with
* the given {@link Contexts}, then that instance will continue to be returned by
* {@link #getMetaData(Contexts)} until the recalculation is completed.</p>
*
* <p>If there was no value calculated and cached prior to the call of this
* method, then one will be calculated.</p>
*
* @param contexts the contexts to recalculate in.
* @throws NullPointerException if contexts is null
*/
void recalculateMeta(@Nonnull Contexts contexts);
/**
* (Re)loads permission data for a given context.
*
* <p>Unlike {@link #recalculatePermissions(Contexts)}, this method immediately
* invalidates any previous {@link PermissionData} values contained within the cache,
* and then schedules a task to reload a new {@link PermissionData} instance to
* replace the one which was invalidated.</p>
*
* <p>The invalidation happens immediately during the execution of this method.
* The result of the re-computation encapsulated by the future.</p>
*
* <p>Subsequent calls to {@link #getPermissionData(Contexts)} will block until
* the result of this operation is complete.</p>
*
* <p>If there was no value calculated and cached prior to the call of this
* method, then one will be calculated.</p>
*
* <p>This method returns a Future so users can optionally choose to wait
* until the recalculation has been performed.</p>
*
* @param contexts the contexts to reload in.
* @throws NullPointerException if contexts is null
* @return a future
* @since 4.0
*/
@Nonnull
CompletableFuture<? extends PermissionData> reloadPermissions(@Nonnull Contexts contexts);
/**
* (Re)loads meta data for a given context.
*
* <p>Unlike {@link #recalculateMeta(MetaContexts)}, this method immediately
* invalidates any previous {@link MetaData} values contained within the cache,
* and then schedules a task to reload a new {@link MetaData} instance to
* replace the one which was invalidated.</p>
*
* <p>The invalidation happens immediately during the execution of this method.
* The result of the re-computation encapsulated by the future.</p>
*
* <p>Subsequent calls to {@link #getMetaData(MetaContexts)} will block until
* the result of this operation is complete.</p>
*
* <p>If there was no value calculated and cached prior to the call of this
* method, then one will be calculated.</p>
*
* <p>This method returns a Future so users can optionally choose to wait
* until the recalculation has been performed.</p>
*
* @param contexts the contexts to reload in.
* @throws NullPointerException if contexts is null
* @return a future
* @since 4.0
*/
@Nonnull
CompletableFuture<? extends MetaData> reloadMeta(@Nonnull MetaContexts contexts);
/**
* (Re)loads meta data for a given context.
*
* <p>Unlike {@link #recalculateMeta(Contexts)}, this method immediately
* invalidates any previous {@link MetaData} values contained within the cache,
* and then schedules a task to reload a new {@link MetaData} instance to
* replace the one which was invalidated.</p>
*
* <p>The invalidation happens immediately during the execution of this method.
* The result of the re-computation encapsulated by the future.</p>
*
* <p>Subsequent calls to {@link #getMetaData(Contexts)} will block until
* the result of this operation is complete.</p>
*
* <p>If there was no value calculated and cached prior to the call of this
* method, then one will be calculated.</p>
*
* <p>This method returns a Future so users can optionally choose to wait
* until the recalculation has been performed.</p>
*
* @param contexts the contexts to reload in.
* @throws NullPointerException if contexts is null
* @return a future
* @since 4.0
*/
@Nonnull
CompletableFuture<? extends MetaData> reloadMeta(@Nonnull Contexts contexts);
/**
* Recalculates permission data for all known contexts.
*
* <p>This method returns immediately. The recalculation is performed
* asynchronously and applied to the cache in the background.</p>
*
* <p>The previous {@link PermissionData} instances will continue to be returned
* by {@link #getPermissionData(Contexts)} until the recalculation is completed.</p>
*/
void recalculatePermissions();
/**
* Recalculates meta data for all known contexts.
*
* <p>This method returns immediately. The recalculation is performed
* asynchronously and applied to the cache in the background.</p>
*
* <p>The previous {@link MetaData} instances will continue to be returned
* by {@link #getMetaData(MetaContexts)} and {@link #getMetaData(Contexts)}
* until the recalculation is completed.</p>
*/
void recalculateMeta();
/**
* Reloads permission data for all known contexts.
*
* <p>Unlike {@link #recalculatePermissions()}, this method immediately
* invalidates all previous {@link PermissionData} values contained within the cache,
* and then schedules a task to reload a new {@link PermissionData} instances to
* replace the ones which were invalidated.</p>
*
* <p>The invalidation happens immediately during the execution of this method.
* The result of the re-computation encapsulated by the future.</p>
*
* <p>Subsequent calls to {@link #getPermissionData(Contexts)} will block until
* the result of this operation is complete.</p>
*
* <p>This method returns a Future so users can optionally choose to wait
* until the recalculation has been performed.</p>
*
* @return a future
* @since 4.0
*/
@Nonnull
CompletableFuture<Void> reloadPermissions();
/**
* Reloads meta data for all known contexts.
*
* <p>Unlike {@link #recalculateMeta()}, this method immediately
* invalidates all previous {@link MetaData} values contained within the cache,
* and then schedules a task to reload a new {@link MetaData} instances to
* replace the ones which were invalidated.</p>
*
* <p>The invalidation happens immediately during the execution of this method.
* The result of the re-computation encapsulated by the future.</p>
*
* <p>Subsequent calls to {@link #getMetaData(MetaContexts)} and
* {@link #getMetaData(Contexts)} will block until the result of this operation
* is complete.</p>
*
* <p>This method returns a Future so users can optionally choose to wait
* until the recalculation has been performed.</p>
*
* @return a future
* @since 4.0
*/
@Nonnull
CompletableFuture<Void> reloadMeta();
/**
* Pre-calculates and caches {@link PermissionData} and {@link MetaData}
* instances for the given contexts.
*
* <p>If the cache already contains a value for the given context,
* no action is taken.</p>
*
* <p>This method blocks until the calculation is completed.</p>
*
* @param contexts a set of contexts
* @throws NullPointerException if contexts is null
*/
default void preCalculate(@Nonnull Set<Contexts> contexts) {
contexts.forEach(this::preCalculate);
}
/**
* Pre-calculates and caches {@link PermissionData} and {@link MetaData}
* instances for a given context.
*
* <p>If the cache already contains a value for the given context,
* no action is taken.</p>
*
* <p>This method blocks until the calculation is completed.</p>
*
* @param contexts the contexts to pre-calculate for
* @throws NullPointerException if contexts is null
*/
void preCalculate(@Nonnull Contexts contexts);
/**
* Invalidates any cached {@link PermissionData} instances mapped to the given
* {@link Contexts}.
*
* @param contexts the contexts to invalidate for
* @since 4.0
*/
void invalidatePermissions(@Nonnull Contexts contexts);
/**
* Invalidates any cached {@link MetaData} instances mapped to the given
* {@link MetaContexts}.
*
* @param contexts the contexts to invalidate for
* @since 4.0
*/
void invalidateMeta(@Nonnull MetaContexts contexts);
/**
* Invalidates any cached {@link MetaData} instances mapped to the given
* {@link Contexts}.
*
* @param contexts the contexts to invalidate for
* @since 4.0
*/
void invalidateMeta(@Nonnull Contexts contexts);
/**
* Invalidates all cached {@link PermissionData} instances.
*
* @since 4.2
*/
void invalidatePermissions();
/**
* Invalidates all cached {@link MetaData} instances.
*
* @since 4.2
*/
void invalidateMeta();
/**
* Invalidates all of the underlying Permission calculators.
*
* <p>Can be called to allow for an update in defaults.</p>
*/
void invalidatePermissionCalculators();
}
@@ -0,0 +1,47 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api.caching;
import me.lucko.luckperms.api.Contexts;
import javax.annotation.Nonnull;
/**
* Holds cached lookup data in a specific set of contexts.
*
* @since 4.1
*/
public interface CachedDataContainer {
/**
* Gets the contexts this container is holding data for.
*
* @return the contexts this container is caching
*/
@Nonnull
Contexts getContexts();
}
@@ -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.api.caching;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Group;
/**
* Holds cached permission and meta lookup data for a {@link Group}.
*
* <p>All calls will account for inheritance, as well as any default data provided
* by the platform. This calls are heavily cached and are therefore fast.</p>
*
* <p>For meta, both methods accepting {@link Contexts} and {@link MetaContexts} are provided. The only difference is that
* the latter allows you to define how the meta stack should be structured internally. Where {@link Contexts} are passed, the
* values from the configuration are used.</p>
*
* @since 4.0
*/
public interface GroupData extends CachedData {
}
@@ -0,0 +1,123 @@
/*
* 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.caching;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.metastacking.MetaStackDefinition;
import java.util.Objects;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
/**
* Encapsulates the options and settings for a meta lookup.
*
* <p>Consists of a standard {@link Contexts} element, plus options to define how
* the meta stack should be constructed.</p>
*
* @since 3.2
*/
@Immutable
public final class MetaContexts {
/**
* Creates a new meta contexts instance
*
* @param contexts the standard contexts for the query
* @param prefixStackDefinition the prefix stack definition to be used
* @param suffixStackDefinition the suffix stack definition to be used
* @return the new instance
*/
public static MetaContexts of(@Nonnull Contexts contexts, @Nonnull MetaStackDefinition prefixStackDefinition, @Nonnull MetaStackDefinition suffixStackDefinition) {
return new MetaContexts(contexts, prefixStackDefinition, suffixStackDefinition);
}
private final Contexts contexts;
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
*
* @param contexts the standard contexts for the query
* @param prefixStackDefinition the prefix stack definition to be used
* @param suffixStackDefinition the suffix stack definition to be used
*/
public MetaContexts(@Nonnull Contexts contexts, @Nonnull MetaStackDefinition prefixStackDefinition, @Nonnull MetaStackDefinition suffixStackDefinition) {
this.contexts = Objects.requireNonNull(contexts, "contexts");
this.prefixStackDefinition = Objects.requireNonNull(prefixStackDefinition, "prefixStackDefinition");
this.suffixStackDefinition = Objects.requireNonNull(suffixStackDefinition, "suffixStackDefinition");
this.hashCode = calculateHashCode();
}
@Nonnull
public Contexts getContexts() {
return this.contexts;
}
@Nonnull
public MetaStackDefinition getPrefixStackDefinition() {
return this.prefixStackDefinition;
}
@Nonnull
public MetaStackDefinition getSuffixStackDefinition() {
return this.suffixStackDefinition;
}
@Override
@Nonnull
public String toString() {
return "MetaContexts(" +
"contexts=" + this.getContexts() + ", " +
"prefixStackDefinition=" + this.getPrefixStackDefinition() + ", " +
"suffixStackDefinition=" + this.getSuffixStackDefinition() +
")";
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof MetaContexts)) return false;
final MetaContexts that = (MetaContexts) o;
return this.contexts.equals(that.contexts) &&
this.prefixStackDefinition.equals(that.prefixStackDefinition) &&
this.suffixStackDefinition.equals(that.suffixStackDefinition);
}
private int calculateHashCode() {
return Objects.hash(this.contexts, this.prefixStackDefinition, this.suffixStackDefinition);
}
@Override
public int hashCode() {
return this.hashCode;
}
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -22,21 +25,55 @@
package me.lucko.luckperms.api.caching;
import com.google.common.collect.ListMultimap;
import me.lucko.luckperms.api.metastacking.MetaStackDefinition;
import java.util.Map;
import java.util.SortedMap;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Holds cached Meta lookup data for a specific set of contexts
* Holds cached meta lookup data for a specific set of contexts.
*
* @since 2.13
*/
public interface MetaData {
public interface MetaData extends CachedDataContainer {
/**
* Gets an immutable copy of the meta this user has
* Gets the contexts this container is holding data for.
*
* @return the contexts this container is caching
*/
@Nonnull
MetaContexts getMetaContexts();
/**
* Gets an immutable copy of the meta this user has.
*
* <p>A list multimap is used because when inherited values are included, each key can be
* mapped to multiple values.</p>
*
* <p>The first value to be accumulated (and used to represent the key in {@link #getMeta()} is at index 0
* in the list. Any additional values are stored in order of accumulation.</p>
*
* @return an immutable multimap of meta
* @since 3.3
*/
@Nonnull
ListMultimap<String, String> getMetaMultimap();
/**
* Gets an immutable copy of the meta this user has.
*
* <p>This map is formed by taking the entries in {@link #getMetaMultimap()}, and mapping each key
* to the value at index 0 in the corresponding list.</p>
*
* @return an immutable map of meta
*/
@Nonnull
Map<String, String> getMeta();
/**
@@ -45,6 +82,7 @@ public interface MetaData {
*
* @return a sorted map of prefixes
*/
@Nonnull
SortedMap<Integer, String> getPrefixes();
/**
@@ -53,6 +91,7 @@ public interface MetaData {
*
* @return a sorted map of suffixes
*/
@Nonnull
SortedMap<Integer, String> getSuffixes();
/**
@@ -60,6 +99,7 @@ public interface MetaData {
*
* @return a prefix string, or null
*/
@Nullable
String getPrefix();
/**
@@ -67,6 +107,25 @@ public interface MetaData {
*
* @return a suffix string, or null
*/
@Nullable
String getSuffix();
/**
* Gets the definition used for the prefix stack
*
* @return the definition used for the prefix stack
* @since 3.2
*/
@Nonnull
MetaStackDefinition getPrefixStackDefinition();
/**
* Gets the definition used for the suffix stack
*
* @return the definition used for the suffix stack
* @since 3.2
*/
@Nonnull
MetaStackDefinition getSuffixStackDefinition();
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -26,21 +29,24 @@ import me.lucko.luckperms.api.Tristate;
import java.util.Map;
import javax.annotation.Nonnull;
/**
* Holds cached Permission lookup data for a specific set of contexts
* Holds cached permission lookup data for a specific set of contexts.
*
* @since 2.13
*/
public interface PermissionData {
public interface PermissionData extends CachedDataContainer {
/**
* Gets a permission value for the given permission node
* Gets a permission check result for the given permission node.
*
* @param permission the permission node
* @return a tristate result
* @throws NullPointerException if permission is null
*/
Tristate getPermissionValue(String permission);
@Nonnull
Tristate getPermissionValue(@Nonnull String permission);
/**
* Invalidates the underlying permission calculator cache.
@@ -54,6 +60,7 @@ public interface PermissionData {
*
* @return an immutable set of permissions
*/
@Nonnull
Map<String, Boolean> getImmutableBacking();
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -23,114 +26,20 @@
package me.lucko.luckperms.api.caching;
import me.lucko.luckperms.api.Contexts;
import java.util.Set;
import me.lucko.luckperms.api.User;
/**
* Holds cached permission and meta lookup data for a {@link me.lucko.luckperms.api.User}.
* Holds cached permission and meta lookup data for a {@link User}.
*
* <p>Data is only likely to be available for online users. All calls will account for inheritance, as well as any
* default data provided by the platform. This calls are heavily cached and are therefore fast.</p>
* <p>All calls will account for inheritance, as well as any default data provided by
* the platform. This calls are heavily cached and are therefore fast.</p>
*
* <p>For meta, both methods accepting {@link Contexts} and {@link MetaContexts} are provided. The only difference is that
* the latter allows you to define how the meta stack should be structured internally. Where {@link Contexts} are passed, the
* values from the configuration are used.</p>
*
* @since 2.13
*/
public interface UserData {
/**
* Gets PermissionData from the cache, given a specified context.
*
* <p>If the data is not cached, it is calculated. Therefore, this call could be costly.</p>
*
* @param contexts the contexts to get the permission data in
* @return a permission data instance
* @throws NullPointerException if contexts is null
*/
PermissionData getPermissionData(Contexts contexts);
/**
* Gets MetaData from the cache, given a specified context.
*
* <p>If the data is not cached, it is calculated. Therefore, this call could be costly.</p>
*
* @param contexts the contexts to get the permission data in
* @return a meta data instance
* @throws NullPointerException if contexts is null
*/
MetaData getMetaData(Contexts contexts);
/**
* Calculates permission data, bypassing the cache.
*
* @param contexts the contexts to get permission data in
* @return a permission data instance
* @throws NullPointerException if contexts is null
*/
PermissionData calculatePermissions(Contexts contexts);
/**
* Calculates meta data, bypassing the cache.
*
* @param contexts the contexts to get meta data in
* @return a meta data instance
* @throws NullPointerException if contexts is null
*/
MetaData calculateMeta(Contexts contexts);
/**
* Calculates permission data and stores it in the cache.
*
* <p>If there is already data cached for the given contexts, and if the resultant output is different,
* the cached value is updated.</p>
*
* @param contexts the contexts to recalculate in.
* @throws NullPointerException if contexts is null
*/
void recalculatePermissions(Contexts contexts);
/**
* Calculates meta data and stores it in the cache.
*
* <p>If there is already data cached for the given contexts, and if the resultant output is different,
* the cached value is updated.</p>
*
* @param contexts the contexts to recalculate in.
* @throws NullPointerException if contexts is null
*/
void recalculateMeta(Contexts contexts);
/**
* Calls {@link #recalculatePermissions(Contexts)} for all current loaded contexts
*/
void recalculatePermissions();
/**
* Calls {@link #recalculateMeta(Contexts)} for all current loaded contexts
*/
void recalculateMeta();
/**
* Calls {@link #preCalculate(Contexts)} for the given contexts
*
* @param contexts a set of contexts
* @throws NullPointerException if contexts is null
*/
void preCalculate(Set<Contexts> contexts);
/**
* Ensures that PermissionData and MetaData is cached for a context.
*
* <p>If the cache does not contain any data for the context, it will be calculated and saved.</p>
*
* @param contexts the contexts to pre-calculate for
* @throws NullPointerException if contexts is null
*/
void preCalculate(Contexts contexts);
/**
* Invalidates all of the underlying Permission calculators.
*
* <p>Can be called to allow for an update in defaults.</p>
*/
void invalidatePermissionCalculators();
public interface UserData extends CachedData {
}
@@ -0,0 +1,121 @@
/*
* 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 com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.common.collect.SetMultimap;
import java.util.Collection;
import java.util.Objects;
import java.util.Set;
import javax.annotation.Nonnull;
abstract class AbstractContextSet implements ContextSet {
protected abstract SetMultimap<String, String> backing();
protected abstract void copyTo(SetMultimap<String, String> other);
@Override
public boolean containsKey(@Nonnull String key) {
return backing().containsKey(sanitizeKey(key));
}
@Nonnull
@Override
public Set<String> getValues(@Nonnull String key) {
Collection<String> values = backing().asMap().get(sanitizeKey(key));
return values != null ? ImmutableSet.copyOf(values) : ImmutableSet.of();
}
@Override
public boolean has(@Nonnull String key, @Nonnull String value) {
return backing().containsEntry(sanitizeKey(key), sanitizeValue(value));
}
@Override
public boolean isEmpty() {
return backing().isEmpty();
}
@Override
public int size() {
return backing().size();
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof ContextSet)) return false;
final ContextSet that = (ContextSet) o;
final Multimap<String, String> otherContexts;
if (that instanceof AbstractContextSet) {
otherContexts = ((AbstractContextSet) that).backing();
} else {
otherContexts = that.toMultimap();
}
return backing().equals(otherContexts);
}
@Override
public int hashCode() {
return backing().hashCode();
}
static String sanitizeKey(String key) {
Objects.requireNonNull(key, "key is null");
if (stringIsEmpty(key)) {
throw new IllegalArgumentException("key is (effectively) empty");
}
return key.toLowerCase();
}
static String sanitizeValue(String value) {
Objects.requireNonNull(value, "value is null");
if (stringIsEmpty(value)) {
throw new IllegalArgumentException("value is (effectively) empty");
}
return value.toLowerCase();
}
private static boolean stringIsEmpty(String s) {
if (s.isEmpty()) {
return true;
}
for (char c : s.toCharArray()) {
if (c != ' ') {
return false;
}
}
return true;
}
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -22,12 +25,15 @@
package me.lucko.luckperms.api.context;
import javax.annotation.Nonnull;
/**
* Calculates whether contexts are applicable to {@link T}
* Calculates whether contexts are applicable to a {@link T subject}.
*
* @param <T> the subject type. Is ALWAYS the player class of the platform.
* @since 2.13
*/
@FunctionalInterface
public interface ContextCalculator<T> {
/**
@@ -38,6 +44,7 @@ public interface ContextCalculator<T> {
* @return the map
* @since 2.13
*/
MutableContextSet giveApplicableContext(T subject, MutableContextSet accumulator);
@Nonnull
MutableContextSet giveApplicableContext(@Nonnull T subject, @Nonnull MutableContextSet accumulator);
}
@@ -0,0 +1,174 @@
/*
* 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:
*
* <p></p>
* <ul>
* <li>{@code org.bukkit.entity.Player}</li>
* <li>{@code net.md_5.bungee.api.connection.ProxiedPlayer}</li>
* <li>{@code org.spongepowered.api.service.permission.Subject}</li>
* </ul>
*
* @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
*/
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
*/
void registerStaticCalculator(@Nonnull StaticContextCalculator calculator);
/**
* Invalidates the lookup cache for a given subject
*
* @param subject the subject
*/
void invalidateCache(@Nonnull Object subject);
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -24,33 +27,57 @@ package me.lucko.luckperms.api.context;
import com.google.common.collect.Multimap;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import javax.annotation.Nonnull;
/**
* Holder of contexts.
* A set of contexts.
*
* <p>Implementations may be either mutable or immutable.</p>
* <p>Context in the most basic sense simply means the circumstances where
* something will apply.</p>
*
* <p>A single "context" consists of a key and a value, both strings. The key
* represents the type of context, and the value represents the setting of the
* context key.</p>
*
* <p>Contexts can be combined with each other to form so called
* "context sets" - simply a collection of context pairs.</p>
*
* <p>Context keys and values are case-insensitive, and will be converted to
* {@link String#toLowerCase() lowercase} by all implementations.</p>
*
* <p>Context keys and values may not be null or empty. A key/value will be
* deemed empty if it's length is zero, or if it consists of only space
* characters.</p>
*
* <p>Two default ContextSet implementations are provided.
* {@link MutableContextSet} allows the addition and removal of context keys
* after construction, and {@link ImmutableContextSet} does not.</p>
*
* @since 2.13
*/
public interface ContextSet {
public interface ContextSet extends Iterable<Map.Entry<String, String>> {
/**
* Creates an ImmutableContextSet from a context pair
* Creates an {@link ImmutableContextSet} from a context pair.
*
* @param key the key
* @param value the value
* @return a new ImmutableContextSet containing one KV pair
* @return a new ImmutableContextSet containing one context pair
* @throws NullPointerException if key or value is null
*/
static ImmutableContextSet singleton(String key, String value) {
@Nonnull
static ImmutableContextSet singleton(@Nonnull String key, @Nonnull String value) {
return ImmutableContextSet.singleton(key, value);
}
/**
* Creates an ImmutableContextSet from two context pairs
* Creates an {@link ImmutableContextSet} from two context pairs.
*
* @param key1 the first key
* @param value1 the first value
@@ -60,169 +87,242 @@ public interface ContextSet {
* @throws NullPointerException if any of the keys or values are null
* @since 3.1
*/
static ImmutableContextSet of(String key1, String value1, String key2, String value2) {
@Nonnull
static ImmutableContextSet of(@Nonnull String key1, @Nonnull String value1, @Nonnull String key2, @Nonnull String value2) {
return ImmutableContextSet.of(key1, value1, key2, value2);
}
/**
* Creates an ImmutableContextSet from an existing map
*
* @param map the map to copy from
* @return a new ImmutableContextSet representing the pairs from the map
* @throws NullPointerException if the map is null
*/
static ImmutableContextSet fromMap(Map<String, String> map) {
return ImmutableContextSet.fromMap(map);
}
/**
* Creates an ImmutableContextSet from an existing iterable of Map Entries
* Creates an {@link ImmutableContextSet} from an existing {@link Iterable} of {@link Map.Entry}s.
*
* @param iterable the iterable to copy from
* @return a new ImmutableContextSet representing the pairs in the iterable
* @throws NullPointerException if the iterable is null
*/
static ImmutableContextSet fromEntries(Iterable<? extends Map.Entry<String, String>> iterable) {
@Nonnull
static ImmutableContextSet fromEntries(@Nonnull Iterable<? extends Map.Entry<String, String>> iterable) {
return ImmutableContextSet.fromEntries(iterable);
}
/**
* Creates an ImmutableContextSet from an existing multimap
* Creates an {@link ImmutableContextSet} from an existing {@link 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 {@link ImmutableContextSet} from an existing {@link Multimap}.
*
* @param multimap the multimap to copy from
* @return a new ImmutableContextSet representing the pairs in the multimap
* @throws NullPointerException if the multimap is null
* @since 2.16
*/
static ImmutableContextSet fromMultimap(Multimap<String, String> multimap) {
@Nonnull
static ImmutableContextSet fromMultimap(@Nonnull Multimap<String, String> multimap) {
return ImmutableContextSet.fromMultimap(multimap);
}
/**
* Creates an new ImmutableContextSet from an existing set.
* Only really useful for converting between mutable and immutable types.
* Creates an new {@link ImmutableContextSet} from an existing {@link Set}.
*
* <p>Only really useful for converting between mutable and immutable types.</p>
*
* @param contextSet the context set to copy from
* @return a new ImmutableContextSet with the same content and the one provided
* @throws NullPointerException if contextSet is null
*/
static ImmutableContextSet fromSet(ContextSet contextSet) {
@Nonnull
static ImmutableContextSet fromSet(@Nonnull ContextSet contextSet) {
return ImmutableContextSet.fromSet(contextSet);
}
/**
* Creates a new empty ImmutableContextSet.
* Returns an empty {@link ImmutableContextSet}.
*
* @return a new ImmutableContextSet
* @return an empty ImmutableContextSet
*/
@Nonnull
static ImmutableContextSet empty() {
return ImmutableContextSet.empty();
}
/**
* Check to see if this set is in an immutable form
* Gets if this {@link ContextSet} is immutable.
*
* <p>The state of immutable instances will never change.</p>
*
* @return true if the set is immutable
*/
boolean isImmutable();
/**
* If the set is mutable, this method will return an immutable copy. Otherwise just returns itself.
* Returns an immutable representation of this {@link ContextSet}.
*
* @return an immutable ContextSet
* <p>If the set is already immutable, the same object will be returned.
* If the set is mutable, an immutable copy will be made.</p>
*
* @return an immutable representation of this set
*/
@Nonnull
ImmutableContextSet makeImmutable();
/**
* Creates a mutable copy of this set.
* Creates a mutable copy of this {@link ContextSet}.
*
* <p>A new copy is returned regardless of the
* {@link #isImmutable() mutability} of this set.</p>
*
* @return a mutable ContextSet
* @since 2.16
*/
@Nonnull
MutableContextSet mutableCopy();
/**
* Converts this ContextSet to an immutable {@link Set} of {@link Map.Entry}s.
* Returns a {@link Set} of {@link Map.Entry}s representing the current
* state of this {@link ContextSet}.
*
* <p>The returned set is immutable, and is a copy of the current set.
* (will not update live)</p>
*
* @return an immutable set
*/
@Nonnull
Set<Map.Entry<String, String>> toSet();
/**
* Converts this ContextSet to an immutable {@link Map}
* Returns a {@link Map} <b>loosely</b> representing the current state of
* this {@link ContextSet}.
*
* <b>NOTE: Use of this method may result in data being lost. ContextSets can contain lots of different values for
* one key.</b>
* <p>The returned map is immutable, and is a copy of the current set.
* (will not update live)</p>
*
* <p>As a single context key can be mapped to multiple values, this method
* may not be a true representation of the set.</p>
*
* <p>If you need a representation of the set in a Java collection instance,
* use {@link #toSet()} or {@link #toMultimap()} followed by
* {@link Multimap#asMap()}.</p>
*
* @return an immutable map
* @deprecated because the resultant map may not contain all data in the ContextSet
*/
@Nonnull
@Deprecated
Map<String, String> toMap();
/**
* Converts this ContextSet to an immutable {@link Multimap}
* Returns a {@link Multimap} representing the current state of this
* {@link ContextSet}.
*
* <p>The returned multimap is immutable, and is a copy of the current set.
* (will not update live)</p>
*
* @return a multimap
* @since 2.16
*/
@Nonnull
Multimap<String, String> toMultimap();
/**
* Check if the set contains at least one value for the given key.
* Returns an {@link Iterator} over each of the context pairs in this set.
*
* <p>The returned iterator represents the state of the set at the time of creation. It is not
* updated as the set changes.</p>
*
* <p>The iterator does not support {@link Iterator#remove()} calls.</p>
*
* @return an iterator
*/
@Nonnull
@Override
Iterator<Map.Entry<String, String>> iterator();
/**
* Returns if the {@link ContextSet} contains at least one value for the
* given key.
*
* @param key the key to check for
* @return true if the set contains a value for the key
* @throws NullPointerException if the key is null
*/
boolean containsKey(String key);
boolean containsKey(@Nonnull String key);
/**
* Gets a set of all of the values mapped to the given key
* Returns a {@link Set} of the values mapped to the given key.
*
* @param key the key to find values for
* <p>The returned set is immutable, and only represents the current state
* of the {@link ContextSet}. (will not update live)</p>
*
* @param key the key to get values for
* @return a set of values
* @throws NullPointerException if the key is null
*/
Set<String> getValues(String key);
@Nonnull
Set<String> getValues(@Nonnull String key);
/**
* Returns any value from this set matching the key, if present.
* Returns any value from this {@link ContextSet} matching the key, if present.
*
* <p>Note that context keys can be mapped to multiple values.
* Use {@link #getValues(String)} to retrieve all associated values.</p>
*
* @param key the key to find values for
* @return an optional containing any match
* @since 3.1
*/
default Optional<String> getAnyValue(String key) {
@Nonnull
default Optional<String> getAnyValue(@Nonnull String key) {
return getValues(key).stream().findAny();
}
/**
* Check if thr set contains a given key mapped to a given value
*
* @param key the key to look for
* @param value the value to look for (case sensitive)
* @return true if the set contains the KV pair
* @throws NullPointerException if the key or value is null
*/
boolean has(String key, String value);
/**
* Same as {@link #has(String, String)}, except ignores the case of the value.
* Returns if the {@link ContextSet} contains a given context pairing.
*
* @param key the key to look for
* @param value the value to look for
* @return true if the set contains the KV pair
* @return true if the set contains the context pair
* @throws NullPointerException if the key or value is null
*/
boolean hasIgnoreCase(String key, String value);
boolean has(@Nonnull String key, @Nonnull String value);
/**
* Checks to see if all entries in this context set are also included in another set.
* Returns if the {@link ContextSet} contains a given context pairing.
*
* @param entry the entry to look for
* @return true if the set contains the context pair
* @throws NullPointerException if the key or value is null
*/
default boolean has(@Nonnull Map.Entry<String, String> entry) {
Objects.requireNonNull(entry, "entry");
return has(entry.getKey(), entry.getValue());
}
/**
* Returns if this {@link ContextSet} is fully "satisfied" by another set.
*
* <p>For a context set to "satisfy" another, it must itself contain all of
* the context pairings in the other set.</p>
*
* <p>Mathematically, this method returns true if this set is a <b>subset</b> of the other.</p>
*
* @param other the other set to check
* @return true if all entries in this set are also in the other set
* @since 3.1
*/
default boolean isSatisfiedBy(ContextSet other) {
default boolean isSatisfiedBy(@Nonnull ContextSet other) {
if (this == other) {
return true;
}
Objects.requireNonNull(other, "other");
if (this.isEmpty()) {
// this is empty, so is therefore always satisfied.
return true;
@@ -234,25 +334,24 @@ public interface ContextSet {
return false;
} else {
// neither are empty, we need to compare the individual entries
for (Map.Entry<String, String> pair : toSet()) {
if (!other.has(pair.getKey(), pair.getValue())) {
for (Map.Entry<String, String> context : toSet()) {
if (!other.has(context)) {
return false;
}
}
return true;
}
}
/**
* Check if the set is empty
* Returns if the {@link ContextSet} is empty.
*
* @return true if the set is empty
*/
boolean isEmpty();
/**
* Gets the number of key-value context pairs in the set
* Gets the number of context pairs in the {@link ContextSet}.
*
* @return the size of the set
*/
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -23,44 +26,54 @@
package me.lucko.luckperms.api.context;
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.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.Spliterator;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
/**
* An immutable implementation of {@link ContextSet}.
*
* @since 2.16
*/
public final class ImmutableContextSet implements ContextSet {
@Immutable
public final class ImmutableContextSet extends AbstractContextSet implements ContextSet {
private static final ImmutableContextSet EMPTY = new ImmutableContextSet(ImmutableSetMultimap.of());
/**
* Creates an ImmutableContextSet from a context pair
* Creates an {@link ImmutableContextSet.Builder}.
*
* @param key the key
* @param value the value
* @return a new ImmutableContextSet containing one KV pair
* @throws NullPointerException if key or value is null
* @return a new ImmutableContextSet builder
* @since 4.1
*/
public static ImmutableContextSet singleton(String key, String value) {
if (key == null) {
throw new NullPointerException("key");
}
if (value == null) {
throw new NullPointerException("value");
}
return new ImmutableContextSet(ImmutableSetMultimap.of(key.toLowerCase(), value));
@Nonnull
public static Builder builder() {
return new Builder();
}
/**
* Creates an ImmutableContextSet from two context pairs
* Creates an {@link ImmutableContextSet} from a context pair.
*
* @param key the key
* @param value the value
* @return a new ImmutableContextSet containing one context pair
* @throws NullPointerException if key or value is null
*/
@Nonnull
public static ImmutableContextSet singleton(@Nonnull String key, @Nonnull String value) {
return new ImmutableContextSet(ImmutableSetMultimap.of(sanitizeKey(key), sanitizeValue(value)));
}
/**
* Creates an {@link ImmutableContextSet} from two context pairs.
*
* @param key1 the first key
* @param value1 the first value
@@ -70,98 +83,98 @@ public final class ImmutableContextSet implements ContextSet {
* @throws NullPointerException if any of the keys or values are null
* @since 3.1
*/
public static ImmutableContextSet of(String key1, String value1, String key2, String value2) {
if (key1 == null) {
throw new NullPointerException("key1");
}
if (value1 == null) {
throw new NullPointerException("value1");
}
if (key2 == null) {
throw new NullPointerException("key2");
}
if (value2 == null) {
throw new NullPointerException("value2");
}
return new ImmutableContextSet(ImmutableSetMultimap.of(key1.toLowerCase(), value1, key2.toLowerCase(), value2));
@Nonnull
public static ImmutableContextSet of(@Nonnull String key1, @Nonnull String value1, @Nonnull String key2, @Nonnull String value2) {
return new ImmutableContextSet(ImmutableSetMultimap.of(
sanitizeKey(key1),
sanitizeValue(value1),
sanitizeKey(key2),
sanitizeValue(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
*/
public static ImmutableContextSet fromMap(Map<String, String> map) {
if (map == null) {
throw new NullPointerException("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());
}
/**
* Creates an ImmutableContextSet from an existing iterable of Map Entries
* Creates an {@link ImmutableContextSet} from an existing {@link Iterable} of {@link Map.Entry}s.
*
* @param iterable the iterable to copy from
* @return a new ImmutableContextSet representing the pairs in the iterable
* @throws NullPointerException if the iterable is null
*/
public static ImmutableContextSet fromEntries(Iterable<? extends Map.Entry<String, String>> iterable) {
if (iterable == null) {
throw new NullPointerException("iterable");
@Nonnull
public static ImmutableContextSet fromEntries(@Nonnull Iterable<? extends Map.Entry<String, String>> iterable) {
Objects.requireNonNull(iterable, "iterable");
ImmutableContextSet.Builder builder = builder();
for (Map.Entry<String, String> entry : iterable) {
builder.add(entry);
}
return MutableContextSet.fromEntries(iterable).makeImmutable();
return builder.build();
}
/**
* Creates an ImmutableContextSet from an existing multimap
* Creates an {@link ImmutableContextSet} from an existing {@link 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(Objects.requireNonNull(map, "map").entrySet());
}
/**
* Creates an {@link ImmutableContextSet} from an existing {@link Multimap}.
*
* @param multimap the multimap to copy from
* @return a new ImmutableContextSet representing the pairs in the multimap
* @throws NullPointerException if the multimap is null
* @since 2.16
*/
public static ImmutableContextSet fromMultimap(Multimap<String, String> multimap) {
if (multimap == null) {
throw new NullPointerException("multimap");
}
return MutableContextSet.fromMultimap(multimap).makeImmutable();
@Nonnull
public static ImmutableContextSet fromMultimap(@Nonnull Multimap<String, String> multimap) {
return fromEntries(Objects.requireNonNull(multimap, "multimap").entries());
}
/**
* Creates a new ImmutableContextSet from an existing set.
* Only really useful for converting between mutable and immutable types.
* Creates an new {@link ImmutableContextSet} from an existing {@link Set}.
*
* <p>Only really useful for converting between mutable and immutable types.</p>
*
* @param contextSet the context set to copy from
* @return a new ImmutableContextSet with the same content and the one provided
* @throws NullPointerException if contextSet is null
*/
public static ImmutableContextSet fromSet(ContextSet contextSet) {
return contextSet.makeImmutable();
@Nonnull
public static ImmutableContextSet fromSet(@Nonnull ContextSet contextSet) {
return Objects.requireNonNull(contextSet, "contextSet").makeImmutable();
}
/**
* Creates an new empty ContextSet.
* Returns an empty {@link ImmutableContextSet}.
*
* @return a new ContextSet
* @return an empty ImmutableContextSet
*/
@Nonnull
public static ImmutableContextSet empty() {
return EMPTY;
}
private final SetMultimap<String, String> map;
private final ImmutableSetMultimap<String, String> map;
private final int hashCode;
ImmutableContextSet(Multimap<String, String> contexts) {
this.map = ImmutableSetMultimap.copyOf(contexts);
ImmutableContextSet(ImmutableSetMultimap<String, String> contexts) {
this.map = contexts;
this.hashCode = this.map.hashCode();
}
@Override
protected SetMultimap<String, String> backing() {
return this.map;
}
@Override
protected void copyTo(SetMultimap<String, String> other) {
other.putAll(this.map);
}
@Override
@@ -169,118 +182,196 @@ public final class ImmutableContextSet implements ContextSet {
return true;
}
@Nonnull
@Override
@Deprecated // This set is already immutable!
public ImmutableContextSet makeImmutable() {
return this;
}
@Nonnull
@Override
public MutableContextSet mutableCopy() {
return MutableContextSet.fromSet(this);
}
@Nonnull
@Override
public Set<Map.Entry<String, String>> toSet() {
return ImmutableSet.copyOf(map.entries());
return this.map.entries();
}
@Nonnull
@Override
@Deprecated
public Map<String, String> toMap() {
ImmutableMap.Builder<String, String> m = ImmutableMap.builder();
for (Map.Entry<String, String> e : map.entries()) {
for (Map.Entry<String, String> e : this.map.entries()) {
m.put(e.getKey(), e.getValue());
}
return m.build();
}
@Nonnull
@Override
public Multimap<String, String> toMultimap() {
return map;
return this.map;
}
@Nonnull
@Override
public Iterator<Map.Entry<String, String>> iterator() {
return this.map.entries().iterator();
}
@Override
public boolean containsKey(String key) {
if (key == null) {
throw new NullPointerException("key");
}
return map.containsKey(key);
}
@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();
}
@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);
}
@Override
public boolean hasIgnoreCase(String key, String value) {
if (key == null) {
throw new NullPointerException("key");
}
if (value == null) {
throw new NullPointerException("value");
}
Collection<String> c = map.get(key);
if (c == null || c.isEmpty()) {
return false;
}
for (String val : c) {
if (val.equalsIgnoreCase(value)) {
return true;
}
}
return false;
}
@Override
public boolean isEmpty() {
return map.isEmpty();
}
@Override
public int size() {
return map.size();
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
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);
public Spliterator<Map.Entry<String, String>> spliterator() {
return this.map.entries().spliterator();
}
@Override
public int hashCode() {
return 59 + (this.map == null ? 43 : this.map.hashCode());
return this.hashCode;
}
@Override
public String toString() {
return "ImmutableContextSet(contexts=" + this.map + ")";
}
/**
* A builder for {@link ImmutableContextSet}.
*
* @since 4.1
*/
public static final class Builder {
private ImmutableSetMultimap.Builder<String, String> builder;
private Builder() {
}
private synchronized ImmutableSetMultimap.Builder<String, String> builder() {
if (this.builder == null) {
this.builder = ImmutableSetMultimap.builder();
}
return this.builder;
}
private void put(String key, String value) {
builder().put(key, value);
}
/**
* Adds a context to the set.
*
* @param key the key to add
* @param value the value to add
* @return the builder
* @throws NullPointerException if the key or value is null
* @see MutableContextSet#add(String, String)
*/
@Nonnull
public Builder add(@Nonnull String key, @Nonnull String value) {
put(sanitizeKey(key), sanitizeValue(value));
return this;
}
/**
* Adds a context to the set.
*
* @param entry the entry to add
* @return the builder
* @throws NullPointerException if the entry is null
* @see MutableContextSet#add(Map.Entry)
*/
@Nonnull
public Builder add(@Nonnull Map.Entry<String, String> entry) {
Objects.requireNonNull(entry, "entry");
add(entry.getKey(), entry.getValue());
return this;
}
/**
* Adds the contexts contained in the given {@link Iterable} to the set.
*
* @param iterable an iterable of key value context pairs
* @return the builder
* @throws NullPointerException if iterable is null
* @see MutableContextSet#addAll(Iterable)
*/
@Nonnull
public Builder addAll(@Nonnull Iterable<? extends Map.Entry<String, String>> iterable) {
for (Map.Entry<String, String> e : Objects.requireNonNull(iterable, "iterable")) {
add(e);
}
return this;
}
/**
* Adds the contexts contained in the given {@link Map} to the set.
*
* @param map the map to add from
* @return the builder
* @throws NullPointerException if the map is null
* @see MutableContextSet#addAll(Map)
*/
@Nonnull
public Builder addAll(@Nonnull Map<String, String> map) {
addAll(Objects.requireNonNull(map, "map").entrySet());
return this;
}
/**
* Adds the contexts contained in the given {@link Multimap} to the set.
*
* @param multimap the multimap to add from
* @return the builder
* @throws NullPointerException if the map is null
* @since 3.4
* @see MutableContextSet#addAll(Multimap)
*/
@Nonnull
public Builder addAll(@Nonnull Multimap<String, String> multimap) {
addAll(Objects.requireNonNull(multimap, "multimap").entries());
return this;
}
/**
* Adds of of the contexts in another {@link ContextSet} to the set.
*
* @param contextSet the set to add from
* @return the builder
* @throws NullPointerException if the contextSet is null
* @see MutableContextSet#addAll(ContextSet)
*/
@Nonnull
public Builder addAll(@Nonnull ContextSet contextSet) {
Objects.requireNonNull(contextSet, "contextSet");
if (contextSet instanceof AbstractContextSet) {
AbstractContextSet other = ((AbstractContextSet) contextSet);
if (!other.isEmpty()) {
builder().putAll(other.backing());
}
} else {
addAll(contextSet.toMultimap());
}
return this;
}
/**
* Creates a {@link ImmutableContextSet} from the values previously
* added to the builder.
*
* @return an {@link ImmutableContextSet} from the builder
*/
@Nonnull
public ImmutableContextSet build() {
if (this.builder == null) {
return empty();
} else {
return new ImmutableContextSet(this.builder.build());
}
}
}
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -30,40 +33,40 @@ import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.SetMultimap;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.Spliterator;
import javax.annotation.Nonnull;
/**
* A mutable implementation of {@link ContextSet}.
*
* @since 2.16
*/
public final class MutableContextSet implements ContextSet {
public final class MutableContextSet extends AbstractContextSet implements ContextSet {
/**
* Make a singleton MutableContextSet from a context pair
* Creates a {@link MutableContextSet} from a context pair.
*
* @param key the key
* @param value the value
* @return a new MutableContextSet containing one KV pair
* @return a new MutableContextSet containing one context pair
* @throws NullPointerException if key or value is null
*/
public static MutableContextSet singleton(String key, String value) {
if (key == null) {
throw new NullPointerException("key");
}
if (value == null) {
throw new NullPointerException("value");
}
MutableContextSet set = new MutableContextSet();
@Nonnull
public static MutableContextSet singleton(@Nonnull String key, @Nonnull String value) {
Objects.requireNonNull(key, "key");
Objects.requireNonNull(value, "value");
MutableContextSet set = MutableContextSet.create();
set.add(key, value);
return set;
}
/**
* Makes a MutableContextSet from two context pairs
* Creates a {@link MutableContextSet} from two context pairs.
*
* @param key1 the first key
* @param value1 the first value
@@ -73,90 +76,87 @@ public final class MutableContextSet implements ContextSet {
* @throws NullPointerException if any of the keys or values are null
* @since 3.1
*/
public static MutableContextSet of(String key1, String value1, String key2, String value2) {
if (key1 == null) {
throw new NullPointerException("key1");
}
if (value1 == null) {
throw new NullPointerException("value1");
}
if (key2 == null) {
throw new NullPointerException("key2");
}
if (value2 == null) {
throw new NullPointerException("value2");
}
MutableContextSet ret = singleton(key1, value1);
ret.add(key2, value2);
return ret;
}
/**
* Creates a MutableContextSet from an existing map
*
* @param map the map to copy from
* @return a new MutableContextSet representing the pairs from the map
* @throws NullPointerException if the map is null
*/
public static MutableContextSet fromMap(Map<String, String> map) {
if (map == null) {
throw new NullPointerException("map");
}
MutableContextSet set = new MutableContextSet();
set.addAll(map);
@Nonnull
public static MutableContextSet of(@Nonnull String key1, @Nonnull String value1, @Nonnull String key2, @Nonnull String value2) {
Objects.requireNonNull(key1, "key1");
Objects.requireNonNull(value1, "value1");
Objects.requireNonNull(key2, "key2");
Objects.requireNonNull(value2, "value2");
MutableContextSet set = create();
set.add(key1, value1);
set.add(key2, value2);
return set;
}
/**
* Creates a MutableContextSet from an existing iterable of Map Entries
* Creates a {@link MutableContextSet} from an existing {@link Iterable} of {@link Map.Entry}s.
*
* @param iterable the iterable to copy from
* @return a new MutableContextSet representing the pairs in the iterable
* @throws NullPointerException if the iterable is null
*/
public static MutableContextSet fromEntries(Iterable<? extends Map.Entry<String, String>> iterable) {
if (iterable == null) {
throw new NullPointerException("iterable");
}
MutableContextSet set = new MutableContextSet();
@Nonnull
public static MutableContextSet fromEntries(@Nonnull Iterable<? extends Map.Entry<String, String>> iterable) {
Objects.requireNonNull(iterable, "iterable");
MutableContextSet set = create();
set.addAll(iterable);
return set;
}
/**
* Creates a MutableContextSet from an existing multimap
* Creates a {@link MutableContextSet} from an existing {@link 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) {
Objects.requireNonNull(map, "map");
MutableContextSet set = create();
set.addAll(map);
return set;
}
/**
* Creates a {@link MutableContextSet} from an existing {@link Multimap}.
*
* @param multimap the multimap to copy from
* @return a new MutableContextSet representing the pairs in the multimap
* @throws NullPointerException if the multimap is null
* @since 2.16
*/
public static MutableContextSet fromMultimap(Multimap<String, String> multimap) {
if (multimap == null) {
throw new NullPointerException("multimap");
}
return fromEntries(multimap.entries());
@Nonnull
public static MutableContextSet fromMultimap(@Nonnull Multimap<String, String> multimap) {
Objects.requireNonNull(multimap, "multimap");
MutableContextSet set = create();
set.addAll(multimap);
return set;
}
/**
* Creates a new MutableContextSet from an existing set.
* Only really useful for converting between mutable and immutable types.
* Creates a new {@link MutableContextSet} from an existing {@link Set}.
*
* <p>Only really useful for converting between mutable and immutable types.</p>
*
* @param contextSet the context set to copy from
* @return a new MutableContextSet with the same content and the one provided
* @throws NullPointerException if contextSet is null
*/
public static MutableContextSet fromSet(ContextSet contextSet) {
if (contextSet == null) {
throw new NullPointerException("contextSet");
}
@Nonnull
public static MutableContextSet fromSet(@Nonnull ContextSet contextSet) {
Objects.requireNonNull(contextSet, "contextSet");
MutableContextSet set = new MutableContextSet();
set.addAll(contextSet.toSet());
return set;
if (contextSet instanceof ImmutableContextSet) {
SetMultimap<String, String> map = ((ImmutableContextSet) contextSet).backing();
return new MutableContextSet(map);
} else if (contextSet instanceof MutableContextSet) {
return contextSet.mutableCopy();
} else {
MutableContextSet set = create();
set.addAll(contextSet);
return set;
}
}
/**
@@ -164,6 +164,7 @@ public final class MutableContextSet implements ContextSet {
*
* @return a new MutableContextSet
*/
@Nonnull
public static MutableContextSet create() {
return new MutableContextSet();
}
@@ -174,8 +175,20 @@ 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(SetMultimap<String, String> other) {
this.map = Multimaps.synchronizedSetMultimap(HashMultimap.create(other));
}
@Override
protected SetMultimap<String, String> backing() {
return this.map;
}
@Override
protected void copyTo(SetMultimap<String, String> other) {
synchronized (this.map) {
other.putAll(this.map);
}
}
@Override
@@ -183,245 +196,166 @@ public final class MutableContextSet implements ContextSet {
return false;
}
@Nonnull
@Override
public ImmutableContextSet makeImmutable() {
return new ImmutableContextSet(map);
// if the map is empty, don't create a new instance
if (this.map.isEmpty()) {
return ImmutableContextSet.empty();
}
synchronized (this.map) {
return new ImmutableContextSet(ImmutableSetMultimap.copyOf(this.map));
}
}
@Nonnull
@Override
public MutableContextSet mutableCopy() {
return new MutableContextSet(map);
synchronized (this.map) {
return new MutableContextSet(this.map);
}
}
@Nonnull
@Override
public Set<Map.Entry<String, String>> toSet() {
return ImmutableSet.copyOf(map.entries());
synchronized (this.map) {
// map.entries() returns immutable Map.Entry instances, so we can just call copyOf
return ImmutableSet.copyOf(this.map.entries());
}
}
@Nonnull
@Override
@Deprecated
public Map<String, String> toMap() {
ImmutableMap.Builder<String, String> m = ImmutableMap.builder();
for (Map.Entry<String, String> e : map.entries()) {
m.put(e.getKey(), e.getValue());
synchronized (this.map) {
for (Map.Entry<String, String> e : this.map.entries()) {
m.put(e.getKey(), e.getValue());
}
}
return m.build();
}
@Nonnull
@Override
public Multimap<String, String> toMultimap() {
return ImmutableSetMultimap.copyOf(map);
synchronized (this.map) {
return ImmutableSetMultimap.copyOf(this.map);
}
}
@Nonnull
@Override
public Iterator<Map.Entry<String, String>> iterator() {
return toSet().iterator();
}
@Override
public boolean containsKey(String key) {
if (key == null) {
throw new NullPointerException("key");
}
return map.containsKey(key);
}
@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();
}
@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);
}
@Override
public boolean hasIgnoreCase(String key, String value) {
if (key == null) {
throw new NullPointerException("key");
}
if (value == null) {
throw new NullPointerException("value");
}
Collection<String> c = map.get(key);
if (c == null || c.isEmpty()) {
return false;
}
for (String val : c) {
if (val.equalsIgnoreCase(value)) {
return true;
}
}
return false;
}
@Override
public boolean isEmpty() {
return map.isEmpty();
}
@Override
public int size() {
return map.size();
public Spliterator<Map.Entry<String, String>> spliterator() {
return toSet().spliterator();
}
/**
* Adds a new key value pair to the set
* Adds a context to this set.
*
* @param key the key to add
* @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) {
this.map.put(sanitizeKey(key), sanitizeValue(value));
}
/**
* Adds a new key value pair to the set
* Adds a context to this set.
*
* @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) {
Objects.requireNonNull(entry, "entry");
add(entry.getKey(), entry.getValue());
}
/**
* Adds an iterable containing contexts to the set
* Adds the contexts contained in the given {@link Iterable} to this set.
*
* @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 : Objects.requireNonNull(iterable, "iterable")) {
add(e);
}
}
/**
* Adds the entry set of a map to the set
* Adds the contexts contained in the given {@link Map} to this set.
*
* @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(Objects.requireNonNull(map, "map").entrySet());
}
/**
* Adds of of the values in another ContextSet to this set
* Adds the contexts contained in the given {@link Multimap} to this 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(Objects.requireNonNull(multimap, "multimap").entries());
}
/**
* Adds of of the contexts in another {@link ContextSet} to this set.
*
* @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) {
Objects.requireNonNull(contextSet, "contextSet");
if (contextSet instanceof AbstractContextSet) {
AbstractContextSet other = ((AbstractContextSet) contextSet);
synchronized (this.map) {
other.copyTo(this.map);
}
} else {
addAll(contextSet.toMultimap());
}
this.map.putAll(contextSet.toMultimap());
}
/**
* Remove a key value pair from this set
*
* @param key the key to remove
* @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");
}
map.entries().removeIf(entry -> entry.getKey().equals(key) && entry.getValue().equals(value));
}
/**
* Same as {@link #remove(String, String)}, except ignores the case of the value
* Removes a context from this set.
*
* @param key the key to remove
* @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");
}
map.entries().removeIf(e -> e.getKey().equalsIgnoreCase(key) && e.getValue().equalsIgnoreCase(value));
public void remove(@Nonnull String key, @Nonnull String value) {
this.map.remove(sanitizeKey(key), sanitizeValue(value));
}
/**
* Removes all pairs with the given key
* Removes all contexts from this set with the given key.
*
* @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) {
this.map.removeAll(sanitizeKey(key));
}
/**
* Clears the set
* Removes all contexts from the set.
*/
public void clear() {
map.clear();
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
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);
}
@Override
public int hashCode() {
return 59 + (this.map == null ? 43 : this.map.hashCode());
this.map.clear();
}
@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);
}
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -24,6 +27,8 @@ package me.lucko.luckperms.api.event;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.annotation.Nonnull;
/**
* Represents an event that can be cancelled
*/
@@ -34,6 +39,38 @@ public interface Cancellable {
*
* @return the cancellation
*/
@Nonnull
AtomicBoolean getCancellationState();
/**
* Returns true if the event is currently cancelled.
*
* @return if the event is cancelled
* @since 4.1
*/
default boolean isCancelled() {
return getCancellationState().get();
}
/**
* Returns true if the event is not currently cancelled.
*
* @return if the event is not cancelled
* @since 4.1
*/
default boolean isNotCancelled() {
return !isCancelled();
}
/**
* Sets the cancellation state of the event.
*
* @param cancelled the new state
* @return the previous state
* @since 4.1
*/
default boolean setCancelled(boolean cancelled) {
return getCancellationState().getAndSet(cancelled);
}
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -25,30 +28,61 @@ package me.lucko.luckperms.api.event;
import java.util.Set;
import java.util.function.Consumer;
import javax.annotation.Nonnull;
/**
* The LuckPerms event bus. Used for subscribing (or registering listeners) to events.
* The LuckPerms event bus.
*
* <p>Used to subscribe (or "listen") to LuckPerms events.</p>
*
* @since 3.0
*/
public interface EventBus {
/**
* Subscribe to an event
* Registers a new subscription to the given event.
*
* <p>The returned {@link EventHandler} instance encapsulates the subscription state. It has
* methods which can be used to terminate the subscription, or view stats about the nature of
* the subscription.</p>
*
* @param eventClass the event class
* @param handler the event handler
* @param <T> the event class
* @return an event handler instance representing this subscription
*/
<T extends LuckPermsEvent> EventHandler<T> subscribe(Class<T> eventClass, Consumer<T> handler);
@Nonnull
<T extends LuckPermsEvent> EventHandler<T> subscribe(@Nonnull Class<T> eventClass, @Nonnull Consumer<? super T> handler);
/**
* Gets a set of all registered handlers for a given event
* Registers a new subscription to the given event.
*
* <p>The returned {@link EventHandler} instance encapsulates the subscription state. It has
* methods which can be used to terminate the subscription, or view stats about the nature of
* the subscription.</p>
*
* <p>Unlike {@link #subscribe(Class, Consumer)}, this method accepts an additional parameter
* for {@code plugin}. This object must be a "plugin" instance on the platform, and is used to
* automatically {@link EventHandler#unregister() unregister} the subscription when the
* corresponding plugin is disabled.</p>
*
* @param <T> the event class
* @param plugin a plugin instance to bind the subscription to.
* @param eventClass the event class
* @param handler the event handler
* @return an event handler instance representing this subscription
*/
@Nonnull
<T extends LuckPermsEvent> EventHandler<T> subscribe(Object plugin, @Nonnull Class<T> eventClass, @Nonnull Consumer<? super T> handler);
/**
* Gets a set of all registered handlers for a given event.
*
* @param eventClass the event to find handlers for
* @param <T> the event class
* @return an immutable set of event handlers
*/
<T extends LuckPermsEvent> Set<EventHandler<T>> getHandlers(Class<T> eventClass);
@Nonnull
<T extends LuckPermsEvent> Set<EventHandler<T>> getHandlers(@Nonnull Class<T> eventClass);
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -24,18 +27,21 @@ package me.lucko.luckperms.api.event;
import java.util.function.Consumer;
import javax.annotation.Nonnull;
/**
* Represents a handler for a LuckPerms event
* Represents a subscription to a {@link LuckPermsEvent}.
*
* @param <T> the event class
*/
public interface EventHandler<T extends LuckPermsEvent> {
public interface EventHandler<T extends LuckPermsEvent> extends AutoCloseable {
/**
* Gets the class this handler is listening to
*
* @return the event class
*/
@Nonnull
Class<T> getEventClass();
/**
@@ -57,7 +63,8 @@ public interface EventHandler<T extends LuckPermsEvent> {
*
* @return the event consumer
*/
Consumer<T> getConsumer();
@Nonnull
Consumer<? super T> getConsumer();
/**
* Gets the number of times this handler has been called
@@ -66,4 +73,8 @@ public interface EventHandler<T extends LuckPermsEvent> {
*/
int getCallCount();
@Override
default void close() {
unregister();
}
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -24,8 +27,10 @@ package me.lucko.luckperms.api.event;
import me.lucko.luckperms.api.LuckPermsApi;
import javax.annotation.Nonnull;
/**
* The base event interface
* A superinterface for all LuckPerms events.
*
* @since 3.0
*/
@@ -36,6 +41,7 @@ public interface LuckPermsEvent {
*
* @return the api instance
*/
@Nonnull
LuckPermsApi getApi();
}
@@ -0,0 +1,50 @@
/*
* 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;
import me.lucko.luckperms.api.event.source.Source;
import javax.annotation.Nonnull;
/**
* Represents an event with a {@link Source}.
*
* @since 4.1
*/
public interface Sourced {
/**
* Gets the events source.
*
* <p>Never returns null. In situations where the source is unknown, a
* {@link Source} with type {@link Source.Type#UNKNOWN} is returned.</p>
*
* @return the source
*/
@Nonnull
Source getSource();
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -0,0 +1,57 @@
/*
* 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.group;
import me.lucko.luckperms.api.Group;
import me.lucko.luckperms.api.caching.GroupData;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import javax.annotation.Nonnull;
/**
* Called when a groups {@link GroupData} is loaded.
*
* @since 4.0
*/
public interface GroupCacheLoadEvent extends LuckPermsEvent {
/**
* Gets the group whose data was loaded
*
* @return the group
*/
@Nonnull
Group getGroup();
/**
* Gets the data that was loaded
*
* @return the loaded data
*/
@Nonnull
GroupData getLoadedData();
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -26,6 +29,8 @@ import me.lucko.luckperms.api.Group;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.cause.CreationCause;
import javax.annotation.Nonnull;
/**
* Called when a group is created
*/
@@ -36,6 +41,7 @@ public interface GroupCreateEvent extends LuckPermsEvent {
*
* @return the new group
*/
@Nonnull
Group getGroup();
/**
@@ -43,6 +49,7 @@ public interface GroupCreateEvent extends LuckPermsEvent {
*
* @return the cause of the creation
*/
@Nonnull
CreationCause getCause();
}
@@ -0,0 +1,57 @@
/*
* 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.group;
import me.lucko.luckperms.api.Group;
import me.lucko.luckperms.api.caching.GroupData;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import javax.annotation.Nonnull;
/**
* Called when a groups cached data is refreshed
*
* @since 4.0
*/
public interface GroupDataRecalculateEvent extends LuckPermsEvent {
/**
* Gets the group whose data was recalculated
*
* @return the group
*/
@Nonnull
Group getGroup();
/**
* Gets the data that was recalculated
*
* @return the data
*/
@Nonnull
GroupData getData();
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -28,6 +31,8 @@ import me.lucko.luckperms.api.event.cause.DeletionCause;
import java.util.Set;
import javax.annotation.Nonnull;
/**
* Called when a group is deleted
*/
@@ -38,6 +43,7 @@ public interface GroupDeleteEvent extends LuckPermsEvent {
*
* @return the name of the deleted group
*/
@Nonnull
String getGroupName();
/**
@@ -45,6 +51,7 @@ public interface GroupDeleteEvent extends LuckPermsEvent {
*
* @return a copy of the groups existing data
*/
@Nonnull
Set<Node> getExistingData();
/**
@@ -52,6 +59,7 @@ public interface GroupDeleteEvent extends LuckPermsEvent {
*
* @return the cause of the deletion
*/
@Nonnull
DeletionCause getCause();
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -25,6 +28,8 @@ package me.lucko.luckperms.api.event.group;
import me.lucko.luckperms.api.Group;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import javax.annotation.Nonnull;
/**
* Called when a group is loaded into memory from the storage.
*
@@ -37,6 +42,7 @@ public interface GroupLoadEvent extends LuckPermsEvent {
*
* @return the group that was loaded
*/
@Nonnull
Group getGroup();
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -26,6 +29,8 @@ import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.api.event.Cancellable;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import javax.annotation.Nonnull;
/**
* Called when a log entry is about to be sent to notifiable players on the platform
*/
@@ -36,6 +41,39 @@ public interface LogBroadcastEvent extends LuckPermsEvent, Cancellable {
*
* @return the log entry to be broadcasted
*/
@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 {
/**
* Marks a log entry which originated from the current server instance
*/
LOCAL,
/**
* Marks a log entry which originated from an API call on the current server instance
*/
LOCAL_API,
/**
* Marks 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,92 @@
/*
* 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.Entity;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.api.event.Cancellable;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import javax.annotation.Nonnull;
/**
* Called when a log entry is about to be sent to specific notifiable object on
* the platform.
*
* <p>This event is not called for players without the notify permission,
* but is called for objects which are ignoring log notifications (called with
* the cancelled flag set to true).</p>
*
* @since 4.1
*/
public interface LogNotifyEvent extends LuckPermsEvent, Cancellable {
/**
* Gets the log entry to be sent
*
* @return the log entry to be sent
*/
@Nonnull
LogEntry getEntry();
/**
* Gets where the log entry originated from.
*
* @return the origin of the log
*/
@Nonnull
Origin getOrigin();
/**
* Gets the object to be notified.
*
* @return the object to notify
*/
@Nonnull
Entity getNotifiable();
/**
* Represents where a log entry is from
*/
enum Origin {
/**
* Marks a log entry which originated from the current server instance
*/
LOCAL,
/**
* Marks a log entry which originated from an API call on the current server instance
*/
LOCAL_API,
/**
* Marks a log entry which was sent to this server via the messaging service
*/
REMOTE
}
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -26,6 +29,8 @@ import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.api.event.Cancellable;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import javax.annotation.Nonnull;
/**
* Called when a log is about to be published to the storage file/table
*/
@@ -36,6 +41,7 @@ public interface LogPublishEvent extends LuckPermsEvent, Cancellable {
*
* @return the log entry to be published
*/
@Nonnull
LogEntry getEntry();
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -20,32 +23,36 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.core;
package me.lucko.luckperms.api.event.log;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import me.lucko.luckperms.common.utils.Identifiable;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import java.util.UUID;
@Getter
@ToString
@EqualsAndHashCode(of = "uuid")
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public final class UserIdentifier implements Identifiable<UUID> {
public static UserIdentifier of(UUID uuid, String username) {
return new UserIdentifier(uuid, username);
}
import javax.annotation.Nonnull;
private final UUID uuid;
private final String username;
/**
* 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();
@Override
public UUID getId() {
return getUuid();
}
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -24,6 +27,8 @@ package me.lucko.luckperms.api.event.node;
import me.lucko.luckperms.api.Node;
import javax.annotation.Nonnull;
/**
* Called when a node is added to a holder
*/
@@ -34,6 +39,7 @@ public interface NodeAddEvent extends NodeMutateEvent {
*
* @return the node that was added
*/
@Nonnull
Node getNode();
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -28,6 +31,8 @@ import me.lucko.luckperms.api.event.LuckPermsEvent;
import java.util.Set;
import javax.annotation.Nonnull;
/**
* Called when a node is added to/removed from a user/group
*/
@@ -38,6 +43,7 @@ public interface NodeMutateEvent extends LuckPermsEvent {
*
* @return the event target
*/
@Nonnull
PermissionHolder getTarget();
/**
@@ -45,6 +51,7 @@ public interface NodeMutateEvent extends LuckPermsEvent {
*
* @return the data before the change
*/
@Nonnull
Set<Node> getDataBefore();
/**
@@ -52,6 +59,7 @@ public interface NodeMutateEvent extends LuckPermsEvent {
*
* @return the data after the change
*/
@Nonnull
Set<Node> getDataAfter();
/**
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -24,6 +27,8 @@ package me.lucko.luckperms.api.event.node;
import me.lucko.luckperms.api.Node;
import javax.annotation.Nonnull;
/**
* Called when a node is removed from a holder
*/
@@ -34,6 +39,7 @@ public interface NodeRemoveEvent extends NodeMutateEvent {
*
* @return the node that was removed
*/
@Nonnull
Node getNode();
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -20,19 +23,25 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.commands.utils;
package me.lucko.luckperms.api.event.source;
import me.lucko.luckperms.api.Entity;
import javax.annotation.Nonnull;
/**
* Utility used to help in commands that take arguments for different contexts
* Represents an {@link Entity} which was the {@link Source} of something.
*
* @since 4.1
*/
public class ContextHelper {
public interface EntitySource extends Source {
public static CommandContext determine(String server, String world) {
return server == null ? CommandContext.NONE : (world == null ? CommandContext.SERVER : CommandContext.SERVER_AND_WORLD);
}
public enum CommandContext {
NONE, SERVER, SERVER_AND_WORLD
}
/**
* Gets the entity.
*
* @return the entity
*/
@Nonnull
Entity getEntity();
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -20,32 +23,45 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.utils;
package me.lucko.luckperms.api.event.source;
import lombok.experimental.UtilityClass;
import me.lucko.luckperms.api.Entity;
import me.lucko.luckperms.common.constants.Patterns;
import javax.annotation.Nonnull;
/**
* Utility for checking arguments for consistency
* Represents the source of an event.
*
* <p>Could also be described as the "thing" that caused an event to occur.</p>
*
* @since 4.1
*/
@UtilityClass
public class ArgumentChecker {
public interface Source {
public static boolean checkUsername(String s) {
return (s.length() > 16 || Patterns.NON_USERNAME.matcher(s).find());
}
/**
* Gets the source type
*
* @return the type
*/
@Nonnull
Type getType();
public static boolean checkName(String s) {
return (s.length() > 36 || Patterns.NON_ALPHA_NUMERIC.matcher(s).find());
}
/**
* Represents a type of source
*/
enum Type {
public static boolean checkNameWithSpace(String s) {
return (s.length() > 36 || Patterns.NON_ALPHA_NUMERIC_SPACE.matcher(s).find());
}
/**
* Represents an {@link Entity} source
*
* @see EntitySource
*/
ENTITY,
public static boolean checkTime(long l) {
return DateUtil.shouldExpire(l);
/**
* Represents an unknown source
*/
UNKNOWN
}
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -27,8 +30,10 @@ import me.lucko.luckperms.api.event.LuckPermsEvent;
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 {
@@ -37,6 +42,7 @@ public interface PreNetworkSyncEvent extends LuckPermsEvent, Cancellable {
*
* @return the id of the sync request
*/
@Nonnull
UUID getSyncId();
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -26,6 +29,8 @@ import me.lucko.luckperms.api.Track;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.cause.CreationCause;
import javax.annotation.Nonnull;
/**
* Called when a track is created
*/
@@ -36,6 +41,7 @@ public interface TrackCreateEvent extends LuckPermsEvent {
*
* @return the new track
*/
@Nonnull
Track getTrack();
/**
@@ -43,6 +49,7 @@ public interface TrackCreateEvent extends LuckPermsEvent {
*
* @return the cause of the creation
*/
@Nonnull
CreationCause getCause();
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -27,6 +30,8 @@ import me.lucko.luckperms.api.event.cause.DeletionCause;
import java.util.List;
import javax.annotation.Nonnull;
/**
* Called when a track is deleted
*/
@@ -37,6 +42,7 @@ public interface TrackDeleteEvent extends LuckPermsEvent {
*
* @return the name of the deleted track
*/
@Nonnull
String getTrackName();
/**
@@ -44,6 +50,7 @@ public interface TrackDeleteEvent extends LuckPermsEvent {
*
* @return a copy of the tracks existing data
*/
@Nonnull
List<String> getExistingData();
/**
@@ -51,6 +58,7 @@ public interface TrackDeleteEvent extends LuckPermsEvent {
*
* @return the cause of the deletion
*/
@Nonnull
DeletionCause getCause();
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -25,6 +28,8 @@ package me.lucko.luckperms.api.event.track;
import me.lucko.luckperms.api.Track;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import javax.annotation.Nonnull;
/**
* Called when a track is loaded into memory from the storage.
*
@@ -37,6 +42,7 @@ public interface TrackLoadEvent extends LuckPermsEvent {
*
* @return the track that was loaded
*/
@Nonnull
Track getTrack();
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -22,6 +25,8 @@
package me.lucko.luckperms.api.event.track.mutate;
import javax.annotation.Nonnull;
/**
* Called when a group is added to a track
*/
@@ -32,6 +37,7 @@ public interface TrackAddGroupEvent extends TrackMutateEvent {
*
* @return the group that was added
*/
@Nonnull
String getGroup();
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -27,6 +30,8 @@ import me.lucko.luckperms.api.event.LuckPermsEvent;
import java.util.List;
import javax.annotation.Nonnull;
/**
* Called when a track is changed
*/
@@ -37,6 +42,7 @@ public interface TrackMutateEvent extends LuckPermsEvent {
*
* @return the track that was mutated
*/
@Nonnull
Track getTrack();
/**
@@ -44,6 +50,7 @@ public interface TrackMutateEvent extends LuckPermsEvent {
*
* @return the data before the change
*/
@Nonnull
List<String> getDataBefore();
/**
@@ -51,6 +58,7 @@ public interface TrackMutateEvent extends LuckPermsEvent {
*
* @return the data after the change
*/
@Nonnull
List<String> getDataAfter();
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -22,6 +25,8 @@
package me.lucko.luckperms.api.event.track.mutate;
import javax.annotation.Nonnull;
/**
* Called when a group is removed from a track
*/
@@ -32,6 +37,7 @@ public interface TrackRemoveGroupEvent extends TrackMutateEvent {
*
* @return the group that was removed
*/
@Nonnull
String getGroup();
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -26,6 +29,8 @@ import me.lucko.luckperms.api.User;
import me.lucko.luckperms.api.caching.UserData;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import javax.annotation.Nonnull;
/**
* Called when a users {@link me.lucko.luckperms.api.caching.UserData} is loaded.
*/
@@ -36,6 +41,7 @@ public interface UserCacheLoadEvent extends LuckPermsEvent {
*
* @return the user
*/
@Nonnull
User getUser();
/**
@@ -43,6 +49,7 @@ public interface UserCacheLoadEvent extends LuckPermsEvent {
*
* @return the loaded data
*/
@Nonnull
UserData getLoadedData();
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -26,6 +29,8 @@ import me.lucko.luckperms.api.User;
import me.lucko.luckperms.api.caching.UserData;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import javax.annotation.Nonnull;
/**
* Called when a users cached data is refreshed
*/
@@ -36,6 +41,7 @@ public interface UserDataRecalculateEvent extends LuckPermsEvent {
*
* @return the user
*/
@Nonnull
User getUser();
/**
@@ -43,6 +49,7 @@ public interface UserDataRecalculateEvent extends LuckPermsEvent {
*
* @return the data
*/
@Nonnull
UserData getData();
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -26,6 +29,8 @@ import me.lucko.luckperms.api.event.LuckPermsEvent;
import java.util.UUID;
import javax.annotation.Nonnull;
/**
* Called when the user logs into the network for the first time.
*
@@ -44,6 +49,7 @@ public interface UserFirstLoginEvent extends LuckPermsEvent {
*
* @return the uuid of the user
*/
@Nonnull
UUID getUuid();
/**
@@ -51,6 +57,7 @@ public interface UserFirstLoginEvent extends LuckPermsEvent {
*
* @return the username of the user
*/
@Nonnull
String getUsername();
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -25,6 +28,8 @@ package me.lucko.luckperms.api.event.user;
import me.lucko.luckperms.api.User;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import javax.annotation.Nonnull;
/**
* Called when a user is loaded into memory from the storage.
*/
@@ -35,6 +40,7 @@ public interface UserLoadEvent extends LuckPermsEvent {
*
* @return the user that was loaded
*/
@Nonnull
User getUser();
}
@@ -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();
}
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
* 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
@@ -25,19 +28,23 @@ package me.lucko.luckperms.api.event.user.track;
import me.lucko.luckperms.api.Track;
import me.lucko.luckperms.api.User;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.Sourced;
import java.util.Optional;
import javax.annotation.Nonnull;
/**
* Called when a user interacts with a track through a promotion or demotion
*/
public interface UserTrackEvent extends LuckPermsEvent {
public interface UserTrackEvent extends LuckPermsEvent, Sourced {
/**
* Gets the track involved in the event
*
* @return the track involved in the event
*/
@Nonnull
Track getTrack();
/**
@@ -45,6 +52,7 @@ public interface UserTrackEvent extends LuckPermsEvent {
*
* @return the user involved in the event
*/
@Nonnull
User getUser();
/**
@@ -52,6 +60,7 @@ public interface UserTrackEvent extends LuckPermsEvent {
*
* @return the action performed
*/
@Nonnull
TrackAction getAction();
/**
@@ -61,6 +70,7 @@ public interface UserTrackEvent extends LuckPermsEvent {
*
* @return the group the user was promoted/demoted from
*/
@Nonnull
Optional<String> getGroupFrom();
/**
@@ -68,6 +78,7 @@ public interface UserTrackEvent extends LuckPermsEvent {
*
* @return the group the user was promoted/demoted to
*/
@Nonnull
Optional<String> getGroupTo();
}
@@ -0,0 +1,207 @@
/*
* 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 me.lucko.luckperms.api.HeldPermission;
import me.lucko.luckperms.api.Storage;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Represents the object responsible for managing {@link Group} instances.
*
* <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, register a
* callback using {@link CompletableFuture#thenAcceptAsync(Consumer, Executor)}.</p>
*
* @since 4.0
*/
public interface GroupManager {
/**
* Creates a new group in the plugin's storage provider and then loads it
* into memory.
*
* <p>If a group by the same name already exists, it will be loaded.</p>
*
* <p>This method is effectively the same as
* {@link Storage#createAndLoadGroup(String)}, however, the Future returns
* the resultant group instance instead of a boolean flag.</p>
*
* <p>Unlike the method in {@link Storage}, when a group cannot be loaded,
* the future will be {@link CompletableFuture completed exceptionally}.</p>
*
* @param name the name of the group
* @return the resultant group
* @throws NullPointerException if the name is null
* @since 4.1
*/
@Nonnull
CompletableFuture<Group> createAndLoadGroup(@Nonnull String name);
/**
* Loads a group from the plugin's storage provider into memory.
*
* <p>Returns an {@link Optional#empty() empty optional} if the group does
* not exist.</p>
*
* <p>This method is effectively the same as
* {@link Storage#loadGroup(String)}, however, the Future returns
* the resultant group instance instead of a boolean flag.</p>
*
* <p>Unlike the method in {@link Storage}, when a group cannot be loaded,
* the future will be {@link CompletableFuture completed exceptionally}.</p>
*
* @param name the name of the group
* @return the resultant group
* @throws NullPointerException if the name is null
* @since 4.1
*/
@Nonnull
CompletableFuture<Optional<Group>> loadGroup(@Nonnull String name);
/**
* Saves a group's data back to the plugin's storage provider.
*
* <p>You should call this after you make any changes to a group.</p>
*
* <p>This method is effectively the same as {@link Storage#saveGroup(Group)},
* however, the Future returns void instead of a boolean flag.</p>
*
* <p>Unlike the method in {@link Storage}, when a group cannot be saved,
* the future will be {@link CompletableFuture completed exceptionally}.</p>
*
* @param group the group to save
* @return a future to encapsulate the operation.
* @throws NullPointerException if group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @since 4.1
*/
@Nonnull
CompletableFuture<Void> saveGroup(@Nonnull Group group);
/**
* Permanently deletes a group from the plugin's storage provider.
*
* <p>This method is effectively the same as {@link Storage#deleteGroup(Group)},
* however, the Future returns void instead of a boolean flag.</p>
*
* <p>Unlike the method in {@link Storage}, when a group cannot be deleted,
* the future will be {@link CompletableFuture completed exceptionally}.</p>
*
*
* @param group the group to delete
* @return a future to encapsulate the operation.
* @throws NullPointerException if group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @since 4.1
*/
@Nonnull
CompletableFuture<Void> deleteGroup(@Nonnull Group group);
/**
* Loads all groups into memory.
*
* <p>This method is effectively the same as {@link Storage#loadAllTracks()},
* however, the Future returns void instead of a boolean flag.</p>
*
* <p>Unlike the method in {@link Storage}, when a group cannot be loaded,
* the future will be {@link CompletableFuture completed exceptionally}.</p>
*
* @return a future to encapsulate the operation.
* @since 4.1
*/
@Nonnull
CompletableFuture<Void> loadAllGroups();
/**
* Searches for a list of groups with a given permission.
*
* @param permission the permission to search for
* @return a list of held permissions, or null if the operation failed
* @throws NullPointerException if the permission is null
* @since 4.2
*/
@Nonnull
CompletableFuture<List<HeldPermission<String>>> getWithPermission(@Nonnull String permission);
/**
* Gets a loaded group.
*
* @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 loaded group.
*
* <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,194 @@
/*
* 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.Storage;
import me.lucko.luckperms.api.Track;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Represents the object responsible for managing {@link Track} instances.
*
* <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, register a
* callback using {@link CompletableFuture#thenAcceptAsync(Consumer, Executor)}.</p>
*
* @since 4.0
*/
public interface TrackManager {
/**
* Creates a new track in the plugin's storage provider and then loads it
* into memory.
*
* <p>If a track by the same name already exists, it will be loaded.</p>
*
* <p>This method is effectively the same as
* {@link Storage#createAndLoadTrack(String)}, however, the Future returns
* the resultant track instance instead of a boolean flag.</p>
*
* <p>Unlike the method in {@link Storage}, when a track cannot be loaded,
* the future will be {@link CompletableFuture completed exceptionally}.</p>
*
* @param name the name of the track
* @return the resultant track
* @throws NullPointerException if the name is null
* @since 4.1
*/
@Nonnull
CompletableFuture<Track> createAndLoadTrack(@Nonnull String name);
/**
* Loads a track from the plugin's storage provider into memory.
*
* <p>Returns an {@link Optional#empty() empty optional} if the track does
* not exist.</p>
*
* <p>This method is effectively the same as
* {@link Storage#loadTrack(String)}, however, the Future returns
* the resultant track instance instead of a boolean flag.</p>
*
* <p>Unlike the method in {@link Storage}, when a track cannot be loaded,
* the future will be {@link CompletableFuture completed exceptionally}.</p>
*
* @param name the name of the track
* @return the resultant track
* @throws NullPointerException if the name is null
* @since 4.1
*/
@Nonnull
CompletableFuture<Optional<Track>> loadTrack(@Nonnull String name);
/**
* Saves a track's data back to the plugin's storage provider.
*
* <p>You should call this after you make any changes to a track.</p>
*
* <p>This method is effectively the same as {@link Storage#saveTrack(Track)},
* however, the Future returns void instead of a boolean flag.</p>
*
* <p>Unlike the method in {@link Storage}, when a track cannot be saved,
* the future will be {@link CompletableFuture completed exceptionally}.</p>
*
* @param track the track to save
* @return a future to encapsulate the operation.
* @throws NullPointerException if track is null
* @throws IllegalStateException if the track instance was not obtained from LuckPerms.
* @since 4.1
*/
@Nonnull
CompletableFuture<Void> saveTrack(@Nonnull Track track);
/**
* Permanently deletes a track from the plugin's storage provider.
*
* <p>This method is effectively the same as {@link Storage#deleteTrack(Track)},
* however, the Future returns void instead of a boolean flag.</p>
*
* <p>Unlike the method in {@link Storage}, when a track cannot be deleted,
* the future will be {@link CompletableFuture completed exceptionally}.</p>
*
*
* @param track the track to delete
* @return a future to encapsulate the operation.
* @throws NullPointerException if track is null
* @throws IllegalStateException if the track instance was not obtained from LuckPerms.
* @since 4.1
*/
@Nonnull
CompletableFuture<Void> deleteTrack(@Nonnull Track track);
/**
* Loads all tracks into memory.
*
* <p>This method is effectively the same as {@link Storage#loadAllTracks()},
* however, the Future returns void instead of a boolean flag.</p>
*
* <p>Unlike the method in {@link Storage}, when a track cannot be loaded,
* the future will be {@link CompletableFuture completed exceptionally}.</p>
*
* @return a future to encapsulate the operation.
* @since 4.1
*/
@Nonnull
CompletableFuture<Void> loadAllTracks();
/**
* Gets a loaded track.
*
* @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 loaded track.
*
* <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,253 @@
/*
* 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.HeldPermission;
import me.lucko.luckperms.api.PlayerSaveResult;
import me.lucko.luckperms.api.Storage;
import me.lucko.luckperms.api.User;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Represents the object responsible for managing {@link User} instances.
*
* <p>Note that User instances are automatically loaded for online players.
* It's likely that offline players will not have an instance pre-loaded.</p>
*
* <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, register a
* callback using {@link CompletableFuture#thenAcceptAsync(Consumer, Executor)}.</p>
*
* @since 4.0
*/
public interface UserManager {
/**
* Loads a user from the plugin's storage provider into memory.
*
* <p>This method is effectively the same as
* {@link Storage#loadUser(UUID, String)}, however, the Future returns the
* resultant user instance instead of a boolean flag.</p>
*
* <p>Unlike the method in {@link Storage}, when a user cannot be loaded,
* the future will be {@link CompletableFuture completed exceptionally}.</p>
*
* @param uuid the uuid of the user
* @param username the username, if known
* @return the resultant user
* @throws NullPointerException if the uuid is null
* @since 4.1
*/
@Nonnull
CompletableFuture<User> loadUser(@Nonnull UUID uuid, @Nullable String username);
/**
* Loads a user from the plugin's storage provider into memory.
*
* <p>This method is effectively the same as {@link Storage#loadUser(UUID)},
* however, the Future returns the resultant user instance instead of a
* boolean flag.</p>
*
* <p>Unlike the method in {@link Storage}, when a user cannot be loaded,
* the future will be {@link CompletableFuture completed exceptionally}.</p>
*
* @param uuid the uuid of the user
* @return the resultant user
* @throws NullPointerException if the uuid is null
* @since 4.1
*/
@Nonnull
default CompletableFuture<User> loadUser(@Nonnull UUID uuid) {
return loadUser(uuid, null);
}
/**
* Uses the LuckPerms cache to find a uuid for the given username.
*
* <p>This lookup is case insensitive.</p>
*
* @param username the username
* @return a uuid, could be null
* @throws NullPointerException if either parameters are null
* @throws IllegalArgumentException if the username is invalid
* @since 4.2
*/
@Nonnull
CompletableFuture<UUID> lookupUuid(@Nonnull String username);
/**
* Uses the LuckPerms cache to find a username for the given uuid.
*
* @param uuid the uuid
* @return a username, could be null
* @throws NullPointerException if either parameters are null
* @throws IllegalArgumentException if the username is invalid
* @since 4.2
*/
@Nonnull
CompletableFuture<String> lookupUsername(@Nonnull UUID uuid);
/**
* Saves a user's data back to the plugin's storage provider.
*
* <p>You should call this after you make any changes to a user.</p>
*
* <p>This method is effectively the same as {@link Storage#saveUser(User)},
* however, the Future returns void instead of a boolean flag.</p>
*
* <p>Unlike the method in {@link Storage}, when a user cannot be saved,
* the future will be {@link CompletableFuture completed exceptionally}.</p>
*
* @param user the user to save
* @return a future to encapsulate the operation.
* @throws NullPointerException if user is null
* @throws IllegalStateException if the user instance was not obtained from LuckPerms.
* @since 4.1
*/
@Nonnull
CompletableFuture<Void> saveUser(@Nonnull User user);
/**
* Saves data about a player to the uuid caching system.
*
* @param uuid the users mojang unique id
* @param username the users username
* @return the result of the operation.
* @throws NullPointerException if either parameters are null
* @throws IllegalArgumentException if the username is invalid
* @since 4.2
*/
@Nonnull
CompletableFuture<PlayerSaveResult> savePlayerData(@Nonnull UUID uuid, @Nonnull String username);
/**
* Gets a set all "unique" user UUIDs.
*
* <p>"Unique" meaning the user isn't just a member of the "default" group.</p>
*
* @return a set of uuids
* @since 4.2
*/
@Nonnull
CompletableFuture<Set<UUID>> getUniqueUsers();
/**
* Searches for a list of users with a given permission.
*
* @param permission the permission to search for
* @return a list of held permissions
* @throws NullPointerException if the permission is null
* @since 4.2
*/
@Nonnull
CompletableFuture<List<HeldPermission<UUID>>> getWithPermission(@Nonnull String permission);
/**
* Gets a loaded user.
*
* @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 loaded user.
*
* @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 loaded user.
*
* @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 loaded user.
*
* @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);
}
Loaded 100 of 871 files, more files were not shown because too many files have changed in this diff. Show more