Compare commits

..
284 Commits
Author SHA1 Message Date
Ben Woo 2754c6ea0d Use version dbo-upload-action v0.1.0 2023-08-20 21:22:22 +08:00
Ben Woo ef6cd16e91 Remove end comma 2023-08-20 21:02:04 +08:00
Ben Woo b2691e979e Better format for project relation 2023-08-20 21:01:29 +08:00
Ben Woo 21e905fc83 Remove some game version that DBO doesnt have 2023-08-20 20:26:00 +08:00
Ben Woo bd6c44279d use game version by name 2023-08-20 20:13:22 +08:00
Ben Woo 743e741a92 Remove the fail 2023-08-20 16:36:17 +08:00
Ben Woo d841d9d5d0 Test without to json 2023-08-20 16:34:35 +08:00
Ben Woo 32d0e39866 Fix display name version 2023-08-20 16:28:04 +08:00
Ben Woo 71fe3de39a Use output version 2023-08-20 16:14:46 +08:00
Ben Woo b973292d0e Fix some upload field keys 2023-08-20 15:53:24 +08:00
Ben Woo 6db2cc25d6 Fix typo multiverse 2023-08-20 15:46:22 +08:00
Ben Woo c24777d282 Update regex 2023-08-20 15:45:29 +08:00
Ben Woo eeb58a05b1 Use regex 2023-08-20 15:41:39 +08:00
Ben Woo 0dd8ecaa84 Use latest version and fix copy paste issue 2023-08-20 15:39:49 +08:00
Ben Woo 01cc8e5177 Try dbo upload action 2023-08-20 15:36:10 +08:00
Ben Woo bd78b441ba Merge pull request #2929 from Multiverse/config_update
feat: Extract generic handler for config with ConfigurationSection
2023-06-29 11:03:14 +08:00
Ben Woo 3b384dbe6d docs: Add docs to new config classes 2023-06-28 20:18:26 +08:00
Ben Woo d1370bfb8c feat: Extract generic handler for config with ConfigurationSection 2023-06-28 19:41:33 +08:00
Ben Woo 314ce11630 Merge pull request #2930 from Multiverse/bump_papi
chore: Bump papi to 2.11.3
2023-06-28 19:40:19 +08:00
Ben Woo c2b943cf0a chore: Bump papi to 2.11.3 2023-06-28 19:37:36 +08:00
Ben Woo 33457ac5d5 Merge pull request #2904 from Multiverse/config-validation
Use Try<Void> for config validation
2023-04-03 10:57:24 +08:00
Ben Woo fac79e0780 fix: Double print error message for getting config value 2023-03-31 23:10:46 +08:00
Ben Woo 16e81ec141 refactor: Use Try<Void> for config validation 2023-03-31 23:08:56 +08:00
Ben Woo ffb238bf24 fix: Enable unstable api help for UsageCommand 2023-03-30 23:51:00 +08:00
Ben Woo 14472f5740 Merge pull request #2903 from Multiverse/improve-config-revamp
Improve config revamp
2023-03-30 23:41:44 +08:00
Ben Woo d9cf933d14 Merge pull request #2898 from Multiverse/async-teleport
feat: Add support for async teleport
2023-03-30 23:32:37 +08:00
Jeremy Wood 15ac39c3c2 Merge pull request #2897 from Multiverse/teleport-queue
refactor: Move teleport queue into seperate class
2023-03-30 08:41:29 -04:00
Jeremy Wood 8a05b3b815 Merge pull request #2899 from Multiverse/remove-serverfolder
refactor: Remove serverFolder value
2023-03-30 08:35:55 -04:00
benwoo1110 bfedc268d4 refactor: Improve setProperty onFailure output 2023-03-30 17:29:39 +08:00
benwoo1110 272c950f3e fix: Resolve context for MVCommandIssuer class 2023-03-30 13:54:13 +08:00
Jeremy Wood aac01b9e7e Merge pull request #2900 from Multiverse/better-revamp-config
refactor: Abstract handle class and improve node handling
2023-03-30 01:43:41 -04:00
Jeremy Wood 259189f23e Use specific exception for not found node. 2023-03-30 01:41:25 -04:00
Jeremy Wood 2a5b670ce6 Merge remote-tracking branch 'origin/MV5' into better-revamp-config 2023-03-30 01:06:00 -04:00
Jeremy Wood b8c95dc71a Merge pull request #2895 from Multiverse/revamp-config
Revamp config
2023-03-30 01:05:27 -04:00
Jeremy Wood 3ffc63a003 Merge remote-tracking branch 'origin/MV5' into revamp-config
# Conflicts:
#	src/main/java/com/onarandombox/MultiverseCore/MultiverseCore.java
#	src/test/java/org/mvplugins/multiverse/core/inject/InjectionTest.kt
2023-03-30 01:02:26 -04:00
Jeremy Wood 3d7af96b41 Merge pull request #2902 from Multiverse/dumptruckman/localized_exceptions
Add localizable message bundles and exceptions.
2023-03-30 00:52:40 -04:00
Jeremy Wood dab8ac2bf8 Set up locales before registering commands. 2023-03-30 00:14:45 -04:00
Jeremy Wood 5dcc0651e4 Add MVCorei18n#bundle for creating Message objects. 2023-03-29 23:59:19 -04:00
Jeremy Wood 2cb134bdeb Add base exception class MultiverseException.
Allows for localized messages to be contained in our exceptions.
2023-03-29 23:58:41 -04:00
Jeremy Wood 032a8c366d Add send message methods to MVCommandIssuer. 2023-03-29 23:45:44 -04:00
Jeremy Wood 1f8f68c383 Add kotlin mockito dependency for tests. 2023-03-29 15:18:08 -04:00
Jeremy Wood 979e80e1bd Use a custom implementation of BukkitCommandIssuer. 2023-03-29 13:09:18 -04:00
Jeremy Wood 224435f6cd Add Message for bundling messages with their arguments. 2023-03-29 12:53:40 -04:00
Jeremy Wood 40d5417629 Make PluginLocales injectable. 2023-03-29 00:51:54 -04:00
Jeremy Wood c32b2a4b51 Update Javadoc for MVConfig. 2023-03-28 17:36:02 -04:00
Jeremy Wood e5bb6bc23b Use Try<Void> rather than Try<Boolean> for ConfigHandle#set. 2023-03-28 17:25:48 -04:00
Jeremy Wood 94251be048 Change call order in FileConfigHandle.get for consistency. 2023-03-28 17:02:20 -04:00
Jeremy Wood 0cc3f93e0b Use Option instead of Optional for ValueNode#getName.
Also clean up nullability annotations in ConfigNode and co.
2023-03-28 16:38:35 -04:00
Jeremy Wood 63078270bf Use Option instead of Optional in NodeGroup. 2023-03-28 16:22:50 -04:00
Ben Woo a19fe76cbc chore: Add docs and remove some unused methods 2023-03-28 17:50:00 +08:00
Ben Woo 5cc5e6828f refactor: Allow for nullable NodeGroup 2023-03-28 17:15:15 +08:00
Ben Woo 90a3388728 refactor: Abstract handle class and improve node handling 2023-03-28 16:56:30 +08:00
Ben Woo 33fcf1ba26 refactor: Remove serverFolder value 2023-03-28 14:38:44 +08:00
Ben Woo f76b9b0670 feat: Add support for async teleport 2023-03-28 12:20:30 +08:00
Ben Woo 985f2e8823 refactor: Move teleport queue into seperate class 2023-03-28 11:32:04 +08:00
Jeremy Wood 9bbf42f993 Rename test methods. 2023-03-27 09:51:27 -04:00
Jeremy Wood 55390952c9 Add additional test set up more idiomatically. 2023-03-27 08:39:18 -04:00
Ben Woo 2f834ebfd6 fix: Relocation of acf dependency 2023-03-27 18:30:38 +08:00
Ben Woo 8f9df0294d chore: Improve logging in ConfigHandle 2023-03-27 18:29:34 +08:00
Ben Woo a5ae29c91a test: Implement test for config 2023-03-27 14:10:49 +08:00
Ben Woo 624d5ad117 fix: Get version without default fallback 2023-03-27 14:10:22 +08:00
Ben Woo 98fc0178aa fix: Migrate from old config on every load 2023-03-27 14:09:36 +08:00
Jeremy Wood 61cd593844 Fix a couple nits. 2023-03-27 01:03:21 -04:00
Jeremy Wood 7b39d78bfd Remove MultiverseCore dependency from DebugCommand. 2023-03-27 00:53:36 -04:00
Jeremy Wood 5a0957d894 Remove unused MultiverseConfigurationException. 2023-03-27 00:51:55 -04:00
Ben Woo 9f1ddcc81e refactor: Remove use of MVCoreConfigProvider 2023-03-27 12:25:13 +08:00
Ben Woo a8c8ef7a6b refactor: Move MVCoreConfigNodes to a non-static context 2023-03-27 11:39:11 +08:00
Ben Woo ce9d53c6e9 refactor: Rename to MVCoreConfig 2023-03-27 11:14:58 +08:00
Ben Woo 7af22c451e chore Remove unused MultiverseCoreConfiguration.java 2023-03-27 10:49:07 +08:00
Ben Woo db9879af8d refactor: Move DefaultMVConfig and MVConfigNodes to config package 2023-03-27 10:48:46 +08:00
Ben Woo f05092076f fix: Don't need to check version before removing serialisation value 2023-03-27 10:39:29 +08:00
Jeremy Wood 7f9c45d8e1 Use DI for new config. 2023-03-26 19:16:14 -04:00
Jeremy Wood a45e95c7fd Merge remote-tracking branch 'origin/MV5' into revamp-config
# Conflicts:
#	build.gradle
#	src/main/java/com/onarandombox/MultiverseCore/MultiverseCore.java
#	src/main/java/com/onarandombox/MultiverseCore/MultiverseCoreConfiguration.java
#	src/main/java/com/onarandombox/MultiverseCore/api/MVConfig.java
#	src/main/java/com/onarandombox/MultiverseCore/commandtools/MVCommandCompletions.java
#	src/main/java/com/onarandombox/MultiverseCore/commandtools/MVCommandContexts.java
#	src/main/java/com/onarandombox/MultiverseCore/listeners/MVChatListener.java
#	src/main/java/com/onarandombox/MultiverseCore/listeners/MVEntityListener.java
#	src/main/java/com/onarandombox/MultiverseCore/listeners/MVPlayerListener.java
#	src/main/java/com/onarandombox/MultiverseCore/world/SimpleMVWorld.java
#	src/main/java/com/onarandombox/MultiverseCore/world/SimpleMVWorldManager.java
2023-03-26 19:09:37 -04:00
Jeremy Wood 43c6945710 Merge pull request #2886 from Multiverse/dumptruckman/inject
Implement simple dependency injection using hk2.
2023-03-26 16:12:16 -04:00
Jeremy Wood edea4aff4b Fix PAPI registration. 2023-03-26 14:48:30 -04:00
Jeremy Wood 44dacdceb1 Use consistency for exception param names. 2023-03-26 14:11:05 -04:00
Jeremy Wood 75998ae2c3 Remove EagerlyLoaded. 2023-03-26 14:10:26 -04:00
Jeremy Wood 16db616546 Remove EagerlyLoaded from SimpleMVWorldManager. 2023-03-26 14:09:40 -04:00
Jeremy Wood 4c94af5f08 Remove EagerlyLoaded from UnsafeCallWrapper. 2023-03-26 14:08:58 -04:00
Jeremy Wood e91bcb9658 Remove EagerlyLoaded from MVPermissions. 2023-03-26 14:08:28 -04:00
Jeremy Wood 0836badea6 Remove EagerlyLoaded from SimpleSafeTTeleporter. 2023-03-26 14:02:06 -04:00
Jeremy Wood 426d7639bb Remove EagerlyLoaded from SimpleLocationManipulation. 2023-03-26 14:01:02 -04:00
Jeremy Wood a74aeb53d0 Remove EagerlyLoaded from SimpleBlockSafety. 2023-03-26 14:00:22 -04:00
Jeremy Wood 52a2ff78c8 Remove EagerlyLoaded from MVEconomist. 2023-03-26 13:59:15 -04:00
Jeremy Wood 6f86416310 Remove EagerlyLoaded from MVCoreConfigProvider. 2023-03-26 13:55:21 -04:00
Jeremy Wood 1f134d4501 Use Provider for MultiverseCorePlaceholders in MultiverseCore. 2023-03-26 13:52:36 -04:00
Jeremy Wood 573b424efe Use vavr for registering listeners. 2023-03-26 13:51:54 -04:00
Jeremy Wood f2347cb620 Use Provider for MetricsConfigurator in MultiverseCore. 2023-03-26 13:33:01 -04:00
Jeremy Wood a8ec599b35 Remove direct getService usage for DestinationsProvider. 2023-03-26 13:18:20 -04:00
Jeremy Wood a8b44dff78 Remove additional direct getService usage for MVCommandProvider. 2023-03-26 13:09:43 -04:00
Jeremy Wood e8a33c0cdf Remove EagerlyLoaded from MVCommandManager. 2023-03-26 13:01:08 -04:00
Jeremy Wood 8b244e7d3b Remove EagerlyLoaded from AnchorManager. 2023-03-26 12:45:14 -04:00
Jeremy Wood 472742dde8 Manually initialize metrics. 2023-03-25 16:49:04 -04:00
Ben Woo cd260b0f5e feat: Fully implement working migration and validation 2023-03-26 00:31:36 +08:00
Jeremy Wood 372569ed6c Don't eagerly load MultiverseCorePlaceholders. 2023-03-25 09:38:15 -04:00
Jeremy Wood aa023f3c44 Use injection in MultiverseCorePlaceholders. 2023-03-25 09:28:27 -04:00
Jeremy Wood 93ac4fffcc Merge remote-tracking branch 'origin/MV5' into dumptruckman/inject
# Conflicts:
#	src/main/java/com/onarandombox/MultiverseCore/MultiverseCore.java
2023-03-25 08:42:20 -04:00
Jeremy Wood 750460fff0 Eagerly load core services. 2023-03-25 00:27:30 -04:00
Jeremy Wood add73be4fc Rename AutoLoadedService to EagerlyLoaded. 2023-03-25 00:17:08 -04:00
Jeremy Wood c65a945203 Fix listener registration. 2023-03-25 00:15:56 -04:00
Jeremy Wood cbc3bace58 Remove InjectionFeature loading. 2023-03-25 00:02:48 -04:00
Jeremy Wood 376fc8db18 Revert "Add API for creating auto-registering services."
This reverts commit b2171717ad.
2023-03-24 23:32:14 -04:00
Jeremy Wood 4aa1782cfd Revert "Add automatic listener registration through ListenerFeature."
This reverts commit d03063f2b9.
2023-03-24 23:31:58 -04:00
Jeremy Wood e38796f492 Revert "Add automatic command registration through BaseCommandFeature."
This reverts commit 0c97aea3dc.
2023-03-24 23:31:37 -04:00
Jeremy Wood 5d2e68a362 Revert "Add automatic destination registration through DestinationFeature."
This reverts commit c6a2cee050.
2023-03-24 23:31:30 -04:00
Ben Woo 358404b407 feat: Add a runnable when value is set. 2023-03-24 23:42:49 +08:00
Ben Woo 3ccdfd7cf5 refactor: Move to configuration package and rename MVSettings -> ConfigHandle 2023-03-24 22:32:10 +08:00
Ben Woo 274a7ed82b docs: Add more docstrings to methods implemented 2023-03-24 22:26:38 +08:00
Ben Woo ba2be24362 docs: Fix inheritDoc more typo 2023-03-24 22:20:56 +08:00
Ben Woo c8ae27894e refactor: Change name to optional and fix inheritDoc typo 2023-03-24 22:20:03 +08:00
Ben Woo cb5877b206 docs: Add docstrings to methods implemented 2023-03-24 22:09:10 +08:00
Ben Woo d126b3d31a feat: Add config for papi hook 2023-03-24 15:47:12 +08:00
Ben Woo 2edf955332 refactor: Rename config methods to align with new structure 2023-03-24 14:39:58 +08:00
Ben Woo 136bd3cbe2 fix: Clean up config migration logging 2023-03-24 14:16:03 +08:00
Ben Woo 433160f187 fix: Java 11 compatibility with instanceof pattern 2023-03-24 14:12:26 +08:00
Ben Woo e3e3c039c3 feat: Fully implement config command 2023-03-24 13:00:29 +08:00
Ben Woo d321851f0d fix: Donation and migration of various node path 2023-03-24 00:14:16 +08:00
Ben Woo 7759a37b4e feat: Implement config names and basic config command 2023-03-23 23:59:19 +08:00
Ben Woo f1a9d3a723 Merge remote-tracking branch 'origin/MV5' into revamp-config 2023-03-22 22:53:50 +08:00
Ben Woo 9ae2cddfda refactor: Flip boolean for custom portal search config 2023-03-22 22:53:16 +08:00
Ben Woo 6cc169cb55 feat: Fully replace with new config api 2023-03-22 22:48:24 +08:00
Ben Woo 783038ffb4 feat: Implement get/set methods from previous MVConfig class 2023-03-18 23:27:57 +08:00
Ben Woo db0e9f3142 feat: Implement migration from old mv config.yml 2023-03-18 23:09:10 +08:00
Zax71andBen Woo 95c3b034ec feat: Add PlaceholderAPI Support (#2888)
* feat:Add PlaceholderAPI Support

Signed-off-by: zax71 <zabax32@gmail.com>

* Implement requested changes

Signed-off-by: zax71 <zabax32@gmail.com>

* Add separate world functionality and half-baked i18n support.

Signed-off-by: zax71 <zabax32@gmail.com>

* refactor: Simplify papi world parsing

* Fix spelling and remove unused i18n.

Signed-off-by: zax71 <zabax32@gmail.com>

* chore: Add warnings

* chore: Remove unused imports

* chore: Setup papi before log enable message

---------

Signed-off-by: zax71 <zabax32@gmail.com>
Co-authored-by: Ben Woo <30431861+benwoo1110@users.noreply.github.com>
2023-03-16 20:18:36 +08:00
Ben Woo 9ce648d06a refactor: Version migrator code 2023-03-16 11:18:31 +08:00
Jeremy Wood 2a504f4360 Add annotation processing for tests. 2023-03-12 17:30:46 -04:00
Jeremy Wood 1d5d7a9ce2 Add hamkrest test dependency. 2023-03-12 17:04:38 -04:00
Jeremy Wood 0601c05761 Revert "Simplify PluginInjection by removing unneeded population."
This reverts commit f7bd538049.
2023-03-12 00:02:46 -05:00
Jeremy Wood c6a2cee050 Add automatic destination registration through DestinationFeature. 2023-03-11 23:56:49 -05:00
Jeremy Wood 0c97aea3dc Add automatic command registration through BaseCommandFeature. 2023-03-11 23:46:15 -05:00
Jeremy Wood 7dcada0c2d MultiverseCore#getAllServices should not instantiate services. 2023-03-11 23:37:03 -05:00
Jeremy Wood d03063f2b9 Add automatic listener registration through ListenerFeature. 2023-03-11 12:30:09 -05:00
Jeremy Wood 485d2428ed Rename PluginService to AutoLoadedService. 2023-03-11 11:40:37 -05:00
Jeremy Wood b2171717ad Add API for creating auto-registering services. 2023-03-11 11:37:33 -05:00
Jeremy Wood 49c23d31b0 MultiverseCore#getService should not instantiate services. 2023-03-11 11:24:24 -05:00
Jeremy Wood f7bd538049 Simplify PluginInjection by removing unneeded population. 2023-03-11 11:05:35 -05:00
Jeremy Wood 9f650d683d Add PluginService and InjectionFeature loading. 2023-03-10 02:07:44 -05:00
Jeremy Wood b40ded9806 Fix relocations and exported maven dependencies. 2023-03-09 15:57:55 -05:00
Jeremy Wood 93b82ae825 Inject MVCoreConfigProvider directly into MultiverseCore. 2023-03-09 11:34:41 -05:00
Jeremy Wood ecec80dfe3 Correctly rename hk2 metadata file. 2023-03-09 11:31:32 -05:00
Jeremy Wood 2f1a3bcc22 Use Provider for MVCoreConfigProvider in MultiverseCore. 2023-03-09 09:24:55 -05:00
Jeremy Wood 1ea88615c7 Don't rename hk2 metadata file. 2023-03-09 09:05:03 -05:00
Jeremy Wood 7fe50d2171 Temporarily throw exception on enable to reveal testing issue. 2023-03-09 08:53:37 -05:00
Jeremy Wood a81e045598 Use getter in MultiverseCore for config provider. 2023-03-09 08:52:51 -05:00
Jeremy Wood eac2fa53cb Stop relocating and minimizing for hk2. 2023-03-09 08:50:16 -05:00
Jeremy Wood 0f1d1adeb2 Remove Service/Contract from MVConfig and impl. 2023-03-09 08:49:29 -05:00
Jeremy Wood d4f43853f5 Skip checkstyle and javadoc in test workflow. 2023-03-08 23:52:39 -05:00
Jeremy Wood d7f907b40c Enable full exception format for gradle test. 2023-03-08 23:52:24 -05:00
Jeremy Wood 686c4a4b16 Simplify config provider usage. 2023-03-08 23:02:17 -05:00
Jeremy Wood ea07a490a6 Update Java version used in GHA. 2023-03-08 15:19:50 -05:00
Jeremy Wood 3d1c3f81f6 Fix relocations and minimize shadow jar. 2023-03-08 13:50:07 -05:00
Jeremy Wood 7fc78d81bc Remove faulty javadoc from CannonDestination. 2023-03-08 13:48:03 -05:00
Jeremy Wood 47002061db Remove some unused imports. 2023-03-08 13:37:41 -05:00
Jeremy Wood 1ea6df4a27 Merge remote-tracking branch 'origin/MV5' into dumptruckman/inject
# Conflicts:
#	src/main/java/com/onarandombox/MultiverseCore/MultiverseCore.java
#	src/main/java/com/onarandombox/MultiverseCore/commands/CheckCommand.java
#	src/main/java/com/onarandombox/MultiverseCore/commands/CloneCommand.java
#	src/main/java/com/onarandombox/MultiverseCore/commands/DeleteCommand.java
#	src/main/java/com/onarandombox/MultiverseCore/commands/GameruleCommand.java
#	src/main/java/com/onarandombox/MultiverseCore/commands/ImportCommand.java
#	src/main/java/com/onarandombox/MultiverseCore/commands/LoadCommand.java
#	src/main/java/com/onarandombox/MultiverseCore/commands/RegenCommand.java
#	src/main/java/com/onarandombox/MultiverseCore/commands/ReloadCommand.java
#	src/main/java/com/onarandombox/MultiverseCore/commands/RemoveCommand.java
#	src/main/java/com/onarandombox/MultiverseCore/commands/RootCommand.java
#	src/main/java/com/onarandombox/MultiverseCore/commands/TeleportCommand.java
#	src/main/java/com/onarandombox/MultiverseCore/commands/UnloadCommand.java
2023-03-08 13:32:59 -05:00
Jeremy Wood 23693835ca Remove PluginDataFolder. 2023-03-08 13:19:31 -05:00
Jeremy Wood 8e7e0ef566 Replace all service getters with DI. 2023-03-08 13:16:18 -05:00
Jeremy Wood dd93223eb1 Use DI for command classes. 2023-03-08 08:43:40 -05:00
Jeremy Wood e6f304fd25 Use specific dependencies in SimpleMVWorldManager and SimpleMVWorld. 2023-03-08 07:39:18 -05:00
Jeremy Wood b6a0d272df Use specific dependencies in UnsafeCallWrapper. 2023-03-07 19:02:11 -05:00
Jeremy Wood 177adf80cb Use specific dependencies in SimpleSafeTTeleporter. 2023-03-07 19:00:06 -05:00
Jeremy Wood 160f49bbae Use specific dependencies in MVPermissions. 2023-03-07 18:54:33 -05:00
Jeremy Wood 397101f712 Use specific dependencies in DestinationsProvider. 2023-03-07 18:49:13 -05:00
Jeremy Wood d1f59e3d86 Use specific dependencies in SimpleBlockSafety. 2023-03-07 18:40:37 -05:00
Jeremy Wood bab0ccd3f2 Use specific dependencies in AnchorManager. 2023-03-07 17:00:24 -05:00
Jeremy Wood 015c58421d Add MVCoreConfigProvider#getConfigUnsafe. 2023-03-07 16:58:29 -05:00
Jeremy Wood a57a83a047 Add injectable wrapper for plugin data folder. 2023-03-07 16:49:14 -05:00
Jeremy Wood 6362a97aaf Move configuration loading/saving into injectable MVCoreConfigProvider. 2023-03-07 16:10:34 -05:00
Jeremy Wood 0db90dc0b9 Set up DI for primary dependencies of MultiverseCore. 2023-03-07 14:39:11 -05:00
Jeremy Wood 6a434746c9 Also bind plugin logger in PluginBinder. 2023-03-07 14:16:58 -05:00
Ben Woo c76652f0a2 feat: Test out new commentedconfiguration 2023-03-07 23:33:35 +08:00
Ben Woo e314539847 dep: Bump CommentedConfiguration to 1.0.1 2023-03-07 23:32:09 +08:00
Jeremy Wood de6b25db35 Also bind MultiverseCore to MVCore and MVPlugin. 2023-03-07 02:24:00 -05:00
Jeremy Wood 40637e6a88 Enable basic dependency injection. 2023-03-07 01:59:48 -05:00
Jeremy Wood 7ad0b04787 Abstract TestWithMockBukkit out of MockBukkitTest. 2023-03-07 00:20:26 -05:00
Jeremy Wood 00554fefc3 Add vavr dependency. 2023-03-06 22:55:36 -05:00
Jeremy Wood 0082287a5d Enable hk2 annotation processing. 2023-03-06 20:41:27 -05:00
Ben Woo 84730e0fcd Merge branch 'main' into MV5 2023-03-06 19:43:46 +08:00
Ben Woo 9dba558ffd Merge pull request #2884 from Lildirt/ld/command-i18n
i18n for strings directly in commands
2023-03-06 16:45:40 +08:00
Lildirt 1f1c8240d9 i18n: move RootCommand further down 2023-03-05 13:00:31 -05:00
Jeremy Wood 4576ca99c9 Add hk2 dependency. 2023-03-04 10:26:49 -05:00
Lildirt eaa8b1ee56 i18n: last bit of colorizing 2023-03-03 12:23:50 -05:00
Lildirt 10c910f00f i18n: fix prompt message mappings 2023-03-03 12:23:43 -05:00
Lildirt 3bd6712f0e i18n: Move mv-core.debug 2023-03-03 12:23:36 -05:00
Lildirt 6a5e8d2522 i18n: Register root command 2023-03-03 12:23:11 -05:00
Lildirt 1dadaa1a73 i18n: use error message levels 2023-03-03 12:23:11 -05:00
Lildirt ef3a50f32b i18n: section out the string file with comments 2023-03-03 12:22:58 -05:00
Lildirt ac31a66a45 i18n: Preserve original string colorization. 2023-03-03 12:22:58 -05:00
Lildirt 992ce7cff5 i18n: more sections & missing confirm description 2023-03-03 12:22:58 -05:00
Lildirt fd237243a4 i18n: Usage command 2023-03-03 12:22:58 -05:00
Lildirt 0512fa1820 i18n: Unload command 2023-03-03 12:22:58 -05:00
Lildirt a9896df2a7 i18n: Teleport command 2023-03-03 12:22:58 -05:00
Lildirt 216adf5fa9 i18n: MV Root command 2023-03-03 12:22:58 -05:00
Lildirt 12f6ceb622 i18n: Remove command 2023-03-03 12:22:58 -05:00
Lildirt ca0f6febb5 i18n: Reload command 2023-03-03 12:22:58 -05:00
Lildirt 3e468dba4d i18n: Regen command 2023-03-03 12:22:58 -05:00
Lildirt 8b450910ba i18n: Load command 2023-03-03 12:22:58 -05:00
Lildirt 38002261b7 i18n: Import command 2023-03-03 12:22:58 -05:00
Lildirt 9e5fb2cf4b i18n: Gamerule command 2023-03-03 12:22:58 -05:00
Lildirt fa0e9f4268 i18n: Delete command 2023-03-03 12:22:58 -05:00
Lildirt 5e4e925bb1 i18n: Clone command 2023-03-03 12:21:19 -05:00
Lildirt c9bb6180bd i18n: Check command 2023-03-03 12:21:14 -05:00
Jeremy Wood 8a69d6ad43 Merge pull request #2883 from Multiverse/artifact_pr_build
build: Add artifacting of PR build
2023-03-03 11:30:37 -05:00
Ben Woo 3b44ea218d build: Fix PR build number 2023-03-03 23:28:55 +08:00
Ben Woo 68c97f7ae6 build: Add artifacting of PR build 2023-03-03 23:21:36 +08:00
Ben Woo 3f6c3047d8 fix: Restore locales setup method (#2881) 2023-03-03 22:23:39 +08:00
Jeremy Wood e4fd23709f Merge pull request #2882 from Multiverse/dumptruckman/fix_mock_bukkit
Downgrade MockBukkit to 2.141.0.
2023-03-03 08:29:57 -05:00
Jeremy Wood a255f55b6f Downgrade MockBukkit to 2.141.0. 2023-03-03 08:27:12 -05:00
Jeremy Wood e0e2a0f0c2 Merge pull request #2879 from Multiverse/dumptruckman/new_tests
Add new test module using Kotlin and JUnit 5.
2023-03-02 08:56:39 -05:00
Jeremy Wood a4e84ad581 Use ServerMock instead of Server. 2023-03-02 08:36:43 -05:00
Jeremy Wood 65cb3f7037 Put test method after tearDown. 2023-03-02 08:35:52 -05:00
Jeremy Wood fc7509cca6 Use a better test method name. 2023-03-02 08:35:30 -05:00
Jeremy Wood eebb4a4a6d Implement initial test using MockBukkit. 2023-03-02 02:22:47 -05:00
Jeremy Wood 698d1c7954 Switch to JUnit 5 for new tests. 2023-03-02 02:10:36 -05:00
Jeremy Wood ed73fd059e Add Kotlin dependency for tests only. 2023-03-02 02:07:38 -05:00
Jeremy Wood 87225b1c65 Move old tests to old-test. 2023-03-02 01:20:38 -05:00
Jeremy Wood 6362d9fb17 Merge pull request #2878 from Multiverse/dumptruckman/merge_main
Merge main branch into MV5
2023-03-02 00:58:37 -05:00
Jeremy Wood d5ba55716b Merge remote-tracking branch 'origin/main' into dumptruckman/merge_main
# Conflicts:
#	build.gradle
2023-03-02 00:56:34 -05:00
Jeremy Wood 4eca331430 Merge pull request #2877 from Multiverse/dumptruckman/separate_test_deps
Use a separate API version for running tests.
2023-03-02 00:53:24 -05:00
Jeremy Wood b6574245b8 Remove junit exclusion from compileOnly bukkit. 2023-03-02 00:48:54 -05:00
Jeremy Wood 85d744d79f Run tests against spigot-api 1.19.3. 2023-03-02 00:44:32 -05:00
Jeremy Wood e536dff1a8 Use a separate bukkit dependency for tests. 2023-03-02 00:37:30 -05:00
Jeremy Wood 39287f55ef Delete CODEOWNERS. 2023-03-01 23:36:41 -05:00
Ben WooandJeremy Wood d5ebde53b9 Add maven central to repositories (#2859)
Co-authored-by: Jeremy Wood <farachan@gmail.com>
2023-03-02 12:32:07 +08:00
Jeremy Wood 101ddae443 Create CODEOWNERS. 2023-02-28 23:03:50 -05:00
Ben Woo e58de8d74d Merge pull request #2843 from Multiverse/help-command
feat: Implement help command
2023-02-28 23:21:36 +08:00
Ben Woo 974afb4751 feat: Implement help command 2023-02-28 23:16:09 +08:00
Ben Woo d819153690 Merge pull request #2842 from Multiverse/file-locales
feat: Improve locale support
2023-02-28 23:13:23 +08:00
Ben Woo 7dbd29b838 refactor: Shift classes and add javadocs 2023-02-28 23:07:19 +08:00
Ben Woo 560e3ab201 refactor: Make FileResClassLoader usable for other file paths. 2023-02-28 23:07:19 +08:00
Ben Woo ffc4c600c5 feat: Enable per player locale support 2023-02-28 23:07:18 +08:00
Ben Woo 44904eaef4 feat: Allow for custom locale folder path 2023-02-28 23:07:18 +08:00
Ben Woo 47a92deffd refactor: Use '&' for chat color formatting 2023-02-28 23:07:17 +08:00
Ben Woo b4549c6791 feat: Add support for loading locales from plugin dir 2023-02-28 23:07:17 +08:00
Jeremy Wood 2b97f7310f Use pull_request_target for auto labeler. 2023-02-25 20:39:56 -05:00
Jeremy Wood 073091525b Label PRs automatically as prerelease. 2023-02-25 20:34:19 -05:00
Jeremy Wood 79b9c12319 Change job name for manually promoting releases. 2023-02-25 20:29:04 -05:00
Jeremy Wood 01f745b027 Skip checking PR labels. 2023-02-25 19:39:14 -05:00
Jeremy Wood 9725bdfeeb Use ref input. 2023-02-25 14:02:01 -05:00
Jeremy Wood cdf9767959 Use target_commitish for GITHUA_SHA. 2023-02-25 13:41:26 -05:00
Jeremy Wood 66e21da6b2 Add version to publish action as well. 2023-02-25 13:39:59 -05:00
Jeremy Wood 87b14d3944 Add publish and upload. 2023-02-25 13:34:24 -05:00
Jeremy Wood 7bbeb90320 Remove dry_run. 2023-02-25 13:34:10 -05:00
Jeremy Wood cd895d03dc Remove extra } in bump_version_scheme. 2023-02-25 13:32:08 -05:00
Jeremy Wood ee2a304148 Reorder version bump types. 2023-02-25 13:31:49 -05:00
Jeremy Wood 06e9e33da4 Workflow requires version bump type. 2023-02-25 13:28:36 -05:00
Jeremy Wood 7065ffaea2 Remove checkstyle from promote workflow. 2023-02-25 13:24:24 -05:00
Jeremy Wood 1bc4e68ff9 Use promote scheme for manual workflow. 2023-02-25 13:20:40 -05:00
Jeremy Wood 4e53d13290 Add workflow for manually promoting a release. 2023-02-25 13:10:53 -05:00
Jeremy Wood 90344d36df Merge pull request #2867 from Multiverse/no_version_bump
Use "no version bump" label instead of "no release".
2023-02-24 13:19:16 -05:00
Jeremy Wood f36a56e854 Use "no version bump" label instead of "no release". 2023-02-24 13:17:39 -05:00
Jeremy Wood 5d4bacc80e Merge pull request #2866 from Multiverse/test_prerelease_2
Remove space to test pre-releases
2023-02-24 12:40:57 -05:00
Jeremy Wood d88bf6e137 Remove space to test pre-releases 2023-02-24 12:40:36 -05:00
Jeremy Wood 63f5d769d8 Merge pull request #2865 from Multiverse/prerelease-test
Add space to trigger release.
2023-02-24 11:57:39 -05:00
Jeremy Wood 9a9bfc03b9 Add space to trigger release. 2023-02-24 11:57:02 -05:00
Jeremy Wood 28112ef4d8 Merge pull request #2864 from Multiverse/simplify_release_name
Drop "Release" prefix on release names.
2023-02-24 11:46:47 -05:00
Jeremy Wood 7e5a3238b8 Drop "Release" prefix on release names. 2023-02-24 11:44:06 -05:00
Jeremy Wood 3279a6a38d Merge pull request #2863 from Multiverse/prerelease_snapshot
Check if the tag name contains pre instead of checking PR labels.
2023-02-24 11:34:18 -05:00
Jeremy Wood b64e48769d Check if the tag name contains pre instead of checking PR labels. 2023-02-24 11:29:28 -05:00
Jeremy Wood ff8002fc13 Merge pull request #2862 from Multiverse/prerelease_snapshot
Publish prerelease versions as snapshots.
2023-02-24 11:21:09 -05:00
Jeremy Wood 2af835f0c3 Publish prerelease versions as snapshots. 2023-02-24 11:15:36 -05:00
Jeremy Wood bf25b65f09 Merge pull request #2861 from Multiverse/test_prerelease
Test prerelease workflow.
2023-02-24 10:53:54 -05:00
Jeremy Wood 52eb3d820f Test out the prerelease action. 2023-02-24 09:58:10 -05:00
Ben Woo d90210d70f Merge pull request #2855 from Multiverse/gradle-build
build: Make MV5 build with gradle
2023-02-20 20:34:56 +08:00
Ben Woo ec254c2989 build: Make MV5 build with gradle 2023-02-20 20:29:08 +08:00
Ben Woo 36549294b7 Merge branch 'main' into gradle-build 2023-02-20 20:25:47 +08:00
Jeremy Wood 908fcb1e44 Merge pull request #2854 from Multiverse/dumptruckman/fix_release_8
Combine release and publish into a single workflow.
2023-02-20 07:20:05 -05:00
Jeremy Wood 73cd26aea3 Combine release and publish into a single workflow. 2023-02-20 07:17:37 -05:00
Jeremy Wood 758d25812b Merge pull request #2853 from Multiverse/fix-gha-release
Fix upload release artifact
2023-02-20 06:42:31 -05:00
Ben Woo fa0ef421c7 Merge branch 'main' into fix-gha-release 2023-02-20 14:57:52 +08:00
Ben Woo e936a6271f Fix upload release artifact 2023-02-20 14:57:01 +08:00
Jeremy Wood 7362e543da Merge pull request #2851 from Multiverse/dumptruckman/fix_release_7
Use new action for uploading artifact.
2023-02-20 00:58:06 -05:00
Jeremy Wood 8a46d70301 Use new action for uploading artifact. 2023-02-20 00:57:21 -05:00
Jeremy Wood a168e5cb48 Merge pull request #2850 from Multiverse/dumptruckman/fix_release_6
Massage the strange release upload url.
2023-02-20 00:38:53 -05:00
Jeremy Wood ae578f9491 Massage the strange release upload url. 2023-02-20 00:36:45 -05:00
Jeremy Wood e72122378d Merge pull request #2849 from Multiverse/dumptruckman/fix_release_5
Fix name of consumed output variable on get_release in more places.
2023-02-20 00:06:05 -05:00
Jeremy Wood fd2ea3df09 Remove tag prefix. 2023-02-20 00:04:43 -05:00
Jeremy Wood e94e071c6e Fix name of consumed output variable on get_release in more places. 2023-02-19 23:58:26 -05:00
Jeremy Wood 0e19236cdc Merge pull request #2848 from Multiverse/dumptruckman/fix_release_4
Use lowercase artifact id.
2023-02-19 23:53:45 -05:00
Jeremy Wood 1c12756acf Use lowercase artifact id. 2023-02-19 23:51:14 -05:00
Jeremy Wood bcfde80c07 Merge pull request #2847 from Multiverse/dumptruckman/fix_release_3
Fix name for consumed output variable on get_release.
2023-02-19 23:39:16 -05:00
Jeremy Wood 8dc9e864eb Fix name for consumed output variable on get_release. 2023-02-19 23:37:25 -05:00
Jeremy Wood fec820f4ba Merge pull request #2846 from Multiverse/dumptruckman/fix_release_2
Use PAT to create release.
2023-02-19 23:27:49 -05:00
Jeremy Wood ff9ffad302 Use organization PAT for creating release. 2023-02-19 23:25:10 -05:00
Jeremy Wood fc2cb6aeae Move publish jobs back into publish action. 2023-02-19 23:24:44 -05:00
139 changed files with 5691 additions and 1613 deletions

No files matched your search

+2
View File
@@ -0,0 +1,2 @@
prerelease:
- '*'
+38
View File
@@ -0,0 +1,38 @@
name: Create Release Version & Publish Package
on:
push:
branches: [dbo-test]
jobs:
dbo_upload_test:
runs-on: ubuntu-latest
steps:
- name: Download release artifact
id: release-artifact
uses: dsaltares/fetch-gh-release-asset@master
with:
token: ${{ secrets.GITHUB_TOKEN }}
# version: tags/${{ github.event.inputs.version }}
regex: true
file: multiverse-core-(.*)\.jar
target: 'subdir/'
- name: Upload to dev.bukkit.org
uses: benwoo1110/dbo-upload-action@v0.1.0
with:
api_token: ${{ secrets.DBO_UPLOAD_API_TOKEN }}
project_id: 30765
changelog: ${{ steps.release-artifact.outputs.body }}
changelog_type: markdown
display_name: ${{ steps.release-artifact.outputs.version }}
game_versions: 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.18.1, 1.18.2, 1.19, 1.19.1, 1.19.2, 1.19.3, 1.19.4, 1.20, 1.20.1
project_relations: >
[
{"slug": "multiverse-portals", "type": "optionalDependency"},
{"slug": "multiverse-netherportals", "type": "optionalDependency"},
{"slug": "multiverse-signportals", "type": "optionalDependency"},
{"slug": "multiverse-inventories", "type": "optionalDependency"}
]
file_path: ${{ github.workspace }}/subdir/multiverse-core-${{ steps.release-artifact.outputs.version }}.jar
debug: true
+17
View File
@@ -0,0 +1,17 @@
name: "Pull Request Labeler"
on:
pull_request_target:
types: [opened]
branches: [main]
jobs:
prerelease_labeler:
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v4
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
+90
View File
@@ -0,0 +1,90 @@
name: Manually promote last prerelease to release
on:
workflow_dispatch:
inputs:
version:
description: 'Version to promote'
required: true
version-bump:
description: 'Version bump to apply - should usually match the version bump used for the prerelease since last release'
required: true
type: choice
options:
- 'patch'
- 'minor'
- 'major'
jobs:
manually_promote_release:
runs-on: ubuntu-latest
steps:
- name: Verify input version is prerelease
run: |
if [[ "${{ github.event.inputs.version }}" != *"pre"* ]]; then
echo "Version must be a prerelease"
exit 1
fi
- name: Get release info
id: get-release
uses: cardinalby/git-get-release-action@v1
env:
GITHUB_TOKEN: ${{ github.token }}
with:
tag: ${{ github.event.inputs.version }}
- uses: actions/checkout@v3
with:
ref: ${{ steps.get-release.outputs.tag_name }}
- uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'adopt'
cache: gradle
- name: Validate Gradle wrapper
uses: gradle/wrapper-validation-action@v1
- name: Remove prerelease tag
run: |
echo "Removing prerelease tag from version"
echo "VERSION=$(echo ${{ steps.get-release.outputs.tag_name }} | sed -E 's/-pre.*//')" >> $GITHUB_ENV
- name: Build
uses: gradle/gradle-build-action@v2
with:
arguments: clean build -x test -x checkstyleMain -x checkstyleTest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_VERSION: ${{ env.VERSION }}
- name: Create release
id: release
uses: Multiverse/release-on-push-action@skip_prs
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
bump_version_scheme: ${{ github.event.inputs.version-bump }}
tag_prefix: ''
release_name: "<RELEASE_VERSION>"
use_github_release_notes: true
ref: ${{ steps.get-release.outputs.target_commitish }}
skip_prs: true
- name: Publish package
uses: gradle/gradle-build-action@v2
with:
arguments: publish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_VERSION: ${{ env.VERSION }}
- name: Upload release artifact
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: build/libs/multiverse-core-${{ env.VERSION }}.jar
asset_name: multiverse-core-${{ steps.release.outputs.tag_name }}.jar
tag: ${{ steps.release.outputs.tag_name }}
+21 -18
View File
@@ -1,4 +1,4 @@
name: Create Release Version
name: Create Release Version & Publish Package
on:
push:
@@ -12,7 +12,7 @@ jobs:
- uses: actions/setup-java@v3
with:
java-version: '11'
java-version: '17'
distribution: 'adopt'
cache: gradle
@@ -27,35 +27,38 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Create release
uses: rymndhng/release-on-push-action@v0.27.0
id: release
uses: Multiverse/release-on-push-action@support_prerelease
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
bump_version_scheme: norelease
tag_prefix: v
release_name: "Release <RELEASE_VERSION>"
tag_prefix: ''
release_name: "<RELEASE_VERSION>"
use_github_release_notes: true
- name: Get release
id: get_release
uses: bruceadams/get-release@v1.3.2
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Modify version scheme
run: |
if [[ "${{ steps.release.outputs.tag_name }}" == *"pre"* ]]; then
echo "Replacing prerelease version scheme with SNAPSHOT"
echo "VERSION=$(echo ${{ steps.release.outputs.tag_name }} | sed -E 's/-pre.*/-SNAPSHOT/')" >> $GITHUB_ENV
else
echo "Using release version scheme"
echo "VERSION=${{ steps.release.outputs.tag_name }}" >> $GITHUB_ENV
fi
- name: Publish package
uses: gradle/gradle-build-action@v2
with:
arguments: publish
env:
GITHUB_VERSION: ${{ steps.get_release.outputs.tag }}
GITHUB_VERSION: ${{ env.VERSION }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload release artifact
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
uses: svenstaro/upload-release-action@v2
with:
upload_url: ${{ steps.get_release.outputs.upload_url }}
asset_path: build/libs/Multiverse-Core-${{ steps.get_release.outputs.tag }}.jar
asset_name: Multiverse-Core-${{ steps.get_release.outputs.tag }}.jar
asset_content_type: application/java-archive
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: build/libs/multiverse-core-${{ env.VERSION }}.jar
asset_name: multiverse-core-${{ steps.release.outputs.tag_name }}.jar
tag: ${{ steps.release.outputs.tag_name }}
+1 -1
View File
@@ -15,4 +15,4 @@ jobs:
with:
mode: exactly
count: 1
labels: "release:major, release:minor, release:patch, no release"
labels: "release:major, release:minor, release:patch, no version bump"
+9 -2
View File
@@ -14,7 +14,7 @@ jobs:
- uses: actions/setup-java@v3
with:
java-version: '11'
java-version: '17'
distribution: 'adopt'
cache: gradle
@@ -24,6 +24,13 @@ jobs:
- name: Run unit tests
uses: gradle/gradle-build-action@v2
with:
arguments: build
arguments: build -x checkstyleMain -x checkstyleTest -x javadoc
env:
GITHUB_VERSION: pr${{ github.event.pull_request.number }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Artifact output
uses: actions/upload-artifact@v3
with:
name: multiverse-core-pr${{ github.event.pull_request.number }}
path: build/libs/multiverse-core-pr${{ github.event.pull_request.number }}.jar
+113 -23
View File
@@ -5,16 +5,23 @@ plugins {
id 'maven-publish'
id 'checkstyle'
id 'com.github.johnrengelman.shadow' version '7.1.2'
id "org.jetbrains.kotlin.jvm" version "1.8.10"
}
version = System.getenv('GITHUB_VERSION')?.substring(1) ?: 'local'
version = System.getenv('GITHUB_VERSION') ?: 'local'
group = 'com.onarandombox.multiversecore'
description = 'Multiverse-Core'
java.sourceCompatibility = JavaVersion.VERSION_11
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(17))
}
}
repositories {
mavenLocal()
mavenCentral()
maven {
url = uri('https://hub.spigotmc.org/nexus/content/repositories/snapshots/')
}
@@ -48,43 +55,80 @@ repositories {
name = 'glaremasters repo'
url = 'https://repo.glaremasters.me/repository/towny/'
}
maven {
name = 'PlaceholderAPI'
url = 'https://repo.extendedclip.com/content/repositories/placeholderapi/'
}
}
configurations {
oldTestImplementation.extendsFrom implementation
oldTestRuntime.extendsFrom runtime
relocatedApi
compileClasspath.extendsFrom relocatedApi
runtimeClasspath.extendsFrom relocatedApi
testCompileClasspath.extendsFrom relocatedApi
testRuntimeClasspath.extendsFrom relocatedApi
oldTestCompileClasspath.extendsFrom relocatedApi
oldTestRuntimeClasspath.extendsFrom relocatedApi
}
dependencies {
// Spigot
implementation('org.spigotmc:spigot-api:1.16.5-R0.1-SNAPSHOT') {
exclude group: 'junit', module: 'junit'
}
compileOnly 'org.spigotmc:spigot-api:1.16.5-R0.1-SNAPSHOT'
// Economy
implementation('com.github.MilkBowl:VaultAPI:1.7.1') {
exclude group: 'org.bukkit', module: 'bukkit'
}
// PlaceholderAPI
implementation 'me.clip:placeholderapi:2.11.3'
// Command Framework
api 'co.aikar:acf-paper:0.5.1-SNAPSHOT'
relocatedApi 'co.aikar:acf-paper:0.5.1-SNAPSHOT'
// Config
api('me.main__.util:SerializationConfig:1.7') {
relocatedApi('me.main__.util:SerializationConfig:1.7') {
exclude group: 'org.bukkit', module: 'bukkit'
}
api('io.github.townyadvanced.commentedconfiguration:CommentedConfiguration:1.0.0') {
relocatedApi('io.github.townyadvanced.commentedconfiguration:CommentedConfiguration:1.0.1') {
exclude group: 'org.spigotmc', module: 'spigot-api'
}
// Utils
api('com.dumptruckman.minecraft:Logging:1.1.1') {
relocatedApi 'io.vavr:vavr:0.10.4'
relocatedApi 'org.glassfish.hk2:hk2-locator:3.0.3'
relocatedApi('com.dumptruckman.minecraft:Logging:1.1.1') {
exclude group: 'junit', module: 'junit'
}
api 'de.themoep.idconverter:mappings:1.2-SNAPSHOT'
api 'org.bstats:bstats-bukkit:2.2.1'
api 'net.minidev:json-smart:2.4.8'
api 'org.jetbrains:annotations:22.0.0'
relocatedApi 'de.themoep.idconverter:mappings:1.2-SNAPSHOT'
relocatedApi 'org.bstats:bstats-bukkit:2.2.1'
relocatedApi 'net.minidev:json-smart:2.4.8'
relocatedApi 'org.jetbrains:annotations:22.0.0'
relocatedApi 'io.papermc:paperlib:1.0.8'
// Tests
testImplementation 'junit:junit:4.13.1'
testImplementation 'org.mockito:mockito-core:3.11.2'
testImplementation 'commons-io:commons-io:2.7'
testImplementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.10'
testImplementation 'com.github.seeseemelk:MockBukkit-v1.19:2.141.0'
testImplementation('com.googlecode.json-simple:json-simple:1.1.1') {
exclude group: 'junit', module: 'junit'
}
testImplementation 'org.jetbrains.kotlin:kotlin-test'
testImplementation 'com.natpryce:hamkrest:1.8.0.1'
testImplementation 'org.mockito.kotlin:mockito-kotlin:4.1.0'
// Old Tests
oldTestImplementation 'org.spigotmc:spigot-api:1.19.3-R0.1-SNAPSHOT'
oldTestImplementation('com.googlecode.json-simple:json-simple:1.1.1') {
exclude group: 'junit', module: 'junit'
}
oldTestImplementation 'junit:junit:4.13.1'
oldTestImplementation 'org.mockito:mockito-core:3.11.2'
oldTestImplementation 'commons-io:commons-io:2.7'
// Annotation Processors
annotationProcessor 'org.glassfish.hk2:hk2-metadata-generator:3.0.3'
testAnnotationProcessor 'org.glassfish.hk2:hk2-metadata-generator:3.0.3'
}
@@ -109,6 +153,19 @@ configurations {
}
}
sourceSets {
oldTest {
java {
compileClasspath += main.output
runtimeClasspath += main.output
srcDir file('src/old-test/java')
}
resources.srcDir file('src/old-test/resources')
}
}
publishing {
publications {
maven(MavenPublication) {
@@ -142,6 +199,19 @@ task prepareSource(type: Sync) {
compileJava {
source = prepareSource.outputs
}
tasks.withType(JavaCompile) {
configure(options) {
options.compilerArgs << '-Aorg.glassfish.hk2.metadata.location=META-INF/hk2-locator/Multiverse-Core'
}
}
compileKotlin {
// We're not using Kotlin in the plugin itself, just tests!
enabled = false
}
configurations.findAll { !it.name.startsWith('test') }.each {
it.exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk8'
}
processResources {
def props = [version: "${project.version}"]
@@ -173,24 +243,44 @@ javadoc {
project.configurations.api.canBeResolved = true
shadowJar {
relocate 'co.alkar.commands', 'com.onarandombox.acf'
relocate 'co.aikar.commands', 'com.onarandombox.acf'
relocate 'com.dumptruckman.minecraft.util.Logging', 'com.onarandombox.MultiverseCore.utils.CoreLogging'
relocate 'com.dumptruckman.minecraft.util.DebugLog', 'com.onarandombox.MultiverseCore.utils.DebugFileLogger'
relocate 'de.themoep.idconverter', 'com.onarandombox.idconverter'
relocate 'io.github.townyadvanced.commentedconfiguration', 'com.onarandombox.commentedconfiguration'
relocate 'me.main__.util', 'com.onarandombox.serializationconfig'
relocate 'org.bstats', 'com.onarandombox.bstats'
relocate 'com.sun', 'com.onarandombox.sun'
relocate 'net.minidev', 'com.onarandombox.minidev'
relocate 'org.objectweb', 'com.onarandombox.objectweb'
relocate 'io.vavr', 'com.onarandombox.vavr'
relocate 'jakarta', 'com.onarandombox.jakarta'
relocate 'javassist', 'com.onarandombox.javassist'
relocate 'org.aopalliance', 'com.onarandombox.aopalliance'
relocate 'org.glassfish', 'com.onarandombox.glassfish'
relocate 'org.jvnet', 'com.onarandombox.jvnet'
relocate 'org.intellij', 'com.onarandombox.intellij'
relocate 'org.jetbrains', 'com.onarandombox.jetbrains'
relocate 'io.papermc.lib', 'com.onarandombox.paperlib'
configurations = [project.configurations.api]
configurations = [project.configurations.api, project.configurations.relocatedApi]
archiveFileName = "$baseName-$version.$extension"
dependencies {
exclude(dependency {
it.moduleGroup == 'org.jetbrains.kotlin'
})
}
}
build.dependsOn shadowJar
jar.enabled = false
// Excludes all test
// TODO: Remove this when we have tests for MV5
test {
exclude '**/*'
useJUnitPlatform()
testLogging {
exceptionFormat = 'full'
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
* This file was generated by the Gradle 'init' task.
*/
rootProject.name = 'Multiverse-Core'
rootProject.name = 'multiverse-core'
@@ -0,0 +1,13 @@
package co.aikar.commands;
import org.bukkit.command.CommandSender;
/**
* Exists just so we can extend BukkitCommandIssuer since it has a package-private constructor.
*/
public abstract class OpenBukkitCommandIssuer extends BukkitCommandIssuer {
protected OpenBukkitCommandIssuer(BukkitCommandManager manager, CommandSender sender) {
super(manager, sender);
}
}
@@ -7,104 +7,70 @@
package com.onarandombox.MultiverseCore;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.anchor.AnchorManager;
import com.onarandombox.MultiverseCore.api.BlockSafety;
import com.onarandombox.MultiverseCore.api.LocationManipulation;
import com.onarandombox.MultiverseCore.api.MVConfig;
import com.onarandombox.MultiverseCore.api.Destination;
import com.onarandombox.MultiverseCore.api.MVCore;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.api.SafeTTeleporter;
import com.onarandombox.MultiverseCore.commands.CheckCommand;
import com.onarandombox.MultiverseCore.commands.CloneCommand;
import com.onarandombox.MultiverseCore.commands.ConfirmCommand;
import com.onarandombox.MultiverseCore.commands.CreateCommand;
import com.onarandombox.MultiverseCore.commands.DebugCommand;
import com.onarandombox.MultiverseCore.commands.DeleteCommand;
import com.onarandombox.MultiverseCore.commands.ImportCommand;
import com.onarandombox.MultiverseCore.commands.GameruleCommand;
import com.onarandombox.MultiverseCore.commands.LoadCommand;
import com.onarandombox.MultiverseCore.commands.RegenCommand;
import com.onarandombox.MultiverseCore.commands.ReloadCommand;
import com.onarandombox.MultiverseCore.commands.RemoveCommand;
import com.onarandombox.MultiverseCore.commands.TeleportCommand;
import com.onarandombox.MultiverseCore.commands.UnloadCommand;
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager;
import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand;
import com.onarandombox.MultiverseCore.commandtools.PluginLocales;
import com.onarandombox.MultiverseCore.config.MVCoreConfig;
import com.onarandombox.MultiverseCore.destination.DestinationsProvider;
import com.onarandombox.MultiverseCore.destination.core.AnchorDestination;
import com.onarandombox.MultiverseCore.destination.core.BedDestination;
import com.onarandombox.MultiverseCore.destination.core.CannonDestination;
import com.onarandombox.MultiverseCore.destination.core.ExactDestination;
import com.onarandombox.MultiverseCore.destination.core.PlayerDestination;
import com.onarandombox.MultiverseCore.destination.core.WorldDestination;
import com.onarandombox.MultiverseCore.economy.MVEconomist;
import com.onarandombox.MultiverseCore.event.MVDebugModeEvent;
import com.onarandombox.MultiverseCore.listeners.MVChatListener;
import com.onarandombox.MultiverseCore.listeners.MVEntityListener;
import com.onarandombox.MultiverseCore.listeners.MVPlayerListener;
import com.onarandombox.MultiverseCore.listeners.MVPortalListener;
import com.onarandombox.MultiverseCore.listeners.MVWeatherListener;
import com.onarandombox.MultiverseCore.listeners.MVWorldInitListener;
import com.onarandombox.MultiverseCore.listeners.MVWorldListener;
import com.onarandombox.MultiverseCore.teleportation.SimpleBlockSafety;
import com.onarandombox.MultiverseCore.teleportation.SimpleLocationManipulation;
import com.onarandombox.MultiverseCore.teleportation.SimpleSafeTTeleporter;
import com.onarandombox.MultiverseCore.utils.MVPermissions;
import com.onarandombox.MultiverseCore.inject.InjectableListener;
import com.onarandombox.MultiverseCore.inject.PluginInjection;
import com.onarandombox.MultiverseCore.placeholders.MultiverseCorePlaceholders;
import com.onarandombox.MultiverseCore.utils.TestingMode;
import com.onarandombox.MultiverseCore.utils.UnsafeCallWrapper;
import com.onarandombox.MultiverseCore.utils.metrics.MetricsConfigurator;
import com.onarandombox.MultiverseCore.world.SimpleMVWorldManager;
import com.onarandombox.MultiverseCore.world.WorldProperties;
import io.vavr.control.Try;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import me.main__.util.SerializationConfig.SerializationConfig;
import org.bukkit.configuration.Configuration;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.plugin.java.JavaPluginLoader;
import org.glassfish.hk2.api.MultiException;
import org.glassfish.hk2.api.ServiceHandle;
import org.glassfish.hk2.api.ServiceLocator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jvnet.hk2.annotations.Service;
/**
* The implementation of the Multiverse-{@link MVCore}.
*/
@Service
public class MultiverseCore extends JavaPlugin implements MVCore {
private static final int PROTOCOL = 50;
// Setup various managers
private final AnchorManager anchorManager = new AnchorManager(this);
private BlockSafety blockSafety = new SimpleBlockSafety(this);
private MVCommandManager commandManager;
private DestinationsProvider destinationsProvider;
private MVEconomist economist;
private LocationManipulation locationManipulation = new SimpleLocationManipulation();
private final MVPermissions mvPermissions = new MVPermissions(this);
private SafeTTeleporter safeTTeleporter = new SimpleSafeTTeleporter(this);
private final UnsafeCallWrapper unsafeCallWrapper = new UnsafeCallWrapper(this);
private final MVWorldManager worldManager = new SimpleMVWorldManager(this);
// Configurations
private FileConfiguration multiverseConfig;
private volatile MultiverseCoreConfiguration config;
// Listeners
private MVChatListener chatListener;
private final MVEntityListener entityListener = new MVEntityListener(this);
private final MVPlayerListener playerListener = new MVPlayerListener(this);
private final MVPortalListener portalListener = new MVPortalListener(this);
private final MVWeatherListener weatherListener = new MVWeatherListener(this);
private final MVWorldListener worldListener = new MVWorldListener(this);
private final MVWorldInitListener worldInitListener = new MVWorldInitListener(this);
private ServiceLocator serviceLocator;
@Inject
private MVCoreConfig config;
@Inject
private Provider<MVWorldManager> worldManagerProvider;
@Inject
private Provider<AnchorManager> anchorManagerProvider;
@Inject
private Provider<MVCommandManager> commandManagerProvider;
@Inject
private Provider<DestinationsProvider> destinationsProviderProvider;
@Inject
private Provider<MetricsConfigurator> metricsConfiguratorProvider;
@Inject
private Provider<MVEconomist> economistProvider;
@Inject
private Provider<PluginLocales> pluginLocalesProvider;
// Counter for the number of plugins that have registered with us
private int pluginCount;
@@ -125,7 +91,6 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
Logging.init(this);
// Register our config classes
SerializationConfig.registerAll(MultiverseCoreConfiguration.class);
SerializationConfig.registerAll(WorldProperties.class);
SerializationConfig.initLogging(Logging.getLogger());
}
@@ -135,38 +100,44 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
*/
@Override
public void onEnable() {
initializeDependencyInjection();
// Load our configs first as we need them for everything else.
this.loadConfigs();
if (this.multiverseConfig == null) {
if (config == null || !config.isLoaded()) {
Logging.severe("Your configs were not loaded.");
Logging.severe("Please check your configs and restart the server.");
this.getServer().getPluginManager().disablePlugin(this);
return;
}
Logging.setShowingConfig(!getMVConfig().getSilentStart());
Logging.setShowingConfig(shouldShowConfig());
this.worldManager.getDefaultWorldGenerators();
this.worldManager.loadDefaultWorlds();
this.worldManager.loadWorlds(true);
var worldManager = worldManagerProvider.get();
worldManager.loadWorldsConfig();
worldManager.getDefaultWorldGenerators();
worldManager.loadDefaultWorlds();
worldManager.loadWorlds(true);
// Now set the firstspawnworld (after the worlds are loaded):
this.worldManager.setFirstSpawnWorld(getMVConfig().getFirstSpawnWorld());
MVWorld firstSpawnWorld = this.worldManager.getFirstSpawnWorld();
worldManager.setFirstSpawnWorld(config.getFirstSpawnLocation());
MVWorld firstSpawnWorld = worldManager.getFirstSpawnWorld();
if (firstSpawnWorld != null) {
getMVConfig().setFirstSpawnWorld(firstSpawnWorld.getName());
config.setFirstSpawnLocation(firstSpawnWorld.getName());
}
//Setup economy here so vault is loaded
this.economist = new MVEconomist(this);
this.loadEconomist();
// Init all the other stuff
this.anchorManager.loadAnchors();
this.loadAnchors();
this.registerEvents();
this.setUpLocales();
this.registerCommands();
this.registerDestinations();
this.setupMetrics();
this.saveMVConfig();
this.loadPlaceholderAPIIntegration();
this.saveAllConfigs();
this.logEnableMessage();
}
@@ -176,56 +147,110 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
@Override
public void onDisable() {
this.saveAllConfigs();
shutdownDependencyInjection();
Logging.shutdown();
}
private void initializeDependencyInjection() {
serviceLocator = PluginInjection.createServiceLocator(new MultiverseCorePluginBinder(this))
.andThenTry(locator -> {
PluginInjection.enable(this, locator);
})
.getOrElseThrow(exception -> {
Logging.severe("Failed to initialize dependency injection");
getServer().getPluginManager().disablePlugin(this);
return new RuntimeException(exception);
});
}
private void shutdownDependencyInjection() {
if (serviceLocator != null) {
PluginInjection.disable(this, serviceLocator);
serviceLocator = null;
}
}
private boolean shouldShowConfig() {
return !config.getSilentStart();
}
private void loadEconomist() {
Try.run(() -> economistProvider.get())
.onFailure(e -> {
Logging.severe("Failed to load economy integration");
e.printStackTrace();
});
}
private void loadAnchors() {
Try.of(() -> anchorManagerProvider.get())
.onSuccess(AnchorManager::loadAnchors)
.onFailure(e -> {
Logging.severe("Failed to load anchors");
e.printStackTrace();
});
}
/**
* Function to Register all the Events needed.
*/
private void registerEvents() {
PluginManager pluginManager = getServer().getPluginManager();
this.chatListener = new MVChatListener(this, this.playerListener);
pluginManager.registerEvents(this.chatListener, this);
pluginManager.registerEvents(this.entityListener, this);
pluginManager.registerEvents(this.playerListener, this);
pluginManager.registerEvents(this.portalListener, this);
pluginManager.registerEvents(this.weatherListener, this);
pluginManager.registerEvents(this.worldListener, this);
pluginManager.registerEvents(this.worldInitListener, this);
var pluginManager = getServer().getPluginManager();
Try.run(() -> serviceLocator.getAllServices(InjectableListener.class)
.forEach(listener -> pluginManager.registerEvents(listener, this)))
.onFailure(e -> {
throw new RuntimeException("Failed to register listeners. Terminating...", e);
});
}
/**
* Register Multiverse-Core commands to Command Manager.
*/
private void registerCommands() {
this.commandManager = new MVCommandManager(this);
this.commandManager.registerCommand(new CheckCommand(this));
this.commandManager.registerCommand(new CloneCommand(this));
this.commandManager.registerCommand(new ConfirmCommand(this));
this.commandManager.registerCommand(new CreateCommand(this));
this.commandManager.registerCommand(new DebugCommand(this));
this.commandManager.registerCommand(new DeleteCommand(this));
this.commandManager.registerCommand(new ImportCommand(this));
this.commandManager.registerCommand(new GameruleCommand(this));
this.commandManager.registerCommand(new LoadCommand(this));
this.commandManager.registerCommand(new RegenCommand(this));
this.commandManager.registerCommand(new ReloadCommand(this));
this.commandManager.registerCommand(new RemoveCommand(this));
this.commandManager.registerCommand(new TeleportCommand(this));
this.commandManager.registerCommand(new UnloadCommand(this));
Try.of(() -> commandManagerProvider.get())
.andThenTry(commandManager -> {
serviceLocator.getAllServices(MultiverseCommand.class)
.forEach(commandManager::registerCommand);
})
.onFailure(e -> {
Logging.severe("Failed to register commands");
e.printStackTrace();
});
}
/**
* Register locales
*/
private void setUpLocales() {
Try.of(() -> commandManagerProvider.get())
.andThen(commandManager -> {
commandManager.usePerIssuerLocale(true, true);
})
.mapTry(commandManager -> pluginLocalesProvider.get())
.andThen(pluginLocales -> {
pluginLocales.addFileResClassLoader(this);
pluginLocales.addMessageBundles("multiverse-core");
})
.onFailure(e -> {
Logging.severe("Failed to register locales");
e.printStackTrace();
});
}
/**
* Register all the destinations.
*/
private void registerDestinations() {
this.destinationsProvider = new DestinationsProvider(this);
this.destinationsProvider.registerDestination(new AnchorDestination(this));
this.destinationsProvider.registerDestination(new BedDestination());
this.destinationsProvider.registerDestination(new CannonDestination(this));
this.destinationsProvider.registerDestination(new ExactDestination(this));
this.destinationsProvider.registerDestination(new PlayerDestination());
this.destinationsProvider.registerDestination(new WorldDestination(this));
Try.of(() -> destinationsProviderProvider.get())
.andThenTry(destinationsProvider -> {
serviceLocator.getAllServices(Destination.class)
.forEach(destinationsProvider::registerDestination);
})
.onFailure(e -> {
Logging.severe("Failed to register destinations");
e.printStackTrace();
});
}
/**
@@ -233,7 +258,14 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
*/
private void setupMetrics() {
if (TestingMode.isDisabled()) {
MetricsConfigurator.configureMetrics(this);
// Load metrics
Try.of(() -> metricsConfiguratorProvider.get())
.onFailure(e -> {
Logging.severe("Failed to setup metrics");
e.printStackTrace();
});
} else {
Logging.info("Metrics are disabled in testing mode.");
}
}
@@ -243,9 +275,20 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
private void logEnableMessage() {
Logging.config("Version %s (API v%s) Enabled - By %s", this.getDescription().getVersion(), PROTOCOL, getAuthors());
if (getMVConfig().isShowingDonateMessage()) {
getLogger().config("Help dumptruckman keep this project alive. Become a patron! https://www.patreon.com/dumptruckman");
getLogger().config("One time donations are also appreciated: https://www.paypal.me/dumptruckman");
if (config.isShowingDonateMessage()) {
Logging.config("Help dumptruckman keep this project alive. Become a patron! https://www.patreon.com/dumptruckman");
Logging.config("One time donations are also appreciated: https://www.paypal.me/dumptruckman");
}
}
private void loadPlaceholderAPIIntegration() {
if (config.isRegisterPapiHook()
&& getServer().getPluginManager().getPlugin("PlaceholderAPI") != null) {
Try.run(() -> serviceLocator.createAndInitialize(MultiverseCorePlaceholders.class))
.onFailure(e -> {
Logging.severe("Failed to load PlaceholderAPI integration.");
e.printStackTrace();
});
}
}
@@ -265,21 +308,6 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
return PROTOCOL;
}
/**
* {@inheritDoc}
*/
public MVEconomist getEconomist() {
return economist;
}
/**
* {@inheritDoc}
*/
@Override
public MVPermissions getMVPerms() {
return this.mvPermissions;
}
/**
* {@inheritDoc}
*/
@@ -304,14 +332,6 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
return authors.toString();
}
/**
* {@inheritDoc}
*/
@Override
public MVCommandManager getMVCommandManager() {
return this.commandManager;
}
/**
* {@inheritDoc}
*/
@@ -320,6 +340,12 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
return this.pluginCount;
}
@NotNull
@Override
public Logger getLogger() {
return Logging.getLogger();
}
/**
* {@inheritDoc}
*/
@@ -336,203 +362,58 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
this.pluginCount -= 1;
}
/**
* {@inheritDoc}
*/
@Override
public DestinationsProvider getDestinationsProvider() {
return this.destinationsProvider;
}
/**
* {@inheritDoc}
*/
@Override
public MVWorldManager getMVWorldManager() {
return this.worldManager;
}
/**
* {@inheritDoc}
*/
@Override
public void loadConfigs() {
// Now grab the Configuration Files.
this.multiverseConfig = YamlConfiguration.loadConfiguration(new File(getDataFolder(), "config.yml"));
InputStream resourceURL = this.getClass().getResourceAsStream("/defaults/config.yml");
// Read in our default config with UTF-8 now
Configuration coreDefaults;
try {
coreDefaults = YamlConfiguration.loadConfiguration(new BufferedReader(new InputStreamReader(resourceURL, "UTF-8")));
this.multiverseConfig.setDefaults(coreDefaults);
} catch (UnsupportedEncodingException e) {
Logging.severe("Couldn't load default config with UTF-8 encoding. Details follow:");
e.printStackTrace();
Logging.severe("Default configs NOT loaded.");
}
this.multiverseConfig.options().copyDefaults(false);
this.multiverseConfig.options().copyHeader(true);
MultiverseCoreConfiguration wantedConfig = null;
try {
wantedConfig = (MultiverseCoreConfiguration) multiverseConfig.get("multiverse-configuration");
} catch (Exception ignore) {
} finally {
config = ((wantedConfig == null) ? new MultiverseCoreConfiguration() : wantedConfig);
}
this.worldManager.loadWorldConfig(new File(getDataFolder(), "worlds.yml"));
int level = Logging.getDebugLevel();
Logging.setDebugLevel(getMVConfig().getGlobalDebug());
if (level != Logging.getDebugLevel()) {
getServer().getPluginManager().callEvent(new MVDebugModeEvent(level));
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean saveMVConfig() {
try {
this.multiverseConfig.set("multiverse-configuration", getMVConfig());
this.multiverseConfig.save(new File(getDataFolder(), "config.yml"));
return true;
} catch (IOException e) {
Logging.severe("Could not save Multiverse config.yml config. Please check your file permissions.");
return false;
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean saveAllConfigs() {
return this.saveMVConfig() && this.worldManager.saveWorldsConfig();
}
/**
* {@inheritDoc}
*/
@Override
public AnchorManager getAnchorManager() {
return this.anchorManager;
}
/**
* {@inheritDoc}
*/
@Override
public BlockSafety getBlockSafety() {
return blockSafety;
}
/**
* {@inheritDoc}
*/
@Override
public void setBlockSafety(BlockSafety blockSafety) {
if (blockSafety == null) {
throw new NullPointerException("block safety may not be null.");
}
this.blockSafety = blockSafety;
}
/**
* {@inheritDoc}
*/
@Override
public LocationManipulation getLocationManipulation() {
return locationManipulation;
}
/**
* {@inheritDoc}
*/
@Override
public void setLocationManipulation(LocationManipulation locationManipulation) {
if (locationManipulation == null) {
throw new NullPointerException("location manipulation may not be null.");
}
this.locationManipulation = locationManipulation;
}
/**
* {@inheritDoc}
*/
@Override
public SafeTTeleporter getSafeTTeleporter() {
return safeTTeleporter;
}
/**
* {@inheritDoc}
*/
@Override
public void setSafeTTeleporter(SafeTTeleporter safeTTeleporter) {
if (safeTTeleporter == null) {
throw new NullPointerException("safeTTeleporter may not be null.");
}
this.safeTTeleporter = safeTTeleporter;
}
/**
* {@inheritDoc}
*/
@Override
public MVConfig getMVConfig() {
return config;
}
/**
* {@inheritDoc}
*/
@Override
public UnsafeCallWrapper getUnsafeCallWrapper() {
return this.unsafeCallWrapper;
return config.save()
&& worldManagerProvider.get().saveWorldsConfig()
&& anchorManagerProvider.get().saveAnchors();
}
//TODO: REMOVE THIS STATIC CRAP - START
private static final Map<String, String> teleportQueue = new HashMap<String, String>();
/**
* This method is used to add a teleportation to the teleportQueue.
* Gets the best service from this plugin that implements the given contract or has the given implementation.
*
* @param teleporter The name of the player that initiated the teleportation.
* @param teleportee The name of the player that was teleported.
* @param contractOrImpl The contract or concrete implementation to get the best instance of
* @param qualifiers The set of qualifiers that must match this service definition
* @return An instance of the contract or impl if it is a service and is already instantiated, null otherwise
* @throws MultiException if there was an error during service lookup
*/
public static void addPlayerToTeleportQueue(String teleporter, String teleportee) {
Logging.finest("Adding mapping '%s' => '%s' to teleport queue", teleporter, teleportee);
teleportQueue.put(teleportee, teleporter);
}
/**
* This method is used to find out who is teleporting a player.
* @param playerName The teleported player (the teleportee).
* @return The player that teleported the other one (the teleporter).
*/
public static String getPlayerTeleporter(String playerName) {
if (teleportQueue.containsKey(playerName)) {
String teleportee = teleportQueue.get(playerName);
teleportQueue.remove(playerName);
return teleportee;
@Nullable
public <T> T getService(@NotNull Class<T> contractOrImpl, Annotation... qualifiers) throws MultiException {
var handle = serviceLocator.getServiceHandle(contractOrImpl, qualifiers);
if (handle != null && handle.isActive()) {
return handle.getService();
}
return null;
}
//TODO: REMOVE THIS STATIC CRAP - END
// For testing purposes only //
private File serverFolder = new File(System.getProperty("user.dir"));
/**
* This is for unit testing.
* Gets all services from this plugin that implement the given contract or have the given implementation and have
* the provided qualifiers.
*
* @param contractOrImpl The contract or concrete implementation to get the best instance of
* @param qualifiers The set of qualifiers that must match this service definition
* @return A list of services implementing this contract or concrete implementation. May not return null, but may
* return an empty list
* @throws MultiException if there was an error during service lookup
*/
@NotNull
public <T> List<T> getAllServices(
@NotNull Class<T> contractOrImpl,
Annotation... qualifiers
) throws MultiException {
var handles = serviceLocator.getAllServiceHandles(contractOrImpl, qualifiers);
return handles.stream()
.filter(ServiceHandle::isActive)
.map(ServiceHandle::getService)
.collect(Collectors.toList());
}
/**
* This is for unit testing ONLY. Do not use this constructor.
*
* @param loader The PluginLoader to use.
* @param description The Description file to use.
@@ -542,61 +423,4 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
public MultiverseCore(JavaPluginLoader loader, PluginDescriptionFile description, File dataFolder, File file) {
super(loader, description, dataFolder, file);
}
/**
* Gets the {@link MVPlayerListener}.
*
* @return The {@link MVPlayerListener}.
*/
public MVPlayerListener getPlayerListener() {
return this.playerListener;
}
/**
* Gets the {@link MVChatListener}.
*
* @return The {@link MVChatListener}.
*/
public MVChatListener getChatListener() {
return this.chatListener;
}
/**
* Gets the {@link MVEntityListener}.
*
* @return The {@link MVEntityListener}.
*/
public MVEntityListener getEntityListener() {
return this.entityListener;
}
/**
* Gets the {@link MVWeatherListener}.
*
* @return The {@link MVWeatherListener}.
*/
public MVWeatherListener getWeatherListener() {
return this.weatherListener;
}
/**
* Gets the server's root-folder as {@link File}.
*
* @return The server's root-folder
*/
public File getServerFolder() {
return serverFolder;
}
/**
* Sets this server's root-folder.
*
* @param newServerFolder The new server-root
*/
public void setServerFolder(File newServerFolder) {
if (!newServerFolder.isDirectory())
throw new IllegalArgumentException("That's not a folder!");
this.serverFolder = newServerFolder;
}
}
@@ -1,316 +0,0 @@
package com.onarandombox.MultiverseCore;
import java.util.Map;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.api.MVConfig;
import com.onarandombox.MultiverseCore.event.MVDebugModeEvent;
import me.main__.util.SerializationConfig.NoSuchPropertyException;
import me.main__.util.SerializationConfig.Property;
import me.main__.util.SerializationConfig.SerializationConfig;
import org.bukkit.Bukkit;
/**
* Our configuration.
*/
public class MultiverseCoreConfiguration extends SerializationConfig implements MVConfig {
private static MultiverseCoreConfiguration instance;
/**
* Sets the statically saved instance.
* @param instance The new instance.
*/
public static void setInstance(MultiverseCoreConfiguration instance) {
MultiverseCoreConfiguration.instance = instance;
}
/**
* @return True if the static instance of config is set.
*/
public static boolean isSet() {
return instance != null;
}
/**
* Gets the statically saved instance.
* @return The statically saved instance.
*/
@Deprecated
public static MultiverseCoreConfiguration getInstance() {
if (instance == null)
throw new IllegalStateException("The instance wasn't set!");
return instance;
}
@Property
private volatile boolean enforceaccess;
@Property
private volatile boolean prefixchat;
@Property
private volatile String prefixchatformat;
@Property
private volatile boolean teleportintercept;
@Property
private volatile boolean firstspawnoverride;
@Property
private volatile boolean displaypermerrors;
@Property
private volatile int globaldebug;
@Property
private volatile boolean silentstart;
@Property
private volatile double version;
@Property
private volatile String firstspawnworld;
@Property
private volatile boolean defaultportalsearch;
@Property
private volatile int portalsearchradius;
@Property
private volatile boolean autopurge;
@Property
private volatile boolean idonotwanttodonate;
public MultiverseCoreConfiguration() {
super();
MultiverseCoreConfiguration.setInstance(this);
}
public MultiverseCoreConfiguration(Map<String, Object> values) {
super(values);
MultiverseCoreConfiguration.setInstance(this);
}
/**
* {@inheritDoc}
*/
@Override
protected void setDefaults() {
// BEGIN CHECKSTYLE-SUPPRESSION: MagicNumberCheck
enforceaccess = false;
prefixchat = false;
prefixchatformat = "[%world%]%chat%";
teleportintercept = true;
firstspawnoverride = true;
displaypermerrors = true;
globaldebug = 0;
this.version = 2.9;
silentstart = false;
defaultportalsearch = true;
portalsearchradius = 128;
autopurge = true;
idonotwanttodonate = false;
// END CHECKSTYLE-SUPPRESSION: MagicNumberCheck
}
/**
* {@inheritDoc}
*/
@Override
public boolean setConfigProperty(String property, String value) {
try {
return this.setProperty(property, value, true);
} catch (NoSuchPropertyException e) {
return false;
}
}
// And here we go:
/**
* {@inheritDoc}
*/
@Override
public boolean getEnforceAccess() {
return this.enforceaccess;
}
/**
* {@inheritDoc}
*/
@Override
public void setEnforceAccess(boolean enforceAccess) {
this.enforceaccess = enforceAccess;
}
/**
* {@inheritDoc}
*/
@Override
public boolean getPrefixChat() {
return this.prefixchat;
}
/**
* {@inheritDoc}
*/
@Override
public void setPrefixChat(boolean prefixChat) {
this.prefixchat = prefixChat;
}
/**
* {@inheritDoc}
*/
@Override
public String getPrefixChatFormat() {
return this.prefixchatformat;
}
/**
* {@inheritDoc}
*/
@Override
public void setPrefixChatFormat(String prefixChatFormat) {
this.prefixchatformat = prefixChatFormat;
}
/**
* {@inheritDoc}
*/
@Override
public boolean getTeleportIntercept() {
return this.teleportintercept;
}
/**
* {@inheritDoc}
*/
@Override
public void setTeleportIntercept(boolean teleportIntercept) {
this.teleportintercept = teleportIntercept;
}
/**
* {@inheritDoc}
*/
@Override
public boolean getFirstSpawnOverride() {
return this.firstspawnoverride;
}
/**
* {@inheritDoc}
*/
@Override
public void setFirstSpawnOverride(boolean firstSpawnOverride) {
this.firstspawnoverride = firstSpawnOverride;
}
/**
* {@inheritDoc}
*/
@Override
public boolean getDisplayPermErrors() {
return this.displaypermerrors;
}
/**
* {@inheritDoc}
*/
@Override
public void setDisplayPermErrors(boolean displayPermErrors) {
this.displaypermerrors = displayPermErrors;
}
/**
* {@inheritDoc}
*/
@Override
public int getGlobalDebug() {
return this.globaldebug;
}
/**
* {@inheritDoc}
*/
@Override
public void setGlobalDebug(int globalDebug) {
this.globaldebug = globalDebug;
Logging.setDebugLevel(globalDebug);
Bukkit.getPluginManager().callEvent(new MVDebugModeEvent(globalDebug));
}
/**
* {@inheritDoc}
*/
@Override
public double getVersion() {
return this.version;
}
/**
* {@inheritDoc}
*/
@Override
public void setVersion(int version) {
this.version = version;
}
/**
* {@inheritDoc}
*/
@Override
public String getFirstSpawnWorld() {
return this.firstspawnworld;
}
/**
* {@inheritDoc}
*/
@Override
public void setFirstSpawnWorld(String firstSpawnWorld) {
this.firstspawnworld = firstSpawnWorld;
}
@Override
public void setSilentStart(boolean silentStart) {
Logging.setShowingConfig(!silentStart);
this.silentstart = silentStart;
}
@Override
public boolean getSilentStart() {
return silentstart;
}
@Override
public void setUseDefaultPortalSearch(boolean useDefaultPortalSearch) {
defaultportalsearch = useDefaultPortalSearch;
}
@Override
public boolean isUsingDefaultPortalSearch() {
return defaultportalsearch;
}
@Override
public void setPortalSearchRadius(int searchRadius) {
this.portalsearchradius = searchRadius;
}
@Override
public int getPortalSearchRadius() {
return portalsearchradius;
}
@Override
public boolean isAutoPurgeEnabled() {
return autopurge;
}
@Override
public void setAutoPurgeEnabled(boolean autopurge) {
this.autopurge = autopurge;
}
@Override
public boolean isShowingDonateMessage() {
return !idonotwanttodonate;
}
@Override
public void setShowDonateMessage(boolean showDonateMessage) {
this.idonotwanttodonate = !showDonateMessage;
}
}
@@ -0,0 +1,18 @@
package com.onarandombox.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVCore;
import com.onarandombox.MultiverseCore.inject.binder.JavaPluginBinder;
import org.glassfish.hk2.utilities.binding.ScopedBindingBuilder;
import org.jetbrains.annotations.NotNull;
class MultiverseCorePluginBinder extends JavaPluginBinder<MultiverseCore> {
protected MultiverseCorePluginBinder(@NotNull MultiverseCore plugin) {
super(plugin);
}
@Override
protected ScopedBindingBuilder<MultiverseCore> bindPluginClass(ScopedBindingBuilder<MultiverseCore> bindingBuilder) {
return super.bindPluginClass(bindingBuilder).to(MVCore.class).to(MultiverseCore.class);
}
}
@@ -9,11 +9,16 @@ package com.onarandombox.MultiverseCore.anchor;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.LocationManipulation;
import com.onarandombox.MultiverseCore.config.MVCoreConfig;
import jakarta.inject.Inject;
import org.bukkit.Location;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.jvnet.hk2.annotations.Service;
import java.io.File;
import java.io.IOException;
@@ -22,18 +27,29 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
/**
* Manages anchors.
*/
@Service
public class AnchorManager {
private MultiverseCore plugin;
private Map<String, Location> anchors;
private FileConfiguration anchorConfig;
public AnchorManager(MultiverseCore plugin) {
private final Plugin plugin;
private final LocationManipulation locationManipulation;
private final MVCoreConfig config;
@Inject
public AnchorManager(
MultiverseCore plugin,
LocationManipulation locationManipulation,
MVCoreConfig config
) {
this.plugin = plugin;
this.locationManipulation = locationManipulation;
this.config = config;
this.anchors = new HashMap<String, Location>();
}
@@ -48,7 +64,7 @@ public class AnchorManager {
Set<String> anchorKeys = anchorsSection.getKeys(false);
for (String key : anchorKeys) {
//world:x,y,z:pitch:yaw
Location anchorLocation = plugin.getLocationManipulation().stringToLocation(anchorsSection.getString(key, ""));
Location anchorLocation = this.locationManipulation.stringToLocation(anchorsSection.getString(key, ""));
if (anchorLocation != null) {
Logging.config("Loading anchor: '%s'...", key);
this.anchors.put(key, anchorLocation);
@@ -98,7 +114,7 @@ public class AnchorManager {
* @return True if the anchor was successfully saved.
*/
public boolean saveAnchorLocation(String anchor, String location) {
Location parsed = plugin.getLocationManipulation().stringToLocation(location);
Location parsed = this.locationManipulation.stringToLocation(location);
return parsed != null && this.saveAnchorLocation(anchor, parsed);
}
@@ -112,7 +128,7 @@ public class AnchorManager {
if (l == null) {
return false;
}
this.anchorConfig.set("anchors." + anchor, plugin.getLocationManipulation().locationToString(l));
this.anchorConfig.set("anchors." + anchor, this.locationManipulation.locationToString(l));
this.anchors.put(anchor, l);
return this.saveAnchors();
}
@@ -144,8 +160,8 @@ public class AnchorManager {
// Add to the list if we're not enforcing access
// OR
// We are enforcing access and the user has the permission.
if (!this.plugin.getMVConfig().getEnforceAccess() ||
(this.plugin.getMVConfig().getEnforceAccess() && p.hasPermission(worldPerm))) {
if (!config.getEnforceAccess() ||
(config.getEnforceAccess() && p.hasPermission(worldPerm))) {
myAnchors.add(anchor);
} else {
Logging.finer(String.format("Not adding anchor %s to the list, user %s doesn't have the %s " +
@@ -4,10 +4,12 @@ import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Minecart;
import org.bukkit.entity.Vehicle;
import org.jvnet.hk2.annotations.Contract;
/**
* Used to get block/location-related information.
*/
@Contract
public interface BlockSafety {
/**
* This function checks whether the block at the given coordinates are above air or not.
@@ -5,7 +5,9 @@ import java.util.Collection;
import co.aikar.commands.BukkitCommandIssuer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jvnet.hk2.annotations.Contract;
@Contract
public interface Destination<T extends DestinationInstance> {
/**
* Returns the identifier or prefix that is required for this destination.
@@ -3,10 +3,12 @@ package com.onarandombox.MultiverseCore.api;
import org.bukkit.Location;
import org.bukkit.entity.Vehicle;
import org.bukkit.util.Vector;
import org.jvnet.hk2.annotations.Contract;
/**
* Used to manipulate locations.
*/
@Contract
public interface LocationManipulation {
/**
* Convert a Location into a Colon separated string to allow us to store it in text.
@@ -1,78 +1,93 @@
package com.onarandombox.MultiverseCore.api;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import com.onarandombox.MultiverseCore.configuration.node.NodeGroup;
import com.onarandombox.MultiverseCore.placeholders.MultiverseCorePlaceholders;
import io.vavr.control.Try;
import org.jvnet.hk2.annotations.Contract;
/**
* The configuration of MultiverseCore.
*/
public interface MVConfig extends ConfigurationSerializable {
/**
* Sets a property using a {@link String}.
* @param property The name of the property.
* @param value The value.
* @return True on success, false if the operation failed.
*/
boolean setConfigProperty(String property, String value);
@Contract
public interface MVConfig {
/**
* Sets firstSpawnWorld.
* @param firstSpawnWorld The new value.
* Loads the config from disk.
* @return True if the config was loaded successfully.
*/
void setFirstSpawnWorld(String firstSpawnWorld);
boolean load();
/**
* Gets firstSpawnWorld.
* @return firstSpawnWorld.
* Whether the config has been loaded.
* @return True if the config has been loaded.
*/
String getFirstSpawnWorld();
boolean isLoaded();
/**
* Sets version.
* @param version The new value.
* Saves the config to disk.
*/
void setVersion(int version);
boolean save();
/**
* Gets version.
* @return version.
* Gets the nodes for the config.
*
* @return The nodes for the config.
*/
double getVersion();
NodeGroup getNodes();
/**
* Sets globalDebug.
* @param globalDebug The new value.
* Gets a property from the config.
*
* @param name The name of the property.
* @return A {@link Try} with the value of the property, otherwise a {@link Try.Failure} if there is no property by
* that name.
*/
void setGlobalDebug(int globalDebug);
Try<Object> getProperty(String name);
/**
* Gets globalDebug.
* @return globalDebug.
* Sets a property in the config.
*
* @param name The name of the property.
* @param value The value of the property.
* @return An empty {@link Try} if the property was set successfully, otherwise a {@link Try.Failure} with the
* exception explaining why the property could not be set.
*/
int getGlobalDebug();
Try<Void> setProperty(String name, Object value);
/**
* Sets displayPermErrors.
* @param displayPermErrors The new value.
* Sets world access permissions should be enforced.
* @param enforceAccess The new value.
*/
void setDisplayPermErrors(boolean displayPermErrors);
void setEnforceAccess(boolean enforceAccess);
/**
* Gets displayPermErrors.
* @return displayPermErrors.
* Gets enforceAccess.
* @return enforceAccess.
*/
boolean getDisplayPermErrors();
boolean getEnforceAccess();
/**
* Sets firstSpawnOverride.
* @param firstSpawnOverride The new value.
* Sets whether the game mode should be enforced.
* @param enforceGameMode The new value.
*/
void setFirstSpawnOverride(boolean firstSpawnOverride);
void setEnforceGameMode(boolean enforceGameMode);
/**
* Gets firstSpawnOverride.
* @return firstSpawnOverride.
* Gets enforceGameMode value.
* @return True if game mode should be enforced.
*/
boolean getFirstSpawnOverride();
boolean getEnforceGameMode();
/**
* Sets whether or not the automatic purge of entities is enabled.
*
* @param autopurge True if automatic purge should be enabled.
*/
void setAutoPurgeEntities(boolean autopurge);
/**
* Gets whether or not the automatic purge of entities is enabled.
*
* @return True if automatic purge is enabled.
*/
boolean isAutoPurgeEntities();
/**
* Sets teleportIntercept.
@@ -86,18 +101,70 @@ public interface MVConfig extends ConfigurationSerializable {
*/
boolean getTeleportIntercept();
/**
* Sets firstSpawnOverride.
* @param firstSpawnOverride The new value.
*/
void setFirstSpawnOverride(boolean firstSpawnOverride);
/**
* Gets firstSpawnOverride.
* @return firstSpawnOverride.
*/
boolean getFirstSpawnOverride();
/**
* Sets firstSpawnWorld.
* @param firstSpawnWorld The new value.
*/
void setFirstSpawnLocation(String firstSpawnWorld);
/**
* Gets firstSpawnWorld.
* @return firstSpawnWorld.
*/
String getFirstSpawnLocation();
/**
* Sets whether or not to let Bukkit determine portal search radius on its own or if Multiverse should give input.
*
* @param useDefaultPortalSearch True to let Bukkit determine portal search radius on its own.
*/
void setUseCustomPortalSearch(boolean useDefaultPortalSearch);
/**
* Gets whether or not Bukkit will be determining portal search radius on its own or if Multiverse should help.
*
* @return True means Bukkit will use its own default values.
*/
boolean isUsingCustomPortalSearch();
/**
* Sets the radius at which vanilla style portals will be searched for to connect to worlds together.
*
* @param searchRadius The portal search radius.
*/
void setCustomPortalSearchRadius(int searchRadius);
/**
* Gets the radius at which vanilla style portals will be searched for to connect to worlds together.
*
* @return The portal search radius.
*/
int getCustomPortalSearchRadius();
/**
* Sets prefixChat.
* @param prefixChat The new value.
*/
void setPrefixChat(boolean prefixChat);
void setEnablePrefixChat(boolean prefixChat);
/**
* Gets prefixChat.
* @return prefixChat.
*/
boolean getPrefixChat();
boolean isEnablePrefixChat();
/**
* Sets prefixChatFormat.
* @param prefixChatFormat The new value.
@@ -111,16 +178,28 @@ public interface MVConfig extends ConfigurationSerializable {
String getPrefixChatFormat();
/**
* Sets enforceAccess.
* @param enforceAccess The new value.
* Sets whether to register the {@link MultiverseCorePlaceholders} class with PlaceholderAPI plugin.
* @param registerPapiHook The new value.
*/
void setEnforceAccess(boolean enforceAccess);
void setRegisterPapiHook(boolean registerPapiHook);
/**
* Gets enforceAccess.
* @return enforceAccess.
* Gets whether to register the {@link MultiverseCorePlaceholders} class with PlaceholderAPI plugin.
* @return registerPapiHook.
*/
boolean getEnforceAccess();
boolean isRegisterPapiHook();
/**
* Sets globalDebug.
* @param globalDebug The new value.
*/
void setGlobalDebug(int globalDebug);
/**
* Gets globalDebug.
* @return globalDebug.
*/
int getGlobalDebug();
/**
* Sets whether to suppress startup messages.
@@ -137,46 +216,11 @@ public interface MVConfig extends ConfigurationSerializable {
boolean getSilentStart();
/**
* Sets whether or not to let Bukkit determine portal search radius on its own or if Multiverse should give input.
* Sets whether or not the donation/patreon messages are shown.
*
* @param useDefaultPortalSearch True to let Bukkit determine portal search radius on its own.
* @param idonotwanttodonate True if donation/patreon messages should be shown.
*/
void setUseDefaultPortalSearch(boolean useDefaultPortalSearch);
/**
* Gets whether or not Bukkit will be determining portal search radius on its own or if Multiverse should help.
*
* @return True means Bukkit will use its own default values.
*/
boolean isUsingDefaultPortalSearch();
/**
* Sets the radius at which vanilla style portals will be searched for to connect to worlds together.
*
* @param searchRadius The portal search radius.
*/
void setPortalSearchRadius(int searchRadius);
/**
* Gets the radius at which vanilla style portals will be searched for to connect to worlds together.
*
* @return The portal search radius.
*/
int getPortalSearchRadius();
/**
* Gets whether or not the automatic purge of entities is enabled.
*
* @return True if automatic purge is enabled.
*/
boolean isAutoPurgeEnabled();
/**
* Sets whether or not the automatic purge of entities is enabled.
*
* @param autopurge True if automatic purge should be enabled.
*/
void setAutoPurgeEnabled(boolean autopurge);
void setShowDonateMessage(boolean idonotwanttodonate);
/**
* Gets whether or not the donation/patreon messages are shown.
@@ -184,11 +228,4 @@ public interface MVConfig extends ConfigurationSerializable {
* @return True if donation/patreon messages should be shown.
*/
boolean isShowingDonateMessage();
/**
* Sets whether or not the donation/patreon messages are shown.
*
* @param idonotwanttodonate True if donation/patreon messages should be shown.
*/
void setShowDonateMessage(boolean idonotwanttodonate);
}
@@ -7,80 +7,12 @@
package com.onarandombox.MultiverseCore.api;
import com.onarandombox.MultiverseCore.anchor.AnchorManager;
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager;
import com.onarandombox.MultiverseCore.destination.DestinationsProvider;
import com.onarandombox.MultiverseCore.economy.MVEconomist;
import com.onarandombox.MultiverseCore.teleportation.SimpleBlockSafety;
import com.onarandombox.MultiverseCore.teleportation.SimpleLocationManipulation;
import com.onarandombox.MultiverseCore.teleportation.SimpleSafeTTeleporter;
import com.onarandombox.MultiverseCore.utils.MVPermissions;
import com.onarandombox.MultiverseCore.utils.UnsafeCallWrapper;
/**
* Multiverse 2 Core API
* <p>
* This API contains a bunch of useful things you can get out of Multiverse in general!
*/
public interface MVCore extends MVPlugin {
/**
* Retrieves Multiverse's friendly economist. The economist can be used for dealing with economies without
* worrying about any of the messy details.
*
* @return the economy manager for Multiverse.
*/
MVEconomist getEconomist();
/**
* Reloads the Multiverse Configuration files:
* worlds.yml and config.yml.
*/
void loadConfigs();
/**
* Gets the {@link UnsafeCallWrapper} class.
*
* @return A non-null {@link UnsafeCallWrapper}.
*/
UnsafeCallWrapper getUnsafeCallWrapper();
/**
* Multiverse uses an advanced permissions setup, this object
* simplifies getting/setting permissions.
*
* @return A non-null {@link MVPermissions}.
*/
MVPermissions getMVPerms();
/**
* Multiverse uses {@link MVCommandManager} to make adding and using commands
* a piece of cake.
*
* @return A non-null {@link MVCommandManager}.
*/
MVCommandManager getMVCommandManager();
/**
* Gets the class responsible for loading many different destinations
* on demand.
*
* @return A valid {@link DestinationsProvider}.
*/
DestinationsProvider getDestinationsProvider();
/**
* Gets the primary class responsible for managing Multiverse Worlds.
*
* @return {@link MVWorldManager}.
*/
MVWorldManager getMVWorldManager();
/**
* Saves the Multiverse-Config.
*
* @return Whether the Multiverse-Config was successfully saved
*/
boolean saveMVConfig();
/**
* Saves all configs.
@@ -89,13 +21,6 @@ public interface MVCore extends MVPlugin {
*/
boolean saveAllConfigs();
/**
* Gets the {@link AnchorManager}.
*
* @return The {@link AnchorManager}
*/
AnchorManager getAnchorManager();
/**
* Decrements the number of plugins that have specifically hooked into core.
*/
@@ -112,58 +37,4 @@ public interface MVCore extends MVPlugin {
* @return The number if plugins that have hooked into core.
*/
int getPluginCount();
/**
* Gets the {@link BlockSafety} this {@link MVCore} is using.
* @return The {@link BlockSafety} this {@link MVCore} is using.
* @see BlockSafety
* @see SimpleBlockSafety
*/
BlockSafety getBlockSafety();
/**
* Sets the {@link BlockSafety} this {@link MVCore} is using.
* @param blockSafety The new {@link BlockSafety}.
* @see BlockSafety
* @see SimpleBlockSafety
*/
void setBlockSafety(BlockSafety blockSafety);
/**
* Gets the {@link LocationManipulation} this {@link MVCore} is using.
* @return The {@link LocationManipulation} this {@link MVCore} is using.
* @see LocationManipulation
* @see SimpleLocationManipulation
*/
LocationManipulation getLocationManipulation();
/**
* Sets the {@link LocationManipulation} this {@link MVCore} is using.
* @param locationManipulation The new {@link LocationManipulation}.
* @see LocationManipulation
* @see SimpleLocationManipulation
*/
void setLocationManipulation(LocationManipulation locationManipulation);
/**
* Gets the {@link SafeTTeleporter} this {@link MVCore} is using.
* @return The {@link SafeTTeleporter} this {@link MVCore} is using.
* @see SafeTTeleporter
* @see SimpleSafeTTeleporter
*/
SafeTTeleporter getSafeTTeleporter();
/**
* Sets the {@link SafeTTeleporter} this {@link MVCore} is using.
* @param safeTTeleporter The new {@link SafeTTeleporter}.
* @see SafeTTeleporter
* @see SimpleSafeTTeleporter
*/
void setSafeTTeleporter(SafeTTeleporter safeTTeleporter);
/**
* Gets the {@link MVConfig}.
* @return The configuration.
*/
MVConfig getMVConfig();
}
@@ -7,16 +7,15 @@
package com.onarandombox.MultiverseCore.api;
import java.io.File;
import java.util.Collection;
import java.util.List;
import com.onarandombox.MultiverseCore.world.SimpleWorldPurger;
import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.WorldType;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.generator.ChunkGenerator;
import org.jvnet.hk2.annotations.Contract;
/**
* Multiverse 2 World Manager API
@@ -24,6 +23,7 @@ import org.bukkit.generator.ChunkGenerator;
* This API contains all of the world managing
* functions that your heart desires!
*/
@Contract
public interface MVWorldManager {
/**
* Add a new World to the Multiverse Setup.
@@ -221,15 +221,6 @@ public interface MVWorldManager {
*/
void loadDefaultWorlds();
/**
* Gets the {@link WorldPurger}.
* <p>
* @return The {@link WorldPurger} this {@link MVWorldManager} is using.
* @see WorldPurger
* @see SimpleWorldPurger
*/
WorldPurger getTheWorldPurger();
/**
* Gets the world players will spawn in on first join.
* Currently this always returns worlds.get(0) from Bukkit.
@@ -253,10 +244,9 @@ public interface MVWorldManager {
/**
* Load the config from a file.
*
* @param file The file to load.
* @return A loaded configuration.
*/
FileConfiguration loadWorldConfig(File file);
FileConfiguration loadWorldsConfig();
/**
* Saves the world config to disk.
@@ -1,15 +1,19 @@
package com.onarandombox.MultiverseCore.api;
import java.util.concurrent.CompletableFuture;
import co.aikar.commands.BukkitCommandIssuer;
import com.onarandombox.MultiverseCore.destination.ParsedDestination;
import com.onarandombox.MultiverseCore.teleportation.TeleportResult;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Entity;
import org.jvnet.hk2.annotations.Contract;
/**
* Used to safely teleport people.
*/
@Contract
public interface SafeTTeleporter extends Teleporter {
/**
@@ -37,8 +41,20 @@ public interface SafeTTeleporter extends Teleporter {
* @param destination Destination to teleport them to
* @return true for success, false for failure
*/
@Deprecated
TeleportResult safelyTeleport(BukkitCommandIssuer teleporter, Entity teleportee, ParsedDestination<?> destination);
/**
* Safely teleport the entity to the MVDestination. This will perform checks to see if the place is safe, and if
* it's not, will adjust the final destination accordingly.
*
* @param teleporter Person who performed the teleport command.
* @param teleportee Entity to teleport
* @param destination Destination to teleport them to
* @return true for success, false for failure
*/
CompletableFuture<TeleportResult> safelyTeleportAsync(BukkitCommandIssuer teleporter, Entity teleportee, ParsedDestination<?> destination);
/**
* Safely teleport the entity to the Location. This may perform checks to
* see if the place is safe, and if
@@ -68,5 +84,4 @@ public interface SafeTTeleporter extends Teleporter {
* @return The next portal-block's {@link Location}.
*/
Location findPortalBlockNextTo(Location l);
}
@@ -1,10 +1,14 @@
package com.onarandombox.MultiverseCore.api;
import java.util.concurrent.CompletableFuture;
import co.aikar.commands.BukkitCommandIssuer;
import com.onarandombox.MultiverseCore.destination.ParsedDestination;
import com.onarandombox.MultiverseCore.teleportation.TeleportResult;
import org.bukkit.entity.Entity;
import org.jvnet.hk2.annotations.Contract;
@Contract
public interface Teleporter {
/**
* Teleport the entity to the Multiverse Destination.
@@ -14,5 +18,16 @@ public interface Teleporter {
* @param destination Destination to teleport them to
* @return true for success, false for failure
*/
@Deprecated
TeleportResult teleport(BukkitCommandIssuer teleporter, Entity teleportee, ParsedDestination<?> destination);
/**
* Teleport the entity to the Multiverse Destination.
*
* @param teleporter Person who performed the teleport command.
* @param teleportee Entity to teleport
* @param destination Destination to teleport them to
* @return true for success, false for failure
*/
CompletableFuture<TeleportResult> teleportAsync(BukkitCommandIssuer teleporter, Entity teleportee, ParsedDestination<?> destination);
}
@@ -4,10 +4,12 @@ import java.util.List;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Entity;
import org.jvnet.hk2.annotations.Contract;
/**
* Used to remove animals from worlds that don't belong there.
*/
@Contract
public interface WorldPurger {
/**
* Synchronizes the given worlds with their settings.
@@ -7,34 +7,47 @@ import co.aikar.commands.annotation.CommandPermission;
import co.aikar.commands.annotation.Description;
import co.aikar.commands.annotation.Subcommand;
import co.aikar.commands.annotation.Syntax;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager;
import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand;
import com.onarandombox.MultiverseCore.destination.DestinationsProvider;
import com.onarandombox.MultiverseCore.destination.ParsedDestination;
import com.onarandombox.MultiverseCore.utils.MVCorei18n;
import jakarta.inject.Inject;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
@Service
@CommandAlias("mv")
public class CheckCommand extends MultiverseCoreCommand {
public CheckCommand(@NotNull MultiverseCore plugin) {
super(plugin);
public class CheckCommand extends MultiverseCommand {
private final DestinationsProvider destinationsProvider;
@Inject
public CheckCommand(@NotNull MVCommandManager commandManager, @NotNull DestinationsProvider destinationsProvider) {
super(commandManager);
this.destinationsProvider = destinationsProvider;
}
@Subcommand("check")
@CommandPermission("multiverse.core.check")
@CommandCompletion("@players @destinations|@mvworlds")
@Syntax("<player> <destination>")
@Description("Checks if a player can teleport to a destination.")
@Description("{@@mv-core.check.description}")
public void onCheckCommand(BukkitCommandIssuer issuer,
@Syntax("<player>")
@Description("Player to check destination on.")
@Description("{@@mv-core.check.player.description}")
Player player,
@Syntax("<destination>")
@Description("A destination location, e.g. a world name.")
@Description("{@@mv-core.check.destination.description}")
ParsedDestination<?> destination
) {
issuer.sendMessage("Checking " + player + " to " + destination + "...");
issuer.sendInfo(MVCorei18n.CHECK_CHECKING,
"{player}", player.getName(),
"{destination}", destination.toString());
//TODO More detailed output on permissions required.
this.plugin.getDestinationsProvider().checkTeleportPermissions(issuer, player, destination);
this.destinationsProvider.checkTeleportPermissions(issuer, player, destination);
}
}
@@ -9,40 +9,53 @@ import co.aikar.commands.annotation.Description;
import co.aikar.commands.annotation.Single;
import co.aikar.commands.annotation.Subcommand;
import co.aikar.commands.annotation.Syntax;
import com.onarandombox.MultiverseCore.MultiverseCore;
import org.bukkit.ChatColor;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager;
import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand;
import com.onarandombox.MultiverseCore.utils.MVCorei18n;
import jakarta.inject.Inject;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
@Service
@CommandAlias("mv")
public class CloneCommand extends MultiverseCoreCommand {
public CloneCommand(@NotNull MultiverseCore plugin) {
super(plugin);
public class CloneCommand extends MultiverseCommand {
private final MVWorldManager worldManager;
@Inject
public CloneCommand(@NotNull MVCommandManager commandManager, @NotNull MVWorldManager worldManager) {
super(commandManager);
this.worldManager = worldManager;
}
@Subcommand("clone")
@CommandPermission("multiverse.core.clone")
@CommandCompletion("@mvworlds:scope=both @empty")
@Syntax("<world> <new world name>")
@Description("Clones a world.")
@Description("{@@mv-core.clone.description}")
public void onCloneCommand(CommandIssuer issuer,
@Conditions("validWorldName:scope=both")
@Syntax("<world>")
@Description("The target world to clone.")
@Description("{@@mv-core.clone.world.description}")
String worldName,
@Single
@Conditions("validWorldName:scope=new")
@Syntax("<new world name>")
@Description("The new cloned world name.")
@Description("{@@mv-core.clone.newWorld.description}")
String newWorldName
) {
issuer.sendMessage(String.format("Cloning world '%s' to '%s'...", worldName, newWorldName));
issuer.sendInfo(MVCorei18n.CLONE_CLONING,
"{world}", worldName,
"{newWorld}", newWorldName);
if (!this.plugin.getMVWorldManager().cloneWorld(worldName, newWorldName)) {
issuer.sendMessage(String.format("%sWorld could not be cloned! See console for more details.", ChatColor.RED));
if (!this.worldManager.cloneWorld(worldName, newWorldName)) {
issuer.sendError(MVCorei18n.CLONE_FAILED);
return;
}
issuer.sendMessage(String.format("%sCloned world '%s'!", ChatColor.GREEN, newWorldName));
issuer.sendInfo(MVCorei18n.CLONE_SUCCESS,
"{world}", newWorldName);
}
}
@@ -0,0 +1,73 @@
package com.onarandombox.MultiverseCore.commands;
import co.aikar.commands.annotation.CommandAlias;
import co.aikar.commands.annotation.CommandCompletion;
import co.aikar.commands.annotation.CommandPermission;
import co.aikar.commands.annotation.Description;
import co.aikar.commands.annotation.Optional;
import co.aikar.commands.annotation.Single;
import co.aikar.commands.annotation.Subcommand;
import co.aikar.commands.annotation.Syntax;
import com.onarandombox.MultiverseCore.commandtools.MVCommandIssuer;
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager;
import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand;
import com.onarandombox.MultiverseCore.commandtools.context.MVConfigValue;
import com.onarandombox.MultiverseCore.config.MVCoreConfig;
import com.onarandombox.MultiverseCore.exceptions.MultiverseException;
import io.vavr.control.Option;
import jakarta.inject.Inject;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
@Service
@CommandAlias("mv")
public class ConfigCommand extends MultiverseCommand {
private final MVCoreConfig config;
@Inject
public ConfigCommand(@NotNull MVCommandManager commandManager, @NotNull MVCoreConfig config) {
super(commandManager);
this.config = config;
}
@Subcommand("config")
@CommandPermission("multiverse.core.config")
@CommandCompletion("@mvconfigs")
@Syntax("<name> [new-value]")
@Description("") //TODO
public void onConfigCommand(MVCommandIssuer issuer,
@Syntax("<name>")
@Description("") //TODO
String name,
@Optional
@Single
@Syntax("[new-value]")
@Description("") //TODO
MVConfigValue value
) {
if (value == null) {
showConfigValue(issuer, name);
return;
}
updateConfigValue(issuer, name, value.getValue());
}
private void showConfigValue(MVCommandIssuer issuer, String name) {
config.getProperty(name)
.onSuccess(value -> issuer.sendMessage(name + "is currently set to " + value))
.onFailure(e -> issuer.sendMessage(e.getMessage()));
}
private void updateConfigValue(MVCommandIssuer issuer, String name, Object value) {
config.setProperty(name, value)
.onSuccess(ignore -> {
config.save();
issuer.sendMessage("Successfully set " + name + " to " + value);
})
.onFailure(ignore -> issuer.sendMessage("Unable to set " + name + " to " + value + "."))
.onFailure(MultiverseException.class, e -> Option.of(e.getMVMessage()).peek(issuer::sendError));
}
}
@@ -5,19 +5,25 @@ import co.aikar.commands.annotation.CommandAlias;
import co.aikar.commands.annotation.CommandPermission;
import co.aikar.commands.annotation.Description;
import co.aikar.commands.annotation.Subcommand;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager;
import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand;
import jakarta.inject.Inject;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
@Service
@CommandAlias("mv")
public class ConfirmCommand extends MultiverseCoreCommand {
public ConfirmCommand(@NotNull MultiverseCore plugin) {
super(plugin);
public class ConfirmCommand extends MultiverseCommand {
@Inject
public ConfirmCommand(@NotNull MVCommandManager commandManager) {
super(commandManager);
}
@Subcommand("confirm")
@CommandPermission("multiverse.core.confirm")
@Description("Confirms dangerous commands before executing them.")
@Description("{@@mv-core.confirm.description}")
public void onConfirmCommand(@NotNull BukkitCommandIssuer issuer) {
this.plugin.getMVCommandManager().getCommandQueueManager().runQueuedCommand(issuer.getIssuer());
this.commandManager.getCommandQueueManager().runQueuedCommand(issuer.getIssuer());
}
}
@@ -17,22 +17,38 @@ import co.aikar.commands.annotation.Description;
import co.aikar.commands.annotation.Optional;
import co.aikar.commands.annotation.Subcommand;
import co.aikar.commands.annotation.Syntax;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager;
import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand;
import com.onarandombox.MultiverseCore.commandtools.flags.CommandFlag;
import com.onarandombox.MultiverseCore.commandtools.flags.CommandFlagGroup;
import com.onarandombox.MultiverseCore.commandtools.flags.CommandValueFlag;
import com.onarandombox.MultiverseCore.commandtools.flags.ParsedCommandFlags;
import com.onarandombox.MultiverseCore.locale.MVCorei18n;
import com.onarandombox.MultiverseCore.utils.MVCorei18n;
import com.onarandombox.MultiverseCore.utils.UnsafeCallWrapper;
import jakarta.inject.Inject;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.WorldType;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
@Service
@CommandAlias("mv")
public class CreateCommand extends MultiverseCoreCommand {
public CreateCommand(@NotNull MultiverseCore plugin) {
super(plugin);
public class CreateCommand extends MultiverseCommand {
private final MVWorldManager worldManager;
@Inject
public CreateCommand(
@NotNull MVCommandManager commandManager,
@NotNull MVWorldManager worldManager,
@NotNull UnsafeCallWrapper unsafeCallWrapper
) {
super(commandManager);
this.worldManager = worldManager;
registerFlagGroup(CommandFlagGroup.builder("mvcreate")
.add(CommandValueFlag.builder("--seed", String.class)
@@ -43,7 +59,7 @@ public class CreateCommand extends MultiverseCoreCommand {
.addAlias("-g")
.completion(() -> Arrays.stream(Bukkit.getServer().getPluginManager().getPlugins())
.filter(Plugin::isEnabled)
.filter(genplugin -> this.plugin.getUnsafeCallWrapper().wrap(
.filter(genplugin -> unsafeCallWrapper.wrap(
() -> genplugin.getDefaultWorldGenerator("world", ""),
genplugin.getName(),
"Get generator"
@@ -8,14 +8,24 @@ import co.aikar.commands.annotation.Description;
import co.aikar.commands.annotation.Subcommand;
import co.aikar.commands.annotation.Syntax;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.locale.MVCorei18n;
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager;
import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand;
import com.onarandombox.MultiverseCore.config.MVCoreConfig;
import com.onarandombox.MultiverseCore.utils.MVCorei18n;
import jakarta.inject.Inject;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
@Service
@CommandAlias("mv")
public class DebugCommand extends MultiverseCoreCommand {
public DebugCommand(@NotNull MultiverseCore plugin) {
super(plugin);
public class DebugCommand extends MultiverseCommand {
private final MVCoreConfig config;
@Inject
public DebugCommand(@NotNull MVCommandManager commandManager, @NotNull MVCoreConfig config) {
super(commandManager);
this.config = config;
}
@Subcommand("debug")
@@ -36,13 +46,13 @@ public class DebugCommand extends MultiverseCoreCommand {
@Description("{@@mv-core.debug.change.level.description}")
int level) {
this.plugin.getMVConfig().setGlobalDebug(level);
this.plugin.saveAllConfigs();
config.setGlobalDebug(level);
config.save();
this.displayDebugMode(issuer);
}
private void displayDebugMode(BukkitCommandIssuer issuer) {
final int debugLevel = this.plugin.getMVConfig().getGlobalDebug();
final int debugLevel = config.getGlobalDebug();
if (debugLevel == 0) {
issuer.sendInfo(MVCorei18n.DEBUG_INFO_OFF);
return;
@@ -1,6 +1,7 @@
package com.onarandombox.MultiverseCore.commands;
import co.aikar.commands.BukkitCommandIssuer;
import co.aikar.commands.MessageType;
import co.aikar.commands.annotation.CommandAlias;
import co.aikar.commands.annotation.CommandCompletion;
import co.aikar.commands.annotation.CommandPermission;
@@ -9,22 +10,32 @@ import co.aikar.commands.annotation.Description;
import co.aikar.commands.annotation.Single;
import co.aikar.commands.annotation.Subcommand;
import co.aikar.commands.annotation.Syntax;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager;
import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand;
import com.onarandombox.MultiverseCore.commandtools.queue.QueuedCommand;
import org.bukkit.ChatColor;
import com.onarandombox.MultiverseCore.utils.MVCorei18n;
import jakarta.inject.Inject;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
@Service
@CommandAlias("mv")
public class DeleteCommand extends MultiverseCoreCommand {
public DeleteCommand(@NotNull MultiverseCore plugin) {
super(plugin);
public class DeleteCommand extends MultiverseCommand {
private final MVWorldManager worldManager;
@Inject
public DeleteCommand(@NotNull MVCommandManager commandManager, @NotNull MVWorldManager worldManager) {
super(commandManager);
this.worldManager = worldManager;
}
@Subcommand("delete")
@CommandPermission("multiverse.core.delete")
@CommandCompletion("@mvworlds:scope=both")
@Syntax("<world>")
@Description("Deletes a world on your server PERMANENTLY.")
@Description("{@@mv-core.delete.description}")
public void onDeleteCommand(BukkitCommandIssuer issuer,
@Single
@@ -33,17 +44,24 @@ public class DeleteCommand extends MultiverseCoreCommand {
@Description("The world you want to delete.")
String worldName
) {
this.plugin.getMVCommandManager().getCommandQueueManager().addToQueue(new QueuedCommand(
this.commandManager.getCommandQueueManager().addToQueue(new QueuedCommand(
issuer.getIssuer(),
() -> {
issuer.sendMessage(String.format("Deleting world '%s'...", worldName));
if (!this.plugin.getMVWorldManager().deleteWorld(worldName)) {
issuer.sendMessage(String.format("%sThere was an issue deleting '%s'! Please check console for errors.", ChatColor.RED, worldName));
issuer.sendInfo(MVCorei18n.DELETE_DELETING,
"{world}", worldName);
if (!this.worldManager.deleteWorld(worldName)) {
issuer.sendError(MVCorei18n.DELETE_FAILED,
"{world}", worldName);
return;
}
issuer.sendMessage(String.format("%sWorld %s was deleted!", ChatColor.GREEN, worldName));
issuer.sendInfo(MVCorei18n.DELETE_SUCCESS,
"{world}", worldName);
},
"Are you sure you want to delete world '" + worldName + "'?"
this.commandManager.formatMessage(
issuer,
MessageType.INFO,
MVCorei18n.DELETE_PROMPT,
"{world}", worldName)
));
}
}
@@ -8,37 +8,43 @@ import co.aikar.commands.annotation.Description;
import co.aikar.commands.annotation.Flags;
import co.aikar.commands.annotation.Subcommand;
import co.aikar.commands.annotation.Syntax;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager;
import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand;
import com.onarandombox.MultiverseCore.commandtools.context.GameRuleValue;
import org.bukkit.ChatColor;
import com.onarandombox.MultiverseCore.utils.MVCorei18n;
import jakarta.inject.Inject;
import org.bukkit.GameRule;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
@Service
@CommandAlias("mv")
public class GameruleCommand extends MultiverseCoreCommand {
public GameruleCommand(@NotNull MultiverseCore plugin) {
super(plugin);
public class GameruleCommand extends MultiverseCommand {
@Inject
public GameruleCommand(@NotNull MVCommandManager commandManager) {
super(commandManager);
}
@Subcommand("gamerule")
@CommandPermission("multiverse.core.gamerule")
@CommandCompletion("@gamerules true|false|@range:1-10 @mvworlds:multiple|*")
@Syntax("<Gamerule> <Gamerule value> [World or *]")
@Description("Changes a gamerule in one or more worlds")
@Description("{@@mv-core.gamerule.description}")
public void onGameruleCommand(BukkitCommandIssuer issuer,
@Syntax("<Gamerule>")
@Description("Gamerule to set")
@Description("{@@mv-core.gamerule.gamerule.description}")
GameRule gamerule,
@Syntax("<Value>")
@Description("Value of gamerule")
@Description("{@@mv-core.gamerule.value.description}")
GameRuleValue gameRuleValue,
@Flags("resolve=issuerAware")
@Syntax("[World or *]")
@Description("World to apply gamerule to, current world by default")
@Description("{@@mv-core.gamerule.world.description}")
MVWorld[] worlds
) {
Object value = gameRuleValue.getValue();
@@ -46,17 +52,27 @@ public class GameruleCommand extends MultiverseCoreCommand {
for(MVWorld world : worlds) {
// Set gamerules and add false to list if it fails
if (!world.getCBWorld().setGameRule(gamerule, value)) {
issuer.sendMessage(ChatColor.RED + "Failed to set gamerule " + gamerule.getName() + " to " + value + " in " + world.getName() + ". It should be a " + gamerule.getType());
issuer.sendError(MVCorei18n.GAMERULE_FAILED,
"{gamerule}", gamerule.getName(),
"{value}", value.toString(),
"{world}", world.getName(),
"{type}", gamerule.getType().getName());
success = false;
}
}
// Tell user if it was successful
if (success) {
if (worlds.length == 1) {
issuer.sendMessage(ChatColor.GREEN + "Successfully set " + gamerule.getName() + " to " + value + " in " + worlds[0].getName());
issuer.sendInfo(MVCorei18n.GAMERULE_SUCCESS_SINGLE,
"{gamerule}", gamerule.getName(),
"{value}", value.toString(),
"{world}", worlds[0].getName());
}
else if (worlds.length > 1) {
issuer.sendMessage(ChatColor.GREEN + "Successfully set " + gamerule.getName() + " to " + value + " in " + worlds.length + " worlds.");
issuer.sendInfo(MVCorei18n.GAMERULE_SUCCESS_MULTIPLE,
"{gamerule}", gamerule.getName(),
"{value}", value.toString(),
"{count}", String.valueOf(worlds.length));
}
}
}
@@ -12,28 +12,43 @@ import co.aikar.commands.annotation.Description;
import co.aikar.commands.annotation.Optional;
import co.aikar.commands.annotation.Subcommand;
import co.aikar.commands.annotation.Syntax;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager;
import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand;
import com.onarandombox.MultiverseCore.commandtools.flags.CommandFlag;
import com.onarandombox.MultiverseCore.commandtools.flags.CommandFlagGroup;
import com.onarandombox.MultiverseCore.commandtools.flags.CommandValueFlag;
import com.onarandombox.MultiverseCore.commandtools.flags.ParsedCommandFlags;
import com.onarandombox.MultiverseCore.utils.MVCorei18n;
import com.onarandombox.MultiverseCore.utils.UnsafeCallWrapper;
import jakarta.inject.Inject;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.World;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
@Service
@CommandAlias("mv")
public class ImportCommand extends MultiverseCoreCommand {
public ImportCommand(@NotNull MultiverseCore plugin) {
super(plugin);
public class ImportCommand extends MultiverseCommand {
private final MVWorldManager worldManager;
@Inject
public ImportCommand(
@NotNull MVCommandManager commandManager,
@NotNull MVWorldManager worldManager,
@NotNull UnsafeCallWrapper unsafeCallWrapper
) {
super(commandManager);
this.worldManager = worldManager;
registerFlagGroup(CommandFlagGroup.builder("mvimport")
.add(CommandValueFlag.builder("--generator", String.class)
.addAlias("-g")
.completion(() -> Arrays.stream(Bukkit.getServer().getPluginManager().getPlugins())
.filter(Plugin::isEnabled)
.filter(genplugin -> this.plugin.getUnsafeCallWrapper().wrap(
.filter(genplugin -> unsafeCallWrapper.wrap(
() -> genplugin.getDefaultWorldGenerator("world", ""),
genplugin.getName(),
"Get generator"
@@ -51,26 +66,27 @@ public class ImportCommand extends MultiverseCoreCommand {
@CommandPermission("multiverse.core.import")
@CommandCompletion("@mvworlds:scope=potential @flags:groupName=mvimport")
@Syntax("<name> <env> --generator [generator[:id]] --adjust-spawn")
@Description("Imports a existing world folder.")
@Description("{@@mv-core.import.description")
public void onImportCommand(BukkitCommandIssuer issuer,
@Conditions("validWorldName:scope=new")
@Syntax("<name>")
@Description("Name of the world folder.")
@Description("{@@mv-core.import.name.description}")
String worldName,
@Syntax("<env>")
@Description("The world's environment. See: /mv env")
@Description("{@@mv-core.import.env.description}")
World.Environment environment,
@Optional
@Syntax("--generator [generator[:id]] --adjust-spawn")
@Description("Other world settings. See: https://gg.gg/nn8c2")
@Description("{@@mv-core.import.other.description}")
String[] flags) {
ParsedCommandFlags parsedFlags = parseFlags(flags);
issuer.sendMessage(String.format("Starting import of world '%s'...", worldName));
issuer.sendInfo(MVCorei18n.IMPORT_IMPORTING,
"{world}", worldName);
if (!this.worldManager.addWorld(
worldName, environment,
@@ -80,9 +96,9 @@ public class ImportCommand extends MultiverseCoreCommand {
parsedFlags.flagValue("--generator", String.class),
parsedFlags.hasFlag("--adjust-spawn"))
) {
issuer.sendMessage(String.format("%sFailed! See console for more details.", ChatColor.RED));
issuer.sendError(MVCorei18n.IMPORT_FAILED);
return;
}
issuer.sendMessage(String.format("%sComplete!", ChatColor.GREEN));
issuer.sendInfo(MVCorei18n.IMPORT_SUCCESS);
}
}
@@ -9,34 +9,48 @@ import co.aikar.commands.annotation.Description;
import co.aikar.commands.annotation.Single;
import co.aikar.commands.annotation.Subcommand;
import co.aikar.commands.annotation.Syntax;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager;
import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand;
import com.onarandombox.MultiverseCore.utils.MVCorei18n;
import jakarta.inject.Inject;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
@Service
@CommandAlias("mv")
public class LoadCommand extends MultiverseCoreCommand {
public LoadCommand(@NotNull MultiverseCore plugin) {
super(plugin);
public class LoadCommand extends MultiverseCommand {
private final MVWorldManager worldManager;
@Inject
public LoadCommand(@NotNull MVCommandManager commandManager, @NotNull MVWorldManager worldManager) {
super(commandManager);
this.worldManager = worldManager;
}
@Subcommand("load")
@CommandPermission("multiverse.core.load")
@CommandCompletion("@mvworlds:scope=unloaded")
@Syntax("<world>")
@Description("Loads a world. World must be already in worlds.yml, else please use /mv import.")
@Description("{@@mv-core.load.description}")
public void onLoadCommand(BukkitCommandIssuer issuer,
@Single
@Conditions("validWorldName:scope=unloaded")
@Syntax("<world>")
@Description("Name of world you want to load.")
@Description("{@@mv-core.load.world.description}")
String worldName
) {
issuer.sendMessage(String.format("Loading world '%s'...", worldName));
issuer.sendInfo(MVCorei18n.LOAD_LOADING,
"{world}", worldName);
if (!this.plugin.getMVWorldManager().loadWorld(worldName)) {
issuer.sendMessage(String.format("Error trying to load world '%s'!", worldName));
if (!this.worldManager.loadWorld(worldName)) {
issuer.sendError(MVCorei18n.LOAD_FAILED,
"{world}", worldName);
return;
}
issuer.sendMessage(String.format("Loaded world '%s'!", worldName));
issuer.sendInfo(MVCorei18n.LOAD_SUCCESS,
"{world}", worldName);
}
}
@@ -1,20 +0,0 @@
package com.onarandombox.MultiverseCore.commands;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand;
import org.jetbrains.annotations.NotNull;
/**
* A base command for Multiverse.
*/
abstract class MultiverseCoreCommand extends MultiverseCommand {
protected final MultiverseCore plugin;
protected final MVWorldManager worldManager;
protected MultiverseCoreCommand(@NotNull MultiverseCore plugin) {
super(plugin);
this.plugin = plugin;
this.worldManager = plugin.getMVWorldManager();
}
}
@@ -4,6 +4,7 @@ import java.util.Collections;
import java.util.Random;
import co.aikar.commands.BukkitCommandIssuer;
import co.aikar.commands.MessageType;
import co.aikar.commands.annotation.CommandAlias;
import co.aikar.commands.annotation.CommandCompletion;
import co.aikar.commands.annotation.CommandPermission;
@@ -12,19 +13,29 @@ import co.aikar.commands.annotation.Description;
import co.aikar.commands.annotation.Optional;
import co.aikar.commands.annotation.Subcommand;
import co.aikar.commands.annotation.Syntax;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager;
import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand;
import com.onarandombox.MultiverseCore.commandtools.flags.CommandFlag;
import com.onarandombox.MultiverseCore.commandtools.flags.CommandFlagGroup;
import com.onarandombox.MultiverseCore.commandtools.flags.CommandValueFlag;
import com.onarandombox.MultiverseCore.commandtools.flags.ParsedCommandFlags;
import com.onarandombox.MultiverseCore.commandtools.queue.QueuedCommand;
import org.bukkit.ChatColor;
import com.onarandombox.MultiverseCore.utils.MVCorei18n;
import jakarta.inject.Inject;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
@Service
@CommandAlias("mv")
public class RegenCommand extends MultiverseCoreCommand {
public RegenCommand(@NotNull MultiverseCore plugin) {
super(plugin);
public class RegenCommand extends MultiverseCommand {
private final MVWorldManager worldManager;
@Inject
public RegenCommand(@NotNull MVCommandManager commandManager, @NotNull MVWorldManager worldManager) {
super(commandManager);
this.worldManager = worldManager;
registerFlagGroup(CommandFlagGroup.builder("mvregen")
.add(CommandValueFlag.builder("--seed", String.class)
@@ -42,38 +53,45 @@ public class RegenCommand extends MultiverseCoreCommand {
@CommandPermission("multiverse.core.regen")
@CommandCompletion("@mvworlds:scope=both @flags:groupName=mvregen")
@Syntax("<world> --seed [seed] --keep-gamerules")
@Description("Regenerates a world on your server. The previous state will be lost PERMANENTLY.")
@Description("{@@mv-core.regen.description}")
public void onRegenCommand(BukkitCommandIssuer issuer,
@Conditions("validWorldName:scope=both")
@Syntax("<world>")
@Description("World that you want to regen.")
@Description("{@@mv-core.regen.world.description}")
String worldName,
@Optional
@Syntax("--seed [seed] --keep-gamerules")
@Description("Other world settings. See: http://gg.gg/nn8lk")
@Description("{@@mv-core.regen.other.description}")
String[] flags
) {
ParsedCommandFlags parsedFlags = parseFlags(flags);
this.plugin.getMVCommandManager().getCommandQueueManager().addToQueue(new QueuedCommand(
this.commandManager.getCommandQueueManager().addToQueue(new QueuedCommand(
issuer.getIssuer(),
() -> {
issuer.sendMessage(String.format("Regenerating world '%s'...", worldName));
if (!this.plugin.getMVWorldManager().regenWorld(
issuer.sendInfo(MVCorei18n.REGEN_REGENERATING,
"{world}", worldName);
if (!this.worldManager.regenWorld(
worldName,
parsedFlags.hasFlag("--seed"),
!parsedFlags.hasFlagValue("--seed"),
parsedFlags.flagValue("--seed", String.class),
parsedFlags.hasFlag("--keep-gamerules")
)) {
issuer.sendMessage(String.format("%sThere was an issue regenerating '%s'! Please check console for errors.", ChatColor.RED, worldName));
issuer.sendError(MVCorei18n.REGEN_FAILED,
"{world}", worldName);
return;
}
issuer.sendMessage(String.format("%sWorld %s was regenerated!", ChatColor.GREEN, worldName));
issuer.sendInfo(MVCorei18n.REGEN_SUCCESS,
"{world}", worldName);
},
"Are you sure you want to regenerate world '" + worldName + "'?"
this.commandManager.formatMessage(
issuer,
MessageType.INFO,
MVCorei18n.REGEN_PROMPT,
"{world}", worldName)
));
}
}
@@ -9,24 +9,52 @@ import co.aikar.commands.annotation.CommandPermission;
import co.aikar.commands.annotation.Description;
import co.aikar.commands.annotation.Subcommand;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.anchor.AnchorManager;
import com.onarandombox.MultiverseCore.api.MVCore;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager;
import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand;
import com.onarandombox.MultiverseCore.config.MVCoreConfig;
import com.onarandombox.MultiverseCore.event.MVConfigReloadEvent;
import org.bukkit.ChatColor;
import com.onarandombox.MultiverseCore.utils.MVCorei18n;
import jakarta.inject.Inject;
import org.bukkit.plugin.PluginManager;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
@Service
@CommandAlias("mv")
public class ReloadCommand extends MultiverseCoreCommand {
public ReloadCommand(@NotNull MultiverseCore plugin) {
super(plugin);
public class ReloadCommand extends MultiverseCommand {
private final MVCoreConfig config;
private final AnchorManager anchorManager;
private final MVWorldManager worldManager;
private final PluginManager pluginManager;
@Inject
public ReloadCommand(
@NotNull MVCommandManager commandManager,
@NotNull MVCoreConfig config,
@NotNull AnchorManager anchorManager,
@NotNull MVWorldManager worldManager,
@NotNull PluginManager pluginManager
) {
super(commandManager);
this.config = config;
this.anchorManager = anchorManager;
this.worldManager = worldManager;
this.pluginManager = pluginManager;
}
@Subcommand("reload")
@CommandPermission("multiverse.core.reload")
@Description("Reloads config files for all multiverse modules.")
@Description("{@@mv-core.reload.description}")
public void onReloadCommand(@NotNull BukkitCommandIssuer issuer) {
issuer.sendMessage(ChatColor.GOLD + "Reloading all Multiverse Plugin configs...");
this.plugin.loadConfigs();
this.plugin.getAnchorManager().loadAnchors();
this.plugin.getMVWorldManager().loadWorlds(true);
issuer.sendInfo(MVCorei18n.RELOAD_RELOADING);
this.config.load();
this.worldManager.loadWorldsConfig();
this.worldManager.loadWorlds(true);
this.anchorManager.loadAnchors();
List<String> configsLoaded = new ArrayList<>();
configsLoaded.add("Multiverse-Core - config.yml");
@@ -34,9 +62,10 @@ public class ReloadCommand extends MultiverseCoreCommand {
configsLoaded.add("Multiverse-Core - anchors.yml");
MVConfigReloadEvent configReload = new MVConfigReloadEvent(configsLoaded);
this.plugin.getServer().getPluginManager().callEvent(configReload);
this.pluginManager.callEvent(configReload);
// @TODO: replace this sendMessage and format the configsLoaded above, maybe?
configReload.getAllConfigsLoaded().forEach(issuer::sendMessage);
issuer.sendMessage(String.format("%sReload Complete!", ChatColor.GREEN));
issuer.sendInfo(MVCorei18n.RELOAD_SUCCESS);
}
}
@@ -9,33 +9,44 @@ import co.aikar.commands.annotation.Description;
import co.aikar.commands.annotation.Single;
import co.aikar.commands.annotation.Subcommand;
import co.aikar.commands.annotation.Syntax;
import com.onarandombox.MultiverseCore.MultiverseCore;
import org.bukkit.ChatColor;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager;
import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand;
import com.onarandombox.MultiverseCore.utils.MVCorei18n;
import jakarta.inject.Inject;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
@Service
@CommandAlias("mv")
public class RemoveCommand extends MultiverseCoreCommand {
public RemoveCommand(@NotNull MultiverseCore plugin) {
super(plugin);
public class RemoveCommand extends MultiverseCommand {
private final MVWorldManager worldManager;
@Inject
public RemoveCommand(@NotNull MVCommandManager commandManager, @NotNull MVWorldManager worldManager) {
super(commandManager);
this.worldManager = worldManager;
}
@Subcommand("remove")
@CommandPermission("multiverse.core.remove")
@CommandCompletion("@mvworlds:scope=both")
@Syntax("<world>")
@Description("Unloads a world from Multiverse and removes it from worlds.yml, this does NOT DELETE the world folder.")
@Description("{@@mv-core.remove.description}")
public void onRemoveCommand(BukkitCommandIssuer issuer,
@Single
@Conditions("mvworlds:scope=both")
@Syntax("<world>")
@Description("World you want to remove from mv's knowledge.")
@Description("{@@mv-core.remove.world.description}")
String worldName
) {
if (!this.plugin.getMVWorldManager().removeWorldFromConfig(worldName)) {
issuer.sendMessage(String.format("%sError trying to remove world from config!", ChatColor.RED));
if (!this.worldManager.removeWorldFromConfig(worldName)) {
issuer.sendError(MVCorei18n.REMOVE_FAILED);
return;
}
issuer.sendMessage(String.format("World '%s' is removed from config!", worldName));
issuer.sendInfo(MVCorei18n.REMOVE_SUCCESS,
"{world}", worldName);
}
}
@@ -0,0 +1,34 @@
package com.onarandombox.MultiverseCore.commands;
import co.aikar.commands.CommandIssuer;
import co.aikar.commands.annotation.CommandAlias;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager;
import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand;
import com.onarandombox.MultiverseCore.utils.MVCorei18n;
import jakarta.inject.Inject;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
@Service
public class RootCommand extends MultiverseCommand {
private final Plugin plugin;
@Inject
public RootCommand(@NotNull MVCommandManager commandManager, @NotNull MultiverseCore plugin) {
super(commandManager);
this.plugin = plugin;
}
@CommandAlias("mv")
public void onRootCommand(CommandIssuer issuer) {
PluginDescriptionFile description = this.plugin.getDescription();
issuer.sendInfo(MVCorei18n.ROOT_TITLE,
"{name}", description.getName(),
"{version}", description.getVersion());
issuer.sendInfo(MVCorei18n.ROOT_HELP);
}
}
@@ -1,5 +1,8 @@
package com.onarandombox.MultiverseCore.commands;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import co.aikar.commands.BukkitCommandIssuer;
import co.aikar.commands.CommandIssuer;
import co.aikar.commands.annotation.CommandAlias;
@@ -8,42 +11,59 @@ import co.aikar.commands.annotation.Description;
import co.aikar.commands.annotation.Flags;
import co.aikar.commands.annotation.Subcommand;
import co.aikar.commands.annotation.Syntax;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager;
import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand;
import com.onarandombox.MultiverseCore.destination.DestinationsProvider;
import com.onarandombox.MultiverseCore.destination.ParsedDestination;
import com.onarandombox.MultiverseCore.utils.MVCorei18n;
import jakarta.inject.Inject;
import org.bukkit.entity.Player;
import org.jvnet.hk2.annotations.Service;
@Service
@CommandAlias("mv")
public class TeleportCommand extends MultiverseCoreCommand {
public TeleportCommand(MultiverseCore plugin) {
super(plugin);
public class TeleportCommand extends MultiverseCommand {
private final DestinationsProvider destinationsProvider;
@Inject
public TeleportCommand(MVCommandManager commandManager, DestinationsProvider destinationsProvider) {
super(commandManager);
this.destinationsProvider = destinationsProvider;
}
@Subcommand("teleport|tp")
@CommandCompletion("@players|@mvworlds:playerOnly|@destinations:playerOnly @mvworlds|@destinations")
@Syntax("[player] <destination>")
@Description("Allows you to the teleport to a location on your server!")
@Description("{@@mv-core.teleport.description}")
public void onTeleportCommand(BukkitCommandIssuer issuer,
@Flags("resolve=issuerAware")
@Syntax("[player]")
@Description("Target player to teleport.")
@Description("{@@mv-core.teleport.player.description}")
Player[] players,
@Syntax("<destination>")
@Description("Location, can be a world name.")
@Description("{@@mv-core.teleport.destination.description}")
ParsedDestination<?> destination
) {
// TODO Add warning if teleporting too many players at once.
for (Player player : players) {
issuer.sendMessage("Teleporting "
+ (issuer.getPlayer() == player ? "you" : player.getName())
+ " to " + destination + "...");
this.plugin.getDestinationsProvider().playerTeleport(issuer, player, destination);
}
CompletableFuture.allOf(Arrays.stream(players)
.map(player -> this.destinationsProvider.playerTeleportAsync(issuer, player, destination))
.toArray(CompletableFuture[]::new))
.thenRun(() -> {
String playerName = players.length == 1
? issuer.getPlayer() == players[0] ? "you" : players[0].getName()
: players.length + " players";
issuer.sendInfo(MVCorei18n.TELEPORT_SUCCESS,
"{player}", playerName, "{destination}", destination.toString());
});
}
@Override
public boolean hasPermission(CommandIssuer issuer) {
return this.plugin.getDestinationsProvider().hasAnyTeleportPermission(issuer);
return this.destinationsProvider.hasAnyTeleportPermission(issuer);
}
}
@@ -7,34 +7,48 @@ import co.aikar.commands.annotation.CommandPermission;
import co.aikar.commands.annotation.Description;
import co.aikar.commands.annotation.Subcommand;
import co.aikar.commands.annotation.Syntax;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager;
import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand;
import com.onarandombox.MultiverseCore.utils.MVCorei18n;
import jakarta.inject.Inject;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
@Service
@CommandAlias("mv")
public class UnloadCommand extends MultiverseCoreCommand {
public UnloadCommand(@NotNull MultiverseCore plugin) {
super(plugin);
public class UnloadCommand extends MultiverseCommand {
private final MVWorldManager worldManager;
@Inject
public UnloadCommand(@NotNull MVCommandManager commandManager, @NotNull MVWorldManager worldManager) {
super(commandManager);
this.worldManager = worldManager;
}
@Subcommand("unload")
@CommandPermission("multiverse.core.unload")
@CommandCompletion("@mvworlds")
@Syntax("<world>")
@Description("Unloads a world from Multiverse. This does NOT remove the world folder. This does NOT remove it from the config file.")
@Description("{@@mv-core.unload.description}")
public void onUnloadCommand(BukkitCommandIssuer issuer,
@Syntax("<world>")
@Description("Name of the world you want to unload.")
@Description("{@@mv-core.unload.world.description}")
MVWorld world
) {
issuer.sendMessage(String.format("Unloading world '%s'...", world.getColoredWorldString()));
issuer.sendInfo(MVCorei18n.UNLOAD_UNLOADING,
"{world}", world.getColoredWorldString());
//TODO API: Should be able to use MVWorld object directly
if (!this.plugin.getMVWorldManager().unloadWorld(world.getName())) {
issuer.sendMessage(String.format("Error unloading world '%s'! See console for more details.", world.getColoredWorldString()));
if (!this.worldManager.unloadWorld(world.getName())) {
issuer.sendError(MVCorei18n.UNLOAD_FAILURE,
"{world}", world.getColoredWorldString());
return;
}
issuer.sendMessage(String.format("Unloaded world '%s'!", world.getColoredWorldString()));
issuer.sendInfo(MVCorei18n.UNLOAD_SUCCESS,
"{world}", world.getColoredWorldString());
}
}
@@ -0,0 +1,39 @@
package com.onarandombox.MultiverseCore.commands;
import co.aikar.commands.CommandHelp;
import co.aikar.commands.annotation.CommandAlias;
import co.aikar.commands.annotation.CommandCompletion;
import co.aikar.commands.annotation.CommandPermission;
import co.aikar.commands.annotation.Description;
import co.aikar.commands.annotation.HelpCommand;
import co.aikar.commands.annotation.Subcommand;
import co.aikar.commands.annotation.Syntax;
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager;
import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand;
import jakarta.inject.Inject;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
@Service
@CommandAlias("mv")
public class UsageCommand extends MultiverseCommand {
@Inject
public UsageCommand(@NotNull MVCommandManager commandManager) {
super(commandManager);
}
@HelpCommand
@Subcommand("help")
@CommandPermission("multiverse.core.help")
@CommandCompletion("@commands:mv")
@Syntax("[filter] [page]")
@Description("{@@mv-core.usage.description}")
public void onUsageCommand(CommandHelp help) {
if (help.getIssuer().isPlayer()) {
// Prevent flooding the chat
help.setPerPage(4);
}
this.commandManager.showUsage(help);
}
}
@@ -5,34 +5,51 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import co.aikar.commands.BukkitCommandCompletionContext;
import co.aikar.commands.BukkitCommandIssuer;
import co.aikar.commands.CommandIssuer;
import co.aikar.commands.PaperCommandCompletions;
import co.aikar.commands.RegisteredCommand;
import co.aikar.commands.RootCommand;
import com.google.common.collect.Sets;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.config.MVCoreConfig;
import com.onarandombox.MultiverseCore.destination.DestinationsProvider;
import com.onarandombox.MultiverseCore.destination.ParsedDestination;
import jakarta.inject.Inject;
import org.bukkit.GameRule;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
@Service
public class MVCommandCompletions extends PaperCommandCompletions {
protected final MVCommandManager commandManager;
private final MultiverseCore plugin;
private final MVWorldManager worldManager;
public MVCommandCompletions(MVCommandManager mvCommandManager, MultiverseCore plugin) {
protected final MVCommandManager commandManager;
private final MVWorldManager worldManager;
private final DestinationsProvider destinationsProvider;
@Inject
public MVCommandCompletions(
@NotNull MVCommandManager mvCommandManager,
@NotNull MVWorldManager worldManager,
@NotNull DestinationsProvider destinationsProvider,
@NotNull MVCoreConfig config
) {
super(mvCommandManager);
this.commandManager = mvCommandManager;
this.plugin = plugin;
this.worldManager = plugin.getMVWorldManager();
this.worldManager = worldManager;
this.destinationsProvider = destinationsProvider;
registerAsyncCompletion("commands", this::suggestCommands);
registerAsyncCompletion("destinations", this::suggestDestinations);
registerAsyncCompletion("flags", this::suggestFlags);
registerStaticCompletion("gamerules", this::suggestGamerules);
registerStaticCompletion("mvconfigs", config.getNodes().getNames());
registerAsyncCompletion("mvworlds", this::suggestMVWorlds);
setDefaultCompletion("destinations", ParsedDestination.class);
@@ -41,12 +58,39 @@ public class MVCommandCompletions extends PaperCommandCompletions {
setDefaultCompletion("mvworlds", MVWorld.class);
}
private Collection<String> suggestCommands(BukkitCommandCompletionContext context) {
String rootCmdName = context.getConfig();
if (rootCmdName == null) {
return Collections.emptyList();
}
RootCommand rootCommand = this.commandManager.getRegisteredRootCommands().stream()
.unordered()
.filter(c -> c.getCommandName().equals(rootCmdName))
.findFirst()
.orElse(null);
if (rootCommand == null) {
return Collections.emptyList();
}
return rootCommand.getSubCommands().entries().stream()
.filter(entry -> checkPerms(context.getIssuer(), entry.getValue()))
.map(Map.Entry::getKey)
.filter(cmdName -> !cmdName.startsWith("__"))
.collect(Collectors.toList());
}
private boolean checkPerms(CommandIssuer issuer, RegisteredCommand<?> command) {
return this.commandManager.hasPermission(issuer, command.getRequiredPermissions());
}
private Collection<String> suggestDestinations(BukkitCommandCompletionContext context) {
if (context.hasConfig("playerOnly") && !context.getIssuer().isPlayer()) {
return Collections.emptyList();
}
return this.plugin.getDestinationsProvider()
return this.destinationsProvider
.suggestDestinations((BukkitCommandIssuer)context.getIssuer(), context.getInput());
}
@@ -6,21 +6,26 @@ import co.aikar.commands.BukkitConditionContext;
import co.aikar.commands.CommandConditions;
import co.aikar.commands.ConditionContext;
import co.aikar.commands.ConditionFailedException;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.world.WorldNameChecker;
import jakarta.annotation.PostConstruct;
import org.jetbrains.annotations.NotNull;
public class MVCommandConditions {
static void load(MVCommandManager commandManager, MultiverseCore plugin) {
new MVCommandConditions(commandManager, plugin);
static void load(MVCommandManager commandManager, MVWorldManager worldManager) {
new MVCommandConditions(commandManager, worldManager);
}
private final MVWorldManager worldManager;
private final MVCommandManager commandManager;
private final MultiverseCore plugin;
public MVCommandConditions(MVCommandManager commandManager, MultiverseCore plugin) {
private MVCommandConditions(@NotNull MVCommandManager commandManager, @NotNull MVWorldManager worldManager) {
this.worldManager = worldManager;
this.commandManager = commandManager;
this.plugin = plugin;
}
@PostConstruct
private void registerConditions() {
CommandConditions<BukkitCommandIssuer, BukkitCommandExecutionContext, BukkitConditionContext> conditions
= commandManager.getCommandConditions();
@@ -36,14 +41,14 @@ public class MVCommandConditions {
switch (scope) {
// Worlds that are loaded
case "loaded":
if (!this.plugin.getMVWorldManager().isMVWorld(worldName)) {
if (!this.worldManager.isMVWorld(worldName)) {
throw new ConditionFailedException("World with name '" + worldName + "' does not exist or is not loaded!");
}
break;
// Worlds that are unloaded
case "unloaded":
if (!this.plugin.getMVWorldManager().hasUnloadedWorld(worldName, false)) {
if (this.plugin.getMVWorldManager().isMVWorld(worldName)) {
if (!this.worldManager.hasUnloadedWorld(worldName, false)) {
if (this.worldManager.isMVWorld(worldName)) {
throw new ConditionFailedException("World with name '" + worldName + "' is loaded already!");
}
throw new ConditionFailedException("World with name '" + worldName + "' does not exist!");
@@ -51,13 +56,13 @@ public class MVCommandConditions {
break;
// World that are loaded or unloaded
case "both":
if (!this.plugin.getMVWorldManager().hasUnloadedWorld(worldName, true)) {
if (!this.worldManager.hasUnloadedWorld(worldName, true)) {
throw new ConditionFailedException("World with name '" + worldName + "' does not exist!");
}
break;
// World that are does not exist
case "new":
if (this.plugin.getMVWorldManager().hasUnloadedWorld(worldName, true)) {
if (this.worldManager.hasUnloadedWorld(worldName, true)) {
throw new ConditionFailedException("World with name '" + worldName + "' already exists!");
}
switch (WorldNameChecker.checkName(worldName)) {
@@ -1,6 +1,7 @@
package com.onarandombox.MultiverseCore.commandtools;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import co.aikar.commands.BukkitCommandExecutionContext;
@@ -9,35 +10,66 @@ import co.aikar.commands.InvalidCommandArgument;
import co.aikar.commands.PaperCommandContexts;
import co.aikar.commands.contexts.ContextResolver;
import com.google.common.base.Strings;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.commandtools.context.GameRuleValue;
import com.onarandombox.MultiverseCore.commandtools.context.MVConfigValue;
import com.onarandombox.MultiverseCore.config.MVCoreConfig;
import com.onarandombox.MultiverseCore.configuration.node.Node;
import com.onarandombox.MultiverseCore.configuration.node.ValueNode;
import com.onarandombox.MultiverseCore.destination.DestinationsProvider;
import com.onarandombox.MultiverseCore.destination.ParsedDestination;
import com.onarandombox.MultiverseCore.display.filters.ContentFilter;
import com.onarandombox.MultiverseCore.display.filters.DefaultContentFilter;
import com.onarandombox.MultiverseCore.display.filters.RegexContentFilter;
import com.onarandombox.MultiverseCore.utils.PlayerFinder;
import io.vavr.control.Option;
import jakarta.inject.Inject;
import org.bukkit.GameRule;
import org.bukkit.entity.Player;
import org.jvnet.hk2.annotations.Service;
@Service
public class MVCommandContexts extends PaperCommandContexts {
private final MultiverseCore plugin;
public MVCommandContexts(MVCommandManager mvCommandManager, MultiverseCore plugin) {
private final MVCommandManager mvCommandManager;
private final DestinationsProvider destinationsProvider;
private final MVWorldManager worldManager;
private final MVCoreConfig config;
@Inject
public MVCommandContexts(
MVCommandManager mvCommandManager,
DestinationsProvider destinationsProvider,
MVWorldManager worldManager,
MVCoreConfig config
) {
super(mvCommandManager);
this.plugin = plugin;
this.mvCommandManager = mvCommandManager;
this.destinationsProvider = destinationsProvider;
this.worldManager = worldManager;
this.config = config;
registerIssuerOnlyContext(BukkitCommandIssuer.class, BukkitCommandExecutionContext::getIssuer);
registerIssuerOnlyContext(MVCommandIssuer.class, this::parseMVCommandIssuer);
registerOptionalContext(ContentFilter.class, this::parseContentFilter);
registerContext(ParsedDestination.class, this::parseDestination);
registerContext(GameRule.class, this::parseGameRule);
registerContext(GameRuleValue.class, this::parseGameRuleValue);
registerContext(MVConfigValue.class, this::parseMVConfigValue);
registerIssuerAwareContext(MVWorld.class, this::parseMVWorld);
registerIssuerAwareContext(MVWorld[].class, this::parseMVWorldArray);
registerIssuerAwareContext(Player.class, this::parsePlayer);
registerIssuerAwareContext(Player[].class, this::parsePlayerArray);
}
private MVCommandIssuer parseMVCommandIssuer(BukkitCommandExecutionContext context) {
if (context.getIssuer() instanceof MVCommandIssuer) {
return (MVCommandIssuer) context.getIssuer();
}
return mvCommandManager.getCommandIssuer(context.getSender());
}
private ContentFilter parseContentFilter(BukkitCommandExecutionContext context) {
if (Strings.isNullOrEmpty(context.getFirstArg())) {
return DefaultContentFilter.get();
@@ -52,7 +84,7 @@ public class MVCommandContexts extends PaperCommandContexts {
throw new InvalidCommandArgument("No destination specified.");
}
ParsedDestination<?> parsedDestination = plugin.getDestinationsProvider().parseDestination(destination);
ParsedDestination<?> parsedDestination = destinationsProvider.parseDestination(destination);
if (parsedDestination == null) {
throw new InvalidCommandArgument("The destination " + destination + " is not valid.");
}
@@ -97,13 +129,46 @@ public class MVCommandContexts extends PaperCommandContexts {
return new GameRuleValue(resolvedValue);
}
private MVConfigValue parseMVConfigValue(BukkitCommandExecutionContext context) {
String configName = (String) context.getResolvedArg(String.class);
if (Strings.isNullOrEmpty(configName)) {
throw new InvalidCommandArgument("No config name specified.");
}
Option<Node> node = config.getNodes().findNode(configName);
if (node.isEmpty()) {
throw new InvalidCommandArgument("The config " + configName + " is not valid.");
}
String valueString = context.getFirstArg();
if (Strings.isNullOrEmpty(valueString)) {
throw new InvalidCommandArgument("No config value specified.");
}
if (!(node.get() instanceof ValueNode)) {
context.popFirstArg();
return new MVConfigValue(valueString);
}
ContextResolver<?, BukkitCommandExecutionContext> resolver = getResolver(((ValueNode<?>) node.get()).getType());
if (resolver == null) {
context.popFirstArg();
return new MVConfigValue(valueString);
}
Object resolvedValue = resolver.getContext(context);
if (resolvedValue == null) {
throw new InvalidCommandArgument("The config value " + valueString + " is not valid for config " + configName + ".");
}
return new MVConfigValue(resolvedValue);
}
private MVWorld parseMVWorld(BukkitCommandExecutionContext context) {
String resolve = context.getFlagValue("resolve", "");
// Get world based on sender only
if (resolve.equals("issuerOnly")) {
if (context.getIssuer().isPlayer()) {
return plugin.getMVWorldManager().getMVWorld(context.getIssuer().getPlayer().getWorld());
return worldManager.getMVWorld(context.getIssuer().getPlayer().getWorld());
}
if (context.isOptional()) {
return null;
@@ -112,7 +177,7 @@ public class MVCommandContexts extends PaperCommandContexts {
}
String worldName = context.getFirstArg();
MVWorld world = plugin.getMVWorldManager().getMVWorld(worldName);
MVWorld world = worldManager.getMVWorld(worldName);
// Get world based on input, fallback to sender if input is not a world
if (resolve.equals("issuerAware")) {
@@ -121,7 +186,7 @@ public class MVCommandContexts extends PaperCommandContexts {
return world;
}
if (context.getIssuer().isPlayer()) {
return plugin.getMVWorldManager().getMVWorld(context.getIssuer().getPlayer().getWorld());
return worldManager.getMVWorld(context.getIssuer().getPlayer().getWorld());
}
if (context.isOptional()) {
return null;
@@ -145,7 +210,7 @@ public class MVCommandContexts extends PaperCommandContexts {
MVWorld playerWorld = null;
if (context.getIssuer().isPlayer()) {
playerWorld = plugin.getMVWorldManager().getMVWorld(context.getIssuer().getPlayer().getWorld());
playerWorld = worldManager.getMVWorld(context.getIssuer().getPlayer().getWorld());
}
// Get world based on sender only
@@ -164,10 +229,10 @@ public class MVCommandContexts extends PaperCommandContexts {
Set<MVWorld> worlds = new HashSet<>(worldNames.length);
for (String worldName : worldNames) {
if ("*".equals(worldName)) {
worlds.addAll(plugin.getMVWorldManager().getMVWorlds());
worlds.addAll(worldManager.getMVWorlds());
break;
}
MVWorld world = plugin.getMVWorldManager().getMVWorld(worldName);
MVWorld world = worldManager.getMVWorld(worldName);
if (world == null) {
throw new InvalidCommandArgument("World " + worldName + " is not a loaded multiverse world.");
}
@@ -0,0 +1,48 @@
package com.onarandombox.MultiverseCore.commandtools;
import co.aikar.commands.MessageType;
import co.aikar.commands.OpenBukkitCommandIssuer;
import co.aikar.locales.MessageKeyProvider;
import com.onarandombox.MultiverseCore.utils.message.Message;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
public class MVCommandIssuer extends OpenBukkitCommandIssuer {
private final MVCommandManager commandManager;
MVCommandIssuer(@NotNull MVCommandManager commandManager, @NotNull CommandSender sender) {
super(commandManager, sender);
this.commandManager = commandManager;
}
@Override
public MVCommandManager getManager() {
return commandManager;
}
public void sendError(Message message) {
sendMessage(MessageType.ERROR, message);
}
public void sendSyntax(Message message) {
sendMessage(MessageType.SYNTAX, message);
}
public void sendInfo(Message message) {
sendMessage(MessageType.INFO, message);
}
private void sendMessage(MessageType messageType, Message message) {
if (message instanceof MessageKeyProvider) {
sendMessage(messageType, (MessageKeyProvider) message, message.getReplacements());
} else {
var formatter = getManager().getFormat(messageType);
if (formatter != null) {
sendMessage(formatter.format(message.formatted()));
} else {
sendMessage(message.formatted());
}
}
}
}
@@ -1,37 +1,66 @@
package com.onarandombox.MultiverseCore.commandtools;
import java.util.Locale;
import java.util.List;
import co.aikar.commands.BukkitCommandCompletionContext;
import co.aikar.commands.BukkitCommandExecutionContext;
import co.aikar.commands.BukkitLocales;
import co.aikar.commands.CommandCompletions;
import co.aikar.commands.CommandContexts;
import co.aikar.commands.CommandHelp;
import co.aikar.commands.HelpEntry;
import co.aikar.commands.PaperCommandManager;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.commandtools.flags.CommandFlagsManager;
import com.onarandombox.MultiverseCore.commandtools.queue.CommandQueueManager;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
/**
* Main class to manage permissions.
*/
@Service
public class MVCommandManager extends PaperCommandManager {
private final MultiverseCore plugin;
private CommandFlagsManager flagsManager;
private CommandQueueManager commandQueueManager;
private final CommandFlagsManager flagsManager;
private final CommandQueueManager commandQueueManager;
private final Provider<MVCommandContexts> commandContextsProvider;
private final Provider<MVCommandCompletions> commandCompletionsProvider;
public MVCommandManager(@NotNull MultiverseCore plugin) {
@Inject
public MVCommandManager(
@NotNull MultiverseCore plugin,
@NotNull CommandFlagsManager flagsManager,
@NotNull CommandQueueManager commandQueueManager,
@NotNull Provider<MVCommandContexts> commandContextsProvider,
@NotNull Provider<MVCommandCompletions> commandCompletionsProvider,
@NotNull MVWorldManager worldManager
) {
super(plugin);
this.plugin = plugin;
this.flagsManager = flagsManager;
this.commandQueueManager = commandQueueManager;
this.commandContextsProvider = commandContextsProvider;
this.commandCompletionsProvider = commandCompletionsProvider;
// Setup conditions
MVCommandConditions.load(this, plugin);
MVCommandConditions.load(this, worldManager);
this.enableUnstableAPI("help");
}
// Setup locale
this.addSupportedLanguage(Locale.ENGLISH);
this.locales.addMessageBundles("multiverse-core");
this.locales.loadLanguages();
void loadLanguages(PluginLocales locales) {
if (this.locales == null) {
this.locales = locales;
this.locales.loadLanguages();
}
}
@Override
public BukkitLocales getLocales() {
return this.locales;
}
/**
@@ -40,9 +69,6 @@ public class MVCommandManager extends PaperCommandManager {
* @return A not-null {@link CommandFlagsManager}.
*/
public synchronized @NotNull CommandFlagsManager getFlagsManager() {
if (this.flagsManager == null) {
this.flagsManager = new CommandFlagsManager();
}
return flagsManager;
}
@@ -52,9 +78,6 @@ public class MVCommandManager extends PaperCommandManager {
* @return A non-null {@link CommandQueueManager}.
*/
public synchronized @NotNull CommandQueueManager getCommandQueueManager() {
if (this.commandQueueManager == null) {
this.commandQueueManager = new CommandQueueManager(this.plugin);
}
return commandQueueManager;
}
@@ -66,7 +89,7 @@ public class MVCommandManager extends PaperCommandManager {
@Override
public synchronized @NotNull CommandContexts<BukkitCommandExecutionContext> getCommandContexts() {
if (this.contexts == null) {
this.contexts = new MVCommandContexts(this, plugin);
this.contexts = commandContextsProvider.get();
}
return this.contexts;
}
@@ -79,8 +102,35 @@ public class MVCommandManager extends PaperCommandManager {
@Override
public synchronized @NotNull CommandCompletions<BukkitCommandCompletionContext> getCommandCompletions() {
if (this.completions == null) {
this.completions = new MVCommandCompletions(this, plugin);
this.completions = commandCompletionsProvider.get();
}
return this.completions;
}
/**
* Standardise usage command formatting for all mv modules.
*
* @param help The target {@link CommandHelp}.
*/
public void showUsage(@NotNull CommandHelp help) {
List<HelpEntry> entries = help.getHelpEntries();
if (entries.size() == 1) {
getHelpFormatter().showDetailedHelp(help, entries.get(0));
return;
}
help.showHelp();
}
public @NotNull MVCommandIssuer getConsoleCommandIssuer() {
return getCommandIssuer(Bukkit.getConsoleSender());
}
@Override
public @NotNull MVCommandIssuer getCommandIssuer(Object issuer) {
if (!(issuer instanceof CommandSender)) {
throw new IllegalArgumentException(issuer.getClass().getName() + " is not a Command Issuer.");
} else {
return new MVCommandIssuer(this, (CommandSender)issuer);
}
}
}
@@ -1,29 +1,35 @@
package com.onarandombox.MultiverseCore.commandtools;
import co.aikar.commands.BaseCommand;
import com.onarandombox.MultiverseCore.api.MVPlugin;
import com.onarandombox.MultiverseCore.commandtools.flags.CommandFlagGroup;
import com.onarandombox.MultiverseCore.commandtools.flags.CommandFlagsManager;
import com.onarandombox.MultiverseCore.commandtools.flags.ParsedCommandFlags;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Contract;
@Contract
public abstract class MultiverseCommand extends BaseCommand {
protected final CommandFlagsManager flagsManager;
protected final MVCommandManager commandManager;
private String flagGroupName;
protected MultiverseCommand(@NotNull MVPlugin plugin) {
this.flagsManager = plugin.getCore().getMVCommandManager().getFlagsManager();
protected MultiverseCommand(@NotNull MVCommandManager commandManager) {
this.commandManager = commandManager;
}
protected CommandFlagsManager getFlagsManager() {
return commandManager.getFlagsManager();
}
protected void registerFlagGroup(@NotNull CommandFlagGroup flagGroup) {
if (flagGroupName != null) {
throw new IllegalStateException("Flag group already registered! (name: " + flagGroupName + ")");
}
flagsManager.registerFlagGroup(flagGroup);
getFlagsManager().registerFlagGroup(flagGroup);
flagGroupName = flagGroup.getName();
}
protected @NotNull ParsedCommandFlags parseFlags(@NotNull String[] flags) {
return flagsManager.parse(flagGroupName, flags);
return getFlagsManager().parse(flagGroupName, flags);
}
}
@@ -0,0 +1,49 @@
package com.onarandombox.MultiverseCore.commandtools;
import co.aikar.commands.BukkitLocales;
import com.onarandombox.MultiverseCore.utils.file.FileResClassLoader;
import jakarta.inject.Inject;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
/**
* Locale manager with additional methods for loading locales from plugin's locales folder.
*/
@Service
public class PluginLocales extends BukkitLocales {
private static final String DEFAULT_LOCALE_FOLDER_PATH = "locales";
/**
* Creates a new instance of {@link PluginLocales}.
*
* @param manager The command manager.
*/
@Inject
public PluginLocales(MVCommandManager manager) {
super(manager);
manager.loadLanguages(this);
}
/**
* Adds a {@link FileResClassLoader} to the list of class loaders to load locales data from.
*
* @param plugin The plugin.
* @return True if the class loader was added successfully.
*/
public boolean addFileResClassLoader(@NotNull Plugin plugin) {
return this.addBundleClassLoader(new FileResClassLoader(plugin, DEFAULT_LOCALE_FOLDER_PATH));
}
/**
* Adds a {@link FileResClassLoader} to the list of class loaders to load locales data from.
*
* @param plugin The plugin.
* @param localesFolderPath The path to the folder containing the locales.
* @return True if the class loader was added successfully.
*/
public boolean addFileResClassLoader(@NotNull Plugin plugin, @NotNull String localesFolderPath) {
return this.addBundleClassLoader(new FileResClassLoader(plugin, localesFolderPath));
}
}
@@ -0,0 +1,13 @@
package com.onarandombox.MultiverseCore.commandtools.context;
public class MVConfigValue {
private final Object value;
public MVConfigValue(Object value) {
this.value = value;
}
public Object getValue() {
return value;
}
}
@@ -9,10 +9,12 @@ import java.util.Map;
import co.aikar.commands.InvalidCommandArgument;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jvnet.hk2.annotations.Service;
/**
* Manages all the flag groups and parsing.
*/
@Service
public class CommandFlagsManager {
private final Map<String, CommandFlagGroup> flagGroupMap;
@@ -12,13 +12,16 @@ import java.util.WeakHashMap;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.MultiverseCore;
import jakarta.inject.Inject;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.block.data.type.CommandBlock;
import org.bukkit.command.BlockCommandSender;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitTask;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
/**
* <p>Manages the queuing of dangerous commands that require {@code /mv confirm} before executing.</p>
@@ -26,14 +29,16 @@ import org.jetbrains.annotations.NotNull;
* <p>Each sender can only have one command in queue at any given time. When a queued command is added
* for a sender that already has a command in queue, it will replace the old queued command.</p>
*/
@Service
public class CommandQueueManager {
private static final long TICKS_PER_SECOND = 20;
private static final DummyCommandBlockSender COMMAND_BLOCK = new DummyCommandBlockSender();
private final MultiverseCore plugin;
private final Plugin plugin;
private final Map<CommandSender, QueuedCommand> queuedCommandMap;
@Inject
public CommandQueueManager(@NotNull MultiverseCore plugin) {
this.plugin = plugin;
this.queuedCommandMap = new WeakHashMap<>();
@@ -0,0 +1,262 @@
package com.onarandombox.MultiverseCore.config;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVConfig;
import com.onarandombox.MultiverseCore.configuration.handle.CommentedYamlConfigHandle;
import com.onarandombox.MultiverseCore.configuration.migration.BooleanMigratorAction;
import com.onarandombox.MultiverseCore.configuration.migration.ConfigMigrator;
import com.onarandombox.MultiverseCore.configuration.migration.IntegerMigratorAction;
import com.onarandombox.MultiverseCore.configuration.migration.InvertBoolMigratorAction;
import com.onarandombox.MultiverseCore.configuration.migration.MoveMigratorAction;
import com.onarandombox.MultiverseCore.configuration.migration.VersionMigrator;
import com.onarandombox.MultiverseCore.configuration.node.NodeGroup;
import io.vavr.control.Try;
import jakarta.inject.Inject;
import org.bukkit.plugin.PluginManager;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
@Service
public class MVCoreConfig implements MVConfig {
public static final String CONFIG_FILENAME = "config.yml";
public static final double CONFIG_VERSION = 5.0;
private final Path configPath;
private final MVCoreConfigNodes configNodes;
private final CommentedYamlConfigHandle configHandle;
@Inject
MVCoreConfig(@NotNull MultiverseCore core, @NotNull PluginManager pluginManager) {
this.configPath = Path.of(core.getDataFolder().getPath(), CONFIG_FILENAME);
this.configNodes = new MVCoreConfigNodes(pluginManager);
this.configHandle = CommentedYamlConfigHandle.builder(configPath)
.logger(Logging.getLogger())
.nodes(configNodes.getNodes())
.migrator(ConfigMigrator.builder(configNodes.VERSION)
.addVersionMigrator(VersionMigrator.builder(5.0)
.addAction(MoveMigratorAction.of("multiverse-configuration.enforceaccess", "world.enforce-access"))
.addAction(BooleanMigratorAction.of("world.enforce-access"))
.addAction(MoveMigratorAction.of("multiverse-configuration.prefixchat", "messaging.enable-chat-prefix"))
.addAction(BooleanMigratorAction.of("messaging.enable-chat-prefix"))
.addAction(MoveMigratorAction.of("multiverse-configuration.prefixchatformat", "messaging.chat-prefix-format"))
.addAction(MoveMigratorAction.of("multiverse-configuration.teleportintercept", "world.teleport-intercept"))
.addAction(BooleanMigratorAction.of("world.teleport-intercept"))
.addAction(MoveMigratorAction.of("multiverse-configuration.firstspawnoverride", "spawn.first-spawn-override"))
.addAction(BooleanMigratorAction.of("spawn.first-spawn-override"))
//.addAction(MoveMigratorAction.of("multiverse-configuration.displaypermerrors", ""))
.addAction(MoveMigratorAction.of("multiverse-configuration.globaldebug", "misc.global-debug"))
.addAction(IntegerMigratorAction.of("misc.global-debug"))
.addAction(MoveMigratorAction.of("multiverse-configuration.silentstart", "misc.silent-start"))
.addAction(BooleanMigratorAction.of("misc.silent-start"))
.addAction(MoveMigratorAction.of("multiverse-configuration.firstspawnworld", "spawn.first-spawn-location"))
.addAction(MoveMigratorAction.of("multiverse-configuration.defaultportalsearch", "portal.use-custom-portal-search"))
.addAction(BooleanMigratorAction.of("portal.use-custom-portal-search"))
.addAction(InvertBoolMigratorAction.of("portal.use-custom-portal-search"))
.addAction(MoveMigratorAction.of("multiverse-configuration.portalsearchradius", "portal.custom-portal-search-radius"))
.addAction(IntegerMigratorAction.of("portal.custom-portal-search-radius"))
.addAction(MoveMigratorAction.of("multiverse-configuration.autopurge", "world.auto-purge-entities"))
.addAction(BooleanMigratorAction.of("world.auto-purge-entities"))
.addAction(MoveMigratorAction.of("multiverse-configuration.idonotwanttodonate", "misc.show-donation-message"))
.addAction(BooleanMigratorAction.of("misc.show-donation-message"))
.addAction(InvertBoolMigratorAction.of("misc.show-donation-message"))
.build())
.build())
.build();
load();
save();
}
private void migrateFromOldConfigFile() {
String content;
try {
content = Files.readString(configPath);
} catch (IOException e) {
return;
}
// Remove the old config section if it is still in the old ConfigurationSerializable.
content = content.replace("==: com.onarandombox.MultiverseCore.MultiverseCoreConfiguration", "");
try {
Files.writeString(configPath, content);
} catch (IOException e) {
// ignore
}
}
@Override
public boolean load() {
migrateFromOldConfigFile();
return configHandle.load();
}
@Override
public boolean isLoaded() {
return configHandle.isLoaded();
}
@Override
public boolean save() {
configHandle.save();
return true;
}
@Override
public NodeGroup getNodes() {
return configNodes.getNodes();
}
@Override
public Try<Object> getProperty(String name) {
return configHandle.get(name);
}
@Override
public Try<Void> setProperty(String name, Object value) {
return configHandle.set(name, value);
}
@Override
public void setEnforceAccess(boolean enforceAccess) {
configHandle.set(configNodes.ENFORCE_ACCESS, enforceAccess);
}
@Override
public boolean getEnforceAccess() {
return configHandle.get(configNodes.ENFORCE_ACCESS);
}
@Override
public void setEnforceGameMode(boolean enforceGameMode) {
configHandle.set(configNodes.ENFORCE_GAMEMODE, enforceGameMode);
}
@Override
public boolean getEnforceGameMode() {
return configHandle.get(configNodes.ENFORCE_GAMEMODE);
}
@Override
public void setAutoPurgeEntities(boolean autopurge) {
configHandle.set(configNodes.AUTO_PURGE_ENTITIES, autopurge);
}
@Override
public boolean isAutoPurgeEntities() {
return configHandle.get(configNodes.AUTO_PURGE_ENTITIES);
}
@Override
public void setTeleportIntercept(boolean teleportIntercept) {
configHandle.set(configNodes.TELEPORT_INTERCEPT, teleportIntercept);
}
@Override
public boolean getTeleportIntercept() {
return configHandle.get(configNodes.TELEPORT_INTERCEPT);
}
@Override
public void setFirstSpawnOverride(boolean firstSpawnOverride) {
configHandle.set(configNodes.FIRST_SPAWN_OVERRIDE, firstSpawnOverride);
}
@Override
public boolean getFirstSpawnOverride() {
return configHandle.get(configNodes.FIRST_SPAWN_OVERRIDE);
}
@Override
public void setFirstSpawnLocation(String firstSpawnWorld) {
configHandle.set(configNodes.FIRST_SPAWN_LOCATION, firstSpawnWorld);
}
@Override
public String getFirstSpawnLocation() {
return configHandle.get(configNodes.FIRST_SPAWN_LOCATION);
}
@Override
public void setUseCustomPortalSearch(boolean useDefaultPortalSearch) {
configHandle.set(configNodes.USE_CUSTOM_PORTAL_SEARCH, useDefaultPortalSearch);
}
@Override
public boolean isUsingCustomPortalSearch() {
return configHandle.get(configNodes.USE_CUSTOM_PORTAL_SEARCH);
}
@Override
public void setCustomPortalSearchRadius(int searchRadius) {
configHandle.set(configNodes.CUSTOM_PORTAL_SEARCH_RADIUS, searchRadius);
}
@Override
public int getCustomPortalSearchRadius() {
return configHandle.get(configNodes.CUSTOM_PORTAL_SEARCH_RADIUS);
}
@Override
public void setEnablePrefixChat(boolean prefixChat) {
configHandle.set(configNodes.ENABLE_CHAT_PREFIX, prefixChat);
}
@Override
public boolean isEnablePrefixChat() {
return configHandle.get(configNodes.ENABLE_CHAT_PREFIX);
}
@Override
public void setPrefixChatFormat(String prefixChatFormat) {
configHandle.set(configNodes.CHAT_PREFIX_FORMAT, prefixChatFormat);
}
@Override
public String getPrefixChatFormat() {
return configHandle.get(configNodes.CHAT_PREFIX_FORMAT);
}
@Override
public void setRegisterPapiHook(boolean registerPapiHook) {
configHandle.set(configNodes.REGISTER_PAPI_HOOK, registerPapiHook);
}
@Override
public boolean isRegisterPapiHook() {
return configHandle.get(configNodes.REGISTER_PAPI_HOOK);
}
@Override
public void setGlobalDebug(int globalDebug) {
configHandle.set(configNodes.GLOBAL_DEBUG, globalDebug);
}
@Override
public int getGlobalDebug() {
return configHandle.get(configNodes.GLOBAL_DEBUG);
}
@Override
public void setSilentStart(boolean silentStart) {
configHandle.set(configNodes.SILENT_START, silentStart);
}
@Override
public boolean getSilentStart() {
return configHandle.get(configNodes.SILENT_START);
}
@Override
public void setShowDonateMessage(boolean showDonateMessage) {
configHandle.set(configNodes.SHOW_DONATION_MESSAGE, showDonateMessage);
}
@Override
public boolean isShowingDonateMessage() {
return configHandle.get(configNodes.SHOW_DONATION_MESSAGE);
}
}
@@ -0,0 +1,216 @@
package com.onarandombox.MultiverseCore.config;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.configuration.node.ConfigHeaderNode;
import com.onarandombox.MultiverseCore.configuration.node.ConfigNode;
import com.onarandombox.MultiverseCore.configuration.node.Node;
import com.onarandombox.MultiverseCore.configuration.node.NodeGroup;
import com.onarandombox.MultiverseCore.event.MVDebugModeEvent;
import com.onarandombox.MultiverseCore.exceptions.MultiverseException;
import io.github.townyadvanced.commentedconfiguration.setting.CommentedNode;
import io.vavr.control.Try;
import org.bukkit.plugin.PluginManager;
class MVCoreConfigNodes {
private final NodeGroup nodes = new NodeGroup();
private PluginManager pluginManager;
MVCoreConfigNodes(PluginManager pluginManager) {
this.pluginManager = pluginManager;
}
public NodeGroup getNodes() {
return nodes;
}
private <N extends Node> N node(N node) {
nodes.add(node);
return node;
}
private final ConfigHeaderNode HEADER = node(ConfigHeaderNode.builder("world") // TODO hacky way to get the header to the top of the file
.comment("####################################################################################################")
.comment("# #")
.comment("# █▀▄▀█ █░█ █░░ ▀█▀ █ █░█ █▀▀ █▀█ █▀ █▀▀   █▀▀ █▀█ █▀█ █▀▀ #")
.comment("# █░▀░█ █▄█ █▄▄ ░█░ █ ▀▄▀ ██▄ █▀▄ ▄█ ██▄   █▄▄ █▄█ █▀▄ ██▄ #")
.comment("# #")
.comment("# #")
.comment("# WIKI: https://github.com/Multiverse/Multiverse-Core/wiki #")
.comment("# DISCORD: https://discord.gg/NZtfKky #")
.comment("# BUG REPORTS: https://github.com/Multiverse/Multiverse-Core/issues #")
.comment("# #")
.comment("# #")
.comment("# Each option in this file is documented and explained here: #")
.comment("# ==> https://github.com/Multiverse/Multiverse-Core/wiki/config.yml #")
.comment("# #")
.comment("# #")
.comment("# New options are added to this file automatically. If you manually made changes #")
.comment("# to this file while your server is running, please run `/mv reload` command. #")
.comment("# #")
.comment("####################################################################################################")
.comment("")
.comment("")
.build());
// private final ConfigHeaderNode WORLD_HEADER = node(ConfigHeaderNode.builder("world")
// .comment("")
// .comment("")
// .build());
public final ConfigNode<Boolean> ENFORCE_ACCESS = node(ConfigNode.builder("world.enforce-access", Boolean.class)
.comment("This setting will prevent players from entering worlds they don't have access to.")
.comment("If this is set to false, players will be able to enter any world they want.")
.comment("If this is set to true, players will only be able to enter worlds they have")
.comment("the `mv.access.<worldname>` permission.")
.defaultValue(false)
.name("enforce-access")
.build());
public final ConfigNode<Boolean> ENFORCE_GAMEMODE = node(ConfigNode.builder("world.enforce-gamemode", Boolean.class)
.comment("")
.comment("Sets whether Multiverse will should enforce gamemode on world change.")
.comment("If enabled, players will be forced into the gamemode of the world they are entering, unless they have")
.comment("the `mv.bypass.gamemode.<worldname>` permission.")
.defaultValue(true)
.name("enforce-gamemode")
.build());
public final ConfigNode<Boolean> AUTO_PURGE_ENTITIES = node(ConfigNode.builder("world.auto-purge-entities", Boolean.class)
.comment("")
.comment("Sets whether Multiverse will purge mobs and entities with be automatically.")
.defaultValue(false)
.name("auto-purge-entities")
.build());
public final ConfigNode<Boolean> TELEPORT_INTERCEPT = node(ConfigNode.builder("world.teleport-intercept", Boolean.class)
.comment("")
.comment("If this is set to true, Multiverse will enforce access permissions for all teleportation,")
.comment("including teleportation from other plugins.")
.defaultValue(true)
.name("teleport-intercept")
.build());
private final ConfigHeaderNode SPAWN_HEADER = node(ConfigHeaderNode.builder("spawn")
.comment("")
.comment("")
.build());
public final ConfigNode<Boolean> FIRST_SPAWN_OVERRIDE = node(ConfigNode.builder("spawn.first-spawn-override", Boolean.class)
.comment("Sets whether Multiverse will override the first spawn location of a world.")
.comment("If enabled, Multiverse will set the first spawn location of a world to the spawn location of the world.")
.comment("If disabled, it will default to server.properties settings.")
.defaultValue(true)
.name("first-spawn-override")
.build());
public final ConfigNode<String> FIRST_SPAWN_LOCATION = node(ConfigNode.builder("spawn.first-spawn-location", String.class)
.comment("")
.comment("Sets the world that Multiverse will use as the location for players that first join the server.")
.comment("This only applies if first-spawn-override is set to true.")
.defaultValue("")
.name("first-spawn-location")
.build());
private final ConfigHeaderNode PORTAL_HEADER = node(ConfigHeaderNode.builder("portal")
.comment("")
.comment("")
.build());
public final ConfigNode<Boolean> USE_CUSTOM_PORTAL_SEARCH = node(ConfigNode.builder("portal.use-custom-portal-search", Boolean.class)
.comment("This config option defines whether or not Multiverse should interfere with's Bukkit's default portal search radius.")
.comment("Setting it to false would mean you want to simply let Bukkit decides the search radius itself.")
.defaultValue(false)
.name("use-custom-portal-search")
.build());
public final ConfigNode<Integer> CUSTOM_PORTAL_SEARCH_RADIUS = node(ConfigNode.builder("portal.custom-portal-search-radius", Integer.class)
.comment("")
.comment("This config option defines the search radius Multiverse should use when searching for a portal.")
.comment("This only applies if use-custom-portal-search is set to true.")
.defaultValue(128)
.name("custom-portal-search-radius")
.validator(value -> value < 0
? Try.failure(new MultiverseException("The value must be greater than or equal to 0.", null))
: Try.success(null))
.build());
private final ConfigHeaderNode MESSAGING_HEADER = node(ConfigHeaderNode.builder("messaging")
.comment("")
.comment("")
.build());
public final ConfigNode<Boolean> ENABLE_CHAT_PREFIX = node(ConfigNode.builder("messaging.enable-chat-prefix", Boolean.class)
.comment("This config option defines whether or not Multiverse should prefix the chat with the world name.")
.comment("This only applies if use-custom-portal-search is set to true.")
.defaultValue(false)
.name("enable-chat-prefix")
.build());
public final ConfigNode<String> CHAT_PREFIX_FORMAT = node(ConfigNode.builder("messaging.chat-prefix-format", String.class)
.comment("")
.comment("This config option defines the format Multiverse should use when prefixing the chat with the world name.")
.comment("This only applies if enable-chat-prefix is set to true.")
.defaultValue("[%world%]%chat%")
.name("chat-prefix-format")
.build());
public final ConfigNode<Boolean> REGISTER_PAPI_HOOK = node(ConfigNode.builder("messaging.register-papi-hook", Boolean.class)
.comment("")
.comment("This config option defines whether or not Multiverse should register the PlaceholderAPI hook.")
.comment("This only applies if PlaceholderAPI is installed.")
.defaultValue(true)
.name("register-papi-hook")
.build());
private final ConfigHeaderNode MISC_HEADER = node(ConfigHeaderNode.builder("misc")
.comment("")
.comment("")
.build());
public final ConfigNode<Integer> GLOBAL_DEBUG = node(ConfigNode.builder("misc.global-debug", Integer.class)
.comment("This is our debug flag to help identify issues with Multiverse.")
.comment("If you are having issues with Multiverse, please set this to 3 and then post your log to pastebin.com")
.comment("Otherwise, there's no need to touch this. If not instructed by a wiki page or developer.")
.comment(" 0 = Off, No debug messages")
.comment(" 1 = fine")
.comment(" 2 = finer")
.comment(" 3 = finest")
.defaultValue(0)
.name("global-debug")
.validator(value -> (value < 0 || value > 3)
? Try.failure(new MultiverseException("Debug level must be between 0 and 3.", null))
: Try.success(null))
.onSetValue((oldValue, newValue) -> {
int level = Logging.getDebugLevel();
Logging.setDebugLevel(newValue);
if (level != Logging.getDebugLevel()) {
pluginManager.callEvent(new MVDebugModeEvent(level));
}
})
.build());
public final ConfigNode<Boolean> SILENT_START = node(ConfigNode.builder("misc.silent-start", Boolean.class)
.comment("")
.comment("If true, the startup console messages will no longer show.")
.defaultValue(false)
.name("silent-start")
.onSetValue((oldValue, newValue) -> Logging.setShowingConfig(!newValue))
.build());
public final ConfigNode<Boolean> SHOW_DONATION_MESSAGE = node(ConfigNode.builder("misc.show-donation-message", Boolean.class)
.comment("")
.comment("If you don't want to donate, you can set this to false and Multiverse will stop nagging you.")
.defaultValue(true)
.name("show-donation-message")
.build());
public final ConfigNode<Double> VERSION = node(ConfigNode.builder("version", Double.class)
.comment("")
.comment("")
.comment("This just signifies the version number so we can see what version of config you have.")
.comment("NEVER TOUCH THIS VALUE")
.defaultValue(MVCoreConfig.CONFIG_VERSION)
.name(null)
.build());
}
@@ -0,0 +1,93 @@
package com.onarandombox.MultiverseCore.configuration.handle;
import java.nio.file.Path;
import java.util.logging.Logger;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.configuration.migration.ConfigMigrator;
import com.onarandombox.MultiverseCore.configuration.node.NodeGroup;
import com.onarandombox.MultiverseCore.configuration.node.CommentedNode;
import com.onarandombox.MultiverseCore.configuration.node.ValueNode;
import io.github.townyadvanced.commentedconfiguration.CommentedConfiguration;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Configuration handle for commented YAML files.
*/
public class CommentedYamlConfigHandle extends FileConfigHandle<CommentedConfiguration> {
/**
* Creates a new builder for a {@link CommentedYamlConfigHandle}.
*
* @param configPath The path to the config file.
* @return The builder.
*/
public static @NotNull Builder builder(@NotNull Path configPath) {
return new Builder(configPath);
}
protected CommentedYamlConfigHandle(@NotNull Path configPath, @Nullable Logger logger, @Nullable NodeGroup nodes, @Nullable ConfigMigrator migrator) {
super(configPath, logger, nodes, migrator);
}
/**
* {@inheritDoc}
*/
@Override
protected boolean loadConfigObject() {
config = new CommentedConfiguration(configPath, logger);
return config.load();
}
/**
* {@inheritDoc}
*/
@Override
protected void setUpNodes() {
if (nodes == null || nodes.isEmpty()) {
return;
}
CommentedConfiguration oldConfig = config;
this.config = new CommentedConfiguration(configPath, logger);
nodes.forEach(node -> {
if (node instanceof CommentedNode typedNode) {
if (typedNode.getComments().length > 0) {
config.addComment(typedNode.getPath(), typedNode.getComments());
}
}
if (node instanceof ValueNode valueNode) {
set(valueNode, oldConfig.getObject(valueNode.getPath(), valueNode.getType(), valueNode.getDefaultValue())).onFailure(e -> {
Logging.warning("Failed to set node " + valueNode.getPath() + " to " + valueNode.getDefaultValue());
setDefault(valueNode);
});
}
});
}
/**
* {@inheritDoc}
*/
@Override
public boolean save() {
config.save();
return true;
}
public static class Builder extends FileConfigHandle.Builder<CommentedConfiguration, Builder> {
protected Builder(@NotNull Path configPath) {
super(configPath);
}
/**
* {@inheritDoc}
*/
@Override
public @NotNull CommentedYamlConfigHandle build() {
return new CommentedYamlConfigHandle(configPath, logger, nodes, migrator);
}
}
}
@@ -0,0 +1,47 @@
package com.onarandombox.MultiverseCore.configuration.handle;
import com.onarandombox.MultiverseCore.configuration.migration.ConfigMigrator;
import com.onarandombox.MultiverseCore.configuration.node.NodeGroup;
import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.logging.Logger;
/**
* Configuration handle for a single configuration section.
*/
public class ConfigurationSectionHandle extends GenericConfigHandle<ConfigurationSection> {
public static Builder<? extends Builder> builder(@NotNull ConfigurationSection configurationSection) {
return new Builder<>(configurationSection);
}
public ConfigurationSectionHandle(@NotNull ConfigurationSection configurationSection,
@Nullable Logger logger,
@Nullable NodeGroup nodes,
@Nullable ConfigMigrator migrator) {
super(logger, nodes, migrator);
this.config = configurationSection;
}
/**
* Builder for {@link ConfigurationSectionHandle}.
*
* @param <B> The builder type.
*/
public static class Builder<B extends Builder<B>> extends GenericConfigHandle.Builder<ConfigurationSection, B> {
private final ConfigurationSection configurationSection;
protected Builder(@NotNull ConfigurationSection configurationSection) {
this.configurationSection = configurationSection;
}
/**
* {@inheritDoc}
*/
@Override
public @NotNull ConfigurationSectionHandle build() {
return new ConfigurationSectionHandle(configurationSection, logger, nodes, migrator);
}
}
}
@@ -0,0 +1,130 @@
package com.onarandombox.MultiverseCore.configuration.handle;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.logging.Logger;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.configuration.migration.ConfigMigrator;
import com.onarandombox.MultiverseCore.configuration.node.NodeGroup;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Generic configuration handle for file based configurations.
* @param <C> The configuration type.
*/
abstract class FileConfigHandle<C extends FileConfiguration> extends GenericConfigHandle<C> {
protected final @NotNull Path configPath;
protected final @NotNull File configFile;
protected FileConfigHandle(@NotNull Path configPath, @Nullable Logger logger, @Nullable NodeGroup nodes, @Nullable ConfigMigrator migrator) {
super(logger, nodes, migrator);
this.configPath = configPath;
this.configFile = configPath.toFile();
}
/**
* {@inheritDoc}
*/
@Override
public boolean load() {
if (!createConfigFile()) {
Logging.severe("Failed to create config file: %s", configFile.getName());
return false;
}
if (!loadConfigObject()) {
Logging.severe("Failed to load config file: %s", configFile.getName());
return false;
}
migrateConfig();
setUpNodes();
return true;
}
/**
* Create a new config file if file does not exist
*
* @return True if file exist or created successfully, otherwise false.
*/
protected boolean createConfigFile() {
if (configFile.exists()) {
return true;
}
try {
if (!configFile.createNewFile()) {
return false;
}
Logging.info("Created new config file: %s", configFile.getName());
} catch (IOException e) {
return false;
}
return true;
}
/**
* Loads the configuration object.
*
* @return True if the configuration was loaded successfully, false otherwise.
*/
protected abstract boolean loadConfigObject();
/**
* Saves the configuration.
*/
public abstract boolean save();
/**
* Checks if the configuration is loaded.
*
* @return True if the configuration is loaded, false otherwise.
*/
public boolean isLoaded() {
return config != null;
}
/**
* Gets the configuration.
*
* @return The configuration.
*/
public C getConfig() {
return config;
}
/**
* Abstract builder for {@link FileConfigHandle}.
*
* @param <C> The configuration type.
* @param <B> The builder type.
*/
public static abstract class Builder<C extends FileConfiguration, B extends Builder<C, B>> extends GenericConfigHandle.Builder<C, B> {
protected @NotNull Path configPath;
protected @Nullable Logger logger;
protected @Nullable NodeGroup nodes;
protected @Nullable ConfigMigrator migrator;
protected Builder(@NotNull Path configPath) {
this.configPath = configPath;
}
/**
* Builds the configuration handle.
*
* @return The configuration handle.
*/
public abstract @NotNull FileConfigHandle<C> build();
@SuppressWarnings("unchecked")
protected B self() {
return (B) this;
}
}
}
@@ -0,0 +1,196 @@
package com.onarandombox.MultiverseCore.configuration.handle;
import com.onarandombox.MultiverseCore.configuration.migration.ConfigMigrator;
import com.onarandombox.MultiverseCore.configuration.node.ConfigNodeNotFoundException;
import com.onarandombox.MultiverseCore.configuration.node.NodeGroup;
import com.onarandombox.MultiverseCore.configuration.node.ValueNode;
import io.vavr.control.Try;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.logging.Logger;
/**
* Generic configuration handle for all ConfigurationSection types.
*/
public abstract class GenericConfigHandle<C extends ConfigurationSection> {
protected final @Nullable Logger logger;
protected final @Nullable NodeGroup nodes;
protected final @Nullable ConfigMigrator migrator;
protected C config;
public GenericConfigHandle(@Nullable Logger logger, @Nullable NodeGroup nodes, @Nullable ConfigMigrator migrator) {
this.logger = logger;
this.nodes = nodes;
this.migrator = migrator;
}
/**
* Loads the configuration.
*
* @return True if the configuration was loaded successfully, false otherwise.
*/
public boolean load() {
migrateConfig();
setUpNodes();
return true;
}
/**
* Migrates the configuration.
*/
protected void migrateConfig() {
if (migrator != null) {
migrator.migrate(config);
}
}
/**
* Sets up the nodes.
*/
protected void setUpNodes() {
if (nodes == null || nodes.isEmpty()) {
return;
}
nodes.forEach(node -> {
if (node instanceof ValueNode valueNode) {
set(valueNode, config.getObject(valueNode.getPath(), valueNode.getType(), valueNode.getDefaultValue()));
}
});
}
/**
* Gets the value of a node, if the node has a default value, it will be returned if the node is not found.
* @param name The name of the node.
* @return The value of the node.
*/
public Try<Object> get(@Nullable String name) {
return nodes.findNode(name, ValueNode.class)
.toTry(() -> new ConfigNodeNotFoundException(name))
.map(node -> get((ValueNode<Object>) node));
}
/**
* Gets the value of a node, if the node has a default value, it will be returned if the node is not found.
*
* @param node The node to get the value of.
* @return The value of the node.
*/
public <T> T get(@NotNull ValueNode<T> node) {
return config.getObject(node.getPath(), node.getType(), node.getDefaultValue());
}
/**
* Sets the value of a node, if the validator is not null, it will be tested first.
*
* @param name The name of the node.
* @param value The value to set.
* @return True if the value was set, false otherwise.
*/
public Try<Void> set(@Nullable String name, Object value) {
return nodes.findNode(name, ValueNode.class)
.toTry(() -> new ConfigNodeNotFoundException(name))
.flatMap(node -> set(node, value));
}
/**
* Sets the value of a node, if the validator is not null, it will be tested first.
*
* @param node The node to set the value of.
* @param value The value to set.
* @return True if the value was set, false otherwise.
* @param <T> The type of the node value.
*/
public <T> Try<Void> set(@NotNull ValueNode<T> node, T value) {
return node.validate(value).map(ignore -> {
T oldValue = get(node);
config.set(node.getPath(), value);
node.onSetValue(oldValue, get(node));
return null;
});
}
/**
* Sets the default value of a node.
*
* @param node The node to set the default value of.
*/
public void setDefault(@NotNull ValueNode node) {
config.set(node.getPath(), node.getDefaultValue());
}
/**
* Abstract builder for {@link GenericConfigHandle}.
*
* @param <C> The configuration type.
* @param <B> The builder type.
*/
public static abstract class Builder<C extends ConfigurationSection, B extends GenericConfigHandle.Builder<C, B>> {
protected @Nullable Logger logger;
protected @Nullable NodeGroup nodes;
protected @Nullable ConfigMigrator migrator;
protected Builder() {}
/**
* Sets the logger.
*
* @param logger The logger.
* @return The builder.
*/
public B logger(@Nullable Logger logger) {
this.logger = logger;
return self();
}
/**
* Sets the logger.
*
* @param plugin The plugin to get the logger from.
* @return The builder.
*/
public B logger(Plugin plugin) {
this.logger = plugin.getLogger();
return self();
}
/**
* Sets the nodes.
*
* @param nodes The nodes.
* @return The builder.
*/
public B nodes(@Nullable NodeGroup nodes) {
this.nodes = nodes;
return self();
}
/**
* Sets the migrator.
*
* @param migrator The migrator.
* @return The builder.
*/
public B migrator(@Nullable ConfigMigrator migrator) {
this.migrator = migrator;
return self();
}
/**
* Builds the configuration handle.
*
* @return The configuration handle.
*/
public abstract @NotNull GenericConfigHandle<C> build();
@SuppressWarnings("unchecked")
protected B self() {
return (B) this;
}
}
}
@@ -0,0 +1,79 @@
package com.onarandombox.MultiverseCore.configuration.handle;
import java.io.IOException;
import java.nio.file.Path;
import java.util.logging.Logger;
import com.onarandombox.MultiverseCore.configuration.migration.ConfigMigrator;
import com.onarandombox.MultiverseCore.configuration.node.NodeGroup;
import com.onarandombox.MultiverseCore.configuration.node.ValueNode;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Configuration handle for YAML files.
*/
public class YamlConfigHandle extends FileConfigHandle<YamlConfiguration> {
/**
* Creates a new builder for {@link YamlConfigHandle}.
*
* @param configPath The path to the config file.
* @return The builder.
*/
public static @NotNull Builder<? extends Builder> builder(@NotNull Path configPath) {
return new Builder<>(configPath);
}
protected YamlConfigHandle(@NotNull Path configPath, @Nullable Logger logger, @Nullable NodeGroup nodes, @Nullable ConfigMigrator migrator) {
super(configPath, logger, nodes, migrator);
}
/**
* {@inheritDoc}
*/
@Override
protected boolean loadConfigObject() {
config = new YamlConfiguration();
try {
config.load(configFile);
} catch (IOException | InvalidConfigurationException e) {
return false;
}
return true;
}
/**
* {@inheritDoc}
*/
@Override
public boolean save() {
try {
config.save(configFile);
} catch (IOException e) {
return false;
}
return true;
}
/**
* Builder for {@link YamlConfigHandle}.
* @param <B> The type of the builder.
*/
public static class Builder<B extends Builder<B>> extends FileConfigHandle.Builder<YamlConfiguration, B> {
protected Builder(@NotNull Path configPath) {
super(configPath);
}
/**
* {@inheritDoc}
*/
@Override
public @NotNull YamlConfigHandle build() {
return new YamlConfigHandle(configPath, logger, nodes, migrator);
}
}
}
@@ -0,0 +1,29 @@
package com.onarandombox.MultiverseCore.configuration.migration;
import co.aikar.commands.ACFUtil;
import com.dumptruckman.minecraft.util.Logging;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
/**
* Single migrator action that converts a string value to a boolean.
*/
public class BooleanMigratorAction implements MigratorAction {
public static BooleanMigratorAction of(String path) {
return new BooleanMigratorAction(path);
}
private final String path;
protected BooleanMigratorAction(String path) {
this.path = path;
}
@Override
public void migrate(ConfigurationSection config) {
config.set(path, ACFUtil.isTruthy(config.getString(path, "")));
Logging.info("Converted %s to boolean %s", path, config.getBoolean(path));
}
}
@@ -0,0 +1,91 @@
package com.onarandombox.MultiverseCore.configuration.migration;
import java.util.ArrayList;
import java.util.List;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.configuration.node.ValueNode;
import io.github.townyadvanced.commentedconfiguration.setting.TypedValueNode;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
/**
* Helper class for migrating configs to the latest config version.
*/
public class ConfigMigrator {
/**
* Creates a new builder for a ConfigMigrator.
*
* @param versionNode The node that stores the version number of the config.
* Default value should be the current latest version number.
* @return The builder instance.
*/
public static Builder builder(ValueNode<Double> versionNode) {
return new Builder(versionNode);
}
private final ValueNode<Double> versionNode;
private final List<VersionMigrator> versionMigrators;
protected ConfigMigrator(ValueNode<Double> versionNode, List<VersionMigrator> versionMigrators) {
this.versionNode = versionNode;
this.versionMigrators = versionMigrators;
}
/**
* Migrates the config to the latest version if necessary.
*
* @param config The target settings instance to migrate.
*/
public void migrate(ConfigurationSection config) {
double versionNumber = config.getDouble(versionNode.getPath());
for (VersionMigrator versionMigrator : versionMigrators) {
if (versionNumber < versionMigrator.getVersion()) {
Logging.info("Migrating config from version %s to %s...", versionNumber, versionMigrator.getVersion());
versionMigrator.migrate(config);
}
}
// Set the version number to the latest version number
config.set(versionNode.getPath(), versionNode.getDefaultValue());
}
/**
* A builder for a ConfigMigrator.
*/
public static class Builder {
private final ValueNode<Double> versionNode;
private final List<VersionMigrator> versionMigrators;
/**
* Creates a new builder for a ConfigMigrator.
*
* @param versionNode The node that stores the version number of the config.
* Default value should be the current latest version number.
*/
public Builder(ValueNode<Double> versionNode) {
this.versionNode = versionNode;
this.versionMigrators = new ArrayList<>();
}
/**
* Adds a version migrator to the list of migrators.
*
* @param versionMigrator The migrator to add.
* @return The builder instance.
*/
public Builder addVersionMigrator(VersionMigrator versionMigrator) {
versionMigrators.add(versionMigrator);
return this;
}
/**
* Builds the ConfigMigrator.
*
* @return The built ConfigMigrator.
*/
public ConfigMigrator build() {
return new ConfigMigrator(versionNode, versionMigrators);
}
}
}
@@ -0,0 +1,28 @@
package com.onarandombox.MultiverseCore.configuration.migration;
import co.aikar.commands.ACFUtil;
import com.dumptruckman.minecraft.util.Logging;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
/**
* Single migrator action that converts a string value to an integer.
*/
public class IntegerMigratorAction implements MigratorAction {
public static IntegerMigratorAction of(String path) {
return new IntegerMigratorAction(path);
}
private final String path;
public IntegerMigratorAction(String path) {
this.path = path;
}
@Override
public void migrate(ConfigurationSection config) {
config.set(path, ACFUtil.parseInt(config.getString(path)));
Logging.info("Converted %s to integer %s", path, config.getInt(path));
}
}
@@ -0,0 +1,37 @@
package com.onarandombox.MultiverseCore.configuration.migration;
import com.dumptruckman.minecraft.util.Logging;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
/**
* Single migrator action that inverts a boolean value for a given path.
*/
public class InvertBoolMigratorAction implements MigratorAction {
/**
* Creates a new migrator action that inverts a boolean value for a given path.
*
* @param path The path to invert value of.
* @return The new migrator action.
*/
public static InvertBoolMigratorAction of(String path) {
return new InvertBoolMigratorAction(path);
}
private final String path;
protected InvertBoolMigratorAction(String path) {
this.path = path;
}
/**
* {@inheritDoc}
*/
@Override
public void migrate(ConfigurationSection config) {
boolean boolValue = !config.getBoolean(path);
config.set(path, boolValue);
Logging.info("Inverted %s to boolean %s", path, boolValue);
}
}
@@ -0,0 +1,17 @@
package com.onarandombox.MultiverseCore.configuration.migration;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
/**
* A migrator action is a single action that is performed when migrating a config.
*/
public interface MigratorAction {
/**
* Performs the migration action.
*
* @param config The target settings instance to migrate.
*/
void migrate(ConfigurationSection config);
}
@@ -0,0 +1,45 @@
package com.onarandombox.MultiverseCore.configuration.migration;
import java.util.Optional;
import com.dumptruckman.minecraft.util.Logging;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
/**
* Single migrator action that moves a value from one path to another.
*/
public class MoveMigratorAction implements MigratorAction {
/**
* Creates a new migrator action that moves a value from one path to another.
*
* @param fromPath The path to move value from.
* @param toPath The path to move value to.
* @return The new migrator action.
*/
public static MoveMigratorAction of(String fromPath, String toPath) {
return new MoveMigratorAction(fromPath, toPath);
}
private final String fromPath;
private final String toPath;
protected MoveMigratorAction(String fromPath, String toPath) {
this.fromPath = fromPath;
this.toPath = toPath;
}
/**
* {@inheritDoc}
*/
@Override
public void migrate(ConfigurationSection config) {
Optional.ofNullable(config.get(fromPath))
.ifPresent(value -> {
config.set(toPath, value);
config.set(fromPath, null);
Logging.config("Moved path %s to %s", fromPath, toPath);
});
}
}
@@ -0,0 +1,86 @@
package com.onarandombox.MultiverseCore.configuration.migration;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
/**
* A version migrator is a collection of migrator actions that are performed when migrating a config to a specific version.
*/
public class VersionMigrator {
/**
* Creates a new builder for a VersionMigrator.
*
* @param version The version number of the config that this migrator migrates to.
* @return The builder instance.
*/
public static Builder builder(double version) {
return new Builder(version);
}
private final double version;
private final List<MigratorAction> actions;
protected VersionMigrator(double version, List<MigratorAction> actions) {
this.version = version;
this.actions = actions;
}
/**
* Performs all the migrator actions.
*
* @param config The target settings instance to migrate.
*/
public void migrate(ConfigurationSection config) {
actions.forEach(action -> action.migrate(config));
}
/**
* Gets the version number of the config that this migrator migrates to.
*
* @return The version number.
*/
public double getVersion() {
return version;
}
/**
* A builder for a VersionMigrator.
*/
public static class Builder {
private final double version;
private final List<MigratorAction> actions = new ArrayList<>();
/**
* Creates a new builder for a VersionMigrator.
*
* @param version The version number of the config that this migrator migrates to.
*/
public Builder(double version) {
this.version = version;
}
/**
* Adds a migrator action to the list of actions.
*
* @param action The action to add.
* @return The builder instance.
*/
public Builder addAction(MigratorAction action) {
actions.add(action);
return this;
}
/**
* Builds the VersionMigrator.
*
* @return The built VersionMigrator.
*/
public VersionMigrator build() {
return new VersionMigrator(version, actions);
}
}
}
@@ -0,0 +1,13 @@
package com.onarandombox.MultiverseCore.configuration.node;
import org.jetbrains.annotations.NotNull;
public interface CommentedNode extends Node {
/**
* Gets the comment of the node.
*
* @return The comment of the node.
*/
@NotNull String[] getComments();
}
@@ -0,0 +1,81 @@
package com.onarandombox.MultiverseCore.configuration.node;
import java.util.ArrayList;
import java.util.List;
import com.google.common.base.Strings;
import org.jetbrains.annotations.NotNull;
/**
* A node that represents a header without any value.
*/
public class ConfigHeaderNode implements CommentedNode {
/**
* Creates a new builder for a {@link ConfigHeaderNode}.
*
* @param path The path of the node.
* @return The new builder.
*/
public static @NotNull Builder<? extends Builder<?>> builder(String path) {
return new Builder<>(path);
}
private final @NotNull String path;
private final @NotNull String[] comments;
protected ConfigHeaderNode(@NotNull String path, @NotNull String[] comments) {
this.path = path;
this.comments = comments;
}
/**
* {@inheritDoc}
*/
@Override
public @NotNull String getPath() {
return path;
}
/**
* {@inheritDoc}
*/
@Override
public @NotNull String[] getComments() {
return comments;
}
public static class Builder<B extends Builder<B>> {
protected final @NotNull String path;
protected final @NotNull List<String> comments;
public Builder(@NotNull String path) {
this.path = path;
this.comments = new ArrayList<>();
}
/**
* Adds a comment line to the node.
*
* @param comment The comment to add.
* @return This builder.
*/
public @NotNull B comment(@NotNull String comment) {
if (!Strings.isNullOrEmpty(comment) && !comment.startsWith("#")) {
comment = "# " + comment;
}
comments.add(comment);
return (B) this;
}
/**
* Builds the node.
*
* @return The built node.
*/
public @NotNull ConfigHeaderNode build() {
return new ConfigHeaderNode(path, comments.toArray(new String[0]));
}
}
}
@@ -0,0 +1,172 @@
package com.onarandombox.MultiverseCore.configuration.node;
import java.util.function.BiConsumer;
import java.util.function.Function;
import io.vavr.control.Option;
import io.vavr.control.Try;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* A node that contains a value.
* @param <T> The type of the value.
*/
public class ConfigNode<T> extends ConfigHeaderNode implements ValueNode<T> {
/**
* Creates a new builder for a {@link ConfigNode}.
*
* @param path The path of the node.
* @param type The type of the value.
* @return The new builder.
* @param <T> The type of the value.
*/
public static @NotNull <T> ConfigNode.Builder<T, ? extends ConfigNode.Builder<T, ?>> builder(
@NotNull String path,
@NotNull Class<T> type
) {
return new ConfigNode.Builder<>(path, type);
}
protected final @Nullable String name;
protected final @NotNull Class<T> type;
protected final @Nullable T defaultValue;
protected final @Nullable Function<T, Try<Void>> validator;
protected final @Nullable BiConsumer<T, T> onSetValue;
protected ConfigNode(
@NotNull String path,
@NotNull String[] comments,
@Nullable String name,
@NotNull Class<T> type,
@Nullable T defaultValue,
@Nullable Function<T, Try<Void>> validator,
@Nullable BiConsumer<T, T> onSetValue
) {
super(path, comments);
this.name = name;
this.type = type;
this.defaultValue = defaultValue;
this.validator = validator;
this.onSetValue = onSetValue;
}
/**
* {@inheritDoc}
*/
@Override
public @NotNull Option<String> getName() {
return Option.of(name);
}
/**
* {@inheritDoc}
*/
@Override
public @NotNull Class<T> getType() {
return type;
}
/**
* {@inheritDoc}
*/
@Override
public @Nullable T getDefaultValue() {
return defaultValue;
}
/**
* {@inheritDoc}
*/
@Override
public Try<Void> validate(@Nullable T value) {
if (validator != null) {
return validator.apply(value);
}
return Try.success(null);
}
/**
* {@inheritDoc}
*/
@Override
public void onSetValue(@Nullable T oldValue, @Nullable T newValue) {
if (onSetValue != null) {
onSetValue.accept(oldValue, newValue);
}
}
/**
* Builder for {@link ConfigNode}.
*
* @param <T> The type of the value.
* @param <B> The type of the builder.
*/
public static class Builder<T, B extends ConfigNode.Builder<T, B>> extends ConfigHeaderNode.Builder<B> {
protected @Nullable String name;
protected @NotNull final Class<T> type;
protected @Nullable T defaultValue;
protected @Nullable Function<T, Try<Void>> validator;
protected @Nullable BiConsumer<T, T> onSetValue;
/**
* Creates a new builder.
*
* @param path The path of the node.
* @param type The type of the value.
*/
protected Builder(@NotNull String path, @NotNull Class<T> type) {
super(path);
this.name = path;
this.type = type;
}
/**
* Sets the default value for this node.
*
* @param defaultValue The default value.
* @return This builder.
*/
public @NotNull B defaultValue(@NotNull T defaultValue) {
this.defaultValue = defaultValue;
return (B) this;
}
/**
* Sets the name of this node. Used for identifying the node from user input.
*
* @param name The name of this node.
* @return This builder.
*/
public @NotNull B name(@Nullable String name) {
this.name = name;
return (B) this;
}
public @NotNull B validator(@NotNull Function<T, Try<Void>> validator) {
this.validator = validator;
return (B) this;
}
/**
* Sets the action to be performed when the value is set.
*
* @param onSetValue The action to be performed.
* @return This builder.
*/
public @NotNull B onSetValue(@NotNull BiConsumer<T, T> onSetValue) {
this.onSetValue = onSetValue;
return (B) this;
}
/**
* {@inheritDoc}
*/
@Override
public @NotNull ConfigNode<T> build() {
return new ConfigNode<>(path, comments.toArray(new String[0]), name, type, defaultValue, validator, onSetValue);
}
}
}
@@ -0,0 +1,14 @@
package com.onarandombox.MultiverseCore.configuration.node;
import com.onarandombox.MultiverseCore.exceptions.MultiverseException;
import org.jetbrains.annotations.Nullable;
import static com.onarandombox.MultiverseCore.utils.MVCorei18n.CONFIG_NODE_NOTFOUND;
import static com.onarandombox.MultiverseCore.utils.message.MessageReplacement.replace;
public class ConfigNodeNotFoundException extends MultiverseException {
public ConfigNodeNotFoundException(@Nullable String nodeName) {
super(CONFIG_NODE_NOTFOUND.bundle("Config node not found: {node}", replace("{node}").with(nodeName)), null);
}
}
@@ -0,0 +1,13 @@
package com.onarandombox.MultiverseCore.configuration.node;
import org.jetbrains.annotations.NotNull;
public interface Node {
/**
* Gets the YAML path of the node.
*
* @return The YAML path of the node.
*/
@NotNull String getPath();
}
@@ -0,0 +1,146 @@
package com.onarandombox.MultiverseCore.configuration.node;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import io.github.townyadvanced.commentedconfiguration.setting.CommentedNode;
import io.vavr.control.Option;
import org.jetbrains.annotations.NotNull;
/**
* A collection of {@link CommentedNode}s, with mappings to nodes by name.
*/
public class NodeGroup implements Collection<Node> {
private final Collection<Node> nodes;
private final Map<String, Node> nodesMap;
public NodeGroup() {
this.nodes = new ArrayList<>();
this.nodesMap = new HashMap<>();
}
public NodeGroup(Collection<Node> nodes) {
this.nodes = nodes;
this.nodesMap = new HashMap<>(nodes.size());
nodes.forEach(this::addNodeIndex);
}
private void addNodeIndex(Node node) {
if (node instanceof ValueNode) {
((ValueNode<?>) node).getName().peek(name -> nodesMap.put(name, node));
}
}
private void removeNodeIndex(Node node) {
if (node instanceof ValueNode) {
((ValueNode<?>) node).getName().peek(nodesMap::remove);
}
}
/**
* Gets the names of all nodes in this group.
*
* @return The names of all nodes in this group.
*/
public Collection<String> getNames() {
return nodesMap.keySet();
}
/**
* Gets the node with the given name.
*
* @param name The name of the node to get.
* @return The node with the given name, or {@link Option.None} if no node with the given name exists.
*/
public Option<Node> findNode(String name) {
return Option.of(nodesMap.get(name));
}
/**
* Gets the node with the given name.
*
* @param name The name of the node to get.
* @param type The type of the node to get.
* @return The node with the given name, or {@link Option.None} if no node with the given name exists.
*/
public <T extends Node> Option<T> findNode(String name, Class<T> type) {
return Option.of(nodesMap.get(name)).map(node -> type.isAssignableFrom(node.getClass()) ? (T) node : null);
}
@Override
public int size() {
return nodes.size();
}
@Override
public boolean isEmpty() {
return nodes.isEmpty();
}
@Override
public boolean contains(Object o) {
return nodes.contains(o);
}
@NotNull
@Override
public Iterator<Node> iterator() {
return nodes.iterator();
}
@Override
public Object @NotNull [] toArray() {
return nodes.toArray();
}
@Override
public <T> T @NotNull [] toArray(T @NotNull [] ts) {
return nodes.toArray(ts);
}
@Override
public boolean add(Node node) {
if (nodes.add(node)) {
addNodeIndex(node);
return true;
}
return false;
}
@Override
public boolean remove(Object o) {
if (nodes.remove(o) && o instanceof CommentedNode) {
removeNodeIndex((Node) o);
return true;
}
return false;
}
@Override
public boolean containsAll(@NotNull Collection<?> collection) {
return nodes.containsAll(collection);
}
@Override
public boolean addAll(@NotNull Collection<? extends Node> collection) {
return nodes.addAll(collection);
}
@Override
public boolean removeAll(@NotNull Collection<?> collection) {
return nodes.removeAll(collection);
}
@Override
public boolean retainAll(@NotNull Collection<?> collection) {
return nodes.retainAll(collection);
}
@Override
public void clear() {
nodes.clear();
}
}
@@ -0,0 +1,46 @@
package com.onarandombox.MultiverseCore.configuration.node;
import io.vavr.control.Option;
import io.vavr.control.Try;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public interface ValueNode<T> extends Node {
/**
* Gets the name of this node. Used for identifying the node from user input.
*
* @return An {@link Option} containing the name of this node, or {@link Option.None} if the node has no name.
*/
@NotNull Option<String> getName();
/**
* Gets the class type {@link T} of the node value.
*
* @return The class type of the node value.
*/
@NotNull Class<T> getType();
/**
* Gets the default value with type {@link T} of the node.
*
* @return The default value of the node.
*/
@Nullable T getDefaultValue();
/**
* Validates the value of this node.
*
* @param value The value to validate.
* @return True if the value is valid, false otherwise.
*/
Try<Void> validate(@Nullable T value);
/**
* Called when the value of this node is set.
*
* @param oldValue The old value.
* @param newValue The new value.
*/
void onSetValue(@Nullable T oldValue, @Nullable T newValue);
}
@@ -3,38 +3,44 @@ package com.onarandombox.MultiverseCore.destination;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import co.aikar.commands.BukkitCommandIssuer;
import co.aikar.commands.CommandIssuer;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.Destination;
import com.onarandombox.MultiverseCore.api.DestinationInstance;
import com.onarandombox.MultiverseCore.api.SafeTTeleporter;
import com.onarandombox.MultiverseCore.api.Teleporter;
import com.onarandombox.MultiverseCore.teleportation.TeleportResult;
import jakarta.inject.Inject;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.permissions.Permission;
import org.bukkit.plugin.PluginManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jvnet.hk2.annotations.Service;
/**
* Provides destinations for teleportation.
*/
@Service
public class DestinationsProvider {
private static final String SEPARATOR = ":";
private static final String PERMISSION_PREFIX = "multiverse.teleport.";
private final MultiverseCore plugin;
private final PluginManager pluginManager;
private final SafeTTeleporter safeTTeleporter;
private final Map<String, Destination<?>> destinationMap;
/**
* Creates a new destinations provider.
*
* @param plugin The plugin.
*/
public DestinationsProvider(@NotNull MultiverseCore plugin) {
this.plugin = plugin;
@Inject
public DestinationsProvider(@NotNull PluginManager pluginManager, @NotNull SafeTTeleporter safeTTeleporter) {
this.pluginManager = pluginManager;
this.safeTTeleporter = safeTTeleporter;
this.destinationMap = new HashMap<>();
}
@@ -49,7 +55,6 @@ public class DestinationsProvider {
}
private void registerDestinationPerms(@NotNull Destination<?> destination) {
PluginManager pluginManager = this.plugin.getServer().getPluginManager();
pluginManager.addPermission(new Permission(PERMISSION_PREFIX + "self." + destination.getIdentifier()));
pluginManager.addPermission(new Permission(PERMISSION_PREFIX + "other." + destination.getIdentifier()));
}
@@ -125,14 +130,14 @@ public class DestinationsProvider {
* @param teleportee The teleportee.
* @param destination The destination.
*/
public void playerTeleport(@NotNull BukkitCommandIssuer teleporter,
public CompletableFuture<TeleportResult> playerTeleportAsync(@NotNull BukkitCommandIssuer teleporter,
@NotNull Player teleportee,
@NotNull ParsedDestination<?> destination
) {
if (!checkTeleportPermissions(teleporter, teleportee, destination)) {
return;
return CompletableFuture.completedFuture(TeleportResult.FAIL_PERMISSION);
}
teleport(teleporter, teleportee, destination);
return teleportAsync(teleporter, teleportee, destination);
}
/**
@@ -142,15 +147,15 @@ public class DestinationsProvider {
* @param teleportee The teleportee.
* @param destination The destination.
*/
public void teleport(@NotNull BukkitCommandIssuer teleporter,
@NotNull Entity teleportee,
@NotNull ParsedDestination<?> destination
public CompletableFuture<TeleportResult> teleportAsync(@NotNull BukkitCommandIssuer teleporter,
@NotNull Entity teleportee,
@NotNull ParsedDestination<?> destination
) {
Teleporter teleportHandler = destination.getDestination().getTeleporter();
if (teleportHandler == null) {
teleportHandler = this.plugin.getSafeTTeleporter();
teleportHandler = safeTTeleporter;
}
teleportHandler.teleport(teleporter, teleportee, destination);
return teleportHandler.teleportAsync(teleporter, teleportee, destination);
}
/**
@@ -3,23 +3,23 @@ package com.onarandombox.MultiverseCore.destination.core;
import java.util.Collection;
import co.aikar.commands.BukkitCommandIssuer;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.anchor.AnchorManager;
import com.onarandombox.MultiverseCore.api.Destination;
import com.onarandombox.MultiverseCore.api.Teleporter;
import jakarta.inject.Inject;
import org.bukkit.Location;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jvnet.hk2.annotations.Service;
@Service
public class AnchorDestination implements Destination<AnchorDestinationInstance> {
private final MultiverseCore plugin;
/**
* Constructor.
*
* @param plugin The MultiverseCore plugin.
*/
public AnchorDestination(MultiverseCore plugin) {
this.plugin = plugin;
private final AnchorManager anchorManager;
@Inject
public AnchorDestination(AnchorManager anchorManager) {
this.anchorManager = anchorManager;
}
/**
@@ -35,7 +35,7 @@ public class AnchorDestination implements Destination<AnchorDestinationInstance>
*/
@Override
public @Nullable AnchorDestinationInstance getDestinationInstance(@Nullable String destinationParams) {
Location anchorLocation = this.plugin.getAnchorManager().getAnchorLocation(destinationParams);
Location anchorLocation = this.anchorManager.getAnchorLocation(destinationParams);
if (anchorLocation == null) {
return null;
}
@@ -47,7 +47,7 @@ public class AnchorDestination implements Destination<AnchorDestinationInstance>
*/
@Override
public @NotNull Collection<String> suggestDestinations(@NotNull BukkitCommandIssuer issuer, @Nullable String destinationParams) {
return this.plugin.getAnchorManager().getAnchors(issuer.getPlayer());
return this.anchorManager.getAnchors(issuer.getPlayer());
}
/**
@@ -12,7 +12,9 @@ import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jvnet.hk2.annotations.Service;
@Service
public class BedDestination implements Destination<BedDestinationInstance> {
public static final String OWN_BED_STRING = "playerbed";
@@ -4,24 +4,24 @@ import java.util.Collection;
import java.util.Collections;
import co.aikar.commands.BukkitCommandIssuer;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.Destination;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.api.Teleporter;
import jakarta.inject.Inject;
import org.bukkit.Location;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jvnet.hk2.annotations.Service;
@Service
public class CannonDestination implements Destination<CannonDestinationInstance> {
private final MultiverseCore plugin;
/**
* Constructor.
*
* @param plugin The MultiverseCore plugin.
*/
public CannonDestination(MultiverseCore plugin) {
this.plugin = plugin;
private final MVWorldManager worldManager;
@Inject
public CannonDestination(MVWorldManager worldManager) {
this.worldManager = worldManager;
}
/**
@@ -53,7 +53,7 @@ public class CannonDestination implements Destination<CannonDestinationInstance>
return null;
}
MVWorld world = this.plugin.getMVWorldManager().getMVWorld(worldName);
MVWorld world = this.worldManager.getMVWorld(worldName);
if (world == null) {
return null;
}
@@ -4,24 +4,24 @@ import java.util.Collection;
import java.util.Collections;
import co.aikar.commands.BukkitCommandIssuer;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.Destination;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.api.Teleporter;
import jakarta.inject.Inject;
import org.bukkit.Location;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jvnet.hk2.annotations.Service;
@Service
public class ExactDestination implements Destination<ExactDestinationInstance> {
private final MultiverseCore plugin;
/**
* Constructor.
*
* @param plugin The MultiverseCore plugin.
*/
public ExactDestination(MultiverseCore plugin) {
this.plugin = plugin;
private final MVWorldManager worldManager;
@Inject
public ExactDestination(MVWorldManager worldManager) {
this.worldManager = worldManager;
}
/**
@@ -49,7 +49,7 @@ public class ExactDestination implements Destination<ExactDestinationInstance> {
return null;
}
MVWorld world = this.plugin.getMVWorldManager().getMVWorld(worldName);
MVWorld world = this.worldManager.getMVWorld(worldName);
if (world == null) {
return null;
}
@@ -11,7 +11,9 @@ import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jvnet.hk2.annotations.Service;
@Service
public class PlayerDestination implements Destination<PlayerDestinationInstance> {
/**
* Creates a new instance of the PlayerDestination.
@@ -4,24 +4,26 @@ import java.util.Collection;
import java.util.Collections;
import co.aikar.commands.BukkitCommandIssuer;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.Destination;
import com.onarandombox.MultiverseCore.api.LocationManipulation;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.api.Teleporter;
import jakarta.inject.Inject;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jvnet.hk2.annotations.Service;
@Service
public class WorldDestination implements Destination<WorldDestinationInstance> {
private final MultiverseCore plugin;
private final MVWorldManager worldManager;
private final LocationManipulation locationManipulation;
/**
* Constructor.
*
* @param plugin The MultiverseCore plugin.
*/
public WorldDestination(MultiverseCore plugin) {
this.plugin = plugin;
@Inject
public WorldDestination(MVWorldManager worldManager, LocationManipulation locationManipulation) {
this.worldManager = worldManager;
this.locationManipulation = locationManipulation;
}
/**
@@ -43,13 +45,13 @@ public class WorldDestination implements Destination<WorldDestinationInstance> {
}
String worldName = items[0];
MVWorld world = this.plugin.getMVWorldManager().getMVWorld(worldName);
MVWorld world = this.worldManager.getMVWorld(worldName);
if (world == null) {
return null;
}
String direction = (items.length == 2) ? items[1] : null;
float yaw = direction != null ? this.plugin.getLocationManipulation().getYaw(direction) : -1;
float yaw = direction != null ? this.locationManipulation.getYaw(direction) : -1;
return new WorldDestinationInstance(world, direction, yaw);
}
@@ -1,18 +1,22 @@
package com.onarandombox.MultiverseCore.economy;
import jakarta.inject.Inject;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.Nullable;
import org.jvnet.hk2.annotations.Service;
/**
* Multiverse's Friendly Economist. This is used to deal with external economies and also item costs for stuff in MV.
*/
@Service
public class MVEconomist {
private final VaultHandler vaultHandler;
@Inject
public MVEconomist(Plugin plugin) {
vaultHandler = new VaultHandler(plugin);
}
@@ -0,0 +1,52 @@
package com.onarandombox.MultiverseCore.exceptions;
import com.onarandombox.MultiverseCore.commandtools.MVCommandIssuer;
import com.onarandombox.MultiverseCore.utils.message.Message;
import org.jetbrains.annotations.Nullable;
/**
* A base exception for Multiverse.
* <br/>
* {@link #getMVMessage()} provides access to a {@link Message} which can be used to provide a localized message. See
* {@link MVCommandIssuer#sendInfo(Message)}.
*/
public class MultiverseException extends Exception {
private final @Nullable Message message;
/**
* Creates a new exception with the given message and cause.
* <br/>
* If the message is not null, this exception will also contain a {@link Message} which can be accessed via
* {@link #getMVMessage()}. This message will just be the given message wrapped in a {@link Message}.
*
* @param message The message for the exception
* @param cause The cause of the exception
*/
public MultiverseException(@Nullable String message, @Nullable Throwable cause) {
this(message != null ? Message.of(message) : null, cause);
}
/**
* Creates a new exception with the given message and cause.
* <br/>
* If the message is not null, this exception will also contain a String message which can be accessed via
* {@link #getMessage()}. This message will just be the given message formatted without locale support.
*
* @param message The message for the exception
* @param cause The cause of the exception
*/
public MultiverseException(@Nullable Message message, @Nullable Throwable cause) {
super(message != null ? message.formatted() : null, cause);
this.message = message;
}
/**
* Gets the {@link Message} for this exception.
*
* @return The message, or null if none was provided
*/
public final @Nullable Message getMVMessage() {
return message;
}
}
@@ -0,0 +1,7 @@
package com.onarandombox.MultiverseCore.inject;
import org.bukkit.event.Listener;
import org.jvnet.hk2.annotations.Contract;
@Contract
public interface InjectableListener extends Listener { }
@@ -0,0 +1,126 @@
package com.onarandombox.MultiverseCore.inject;
import com.onarandombox.MultiverseCore.inject.binder.JavaPluginBinder;
import com.onarandombox.MultiverseCore.inject.binder.PluginBinder;
import com.onarandombox.MultiverseCore.inject.binder.ServerBinder;
import io.vavr.control.Try;
import org.bukkit.plugin.Plugin;
import org.glassfish.hk2.api.DynamicConfigurationService;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.api.ServiceLocatorFactory;
import org.glassfish.hk2.internal.ServiceLocatorFactoryImpl;
import org.glassfish.hk2.utilities.ClasspathDescriptorFileFinder;
import org.glassfish.hk2.utilities.ServiceLocatorUtilities;
import org.jetbrains.annotations.NotNull;
/**
* Provides methods to set up dependency injection for plugins.
* <br/>
* This class is a wrapper around the HK2 dependency injection library. It provides methods to create a service locators
* for plugins and to perform injection tasks on plugin instances on enable and disable.
*/
public final class PluginInjection {
/**
* Creates a {@link ServiceLocator} for the given plugin binder.
* <br/>
* The service locator is populated with the plugin instance and all dependencies that are bound in the
* {@link PluginBinder} of the plugin. Plugins must implement their own {@link PluginBinder} to use this class.
* {@link JavaPluginBinder} is provided as a convenience for plugins that extend
* {@link org.bukkit.plugin.java.JavaPlugin}.
*
* @param pluginBinder The plugin binder for the plugin.
* @return
*/
@NotNull
public static Try<ServiceLocator> createServiceLocator(@NotNull PluginBinder<?> pluginBinder) {
var factory = new ServiceLocatorFactoryImpl();
return createSystemServiceLocator(factory)
.flatMap(systemLocator -> createServerServiceLocator(factory, systemLocator))
.flatMap(serverLocator -> new PluginInjection(pluginBinder, factory, serverLocator).load());
}
/**
* Performs necessary steps to enable dependency injection for the given plugin.
* <br/>
* This method will inject all dependencies into the plugin instance and call the {@code @PostConstruct} methods.
*
* @param plugin The plugin to enable dependency injection for.
* @param pluginServiceLocator The service locator for the plugin.
*/
public static void enable(@NotNull Plugin plugin, @NotNull ServiceLocator pluginServiceLocator) {
pluginServiceLocator.inject(plugin);
pluginServiceLocator.postConstruct(plugin);
}
/**
* Performs necessary steps to disable dependency injection for the given plugin.
* <br/>
* This method will call the {@code @PreDestroy} methods and shutdown the service locator.
*
* @param plugin The plugin to disable dependency injection for.
* @param pluginServiceLocator The service locator for the plugin.
*/
public static void disable(@NotNull Plugin plugin, @NotNull ServiceLocator pluginServiceLocator) {
pluginServiceLocator.preDestroy(plugin);
pluginServiceLocator.shutdown();
}
private final PluginBinder<?> pluginBinder;
private final Plugin plugin;
private final ServiceLocator pluginServiceLocator;
private PluginInjection(
@NotNull PluginBinder<?> pluginBinder,
@NotNull ServiceLocatorFactory serviceLocatorFactory,
@NotNull ServiceLocator serverServiceLocator
) {
this.pluginBinder = pluginBinder;
plugin = pluginBinder.getPlugin();
pluginServiceLocator = serviceLocatorFactory.create(plugin.getName(), serverServiceLocator);
}
private Try<ServiceLocator> load() {
return Try.runRunnable(() -> ServiceLocatorUtilities.bind(pluginServiceLocator, pluginBinder))
.flatMap(ignored -> populatePluginServiceLocator(pluginServiceLocator, plugin));
}
@NotNull
private static Try<ServiceLocator> createServerServiceLocator(
@NotNull ServiceLocatorFactory serviceLocatorFactory,
@NotNull ServiceLocator systemServiceLocator
) {
return Try.of(() -> serviceLocatorFactory.create("server", systemServiceLocator))
.andThenTry(locator -> ServiceLocatorUtilities.bind(locator, new ServerBinder()));
}
@NotNull
private static Try<ServiceLocator> createSystemServiceLocator(
@NotNull ServiceLocatorFactory serviceLocatorFactory
) {
ServiceLocator serviceLocator = serviceLocatorFactory.create("system");
return Try.of(() -> serviceLocator.getService(DynamicConfigurationService.class))
.mapTry(dynamicConfigurationService -> {
dynamicConfigurationService.getPopulator().populate();
return serviceLocator;
});
}
@NotNull
private static Try<ServiceLocator> populatePluginServiceLocator(
@NotNull ServiceLocator serviceLocator,
@NotNull Plugin plugin
) {
return Try.of(() -> serviceLocator.getService(DynamicConfigurationService.class))
.mapTry(dynamicConfigurationService -> {
dynamicConfigurationService
.getPopulator()
.populate(new ClasspathDescriptorFileFinder(
plugin.getClass().getClassLoader(),
plugin.getName()));
return serviceLocator;
});
}
}
@@ -0,0 +1,22 @@
package com.onarandombox.MultiverseCore.inject.binder;
import org.bukkit.plugin.java.JavaPlugin;
import org.glassfish.hk2.utilities.binding.ScopedBindingBuilder;
import org.jetbrains.annotations.NotNull;
/**
* A base class for java plugin binders. Binds the plugin to the {@link JavaPlugin} interface.
*
* @param <T> The type of the plugin.
*/
public abstract class JavaPluginBinder<T extends JavaPlugin> extends PluginBinder<T> {
protected JavaPluginBinder(@NotNull T plugin) {
super(plugin);
}
@Override
protected ScopedBindingBuilder<T> bindPluginClass(ScopedBindingBuilder<T> bindingBuilder) {
return bindingBuilder.to(JavaPlugin.class);
}
}
@@ -0,0 +1,41 @@
package com.onarandombox.MultiverseCore.inject.binder;
import org.bukkit.plugin.Plugin;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.hk2.utilities.binding.ScopedBindingBuilder;
import org.jetbrains.annotations.NotNull;
import java.util.logging.Logger;
/**
* The base class for all plugin binders. Initiates the binding of the plugin instance and initially binds it to the
* {@link Plugin} interface.
*
* @param <T> The type of the plugin.
*/
public abstract class PluginBinder<T extends Plugin> extends AbstractBinder {
private final T plugin;
protected PluginBinder(@NotNull T plugin) {
this.plugin = plugin;
}
@NotNull
public T getPlugin() {
return plugin;
}
@Override
protected final void configure() {
var bindingBuilder = bindPlugin(getPlugin());
bindingBuilder.to(Plugin.class);
bind(plugin.getLogger()).to(Logger.class);
}
private ScopedBindingBuilder<T> bindPlugin(T plugin) {
return bind(plugin);
}
protected abstract ScopedBindingBuilder<T> bindPluginClass(ScopedBindingBuilder<T> bindingBuilder);
}
@@ -0,0 +1,18 @@
package com.onarandombox.MultiverseCore.inject.binder;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.plugin.PluginManager;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
/**
* Binds the Bukkit {@link Server} and it's associated services we make use of in Multiverse.
*/
public class ServerBinder extends AbstractBinder {
@Override
protected void configure() {
bind(Bukkit.getServer()).to(Server.class);
bind(Bukkit.getPluginManager()).to(PluginManager.class);
}
}
@@ -1,25 +1,33 @@
package com.onarandombox.MultiverseCore.listeners;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.config.MVCoreConfig;
import com.onarandombox.MultiverseCore.inject.InjectableListener;
import jakarta.inject.Inject;
import org.bukkit.ChatColor;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.jvnet.hk2.annotations.Service;
/**
* Multiverse's {@link org.bukkit.event.Listener} for players.
* Multiverse's Listener for players.
*/
public class MVChatListener implements Listener {
private final MultiverseCore plugin;
@Service
public class MVChatListener implements InjectableListener {
private final MVCoreConfig config;
private final MVWorldManager worldManager;
private final MVPlayerListener playerListener;
public MVChatListener(MultiverseCore plugin, MVPlayerListener playerListener) {
this.plugin = plugin;
this.worldManager = plugin.getMVWorldManager();
@Inject
public MVChatListener(
MVCoreConfig config,
MVWorldManager worldManager,
MVPlayerListener playerListener
) {
this.config = config;
this.worldManager = worldManager;
this.playerListener = playerListener;
}
@@ -34,7 +42,7 @@ public class MVChatListener implements Listener {
}
// Check whether the Server is set to prefix the chat with the World name.
// If not we do nothing, if so we need to check if the World has an Alias.
if (plugin.getMVConfig().getPrefixChat()) {
if (config.isEnablePrefixChat()) {
String world = playerListener.getPlayerWorld().get(event.getPlayer().getName());
if (world == null) {
world = event.getPlayer().getWorld().getName();
@@ -52,7 +60,7 @@ public class MVChatListener implements Listener {
prefix = mvworld.getColoredWorldString();
String chat = event.getFormat();
String prefixChatFormat = plugin.getMVConfig().getPrefixChatFormat();
String prefixChatFormat = config.getPrefixChatFormat();
prefixChatFormat = prefixChatFormat.replace("%world%", prefix).replace("%chat%", chat);
prefixChatFormat = ChatColor.translateAlternateColorCodes('&', prefixChatFormat);
@@ -8,9 +8,12 @@
package com.onarandombox.MultiverseCore.listeners;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.api.WorldPurger;
import com.onarandombox.MultiverseCore.config.MVCoreConfig;
import com.onarandombox.MultiverseCore.inject.InjectableListener;
import jakarta.inject.Inject;
import org.bukkit.World;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
@@ -22,17 +25,27 @@ import org.bukkit.event.entity.EntityPortalEvent;
import org.bukkit.event.entity.EntityRegainHealthEvent;
import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason;
import org.bukkit.event.entity.FoodLevelChangeEvent;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
/**
* Multiverse's Entity {@link Listener}.
*/
public class MVEntityListener implements Listener {
private MultiverseCore plugin;
private MVWorldManager worldManager;
@Service
public class MVEntityListener implements InjectableListener {
private final MVCoreConfig config;
private final MVWorldManager worldManager;
private final WorldPurger worldPurger;
public MVEntityListener(MultiverseCore plugin) {
this.plugin = plugin;
this.worldManager = plugin.getMVWorldManager();
@Inject
public MVEntityListener(
@NotNull MVCoreConfig config,
@NotNull MVWorldManager worldManager,
@NotNull WorldPurger worldPurger
) {
this.config = config;
this.worldManager = worldManager;
this.worldPurger = worldPurger;
}
/**
@@ -46,7 +59,7 @@ public class MVEntityListener implements Listener {
}
if (event.getEntity() instanceof Player) {
Player p = (Player) event.getEntity();
MVWorld w = this.plugin.getMVWorldManager().getMVWorld(p.getWorld().getName());
MVWorld w = this.worldManager.getMVWorld(p.getWorld().getName());
if (w != null && !w.getHunger()) {
// If the world has hunger set to false, do not let the level go down
if (event.getFoodLevel() < ((Player) event.getEntity()).getFoodLevel()) {
@@ -103,7 +116,7 @@ public class MVEntityListener implements Listener {
}
MVWorld mvworld = this.worldManager.getMVWorld(world.getName());
event.setCancelled(this.plugin.getMVWorldManager().getTheWorldPurger().shouldWeKillThisCreature(mvworld, event.getEntity()));
event.setCancelled(this.worldPurger.shouldWeKillThisCreature(mvworld, event.getEntity()));
}
/**
@@ -115,8 +128,8 @@ public class MVEntityListener implements Listener {
if (event.isCancelled() || event.getTo() == null) {
return;
}
if (!this.plugin.getMVConfig().isUsingDefaultPortalSearch()) {
event.setSearchRadius(this.plugin.getMVConfig().getPortalSearchRadius());
if (!config.isUsingCustomPortalSearch()) {
event.setSearchRadius(config.getCustomPortalSearchRadius());
}
}
}
@@ -8,43 +8,82 @@
package com.onarandombox.MultiverseCore.listeners;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.api.SafeTTeleporter;
import com.onarandombox.MultiverseCore.config.MVCoreConfig;
import com.onarandombox.MultiverseCore.event.MVRespawnEvent;
import com.onarandombox.MultiverseCore.inject.InjectableListener;
import com.onarandombox.MultiverseCore.teleportation.TeleportQueue;
import com.onarandombox.MultiverseCore.utils.MVPermissions;
import com.onarandombox.MultiverseCore.utils.PermissionTools;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerPortalEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.plugin.Plugin;
import org.jvnet.hk2.annotations.Service;
/**
* Multiverse's {@link Listener} for players.
* Multiverse's Listener for players.
*/
public class MVPlayerListener implements Listener {
private final MultiverseCore plugin;
private final MVWorldManager worldManager;
@Service
public class MVPlayerListener implements InjectableListener {
private final Plugin plugin;
private final MVCoreConfig config;
private final Provider<MVWorldManager> worldManagerProvider;
private final PermissionTools pt;
private final Provider<MVPermissions> mvPermsProvider;
private final SafeTTeleporter safeTTeleporter;
private final Server server;
private final TeleportQueue teleportQueue;
private final Map<String, String> playerWorld = new ConcurrentHashMap<String, String>();
public MVPlayerListener(MultiverseCore plugin) {
@Inject
public MVPlayerListener(
MultiverseCore plugin,
MVCoreConfig config,
Provider<MVWorldManager> worldManagerProvider,
PermissionTools permissionTools,
Provider<MVPermissions> mvPermsProvider,
SafeTTeleporter safeTTeleporter,
Server server,
TeleportQueue teleportQueue
) {
this.plugin = plugin;
worldManager = plugin.getMVWorldManager();
pt = new PermissionTools(plugin);
this.config = config;
this.worldManagerProvider = worldManagerProvider;
this.pt = permissionTools;
this.mvPermsProvider = mvPermsProvider;
this.safeTTeleporter = safeTTeleporter;
this.server = server;
this.teleportQueue = teleportQueue;
}
private MVWorldManager getWorldManager() {
return worldManagerProvider.get();
}
private MVPermissions getMVPerms() {
return mvPermsProvider.get();
}
/**
@@ -61,7 +100,7 @@ public class MVPlayerListener implements Listener {
@EventHandler(priority = EventPriority.LOW)
public void playerRespawn(PlayerRespawnEvent event) {
World world = event.getPlayer().getWorld();
MVWorld mvWorld = this.worldManager.getMVWorld(world.getName());
MVWorld mvWorld = getWorldManager().getMVWorld(world.getName());
// If it's not a World MV manages we stop.
if (mvWorld == null) {
return;
@@ -74,8 +113,8 @@ public class MVPlayerListener implements Listener {
// Get the instance of the World the player should respawn at.
MVWorld respawnWorld = null;
if (this.worldManager.isMVWorld(mvWorld.getRespawnToWorld())) {
respawnWorld = this.worldManager.getMVWorld(mvWorld.getRespawnToWorld());
if (getWorldManager().isMVWorld(mvWorld.getRespawnToWorld())) {
respawnWorld = getWorldManager().getMVWorld(mvWorld.getRespawnToWorld());
}
// If it's null then it either means the World doesn't exist or the value is blank, so we don't handle it.
@@ -87,12 +126,12 @@ public class MVPlayerListener implements Listener {
Location respawnLocation = getMostAccurateRespawnLocation(world);
MVRespawnEvent respawnEvent = new MVRespawnEvent(respawnLocation, event.getPlayer(), "compatability");
this.plugin.getServer().getPluginManager().callEvent(respawnEvent);
this.server.getPluginManager().callEvent(respawnEvent);
event.setRespawnLocation(respawnEvent.getPlayersRespawnLocation());
}
private Location getMostAccurateRespawnLocation(World w) {
MVWorld mvw = this.worldManager.getMVWorld(w.getName());
MVWorld mvw = getWorldManager().getMVWorld(w.getName());
if (mvw != null) {
return mvw.getSpawnLocation();
}
@@ -108,16 +147,16 @@ public class MVPlayerListener implements Listener {
Player p = event.getPlayer();
if (!p.hasPlayedBefore()) {
Logging.finer("Player joined for the FIRST time!");
if (plugin.getMVConfig().getFirstSpawnOverride()) {
if (config.getFirstSpawnOverride()) {
Logging.fine("Moving NEW player to(firstspawnoverride): "
+ worldManager.getFirstSpawnWorld().getSpawnLocation());
+ getWorldManager().getFirstSpawnWorld().getSpawnLocation());
this.sendPlayerToDefaultWorld(p);
}
return;
} else {
Logging.finer("Player joined AGAIN!");
if (this.plugin.getMVConfig().getEnforceAccess() // check this only if we're enforcing access!
&& !this.plugin.getMVPerms().hasPermission(p, "multiverse.access." + p.getWorld().getName(), false)) {
if (config.getEnforceAccess() // check this only if we're enforcing access!
&& !this.getMVPerms().hasPermission(p, "multiverse.access." + p.getWorld().getName(), false)) {
p.sendMessage("[MV] - Sorry you can't be in this world anymore!");
this.sendPlayerToDefaultWorld(p);
}
@@ -151,19 +190,19 @@ public class MVPlayerListener implements Listener {
}
Player teleportee = event.getPlayer();
CommandSender teleporter = null;
String teleporterName = MultiverseCore.getPlayerTeleporter(teleportee.getName());
if (teleporterName != null) {
Optional<String> teleporterName = teleportQueue.popFromQueue(teleportee.getName());
if (teleporterName.isPresent()) {
if (teleporterName.equals("CONSOLE")) {
Logging.finer("We know the teleporter is the console! Magical!");
teleporter = this.plugin.getServer().getConsoleSender();
teleporter = this.server.getConsoleSender();
} else {
teleporter = this.plugin.getServer().getPlayerExact(teleporterName);
teleporter = this.server.getPlayerExact(teleporterName.get());
}
}
Logging.finer("Inferred sender '" + teleporter + "' from name '"
+ teleporterName + "', fetched from name '" + teleportee.getName() + "'");
MVWorld fromWorld = this.worldManager.getMVWorld(event.getFrom().getWorld().getName());
MVWorld toWorld = this.worldManager.getMVWorld(event.getTo().getWorld().getName());
MVWorld fromWorld = getWorldManager().getMVWorld(event.getFrom().getWorld().getName());
MVWorld toWorld = getWorldManager().getMVWorld(event.getTo().getWorld().getName());
if (toWorld == null) {
Logging.fine("Player '" + teleportee.getName() + "' is teleporting to world '"
+ event.getTo().getWorld().getName() + "' which is not managed by Multiverse-Core. No further "
@@ -188,7 +227,7 @@ public class MVPlayerListener implements Listener {
}
// Check if player is allowed to enter the world if we're enforcing permissions
if (plugin.getMVConfig().getEnforceAccess()) {
if (config.getEnforceAccess()) {
event.setCancelled(!pt.playerCanGoFromTo(fromWorld, toWorld, teleporter, teleportee));
if (event.isCancelled() && teleporter != null) {
Logging.fine("Player '" + teleportee.getName()
@@ -241,7 +280,7 @@ public class MVPlayerListener implements Listener {
// REMEMBER! getTo MAY be NULL HERE!!!
// If the player was actually outside of the portal, adjust the from location
if (event.getFrom().getWorld().getBlockAt(event.getFrom()).getType() != Material.NETHER_PORTAL) {
Location newloc = this.plugin.getSafeTTeleporter().findPortalBlockNextTo(event.getFrom());
Location newloc = this.safeTTeleporter.findPortalBlockNextTo(event.getFrom());
// TODO: Fix this. Currently, we only check for PORTAL blocks. I'll have to figure out what
// TODO: we want to do here.
if (newloc != null) {
@@ -266,8 +305,8 @@ public class MVPlayerListener implements Listener {
if (event.getTo() == null) {
return;
}
MVWorld fromWorld = this.worldManager.getMVWorld(event.getFrom().getWorld().getName());
MVWorld toWorld = this.worldManager.getMVWorld(event.getTo().getWorld().getName());
MVWorld fromWorld = getWorldManager().getMVWorld(event.getFrom().getWorld().getName());
MVWorld toWorld = getWorldManager().getMVWorld(event.getTo().getWorld().getName());
if (event.getFrom().getWorld().equals(event.getTo().getWorld())) {
// The player is Portaling to the same world.
Logging.finer("Player '" + event.getPlayer().getName() + "' is portaling to the same world.");
@@ -280,7 +319,7 @@ public class MVPlayerListener implements Listener {
+ "' because they don't have the FUNDS required to enter.");
return;
}
if (plugin.getMVConfig().getEnforceAccess()) {
if (config.getEnforceAccess()) {
event.setCancelled(!pt.playerCanGoFromTo(fromWorld, toWorld, event.getPlayer(), event.getPlayer()));
if (event.isCancelled()) {
Logging.fine("Player '" + event.getPlayer().getName()
@@ -292,18 +331,18 @@ public class MVPlayerListener implements Listener {
+ "' was allowed to go to '" + event.getTo().getWorld().getName()
+ "' because enforceaccess is off.");
}
if (!this.plugin.getMVConfig().isUsingDefaultPortalSearch()) {
event.setSearchRadius(this.plugin.getMVConfig().getPortalSearchRadius());
if (!config.isUsingCustomPortalSearch()) {
event.setSearchRadius(config.getCustomPortalSearchRadius());
}
}
private void sendPlayerToDefaultWorld(final Player player) {
// Remove the player 1 tick after the login. I'm sure there's GOT to be a better way to do this...
this.plugin.getServer().getScheduler().scheduleSyncDelayedTask(this.plugin,
this.server.getScheduler().scheduleSyncDelayedTask(this.plugin,
new Runnable() {
@Override
public void run() {
player.teleport(plugin.getMVWorldManager().getFirstSpawnWorld().getSpawnLocation());
player.teleport(getWorldManager().getFirstSpawnWorld().getSpawnLocation());
}
}, 1L);
}
@@ -311,7 +350,7 @@ public class MVPlayerListener implements Listener {
// FOLLOWING 2 Methods and Private class handle Per Player GameModes.
private void handleGameModeAndFlight(Player player, World world) {
MVWorld mvWorld = this.worldManager.getMVWorld(world.getName());
MVWorld mvWorld = getWorldManager().getMVWorld(world.getName());
if (mvWorld != null) {
this.handleGameModeAndFlight(player, mvWorld);
} else {
@@ -328,7 +367,7 @@ public class MVPlayerListener implements Listener {
public void handleGameModeAndFlight(final Player player, final MVWorld world) {
// We perform this task one tick later to MAKE SURE that the player actually reaches the
// destination world, otherwise we'd be changing the player mode if they havent moved anywhere.
this.plugin.getServer().getScheduler().scheduleSyncDelayedTask(this.plugin,
this.server.getScheduler().scheduleSyncDelayedTask(this.plugin,
new Runnable() {
@Override
public void run() {
@@ -8,26 +8,30 @@
package com.onarandombox.MultiverseCore.listeners;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.inject.InjectableListener;
import jakarta.inject.Inject;
import org.bukkit.Material;
import org.bukkit.PortalType;
import org.bukkit.block.BlockState;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.world.PortalCreateEvent;
import org.jvnet.hk2.annotations.Service;
/**
* A custom listener for portal related events.
*/
public class MVPortalListener implements Listener {
@Service
public class MVPortalListener implements InjectableListener {
private MultiverseCore plugin;
private MVWorldManager worldManager;
public MVPortalListener(MultiverseCore core) {
this.plugin = core;
@Inject
public MVPortalListener(MVWorldManager worldManager) {
this.worldManager = worldManager;
}
/**
@@ -38,7 +42,7 @@ public class MVPortalListener implements Listener {
public void portalForm(PortalCreateEvent event) {
Logging.fine("Attempting to create portal at '%s' with reason: %s", event.getWorld().getName(), event.getReason());
MVWorld world = this.plugin.getMVWorldManager().getMVWorld(event.getWorld());
MVWorld world = this.worldManager.getMVWorld(event.getWorld());
if (world == null) {
Logging.fine("World '%s' is not managed by Multiverse! Ignoring at PortalCreateEvent.", event.getWorld().getName());
return;
@@ -94,7 +98,7 @@ public class MVPortalListener implements Listener {
return;
}
MVWorld world = this.plugin.getMVWorldManager().getMVWorld(event.getPlayer().getWorld());
MVWorld world = this.worldManager.getMVWorld(event.getPlayer().getWorld());
if (world == null) {
Logging.fine("World '%s' is not managed by Multiverse! Ignoring at PlayerInteractEvent.",
event.getPlayer().getWorld().getName());
@@ -7,21 +7,26 @@
package com.onarandombox.MultiverseCore.listeners;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.inject.InjectableListener;
import jakarta.inject.Inject;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.weather.ThunderChangeEvent;
import org.bukkit.event.weather.WeatherChangeEvent;
import org.jvnet.hk2.annotations.Service;
/**
* Multiverse's Weather {@link Listener}.
* Multiverse's Weather Listener.
*/
public class MVWeatherListener implements Listener {
private MultiverseCore plugin;
@Service
public class MVWeatherListener implements InjectableListener {
public MVWeatherListener(MultiverseCore plugin) {
this.plugin = plugin;
private MVWorldManager worldManager;
@Inject
public MVWeatherListener(MVWorldManager worldManager) {
this.worldManager = worldManager;
}
/**
@@ -33,7 +38,7 @@ public class MVWeatherListener implements Listener {
if (event.isCancelled()) {
return;
}
MVWorld world = this.plugin.getMVWorldManager().getMVWorld(event.getWorld().getName());
MVWorld world = this.worldManager.getMVWorld(event.getWorld().getName());
if (world != null) {
// If it's going to start raining and we have weather disabled
event.setCancelled((event.toWeatherState() && !world.isWeatherEnabled()));
@@ -49,7 +54,7 @@ public class MVWeatherListener implements Listener {
if (event.isCancelled()) {
return;
}
MVWorld world = this.plugin.getMVWorldManager().getMVWorld(event.getWorld().getName());
MVWorld world = this.worldManager.getMVWorld(event.getWorld().getName());
if (world != null) {
// If it's going to start raining and we have weather disabled
event.setCancelled((event.toThunderState() && !world.isWeatherEnabled()));
@@ -7,22 +7,26 @@
package com.onarandombox.MultiverseCore.listeners;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.inject.InjectableListener;
import jakarta.inject.Inject;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.world.WorldInitEvent;
import org.jvnet.hk2.annotations.Service;
public class MVWorldInitListener implements Listener {
@Service
public class MVWorldInitListener implements InjectableListener {
MultiverseCore plugin;
private final MVWorldManager worldManager;
public MVWorldInitListener(MultiverseCore plugin) {
this.plugin = plugin;
@Inject
public MVWorldInitListener(MVWorldManager worldManager) {
this.worldManager = worldManager;
}
@EventHandler
public void initWorld(WorldInitEvent event) {
if (!plugin.getMVWorldManager().isKeepingSpawnInMemory(event.getWorld())) {
if (!worldManager.isKeepingSpawnInMemory(event.getWorld())) {
event.getWorld().setKeepSpawnInMemory(false);
}
}
@@ -7,25 +7,27 @@
package com.onarandombox.MultiverseCore.listeners;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.inject.InjectableListener;
import jakarta.inject.Inject;
import org.bukkit.World;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.event.world.WorldUnloadEvent;
import org.jvnet.hk2.annotations.Service;
/**
* Multiverse's World {@link Listener}.
* Multiverse's World Listener.
*/
public class MVWorldListener implements Listener {
private MultiverseCore plugin;
@Service
public class MVWorldListener implements InjectableListener {
private MVWorldManager worldManager;
public MVWorldListener(MultiverseCore plugin) {
this.plugin = plugin;
this.worldManager = plugin.getMVWorldManager();
@Inject
public MVWorldListener(MVWorldManager worldManager) {
this.worldManager = worldManager;
}
/**
@@ -40,7 +42,7 @@ public class MVWorldListener implements Listener {
if (event.getWorld() instanceof World) {
World world = (World) event.getWorld();
if (world != null) {
this.plugin.getMVWorldManager().unloadWorld(world.getName(), false);
this.worldManager.unloadWorld(world.getName(), false);
}
}
}
@@ -53,10 +55,10 @@ public class MVWorldListener implements Listener {
public void loadWorld(WorldLoadEvent event) {
World world = event.getWorld();
if (world != null) {
if (this.plugin.getMVWorldManager().getUnloadedWorlds().contains(world.getName())) {
this.plugin.getMVWorldManager().loadWorld(world.getName());
if (this.worldManager.getUnloadedWorlds().contains(world.getName())) {
this.worldManager.loadWorld(world.getName());
}
MVWorld mvWorld = plugin.getMVWorldManager().getMVWorld(world);
MVWorld mvWorld = worldManager.getMVWorld(world);
if (mvWorld != null) {
// This is where we can temporarily fix those pesky property issues!
world.setPVP(mvWorld.isPVPEnabled());
@@ -14,13 +14,13 @@ import com.onarandombox.MultiverseCore.event.MVTeleportEvent;
import com.onarandombox.MultiverseCore.event.MVVersionEvent;
import com.onarandombox.MultiverseCore.event.MVWorldDeleteEvent;
import com.onarandombox.MultiverseCore.event.MVWorldPropertyChangeEvent;
import com.onarandombox.MultiverseCore.inject.InjectableListener;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
/**
* Subclasses of this listener can be used to conveniently listen to MultiverseCore-events.
*/
public abstract class MultiverseCoreListener implements Listener {
public abstract class MultiverseCoreListener implements InjectableListener {
/**
* Called when a {@link MVWorldPropertyChangeEvent} is fired.
* @param event The event.
@@ -1,29 +0,0 @@
package com.onarandombox.MultiverseCore.locale;
import co.aikar.locales.MessageKey;
import co.aikar.locales.MessageKeyProvider;
public enum MVCorei18n implements MessageKeyProvider {
CONFIG_SAVE_FAILED,
CREATE_PROPERTIES,
CREATE_PROPERTIES_ENVIRONMENT,
CREATE_PROPERTIES_SEED,
CREATE_PROPERTIES_WORLDTYPE,
CREATE_PROPERTIES_ADJUSTSPAWN,
CREATE_PROPERTIES_GENERATOR,
CREATE_PROPERTIES_STRUCTURES,
CREATE_LOADING,
CREATE_FAILED,
CREATE_SUCCESS,
DEBUG_INFO_OFF,
DEBUG_INFO_ON;
private final MessageKey key = MessageKey.of("mv-core." + this.name().replace('_', '.').toLowerCase());
@Override
public MessageKey getMessageKey() {
return this.key;
}
}
@@ -1,4 +0,0 @@
/**
* This package contains all the locale reference for Multiverse-Core.
*/
package com.onarandombox.MultiverseCore.locale;
@@ -0,0 +1,166 @@
package com.onarandombox.MultiverseCore.placeholders;
import java.util.Optional;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.economy.MVEconomist;
import jakarta.annotation.PostConstruct;
import jakarta.inject.Inject;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jvnet.hk2.annotations.Service;
@Service
public class MultiverseCorePlaceholders extends PlaceholderExpansion {
private final MultiverseCore plugin;
private final MVWorldManager worldManager;
private final MVEconomist economist;
@Inject
public MultiverseCorePlaceholders(MultiverseCore plugin, MVWorldManager worldManager, MVEconomist economist) {
this.plugin = plugin;
this.worldManager = worldManager;
this.economist = economist;
}
@PostConstruct
@Override
public boolean register() {
return super.register();
}
@Override
public @NotNull String getIdentifier() {
return "multiverse-core";
}
@Override
public @NotNull String getAuthor() {
return plugin.getAuthors();
}
@Override
public @NotNull String getVersion() {
return plugin.getDescription().getVersion();
}
@Override
public boolean persist() {
return true;
}
/**
* Placeholder implementation, format: %multiverse-core_&lt;placeholder&gt;_[world]% world is optional.
*
* @param offlinePlayer Player to get the placeholder for
* @param params Placeholder to get
* @return Placeholder value
*/
@Override
public @Nullable String onRequest(OfflinePlayer offlinePlayer, @NotNull String params) {
// Split string in to an Array with underscores
String[] paramsArray = params.split("_", 2);
// No placeholder defined
if (paramsArray.length < 1) {
warning("No placeholder defined");
return null;
}
final var placeholder = paramsArray[0];
Optional<MVWorld> targetWorld;
// If no world is defined, use the player's world
if (paramsArray.length == 1) {
if (!offlinePlayer.isOnline()) {
return null;
}
targetWorld = Optional.ofNullable(worldManager.getMVWorld(((Player)offlinePlayer).getWorld()));
} else {
targetWorld = Optional.ofNullable(worldManager.getMVWorld(paramsArray[1]));
}
// Fail if world is null
return targetWorld.map(world -> getWorldPlaceHolderValue(placeholder, world))
.orElse(null);
}
private @Nullable String getWorldPlaceHolderValue(@NotNull String placeholder, @NotNull MVWorld world) {
// Switch to find what specific placeholder we want
switch (placeholder.toLowerCase()) {
case "alias" -> {
return world.getColoredWorldString();
}
case "animalspawn" -> {
return String.valueOf(world.canAnimalsSpawn());
}
case "autoheal" -> {
return String.valueOf(world.getAutoHeal());
}
case "blacklist" -> {
return String.join(", ", world.getWorldBlacklist());
}
case "currency" -> {
return String.valueOf(world.getCurrency());
}
case "difficulty" -> {
return world.getDifficulty().toString();
}
case "entryfee" -> {
return economist.formatPrice(world.getPrice(), world.getCurrency());
}
case "environment" -> {
return world.getEnvironment().toString().toLowerCase();
}
case "flight" -> {
return String.valueOf(world.getAllowFlight());
}
case "gamemode" -> {
return world.getGameMode().toString().toLowerCase();
}
case "generator" -> {
return world.getGenerator();
}
case "hunger" -> {
return String.valueOf(world.getHunger());
}
case "monstersspawn" -> {
return String.valueOf(world.canMonstersSpawn());
}
case "name" -> {
return world.getName();
}
case "playerlimit" -> {
return String.valueOf(world.getPlayerLimit());
}
case "price" -> {
return String.valueOf(world.getPrice());
}
case "pvp" -> {
return String.valueOf(world.isPVPEnabled());
}
case "seed" -> {
return String.valueOf(world.getSeed());
}
case "time" -> {
return world.getTime();
}
case "type" -> {
return world.getWorldType().toString().toLowerCase();
}
case "weather" -> {
return String.valueOf(world.isWeatherEnabled());
}
default -> {
warning("Unknown placeholder: " + placeholder);
return null;
}
}
}
}
@@ -9,7 +9,8 @@ package com.onarandombox.MultiverseCore.teleportation;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.api.BlockSafety;
import com.onarandombox.MultiverseCore.api.MVCore;
import com.onarandombox.MultiverseCore.api.LocationManipulation;
import jakarta.inject.Inject;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
@@ -18,6 +19,7 @@ import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.Bed;
import org.bukkit.entity.Minecart;
import org.bukkit.entity.Vehicle;
import org.jvnet.hk2.annotations.Service;
import java.util.EnumSet;
import java.util.Iterator;
@@ -26,8 +28,9 @@ import java.util.Set;
/**
* The default-implementation of {@link BlockSafety}.
*/
@Service
public class SimpleBlockSafety implements BlockSafety {
private final MVCore plugin;
private final LocationManipulation locationManipulation;
private static final Set<BlockFace> AROUND_BLOCK = EnumSet.noneOf(BlockFace.class);
static {
@@ -41,8 +44,9 @@ public class SimpleBlockSafety implements BlockSafety {
AROUND_BLOCK.add(BlockFace.NORTH_WEST);
}
public SimpleBlockSafety(MVCore plugin) {
this.plugin = plugin;
@Inject
public SimpleBlockSafety(LocationManipulation locationManipulation) {
this.locationManipulation = locationManipulation;
}
/**
@@ -248,7 +252,7 @@ public class SimpleBlockSafety implements BlockSafety {
if (this.isBlockAboveAir(cart.getLocation())) {
return true;
}
if (this.isEntitiyOnTrack(plugin.getLocationManipulation().getNextBlock(cart))) {
if (this.isEntitiyOnTrack(locationManipulation.getNextBlock(cart))) {
return true;
}
return false;
@@ -15,6 +15,7 @@ import org.bukkit.entity.Vehicle;
import org.bukkit.util.Vector;
import com.onarandombox.MultiverseCore.api.LocationManipulation;
import org.jvnet.hk2.annotations.Service;
import java.text.DecimalFormat;
import java.util.Collections;
@@ -25,6 +26,7 @@ import java.util.Map;
/**
* The default-implementation of {@link LocationManipulation}.
*/
@Service
public class SimpleLocationManipulation implements LocationManipulation {
private static final Map<String, Integer> ORIENTATION_INTS;
@@ -7,12 +7,18 @@
package com.onarandombox.MultiverseCore.teleportation;
import java.util.concurrent.CompletableFuture;
import co.aikar.commands.BukkitCommandIssuer;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.BlockSafety;
import com.onarandombox.MultiverseCore.api.DestinationInstance;
import com.onarandombox.MultiverseCore.api.LocationManipulation;
import com.onarandombox.MultiverseCore.api.SafeTTeleporter;
import com.onarandombox.MultiverseCore.destination.ParsedDestination;
import io.papermc.lib.PaperLib;
import jakarta.inject.Inject;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
@@ -24,15 +30,29 @@ import org.bukkit.entity.Minecart;
import org.bukkit.entity.Player;
import org.bukkit.entity.Vehicle;
import org.bukkit.util.Vector;
import org.jvnet.hk2.annotations.Service;
/**
* The default-implementation of {@link SafeTTeleporter}.
*/
@Service
public class SimpleSafeTTeleporter implements SafeTTeleporter {
private MultiverseCore plugin;
private final MultiverseCore plugin;
private final LocationManipulation locationManipulation;
private final BlockSafety blockSafety;
private final TeleportQueue teleportQueue;
public SimpleSafeTTeleporter(MultiverseCore plugin) {
@Inject
public SimpleSafeTTeleporter(
MultiverseCore plugin,
LocationManipulation locationManipulation,
BlockSafety blockSafety,
TeleportQueue teleportQueue
) {
this.plugin = plugin;
this.locationManipulation = locationManipulation;
this.blockSafety = blockSafety;
this.teleportQueue = teleportQueue;
}
private static final Vector DEFAULT_VECTOR = new Vector();
@@ -58,7 +78,7 @@ public class SimpleSafeTTeleporter implements SafeTTeleporter {
if (safe != null) {
safe.setX(safe.getBlockX() + .5); // SUPPRESS CHECKSTYLE: MagicNumberCheck
safe.setZ(safe.getBlockZ() + .5); // SUPPRESS CHECKSTYLE: MagicNumberCheck
Logging.fine("Hey! I found one: " + plugin.getLocationManipulation().strCoordsRaw(safe));
Logging.fine("Hey! I found one: " + locationManipulation.strCoordsRaw(safe));
} else {
Logging.fine("Uh oh! No safe place found!");
}
@@ -72,7 +92,7 @@ public class SimpleSafeTTeleporter implements SafeTTeleporter {
}
// We want half of it, so we can go up and down
tolerance /= 2;
Logging.finer("Given Location of: " + plugin.getLocationManipulation().strCoordsRaw(l));
Logging.finer("Given Location of: " + locationManipulation.strCoordsRaw(l));
Logging.finer("Checking +-" + tolerance + " with a radius of " + radius);
// For now this will just do a straight up block.
@@ -140,13 +160,13 @@ public class SimpleSafeTTeleporter implements SafeTTeleporter {
// ...
int adjustedCircle = ((circle - 1) / 2);
checkLoc.add(adjustedCircle, 0, 0);
if (plugin.getBlockSafety().playerCanSpawnHereSafely(checkLoc)) {
if (blockSafety.playerCanSpawnHereSafely(checkLoc)) {
return true;
}
// Now we go to the right that adjustedCircle many
for (int i = 0; i < adjustedCircle; i++) {
checkLoc.add(0, 0, 1);
if (plugin.getBlockSafety().playerCanSpawnHereSafely(checkLoc)) {
if (blockSafety.playerCanSpawnHereSafely(checkLoc)) {
return true;
}
}
@@ -154,7 +174,7 @@ public class SimpleSafeTTeleporter implements SafeTTeleporter {
// Then down adjustedCircle *2
for (int i = 0; i < adjustedCircle * 2; i++) {
checkLoc.add(-1, 0, 0);
if (plugin.getBlockSafety().playerCanSpawnHereSafely(checkLoc)) {
if (blockSafety.playerCanSpawnHereSafely(checkLoc)) {
return true;
}
}
@@ -162,7 +182,7 @@ public class SimpleSafeTTeleporter implements SafeTTeleporter {
// Then left adjustedCircle *2
for (int i = 0; i < adjustedCircle * 2; i++) {
checkLoc.add(0, 0, -1);
if (plugin.getBlockSafety().playerCanSpawnHereSafely(checkLoc)) {
if (blockSafety.playerCanSpawnHereSafely(checkLoc)) {
return true;
}
}
@@ -170,7 +190,7 @@ public class SimpleSafeTTeleporter implements SafeTTeleporter {
// Then up Then left adjustedCircle *2
for (int i = 0; i < adjustedCircle * 2; i++) {
checkLoc.add(1, 0, 0);
if (plugin.getBlockSafety().playerCanSpawnHereSafely(checkLoc)) {
if (blockSafety.playerCanSpawnHereSafely(checkLoc)) {
return true;
}
}
@@ -178,7 +198,7 @@ public class SimpleSafeTTeleporter implements SafeTTeleporter {
// Then finish up by doing adjustedCircle - 1
for (int i = 0; i < adjustedCircle - 1; i++) {
checkLoc.add(0, 0, 1);
if (plugin.getBlockSafety().playerCanSpawnHereSafely(checkLoc)) {
if (blockSafety.playerCanSpawnHereSafely(checkLoc)) {
return true;
}
}
@@ -190,9 +210,14 @@ public class SimpleSafeTTeleporter implements SafeTTeleporter {
*/
@Override
public TeleportResult safelyTeleport(BukkitCommandIssuer teleporter, Entity teleportee, ParsedDestination<?> destination) {
return safelyTeleportAsync(teleporter, teleportee, destination).join();
}
@Override
public CompletableFuture<TeleportResult> safelyTeleportAsync(BukkitCommandIssuer teleporter, Entity teleportee, ParsedDestination<?> destination) {
if (destination == null) {
Logging.finer("Entity tried to teleport to an invalid destination");
return TeleportResult.FAIL_INVALID;
return CompletableFuture.completedFuture(TeleportResult.FAIL_INVALID);
}
Player teleporteePlayer = null;
@@ -203,10 +228,10 @@ public class SimpleSafeTTeleporter implements SafeTTeleporter {
}
if (teleporteePlayer == null) {
return TeleportResult.FAIL_INVALID;
return CompletableFuture.completedFuture(TeleportResult.FAIL_INVALID);
}
MultiverseCore.addPlayerToTeleportQueue(teleporter.getIssuer().getName(), teleporteePlayer.getName());
teleportQueue.addToQueue(teleporter.getIssuer().getName(), teleporteePlayer.getName());
Location safeLoc = destination.getLocation(teleportee);
if (destination.getDestination().checkTeleportSafety()) {
@@ -214,20 +239,26 @@ public class SimpleSafeTTeleporter implements SafeTTeleporter {
}
if (safeLoc == null) {
return TeleportResult.FAIL_UNSAFE;
return CompletableFuture.completedFuture(TeleportResult.FAIL_UNSAFE);
}
if (!teleportee.teleport(safeLoc)) {
return TeleportResult.FAIL_OTHER;
}
CompletableFuture<TeleportResult> future = new CompletableFuture<>();
Vector v = destination.getDestinationInstance().getVelocity(teleportee);
if (v != null && !DEFAULT_VECTOR.equals(v)) {
Bukkit.getScheduler().runTaskLater(this.plugin, () -> {
teleportee.setVelocity(v);
}, 1);
}
return TeleportResult.SUCCESS;
PaperLib.teleportAsync(teleportee, safeLoc).thenAccept(result -> {
if (!result) {
future.complete(TeleportResult.FAIL_OTHER);
return;
}
Vector v = destination.getDestinationInstance().getVelocity(teleportee);
if (v != null && !DEFAULT_VECTOR.equals(v)) {
Bukkit.getScheduler().runTaskLater(this.plugin, () -> {
teleportee.setVelocity(v);
}, 1);
}
future.complete(TeleportResult.SUCCESS);
});
return future;
}
/**
@@ -251,25 +282,25 @@ public class SimpleSafeTTeleporter implements SafeTTeleporter {
@Override
public Location getSafeLocation(Entity entity, DestinationInstance destination) {
Location l = destination.getLocation(entity);
if (plugin.getBlockSafety().playerCanSpawnHereSafely(l)) {
if (blockSafety.playerCanSpawnHereSafely(l)) {
Logging.fine("The first location you gave me was safe.");
return l;
}
if (entity instanceof Minecart) {
Minecart m = (Minecart) entity;
if (!plugin.getBlockSafety().canSpawnCartSafely(m)) {
if (!blockSafety.canSpawnCartSafely(m)) {
return null;
}
} else if (entity instanceof Vehicle) {
Vehicle v = (Vehicle) entity;
if (!plugin.getBlockSafety().canSpawnVehicleSafely(v)) {
if (!blockSafety.canSpawnVehicleSafely(v)) {
return null;
}
}
Location safeLocation = this.getSafeLocation(l);
if (safeLocation != null) {
// Add offset to account for a vehicle on dry land!
if (entity instanceof Minecart && !plugin.getBlockSafety().isEntitiyOnTrack(safeLocation)) {
if (entity instanceof Minecart && !blockSafety.isEntitiyOnTrack(safeLocation)) {
safeLocation.setY(safeLocation.getBlockY() + .5);
Logging.finer("Player was inside a minecart. Offsetting Y location.");
}
@@ -336,6 +367,11 @@ public class SimpleSafeTTeleporter implements SafeTTeleporter {
@Override
public TeleportResult teleport(BukkitCommandIssuer teleporter, Entity teleportee, ParsedDestination<?> destination) {
return this.safelyTeleport(teleporter, teleportee, destination);
return safelyTeleport(teleporter, teleportee, destination);
}
@Override
public CompletableFuture<TeleportResult> teleportAsync(BukkitCommandIssuer teleporter, Entity teleportee, ParsedDestination<?> destination) {
return safelyTeleportAsync(teleporter, teleportee, destination);
}
}
Loaded 100 of 139 files, more files were not shown because too many files have changed in this diff. Show more