Compare commits

..
1137 Commits
Author SHA1 Message Date
Luck 99c3d68d3a API 5.4 2022-02-09 21:39:45 +00:00
Luck 59f3866e36 Warn if the API was classloaded by another plugin 2022-02-09 21:08:18 +00:00
Sxtanna d45d9a295b Optimize parent resolution in info commands (#3309) 2022-02-09 20:15:18 +00:00
Luck b13a74c61e Pre-generate web editor keypair to speed up initial session init 2022-02-09 20:08:16 +00:00
Luck 0fe85ed6ff Ignore http 503 error from socket server 2022-02-09 19:59:01 +00:00
Luck bc15e348f5 Optimize bulk user loading for editor command (#3273) 2022-02-08 22:45:00 +00:00
Luck 1b3b9b5c62 Update commodore to fix running LP commands from a Forge client (#3299) 2022-02-07 22:35:52 +00:00
Luck fe80ba6cc4 Shutdown ForkJoinPool worker on disable (#3247) 2022-02-07 21:27:26 +00:00
Luck 65751cd56b Velocity world context use ServerConnectedEvent (#3245) 2022-02-07 21:25:43 +00:00
lucko ee79f53612 SpongeAPI 8 (#2728) 2022-02-07 21:10:01 +00:00
lucko d3029a8467 Web editor socket connection (#3303) 2022-02-07 19:13:09 +00:00
Luck f61d9ff9f0 Fix NPE from permission holder initialisation order (#3263) 2022-01-02 16:58:15 +00:00
Luck a53c9fad00 Reuse the same InheritanceOrigin object where possible 2022-01-01 20:49:12 +00:00
Luck 4de7448394 Include whether a node is normal/transient in InheritanceOriginMetadata 2022-01-01 19:33:48 +00:00
Luck 6781c1fb51 Provide API access to cached data result info (#3243) 2022-01-01 14:38:46 +00:00
Luck acdc259771 Fix MetaValueSelector NPE 2021-12-31 17:50:42 +00:00
Luck d319d8dc52 Fix TristateResult NPE 2021-12-31 17:24:38 +00:00
Andrew 419d711fb6 Add full support for transient permissions through Vault API (#3258) 2021-12-31 16:16:06 +00:00
lucko 2d662cbab9 Retain cause node information for cached permission/meta data (#3250) 2021-12-31 16:03:00 +00:00
OmegaWeaponDev ae93c9768b Add default file name for export command (#3248) 2021-12-31 16:02:24 +00:00
Luck 664cad21a9 Clarify uuid type in user info command (#3233) 2021-12-10 23:47:06 +00:00
Luck 8cc126f711 Add config option to disable bulkupdate functionality 2021-12-09 21:32:02 +00:00
Luck 9c0874162b Fix cast to long in MongoStorage 2021-12-04 10:41:12 +00:00
Luck f35a9b6a09 Update dependencies for 1.18 2021-12-02 13:24:02 +00:00
Luck fa17404133 Fabric 1.18 2021-11-30 20:03:16 +00:00
Tadhg Boyle 64bd8b5eaf Add pagination to listgroups command (#3226) 2021-11-30 19:52:43 +00:00
Luck e227d96cbf Fix sql insert player query (#3225) 2021-11-28 10:46:48 +00:00
Luck 6e07d6ad36 Revert "Fix player insert duplicate key issue with PSQL (#3223)"
This reverts commit d6c810aa71.
2021-11-28 10:29:55 +00:00
Tadhg Boyle d6c810aa71 Fix player insert duplicate key issue with PSQL (#3223) 2021-11-27 22:48:22 +00:00
Luck 10f698b70f Add warning for common editor mistakes 2021-11-27 17:58:10 +00:00
Luck 594f50bee7 Add config option to disable context calculators 2021-11-27 09:49:01 +00:00
Luck 9204848ffb Fix username lookup returning "null" instead of null (#3220) 2021-11-27 09:43:47 +00:00
Luck 272d289d4a More context performance improvements (#3209) 2021-11-18 18:21:30 +00:00
Luck c9d4c7dac7 ContextSet performance improvements (#3209)
A bit experimental, should be stable enough though.
2021-11-17 23:18:11 +00:00
Eduard Wayland 848fc353d4 Added redis authentication with username (#3201) 2021-11-12 22:49:46 +00:00
Luck f896ed723d Edit issue templates (again) 2021-10-22 20:03:33 +01:00
Luck 00b62d7cd9 Edit issue templates 2021-10-22 20:01:46 +01:00
Larry f84f425817 Better issue templates (#3184) 2021-10-22 19:58:12 +01:00
Luck 9c5a43b487 Allow meta/prefix/suffix nodes to be negated to cancel inheritance (#3020) 2021-10-18 22:10:20 +01:00
Luck b2c76aca7d Improve translations handling (#3166) 2021-10-10 13:26:33 +01:00
RedstoneFuture 04bb035a83 Add warning nore about enable-ops to config files (#3170) 2021-10-03 18:55:38 +01:00
Luck 2cf77db8b6 TranslationManager fixes and improvements (#3165) 2021-09-18 17:30:17 +01:00
Luck d1cb644712 Fix empty prefix/suffix strings in YAML storage (#3139, #3160) 2021-09-10 19:14:47 +01:00
Luck 4e2807cff5 Refactor mod container retrieval in Fabric mod 2021-09-10 18:32:43 +01:00
Emily 5735e0ef44 Fix fabric/build.gradle placeholder replacement (#3153) 2021-09-04 22:15:13 +01:00
Luck 9cd33d26f2 Fix toLowerCase/toUpperCase locale sensitivity 2021-08-25 20:09:20 +01:00
Luck 062fca3f75 Fix Fabric version placeholder in metadata file (#3141) 2021-08-25 19:36:53 +01:00
Luck a182768cfa Change user housekeeper to be more lenient towards API usage (#3143) 2021-08-25 19:30:46 +01:00
Luck 93683c3a2f Update Fabric to 1.17, fix version placeholder filtering 2021-08-20 18:46:39 +01:00
Callum Seabrook ba522597a8 Update to Gradle 7 (#3051) 2021-08-20 18:16:39 +01:00
Luck b232cb94b4 ReflectionClassPathAppender on Java 16+ 2021-08-17 21:29:10 +01:00
Luck ee6aa47d99 Listen for ServerPostConnectEvent in Velocity context listener (#3133) 2021-08-14 09:08:14 +01:00
Luck b3ebf202fd Update adventure-platform for 1.17 (#3127) 2021-08-06 14:35:23 +01:00
Emily 0fa3095241 Save renamed group before syncing with storage (#3129) 2021-08-06 09:59:38 +01:00
Luck 433272518f Fix bad Continuation usage in Velocity listener 2021-07-31 08:29:32 +01:00
Luck 26de6d3a78 Update Velocity to 3.0.0, use a Continuation for permissions setup event 2021-07-30 13:07:54 +01:00
Luck 5ea2aee2f4 More helpful error message when user is null in API PlayerAdapter (#3104) 2021-07-18 20:38:06 +01:00
Luck 5a377e713e Fix NPE from null primary group in Vault hook (#3103) 2021-07-18 20:35:31 +01:00
Luck cfb298f69b Use different classifier for dependency files with Bukkit-Legacy remappings 2021-07-08 22:54:04 +01:00
Emily 563b5be9b2 Implement enable-ops and auto-op on Fabric (#3069) 2021-07-04 10:01:47 +01:00
Emily fb36bd0ced Bulk update triggers for group related commands (#3073) 2021-07-04 10:00:18 +01:00
Luck 979c80d9ee Clarify config comments for mongodb-connection-uri option (#3062) 2021-06-15 20:41:36 +01:00
Luck 4598435dd4 Fix extension loading causing whole plugin to error 2021-06-13 12:46:02 +01:00
Luck 51202924af Update commodore for MC 1.17 support 2021-06-12 17:57:43 +01:00
Jacob C 8ae70990ad Generify SqlStorage shutdown exception message (#3039) 2021-06-10 21:16:23 +01:00
Tjeu Kayim a63be102cf Implement command list updater for Fabric (#3060) 2021-06-10 21:15:33 +01:00
Tjeu Kayim 044deccd22 Fabric, fix GameMode.NOT_SET removed in 1.17 (#3053) 2021-06-10 21:12:03 +01:00
Luck ad49508b74 Some misc tidying up 2021-05-23 11:29:22 +01:00
Luck 05c9ca5951 Properly cleanup JarInJarClassLoader when plugin disables 2021-05-23 11:27:45 +01:00
Luck f5cdb98b01 Fix ExpiringSet not really working & causing memory leaks (#3027) 2021-05-19 12:31:48 +01:00
Luck 228687b741 Fix Nukkit PermissionAttachments always throwing NPEs 2021-05-10 17:39:08 +01:00
lucko 7ebbfcf0d2 Update banner in readme 2021-05-10 14:30:09 +01:00
Luck 49c17c4a18 Clarify message in API NotLoadedException 2021-05-06 13:38:49 +01:00
Luck 7c42b9aeca Revert "Add extra check to ensure RedisBungee is loaded (#2981)"
This reverts commit a68a5d91c4.
2021-05-06 13:25:23 +01:00
Luck 1511193e58 Add Bukkit child permissions to the PermissionRegistry 2021-05-06 12:23:09 +01:00
Luck 528d668bc6 API User#setPrimaryGroup should care about stored value only (#3008) 2021-05-03 23:10:57 +01:00
Luck 71896a75bf Warn users with multiple permissions plugins installed (#3006) 2021-05-02 16:14:23 +01:00
Luck 931d61e2ed Include more information about targets in verbose payloads 2021-05-02 15:50:38 +01:00
Luck b87b1c7123 Improve structure of LuckPermsSubscriptionMap 2021-05-02 15:26:44 +01:00
Luck fed5a0fd87 Fix potential race condition in LuckPermsProvider#get 2021-04-23 20:17:48 +01:00
Luck 9d4f278117 Remove redundant CommandResult enum 2021-04-22 21:01:57 +01:00
Luck 1d465aa800 Fix track editor command for empty tracks (£2997) 2021-04-22 20:32:43 +01:00
Luck 8741e8259f Fix commodore not working after dependency update 2021-04-18 18:42:57 +01:00
Luck 98adb046ee Update lots of dependencies 2021-04-18 18:20:54 +01:00
Luck a68a5d91c4 Add extra check to ensure RedisBungee is loaded (#2981) 2021-04-18 13:48:45 +01:00
Luck 0808392353 Update adventure 2021-04-18 13:33:22 +01:00
Luck 07f672ae1f Add 'skip-bulkupdate-confirmation' config option (#2980) 2021-04-18 11:55:06 +01:00
Federico López e219237e44 API Javadoc gen fixes (#2977) 2021-04-18 11:37:46 +01:00
Luck c533446ab0 Fabric fix compat with fake players
https://github.com/lucko/fabric-permissions-api/issues/3
2021-04-07 20:56:51 +01:00
Luck 82488140ee Parallelize user data load in web editor request (#2973) 2021-04-07 08:32:02 +01:00
Luck 327ccec02f Use the correct config file location on Fabric and Sponge (#2972) 2021-04-07 08:24:38 +01:00
Federico López 46efe0ef93 Give default group if needed on UserManager#modifyUser (#2971) 2021-04-07 08:11:19 +01:00
Luck c2231bcc2e Disallow empty permission node (#2966) 2021-04-05 18:30:12 +01:00
Luck d150bd39a5 Send messaging service ping for creategroup command (#2956) 2021-03-25 22:28:52 +00:00
Federico López f813122468 Fix 'meta settemp' ignoring temporary modifier (#2958) 2021-03-24 21:28:00 +00:00
Luck 2e62c98c45 Avoid blocking worker pool for command timeout check (#2951)
3rd time lucky...
2021-03-24 12:40:24 +00:00
Luck f0e1a8f092 Remove some BungeeCord/Velocity command aliases 2021-03-23 13:45:34 +00:00
Luck 2dc6902001 Fix deadlock when lots of commands are executed at the same time (#2951) 2021-03-23 11:10:18 +00:00
Luck 21f5c24847 Optimize Bukkit/Nukkit ChildProcessor refresh (#2952) 2021-03-20 18:17:17 +00:00
Luck 6b2c4bca58 Change command manager lock handling to avoid non-fair tryLock call 2021-03-20 15:28:45 +00:00
Luck 4564a97371 Update fabric-loop, explicitly set archivesBaseName to 'luckperms' (#2880) 2021-03-19 20:39:42 +00:00
Luck 1df66255e4 Fix RCON permission checking for LP commands on Bukkit (#2948) 2021-03-19 20:03:21 +00:00
Luck 1c7e2dfb8c Fix very lenient duration parsing (#2940) 2021-03-19 19:59:15 +00:00
Luck ad1ba3c126 Fix player locale retrieval on Bukkit 1.8 (#2930) 2021-03-19 19:33:18 +00:00
lucko 0f63b024e4 Update readme to clarify build output dirs 2021-03-15 12:17:02 +00:00
Daniil a17b441165 Don't rely on getPackage to determine generated class name (#2937) 2021-03-15 12:12:02 +00:00
Luck e3138eb94c Make console detection more resilient against spoofed UUIDs 2021-03-13 14:25:33 +00:00
Luck 53bb61f9b2 Allow server name to be specified by a system property 2021-03-13 14:16:02 +00:00
Luck 370e2aed0d Add some missing null annotations 2021-03-13 14:14:59 +00:00
Luck b7f05a2f91 API 5.3 2021-03-04 15:13:40 +00:00
Luck bb01c74642 Fix typo 2021-03-04 15:01:47 +00:00
Luck ba71345cbd Improve Vault sync lookup error message 2021-03-04 14:58:00 +00:00
Luck 2c636c5ac6 Further javadoc improvements 2021-03-04 00:25:11 +00:00
Luck 0884dd7e97 Add package description javadocs to the API 2021-03-03 11:48:20 +00:00
Luck c948632dfa Create a copy of args for command timeout catcher 2021-03-02 17:53:10 +00:00
Luck 9647b7de43 Translation file fixes 2021-03-01 13:20:47 +00:00
Luck e7f2a8d713 Add config option to disable built-in contexts 2021-03-01 11:18:21 +00:00
Luck bf0ac1a867 Micro-optimise some frequently iterated lists 2021-03-01 10:38:48 +00:00
Luck 89894353b6 Add web editor deletion cause 2021-03-01 10:16:21 +00:00
Luck ca65e2175d Add getMetaValue API method that accepts a value transformer function 2021-02-28 12:04:23 +00:00
Luck 84c5b818b8 Add cancellable UserUnloadEvent 2021-02-27 18:24:39 +00:00
Luck 843eaaed0c Fix getLocale on older Bukkit releases (#2915) 2021-02-27 15:43:46 +00:00
Luck 4ff2c75538 Add config option to set Hikari keepalive property 2021-02-22 23:02:43 +00:00
Luck 734b011dc7 Some minor tidying 2021-02-22 22:51:45 +00:00
Federico López 4018493285 Fix holder type and name on hover and click events in meta info entries (#2906) 2021-02-22 11:14:45 +00:00
Hai-tun 435e039b38 Bump PostgreSQL version (#2903) 2021-02-20 11:09:07 +00:00
Luck 7579bbe549 Update gradle wrapper 2021-02-20 11:06:41 +00:00
Luck 16ee500054 Fix NoClassDefFoundError when loading extensions on non-JiJ platforms 2021-02-19 16:33:59 +00:00
Luck 88f040e822 Allow extensions to opt to be added to the parent classloader instead 2021-02-19 16:25:11 +00:00
Luck a766c0e9aa Support the web editor payload format in /lp import
This means that if a user accidentally deletes data locally but still has a working web editor session, they can automatically recover the data contained in the session by importing it with the --upload flag.

Of course, this will only be able to recover the data present in the session. The sensible thing would be to create proper backups (using /lp export or otherwise) - but hey, people are dumb.
2021-02-19 14:33:54 +00:00
Luck 40e8038604 Fix non-lower-case meta lookups via the API (#2900) 2021-02-19 09:43:37 +00:00
Luck 3c4091018c Fix bukkit legacy 1.7 build 2021-02-18 13:28:47 +00:00
lucko 75d8f00400 Implement jar-in-jar loader system (#2899)
This fixes an issue that prevented LuckPerms from loading on Java 16
2021-02-18 12:21:17 +00:00
Luck cb5f403043 Invalidate context cache on Bukkit PlayerJoinEvent
The players world is first defined just before this event, so we need to invalidate here as well as on world change
2021-02-16 17:38:45 +00:00
Luck 997e3c7ef7 Add timeout for command executions (#2887) 2021-02-10 11:38:35 +00:00
Luck cb9e0899fc Misc refactoring and tidying up 2021-02-10 11:12:30 +00:00
Luck ab009ed110 Don't use pretty-printed JSON when uploading to bytebin for web apps 2021-02-05 12:44:48 +00:00
Luck c8b89f245e Tidy up RabbitMQMessenger a bit 2021-02-05 12:00:16 +00:00
Callum Seabrook d8aefd23d3 Added virtual host support for RabbitMQ (#2877) 2021-02-05 11:38:13 +00:00
ruViolence a8dfd38fe6 RabbitMQ messenger support (#2874) 2021-02-04 17:10:30 +00:00
Luck b7ac05a0a5 Improve Fabric initial connection debug 2021-02-04 13:29:33 +00:00
Luck b8e044c4e3 Fix Sponge build 2021-01-31 12:51:16 +00:00
Federico López b708d04141 Improve CraftBukkit detection (#2867) 2021-01-31 11:01:44 +00:00
Federico López d485017744 Fix trailing period in translation bundle (#2868) 2021-01-31 11:00:55 +00:00
Luck 35f5944d7b Make separated flat-file read/writes atomic (#2860)
This has become an issue as a result of removing the global per user/group/track IO locks in 478fddc486
2021-01-29 11:42:48 +00:00
Federico López d12be01ecd Fix checking for table existence on SQL storage types (#2864) 2021-01-29 09:34:55 +00:00
Conclure 8043b84dc4 Substitute null check with Configuration#isSet (#2851) 2021-01-26 11:52:12 +00:00
Luck 284e260bc2 Fix node change events not being called for web editor changes (#2857) 2021-01-26 11:41:38 +00:00
Luck ec296460b2 Always allow console to use LP commands (#2841) 2021-01-22 19:16:53 +00:00
Luck 20fee360fb Don't use a WeakReference to hold platform sender objects (#2838) 2021-01-21 12:58:59 +00:00
Luck cd496fdc39 Default apply-default-negated-permissions-before-wildcards to false on Bukkit/Nukkit (#2787) 2021-01-19 14:34:54 +00:00
Luck f9030825fd Add some more annotations to mark API methods 2021-01-19 14:29:49 +00:00
Luck 0a92597767 Don't use adventure-platform on Sponge (#2822) 2021-01-18 22:57:27 +00:00
Luck 6c34da6b32 Catch another Hikari/classloading issue 2021-01-18 13:18:05 +00:00
Luck d5cefac65d Fix Fabric permissions not being copied during player respawn (#2818) 2021-01-16 18:25:26 +00:00
Luck 2a44572fb2 Fix non-daemon command manager thread sometimes preventing shutdown 2021-01-16 18:24:10 +00:00
Luck 73230bc9b6 Tidy up node + context comparators a bit 2021-01-14 20:45:51 +00:00
Luck be1b9d45fa Show the full redis exception in logger output 2021-01-14 20:43:39 +00:00
Luck 238a4fba75 Rename MapProcessor to DirectProcessor 2021-01-13 18:25:02 +00:00
Luck 33e412f663 Include info about wildcards in permission check command output 2021-01-13 17:55:41 +00:00
Luck c904ede972 Improve & consolidate permission check commands 2021-01-13 16:40:57 +00:00
Luck 489c09ddfc Add /lp track <track> editor command (#2752) 2021-01-13 14:33:01 +00:00
Luck 505c073c8e Add config to control whether display names are returned by the Vault hook 2021-01-09 20:36:08 +00:00
Luck 443ea510bb Implement plugin message messenger service on Fabric 2021-01-06 13:14:41 +00:00
Luck 848c36928f Fix logging in on Fabric using offline mode (#2810) 2021-01-05 10:30:28 +00:00
i509VCB 21abb94796 Fabric (#2029) 2021-01-04 15:23:54 +00:00
Luck 0a99a96188 Tidy up Node add/remove/clear API events 2021-01-02 21:16:45 +00:00
Luck a8b1dc8c07 Only store ids of received messages for 1 hour to prevent high memory usage on instances with high uptime (#2807) 2021-01-02 20:08:56 +00:00
Luck c3581c00d3 Fix verbose command no checks message format 2021-01-02 00:50:18 +00:00
Luck 8124a17adb Conserve expiry time when promoting/demoting (#2794) 2021-01-01 20:25:47 +00:00
Luck 68167490d4 Fix permissible injection issue on Nukkit (#2791, #2799) 2021-01-01 20:00:03 +00:00
Luck 657cf2a45e Brigadier arguments in the same parse tree need unique names (#2798) 2021-01-01 19:38:55 +00:00
Luck d83559b949 Change permission tree size limits to be less restrictive 2021-01-01 18:17:56 +00:00
Luck 8167fbf73f Give false default permissions priority over wildcards
I think this is a good compromise. It won't apply to registered permissions that are defaulted to 'op' (Bukkit) or 'undefined' (Sponge), only to those that are specifically set to false.

The change is configurable, enabled by default for new installs of LP.

Will hopefully go some way to resolving:
- #2787
- https://v2.nucleuspowered.org/docs/nowildcard.html
- NucleusPowered/Nucleus#1093 (and related)

cc: @dualspiral @slipcor
2020-12-23 14:36:31 +00:00
Luck 8dfeef9575 Some misc tidying up 2020-12-23 12:16:14 +00:00
Luck 5c44333892 Move migration commands to a separate jar 2020-12-22 14:53:22 +00:00
Luck 142cdc8e89 Add some unit tests
This is a start at least.. I have some catching up to do!
2020-12-22 14:40:29 +00:00
Luck abb608b856 Support Bukkit-Forge hacks which add enum constants at runtime (#2779) 2020-12-20 15:45:57 +00:00
Luck c28b1949a9 Process 'give default if needed' when saving instead of after each change made in the API (#2775) 2020-12-18 19:17:01 +00:00
Luck 8ef871f6db Fix bug with NodeMap#remove (#2772) 2020-12-15 14:31:04 +00:00
Federico López fa89236e48 Fix translation key used for parent clear (#2773) 2020-12-14 21:49:25 +00:00
Luck 2d4af4c691 Mark a number of API methods as NonExtendable 2020-12-14 16:07:20 +00:00
Luck 16fbf566f3 Ensure child permissions are handled as lowercase when resolving (#2761) 2020-12-14 15:22:41 +00:00
Luck e6a5cb06af Include note in verbose command-exec-as response if there were no matches (#2734) 2020-12-14 15:11:49 +00:00
Luck 7bc422c83f Add soft-dependency on ViaVersion to avoid warning msg (#2771) 2020-12-14 14:54:12 +00:00
lucko 478fddc486 Track individual changes to users/groups instead of writing in full on each save (#2767) 2020-12-13 13:08:15 +00:00
Luck 97d1deec9c Slightly optimize weight and display name lookups 2020-12-11 10:38:57 +00:00
Luck 45188c6334 Fix NPE from null path in AbstractFileWatcher (#2759) 2020-12-09 18:21:54 +00:00
Luck 17f67f6e13 Use case insensitive LIKE command on H2 databases (#2760) 2020-12-09 18:08:17 +00:00
Luck 39a5ccf9a9 Some tidying up 2020-12-09 10:46:22 +00:00
Luck 5fbb80f16a Ensure meta keys are always lowercase, and fix 'similar' comparison case sensitivity (#2760) 2020-12-09 10:38:22 +00:00
Luck 798a539024 Fix saving to flatfile storage when sections become empty (#2755) 2020-12-05 14:28:54 +00:00
Luck 645efb0e5b Cleanup applying bulkupdates to Node objects directly 2020-12-05 14:27:32 +00:00
Luck 5bfbf26e2f Fix ArrayIndexOutOfBoundsException from null environment in BukkitPlayerCalculator 2020-12-04 14:17:35 +00:00
Luck 7d7d40b087 Add some missing arg-based permission checks 2020-12-04 14:12:36 +00:00
Luck e183f520d6 Cleanup EventDispatcher and some other minor tidying 2020-12-01 23:31:20 +00:00
Sven Arends 727c2f92c3 PowerRanks migration (#2718) 2020-11-26 17:52:31 +00:00
Luck fdd3b117f1 Reduce translation cache refresh slightly to 23 hours 2020-11-26 17:24:37 +00:00
Luck 8a38c5f4b7 Properly open URLClassLoader module on Java 9+ to allow reflection and avoid access warning (#952) 2020-11-26 15:52:39 +00:00
Luck 53fb46ee85 Expose uuid/username lookups and validity checks as events in the API 2020-11-23 23:54:02 +00:00
Luck d136359cd9 Fix Bungee identifyClassLoader method (again) 2020-11-19 16:51:36 +00:00
Luck d449834767 Fix Bungee identifyClassLoader method 2020-11-19 16:50:31 +00:00
powercas_gamer e851234723 Remove debug command & add more usages to commands (#2725) 2020-11-18 23:52:26 +00:00
Federico López 26f7dfcb24 Fix .verbose.enabled and enabled-recording args (#2732) 2020-11-18 23:51:32 +00:00
Luck d1b53f65ae Cleanup flatfile database handling 2020-11-16 01:17:24 +00:00
Luck c39749e526 Use a better approach for avoiding MySQL driver sharing 2020-11-14 14:10:54 +00:00
Luck 23c7eb79d0 Fix leftover code in MariaDbConnectionFactory 2020-11-14 13:50:37 +00:00
Luck 9af6dccd9d Use the non-registering MySQL driver and revert to using DataSource for MariaDB 2020-11-14 13:44:32 +00:00
Luck 129a10aa60 Automatically install translation bundles 2020-11-12 00:28:02 +00:00
Luck 62270bfd93 Set serverTimezone property on MySQL driver 2020-11-11 13:00:02 +00:00
Luck 9f8b4b2404 Fix inf loop when sending messages to command blocks on Bukkit (#2702) 2020-11-10 16:17:23 +00:00
Luck 00d4a2a1da Update MySQL driver to 8.0, cleanup Hikari usage 2020-11-10 16:00:36 +00:00
Luck 4ce8ea21f9 Sort users with no known username to the bottom of the editor menu 2020-11-10 15:04:36 +00:00
Luck 93d0c54687 Cache some PermissionProcessor instances 2020-11-10 15:04:05 +00:00
Luck 6564cc89f4 Fix NPE when player gamemode or world is null 2020-11-07 17:46:38 +00:00
Luck 9796d2421f Player context calculator fixes, fix compat with Sponge API 7 (#2703) 2020-11-07 11:40:26 +00:00
Luck 0ea0ce9d26 Provide 'gamemode' and 'dimension-type' contexts by default
Also, optimize world rewrites
2020-11-07 00:57:57 +00:00
Luck 3f04d439b4 Fix permission check message arg ordering 2020-11-03 12:17:05 +00:00
Federico López 5bdc798237 Allow creategroup command to take weight and display name as optional arguments (#2698) 2020-11-02 09:48:02 +00:00
Federico López 5d0c578da1 Fix bulk update command failing on SQL based storages when tracking operation stats with multiple constraints (#2699) 2020-11-02 09:46:45 +00:00
MrMicky 7854de8991 Move exception printing to logger (#2695) 2020-10-31 22:25:11 +00:00
Luck 4c23f93a67 Improve locale display names 2020-10-30 13:14:52 +00:00
Luck 7b3beae57f Change wiki links from GitHub to luckperms.net 2020-10-28 11:58:41 +00:00
Luck 15d3000fc1 Make storage meta keys translatable 2020-10-28 10:42:47 +00:00
Luck ad174742e9 Implement localisation for displaying durations 2020-10-25 13:39:14 +00:00
Luck ab0e25a56d Fix loading custom en based translations 2020-10-22 09:17:30 +01:00
Luck 6b05e47deb Include expiry in meta info command (#2663) 2020-10-20 13:10:39 +01:00
Luck b9eb022011 Fix null player locale causing NPE (#2678) 2020-10-20 12:25:35 +01:00
Luck 7d47b31bcb Retain compatibility with older velocity versions (#2676) 2020-10-19 15:15:14 +01:00
Federico López f3857090fa Format group info prefix and suffix (#2677) 2020-10-19 14:47:36 +01:00
Luck d7fa9e08f3 Fix various translation issues 2020-10-19 13:24:44 +01:00
Luck 2c7ff2120c Fix legacy codes in formatted holder display names 2020-10-19 12:37:27 +01:00
Federico López 703b18e51c Make bulk update operations a bit more verbose (#2647) 2020-10-16 12:11:30 +01:00
Luck 3b779dbbd3 Add note to build scripts about our repackaged version of the adventure library 2020-10-16 00:17:42 +01:00
Luck 9af397c2bc Change some of the wording slightly in the translations command 2020-10-15 23:47:51 +01:00
Luck b6e5b0bd47 Fix sending messages on Velocity proxies 2020-10-15 23:35:59 +01:00
Luck 6e7c49488d Add /lp translations command 2020-10-15 23:02:11 +01:00
Underscore11 c5841b58a7 Fix some formatting issues (#2671) 2020-10-15 00:50:00 +01:00
Federico López e8b1214219 Make import take 3 args max so lp import <code> --upload --replace is possible (#2651) 2020-10-14 12:38:05 +01:00
Luck 4811129ab1 Convert to text components and implement new translation system 2020-10-14 12:26:09 +01:00
Luck 63878166db Release 5.2 2020-10-14 12:18:50 +01:00
Luck 2ea43d4b2e Some misc refactoring and cleanup 2020-09-10 21:13:12 +01:00
Luck 442c7d46f9 Ensure that player data is removed even if a corresponding user doesn't exist 2020-09-07 18:16:25 +01:00
Luck 971bb67b51 Add support for user deletion from the web editor 2020-09-07 18:13:33 +01:00
Luck 020aff66aa Refactor web editor session handling 2020-09-07 18:06:40 +01:00
Luck 198b86d7c3 Implement the basis for deleting player uuid data from storage 2020-09-07 17:22:42 +01:00
Luck 84e7fd4d09 Update usage string for /lp import 2020-09-07 16:55:08 +01:00
Luck 4027129052 Default to merge when using /lp import (#2601) 2020-09-07 16:54:27 +01:00
Luck 63f67ca72c Default use-vault-server to false (#2599) 2020-09-07 16:51:07 +01:00
Luck 2adaea2dac Avoid calling JsonObject#size for compat with older gson versions (#2598) 2020-09-05 22:00:56 +01:00
Luck 5e48224c78 Use a map factory when resolving permissions for cached data 2020-08-30 09:14:33 +01:00
Luck cc1d8984da Config option for registering brigadier command list data 2020-08-30 09:13:59 +01:00
Luck 8d9b4182f4 Modify issue templates slightly 2020-08-29 18:37:21 +01:00
Luck f972113d11 Add GitHub issue templates
Credit to @Andre601 and PR #1735 for the original proposal of these templates.

I've held off from adding this for a while, but I now feel that the GitHub UI is nice enough to justify the change.
2020-08-29 18:32:39 +01:00
Luck 4d5a24f2c4 ContextSetJsonSerializer output should be sorted 2020-08-14 16:25:55 +01:00
Luck e2b575dd24 Handle null or empty server/world field in SQL (#2553) 2020-08-13 11:40:33 +01:00
Luck 7fae141e33 Ignore cancelled events for OP command disabling (#2527) 2020-08-13 11:03:24 +01:00
Luck 6f90e545fc Don't attempt further poll operations after SQL messenger has closed (#2516) 2020-08-13 10:49:18 +01:00
Luck ee3bb22c2c Improve Bukkit identifyClassLoader (#2444) 2020-08-13 10:31:20 +01:00
Luck 361a4d66bc Refactor exporter into separate classes 2020-08-13 10:12:36 +01:00
Luck e1bac438aa Add /lp export --without-groups (#2498) 2020-08-13 10:00:49 +01:00
Luck ac9706b83f Ignore FileAlreadyExistsException in MoreFiles#createDirectories (#2525) 2020-08-10 22:29:12 +01:00
Luck fea757887c Use official configurate 3.7 branch 2020-08-01 11:08:46 +01:00
Luck 1eab127f50 Refactor op command detection 2020-08-01 10:20:49 +01:00
Luck 92e008ff0a Fix bug in PermissionHolder#hasNode (#2490)
Regression introduced in bd6d3ab7c0
2020-07-26 14:14:41 +01:00
Luck 9659333d0e Some misc cleanup for migration commands 2020-07-25 16:56:52 +01:00
Larry d8020e77fe Fix import with no users object (#2488, #2489) 2020-07-24 11:43:49 +01:00
Luck 232d17436c Rename config based static calculator 2020-07-21 11:26:16 +01:00
Luck 1461651e22 Include a wider range of potential contexts in web editor payload (#2470) 2020-07-21 11:25:50 +01:00
Luck ef556f7cf7 Pre-generate event classes (#2463) 2020-07-16 21:00:17 +01:00
Luck 47ca6b162b Catch throwable instead of exception when handling hikari errors (#2444) 2020-07-16 20:26:54 +01:00
Luck f72a5cb6b5 Ensure group/track names are always lowercase'd when created via the API (#2440) 2020-07-16 20:19:33 +01:00
Luck cd0fd80b33 Impose 15 second timeout on all http calls (#2436) 2020-07-16 20:15:53 +01:00
Sam Goodger 0fd7f643a7 Add option to use bytebin for exports/imports (#2432) 2020-07-04 20:41:34 +01:00
Mark 6c7c1b67b8 Try to reopen Redis pub-sub connection on failure (#2430) 2020-07-04 20:08:58 +01:00
Luck 4514a17eaf Remove MRUCache
Now we're using ConcurrentHashMap, it's usefulness in terms of performance is debatable
2020-07-03 18:23:34 +01:00
Luck adbd2fc81f Use ConcurrentHashMap instead of Caffeine in CachedDataManager
The behaviour of Caffeine cache invalidation calls is "undefined for an entry that is being loaded (or reloaded)" - this causes a nasty race condition in CachedDataManager, because we rely on the call to #invalidate to completely clear the cache and prevent old/outdated data from sticking around & being used for permission queries.

This is an unfortunate characteristic of Caffeine, because other than that, it is perfect for our use-case.
2020-07-03 17:57:53 +01:00
Luck 8b506b6a95 Don't re-use PermissionCache instances 2020-07-03 15:18:58 +01:00
Luck 426c8565fd Small optimization to processExportedPermissions 2020-07-03 14:57:46 +01:00
Luck bd6d3ab7c0 Optimize PermissionHolder#hasNode 2020-07-02 12:28:30 +01:00
Luck d12d13d6ea Fix NodeMap#size method and rename some things 2020-07-02 12:16:13 +01:00
Luck cc08390abe Remove NodeMap immutable cache 2020-07-02 12:06:37 +01:00
Luck b460e282b1 Add ConstraintNodeMatcher toString method for use in commands 2020-07-02 10:44:52 +01:00
Tobi 005d19f2a3 Fix JavaDoc typo (#2421) 2020-07-02 10:42:37 +01:00
Jonas Baars 8817e17d2c Fix typo in config file 2020-06-29 15:17:42 +01:00
Luck 0f23b7a460 Avoid calling #stream on the result of Bukkit getOnlinePlayers 2020-06-25 10:24:33 +01:00
Luck 21ae1dbac0 Fix potential race condition in MRUCache 2020-06-21 22:07:53 +01:00
Luck 6cb0f5e810 Use a non-async cache in CachedDataManager 2020-06-21 21:23:57 +01:00
Luck 2ac7d3dfe6 Refactor command argument parsing 2020-06-21 19:58:17 +01:00
Luck bfaa543ecd Fix NPE in ConfigurateConfigAdapter#getStringList (#2399) 2020-06-21 10:18:27 +01:00
Luck f893b1c632 Add optional time parameters to permission/parent removetemp commands (#1384) 2020-06-20 22:01:27 +01:00
Luck cb5a28f043 Use the only/default track if one is not specifed in the promote/demote command (#1581) 2020-06-20 21:03:01 +01:00
Luck bd9718c5af Add log notification filters (#1980) 2020-06-20 20:46:54 +01:00
Luck 97a0dbebcb Add DataTypeFilter#NONE 2020-06-13 21:07:59 +01:00
Luck df324de9ec Add DataTypeFilter 2020-06-12 23:14:33 +01:00
Luck 6fa690a49d Update API pom description 2020-06-12 20:36:41 +01:00
Luck 2bb1aa7511 Change behaviour of resolveInheritanceTree when 'resolve inheritance' flag is false 2020-06-12 20:34:57 +01:00
Luck 0bef0902c0 Update some dependencies 2020-06-10 20:41:39 +01:00
Luck f10f60e27f Define dependency on Vault during enable (#1959) 2020-06-10 20:24:11 +01:00
Luck 91337b49ea Just use the section char instead of some other random one
Idk wtf I was thinking
2020-06-08 23:47:10 +01:00
Luck f5e41f7e7e Cleanup chat meta commands 2020-06-08 23:44:25 +01:00
Luck fe0e82f285 Verbose command shouldn't be able to run as console 2020-06-04 14:46:11 +01:00
Luck 8996cf02af Add player argument to'/lp verbose command' to execute the test command as another player 2020-06-04 01:32:56 +01:00
Luck e37c77a1be Add '/lp verbose command <command>' for easy testing of command permissions 2020-06-03 22:32:24 +01:00
Luck 11998b2dd6 Some misc cleanup 2020-06-03 21:20:41 +01:00
Luck 8754123535 Fix parsing second optional argument in editor command 2020-05-30 02:39:37 +01:00
Luck 91d75424f4 Include users which inherit the group when running /lp group <group> editor 2020-05-30 02:13:18 +01:00
Luck c5c99abd16 Improve argument based perm checks for the editor 2020-05-30 01:54:18 +01:00
Luck 6c88f7629e Add optional filter argument to editor command 2020-05-30 01:47:31 +01:00
Luck 98c71739f8 Fix user ordering in the editor 2020-05-30 01:37:24 +01:00
Luck 25551641fc Add option to merge into instead of overriding existing data in imports (#2324) 2020-05-28 21:36:06 +01:00
Luck 00b701f129 Improve undo command generation (#2318) 2020-05-28 20:53:07 +01:00
Luck ab082aa311 Group names should always be lowercase in inheritance nodes 2020-05-28 00:49:46 +01:00
Joshua Schmitt dc32c84bb3 Increase world column max length (#2334) 2020-05-27 14:02:53 +01:00
Luck 0bb4161397 Use nicer toString for Durations in log messages 2020-05-27 10:46:24 +01:00
Luck 4a049ca732 Use contains instead of startsWith for context tab completions 2020-05-27 10:43:30 +01:00
Luck d5ac45d230 Formalize more of the contexts spec 2020-05-25 22:46:26 +01:00
Luck 6b3e4bdc71 Add ContextUpdateEvent and related functionality 2020-05-25 21:49:49 +01:00
Luck 5c0d82f306 Refactor config handler classes 2020-05-25 10:42:32 +01:00
Luck 5a6176def5 Enforce removal of server=global and world=global contexts at a higher level 2020-05-21 17:30:13 +01:00
Luck 13ebc87b29 Fix compatibility with modified SimplePluginManager in Mohist fork
https://github.com/Mohist-Community/Mohist/blob/eab0f722a48759152f5d562b39689317f647ce99/src/main/java/org/bukkit/plugin/SimplePluginManager.java#L674
2020-05-20 21:37:07 +01:00
Luck 1ca1bcf1d1 Make getUniqueUsers more resilient to invalid uuids 2020-05-20 21:23:40 +01:00
Luck ea5a05d770 Fix incorrectly reading node value from the value field when reading from the flatfile meta section (#2312) 2020-05-20 18:22:10 +01:00
Luck ed85ab1bfd Change ContextSet 'satisfy' behaviour (#2300) 2020-05-20 14:51:03 +01:00
Luck c09e4a1aa0 Update web app urls 2020-05-20 14:45:20 +01:00
Luck ee36fa9d81 Fix prefix being displayed twice in extensions info section 2020-05-19 17:47:07 +01:00
Luck bfa5fc43cd Rename getWithPermission method internally 2020-05-19 17:45:16 +01:00
Luck 5d6389249a Fix bug with searching for group permissions via the api 2020-05-19 13:32:06 +01:00
Luck 637cb0d836 Fix group info command 2020-05-19 09:55:00 +01:00
Luck bfebe6a5d0 Cleanup MetaStack, cache the computed prefix/suffix when meta accumulator completes 2020-05-19 00:36:39 +01:00
Luck 4cbbbd390f Don't schedule command list updates if the server is stopping (#2301) 2020-05-16 18:19:05 +01:00
Luck c120fa6a4d Fix startup on Nukkit (#2290) 2020-05-16 11:52:51 +01:00
Luck 918ea7503a Fix bug with duplicated users in editor (lucko/LuckPermsWeb#235) 2020-05-13 11:20:11 +01:00
Luck dbe07827bd Update readme 2020-05-12 23:12:53 +01:00
Luck 98eb756951 Add contextual data section to group info command too 2020-05-12 18:34:07 +01:00
Luck 86eeeb5b94 Slightly change plugin prefix 2020-05-12 17:54:06 +01:00
Luck a3e6628e11 Improve user info command 2020-05-12 16:54:02 +01:00
Luck 84bc4217de Fix command arg rewriting 2020-05-12 16:35:43 +01:00
Luck b88819b9bb Cleanup Bukkit/Nukkit dummy classes, some aren't necessary anymore 2020-05-11 21:58:24 +01:00
Luck c7a0e59919 Catch RejectedExecutionException in BufferedRequest (#2289) 2020-05-11 21:15:42 +01:00
Luck 9984d4be42 Optimize ActionLog and Paginated util 2020-05-11 21:00:42 +01:00
Luck a1c91b9007 Improve sync task performance 2020-05-11 13:46:02 +01:00
Luck 6a256d59f5 Fix null check in selectAllGroupPermissions 2020-05-11 13:12:30 +01:00
Luck fca2f1e6de Optimize loading lots of groups from SQL storage types (#2287) 2020-05-11 12:54:42 +01:00
Luck ec7994a561 Print more useful debug message when a LinkageError is thrown due to bad SLF4J classloading
This is a longstanding issue, mostly caused by plugins with bad Maven shade configurations.

https://github.com/lucko/LuckPerms/issues?q=slf4j
2020-05-11 01:41:01 +01:00
Luck 2839c36ea2 Fix NPE in Nukkit disconnect handling (#2269) 2020-05-10 22:24:47 +01:00
Luck 9f22bf2fbf Update the client commands list when permissions are changed (#2262) 2020-05-10 22:18:01 +01:00
Luck 5f0df1b167 Increase editor users limit to 1000 & sort users according to their max inherited group weight 2020-05-10 16:31:35 +01:00
Luck 3bf2fab2e9 Release API 5.1 2020-05-10 14:02:57 +01:00
Luck 73d76d860e Move PlayerAdapter to platform package 2020-05-10 13:51:30 +01:00
Luck bcfcb64931 Add modifyUser and modifyGroup convenience API methods 2020-05-10 12:40:20 +01:00
Luck a19cb71394 Add PermissionHolder#getQueryOptions API method 2020-05-10 12:22:40 +01:00
Luck 52731fe68e Add getInheritedGroups and getNodes filtered by type methods to the API (#1926) 2020-05-10 01:19:43 +01:00
Luck 7845d89f10 Add some convenience API methods (#1926) 2020-05-09 23:41:28 +01:00
Luck 3d358e57ff Fix group listmembers command behaviour with the default group (#2088) 2020-05-09 19:16:17 +01:00
Luck bd9ae9dbd5 Cleanup command manager aliases handling 2020-05-09 19:04:50 +01:00
Luck f281927578 Re-add group/g --> parent alias (#2054) 2020-05-09 18:40:15 +01:00
Luck 665c53093a Tweak HikariCP config to hopefully improve recovery from database downtime (#2223, #2084) 2020-05-09 18:19:49 +01:00
Luck 10fbc24f43 Add option for Sponge style wildcards on other platforms (#1625) 2020-05-09 17:48:29 +01:00
Luck 6631e9144e Put Nullable annotations in the right place 2020-05-09 17:32:52 +01:00
Luck 7ae532f082 Add UserManager/GroupManager searchAll method 2020-05-09 17:27:17 +01:00
Luck 1af55e3720 Rename InheritanceHandler --> InheritanceGraphFactory 2020-05-07 03:48:09 +01:00
Luck fe32aa2d33 Download dependencies in parallel 2020-05-06 02:50:19 +01:00
Luck f6460c2802 Fix Year 2038 problem for future installs (#2126) 2020-05-06 00:13:19 +01:00
Luck 045c10048d RedisMessenger support for SSL (#2263) 2020-05-05 17:38:24 +01:00
Luck 308356de80 Refactor group name parsing in commands 2020-05-05 17:24:44 +01:00
Luck 8771d4c5e5 Detect incompatible BungeeCord versions 2020-05-03 00:23:58 +01:00
Luck cd25681cd3 Remove special message for error 403
it was a firewall config error at my end after all lol woops
2020-04-28 21:40:52 +01:00
Luck ad6a11819d Ignore null entries in Permission#children map on Bukkit/Nukkit (#2235) 2020-04-28 13:54:23 +01:00
Luck b17da055af Increase UserHousekeeper cleanup interval & print debug message when unloading 2020-04-28 13:47:13 +01:00
Luck 2fd896508b Attempt to fix issue with user instances being unloaded for online players on Bungee (#2238, #2225, #2107 & more) 2020-04-28 13:46:17 +01:00
Luck 99348fce53 Reply with more descriptive message when http requests fail 2020-04-28 13:29:09 +01:00
Luck eb0d758efc Fix Bukkit command map access (#2229) 2020-04-28 12:57:40 +01:00
Luck c03aca35d6 Add checkTime property to verbose data (#2226) 2020-04-26 10:50:10 +01:00
Tobi f484e87828 Add other options to meta formatting config comment (#2222, #2090) 2020-04-24 19:57:50 +01:00
Luck 07b2df7c7e Cleanup configuration files slightly 2020-04-23 13:05:39 +01:00
Luck cab15d39c3 Make the injected LP permSubs replacement value maps thread safe 2020-04-21 20:06:52 +01:00
Luck 36335c10a4 Cleanup imports 2020-04-17 17:49:32 +01:00
Luck 642d14d003 Allow leading '/' in LP commands executed from the console
https://github.com/Turbotailz/LuckPermsWeb/issues/34
2020-04-17 17:46:48 +01:00
Luck 175808e251 Attempt to fix some PowerfulPerms migration issues (#2168) 2020-04-16 15:13:41 +01:00
Luck 14d952a212 Code style 2020-04-16 15:09:01 +01:00
Luck 37e09caac5 Slightly optimize SimpleMetaValueSelector by only invoking the selection strategy if there is a selection to be made 2020-04-16 14:50:44 +01:00
Luck 4d7a6cb658 Add meta-value-selection config setting (#2167) 2020-04-16 14:44:38 +01:00
Luck cc80fe5105 Cleanup ConfigKeys class a bit 2020-04-09 12:00:32 +01:00
Luck b79f6b0fdd Build against SpongeAPI 7.2 2020-04-09 11:47:10 +01:00
Luck 83e9ac04b2 Optimize VerboseHandler by delaying construction of stack trace array until later 2020-04-07 17:56:56 +01:00
Luck 8cecfe5b7c Avoid calls to the Bukkit singleton 2020-04-07 17:50:08 +01:00
Luck 54aed80db8 Fix applying track reordering from the webeditor (#2144) 2020-04-06 11:55:49 +01:00
Luck 0d89fc9d28 Revert "Trial using the default Java hostname verifier instead of okhttp's (#2134)"
This reverts commit cee34d0c31.
2020-04-05 17:49:20 +01:00
Luck cee34d0c31 Trial using the default Java hostname verifier instead of okhttp's (#2134) 2020-04-05 17:41:32 +01:00
Luck d2e60eb5ac Attempt to fix issue converting MongoDB document _id to UUID (#2110) 2020-04-05 16:42:09 +01:00
Luck c71742a996 Use slightly less spammy logging when user data isn't loaded in Bungee permission check handling 2020-04-05 16:25:33 +01:00
Luck fe139f8420 Replace 'none' option with 'auto' in messaging service config description 2020-04-05 16:04:38 +01:00
caramat bb015d0c88 Fix the link to Storage types wiki page in config files (#2135) 2020-04-05 16:03:19 +01:00
Luck 94809c2a66 Defer legacy component handling on 1.7 servers to Kyori lib 2020-04-05 15:48:07 +01:00
Luck 141d3e26ea Update dependencies 2020-04-04 22:47:43 +01:00
Luck efb958ba44 Move Bungee connection event registerIntent call to after possible method return 2020-04-04 12:04:22 +01:00
Luck 9f0fe9e0cb Use a dynamically generated class instead of a reflection Proxy in NonClosableConnection 2020-03-31 14:29:09 +01:00
Luck 2028d65579 Rename some classes 2020-03-31 13:38:28 +01:00
Luck c98c60b120 Fix IllegalStateException when constructing a MetaCache for CalculatedSubjects (#2123) 2020-03-30 22:57:08 +01:00
Luck 6805574553 Use a MethodHandle to call event class constructors 2020-03-30 19:46:30 +01:00
Luck c3128dec0d Generate actual classes for LP events at runtime instead of using proxies + InvocationHandlers 2020-03-30 19:19:27 +01:00
Luck b65639cd76 Ignore empty string world names in Bukkit WorldCalculator (#2119) 2020-03-30 14:32:27 +01:00
Luck 42e9f43443 Store result of primary group calculation in CachedMetaData 2020-03-30 14:13:17 +01:00
Luck c40ad63291 Slightly refactor AbstractConfigurateStorage#appendNode 2020-03-28 10:22:04 +00:00
Luck 0964762217 Avoid call to PermissionUser.initialize in PEX migration (#2102) 2020-03-26 23:09:09 +00:00
Luck 3553a0f9fe Don't attempt to migrate empty users in PEX migration (#2102) 2020-03-26 22:32:53 +00:00
Luck 24304a61a7 Work around issue accessing PEX async in migration (#2102) 2020-03-26 17:18:00 +00:00
Luck 497846e5a6 Run some auto code inspections 2020-03-26 17:01:55 +00:00
Luck 0729be0f0a Print IOException when uploading web editor data fails (#2087) 2020-03-24 10:44:31 +00:00
Luck 2adea2d3dc Improve reliability of java version check in ReflectionClassLoader (#2093) 2020-03-24 10:35:13 +00:00
Luck 30d7768299 Fix parsing contexts from commands with server/world = global (#2093) 2020-03-24 10:03:34 +00:00
Luck 3a7fadb843 Perform uninject tasks synchronously on Bukkit player quit (#2080) 2020-03-24 09:43:32 +00:00
Luck 779bbb9f88 Fix typo
https://github.com/lucko/LuckPerms/commit/3973aa1000f40aca181225961aea9a65852169a9#r37923265
2020-03-19 16:24:14 +00:00
Luck a721cc0b7c Remove unused DefaultQueryOptions class 2020-03-19 12:57:52 +00:00
Luck 3973aa1000 Add notice to inform users to ignore 'illegal reflective access' warning messages (#952) 2020-03-19 12:14:17 +00:00
Luck ac9fe74785 Catch subclasses of Throwable when trying to create a FileWatcher (#2066) 2020-03-19 11:30:19 +00:00
Luck 46c9e3b713 Clarify method name in QuotedStringTokenizer 2020-03-19 11:06:41 +00:00
Luck 05b82cdbab Slightly optimize Permissible#getEffectivePermissions 2020-03-19 11:04:52 +00:00
Luck 3086724e92 Don't print InterruptedExceptions in AbstractFileWatcher (#2044) 2020-03-14 21:26:13 +00:00
Luck fbac03e372 Remove MinimalApiProvider & refactor usages away from static access 2020-03-13 18:13:12 +00:00
Luck 2518a7c8e5 Fix NPE in QueryOptionsImpl (#2051, #2052) 2020-03-11 11:38:38 +00:00
Luck bbec0932fd Fix typo 2020-03-10 23:55:47 +00:00
Luck bca766c20d Ensure immutability of QueryOptions options map 2020-03-04 12:45:13 +00:00
Luck bb3afa21a4 Always store node metadata keys in a HashMap, not IdentityHashMap, and ensure immutability when built 2020-03-04 12:44:47 +00:00
Luck 85451a9a20 Remove legacy import functionality
Users wishing to import data from the old export formats will need to downgrade LuckPerms to a version before this commit, import their data, and then upgrade again.
2020-03-03 11:20:32 +00:00
Luck d475ace76c Export users & tracks in a consistent order 2020-03-03 11:03:30 +00:00
Luck 9f3395f256 Fix StringIndexOutOfBoundsException with empty string in QuotedStringTokenizer (#2041) 2020-03-02 22:52:08 +00:00
Luck c6bda0875c Change argument tokenizer to support unicode double quote characters (#1999) 2020-03-02 15:28:32 +00:00
Luck 4f63a00bad Update FUNDING.yml 2020-03-01 10:23:40 +00:00
Luck 0a3141841c Rename variable for silent flag 2020-02-27 13:20:14 +00:00
Luck 6fea194ef5 Don't attempt to refresh auto op if server is stopping (#1989) 2020-02-27 13:19:53 +00:00
Luck e66ab1be0d Properly close file watcher on disable
https://github.com/lucko/LuckPerms/commit/5ce8217cd53a6540e0e9bd74a996538b55555059#r37466536
2020-02-24 23:45:30 +00:00
Luck 5ce8217cd5 Refactor file watcher 2020-02-24 18:26:52 +00:00
povsisterandLuck 2ed45c92a6 Enhance default config (#2005, #2006)
Co-authored-by: Luck <git@lucko.me>
2020-02-21 20:08:58 +00:00
Luck 9f7d431d34 Accept empty contexts.json file as valid 2020-02-11 15:35:16 +00:00
Luck d937c9ce06 Update commodore to 1.7 2020-02-10 00:45:47 +00:00
Luck 6a96d40da4 Tiny cleanup to #expiry method in NodeBuilder 2020-02-10 00:27:29 +00:00
Luck 2eabe845d7 Update commodore to 1.6 (#1939) 2020-02-09 15:44:52 +00:00
Luck 4cfee76202 Change layout of library storage 2020-02-09 15:24:04 +00:00
Luck 446fa48d9a Optimize LuckPermsPermissionMap putAll implementation 2020-02-05 20:59:10 +00:00
Luck 9546987970 Fix AbstractUserManager to only load users once in #loadAllUsers 2020-02-03 00:44:08 +00:00
Luck 7a624fb449 Add additional call to invalidate cached data during a sync task 2020-02-03 00:30:18 +00:00
Luck 26de6cf86f Refactor CraftBukkitImplementation utility 2020-01-25 16:43:53 +00:00
Luck 5fe7302965 Simplify vault hasPerm check for users 2020-01-25 16:43:31 +00:00
Luck a779b31ca5 Refactor SQL storage implementation 2020-01-25 16:02:37 +00:00
Luck 8fa629a243 Fix/catch IllegalArgumentException when estimating potential world contexts (#1951) 2020-01-25 12:59:41 +00:00
Luck 0864cf756c Cancel delayed/repeating tasks at the start of the disable process (#1935) 2020-01-25 12:38:24 +00:00
Luck e9d72df890 Check for an empty buffer in async tab complete handler (#1949) 2020-01-25 12:25:00 +00:00
Luck c39a44c3ac Add reminder to remove other plugin jar after migration (#1923) 2020-01-25 12:17:23 +00:00
Luck 7e8402b542 Fix compile errors 2020-01-17 10:05:19 +00:00
Luck a050a2604f Fix error extracting command label in AsyncTabComplete handler 2020-01-16 17:55:03 +00:00
Luck abad672bef Implement support for Vanilla command target selectors (e.g. @p, @r) for Bukkit & Sponge 2020-01-16 17:49:28 +00:00
Luck fe3d715f09 Implement Paper's AsyncTabCompleteEvent 2020-01-16 17:20:54 +00:00
Luck e151fbe298 Build against 1.15 APIs 2020-01-16 16:05:19 +00:00
Luck 2ccb475aa0 Cleanup command abstraction classes 2020-01-15 23:54:43 +00:00
Luck 4c83d439af Refactor Vault provider world rewriting 2020-01-14 15:18:45 +00:00
Luck 352f3bd263 Ensure response body is closed when a http request is not successful (#1912) 2020-01-10 12:50:40 +00:00
Luck b73b73e221 Add rewrite rule in legacy importer for for switchprimarygroup command (#1922) 2020-01-09 23:18:05 +00:00
Luck c454d17826 Refactor Vault Chat #setMeta impl 2020-01-07 15:07:21 +00:00
Luck 098f8d8231 Fix NPE when trying to set (chat)meta with a null would through Vault (#1920) 2020-01-07 14:24:04 +00:00
Luck c1e3660551 Update commodore to 1.5 2020-01-04 23:26:53 +00:00
Luck 3ceb53aa4f Improve n/bukkit SenderFactory getPermissionValue impls 2020-01-04 22:00:53 +00:00
Luck a33f326cfc Fix duration parser handling of weeks, months & years (#1905) 2019-12-31 18:04:03 +00:00
Luck 83883aa7e6 Replace internal brigadier command structure with Commodore's file format 2019-12-29 22:01:38 +00:00
Luck 3fae4e5e9e Refactor CacheMetadata 2019-12-29 18:34:55 +00:00
Luck 4e9b11f30a Only apply DefaultsProcessor for users 2019-12-29 18:01:13 +00:00
Luck 46dc4e5104 Cleanup verbose logging for groups 2019-12-29 17:54:11 +00:00
Luck 9c8bdb1166 Fix support for setting vault npc op status 2019-12-29 17:53:39 +00:00
Luck 242993763c Remove vault-debug option
This is now covered pretty much entirely by verbose data.
2019-12-29 17:37:08 +00:00
Luck b84518e1f1 Lots of misc cleanup 2019-12-29 16:26:05 +00:00
Luck b2593d409e Invalidate all user/group caches after node changes are made to groups via the API 2019-12-29 01:17:30 +00:00
Luck d3b3a8af38 Some small cleanup changes 2019-12-29 00:55:41 +00:00
Luck ec2cb5007c Move op handling into a permission processor 2019-12-28 23:41:02 +00:00
Luck ca33cee79d Fix DateTimeFormatter usage in VerboseListener 2019-12-27 23:30:33 +00:00
Luck 2d456bd346 Iterators class refactoring 2019-12-27 23:17:18 +00:00
Luck 10680668db Fix NPEs caused by RepeatingTask initialisation race condition 2019-12-26 20:25:14 +00:00
Luck 0e64b61be4 Improve DurationParser regex 2019-12-25 00:04:39 +00:00
Luck 96c53091d0 Make use of Instant / Duration classes where possible for time handling 2019-12-24 23:10:26 +00:00
Luck 6e64f80c81 Cleanup temporary handing in PermissionHolder#setNode 2019-12-24 18:11:58 +00:00
Luck 8906e4c4fc Fix PermissionHolder#setNode with accumulate temporary modifier (#1839) 2019-12-24 17:54:35 +00:00
Luck cc5d7ea873 Don't randomly add 1 second to parsed dates 2019-12-24 17:49:27 +00:00
Luck 6237d58ad6 Fix license header checks violation 2019-12-24 17:16:40 +00:00
Luck fae5ebe226 Prefer "storage provider" to "dao" in logging messages for consistency with rest of code base 2019-12-24 14:08:23 +00:00
Luck 9a92920120 Downgrade h2 version to 1.4.199
Fixes https://gist.github.com/lucko/2ba1a9eb52fd76da19e54888c2595381

See: h2database/h2database#2078
2019-12-24 14:00:48 +00:00
Luck dc5c6b0138 Set character set to utf8 for messenger table (#1887) 2019-12-24 13:46:19 +00:00
Luck 88c432496b Reimplement "legacy" shorthand syntax
i.e. using ( ) for groups, and | for list separation
2019-12-24 13:24:20 +00:00
Luck 63b890d522 Rename EventFactory --> EventDispatcher 2019-12-24 13:05:48 +00:00
Luck cd5c8d7cdf NodeEqualityPredicate refactoring 2019-12-21 19:58:37 -05:00
Luck d80017ba7b Refactor /lp import command, better handling when no file extension is provided 2019-12-21 17:46:37 -05:00
Luck 5eb8a262be Set giveDefault to true when running the 'clear' command 2019-12-14 17:22:48 +00:00
Luck 7474842b45 Cleanup the way contexts for transient permissions are determined 2019-12-14 17:06:26 +00:00
Luck 9093385de3 Fix NPE in Permissible#recalculatePermissions 2019-12-13 14:30:37 +00:00
Luck bd349ac4a3 Use standard (not Identity) HashMaps for OptionKeys and NodeMetadataKeys 2019-12-13 14:02:31 +00:00
Luck 37367fe91f Invalidate QueryOptions cache when op status changes 2019-12-13 13:56:34 +00:00
Luck dce792083b Fix some issues with null world contexts in migration scripts 2019-12-13 11:51:42 +00:00
Luck 06f7900318 Use thee default set of flags by default in QueryOptions.Builder, etc 2019-12-13 11:28:46 +00:00
electron d8ac199858 Additional SQL query escaping fixes (#1847, #1854) 2019-12-05 21:46:00 +00:00
Luck 9cf21e2927 Include loaded extensions in the info command (#1849) 2019-12-05 21:44:45 +00:00
electron 86a15b9a66 Escape table name with backticks (`) in sql messenger (#1847, #1848) 2019-12-04 20:50:56 +00:00
electron 31b57df567 Fix json action serialization (#1843, #1844) 2019-12-04 11:18:37 +00:00
Luck a07f876c85 Re-implement parsing first/second context values as server/world respectively (#1837) 2019-12-02 21:23:58 +00:00
Luck 2eb0c1e67e Use getPlainDisplayName to get name for hover messages (#1663) 2019-12-02 21:03:45 +00:00
Luck 6325e25630 Limit the number of scheduler work threads 2019-12-02 15:10:18 +00:00
Luck 6fdd349654 Fix (un)setting nodes through Vault with null worlds (#1826) 2019-11-29 12:16:24 +00:00
Luck 01e17adf82 Cleanup imports 2019-11-25 22:52:37 +00:00
Luck acdd5f3faa Don't attempt to load permissions data for login events cancelled at the lowest priority
Makes LuckPerms more compatible with "anti-bot" plugins.
2019-11-25 22:51:11 +00:00
Luck 4d3c692402 Fix concurrency bug in CachedDataManager MRU cache
This resolves a longstanding issue with TownyPerms (#1330)
2019-11-25 20:31:14 +00:00
Luck 787f691f44 Improve shorthand parser 2019-11-25 00:34:23 +00:00
OmegaWeapon_ 500385cd3e Add temporary modifier to the argument list for permission/parent settemp (#1817) 2019-11-24 16:27:36 +00:00
Luck 6df64a29dc Don't set username to null when a user is requested by uuid alone 2019-11-24 00:40:38 +00:00
Luck 233324f6c9 NodeMap optimizations 2019-11-24 00:40:38 +00:00
Andre_601 da253c47da Update badges for new API coordinates (#1816) 2019-11-24 00:38:22 +00:00
Luck 8725ace739 LuckPerms v5 2019-11-23 18:21:32 +00:00
Andre_601 0d9106185c Add note about checking console to storage errors (#1678) 2019-11-23 18:19:19 +00:00
Luck 7449f6f9af Update patreon link 2019-11-23 18:18:25 +00:00
Luck 2316b6806e Cleanup in StackTracePrinter 2019-11-23 17:43:56 +00:00
Luck 94418d3648 Log thread in verbose events 2019-11-23 17:26:48 +00:00
Luck 479b2d026c Remove sql schema migrations 2019-11-23 14:15:30 +00:00
Luck 8e9683b33f Fix compile 2019-11-23 14:10:17 +00:00
Luck 6481bac045 Fix license violations 2019-11-23 13:21:11 +00:00
Luck 86aadf2cf8 A few more small API changes 2019-11-23 12:59:40 +00:00
Luck 95d2832884 A few more small API changes 2019-11-23 12:52:26 +00:00
Luck 213b2fcb44 Downgrade okhttp & okio 2019-11-19 18:09:14 +00:00
Luck c4bd657826 Changes to messaging service setup 2019-11-19 15:18:47 +00:00
Luck a5e15b8a29 More work 2019-11-18 21:19:59 +00:00
Luck 7a37fcd792 Implement a simple compiler (lexer + parser) for verbose filters
Removes the dependency on the Nashorn runtime.
2019-11-14 22:58:29 +00:00
Luck 81cbe02a9c Move some things around a bit 2019-11-14 19:43:57 +00:00
Luck 79c10c986e Web editor changes 2019-11-12 12:12:53 +00:00
Luck c836cce59b Moreeee stuff 2019-11-09 22:50:10 +00:00
Luck 287c0f7f7a All the cleanup 2019-11-09 22:34:12 +00:00
Luck dc52807a46 Fix issues with *-combined file storage methods (#1793) 2019-11-04 19:26:53 +00:00
Luck 916e3dbb0b Revert bad text refactoring, bump version to 3.0.2 2019-10-15 13:58:20 +01:00
Luck 4b0574710e Implement new compressed json import/export format
The old "command list" style is now only supported for import.
2019-10-14 17:25:37 +01:00
Luck 7764a04d46 More work 2019-10-13 15:04:03 +01:00
Luck 9438df787a Changes to option keys 2019-10-12 00:27:53 +01:00
Luck fd954d8293 More work 2019-10-06 21:34:24 +01:00
Luck 72dec16f54 Context parsing changes 2019-09-21 08:30:14 +01:00
Luck 40218563e1 Cut down on the number of command aliases 2019-09-04 22:34:25 +01:00
Luck 0251f2add9 Cleanup some stuff 2019-09-04 22:29:36 +01:00
Luck f0e42c6db6 Allow context calculators to define "potential contexts", and use these for tab completions 2019-09-04 22:08:24 +01:00
Luck 4b793d1f14 More work 2019-09-04 20:58:46 +01:00
Luck 61e5da928a Fix various runtime errors 2019-08-29 22:07:12 +01:00
Luck 419707aa5f Cleanup web clients 2019-08-26 20:37:33 +01:00
Luck 8b970c21fc Remove default assignments
For real this time
2019-08-26 19:33:43 +01:00
Luck 7a31edea09 Extensions 2019-08-26 19:31:55 +01:00
Luck b286faa1c5 Change API package to net.luckperms 2019-08-26 18:06:45 +01:00
Luck 5e2f45ebd0 Web editor changes, towards #1703 2019-08-26 15:03:30 +01:00
Luck eff93c788b Log action serialization changes 2019-08-26 14:04:49 +01:00
Luck 4667ffc681 Allow data query order to be specified via the API 2019-08-26 14:04:49 +01:00
Luck bafada4f17 Context & action log changes 2019-08-26 14:04:50 +01:00
Luck 5b97d01363 Permission holder refactoring 2019-08-26 14:02:39 +01:00
Luck 3474c66c1c Big API refactor
- removed a bunch of ugly / badly designed methods and APIs
- refactored 'Contexts' --> 'QueryOptions'
- Removed the FullySatisfiedContexts hack and replaced it with a sane API
- Made PermissionHolder (in the API) less ugly and horrible
- removed lots of deprecated / duplicated API functionality
and much more...
2019-08-26 14:02:44 +01:00
Luck 8f8c916be3 API: remove storage interface 2019-08-04 11:27:31 +01:00
Luck a823290d66 API: remove uuid cache 2019-08-04 11:27:27 +01:00
Luck 5577e3f590 Jedis requires SLF4J (#1579) 2019-07-14 09:11:54 +01:00
Luck ffe6c24b53 Properly remove "minecraft:" prefixed brigadier aliases 2019-06-03 20:15:29 +01:00
Luck 4e4982a98d Create FUNDING.yml 2019-05-27 10:40:12 +01:00
Luck 7f4f9bb917 Fix build 2019-05-20 23:09:02 +01:00
Luck 8d8024ba5e Fix group changes via the API not properly invalidating caches (#1534) 2019-05-20 10:42:48 +01:00
Luck 2e16b15b0e Change Sender#getNameWithLocation behaviour 2019-05-14 20:32:35 +01:00
Luck 1ebed37297 Remove use-server-properties-name option
This was removed from Minecraft 1.14, and isn't something I feel was ever really necessary to support.
2019-05-11 23:17:59 +01:00
Luck ff37ad176b Update text adapters to latest version (#1525) 2019-05-11 23:12:55 +01:00
Luck d0c5d89e91 Update to expect Velocity shading text 3
This reverts the reflection workaround implemented in f49446011a
2019-05-07 13:59:44 +01:00
Luck f49446011a Update to text 3 2019-05-07 00:23:40 +01:00
Luck d762a0aaa6 Reduce new instance creation further in TristateResult.Factory 2019-04-28 15:35:46 +01:00
Luck 2dc211a91e Don't account for wildcard/default permissions when running require-sender-group-membership-to-modify checks (#1512) 2019-04-24 18:40:27 +01:00
Luck 2c62de9658 Refactor storage type config read 2019-04-23 21:57:43 +01:00
Luck 494ab6787f Update okhttp 2019-04-23 20:45:02 +01:00
Luck b81e8a40a4 Refactor VaultHookManager 2019-04-22 10:27:29 +01:00
Luck 2fd2f4fedb Ignore exception if Brigadier is not supported by the server (#1506)
This error occurs when another plugin/the server shades the brigadier library without relocation on pre 1.13 MC versions.
2019-04-22 09:24:05 +01:00
Luck 493e5d08be Finish refactoring 2019-04-22 09:15:46 +01:00
Chinese Marc 62a834e145 Fix build (#1509) 2019-04-21 21:49:13 +01:00
Luck 241f13c8f1 Package renames 2019-04-20 18:10:31 +01:00
Luck 98ea255667 Refactor blank message sending 2019-04-19 09:46:45 +01:00
Luck 420ec2bf1a Don't attempt to read a boolean 'value' from parent/chatmeta/meta entries in file based storage files (#1505) 2019-04-18 23:14:23 +01:00
Luck 364a494ac6 Fix making changes to group subjects via the Sponge API (#1495) 2019-04-18 22:57:53 +01:00
Luck 821d1cb8dd Fallback to utf8 encoding if utf8mb4 isn't supported (#1497) 2019-04-17 18:44:34 +01:00
Luck 544ffbad19 Add missing javadocs to ConfigKeys 2019-04-06 18:22:19 +01:00
Luck 4fa6cd2577 Add configuration option to perform a post-traversal sort according to the inheritance (weight) rules 2019-04-06 18:20:30 +01:00
Luck 37d1f5efab Improve behaviour of userInGroup and userHasPermission Vault calls 2019-04-03 10:12:24 +01:00
Luck 7cd8e8bf5b Fix NPE in Vault contextForLookup method
Fixes CodeCrafter47/BungeeTabListPlus#415
2019-04-03 10:01:18 +01:00
Luck 8eed4558f4 Release API v4.4 2019-04-02 16:36:22 +01:00
Luck 62ca2d9c79 Implement special handling in the LP Vault implementation for NPC players (#1470) 2019-04-01 15:09:58 +01:00
Luck c7a0d7026c Update API build script 2019-04-01 14:00:46 +01:00
Luck ce74813ce5 Fallback to node/context ordering in InheritanceComparator, refactor graph traverser classes 2019-03-14 15:23:26 +00:00
Luck d1511e43f2 Fix build 2019-03-10 19:19:46 +00:00
Luck 6ef749c76a Update some dependencies 2019-03-08 23:11:32 +00:00
Luck 8846932cb6 Refactor the HolderType enum 2019-03-08 20:19:08 +00:00
Luck 12b861db3f Update PermissionHolderSubjectData#save code 2019-03-08 19:56:07 +00:00
Luck 0a50df6557 Code style: move private constructors for singleton classes to the top of the file 2019-03-05 12:36:09 +00:00
Luck 3726f6de41 Use a separate fork join pool for cache loading operations 2019-03-05 12:35:29 +00:00
Luck d1ca7684d6 Refactor AbstractJavaScheduler to make use of a cached thread pool 2019-03-05 12:32:16 +00:00
Luck 512b621a7a Refactor Dependency class a bit 2019-03-03 16:46:20 +00:00
Luck 2cf919a17a Bump hikari version 2019-03-03 12:01:15 +00:00
Luck 46072eb465 Attempt to detect and warn about CraftBukkit + offline mode problems (#1439) 2019-02-21 14:14:00 +00:00
Luck ae63a42c2e Slightly optimize regex and wildcard processors 2019-02-21 12:37:23 +00:00
Luck 8773ec07ab Include processor & cause in verbose hover message 2019-02-19 23:30:11 +00:00
Luck 287cc308d6 Fix parsing log entry types (#1438) 2019-02-19 14:17:33 +00:00
Luck beeb4fa169 Fix DuplicateRemovalFunction javadocs 2019-02-19 14:09:26 +00:00
Luck 4ef3d50965 Properly implement ContextManager#unregisterCalculator (#1422) 2019-02-09 11:50:00 +00:00
Luck dae64fc8c4 Cleanup some of the Sponge permission holder implementation code 2019-02-07 15:35:09 +00:00
Luck 215031a1f3 Close messaging service before storage
Fixes https://www.spigotmc.org/threads/174259/page-129#post-3302827
2019-02-07 12:38:24 +00:00
Luck 85d2f0b51f Add method to unregister context calculators (#1422) 2019-02-07 12:24:23 +00:00
Luck d91355e4d6 Remove some unused code 2019-02-04 20:35:39 +00:00
Luck 1a690dabd7 Implement NodeMap without using Guava's Multimap util (#1416) 2019-02-04 20:35:20 +00:00
Luck 526448ce40 Don't try to set unicode connection properties for PostgreSQL (#1134) 2019-02-04 19:36:53 +00:00
Luck 43d04a97f5 Correctly implement Bukkit/Nukkit isPermissionSet method, inline with the behaviour in PermissibleBase (#1403) 2019-01-31 01:14:38 +00:00
Luck 307614e704 Cleanup import statements 2019-01-31 00:53:42 +00:00
Luck f6c0794691 Return more detailed information about exactly how a permission check result was determined 2019-01-31 00:45:56 +00:00
Luck 83db00aef8 Better null checking in HikariConnectionFactory (#1408) 2019-01-30 16:24:30 +00:00
untuned 22252fa46d Update MIT license text to allow GitHub detection (#1400) 2019-01-28 10:46:05 +00:00
Luck 7b8426977a Switch text dependency back to 1.11 (#1404) 2019-01-28 10:39:08 +00:00
Luck d9912cb93f Update some dependencies 2019-01-27 22:51:05 +00:00
Luck 5db999f995 Only form data buf once in Bukkit PluginMessage messenger 2019-01-23 12:12:33 +00:00
Luck b744e35ad8 Fix typo in Vault exception message 2019-01-18 23:21:23 +00:00
Andre_601 b6769811a2 Fix some small typos (#1389) 2019-01-18 09:47:03 +00:00
Luck 1d9fc568e4 Fix calling default methods on Event interfaces (#1386) 2019-01-16 14:43:55 +00:00
Luck 3c0d1ba7a1 Ensure caches are invalidated when Bukkit/Nukkit's Permission#getChildren map is modified (#1378) 2019-01-13 16:58:31 +00:00
Luck 78a74510cf Fix Sponge and Velocity build scripts 2019-01-12 13:39:07 +00:00
Luck d3ae3324fa Allow the bytebin url to be configured 2019-01-12 12:02:16 +00:00
Luck 4b97c9419e Finish updating commodore
woops
2019-01-07 21:29:28 +00:00
Luck db830a0bef Buildscript changes 2019-01-07 21:25:11 +00:00
Luck 797c195424 unInject -> uninject 2019-01-07 20:45:47 +00:00
Luck 4788290615 Rename Vault implementation classes 2019-01-07 20:44:52 +00:00
Luck d0c016f6b7 Cleanup with way permissibles are monitored on Bukkit/Nukkit
- The removal of the call to recalculatePermissions should fix CMEs on startup, in particular with Vault.
- Monitored permissibles are now uninjected when the plugin disables.
2019-01-07 20:21:36 +00:00
Luck 9b1c73ed23 Implement use of a Maven Central mirror for dependency downloads
People keep telling me that LP's use of Maven Central for downloading dependencies is not allowed / inappropriate / abusive. I disagree but I'm bored of hearing it. Using a mirror will mean that all of the load is taken off of Central, and is instead absorbed by my servers + (mostly) Cloudflare.

- The mirror is (currently) hosted at https://nexus.lucko.me/repository/maven-central/
- The prospect of the mirror becoming compromised is not a concern. LuckPerms compares the downloaded content against a checksum before saving it.
- The prospect of the mirror going offline is also not a concern. We will fallback to Maven Central if a connection cannot be made to the mirror.
2019-01-07 16:56:16 +00:00
Luck 048768007d Change the way static contexts are displayed in /lp info 2019-01-07 15:44:54 +00:00
Luck ec7a5321a6 Some misc refactoring / code cleanup 2019-01-07 15:08:13 +00:00
Luck c396323308 Log exceptions thrown by BufferedRequest tasks 2019-01-05 23:06:57 +00:00
Luck 6fc2321fad Refactor PlayerLoginProcessEvent
This is technically a breaking change, but I'm fairly sure I'm the only person using this event. It's quite obscure ;p
2019-01-02 13:54:55 +00:00
Luck a0d04790a5 Update text-adapter-bungeecord to 1.0.2 (#1362) 2019-01-01 15:33:18 +00:00
Luck c4154c09da Remove SQL indexes on the permission field 2018-12-23 21:56:51 +00:00
Luck 8eed3131f2 Fix sending component messages on older CB/S releases (#1344) 2018-12-23 16:52:00 +00:00
Luck e5c4b710f6 Fix CME in Bukkit refreshAutoOp
cc @Exloki
2018-12-22 17:04:32 +00:00
Luck 2ccffc6e6d Fix error message when event handlers throw an exception 2018-12-22 17:03:51 +00:00
Luck fc69002c86 Fix wrong checksum for text-adapter-bukkit 2018-12-19 14:36:20 +00:00
Luck e3a6db5f97 Refactor ProgressLogger slightly 2018-12-19 10:39:48 +00:00
Luck 6d8077ffd0 Use text-adapter-bukkit for sending Components to Bukkit objects 2018-12-19 10:29:22 +00:00
Luck 784161d66d Update okhttp and okio versions 2018-12-19 10:06:36 +00:00
Jonathan Frederick 115f793733 Make gradlew script executable by default (#1338) 2018-12-19 09:24:44 +00:00
Luck 2cb5e437fd Switch default MySQL/MariaDB charset from utf8 to utf8mb4
https://medium.com/@adamhooper/in-mysql-never-use-utf8-use-utf8mb4-11761243e434
Relates to #1337
2018-12-18 16:02:25 +00:00
Luck 8c57c2b46d Remove static imports 2018-12-18 12:51:26 +00:00
Luck 879a88a398 Account for 'allow-invalid-usernames' setting in API calls 2018-12-18 12:50:52 +00:00
Luck 7e50c3c777 Update Gradle to 5.0 2018-12-15 22:24:17 +00:00
Luck 4b1cf51530 replace LoadingCache with more simple LoadingMap alternative when no auto expiry is needed 2018-12-14 18:37:56 +00:00
Luck de24817d9c Some node equality changes 2018-12-14 17:27:34 +00:00
Luck 085e7af681 Small cleanup in Contexts class 2018-12-10 15:33:57 +00:00
Luck 1aabd7610e Tweak PlayerSaveResult javadoc 2018-12-10 15:33:38 +00:00
Luck ef31db1431 Improve /op and /deop command matching 2018-12-10 15:33:04 +00:00
Luck 757e9d6be6 Add API method to get known permissions & improve the way PermissionDescriptions are migrated from existing Sponge services when LP enables 2018-12-07 14:07:54 +00:00
Luck b3a028e3ca Refactor AbstractConnectionListener for the addition of Velocity support 2018-12-07 13:36:38 +00:00
Luck e222e4e98c Missing nullability annotations 2018-12-07 13:33:05 +00:00
Luck 1213e58240 Depend on a specific Velocity snapshot version
Fixes #1319
Fixes VelocityPowered/Velocity#159
2018-12-06 14:04:31 +00:00
Luck b7ff0824b9 Optimize context set manipulation 2018-12-06 14:02:41 +00:00
Luck 7b5917660c Implement LoadingMap using Guava's ForwardingMap utility 2018-11-28 12:35:38 +00:00
Luck 1544487e92 Convert permissions to lowercase inside the cache
Slight optimization, toLowerCase is a relatively expensive call in the scheme of permission checks.
2018-11-24 13:09:26 +00:00
Luck c19ef84116 Optimize ImmutableContextSet#equals by comparing the hashcodes (constant time lookup) 2018-11-24 01:25:02 +00:00
Luck e8c4a55dc3 Cache the most recent lookup for permission/meta data in AbstractCachedData.
This avoids a (somewhat) costly lookup operation involving Contexts comparison. It aims to be effective on the basis that lookup calls within the same period of time are likely to target the same context (and therefore have the same result).
2018-11-24 01:17:42 +00:00
Luck 97d6aaed5c Experiment with different cache implementation in PermissionCalculator
Caffeine seems to just fallback to a ConcurrentHashMap based implementation in this case anyway.
2018-11-24 00:15:56 +00:00
Luck fe77834cef Optimize LookupSetting storage/manipulation within Contexts
Fixes some performance issues resulting from bad use / implementation of ImmutableEnumSets
2018-11-23 23:58:49 +00:00
Luck 2da6298c53 Update references to the project website 2018-11-22 15:25:39 +00:00
Luck e111270aed Add api-version option to Bukkit plugin.yml file
This doesn't make any functional change, LP doesn't use any of the remapped Material APIs. It only saves on the amount of remapping CB tries to perform when loading the plugin.
2018-11-22 15:19:12 +00:00
Luck e07f8c0fbe Don't send 1.13 tab completions to players without access to any LP commands (#1310) 2018-11-22 15:07:55 +00:00
Luck 90246afd03 Some misc refactoring 2018-11-22 14:51:20 +00:00
Luck 9809e591ad Reorganise some packages 2018-11-10 23:16:28 +00:00
Luck 26973461e7 Don't show negated group membership permissions in the output to 'user info' and 'group listmembers' 2018-11-10 22:42:54 +00:00
Luck 759ec5d499 Attempt to parse uuid from username string in Vault hook 2018-11-10 20:23:40 +00:00
Luck 58ab3c325c misc tidying up 2018-11-10 20:21:08 +00:00
Luck 44c8c67803 Update README.md 2018-11-06 16:36:34 +00:00
Luck acb56d683a Add missing since tag to MetaStackFactory 2018-11-06 15:42:59 +00:00
Luck 5dda522a62 Add option to deduplicate prefix/suffix stacks (#1285) 2018-11-06 14:29:15 +00:00
Luck 79091c726b Update readme badges 2018-11-06 13:28:05 +00:00
Luck e5be06e07b Use the newly added API method to retrieve Velocity implementation name / version 2018-11-06 13:18:58 +00:00
Luck f63992e209 Return a more informative error for invalid verbose filters 2018-11-06 13:16:07 +00:00
Luck 9988011308 Improve the way meta lookups are caught & reported to the verbose handler 2018-11-06 13:15:30 +00:00
Luck 8584a9b72c Sponge Subject lookup methods without a contexts param should default to current contexts, not global (#1279) 2018-11-02 22:39:02 +00:00
Luck 42c8cb1354 Use the fragment identifier instead of query parameters to convey the editor/verbose/treeview data id
This fixes the issue Multicraft panels have with displaying ? characters in console. (absolute quality)
2018-10-28 22:32:02 +00:00
Luck aaeaf5cfa0 Nicer format for verbose meta logging 2018-10-28 21:56:42 +00:00
Luck 45b4e1463f Match the type in verbose filters 2018-10-28 15:18:02 +00:00
Luck be92a67544 Increase verbose stacktrace truncation length for web outputs 2018-10-28 12:40:56 +00:00
Luck 5e0b8ebdf6 Include meta lookup events in verbose output 2018-10-28 12:31:47 +00:00
Luck 9d4ccd33e1 Update commodore for tab complete fix (#1257) 2018-10-26 20:21:00 +01:00
Luck f5c42c70e5 Catch Throwable instead of Exception when calling context calculators
Related to:  lucko/ExtraContexts#4
2018-10-15 22:32:52 +01:00
Luck dcc4656e5e Update buildscripts for Sponge Ore deployment 2018-10-15 22:30:36 +01:00
MrMicky ee2de3cff1 Some minor code cleanup (#1262) 2018-10-09 18:00:53 +01:00
Luck f96518b8e4 misc tidying 2018-10-07 19:48:20 +01:00
Luck dac59966aa Setup gradle license format check 2018-09-24 13:52:59 +01:00
Luck 8115fbaa98 Refactor storage system 2018-09-23 21:49:49 +01:00
Luck 8b97439ffc Use the correct permission check method when forming tree views 2018-09-23 19:53:37 +01:00
Luck fa83986250 Refactor Constraint/Comparison impls for bulkupdate 2018-09-23 19:53:16 +01:00
Luck e1b16465f8 Fix race condition in BufferedRequest 2018-09-23 19:52:42 +01:00
Luck 57619dacb1 Update commodore to 1.1 2018-09-23 15:40:33 +01:00
Luck 64e54d89eb Refactor buildscript determinePatchVersion function 2018-09-23 15:20:22 +01:00
Luck aa4139f0b7 Release v4.3.0 2018-09-23 15:04:15 +01:00
Luck e2f1c1e16b Remove specific dependency on Sponge API 8 in the mod info file (#1221) 2018-09-23 15:02:02 +01:00
Luck 1e7ef15e54 Fix class cast exception in NodeTypeKey#getTypeName (#1230) 2018-09-23 14:38:27 +01:00
Luck 1cc156d6f6 Fix buildscript deployment config for Sonatype 2018-09-23 14:30:09 +01:00
Imortalshard 1445a3faec Fix typo in the description of /lp export (#1229) 2018-09-23 11:28:48 +01:00
Luck 1cf90692cf fix typo 2018-09-21 21:53:06 +01:00
Luck 5656bea3f9 Update for latest Velocity changes 2018-09-21 21:36:44 +01:00
Luck 8e344cea76 Cleanup imports 2018-09-20 21:17:28 +01:00
Luck 5b1229c882 Fix slf4j loading (#1224) 2018-09-20 21:17:00 +01:00
Luck 834649b390 Improve Uuids#parse
thanks @kashike
2018-09-20 15:30:22 +01:00
Luck d28170cc3f Operations to add new nodes with differing values should just override existing entries, instead of failing with the ALREADY_HAS result (#1198) 2018-09-20 11:25:31 +01:00
Luck 04e511026d Detach from permissible objects with a 1 tick delay after player quit to allow plugins listening on monitor to still access data (#1220) 2018-09-20 11:07:20 +01:00
Luck 11a3ecbba0 Fix NPE when loading subject data on Sponge (#1222) 2018-09-20 10:51:00 +01:00
Luck 51b7bb93e2 Don't trigger Vault primary thread checks whilst the server is starting up 2018-09-20 10:44:04 +01:00
Luck 9fd2028d9f Update for velocity API changes 2018-09-19 21:47:22 +01:00
Luck 75f0f40d70 NonNull annotations should be on the same line in interfaces 2018-09-19 21:12:54 +01:00
Luck 3941c77826 Move from findbugs jsr305 to checker-qual 2018-09-19 20:40:25 +01:00
Luck 4987ca3ba2 Update gradle wrapper and buildscript plugins 2018-09-19 19:41:47 +01:00
Jesse Boyd 5fa481337a Fix Nukkit permissible null handling - fixes #1191 (#1213) 2018-09-12 08:58:55 +01:00
Luck dd78e0e271 Separate formatted vs plain display name methods in User/Group
Continues from 3c773e6823 & #1210
2018-09-10 16:54:16 +01:00
Max Lee 3c773e6823 Use neutral color to display potentially colored names - fixes #1170 (#1210) 2018-09-10 16:41:14 +01:00
Luck 54a9ff9256 Fix compile 2018-09-09 11:31:17 +01:00
Luck eca6b09b18 Refactor config keys 2018-09-05 20:49:37 +01:00
Luck b7f8ca6658 Add 'require-sender-group-membership-to-modify' config option (#1140) 2018-09-05 15:49:29 +01:00
Luck ffdeadac8a Add flag to prevent users from being added/removed to/from the first group on a track (#1151) 2018-09-05 15:15:15 +01:00
Luck 9e769904bf Expose TemporaryMergeBehaviour in the API (#1189) 2018-09-05 11:11:45 +01:00
Luck 8d79ec6b07 Rename "update task" --> "sync task" 2018-09-04 21:11:03 +01:00
Luck 3a123f9fa1 Avoid running full "update tasks" unless they're absolutely needed. Process Vault API "set" requests immediately instead of in the background 2018-09-04 21:02:40 +01:00
Luck f0c0328919 Refactor MetaAccumulator to be a little more sane 2018-09-04 20:33:22 +01:00
Luck 274286032a Update banner in readme 2018-09-03 13:56:49 +01:00
Luck 76517374a2 Only allow import and export commands to interact with files in the data directory (#1193) 2018-09-02 22:20:29 +01:00
Luck 2da027f3b5 Revert MySQL driver update 2018-09-02 20:04:26 +01:00
Luck fd712f131f Update some dependency versions 2018-09-02 16:36:28 +01:00
Luck 38613e5f03 Update gitignore 2018-08-31 20:27:13 +01:00
Luck ec9060ba80 Update messenger log prefixes 2018-08-31 20:22:31 +01:00
Luck 502d57e744 Optimize event generation & other misc improvements 2018-08-27 22:11:03 +01:00
Luck c59f2ab37a Don't call NodeAddEvent when adding the default group (#1177) 2018-08-27 22:06:49 +01:00
Luck 066189b486 Send a more informative message when the bulkupdate command is used from in-game 2018-08-27 18:25:57 +01:00
Luck 37d4f92c33 Update README 2018-08-27 09:37:41 +01:00
Luck 55220e9d10 Add support for Velocity 2018-08-26 22:24:46 +01:00
Luck bd41286076 Fix build 2018-08-26 18:45:33 +01:00
Luck d84484c81c Optimize event generation and posting 2018-08-26 10:28:04 +01:00
Luck fec87d4c6a Update event to 3.0.0 2018-08-16 20:01:26 +01:00
Luck 68ec6e2a37 Include license file in the jar 2018-08-14 10:56:07 +01:00
Luck a784ad435f Fix applying group web editor changes (#1148) 2018-08-13 22:44:10 +01:00
Luck cc9bb34873 Update kyori/event dependency 2018-08-13 20:03:57 +01:00
Luck 2ddae5a96c Avoid UnsupportedEncodingException in LilyPad messenger 2018-08-12 10:40:26 +01:00
Luck 40ad489c56 Update build instructions in the README file 2018-08-12 10:27:21 +01:00
Luck 56c55d71fe Improve the way Vault lookups for offline players are handled (#1150)
1) The behaviour of online player lookups is unchanged - this only affects offline player data lookups.
2) If a 'offline player' request is made from an async task, it is executed normally. (the data is loaded)
3) If a 'offline player' request that cannot be immediately fulfilled is made from the main server thread, an exception is thrown.

The exception thrown as a result of 3) can be disabled in the config. In this case, the query is performed anyway. The main server thread will block until the request is complete.
2018-08-11 19:02:57 +01:00
Luck 56df15caf8 Add bukkit-legacy build back to the main project 2018-08-11 18:11:30 +01:00
Luck 03720665b3 Move to gradle 2018-08-10 20:39:29 +01:00
Luck 445429b510 Update text & asm dependencies (fixes #1142)
Updates for:
https://github.com/KyoriPowered/text/commit/6a7fda4e80c48884ba957ffaadd9219cead7962d
2018-08-10 00:09:34 +01:00
Luck c698587d53 Update text dependency 2018-08-09 22:43:41 +01:00
Luck b8466beee5 Completely rework event system
* Event instances are now generated dynamically at runtime. The performance hit of creating proxies at runtime is negligible in this case.

* A better EventBus implementation is now being used internally, API contracts are unaffected.
2018-08-09 22:39:33 +01:00
Luck efa666445f Initial support for Brigadier (1.13 commands) on Bukkit servers 2018-08-08 23:42:25 +01:00
Luck 59c7d77525 Load a up-to-date copy of group data before applying web editor changes 2018-08-08 09:00:35 +01:00
Luck 553da9baf6 Give some form of feedback when trying to applyedits no changes instead of no feedback at all (#1136) 2018-08-08 08:58:58 +01:00
Luck 486ddb3d42 Don't include any database properties by default (#1134) 2018-08-05 21:59:48 +01:00
Luck 381922fc02 Don't schedule a delayed load task on startup (#1130) 2018-08-05 21:51:53 +01:00
Luck 4c891f0819 Fix uppercase inconsistencies when saving users to SQL storage types (#1119)
This was causing issues when user data was saved, without UUID data being saved beforehand.

This commit fixes the way the inconsistency was introduced, and ensures that inconsistent data is made consistent in the future. (when players next login)
2018-07-30 11:22:50 -07:00
Luck 4b3d11ccab More SQL escaping (#1091 & #1126)
Follows from c16630c32b
2018-07-29 17:14:48 -07:00
Luck b1ab465991 Misc cleanup 2018-07-29 17:12:05 -07:00
Luck 952e41ad3d A few API javadoc improvements 2018-07-27 23:45:16 -07:00
Luck ae3adf23c8 Fail silently when plugins use reflection to add to dummy permissibles (#1117) 2018-07-24 21:21:05 -07:00
Luck c3cdf387c2 Fix NPE in GroupManager migration (#1118) 2018-07-24 21:03:14 -07:00
Luck 054f0c2c19 Don't add spaces when formatting 'concise' durations 2018-07-24 20:59:49 -07:00
Luck 2f7fce2109 Change name of Sql messenger table for compat with changes in the previous commit 2018-07-15 22:49:09 -07:00
Luck 07469599bc Rewrite MessagingService message encoding, conform to new plugin message channel requirements
* This change isn't backwards compatible with previous builds, this version (& onwards) won't be able to "communicate" with old versions, and vice versa.

* MC 1.13 requires plugin message channel names to be namespaced, so 'lpuc' has been changed to 'luckperms:update'

* The channel names for Redis/Lily types have also changed, I've been wanting to change the encoded format to something a bit saner for a while, and this seemed like a good time. Changing the channel names a) keeps things consistent and b) means I don't have to worry about old versions interpreting the new format.
2018-07-15 22:42:37 -07:00
Luck 08869da96e misc cleanup 2018-07-13 17:51:30 -07:00
Luck 7540a6eb70 Send more appropriate message when no users/groups match the editor type (#1096) 2018-07-13 17:51:21 -07:00
Luck fa2d9357b8 Allow FileWatcher locations to be registered after initial start 2018-07-12 17:10:07 -07:00
Luck 247a40b65f Fix /lp search for groups when using separated file storage (#1094) 2018-07-12 16:35:32 -07:00
Luck 01ffe6ad5a Use synchronized wrapper for NodeMap backings 2018-07-12 09:50:10 -07:00
Luck da3c2a073a cleanup build scripts a bit 2018-07-11 13:09:54 -07:00
Luck c16630c32b Escape groups keyword in SQL queries to (hopefully) fix compat with newer versions of MySQL (#1091) 2018-07-11 13:09:20 -07:00
Luck bf64f465a8 Re-implement Bukkit 1.7.10 support 2018-07-01 15:31:28 +01:00
Luck c1e0b874d8 Add helpful message for users on first startup 2018-07-01 15:07:25 +01:00
Luck c780266139 Add setprefix, setsuffix, settempprefix, settempsuffix commands (#840) 2018-06-27 17:31:30 +01:00
Luck 08454d58d0 Refactor the way contexts are cached on all platforms (#1071)
Should fix memory leak issues on BungeeCord
2018-06-27 00:17:53 +01:00
Luck ee13540d78 Specify explicit global context in generated LP commands when default contexts have been set (#1062) 2018-06-26 14:39:18 +01:00
Luck b4ff54ffc8 Apply Sponge implicit wildcards after Bukkit style .* wildcards 2018-06-24 21:44:12 +01:00
Luck 6f96d9c7d1 Fix NPE on Nukkit load (#1059) 2018-06-19 23:40:13 +01:00
Luck 5b66436519 Ensure the backing of LPSubscriptionValueMaps is a WeakHashMap (#1058) 2018-06-19 23:35:19 +01:00
Luck 379eb00b69 Cleanup various message localisations, limit the size of the PermissionRegistry 2018-06-19 22:27:47 +01:00
Luck 2036127612 Cleanup action log formatting and pagination
This is technically a breaking change to the API, but I'm fairly certain hardly anyone is using these methods (the pagination functionality in the API is pretty useless)

Can always add them back if it becomes an issue
2018-06-18 16:08:18 +01:00
Luck 957a918bd6 Fix loading on BungeeCord (#1054) 2018-06-17 09:49:38 +01:00
Luck 6b305972ac Fix sponge build script 2018-06-16 18:41:53 +01:00
Luck b8c06904ab Make logging messages a bit less obnoxious
* Removed the ascii text from the startup output
* Log messages (but not command output) is now sent through the standard server logger, and isn't colored
2018-06-16 16:59:59 +01:00
Luck 6baa472567 Fix context cache invalidation 2018-06-15 19:07:24 +01:00
Luck 9c449def57 Update some dependency versions 2018-06-13 20:29:00 +01:00
Luck e4acc133a9 remove some unnecessary interfaces 2018-06-12 18:18:38 +01:00
Luck 8b181b877b Nukkit stores attachments in a set, not a list (#1046) 2018-06-11 17:07:56 +01:00
Luck 194790110d Fix node comparison for identical nodes except the value 2018-06-07 19:58:55 +01:00
Luck c0cd197bd0 Don't allow players to be added to SubscriptionValueMaps 2018-06-07 17:01:25 +01:00
Luck 30ce269873 Disable hikari leak detection (#1033) 2018-06-05 20:33:23 +01:00
Luck 4d7be13c16 Don't reload Sponge persisted subjects when a save is pending 2018-06-03 20:46:50 +01:00
Luck 8cf0f7da5f Improve buffering code 2018-06-03 19:36:55 +01:00
Luck bcb4e5ca64 cleanup various comparators 2018-05-31 23:41:37 +01:00
Luck 07b003c77a Make the dummy attachment a bit more compatible
still MassiveCore lol
2018-05-31 01:01:29 +01:00
Luck f4e4f727dd More workarounds to support MassiveCore's modification of attachment permissions via reflection 2018-05-31 00:51:33 +01:00
Luck 644c53a074 Add workaround for plugins adding/removing/modifying permission attachments via reflection (#1024)
who knows why they're doing it, it's not even beneficial for performance...
2018-05-30 13:17:41 +01:00
Luck c66622bd09 Fix regex permissions not really working properly (#1021) 2018-05-29 14:45:21 +01:00
Luck adf0589184 Print a more informative error when the port is missing from the address arg (#1022) 2018-05-29 12:40:39 +01:00
Luck b7de0e6901 Provide an even more detailed warning message when other uuids are present for a username
We can use the data we have about the UUID and the platform LP is running on to infer more information about what the problem (potentially) is.
2018-05-25 17:05:26 +01:00
Luck a90e59ec97 Fix cache invalidation when group data changes (#1010) 2018-05-21 18:48:47 +01:00
Luck f4882c1c14 Cache the creation of Sponge proxy subject classes (#1005) 2018-05-17 18:19:45 +01:00
Luck ed3b5a3cf1 Lazily load contexts cache for Sponge subjects (#1005) 2018-05-17 18:12:20 +01:00
Luck 45e2b7b12f Fix saving node attributes on non-YAML file storage types (#999) 2018-05-16 19:30:05 +01:00
Luck 1e73986c60 Allow world rewrite options to apply in (some) Vault lookups (#990) 2018-05-16 19:04:09 +01:00
Luck 20f992110d Refactor meta stack element creation, add 'from_group' & 'not_from_group' elements 2018-05-16 18:46:25 +01:00
Luck 18f09f9862 Various performance optimizations 2018-05-15 00:08:23 +01:00
Luck a0be1c7c48 Fix issue with Bukkit attachment permissions never being removed (#991) 2018-05-13 14:06:23 +01:00
DoNotSpamPls 5d34661a15 Readme fixes (#993) 2018-05-12 16:40:54 +01:00
Luck 1639879106 Reduce the number of config lookups required when calculating contexts 2018-05-12 01:51:38 +01:00
Luck a927ca659f Reduce the throughput on the contexts cache in ContextManager (#929) 2018-05-12 01:34:34 +01:00
Luck 804c884d8b Update configurate to fix issues with legacy guava compat 2018-05-06 19:57:50 +01:00
Luck 51f215b8ac Add PlayerDataSaveEvent 2018-05-06 18:21:14 +01:00
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
1169 changed files with 93549 additions and 57168 deletions

No files matched your search

+2
View File
@@ -0,0 +1,2 @@
github: lucko
patreon: luckdev
+63
View File
@@ -0,0 +1,63 @@
name: 🐛 ​ Bug report
description: Report an issue or problem with the way LuckPerms is functioning.
labels: ["type: issue"]
body:
- type: markdown
attributes:
value: "Before going any further, please check to see if your problem is fixed by updating to a newer version. The latest development builds can be obtained from https://luckperms.net/download"
- type: textarea
id: description
attributes:
label: Description
description: Please provide a short description of the issue in the space below.
placeholder: Description goes here!
validations:
required: true
- type: textarea
id: reproduction-steps
attributes:
label: Reproduction Steps
description: Please provide a clear list of steps we should follow in order to reproduce your issue in the space below.
placeholder: List reproduction steps here, please!
validations:
required: true
- type: textarea
id: expected-behaviour
attributes:
label: Expected Behaviour
description: Please provide a description of what you expected to happen.
placeholder: Describe what you expected to happen here.
validations:
required: true
- type: input
id: server-info
attributes:
label: Server Details
description: Please provide a description of the server details, including type and specific version number.
placeholder: 'git-Paper-124 (MC: 1.17.1)'
validations:
required: true
- type: input
id: luckperms-version
attributes:
label: LuckPerms Version
description: Please provide the specific, precise version number of LuckPerms you are using to reproduce this bug.
placeholder: v5.3.70
validations:
required: true
- type: textarea
id: logs
attributes:
label: Logs and Configs
description: If you think it would be helpful, please also include a pastebin of any relevant config files or log output. You should use https://gist.github.com/ to upload, then include the link below.
placeholder: https://gist.github.com/HelpfulBugReporter/ThisIsAVeryUsefulLogOutput
validations:
required: false
- type: textarea
id: extra-info
attributes:
label: Extra Details
description: Please include any other relevant details in the space below.
placeholder: I was able to reproduce this only at the end of a rainbow.
validations:
required: false
+5
View File
@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: 💬 ​ Ask a question
url: https://discord.gg/luckperms
about: We use Discord to provide support for the project. If you have a question, need help, or aren't sure if you've found a bug or not, please come and talk to us there!
+31
View File
@@ -0,0 +1,31 @@
name: 💡 ​ Suggestion
description: Suggest an idea for an improvement or change to LuckPerms.
labels: ["type: suggestion"]
body:
- type: markdown
attributes:
value: "Before going any further, please check to see if your suggestion has already been added by checking the [wiki](https://luckperms.net/wiki/Home). The latest development builds can be obtained from https://luckperms.net/download"
- type: textarea
id: description
attributes:
label: Description
description: Please provide a short description of your suggestion in the space below.
placeholder: Hello, perhaps you should...
validations:
required: true
- type: textarea
id: proposed-behaviour
attributes:
label: Proposed Behaviour
description: Please provide a short explanation of how the feature should work / be changed, and how this will affect the project.
placeholder: It would...
validations:
required: true
- type: textarea
id: extra-info
attributes:
label: Extra Details
description: Please include any other relevant details in the space below.
placeholder: I think this should only function at the end of a rainbow.
validations:
required: false
+23 -110
View File
@@ -1,40 +1,14 @@
# Created by https://www.gitignore.io/
### Intellij ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff:
.idea/
*.iws
/out/
### Gradle & IntelliJ ###
.gradle/
/.idea/
build/
out/
run/
*.iml
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
### Maven ###
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
### Eclipse ###
.metadata
bin/
tmp/
@@ -46,73 +20,29 @@ local.properties
.settings/
.loadpath
.recommenders
# Eclipse Core
.project
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# PyDev specific (Python IDE for Eclipse)
*.pydevproject
# CDT-specific (C/C++ Development Tooling)
.cproject
# JDT-specific (Eclipse Java Development Tools)
.classpath
# Java annotation processor (APT)
.factorypath
# PDT-specific (PHP Development Tools)
.buildpath
# sbteclipse plugin
.target
# Tern plugin
.tern-project
# TeXlipse plugin
.texlipse
# STS (Spring Tool Suite)
.springBeans
# Code Recommenders
.recommenders/
.apt_generated/
.project
.classpath
### Linux ###
*~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
### macOS ###
*.DS_Store
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
@@ -120,7 +50,6 @@ Icon
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
@@ -128,37 +57,21 @@ Temporary Items
.apdisk
### NetBeans ###
nbproject/private/
build/
nbbuild/
dist/
nbdist/
.nb-gradle/
### Windows ###
# Windows image file caches
# Windows thumbnail cache files
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
ehthumbs_vista.db
*.stackdump
[Dd]esktop.ini
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# Windows shortcuts
*.lnk
### Java ###
*.class
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.ear
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
-726
View File
@@ -1,726 +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}"
verbose-log: "&3VERBOSE &3&l> {0}"
export-log: "&3EXPORT &3&l> &f{0}"
export-log-progress: "&3EXPORT &3&l> &7{0}"
migration-log: "&3MIGRATION &7[&3{0}&7] &3&l> &f{1}"
migration-log-progress: "&3MIGRATION &7[&3{0}&7] &3&l> &7{1}"
command-not-recognised: "Command not recognised."
command-no-permission: "You do not have permission to use this command!"
already-haspermission: "{0} already has this permission!"
does-not-havepermission: "{0} does not have this permission set."
already-has-temp-permission: "{0} already has this permission set temporarily!"
does-not-have-temp-permission: "{0} does not have this permission set temporarily."
user-not-found: "&bUser could not be found."
user-not-online: "&bUser &a{0}&b is not online."
user-save-error: "There was an error whilst saving the user."
group-not-found: "&bGroup could not be found."
group-save-error: "There was an error whilst saving the group."
track-not-found: "&bTrack could not be found."
track-save-error: "There was an error whilst saving the track."
user-invalid-entry: "&d{0}&c is not a valid username/uuid."
group-invalid-entry: "Group names can only contain alphanumeric characters."
track-invalid-entry: "Track names can only contain alphanumeric characters."
server-world-invalid-entry: "Server/world names can only contain alphanumeric characters and cannot exceed 36 characters in length."
use-inherit-command: "Use the 'parent add' and 'parent remove' commands instead of specifying the node."
verbose-invalid-filter: "&cInvalid verbose filter: &f{0}"
verbose-on: "&bVerbose checking output set to &aTRUE &bfor all permissions."
verbose-on-query: "&bVerbose checking output set to &aTRUE &bfor permissions matching filter: &f{0}"
verbose-off: "&bVerbose checking output set to &cFALSE&b."
verbose-recording-on: "&bVerbose recording set to &aTRUE &bfor all permissions."
verbose-recording-on-query: "&bVerbose recording set to &aTRUE &bfor permissions matching filter: &f{0}"
verbose-recording-upload-start: "&bVerbose recording was disabled. Uploading results..."
verbose-recording-url: "&aVerbose results URL:"
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-searching-members: "&aSearching for users and groups who inherit from &b{0}&a..."
search-result: "&aFound &b{0}&a entries from &b{1}&a users and &b{2}&a groups."
search-showing-users: "&bShowing user entries:"
search-showing-groups: "&bShowing group entries:"
search-showing-users-with-page: "&bShowing user entries: {0}"
search-showing-groups-with-page: "&bShowing group entries: {0}"
apply-edits-invalid-code: "&aInvalid code. &7({0})"
apply-edits-unable-to-read: "&aUnable to read data using the given code. &7({0})"
apply-edits-no-target: "&aUnable to parse the target of the edit. Please supply it as an extra argument."
apply-edits-target-group-not-exists: "&aTarget group &b{0}&a does not exist."
apply-edits-target-user-not-uuid: "&aTarget user &b{0}&a is not a valid uuid."
apply-edits-target-user-unable-to-load: "&aUnable to load target user &b{0}&a."
apply-edits-target-unknown: "&aInvalid target. &7({0})"
apply-edits-success: "&aSuccessfully applied &b{0}&a nodes to &b{1}&a."
editor-upload-failure: "&cUnable to upload permission data to the editor."
editor-url: "&aEditor URL:"
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-top: >
{PREFIX}&2Running &bLuckPerms v{0}&2 by &bLuck&2.\n
{PREFIX}&f- &3Platform: &f{1}\n
{PREFIX}&f- &3Server Brand: &f{2}\n
{PREFIX}&f- &3Server Version: &f{3}
info-middle: >
{PREFIX}&f- &bMessaging Type: &f{0}\n
{PREFIX}&f- &bInstance:\n
{PREFIX}&f- &3Server Name: &f{1}\n
{PREFIX}&f- &3Online Players: &a{2}\n
{PREFIX}&f- &3Unique Connections: &a{3}\n
{PREFIX}&f- &3Uptime: &7{4}\n
{PREFIX}&f- &3Local Data: &a{5} &7users, &a{6} &7groups, &a{7} &7tracks\n
{PREFIX}&f- &3Context Calculators: &a{8}\n
{PREFIX}&f- &3Known permissions: &a{9}\n
{PREFIX}&f- &3Active processors: &7{10}
create-group-error: "There was an error whilst creating the group."
delete-group-error: "There was an error whilst deleting the group."
delete-group-error-default: "You cannot delete the default group."
groups-list: "&aGroups: &7(name, weight, tracks)"
groups-list-entry: "&f- &3{0} &7- &b{1}"
groups-list-entry-with-tracks: "&f- &3{0} &7- &b{1} &7- [&3{2}&7]"
create-track-error: "There was an error whilst creating the track."
delete-track-error: "There was an error whilst deleting the track."
tracks-list: "&aTracks: {0}"
listnodes: "&b{0}'s Nodes:"
listnodes-with-page: "&b{0}'s Nodes: {1}"
listnodes-temp: "&b{0}'s Temporary Nodes:"
listnodes-temp-with-page: "&b{0}'s Temporary Nodes: {1}"
listparents: "&b{0}'s Parent Groups:"
listparents-temp: "&b{0}'s Temporary Parent Groups:"
list-tracks: >
&b{0}'s Tracks:\n
{1}
list-tracks-empty: "{0} is not on any tracks."
context-pair-inline: "&3{0}=&b{1}"
context-pair--global-inline: "&eglobal"
context-pair-sep: "&a, "
context-pair: "&8(&7{0}=&f{1}&8)"
check-permission: "&b{0}&a has permission &b{1}&a set to {2}&a in context {3}&a."
check-inherits-permission: "&b{0}&a has permission &b{1}&a set to {2}&a in context {3}&a. &7(inherited from &a{4}&7)"
setpermission-success: "&aSet &b{0}&a to &b{1}&a for &b{2}&a in context {3}&a."
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."
set-track-parent-success: "&b{0}&a had their existing parent groups on track &b{1}&a cleared, and now only inherits &b{2}&a in context {3}&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 in context {1}&a. (&b{2}&a nodes were removed.)"
clear-success-singular: "&b{0}&a's permissions were cleared in context {1}&a. (&b{2}&a node was removed.)"
parent-clear-success: "&b{0}&a's parents were cleared in context {1}&a. (&b{2}&a nodes were removed.)"
parent-clear-success-singular: "&b{0}&a's parents were cleared in context {1}&a. (&b{2}&a node was removed.)"
parent-clear-track-success: "&b{0}&a's parents on track &b{1}&a were cleared in context {2}&a. (&b{3}&a nodes were removed.)"
parent-clear-track-success-singular: "&b{0}&a's parents on track &b{1}&a were cleared in context {2}&a. (&b{3}&a node was removed.)"
meta-clear-success: "&b{0}&a's meta matching type &b{1}&a was cleared in context {2}&a. (&b{3}&a nodes were removed.)"
meta-clear-success-singular: "&b{0}&a's meta matching type &b{1}&a was cleared in context {2}&a. (&b{3}&a node was removed.)"
illegal-date-error: "Could not parse date '{0}'."
past-date-error: "You cannot set a date in the past!"
chat-meta-prefix-header: "&b{0}'s Prefixes"
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{2}&a removed in context {3}&a."
remove-temp-chatmeta-success: "&b{0}&a had temporary {1} &f\"{2}&f\"&a at priority &b{3}&a removed in context {4}&a."
bulk-remove-temp-chatmeta-success: "&b{0}&a had all temporary {1}es at priority &b{2}&a removed in context {3}&a."
already-has-meta: "{0} already has that meta key value pair set."
set-meta-success: "&aSet meta value for key &f\"{0}&f\"&a to &f\"{1}&f\"&a for &b{2}&a in context {3}&a."
set-meta-temp-success: "&aSet meta value for key &f\"{0}&f\"&a to &f\"{1}&f\"&a for &b{2}&a for a duration of &b{3}&a in context {4}&a."
unset-meta-success: "&aUnset meta value with key &f\"{0}&f\"&a for &b{1}&a in context {2}&a."
unset-meta-temp-success: "&aUnset temporary meta value with key &f\"{0}&f\"&a for &b{1}&a in context {2}&a."
bulk-update-invalid-data-type: "Invalid type. Was expecting 'all', 'users' or 'groups'."
bulk-update-invalid-constraint: "Invalid constraint &4{0}&c. Constraints should be in the format '&f<field> <comparison operator> <value>&c'."
bulk-update-invalid-comparison: "Invalid comparison operator '&4{0}&c'. Expected one of the following: &f== != ~~ ~!"
bulk-update-queued: "&aBulk update operation was queued. &7(&f{0}&7)"
bulk-update-confirm: "&aRun &b/{0} bulkupdate confirm {1} &ato execute the update."
bulk-update-unknown-id: "&aOperation with id &b{0}&a does not exist or has expired."
bulk-update-starting: "&aRunning bulk update."
bulk-update-success: "&bBulk update completed successfully."
bulk-update-failure: "&cBulk update failed. Check the console for errors."
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- &3Has contextual data: {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-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 in context {2}&a."
user-promote-success: "&aPromoting user along track &b{0}&a from &b{1}&a to &b{2}&a in context {3}&a."
user-promote-error-endoftrack: "The end of track &4{0}&c was reached. Unable to promote user."
user-promote-error-malformed: >
{PREFIX}The next group on the track, {0}, no longer exists. Unable to promote user.\n
{PREFIX}Either create the group, or remove it from the track and try again.
user-demote-success: "&aDemoting user along track &b{0}&a from &b{1}&a to &b{2}&a in context {3}&a."
user-demote-endoftrack: "The end of track &4{0}&c was reached, so &4{1}&c was removed from &4{2}&c."
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.
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-console: "&cCannot toggle notifications for console."
log-notify-toggle-on: "&aEnabled&b logging output."
log-notify-toggle-off: "&cDisabled&b logging output."
log-notify-already-on: "You are already receiving notifications."
log-notify-already-off: "You aren't currently receiving notifications."
log-notify-unknown: "State unknown. Expecting \"on\" or \"off\"."
log-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<------------------------------------------>"
command-specs:
user:
description: "User commands"
usage: "/%s user <user>"
group:
description: "Group commands"
usage: "/%s group <group>"
track:
description: "Track commands"
usage: "/%s track <track>"
log:
description: "Log commands"
usage: "/%s log"
sync:
description: "Sync changes with the storage"
usage: "/%s sync"
info:
description: "Print general plugin info"
usage: "/%s info"
verbose:
description: "Manage verbose permission checking"
usage: "/%s verbose <true|false> [filter]"
args:
"on|record|off|paste": "whether to enable/disable logging, or to paste the logged output"
"filter": "the filter to match entries against"
tree:
description: "Generate a tree view of permissions"
usage: "/%s tree [selection] [max level] [player]"
args:
"selection": "the root of the tree. specify \".\" to include all permissions"
"max level": "how many branch levels should be returned"
"player": "the name of an online player to check against"
search:
description: "Search for users/groups with a specific permission"
usage: "/%s search <permission>"
args:
"permission": "the permission to search for"
"page": "the page to view"
check:
description: "Perform a standard permission check on an online player"
usage: "/%s check <user> <permission>"
args:
"user": "the user to check"
"permission": "the permission to check for"
network-sync:
description: "Sync changes with the storage and request that all other servers on the network do the same"
usage: "/%s networksync"
import:
description: "Import data from a file"
usage: "/%s import <file>"
args:
"file": "the file to import from"
export:
description: "Export data to a file"
usage: "/%s export <file>"
args:
"file": "the file to export to"
reload-config:
description: "Reload some of the config options"
usage: "/%s reloadconfig"
bulk-update:
description: "Execute bulk change queries on all data"
usage: "/%s bulkupdate"
args:
"data type": "the type of data being changed. ('all', 'users' or 'groups')"
"action": "the action to perform on the data. ('update' or 'delete')"
"action field": "the field to act upon. only required for 'update'. ('permission', 'server' or 'world')"
"action value": "the value to replace with. only required for 'update'."
"constraint...": "the constraints required for the update"
migration:
description: "Migration commands"
usage: "/%s migration"
apply-edits:
description: "Applies permission changes made from the web editor"
usage: "/%s applyedits <code> [target]"
args:
"code": "the unique code for the data"
"target": "who to apply the data to"
create-group:
description: "Create a new group"
usage: "/%s creategroup <group>"
args:
"name": "the name of the group"
delete-group:
description: "Delete a group"
usage: "/%s deletegroup <group>"
args:
"name": "the name of the group"
list-groups:
description: "List all groups on the platform"
usage: "/%s listgroups"
create-track:
description: "Create a new track"
usage: "/%s createtrack <track>"
args:
"name": "the name of the track"
delete-track:
description: "Delete a track"
usage: "/%s deletetrack <track>"
args:
"name": "the name of the track"
list-tracks:
description: "List all tracks on the platform"
usage: "/%s listtracks"
user-info:
description: "Shows info about the user"
user-switchprimarygroup:
description: "Switches the user's primary group"
args:
"group": "the group to switch to"
user-promote:
description: "Promotes the user up a track"
args:
"track": "the track to promote the user up"
"context...": "the contexts to promote the user in"
user-demote:
description: "Demotes the user down a track"
args:
"track": "the track to demote the user down"
"context...": "the contexts to demote the user in"
group-info:
description: "Gives info about the group"
group-listmembers:
description: "Show the users/groups who inherit from this group"
args:
"page": "the page to view"
group-setweight:
description: "Set the groups weight"
args:
"weight": "the weight to set"
group-rename:
description: "Rename the group"
args:
"name": "the new name"
group-clone:
description: "Clone the group"
args:
"name": "the name of the group to clone onto"
holder-editor:
description: "Opens the web permission editor"
holder-showtracks:
description: "Lists the tracks that the object is on"
holder-clear:
description: "Removes all permissions, parents and meta"
args:
"context...": "the contexts to filter by"
permission:
description: "Edit permissions"
parent:
description: "Edit inheritances"
meta:
description: "Edit metadata values"
permission-info:
description: "Lists the permission nodes the object has"
args:
"page": "the page to view"
"filter": "the string to filter by"
permission-set:
description: "Sets a permission for the object"
args:
"node": "the permission node to set"
"true|false": "the value of the node"
"context...": "the contexts to add the permission in"
permission-unset:
description: "Unsets a permission for the object"
args:
"node": "the permission node to unset"
"context...": "the contexts to remove the permission in"
permission-settemp:
description: "Sets a permission for the object temporarily"
args:
"node": "the permission node to set"
"true|false": "the value of the node"
"duration": "the duration until the permission node expires"
"context...": "the contexts to add the permission in"
permission-unsettemp:
description: "Unsets a temporary permission for the object"
args:
"node": "the permission node to unset"
"context...": "the contexts to remove the permission in"
permission-check:
description: "Checks to see if the object has a certain permission node"
args:
"node": "the permission node to check for"
"context...": "the contexts to check in"
permission-check-inherits:
description: "Checks to see if the object inherits a certain permission node"
args:
"node": "the permission node to check for"
"context...": "the contexts to check in"
parent-info:
description: "Lists the groups that this object inherits from"
parent-set:
description: "Removes all other groups the object inherits already and adds them to the one given"
args:
"group": "the group to set to"
"context...": "the contexts to set the group in"
parent-add:
description: "Sets another group for the object to inherit permissions from"
args:
"group": "the group to inherit from"
"context...": "the contexts to inherit the group in"
parent-remove:
description: "Removes a previously set inheritance rule"
args:
"group": "the group to remove"
"context...": "the contexts to remove the group in"
parent-set-track:
description: "Removes all other groups the object inherits from already on the given track and adds them to the one given"
args:
"track": "the track to set on"
"group": "the group to set to, or a number relating to the position of the group on the given track"
"context...": "the contexts to set the group in"
parent-add-temp:
description: "Sets another group for the object to inherit permissions from temporarily"
args:
"group": "the group to inherit from"
"duration": "the duration of the group membership"
"context...": "the contexts to inherit the group in"
parent-remove-temp:
description: "Removes a previously set temporary inheritance rule"
args:
"group": "the group to remove"
"context...": "the contexts to remove the group in"
parent-clear:
description: "Clears all parents"
args:
"context...": "the contexts to filter by"
parent-clear-track:
description: "Clears all parents on a given track"
args:
"track": "the track to remove on"
"context...": "the contexts to filter by"
meta-info:
description: "Shows all chat meta"
meta-set:
description: "Sets a meta value"
args:
"key": "the key to set"
"value": "the value to set"
"context...": "the contexts to add the meta pair in"
meta-unset:
description: "Unsets a meta value"
args:
"key": "the key to unset"
"context...": "the contexts to remove the meta pair in"
meta-settemp:
description: "Sets a meta value temporarily"
args:
"key": "the key to set"
"value": "the value to set"
"duration": "the duration until the meta value expires"
"context...": "the contexts to add the meta pair in"
meta-unsettemp:
description: "Unsets a temporary meta value"
args:
"key": "the key to unset"
"context...": "the contexts to remove the meta pair in"
meta-addprefix:
description: "Adds a prefix"
args:
"priority": "the priority to add the prefix at"
"prefix": "the prefix string"
"context...": "the contexts to add the prefix in"
meta-addsuffix:
description: "Adds a suffix"
args:
"priority": "the priority to add the suffix at"
"suffix": "the suffix string"
"context...": "the contexts to add the suffix in"
meta-removeprefix:
description: "Removes a prefix"
args:
"priority": "the priority to remove the prefix at"
"prefix": "the prefix string"
"context...": "the contexts to remove the prefix in"
meta-removesuffix:
description: "Removes a suffix"
args:
"priority": "the priority to remove the suffix at"
"suffix": "the suffix string"
"context...": "the contexts to remove the suffix in"
meta-addtemp-prefix:
description: "Adds a prefix temporarily"
args:
"priority": "the priority to add the prefix at"
"prefix": "the prefix string"
"duration": "the duration until the prefix expires"
"context...": "the contexts to add the prefix in"
meta-addtemp-suffix:
description: "Adds a suffix temporarily"
args:
"priority": "the priority to add the suffix at"
"suffix": "the suffix string"
"duration": "the duration until the suffix expires"
"context...": "the contexts to add the suffix in"
meta-removetemp-prefix:
description: "Removes a temporary prefix"
args:
"priority": "the priority to remove the prefix at"
"prefix": "the prefix string"
"context...": "the contexts to remove the prefix in"
meta-removetemp-suffix:
description: "Removes a temporary suffix"
args:
"priority": "the priority to remove the suffix at"
"suffix": "the suffix string"
"context...": "the contexts to remove the suffix in"
meta-clear:
description: "Clears all meta"
args:
"type": "the type of meta to remove"
"context...": "the contexts to filter by"
track-info:
description: "Gives info about the track"
track-append:
description: "Appends a group onto the end of the track"
args:
"group": "the group to append"
track-insert:
description: "Inserts a group at a given position along the track"
args:
"group": "the group to insert"
"position": "the position to insert the group at (the first position on the track is 1)"
track-remove:
description: "Removes a group from the track"
args:
"group": "the group to remove"
track-clear:
description: "Clears the groups on the track"
track-rename:
description: "Rename the track"
args:
"name": "the new name"
track-clone:
description: "Clone the track"
args:
"name": "the name of the track to clone onto"
log-recent:
description: "View recent actions"
args:
"user": "the name/uuid of the user to filter by"
"page": "the page number to view"
log-search:
description: "Search the log for an entry"
args:
"query": "the query to search by"
"page": "the page number to view"
log-notify:
description: "Toggle log notifications"
args:
"on|off": "whether to toggle on or off"
log-user-history:
description: "View a user's history"
args:
"user": "the name/uuid of the user"
"page": "the page number to view"
log-group-history:
description: "View an group's history"
args:
"group": "the name of the group"
"page": "the page number to view"
log-track-history:
description: "View a track's history"
args:
"track": "the name of the track"
"page": "the page number to view"
sponge:
description: "Edit extra Sponge data"
usage: "/%s sponge <collection> <subject>"
args:
"collection": "the collection to query"
"subject": "the subject to modify"
sponge-permission-info:
description: "Shows info about the subject's permissions"
args:
"contexts...": "the contexts to filter by"
sponge-permission-set:
description: "Sets a permission for the Subject"
args:
"node": "the permission node to set"
"tristate": "the value to set the permission to"
"contexts...": "the contexts to set the permission in"
sponge-permission-clear:
description: "Clears the Subjects permissions"
args:
"contexts...": "the contexts to clear permissions in"
sponge-parent-info:
description: "Shows info about the subject's parents"
args:
"contexts...": "the contexts to filter by"
sponge-parent-add:
description: "Adds a parent to the Subject"
args:
"collection": "the subject collection where the parent Subject is"
"subject": "the name of the parent Subject"
"contexts...": "the contexts to add the parent in"
sponge-parent-remove:
description: "Removes a parent from the Subject"
args:
"collection": "the subject collection where the parent Subject is"
"subject": "the name of the parent Subject"
"contexts...": "the contexts to remove the parent in"
sponge-parent-clear:
description: "Clears the Subjects parents"
args:
"contexts...": "the contexts to clear parents in"
sponge-option-info:
description: "Shows info about the subject's options"
args:
"contexts...": "the contexts to filter by"
sponge-option-set:
description: "Sets an option for the Subject"
args:
"key": "the key to set"
"value": "the value to set the key to"
"contexts...": "the contexts to set the option in"
sponge-option-unset:
description: "Unsets an option for the Subject"
args:
"key": "the key to unset"
"contexts...": "the contexts to unset the key in"
sponge-option-clear:
description: "Clears the Subjects options"
args:
"contexts...": "the contexts to clear options in"
migration-command:
description: "Migration command"
migration-groupmanager:
description: "Migration command"
args:
"migrate as global": "if world permissions should be ignored, and just migrated as global"
migration-powerfulperms:
description: "Migration command"
args:
"address": "the address of the PP database"
"database": "the name of the PP database"
"username": "the username to log into the DB"
"password": "the password to log into the DB"
"db table": "the name of the PP table where player data is stored"
-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<------------------------------------------>"
-290
View File
@@ -1,290 +0,0 @@
# LuckPerms Language File
# Locale: pl_PL (Polish)
# Author: dzegarek
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[UWAGA] {0}"
log-error: "&7&l[&bLuck&3Perms&7&l] &4[BŁĄD] {0}"
empty: "{0}"
player-online: "&aOnline"
player-offline: "&cOffline"
loading-error: "Nie można załadować danych uprawnień. Spróbuj ponownie później."
op-disabled: "&bSystem vanilla OP jest wyłączony na tym serwerze."
op-disabled-sponge: "&2Stan operatora serwera nie ma wpływu na instalację wtyczki uprawnień. Proszę bezpośrednio edytować dane użytkownika."
log: "&3LOG &3&l> {0}"
export-log: "&3Eksport &3&l> &f{0}"
export-log-progress: "&3Eksport &3&l> &7{0}"
migration-log: "&3MIGRACJA &7[&3{0}&7] &3&l> &f{1}"
migration-log-progress: "&3MIGRACJA &7[&3{0}&7] &3&l> &7{1}"
command-not-recognised: "Komenda nie została rozpoznana."
command-no-permission: "Nie masz uprawnień do korzystania z tego polecenia!"
already-haspermission: "{0} ma już to uprawnienie!"
does-not-havepermission: "{0} nie ma tego zestawu uprawnień."
already-has-temp-permission: "{0} ma już tymczasowo uprawnienie!"
does-not-have-temp-permission: "{0} nie ma tymczasowego zezwolenia."
user-not-found: "&bNie można znaleźć użytkownika."
user-not-online: "&bUżytkownik &a{0}&b nie jest online."
user-save-success: "&7(Dane użytkownika zostały zapisane w pamięci)"
user-save-error: "Podczas zapisywania użytkownika wystąpił błąd."
group-not-found: "&bNie można odnaleźć grupy."
group-save-success: "&7(Dane grupy zostały zapisane w pamięci)"
group-save-error: "Podczas zapisywania grupy wystąpił błąd."
track-not-found: "&bŚcieżka nie została odnaleziona."
track-save-success: "&7(Dane ścieżki zostały zapisane w pamięci)"
track-save-error: "Podczas zapisywania ścieżki wystąpił błąd."
user-invalid-entry: "&d{0}&c nie jest poprawną nazwą użytkownika/uuid."
group-invalid-entry: "Nazwy grup mogą zawierać tylko znaki alfanumeryczne."
track-invalid-entry: "Nazwy dróg mogą zawierać tylko znaki alfanumeryczne."
server-world-invalid-entry: "Nazwy serwerów/świata mogą zawierać znaki alfanumeryczne, ale nie mogą przekraczać 36 znaków."
use-inherit-command: "Użyj komendy 'parent add' lub 'parent remove' zamiast określenia węzła."
verbose-invalid-filter: "&cNieprawidłowy szczegółowy filtr: &f{0}"
verbose-on: "&bZapis szczegółowych plików wyjściowych ustawiony jest na & aTRUE & bdla wszystkich uprawnień."
verbose-on-query: "&bZapis szczegółowych plików wyjściowych ustawiony jest na & aTRUE & bdla wszystkich pasujących do filtra: &f{0}"
verbose-off: "&bZapis szczegółowych plików wyjściowych jest ustawiony na &cFALSE&b."
verbose-recording-on: "&bVerbose recording set to &aTRUE &bfor all permissions."
verbose-recording-on-query: "&bZapis szczegółowych zapisów jest ustawiony na &aTRUE &bdla wszystkich uprawnień pasujących do filtra: &f{0}"
verbose-recording-upload-start: "&Zapis szczegółowych zapisów został wyłączony. Przesyłanie wyników..."
verbose-recording-url: "&aSzczegółowe URL wyników:"
tree-upload-start: "&bGenerowanie drzewa uprawnień..."
tree-empty: "&aNie można wygenerować drzewa. Nie znaleziono żadnych wyników."
tree-url: "&aURL drzewa uprawnień:"
search-searching: "&aPoszukiwanie użytkowników i grup &b{0}&a..."
search-searching-members: "&aWyszukiwanie użytkowników i grup, które dziedziczą &b{0}&a..."
search-result: "&aZnaleziono &b{0}&a wpisy z &b{1}&a użytkowników i &b{2}&a grup."
search-showing-users: "&bWyświetlanie wpisów użytkownika:"
search-showing-groups: "&bWyświetlanie wpisów grup:"
search-showing-users-with-page: "&bWyświetlanie wpisów użytkownika: {0}"
search-showing-groups-with-page: "&bWyświetlanie wpisów grup: {0}"
check-result: "&aWynik sprawdzenia uprawnień dla użytkownika &b{0}&a dla uprawnień &b{1}&a: &f{2}"
create-success: "&b{0}&a został pomyślnie utworzone."
delete-success: "&b{0}&a został pomyślnie usunięty."
rename-success: "&b{0}&a został pomyślnie zmieniony na &b{1}&a."
clone-success: "&b{0}&a został pomyślnie sklonowany na &b{1}&a."
already-inherits: "{0} już dziedziczy '{1}'."
does-not-inherit: "{0} nie dziedziczy '{1}'."
already-temp-inherits: "{0} już tymczasowo dziedziczy '{1}'."
does-not-temp-inherit: "{0} nie dziedziczy tymczasowo '{1}'."
track-already-contains: "Ścieżka {0} zawiera już grupę '{1}'."
track-does-not-contain: "Ścieżka {0} nie zawiera tej grupy '{1}'."
track-ambiguous-call: "Podany użytkownik jest członkiem wielu grup na tej ścieżce. Nie można określić ich lokalizacji."
group-already-exists: "Ta grupa już istnieje!"
group-does-not-exist: "Ta grupa nie istnieje!"
group-load-error: "Wystąpił nieoczekiwany błąd. Grupa nie została załadowana."
groups-load-error: "Wystąpił nieoczekiwany błąd. Nie można załadować wszystkich grup."
track-already-exists: "Ta ścieżka już istnieje!"
track-does-not-exist: "Ta ścieżka nie istnieje!"
track-load-error: "Wystąpił nieoczekiwany błąd. Ścieżka nie została załadowana."
tracks-load-error: "Wystąpił nieoczekiwany błąd. Nie można wczytać wszystkich ścieżek."
track-empty: "Ścieżka nie może być używana jako pusta lub zawierać tylko jedną grupę."
update-task-request: "&bZaktualizuj zaplanowane zadanie."
update-task-complete: "&aZaktualizowano zadanie."
update-task-complete-network: "&aZaktualizowano zadanie. Teraz próbuj wejść na inne serwery."
update-task-push-success: "&aInne serwery zostały powiadomione za pośrednictwem & b {0} wiadomości &apomyślnie."
update-task-push-failure: "&cPodczas przesyłania zmian do innych serwerów wystąpił błąd."
update-task-push-failure-not-setup: "&cPodczas przesyłania zmian do innych serwerów wystąpił błąd. Usługa wiadomości nie została skonfigurowana."
reload-config-success: "&aPlik konfiguracyjny został ponownie załadowany. &7(niektóre opcje będą obowiązywać tylko po ponownym uruchomieniu serwera.)"
info: >
{PREFIX}&2Uruchamianie &bLuckPerms v{0}&2 by &bLuck&2.\n
{PREFIX}&f- &3Platforma: &f{1}\n
{PREFIX}&f- &3Metoda Składowania: &f{2}\n
{PREFIX}&f- &3Nazwa Serwera: &f{3}\n
{PREFIX}&f- &3Synchronizacja Czasu: &a{4} &fminuty\n
{PREFIX}&f- &3Usługa wiadomości: &f{5}\n
{PREFIX}&f- &bLiczba:\n
{PREFIX}&f- &3Online Graczy: &a{6}\n
{PREFIX}&f- &3Załadowanych użytkowników: &a{7}\n
{PREFIX}&f- &3Załadowanych grup: &a{8}\n
{PREFIX}&f- &3Załadowanych Ścieżek: &a{9}\n
{PREFIX}&f- &3Rozmiar Loga: &a{10}\n
{PREFIX}&f- &3Rozmiar pamięci podręcznej UUID: &a{11}\n
{PREFIX}&f- &3Załadowane tłumaczenia: &a{12}\n
{PREFIX}&f- &3Kontrole wstępne: &a{13}\n
{PREFIX}&f- &3Kalkulatory Kontekstu: &a{14}\n
{PREFIX}&f- &3Unikalne uprawnienia: &a{15}\n
{PREFIX}&f- &bKonfiguracja:\n
{PREFIX}&f- &3Używany Server UUIDs: {16}\n
{PREFIX}&f- &bObliczanie uprawnień:\n
{PREFIX}&f- &3Łącznie ze światem: {17}\n
{PREFIX}&f- &3Łącznie z globalnym światem: {18}\n
{PREFIX}&f- &3Stosowanie grup globalnych: {19}\n
{PREFIX}&f- &3Stosowanie Globalnych Grup Światowych: {20}\n
{PREFIX}&f- &3Stosowanie symboli wieloznacznych: {21}\n
{PREFIX}&f- &3Stosowanie Regex: {22}\n
{PREFIX}&f- &3Stosowanie skrótu: {23}
create-group-error: "Podczas tworzenia grupy wystąpił błąd."
delete-group-error: "Podczas usuwania grupy wystąpił błąd."
delete-group-error-default: "Nie można usunąć grupy domyślnej."
groups-list: "&aGrupy: {0}"
create-track-error: "Podczas tworzenia ścieżki wystąpił błąd."
delete-track-error: "Podczas usuwania ścieżki wystąpił błąd."
tracks-list: "&aŚcieżki: {0}"
listnodes: "&b{0}'s Węzły:"
listnodes-with-page: "&b{0}'s Węzły: {1}"
listnodes-temp: >
&b{0}'s Tymczasowe Węzły:\n
{1}
listparents: >
&b{0}'s Grupy Rodzicielskie:\n
{1}
listparents-temp: >
&b{0}'s Tymczasowe Grupy Rodzicielskie:\n
{1}
list-tracks: >
&b{0}'s Ścieżki:\n
{1}
list-tracks-empty: "{0} nie jest na żadnej ścieżce."
context-pair-inline: "&3{0}=&b{1}"
context-pair--global-inline: "&eglobalnie"
context-pair-sep: "&a, "
context-pair: "&8(&7{0}=&f{1}&8)"
check-permission: "&b{0}&a ma uprawnienia &b{1}&a ustawione na {2}&a w kontekście {3}&a."
setpermission-success: "&aUstawiono &b{0}&a na &b{1}&a dla &b{2}&a w kontekście {3}&a."
setpermission-temp-success: "&aUstawiono &b{0}&a na &b{1}&a dla &b{2}&a na czas trwania &b{3}&a w kontekście {4}&a."
unsetpermission-success: "&aUsunięto &b{0}&a dla &b{1}&a w kontekście {2}&a."
unset-temp-permission-success: "&aTymczasowe uprawnienia &b{0}&a dla &b{1}&a w kontekście {2}&a."
set-inherit-success: "&b{0}&a teraz dziedziczy uprawnienia od &b{1}&a w kontekście {2}&a."
set-temp-inherit-success: "&b{0}&a teraz dziedziczy uprawnienia &b{1}&a na czas trwania &b{2}&a w kontekście {3}&a."
set-parent-success: "&b{0}&a gdyby istniejące grupy macierzyste zostały wyczyszczone, a teraz tylko dziedziczą &b{1}&a w kontekście {2}&a."
set-track-parent-success: "&b{0}&a miały istniejące grupy macierzyste na ścieżce &b{1}&a wyczyszczone, a teraz dziedziczą &b{2}&a w kontekście {3}&a."
unset-inherit-success: "&b{0}&a już nie dziedziczy uprawnień &b{1}&a w kontekście {2}&a."
unset-temp-inherit-success: "&b{0}&a przestaje tymczasowo dziedziczyć uprawnienia &b{1}&a w kontekście {2}&a."
clear-success: "&b{0}&a's uprawnienia zostały wyczyszczone w kontekście {1}&a. (&b{2}&a węzły zostały usunięte.)"
clear-success-singular: "&b{0}&a's uprawnienia zostały wyczyszczone w kontekście {1}&a. (&b{2}&a węzeł został usunięty.)"
parent-clear-success: "&b{0}&a's rodzice zostali wyczyszczeni w kontekście {1}&a. &b{2}&a węzły zostały usunięte.)"
parent-clear-success-singular: "&b{0}&a's rodzice zostali wyczyszczeni w kontekście {1}&a. &b{2}&a węzeł został usunięty.)"
parent-clear-track-success: "&b{0}&a's rodzice na ścieżce &b{1}&a zostali wyczyszczeni w kontekście {2}&a. &b{3}&a węzły zostały usunięte.)"
parent-clear-track-success-singular: "&b{0}&a's parents on track &b{1}&a were cleared in context {2}&a. &b{3}&a węzeł został usunięty.)"
meta-clear-success: "&b{0}&a's meta zostały usunięte w kontekście {1}&a. &b{2}&a węzły zostały usunięte.)"
meta-clear-success-singular: "&b{0}&a's meta zostały usunięte w kontekście {1}&a. &b{2}&a węzeł został usunięty.)"
illegal-date-error: "Nie można przeanalizować daty '{0}'."
past-date-error: "W przeszłości nie można ustawić daty!"
chat-meta-prefix-header: "&b{0}'s Prefiksy"
chat-meta-suffix-header: "&b{0}'s Suffiksy"
meta-header: "&b{0}'s Meta"
chat-meta-entry: "&b-> {0} &f- &f\"{1}&f\" &8(&7odziedziczone po &a{2}&8)"
chat-meta-entry-with-context: "&b-> {0} &f- &f\"{1}&f\" &8(&7odziedziczone po &a{2}&8){3}"
meta-entry: "&b-> &a{0} &f= &f\"{1}&f\" &8(&7odziedziczone po &a{2}&8)"
meta-entry-with-context: "&b-> &a{0} &f= &f\"{1}&f\" &8(&7odziedziczone po &a{2}&8){3}"
chat-meta-prefix-none: "&b{0} nie ma prefiksów."
chat-meta-suffix-none: "&b{0} has no suffiksów."
meta-none: "&b{0} nie ma meta."
meta-invalid-priority: "Nieprawidłowy priorytet '{0}'. Spodziewany numer."
already-has-chat-meta: "{0} już to ma {1} ustawione."
does-not-have-chat-meta: "{0} nie ma tego {1} ustawionego."
add-chatmeta-success: "&b{0}&a ma {1} &f\"{2}&f\"&a ustawiony priorytet z &b{3}&a w kontekście {4}&a."
add-temp-chatmeta-success: "&b{0}&a ma {1} &f\"{2}&f\"&a ustawiony priorytet z &b{3}&a na czas trwania &b{4}&a w kontekście {5}&a."
remove-chatmeta-success: "&b{0}&a ma {1} &f\"{2}&f\"&a at priority &b{3}&a removed in context {4}&a."
bulk-remove-chatmeta-success: "&b{0}&a ma cały {1}es na priorytecie &b{2}&a usunięte w kontekście {3}&a."
remove-temp-chatmeta-success: "&b{0}&a ma tymczasowo {1} &f\"{2}&f\"&a at priority &b{3}&a usunięte w kontekście {4}&a."
bulk-remove-temp-chatmeta-success: "&b{0}&a miał wszystkie tymczasowe {1}es na priorytecie &b{2}&a usunięte w kontekście {3}&a."
already-has-meta: "{0} ma już tę parę par kluczy meta."
set-meta-success: "&aUstawiono wartość meta dla klucza &f\"{0}&f\"&a do &f\"{1}&f\"&a dla &b{2}&a w kontekście {3}&a."
set-meta-temp-success: "&aUstawiono wartości meta dla klucza &f\"{0}&f\"&a do &f\"{1}&f\"&a dla &b{2}&a na czas trwania &b{3}&a w kontekście {4}&a."
unset-meta-success: "&aUsunięto wartość meta za pomocą klucza &f\"{0}&f\"&a dla &b{1}&a w kontekście {2}&a."
unset-meta-temp-success: "&aUsunięcie tymczasowej wartości meta za pomocą klucza &f\"{0}&f\"&a dla &b{1}&a w kontekście {2}&a."
bulk-update-invalid-data-type: "Nieprawidłowy typ. Spodziewane 'all', 'users' lub 'groups'."
bulk-update-invalid-constraint: "Nieprawidłowe ograniczenie &4{0}&c. Ograniczenia powinny być w formacie '&f<field> <comparison operator> <value>&c'."
bulk-update-invalid-comparison: "Nieprawidłowy operator porównania '&4{0}&c'. Oczekiwany jeden z poniższych: &f== != ~~ ~!"
bulk-update-queued: "&aOperacja aktualizacji została w kolejce. &7(&f{0}&7)"
bulk-update-confirm: "&aUruchom &b/{0} uaktualnianie zbiorcze {1} &a i wykonaj aktualizacje."
bulk-update-unknown-id: "&aOperacja z id &b{0}&a nie istnieje lub upłynął."
bulk-update-starting: "&aUaktualnianie zbiorcze."
bulk-update-success: "&bAktualizacja zbiorcza powiodła się pomyślnie."
bulk-update-failure: "&cAktualizacja zbiorcza nie powiodła się. Sprawdź, czy konsola nie zawiera błędów."
user-info-general: >
{PREFIX}&b&l> &bInfo Użytkownika: &f{0}\n
{PREFIX}&f- &3UUID: &f{1}\n
{PREFIX}&f- &3Status: {2}\n
{PREFIX}&f- &3Grupa Podstawowa: &f{3}\n
{PREFIX}&f- &aLiczba:\n
{PREFIX}&f- &3Uprawnień: &a{4}\n
{PREFIX}&f- &3Tymczasowych uprawnień: &a{5}\n
{PREFIX}&f- &3Prefiksów: &a{6}\n
{PREFIX}&f- &3Suffiksów: &a{7}\n
{PREFIX}&f- &3Meta: &a{8}
user-info-data: >
{PREFIX}&f- &aDane buforowane:\n
{PREFIX}&f- &3Posiada dane kontekstowe: {0}\n
{PREFIX}&f- &3Obecne konteksty: {1}\n
{PREFIX}&f- &3Obecny Prefiks: {2}\n
{PREFIX}&f- &3Obecny Suffiks: {3}
info-parent-header: "&f- &aGrupy Rodziców:"
info-temp-parent-header: "&f- &aTymczasowe Grupy Rodziców:"
user-removegroup-error-primary: "Nie można usunąć użytkownika z podstawowej grupy."
user-primarygroup-success: "&b{0}&a's pierwsza grupa została ustawiona na &b{1}&a."
user-primarygroup-warn-option: "&cUwaga: Podstawowa metoda obliczania grupy jest używana przez ten serwer &7({0}) &cmoże nie odzwierciedlać tej zmiany."
user-primarygroup-error-alreadyhas: "Użytkownik ma już tę grupę jako pierwszą."
user-primarygroup-error-notmember: "&b{0}&a nie był już użytkownikiem z &b{1}&a, dodając je teraz."
user-track-error-not-contain-group: "Podany przez Ciebie użytkownik nie jest jeszcze w żadnej z grup na tej ścieżce."
user-track-added-to-first: "&b{0}&a nie jest w żadnej grupie na tej ścieżce, więc został dodany do pierwszej grupy, &b{1}&a w kontekście {2}&a."
user-promote-success: "&aPromowanie użytkownika wzdłuż toru &b{0}&a z &b{1}&a do &b{2}&a w kontekście {3}&a."
user-promote-error-endoftrack: "Koniec ścieżki &4{0}&c został osiągnięty. Nie można promować użytkownika."
user-promote-error-malformed: >
{PREFIX}Następna grupa na ścieżce, {0}, już nie istnieje. Nie można promować użytkownika..\n
{PREFIX}Albo utwórz grupę lub usuń ją ze ścieżki i spróbuj ponownie.
user-demote-success: "&aObniżanie użytkownika wzdłuż ścieżki &b{0}&a z &b{1}&a do &b{2}&a w kontekście {3}&a."
user-demote-endoftrack: "Koniec ścieżki &4{0}&c został osiągnięty, więc &4{1}&c zostało usunięte z &4{2}&c."
user-demote-error-malformed: >
{PREFIX}Poprzednia grupa na ścieżce, {0}, już nie istnieje. Nie można obniżyć użytkownika.\n
{PREFIX}Albo utwórz grupę lub usuń ją ze ścieżki i spróbuj ponownie.
group-info-general: >
{PREFIX}&b&l> &bInfo Grupy: &f{0}\n
{PREFIX}&f- &3Wyświetlana Nazwa: &f{1}\n
{PREFIX}&f- &3Rola: &f{2}\n
{PREFIX}&f- &aLiczba:\n
{PREFIX}&f- &3Uprawnienia: &a{3}\n
{PREFIX}&f- &3Tymczasowe Uprawnienia: &a{4}\n
{PREFIX}&f- &3Prefiksy: &a{5}\n
{PREFIX}&f- &3Suffiksy: &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> &bWyświetlanie ścieżki: &f{0}\n
{PREFIX}&f- &7Ścieżka: &f{1}
track-clear: "&b{0}&a grupy zostały usunięte"
track-append-success: "&aGrupa &b{0}&a została z powodzeniem dodana do śledzenia &b{1}&a."
track-insert-success: "&aGrupa &b{0}&a została pomyślnie wstawiona do ścieżki &b{1}&a na pozycji &b{2}&a."
track-insert-error-number: "Przewidywany numer, ale otrzymany: {0}"
track-insert-error-invalid-pos: "Nie można wstawić w pozycji {0}. Wyloguj się z granic."
track-remove-success: "&aGrupa &b{0}&a została z powodzeniem usunięta ze ścieżki &b{1}&a."
log-load-error: "Nie można załadować loga."
log-invalid-page: "Nieprawidłowy numer strony."
log-invalid-page-range: "Nieprawidłowy numer strony. Wprowadź wartość między 1 a {0}."
log-no-entries: "&bBrak wpisów do logów."
log-entry: "&b#{0} -> &8(&7{1} temu&8) {2}"
log-notify-toggle-on: "&aWłączone&b wyjście z logowania."
log-notify-toggle-off: "&cWyłączone&b wyjście z logowania."
log-notify-already-on: "Obecnie otrzymujesz powiadomienia."
log-notify-already-off: "Obecnie nie otrzymujesz powiadomień."
log-notify-unknown: "Stan nieznany. Oczekiwanie na \"on\" lub \"off\"."
log-search-header: "&aWyświetlanie ostatnich działań dotyczących zapytania &b{0} &a(strona &f{1}&a z &f{2}&a)"
log-recent-header: "&aWyświetlanie ostatnich działań (strona &f{0}&a z &f{1}&a)"
log-recent-by-header: "&aPokazanie ostatnich działań przez &b{0} &a(strona &f{1}&a z &f{2}&a)"
log-history-user-header: "&aWyświetlanie historii dla użytkowników &b{0} &a(strona &f{1}&a z &f{2}&a)"
log-history-group-header: "&aWyświetlanie historii dla grup &b{0} &a(strona &f{1}&a z &f{2}&a)"
log-history-track-header: "&aWyświetlanie historii dla ścieżki &b{0} &a(strona &f{1}&a z &f{2}&a)"
log-export-already-exists: "Błąd: Plik {0} już istnieje."
log-export-not-writable: "Błąd: Plik {0} jest tylko do odczytu."
log-export-empty: "Log jest pusty i dlatego nie może być eksportowany"
log-export-failure: "Podczas zapisywania do pliku wystąpił nieoczekiwany błąd."
log-export-success: "&aPomyślnie exportowano log do &b{0}&a."
import-already-running: "Inny proces importowania jest już uruchomiony. Spróbuj ponownie później."
export-already-running: "Inny proces eksportowania jest już uruchomiony. Spróbuj ponownie później."
import-log-doesnt-exist: "Błąd: Plik {0} nie istnieje."
import-log-not-readable: "Błąd: Plik {0} nie można odczytać."
import-log-failure: "Podczas odtwarzania loga wystąpił nieoczekiwany błąd."
import-progress: "&b(Import) &b-> &f{0} &fprocent kompletne &7- &b{1}&f/&b{2} &foperacja zakończona z &c{3} &fbłędami."
import-progress-sin: "&b(Import) &b-> &f{0} &fprocent kompletne &7- &b{1}&f/&b{2} &foperacja zakończona z &c{3} &fbłędami."
import-start: "&b(Import) &b-> &fUruchamianie procesu importowania."
import-end-complete: "&b(Import) &a&lZAKOŃCZONE &7- zajęło &b{0} &7sekundy - &7Nie ma błędów."
import-end-complete-err: "&b(Import) &a&lZAKOŃCZONE &7- zajęło &b{0} &7sekundy - &c{1} błędy."
import-end-complete-err-sin: "&b(Import) &a&lZAKOŃCZONE &7- zajęło &b{0} &7sekundy - &c{1} błąd."
import-end-error-header: >
{PREFIX}&b(Import) &7------------> &fWyświetlanie błędu #&b{0} &7<------------\n
{PREFIX}&b(Import) &fWykonując: &3Komende #{1}\n
{PREFIX}&b(Import) &fKomenda: &7{2}\n
{PREFIX}&b(Import) &fWpisane: &3{3}\n
{PREFIX}&b(Import) &fWyjście:
import-end-error-content: "&b(Import) &b-> &c{0}"
import-end-error-footer: "&b(Import) &7<------------------------------------------>"
-303
View File
@@ -1,303 +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[ПРЕДУПРЕЖДЕНИЕ] {0}"
log-error: "&7&l[&bLuck&3Perms&7&l] &4[ОШИБКА] {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-save-success: "&7(Данные о путе сохранены на хранение)"
track-save-error: "При сохранении пути произошла ошибка."
user-invalid-entry: "&d{0}&c не является допустимым именем пользователя/uuid."
group-invalid-entry: "Имена групп могут содержать только буквенно-цифровые символы."
track-invalid-entry: "Имена путей могут содержать только буквенно-цифровые символы."
server-invalid-entry: "Имена серверов могут содержать только буквенно-цифровые символы."
use-inherit-command: "Используйте команды «parent add» и «parent remove» вместо указания узла (node)."
verbose-invalid-filter: "&cНедопустимый подробный (verbose) фильтр: &f{0}"
verbose-on: "&Запись подробной проверки установлена на &aTRUE &bдля всех разрешений (пермов)."
verbose-on-query: "&Запись подробной проверки установлена на &aTRUE &bДля разрешений, соответствующих следующим фильтрам: &f{0}"
verbose-off: "&Запись подробной проверки установлена на &cFALSE&b."
verbose-recording-on: "&Запись подробной записи установлена ​​на &aTRUE &bдля всех разрешений."
verbose-recording-on-query: "&Запись подробной записи установлена ​​на &aTRUE &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-searching-members: "&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: "Путь {0} уже содержит группу '{1}'."
track-does-not-contain: "Путь {0} не содержит группу '{1}'."
track-ambiguous-call: "Указанный пользователь является членом нескольких групп на этом пути. Невозможно определить их местоположение."
group-already-exists: "Эта группа уже существует!"
group-does-not-exist: "Эта группа не существует!"
group-load-error: "Произошла непредвиденная ошибка. Группа не загружена."
groups-load-error: "Произошла непредвиденная ошибка. Не удалось загрузить все группы."
track-already-exists: "Этот путь уже существует!"
track-does-not-exist: "Этот путь не существует!"
track-load-error: "Произошла непредвиденная ошибка. Путь не загружен."
tracks-load-error: "Произошла непредвиденная ошибка. Не удалось загрузить все пути."
track-empty: "Путь нельзя использовать, так как он пуст или содержит только одну группу."
update-task-request: "&bОбновление задачи запланировано."
update-task-complete: "&aОбновление задачи завершено."
update-task-complete-network: "&aОбновление задачи завершено. Теперь пытаемся подключиться к другим серверам."
update-task-push-success: "&aДругие серверы были уведомлены через &b{0} cообщения и удаленный доступ."
update-task-push-failure: "&cОшибка при нажатии изменений на других серверах."
update-task-push-failure-not-setup: "&cОшибка при нажатии изменений на других серверах. Служба обмена сообщениями не настроена."
reload-config-success: "&aФайл конфигурации был перезагружен. &7(Некоторые параметры будут применяться только после перезапуска сервера.)"
info: >
{PREFIX}&2Выполнение &bLuckPerms v{0}&2 by &bLuck&2.\n
{PREFIX}&f- &3Платформа: &f{1}\n
{PREFIX}&f- &3Способ Хранения: &f{2}\n
{PREFIX}&f- &3Имя Сервера: &f{3}\n
{PREFIX}&f- &3Интервал Синхронизации: &a{4} &fминут\n
{PREFIX}&f- &3Служба обмена сообщениями: &f{5}\n
{PREFIX}&f- &bГрафы:\n
{PREFIX}&f- &3Игроки Онлайн: &a{6}\n
{PREFIX}&f- &3Загруженные пользователи: &a{7}\n
{PREFIX}&f- &3Загруженные группы: &a{8}\n
{PREFIX}&f- &3Загруженные пути: &a{9}\n
{PREFIX}&f- &3Размер лога: &a{10}\n
{PREFIX}&f- &3UUID Размер кеша: &a{11}\n
{PREFIX}&f- &3Переводы загружены: &a{12}\n
{PREFIX}&f- &3Контексты перед обработкой: &a{13}\n
{PREFIX}&f- &3Счетчик контекста: &a{14}\n
{PREFIX}&f- &3Уникальные разрешения: &a{15}\n
{PREFIX}&f- &bКонфигурация:\n
{PREFIX}&f- &3Использует сервер UUIDs: {16}\n
{PREFIX}&f- &bСчетчик разрешений:\n
{PREFIX}&f- &3Включая глобальные: {17}\n
{PREFIX}&f- &3Включая глобальный мир: {18}\n
{PREFIX}&f- &3Применения глобальных групп: {19}\n
{PREFIX}&f- &3Применения глобальных групп мира: {20}\n
{PREFIX}&f- &3Применения подстановочных знаков (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: "При создании пути произошла ошибка."
delete-track-error: "При удалении пути произошла ошибка."
tracks-list: "&aГенеральные пути: {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 Пути:\n
{1}
list-tracks-empty: "{0} не на каких-либо путях."
context-pair-inline: "&3{0}=&b{1}"
context-pair--global-inline: "&eГлобальный"
context-pair-end: "&a."
context-pair-sep: "&a, "
context-pair: "&8(&7{0}=&f{1}&8)"
check-permission: "&b{0}&a имеет разрешение &b{1}&a установленое в {2}&a в контексте {3}&a."
check-permission-inherited: "&b{0}&a имеет разрешение &b{1}&a установленое в {2}&a в контексте {3}&a, наследованный от &b{4}&a."
setpermission-success: "&aУстановить &b{0}&a к &b{1}&a для &b{2}&a."
setpermission-temp-success: "&aУстановить &b{0}&a к &b{1}&a для &b{2}&a На срок &b{3}&a."
unsetpermission-success: "&aСбросить &b{0}&a для &b{1}&a."
unset-temp-permission-success: "&aСбросить временное разрешение &b{0}&a для &b{1}&a."
set-inherit-success: "&b{0}&a теперь наследует разрешения от &b{1}&a."
set-parent-success: "&b{0}&a их существующие родительские группы очищены, и теперь только наследуют &b{1}&a."
set-temp-inherit-success: "&b{0}&a теперь наследует разрешения от &b{1}&a на срок &b{2}&a."
unset-inherit-success: "&b{0}&a больше не наследует разрешения от &b{1}&a."
unset-temp-inherit-success: "&b{0}&a больше не наследует временные разрешения (пермы) &b{1}&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 мета очищена. (&b{1}&a узлы были удалены.)"
meta-clear-success-singular: "&b{0}&a's мета очищена. (&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 Мета"
chat-meta-entry: "&b-> {0} &f- &f\"{1}&f\" &8(&7унаследованный от &a{2}&8)"
chat-meta-entry-with-context: "&b-> {0} &f- &f\"{1}&f\" &8(&7унаследованный от &a{2}&8){3}"
meta-entry: "&b-> &a{0} &f= &f\"{1}&f\" &8(&7унаследованный от &a{2}&8)"
meta-entry-with-context: "&b-> &a{0} &f= &f\"{1}&f\" &8(&7унаследованный от &a{2}&8){3}"
chat-meta-prefix-none: "&b{0} не имеет префиксов."
chat-meta-suffix-none: "&b{0} не имеет суффиксов."
meta-none: "&b{0} не имеет мету."
meta-invalid-priority: "Недопустимый приоритет '{0}'. Ожидается число."
already-has-chat-meta: "{0} уже имеет этот {1}."
does-not-have-chat-meta: "{0} не имеет этого {1}."
add-chatmeta-success: "&b{0}&a имеет {1} &f\"{2}&f\"&a установлен в приоритете &b{3}&a в контексте {4}&a."
add-temp-chatmeta-success: "&b{0}&a имеет {1} &f\"{2}&f\"&a установлен в приоритете &b{3}&a на срок &b{4}&a в контексте {5}&a."
remove-chatmeta-success: "&b{0}&a имеет {1} &f\"{2}&f\"&a в приоритете &b{3}&a удален из контекста {4}&a."
bulk-remove-chatmeta-success: "&b{0}&a все временные {1}es в приоритете &b{3}&a были удалены из контекста {4}&a."
remove-temp-chatmeta-success: "&b{0}&a временно установленный {1} &f\"{2}&f\"&a в приоритете &b{3}&a был удален из контекста {4}&a."
bulk-remove-temp-chatmeta-success: "&b{0}&a все временные {1}es в приоритете &b{3}&a были удалены из контекста {4}&a."
already-has-meta: "{0} уже установлено, что установлена ​​пара мета-значения клавиши."
set-meta-success: "&aУстановить метазначение для клавиши &f\"{0}&f\"&a к &f\"{1}&f\"&a для &b{2}&a."
set-meta-temp-success: "&aУстановить метазначение для клавиши &f\"{0}&f\"&a к &f\"{1}&f\"&a для &b{2}&a на срок &b{3}&a."
unset-meta-success: "&aСбросить метазначение с помощью клавиши &f\"{0}&f\"&a для &b{1}&a."
unset-meta-temp-success: "&aСбросить временное мета-значение с помощью клавиши &f\"{0}&f\"&a для &b{1}&a."
bulk-update-invalid-data-type: "Недопустимый тип. Выберите 'all', 'users' или 'groups'."
bulk-update-invalid-constraint: "Недопустимое ограничение &4{0}&c. Ограничения должны быть в формате '&f<поле> <оператор сравнения> <значение>&c'."
bulk-update-invalid-comparison: "Недопустимый оператор сравнения '&4{0}&c'. Выберите одно из следующих: &f== != ~~ ~!"
bulk-update-queued: "&aМассовое обновление было поставлено в очередь. &7(&f{0}&7)"
bulk-update-confirm: "&aВведите &b/{0} bulkupdate confirm {1} &aчтобы подтвердить выполнение массового обновления."
bulk-update-unknown-id: "&aОперация с id &b{0} &aне существует или истек срок действия."
bulk-update-starting: "&aВыполнение массового обновления."
bulk-update-success: "&bМассовое обновление успешно завершено."
bulk-update-failure: "&cНе удалось выполнить массовое обновление. Проверьте консоль на наличие ошибок."
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- &3Мета: &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: "Указанный пользователь не находится ни в каких группах на этом пути."
user-track-added-to-first: "&b{0}&a не находится ни в каких группах на этом треке, поэтому они были добавлены в первую группу &b{1}&a в контексте {2}&a."
user-promote-success: "&aПовышение пользователя &b{0}&a от &b{1}&a к &b{2}&a в контексте {3}&a."
user-promote-error-endoftrack: "Конец пути &4{0}&c, был достигнут. Не удалось повысить пользователя."
user-promote-error-malformed: >
{PREFIX}Следующая группа на пути, {0}, более не существует. Не удалось продвинуть пользователя.\n
{PREFIX}Создайте группу или удалите ее с пути и повторите попытку.
user-demote-success: "&aПонижение пользователя по пути &b{0}&a от &b{1}&a к &b{2}&a в контексте {3}&a."
user-demote-endoftrack: "Конец пути &4{0}&c был достингут, поэтому &4{1}&c был удален из &4{2}&c."
user-demote-error-malformed: >
{PREFIX}Предыдущая группа на пути, {0}, более не существуют. Невозможно понизить рейтинг пользователя.\n
{PREFIX}Создайте группу или удалите ее с пути и повторите попытку.
user-showpos: >
&aпоказывает &b{0}&a's позицию на пути &b{1}&a.\n
{2}
group-info-general: >
{PREFIX}&b&l> &bИнфо о группе: &f{0}\n
{PREFIX}&f- &3Отображаемое имя: &f{1}\n
{PREFIX}&f- &3Значение: &f{2}\n
{PREFIX}&f- &aГрафы:\n
{PREFIX}&f- &3Разрешения: &a{3}\n
{PREFIX}&f- &3Временные разрешения: &a{4}\n
{PREFIX}&f- &3Префиксы: &a{5}\n
{PREFIX}&f- &3Суффиксы: &a{6}\n
{PREFIX}&f- &3Мета: &a{7}
group-set-weight: "&aУстановить значение &b{0}&a для группы &b{1}&a."
track-info: >
{PREFIX}&b&l> &bПоказать путь: &f{0}\n
{PREFIX}&f- &7Путь: &f{1}
track-clear: "&b{0}&a's путь групп был очищен."
track-append-success: "&aГруппа &b{0}&a успешно добавлен в путь &b{1}&a."
track-insert-success: "&aГруппа &b{0}&a был успешно добавлен в путь &b{1}&a на позиции &b{2}&a."
track-insert-error-number: "Ожидаемое число, но вместо этого получено: {0}"
track-insert-error-invalid-pos: "Невозможно вставить в позицию {0}. Индекс вне пределов."
track-remove-success: "&aГруппа &b{0}&a Успешно удален с пути &b{1}&a."
log-load-error: "Не удалось загрузить лог."
log-invalid-page: "Недействительный номер страницы."
log-invalid-page-range: "Недопустимый номер страницы. Введите значение от 1 до {0}."
log-no-entries: "&bНет логов для отображения."
log-entry: "&b#{0} -> &8(&7{1} тому назад&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(страница &f{1}&a из &f{2}&a)"
log-recent-header: "&aПоследние действия (страница &f{0}&a из &f{1}&a)"
log-recent-by-header: "&aПоказывать последние действия &b{0} &a(страница &f{1}&a из &f{2}&a)"
log-history-user-header: "&aОтображение истории для пользователя &b{0} &a(страница &f{1}&a из &f{2}&a)"
log-history-group-header: "&aОтображение истории для группы &b{0} &a(страница &f{1}&a из &f{2}&a)"
log-history-track-header: "&aОтображение истории для пути &b{0} &a(страница &f{1}&a из &f{2}&a)"
log-export-already-exists: "Ошибка: файл {0} уже существует."
log-export-not-writable: "Ошибка: файл {0} недоступен для записи."
log-export-empty: "Логи пусты и поэтому не могут быть экспортированы."
log-export-failure: "Произошла непредвиденная ошибка во время записи в файл."
log-export-success: "&aФайл логов успешно экспортирован в &b{0}&a."
import-already-running: "Другой процесс импорта уже запущен. Дождитесь завершения и повторите попытку."
export-already-running: "Другой процесс экспорта уже запущен. Дождитесь завершения и повторите попытку."
import-log-doesnt-exist: "Ошибка: файл {0} не существует."
import-log-not-readable: "Ошибка: файл {0} не читается."
import-log-failure: "Произошла непредвиденная ошибка при чтении лога."
import-progress: "&b(Импортировать) &b-> &f{0} &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<------------------------------------------>"
-738
View File
@@ -1,738 +0,0 @@
# LuckPerms Language File
# Locale: zh-CN (Simplified Chinese)
# Author: EuropeJing
prefix: "&7&l[&b&lL&3&lP&7&l] &c"
log-info: "&7&l[&bL&3P&7&l] &3{0}"
log-warn: "&7&l[&bLuck&3Perms&7&l] &c[警告] {0}"
log-error: "&7&l[&bLuck&3Perms&7&l] &4[错误] {0}"
empty: "{0}"
player-online: "&a在线"
player-offline: "&c离线"
loading-error: "无法加载权限数据,请稍后再试。"
op-disabled: "&b此服务器上禁用了vanilla OP系统。"
op-disabled-sponge: "&2安装了权限插件时,服务器OP状态无效,请直接编辑用户数据。"
log: "&3日志 &3&l> {0}"
verbose-log: "&3详细 &3&l> {0}"
export-log: "&3输出 &3&l> &f{0}"
export-log-progress: "&3输出 &3&l> &7{0}"
migration-log: "&3移动 &7[&3{0}&7] &3&l> &f{1}"
migration-log-progress: "&3移动 &7[&3{0}&7] &3&l> &7{1}"
command-not-recognised: "命令未被识别。"
command-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-save-success: "&7(保存用户数据到文件)"
user-save-error: "保存用户数据时出错。"
group-not-found: "&b找不到组。"
group-save-success: "&7(保存组数据到文件)"
group-save-error: "保存组数据时出错。"
track-not-found: "&b无法找到权限组轨道。"
track-save-success: "&7(保存权限组轨道到文件)"
track-save-error: "保存权限组轨道时出错。"
user-invalid-entry: "&d{0}&c不是有效的用户名/uuid。"
group-invalid-entry: "组名只能包含字母数字字符。"
track-invalid-entry: "权限组轨道名称只能包含字母数字字符。"
server-world-invalid-entry: "服务器/世界名称只能包含字母数字字符,长度不能超过36个字符。"
use-inherit-command: "使用'parent add'和'parent remove'命令,而不是指定节点。"
verbose-invalid-filter: "&c无效的详细过滤器: &f{0}"
verbose-on: "&b所有权限的详细输出设置为&a开&b。"
verbose-on-query: "&b将匹配过滤器:&f{0}&b的权限详细输出设置为&a开&b。"
verbose-off: "&b所有权限的详细输出设置为&c关&b。"
verbose-recording-on: "&b所有权限的详细记录设置为&a开&b。"
verbose-recording-on-query: "&b将匹配过滤器:&f{0}&b的权限详细记录设置为&a开&b。"
verbose-recording-upload-start: "&b详细记录被禁用。正在上传结果..."
verbose-recording-url: "&a详细结果的网址:"
tree-upload-start: "&b生成权限树..."
tree-empty: "&a无法生成树,没有找到结果。"
tree-url: "&a权限树网址:"
search-searching: "&a使用&b{0}&a搜索用户和组..."
search-searching-members: "&a正在搜索继承自&b{0}&a的用户和组..."
search-result: "&a从&b{1}&a用户和&b{2}&a组找到&b{0}&a个条目。"
search-showing-users: "&b显示用户条目:"
search-showing-groups: "&b显示组条目:"
search-showing-users-with-page: "&b显示用户条目: {0}"
search-showing-groups-with-page: "&b显示组条目: {0}"
apply-edits-invalid-code: "&a无效的代码。&7({0})"
apply-edits-unable-to-read: "&a无法使用给定代码读取数据。&7({0})"
apply-edits-no-target: "&a无法解析编辑的目标。请提供它作为一个额外的参数。"
apply-edits-target-group-not-exists: "&a目标组&b{0}&a不存在。"
apply-edits-target-user-not-uuid: "&a目标用户&b{0}&a不是一个有效的uuid。"
apply-edits-target-user-unable-to-load: "&a无法加载目标用户&b{0}&a。"
apply-edits-target-unknown: "&a目标无效。&7({0})"
apply-edits-success: "&a成功应用&b{0}&a节点到&b{1}&a。"
editor-upload-failure: "&c无法将权限数据上传到编辑器。"
editor-url: "&a编辑器URL:"
check-result: "&a用户&b{0}&a获得允许&b{1}&a权限的检查结果&a: &f{2}"
create-success: "&b{0}&a创建成功。"
delete-success: "&b{0}&a删除成功。"
rename-success: "&b{0}&a成功被重命名为&b{1}&a。"
clone-success: "&b{0}&a成功地复制到&b{1}&a。"
already-inherits: "{0}已经继承'{1}'。"
does-not-inherit: "{0}不再继承'{1}'。"
already-temp-inherits: "{0}已临时继承'{1}'。"
does-not-temp-inherit: "{0}不再临时继承'{1}'。"
track-already-contains: "权限组轨道{0}已经包含组'{1}'。"
track-does-not-contain: "权限组轨道{0}不包含组'{1}'。"
track-ambiguous-call: "指定的用户是此权限组轨道上多个组的成员,无法确定他们的位置。"
group-already-exists: "该组已存在!"
group-does-not-exist: "组不存在!"
group-load-error: "发生意外错误,组未加载。"
groups-load-error: "发生意外错误,无法加载所有组。"
track-already-exists: "权限组轨道已存在!"
track-does-not-exist: "权限组轨道不存在!"
track-load-error: "发生意外错误。权限组轨道未加载。"
tracks-load-error: "出现意外错误,无法加载所有权限组轨道。"
track-empty: "权限组轨道不能使用,因为它是空的或只包含一个组。"
update-task-request: "&b安排更新任务。"
update-task-complete: "&a更新任务完成。"
update-task-complete-network: "&a更新任务完成,现在尝试推送到其他服务器。"
update-task-push-success: "&a其他服务器通过&b{0}消息传递成功通知。"
update-task-push-failure: "&c将更改推送到其他服务器时出错。"
update-task-push-failure-not-setup: "&c将更改推送到其他服务器时出错,未配置消息传递服务。"
reload-config-success: "&a重新加载配置文件。&7(一些选项将仅在服务器重新启动后才应用。)"
info: >
{PREFIX}&2运行 &bLuckPerms v{0}&2 by &bLuck&2。\n
{PREFIX}&f- &3平台: &f{1}\n
{PREFIX}&f- &3存储方式: &f{2}\n
{PREFIX}&f- &3服务器名称: &f{3}\n
{PREFIX}&f- &3同步间隔: &a{4} &f分钟\n
{PREFIX}&f- &3消息服务: &f{5}\n
{PREFIX}&f- &b统计:\n
{PREFIX}&f- &3在线玩家: &a{6}\n
{PREFIX}&f- &3加载用户: &a{7}\n
{PREFIX}&f- &3加载组: &a{8}\n
{PREFIX}&f- &3加载权限组轨道: &a{9}\n
{PREFIX}&f- &3日志大小: &a{10}\n
{PREFIX}&f- &3UUID缓存大小: &a{11}\n
{PREFIX}&f- &3翻译加载: &a{12}\n
{PREFIX}&f- &3预处理环境: &a{13}\n
{PREFIX}&f- &3环境计算器: &a{14}\n
{PREFIX}&f- &3唯一权限: &a{15}\n
{PREFIX}&f- &b配置:\n
{PREFIX}&f- &3使用服务器UUIDs: {16}\n
{PREFIX}&f- &b权限计算:\n
{PREFIX}&f- &3包括全部: {17}\n
{PREFIX}&f- &3包括全部世界: {18}\n
{PREFIX}&f- &3应用全部组: {19}\n
{PREFIX}&f- &3应用全部世界组: {20}\n
{PREFIX}&f- &3应用通配符: {21}\n
{PREFIX}&f- &3应用正则表达式: {22}\n
{PREFIX}&f- &3应用速记: {23}
create-group-error: "创建组时出错。"
delete-group-error: "删除组时出错。"
delete-group-error-default: "您不能删除默认组。"
groups-list: "&a组: &7(名字,权重,权限组轨道)"
groups-list-entry: "&f- &3{0} &7- &b{1}"
groups-list-entry-with-tracks: "&f- &3{0} &7- &b{1} &7- [&3{2}&7]"
create-track-error: "创建权限组轨道时出错。"
delete-track-error: "删除权限组轨道时出错。"
tracks-list: "&a权限组轨道: {0}"
listnodes: "&b{0}的节点:"
listnodes-with-page: "&b{0}的节点: {1}"
listnodes-temp: "&b{0}的临时节点:"
listnodes-temp-with-page: "&b{0}的临时节点: {1}"
listparents: "&b{0}的父组"
listparents-temp: "&b{0}的临时父组:"
list-tracks: >
&b{0}的权限组轨道:\n
{1}
list-tracks-empty: "{0}不在任何权限组轨道上。"
context-pair-inline: "&3{0}=&b{1}"
context-pair--global-inline: "&e全局"
context-pair-sep: "&a,"
context-pair: "&8(&7{0}=&f{1}&8)"
check-permission: "&b在环境&b{3}&b中,&b{0}&b的权限&b{1}&b被设置为&b{2}&b。"
setpermission-success: "&a在环境&b{3}&a中将&b{2}&a的&b{0}&a权限设置为&b{1}&a。"
setpermission-temp-success: "&a在环境&b{4}&a中将&b{2}&a的&b{0}&a临时权限设为&b{1}&a,持续时间&b{3}&a。"
unsetpermission-success: "&a在环境&b{2}&a中取消&b{1}&a的&b{0}&a权限。"
unset-temp-permission-success: "&a在环境&b{2}&a中取消&b{1}&a的临时权限&b{0}&a。"
set-inherit-success: "&b{0}&a现在在环境&b{2}&a中继承&b{1}&a的权限&a。"
set-temp-inherit-success: "&b{0}&a现在在环境&b{3}&a中继承&b{1}&a的权限,持续时间&b{2}&a。"
set-parent-success: "&b{0}&a现有的父组被清除,现在只在&b{2}&a中继承&b{1}&a。"
set-track-parent-success: "在权限组轨道&b{1}&a上&b{0}&a现有的父组被清除,现在只在&b{3}&a中继承&b{2}&a。"
unset-inherit-success: "&b{0}&a不再继承环境&b{2}&a中&b{1}&a的权限。"
unset-temp-inherit-success: "&b{0}&a在环境&b{2}&a中不再继承临时权限&b{1}&a。"
clear-success: "&b{0}&a的权限在环境&b{1}&a中被清除。(&b{2}&a节点已被删除。)"
clear-success-singular: "&b{0}&a的权限在环境&b{1}&a中被清除。(&b{2}&a节点已被删除。)"
parent-clear-success: "&b{0}&a的父组在环境&b{1}&a中被清除。&b{2}&a节点被删除。)"
parent-clear-success-singular: "&b{0}&a的父组在环境&b{1}&a中被清除。&b{2}&a节点被删除。)"
parent-clear-track-success: "在权限组轨道&b{1}&a上,&b{0}&a的父组在环境&b{2}&a中被清除。&b{3}&a节点被删除。)"
parent-clear-track-success-singular: "在权限组轨道&b{1}&a上,&b{0}&a的父组在环境&b{2}&a中被清除。&b{3}&a节点被删除。)"
meta-clear-success: "&b{0}&a的元数据在环境&b{1}&a中被清除。&b{2}&a节点已被删除。)"
meta-clear-success-singular: "&b{0}&a的元数据在环境&b{1}&a中被清除。&b{2}&a节点已被删除。)"
illegal-date-error: "无法解析日期'{0}'。"
past-date-error: "您不能设定一个过去的日期!"
chat-meta-prefix-header: "&b{0}的前缀"
chat-meta-suffix-header: "&b{0}的后缀"
meta-header: "&b{0}的元信息"
chat-meta-entry: "&b-> {0} &f- &f\"{1}&f\" &8(&7继承自&a{2}&8)"
chat-meta-entry-with-context: "&b-> {0} &f- &f\"{1}&f\" &8(&7继承自&a{2}&8){3}"
meta-entry: "&b-> &a{0} &f= &f\"{1}&f\" &8(&7继承自&a{2}&8)"
meta-entry-with-context: "&b-> &a{0} &f= &f\"{1}&f\" &8(&7继承自&a{2}&8){3}"
chat-meta-prefix-none: "&b{0}没有前缀。"
chat-meta-suffix-none: "&b{0}没有后缀。"
meta-none: "&b{0}没有元信息。"
meta-invalid-priority: "优先级'{0}'无效。应该是一个数字。"
already-has-chat-meta: "{0}已经设置了{1}。"
does-not-have-chat-meta: "{0}没有设置{1}。"
add-chatmeta-success: "在环境&b{4}&a中将&b{0}&a的{1}设置为&f\"{2}&f\",优先级&b{3}&a。"
add-temp-chatmeta-success: "在环境&b{5}&a中将&b{0}&a的{1}设置为&f\"{2}&f\"&a,优先级&b{3}&a,持续时间为&b{4}&a。"
remove-chatmeta-success: "在环境&b{3}&a中删除了&b{0}&a优先级为&b{3}&a的{1} &f\"{2}&f\"&a。"
bulk-remove-chatmeta-success: "在环境&b{3}&a中删除了&b{0}&a优先级&b{2}&a的所有&b{1}&a。"
remove-temp-chatmeta-success: "在环境&b{4}&a中删除了&b{0}&a优先级&b{3}&a的临时{1} &f\"{2}&f\"&a。"
bulk-remove-temp-chatmeta-success: "在环境&b{3}&a中删除了&b{0}&a优先级&b{2}&a的所有临时&b{1}&a。"
already-has-meta: "{0}已经有了这个元信息集。"
set-meta-success: "将环境&b{3}&a中&b{2}&a的键&f\"{0}&f\"&a的元信息设置为&f\"{1}&f\"&a。"
set-meta-temp-success: "&a在环境&b{4}&a中将&b{2}&a的键&f\"{0}&f\"&a的值设置为&f\"{1}&f\"&a,持续时间为&b{3}&a。"
unset-meta-success: "&a在环境{2}中取消设置&b{1}&a的键&f\"{0}&f\"&a的元信息。"
unset-meta-temp-success: "&a在环境{2}中取消设置&b{1}&a的键&f\"{0}&f\"&a的临时元信息。"
bulk-update-invalid-data-type: "类型无效。期望类型是'全部'、'用户'或'组'。"
bulk-update-invalid-constraint: "无效的约束&4{0}&c。约束的格式应该是'&f<field> <comparison operator> <value>&c'。"
bulk-update-invalid-comparison: "比较运算符无效'&4{0}&c'。应该以下之一: &f== != ~~ ~!"
bulk-update-queued: "&a批量更新操作已排队。&7(&f{0}&7)"
bulk-update-confirm: "&a运行&b/{0} bulkupdate &a确认{1}执行更新。"
bulk-update-unknown-id: "&a使用id&b{0}&a的操作不存在或已过期。"
bulk-update-starting: "&a运行批量更新。"
bulk-update-success: "&b批量更新已成功完成。"
bulk-update-failure: "&c批量更新失败。检查控制台是否有错误。"
user-info-general: >
{PREFIX}&b&l> &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- &3元信息: &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-removegroup-error-primary: "您不能从其主组中删除用户。"
user-primarygroup-success: "&b{0}&a的主组已设为&b{1}&a。"
user-primarygroup-warn-option: "&c警告:此服务器&7({0})&c使用的主组计算方法可能无法反映此更改。"
user-primarygroup-error-alreadyhas: "用户已将此组设置为其主组。"
user-primarygroup-error-notmember: "&b{0}&a不是&b{1}&a的成员,现在添加它们。"
user-track-error-not-contain-group: "指定的用户尚未在此权限组轨道上的任何组中。"
user-track-added-to-first: "&b{0}&a不在此权限组轨道上的任何组中,因此在环境&b{2}&a中将其添加到第一组&b{2}&a。"
user-promote-success: "&a在环境&b{3}&a中将用户沿权限组轨道&b{0}&a从&b{1}&a提升到&b{2}&a。"
user-promote-error-endoftrack: "已达到权限组轨道&4{0}&c的结尾,所以无法提升用户。"
user-promote-error-malformed: >
{PREFIX}权限组轨道上的下一个组{0}不存在。无法提升用户。\n
{PREFIX}创建组,或将其从权限组轨道中删除,然后重试。
user-demote-success: "&a在环境&b{3}&a中将用户沿权限组轨道&b{0}&a从&b{1}&a下降到&b{2}&a。"
user-demote-endoftrack: "已达到权限组轨道&4{0}&c的结尾,所以&4{1}&c已从&4{2}&c中移除。"
user-demote-error-malformed: >
{PREFIX}权限组轨道上的上一组{0}不存在。无法降级用户。\n
{PREFIX}创建组,或将其从权限组轨道中删除,然后重试。
group-info-general: >
{PREFIX}&b&l> &b组信息: &f{0}\n
{PREFIX}&f- &3显示名称: &f{1}\n
{PREFIX}&f- &3权重: &f{2}\n
{PREFIX}&f- &a统计:\n
{PREFIX}&f- &3权限: &a{3}\n
{PREFIX}&f- &3临时权限: &a{4}\n
{PREFIX}&f- &3前缀: &a{5}\n
{PREFIX}&f- &3后缀: &a{6}\n
{PREFIX}&f- &3元信息: &a{7}
group-set-weight: "&a将组&b{1}&a的权重设置为&b{0}&a。"
track-info: >
{PREFIX}&b&l> &b显示权限组轨道: &f{0}\n
{PREFIX}&f- &7路径: &f{1}
track-clear: "&b{0}&a的权限组轨道已被清除。"
track-append-success: "&a组&b{0}&a已成功添加到权限组轨道&b{1}&a。"
track-insert-success: "&a组&b{0}&a已成功插入权限组轨道&b{1}&a的&b{2}&a位置。"
track-insert-error-number: "没有预期的数量,而是收到: {0}"
track-insert-error-invalid-pos: "无法插入位置{0}。索引超出范围。"
track-remove-success: "&a组&b{0}&a已成功从权限组轨道&b{1}&a移除。"
log-load-error: "日志无法加载。"
log-invalid-page: "页码无效。"
log-invalid-page-range: "页码无效,请输入1和{0}之间的值。"
log-no-entries: "&b没有日志条目显示。"
log-entry: "&b#{0} -> &8(&7{1} ago&8) {2}"
log-notify-toggle-on: "&a启用&b记录输出。"
log-notify-toggle-off: "&c禁用&b记录输出。"
log-notify-already-on: "您已经收到通知。"
log-notify-already-off: "您目前没有收到通知。"
log-notify-unknown: "状态未知。输入 \"on\" 或者 \"off\"。"
log-search-header: "&a显示最近的查询操作&b{0} &a(&f{1}&a/&f{2}&a)"
log-recent-header: "&a显示最近操作 (&f{0}&a/&f{1}&a)"
log-recent-by-header: "&a显示&b{0}&a的最近操作 (&f{1}&a/&f{2}&a)"
log-history-user-header: "&a显示用户的历史记录&b{0} &a(&f{1}&a/&f{2}&a)"
log-history-group-header: "&a显示组的历史记录 &b{0} &a(&f{1}&a/&f{2}&a)"
log-history-track-header: "&a显示权限组轨道的历史记录 &b{0} &a(&f{1}&a/&f{2}&a)"
log-export-already-exists: "错误: 文件{0}已经存在。"
log-export-not-writable: "错误: 文件{0}不可写。"
log-export-empty: "日志为空,因此无法导出。"
log-export-failure: "写入文件时出现意外错误。"
log-export-success: "&a成功导出日志&b{0}&a。"
import-already-running: "另一个导入过程已经在运行,请等待完成,然后重试。"
export-already-running: "另一个导出过程已经在运行,请等待完成,然后重试。"
import-log-doesnt-exist: "错误: 文件{0}不存在。"
import-log-not-readable: "错误: 文件{0}不可读。"
import-log-failure: "从日志文件读取时发生意外错误。"
import-progress: "&b(导入) &b-> &f百分之{0}完成 &7- &b{1}&f/&b{2} &f完成 &c{3}&f错误。"
import-progress-sin: "&b(导入) &b-> &f百分之{0}完成 &7- &b{1}&f/&b{2} &f完成 &c{3}&f错误。"
import-start: "&b(导入) &b-> &f开始导入过程。"
import-end-complete: "&b(导入) &a&l已完成 &7- 用了 &b{0} &7秒 - &7没有错误。"
import-end-complete-err: "&b(导入) &a&l已完成 &7- 用了 &b{0} &7秒 - &c{1}错误。"
import-end-complete-err-sin: "&b(导入) &a&l已完成 &7- 用了 &b{0} &7秒 - &c{1}错误。"
import-end-error-header: >
{PREFIX}&b(导入) &7------------> &f显示错误 #&b{0} &7<------------\n
{PREFIX}&b(导入) &f执行: &3命令 #{1}\n
{PREFIX}&b(导入) &f命令: &7{2}\n
{PREFIX}&b(导入) &f类型: &3{3}\n
{PREFIX}&b(导入) &f输出:
import-end-error-content: "&b(导入) &b-> &c{0}"
import-end-error-footer: "&b(导入) &7<------------------------------------------>"
command-specs:
user:
description: "用户命令"
usage: "/%s user <用户>"
group:
description: "组命令"
usage: "/%s group <组>"
track:
description: "权限组轨道指令"
usage: "/%s track <权限组轨道>"
log:
description: "日志命令"
usage: "/%s log"
sync:
description: "与存储同步更改"
usage: "/%s sync"
info:
description: "打印通用插件信息"
usage: "/%s info"
verbose:
description: "管理详细权限检查"
usage: "/%s verbose <true|false> [filter]"
args:
"on|record|off|paste": "是否启用/禁用日志记录,或粘贴记录的输出"
"filter": "过滤器匹配项"
tree:
description: "生成权限的树视图"
usage: "/%s tree [selection] [max level] [player]"
args:
"selection": "树的根,指定\".\"包括所有权限"
"max level": "应该返回多少分支级别"
"player": "要检查的在线玩家的名称"
search:
description: "搜索具有特定权限的用户/组"
usage: "/%s search <permission>"
args:
"permission": "权限搜索"
"page": "页面查看"
check:
description: "对用户执行标准的权限检查"
usage: "/%s check <user> <permission>"
args:
"user": "检查用户"
"permission": "允许检查"
network-sync:
description: "与存储同步更改并请求网络上所有其他服务器都同步"
usage: "/%s networksync"
import:
description: "从文件导入数据"
usage: "/%s import <file>"
args:
"file": "要导入的文件"
export:
description: "将数据导出到文件"
usage: "/%s export <file>"
args:
"file": "要导出的文件"
reload-config:
description: "重新加载部分配置选项"
usage: "/%s reloadconfig"
bulk-update:
description: "对所有数据执行批量更改查询"
usage: "/%s bulkupdate"
args:
"data type": "正在更改的数据类型。('all'、'users'、'groups')"
"action": "对数据执行的操作。('update' or 'delete')"
"action field": "要采取行动的领域。只需要'update'。('permission'、'server'、'world')"
"action value": "替换的值。只需要'update'。"
"constraint...": "更新所需的限制"
migration:
description: "迁移命令"
usage: "/%s migration"
apply-edits:
description: "应用从Web编辑器进行的权限更改"
usage: "/%s applyedits <code> [target]"
args:
"code": "数据的唯一代码"
"target": "应用数据到谁"
create-group:
description: "创建新组"
usage: "/%s creategroup <group>"
args:
"name": "组的名称"
delete-group:
description: "删除组"
usage: "/%s deletegroup <group>"
args:
"name": "组的名称"
list-groups:
description: "列出平台上的所有组"
usage: "/%s listgroups"
create-track:
description: "创建新权限组轨道"
usage: "/%s createtrack <track>"
args:
"name": "权限组轨道的名称"
delete-track:
description: "删除权限组轨道"
usage: "/%s deletetrack <track>"
args:
"name": "权限组轨道的名称"
list-tracks:
description: "列出平台上的所有权限组轨道"
usage: "/%s listtracks"
user-info:
description: "显示有关用户的信息"
user-switchprimarygroup:
description: "切换用户的主组"
args:
"group": "组切换到"
user-promote:
description: "在权限组轨道提升用户"
args:
"track": "提升用户的权限组轨道"
"context...": "提升用户使用的环境"
user-demote:
description: "在权限组轨道降低用户"
args:
"track": "降低用户的权限组轨道"
"context...": "降低用户使用的环境"
group-info:
description: "提供有关组的信息"
group-listmembers:
description: "显示从该组继承的用户/组"
args:
"page": "页面查看"
group-setweight:
description: "设置组权重"
args:
"weight": "设定权重"
group-rename:
description: "重命名组"
args:
"name": "新名字"
group-clone:
description: "克隆组"
args:
"name": "要克隆到的组的名称"
holder-editor:
description: "打开网页权限编辑器"
holder-showtracks:
description: "列出对象所在的权限组轨道"
holder-clear:
description: "删除所有权限,父组和元"
args:
"context...": "过滤的环境"
permission:
description: "编辑权限"
parent:
description: "编辑继承"
meta:
description: "编辑元数据值"
permission-info:
description: "列出对象拥有的权限节点"
args:
"page": "页面查看"
"filter": "要过滤的字符串"
permission-set:
description: "设置对象的权限"
args:
"node": "要添加的权限"
"true|false": "节点的值"
"context...": "添加权限的环境"
permission-unset:
description: "取消对象的权限"
args:
"node": "取消的权限节点"
"context...": "删除权限的环境"
permission-settemp:
description: "设置对象的临时权限"
args:
"node": "要添加的权限"
"true|false": "节点的值"
"duration": "到期时间"
"context...": "权限的环境"
permission-unsettemp:
description: "取消对对象的临时权限"
args:
"node": "要取消的权限"
"context...": "权限的环境"
permission-check:
description: "检查对象是否具有某个权限节点"
args:
"node": "要检查的权限"
"context...": "权限的环境"
permission-check-inherits:
description: "检查对象是否继承某个权限节点"
args:
"node": "要检查的权限"
"context...": "权限的环境"
parent-info:
description: "列出此对象从哪里继承的组"
parent-set:
description: "删除对象已经继承的所有其他组,并将其添加到给定的对象组中。"
args:
"group": "组设为"
"context...": "设置组的环境"
parent-add:
description: "为该对象设置另一个组来继承权限"
args:
"group": "要继承的组"
"context...": "继承该组的环境"
parent-remove:
description: "删除先前设置的继承规则"
args:
"group": "删除的组"
"context...": "删除组的环境"
parent-set-track:
description: "删除对象在给定权限组轨道上继承的所有其他组,并将其添加到给定的权限组轨道上。"
args:
"track": "设置的权限组轨道"
"group": "组中设置的组,或与组中在给定权限组轨道上的位置相关的数字"
"context...": "设置组的环境"
parent-add-temp:
description: "为对象设置另一个组,以便从临时继承权限"
args:
"group": "要继承的组"
"duration": "持续时间"
"context...": "继承该组的环境"
parent-remove-temp:
description: "删除以前设置的临时继承规则"
args:
"group": "组删除"
"context...": "删除组的环境"
parent-clear:
description: "清除所有的父组"
args:
"context...": "过滤的环境"
parent-clear-track:
description: "清除给定权限组轨道上的所有父组"
args:
"track": "删除的权限组轨道"
"contexts...": "选择的环境"
meta-info:
description: "显示所有聊天元"
meta-set:
description: "设置元值"
args:
"key": "设定的键"
"value": "要设置的值"
"context...": "将元添加到"
meta-unset:
description: "取消设定元值"
args:
"key": "要取消的键"
"context...": "删除元的环境"
meta-settemp:
description: "暂时设置一个元值"
args:
"key": "设定的键"
"value": "要设置的值"
"duration": "持续时间"
"context...": "将元组添加到"
meta-unsettemp:
description: "取消设置临时元值"
args:
"key": "要取消的键"
"context...": "删除元的环境"
meta-addprefix:
description: "添加前缀"
args:
"priority": "添加的前缀优先级"
"prefix": "前缀字符串"
"context...": "添加前缀的环境"
meta-addsuffix:
description: "添加后缀"
args:
"priority": "添加的后缀优先级"
"suffix": "后缀字符串"
"context...": "添加后缀的环境"
meta-removeprefix:
description: "删除前缀"
args:
"priority": "删除的前缀优先级"
"prefix": "前缀字符串"
"context...": "删除前缀的环境"
meta-removesuffix:
description: "删除后缀"
args:
"priority": "删除的后缀优先级"
"suffix": "后缀字符串"
"context...": "删除后缀的环境"
meta-addtemp-prefix:
description: "添加临时前缀"
args:
"priority": "删除的前缀优先级"
"prefix": "前缀字符串"
"duration": "持续时间"
"context...": "添加前缀的环境"
meta-addtemp-suffix:
description: "添加临时后缀"
args:
"priority": "添加的后缀优先级"
"suffix": "后缀字符串"
"duration": "持续时间"
"context...": "添加后缀的环境"
meta-removetemp-prefix:
description: "删除临时前缀"
args:
"priority": "删除的前缀优先级"
"prefix": "前缀字符串"
"context...": "删除前缀的环境"
meta-removetemp-suffix:
description: "删除临时后缀"
args:
"priority": "删除的后缀优先级"
"suffix": "后缀字符串"
"context...": "删除后缀的环境"
meta-clear:
description: "清除所有聊天元"
args:
"context...": "过滤的环境"
track-info:
description: "提供有关权限组轨道的信息"
track-append:
description: "追加一个组到权限组轨道的最后"
args:
"group": "追加的组"
track-insert:
description: "在权限组轨道上的给定位置插入一个组"
args:
"group": "插入的组"
"position": "插入组的位置(权限组轨道上的第一个位置为1)"
track-remove:
description: "从权限组轨道中删除一个组"
args:
"group": "删除的组"
track-clear:
description: "清除权限组轨道上的组"
track-rename:
description: "重命名权限组轨道"
args:
"name": "新名字"
track-clone:
description: "克隆权限组轨道"
args:
"name": "要克隆的权限组轨道的名称"
log-recent:
description: "查看最近的登陆"
args:
"user": "用户的名称/uuid"
"page": "要查看的页码"
log-search:
description: "搜索日志中的条目"
args:
"query": "搜索的查询"
"page": "要查看的页码"
log-notify:
description: "切换日志通知"
args:
"on|off": "是否打开或关闭"
log-user-history:
description: "查看用户的历史记录"
args:
"user": "用户名/ uuid"
"page": "要查看的页码"
log-group-history:
description: "查看组的历史"
args:
"group": "组名"
"page": "要查看的页码"
log-track-history:
description: "查看权限组轨道的历史"
args:
"track": "权限组轨道的名称"
"page": "要查看的页码"
sponge:
description: "编辑额外的Sponge数据"
usage: "/%s sponge <collection> <subject>"
args:
"collection": "要查询的集合"
"subject": "修改的主题"
sponge-permission-info:
description: "显示有关主题权限的信息"
args:
"contexts...": "选择的环境"
sponge-permission-set:
description: "设置一个主题的权限"
args:
"node": "要设置的权限节点"
"tristate": "设置允许值"
"contexts...": "选择的环境"
sponge-permission-clear:
description: "清除一个主题的权限"
args:
"contexts...": "清除的环境"
sponge-parent-info:
description: "显示关于该主题父项的信息"
args:
"contexts...": "选择的环境"
sponge-parent-add:
description: "向主题添加父项"
args:
"collection": "父主题的主题集合"
"subject": "父主题的名称"
"contexts...": "添加父项的环境"
sponge-parent-remove:
description: "从主题中删除父项"
args:
"collection": "父主题的主题集合"
"subject": "父主题的名称"
"contexts...": "删除父项的环境"
sponge-parent-clear:
description: "清除主题父项"
args:
"contexts...": "清除父项的主题"
sponge-option-info:
description: "显示有关主题选项的信息"
args:
"contexts...": "选择的环境"
sponge-option-set:
description: "为主题设置一个选项"
args:
"key": "设定键"
"value": "设置的键"
"contexts...": "设置选项的环境"
sponge-option-unset:
description: "取消主题一个选项"
args:
"key": "取消的键"
"contexts...": "取消选项的环境"
sponge-option-clear:
description: "清除对象的选择"
args:
"contexts...": "清除选项的环境"
migration-command:
description: "迁移命令"
migration-groupmanager:
description: "迁移命令"
args:
"migrate as global": "如果世界权限应该被忽略,并且刚刚迁移为全局"
migration-powerfulperms:
description: "迁移命令"
args:
"address": "PP数据库的地址"
"database": "PP数据库的名称"
"username": "登录DB的用户名"
"password": "登录DB的用密码"
"db table": "存储用户数据的PP表的名称"
+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://luckperms.net/wiki/Home#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 impact on the maintainability of the project, and require more consideration.
#### Project Layout
The project is split up into a few separate 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, Velocity & Fabric** - Each use the common module to implement plugins on the respective server platforms.
+22
View File
@@ -0,0 +1,22 @@
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.
+2 -2
View File
@@ -1,4 +1,4 @@
The MIT License.
MIT License
Copyright (c) lucko (Luck) <luck@lucko.me>
Copyright (c) contributors
@@ -19,4 +19,4 @@ 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.
SOFTWARE.
+28 -38
View File
@@ -1,63 +1,53 @@
![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 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.
![](https://raw.githubusercontent.com/LuckPerms/branding/master/banner/banner.png "Banner")
# LuckPerms
[![Build Status](https://ci.lucko.me/job/LuckPerms/badge/icon)](https://ci.lucko.me/job/LuckPerms/)
[![javadoc](https://javadoc.io/badge2/net.luckperms/api/javadoc.svg)](https://javadoc.io/doc/net.luckperms/api)
[![Maven Central](https://img.shields.io/maven-metadata/v/https/repo1.maven.org/maven2/net/luckperms/api/maven-metadata.xml.svg?label=maven%20central&colorB=brightgreen)](https://search.maven.org/artifact/net.luckperms/api)
[![Discord](https://img.shields.io/discord/241667244927483904.svg?label=discord&logo=discord)](https://discord.gg/luckperms)
LuckPerms also includes an extensive API for developers, and support for a variety of Minecraft server software & data storage options.
LuckPerms is a permissions plugin for Minecraft servers. It allows server admins to control what features players can use by creating groups and assigning permissions.
[See the charts below](https://github.com/lucko/LuckPerms#luckperms-vs-other-plugins) for a partial list of features & comparison with other providers.
The latest downloads, wiki & other useful links can be found on the project homepage at [luckperms.net](https://luckperms.net/).
* [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")
It is:
## Useful Links
* **Development Builds** - <https://ci.lucko.me/job/LuckPerms>
* **Javadocs** - <https://luckperms.lucko.me/javadocs/>
* **Wiki** - <https://github.com/lucko/LuckPerms/wiki>
* **fast** - written with performance and scalability in mind.
* **reliable** - trusted by thousands of server admins, and the largest of server networks.
* **easy to use** - setup permissions using commands, directly in config files, or using the web editor.
* **flexible** - supports a variety of data storage options, and works on lots of different server types.
* **extensive** - a plethora of customization options and settings which can be changed to suit your server.
* **free** - available for download and usage at no cost, and permissively licensed so it can remain free forever.
For more information, see the wiki article on [Why LuckPerms?](https://luckperms.net/wiki/Why-LuckPerms)
## Building
LuckPerms uses Maven to handle dependencies.
LuckPerms uses Gradle to handle dependencies & building.
#### Requirements
* Java 8 JDK
* Maven 3.3.x (the older versions will not work.)
* Java 8 JDK or newer
* Git
#### Then run
#### Compiling from source
```sh
git clone https://github.com/lucko/LuckPerms.git
cd LuckPerms/
mvn clean package
./gradlew build
```
You can find the output jars in the `target` directories.
You can find the output jars in the `loader/build/libs` or `build/libs` directories.
## Contributing
In order to contribute to and make changes to the plugin, you will need the dependencies listed above, plus the [Lombok plugin](https://projectlombok.org/download.html) for your IDE.
#### Pull Requests
If you make any changes or improvements to the plugin which you think would be beneficial upstream, please consider making a Pull Request to merge your changes back into the upstream project. (especially if your changes are bug fixes!)
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), with a few minor changes here and there. Generally, try to copy the style of code found in the class you're editing.
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.
The project is split up into a few separate modules.
* **API** - The public facing API classes used by other plugins when integrating with LuckPerms. This is basically just a collection of interfaces implemented inside of the plugin.
* **Common** - This includes all of the classes shared by separate implementations of LuckPerms. This is where the bulk of the project is.
* **Bukkit, BungeeCord & Sponge** - Includes all of the platform specific classes used to implement LuckPerms on each of the 3 supported platforms.
* **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, Fabric, Nukkit & Velocity** - 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").
+116
View File
@@ -0,0 +1,116 @@
group = 'net.luckperms'
project.version = '5.3'
dependencies {
compileOnly 'org.checkerframework:checker-qual:3.12.0'
compileOnly 'org.jetbrains:annotations:20.1.0'
}
// Only used occasionally for deployment - not needed for normal builds.
/*
if (project.hasProperty('sonatypeUsername') && project.hasProperty('sonatypePassword')) {
apply plugin: 'signing'
javadoc {
title = 'LuckPerms API (v' + project.ext.apiVersion + ')'
options.overview = 'javadoc/overview.html'
options.encoding = 'UTF-8'
options.charSet = 'UTF-8'
options.links(
'https://checkerframework.org/api/',
'https://javadoc.io/static/org.jetbrains/annotations/20.1.0/'
)
options.addStringOption('Xdoclint:none', '-quiet')
if (JavaVersion.current() > JavaVersion.VERSION_1_8) {
options.addBooleanOption('-no-module-directories', true)
options.links.add('https://docs.oracle.com/en/java/javase/11/docs/api/')
} else {
options.links.add('https://docs.oracle.com/javase/8/docs/api/')
}
}
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier 'javadoc'
from javadoc.destinationDir
}
task sourcesJar(type: Jar) {
classifier 'sources'
from sourceSets.main.allSource
}
artifacts {
archives javadocJar
archives sourcesJar
}
signing {
useGpgCmd()
sign configurations.archives
}
publishing {
repositories {
maven {
def releasesRepoUrl = 'https://oss.sonatype.org/service/local/staging/deploy/maven2/'
def snapshotsRepoUrl = 'https://oss.sonatype.org/content/repositories/snapshots/'
url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
credentials {
username sonatypeUsername
password sonatypePassword
}
}
}
publications {
mavenJava(MavenPublication) {
artifactId = 'api'
from components.java
artifact sourcesJar
artifact javadocJar
pom {
name 'LuckPerms API'
description 'A permissions plugin for Minecraft servers.'
url 'https://luckperms.net'
licenses {
license {
name 'MIT'
url 'https://opensource.org/licenses/MIT'
}
}
developers {
developer {
id 'lucko'
name 'Luck'
url 'https://lucko.me'
email 'git@lucko.me'
}
}
scm {
connection 'scm:git:https://github.com/lucko/LuckPerms.git'
developerConnection 'scm:git:git@github.com:lucko/LuckPerms.git'
url 'https://github.com/lucko/LuckPerms'
}
ciManagement {
system 'Jenkins'
url 'https://ci.lucko.me/job/LuckPerms'
}
issueManagement {
system 'GitHub'
url 'https://github.com/lucko/LuckPerms/issues'
}
}
}
}
}
}
*/
+19
View File
@@ -0,0 +1,19 @@
<body>
<p>
LuckPerms is a permissions plugin for Minecraft servers. It allows server admins to control what
features players can use by creating groups and assigning permissions.
</p>
<h4>Useful Links</h4>
<ul>
<li><a target="_top" href="https://luckperms.net">Project Website</a></li>
<li><a target="_top" href="https://luckperms.net/wiki/Developer-API">Wiki - API Introduction</a></li>
<li><a target="_top" href="https://luckperms.net/wiki/Developer-API-Usage">Wiki - API Usage</a></li>
</ul>
<h4>Maven</h4>
<p>
The API artifact is deployed to Maven Central under
<a target="_top" href="https://search.maven.org/artifact/net.luckperms/api">
group id: <b><code>net.luckperms</code></b>, artifact id: <b><code>api</code></b>.
</a>
</p>
</body>
-116
View File
@@ -1,116 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>3.4-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>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler.version}</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</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>2.10.4</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>
<profile>
<id>sign</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>${gpg.version}</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<dependencies>
<!-- guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>3.0.2</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
@@ -1,94 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms;
import me.lucko.luckperms.api.LuckPermsApi;
import java.util.Optional;
import javax.annotation.Nonnull;
/**
* Provides static access to the {@link LuckPermsApi}.
*
* <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 instance = null;
/**
* 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 (instance == null) {
throw new IllegalStateException("API is not loaded.");
}
return instance;
}
/**
* Gets an instance of {@link LuckPermsApi}, if it is loaded.
*
* <p>Unlike {@link LuckPerms#getApi}, this method will not throw an
* {@link IllegalStateException} if 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(instance);
}
/**
* 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() {
LuckPerms.instance = null;
}
private LuckPerms() {
throw new UnsupportedOperationException("This class cannot be instantiated.");
}
}
@@ -1,126 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api;
import com.google.common.base.Preconditions;
import java.util.Map;
import java.util.Optional;
import javax.annotation.Nonnull;
/**
* Represents a type of chat meta
*
* @since 3.2
*/
public enum ChatMetaType {
/**
* Represents a prefix
*/
PREFIX {
@Override
public boolean matches(Node node) {
return Preconditions.checkNotNull(node, "node").isPrefix();
}
@Override
public boolean shouldIgnore(Node node) {
return !Preconditions.checkNotNull(node, "node").isPrefix();
}
@Override
public Map.Entry<Integer, String> getEntry(Node node) {
return Preconditions.checkNotNull(node, "node").getPrefix();
}
},
/**
* Represents a suffix
*/
SUFFIX {
@Override
public boolean matches(Node node) {
return Preconditions.checkNotNull(node, "node").isSuffix();
}
@Override
public boolean shouldIgnore(Node node) {
return !Preconditions.checkNotNull(node, "node").isSuffix();
}
@Override
public Map.Entry<Integer, String> getEntry(Node node) {
return Preconditions.checkNotNull(node, "node").getSuffix();
}
};
/**
* 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 abstract boolean shouldIgnore(@Nonnull Node 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);
/**
* 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,236 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api;
import me.lucko.luckperms.api.context.ContextSet;
import javax.annotation.Nonnull;
/**
* Context and options for a permission lookup.
*
* <p>All values are immutable.</p>
*
* @since 2.11
*/
public class Contexts {
public static final String SERVER_KEY = "server";
public static final String WORLD_KEY = "world";
private static final Contexts GLOBAL = new Contexts(ContextSet.empty(), true, true, true, true, true, false);
/**
* Gets the {@link FullySatisfiedContexts} instance.
*
* @return a context that will satisfy all contextual requirements.
*/
@Nonnull
public static Contexts allowAll() {
return FullySatisfiedContexts.getInstance();
}
/**
* A contexts instance with no defined context.
*
* @return the global contexts
* @since 3.3
*/
@Nonnull
public static Contexts global() {
return GLOBAL;
}
public static Contexts of(@Nonnull ContextSet context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups, boolean op) {
return new Contexts(context, includeGlobal, includeGlobalWorld, applyGroups, applyGlobalGroups, applyGlobalWorldGroups, op);
}
/**
* The contexts that apply for this lookup
* The keys for servers and worlds are defined as static values.
*/
private final ContextSet context;
/**
* The mode to parse defaults on Bukkit
*
* @since 2.12
*/
private final boolean op;
/**
* 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(@Nonnull 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;
}
/**
* Gets the contexts that apply for this lookup
*
* @return an immutable set of context key value pairs
* @since 2.13
*/
@Nonnull
public ContextSet getContexts() {
return this.context;
}
/**
* Gets if OP defaults should be included
*
* @return true if op defaults should be included
*/
public boolean isOp() {
return this.op;
}
/**
* Gets if global or non server specific nodes should be applied
*
* @return true if global or non server specific nodes should be applied
*/
public boolean isIncludeGlobal() {
return this.includeGlobal;
}
/**
* Gets if global or non world specific nodes should be applied
*
* @return true if global or non world specific nodes should be applied
*/
public boolean isIncludeGlobalWorld() {
return this.includeGlobalWorld;
}
/**
* Gets if parent groups should be applied
*
* @return true if parent groups should be applied
*/
public boolean isApplyGroups() {
return this.applyGroups;
}
/**
* Gets if global or non server specific group memberships should be applied
*
* @return true if global or non server specific group memberships should be applied
*/
public boolean isApplyGlobalGroups() {
return this.applyGlobalGroups;
}
/**
* Gets if global or non world specific group memberships should be applied
*
* @return true if global or non world specific group memberships should be applied
*/
public boolean isApplyGlobalWorldGroups() {
return this.applyGlobalWorldGroups;
}
@Override
@Nonnull
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() +
")";
}
/*
* Ugly auto-generated lombok code
*/
@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().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();
}
@Override
public int hashCode() {
final int PRIME = 59;
int result = 1;
final Object contexts = this.getContexts();
result = result * PRIME + 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);
return result;
}
}
@@ -1,111 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import java.util.function.Supplier;
/**
* Represents the result of a mutation call.
*/
public enum DataMutateResult {
/**
* Indicates the mutation was a success
*/
SUCCESS(true, null),
/**
* Indicates the mutation failed because the subject already has something
*/
ALREADY_HAS(false, ObjectAlreadyHasException::new),
/**
* Indicates the mutation failed because the subject lacks something
*/
LACKS(false, ObjectLacksException::new),
/**
* Indicates the mutation failed
*/
FAIL(false, RuntimeException::new);
private boolean value;
private final Supplier<? extends Exception> exceptionSupplier;
DataMutateResult(boolean value, Supplier<? extends Exception> exceptionSupplier) {
this.value = value;
this.exceptionSupplier = exceptionSupplier;
}
public void throwException() {
if (exceptionSupplier != null) {
sneakyThrow(exceptionSupplier.get());
}
}
/**
* Gets a boolean representation of the result.
*
* @return a boolean representation
*/
public boolean asBoolean() {
return value;
}
/**
* Gets if the result indicates a success
*
* @return if the result indicates a success
* @since 3.4
*/
public boolean wasSuccess() {
return value;
}
/**
* Gets if the result indicates a failure
*
* @return if the result indicates a failure
* @since 3.4
*/
public boolean wasFailure() {
return !value;
}
// allows us to throw checked exceptions without declaring it, as #throwException throws a number of
// exception types.
private static void sneakyThrow(Throwable t) {
sneakyThrow0(t);
}
private static <T extends Throwable> void sneakyThrow0(Throwable t) throws T {
throw (T) t;
}
}
@@ -1,319 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import java.util.List;
import java.util.OptionalInt;
import javax.annotation.Nonnull;
/**
* An inheritable holder of permission data.
*/
public interface Group extends PermissionHolder {
/**
* Get the name of the group
*
* @return the name of the group
*/
@Nonnull
String getName();
/**
* Check to see if a group inherits another group directly
*
* @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(@Nonnull Group group);
/**
* Check to see if a group inherits another group directly
*
* @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 3.2
*/
boolean inheritsGroup(@Nonnull Group group, @Nonnull ContextSet contextSet);
/**
* Gets the weight of this group, if present.
*
* @return the group weight
* @since 2.17
*/
@Nonnull
OptionalInt getWeight();
/**
* Check to see if the group inherits a group on a specific server
*
* @param group The group to check membership of
* @param server The server to check on
* @return true if the group inherits the group on the server
* @throws NullPointerException if the group or server is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @throws IllegalArgumentException if the server is invalid
* @deprecated in favour of {@link #inheritsGroup(Group, ContextSet)}
*/
@Deprecated
boolean inheritsGroup(@Nonnull Group group, @Nonnull String server);
/**
* Check to see if the group inherits a group on a specific server and world
*
* @param group The group to check membership of
* @param server The server to check on
* @param world The world to check on
* @return true if the group inherits the group on the server and world
* @throws NullPointerException if the group, server or world is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @throws IllegalArgumentException if the server or world is invalid
* @deprecated in favour of {@link #inheritsGroup(Group, ContextSet)}
*/
@Deprecated
boolean inheritsGroup(@Nonnull Group group, @Nonnull String server, @Nonnull String world);
/**
* Make this group inherit another group
*
* @param group the group to be inherited
* @throws ObjectAlreadyHasException if the group already inherits the group
* @throws NullPointerException if the group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
*/
@Deprecated
void setInheritGroup(@Nonnull Group group) throws ObjectAlreadyHasException;
/**
* Make this group inherit another group on a specific server
*
* @param group the group to be inherited
* @param server The server to inherit the group on
* @throws ObjectAlreadyHasException if the group already inherits the group on that server
* @throws NullPointerException if the group or server is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @throws IllegalArgumentException if the server is invalid
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
*/
@Deprecated
void setInheritGroup(@Nonnull Group group, @Nonnull String server) throws ObjectAlreadyHasException;
/**
* Make this group inherit another group on a specific server and world
*
* @param group the group to be inherited
* @param server The server to inherit the group on
* @param world The world to inherit the group on
* @throws ObjectAlreadyHasException if the group already inherits the group on that server and world
* @throws NullPointerException if the group, server or world is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @throws IllegalArgumentException if the server or world is invalid
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
*/
@Deprecated
void setInheritGroup(@Nonnull Group group, @Nonnull String server, @Nonnull String world) throws ObjectAlreadyHasException;
/**
* Make this group inherit another group temporarily
*
* @param group the group to be inherited
* @param expireAt the unix time when the group should expire
* @throws ObjectAlreadyHasException if the group already inherits the group temporarily
* @throws NullPointerException if the group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @throws IllegalArgumentException if the expiry time is in the past
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
*/
@Deprecated
void setInheritGroup(@Nonnull Group group, long expireAt) throws ObjectAlreadyHasException;
/**
* Make this group inherit another group on a specific server temporarily
*
* @param group the group to be inherited
* @param server The server inherit add the group on
* @param expireAt when the group should expire
* @throws ObjectAlreadyHasException if the group already inherits the group on that server temporarily
* @throws NullPointerException if the group or server is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @throws IllegalArgumentException if the expiry time is in the past or the server is invalid
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
*/
@Deprecated
void setInheritGroup(@Nonnull Group group, @Nonnull String server, long expireAt) throws ObjectAlreadyHasException;
/**
* Make this group inherit another group on a specific server and world temporarily
*
* @param group the group to be inherited
* @param server The server to inherit the group on
* @param world The world to inherit the group on
* @param expireAt when the group should expire
* @throws ObjectAlreadyHasException if the group already inherits the group on that server and world temporarily
* @throws NullPointerException if the group, server or world is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @throws IllegalArgumentException if the expiry time is in the past or the server/world is invalid
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
*/
@Deprecated
void setInheritGroup(@Nonnull Group group, @Nonnull String server, @Nonnull String world, long expireAt) throws ObjectAlreadyHasException;
/**
* Remove a previously set inheritance rule
*
* @param group the group to uninherit
* @throws ObjectLacksException if the group does not already inherit the group
* @throws NullPointerException if the group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
*/
@Deprecated
void unsetInheritGroup(@Nonnull Group group) throws ObjectLacksException;
/**
* Remove a previously set inheritance rule
*
* @param group the group to uninherit
* @param temporary if the group being removed is temporary
* @throws ObjectLacksException if the group does not already inherit the group
* @throws NullPointerException if the group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
*/
@Deprecated
void unsetInheritGroup(@Nonnull Group group, boolean temporary) throws ObjectLacksException;
/**
* Remove a previously set inheritance rule on a specific server
*
* @param group the group to uninherit
* @param server The server to remove the group on
* @throws ObjectLacksException if the group does not already inherit the group on that server
* @throws NullPointerException if the group or server is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @throws IllegalArgumentException if the server is invalid
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
*/
@Deprecated
void unsetInheritGroup(@Nonnull Group group, @Nonnull String server) throws ObjectLacksException;
/**
* Remove a previously set inheritance rule on a specific server and world
*
* @param group the group to uninherit
* @param server The server to remove the group on
* @param world The world to remove the group on
* @throws ObjectLacksException if the group does not already inherit the group
* @throws NullPointerException if the group, server or world is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @throws IllegalArgumentException if the server or world is invalid
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
*/
@Deprecated
void unsetInheritGroup(@Nonnull Group group, @Nonnull String server, @Nonnull String world) throws ObjectLacksException;
/**
* Remove a previously set inheritance rule on a specific server
*
* @param group the group to uninherit
* @param server The server to remove the group on
* @param temporary if the group being removed is temporary
* @throws ObjectLacksException if the group does not already inherit the group
* @throws NullPointerException if the group or server is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @throws IllegalArgumentException if the expiry time is in the past or the server is invalid
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
*/
@Deprecated
void unsetInheritGroup(@Nonnull Group group, @Nonnull String server, boolean temporary) throws ObjectLacksException;
/**
* Remove a previously set inheritance rule on a specific server and world
*
* @param group the group to uninherit
* @param server The server to remove the group on
* @param world The world to remove the group on
* @param temporary if the group being removed was set temporarily
* @throws ObjectLacksException if the group does not already inherit the group
* @throws NullPointerException if the group, server or world is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @throws IllegalArgumentException if the expiry time is in the past or the server/world is invalid
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
*/
@Deprecated
void unsetInheritGroup(@Nonnull Group group, @Nonnull String server, @Nonnull String world, boolean temporary) throws ObjectLacksException;
/**
* Get a {@link List} of all of the groups the group inherits, on all servers
*
* @return a {@link List} of group names
* @deprecated in favour of just querying a users permissions
*/
@Deprecated
@Nonnull
List<String> getGroupNames();
/**
* Get a {@link List} of the groups the group inherits on a specific server
*
* @param server the server to check
* @return a {@link List} of group names
* @throws NullPointerException if the server is null
* @throws IllegalArgumentException if the server is invalid
* @deprecated in favour of just querying a users permissions
*/
@Deprecated
@Nonnull
List<String> getLocalGroups(@Nonnull String server);
/**
* Get a {@link List} of the groups the group inherits on a specific server and world
*
* @param server the server to check
* @param world the world to check
* @return a {@link List} of group names
* @throws NullPointerException if the server or world is null
* @throws IllegalArgumentException if the server or world is invalid
* @deprecated in favour of just querying a users permissions
*/
@Deprecated
@Nonnull
List<String> getLocalGroups(@Nonnull String server, @Nonnull String world);
}
@@ -1,116 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api;
import com.google.common.collect.Multimap;
import me.lucko.luckperms.api.context.ContextSet;
import java.util.Optional;
import java.util.OptionalLong;
import javax.annotation.Nonnull;
/**
* A relationship between a PermissionHolder and a permission
*
* @param <T> the identifier type of the holder
* @since 2.17
*/
public interface HeldPermission<T> {
/**
* Gets the holder of the permission
*
* @return the holder
*/
@Nonnull
T getHolder();
/**
* Gets the permission being held
*
* @return the permission
*/
@Nonnull
String getPermission();
/**
* Gets the value of the permission
*
* @return the value
*/
boolean getValue();
/**
* Gets the server where the permission is held
*
* @return the server
*/
@Nonnull
Optional<String> getServer();
/**
* Gets the world where the permission is held
*
* @return the world
*/
@Nonnull
Optional<String> getWorld();
/**
* Gets the time in unix time when the permission will expire
*
* @return the expiry time
*/
OptionalLong getExpiry();
/**
* Gets the context for the permission.
*
* @return the context
* @deprecated in favour of {@link #getContexts()}.
*/
@Nonnull
@Deprecated
Multimap<String, String> getContext();
/**
* Gets the extra context for the permission.
*
* @return the extra context
*/
ContextSet getContexts();
/**
* Converts this permission into a Node
*
* @return a Node copy of this permission
*/
@Nonnull
Node asNode();
}
@@ -1,216 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api;
import me.lucko.luckperms.api.data.DatastoreConfiguration;
import java.util.Map;
import javax.annotation.Nonnull;
/**
* Wrapper around parts of the LuckPerms configuration file
*/
public interface LPConfiguration {
/**
* Gets the name of this server
*
* @return the name of this server
*/
@Nonnull
String getServer();
/**
* Gets how often a sync task will run in minutes
*
* @return how often a sync task will run in minutes
*/
int getSyncTime();
/**
* 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();
/**
* 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();
/**
* Gets if the platform is applying global groups
*
* @return true if the platform is applying global groups
* @since 2.9
*/
boolean getApplyGlobalGroups();
/**
* Gets if the platform is applying global world groups
*
* @return true if the platform is applying global world groups
* @since 2.9
*/
boolean getApplyGlobalWorldGroups();
/**
* Gets the online mode setting
*
* @return the online mode setting
*/
boolean getOnlineMode();
/**
* Gets if LuckPerms is applying wildcard permissions
*
* @return if LuckPerms is applying wildcard permissions
*/
boolean getApplyWildcards();
/**
* Returns if LuckPerms is resolving and applying regex permissions
*
* @return if LuckPerms is resolving and applying regex permissions
*/
boolean getApplyRegex();
/**
* Gets if LuckPerms is expanding shorthand permissions
*
* @return if LuckPerms is expanding shorthand permissions
*/
boolean getApplyShorthand();
/**
* Gets if LuckPerms will send notifications to users when permissions are modified
*
* @return if LuckPerms will send notifications to users when permissions are modified
* @since 2.7
*/
boolean getLogNotify();
/**
* Gets if the vanilla op system is enabled
*
* @return true if the vanilla op system is enabled
* @since 2.8
*/
boolean getEnableOps();
/**
* Gets if opped players are allowed to use LuckPerms commands
*
* @return true if opped players are allowed to use LuckPerms commands
* @since 2.8
*/
boolean getCommandsAllowOp();
/**
* Gets if auto op is enabled
*
* @return true if auto op is enabled
* @since 2.9
*/
boolean getAutoOp();
/**
* Gets the name of the server used within Vault operations
*
* @return the name of the server used within Vault operations
* @since 2.7
*/
@Nonnull
String getVaultServer();
/**
* Gets if global permissions should be considered when retrieving meta or player groups
*
* @return true if global permissions should be considered when retrieving meta or player groups
* @since 2.7
*/
boolean getVaultIncludeGlobal();
/**
* Gets the values set for data storage in the configuration
*
* @return the values set for data storage in the configuration
*/
@Nonnull
DatastoreConfiguration getDatastoreConfig();
/**
* Gets the storage method string from the configuration
*
* @return the storage method string from the configuration
*/
@Nonnull
String getStorageMethod();
/**
* Gets true if split storage is enabled
*
* @return true if split storage is enabled
* @since 2.7
*/
boolean getSplitStorage();
/**
* 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 parameter 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,230 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.UUID;
import javax.annotation.Nonnull;
/**
* Represents the internal LuckPerms log.
*
* <p>The returned instance provides a copy of the data at the time of retrieval.</p>
*
* <p>Any changes made to log entries will only apply to this instance of the log.
* You can add to the log using the {@link Storage}, and then request an updated copy.</p>
*
* <p>All methods are thread safe, and return immutable & thread safe collections.</p>
*/
public interface Log {
/**
* Get the content of the log
*
* @return a {@link SortedSet} of all of the {@link LogEntry} objects in this {@link Log}
*/
@Nonnull
SortedSet<LogEntry> getContent();
/**
* Get the content of the log
*
* @return all content in this log
*/
@Nonnull
SortedSet<LogEntry> getRecent();
/**
* Gets the recent content separated by page
*
* @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()}
*/
@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
*/
@Nonnull
SortedSet<LogEntry> getRecent(@Nonnull UUID actor);
/**
* 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)}
*/
@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(@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
*/
@Nonnull
SortedSet<LogEntry> getUserHistory(@Nonnull UUID uuid);
/**
* 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)}
*/
@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(@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
*/
@Nonnull
SortedSet<LogEntry> getGroupHistory(@Nonnull String name);
/**
* 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)}
*/
@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(@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
*/
@Nonnull
SortedSet<LogEntry> getTrackHistory(@Nonnull String name);
/**
* Gets the log content for a given track, separated by page
*
* @param pageNo the page number
* @param name the name of the acted track to filter by
* @return the page content
* @throws IllegalArgumentException if the pageNo is less than 1
* @throws IllegalStateException if the log doesn't contain enough entries to populate the page. See {@link #getTrackHistoryMaxPages(String)}
*/
@Nonnull
SortedMap<Integer, LogEntry> getTrackHistory(int pageNo, @Nonnull String name);
/**
* Gets the max page number for the track history pages.
*
* @param name the name to filter by
* @return the max page number allowed in the {@link #getTrackHistory(int, String)} method
*/
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
*/
@Nonnull
SortedSet<LogEntry> getSearch(@Nonnull String query);
/**
* Gets the log content for a given search query, separated by page
*
* @param pageNo the page number
* @param query the query 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 #getSearchMaxPages(String)}}
*/
@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(@Nonnull String query);
}
@@ -1,554 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api;
import com.google.common.base.Preconditions;
import java.util.Comparator;
import java.util.UUID;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* A single entry in the log.
*/
public class LogEntry implements Comparable<LogEntry> {
/**
* Compares two LogEntries
*
* @since 3.3
*/
public static final Comparator<LogEntry> COMPARATOR = Comparator
.comparingLong(LogEntry::getTimestamp)
.thenComparing(LogEntry::getActor)
.thenComparing(LogEntry::getActorName, String.CASE_INSENSITIVE_ORDER)
.thenComparing(LogEntry::getEntryType)
.thenComparing(e -> {
UUID u = e.getActed();
return u == null ? "" : u.toString();
})
.thenComparing(LogEntry::getActedName, String.CASE_INSENSITIVE_ORDER)
.thenComparing(LogEntry::getAction);
/**
* Compares two LogEntries in reverse order
*
* @since 3.3
* @see #COMPARATOR
*/
public static final Comparator<LogEntry> REVERSE_ORDER = COMPARATOR.reversed();
private static final String FORMAT = "&8(&e%s&8) [&a%s&8] (&b%s&8) &7--> &f%s";
/**
* Creates a new LogEntry builder
*
* @return a new builder
*/
@Nonnull
public static LogEntryBuilder builder() {
return new LogEntryBuilder();
}
/**
* The time when the log event occurred in unix seconds.
*/
private long timestamp;
/**
* The player who enacted the change
*/
@Nonnull
private UUID actor;
/**
* The name of the player who enacted the change
*/
@Nonnull
private String actorName;
/**
* The entry type.
*/
@Nonnull
private Type type;
/**
* The user who was acted upon
*/
@Nullable
private UUID acted;
/**
* The name of the object who was acted upon
*/
@Nonnull
private String actedName;
/**
* A description of the action
*/
@Nonnull
private String action;
/**
* Creates a new log entry
*
* @param timestamp the timestamp
* @param actor the actor
* @param actorName the actorName
* @param type the type
* @param acted the acted object, or null
* @param actedName the acted object name
* @param action the action
* @since 3.3
*/
public LogEntry(long timestamp, @Nonnull UUID actor, @Nonnull String actorName, @Nonnull Type type, @Nullable UUID acted, @Nonnull String actedName, @Nonnull String action) {
Preconditions.checkNotNull(actor, "actor");
Preconditions.checkNotNull(actorName, "actorName");
Preconditions.checkNotNull(type, "type");
Preconditions.checkNotNull(actedName, "actedName");
Preconditions.checkNotNull(action, "action");
this.timestamp = timestamp;
this.actor = actor;
this.actorName = actorName;
this.type = type;
this.acted = acted;
this.actedName = actedName;
this.action = action;
}
/**
* Creates a new log entry
*
* @param timestamp the timestamp
* @param actor the actor
* @param actorName the actorName
* @param type the type code
* @param acted the acted object, or null
* @param actedName the acted object name
* @param action the action
*/
public LogEntry(long timestamp, @Nonnull UUID actor, @Nonnull String actorName, char type, @Nullable UUID acted, @Nonnull String actedName, @Nonnull String action) {
Preconditions.checkNotNull(actor, "actor");
Preconditions.checkNotNull(actorName, "actorName");
Preconditions.checkNotNull(actedName, "actedName");
Preconditions.checkNotNull(action, "action");
this.timestamp = timestamp;
this.actor = actor;
this.actorName = actorName;
this.type = Type.valueOf(type);
this.acted = acted;
this.actedName = actedName;
this.action = action;
}
/**
* Creates a new LogEntry and copies the values from another
*
* @param other the entry to copy values from
* @since 3.3
*/
protected LogEntry(@Nonnull LogEntry other) {
this.timestamp = other.timestamp;
this.actor = other.actor;
this.actorName = other.actorName;
this.type = other.type;
this.acted = other.acted;
this.actedName = other.actedName;
this.action = other.action;
}
protected LogEntry() {
this.timestamp = 0L;
this.actor = null;
this.actorName = null;
this.type = null;
this.acted = null;
this.actedName = null;
this.action = null;
}
@Override
public int compareTo(@Nonnull LogEntry other) {
Preconditions.checkNotNull(other, "other");
return COMPARATOR.compare(this, other);
}
/**
* Creates a copy of this log entry
*
* @return a copy of this log entry
* @since 3.3
*/
public LogEntry copy() {
return new LogEntry(this);
}
public long getTimestamp() {
return timestamp;
}
void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
@Nonnull
public UUID getActor() {
return Preconditions.checkNotNull(actor, "actor");
}
void setActor(@Nonnull UUID actor) {
this.actor = Preconditions.checkNotNull(actor, "actor");
}
@Nonnull
public String getActorName() {
return Preconditions.checkNotNull(actorName, "actorName");
}
void setActorName(@Nonnull String actorName) {
this.actorName = Preconditions.checkNotNull(actorName, "actorName");
}
/**
* Gets the type of this entry
*
* @return the type of this entry
* @since 3.3
*/
@Nonnull
public Type getEntryType() {
return Preconditions.checkNotNull(type, "type");
}
/**
* Sets the type of this entry
*
* @param type the new type
* @since 3.3
*/
public void setEntryType(@Nonnull Type type) {
this.type = Preconditions.checkNotNull(type, "type");
}
/**
* Gets the code representing this entry type
*
* @return the code representing this entry type
* @deprecated in favour of {@link #getEntryType()}
*/
@Deprecated
public char getType() {
return getEntryType().getCode();
}
/**
* Sets the type of this entry by code
*
* @param code the code type
* @deprecated in favour of {@link #setEntryType(Type)}
*/
@Deprecated
void setType(char code) {
setEntryType(Type.valueOf(code));
}
@Nullable
public UUID getActed() {
return acted;
}
void setActed(@Nullable UUID acted) {
this.acted = acted;
}
@Nonnull
public String getActedName() {
return Preconditions.checkNotNull(actedName, "actedName");
}
void setActedName(@Nonnull String actedName) {
this.actedName = Preconditions.checkNotNull(actedName, "actedName");
}
@Nonnull
public String getAction() {
return Preconditions.checkNotNull(action, "action");
}
void setAction(@Nonnull String action) {
this.action = Preconditions.checkNotNull(action, "action");
}
public boolean matchesSearch(@Nonnull String query) {
query = Preconditions.checkNotNull(query, "query").toLowerCase();
return actorName.toLowerCase().contains(query) ||
actedName.toLowerCase().contains(query) ||
action.toLowerCase().contains(query);
}
@Nonnull
public String getFormatted() {
return String.format(FORMAT,
String.valueOf(actorName).equals("null") ? actor.toString() : actorName,
Character.toString(type.getCode()),
String.valueOf(actedName).equals("null") && acted != null ? acted.toString() : actedName,
action
);
}
@Override
public String toString() {
return "LogEntry(" +
"timestamp=" + this.getTimestamp() + ", " +
"actor=" + this.getActor() + ", " +
"actorName=" + this.getActorName() + ", " +
"type=" + this.getEntryType() + ", " +
"acted=" + this.getActed() + ", " +
"actedName=" + this.getActedName() + ", " +
"action=" + this.getAction() + ")";
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof LogEntry)) return false;
final LogEntry other = (LogEntry) o;
return this.getTimestamp() == other.getTimestamp() &&
this.getActor().equals(other.getActor()) &&
this.getActorName().equals(other.getActorName()) &&
this.getEntryType() == other.getEntryType() &&
(this.getActed() == null ? other.getActed() == null : this.getActed().equals(other.getActed())) &&
this.getActedName().equals(other.getActedName()) &&
this.getAction().equals(other.getAction());
}
@Override
public int hashCode() {
final int PRIME = 59;
int result = 1;
result = result * PRIME + (int) (this.getTimestamp() >>> 32 ^ this.getTimestamp());
result = result * PRIME + this.getActor().hashCode();
result = result * PRIME + this.getActorName().hashCode();
result = result * PRIME + this.getEntryType().hashCode();
result = result * PRIME + (this.getActed() == null ? 43 : this.getActed().hashCode());
result = result * PRIME + this.getActedName().hashCode();
result = result * PRIME + this.getAction().hashCode();
return result;
}
/**
* The LogEntry type
* @since 3.3
*/
public enum Type {
USER('U'),
GROUP('G'),
TRACK('T');
private final char code;
Type(char code) {
this.code = code;
}
public char getCode() {
return this.code;
}
public static Type valueOf(char code) {
switch (code) {
case 'U':
case 'u':
return USER;
case 'G':
case 'g':
return GROUP;
case 'T':
case 't':
return TRACK;
default:
throw new IllegalArgumentException("Unknown code: " + code);
}
}
}
/**
* Builds LogEntry instances
*/
public static class LogEntryBuilder extends AbstractLogEntryBuilder<LogEntry, LogEntry.LogEntryBuilder> {
@Override
protected LogEntry createEmptyLog() {
return new LogEntry();
}
@Override
protected LogEntryBuilder getThisBuilder() {
return this;
}
}
/**
* An abstract log entry builder
*
* @param <T> the log type
* @param <B> the log builder type
*/
public static abstract class AbstractLogEntryBuilder<T extends LogEntry, B extends AbstractLogEntryBuilder<T, B>> {
private T obj;
private B thisObj;
public AbstractLogEntryBuilder() {
obj = createEmptyLog();
thisObj = getThisBuilder();
}
protected abstract T createEmptyLog();
protected abstract B getThisBuilder();
public long getTimestamp() {
return obj.getTimestamp();
}
@Nonnull
public UUID getActor() {
return obj.getActor();
}
@Nonnull
public String getActorName() {
return obj.getActorName();
}
@Nonnull
public Type getEntryType() {
return obj.getEntryType();
}
@Nonnull
@Deprecated
public char getType() {
return obj.getType();
}
@Nullable
public UUID getActed() {
return obj.getActed();
}
@Nonnull
public String getActedName() {
return obj.getActedName();
}
@Nonnull
public String getAction() {
return obj.getAction();
}
@Nonnull
public B timestamp(long timestamp) {
obj.setTimestamp(timestamp);
return thisObj;
}
@Nonnull
public B actor(@Nonnull UUID actor) {
obj.setActor(actor);
return thisObj;
}
@Nonnull
public B actorName(@Nonnull String actorName) {
obj.setActorName(actorName);
return thisObj;
}
@Nonnull
public B entryType(@Nonnull Type type) {
obj.setEntryType(type);
return thisObj;
}
@Nonnull
@Deprecated
public B type(char type) {
obj.setType(type);
return thisObj;
}
@Nonnull
public B acted(@Nullable UUID acted) {
obj.setActed(acted);
return thisObj;
}
@Nonnull
public B actedName(@Nonnull String actedName) {
obj.setActedName(actedName);
return thisObj;
}
@Nonnull
public B action(@Nonnull String action) {
obj.setAction(action);
return thisObj;
}
@Nonnull
public T build() {
Preconditions.checkNotNull(getActor(), "actor");
Preconditions.checkNotNull(getActorName(), "actorName");
Preconditions.checkNotNull(getEntryType(), "type");
Preconditions.checkNotNull(getActedName(), "actedName");
Preconditions.checkNotNull(getAction(), "action");
return obj;
}
@Override
public String toString() {
return "LogEntry.LogEntryBuilder(" +
"timestamp=" + this.getTimestamp() + ", " +
"actor=" + this.getActor() + ", " +
"actorName=" + this.getActorName() + ", " +
"type=" + this.getEntryType() + ", " +
"acted=" + this.getActed() + ", " +
"actedName=" + this.getActedName() + ", " +
"action=" + this.getAction() + ")";
}
}
}
@@ -1,365 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api;
import me.lucko.luckperms.LuckPerms;
import me.lucko.luckperms.api.context.ContextCalculator;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.event.EventBus;
import me.lucko.luckperms.api.metastacking.MetaStackFactory;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* 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
*/
void runUpdateTask();
/**
* Gets the API version
*
* @return the version of the API running on the platform
* @since 2.6
*/
double getApiVersion();
/**
* Gets the plugin version
*
* @return the version of the plugin running on the platform
*/
@Nonnull
String getVersion();
/**
* Gets the platform LuckPerms is running on
*
* @return the platform LuckPerms is running on
* @since 2.7
*/
@Nonnull
PlatformType getPlatformType();
/**
* Gets the event bus, used for subscribing to events
*
* @return the event bus
* @since 3.0
*/
@Nonnull
EventBus getEventBus();
/**
* Gets a wrapped {@link LPConfiguration} instance, with read only access
*
* @return a configuration instance
*/
@Nonnull
LPConfiguration getConfiguration();
/**
* Gets a wrapped {@link Storage} instance.
*
* @return a storage instance
* @since 2.14
*/
@Nonnull
Storage getStorage();
/**
* Gets the messaging service in use on the platform, if present.
*
* @return an optional that may contain a messaging service instance.
*/
@Nonnull
Optional<MessagingService> getMessagingService();
/**
* Gets the {@link Logger} wrapping used by the platform
*
* @return the logger instance
*/
@Nonnull
Logger getLogger();
/**
* Gets a wrapped {@link UuidCache} instance, providing read access to the LuckPerms internal uuid caching system
*
* @return a uuid cache instance
*/
@Nonnull
UuidCache getUuidCache();
/**
* Gets a wrapped user object from the user storage
*
* @param uuid the uuid of the user to get
* @return a {@link User} object, if one matching the uuid is loaded, or null if not
* @throws NullPointerException if the uuid is null
*/
@Nullable
User getUser(@Nonnull UUID uuid);
/**
* Gets a wrapped user object from the user storage.
*
* <p>This method does not return null, unlike {@link #getUser(UUID)}</p>
*
* @param uuid the uuid of the user to get
* @return an optional {@link User} object
* @throws NullPointerException if the uuid is null
*/
@Nonnull
Optional<User> getUserSafe(@Nonnull UUID uuid);
/**
* Gets a wrapped user object from the user storage
*
* @param name the username of the user to get
* @return a {@link User} object, if one matching the uuid is loaded, or null if not
* @throws NullPointerException if the name is null
*/
@Nullable
User getUser(@Nonnull String name);
/**
* Gets a wrapped user object from the user storage.
*
* <p>This method does not return null, unlike {@link #getUser(String)}</p>
*
* @param name the username of the user to get
* @return an optional {@link User} object
* @throws NullPointerException if the name is null
*/
@Nonnull
Optional<User> getUserSafe(@Nonnull String name);
/**
* Gets a set of all loaded users.
*
* @return a {@link Set} of {@link User} objects
*/
@Nonnull
Set<User> getUsers();
/**
* 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 isUserLoaded(@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
* @since 2.6
*/
void cleanupUser(@Nonnull User user);
/**
* Gets a wrapped group object from the group storage
*
* @param name the name of the group to get
* @return a {@link Group} object, if one matching the name exists, or null if not
* @throws NullPointerException if the name is null
*/
@Nullable
Group getGroup(@Nonnull String name);
/**
* Gets a wrapped group object from the group storage.
*
* <p>This method does not return null, unlike {@link #getGroup}</p>
*
* @param name the name of the group to get
* @return an optional {@link Group} object
* @throws NullPointerException if the name is null
*/
@Nonnull
Optional<Group> getGroupSafe(@Nonnull String name);
/**
* Gets a set of all loaded groups.
*
* @return a {@link Set} of {@link Group} objects
*/
@Nonnull
Set<Group> getGroups();
/**
* 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 isGroupLoaded(@Nonnull String 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
* @throws NullPointerException if the name is null
*/
@Nullable
Track getTrack(@Nonnull String name);
/**
* Gets a wrapped track object from the track storage.
*
* <p>This method does not return null, unlike {@link #getTrack}</p>
*
* @param name the name of the track to get
* @return an optional {@link Track} object
* @throws NullPointerException if the name is null
*/
@Nonnull
Optional<Track> getTrackSafe(@Nonnull String name);
/**
* Gets a set of all loaded tracks.
*
* @return a {@link Set} of {@link Track} objects
*/
@Nonnull
Set<Track> getTracks();
/**
* 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 isTrackLoaded(@Nonnull String name);
/**
* Gets the node factory instance for the platform
*
* @return the node factory
*/
@Nonnull
NodeFactory getNodeFactory();
/**
* Gets the MetaStackFactory, used for creating MetaStacks.
*
* @return the meta stack factory
* @since 3.2
*/
@Nonnull
MetaStackFactory getMetaStackFactory();
/**
* Returns a permission builder instance
*
* @param permission the main permission node to build
* @return a {@link Node.Builder} instance
* @throws IllegalArgumentException if the permission is invalid
* @throws NullPointerException if the permission is null
* @since 2.6
*/
@Nonnull
Node.Builder buildNode(@Nonnull String permission) throws IllegalArgumentException;
/**
* 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.
* @throws ClassCastException if the type is not the player class of the platform.
*/
void registerContextCalculator(@Nonnull ContextCalculator<?> contextCalculator);
/**
* Gets a calculated context instance for the user using the rules of the platform.
*
* <p> These values are calculated using the options in the configuration, and the provided calculators.
*
* @param user the user to get contexts for
* @return an optional containing contexts. Will return empty if the user is not online.
*/
@Nonnull
Optional<Contexts> getContextForUser(@Nonnull User user);
/**
* Gets set of contexts applicable to a 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 2.17
*/
@Nonnull
ContextSet getContextForPlayer(@Nonnull Object 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
Contexts getContextsForPlayer(@Nonnull Object player);
/**
* Gets the unique players which have connected to the server since it started.
*
* @return the unique connections
* @since 3.3
*/
@Nonnull
Set<UUID> getUniqueConnections();
/**
* Gets the time when the plugin first started in milliseconds.
*
* @return the enable time
* @since 3.3
*/
long getStartTime();
}
@@ -1,287 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api;
import me.lucko.luckperms.LuckPerms;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* A collection of utilities to help retrieve meta values for {@link PermissionHolder}s
*
* @since 2.7
* @deprecated in favour of using {@link NodeFactory#makeMetaNode(String, String)} or {@link me.lucko.luckperms.api.caching.MetaData}.
*/
@Deprecated
public class MetaUtils {
private static final String[] DELIMS = new String[]{".", "/", "-", "$"};
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, DELIMS);
}
/**
* 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, DELIMS);
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.getValuePrimitive() || !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.getValuePrimitive()) 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() {
}
}
@@ -1,482 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api;
import me.lucko.luckperms.api.context.ContextSet;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Represents a permission node.
*
* <p>All implementations of this interface must be immutable.</p>
*
* <p>Use the {@link NodeFactory} to obtain and construct instances.</p>
*
* @since 2.6
*/
public interface Node extends Map.Entry<String, Boolean> {
/**
* Gets the permission string
*
* @return the actual permission node
*/
@Nonnull
String getPermission();
/**
* Gets the value.
*
* <p>A negated node would return a value of <code>false</code>.</p>
*
* @return the permission's value
*/
@Override
@Nonnull
default Boolean getValue() {
return getValuePrimitive();
}
/**
* Gets the value.
*
* <p>A negated node would return a value of <code>false</code>.</p>
*
* @return the permission's value
*/
boolean getValuePrimitive();
/**
* Gets the value of this node as a {@link Tristate}
*
* @return the value of this node as a Tristate
*/
@Nonnull
default Tristate getTristate() {
return Tristate.fromBoolean(getValuePrimitive());
}
/**
* Gets if the node is negated
*
* @return true if the node is negated
*/
default boolean isNegated() {
return !getValuePrimitive();
}
/**
* 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
*
* @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
*
* @return an {@link Optional} containing the world, if one is defined
*/
@Nonnull
Optional<String> getWorld();
/**
* Gets if this node is server specific
*
* @return true if this node is server specific
*/
boolean isServerSpecific();
/**
* Gets if this node is server specific
*
* @return true if this node is server specific
*/
boolean isWorldSpecific();
/**
* 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
*/
boolean appliesGlobally();
/**
* 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
*/
boolean hasSpecificContext();
/**
* Gets if this node is able to apply in the given context
*
* @param includeGlobal if global server values should apply
* @param includeGlobalWorld if global world values should apply
* @param server the server being checked against, or null
* @param world the world being checked against, or null
* @param context the context being checked against, or null
* @param applyRegex if regex should be applied
* @return true if the node should apply, otherwise false
* @since 3.1
*/
boolean shouldApply(boolean includeGlobal, boolean includeGlobalWorld, @Nullable String server, @Nullable String world, @Nullable ContextSet context, boolean applyRegex);
/**
* Gets if this node should apply on a specific server
*
* @param server the name of the server
* @param includeGlobal if global permissions should apply
* @param applyRegex if regex should be applied
* @return true if the node should apply
*/
boolean shouldApplyOnServer(@Nullable String server, boolean includeGlobal, boolean applyRegex);
/**
* Gets if this node should apply on a specific world
*
* @param world the name of the world
* @param includeGlobal if global permissions should apply
* @param applyRegex if regex should be applied
* @return true if the node should apply
*/
boolean shouldApplyOnWorld(@Nullable String world, boolean includeGlobal, boolean applyRegex);
/**
* Gets if this node should apply in the given context
*
* @param context the context key value pairs
* @param worldAndServer if world and server contexts should be checked
* @return true if the node should apply
* @since 2.13
*/
boolean shouldApplyWithContext(@Nonnull ContextSet context, boolean worldAndServer);
/**
* Gets if this node should apply in the given context
*
* @param context the context key value pairs
* @return true if the node should apply
* @since 2.13
*/
boolean shouldApplyWithContext(@Nonnull ContextSet context);
/**
* Similar to {@link #shouldApplyOnServer(String, boolean, boolean)}, except this method accepts a List
*
* @param servers the list of servers
* @param includeGlobal if global permissions should apply
* @return true if the node should apply
*/
boolean shouldApplyOnAnyServers(@Nonnull List<String> servers, boolean includeGlobal);
/**
* Similar to {@link #shouldApplyOnWorld(String, boolean, boolean)}, except this method accepts a List
*
* @param worlds the list of world
* @param includeGlobal if global permissions should apply
* @return true if the node should apply
*/
boolean shouldApplyOnAnyWorlds(@Nonnull List<String> worlds, boolean includeGlobal);
/**
* Resolves a list of wildcards that match this node
*
* @param possibleNodes a list of possible permission nodes
* @return a list of permissions that match this wildcard
* @deprecated as this is no longer used internally to resolve wildcards
*/
@Nonnull
@Deprecated
List<String> resolveWildcard(@Nonnull List<String> possibleNodes);
/**
* Resolves any shorthand parts of this node and returns the full list
*
* @return a list of full nodes
*/
@Nonnull
List<String> resolveShorthand();
/**
* Gets if this node will expire in the future
*
* @return true if this node will expire in the future
*/
boolean isTemporary();
/**
* Gets if this node will not expire
*
* @return true if this node will not expire
*/
default boolean isPermanent() {
return !isTemporary();
}
/**
* Gets a unix timestamp in seconds when this node will expire
*
* @return the time in Unix time when this node will expire
* @throws IllegalStateException if the node is not temporary
*/
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
*/
@Nonnull
Date getExpiry() throws IllegalStateException;
/**
* Gets the number of seconds until this permission will expire
*
* @return the number of seconds until this permission will expire
* @throws IllegalStateException if the node is not temporary
*/
long getSecondsTilExpiry() throws IllegalStateException;
/**
* Gets if the node has expired.
*
* <p>This also returns false if the node is not temporary.</p>
*
* @return true if this node has expired
*/
boolean hasExpired();
/**
* Gets the extra contexts required for this node to apply
*
* @return the extra contexts required for this node to apply
* @since 2.13
*/
@Nonnull
ContextSet getContexts();
/**
* The same as {@link #getContexts()}, but also includes values for "server" and "world" keys if present.
*
* @return the full contexts required for this node to apply
* @since 3.1
*/
@Nonnull
ContextSet getFullContexts();
/**
* Converts this node into a serialized form
*
* @return a serialized node string
* @deprecated because this serialized form is no longer used by the implementation.
*/
@Deprecated
@Nonnull
String toSerializedNode();
/**
* Gets if this is a group node
*
* @return true if this is a group node
*/
boolean isGroupNode();
/**
* Gets the name of the group, if this is a group node.
*
* @return the name of the group
* @throws IllegalStateException if this is not a group node. See {@link #isGroupNode()}
*/
@Nonnull
String getGroupName() throws IllegalStateException;
/**
* Gets if this node is a wildcard node
*
* @return true if this node is a wildcard node
*/
boolean isWildcard();
/**
* Gets the level of this wildcard, higher is more specific
*
* @return the wildcard level
* @throws IllegalStateException if this is not a wildcard
*/
int getWildcardLevel() throws IllegalStateException;
/**
* Gets if this node is a meta node
*
* @return true if this node is a meta node
*/
boolean isMeta();
/**
* Gets the meta value from this node
*
* @return the meta value
* @throws IllegalStateException if this node is not a meta node
*/
@Nonnull
Map.Entry<String, String> getMeta() throws IllegalStateException;
/**
* Gets if this node is a prefix node
*
* @return true if this node is a prefix node
*/
boolean isPrefix();
/**
* Gets the prefix value from this node
*
* @return the prefix value
* @throws IllegalStateException if this node is a not a prefix node
*/
@Nonnull
Map.Entry<Integer, String> getPrefix() throws IllegalStateException;
/**
* Gets if this node is a suffix node
*
* @return true if this node is a suffix node
*/
boolean isSuffix();
/**
* Gets the suffix value from this node
*
* @return the suffix value
* @throws IllegalStateException if this node is a not a suffix node
*/
@Nonnull
Map.Entry<Integer, String> getSuffix() throws IllegalStateException;
/**
* Checks 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
*/
@Override
boolean equals(Object obj);
/**
* 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
*/
boolean equalsIgnoringValue(@Nonnull Node other);
/**
* 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
*/
boolean almostEquals(@Nonnull Node other);
/**
* 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
*/
boolean equalsIgnoringValueOrTemp(@Nonnull Node other);
/**
* Builds a Node instance
*/
interface Builder {
@Nonnull
Builder setNegated(boolean negated);
@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.
*/
@Nonnull
Builder setOverride(boolean override);
@Nonnull
Builder setExpiry(long expireAt);
@Nonnull
Builder setWorld(@Nonnull String world);
@Nonnull
Builder setServer(@Nonnull String server) throws IllegalArgumentException;
@Nonnull
Builder withExtraContext(@Nonnull String key, @Nonnull String value);
@Nonnull
Builder withExtraContext(@Nonnull Map<String, String> map);
@Nonnull
Builder withExtraContext(@Nonnull Set<Map.Entry<String, String>> context);
@Nonnull
Builder withExtraContext(@Nonnull Map.Entry<String, String> entry);
@Nonnull
Builder withExtraContext(@Nonnull ContextSet set);
@Nonnull
Node build();
}
}
@@ -1,146 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api;
import javax.annotation.Nonnull;
/**
* Assists with constructing {@link Node} instances.
*
* @since 2.17
*/
public interface NodeFactory {
/**
* Creates a new node builder from a given base permission string
*
* @param permission the permission
* @return a node builder instance
* @throws NullPointerException if the permission is null
*/
@Nonnull
Node.Builder newBuilder(@Nonnull String permission);
/**
* Creates a node builder instance from an existing node
*
* @param other the other node
* @return a node builder instance
* @throws NullPointerException if the other node is null
*/
@Nonnull
Node.Builder newBuilderFromExisting(@Nonnull Node other);
/**
* Creates a node builder from a group
*
* @param group the group
* @return a node builder instance
* @throws NullPointerException if the group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @since 3.1
*/
@Nonnull
Node.Builder makeGroupNode(@Nonnull Group group);
/**
* Creates a node builder from a key value pair
*
* @param key the key
* @param value the value
* @return a node builder instance
* @throws NullPointerException if the key or value is null
*/
@Nonnull
Node.Builder makeMetaNode(@Nonnull String key, @Nonnull String value);
/**
* Creates a node builder for the given chat meta 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
*
* @param priority the priority
* @param prefix the prefix string
* @return a node builder instance
* @throws NullPointerException if the prefix is null
*/
@Nonnull
Node.Builder makePrefixNode(int priority, @Nonnull String prefix);
/**
* Creates a node builder from a prefix string and priority
*
* @param priority the priority
* @param suffix the suffix string
* @return a node builder instance
* @throws NullPointerException if the suffix is null
*/
@Nonnull
Node.Builder makeSuffixNode(int priority, @Nonnull String suffix);
/**
* Creates a node from a serialised node string
*
* <p>This format is what was previously used in YAML/JSON storage files.</p>
*
* @param serialisedPermission the serialised permission string
* @param value the value of the node
* @return a node instance
* @throws NullPointerException if the permission is null
* @deprecated since this format isn't used internally for permissions anymore
* @see Node#toSerializedNode()
*/
@Deprecated
@Nonnull
Node fromSerialisedNode(@Nonnull String serialisedPermission, boolean value);
/**
* Creates a node builder from a serialised node string
*
* @param serialisedPermission the serialised permission string
* @param value the value of the node
* @return a node builder instance
* @throws NullPointerException if the permission is null
* @deprecated since this format isn't used internally for permissions anymore
* @see Node#toSerializedNode()
*/
@Deprecated
@Nonnull
Node.Builder newBuilderFromSerialisedNode(@Nonnull String serialisedPermission, boolean value);
}
@@ -1,875 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Multimap;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.function.Predicate;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* An object which holds permissions.
*
* <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.
*
* <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 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.
*
* <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();
/**
* Similar to {@link #getPermissions()}, except without enduring permissions.
*
* <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
*
* <p>Unlike {@link #getAllNodesFiltered(Contexts)}, this method will not filter individual nodes. The context is only
* used to determine which groups should apply.</p>
*
* <p>Nodes are sorted into priority order.</p>
*
* @param contexts the context for the lookup
* @return a mutable sorted set of permissions
* @throws NullPointerException if the context is null
* @since 2.11
*/
@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.
*
* <p>Unlike {@link #getAllNodes(Contexts)}, this method WILL filter individual nodes, and only return ones that fully
* meet the context provided.</p>
*
* @param contexts the context for the lookup
* @return a mutable set of permissions
* @throws NullPointerException if the context is null
* @since 2.11
*/
@Nonnull
Set<LocalizedNode> getAllNodesFiltered(@Nonnull Contexts contexts);
/**
* Converts the output of {@link #getAllNodesFiltered(Contexts)}, and expands shorthand permissions.
*
* @param contexts the context for the lookup
* @param lowerCase if the keys should be made lowercase whilst being exported
* @return a mutable map of permissions
*/
@Nonnull
Map<String, Boolean> exportNodes(@Nonnull Contexts contexts, boolean lowerCase);
/**
* Removes temporary permissions that have expired
*/
void auditTemporaryPermissions();
/**
* Checks to see if the object has a certain permission
*
* @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
*/
@Nonnull
Tristate hasPermission(@Nonnull Node node);
/**
* Checks to see if the object has a certain permission
*
* @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
*/
@Nonnull
Tristate hasTransientPermission(@Nonnull Node node);
/**
* Checks to see if the object inherits a certain permission
*
* @param node the node to check for
* @return a Tristate for the holders inheritance status for the node
* @throws NullPointerException if the node is null
* @since 2.6
*/
@Nonnull
Tristate inheritsPermission(@Nonnull Node node);
/**
* Sets a permission for the object
*
* @param node The node to be set
* @throws ObjectAlreadyHasException if the object already has the permission
* @throws NullPointerException if the node is null
* @since 2.6
*/
void setPermission(@Nonnull Node node) throws ObjectAlreadyHasException;
/**
* Sets a permission for the object
*
* @param node The node to be set
* @throws NullPointerException if the node is null
* @return the result of the operation
* @since 3.1
*/
@Nonnull
DataMutateResult setPermissionUnchecked(@Nonnull Node node);
/**
* 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 ObjectAlreadyHasException if the object already has the permission
* @throws NullPointerException if the node is null
* @since 2.6
*/
void setTransientPermission(@Nonnull Node node) throws ObjectAlreadyHasException;
/**
* Sets a transient permission for the object
*
* <p>A transient node is a permission that does not persist.
* Whenever a user logs out of the server, or the server restarts, this permission will disappear.
* It is never saved to the datastore, and therefore will not apply on other servers.</p>
*
* <p>This is useful if you want to temporarily set a permission for a user while they're online, but don't
* want it to persist, and have to worry about removing it when they log out.</p>
*
* <p>For unsetting a transient permission, see {@link #unsetTransientPermission(Node)}</p>
*
* @param node The node to be set
* @throws NullPointerException if the node is null
* @return the result of the operation
* @since 3.1
*/
@Nonnull
DataMutateResult setTransientPermissionUnchecked(@Nonnull Node node);
/**
* Unsets a permission for the object
*
* @param node The node to be unset
* @throws ObjectLacksException if the node wasn't already set
* @throws NullPointerException if the node is null
* @since 2.6
*/
void unsetPermission(@Nonnull Node node) throws ObjectLacksException;
/**
* Unsets a permission for the object
*
* @param node The node to be unset
* @throws NullPointerException if the node is null
* @return the result of the operation
* @since 3.1
*/
@Nonnull
DataMutateResult unsetPermissionUnchecked(@Nonnull Node node);
/**
* Unsets a transient permission for the object
*
* @param node The node to be unset
* @throws ObjectLacksException if the node wasn't already set
* @throws NullPointerException if the node is null
* @since 2.6
*/
void unsetTransientPermission(@Nonnull Node node) throws ObjectLacksException;
/**
* Unsets a transient permission for the object
*
* @param node The node to be unset
* @throws NullPointerException if the node is null
* @return the result of the operation
* @since 3.1
*/
@Nonnull
DataMutateResult unsetTransientPermissionUnchecked(@Nonnull Node node);
/**
* Clears any nodes from the holder which pass the predicate
*
* @param test the predicate to test for nodes which should be removed
* @since 3.2
*/
void clearMatching(@Nonnull Predicate<Node> test);
/**
* Clears any transient nodes from the holder which pass the predicate
*
* @param test the predicate to test for nodes which should be removed
* @since 3.2
*/
void clearMatchingTransient(@Nonnull Predicate<Node> test);
/**
* Clears all nodes held by the object
*
* @since 2.17
*/
void clearNodes();
/**
* Clears all nodes held by the object in a specific context
*
* @param contextSet the contexts to filter by
* @since 3.2
*/
void clearNodes(@Nonnull ContextSet contextSet);
/**
* Clears all parent groups
*
* @since 2.17
*/
void clearParents();
/**
* Clears all parent groups in a specific context
*
* @param contextSet the contexts to filter by
* @since 3.2
*/
void clearParents(@Nonnull ContextSet contextSet);
/**
* Clears all meta held by the object
*
* @since 2.17
*/
void clearMeta();
/**
* Clears all meta held by the object in a specific context
*
* @param contextSet the contexts to filter by
* @since 3.2
*/
void clearMeta(@Nonnull ContextSet contextSet);
/**
* Clears all transient permissions the holder has.
*/
void clearTransientNodes();
/**
* Checks to see if the object has a certain permission
*
* @param node The permission node
* @param b If the node is true/false(negated)
* @return true if the object has the permission
* @throws NullPointerException if the node is null
* @throws IllegalArgumentException if the node is invalid
* @deprecated in favour of {@link #hasPermission(Node)}
*/
@Deprecated
boolean hasPermission(@Nonnull String node, boolean b);
/**
* Checks to see the the object has a permission on a certain server
*
* @param node The permission node
* @param b If the node is true/false(negated)
* @param server The server
* @return true if the object has the permission
* @throws NullPointerException if the node or server is null
* @throws IllegalArgumentException if the node or server is invalid
* @deprecated in favour of {@link #hasPermission(Node)}
*/
@Deprecated
boolean hasPermission(@Nonnull String node, boolean b, @Nonnull String server);
/**
* Checks to see the the object has a permission on a certain server and world
*
* @param node The permission node
* @param b If the node is true/false(negated)
* @param server The server
* @param world The world
* @return true if the object has the permission
* @throws NullPointerException if the node, server or world is null
* @throws IllegalArgumentException if the node, server or world is invalid
* @deprecated in favour of {@link #hasPermission(Node)}
*/
@Deprecated
boolean hasPermission(@Nonnull String node, boolean b, @Nonnull String server, @Nonnull String world);
/**
* Checks to see the the object has a permission
*
* @param node The permission node
* @param b If the node is true/false(negated)
* @param temporary if the permission is temporary
* @return true if the object has the permission
* @throws NullPointerException if the node is null
* @throws IllegalArgumentException if the node is invalid
* @deprecated in favour of {@link #hasPermission(Node)}
*/
@Deprecated
boolean hasPermission(@Nonnull String node, boolean b, boolean temporary);
/**
* Checks to see the the object has a permission on a certain server
*
* @param node The permission node
* @param b If the node is true/false(negated)
* @param server The server to check on
* @param temporary if the permission is temporary
* @return true if the object has the permission
* @throws NullPointerException if the node or server is null
* @throws IllegalArgumentException if the node or server is invalid
* @deprecated in favour of {@link #hasPermission(Node)}
*/
@Deprecated
boolean hasPermission(@Nonnull String node, boolean b, @Nonnull String server, boolean temporary);
/**
* Checks to see the the object has a permission on a certain server and world
*
* @param node The permission node
* @param b If the node is true/false(negated)
* @param server The server to check on
* @param world The world to check on
* @param temporary if the permission is temporary
* @return true if the object has the permission
* @throws NullPointerException if the node, server or world is null
* @throws IllegalArgumentException if the node, server or world is invalid
* @deprecated in favour of {@link #hasPermission(Node)}
*/
@Deprecated
boolean hasPermission(@Nonnull String node, boolean b, @Nonnull String server, @Nonnull String world, boolean temporary);
/**
* Checks to see if the object inherits a certain permission
*
* @param node The permission node
* @param b If the node is true/false(negated)
* @return true if the object inherits the permission
* @throws NullPointerException if the node is null
* @throws IllegalArgumentException if the node is invalid
* @deprecated in favour of {@link #hasPermission(Node)}
*/
@Deprecated
boolean inheritsPermission(@Nonnull String node, boolean b);
/**
* Checks to see the the object inherits a permission on a certain server
*
* @param node The permission node
* @param b If the node is true/false(negated)
* @param server The server
* @return true if the object inherits the permission
* @throws NullPointerException if the node or server is null
* @throws IllegalArgumentException if the node or server is invalid
* @deprecated in favour of {@link #hasPermission(Node)}
*/
@Deprecated
boolean inheritsPermission(@Nonnull String node, boolean b, @Nonnull String server);
/**
* Checks to see the the object inherits a permission on a certain server and world
*
* @param node The permission node
* @param b If the node is true/false(negated)
* @param server The server
* @param world The world
* @return true if the object inherits the permission
* @throws NullPointerException if the node, server or world is null
* @throws IllegalArgumentException if the node server or world is invalid
* @deprecated in favour of {@link #hasPermission(Node)}
*/
@Deprecated
boolean inheritsPermission(@Nonnull String node, boolean b, @Nonnull String server, @Nonnull String world);
/**
* Checks to see if the object inherits a permission
*
* @param node The permission node
* @param b If the node is true/false(negated)
* @param temporary if the permission is temporary
* @return true if the object inherits the permission
* @throws NullPointerException if the node is null
* @throws IllegalArgumentException if the node is invalid
* @deprecated in favour of {@link #hasPermission(Node)}
*/
@Deprecated
boolean inheritsPermission(@Nonnull String node, boolean b, boolean temporary);
/**
* Checks to see if the object inherits a permission on a certain server
*
* @param node The permission node
* @param b If the node is true/false(negated)
* @param server The server
* @param temporary if the permission is temporary
* @return true if the object inherits the permission
* @throws NullPointerException if the node or server is null
* @throws IllegalArgumentException if the node or server is invalid
* @deprecated in favour of {@link #hasPermission(Node)}
*/
@Deprecated
boolean inheritsPermission(@Nonnull String node, boolean b, @Nonnull String server, boolean temporary);
/**
* Checks to see if the object inherits a permission on a certain server and world
*
* @param node The permission node
* @param b If the node is true/false(negated)
* @param server The server
* @param world The world
* @param temporary if the permission is temporary
* @return true if the object inherits the permission
* @throws NullPointerException if the node, server or world is null
* @throws IllegalArgumentException if the node, server or world if invalid
* @deprecated in favour of {@link #hasPermission(Node)}
*/
@Deprecated
boolean inheritsPermission(@Nonnull String node, boolean b, @Nonnull String server, @Nonnull String world, boolean temporary);
/**
* Sets a permission for the object
*
* @param node The node to be set
* @param value What to set the node to - true/false(negated)
* @throws ObjectAlreadyHasException if the object already has the permission
* @throws NullPointerException if the node is null
* @throws IllegalArgumentException if the node is invalid
* @deprecated in favour of {@link #setPermission(Node)}
*/
@Deprecated
void setPermission(@Nonnull 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(@Nonnull String node, boolean value, @Nonnull String server) throws ObjectAlreadyHasException;
/**
* Sets a permission for the object on a specific server and world
*
* @param node The node to set
* @param value What to set the node to - true/false(negated)
* @param server The server to set the permission on
* @param world The world to set the permission on
* @throws ObjectAlreadyHasException if the object already has the permission
* @throws NullPointerException if the node, server or world is null
* @throws IllegalArgumentException if the node, server or world is invalid
* @deprecated in favour of {@link #setPermission(Node)}
*/
@Deprecated
void setPermission(@Nonnull String node, boolean value, @Nonnull String server, @Nonnull String world) throws ObjectAlreadyHasException;
/**
* Sets a temporary permission for the object
*
* @param node The node to set
* @param value What to set the node to - true/false(negated)
* @param expireAt The time in unixtime when the permission will expire
* @throws ObjectAlreadyHasException if the object already has the permission
* @throws NullPointerException if the node is null
* @throws IllegalArgumentException if the node is invalid or if the expiry time is in the past
* @deprecated in favour of {@link #setPermission(Node)}
*/
@Deprecated
void setPermission(@Nonnull String node, boolean value, long expireAt) throws ObjectAlreadyHasException;
/**
* Sets a temporary permission for the object on a specific server
*
* @param node The node to set
* @param value What to set the node to - true/false(negated)
* @param server The server to set the permission on
* @param expireAt The time in unixtime when the permission will expire
* @throws ObjectAlreadyHasException if the object already has the permission
* @throws NullPointerException if the node or server is null
* @throws IllegalArgumentException if the node/server is invalid or if the expiry time is in the past
* @deprecated in favour of {@link #setPermission(Node)}
*/
@Deprecated
void setPermission(@Nonnull String node, boolean value, @Nonnull String server, long expireAt) throws ObjectAlreadyHasException;
/**
* Sets a temporary permission for the object on a specific server and world
*
* @param node The node to set
* @param value What to set the node to - true/false(negated)
* @param server The server to set the permission on
* @param world The world to set the permission on
* @param expireAt The time in unixtime when the permission will expire
* @throws ObjectAlreadyHasException if the object already has the permission
* @throws NullPointerException if the node, server or world is null
* @throws IllegalArgumentException if the node/server/world is invalid, or if the expiry time is in the past
* @deprecated in favour of {@link #setPermission(Node)}
*/
@Deprecated
void setPermission(String node, boolean value, @Nonnull String server, @Nonnull String world, long expireAt) throws ObjectAlreadyHasException;
/**
* Unsets a permission for the object
*
* @param node The node to be unset
* @param temporary if the permission being removed is temporary
* @throws ObjectLacksException if the node wasn't already set
* @throws NullPointerException if the node is null
* @throws IllegalArgumentException if the node is invalid
* @deprecated in favour of {@link #unsetPermission(Node)}
*/
@Deprecated
void unsetPermission(@Nonnull String node, boolean temporary) throws ObjectLacksException;
/**
* Unsets a permission for the object
*
* @param node The node to be unset
* @throws ObjectLacksException if the node wasn't already set
* @throws NullPointerException if the node is null
* @throws IllegalArgumentException if the node is invalid
* @deprecated in favour of {@link #unsetPermission(Node)}
*/
@Deprecated
void unsetPermission(@Nonnull 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(@Nonnull String node, @Nonnull String server) throws ObjectLacksException;
/**
* Unsets a permission for the object on a specific server and world
*
* @param node The node to be unset
* @param server The server to unset the node on
* @param world The world to unset the node on
* @throws ObjectLacksException if the node wasn't already set
* @throws NullPointerException if the node, server or world is null
* @throws IllegalArgumentException if the node, server or world is invalid
* @deprecated in favour of {@link #unsetPermission(Node)}
*/
@Deprecated
void unsetPermission(@Nonnull String node, @Nonnull String server, @Nonnull String world) throws ObjectLacksException;
/**
* Unsets a permission for the object on a specific server
*
* @param node The node to be unset
* @param server The server to unset the node on
* @param temporary if the permission being unset is temporary
* @throws ObjectLacksException if the node wasn't already set
* @throws NullPointerException if the node or server is null
* @throws IllegalArgumentException if the node or server is invalid
* @deprecated in favour of {@link #unsetPermission(Node)}
*/
@Deprecated
void unsetPermission(@Nonnull String node, @Nonnull String server, boolean temporary) throws ObjectLacksException;
/**
* Unsets a permission for the object on a specific server and world
*
* @param node The node to be unset
* @param server The server to unset the node on
* @param world The world to unset the node on
* @param temporary if the permission being unset is temporary
* @throws ObjectLacksException if the node wasn't already set
* @throws NullPointerException if the node, server or world is null
* @throws IllegalArgumentException if the node, server or world is invalid
* @deprecated in favour of {@link #unsetPermission(Node)}
*/
@Deprecated
void unsetPermission(@Nonnull String node, @Nonnull String server, @Nonnull String world, boolean temporary) throws ObjectLacksException;
/**
* Clears all nodes held by the object on a specific server
*
* @param server the server to filter by, can be null
* @since 2.17
* @deprecated in favour of {@link #clearNodes(ContextSet)}
*/
@Deprecated
void clearNodes(@Nullable String server);
/**
* Clears all nodes held by the object on a specific server and world
*
* @param server the server to filter by, can be null
* @param world the world to filter by, can be null
* @since 2.17
* @deprecated in favour of {@link #clearNodes(ContextSet)}
*/
@Deprecated
void clearNodes(@Nullable String server, @Nullable String world);
/**
* Clears all parents on a specific server
*
* @param server the server to filter by, can be null
* @since 2.17
* @deprecated in favour of {@link #clearParents(ContextSet)}
*/
@Deprecated
void clearParents(@Nullable String server);
/**
* Clears all parents on a specific server and world
*
* @param server the server to filter by, can be null
* @param world the world to filter by, can be null
* @since 2.17
* @deprecated in favour of {@link #clearParents(ContextSet)}
*/
@Deprecated
void clearParents(@Nullable String server, @Nullable String world);
/**
* Clears all meta held by the object on a specific server
*
* @param server the server to filter by, can be null
* @since 2.17
* @deprecated in favour of {@link #clearMeta(ContextSet)}
*/
@Deprecated
void clearMeta(@Nullable String server);
/**
* Clears all meta held by the object on a specific server and world
*
* @param server the server to filter by, can be null
* @param world the world to filter by, can be null
* @since 2.17
* @deprecated in favour of {@link #clearMeta(ContextSet)}
*/
@Deprecated
void clearMeta(@Nullable String server, @Nullable String world);
/**
* Clears all meta for a given key.
*
* @param key the meta key
* @param server the server to filter by, can be null
* @param world the world to filter by, can be null
* @param temporary whether the query is for temporary nodes or not.
* @deprecated in favour of {@link #clearMatching(Predicate)}
*/
@Deprecated
void clearMetaKeys(@Nonnull String key, @Nullable String server, @Nullable String world, boolean temporary);
}
@@ -1,315 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api;
import 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 permission data to/from the backend.
*
* <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)} and {@link #getSyncExecutor()}.</p>
*
* @since 2.14
*/
public interface Storage {
/**
* Get the name of the storage implementation.
*
* @return the name of the implementation
*/
@Nonnull
String getName();
/**
* Gets whether the storage instance is allowing logins on the platform.
*
* @return true if logins are enabled
*/
boolean isAcceptingLogins();
/**
* Returns an executor which will run all passed runnables on the main server thread.
*
* @return an executor instance
*/
@Nonnull
Executor getSyncExecutor();
/**
* Returns an executor which will run all passed runnables asynchronously using the platforms scheduler and thread
* pools.
*
* @return an executor instance
*/
@Nonnull
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
*/
@Nonnull
CompletableFuture<Boolean> logAction(@Nonnull LogEntry entry);
/**
* Loads and returns the entire log from storage
*
* @return a log instance, could be null if loading failed
*/
@Nonnull
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, or null if it is not known.
* @return if the operation completed successfully
* @throws NullPointerException if uuid is null
*/
@Nonnull
CompletableFuture<Boolean> loadUser(@Nonnull UUID uuid, @Nullable String username);
/**
* 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
*/
@Nonnull
default CompletableFuture<Boolean> loadUser(@Nonnull UUID uuid) {
return loadUser(uuid, null);
}
/**
* Saves a user object back to storage. You should call this after you make any changes to a user.
*
* @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.
*/
@Nonnull
CompletableFuture<Boolean> saveUser(@Nonnull User user);
/**
* Removes users from the main storage who are "default". This is called every time the plugin loads.
*
* @return true if the operation completed successfully
*/
@Nonnull
CompletableFuture<Boolean> cleanupUsers();
/**
* Gets a set all "unique" user UUIDs.
*
* <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.
*/
@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, or null if the operation failed
* @throws NullPointerException if the permission is null
* @since 2.17
*/
@Nonnull
CompletableFuture<List<HeldPermission<UUID>>> getUsersWithPermission(@Nonnull String permission);
/**
* Creates and loads a group into the plugins local storage
*
* @param name the name of the group
* @return true if the operation completed successfully
* @throws NullPointerException if name is null
* @throws IllegalArgumentException if the name is invalid
*/
@Nonnull
CompletableFuture<Boolean> createAndLoadGroup(@Nonnull String name);
/**
* Loads a group into the plugins local storage.
*
* @param name the name of the group
* @return true if the operation completed successfully
* @throws NullPointerException if name is null
* @throws IllegalArgumentException if the name is invalid
*/
@Nonnull
CompletableFuture<Boolean> loadGroup(@Nonnull String name);
/**
* Loads all groups from the storage into memory
*
* @return true if the operation completed successfully.
*/
@Nonnull
CompletableFuture<Boolean> loadAllGroups();
/**
* Saves a group back to storage. You should call this after you make any changes to a group.
*
* @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.
*/
@Nonnull
CompletableFuture<Boolean> saveGroup(@Nonnull Group group);
/**
* Permanently deletes a group from storage.
*
* @param group the group to delete
* @return true if the operation completed successfully.
* @throws NullPointerException if group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
*/
@Nonnull
CompletableFuture<Boolean> deleteGroup(@Nonnull Group group);
/**
* 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 2.17
*/
@Nonnull
CompletableFuture<List<HeldPermission<String>>> getGroupsWithPermission(@Nonnull String permission);
/**
* Creates and loads a track into the plugins local storage
*
* @param name the name of the track
* @return true if the operation completed successfully
* @throws NullPointerException if name is null
* @throws IllegalArgumentException if the name is invalid
*/
@Nonnull
CompletableFuture<Boolean> createAndLoadTrack(@Nonnull String name);
/**
* Loads a track into the plugins local storage.
*
* @param name the name of the track
* @return true if the operation completed successfully
* @throws NullPointerException if name is null
* @throws IllegalArgumentException if the name is invalid
*/
@Nonnull
CompletableFuture<Boolean> loadTrack(@Nonnull String name);
/**
* Loads all tracks from the storage into memory
*
* @return true if the operation completed successfully.
*/
@Nonnull
CompletableFuture<Boolean> loadAllTracks();
/**
* Saves a track back to storage. You should call this after you make any changes to a track.
*
* @param track the track to save
* @return true if the operation completed successfully.
* @throws NullPointerException if track is null
* @throws IllegalStateException if the track instance was not obtained from LuckPerms.
*/
@Nonnull
CompletableFuture<Boolean> saveTrack(@Nonnull Track track);
/**
* Permanently deletes a track from storage
*
* @param track the track to delete
* @return true if the operation completed successfully.
* @throws NullPointerException if track is null
* @throws IllegalStateException if the track instance was not obtained from LuckPerms.
*/
@Nonnull
CompletableFuture<Boolean> deleteTrack(@Nonnull Track track);
/**
* Saves UUID caching data to the global cache
*
* @param username the users username
* @param uuid the users mojang unique id
* @return true if the operation completed successfully.
* @throws NullPointerException if either parameters are null
* @throws IllegalArgumentException if the username is invalid
*/
@Nonnull
CompletableFuture<Boolean> saveUUIDData(@Nonnull String username, @Nonnull UUID uuid);
/**
* Gets a UUID from a username
*
* @param username the corresponding username
* @return a uuid object, could be null
* @throws NullPointerException if either parameters are null
* @throws IllegalArgumentException if the username is invalid
*/
@Nonnull
CompletableFuture<UUID> getUUID(@Nonnull String username);
/**
* Gets a username from a UUID
*
* @param uuid the corresponding uuid
* @return a name string, could be null
* @throws NullPointerException if either parameters are null
* @since 2.17
*/
@Nonnull
CompletableFuture<String> getName(@Nonnull UUID uuid);
}
@@ -1,378 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api;
import me.lucko.luckperms.api.caching.UserData;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* A player which holds permission data.
*/
public interface User extends PermissionHolder {
/**
* Gets the users unique ID
*
* @return the users Mojang assigned unique id
*/
@Nonnull
UUID getUuid();
/**
* Gets 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 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. 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
* @throws IllegalStateException if the user is not a member of that group
* @throws NullPointerException if the group is null
*/
void setPrimaryGroup(@Nonnull String group) throws ObjectAlreadyHasException;
/**
* Refresh and re-assign the users permissions.
*
* <p>This request is not buffered, and the refresh call will be ran directly. This should be called on an
* asynchronous thread.</p>
*/
void refreshPermissions();
/**
* Gets the user's {@link UserData} cache.
*
* @return the users cached data.
* @since 3.2
*/
@Nonnull
UserData getCachedData();
/**
* Pre-calculates some values in the user's data cache.
*
* <p>Is it <b>not</b> necessary to call this method before
* using {@link #getCachedData()}.</p>
*
* @since 2.17
*/
void setupDataCache();
/**
* Check to see if the user is a direct member of a group
*
* @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
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
*/
boolean isInGroup(@Nonnull Group group);
/**
* Check to see if the user is a direct member of a group in a specific context
*
* @param group the group to check membership of
* @param contextSet the context set to filter by
* @return true if the user is a member of the group
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @since 3.2
*/
boolean isInGroup(@Nonnull Group group, @Nonnull ContextSet contextSet);
/**
* Gets the user's {@link UserData} cache, if they have one setup.
*
* @return an optional, possibly containing the user's cached lookup data.
* @since 2.13
* @deprecated in version 3.2, as this cache is now always loaded
*/
@Deprecated
@Nonnull
Optional<UserData> getUserDataCache();
/**
* Check to see if a user is a member of a group on a specific server
*
* @param group The group to check membership of
* @param server The server to check on
* @return true if the user is a member of the group
* @throws NullPointerException if the group or server is null
* @throws IllegalArgumentException if the server is invalid
* @deprecated in favour of {@link #isInGroup(Group, ContextSet)}
*/
@Deprecated
boolean isInGroup(@Nonnull Group group, @Nonnull String server);
/**
* Check to see if a user is a member of a group on a specific server and world
*
* @param group The group to check membership of
* @param server The server to check on
* @param world The world to check on
* @return true if the user is a member of the group
* @throws NullPointerException if the group, server or world is null
* @throws IllegalArgumentException if the server or world is invalid
* @deprecated in favour of {@link #isInGroup(Group, ContextSet)}
*/
@Deprecated
boolean isInGroup(@Nonnull Group group, @Nonnull String server, @Nonnull String world);
/**
* Add a user to a group
*
* @param group The group to add the user to
* @throws ObjectAlreadyHasException if the user is already a member of the group
* @throws NullPointerException if the group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
*/
@Deprecated
void addGroup(@Nonnull Group group) throws ObjectAlreadyHasException;
/**
* Add a user to a group on a specific server
*
* @param group The group to add the user to
* @param server The server to add the group on
* @throws ObjectAlreadyHasException if the user is already a member of the group on that server
* @throws NullPointerException if the group or server is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @throws IllegalArgumentException if the server is invalid
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
*/
@Deprecated
void addGroup(@Nonnull Group group, @Nonnull String server) throws ObjectAlreadyHasException;
/**
* Add a user to a group on a specific server and world
*
* @param group The group to add the user to
* @param server The server to add the group on
* @param world The world to add the group on
* @throws ObjectAlreadyHasException if the user is already a member of the group on that server
* @throws NullPointerException if the group, server or world is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @throws IllegalArgumentException if the server or world is invalid
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
*/
@Deprecated
void addGroup(@Nonnull Group group, @Nonnull String server, @Nonnull String world) throws ObjectAlreadyHasException;
/**
* Add a user to a group temporarily on a specific server
*
* @param group The group to add the user to
* @param expireAt when the group should expire
* @throws ObjectAlreadyHasException if the user is already a member of the group on that server
* @throws NullPointerException if the group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @throws IllegalArgumentException if the expiry time is in the past
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
*/
@Deprecated
void addGroup(@Nonnull Group group, long expireAt) throws ObjectAlreadyHasException;
/**
* Add a user to a group temporarily on a specific server
*
* @param group The group to add the user to
* @param server The server to add the group on
* @param expireAt when the group should expire
* @throws ObjectAlreadyHasException if the user is already a member of the group on that server
* @throws NullPointerException if the group or server is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @throws IllegalArgumentException if the expiry time is in the past or the server is invalid
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
*/
@Deprecated
void addGroup(@Nonnull Group group, @Nonnull String server, long expireAt) throws ObjectAlreadyHasException;
/**
* Add a user to a group temporarily on a specific server and world
*
* @param group The group to add the user to
* @param server The server to add the group on
* @param world The world to add the group on
* @param expireAt when the group should expire
* @throws ObjectAlreadyHasException if the user is already a member of the group on that server
* @throws NullPointerException if the group, server or world is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @throws IllegalArgumentException if the expiry time is in the past or the server/world is invalid
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
*/
@Deprecated
void addGroup(@Nonnull Group group, @Nonnull String server, @Nonnull String world, long expireAt) throws ObjectAlreadyHasException;
/**
* Remove the user from a group
*
* @param group the group to remove the user from
* @throws ObjectLacksException if the user isn't a member of the group
* @throws NullPointerException if the group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
*/
@Deprecated
void removeGroup(@Nonnull Group group) throws ObjectLacksException;
/**
* Remove the user from a group
*
* @param group the group to remove the user from
* @param temporary if the group being removed is temporary
* @throws ObjectLacksException if the user isn't a member of the group
* @throws NullPointerException if the group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
*/
@Deprecated
void removeGroup(@Nonnull Group group, boolean temporary) throws ObjectLacksException;
/**
* Remove the user from a group on a specific server
*
* @param group The group to remove the user from
* @param server The server to remove the group on
* @throws ObjectLacksException if the user isn't a member of the group
* @throws NullPointerException if the group or server is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @throws IllegalArgumentException if the server is invalid
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
*/
@Deprecated
void removeGroup(@Nonnull Group group, @Nonnull String server) throws ObjectLacksException;
/**
* Remove the user from a group on a specific server and world
*
* @param group The group to remove the user from
* @param server The server to remove the group on
* @param world The world to remove the group on
* @throws ObjectLacksException if the user isn't a member of the group
* @throws NullPointerException if the group, server or world is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @throws IllegalArgumentException if the server or world is invalid
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
*/
@Deprecated
void removeGroup(@Nonnull Group group, @Nonnull String server, @Nonnull String world) throws ObjectLacksException;
/**
* Remove the user from a group on a specific server
*
* @param group The group to remove the user from
* @param server The server to remove the group on
* @param temporary if the group being removed is temporary
* @throws ObjectLacksException if the user isn't a member of the group
* @throws NullPointerException if the group or server is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @throws IllegalArgumentException if the expiry time is in the past or the server is invalid
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
*/
@Deprecated
void removeGroup(@Nonnull Group group, @Nonnull String server, boolean temporary) throws ObjectLacksException;
/**
* Remove the user from a group on a specific server and world
*
* @param group The group to remove the user from
* @param server The server to remove the group on
* @param world The world to remove the group on
* @param temporary if the group being removed is temporary
* @throws ObjectLacksException if the user isn't a member of the group
* @throws NullPointerException if the group, server or world is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @throws IllegalArgumentException if the expiry time is in the past or the server/world is invalid
* @deprecated in favour of {@link NodeFactory#makeGroupNode(Group)}
*/
@Deprecated
void removeGroup(@Nonnull Group group, @Nonnull String server, @Nonnull String world, boolean temporary) throws ObjectLacksException;
/**
* Get a {@link List} of all of the groups the user is a member of, on all servers
*
* @return a {@link List} of group names
* @deprecated in favour of just querying a users permissions
*/
@Deprecated
@Nonnull
List<String> getGroupNames();
/**
* Get a {@link List} of the groups the user is a member of on a specific server
*
* @param server the server to check
* @param world the world to check
* @return a {@link List} of group names
* @throws NullPointerException if the server or world is null
* @throws IllegalArgumentException if the server or world is invalid
* @deprecated in favour of just querying a users permissions
*/
@Deprecated
@Nonnull
List<String> getLocalGroups(@Nonnull String server, @Nonnull String world);
/**
* Get a {@link List} of the groups the user is a member of on a specific server
*
* @param server the server to check
* @return a {@link List} of group names
* @throws NullPointerException if the server is null
* @throws IllegalArgumentException if the server is invalid
* @deprecated in favour of just querying a users permissions
*/
@Deprecated
@Nonnull
List<String> getLocalGroups(@Nonnull String server);
}
@@ -1,65 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api;
import java.util.UUID;
import javax.annotation.Nonnull;
/**
* A UUID cache for online users, between external Mojang UUIDs, and internal LuckPerms UUIDs.
*
* <p>A user's internal LuckPerms UUID is always the same as their Mojang one,
* unless <code>use-server-uuids</code> is disabled.</p>
*
* <p>When this setting is disabled, this cache becomes active, and allows you to convert
* between 'internal' and 'server provided' uuids.</p>
*
* <p><strong>This is only effective for online players. Use {@link Storage#getUUID(String)} for offline players.</strong></p>
*/
public interface UuidCache {
/**
* Gets a users "internal" LuckPerms UUID, from the one given by the server.
*
* <p>When <code>use-server-uuids</code> is true, this returns the same UUID instance.</p>
*
* @param mojangUuid the UUID assigned by the server, through <code>Player#getUniqueId</code> or <code>ProxiedPlayer#getUniqueId</code>
* @return the corresponding internal UUID
*/
@Nonnull
UUID getUUID(@Nonnull UUID mojangUuid);
/**
* Gets a users "external", server assigned unique id, from the internal one used within LuckPerms.
*
* @param internalUuid the UUID used within LuckPerms, through <code>User#getUuid</code>
* @return the corresponding external UUID
*/
@Nonnull
UUID getExternalUUID(@Nonnull UUID internalUuid);
}
@@ -1,118 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api.caching;
import com.google.common.base.Preconditions;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.metastacking.MetaStackDefinition;
import javax.annotation.Nonnull;
/**
* Represents the context for a meta lookup.
*
* <p>Consisting of a standard {@link Contexts} element, plus options to define how
* the meta stack should be constructed.</p>
*
* @since 3.2
*/
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;
/**
* 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 = Preconditions.checkNotNull(contexts, "contexts");
this.prefixStackDefinition = Preconditions.checkNotNull(prefixStackDefinition, "prefixStackDefinition");
this.suffixStackDefinition = Preconditions.checkNotNull(suffixStackDefinition, "suffixStackDefinition");
}
@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 other = (MetaContexts) o;
return this.getContexts().equals(other.getContexts()) &&
this.getPrefixStackDefinition().equals(other.getPrefixStackDefinition()) &&
this.getSuffixStackDefinition().equals(other.getSuffixStackDefinition());
}
@Override
public int hashCode() {
final int PRIME = 59;
int result = 1;
result = result * PRIME + this.getContexts().hashCode();
result = result * PRIME + this.getPrefixStackDefinition().hashCode();
result = result * PRIME + this.getSuffixStackDefinition().hashCode();
return result;
}
}
@@ -1,123 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api.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
*
* @since 2.13
*/
public interface MetaData {
/**
* 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();
/**
* Gets an immutable sorted map of all of the prefixes the user has, whereby the first value is the highest priority
* prefix.
*
* @return a sorted map of prefixes
*/
@Nonnull
SortedMap<Integer, String> getPrefixes();
/**
* Gets an immutable sorted map of all of the suffixes the user has, whereby the first value is the highest priority
* suffix.
*
* @return a sorted map of suffixes
*/
@Nonnull
SortedMap<Integer, String> getSuffixes();
/**
* Gets the user's highest priority prefix, or null if the user has no prefixes
*
* @return a prefix string, or null
*/
@Nullable
String getPrefix();
/**
* Gets the user's highest priority suffix, or null if the user has no suffixes
*
* @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,185 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api.caching;
import me.lucko.luckperms.api.Contexts;
import java.util.Set;
import javax.annotation.Nonnull;
/**
* Holds cached permission and meta lookup data for a {@link me.lucko.luckperms.api.User}.
*
* <p>Data is only likely to be available for online users. All calls will account for inheritance, as well as any
* default data provided by the platform. This calls are heavily cached and are therefore fast.</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
*/
@Nonnull
PermissionData getPermissionData(@Nonnull 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
* @since 3.2
*/
@Nonnull
MetaData getMetaData(@Nonnull MetaContexts 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
*/
@Nonnull
MetaData getMetaData(@Nonnull 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
*/
@Nonnull
PermissionData calculatePermissions(@Nonnull 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
* @since 3.2
*/
@Nonnull
MetaData calculateMeta(@Nonnull MetaContexts 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
*/
@Nonnull
MetaData calculateMeta(@Nonnull 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(@Nonnull 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
* @since 3.2
*/
void recalculateMeta(@Nonnull MetaContexts 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(@Nonnull 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(@Nonnull 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(@Nonnull Contexts contexts);
/**
* Invalidates all of the underlying Permission calculators.
*
* <p>Can be called to allow for an update in defaults.</p>
*/
void invalidatePermissionCalculators();
}
@@ -1,49 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api.context;
import javax.annotation.Nonnull;
/**
* Calculates whether contexts are applicable to {@link T}
*
* @param <T> the subject type. Is ALWAYS the player class of the platform.
* @since 2.13
*/
public interface ContextCalculator<T> {
/**
* 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
* @since 2.13
*/
@Nonnull
MutableContextSet giveApplicableContext(@Nonnull T subject, @Nonnull MutableContextSet accumulator);
}
@@ -1,334 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api.context;
import com.google.common.base.Preconditions;
import com.google.common.collect.Multimap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import javax.annotation.Nonnull;
/**
* A set of context pairs.
*
* <p>You can think of ContextSets as a wrapped <code>Multimap&lt;String, String&gt;</code>.
* Each key can be mapped to multiple values.</p>
*
* <p>Keys are automatically converted to lowercase when added, and are therefore
* case-insensitive. Values however are not.</p>
*
* <p>Implementations may be either mutable or immutable.</p>
*
* @since 2.13
*/
public interface ContextSet {
/**
* Creates an ImmutableContextSet from a context pair
*
* @param key the key
* @param value the value
* @return a new ImmutableContextSet containing one KV pair
* @throws NullPointerException if key or value is null
*/
@Nonnull
static ImmutableContextSet singleton(@Nonnull String key, @Nonnull String value) {
return ImmutableContextSet.singleton(key, value);
}
/**
* Creates an ImmutableContextSet from two context pairs
*
* @param key1 the first key
* @param value1 the first value
* @param key2 the second key
* @param value2 the second value
* @return a new ImmutableContextSet containing the two pairs
* @throws NullPointerException if any of the keys or values are null
* @since 3.1
*/
@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 iterable of Map Entries
*
* @param iterable the iterable to copy from
* @return a new ImmutableContextSet representing the pairs in the iterable
* @throws NullPointerException if the iterable is null
*/
@Nonnull
static ImmutableContextSet fromEntries(@Nonnull Iterable<? extends Map.Entry<String, String>> iterable) {
return ImmutableContextSet.fromEntries(iterable);
}
/**
* Creates an ImmutableContextSet from an existing map
*
* @param map the map to copy from
* @return a new ImmutableContextSet representing the pairs from the map
* @throws NullPointerException if the map is null
*/
@Nonnull
static ImmutableContextSet fromMap(@Nonnull Map<String, String> map) {
return ImmutableContextSet.fromMap(map);
}
/**
* Creates an ImmutableContextSet from an existing multimap
*
* @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
*/
@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.
*
* @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
*/
@Nonnull
static ImmutableContextSet fromSet(@Nonnull ContextSet contextSet) {
return ImmutableContextSet.fromSet(contextSet);
}
/**
* Creates a new empty ImmutableContextSet.
*
* @return a new ImmutableContextSet
*/
@Nonnull
static ImmutableContextSet empty() {
return ImmutableContextSet.empty();
}
/**
* Gets if this set is in an immutable form
*
* @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.
*
* @return an immutable ContextSet
*/
@Nonnull
ImmutableContextSet makeImmutable();
/**
* Creates a mutable copy of this set.
*
* @return a mutable ContextSet
* @since 2.16
*/
@Nonnull
MutableContextSet mutableCopy();
/**
* Converts this ContextSet to an immutable {@link Set} of {@link Map.Entry}s.
*
* @return an immutable set
*/
@Nonnull
Set<Map.Entry<String, String>> toSet();
/**
* Converts this ContextSet to an immutable {@link Map}
*
* <b>IMPORTANT: Use of this method may result in data being lost. ContextSets can contain lots of different values for
* one key.</b>
*
* @return an immutable map
* @deprecated because the resultant map may not contain all data in the ContextSet
*/
@Nonnull
@Deprecated
Map<String, String> toMap();
/**
* Converts this ContextSet to an immutable {@link Multimap}
*
* @return a multimap
* @since 2.16
*/
@Nonnull
Multimap<String, String> toMultimap();
/**
* Check if the set 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(@Nonnull String key);
/**
* Gets a set of all of the values mapped to the given key
*
* @param key the key to find values for
* @return a set of values
* @throws NullPointerException if the key is null
*/
@Nonnull
Set<String> getValues(@Nonnull String key);
/**
* Returns any value from this set matching the key, if present.
*
* @param key the key to find values for
* @return an optional containing any match
* @since 3.1
*/
@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(@Nonnull String key, @Nonnull String value);
/**
* Check if thr set contains a given key mapped to a given value
*
* @param entry the entry to look for
* @return true if the set contains the KV pair
* @throws NullPointerException if the key or value is null
* @since 3.4
*/
default boolean has(@Nonnull Map.Entry<String, String> entry) {
Preconditions.checkNotNull(entry, "entry");
return has(entry.getKey(), entry.getValue());
}
/**
* Same as {@link #has(String, String)}, except ignores the case of the value.
*
* @param key the key to look for
* @param value the value to look for
* @return true if the set contains the KV pair
* @throws NullPointerException if the key or value is null
*/
boolean hasIgnoreCase(@Nonnull String key, @Nonnull String value);
/**
* Same as {@link #has(Map.Entry)}, except ignores the case of the value.
*
* @param entry the entry to look for
* @return true if the set contains the KV pair
* @throws NullPointerException if the key or value is null
* @since 3.4
*/
default boolean hasIgnoreCase(@Nonnull Map.Entry<String, String> entry) {
Preconditions.checkNotNull(entry, "entry");
return hasIgnoreCase(entry.getKey(), entry.getValue());
}
/**
* Checks to see if all entries in this context set are also included in another set.
*
* @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(@Nonnull ContextSet other) {
return isSatisfiedBy(other, true);
}
/**
* Checks to see if all entries in this context set are also included in another set.
*
* @param other the other set to check
* @param caseSensitive if the lookup should be case sensitive. see {@link #has(Map.Entry)} and {@link #hasIgnoreCase(Map.Entry)}.
* @return true if all entries in this set are also in the other set
* @since 3.4
*/
default boolean isSatisfiedBy(@Nonnull ContextSet other, boolean caseSensitive) {
Preconditions.checkNotNull(other, "other");
if (this.isEmpty()) {
// this is empty, so is therefore always satisfied.
return true;
} else if (other.isEmpty()) {
// this set isn't empty, but the other one is
return false;
} else if (this.size() > other.size()) {
// this set has more unique entries than the other set, so there's no way this can be satisfied.
return false;
} else {
// neither are empty, we need to compare the individual entries
for (Map.Entry<String, String> pair : toSet()) {
if (caseSensitive) {
if (!other.has(pair)) {
return false;
}
} else {
if (!other.hasIgnoreCase(pair)) {
return false;
}
}
}
return true;
}
}
/**
* Check if the set is empty
*
* @return true if the set is empty
*/
boolean isEmpty();
/**
* Gets the number of key-value context pairs in the set
*
* @return the size of the set
*/
int size();
}
@@ -1,274 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api.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 java.util.Collection;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nonnull;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* An immutable implementation of {@link ContextSet}.
*
* <p>On construction, all keys/values are {@link String#intern()}ed, in order to increase
* comparison speed.</p>
*
* @since 2.16
*/
public final class ImmutableContextSet implements ContextSet {
private static final ImmutableContextSet EMPTY = new ImmutableContextSet(ImmutableSetMultimap.of());
/**
* Creates an ImmutableContextSet from a context pair
*
* @param key the key
* @param value the value
* @return a new ImmutableContextSet containing one KV 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(
checkNotNull(key, "key").toLowerCase().intern(),
checkNotNull(value, "value").intern()
));
}
/**
* Creates an ImmutableContextSet from two context pairs
*
* @param key1 the first key
* @param value1 the first value
* @param key2 the second key
* @param value2 the second value
* @return a new ImmutableContextSet containing the two pairs
* @throws NullPointerException if any of the keys or values are null
* @since 3.1
*/
@Nonnull
public static ImmutableContextSet of(@Nonnull String key1, @Nonnull String value1, @Nonnull String key2, @Nonnull String value2) {
return new ImmutableContextSet(ImmutableSetMultimap.of(
checkNotNull(key1, "key1").toLowerCase().intern(),
checkNotNull(value1, "value1").intern(),
checkNotNull(key2, "key2").toLowerCase().intern(),
checkNotNull(value2, "value2").intern()
));
}
/**
* Creates an ImmutableContextSet from an existing iterable of Map Entries
*
* @param iterable the iterable to copy from
* @return a new ImmutableContextSet representing the pairs in the iterable
* @throws NullPointerException if the iterable is null
*/
@Nonnull
public static ImmutableContextSet fromEntries(@Nonnull Iterable<? extends Map.Entry<String, String>> iterable) {
checkNotNull(iterable, "iterable");
ImmutableSetMultimap.Builder<String, String> b = ImmutableSetMultimap.builder();
for (Map.Entry<String, String> e : iterable) {
b.put(checkNotNull(e.getKey()).toLowerCase().intern(), checkNotNull(e.getValue()).intern());
}
return new ImmutableContextSet(b.build());
}
/**
* Creates an ImmutableContextSet from an existing map
*
* @param map the map to copy from
* @return a new ImmutableContextSet representing the pairs from the map
* @throws NullPointerException if the map is null
*/
@Nonnull
public static ImmutableContextSet fromMap(@Nonnull Map<String, String> map) {
return fromEntries(checkNotNull(map, "map").entrySet());
}
/**
* Creates an ImmutableContextSet from an existing 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
*/
@Nonnull
public static ImmutableContextSet fromMultimap(@Nonnull Multimap<String, String> multimap) {
return fromEntries(checkNotNull(multimap, "multimap").entries());
}
/**
* Creates a new ImmutableContextSet from an existing set.
* Only really useful for converting between mutable and immutable types.
*
* @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
*/
@Nonnull
public static ImmutableContextSet fromSet(@Nonnull ContextSet contextSet) {
return checkNotNull(contextSet, "contextSet").makeImmutable();
}
/**
* Creates an new empty ContextSet.
*
* @return a new ContextSet
*/
@Nonnull
public static ImmutableContextSet empty() {
return EMPTY;
}
private final ImmutableSetMultimap<String, String> map;
ImmutableContextSet(ImmutableSetMultimap<String, String> contexts) {
this.map = contexts;
}
@Override
public boolean isImmutable() {
return true;
}
@Override
@Deprecated // This set is already immutable!
@Nonnull
public ImmutableContextSet makeImmutable() {
return this;
}
@Override
@Nonnull
public MutableContextSet mutableCopy() {
return MutableContextSet.fromSet(this);
}
@Override
@Nonnull
public Set<Map.Entry<String, String>> toSet() {
return map.entries();
}
@Override
@Nonnull
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());
}
return m.build();
}
@Override
@Nonnull
public Multimap<String, String> toMultimap() {
return map;
}
@Override
@Nonnull
public boolean containsKey(@Nonnull String key) {
return map.containsKey(checkNotNull(key, "key").toLowerCase().intern());
}
@Override
@Nonnull
public Set<String> getValues(@Nonnull String key) {
Collection<String> values = map.get(checkNotNull(key, "key").toLowerCase().intern());
return values != null ? ImmutableSet.copyOf(values) : ImmutableSet.of();
}
@Override
@Nonnull
public boolean has(@Nonnull String key, @Nonnull String value) {
return map.containsEntry(checkNotNull(key, "key").toLowerCase().intern(), checkNotNull(value, "value").intern());
}
@Override
@Nonnull
public boolean hasIgnoreCase(@Nonnull String key, @Nonnull String value) {
value = checkNotNull(value, "value").intern();
Collection<String> values = map.get(checkNotNull(key, "key").toLowerCase().intern());
if (values == null || values.isEmpty()) {
return false;
}
for (String val : values) {
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;
// saves on copying the multimap
if (other instanceof MutableContextSet) {
return other.equals(this);
}
final Multimap<String, String> thisContexts = this.toMultimap();
final Multimap<String, String> otherContexts = other.toMultimap();
return thisContexts.equals(otherContexts);
}
@Override
public int hashCode() {
return map.hashCode();
}
@Override
public String toString() {
return "ImmutableContextSet(contexts=" + this.map + ")";
}
}
@@ -1,407 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api.context;
import com.google.common.base.Preconditions;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.SetMultimap;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nonnull;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* A mutable implementation of {@link ContextSet}.
*
* <p>On construction, all keys/values are {@link String#intern()}ed, in order to increase
* comparison speed.</p>
*
* @since 2.16
*/
public final class MutableContextSet implements ContextSet {
/**
* Make a singleton MutableContextSet from a context pair
*
* @param key the key
* @param value the value
* @return a new MutableContextSet containing one KV pair
* @throws NullPointerException if key or value is null
*/
@Nonnull
public static MutableContextSet singleton(@Nonnull String key, @Nonnull String value) {
checkNotNull(key, "key");
checkNotNull(value, "value");
MutableContextSet set = MutableContextSet.create();
set.add(key, value);
return set;
}
/**
* Makes a MutableContextSet from two context pairs
*
* @param key1 the first key
* @param value1 the first value
* @param key2 the second key
* @param value2 the second value
* @return a new MutableContextSet containing the two pairs
* @throws NullPointerException if any of the keys or values are null
* @since 3.1
*/
@Nonnull
public static MutableContextSet of(@Nonnull String key1, @Nonnull String value1, @Nonnull String key2, @Nonnull String value2) {
checkNotNull(key1, "key1");
checkNotNull(value1, "value1");
checkNotNull(key2, "key2");
checkNotNull(value2, "value2");
MutableContextSet set = MutableContextSet.create();
set.add(key1, value1);
set.add(key2, value2);
return set;
}
/**
* Creates a MutableContextSet from an existing iterable of Map Entries
*
* @param iterable the iterable to copy from
* @return a new MutableContextSet representing the pairs in the iterable
* @throws NullPointerException if the iterable is null
*/
@Nonnull
public static MutableContextSet fromEntries(@Nonnull Iterable<? extends Map.Entry<String, String>> iterable) {
checkNotNull(iterable, "iterable");
MutableContextSet set = MutableContextSet.create();
set.addAll(iterable);
return set;
}
/**
* Creates a MutableContextSet from an existing map
*
* @param map the map to copy from
* @return a new MutableContextSet representing the pairs from the map
* @throws NullPointerException if the map is null
*/
@Nonnull
public static MutableContextSet fromMap(@Nonnull Map<String, String> map) {
checkNotNull(map, "map");
MutableContextSet set = MutableContextSet.create();
set.addAll(map);
return set;
}
/**
* Creates a MutableContextSet from an existing multimap
*
* @param multimap the multimap to copy from
* @return a new MutableContextSet representing the pairs in the multimap
* @throws NullPointerException if the multimap is null
*/
@Nonnull
public static MutableContextSet fromMultimap(@Nonnull Multimap<String, String> multimap) {
checkNotNull(multimap, "multimap");
MutableContextSet set = MutableContextSet.create();
set.addAll(multimap);
return set;
}
/**
* Creates a new MutableContextSet from an existing set.
* Only really useful for converting between mutable and immutable types.
*
* @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
*/
@Nonnull
public static MutableContextSet fromSet(@Nonnull ContextSet contextSet) {
Preconditions.checkNotNull(contextSet, "contextSet");
MutableContextSet set = new MutableContextSet();
set.addAll(contextSet.toSet());
return set;
}
/**
* Creates a new empty MutableContextSet.
*
* @return a new MutableContextSet
*/
@Nonnull
public static MutableContextSet create() {
return new MutableContextSet();
}
private final SetMultimap<String, String> map;
public MutableContextSet() {
this.map = Multimaps.synchronizedSetMultimap(HashMultimap.create());
}
private MutableContextSet(MutableContextSet other) {
this.map = Multimaps.synchronizedSetMultimap(HashMultimap.create(other.map));
}
@Override
public boolean isImmutable() {
return false;
}
@Nonnull
@Override
public ImmutableContextSet makeImmutable() {
return new ImmutableContextSet(ImmutableSetMultimap.copyOf(map));
}
@Nonnull
@Override
public MutableContextSet mutableCopy() {
return new MutableContextSet(this);
}
@Nonnull
@Override
public Set<Map.Entry<String, String>> toSet() {
return ImmutableSet.copyOf(map.entries());
}
@Nonnull
@Override
public Map<String, String> toMap() {
ImmutableMap.Builder<String, String> m = ImmutableMap.builder();
for (Map.Entry<String, String> e : map.entries()) {
m.put(e.getKey(), e.getValue());
}
return m.build();
}
@Nonnull
@Override
public Multimap<String, String> toMultimap() {
return ImmutableSetMultimap.copyOf(map);
}
@Nonnull
@Override
public boolean containsKey(@Nonnull String key) {
return map.containsKey(checkNotNull(key, "key").toLowerCase().intern());
}
@Nonnull
@Override
public Set<String> getValues(@Nonnull String key) {
Collection<String> values = map.get(checkNotNull(key, "key").toLowerCase().intern());
return values != null ? ImmutableSet.copyOf(values) : ImmutableSet.of();
}
@Nonnull
@Override
public boolean has(@Nonnull String key, @Nonnull String value) {
return map.containsEntry(checkNotNull(key, "key").toLowerCase().intern(), checkNotNull(value, "value").intern());
}
@Nonnull
@Override
public boolean hasIgnoreCase(@Nonnull String key, @Nonnull String value) {
value = checkNotNull(value, "value").intern();
Collection<String> values = map.get(checkNotNull(key, "key").toLowerCase().intern());
if (values == null || values.isEmpty()) {
return false;
}
for (String val : values) {
if (val.equalsIgnoreCase(value)) {
return true;
}
}
return false;
}
@Override
public boolean isEmpty() {
return map.isEmpty();
}
@Override
public int size() {
return map.size();
}
/**
* Adds a new key value pair to the 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(@Nonnull String key, @Nonnull String value) {
map.put(checkNotNull(key, "key").toLowerCase().intern(), checkNotNull(value, "value").intern());
}
/**
* Adds a new key value pair to the set
*
* @param entry the entry to add
* @throws NullPointerException if the entry is null
*/
public void add(@Nonnull Map.Entry<String, String> entry) {
checkNotNull(entry, "entry");
add(entry.getKey(), entry.getValue());
}
/**
* Adds an iterable containing contexts to the set
*
* @param iterable an iterable of key value context pairs
* @throws NullPointerException if iterable is null
*/
public void addAll(@Nonnull Iterable<? extends Map.Entry<String, String>> iterable) {
for (Map.Entry<String, String> e : checkNotNull(iterable, "iterable")) {
add(e);
}
}
/**
* Adds the entry set of a map to the set
*
* @param map the map to add from
* @throws NullPointerException if the map is null
*/
public void addAll(@Nonnull Map<String, String> map) {
addAll(checkNotNull(map, "map").entrySet());
}
/**
* Adds the entries of a multimap to the set
*
* @param multimap the multimap to add from
* @throws NullPointerException if the map is null
* @since 3.4
*/
public void addAll(@Nonnull Multimap<String, String> multimap) {
addAll(checkNotNull(multimap, "multimap").entries());
}
/**
* Adds of of the values in another ContextSet to this set
*
* @param contextSet the set to add from
* @throws NullPointerException if the contextSet is null
*/
public void addAll(@Nonnull ContextSet contextSet) {
checkNotNull(contextSet, "contextSet");
if (contextSet instanceof MutableContextSet) {
MutableContextSet other = ((MutableContextSet) contextSet);
this.map.putAll(other.map);
} else {
addAll(contextSet.toMultimap());
}
}
/**
* 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(@Nonnull String key, @Nonnull String value) {
String k = checkNotNull(key, "key").toLowerCase().intern();
String v = checkNotNull(value, "value").intern();
//noinspection StringEquality
map.entries().removeIf(entry -> entry.getKey() == k && entry.getValue() == v);
}
/**
* Same as {@link #remove(String, String)}, except ignores the case of the value
*
* @param key the key to remove
* @param value the value to remove
* @throws NullPointerException if the key or value is null
*/
public void removeIgnoreCase(@Nonnull String key, @Nonnull String value) {
String k = checkNotNull(key, "key").toLowerCase().intern();
String v = checkNotNull(value, "value").intern();
//noinspection StringEquality
map.entries().removeIf(e -> e.getKey() == k && e.getValue().equalsIgnoreCase(v));
}
/**
* Removes all pairs with the given key
*
* @param key the key to remove
* @throws NullPointerException if the key is null
*/
public void removeAll(@Nonnull String key) {
map.removeAll(checkNotNull(key, "key").toLowerCase());
}
/**
* Clears 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> otherContexts;
if (other instanceof MutableContextSet) {
otherContexts = ((MutableContextSet) other).map;
} else {
otherContexts = other.toMultimap();
}
return this.map.equals(otherContexts);
}
@Override
public int hashCode() {
return map.hashCode();
}
@Override
public String toString() {
return "MutableContextSet(contexts=" + this.map + ")";
}
}
@@ -1,61 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api.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.
*
* @since 3.0
*/
public interface EventBus {
/**
* Subscribe to an event
*
* @param eventClass the event class
* @param handler the event handler
* @param <T> the event class
* @return an event handler instance representing this subscription
*/
@Nonnull
<T extends LuckPermsEvent> EventHandler<T> subscribe(@Nonnull Class<T> eventClass, @Nonnull Consumer<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
*/
@Nonnull
<T extends LuckPermsEvent> Set<EventHandler<T>> getHandlers(@Nonnull Class<T> eventClass);
}
@@ -1,40 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.exceptions;
/**
* Thrown when an object already has something.
*
* <p>For example, when:</p>
* <p></p>
* <ul>
* <li>a permission holding object already has a permission</li>
* <li>a permission holding object is already a member of a group</li>
* <li>a track already contains a group</li>
* </ul>
*/
public class ObjectAlreadyHasException extends MembershipException {
}
@@ -1,40 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.exceptions;
/**
* Thrown when an object lacks something.
*
* <p>For example, when:</p>
* <p></p>
* <ul>
* <li>a permission holding object doesn't have a permission</li>
* <li>a permission holding object isn't already a member of a group</li>
* <li>a track doesn't contain a group</li>
* </ul>
*/
public class ObjectLacksException extends MembershipException {
}
@@ -0,0 +1,259 @@
/*
* 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 net.luckperms.api;
import net.luckperms.api.actionlog.ActionLogger;
import net.luckperms.api.context.ContextCalculator;
import net.luckperms.api.context.ContextManager;
import net.luckperms.api.event.EventBus;
import net.luckperms.api.messaging.MessagingService;
import net.luckperms.api.messenger.MessengerProvider;
import net.luckperms.api.metastacking.MetaStackDefinition;
import net.luckperms.api.metastacking.MetaStackElement;
import net.luckperms.api.metastacking.MetaStackFactory;
import net.luckperms.api.model.group.Group;
import net.luckperms.api.model.group.GroupManager;
import net.luckperms.api.model.user.User;
import net.luckperms.api.model.user.UserManager;
import net.luckperms.api.node.NodeBuilderRegistry;
import net.luckperms.api.node.matcher.NodeMatcherFactory;
import net.luckperms.api.platform.Platform;
import net.luckperms.api.platform.PlayerAdapter;
import net.luckperms.api.platform.PluginMetadata;
import net.luckperms.api.query.QueryOptionsRegistry;
import net.luckperms.api.track.Track;
import net.luckperms.api.track.TrackManager;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.jetbrains.annotations.ApiStatus.Internal;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
/**
* The LuckPerms API.
*
* <p>The API allows other plugins on the server to read and modify LuckPerms
* data, change behaviour of the plugin, listen to certain events, and integrate
* LuckPerms into other plugins and systems.</p>
*
* <p>This interface represents the base of the API package. All functions are
* accessed via this interface.</p>
*
* <p>To start using the API, you need to obtain an instance of this interface.
* These are registered by the LuckPerms plugin to the platforms Services
* Manager. This is the preferred method for obtaining an instance.</p>
*
* <p>For ease of use, and for platforms without a Service Manager, an instance
* can also be obtained from the static singleton accessor in
* {@link LuckPermsProvider}.</p>
*/
public interface LuckPerms {
/**
* Gets the name of this server.
*
* <p>This is defined in the LuckPerms configuration file, and is used for
* server specific permission handling.</p>
*
* <p>The default server name is "global".</p>
*
* @return the server name
*/
@NonNull String getServerName();
/**
* 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>
*
* @return the user manager
*/
@NonNull UserManager getUserManager();
/**
* 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>
*
* @return the group manager
*/
@NonNull GroupManager getGroupManager();
/**
* 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>
*
* @return the track manager
*/
@NonNull TrackManager getTrackManager();
/**
* Gets the {@link PlayerAdapter} instance, a utility class for adapting platform Player
* instances to {@link User}s.
*
* <p>The {@code playerClass} parameter must be equal to the class or interface used by the
* server platform to represent players.</p>
*
* <p>Specifically:</p>
*
* <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/entity.living.player.Player}</li>
* <li>{@code net.minecraft.server.network.ServerPlayerEntity} (Fabric)</li>
* <li>{@code cn.nukkit.Player}</li>
* <li>{@code com.velocitypowered.api.proxy.Player}</li>
* </ul>
*
* @param playerClass the class used by the platform to represent players
* @param <T> the player class type
* @return the player adapter
* @throws IllegalArgumentException if the player class is not correct
* @since 5.1
*/
<T> @NonNull PlayerAdapter<T> getPlayerAdapter(@NonNull Class<T> playerClass);
/**
* Gets the {@link Platform}, which represents the server platform the
* plugin is running on.
*
* @return the platform
*/
@NonNull Platform getPlatform();
/**
* Gets the {@link PluginMetadata}, responsible for providing metadata about
* the LuckPerms plugin currently running.
*
* @return the plugin metadata
*/
@NonNull PluginMetadata getPluginMetadata();
/**
* Gets the {@link EventBus}, used for subscribing to internal LuckPerms
* events.
*
* @return the event bus
*/
@NonNull EventBus getEventBus();
/**
* Gets the {@link MessagingService}, used to dispatch updates throughout a
* network of servers running the plugin.
*
* <p>Not all instances of LuckPerms will have a messaging service setup and
* configured.</p>
*
* @return the messaging service instance, if present.
*/
@NonNull Optional<MessagingService> getMessagingService();
/**
* Gets the {@link ActionLogger}, responsible for saving and broadcasting
* defined actions occurring on the platform.
*
* @return the action logger
*/
@NonNull ActionLogger getActionLogger();
/**
* Gets the {@link ContextManager}, responsible for managing
* {@link ContextCalculator}s, and calculating applicable contexts.
*
* @return the context manager
*/
@NonNull ContextManager getContextManager();
/**
* Gets the {@link MetaStackFactory}.
*
* <p>The metastack factory provides methods for retrieving
* {@link MetaStackElement}s and constructing
* {@link MetaStackDefinition}s.</p>
*
* @return the meta stack factory
*/
@NonNull MetaStackFactory getMetaStackFactory();
/**
* 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
*/
@NonNull CompletableFuture<Void> runUpdateTask();
/**
* Registers a {@link MessengerProvider} for use by the platform.
*
* <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.
*/
void registerMessengerProvider(@NonNull MessengerProvider messengerProvider);
/**
* Gets the {@link NodeBuilderRegistry}.
*
* @return the node builder registry
*/
@Internal
@NonNull NodeBuilderRegistry getNodeBuilderRegistry();
/**
* Gets the {@link QueryOptionsRegistry}.
*
* @return the query options registry
* @since 5.1
*/
@Internal
@NonNull QueryOptionsRegistry getQueryOptionsRegistry();
/**
* Gets the {@link NodeMatcherFactory}.
*
* @return the node matcher factory
* @since 5.1
*/
@Internal
@NonNull NodeMatcherFactory getNodeMatcherFactory();
}
@@ -0,0 +1,89 @@
/*
* 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 net.luckperms.api;
import org.checkerframework.checker.nullness.qual.NonNull;
import static org.jetbrains.annotations.ApiStatus.Internal;
/**
* Provides static access to the {@link LuckPerms} API.
*
* <p>Ideally, the ServiceManager for the platform should be used to obtain an
* instance, however, this provider can be used if this is not viable.</p>
*/
public final class LuckPermsProvider {
private static LuckPerms instance = null;
/**
* Gets an instance of the {@link LuckPerms} API,
* throwing {@link IllegalStateException} if the API is not loaded yet.
*
* <p>This method will never return null.</p>
*
* @return an instance of the LuckPerms API
* @throws IllegalStateException if the API is not loaded yet
*/
public static @NonNull LuckPerms get() {
LuckPerms instance = LuckPermsProvider.instance;
if (instance == null) {
throw new NotLoadedException();
}
return instance;
}
@Internal
static void register(LuckPerms instance) {
LuckPermsProvider.instance = instance;
}
@Internal
static void unregister() {
LuckPermsProvider.instance = null;
}
@Internal
private LuckPermsProvider() {
throw new UnsupportedOperationException("This class cannot be instantiated.");
}
/**
* Exception thrown when the API is requested before it has been loaded.
*/
private static final class NotLoadedException extends IllegalStateException {
private static final String MESSAGE = "The LuckPerms API isn't loaded yet!\n" +
"This could be because:\n" +
" a) the LuckPerms plugin is not installed or it failed to enable\n" +
" b) the plugin in the stacktrace does not declare a dependency on LuckPerms\n" +
" c) the plugin in the stacktrace is retrieving the API before the plugin 'enable' phase\n" +
" (call the #get method in onEnable, not the constructor!)\n";
NotLoadedException() {
super(MESSAGE);
}
}
}
@@ -0,0 +1,208 @@
/*
* 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 net.luckperms.api.actionlog;
import net.luckperms.api.LuckPermsProvider;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.time.Instant;
import java.util.Optional;
import java.util.UUID;
/**
* Represents a logged action.
*/
public interface Action extends Comparable<Action> {
/**
* Gets a {@link Action.Builder}
*
* @return a new builder
*/
static @NonNull Builder builder() {
return LuckPermsProvider.get().getActionLogger().actionBuilder();
}
/**
* Gets the time when the action occurred.
*
* @return the timestamp
*/
@NonNull Instant getTimestamp();
/**
* Gets the source of the action.
*
* @return the source
*/
@NonNull Source getSource();
/**
* Gets the target of the action.
*
* @return the target
*/
@NonNull Target getTarget();
/**
* 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 getDescription();
/**
* Represents the source of an action.
*/
interface Source {
/**
* Gets the source unique id.
*
* @return the source unique id
*/
@NonNull UUID getUniqueId();
/**
* Gets the source name.
*
* @return the source name
*/
@NonNull String getName();
}
/**
* Represents the target of an action.
*/
interface Target {
/**
* Gets the target unique id.
*
* @return the target unique id
*/
@NonNull Optional<UUID> getUniqueId();
/**
* Gets the target name.
*
* @return the target name
*/
@NonNull String getName();
/**
* Gets the target type.
*
* @return the target type
*/
@NonNull Type getType();
/**
* Represents the type of a {@link Target}.
*/
enum Type {
USER, GROUP, TRACK
}
}
/**
* Builds an {@link Action} instance
*/
interface Builder {
/**
* Sets the timestamp of the entry.
*
* @param timestamp the timestamp
* @return the builder
* @see Action#getTimestamp()
*/
@NonNull Builder timestamp(@NonNull Instant timestamp);
/**
* Sets the actor of the entry.
*
* @param actor the actor
* @return the builder
*/
@NonNull Builder source(@NonNull UUID actor);
/**
* Sets the actor name of the entry.
*
* @param actorName the actor name
* @return the builder
*/
@NonNull Builder sourceName(@NonNull String actorName);
/**
* Sets the type of the entry.
*
* @param type the type
* @return the builder
*/
@NonNull Builder targetType(Target.@NonNull Type type);
/**
* Sets the acted object for the entry.
*
* @param acted the acted object
* @return the builder
*/
@NonNull Builder target(@Nullable UUID acted);
/**
* Sets the acted name for the entry.
*
* @param actedName the acted name
* @return the builder
*/
@NonNull Builder targetName(@NonNull String actedName);
/**
* Sets the action of the entry.
*
* @param action the action
* @return the builder
*/
@NonNull Builder description(@NonNull String action);
/**
* Creates a {@link Action} instance from the builder.
*
* @return a new log entry instance
*/
@NonNull Action build();
}
}
@@ -0,0 +1,85 @@
/*
* 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 net.luckperms.api.actionlog;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.jetbrains.annotations.Unmodifiable;
import java.util.SortedSet;
import java.util.UUID;
/**
* Represents the internal LuckPerms log.
*
* <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 ActionLogger}, and then request an updated copy.</p>
*
* <p>All methods are thread safe, and return immutable and thread safe collections.</p>
*/
public interface ActionLog {
/**
* Gets the {@link Action}s that make up this log.
*
* @return the content
*/
@NonNull @Unmodifiable SortedSet<Action> getContent();
/**
* Gets the entries in the log performed by the given actor.
*
* @param actor the uuid of the actor to filter by
* @return the content for the given actor
*/
@NonNull @Unmodifiable SortedSet<Action> getContent(@NonNull UUID actor);
/**
* Gets the log content for a given user
*
* @param uniqueId the uuid to filter by
* @return all content in this log where the user = uuid
*/
@NonNull @Unmodifiable SortedSet<Action> getUserHistory(@NonNull UUID uniqueId);
/**
* 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
*/
@NonNull @Unmodifiable SortedSet<Action> getGroupHistory(@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
*/
@NonNull @Unmodifiable SortedSet<Action> getTrackHistory(@NonNull String name);
}
@@ -0,0 +1,90 @@
/*
* 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 net.luckperms.api.actionlog;
import net.luckperms.api.messaging.MessagingService;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.concurrent.CompletableFuture;
/**
* Represents the object responsible for handling action logging.
*/
public interface ActionLogger {
/**
* Returns a new {@link Action.Builder} instance
*
* @return a new builder
*/
Action.@NonNull Builder actionBuilder();
/**
* Gets a {@link ActionLog} instance from the plugin storage.
*
* @return a log instance
*/
@NonNull CompletableFuture<ActionLog> 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(Action)} and {@link #broadcastAction(Action)},
* 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 Action entry);
/**
* Submits a log entry to the plugins storage handler.
*
* @param entry the entry to submit
* @return a future which will complete when the action is done
*/
@NonNull CompletableFuture<Void> submitToStorage(@NonNull Action 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 Action entry);
}
@@ -23,10 +23,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.managers;
import me.lucko.luckperms.common.model.Group;
public interface GroupManager extends Manager<String, Group> {
}
/**
* {@link net.luckperms.api.actionlog.ActionLog} related functionality.
*/
package net.luckperms.api.actionlog;
@@ -0,0 +1,48 @@
/*
* 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 net.luckperms.api.cacheddata;
import net.luckperms.api.query.QueryOptions;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* Holds cached lookup data for a given set of query options.
*
* <p>All calls will account for inheritance, as well as any default data
* provided by the platform. These calls are heavily cached and are therefore
* fast.</p>
*/
public interface CachedData {
/**
* Gets the query options this container is holding data for.
*
* @return the query options this container is caching
*/
@NonNull QueryOptions getQueryOptions();
}
@@ -0,0 +1,248 @@
/*
* 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 net.luckperms.api.cacheddata;
import net.luckperms.api.context.ContextManager;
import net.luckperms.api.model.PermissionHolder;
import net.luckperms.api.model.group.Group;
import net.luckperms.api.model.user.User;
import net.luckperms.api.query.QueryOptions;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.concurrent.CompletableFuture;
/**
* 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. These calls are heavily cached and are therefore
* fast.</p>
*/
public interface CachedDataManager {
/**
* Gets the manager for {@link CachedPermissionData}.
*
* @return the permission data manager
*/
@NonNull Container<CachedPermissionData> permissionData();
/**
* Gets the manager for {@link CachedMetaData}.
*
* @return the meta data manager
*/
@NonNull Container<CachedMetaData> metaData();
/**
* Gets PermissionData from the cache, using the given query options.
*
* @param queryOptions the query options
* @return a permission data instance
*/
@NonNull CachedPermissionData getPermissionData(@NonNull QueryOptions queryOptions);
/**
* Gets MetaData from the cache, using the given query options.
*
* @param queryOptions the query options
* @return a meta data instance
*/
@NonNull CachedMetaData getMetaData(@NonNull QueryOptions queryOptions);
/**
* Gets PermissionData from the cache, using the most appropriate query options
* available at the time.
*
* <p>For {@link User}s, the most appropriate query options will be their
* {@link ContextManager#getQueryOptions(User) current active query options} if the
* corresponding player is online, and otherwise, will fallback to
* {@link ContextManager#getStaticQueryOptions() the current static query options}.</p>
*
* <p>For {@link Group}s, the most appropriate query options will always be
* {@link ContextManager#getStaticQueryOptions() the current static query options}.</p>
*
* @return a permission data instance
* @since 5.1
*/
@NonNull CachedPermissionData getPermissionData();
/**
* Gets MetaData from the cache, using the most appropriate query options
* available at the time.
*
* <p>For {@link User}s, the most appropriate query options will be their
* {@link ContextManager#getQueryOptions(User) current active query options} if the
* corresponding player is online, and otherwise, will fallback to
* {@link ContextManager#getStaticQueryOptions() the current static query options}.</p>
*
* <p>For {@link Group}s, the most appropriate query options will always be
* {@link ContextManager#getStaticQueryOptions() the current static query options}.</p>
*
* @return a meta data instance
* @since 5.1
* @see PermissionHolder#getQueryOptions()
*/
@NonNull CachedMetaData getMetaData();
/**
* Invalidates all cached {@link CachedPermissionData} and {@link CachedMetaData}
* instances.
*/
void invalidate();
/**
* Invalidates all underlying permission calculators.
*
* <p>Can be called to allow for an update in defaults.</p>
*/
void invalidatePermissionCalculators();
/**
* Manages a specific type of {@link CachedData cached data} within
* a {@link CachedDataManager} instance.
*
* @param <T> the data type
*/
interface Container<T extends CachedData> {
/**
* Gets {@link T data} from the cache.
*
* @param queryOptions the query options
* @return a data instance
* @throws NullPointerException if contexts is null
*/
@NonNull T get(@NonNull QueryOptions queryOptions);
/**
* Calculates {@link T 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 #get(QueryOptions)} instead.</p>
*
* <p>The use cases of this method are more around constructing one-time
* instances of {@link T data}, without adding the result to the cache.</p>
*
* @param queryOptions the query options
* @return a data instance
* @throws NullPointerException if contexts is null
*/
@NonNull T calculate(@NonNull QueryOptions queryOptions);
/**
* (Re)calculates 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 data instance associated with
* the given {@link QueryOptions}, then that instance will continue to be returned by
* {@link #get(QueryOptions)} 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 queryOptions the query options
* @throws NullPointerException if contexts is null
*/
void recalculate(@NonNull QueryOptions queryOptions);
/**
* (Re)loads permission data for a given context.
*
* <p>Unlike {@link #recalculate(QueryOptions)}, this method immediately
* invalidates any previous data values contained within the cache,
* and then schedules a task to reload a new data 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 #get(QueryOptions)} 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 queryOptions the query options.
* @return a future
* @throws NullPointerException if contexts is null
*/
@NonNull CompletableFuture<? extends T> reload(@NonNull QueryOptions queryOptions);
/**
* Recalculates 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 data instances will continue to be returned
* by {@link #get(QueryOptions)} until the recalculation is completed.</p>
*/
void recalculate();
/**
* Reloads permission data for all known contexts.
*
* <p>Unlike {@link #recalculate()}, this method immediately
* invalidates all previous data values contained within the cache,
* and then schedules a task to reload new data 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 #get(QueryOptions)} 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
*/
@NonNull CompletableFuture<Void> reload();
/**
* Invalidates any cached data instances mapped to the given context.
*
* @param queryOptions the queryOptions to invalidate for
*/
void invalidate(@NonNull QueryOptions queryOptions);
/**
* Invalidates all cached data instances.
*/
void invalidate();
}
}
@@ -0,0 +1,231 @@
/*
* 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 net.luckperms.api.cacheddata;
import net.luckperms.api.metastacking.MetaStackDefinition;
import net.luckperms.api.node.types.MetaNode;
import net.luckperms.api.node.types.PrefixNode;
import net.luckperms.api.node.types.SuffixNode;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.jetbrains.annotations.Unmodifiable;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.SortedMap;
import java.util.function.Function;
/**
* Holds cached meta lookup data for a specific set of contexts.
*
* <p>Meta data refers to {@link PrefixNode prefixes}, {@link SuffixNode suffixes} and
* {@link MetaNode meta (options)} held by a permission holder.</p>
*
* <p>All calls will account for inheritance, as well as any default data
* provided by the platform. These calls are heavily cached and are therefore
* fast.</p>
*/
public interface CachedMetaData extends CachedData {
/**
* Query a meta value for the given {@code key}.
*
* <p>This method will always return a {@link Result}, but the
* {@link Result#result() inner result} {@link String} will be null if a value
* for the given key was not found.</p>
*
* @param key the key
* @return a result containing the value
* @since 5.4
*/
@NonNull Result<String, MetaNode> queryMetaValue(@NonNull String key);
/**
* Gets a value for the given meta key.
*
* <p>If no such meta value exists for the given key, {@code null} is returned.</p>
*
* @param key the key
* @return the value
*/
default @Nullable String getMetaValue(@NonNull String key) {
return queryMetaValue(key).result();
}
/**
* Gets a value for the given meta key, and runs it through the given {@code transformer}.
*
* <p>If no such meta value exists, an {@link Optional#empty() empty optional} is returned.
* (the transformer will never be passed a null argument)</p>
*
* <p>The transformer is allowed to throw {@link IllegalArgumentException} or return null. This
* will also result in an {@link Optional#empty() empty optional} being returned.</p>
*
* <p>For example, to parse and return an integer meta value, use:</p>
* <p><blockquote><pre>
* getMetaValue("my-int-val", Integer::parseInt).orElse(0);
* </pre></blockquote>
*
* @param key the key
* @param valueTransformer the transformer used to transform the value
* @param <T> the type of the transformed result
* @return the meta value
* @since 5.3
*/
default <T> @NonNull Optional<T> getMetaValue(@NonNull String key, @NonNull Function<String, ? extends T> valueTransformer) {
return Optional.ofNullable(getMetaValue(key)).map(value -> {
try {
return valueTransformer.apply(value);
} catch (IllegalArgumentException e) {
return null;
}
});
}
/**
* Query for a prefix.
*
* <p>This method uses the rules defined by the {@link #getPrefixStackDefinition() prefix stack}
* to produce a {@link String} output.</p>
*
* <p>Assuming the default configuration is used, this will usually be the value of the
* holder's highest priority prefix node.</p>
*
* <p>This method will always return a {@link Result}, but the
* {@link Result#result() inner result} {@link String} will be null if
* a the resultant prefix stack contained no elements.</p>
*
* @return a result containing the prefix
* @since 5.4
*/
@NonNull Result<String, PrefixNode> queryPrefix();
/**
* Gets the prefix.
*
* <p>This method uses the rules defined by the {@link #getPrefixStackDefinition() prefix stack}
* to produce a {@link String} output.</p>
*
* <p>Assuming the default configuration is used, this will usually be the value of the
* holder's highest priority prefix node.</p>
*
* <p>If the resultant prefix stack contained no elements, {@code null} is returned.</p>
*
* @return a prefix string, or null
*/
default @Nullable String getPrefix() {
return queryPrefix().result();
}
/**
* Query for a suffix.
*
* <p>This method uses the rules defined by the {@link #getSuffixStackDefinition() suffix stack}
* to produce a {@link String} output.</p>
*
* <p>Assuming the default configuration is used, this will usually be the value of the
* holder's highest priority suffix node.</p>
*
* <p>This method will always return a {@link Result}, but the
* {@link Result#result() inner result} {@link String} will be null if
* a the resultant suffix stack contained no elements.</p>
*
* @return a result containing the suffix
* @since 5.4
*/
@NonNull Result<String, SuffixNode> querySuffix();
/**
* Gets the suffix.
*
* <p>This method uses the rules defined by the {@link #getSuffixStackDefinition() suffix stack}
* to produce a {@link String} output.</p>
*
* <p>Assuming the default configuration is used, this will usually be the value of the
* holder's highest priority suffix node.</p>
*
* <p>If the resultant suffix stack contained no elements, {@code null} is returned.</p>
*
* @return a suffix string, or null
*/
default @Nullable String getSuffix() {
return querySuffix().result();
}
/**
* Gets a map of all accumulated {@link MetaNode meta}.
*
* <p>Prefer using the {@link #getMetaValue(String)} method for querying values.</p>
*
* @return a map of meta
*/
@NonNull @Unmodifiable Map<String, List<String>> getMeta();
/**
* Gets a sorted map of all accumulated {@link PrefixNode prefixes}.
*
* <p>Prefer using the {@link #getPrefix()} method for querying.</p>
*
* @return a sorted map of prefixes
*/
@NonNull @Unmodifiable SortedMap<Integer, String> getPrefixes();
/**
* Gets a sorted map of all accumulated {@link SuffixNode suffixes}.
*
* <p>Prefer using the {@link #getSuffix()} method for querying.</p>
*
* @return a sorted map of suffixes
*/
@NonNull @Unmodifiable SortedMap<Integer, String> getSuffixes();
/**
* Gets the name of the holders primary group.
*
* <p>Will return {@code null} for Group holder types.</p>
*
* @return the name of the primary group
* @since 5.1
*/
@Nullable String getPrimaryGroup();
/**
* Gets the definition used for the prefix stack.
*
* @return the definition used for the prefix stack
*/
@NonNull MetaStackDefinition getPrefixStackDefinition();
/**
* Gets the definition used for the suffix stack.
*
* @return the definition used for the suffix stack
*/
@NonNull MetaStackDefinition getSuffixStackDefinition();
}
@@ -0,0 +1,86 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.luckperms.api.cacheddata;
import net.luckperms.api.node.Node;
import net.luckperms.api.util.Tristate;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.jetbrains.annotations.Unmodifiable;
import java.util.Map;
/**
* Holds cached permission lookup data for a specific set of contexts.
*
* <p>All calls will account for inheritance, as well as any default data
* provided by the platform. These calls are heavily cached and are therefore
* fast.</p>
*/
public interface CachedPermissionData extends CachedData {
/**
* Performs a permission check for the given {@code permission} node.
*
* <p>This check is equivalent to the "hasPermission" method call on most platforms.
* You can use {@link Tristate#asBoolean()} if you need a truthy result.</p>
*
* @param permission the permission node
* @return a result containing the tristate
* @throws NullPointerException if permission is null
* @since 5.4
*/
@NonNull Result<Tristate, Node> queryPermission(@NonNull String permission);
/**
* Performs a permission check for the given {@code permission} node.
*
* <p>This check is equivalent to the "hasPermission" method call on most platforms.
* You can use {@link Tristate#asBoolean()} if you need a truthy result.</p>
*
* @param permission the permission node
* @return a tristate result
* @throws NullPointerException if permission is null
*/
default @NonNull Tristate checkPermission(@NonNull String permission) {
return queryPermission(permission).result();
}
/**
* Invalidates the underlying permission calculator cache.
*
* <p>Can be called to allow for an update in defaults.</p>
*/
void invalidateCache();
/**
* Gets an immutable copy of the permission map backing the permission calculator
*
* @return an immutable set of permissions
*/
@NonNull @Unmodifiable Map<String, Boolean> getPermissionMap();
}
@@ -0,0 +1,82 @@
/*
* 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 net.luckperms.api.cacheddata;
import net.luckperms.api.node.Node;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Represents the result of a cached data lookup.
*
* <p>You can find "the holder that has the node that caused this result"
* using the following code:</p>
* <p></p>
* <blockquote>
* <pre>
* public static {@link net.luckperms.api.model.PermissionHolder.Identifier} holderThatHasTheNodeThatCausedTheResult(Result&lt;?, ?&gt; result) {
* {@link Node} node = result.node();
* if (node == null) {
* return null;
* }
* {@link net.luckperms.api.node.metadata.types.InheritanceOriginMetadata} origin = node.getMetadata(InheritanceOriginMetadata.KEY).orElse(null);
* if (origin == null) {
* return null;
* }
* return origin.getOrigin();
* }
* </pre>
*
* <p>Combined with the node itself, this is all the information needed to determine
* the root cause of the result.</p>
* </blockquote>
*
* <p>The nullability of {@link #result()} is purposely undefined to allow the
* flexibility for methods using {@link Result} to declare it. In general, if the {@code T} type
* has a nullable/undefined value, then the return of {@link #result()} will be non-null,
* and if not, it will be nullable.</p>
*
* @param <T> the result type
* @param <N> the node type
* @since 5.4
*/
public interface Result<T, N extends Node> {
/**
* Gets the underlying result.
*
* @return the underlying result
*/
T result();
/**
* Gets the node that caused the result.
*
* @return the causing node
*/
@Nullable N node();
}
@@ -0,0 +1,30 @@
/*
* 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.
*/
/**
* Caches permission checks and meta lookups for {@link net.luckperms.api.model.user.User}s and
* {@link net.luckperms.api.model.group.Group}s.
*/
package net.luckperms.api.cacheddata;
@@ -0,0 +1,101 @@
/*
* 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 net.luckperms.api.context;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Represents an individual context pair.
*
* <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>
*
* @see ContextSet
*/
public interface Context {
/**
* Tests whether {@code key} is valid.
*
* <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>An exception is thrown when an invalid key is added to a {@link ContextSet}.</p>
*
* @param key the key to test
* @return true if valid, false otherwise.
* @since 5.1
*/
static boolean isValidKey(@Nullable String key) {
if (key == null || key.isEmpty()) {
return false;
}
// look for a non-whitespace character
for (int i = 0, n = key.length(); i < n; i++) {
if (key.charAt(i) != ' ') {
return true;
}
}
return false;
}
/**
* Tests whether {@code value} is valid.
*
* <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>An exception is thrown when an invalid value is added to a {@link ContextSet}.</p>
*
* @param value the value to test
* @return true if valid, false otherwise.
* @since 5.1
*/
static boolean isValidValue(@Nullable String value) {
return isValidKey(value); // the same for now...
}
/**
* Gets the context key.
*
* @return the key
*/
@NonNull String getKey();
/**
* Gets the context value
*
* @return the value
*/
@NonNull String getValue();
}
@@ -0,0 +1,110 @@
/*
* 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 net.luckperms.api.context;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Objects;
import java.util.function.Function;
/**
* Calculates the contexts applicable for a contextual subject.
*
* <p>Implementations of this interface should satisfy the following
* requirements:</p>
* <ul>
* <li>Context lookups should be <i>fast</i>: lookup methods are likely to
* be invoked frequently, and should therefore be fast to execute. If
* determining the current contexts involves a particularly time consuming
* lookup (database queries, network requests, etc), then such results
* should be cached ahead of time.</li>
*
* <li>Context lookups should be <i>thread-safe</i>: lookups will sometimes
* be performed from "async" threads, and therefore should not access any
* part of the server only safe for access from a sync context. If
* necessary, such results should be determined ahead of time and stored in
* a thread-safe collection for retrieval later.</li>
*
* <li>Context lookups should <i>not query active contexts</i>: doing so is
* likely to result in a stack overflow, or thread deadlock. Care should be
* taken to avoid (indirect) calls to the same calculator.</li>
* </ul>
* <p></p>
*
* <p>Calculators should be registered using
* {@link ContextManager#registerCalculator(ContextCalculator)}.</p>
*/
@FunctionalInterface
public interface ContextCalculator<T> {
/**
* Creates a new {@link ContextCalculator} that provides a single context.
*
* @param key the key of the context provided by the calculator
* @param valueFunction the function used to compute the corresponding value
* for each query. A context will not be "accumulated"
* if the value returned is null.
* @param <T> the contextual type
* @return the resultant calculator
*/
static <T> @NonNull ContextCalculator<T> forSingleContext(@NonNull String key, @NonNull Function<T, String> valueFunction) {
Objects.requireNonNull(key, "key");
Objects.requireNonNull(valueFunction, "valueFunction");
return (target, consumer) -> {
String value = valueFunction.apply(target);
if (value != null) {
consumer.accept(key, value);
}
};
}
/**
* Submits any contexts this calculator determines to be applicable to
* the {@code target} contextual subject.
*
* <p>Care should be taken to ensure implementations of this method meet the
* general requirements for {@link ContextCalculator}, defined in the class
* doc.</p>
*
* @param target the target contextual subject for this operation
* @param consumer the {@link ContextConsumer} to submit contexts to
*/
void calculate(@NonNull T target, @NonNull ContextConsumer consumer);
/**
* Gets a {@link ContextSet}, containing some/all of the contexts this
* calculator could potentially submit.
*
* <p>The result of this call is primarily intended on providing
* suggestions to end users when defining permissions.</p>
*
* @return a set of potential contexts
*/
default @NonNull ContextSet estimatePotentialContexts() {
return ImmutableContextSet.empty();
}
}
@@ -23,34 +23,42 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.processors;
package net.luckperms.api.context;
import me.lucko.luckperms.api.Tristate;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* A processor within a {@link me.lucko.luckperms.common.calculators.PermissionCalculator}.
* Functional interface that accepts context key value pairs.
*/
public interface PermissionProcessor {
@FunctionalInterface
public interface ContextConsumer {
/**
* Returns the permission value determined by this calculator.
* Accepts a context pair.
*
* @param permission the permission
* @return a tristate
* @param key the key
* @param value the value
*/
Tristate hasPermission(String permission);
void accept(@NonNull String key, @NonNull String value);
/**
* Called each time the permission calculators backing is updated.
* Accepts a context pair.
*
* <p>Note that the same map instance is passed to this method on each update,
* so, if no processing is needed on the backing map, this can be cached on
* the first invocation.</p>
*
* @param map the map
* @param context the context
*/
void updateBacking(Map<String, Boolean> map);
default void accept(@NonNull Context context) {
accept(context.getKey(), context.getValue());
}
/**
* Accepts a context set.
*
* @param contextSet the context set
*/
default void accept(@NonNull ContextSet contextSet) {
for (Context entry : contextSet) {
accept(entry);
}
}
}
@@ -0,0 +1,175 @@
/*
* 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 net.luckperms.api.context;
import net.luckperms.api.model.user.User;
import net.luckperms.api.query.QueryMode;
import net.luckperms.api.query.QueryOptions;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.jetbrains.annotations.ApiStatus.Internal;
import java.util.Optional;
/**
* Manages {@link ContextCalculator}s, and calculates applicable contexts for a
* given type.
*
* <p>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.</p>
*
* <p>Specifically:</p>
*
* <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>
* <li>{@code net.minecraft.server.network.ServerPlayerEntity} (Fabric)</li>
* <li>{@code cn.nukkit.Player}</li>
* <li>{@code com.velocitypowered.api.proxy.Player}</li>
* </ul>
*/
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 getContext(@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 obtain a {@link ImmutableContextSet} 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> getContext(@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();
/**
* Creates a new {@link QueryOptions.Builder}.
*
* @param mode the mode
* @return a new query options builder
*/
QueryOptions.@NonNull Builder queryOptionsBuilder(@NonNull QueryMode mode);
/**
* Obtains current {@link QueryOptions} for the subject.
*
* @param subject the subject
* @return the query options for the subject
*/
@NonNull QueryOptions getQueryOptions(@NonNull Object subject);
/**
* Obtains current {@link QueryOptions} 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 obtain a {@link QueryOptions} instance regardless, you should
* initially try this method, and then fallback on {@link #getStaticQueryOptions()}.</p>
*
* @param user the user
* @return the query options for the subject
*/
@NonNull Optional<QueryOptions> getQueryOptions(@NonNull User user);
/**
* Gets the static query options, using the registered static context calculators.
*
* @return the current static query options
*/
@NonNull QueryOptions getStaticQueryOptions();
/**
* Registers a context calculator with the manager.
*
* @param calculator the calculator
*/
void registerCalculator(@NonNull ContextCalculator<?> calculator);
/**
* Unregisters a context calculator with the manager.
*
* @param calculator the calculator
*/
void unregisterCalculator(@NonNull ContextCalculator<?> calculator);
/**
* Signal to the {@link ContextManager} that a {@code subject}s
* current contexts have changed.
*
* <p>It is not strictly necessary to make a call to this method every time a context
* changes.</p>
*
* @param subject the subject
* @since 5.2
*/
void signalContextUpdate(@NonNull Object subject);
/**
* Gets the {@link ContextSetFactory}, responsible for creating
* {@link ContextSet} instances.
*
* @return the context set factory
*/
@Internal
@NonNull ContextSetFactory getContextSetFactory();
/**
* Invalidates the lookup cache for a given subject
*
* @param subject the subject
* @deprecated Use {@link #signalContextUpdate(Object)} instead
*/
@Deprecated
default void invalidateCache(@NonNull Object subject) {
signalContextUpdate(subject);
}
}
@@ -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 net.luckperms.api.context;
import net.luckperms.api.query.OptionKey;
/**
* Mode for determining whether a {@link ContextSet} satisfies another.
*
* @since 5.2
* @see ContextSet#isSatisfiedBy(ContextSet, ContextSatisfyMode)
*/
public enum ContextSatisfyMode {
/**
* Mode where a {@link ContextSet} A will be satisfied by another set B, if at least one of the
* key-value entries per key in A are also in B.
*
* <p>For example, given <code>A = {server=survival, world=overworld, world=nether}</code>,
* another set {@code X} will satisfy {@code A} if {@code X} contains
* <code>server=survival AND (world=overworld OR world=nether)</code>.</p>
*/
AT_LEAST_ONE_VALUE_PER_KEY,
/**
* Mode where a {@link ContextSet} A will be satisfied by another set B, if all key-value
* entries in A are also in B.
*
* <p>For example, given <code>A = {server=survival, world=overworld, world=nether}</code>,
* another set {@code X} will satisfy {@code A} if {@code X} contains
* <code>server=survival AND world=overworld AND world=nether</code>.</p>
*/
ALL_VALUES_PER_KEY;
/**
* The {@link OptionKey} for {@link ContextSatisfyMode}.
*/
public static final OptionKey<ContextSatisfyMode> KEY = OptionKey.of("contextsatisfymode", ContextSatisfyMode.class);
}
@@ -0,0 +1,271 @@
/*
* 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 net.luckperms.api.context;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.jetbrains.annotations.Unmodifiable;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
/**
* A set of contexts.
*
* <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
* describes the type of the context, and the value represents what the key is
* set to.</p>
*
* <p>For example, a context with {@code key=world} and {@code value=world_nether}
* describes that a subject is in the "world_nether" world.</p>
*
* <p>Contexts are exposed to end users and manipulated when managing permissions.
* For this reason, context keys should strike a balance between being descriptive
* and succinct.</p>
*
* <p>Context keys and values are case-insensitive, and will be automatically
* converted to {@link String#toLowerCase() lowercase} when added to a
* context set. Keys and values cannot be null or empty (len=0 or consisting of
* only whitespace).</p>
*
* <p>If a context key is formed of more than one word, the parts should be
* separated by the '{@code -}' character. (e.g. "{@code server-type}")</p>
*
* <p>If a context key is likely to conflict with another plugin, it should be
* appropriately namespaced using the name of the plugin providing the context.
* The namespace should be at the start of the context key, and separated using
* the '{@code :}' character. (e.g. "{@code worldguard:region}" for WorldGuard
* regions)</p>
*
* <p>Contexts can be combined with each other to form so called
* "context sets" - simply a collection of context pairs.</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>
*/
public interface ContextSet extends Iterable<Context> {
/**
* 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();
/**
* Returns an immutable representation of this {@link 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 immutableCopy();
/**
* 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
*/
@NonNull MutableContextSet mutableCopy();
/**
* Returns a {@link Set} of {@link Context}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 @Unmodifiable Set<Context> toSet();
/**
* Returns a {@link Map} 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 a map
*/
@NonNull @Unmodifiable Map<String, Set<String>> toMap();
/**
* Returns a {@link Map} <b>loosely</b> representing the current state of
* this {@link ContextSet}.
*
* <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>
*
* @return an immutable map
* @deprecated Deprecated because the returned map may not contain all data in the ContextSet
*/
@Deprecated
@NonNull @Unmodifiable Map<String, String> toFlattenedMap();
/**
* 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
*/
@Override
@NonNull @Unmodifiable Iterator<Context> 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(@NonNull String key);
/**
* Returns a {@link Set} of the values mapped to the given key.
*
* <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
*/
@NonNull @Unmodifiable Set<String> getValues(@NonNull String key);
/**
* 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
*/
default @NonNull Optional<String> getAnyValue(@NonNull String key) {
return getValues(key).stream().findAny();
}
/**
* 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 context pair
* @throws NullPointerException if the key or value is null
*/
boolean contains(@NonNull String key, @NonNull String value);
/**
* 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 contains(@NonNull Context entry) {
Objects.requireNonNull(entry, "entry");
return contains(entry.getKey(), entry.getValue());
}
/**
* Returns if the {@link ContextSet} contains any of the given context pairings.
*
* @param key the key to look for
* @param values the values to look for
* @return true if the set contains any of the pairs
* @since 5.2
*/
default boolean containsAny(@NonNull String key, @NonNull Iterable<String> values) {
Objects.requireNonNull(key, "key");
Objects.requireNonNull(values, "values");
for (String value : values) {
if (contains(key, value)) {
return true;
}
}
return false;
}
/**
* Returns if this {@link ContextSet} is "satisfied" by another set.
*
* <p>{@link ContextSatisfyMode#AT_LEAST_ONE_VALUE_PER_KEY} is the mode used by this method.</p>
*
* @param other the other set
* @return true if this context set is satisfied by the other
*/
default boolean isSatisfiedBy(@NonNull ContextSet other) {
return isSatisfiedBy(other, ContextSatisfyMode.AT_LEAST_ONE_VALUE_PER_KEY);
}
/**
* Returns if this {@link ContextSet} is "satisfied" by another set, according to the given
* {@code mode}.
*
* @param other the other set
* @param mode the mode to use
* @return true if this context set is satisfied by the other
* @since 5.2
*/
boolean isSatisfiedBy(@NonNull ContextSet other, @NonNull ContextSatisfyMode mode);
/**
* Returns if the {@link ContextSet} is empty.
*
* @return true if the set is empty
*/
boolean isEmpty();
/**
* Gets the number of context pairs in the {@link ContextSet}.
*
* @return the size of the set
*/
int size();
}
@@ -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 net.luckperms.api.context;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.jetbrains.annotations.ApiStatus.Internal;
/**
* A factory for creating {@link ContextSet}s.
*
* <p>Prefer using the static methods on {@link ImmutableContextSet} or {@link MutableContextSet}
* instead of this interface.</p>
*/
@Internal
public interface ContextSetFactory {
/**
* Prefer using {@link ImmutableContextSet#builder()}.
*
* @return a immutable context set builder
* @see ImmutableContextSet#builder()
*/
ImmutableContextSet.@NonNull Builder immutableBuilder();
/**
* Prefer using {@link ImmutableContextSet#of(String, String)}.
*
* @param key the key
* @param value the value
* @return an immutable context set
* @see ImmutableContextSet#of(String, String)
*/
@NonNull ImmutableContextSet immutableOf(@NonNull String key, @NonNull String value);
/**
* Prefer using {@link ImmutableContextSet#empty()}.
*
* @return an empty immutable context set
* @see ImmutableContextSet#empty()
*/
@NonNull ImmutableContextSet immutableEmpty();
/**
* Prefer using {@link MutableContextSet#create()}.
*
* @return a new mutable context set
* @see MutableContextSet#create()
*/
@NonNull MutableContextSet mutable();
}
@@ -23,47 +23,42 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.metastacking;
import me.lucko.luckperms.api.LocalizedNode;
import me.lucko.luckperms.api.metastacking.MetaStackElement;
import java.util.Map;
import java.util.Optional;
package net.luckperms.api.context;
/**
* Represents a specific entry in a {@link MetaStack}.
* An entry is basically a live/mutable version of a {@link MetaStackElement}.
* Some default context keys used by the plugin.
*/
public interface MetaStackEntry {
public final class DefaultContextKeys {
private DefaultContextKeys() {
throw new AssertionError();
}
/**
* Gets the stack this entry belongs to.
*
* @return the parent stack
* The context key used to denote the name of the subjects server.
*/
MetaStack getParentStack();
public static final String SERVER_KEY = "server";
/**
* Gets the element this entry was formed form
*
* @return the forming element
* The context key used to denote the name of the subjects world.
*/
MetaStackElement getElement();
public static final String WORLD_KEY = "world";
/**
* Gets the value currently held by this entry.
* The context key used to denote the dimension type of the subjects world.
*
* @return the entry
* <p>Possible values: overworld, the_nether, the_end</p>
*
* @since 5.3
*/
Optional<Map.Entry<Integer, String>> getCurrentValue();
public static final String DIMENSION_TYPE_KEY = "dimension-type";
/**
* Accumulates a node to this entry
* The context key used to denote the subjects gamemode.
*
* @param node the node to accumulate
* @return if the node was accepted
* <p>Possible values: survival, creative, adventure, spectator</p>
*
* @since 5.3
*/
boolean accumulateNode(LocalizedNode node);
public static final String GAMEMODE_KEY = "gamemode";
}
@@ -0,0 +1,139 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.luckperms.api.context;
import net.luckperms.api.LuckPermsProvider;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Objects;
/**
* An immutable implementation of {@link ContextSet}.
*/
public interface ImmutableContextSet extends ContextSet {
/**
* Creates an {@link ImmutableContextSet.Builder}.
*
* @return a new ImmutableContextSet builder
*/
static @NonNull Builder builder() {
return LuckPermsProvider.get().getContextManager().getContextSetFactory().immutableBuilder();
}
/**
* Returns an empty {@link ImmutableContextSet}.
*
* @return an empty ImmutableContextSet
*/
static @NonNull ImmutableContextSet empty() {
return LuckPermsProvider.get().getContextManager().getContextSetFactory().immutableEmpty();
}
/**
* 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
*/
static @NonNull ImmutableContextSet of(@NonNull String key, @NonNull String value) {
return LuckPermsProvider.get().getContextManager().getContextSetFactory().immutableOf(key, value);
}
/**
* @deprecated This context set is already immutable!
*/
@Override
@Deprecated
@NonNull ImmutableContextSet immutableCopy();
/**
* A builder for {@link ImmutableContextSet}.
*/
interface Builder {
/**
* 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 Builder add(@NonNull String key, @NonNull String value);
/**
* 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(Context)
*/
default @NonNull Builder add(@NonNull Context 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)
*/
default @NonNull Builder addAll(@NonNull Iterable<Context> iterable) {
for (Context e : Objects.requireNonNull(iterable, "iterable")) {
add(e);
}
return this;
}
/**
* Adds all 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 Builder addAll(@NonNull ContextSet contextSet);
/**
* Creates a {@link ImmutableContextSet} from the values previously
* added to the builder.
*
* @return an {@link ImmutableContextSet} from the builder
*/
@NonNull ImmutableContextSet build();
}
}
@@ -0,0 +1,126 @@
/*
* 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 net.luckperms.api.context;
import net.luckperms.api.LuckPermsProvider;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Objects;
/**
* A mutable implementation of {@link ContextSet}.
*/
public interface MutableContextSet extends ContextSet {
/**
* Creates a new empty MutableContextSet.
*
* @return a new MutableContextSet
*/
static @NonNull MutableContextSet create() {
return LuckPermsProvider.get().getContextManager().getContextSetFactory().mutable();
}
/**
* Creates a {@link MutableContextSet} from a context pair.
*
* @param key the key
* @param value the value
* @return a new MutableContextSet containing one context pair
* @throws NullPointerException if key or value is null
*/
static @NonNull MutableContextSet of(@NonNull String key, @NonNull String value) {
Objects.requireNonNull(key, "key");
Objects.requireNonNull(value, "value");
MutableContextSet set = create();
set.add(key, value);
return 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
*/
void add(@NonNull String key, @NonNull String value);
/**
* Adds a context to this set.
*
* @param entry the entry to add
* @throws NullPointerException if the entry is null
*/
default void add(@NonNull Context entry) {
Objects.requireNonNull(entry, "entry");
add(entry.getKey(), entry.getValue());
}
/**
* 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
*/
default void addAll(@NonNull Iterable<Context> iterable) {
for (Context e : Objects.requireNonNull(iterable, "iterable")) {
add(e);
}
}
/**
* Adds all the contexts in another {@link ContextSet} to this set.
*
* @param contextSet the set to add from
* @throws NullPointerException if the contextSet is null
*/
void addAll(@NonNull ContextSet contextSet);
/**
* 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
*/
void remove(@NonNull String key, @NonNull String value);
/**
* Removes all contexts from this set with the given key.
*
* @param key the key to remove
* @throws NullPointerException if the key is null
*/
void removeAll(@NonNull String key);
/**
* Removes all contexts from the set.
*/
void clear();
}
@@ -0,0 +1,75 @@
/*
* 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 net.luckperms.api.context;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Objects;
import java.util.function.Supplier;
/**
* Extension of {@link ContextCalculator} which provides the same context
* regardless of the subject.
*/
@FunctionalInterface
public interface StaticContextCalculator extends ContextCalculator<Object> {
/**
* Creates a new {@link StaticContextCalculator} that provides a single context.
*
* @param key the key of the context provided by the calculator
* @param valueFunction the function used to compute the corresponding value
* for each query. A context will not be "accumulated"
* if the value returned is null.
* @return the resultant calculator
*/
static StaticContextCalculator forSingleContext(String key, Supplier<String> valueFunction) {
Objects.requireNonNull(key, "key");
Objects.requireNonNull(valueFunction, "valueFunction");
return consumer -> {
String value = valueFunction.get();
if (value != null) {
consumer.accept(key, value);
}
};
}
/**
* Submits any contexts this calculator determines to be applicable.
*
* <p>Care should be taken to ensure implementations of this method meet the
* general requirements for {@link ContextCalculator}, defined in the class
* doc.</p>
*
* @param consumer the {@link ContextConsumer} to submit contexts to
*/
void calculate(@NonNull ContextConsumer consumer);
@Override
default void calculate(@NonNull Object target, @NonNull ContextConsumer consumer) {
calculate(consumer);
}
}
@@ -0,0 +1,30 @@
/*
* 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.
*/
/**
* Context functionality, including {@link net.luckperms.api.context.ContextSet}s and
* {@link net.luckperms.api.context.ContextCalculator}s.
*/
package net.luckperms.api.context;
@@ -0,0 +1,84 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.luckperms.api.event;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.jetbrains.annotations.Unmodifiable;
import java.util.Set;
import java.util.function.Consumer;
/**
* The LuckPerms event bus.
*
* <p>Used to subscribe (or "listen") to LuckPerms events.</p>
*/
public interface EventBus {
/**
* Registers a new subscription to the given event.
*
* <p>The returned {@link EventSubscription} 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> @NonNull EventSubscription<T> subscribe(@NonNull Class<T> eventClass, @NonNull Consumer<? super T> handler);
/**
* Registers a new subscription to the given event.
*
* <p>The returned {@link EventSubscription} 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 EventSubscription#close() 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
*/
<T extends LuckPermsEvent> @NonNull EventSubscription<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> @NonNull @Unmodifiable Set<EventSubscription<T>> getSubscriptions(@NonNull Class<T> eventClass);
}
@@ -23,26 +23,25 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.event;
package net.luckperms.api.event;
import org.checkerframework.checker.nullness.qual.NonNull;
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 EventSubscription<T extends LuckPermsEvent> extends AutoCloseable {
/**
* Gets the class this handler is listening to
*
* @return the event class
*/
@Nonnull
Class<T> getEventClass();
@NonNull Class<T> getEventClass();
/**
* Returns true if this handler is active
@@ -52,25 +51,15 @@ public interface EventHandler<T extends LuckPermsEvent> {
boolean isActive();
/**
* Unregisters this handler from the event bus
*
* @return true if the handler wasn't already unregistered
* Unregisters this handler from the event bus.
*/
boolean unregister();
@Override
void close();
/**
* Gets the event consumer responsible for handling the event
*
* @return the event consumer
*/
@Nonnull
Consumer<T> getConsumer();
/**
* Gets the number of times this handler has been called
*
* @return the number of times this handler has been called
*/
int getCallCount();
@NonNull Consumer<? super T> getHandler();
}
@@ -23,16 +23,14 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.event;
package net.luckperms.api.event;
import me.lucko.luckperms.api.LuckPermsApi;
import net.luckperms.api.LuckPerms;
import javax.annotation.Nonnull;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* The base event interface
*
* @since 3.0
* A superinterface for all LuckPerms events.
*/
public interface LuckPermsEvent {
@@ -41,7 +39,13 @@ public interface LuckPermsEvent {
*
* @return the api instance
*/
@Nonnull
LuckPermsApi getApi();
@NonNull LuckPerms getLuckPerms();
/**
* Gets the type of the event.
*
* @return the type of the event
*/
@NonNull Class<? extends LuckPermsEvent> getEventType();
}
@@ -23,7 +23,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.event.cause;
package net.luckperms.api.event.cause;
/**
* The cause of a group/track creation
@@ -35,6 +35,11 @@ public enum CreationCause {
*/
COMMAND,
/**
* The creation was caused by the web editor
*/
WEB_EDITOR,
/**
* The creation was caused by an API call
*/
@@ -23,7 +23,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.event.cause;
package net.luckperms.api.event.cause;
/**
* The cause of a group/track deletion
@@ -35,6 +35,12 @@ public enum DeletionCause {
*/
COMMAND,
/**
* The deletion was caused by the web editor
* @since 5.3
*/
WEB_EDITOR,
/**
* The deletion was caused by an API call
*/
@@ -0,0 +1,29 @@
/*
* 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.
*/
/**
* Event causes.
*/
package net.luckperms.api.event.cause;
@@ -0,0 +1,76 @@
/*
* 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 net.luckperms.api.event.context;
import net.luckperms.api.context.ContextManager;
import net.luckperms.api.event.LuckPermsEvent;
import net.luckperms.api.event.util.Param;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Optional;
/**
* Called when a subject's current/active contexts are updated.
*
* <p>There are no guarantees that this event will be called for every update. It is merely to be
* used as a "hint" for plugins which depend on the current active contexts for a player.</p>
*
* <p>It will always be fired following a call to
* {@link ContextManager#signalContextUpdate(Object)}.</p>
*
* <p>The {@link #getSubject() subject} is always an instance of the platform's subject type. See
* {@link ContextManager} for details.</p>
*
* <p>Unlike most other LuckPerms events, this event is not fired asynchronously. Care should be
* taken to ensure listeners are lightweight. Additionally, listeners should ensure they do not
* cause further updates to player context, thus possibly causing a stack overflow.</p>
*
* @since 5.2
*/
public interface ContextUpdateEvent extends LuckPermsEvent {
/**
* Gets the subject whose contexts were updated.
*
* @return the subject
*/
@Param(0)
@NonNull Object getSubject();
/**
* Gets the subject whose contexts were updated, casted to a given type.
*
* @param subjectClass the type to cast to
* @param <T> the subject type
* @return the casted subject
*/
default <T> @NonNull Optional<T> getSubject(@NonNull Class<T> subjectClass) {
Object subject = getSubject();
return subjectClass.isInstance(subject) ? Optional.of(subjectClass.cast(subject)) : Optional.empty();
}
}
@@ -0,0 +1,29 @@
/*
* 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.
*/
/**
* Events relating to {@link net.luckperms.api.context.Context}s.
*/
package net.luckperms.api.event.context;
@@ -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 net.luckperms.api.event.extension;
import net.luckperms.api.event.LuckPermsEvent;
import net.luckperms.api.event.util.Param;
import net.luckperms.api.extension.Extension;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* Called when an {@link Extension} is loaded.
*/
public interface ExtensionLoadEvent extends LuckPermsEvent {
/**
* Gets the extension that was loaded.
*
* @return the extension
*/
@Param(0)
@NonNull Extension getExtension();
}
@@ -0,0 +1,29 @@
/*
* 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.
*/
/**
* Events relating to {@link net.luckperms.api.extension.Extension}s.
*/
package net.luckperms.api.event.extension;
@@ -0,0 +1,56 @@
/*
* 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 net.luckperms.api.event.group;
import net.luckperms.api.cacheddata.CachedDataManager;
import net.luckperms.api.event.LuckPermsEvent;
import net.luckperms.api.event.util.Param;
import net.luckperms.api.model.group.Group;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* Called when a groups {@link CachedDataManager} is loaded.
*/
public interface GroupCacheLoadEvent extends LuckPermsEvent {
/**
* Gets the group whose data was loaded
*
* @return the group
*/
@Param(0)
@NonNull Group getGroup();
/**
* Gets the data that was loaded
*
* @return the loaded data
*/
@Param(1)
@NonNull CachedDataManager getLoadedData();
}
@@ -23,13 +23,14 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.event.group;
package net.luckperms.api.event.group;
import me.lucko.luckperms.api.Group;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.cause.CreationCause;
import net.luckperms.api.event.LuckPermsEvent;
import net.luckperms.api.event.cause.CreationCause;
import net.luckperms.api.event.util.Param;
import net.luckperms.api.model.group.Group;
import javax.annotation.Nonnull;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* Called when a group is created
@@ -41,15 +42,15 @@ public interface GroupCreateEvent extends LuckPermsEvent {
*
* @return the new group
*/
@Nonnull
Group getGroup();
@Param(0)
@NonNull Group getGroup();
/**
* Gets the cause of the creation
*
* @return the cause of the creation
*/
@Nonnull
CreationCause getCause();
@Param(1)
@NonNull CreationCause getCause();
}
@@ -0,0 +1,56 @@
/*
* 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 net.luckperms.api.event.group;
import net.luckperms.api.cacheddata.CachedDataManager;
import net.luckperms.api.event.LuckPermsEvent;
import net.luckperms.api.event.util.Param;
import net.luckperms.api.model.group.Group;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* Called when a groups cached data is refreshed
*/
public interface GroupDataRecalculateEvent extends LuckPermsEvent {
/**
* Gets the group whose data was recalculated
*
* @return the group
*/
@Param(0)
@NonNull Group getGroup();
/**
* Gets the data that was recalculated
*
* @return the data
*/
@Param(1)
@NonNull CachedDataManager getData();
}
@@ -23,16 +23,17 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.event.group;
package net.luckperms.api.event.group;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.cause.DeletionCause;
import net.luckperms.api.event.LuckPermsEvent;
import net.luckperms.api.event.cause.DeletionCause;
import net.luckperms.api.event.util.Param;
import net.luckperms.api.node.Node;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Set;
import javax.annotation.Nonnull;
/**
* Called when a group is deleted
*/
@@ -43,23 +44,23 @@ public interface GroupDeleteEvent extends LuckPermsEvent {
*
* @return the name of the deleted group
*/
@Nonnull
String getGroupName();
@Param(0)
@NonNull String getGroupName();
/**
* Gets an immutable copy of the groups existing data
*
* @return a copy of the groups existing data
*/
@Nonnull
Set<Node> getExistingData();
@Param(1)
@NonNull Set<Node> getExistingData();
/**
* Gets the cause of the deletion
*
* @return the cause of the deletion
*/
@Nonnull
DeletionCause getCause();
@Param(2)
@NonNull DeletionCause getCause();
}
@@ -23,9 +23,9 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.event.group;
package net.luckperms.api.event.group;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import net.luckperms.api.event.LuckPermsEvent;
/**
* Called when all groups have been loaded in from storage.
@@ -23,12 +23,13 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.event.group;
package net.luckperms.api.event.group;
import me.lucko.luckperms.api.Group;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import net.luckperms.api.event.LuckPermsEvent;
import net.luckperms.api.event.util.Param;
import net.luckperms.api.model.group.Group;
import javax.annotation.Nonnull;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* Called when a group is loaded into memory from the storage.
@@ -42,7 +43,7 @@ public interface GroupLoadEvent extends LuckPermsEvent {
*
* @return the group that was loaded
*/
@Nonnull
Group getGroup();
@Param(0)
@NonNull Group getGroup();
}
@@ -0,0 +1,29 @@
/*
* 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.
*/
/**
* Events relating to {@link net.luckperms.api.model.group.Group}s.
*/
package net.luckperms.api.event.group;
@@ -23,13 +23,14 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.event.log;
package net.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 net.luckperms.api.actionlog.Action;
import net.luckperms.api.event.LuckPermsEvent;
import net.luckperms.api.event.type.Cancellable;
import net.luckperms.api.event.util.Param;
import javax.annotation.Nonnull;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* Called when a log entry is about to be sent to notifiable players on the platform
@@ -41,32 +42,34 @@ public interface LogBroadcastEvent extends LuckPermsEvent, Cancellable {
*
* @return the log entry to be broadcasted
*/
@Nonnull
LogEntry getEntry();
@Param(0)
@NonNull Action getEntry();
/**
* Gets where the log entry originated from.
*
* @return the origin of the log
* @since 3.3
*/
@Nonnull
Origin getOrigin();
@Param(1)
@NonNull Origin getOrigin();
/**
* Represents where a log entry is from
*
* @since 3.3
*/
enum Origin {
/**
* Represents a log entry which originated from the current server instance
* Marks a log entry which originated from the current server instance
*/
LOCAL,
/**
* Represents a log entry which was sent to this server via the messaging service
* 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
}
@@ -23,20 +23,19 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.event.log;
package net.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 net.luckperms.api.actionlog.Action;
import net.luckperms.api.event.LuckPermsEvent;
import net.luckperms.api.event.type.Cancellable;
import net.luckperms.api.event.util.Param;
import org.checkerframework.checker.nullness.qual.NonNull;
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 {
@@ -45,15 +44,15 @@ public interface LogNetworkPublishEvent extends LuckPermsEvent, Cancellable {
*
* @return the id of the log entry being published
*/
@Nonnull
UUID getLogId();
@Param(0)
@NonNull UUID getLogId();
/**
* Gets the log entry to be published
*
* @return the log entry to be published
*/
@Nonnull
LogEntry getEntry();
@Param(1)
@NonNull Action getEntry();
}
@@ -0,0 +1,91 @@
/*
* 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 net.luckperms.api.event.log;
import net.luckperms.api.actionlog.Action;
import net.luckperms.api.event.LuckPermsEvent;
import net.luckperms.api.event.type.Cancellable;
import net.luckperms.api.event.util.Param;
import net.luckperms.api.platform.PlatformEntity;
import org.checkerframework.checker.nullness.qual.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>
*/
public interface LogNotifyEvent extends LuckPermsEvent, Cancellable {
/**
* Gets the log entry to be sent
*
* @return the log entry to be sent
*/
@Param(0)
@NonNull Action getEntry();
/**
* Gets where the log entry originated from.
*
* @return the origin of the log
*/
@Param(1)
@NonNull Origin getOrigin();
/**
* Gets the object to be notified.
*
* @return the object to notify
*/
@Param(2)
@NonNull PlatformEntity 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
}
}
@@ -23,13 +23,14 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.event.log;
package net.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 net.luckperms.api.actionlog.Action;
import net.luckperms.api.event.LuckPermsEvent;
import net.luckperms.api.event.type.Cancellable;
import net.luckperms.api.event.util.Param;
import javax.annotation.Nonnull;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* Called when a log is about to be published to the storage file/table
@@ -41,7 +42,7 @@ public interface LogPublishEvent extends LuckPermsEvent, Cancellable {
*
* @return the log entry to be published
*/
@Nonnull
LogEntry getEntry();
@Param(0)
@NonNull Action getEntry();
}
@@ -23,19 +23,18 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.event.log;
package net.luckperms.api.event.log;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import net.luckperms.api.actionlog.Action;
import net.luckperms.api.event.LuckPermsEvent;
import net.luckperms.api.event.util.Param;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.UUID;
import javax.annotation.Nonnull;
/**
* Called when a log entry is received via the MessagingService
*
* @since 3.3
*/
public interface LogReceiveEvent extends LuckPermsEvent {
@@ -44,15 +43,15 @@ public interface LogReceiveEvent extends LuckPermsEvent {
*
* @return the id of the log entry being received
*/
@Nonnull
UUID getLogId();
@Param(0)
@NonNull UUID getLogId();
/**
* Gets the log entry being received
*
* @return the log entry being received
*/
@Nonnull
LogEntry getEntry();
@Param(1)
@NonNull Action getEntry();
}
@@ -0,0 +1,29 @@
/*
* 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.
*/
/**
* Events relating to the {@link net.luckperms.api.actionlog.ActionLog}.
*/
package net.luckperms.api.event.log;
@@ -23,25 +23,36 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.calculators;
package net.luckperms.api.event.node;
import com.google.common.collect.MapMaker;
import net.luckperms.api.event.util.Param;
import net.luckperms.api.node.Node;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.jetbrains.annotations.Unmodifiable;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public abstract class AbstractCalculatorFactory implements CalculatorFactory {
private final Set<PermissionCalculator> calculators = Collections.newSetFromMap(new MapMaker().weakKeys().makeMap());
/**
* Called when a node is added to a holder
*/
public interface NodeAddEvent extends NodeMutateEvent {
protected PermissionCalculator registerCalculator(PermissionCalculator calculator) {
calculators.add(calculator);
return calculator;
}
/**
* Gets the node that was added
*
* @return the node that was added
*/
@Param(3)
@NonNull Node getNode();
@Override
public void invalidateAll() {
for (PermissionCalculator calculator : calculators) {
calculator.invalidateCache();
}
default @NonNull @Unmodifiable Set<Node> getDataBefore() {
// Get data after, then reverse the action
Set<Node> nodes = new HashSet<>(this.getDataAfter());
nodes.remove(this.getNode());
return Collections.unmodifiableSet(nodes);
}
}
@@ -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 net.luckperms.api.event.node;
import net.luckperms.api.event.util.Param;
import net.luckperms.api.node.Node;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.jetbrains.annotations.Unmodifiable;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/**
* Called when a holder has their nodes cleared
*/
public interface NodeClearEvent extends NodeMutateEvent {
/**
* Gets the nodes that were cleared
*
* @return the nodes that were removed
* @since 5.3
*/
@Param(3)
@NonNull @Unmodifiable Set<Node> getNodes();
@Override
default @NonNull @Unmodifiable Set<Node> getDataBefore() {
// Get data after, then reverse the action
Set<Node> nodes = new HashSet<>(this.getDataAfter());
nodes.addAll(this.getNodes());
return Collections.unmodifiableSet(nodes);
}
}
@@ -23,16 +23,21 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.event.node;
package net.luckperms.api.event.node;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.PermissionHolder;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import net.luckperms.api.event.LuckPermsEvent;
import net.luckperms.api.event.util.Param;
import net.luckperms.api.model.PermissionHolder;
import net.luckperms.api.model.data.DataType;
import net.luckperms.api.model.group.Group;
import net.luckperms.api.model.user.User;
import net.luckperms.api.node.Node;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.jetbrains.annotations.Unmodifiable;
import java.util.Set;
import javax.annotation.Nonnull;
/**
* Called when a node is added to/removed from a user/group
*/
@@ -43,41 +48,52 @@ public interface NodeMutateEvent extends LuckPermsEvent {
*
* @return the event target
*/
@Nonnull
PermissionHolder getTarget();
@Param(0)
@NonNull PermissionHolder getTarget();
/**
* Gets the data type that was mutated.
*
* @return the data type
*/
@Param(1)
@NonNull DataType getDataType();
/**
* Gets an immutable copy of the holders data before the change
*
* @return the data before the change
*/
@Nonnull
Set<Node> getDataBefore();
@NonNull @Unmodifiable Set<Node> getDataBefore();
/**
* Gets an immutable copy of the holders data after the change
*
* @return the data after the change
*/
@Nonnull
Set<Node> getDataAfter();
@Param(2)
@NonNull @Unmodifiable Set<Node> getDataAfter();
/**
* Gets whether the target of this event is a {@link me.lucko.luckperms.api.User}
* Gets whether the target of this event is a {@link User}
*
* <p>This is equivalent to checking if getTarget() instanceof User</p>
*
* @return if the event is targeting a user
*/
boolean isUser();
default boolean isUser() {
return getTarget() instanceof User;
}
/**
* Gets whether the target of this event is a {@link me.lucko.luckperms.api.Group}
* Gets whether the target of this event is a {@link Group}
*
* <p>This is equivalent to checking if getTarget() instanceof Group</p>
*
* @return if the event is targeting a group
*/
boolean isGroup();
default boolean isGroup() {
return getTarget() instanceof Group;
}
}
@@ -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 net.luckperms.api.event.node;
import net.luckperms.api.event.util.Param;
import net.luckperms.api.node.Node;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.jetbrains.annotations.Unmodifiable;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/**
* Called when a node is removed from a holder
*/
public interface NodeRemoveEvent extends NodeMutateEvent {
/**
* Gets the node that was removed
*
* @return the node that was removed
*/
@Param(3)
@NonNull Node getNode();
@Override
default @NonNull @Unmodifiable Set<Node> getDataBefore() {
// Get data after, then reverse the action
Set<Node> nodes = new HashSet<>(this.getDataAfter());
nodes.add(this.getNode());
return Collections.unmodifiableSet(nodes);
}
}
@@ -0,0 +1,30 @@
/*
* 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.
*/
/**
* Events relating to changes to a {@link net.luckperms.api.model.user.User} or
* {@link net.luckperms.api.model.group.Group}s {@link net.luckperms.api.model.data.NodeMap}.
*/
package net.luckperms.api.event.node;
@@ -0,0 +1,29 @@
/*
* 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.
*/
/**
* Main events package.
*/
package net.luckperms.api.event;
@@ -23,44 +23,46 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.caching;
package net.luckperms.api.event.player;
import me.lucko.luckperms.api.Tristate;
import net.luckperms.api.event.LuckPermsEvent;
import net.luckperms.api.event.util.Param;
import net.luckperms.api.model.PlayerSaveResult;
import net.luckperms.api.model.user.UserManager;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.NonNull;
import javax.annotation.Nonnull;
import java.util.UUID;
/**
* Holds cached Permission lookup data for a specific set of contexts
* Called when player data is saved to the storage.
*
* @since 2.13
* <p>Data can be saved using {@link UserManager#savePlayerData(UUID, String)}.</p>
*/
public interface PermissionData {
public interface PlayerDataSaveEvent extends LuckPermsEvent {
/**
* Gets a permission value for the given permission node
* Gets the unique ID that was saved.
*
* @param permission the permission node
* @return a tristate result
* @throws NullPointerException if permission is null
* @return the uuid
*/
@Nonnull
Tristate getPermissionValue(@Nonnull String permission);
@Param(0)
@NonNull UUID getUniqueId();
/**
* Invalidates the underlying permission calculator cache.
* Gets the username that was saved.
*
* <p>Can be called to allow for an update in defaults.</p>
* @return the username
*/
void invalidateCache();
@Param(1)
@NonNull String getUsername();
/**
* Gets an immutable copy of the permission map backing the permission calculator
* Gets the result of the operation.
*
* @return an immutable set of permissions
* @return the result
*/
@Nonnull
Map<String, Boolean> getImmutableBacking();
@Param(2)
@NonNull PlayerSaveResult getResult();
}
@@ -23,50 +23,71 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.event.user;
package net.luckperms.api.event.player;
import me.lucko.luckperms.api.User;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import net.luckperms.api.event.LuckPermsEvent;
import net.luckperms.api.event.util.Param;
import net.luckperms.api.model.user.User;
import net.luckperms.api.util.Result;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.UUID;
import javax.annotation.Nonnull;
/**
* Called when LuckPerms has finished processing a certain Player's connection.
* Called when LuckPerms has finished processing a Player's initial connection.
*
* <p>This event will always execute during the platforms async login/auth event.
* All handlers will be called instantly.</p>
* <p>This event will always execute during the platforms async connection
* event. The LuckPerms platform listener processing the connection will block
* while this event is posted.</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>
* <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
* <p>The implementation will make an attempt to ensure this event is called
* for all connections, even if the operation to load User data was not
* successful. Note that LuckPerms will usually cancel the platform connection
* event if data could not be loaded.</p>
*/
public interface UserLoginProcessEvent extends LuckPermsEvent {
public interface PlayerLoginProcessEvent extends LuckPermsEvent, Result {
/**
* Gets the UUID of the connection which was processed
*
* @return the uuid of the connection which was processed
*/
@Nonnull
UUID getUuid();
@Param(0)
@NonNull UUID getUniqueId();
/**
* Gets the username of the connection which was processed
*
* @return the username of the connection which was processed
*/
@Nonnull
String getUsername();
@Param(1)
@NonNull String getUsername();
/**
* Gets if the login was processed successfully.
*
* @return true if the login was successful
*/
@Override
default boolean wasSuccessful() {
return getUser() != null;
}
/**
* Gets the resultant User instance which was loaded.
*
* <p>Returns {@code null} if the login was not processed
* {@link #wasSuccessful() successfully.}</p>
*
* @return the user instance
*/
User getUser();
@Param(2)
@Nullable User getUser();
}
@@ -0,0 +1,102 @@
/*
* 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 net.luckperms.api.event.player.lookup;
import net.luckperms.api.event.LuckPermsEvent;
import net.luckperms.api.event.type.ResultEvent;
import net.luckperms.api.event.util.Param;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Objects;
import java.util.UUID;
/**
* Called when the platform needs to determine the type of a player's {@link UUID unique id}.
*
* @since 5.3
*/
public interface UniqueIdDetermineTypeEvent extends LuckPermsEvent, ResultEvent<String> {
/**
* The players UUID has been obtained by authenticating with the Mojang session servers.
*
* <p>Usually indicated by the UUID being {@link UUID#version() version} 4.</p>
*/
String TYPE_AUTHENTICATED = "authenticated";
/**
* The players UUID has not been obtained through authentication, and instead is likely based
* on the username they connected with.
*
* <p>Usually indicated by the UUID being {@link UUID#version() version} 3.</p>
*/
String TYPE_UNAUTHENTICATED = "unauthenticated";
/**
* The players UUID most likely belongs to a NPC (non-player character).
*
* <p>Usually indicated by the UUID being {@link UUID#version() version} 2.</p>
*
* @since 5.4
*/
String TYPE_NPC = "npc";
/**
* Unknown UUID type.
*
* @since 5.4
*/
String TYPE_UNKNOWN = "unknown";
/**
* Gets the {@link UUID unique id} being queried.
*
* @return the unique id
*/
@Param(0)
@NonNull UUID getUniqueId();
/**
* Gets the current result unique id type.
*
* @return the type
*/
default @NonNull String getType() {
return result().get();
}
/**
* Sets the result unique id type.
*
* @param type the type
*/
default void setType(@NonNull String type) {
Objects.requireNonNull(type, "type");
result().set(type);
}
}
Loaded 100 of 1169 files, more files were not shown because too many files have changed in this diff. Show more