Compare commits

..

142 Commits

Author SHA1 Message Date
Auxilor
f77fc5d182 Fixed compile bug 2022-10-02 14:24:30 +01:00
Auxilor
6d1cc4c05d Fixed buildscript comments 2022-10-02 14:19:16 +01:00
Auxilor
0775f0992f Internal refactoring, added Model Engine support as an arg parser 2022-10-02 14:12:57 +01:00
Auxilor
debb39105d Moved #getPage #getMaxPage to Menu 2022-10-02 12:20:57 +01:00
Auxilor
3b4aa59bfb Fixed startup bug 2022-10-02 12:03:29 +01:00
Auxilor
4e902c3964 Added warning to legacy MySQL 2022-10-02 02:20:58 +01:00
Auxilor
3e325697e7 Added PersistentDataKeyType#CONFIG 2022-10-02 02:17:42 +01:00
Auxilor
13b3e1e440 Cleaning up after Handler 2022-10-02 02:08:22 +01:00
Auxilor
2b2406a4d0 Deprecated PluginDependent 2022-10-02 01:57:13 +01:00
Auxilor
048982c74a Deprecated PluginDependent 2022-10-02 01:56:45 +01:00
Auxilor
29b63a2ebb Removed Handler, HandlerComponent, and all internal-only API components except Eco; huge backend rework 2022-10-02 01:52:35 +01:00
Auxilor
2a9cbdacfd Cleanup 2022-10-02 00:33:36 +01:00
Auxilor
35cfcdf4a9 Improved ConfigSlot 2022-10-02 00:30:30 +01:00
Auxilor
06c1dc9afb Fixed excludes 2022-10-01 22:34:06 +01:00
Auxilor
18b58d584f Fixes to GUI 2022-10-01 22:31:37 +01:00
Auxilor
a774791e65 Updated excludes 2022-10-01 22:26:43 +01:00
Auxilor
bc22adae84 Fixed changing item bugs with Menu, added Menu#allowsChangingHeldItem 2022-10-01 22:24:24 +01:00
Auxilor
0eba82b221 Added .toml support to config 2022-10-01 21:59:16 +01:00
Auxilor
4822ec3955 Prevented changing the held item with a menu open 2022-10-01 20:55:56 +01:00
Auxilor
b845001467 Many improvements to captive items and menus 2022-10-01 14:36:53 +01:00
Auxilor
25b6a15c9c Fixed getStringsOrNull 2022-10-01 13:11:42 +01:00
Auxilor
1a3d035f78 Revert "Fixed null lore bug with AbstractItemStackBuilder"
This reverts commit a69f9f6e11.
2022-10-01 13:02:21 +01:00
Auxilor
a69f9f6e11 Fixed null lore bug with AbstractItemStackBuilder 2022-10-01 12:55:28 +01:00
Auxilor
6efd9e4fcd Fixed MySQLDataHandler 2022-10-01 12:47:41 +01:00
Auxilor
3e948beb7a Hotfix for SnakeYaml 2022-09-30 20:05:16 +01:00
Auxilor
a8a491a0b7 Brushing over some deprecated behaviour 2022-09-30 19:59:34 +01:00
Auxilor
2c0330898c Javadoc 2022-09-30 19:57:23 +01:00
Auxilor
e9794cfbf4 Fixed OfflinePlayer#exactBalance 2022-09-30 19:54:10 +01:00
Auxilor
1694d858bc Fixed EconomyIntegration javadoc 2022-09-30 19:51:23 +01:00
Auxilor
b79955ae9e Switched EconomyIntegration to be based around BigDecimal 2022-09-30 19:49:20 +01:00
Auxilor
803a8c5d17 Fixed yaml size limit 2022-09-30 19:39:47 +01:00
Auxilor
c5cd15ad92 Merge remote-tracking branch 'origin/master' into develop 2022-09-30 15:24:43 +01:00
Auxilor
489b170888 Added lambda parameter names to GUI DSL 2022-09-30 15:17:39 +01:00
Auxilor
9f57a322e8 Added ItemStack#toSNBT extension function 2022-09-30 15:15:34 +01:00
Auxilor
86e113214d Internal refactoring 2022-09-30 15:10:10 +01:00
Auxilor
e791bb8893 Renamed signals to menu events 2022-09-30 15:04:44 +01:00
Auxilor
f1220bd186 Added dispenserMenu() to GUI DSL 2022-09-30 14:07:54 +01:00
Auxilor
21d933cb11 Added support for 3x3 menus, improved Java Page API. 2022-09-30 14:06:39 +01:00
Auxilor
e1c063d5f4 Added dynamic-size components 2022-09-30 13:29:50 +01:00
Auxilor
27d2b5c8a4 Added menu signals 2022-09-30 12:44:06 +01:00
Auxilor
3b34d6ef27 Made captivity reactive 2022-09-30 12:20:46 +01:00
Auxilor
bc1c8b8f46 Re-added MythicMobs (repo back up) 2022-09-30 12:09:20 +01:00
Auxilor
2fa926ec02 Fix 2022-09-30 12:05:09 +01:00
Auxilor
d7891e1218 Improved Page API 2022-09-29 20:17:57 +01:00
Auxilor
11685cd352 Fixed PageChanger 2022-09-29 20:04:43 +01:00
Auxilor
785127fe16 Optimized AbstractItemStackBuilder via FIS 2022-09-29 19:56:44 +01:00
Auxilor
4a13bc5fea Cleanup 2022-09-29 19:52:43 +01:00
Auxilor
c7ad122050 Minor fix 2022-09-29 19:52:25 +01:00
Auxilor
28d63fc2e3 Improved performance of menu renders 2022-09-29 19:51:33 +01:00
Auxilor
bb62cc0bcd Fixed default layer 2022-09-29 19:12:29 +01:00
Auxilor
740c79f087 Added layers to menus and fixed several bugs (and temporarily removed MythicCraft repos) 2022-09-29 19:10:02 +01:00
Auxilor
33ab8e04a0 Fixed javadoc 2022-09-29 17:35:53 +01:00
Auxilor
fcd3aac363 Updated to 6.43.0 2022-09-29 17:33:56 +01:00
Auxilor
753d148d1b Refactor 2022-09-29 17:33:45 +01:00
Auxilor
1bb47a9f13 Improved MergedStateMenu 2022-09-29 17:21:31 +01:00
Auxilor
40b4c26e0f Added menu pagination 2022-09-29 17:17:13 +01:00
Auxilor
97adae7b32 More GUI improvements, improving Slot API 2022-09-29 16:15:19 +01:00
Auxilor
3d35a91314 Major improvements to menus 2022-09-29 15:51:26 +01:00
Auxilor
0caa328b1e Overhauled GUI component-based backend to support reactive and static slots 2022-09-29 15:08:34 +01:00
Auxilor
ab8c946914 Reworked GUI backend to be component-based 2022-09-29 14:10:41 +01:00
Auxilor
e667537404 Fixed CustomSlot 2022-09-29 13:41:29 +01:00
Auxilor
6bd2f2b823 Codestyle 2022-09-29 12:54:54 +01:00
Auxilor
8d8a8045c0 Moved frontend -> backend communication to be purely via the handler 2022-09-29 09:51:43 +01:00
Auxilor
d5c669c72c Added shorthand NamespacedKey and FixedMetadataValue creation 2022-09-29 08:49:17 +01:00
Auxilor
28b268e175 Added %player% to configslot 2022-09-28 12:38:38 +01:00
Auxilor
33937d1ce7 Switched Crunch to fork 2022-09-28 11:04:59 +01:00
Auxilor
e971778cc3 Updated to 6.42.0 2022-09-28 10:47:51 +01:00
Auxilor
f99612ded3 Added CustomSlot, improved various GUI elements, added GUI components. 2022-09-28 10:47:42 +01:00
Auxilor
50272bbbcf Improved skull texture API backend 2022-09-28 08:44:16 +01:00
Auxilor
9a703f6190 One more held item slot fix 2022-09-26 14:02:20 +01:00
Auxilor
f8fec7eec4 Updated to 6.41.3 2022-09-26 13:57:50 +01:00
Auxilor
f6aadda4ed Fixed PacketHeldItemSlot 2022-09-26 13:57:39 +01:00
Auxilor
d8fca0f348 Switched KingdomsX to local jar 2022-09-26 12:52:46 +01:00
Auxilor
65ff4c4a31 PR Codestyle 2022-09-26 12:36:34 +01:00
Auxilor
90702bc7aa Merge remote-tracking branch 'origin/develop' into develop 2022-09-26 12:34:53 +01:00
Will FP
e81b788a1b Merge pull request #199 from mani1232/master
Update KingdomsX dependence
2022-09-26 12:34:46 +01:00
Auxilor
ebc0ee7940 Updated to 6.41.2 2022-09-26 12:33:25 +01:00
Auxilor
82d269daf1 Improved PacketWindowItems and DisplayFrame 2022-09-26 12:32:07 +01:00
Auxilor
9d5300d6ae Began display system fixes 2022-09-26 12:10:22 +01:00
mani1232
8870e4d6fb Update KingdomsX dependence 2022-09-25 21:26:21 +02:00
Auxilor
d826a9f71f Switched FabledSkyblock to local jar 2022-09-14 21:18:55 +01:00
Auxilor
7ec3355237 Updated to 6.41.1 2022-09-14 21:18:28 +01:00
Auxilor
e59a8cc2e6 Oops 2022-09-14 21:13:33 +01:00
Auxilor
88f974fd10 Fixed long standing bug with ItemProvider (and scyther integration) 2022-09-14 21:08:14 +01:00
Auxilor
dfe2f1361b Updated to 6.41.0 2022-09-14 13:58:10 +01:00
Auxilor
3826f9f713 Added item price API 2022-09-14 13:57:01 +01:00
Auxilor
c2d2303c91 Added scyther integration and BigDecimal economy support 2022-09-14 13:45:32 +01:00
Auxilor
b1158ceb3d Added configurable host to Paste 2022-09-12 14:39:15 +01:00
Auxilor
af4048afbe Updated to 6.40.2 2022-09-12 13:53:51 +01:00
Auxilor
fce12020d5 Fixed bug with old MySQL versions 2022-09-12 13:53:35 +01:00
Auxilor
7e37332b64 Updated to 6.40.1 2022-09-11 10:47:23 +01:00
Auxilor
52dbf9ff52 Codestyle 2022-09-11 10:47:00 +01:00
Auxilor
78b6292367 Merge remote-tracking branch 'origin/master' 2022-09-11 10:46:43 +01:00
Will FP
09705e787b Merge pull request #193
Fix DeluxeCombat and FabledSkyBlock integration
2022-09-11 10:46:44 +01:00
Auxilor
9c86069a85 Added option to disable the update checker 2022-09-11 10:45:40 +01:00
Auxilor
0a7acceb83 Updated to 6.40.0 2022-09-10 19:59:07 +01:00
Auxilor
40aa8b17dd Fixed MySQL changes 2022-09-10 19:58:57 +01:00
Auxilor
71eb386a19 Reworked MySQL data handler and data migration 2022-09-10 19:22:29 +01:00
Kapitowa
c857df2360 fix FabledSkyBlock integration for proper check 2022-09-09 14:45:33 +03:00
Kapitowa
f4fc611f3b Fix when damager with DeluxeCombat protection can cause damage 2022-09-09 05:31:54 +03:00
Auxilor
0d91324d47 Updated crunch 2022-09-06 15:26:46 +01:00
Auxilor
e9dbc3ec73 Updated crunch 2022-09-06 15:11:42 +01:00
Auxilor
493d1b1b6d Updated crunch 2022-09-06 15:11:14 +01:00
Auxilor
68221d5912 Updated crunch 2022-09-06 15:07:29 +01:00
Auxilor
7f2ef4e038 Updated to 6.39.1 2022-09-06 15:06:11 +01:00
Auxilor
be0a19175b Added additional players to config expression getters 2022-09-06 15:05:52 +01:00
Auxilor
5afdcd75f7 Added min and max functions to crunch 2022-09-06 14:49:40 +01:00
Auxilor
a1c0b8c857 Fixed FUUID 2022-09-06 13:25:17 +01:00
Auxilor
0442ccf58f Fixed FactionsUUID jar 2022-09-06 13:23:59 +01:00
Auxilor
1c1a796610 FactionsUUID to local jar 2022-09-06 13:19:49 +01:00
Auxilor
eacb243493 Fixed FactionsUUID 2022-09-06 13:17:55 +01:00
Auxilor
7bbed31d4e Fixed FactionsUUID 2022-09-06 13:17:43 +01:00
Auxilor
58bccf3cd7 Added songoda repo for FabledSkyblock 2022-09-06 13:15:36 +01:00
Auxilor
4502e1e311 Removed ender.zone, using JitPack build instead 2022-09-06 13:14:27 +01:00
Auxilor
054a8d5a5e Updated to 6.39.0 2022-09-06 13:04:55 +01:00
Auxilor
dbdd4785ba Added AdditionalPlayer support to placeholders 2022-09-06 13:04:00 +01:00
Will FP
35f800b62a Merge pull request #178
Added FabledSkyBlock integration in AntigriefManager
2022-09-06 12:50:56 +01:00
Auxilor
591800dba8 Updated to 6.38.3 2022-08-22 14:16:20 +02:00
Auxilor
46673e8d24 Fixed SNBT 2022-08-22 14:16:07 +02:00
Kapitowa
bb7c300074 fix space and fill softdepend 2022-08-02 18:46:09 +03:00
Kapitowa
b003ec96f7 Added FabledSkyBlock integration in AntigriefManager 2022-08-02 18:33:18 +03:00
Will FP
a526f51780 Update README.md 2022-07-28 16:07:08 +01:00
Auxilor
dd14fc666a Updated to 6.38.2 2022-07-27 19:42:19 +01:00
Auxilor
ae0150f012 Bumped ShopGUI+ 2022-07-27 19:42:06 +01:00
Auxilor
04418fa038 Updated ProtocolLib for compatibility 2022-07-27 19:40:08 +01:00
Auxilor
bcb9523315 Updated to 6.38.1 2022-07-25 16:51:55 +01:00
Auxilor
43e7972ca3 Improved menu re-renders 2022-07-25 16:51:38 +01:00
Auxilor
7ea61eb393 Removed source/target compatibility no longer required by kotlin 1.7.x 2022-07-22 14:08:33 +01:00
Auxilor
5245a9b1d8 Updated to 6.38.0 2022-07-22 14:05:53 +01:00
Auxilor
195932463c Added DisplayProperties to DisplayModule 2022-07-22 14:04:42 +01:00
Auxilor
3cf60a7e2c Added MenuUtils#getOpenMenu 2022-07-22 13:54:45 +01:00
Auxilor
0f9f57fca2 Merge remote-tracking branch 'origin/master' 2022-07-22 13:47:03 +01:00
Will FP
fe21616dd5 Merge pull request #161 from Syrent/master
Add MythicMobs 5.X support.
2022-07-22 13:46:53 +01:00
Auxilor
396144abaa Added Vector#isSafeVelocity 2022-07-22 13:46:08 +01:00
Auxilor
50b4fa59ab Added onOpen to menu 2022-07-22 13:42:48 +01:00
Auxilor
a6754379e8 Updated to 6.37.3 2022-07-07 22:55:03 +01:00
Auxilor
bbd0182c2a Fixed weird bug 2022-07-07 22:54:54 +01:00
Auxilor
0370e9f454 Fixed startup order 2022-07-03 16:49:26 +01:00
Auxilor
8d585b58cb Fixed initializing text 2022-07-03 16:45:44 +01:00
Auxilor
0bfbd4c036 Updated to 6.37.2 2022-07-03 16:38:32 +01:00
Auxilor
881839955e Added player health fixer 2022-07-03 16:38:21 +01:00
Syrent
8ffc5f9c0f Add MythicMobs 5.X support. 2022-06-28 08:07:05 +04:30
204 changed files with 4952 additions and 2863 deletions

View File

@@ -39,7 +39,7 @@ and many more.
# For developers
## Javadoc
The 6.27.2 Javadoc can be found [here](https://javadoc.jitpack.io/com/willfp/eco/6.27.2/javadoc/)
The 6.38.2 Javadoc can be found [here](https://javadoc.jitpack.io/com/willfp/eco/6.38.2/javadoc/)
## Plugin Information

View File

@@ -4,7 +4,7 @@ buildscript {
}
dependencies {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10")
}
}
@@ -13,7 +13,7 @@ plugins {
id("com.github.johnrengelman.shadow") version "7.1.2"
id("maven-publish")
id("java")
kotlin("jvm") version "1.6.21"
kotlin("jvm") version "1.7.10"
}
dependencies {
@@ -61,7 +61,7 @@ allprojects {
maven("https://maven.enginehub.org/repo/")
// FactionsUUID
maven("https://ci.ender.zone/plugin/repository/everything/")
//maven("https://ci.ender.zone/plugin/repository/everything/")
// NoCheatPlus
maven("https://repo.md-5.net/content/repositories/snapshots/")
@@ -81,8 +81,8 @@ allprojects {
dependencies {
// Kotlin
implementation(kotlin("stdlib", version = "1.6.21"))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.1")
implementation(kotlin("stdlib", version = "1.7.10"))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.2")
// Included in spigot jar, no need to move to implementation
compileOnly("org.jetbrains:annotations:23.0.0")
@@ -129,8 +129,6 @@ allprojects {
kotlinOptions {
jvmTarget = "17"
}
targetCompatibility = "17"
sourceCompatibility = "17"
}
shadowJar {
@@ -160,6 +158,7 @@ allprojects {
relocate("org.litote", "com.willfp.eco.libs.litote")
relocate("org.reactivestreams", "com.willfp.eco.libs.reactivestreams")
relocate("reactor.", "com.willfp.eco.libs.reactor.") // Dot in name to be safe
relocate("com.moandjiezana.toml", "com.willfp.eco.libs.toml")
/*
Kotlin and caffeine are not shaded so that they can be accessed directly by eco plugins.

View File

@@ -1,82 +1,583 @@
package com.willfp.eco.core;
import com.willfp.eco.core.config.ConfigType;
import com.willfp.eco.core.config.interfaces.Config;
import com.willfp.eco.core.config.interfaces.LoadableConfig;
import com.willfp.eco.core.config.updating.ConfigHandler;
import com.willfp.eco.core.data.ExtendedPersistentDataContainer;
import com.willfp.eco.core.data.PlayerProfile;
import com.willfp.eco.core.data.ServerProfile;
import com.willfp.eco.core.data.keys.PersistentDataKey;
import com.willfp.eco.core.drops.DropQueue;
import com.willfp.eco.core.entities.ai.EntityController;
import com.willfp.eco.core.events.EventManager;
import com.willfp.eco.core.extensions.ExtensionLoader;
import com.willfp.eco.core.factory.MetadataValueFactory;
import com.willfp.eco.core.factory.NamespacedKeyFactory;
import com.willfp.eco.core.factory.RunnableFactory;
import com.willfp.eco.core.fast.FastItemStack;
import com.willfp.eco.core.gui.menu.Menu;
import com.willfp.eco.core.gui.menu.MenuBuilder;
import com.willfp.eco.core.gui.menu.MenuType;
import com.willfp.eco.core.gui.slot.SlotBuilder;
import com.willfp.eco.core.gui.slot.functional.SlotProvider;
import com.willfp.eco.core.integrations.placeholder.PlaceholderIntegration;
import com.willfp.eco.core.items.TestableItem;
import com.willfp.eco.core.placeholder.AdditionalPlayer;
import com.willfp.eco.core.placeholder.PlaceholderInjectable;
import com.willfp.eco.core.proxy.ProxyFactory;
import com.willfp.eco.core.scheduling.Scheduler;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.NamespacedKey;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Mob;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.SkullMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Logger;
/**
* Holds the instance of the eco handler for bridging between the frontend
* Holds the instance of eco for bridging between the frontend
* and backend.
* <p>
* <strong>Do not use this in your plugins!</strong> It can and will contain
* breaking changes between minor versions and even patches, and you will create
* compatibility issues by. All parts of this have been abstracted
* into logically named API components that you can use.
*
* @see Eco#getHandler()
* @see Handler
* @see Eco#get()
*/
@ApiStatus.Internal
public final class Eco {
public interface Eco {
/**
* Instance of eco handler.
*/
@ApiStatus.Internal
private static Handler handler;
/**
* Set the handler.
* Create a scheduler.
*
* @param handler The handler.
* @param plugin The plugin.
* @return The scheduler.
*/
@ApiStatus.Internal
public static void setHandler(@NotNull final Handler handler) {
Validate.isTrue(Eco.handler == null, "Already initialized!");
Eco.handler = handler;
}
@NotNull
Scheduler createScheduler(@NotNull EcoPlugin plugin);
/**
* Get the instance of the eco handler; the bridge between the api frontend
* and the implementation backend.
* <p>
* <strong>Do not use the handler in your plugins!</strong> It can and will contain
* breaking changes between minor versions and even patches, and you will create
* compatibility issues by using the handler. All parts of the handler have been abstracted
* into logically named API components that you can use.
* <p>
* Prior to version 6.12.0, the handler was considered as an API component, but it has
* since been moved into an internal component, and in 6.17.0, the first breaking change
* was introduced to {@link com.willfp.eco.core.config.wrapper.ConfigFactory}. This means
* that any usages of the handler can now cause problems in your plugins.
* Create an event manager.
*
* @param plugin The plugin.
* @return The event manager.
*/
@NotNull
EventManager createEventManager(@NotNull EcoPlugin plugin);
/**
* Create a NamespacedKey factory.
*
* @param plugin The plugin.
* @return The factory.
*/
@NotNull
NamespacedKeyFactory createNamespacedKeyFactory(@NotNull EcoPlugin plugin);
/**
* Create a MetadataValue factory.
*
* @param plugin The plugin.
* @return The factory.
*/
@NotNull
MetadataValueFactory createMetadataValueFactory(@NotNull EcoPlugin plugin);
/**
* Create a Runnable factory.
*
* @param plugin The plugin.
* @return The factory.
*/
@NotNull
RunnableFactory createRunnableFactory(@NotNull EcoPlugin plugin);
/**
* Create an ExtensionLoader.
*
* @param plugin The plugin.
* @return The factory.
*/
@NotNull
ExtensionLoader createExtensionLoader(@NotNull EcoPlugin plugin);
/**
* Create a config handler.
*
* @param plugin The plugin.
* @return The handler.
*/
@NotNull
ConfigHandler createConfigHandler(@NotNull EcoPlugin plugin);
/**
* Create a logger.
*
* @param plugin The plugin.
* @return The logger.
*/
@NotNull
Logger createLogger(@NotNull EcoPlugin plugin);
/**
* Create a PAPI integration.
*
* @param plugin The plugin.
* @return The integration.
*/
@NotNull
PlaceholderIntegration createPAPIIntegration(@NotNull EcoPlugin plugin);
/**
* Create a proxy factory.
*
* @param plugin The plugin.
* @return The factory.
*/
@NotNull
ProxyFactory createProxyFactory(@NotNull EcoPlugin plugin);
/**
* Get eco Spigot plugin.
*
* @return The plugin.
*/
@NotNull
EcoPlugin getEcoPlugin();
/**
* Updatable config.
*
* @param configName The name of the config
* @param plugin The plugin.
* @param subDirectoryPath The subdirectory path.
* @param source The class that owns the resource.
* @param removeUnused Whether keys not present in the default config should be removed on update.
* @param type The config type.
* @param updateBlacklist Substring of keys to not add/remove keys for.
* @param requiresChangesToSave If the config must be changed in order to save the config.
* @return The config implementation.
*/
LoadableConfig createUpdatableConfig(@NotNull String configName,
@NotNull PluginLike plugin,
@NotNull String subDirectoryPath,
@NotNull Class<?> source,
boolean removeUnused,
@NotNull ConfigType type,
boolean requiresChangesToSave,
@NotNull String... updateBlacklist);
/**
* Loadable config.
*
* @param configName The name of the config
* @param plugin The plugin.
* @param subDirectoryPath The subdirectory path.
* @param source The class that owns the resource.
* @param type The config type.
* @param requiresChangesToSave If the config must be changed in order to save the config.
* @return The config implementation.
*/
LoadableConfig createLoadableConfig(@NotNull String configName,
@NotNull PluginLike plugin,
@NotNull String subDirectoryPath,
@NotNull Class<?> source,
@NotNull ConfigType type,
boolean requiresChangesToSave);
/**
* Create config.
*
* @param config The handle.
* @return The config implementation.
*/
Config wrapConfigurationSection(@NotNull ConfigurationSection config);
/**
* Create config.
*
* @param values The values.
* @param type The config type.
* @return The config implementation.
*/
Config createConfig(@NotNull Map<String, Object> values,
@NotNull ConfigType type);
/**
* Create config.
*
* @param contents The file contents.
* @param type The type.
* @return The config implementation.
*/
Config createConfig(@NotNull String contents,
@NotNull ConfigType type);
/**
* Create a Drop Queue.
*
* @param player The player.
* @return The drop queue.
*/
@NotNull
DropQueue createDropQueue(@NotNull Player player);
/**
* Create slot builder.
*
* @param provider The provider.
* @return The builder.
*/
@NotNull
SlotBuilder createSlotBuilder(@NotNull SlotProvider provider);
/**
* Create menu builder.
*
* @param rows The amount of rows.
* @param type The type.
* @return The builder.
*/
@NotNull
MenuBuilder createMenuBuilder(int rows,
@NotNull MenuType type);
/**
* Combine the state of two menus together.
*
* @param base The base menu.
* @param additional The additional state.
* @return The menu.
*/
@NotNull
Menu blendMenuState(@NotNull Menu base,
@NotNull Menu additional);
/**
* Clean up ClassLoader (etc.) to allow PlugMan support.
*
* @param plugin The plugin to clean up.
*/
void clean(@NotNull EcoPlugin plugin);
/**
* Add new plugin.
*
* @param plugin The plugin.
*/
void addNewPlugin(@NotNull EcoPlugin plugin);
/**
* Get plugin by name.
*
* @param name The name.
* @return The plugin.
*/
@Nullable
EcoPlugin getPluginByName(@NotNull String name);
/**
* Get all loaded eco plugins.
*
* @return A list of plugin names in lowercase.
*/
@NotNull
List<String> getLoadedPlugins();
/**
* Create a FastItemStack.
*
* @param itemStack The base ItemStack.
* @return The FastItemStack.
*/
@NotNull
FastItemStack createFastItemStack(@NotNull ItemStack itemStack);
/**
* Register bStats metrics.
*
* @param plugin The plugin.
*/
void registerBStats(@NotNull EcoPlugin plugin);
/**
* Get Adventure audiences.
*
* @return The audiences.
*/
@Nullable
BukkitAudiences getAdventure();
/**
* Register a persistent data key to be stored.
*
* @param key The key.
*/
void registerPersistentKey(@NotNull PersistentDataKey<?> key);
/**
* Get all registered keys.
*
* @return The keys.
*/
Set<PersistentDataKey<?>> getRegisteredPersistentDataKeys();
/**
* Get persistent data key from namespaced key.
*
* @param namespacedKey The key.
* @return The key, or null if not found.
*/
@Nullable
PersistentDataKey<?> getPersistentDataKeyFrom(@NotNull NamespacedKey namespacedKey);
/**
* Load a player profile.
*
* @param uuid The UUID.
* @return The profile.
*/
PlayerProfile loadPlayerProfile(@NotNull UUID uuid);
/**
* Load the server profile.
*
* @return The profile.
*/
ServerProfile getServerProfile();
/**
* Unload a player profile from memory.
* <p>
* This will not save the profile first.
*
* @param uuid The uuid.
*/
void unloadPlayerProfile(@NotNull UUID uuid);
/**
* Save keys for a player.
* <p>
* Can run async if using MySQL.
*
* @param uuid The uuid.
* @param keys The keys.
*/
void savePersistentDataKeysFor(@NotNull UUID uuid,
@NotNull Set<PersistentDataKey<?>> keys);
/**
* Commit all changes to the file.
* <p>
* Does nothing if using MySQL.
*/
void saveAllProfiles();
/**
* Create dummy entity - never spawned, exists purely in code.
*
* @param location The location.
* @return The entity.
*/
@NotNull
Entity createDummyEntity(@NotNull Location location);
/**
* Create a {@link NamespacedKey} quickly
* <p>
* Bypasses the constructor, allowing for the creation of invalid keys,
* therefore this is considered unsafe and should only be called after
* the key has been confirmed to be valid.
*
* @param namespace The namespace.
* @param key The key.
* @return The key.
*/
@NotNull
NamespacedKey createNamespacedKey(@NotNull String namespace,
@NotNull String key);
/**
* Return or get props for a plugin.
*
* @param existing The existing constructor props.
* @param plugin The plugin.
* @return The props.
*/
@NotNull
PluginProps getProps(@Nullable PluginProps existing,
@NotNull Class<? extends EcoPlugin> plugin);
/**
* Format a string with MiniMessage.
*
* @param message The message.
* @return The formatted string.
*/
@NotNull
String formatMiniMessage(@NotNull String message);
/**
* Create controlled entity from a mob.
*
* @param mob The mob.
* @param <T> The mob type.
* @return The controlled entity.
*/
@NotNull <T extends Mob> EntityController<T> createEntityController(@NotNull T mob);
/**
* Adapt base PDC to extended PDC.
*
* @param container The container.
* @return The extended container.
*/
@NotNull
ExtendedPersistentDataContainer adaptPdc(@NotNull PersistentDataContainer container);
/**
* Create new PDC.
*
* @return The container.
*/
@NotNull
PersistentDataContainer newPdc();
/**
* Get item from SNBT.
*
* @param snbt The NBT string.
* @return The ItemStack, or null if invalid.
*/
@Nullable
ItemStack fromSNBT(@NotNull String snbt);
/**
* Convert item to SNBT.
*
* @param itemStack The item.
* @return The NBT string.
*/
@NotNull
String toSNBT(@NotNull ItemStack itemStack);
/**
* Make TestableItem from SNBT.
*
* @param snbt The NBT string.
* @return The TestableItem.
*/
@NotNull
TestableItem testableItemFromSNBT(@NotNull String snbt);
/**
* Get the texture of a skull.
*
* @param meta The skull meta.
* @return The texture, or null if not found.
*/
@Nullable
String getSkullTexture(@NotNull SkullMeta meta);
/**
* Set the texture of a skull.
*
* @param meta The skull meta.
* @param base64 The texture.
*/
void setSkullTexture(@NotNull SkullMeta meta,
@NotNull String base64);
/**
* Get the current server TPS.
*
* @return The TPS.
*/
double getTPS();
/**
* Evaluate an expression.
*
* @param expression The expression.
* @param player The player.
* @param injectable The injectable placeholders.
* @param additionalPlayers The additional players.
* @return The value of the expression, or zero if invalid.
*/
double evaluate(@NotNull String expression,
@Nullable Player player,
@NotNull PlaceholderInjectable injectable,
@NotNull Collection<AdditionalPlayer> additionalPlayers);
/**
* Get the menu a player currently has open.
*
* @param player The player.
* @return The menu, or null if no menu open.
*/
@Nullable
Menu getOpenMenu(@NotNull Player player);
/**
* Get the instance of eco; the bridge between the api frontend
* and the implementation backend.
*
* @return The instance of eco.
*/
@ApiStatus.Internal
public static Handler getHandler() {
return handler;
static Eco get() {
return Instance.get();
}
/**
* Eco Handler components are internals, so if a class is marked as a handler component,
* then it should be treated the same as if it was marked with {@link ApiStatus.Internal}.
* <p>
* If a class is marked with {@link HandlerComponent}, <strong>Do not reference it in
* your code!</strong> It can and will contain breaking changes between minor versions and
* even patches, and you will create compatibility issues by using them.
* <p>
* Handler components should also be marked with {@link ApiStatus.Internal} in order to
* cause compiler / IDE warnings.
* Manages the internal frontend -> backend communication.
*/
@Documented
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.TYPE})
public @interface HandlerComponent {
@ApiStatus.Internal
final class Instance {
/**
* Instance of eco.
*/
@ApiStatus.Internal
private static Eco eco;
/**
* Initialize eco.
*
* @param eco The instance of eco.
*/
@ApiStatus.Internal
static void set(@NotNull final Eco eco) {
Validate.isTrue(Instance.eco == null, "Already initialized!");
Instance.eco = eco;
}
private Eco() {
/**
* Get eco.
*
* @return eco.
*/
static Eco get() {
return eco;
}
private Instance() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}
}
}

View File

@@ -20,8 +20,10 @@ import com.willfp.eco.core.web.UpdateChecker;
import org.apache.commons.lang.Validate;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.event.Listener;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
@@ -79,12 +81,12 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
private final Set<String> loadedIntegrations = new HashSet<>();
/**
* The internal plugin scheduler.
* The plugin scheduler.
*/
private final Scheduler scheduler;
/**
* The internal plugin Event Manager.
* The plugin Event Manager.
*/
private final EventManager eventManager;
@@ -99,17 +101,17 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
private final LangYml langYml;
/**
* The internal factory to produce {@link org.bukkit.NamespacedKey}s.
* The factory to produce {@link org.bukkit.NamespacedKey}s.
*/
private final NamespacedKeyFactory namespacedKeyFactory;
/**
* The internal factory to produce {@link org.bukkit.metadata.FixedMetadataValue}s.
* The factory to produce {@link org.bukkit.metadata.FixedMetadataValue}s.
*/
private final MetadataValueFactory metadataValueFactory;
/**
* The internal factory to produce {@link com.willfp.eco.core.scheduling.RunnableTask}s.
* The factory to produce {@link com.willfp.eco.core.scheduling.RunnableTask}s.
*/
private final RunnableFactory runnableFactory;
@@ -258,42 +260,42 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
*/
protected EcoPlugin(@Nullable final PluginProps pluginProps) {
/*
The handler must be initialized before any plugin's constructors
are called, as the constructors call Eco#getHandler().
Eco must be initialized before any plugin's constructors
are called, as the constructors call Eco#get().
To fix this, EcoSpigotPlugin an abstract class and the 'actual'
plugin class is EcoHandler - that way I can create the handler
plugin class is EcoImpl - that way I can initialize eco
before any plugins are loaded while still having a separation between
the plugin class and the handler class (for code clarity).
the plugin class and the implementation class (for code clarity).
I don't really like the fact that the handler class *is* the
I don't really like the fact that the implementation class *is* the
spigot plugin, but it is what it is.
There is probably a better way of doing it - maybe with
some sort of HandlerCreator interface in order to still have
a standalone handler class, but then there would be an interface
some sort of EcoCrater interface in order to still have
a standalone eco class, but then there would be an interface
left in the API that doesn't really help anything.
The other alternative would be to use reflection to get a 'createHandler'
The other alternative would be to use reflection to get a 'createEco'
method that only exists in EcoSpigotPlugin - but that feels filthy,
and I'd rather only use reflection where necessary.
*/
if (Eco.getHandler() == null && this instanceof Handler) {
if (Eco.get() == null && this instanceof Eco) {
/*
This code is only ever called by EcoSpigotPlugin (EcoHandler)
as it's the first plugin to load, and it is a handler.
This code is only ever called by EcoSpigotPlugin (EcoImpl)
as it's the first plugin to load, and it's an instance of eco.
Any other plugins will never call this code as the handler
will have already been initialized.
Any other plugins will never call this code as eco will have already
been initialized.
*/
Eco.setHandler((Handler) this);
Eco.Instance.set((Eco) this);
}
assert Eco.getHandler() != null;
assert Eco.get() != null;
PluginProps generatedProps = Eco.getHandler().getProps(pluginProps, this.getClass());
PluginProps generatedProps = Eco.get().getProps(pluginProps, this.getClass());
generatedProps.validate();
PluginProps props = this.mutateProps(generatedProps);
props.validate();
@@ -304,22 +306,23 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
this.color = props.getColor();
this.supportingExtensions = props.isSupportingExtensions();
this.scheduler = Eco.getHandler().createScheduler(this);
this.eventManager = Eco.getHandler().createEventManager(this);
this.namespacedKeyFactory = Eco.getHandler().createNamespacedKeyFactory(this);
this.metadataValueFactory = Eco.getHandler().createMetadataValueFactory(this);
this.runnableFactory = Eco.getHandler().createRunnableFactory(this);
this.extensionLoader = Eco.getHandler().createExtensionLoader(this);
this.configHandler = Eco.getHandler().createConfigHandler(this);
this.logger = Eco.getHandler().createLogger(this);
this.proxyFactory = this.proxyPackage.equalsIgnoreCase("") ? null : Eco.getHandler().createProxyFactory(this);
this.proxyFactory = this.proxyPackage.equalsIgnoreCase("") ? null : Eco.get().createProxyFactory(this);
this.logger = Eco.get().createLogger(this);
this.getLogger().info("Initializing " + this.getColor() + this.getName());
this.scheduler = Eco.get().createScheduler(this);
this.eventManager = Eco.get().createEventManager(this);
this.namespacedKeyFactory = Eco.get().createNamespacedKeyFactory(this);
this.metadataValueFactory = Eco.get().createMetadataValueFactory(this);
this.runnableFactory = Eco.get().createRunnableFactory(this);
this.extensionLoader = Eco.get().createExtensionLoader(this);
this.configHandler = Eco.get().createConfigHandler(this);
this.langYml = this.createLangYml();
this.configYml = this.createConfigYml();
Eco.getHandler().addNewPlugin(this);
this.getLogger().info("Initializing " + this.getColor() + this.getName());
Eco.get().addNewPlugin(this);
/*
The minimum eco version check was moved here because it's very common
@@ -328,7 +331,7 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
they have an outdated version of eco installed.
*/
DefaultArtifactVersion runningVersion = new DefaultArtifactVersion(Eco.getHandler().getEcoPlugin().getDescription().getVersion());
DefaultArtifactVersion runningVersion = new DefaultArtifactVersion(Eco.get().getEcoPlugin().getDescription().getVersion());
DefaultArtifactVersion requiredVersion = new DefaultArtifactVersion(this.getMinimumEcoVersion());
if (!(runningVersion.compareTo(requiredVersion) > 0 || runningVersion.equals(requiredVersion))) {
this.getLogger().severe("You are running an outdated version of eco!");
@@ -349,7 +352,7 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
this.getLogger().info("");
this.getLogger().info("Loading " + this.getColor() + this.getName());
if (this.getResourceId() != 0) {
if (this.getResourceId() != 0 && !Eco.get().getEcoPlugin().getConfigYml().getBool("no-update-checker")) {
new UpdateChecker(this).getVersion(version -> {
DefaultArtifactVersion currentVersion = new DefaultArtifactVersion(this.getDescription().getVersion());
DefaultArtifactVersion mostRecentVersion = new DefaultArtifactVersion(version);
@@ -363,7 +366,7 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
}
if (this.getBStatsId() != 0) {
Eco.getHandler().registerBStats(this);
Eco.get().registerBStats(this);
}
Set<String> enabledPlugins = Arrays.stream(Bukkit.getPluginManager().getPlugins())
@@ -373,7 +376,7 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
if (enabledPlugins.contains("PlaceholderAPI".toLowerCase())) {
this.loadedIntegrations.add("PlaceholderAPI");
PlaceholderManager.addIntegration(Eco.getHandler().createPAPIIntegration(this));
PlaceholderManager.addIntegration(Eco.get().createPAPIIntegration(this));
}
this.loadIntegrationLoaders().forEach(integrationLoader -> {
@@ -432,7 +435,7 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
}
this.getLogger().info("Cleaning up...");
Eco.getHandler().getCleaner().clean(this);
Eco.get().clean(this);
}
/**
@@ -745,7 +748,7 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
* @return The plugin.
*/
public static EcoPlugin getPlugin(@NotNull final String pluginName) {
return Eco.getHandler().getPluginByName(pluginName);
return Eco.get().getPluginByName(pluginName);
}
/**
@@ -754,7 +757,7 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
* @return The set of names.
*/
public static Set<String> getPluginNames() {
return new HashSet<>(Eco.getHandler().getLoadedPlugins());
return new HashSet<>(Eco.get().getLoadedPlugins());
}
/**
@@ -920,4 +923,26 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
public ProxyFactory getProxyFactory() {
return this.proxyFactory;
}
/**
* Create a NamespacedKey.
*
* @param key The key.
* @return The namespaced key.
*/
@NotNull
public NamespacedKey createNamespacedKey(@NotNull final String key) {
return this.getNamespacedKeyFactory().create(key);
}
/**
* Create a metadata value.
*
* @param value The value.
* @return The metadata value.
*/
@NotNull
public FixedMetadataValue createMetadataValue(@NotNull final Object value) {
return this.getMetadataValueFactory().create(value);
}
}

View File

@@ -1,312 +0,0 @@
package com.willfp.eco.core;
import com.willfp.eco.core.config.updating.ConfigHandler;
import com.willfp.eco.core.config.wrapper.ConfigFactory;
import com.willfp.eco.core.data.ExtendedPersistentDataContainer;
import com.willfp.eco.core.data.ProfileHandler;
import com.willfp.eco.core.data.keys.KeyRegistry;
import com.willfp.eco.core.drops.DropQueueFactory;
import com.willfp.eco.core.entities.ai.EntityController;
import com.willfp.eco.core.events.EventManager;
import com.willfp.eco.core.extensions.ExtensionLoader;
import com.willfp.eco.core.factory.MetadataValueFactory;
import com.willfp.eco.core.factory.NamespacedKeyFactory;
import com.willfp.eco.core.factory.RunnableFactory;
import com.willfp.eco.core.fast.FastItemStack;
import com.willfp.eco.core.gui.GUIFactory;
import com.willfp.eco.core.integrations.placeholder.PlaceholderIntegration;
import com.willfp.eco.core.items.SNBTHandler;
import com.willfp.eco.core.proxy.Cleaner;
import com.willfp.eco.core.proxy.ProxyFactory;
import com.willfp.eco.core.scheduling.Scheduler;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import org.bukkit.Location;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Mob;
import org.bukkit.inventory.ItemStack;
import org.bukkit.persistence.PersistentDataContainer;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.logging.Logger;
/**
* @see Eco#getHandler()
*/
@ApiStatus.Internal
public interface Handler {
/**
* Create a scheduler.
*
* @param plugin The plugin.
* @return The scheduler.
*/
@NotNull
Scheduler createScheduler(@NotNull EcoPlugin plugin);
/**
* Create an event manager.
*
* @param plugin The plugin.
* @return The event manager.
*/
@NotNull
EventManager createEventManager(@NotNull EcoPlugin plugin);
/**
* Create a NamespacedKey factory.
*
* @param plugin The plugin.
* @return The factory.
*/
@NotNull
NamespacedKeyFactory createNamespacedKeyFactory(@NotNull EcoPlugin plugin);
/**
* Create a MetadataValue factory.
*
* @param plugin The plugin.
* @return The factory.
*/
@NotNull
MetadataValueFactory createMetadataValueFactory(@NotNull EcoPlugin plugin);
/**
* Create a Runnable factory.
*
* @param plugin The plugin.
* @return The factory.
*/
@NotNull
RunnableFactory createRunnableFactory(@NotNull EcoPlugin plugin);
/**
* Create an ExtensionLoader.
*
* @param plugin The plugin.
* @return The factory.
*/
@NotNull
ExtensionLoader createExtensionLoader(@NotNull EcoPlugin plugin);
/**
* Create a config handler.
*
* @param plugin The plugin.
* @return The handler.
*/
@NotNull
ConfigHandler createConfigHandler(@NotNull EcoPlugin plugin);
/**
* Create a logger.
*
* @param plugin The plugin.
* @return The logger.
*/
@NotNull
Logger createLogger(@NotNull EcoPlugin plugin);
/**
* Create a PAPI integration.
*
* @param plugin The plugin.
* @return The integration.
*/
@NotNull
PlaceholderIntegration createPAPIIntegration(@NotNull EcoPlugin plugin);
/**
* Create a proxy factory.
*
* @param plugin The plugin.
* @return The factory.
*/
@NotNull
ProxyFactory createProxyFactory(@NotNull EcoPlugin plugin);
/**
* Get eco Spigot plugin.
*
* @return The plugin.
*/
@NotNull
EcoPlugin getEcoPlugin();
/**
* Get config factory.
*
* @return The factory.
*/
@NotNull
ConfigFactory getConfigFactory();
/**
* Get drop queue factory.
*
* @return The factory.
*/
@NotNull
DropQueueFactory getDropQueueFactory();
/**
* Get GUI factory.
*
* @return The factory.
*/
@NotNull
GUIFactory getGUIFactory();
/**
* Get cleaner.
*
* @return The cleaner.
*/
@NotNull
Cleaner getCleaner();
/**
* Add new plugin.
*
* @param plugin The plugin.
*/
void addNewPlugin(@NotNull EcoPlugin plugin);
/**
* Get plugin by name.
*
* @param name The name.
* @return The plugin.
*/
@Nullable
EcoPlugin getPluginByName(@NotNull String name);
/**
* Get all loaded eco plugins.
*
* @return A list of plugin names in lowercase.
*/
@NotNull
List<String> getLoadedPlugins();
/**
* Create a FastItemStack.
*
* @param itemStack The base ItemStack.
* @return The FastItemStack.
*/
@NotNull
FastItemStack createFastItemStack(@NotNull ItemStack itemStack);
/**
* Register bStats metrics.
*
* @param plugin The plugin.
*/
void registerBStats(@NotNull EcoPlugin plugin);
/**
* Get Adventure audiences.
*
* @return The audiences.
*/
@Nullable
BukkitAudiences getAdventure();
/**
* Get the key registry.
*
* @return The registry.
*/
@NotNull
KeyRegistry getKeyRegistry();
/**
* Get the PlayerProfile handler.
*
* @return The handler.
*/
@NotNull
ProfileHandler getProfileHandler();
/**
* Create dummy entity - never spawned, exists purely in code.
*
* @param location The location.
* @return The entity.
*/
@NotNull
Entity createDummyEntity(@NotNull Location location);
/**
* Create a {@link NamespacedKey} quickly
* <p>
* Bypasses the constructor, allowing for the creation of invalid keys,
* therefore this is considered unsafe and should only be called after
* the key has been confirmed to be valid.
*
* @param namespace The namespace.
* @param key The key.
* @return The key.
*/
@NotNull
NamespacedKey createNamespacedKey(@NotNull String namespace,
@NotNull String key);
/**
* Return or get props for a plugin.
*
* @param existing The existing constructor props.
* @param plugin The plugin.
* @return The props.
*/
@NotNull
PluginProps getProps(@Nullable PluginProps existing,
@NotNull Class<? extends EcoPlugin> plugin);
/**
* Format a string with MiniMessage.
*
* @param message The message.
* @return The formatted string.
*/
@NotNull
String formatMiniMessage(@NotNull String message);
/**
* Create controlled entity from a mob.
*
* @param mob The mob.
* @param <T> The mob type.
* @return The controlled entity.
*/
@NotNull <T extends Mob> EntityController<T> createEntityController(@NotNull T mob);
/**
* Adapt base PDC to extended PDC.
*
* @param container The container.
* @return The extended container.
*/
@NotNull
ExtendedPersistentDataContainer adaptPdc(@NotNull PersistentDataContainer container);
/**
* Create new PDC.
*
* @return The container.
*/
@NotNull
PersistentDataContainer newPdc();
/**
* Get SNBT handler.
*
* @return The SNBT handler.
*/
@NotNull
SNBTHandler getSNBTHandler();
}

View File

@@ -13,7 +13,9 @@ import org.jetbrains.annotations.NotNull;
* in the constructor.
*
* @param <T> The eco plugin type.
* @deprecated Leaky inheritance, shouldn't exist.
*/
@Deprecated(since = "6.43.0", forRemoval = true)
public abstract class PluginDependent<T extends EcoPlugin> {
/**
* The {@link EcoPlugin} that is stored.

View File

@@ -41,11 +41,19 @@ public class Prerequisite {
"Requires server to have vault"
);
/**
* Requires the server to be running 1.19.
*/
public static final Prerequisite HAS_1_19 = new Prerequisite(
() -> ProxyConstants.NMS_VERSION.contains("19"),
"Requires server to be running 1.19+"
);
/**
* Requires the server to be running 1.18.
*/
public static final Prerequisite HAS_1_18 = new Prerequisite(
() -> ProxyConstants.NMS_VERSION.contains("18"),
() -> ProxyConstants.NMS_VERSION.contains("18") || HAS_1_19.isMet(),
"Requires server to be running 1.18+"
);

View File

@@ -40,7 +40,7 @@ public abstract class BaseConfig extends LoadableConfigWrapper {
final boolean removeUnused,
@NotNull final ConfigType type,
final boolean requiresChangeToSave) {
super(Eco.getHandler().getConfigFactory().createUpdatableConfig(
super(Eco.get().createUpdatableConfig(
configName,
plugin,
"",

View File

@@ -14,7 +14,12 @@ public enum ConfigType {
/**
* .yml config.
*/
YAML("yml");
YAML("yml"),
/**
* .toml config.
*/
TOML("toml");
/**
* The file extension.

View File

@@ -31,7 +31,7 @@ public abstract class ExtendableConfig extends LoadableConfigWrapper {
@NotNull final String subDirectoryPath,
@NotNull final ConfigType type,
@NotNull final String... updateBlacklist) {
super(Eco.getHandler().getConfigFactory().createUpdatableConfig(
super(Eco.get().createUpdatableConfig(
configName,
plugin,
subDirectoryPath,

View File

@@ -21,7 +21,7 @@ public abstract class StaticBaseConfig extends LoadableConfigWrapper {
protected StaticBaseConfig(@NotNull final String configName,
@NotNull final PluginLike plugin,
@NotNull final ConfigType type) {
super(Eco.getHandler().getConfigFactory().createLoadableConfig(
super(Eco.get().createLoadableConfig(
configName,
plugin,
"",

View File

@@ -26,7 +26,7 @@ public class TransientConfig extends ConfigWrapper<Config> {
* @param config The ConfigurationSection handle.
*/
public TransientConfig(@NotNull final ConfigurationSection config) {
super(Eco.getHandler().getConfigFactory().createConfig(config));
super(Eco.get().wrapConfigurationSection(config));
}
/**
@@ -42,7 +42,7 @@ public class TransientConfig extends ConfigWrapper<Config> {
* @param stream The InputStream.
*/
public TransientConfig(@Nullable final InputStream stream) {
super(stream != null ? Eco.getHandler().getConfigFactory().createConfig(YamlConfiguration.loadConfiguration(
super(stream != null ? Eco.get().wrapConfigurationSection(YamlConfiguration.loadConfiguration(
new InputStreamReader(stream)
)) : new TransientConfig());
}
@@ -62,7 +62,7 @@ public class TransientConfig extends ConfigWrapper<Config> {
*/
public TransientConfig(@Nullable final File file,
@NotNull final ConfigType type) {
super(file != null ? Eco.getHandler().getConfigFactory().createConfig(readFile(file), type)
super(file != null ? Eco.get().createConfig(readFile(file), type)
: new TransientConfig());
}
@@ -72,7 +72,7 @@ public class TransientConfig extends ConfigWrapper<Config> {
* @param values The values.
*/
public TransientConfig(@NotNull final Map<String, Object> values) {
super(Eco.getHandler().getConfigFactory().createConfig(values, ConfigType.YAML));
super(Eco.get().createConfig(values, ConfigType.YAML));
}
/**
@@ -83,7 +83,7 @@ public class TransientConfig extends ConfigWrapper<Config> {
*/
public TransientConfig(@NotNull final Map<String, Object> values,
@NotNull final ConfigType type) {
super(Eco.getHandler().getConfigFactory().createConfig(values, type));
super(Eco.get().createConfig(values, type));
}
/**
@@ -99,7 +99,7 @@ public class TransientConfig extends ConfigWrapper<Config> {
*/
public TransientConfig(@NotNull final String contents,
@NotNull final ConfigType type) {
super(Eco.getHandler().getConfigFactory().createConfig(contents, type));
super(Eco.get().createConfig(contents, type));
}
/**

View File

@@ -3,6 +3,7 @@ package com.willfp.eco.core.config.interfaces;
import com.willfp.eco.core.config.BuildableConfig;
import com.willfp.eco.core.config.ConfigType;
import com.willfp.eco.core.config.TransientConfig;
import com.willfp.eco.core.placeholder.AdditionalPlayer;
import com.willfp.eco.core.placeholder.InjectablePlaceholder;
import com.willfp.eco.core.placeholder.PlaceholderInjectable;
import com.willfp.eco.util.NumberUtils;
@@ -14,6 +15,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -77,7 +79,6 @@ public interface Config extends Cloneable, PlaceholderInjectable {
/**
* Get an object from config.
* Default implementations call {@link org.bukkit.configuration.file.YamlConfiguration#get(String)}.
*
* @param path The path.
* @return The object.
@@ -87,7 +88,6 @@ public interface Config extends Cloneable, PlaceholderInjectable {
/**
* Set an object in config.
* Default implementations call {@link org.bukkit.configuration.file.YamlConfiguration#set(String, Object)}
*
* @param path The path.
* @param object The object.
@@ -159,6 +159,20 @@ public interface Config extends Cloneable, PlaceholderInjectable {
return Double.valueOf(getDoubleFromExpression(path, player)).intValue();
}
/**
* Get a decimal value via a mathematical expression.
*
* @param path The key to fetch the value from.
* @param player The player to evaluate placeholders with respect to.
* @param additionalPlayers The additional players to evaluate placeholders with respect to.
* @return The computed value, or 0 if not found or invalid.
*/
default int getIntFromExpression(@NotNull String path,
@Nullable Player player,
@NotNull Collection<AdditionalPlayer> additionalPlayers) {
return Double.valueOf(getDoubleFromExpression(path, player, additionalPlayers)).intValue();
}
/**
* Get an integer from config.
@@ -474,6 +488,20 @@ public interface Config extends Cloneable, PlaceholderInjectable {
return NumberUtils.evaluateExpression(this.getString(path), player, this);
}
/**
* Get a decimal value via a mathematical expression.
*
* @param path The key to fetch the value from.
* @param player The player to evaluate placeholders with respect to.
* @param additionalPlayers The additional players to evaluate placeholders with respect to.
* @return The computed value, or 0 if not found or invalid.
*/
default double getDoubleFromExpression(@NotNull String path,
@Nullable Player player,
@NotNull Collection<AdditionalPlayer> additionalPlayers) {
return NumberUtils.evaluateExpression(this.getString(path), player, this, additionalPlayers);
}
/**
* Get a decimal from config.
*

View File

@@ -1,87 +0,0 @@
package com.willfp.eco.core.config.wrapper;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.PluginLike;
import com.willfp.eco.core.config.ConfigType;
import com.willfp.eco.core.config.interfaces.Config;
import com.willfp.eco.core.config.interfaces.LoadableConfig;
import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
/**
* Internal component to create backend config implementations.
*/
@ApiStatus.Internal
@Eco.HandlerComponent
public interface ConfigFactory {
/**
* Updatable config.
*
* @param configName The name of the config
* @param plugin The plugin.
* @param subDirectoryPath The subdirectory path.
* @param source The class that owns the resource.
* @param removeUnused Whether keys not present in the default config should be removed on update.
* @param type The config type.
* @param updateBlacklist Substring of keys to not add/remove keys for.
* @param requiresChangesToSave If the config must be changed in order to save the config.
* @return The config implementation.
*/
LoadableConfig createUpdatableConfig(@NotNull String configName,
@NotNull PluginLike plugin,
@NotNull String subDirectoryPath,
@NotNull Class<?> source,
boolean removeUnused,
@NotNull ConfigType type,
boolean requiresChangesToSave,
@NotNull String... updateBlacklist);
/**
* Loadable config.
*
* @param configName The name of the config
* @param plugin The plugin.
* @param subDirectoryPath The subdirectory path.
* @param source The class that owns the resource.
* @param type The config type.
* @param requiresChangesToSave If the config must be changed in order to save the config.
* @return The config implementation.
*/
LoadableConfig createLoadableConfig(@NotNull String configName,
@NotNull PluginLike plugin,
@NotNull String subDirectoryPath,
@NotNull Class<?> source,
@NotNull ConfigType type,
boolean requiresChangesToSave);
/**
* Create config.
*
* @param config The handle.
* @return The config implementation.
*/
Config createConfig(@NotNull ConfigurationSection config);
/**
* Create config.
*
* @param values The values.
* @param type The config type.
* @return The config implementation.
*/
Config createConfig(@NotNull Map<String, Object> values,
@NotNull ConfigType type);
/**
* Create config.
*
* @param contents The file contents.
* @param type The type.
* @return The config implementation.
*/
Config createConfig(@NotNull String contents,
@NotNull ConfigType type);
}

View File

@@ -87,7 +87,7 @@ public interface ExtendedPersistentDataContainer {
* @return The extended container.
*/
static ExtendedPersistentDataContainer extend(@NotNull PersistentDataContainer base) {
return Eco.getHandler().adaptPdc(base);
return Eco.get().adaptPdc(base);
}
/**
@@ -96,6 +96,6 @@ public interface ExtendedPersistentDataContainer {
* @return The extended container.
*/
static ExtendedPersistentDataContainer create() {
return extend(Eco.getHandler().newPdc());
return extend(Eco.get().newPdc());
}
}

View File

@@ -31,6 +31,6 @@ public interface PlayerProfile extends Profile {
*/
@NotNull
static PlayerProfile load(@NotNull final UUID uuid) {
return Eco.getHandler().getProfileHandler().load(uuid);
return Eco.get().loadPlayerProfile(uuid);
}
}

View File

@@ -1,94 +0,0 @@
package com.willfp.eco.core.data;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.data.keys.PersistentDataKey;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.util.Set;
import java.util.UUID;
/**
* API to handle profiles.
*/
@ApiStatus.Internal
@Eco.HandlerComponent
public interface ProfileHandler {
/**
* Load a player profile.
*
* @param uuid The UUID.
* @return The profile.
*/
PlayerProfile load(@NotNull UUID uuid);
/**
* Load the server profile.
*
* @return The profile.
*/
ServerProfile loadServerProfile();
/**
* Unload a player profile from memory.
* <p>
* This will not save the profile first.
*
* @param uuid The uuid.
*/
void unloadPlayer(@NotNull UUID uuid);
/**
* Save a player profile.
* <p>
* Can run async if using MySQL.
*
* @param uuid The uuid.
* @deprecated Saving changes is faster and should be used. Saving a player manually is not recommended.
*/
@Deprecated
default void savePlayer(@NotNull UUID uuid) {
this.saveKeysFor(uuid, PersistentDataKey.values());
}
/**
* Save keys for a player.
* <p>
* Can run async if using MySQL.
*
* @param uuid The uuid.
* @param keys The keys.
*/
void saveKeysFor(@NotNull UUID uuid,
@NotNull Set<PersistentDataKey<?>> keys);
/**
* Save all player data.
*
* @param async If the saving should be done asynchronously.
* @deprecated async is now handled automatically depending on implementation.
*/
@Deprecated(forRemoval = true)
default void saveAll(boolean async) {
saveAll();
}
/**
* Save all player data.
* <p>
* Can run async if using MySQL.
*
* @deprecated Never used.
*/
@Deprecated(since = "6.36.0", forRemoval = true)
default void saveAll() {
// Do nothing.
}
/**
* Commit all changes to the file.
* <p>
* Does nothing if using MySQL.
*/
void save();
}

View File

@@ -16,6 +16,6 @@ public interface ServerProfile extends Profile {
*/
@NotNull
static ServerProfile load() {
return Eco.getHandler().getProfileHandler().loadServerProfile();
return Eco.get().getServerProfile();
}
}

View File

@@ -1,72 +0,0 @@
package com.willfp.eco.core.data.keys;
import com.willfp.eco.core.Eco;
import org.bukkit.NamespacedKey;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
/**
* API to register persistent data keys.
*/
@ApiStatus.Internal
@Eco.HandlerComponent
public interface KeyRegistry {
/**
* Register a persistent data key to be stored.
*
* @param key The key.
*/
void registerKey(@NotNull PersistentDataKey<?> key);
/**
* Get a key's category.
*
* @param key The key.
* @return The category.
*/
@Nullable
KeyCategory getCategory(@NotNull PersistentDataKey<?> key);
/**
* Get all registered keys.
*
* @return The keys.
*/
Set<PersistentDataKey<?>> getRegisteredKeys();
/**
* Mark key as category.
*
* @param key The key.
* @param category The category.
*/
void markKeyAs(@NotNull PersistentDataKey<?> key,
@NotNull KeyRegistry.KeyCategory category);
/**
* Get persistent data key from namespaced key.
*
* @param namespacedKey The key.
* @return The key, or null if not found.
*/
@Nullable
PersistentDataKey<?> getKeyFrom(@NotNull NamespacedKey namespacedKey);
/**
* Locations for key categorization.
*/
enum KeyCategory {
/**
* Player keys.
*/
PLAYER,
/**
* Server keys.
*/
SERVER
}
}

View File

@@ -43,7 +43,7 @@ public final class PersistentDataKey<T> {
this.defaultValue = defaultValue;
this.type = type;
Eco.getHandler().getKeyRegistry().registerKey(this);
Eco.get().registerPersistentKey(this);
}
@Override
@@ -83,28 +83,40 @@ public final class PersistentDataKey<T> {
}
/**
* In older eco versions, keys would have to be categorized in order
* to register the columns in the MySQL database. This is no longer needed.
* <p>
* Old description is below:
* <p>
* Categorize key as a server key, will register new column to MySQL
* database immediately rather than waiting for auto-categorization.
* <p>
* This will improve performance.
*
* @return The key.
* @deprecated Not required since the new MySQL data handler was introduced.
*/
@Deprecated(since = "6.40.0", forRemoval = true)
public PersistentDataKey<T> server() {
Eco.getHandler().getKeyRegistry().markKeyAs(this, KeyRegistry.KeyCategory.SERVER);
return this;
}
/**
* In older eco versions, keys would have to be categorized in order
* to register the columns in the MySQL database. This is no longer needed.
* <p>
* Old description is below:
* <p>
* Categorize key as a player key, will register new column to MySQL
* database immediately rather than waiting for auto-categorization.
* <p>
* This will improve performance.
*
* @return The key.
* @deprecated Not required since the new MySQL data handler was introduced.
*/
@Deprecated(since = "6.40.0", forRemoval = true)
public PersistentDataKey<T> player() {
Eco.getHandler().getKeyRegistry().markKeyAs(this, KeyRegistry.KeyCategory.PLAYER);
return this;
}
@@ -114,7 +126,7 @@ public final class PersistentDataKey<T> {
* @return The keys.
*/
public static Set<PersistentDataKey<?>> values() {
return Eco.getHandler().getKeyRegistry().getRegisteredKeys();
return Eco.get().getRegisteredPersistentDataKeys();
}
@Override

View File

@@ -1,5 +1,6 @@
package com.willfp.eco.core.data.keys;
import com.willfp.eco.core.config.interfaces.Config;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -43,6 +44,11 @@ public final class PersistentDataKeyType<T> {
*/
public static final PersistentDataKeyType<List<String>> STRING_LIST = new PersistentDataKeyType<>(null, "STRING_LIST");
/**
* Config.
*/
public static final PersistentDataKeyType<Config> CONFIG = new PersistentDataKeyType<>(Config.class, "CONFIG");
/**
* The class of the type.
*/

View File

@@ -1,11 +1,22 @@
package com.willfp.eco.core.display;
import com.willfp.eco.core.fast.FastItemStack;
import com.willfp.eco.util.NamespacedKeyUtils;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
/**
* Utility class to manage client-side item display.
*/
@@ -16,9 +27,14 @@ public final class Display {
public static final String PREFIX = "§z";
/**
* The display handler.
* All registered modules.
*/
private static DisplayHandler handler = null;
private static final Map<Integer, List<DisplayModule>> REGISTERED_MODULES = new TreeMap<>();
/**
* The finalize key.
*/
private static final NamespacedKey FINALIZE_KEY = NamespacedKeyUtils.createEcoKey("finalized");
/**
* Display on ItemStacks.
@@ -39,7 +55,49 @@ public final class Display {
*/
public static ItemStack display(@NotNull final ItemStack itemStack,
@Nullable final Player player) {
return handler.display(itemStack, player);
Map<String, Object[]> pluginVarArgs = new HashMap<>();
for (List<DisplayModule> modules : REGISTERED_MODULES.values()) {
for (DisplayModule module : modules) {
pluginVarArgs.put(module.getPluginName(), module.generateVarArgs(itemStack));
}
}
Display.revert(itemStack);
if (!itemStack.hasItemMeta()) {
return itemStack;
}
ItemStack original = itemStack.clone();
Inventory inventory = player == null ? null : player.getOpenInventory().getTopInventory();
boolean inInventory = inventory != null && inventory.contains(original);
boolean inGui = inventory != null && inventory.getHolder() == null;
DisplayProperties properties = new DisplayProperties(
inInventory,
inGui,
original
);
for (List<DisplayModule> modules : REGISTERED_MODULES.values()) {
for (DisplayModule module : modules) {
Object[] varargs = pluginVarArgs.get(module.getPluginName());
if (varargs == null) {
continue;
}
module.display(itemStack, varargs);
if (player != null) {
module.display(itemStack, player, varargs);
module.display(itemStack, player, properties, varargs);
}
}
}
return itemStack;
}
/**
@@ -71,7 +129,25 @@ public final class Display {
* @return The ItemStack.
*/
public static ItemStack revert(@NotNull final ItemStack itemStack) {
return handler.revert(itemStack);
if (Display.isFinalized(itemStack)) {
Display.unfinalize(itemStack);
}
FastItemStack fast = FastItemStack.wrap(itemStack);
List<String> lore = fast.getLore();
if (!lore.isEmpty() && lore.removeIf(line -> line.startsWith(Display.PREFIX))) {
fast.setLore(lore);
}
for (List<DisplayModule> modules : REGISTERED_MODULES.values()) {
for (DisplayModule module : modules) {
module.revert(itemStack);
}
}
return itemStack;
}
/**
@@ -81,7 +157,15 @@ public final class Display {
* @return The ItemStack.
*/
public static ItemStack finalize(@NotNull final ItemStack itemStack) {
return handler.finalize(itemStack);
if (itemStack.getType().getMaxStackSize() > 1) {
return itemStack;
}
FastItemStack.wrap(itemStack)
.getPersistentDataContainer()
.set(FINALIZE_KEY, PersistentDataType.INTEGER, 1);
return itemStack;
}
/**
@@ -91,7 +175,11 @@ public final class Display {
* @return The ItemStack.
*/
public static ItemStack unfinalize(@NotNull final ItemStack itemStack) {
return handler.unfinalize(itemStack);
FastItemStack.wrap(itemStack)
.getPersistentDataContainer()
.remove(FINALIZE_KEY);
return itemStack;
}
/**
@@ -101,7 +189,9 @@ public final class Display {
* @return If finalized.
*/
public static boolean isFinalized(@NotNull final ItemStack itemStack) {
return handler.isFinalized(itemStack);
return FastItemStack.wrap(itemStack)
.getPersistentDataContainer()
.has(FINALIZE_KEY, PersistentDataType.INTEGER);
}
/**
@@ -110,23 +200,15 @@ public final class Display {
* @param module The module.
*/
public static void registerDisplayModule(@NotNull final DisplayModule module) {
handler.registerDisplayModule(module);
}
List<DisplayModule> modules = REGISTERED_MODULES.getOrDefault(
module.getWeight(),
new ArrayList<>()
);
/**
* Set the display handler.
* <p>
* Internal API component, you will cause bugs if you create your own handler.
*
* @param handler The handler.
*/
@ApiStatus.Internal
public static void setHandler(@NotNull final DisplayHandler handler) {
if (Display.handler != null) {
throw new IllegalStateException("Display already initialized!");
}
modules.removeIf(it -> it.getPluginName().equalsIgnoreCase(module.getPluginName()));
modules.add(module);
Display.handler = handler;
REGISTERED_MODULES.put(module.getWeight(), modules);
}
private Display() {

View File

@@ -1,64 +0,0 @@
package com.willfp.eco.core.display;
import com.willfp.eco.core.Eco;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Interface for display implementations.
*/
@ApiStatus.Internal
@Eco.HandlerComponent
public interface DisplayHandler {
/**
* Register display module.
*
* @param module The module.
*/
void registerDisplayModule(@NotNull DisplayModule module);
/**
* Display on ItemStacks.
*
* @param itemStack The item.
* @param player The player.
* @return The ItemStack.
*/
ItemStack display(@NotNull ItemStack itemStack,
@Nullable Player player);
/**
* Revert on ItemStacks.
*
* @param itemStack The item.
* @return The ItemStack.
*/
ItemStack revert(@NotNull ItemStack itemStack);
/**
* Finalize an ItemStacks.
*
* @param itemStack The item.
* @return The ItemStack.
*/
ItemStack finalize(@NotNull ItemStack itemStack);
/**
* Unfinalize an ItemStacks.
*
* @param itemStack The item.
* @return The ItemStack.
*/
ItemStack unfinalize(@NotNull ItemStack itemStack);
/**
* If an item is finalized.
*
* @param itemStack The item.
* @return If finalized.
*/
boolean isFinalized(@NotNull ItemStack itemStack);
}

View File

@@ -1,7 +1,6 @@
package com.willfp.eco.core.display;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginDependent;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
@@ -10,12 +9,17 @@ import org.jetbrains.annotations.Nullable;
/**
* Class for all plugin-specific client-side item display modules.
*/
public abstract class DisplayModule extends PluginDependent<EcoPlugin> {
public abstract class DisplayModule {
/**
* The priority of the module.
*/
private final int weight;
/**
* The plugin.
*/
private final EcoPlugin plugin;
/**
* Create a new display module.
*
@@ -24,8 +28,7 @@ public abstract class DisplayModule extends PluginDependent<EcoPlugin> {
*/
protected DisplayModule(@NotNull final EcoPlugin plugin,
@NotNull final DisplayPriority priority) {
super(plugin);
this.weight = priority.getWeight();
this(plugin, priority.getWeight());
}
/**
@@ -36,7 +39,7 @@ public abstract class DisplayModule extends PluginDependent<EcoPlugin> {
*/
protected DisplayModule(@NotNull final EcoPlugin plugin,
final int weight) {
super(plugin);
this.plugin = plugin;
this.weight = weight;
}
@@ -64,6 +67,21 @@ public abstract class DisplayModule extends PluginDependent<EcoPlugin> {
// Technically optional.
}
/**
* Display an item.
*
* @param itemStack The item.
* @param player The player.
* @param properties The properties.
* @param args Optional args for display.
*/
public void display(@NotNull final ItemStack itemStack,
@Nullable final Player player,
@NotNull final DisplayProperties properties,
@NotNull final Object... args) {
// Technically optional.
}
/**
* Revert an item.
*
@@ -89,7 +107,7 @@ public abstract class DisplayModule extends PluginDependent<EcoPlugin> {
* @return The plugin name.
*/
public final String getPluginName() {
return super.getPlugin().getName();
return this.getPlugin().getName();
}
/**
@@ -117,4 +135,13 @@ public abstract class DisplayModule extends PluginDependent<EcoPlugin> {
public int getWeight() {
return this.weight;
}
/**
* Get the plugin.
*
* @return The plugin.
*/
public EcoPlugin getPlugin() {
return plugin;
}
}

View File

@@ -0,0 +1,18 @@
package com.willfp.eco.core.display;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
/**
* Extra properties passed into {@link DisplayModule}.
*
* @param inInventory If the item was in an inventory.
* @param inGui If the item is assumed to be in a gui. (Not perfectly accurate).
* @param originalItem The original item, not to be modified.
*/
public record DisplayProperties(
boolean inInventory,
boolean inGui,
@NotNull ItemStack originalItem
) {
}

View File

@@ -21,13 +21,25 @@ public class DropQueue {
/**
* The internally used {@link DropQueue}.
*/
private final InternalDropQueue handle;
private final DropQueue delegate;
/**
* Create a new DropQueue.
*
* @param player The player.
*/
public DropQueue(@NotNull final Player player) {
handle = Eco.getHandler().getDropQueueFactory().create(player);
this.delegate = Eco.get().createDropQueue(player);
}
/**
* Create a new DropQueue with no delegate.
* <p>
* Call this constructor if you're creating custom DropQueue
* implementations.
*/
protected DropQueue() {
this.delegate = null;
}
/**
@@ -37,7 +49,11 @@ public class DropQueue {
* @return The DropQueue.
*/
public DropQueue addItem(@NotNull final ItemStack item) {
handle.addItem(item);
if (delegate == null) {
return this;
}
delegate.addItem(item);
return this;
}
@@ -48,7 +64,11 @@ public class DropQueue {
* @return The DropQueue.
*/
public DropQueue addItems(@NotNull final Collection<ItemStack> itemStacks) {
handle.addItems(itemStacks);
if (delegate == null) {
return this;
}
delegate.addItems(itemStacks);
return this;
}
@@ -59,7 +79,11 @@ public class DropQueue {
* @return The DropQueue.
*/
public DropQueue addXP(final int amount) {
handle.addXP(amount);
if (delegate == null) {
return this;
}
delegate.addXP(amount);
return this;
}
@@ -70,7 +94,11 @@ public class DropQueue {
* @return The DropQueue.
*/
public DropQueue setLocation(@NotNull final Location location) {
handle.setLocation(location);
if (delegate == null) {
return this;
}
delegate.setLocation(location);
return this;
}
@@ -80,7 +108,11 @@ public class DropQueue {
* @return The DropQueue.
*/
public DropQueue forceTelekinesis() {
handle.forceTelekinesis();
if (delegate == null) {
return this;
}
delegate.forceTelekinesis();
return this;
}
@@ -88,6 +120,10 @@ public class DropQueue {
* Push the queue.
*/
public void push() {
handle.push();
if (delegate == null) {
return;
}
delegate.push();
}
}

View File

@@ -1,21 +0,0 @@
package com.willfp.eco.core.drops;
import com.willfp.eco.core.Eco;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
/**
* Internal component to create backend DropQueue implementations.
*/
@ApiStatus.Internal
@Eco.HandlerComponent
public interface DropQueueFactory {
/**
* Create a DropQueue.
*
* @param player The player.
* @return The Queue.
*/
InternalDropQueue create(@NotNull Player player);
}

View File

@@ -1,60 +0,0 @@
package com.willfp.eco.core.drops;
import com.willfp.eco.core.Eco;
import org.bukkit.Location;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
/**
* Internal interface for backend DropQueue implementations.
*/
@ApiStatus.Internal
@Eco.HandlerComponent
public interface InternalDropQueue {
/**
* Add item to queue.
*
* @param item The item to add.
* @return The DropQueue.
*/
InternalDropQueue addItem(@NotNull ItemStack item);
/**
* Add multiple items to queue.
*
* @param itemStacks The items to add.
* @return The DropQueue.
*/
InternalDropQueue addItems(@NotNull Collection<ItemStack> itemStacks);
/**
* Add xp to queue.
*
* @param amount The amount to add.
* @return The DropQueue.
*/
InternalDropQueue addXP(int amount);
/**
* Set location of the origin of the drops.
*
* @param location The location.
* @return The DropQueue.
*/
InternalDropQueue setLocation(@NotNull Location location);
/**
* Force the queue to act as if player is telekinetic.
*
* @return The DropQueue.
*/
InternalDropQueue forceTelekinesis();
/**
* Push the queue.
*/
void push();
}

View File

@@ -101,6 +101,6 @@ public interface EntityController<T extends Mob> {
* @return The entity controller.
*/
static <T extends Mob> EntityController<T> getFor(@NotNull final T entity) {
return Eco.getHandler().createEntityController(entity);
return Eco.get().createEntityController(entity);
}
}

View File

@@ -28,6 +28,6 @@ public class EmptyTestableEntity implements TestableEntity {
public Entity spawn(@NotNull final Location location) {
Validate.notNull(location.getWorld());
return Eco.getHandler().createDummyEntity(location);
return Eco.get().createDummyEntity(location);
}
}

View File

@@ -3,7 +3,7 @@ package com.willfp.eco.core.extensions;
import java.util.Set;
/**
* Internal component to manage loading and unloading extensions.
* Manages the loading and unloading of extensions for a particular plugin.
*/
public interface ExtensionLoader {
/**

View File

@@ -72,6 +72,7 @@ public interface FastItemStack extends PersistentDataHolder {
* @deprecated Poorly named method. Use getEnchantmentLevel instead.
*/
@Deprecated(since = "6.34.0", forRemoval = true)
@SuppressWarnings("DeprecatedIsStillUsed")
default int getLevelOnItem(@NotNull Enchantment enchantment,
boolean checkStored) {
return getEnchantmentLevel(enchantment, checkStored);
@@ -271,6 +272,6 @@ public interface FastItemStack extends PersistentDataHolder {
* @return The FastItemStack.
*/
static FastItemStack wrap(@Nullable final ItemStack itemStack) {
return Eco.getHandler().createFastItemStack(Objects.requireNonNullElseGet(itemStack, () -> new ItemStack(Material.AIR)));
return Eco.get().createFastItemStack(Objects.requireNonNullElseGet(itemStack, () -> new ItemStack(Material.AIR)));
}
}

View File

@@ -0,0 +1,82 @@
package com.willfp.eco.core.gui;
import com.willfp.eco.core.gui.menu.Menu;
import com.willfp.eco.core.gui.slot.Slot;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* A GUI Component is a 2-dimensional set of slots that can be
* placed in a menu.
*/
public interface GUIComponent {
/**
* Get the amount of rows in the component.
*
* @return The rows.
*/
int getRows();
/**
* Get the amount of columns in the component.
*
* @return The columns.
*/
int getColumns();
/**
* Initialize the component.
* <p>
* This is called before getRows / getColumns is queried,
* and allows for dynamically sized components.
* <p>
* getRows and getColumns can return values bigger than this,
* it will simply prevent the component from being added at
* this position (for minimum-sized components).
*
* @param maxRows The maximum number of rows.
* @param maxColumns The maximum number of columns.
*/
default void init(final int maxRows,
final int maxColumns) {
// Most components will not require initialization.
}
/**
* Get the slot at a certain position in the component.
* <p>
* It's safe to assume to the row and column will always be in bounds.
*
* @param row The row (1-indexed).
* @param column The column (1-indexed).
* @return The slot, or null if no slot at the location.
*/
@Nullable
default Slot getSlotAt(final int row,
final int column) {
return null;
}
/**
* Get the slot at a certain position in the component.
* <p>
* If your component doesn't use context data (player, menu),
* then it will default to the raw slot.
* <p>
* It's safe to assume to the row and column will always be in bounds.
*
* @param row The row (1-indexed).
* @param column The column (1-indexed).
* @param player The player.
* @param menu The menu.
* @return The slot, or null if no slot at the location.
*/
@Nullable
default Slot getSlotAt(final int row,
final int column,
@NotNull final Player player,
@NotNull final Menu menu) {
return getSlotAt(row, column);
}
}

View File

@@ -1,33 +0,0 @@
package com.willfp.eco.core.gui;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.gui.menu.MenuBuilder;
import com.willfp.eco.core.gui.slot.SlotBuilder;
import com.willfp.eco.core.gui.slot.functional.SlotProvider;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
/**
* Internal component used by {@link com.willfp.eco.core.gui.menu.Menu#builder(int)}
* and {@link com.willfp.eco.core.gui.slot.Slot#builder(ItemStack)}.
*/
@ApiStatus.Internal
@Eco.HandlerComponent
public interface GUIFactory {
/**
* Create slot builder.
*
* @param provider The provider.
* @return The builder.
*/
SlotBuilder createSlotBuilder(@NotNull SlotProvider provider);
/**
* Create menu builder.
*
* @param rows The amount of rows.
* @return The builder.
*/
MenuBuilder createMenuBuilder(int rows);
}

View File

@@ -1,7 +1,9 @@
package com.willfp.eco.core.gui.menu;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.gui.page.Page;
import com.willfp.eco.core.gui.slot.Slot;
import com.willfp.eco.util.NamespacedKeyUtils;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
@@ -12,7 +14,9 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
/**
* GUI version of {@link Inventory}.
@@ -28,7 +32,19 @@ public interface Menu {
int getRows();
/**
* Get slot at given row and column.
* Get the amount of columns.
*
* @return The amount of columns.
*/
default int getColumns() {
return 9;
}
/**
* Get a static slot at a given row and column.
* <p>
* If the slot at the location is reactive, this will return
* an empty slot.
*
* @param row The row.
* @param column The column.
@@ -37,6 +53,24 @@ public interface Menu {
Slot getSlot(int row,
int column);
/**
* Get a slot at a given row and column.
* <p>
* Defaults to static slot if no reactive slot exists.
*
* @param row The row.
* @param column The column.
* @param player The player
* @param menu The menu.
* @return The slot.
*/
default Slot getSlot(int row,
int column,
@NotNull Player player,
@NotNull Menu menu) {
return this.getSlot(row, column);
}
/**
* Get the menu title.
*
@@ -60,6 +94,21 @@ public interface Menu {
*/
List<ItemStack> getCaptiveItems(@NotNull Player player);
/**
* Get a captive item at a specific position.
*
* @param player The player.
* @param row The row.
* @param column The column.
* @return The captive item.
*/
@Nullable
default ItemStack getCaptiveItem(@NotNull final Player player,
final int row,
final int column) {
return null;
}
/**
* Add state for a player.
*
@@ -107,6 +156,55 @@ public interface Menu {
*/
Map<String, Object> getState(@NotNull Player player);
/**
* Re-render the menu for a player.
*
* @param player The player.
*/
void refresh(@NotNull Player player);
/**
* If the menu allows changing the held item.
*
* @return If allowed.
*/
default boolean allowsChangingHeldItem() {
return false;
}
/**
* Call a menu event.
*
* @param player The player.
* @param menuEvent The event.
*/
default void callEvent(@NotNull final Player player,
@NotNull final MenuEvent menuEvent) {
// Override when needed.
}
/**
* Get the current page a player is on.
*
* @param player The player.
* @return The page.
*/
default int getPage(@NotNull final Player player) {
Integer pageState = this.getState(player, Page.PAGE_KEY);
return Objects.requireNonNullElse(pageState, 1);
}
/**
* Get the max page for a player.
*
* @param player The player.
* @return The page.
*/
default int getMaxPage(@NotNull final Player player) {
Integer pageState = this.getState(player, Page.MAX_PAGE_KEY);
return Objects.requireNonNullElse(pageState, Integer.MAX_VALUE);
}
/**
* Write data.
*
@@ -119,10 +217,12 @@ public interface Menu {
* @deprecated Use addState instead.
*/
@Deprecated(since = "6.35.0", forRemoval = true)
<T, Z> void writeData(@NotNull Player player,
@NotNull NamespacedKey key,
@NotNull PersistentDataType<T, Z> type,
@NotNull Z value);
default <T, Z> void writeData(@NotNull final Player player,
@NotNull final NamespacedKey key,
@NotNull final PersistentDataType<T, Z> type,
@NotNull final Z value) {
this.addState(player, key.toString(), value);
}
/**
* Read data.
@@ -136,9 +236,11 @@ public interface Menu {
* @deprecated Use getState instead.
*/
@Deprecated(since = "6.35.0", forRemoval = true)
@Nullable <T, Z> T readData(@NotNull Player player,
@NotNull NamespacedKey key,
@NotNull PersistentDataType<T, Z> type);
default @Nullable <T, Z> T readData(@NotNull final Player player,
@NotNull final NamespacedKey key,
@NotNull final PersistentDataType<T, Z> type) {
return this.getState(player, key.toString());
}
/**
* Get all data keys for a player.
@@ -148,14 +250,12 @@ public interface Menu {
* @deprecated Use getState instead.
*/
@Deprecated(since = "6.35.0", forRemoval = true)
Set<NamespacedKey> getKeys(@NotNull Player player);
/**
* Re-render the menu for a player.
*
* @param player The player.
*/
void refresh(@NotNull Player player);
default Set<NamespacedKey> getKeys(@NotNull final Player player) {
return this.getState(player).keySet().stream()
.map(NamespacedKeyUtils::fromStringOrNull)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
}
/**
* Create a builder with a given amount of rows.
@@ -164,6 +264,19 @@ public interface Menu {
* @return The builder.
*/
static MenuBuilder builder(final int rows) {
return Eco.getHandler().getGUIFactory().createMenuBuilder(rows);
return Eco.get().createMenuBuilder(
rows,
MenuType.NORMAL
);
}
/**
* Create a builder with a given type.
*
* @param type The menu type.
* @return The builder.
*/
static MenuBuilder builder(@NotNull final MenuType type) {
return Eco.get().createMenuBuilder(type.getDefaultRows(), type);
}
}

View File

@@ -1,5 +1,8 @@
package com.willfp.eco.core.gui.menu;
import com.willfp.eco.core.gui.GUIComponent;
import com.willfp.eco.core.gui.page.Page;
import com.willfp.eco.core.gui.page.PageBuilder;
import com.willfp.eco.core.gui.slot.FillerMask;
import com.willfp.eco.core.gui.slot.Slot;
import org.bukkit.entity.Player;
@@ -8,11 +11,12 @@ import org.jetbrains.annotations.NotNull;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* Builder to create menus.
*/
public interface MenuBuilder {
public interface MenuBuilder extends PageBuilder {
/**
* Set the menu title.
*
@@ -21,6 +25,15 @@ public interface MenuBuilder {
*/
MenuBuilder setTitle(@NotNull String title);
/**
* Get the menu title.
*
* @return The builder.
*/
default String getTitle() {
return "";
}
/**
* Set a slot.
*
@@ -29,9 +42,44 @@ public interface MenuBuilder {
* @param slot The slot.
* @return The builder.
*/
MenuBuilder setSlot(int row,
@Override
default MenuBuilder setSlot(final int row,
final int column,
@NotNull final Slot slot) {
return this.addComponent(row, column, slot);
}
/**
* Add a component.
*
* @param layer The layer.
* @param row The row of the top left corner.
* @param column The column of the top left corner.
* @param component The component.
* @return The builder.
*/
@Override
MenuBuilder addComponent(@NotNull MenuLayer layer,
int row,
int column,
@NotNull Slot slot);
@NotNull GUIComponent component);
/**
* Add a component.
*
* @param row The row of the top left corner.
* @param column The column of the top left corner.
* @param component The component.
* @return The builder.
*/
@Override
default MenuBuilder addComponent(final int row,
final int column,
@NotNull final GUIComponent component) {
return this.addComponent(MenuLayer.MIDDLE, row, column, component);
}
/**
* Run function to modify the builder.
@@ -47,21 +95,65 @@ public interface MenuBuilder {
* @param mask The mask.
* @return The builder.
*/
MenuBuilder setMask(@NotNull FillerMask mask);
@Override
default MenuBuilder setMask(@NotNull final FillerMask mask) {
return this.addComponent(MenuLayer.BACKGROUND, 1, 1, mask);
}
/**
* Set the menu close handler.
* Add a page.
*
* @param page The page.
* @return The builder.
*/
default MenuBuilder addPage(@NotNull final Page page) {
return this.addComponent(MenuLayer.TOP, 1, 1, page);
}
/**
* Add a page.
*
* @param pageNumber The page number.
* @param builder The page builder.
* @return The builder.
*/
default MenuBuilder addPage(final int pageNumber,
@NotNull final PageBuilder builder) {
return this.addPage(new Page(pageNumber, ((MenuBuilder) builder).build()));
}
/**
* Set the max pages.
*
* @param pages The max pages.
* @return The builder.
*/
default MenuBuilder maxPages(final int pages) {
return this.maxPages(player -> pages);
}
/**
* Set the max pages dynamically for a player.
*
* @param pages The max pages.
* @return The builder.
*/
default MenuBuilder maxPages(@NotNull final Function<Player, Integer> pages) {
return onOpen((player, menu) -> menu.addState(player, Page.MAX_PAGE_KEY, pages.apply(player)));
}
/**
* Add a menu close handler.
*
* @param action The handler.
* @return The builder.
*/
default MenuBuilder onClose(@NotNull Consumer<InventoryCloseEvent> action) {
onClose((event, menu) -> action.accept(event));
return this;
default MenuBuilder onClose(@NotNull final Consumer<InventoryCloseEvent> action) {
return this.onClose((event, menu) -> action.accept(event));
}
/**
* Set the menu close handler.
* Add a menu close handler.
*
* @param action The handler.
* @return The builder.
@@ -69,13 +161,40 @@ public interface MenuBuilder {
MenuBuilder onClose(@NotNull CloseHandler action);
/**
* Set the action to run on render.
* Add a menu open handler.
*
* @param action The handler.
* @return The builder.
*/
MenuBuilder onOpen(@NotNull OpenHandler action);
/**
* Add an action to run on render.
*
* @param action The action.
* @return The builder.
*/
MenuBuilder onRender(@NotNull BiConsumer<Player, Menu> action);
/**
* Add an action to run on an event.
*
* @param action The action.
* @return The builder.
*/
default MenuBuilder onEvent(@NotNull final MenuEventHandler<?> action) {
return this;
}
/**
* Allow the player to change their held item.
*
* @return The builder.
*/
default MenuBuilder allowChangingHeldItem() {
return this;
}
/**
* Build the menu.
*

View File

@@ -0,0 +1,8 @@
package com.willfp.eco.core.gui.menu;
/**
* Represents an event sent to a menu.
*/
public interface MenuEvent {
}

View File

@@ -0,0 +1,45 @@
package com.willfp.eco.core.gui.menu;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
/**
* Handles menu events.
*/
public abstract class MenuEventHandler<T extends MenuEvent> {
/**
* The class of the event.
*/
private final Class<T> eventClass;
/**
* Create a new menu event handler.
*
* @param eventClass The class of event to handle.
*/
protected MenuEventHandler(@NotNull final Class<T> eventClass) {
this.eventClass = eventClass;
}
/**
* Performs this operation on the given arguments.
*
* @param player The player.
* @param menu The menu.
* @param event The event.
*/
public abstract void handle(@NotNull Player player,
@NotNull Menu menu,
@NotNull T event);
/**
* Get if this handler can handle a certain event.
*
* @param menuEvent The event
* @return If the event can be handled.
*/
public boolean canHandleEvent(@NotNull final MenuEvent menuEvent) {
return eventClass.isAssignableFrom(menuEvent.getClass());
}
}

View File

@@ -0,0 +1,31 @@
package com.willfp.eco.core.gui.menu;
/**
* Different layers of the menu.
*/
public enum MenuLayer {
/**
* Right at the back.
*/
BACKGROUND,
/**
* Second from the back.
*/
LOWER,
/**
* In the middle (default).
*/
MIDDLE,
/**
* Near the top.
*/
UPPER,
/**
* At the absolute top.
*/
TOP
}

View File

@@ -0,0 +1,56 @@
package com.willfp.eco.core.gui.menu;
/**
* The type of menu.
*/
public enum MenuType {
/**
* Normal menu (1x9, 2x9, 3x9, etc).
*/
NORMAL(9, 6),
/**
* Dispenser menu (3x3).
*/
DISPENSER(3, 3);
/**
* The amount of columns.
*/
private final int columns;
/**
* The default amount of rows.
*/
private final int defaultRows;
/**
* Create a new menu type.
*
* @param columns The number of columns.
* @param defaultRows The default number of rows.
*/
MenuType(final int columns,
final int defaultRows) {
this.columns = columns;
this.defaultRows = defaultRows;
}
/**
* Get the amount of columns.
*
* @return The columns.
*/
public int getColumns() {
return columns;
}
/**
* Get the default amount of rows.
*
* @return The default amount of rows.
*/
public int getDefaultRows() {
return defaultRows;
}
}

View File

@@ -0,0 +1,19 @@
package com.willfp.eco.core.gui.menu;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
/**
* Interface to run on menu open.
*/
@FunctionalInterface
public interface OpenHandler {
/**
* Performs this operation on the given arguments.
*
* @param player The player.
* @param menu The menu.
*/
void handle(@NotNull Player player,
@NotNull Menu menu);
}

View File

@@ -0,0 +1,117 @@
package com.willfp.eco.core.gui.page;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.gui.GUIComponent;
import com.willfp.eco.core.gui.menu.Menu;
import com.willfp.eco.core.gui.menu.MenuBuilder;
import com.willfp.eco.core.gui.slot.Slot;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
/**
* A page is a component representing another menu.
* This allows full component support in pagination.
*/
public final class Page implements GUIComponent {
/**
* The Menu state key for the current page.
*/
public static final String PAGE_KEY = "page";
/**
* The Menu state key for the amount of pages.
*/
public static final String MAX_PAGE_KEY = "max_page";
/**
* The page number.
*/
private final int pageNumber;
/**
* The base menu.
*/
private final Menu page;
/**
* The delegate menu.
*/
private Menu delegate = null;
/**
* The rows for the page to have.
*/
private int rows = 6;
/**
* The columns for the page to have.
*/
private int columns = 9;
/**
* Create a new page.
*
* @param pageNumber The page number.
* @param page The base menu.
*/
public Page(final int pageNumber,
@NotNull final Menu page) {
this.pageNumber = pageNumber;
this.page = page;
}
/**
* Get the current page number.
*
* @return The page number.
*/
public int getPageNumber() {
return this.pageNumber;
}
@Override
public @Nullable Slot getSlotAt(final int row,
final int column,
@NotNull final Player player,
@NotNull final Menu menu) {
if (menu.getPage(player) != pageNumber) {
return null;
}
if (delegate == null) {
delegate = Eco.get().blendMenuState(page, menu);
}
return page.getSlot(row, column, player, delegate);
}
@Override
public void init(final int maxRows,
final int maxColumns) {
this.rows = maxRows;
this.columns = maxColumns;
}
@Override
public int getRows() {
return rows;
}
@Override
public int getColumns() {
return columns;
}
/**
* Create a new page builder.
*
* @param context The context to create the page for.
* @return The page builder.
*/
public static PageBuilder builder(@NotNull final MenuBuilder context) {
return Menu.builder(context.getRows());
}
}

View File

@@ -0,0 +1,92 @@
package com.willfp.eco.core.gui.page;
import com.willfp.eco.core.gui.GUIComponent;
import com.willfp.eco.core.gui.menu.Menu;
import com.willfp.eco.core.gui.menu.MenuLayer;
import com.willfp.eco.core.gui.slot.FillerMask;
import com.willfp.eco.core.gui.slot.Slot;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.function.BiConsumer;
/**
* Builder to create pages.
*/
public interface PageBuilder {
/**
* Get the amount of rows.
*
* @return The amount of rows.
*/
int getRows();
/**
* Get the amount of columns.
*
* @return The amount of columns.
*/
int getColumns();
/**
* Set a slot.
*
* @param row The row.
* @param column The column.
* @param slot The slot.
* @return The builder.
*/
default PageBuilder setSlot(final int row,
final int column,
@NotNull final Slot slot) {
return this.addComponent(row, column, slot);
}
/**
* Add a component.
*
* @param layer The layer.
* @param row The row of the top left corner.
* @param column The column of the top left corner.
* @param component The component.
* @return The builder.
*/
PageBuilder addComponent(@NotNull MenuLayer layer,
int row,
int column,
@NotNull GUIComponent component);
/**
* Add a component.
*
* @param row The row of the top left corner.
* @param column The column of the top left corner.
* @param component The component.
* @return The builder.
*/
default PageBuilder addComponent(final int row,
final int column,
@NotNull final GUIComponent component) {
return this.addComponent(MenuLayer.MIDDLE, row, column, component);
}
/**
* Set the menu mask.
*
* @param mask The mask.
* @return The builder.
*/
default PageBuilder setMask(@NotNull final FillerMask mask) {
return this.addComponent(MenuLayer.BACKGROUND, 1, 1, mask);
}
/**
* Set the action to run on render.
*
* @param action The action.
* @return The builder.
*/
PageBuilder onRender(@NotNull BiConsumer<Player, Menu> action);
}

View File

@@ -0,0 +1,16 @@
package com.willfp.eco.core.gui.page;
import com.willfp.eco.core.gui.menu.MenuEvent;
/**
* Represents a page change.
*
* @param newPage The new page.
* @param oldPage The old page.
*/
public record PageChangeEvent(
int newPage,
int oldPage
) implements MenuEvent {
}

View File

@@ -0,0 +1,126 @@
package com.willfp.eco.core.gui.page;
import com.willfp.eco.core.gui.GUIComponent;
import com.willfp.eco.core.gui.menu.Menu;
import com.willfp.eco.core.gui.slot.Slot;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* A slot loaded in from config.
*/
public final class PageChanger implements GUIComponent {
/**
* The slot to be shown.
*/
private final Slot slot;
/**
* The direction to turn the page.
*/
private final Direction direction;
/**
* Create a new page change slot.
*
* @param itemStack The ItemStack.
* @param direction The direction.
*/
public PageChanger(@NotNull final ItemStack itemStack,
@NotNull final Direction direction) {
this.direction = direction;
slot = Slot.builder(itemStack)
.onLeftClick((event, slot, menu) -> {
Player player = (Player) event.getWhoClicked();
int page = menu.getPage(player);
int newPage = Math.max(
1,
Math.min(
page + direction.getChange(),
menu.getMaxPage(player)
)
);
if (newPage == page) {
return;
}
menu.addState(player, Page.PAGE_KEY, newPage);
menu.callEvent(player, new PageChangeEvent(
newPage,
page
));
})
.build();
}
@Override
public int getRows() {
return 1;
}
@Override
public int getColumns() {
return 1;
}
@Override
public @Nullable Slot getSlotAt(final int row,
final int column,
@NotNull final Player player,
@NotNull final Menu menu) {
int page = menu.getPage(player);
int maxPage = menu.getMaxPage(player);
if (page <= 1 && this.direction == Direction.BACKWARDS) {
return null;
}
if (page >= maxPage - 1 && this.direction == Direction.FORWARDS) {
return null;
}
return slot;
}
/**
* The direction to change the page.
*/
public enum Direction {
/**
* Increment the page by 1.
*/
FORWARDS(1),
/**
* Decrement the page by 1.
*/
BACKWARDS(-1);
/**
* The amount of pages to change by.
*/
private final int change;
/**
* Create a new direction.
*
* @param change The amount of pages to change by.
*/
Direction(final int change) {
this.change = change;
}
/**
* Get the amount of pages to change by.
*
* @return The change.
*/
public int getChange() {
return change;
}
}
}

View File

@@ -0,0 +1,123 @@
package com.willfp.eco.core.gui.slot;
import com.willfp.eco.core.config.interfaces.Config;
import com.willfp.eco.core.gui.slot.functional.SlotHandler;
import com.willfp.eco.core.items.Items;
import com.willfp.eco.util.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
/**
* A slot loaded in from config.
*/
public class ConfigSlot extends CustomSlot {
/**
* The config of the slot.
*/
private final Config config;
/**
* Cached handlers, for performance.
*/
private final Map<String, List<CommandToDispatch>> handlers = new HashMap<>();
/**
* Create a new config slot.
*
* @param config The config.
*/
public ConfigSlot(@NotNull final Config config) {
this.config = config;
SlotBuilder builder = Slot.builder(Items.lookup(config.getString("item")));
for (ClickType clickType : ClickType.values()) {
builder.onClick(
clickType,
dispatchCommandHandler(
clickType.name().toLowerCase(Locale.ROOT)
.replace("_", "-")
+ "-click"
)
);
}
init(builder.build());
}
/**
* Create a slot handler for dispatching commands.
*
* @param configKey The config key.
* @return The handler.
*/
private SlotHandler dispatchCommandHandler(@NotNull final String configKey) {
if (!handlers.containsKey(configKey)) {
List<CommandToDispatch> commands = new ArrayList<>();
for (String command : config.getStrings(configKey)) {
if (command.startsWith("console:")) {
commands.add(new CommandToDispatch(
StringUtils.removePrefix("console:", command),
true
));
} else {
commands.add(new CommandToDispatch(
command,
false
));
}
}
handlers.put(configKey, commands);
}
List<CommandToDispatch> toDispatch = handlers.get(configKey);
return (event, slot, menu) -> {
Player player = (Player) event.getWhoClicked();
for (CommandToDispatch dispatch : toDispatch) {
dispatch.dispatch(player);
}
};
}
/**
* Signifies a command to dispatch.
*
* @param command The command.
* @param console If the command should be run as console.
*/
private record CommandToDispatch(
@NotNull String command,
boolean console
) {
/**
* Dispatch command.
*
* @param player The player.
*/
void dispatch(@NotNull final Player player) {
if (console()) {
Bukkit.dispatchCommand(
Bukkit.getConsoleSender(),
command().replace("%player%", player.getName())
);
} else {
Bukkit.dispatchCommand(
player,
command().replace("%player%", player.getName())
);
}
}
}
}

View File

@@ -0,0 +1,94 @@
package com.willfp.eco.core.gui.slot;
import com.willfp.eco.core.gui.menu.Menu;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
/**
* Base class for custom slot implementations.
*/
public abstract class CustomSlot implements Slot {
/**
* The internal slot to delegate to.
*/
private Slot delegate = null;
/**
* Create a new custom slot.
*/
protected CustomSlot() {
}
/**
* Initialize the slot with the delegate.
*
* @param slot The slot to delegate to.
*/
protected void init(@NotNull final Slot slot) {
this.delegate = slot;
}
@Override
public ItemStack getItemStack(@NotNull final Player player) {
if (delegate == null) {
throw new IllegalStateException("Custom Slot was not initialized!");
}
return delegate.getItemStack(player);
}
@Override
public boolean isCaptive(@NotNull final Player player,
@NotNull final Menu menu) {
if (delegate == null) {
throw new IllegalStateException("Custom Slot was not initialized!");
}
return delegate.isCaptive(player, menu);
}
@Override
public boolean isCaptiveFromEmpty() {
if (delegate == null) {
throw new IllegalStateException("Custom Slot was not initialized!");
}
return delegate.isCaptiveFromEmpty();
}
@Override
public final Slot getActionableSlot(@NotNull final Player player,
@NotNull final Menu menu) {
return delegate;
}
@Override
public final int getRows() {
return Slot.super.getRows();
}
@Override
public final int getColumns() {
return Slot.super.getColumns();
}
@Override
public final Slot getSlotAt(int row, int column) {
return Slot.super.getSlotAt(row, column);
}
/**
* Get the delegate slot.
* <p>
* This is not required to add the slot to a menu, but is instead used internally.
*
* @return The slot.
* @deprecated Replaced with {@link Slot#getActionableSlot(Player, Menu)}
*/
@Deprecated(since = "6.43.0", forRemoval = true)
public Slot getDelegate() {
return this.delegate;
}
}

View File

@@ -1,5 +1,6 @@
package com.willfp.eco.core.gui.slot;
import com.willfp.eco.core.gui.GUIComponent;
import com.willfp.eco.core.items.builder.ItemStackBuilder;
import com.willfp.eco.core.recipe.parts.EmptyTestableItem;
import com.willfp.eco.core.recipe.parts.MaterialTestableItem;
@@ -7,6 +8,7 @@ import com.willfp.eco.util.ListUtils;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.List;
@@ -26,12 +28,17 @@ import java.util.List;
* "11111111"
* );
*/
public class FillerMask {
public class FillerMask implements GUIComponent {
/**
* Mask.
*/
private final List<List<Slot>> mask;
/**
* Rows.
*/
private final int rows;
/**
* Create a new filler mask.
*
@@ -71,7 +78,8 @@ public class FillerMask {
throw new IllegalArgumentException("Items cannot be empty!");
}
mask = ListUtils.create2DList(6, 9);
rows = pattern.length;
mask = ListUtils.create2DList(rows, 9);
for (int i = 0; i < items.items().length; i++) {
ItemStack itemStack = new ItemStackBuilder(items.items()[i])
@@ -82,9 +90,6 @@ public class FillerMask {
for (String patternRow : pattern) {
int column = 0;
if (patternRow.length() != 9) {
throw new IllegalArgumentException("Invalid amount of columns in pattern!");
}
for (char c : patternRow.toCharArray()) {
if (c == '0') {
mask.get(row).set(column, null);
@@ -107,4 +112,20 @@ public class FillerMask {
public List<List<Slot>> getMask() {
return this.mask;
}
@Override
public int getRows() {
return rows;
}
@Override
public int getColumns() {
return 9;
}
@Override
public @Nullable Slot getSlotAt(final int row,
final int column) {
return mask.get(row - 1).get(column - 1);
}
}

View File

@@ -1,6 +1,5 @@
package com.willfp.eco.core.gui.slot;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
@@ -9,37 +8,16 @@ import org.jetbrains.annotations.NotNull;
* <p>
* Useful for backgrounds.
*/
public class FillerSlot implements Slot {
/**
* The ItemStack.
*/
private final ItemStack itemStack;
public class FillerSlot extends CustomSlot {
/**
* Create new filler slot.
*
* @param itemStack The ItemStack.
*/
public FillerSlot(@NotNull final ItemStack itemStack) {
this.itemStack = itemStack;
}
@Override
public ItemStack getItemStack(@NotNull final Player player) {
return itemStack;
}
@Override
public boolean isCaptive() {
return false;
}
/**
* Get the ItemStack.
*
* @return The ItemStack.
*/
public ItemStack getItemStack() {
return this.itemStack;
init(
Slot.builder(itemStack)
.build()
);
}
}

View File

@@ -0,0 +1,62 @@
package com.willfp.eco.core.gui.slot;
import com.willfp.eco.core.gui.menu.Menu;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
/**
* Base class for custom slot implementations.
*/
public abstract class ReactiveSlot implements Slot {
/**
* Create a new reactive slot.
*/
protected ReactiveSlot() {
}
/**
* Get the actual slot to be shown.
*
* @param player The player.
* @param menu The menu.
* @return The slot.
*/
@NotNull
public abstract Slot getSlot(@NotNull final Player player,
@NotNull final Menu menu);
@Override
public ItemStack getItemStack(@NotNull final Player player) {
return new ItemStack(Material.STONE);
}
@Override
public boolean isCaptive(@NotNull final Player player,
@NotNull final Menu menu) {
return getSlot(player, menu).isCaptive(player, menu);
}
@Override
public final Slot getActionableSlot(@NotNull final Player player,
@NotNull final Menu menu) {
return getSlot(player, menu);
}
@Override
public final int getRows() {
return Slot.super.getRows();
}
@Override
public final int getColumns() {
return Slot.super.getColumns();
}
@Override
public final Slot getSlotAt(int row, int column) {
return Slot.super.getSlotAt(row, column);
}
}

View File

@@ -1,7 +1,10 @@
package com.willfp.eco.core.gui.slot;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.gui.GUIComponent;
import com.willfp.eco.core.gui.menu.Menu;
import com.willfp.eco.core.gui.slot.functional.SlotProvider;
import com.willfp.eco.core.items.TestableItem;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
@@ -11,8 +14,16 @@ import java.util.function.Function;
/**
* A slot is an item in a GUI that can handle clicks.
* <p>
* While you can create custom Slot implementations directly from this class,
* it's heavily encouraged to extend {@link CustomSlot}, which will abstract
* internal functionality away.
* <p>
* A lot of methods here are marked as default as in 6.43.0 the GUI system
* was overhauled, but to preserve backwards compatibility, the new methods
* had to be marked default, and many old methods became deprecated.
*/
public interface Slot {
public interface Slot extends GUIComponent {
/**
* Get the ItemStack that would be shown to a player.
*
@@ -24,18 +35,34 @@ public interface Slot {
/**
* If the slot is captive. (Can items be placed in it).
*
* @param player The player.
* @param menu The menu.
* @return If captive.
*/
boolean isCaptive();
default boolean isCaptive(@NotNull final Player player,
@NotNull final Menu menu) {
return false;
}
/**
* If the slot is not captive for a player.
* Get the actionable slot to be shown.
* <p>
* This is mostly internal, if you want to implement custom slots you should
* turn to {@link CustomSlot} or {@link ReactiveSlot}, which abstract this
* behaviour away.
* <p>
* **Never** return {@code this} from this method. Always make sure that your
* slots eventually delegate to a slot created by {@link Slot#builder()}.
* <p>
* {@code this} is returned by default for backwards-compatibility.
*
* @param player The player.
* @return If not captive for the player.
* @param menu The menu.
* @return The slot.
*/
default boolean isNotCaptiveFor(@NotNull Player player) {
return false;
default Slot getActionableSlot(@NotNull final Player player,
@NotNull final Menu menu) {
return this;
}
/**
@@ -48,13 +75,29 @@ public interface Slot {
return false;
}
@Override
default int getRows() {
return 1;
}
@Override
default int getColumns() {
return 1;
}
@Override
default Slot getSlotAt(final int row,
final int column) {
return this;
}
/**
* Create a builder for an ItemStack.
*
* @return The builder.
*/
static SlotBuilder builder() {
return Eco.getHandler().getGUIFactory().createSlotBuilder((player, menu) -> new ItemStack(Material.AIR));
return Eco.get().createSlotBuilder((player, menu) -> new ItemStack(Material.AIR));
}
/**
@@ -64,7 +107,17 @@ public interface Slot {
* @return The builder.
*/
static SlotBuilder builder(@NotNull final ItemStack itemStack) {
return Eco.getHandler().getGUIFactory().createSlotBuilder((player, menu) -> itemStack);
return Eco.get().createSlotBuilder((player, menu) -> itemStack);
}
/**
* Create a builder for a TestableItem.
*
* @param item The item.
* @return The builder.
*/
static SlotBuilder builder(@NotNull final TestableItem item) {
return Eco.get().createSlotBuilder((player, menu) -> item.getItem());
}
/**
@@ -74,7 +127,7 @@ public interface Slot {
* @return The builder.
*/
static SlotBuilder builder(@NotNull final Function<Player, ItemStack> provider) {
return Eco.getHandler().getGUIFactory().createSlotBuilder((player, menu) -> provider.apply(player));
return Eco.get().createSlotBuilder((player, menu) -> provider.apply(player));
}
/**
@@ -84,6 +137,29 @@ public interface Slot {
* @return The builder.
*/
static SlotBuilder builder(@NotNull final SlotProvider provider) {
return Eco.getHandler().getGUIFactory().createSlotBuilder(provider);
return Eco.get().createSlotBuilder(provider);
}
/**
* If the slot is not captive for a player.
*
* @param player The player.
* @return If not captive for the player.
* @deprecated Captivity is now reactive, this method can produce incorrect results.
*/
@Deprecated(since = "6.43.0", forRemoval = true)
default boolean isNotCaptiveFor(@NotNull Player player) {
return false;
}
/**
* If the slot is captive. (Can items be placed in it).
*
* @return If captive.
* @deprecated Captivity is now reactive, this method can produce incorrect results.
*/
@Deprecated(since = "6.43.0", forRemoval = true)
default boolean isCaptive() {
return false;
}
}

View File

@@ -4,6 +4,7 @@ import com.willfp.eco.core.gui.slot.functional.SlotHandler;
import com.willfp.eco.core.gui.slot.functional.SlotModifier;
import com.willfp.eco.core.gui.slot.functional.SlotUpdater;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.jetbrains.annotations.NotNull;
@@ -14,6 +15,28 @@ import java.util.function.Predicate;
* Builder to create slots.
*/
public interface SlotBuilder {
/**
* Set click handler.
*
* @param type The click type.
* @param handler The handler.
* @return The builder.
*/
SlotBuilder onClick(@NotNull ClickType type,
@NotNull SlotHandler handler);
/**
* Set click handler.
*
* @param type The click type.
* @param action The handler.
* @return The builder.
*/
default SlotBuilder onClick(@NotNull final ClickType type,
@NotNull final BiConsumer<InventoryClickEvent, Slot> action) {
return onClick(type, (event, slot, menu) -> action.accept(event, slot));
}
/**
* Set click handler.
*
@@ -30,7 +53,9 @@ public interface SlotBuilder {
* @param handler The handler.
* @return The builder.
*/
SlotBuilder onLeftClick(@NotNull SlotHandler handler);
default SlotBuilder onLeftClick(@NotNull final SlotHandler handler) {
return onClick(ClickType.LEFT, handler);
}
/**
* Set click handler.
@@ -48,7 +73,9 @@ public interface SlotBuilder {
* @param handler The handler.
* @return The builder.
*/
SlotBuilder onRightClick(@NotNull SlotHandler handler);
default SlotBuilder onRightClick(@NotNull final SlotHandler handler) {
return onClick(ClickType.RIGHT, handler);
}
/**
* Set click handler.
@@ -66,7 +93,9 @@ public interface SlotBuilder {
* @param handler The handler.
* @return The builder.
*/
SlotBuilder onShiftLeftClick(@NotNull SlotHandler handler);
default SlotBuilder onShiftLeftClick(@NotNull final SlotHandler handler) {
return onClick(ClickType.SHIFT_LEFT, handler);
}
/**
* Set click handler.
@@ -84,7 +113,9 @@ public interface SlotBuilder {
* @param handler The handler.
* @return The builder.
*/
SlotBuilder onShiftRightClick(@NotNull SlotHandler handler);
default SlotBuilder onShiftRightClick(@NotNull final SlotHandler handler) {
return onClick(ClickType.SHIFT_RIGHT, handler);
}
/**
* Set click handler.
@@ -102,7 +133,9 @@ public interface SlotBuilder {
* @param handler The handler.
* @return The builder.
*/
SlotBuilder onMiddleClick(@NotNull SlotHandler handler);
default SlotBuilder onMiddleClick(@NotNull final SlotHandler handler) {
return onClick(ClickType.MIDDLE, handler);
}
/**
* Prevent captive for players that match a predicate.
@@ -112,21 +145,6 @@ public interface SlotBuilder {
*/
SlotBuilder notCaptiveFor(@NotNull Predicate<Player> predicate);
/**
* Modify the ItemStack.
*
* @param modifier The modifier.
* @return The builder.
* @deprecated Use {@link SlotBuilder#setUpdater(SlotUpdater)} instead.
*/
@Deprecated
default SlotBuilder setModifier(@NotNull SlotModifier modifier) {
return setUpdater((player, menu, previous) -> {
modifier.modify(player, menu, previous);
return previous;
});
}
/**
* Set the ItemStack updater.
*
@@ -158,4 +176,19 @@ public interface SlotBuilder {
* @return The slot.
*/
Slot build();
/**
* Modify the ItemStack.
*
* @param modifier The modifier.
* @return The builder.
* @deprecated Use {@link SlotBuilder#setUpdater(SlotUpdater)} instead.
*/
@Deprecated
default SlotBuilder setModifier(@NotNull SlotModifier modifier) {
return setUpdater((player, menu, previous) -> {
modifier.modify(player, menu, previous);
return previous;
});
}
}

View File

@@ -4,6 +4,7 @@ import com.willfp.eco.core.gui.menu.Menu;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Interface to run on slot display.
@@ -17,6 +18,7 @@ public interface SlotProvider {
* @param menu The menu.
* @return The ItemStack.
*/
@Nullable
ItemStack provide(@NotNull Player player,
@NotNull Menu menu);
}

View File

@@ -4,6 +4,7 @@ import com.willfp.eco.core.gui.menu.Menu;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Interface to run on slot update.
@@ -18,6 +19,7 @@ public interface SlotUpdater {
* @param previous The previous ItemStack.
* @return The new ItemStack.
*/
@Nullable
ItemStack update(@NotNull Player player,
@NotNull Menu menu,
@NotNull ItemStack previous);

View File

@@ -38,7 +38,7 @@ public final class AnticheatManager {
*/
public static void register(@NotNull final AnticheatIntegration anticheat) {
if (anticheat instanceof Listener) {
Eco.getHandler().getEcoPlugin().getEventManager().registerListener((Listener) anticheat);
Eco.get().getEcoPlugin().getEventManager().registerListener((Listener) anticheat);
}
ANTICHEATS.removeIf(it -> it.getPluginName().equalsIgnoreCase(anticheat.getPluginName()));
ANTICHEATS.add(anticheat);

View File

@@ -4,9 +4,23 @@ import com.willfp.eco.core.integrations.Integration;
import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.NotNull;
import java.math.BigDecimal;
/**
* Wrapper class for economy integrations.
* <p>
* If you're adding your economy to be supported in eco,
* it's recommended to override the {@link BigDecimal} methods
* as opposed to the {@code double} methods.
* <p>
* <strong>You must override at least one of all methods</strong>,
* i.e. one {@code hasAmount}, one {@code giveMoney}, etc.,
* otherwise your integration will cause {@link StackOverflowError}.
* <p>
* All methods are marked as default to preserve compatibility with
* integrations made before 6.43.0.
*/
@SuppressWarnings("DeprecatedIsStillUsed")
public interface EconomyIntegration extends Integration {
/**
* Get if a player has a certain amount.
@@ -14,9 +28,39 @@ public interface EconomyIntegration extends Integration {
* @param player The player.
* @param amount The amount.
* @return If the player has the amount.
* @deprecated Use {@link BigDecimal} methods instead.
*/
boolean hasAmount(@NotNull OfflinePlayer player,
double amount);
@Deprecated(since = "6.43.0")
default boolean hasAmount(@NotNull OfflinePlayer player,
double amount) {
return hasAmount(player, BigDecimal.valueOf(amount));
}
/**
* Get if a player has a certain amount.
*
* @param player The player.
* @param amount The amount
* @return If the player has the amount.
*/
default boolean hasAmount(@NotNull OfflinePlayer player,
@NotNull BigDecimal amount) {
return hasAmount(player, amount.doubleValue());
}
/**
* Give money to a player.
*
* @param player The player.
* @param amount The amount to give.
* @return If the transaction was a success.
* @deprecated Use {@link BigDecimal} methods instead.
*/
@Deprecated(since = "6.43.0")
default boolean giveMoney(@NotNull OfflinePlayer player,
double amount) {
return giveMoney(player, BigDecimal.valueOf(amount));
}
/**
* Give money to a player.
@@ -25,8 +69,24 @@ public interface EconomyIntegration extends Integration {
* @param amount The amount to give.
* @return If the transaction was a success.
*/
boolean giveMoney(@NotNull OfflinePlayer player,
double amount);
default boolean giveMoney(@NotNull OfflinePlayer player,
@NotNull BigDecimal amount) {
return giveMoney(player, amount.doubleValue());
}
/**
* Remove money from a player.
*
* @param player The player.
* @param amount The amount to remove.
* @return If the transaction was a success.
* @deprecated Use {@link BigDecimal} methods instead.
*/
@Deprecated(since = "6.43.0")
default boolean removeMoney(@NotNull OfflinePlayer player,
double amount) {
return removeMoney(player, BigDecimal.valueOf(amount));
}
/**
* Remove money from a player.
@@ -35,8 +95,23 @@ public interface EconomyIntegration extends Integration {
* @param amount The amount to remove.
* @return If the transaction was a success.
*/
boolean removeMoney(@NotNull OfflinePlayer player,
double amount);
default boolean removeMoney(@NotNull OfflinePlayer player,
@NotNull BigDecimal amount) {
return removeMoney(player, amount.doubleValue());
}
/**
* Get the balance of a player.
*
* @param player The player.
* @return The balance.
* @deprecated Use {@link BigDecimal} methods instead.
*/
@Deprecated(since = "6.43.0")
default double getBalance(@NotNull OfflinePlayer player) {
return getExactBalance(player).doubleValue();
}
/**
* Get the balance of a player.
@@ -44,5 +119,7 @@ public interface EconomyIntegration extends Integration {
* @param player The player.
* @return The balance.
*/
double getBalance(@NotNull OfflinePlayer player);
default BigDecimal getExactBalance(@NotNull OfflinePlayer player) {
return BigDecimal.valueOf(getBalance(player));
}
}

View File

@@ -3,6 +3,7 @@ package com.willfp.eco.core.integrations.economy;
import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.NotNull;
import java.math.BigDecimal;
import java.util.HashSet;
import java.util.Set;
@@ -43,6 +44,18 @@ public final class EconomyManager {
*/
public static boolean hasAmount(@NotNull final OfflinePlayer player,
final double amount) {
return hasAmount(player, BigDecimal.valueOf(amount));
}
/**
* Get if a player has a certain amount.
*
* @param player The player.
* @param amount The amount.
* @return If the player has the amount.
*/
public static boolean hasAmount(@NotNull final OfflinePlayer player,
final BigDecimal amount) {
for (EconomyIntegration integration : REGISTERED) {
return integration.hasAmount(player, amount);
}
@@ -59,6 +72,18 @@ public final class EconomyManager {
*/
public static boolean giveMoney(@NotNull final OfflinePlayer player,
final double amount) {
return giveMoney(player, BigDecimal.valueOf(amount));
}
/**
* Give money to a player.
*
* @param player The player.
* @param amount The amount to give.
* @return If the transaction was a success.
*/
public static boolean giveMoney(@NotNull final OfflinePlayer player,
@NotNull final BigDecimal amount) {
for (EconomyIntegration integration : REGISTERED) {
return integration.giveMoney(player, amount);
}
@@ -75,6 +100,18 @@ public final class EconomyManager {
*/
public static boolean removeMoney(@NotNull final OfflinePlayer player,
final double amount) {
return removeMoney(player, BigDecimal.valueOf(amount));
}
/**
* Remove money from a player.
*
* @param player The player.
* @param amount The amount to remove.
* @return If the transaction was a success.
*/
public static boolean removeMoney(@NotNull final OfflinePlayer player,
@NotNull final BigDecimal amount) {
for (EconomyIntegration integration : REGISTERED) {
return integration.removeMoney(player, amount);
}
@@ -89,11 +126,21 @@ public final class EconomyManager {
* @return The balance.
*/
public static double getBalance(@NotNull final OfflinePlayer player) {
for (EconomyIntegration integration : REGISTERED) {
return integration.getBalance(player);
return getExactBalance(player).doubleValue();
}
return 0;
/**
* Get the balance of a player.
*
* @param player The player.
* @return The balance.
*/
public static BigDecimal getExactBalance(@NotNull final OfflinePlayer player) {
for (EconomyIntegration integration : REGISTERED) {
return integration.getExactBalance(player);
}
return BigDecimal.ZERO;
}
private EconomyManager() {

View File

@@ -158,13 +158,13 @@ public class PlaceholderEntry {
Placeholder toModernPlaceholder() {
if (this.requiresPlayer) {
return new PlayerPlaceholder(
Objects.requireNonNullElse(plugin, Eco.getHandler().getEcoPlugin()),
Objects.requireNonNullElse(plugin, Eco.get().getEcoPlugin()),
identifier,
function
);
} else {
return new PlayerlessPlaceholder(
Objects.requireNonNullElse(plugin, Eco.getHandler().getEcoPlugin()),
Objects.requireNonNullElse(plugin, Eco.get().getEcoPlugin()),
identifier,
() -> function.apply(null)
);

View File

@@ -4,6 +4,7 @@ import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.placeholder.AdditionalPlayer;
import com.willfp.eco.core.placeholder.InjectablePlaceholder;
import com.willfp.eco.core.placeholder.Placeholder;
import com.willfp.eco.core.placeholder.PlaceholderInjectable;
@@ -11,11 +12,13 @@ import com.willfp.eco.core.placeholder.PlayerPlaceholder;
import com.willfp.eco.core.placeholder.PlayerStaticPlaceholder;
import com.willfp.eco.core.placeholder.PlayerlessPlaceholder;
import com.willfp.eco.core.placeholder.StaticPlaceholder;
import com.willfp.eco.util.StringUtils;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -23,6 +26,8 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Class to handle placeholder integrations.
@@ -56,11 +61,17 @@ public final class PlaceholderManager {
}
@Override
public @NotNull List<InjectablePlaceholder> getPlaceholderInjections() {
public @NotNull
List<InjectablePlaceholder> getPlaceholderInjections() {
return Collections.emptyList();
}
};
/**
* The default PlaceholderAPI pattern; brought in for compatibility.
*/
private static final Pattern PATTERN = Pattern.compile("[%]([^%]+)[%]");
/**
* Register a new placeholder integration.
*
@@ -81,7 +92,7 @@ public final class PlaceholderManager {
throw new IllegalArgumentException("Static placeholders cannot be registered!");
}
EcoPlugin plugin = placeholder.getPlugin() == null ? Eco.getHandler().getEcoPlugin() : placeholder.getPlugin();
EcoPlugin plugin = placeholder.getPlugin() == null ? Eco.get().getEcoPlugin() : placeholder.getPlugin();
Map<String, Placeholder> pluginPlaceholders = REGISTERED_PLACEHOLDERS
.getOrDefault(plugin, new HashMap<>());
pluginPlaceholders.put(placeholder.getIdentifier(), placeholder);
@@ -125,11 +136,11 @@ public final class PlaceholderManager {
public static String getResult(@Nullable final Player player,
@NotNull final String identifier,
@Nullable final EcoPlugin plugin) {
EcoPlugin owner = plugin == null ? Eco.getHandler().getEcoPlugin() : plugin;
EcoPlugin owner = plugin == null ? Eco.get().getEcoPlugin() : plugin;
Placeholder placeholder = REGISTERED_PLACEHOLDERS.getOrDefault(owner, new HashMap<>()).get(identifier.toLowerCase());
if (placeholder == null && plugin != null) {
Placeholder alternate = REGISTERED_PLACEHOLDERS.getOrDefault(Eco.getHandler().getEcoPlugin(), new HashMap<>())
Placeholder alternate = REGISTERED_PLACEHOLDERS.getOrDefault(Eco.get().getEcoPlugin(), new HashMap<>())
.get(identifier.toLowerCase());
if (alternate != null) {
placeholder = alternate;
@@ -192,7 +203,45 @@ public final class PlaceholderManager {
public static String translatePlaceholders(@NotNull final String text,
@Nullable final Player player,
@NotNull final PlaceholderInjectable context) {
return translatePlaceholders(text, player, context, new ArrayList<>());
}
/**
* Translate all placeholders with respect to a player.
*
* @param text The text that may contain placeholders to translate.
* @param player The player to translate the placeholders with respect to.
* @param context The injectable context.
* @param additionalPlayers Additional players to translate placeholders for.
* @return The text, translated.
*/
public static String translatePlaceholders(@NotNull final String text,
@Nullable final Player player,
@NotNull final PlaceholderInjectable context,
@NotNull final Collection<AdditionalPlayer> additionalPlayers) {
String processed = text;
// Prevent running 2 scans if there are no additional players.
if (!additionalPlayers.isEmpty()) {
List<String> found = findPlaceholdersIn(text);
for (AdditionalPlayer additionalPlayer : additionalPlayers) {
for (String placeholder : found) {
String prefix = "%" + additionalPlayer.getIdentifier() + "_";
if (placeholder.startsWith(prefix)) {
processed = processed.replace(
placeholder,
translatePlaceholders(
"%" + StringUtils.removePrefix(prefix, placeholder),
additionalPlayer.getPlayer()
)
);
}
}
}
}
for (PlaceholderIntegration integration : REGISTERED_INTEGRATIONS) {
processed = integration.translate(processed, player);
}
@@ -214,12 +263,21 @@ public final class PlaceholderManager {
* @return The placeholders.
*/
public static List<String> findPlaceholdersIn(@NotNull final String text) {
List<String> found = new ArrayList<>();
Set<String> found = new HashSet<>();
// Mock PAPI for those without it installed
if (REGISTERED_INTEGRATIONS.isEmpty()) {
Matcher matcher = PATTERN.matcher(text);
while (matcher.find()) {
found.add(matcher.group());
}
}
for (PlaceholderIntegration integration : REGISTERED_INTEGRATIONS) {
found.addAll(integration.findPlaceholdersIn(text));
}
return found;
return new ArrayList<>(found);
}
private record EntryWithPlayer(@NotNull PlayerPlaceholder entry,

View File

@@ -1,7 +1,10 @@
package com.willfp.eco.core.integrations.shop;
import com.willfp.eco.core.integrations.Integration;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
@@ -25,4 +28,27 @@ public interface ShopIntegration extends Integration {
// Do nothing unless overridden.
return null;
}
/**
* Get the price of an item.
*
* @param itemStack The item.
* @return The price.
*/
default double getPrice(@NotNull final ItemStack itemStack) {
// Do nothing unless overridden.
return 0.0;
}
/**
* Get the price of an item.
*
* @param itemStack The item.
* @param player The player.
* @return The price.
*/
default double getPrice(@NotNull final ItemStack itemStack,
@NotNull final Player player) {
return getPrice(itemStack);
}
}

View File

@@ -1,9 +1,12 @@
package com.willfp.eco.core.integrations.shop;
import com.willfp.eco.core.EcoPlugin;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashSet;
import java.util.Set;
@@ -27,22 +30,6 @@ public final class ShopManager {
REGISTERED.add(integration);
}
/**
* Register the events with eco.
*
* @param plugin Instance of eco.
*/
@ApiStatus.Internal
public static void registerEvents(@NotNull final EcoPlugin plugin) {
for (ShopIntegration integration : REGISTERED) {
Listener listener = integration.getSellEventAdapter();
if (listener != null) {
plugin.getEventManager().registerListener(listener);
}
}
}
/**
* Register eco item provider for shop plugins.
*/
@@ -52,6 +39,49 @@ public final class ShopManager {
}
}
/**
* Get the price of an item.
*
* @param itemStack The item.
* @return The price.
*/
public static double getItemPrice(@Nullable final ItemStack itemStack) {
return getItemPrice(itemStack, null);
}
/**
* Get the price of an item.
*
* @param itemStack The item.
* @param player The player.
* @return The price.
*/
public static double getItemPrice(@Nullable final ItemStack itemStack,
@Nullable final Player player) {
if (itemStack == null) {
return 0.0;
}
for (ShopIntegration shopIntegration : REGISTERED) {
if (player == null) {
return shopIntegration.getPrice(itemStack);
} else {
return shopIntegration.getPrice(itemStack, player);
}
}
return 0.0;
}
/**
* Get all registered integrations.
*
* @return The integrations.
*/
public static Set<ShopIntegration> getRegisteredIntegrations() {
return new HashSet<>(REGISTERED);
}
private ShopManager() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}

View File

@@ -53,7 +53,7 @@ public class CustomItem implements TestableItem {
immediately after due to registration order; so eco waits until the item should be
working in order to check.
*/
Eco.getHandler().getEcoPlugin().getScheduler().runLater(() -> {
Eco.get().getEcoPlugin().getScheduler().runLater(() -> {
if (!matches(getItem())) {
Bukkit.getLogger().severe("Item with key " + key + " is invalid!");
}

View File

@@ -81,6 +81,11 @@ public final class Items {
*/
private static final ItemsLookupHandler ITEMS_LOOKUP_HANDLER = new ItemsLookupHandler(Items::doParse);
/**
* Instance of EmptyTestableItem.
*/
private static final TestableItem EMPTY_TESTABLE_ITEM = new EmptyTestableItem();
/**
* Register a new custom item.
*
@@ -187,7 +192,7 @@ public final class Items {
@NotNull
public static TestableItem lookup(@NotNull final String key) {
if (key.startsWith("{")) {
return Eco.getHandler().getSNBTHandler().createTestable(key);
return Eco.get().testableItemFromSNBT(key);
}
return ITEMS_LOOKUP_HANDLER.parseKey(key);
@@ -230,11 +235,11 @@ public final class Items {
String reformattedKey = keyID.replace("__", ":");
item = provider.provideForKey(reformattedKey);
if (item instanceof EmptyTestableItem || item == null) {
part = provider.provideForKey(reformattedKey);
if (part instanceof EmptyTestableItem || part == null) {
return new EmptyTestableItem();
}
registerCustomItem(namespacedKey, item);
registerCustomItem(namespacedKey, part);
}
/*
@@ -533,7 +538,7 @@ public final class Items {
*/
@NotNull
public static String toSNBT(@NotNull final ItemStack itemStack) {
return Eco.getHandler().getSNBTHandler().toSNBT(itemStack);
return Eco.get().toSNBT(itemStack);
}
/**
@@ -544,7 +549,17 @@ public final class Items {
*/
@Nullable
public static ItemStack fromSNBT(@NotNull final String snbt) {
return Eco.getHandler().getSNBTHandler().fromSNBT(snbt);
return Eco.get().fromSNBT(snbt);
}
/**
* Get if an item is empty.
*
* @param itemStack The item.
* @return If empty.
*/
public static boolean isEmpty(@Nullable final ItemStack itemStack) {
return EMPTY_TESTABLE_ITEM.matches(itemStack);
}
private Items() {

View File

@@ -1,41 +0,0 @@
package com.willfp.eco.core.items;
import com.willfp.eco.core.Eco;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* API to handle SNBT conversion.
*/
@ApiStatus.Internal
@Eco.HandlerComponent
public interface SNBTHandler {
/**
* Get item from SNBT.
*
* @param snbt The NBT string.
* @return The ItemStack, or null if invalid.
*/
@Nullable
ItemStack fromSNBT(@NotNull String snbt);
/**
* Convert item to SNBT.
*
* @param itemStack The item.
* @return The NBT string.
*/
@NotNull
String toSNBT(@NotNull ItemStack itemStack);
/**
* Make TestableItem from SNBT.
*
* @param snbt The NBT string.
* @return The TestableItem.
*/
@NotNull
TestableItem createTestable(@NotNull String snbt);
}

View File

@@ -1,5 +1,6 @@
package com.willfp.eco.core.items.builder;
import com.willfp.eco.core.fast.FastItemStack;
import com.willfp.eco.core.items.TestableItem;
import com.willfp.eco.util.StringUtils;
import org.apache.commons.lang.Validate;
@@ -28,7 +29,7 @@ public abstract class AbstractItemStackBuilder<T extends ItemMeta, U extends Abs
/**
* The ItemMeta used while building.
*/
private final T meta;
private T meta;
/**
* The ItemStack.
@@ -113,10 +114,15 @@ public abstract class AbstractItemStackBuilder<T extends ItemMeta, U extends Abs
@Override
public U addLoreLine(@NotNull final String line) {
List<String> lore = meta.hasLore() ? meta.getLore() : new ArrayList<>();
assert lore != null;
base.setItemMeta(meta);
FastItemStack fis = FastItemStack.wrap(base);
List<String> lore = fis.getLore();
lore.add(StringUtils.format(line));
meta.setLore(lore);
fis.setLore(lore);
meta = (T) base.getItemMeta();
return (U) this;
}
@@ -130,12 +136,19 @@ public abstract class AbstractItemStackBuilder<T extends ItemMeta, U extends Abs
@Override
public U addLoreLines(@NotNull final List<String> lines) {
List<String> lore = meta.hasLore() ? meta.getLore() : new ArrayList<>();
assert lore != null;
base.setItemMeta(meta);
FastItemStack fis = FastItemStack.wrap(base);
List<String> lore = fis.getLore();
for (String line : lines) {
lore.add(StringUtils.format(line));
}
meta.setLore(lore);
fis.setLore(lore);
meta = (T) base.getItemMeta();
return (U) this;
}

View File

@@ -0,0 +1,49 @@
package com.willfp.eco.core.placeholder;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
/**
* An additional player with an identifier to parse placeholders for the player.
*/
public class AdditionalPlayer {
/**
* The player.
*/
private final Player player;
/**
* The identifier.
*/
private final String identifier;
/**
* Create a new additional player.
*
* @param player The player.
* @param identifier The identifier.
*/
public AdditionalPlayer(@NotNull final Player player,
@NotNull final String identifier) {
this.player = player;
this.identifier = identifier;
}
/**
* Get the player.
*
* @return The player.
*/
public Player getPlayer() {
return player;
}
/**
* Get the identifier.
*
* @return The identifier.
*/
public String getIdentifier() {
return identifier;
}
}

View File

@@ -9,6 +9,6 @@ import com.willfp.eco.core.EcoPlugin;
public sealed interface InjectablePlaceholder extends Placeholder permits PlayerStaticPlaceholder, StaticPlaceholder {
@Override
default EcoPlugin getPlugin() {
return Eco.getHandler().getEcoPlugin();
return Eco.get().getEcoPlugin();
}
}

View File

@@ -7,7 +7,10 @@ import org.jetbrains.annotations.NotNull;
* A cleaner is an internal component to fix classloader errors.
* <p>
* Important to allow for PlugMan/ServerUtils support.
*
* @deprecated No reason for this to be in the API.
*/
@Deprecated(since = "6.43.0", forRemoval = true)
public interface Cleaner {
/**
* Clean up classes left over from plugin.

View File

@@ -2,7 +2,6 @@ package com.willfp.eco.core.recipe.recipes;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginDependent;
import com.willfp.eco.core.items.TestableItem;
import com.willfp.eco.core.recipe.Recipes;
import com.willfp.eco.core.recipe.parts.EmptyTestableItem;
@@ -25,7 +24,12 @@ import java.util.List;
/**
* Shaped 3x3 crafting recipe.
*/
public final class ShapedCraftingRecipe extends PluginDependent<EcoPlugin> implements CraftingRecipe {
public final class ShapedCraftingRecipe implements CraftingRecipe {
/**
* The plugin.
*/
private final EcoPlugin plugin;
/**
* Recipe parts.
*/
@@ -56,8 +60,7 @@ public final class ShapedCraftingRecipe extends PluginDependent<EcoPlugin> imple
@NotNull final List<TestableItem> parts,
@NotNull final ItemStack output,
@Nullable final String permission) {
super(plugin);
this.plugin = plugin;
this.parts = parts;
this.key = plugin.getNamespacedKeyFactory().create(key);
this.displayedKey = plugin.getNamespacedKeyFactory().create(key + "_displayed");
@@ -96,7 +99,7 @@ public final class ShapedCraftingRecipe extends PluginDependent<EcoPlugin> imple
shapedRecipe.setIngredient(character, parts.get(i).getItem().getType());
}
if (Eco.getHandler().getEcoPlugin().getConfigYml().getBool("displayed-recipes")) {
if (Eco.get().getEcoPlugin().getConfigYml().getBool("displayed-recipes")) {
ShapedRecipe displayedRecipe = new ShapedRecipe(this.getDisplayedKey(), this.getOutput());
displayedRecipe.shape("012", "345", "678");
for (int i = 0; i < 9; i++) {
@@ -124,7 +127,7 @@ public final class ShapedCraftingRecipe extends PluginDependent<EcoPlugin> imple
List<String> lore = meta.hasLore() ? meta.getLore() : new ArrayList<>();
assert lore != null;
lore.add("");
String add = Eco.getHandler().getEcoPlugin().getLangYml().getFormattedString("multiple-in-craft");
String add = Eco.get().getEcoPlugin().getLangYml().getFormattedString("multiple-in-craft");
add = add.replace("%amount%", String.valueOf(item.getAmount()));
lore.add(add);
meta.setLore(lore);
@@ -145,6 +148,15 @@ public final class ShapedCraftingRecipe extends PluginDependent<EcoPlugin> imple
Bukkit.getServer().addRecipe(shapedRecipe);
}
/**
* Get the plugin.
*
* @return The plugin.
*/
public EcoPlugin getPlugin() {
return plugin;
}
/**
* Create a new recipe builder.
*

View File

@@ -3,7 +3,6 @@ package com.willfp.eco.core.recipe.recipes;
import com.google.common.annotations.Beta;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginDependent;
import com.willfp.eco.core.items.TestableItem;
import com.willfp.eco.core.recipe.Recipes;
import com.willfp.eco.core.recipe.parts.EmptyTestableItem;
@@ -26,7 +25,12 @@ import java.util.Optional;
* Shapeless crafting recipe.
*/
@Beta
public final class ShapelessCraftingRecipe extends PluginDependent<EcoPlugin> implements CraftingRecipe {
public final class ShapelessCraftingRecipe implements CraftingRecipe {
/**
* The plugin.
*/
private final EcoPlugin plugin;
/**
* Recipe parts.
*/
@@ -57,8 +61,7 @@ public final class ShapelessCraftingRecipe extends PluginDependent<EcoPlugin> im
@NotNull final List<TestableItem> parts,
@NotNull final ItemStack output,
@Nullable final String permission) {
super(plugin);
this.plugin = plugin;
this.parts = parts;
this.key = plugin.getNamespacedKeyFactory().create(key);
this.displayedKey = plugin.getNamespacedKeyFactory().create(key + "_displayed");
@@ -101,7 +104,7 @@ public final class ShapelessCraftingRecipe extends PluginDependent<EcoPlugin> im
shapelessRecipe.addIngredient(part.getItem().getType());
}
if (Eco.getHandler().getEcoPlugin().getConfigYml().getBool("displayed-recipes")) {
if (Eco.get().getEcoPlugin().getConfigYml().getBool("displayed-recipes")) {
ShapelessRecipe displayedRecipe = new ShapelessRecipe(this.getDisplayedKey(), this.getOutput());
for (TestableItem part : parts) {
List<TestableItem> items = new ArrayList<>();
@@ -122,7 +125,7 @@ public final class ShapelessCraftingRecipe extends PluginDependent<EcoPlugin> im
List<String> lore = meta.hasLore() ? meta.getLore() : new ArrayList<>();
assert lore != null;
lore.add("");
String add = Eco.getHandler().getEcoPlugin().getLangYml().getFormattedString("multiple-in-craft");
String add = Eco.get().getEcoPlugin().getLangYml().getFormattedString("multiple-in-craft");
add = add.replace("%amount%", String.valueOf(item.getAmount()));
lore.add(add);
meta.setLore(lore);
@@ -143,6 +146,15 @@ public final class ShapelessCraftingRecipe extends PluginDependent<EcoPlugin> im
Bukkit.getServer().addRecipe(shapelessRecipe);
}
/**
* Get the plugin.
*
* @return The plugin.
*/
public EcoPlugin getPlugin() {
return plugin;
}
/**
* Create a new recipe builder.
*

View File

@@ -25,13 +25,30 @@ public class Paste {
*/
private final String contents;
/**
* The host.
*/
private final String host;
/**
* Create a new paste.
*
* @param contents The contents.
*/
public Paste(@NotNull final String contents) {
this(contents, "https://paste.willfp.com");
}
/**
* Create a new paste.
*
* @param contents The contents.
* @param host The host.
*/
public Paste(@NotNull final String contents,
@NotNull final String host) {
this.contents = contents;
this.host = host;
}
/**
@@ -42,12 +59,12 @@ public class Paste {
* @param callback The consumer to accept the response token.
*/
public void getHastebinToken(@NotNull final Consumer<String> callback) {
Eco.getHandler().getEcoPlugin().getScheduler().runAsync(() -> {
Eco.get().getEcoPlugin().getScheduler().runAsync(() -> {
try {
byte[] postData = URLEncoder.encode(contents, StandardCharsets.UTF_8).getBytes(StandardCharsets.UTF_8);
int postDataLength = postData.length;
String requestURL = "https://paste.willfp.com/documents";
String requestURL = this.host + "/documents";
URL url = new URL(requestURL);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setDoOutput(true);
@@ -85,14 +102,26 @@ public class Paste {
* @return The paste.
*/
public static Paste getFromHastebin(@NotNull final String token) {
return getFromHastebin(token, "https://paste.willfp.com");
}
/**
* Get paste from hastebin.
*
* @param token The token.
* @param host The host.
* @return The paste.
*/
public static Paste getFromHastebin(@NotNull final String token,
@NotNull final String host) {
try {
StringBuilder result = new StringBuilder();
URL url = new URL("https://paste.willfp.com/raw/" + token);
URL url = new URL(host + "/raw/" + token);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
try (var reader = new BufferedReader(
new InputStreamReader(conn.getInputStream()))) {
for (String line; (line = reader.readLine()) != null;) {
for (String line; (line = reader.readLine()) != null; ) {
result.append(line);
}
}

View File

@@ -1,7 +1,6 @@
package com.willfp.eco.core.web;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginDependent;
import org.bukkit.util.Consumer;
import org.jetbrains.annotations.NotNull;
@@ -13,14 +12,19 @@ import java.util.Scanner;
/**
* Class to check for updates of a plugin on spigot.
*/
public class UpdateChecker extends PluginDependent<EcoPlugin> {
public class UpdateChecker {
/**
* The plugin.
*/
private final EcoPlugin plugin;
/**
* Create an update checker for the specified spigot resource id.
*
* @param plugin The plugin to check.
*/
public UpdateChecker(@NotNull final EcoPlugin plugin) {
super(plugin);
this.plugin = plugin;
}
/**
@@ -44,4 +48,13 @@ public class UpdateChecker extends PluginDependent<EcoPlugin> {
}
});
}
/**
* Get the plugin.
*
* @return The plugin.
*/
public EcoPlugin getPlugin() {
return plugin;
}
}

View File

@@ -1,7 +1,11 @@
package com.willfp.eco.util;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.gui.menu.Menu;
import com.willfp.eco.core.tuples.Pair;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Utilities / API methods for menus.
@@ -15,9 +19,7 @@ public final class MenuUtils {
*/
@NotNull
public static Pair<Integer, Integer> convertSlotToRowColumn(final int slot) {
int row = Math.floorDiv(slot, 9);
int column = slot - row * 9;
return new Pair<>(row + 1, column + 1);
return convertSlotToRowColumn(slot, 9);
}
/**
@@ -28,7 +30,47 @@ public final class MenuUtils {
* @return The slot.
*/
public static int rowColumnToSlot(final int row, final int column) {
return (column - 1) + ((row - 1) * 9);
return rowColumnToSlot(row, column, 9);
}
/**
* Convert 0-53 slot to row and column pair.
*
* @param slot The slot.
* @param columns The columns.
* @return The pair of row and columns.
*/
@NotNull
public static Pair<Integer, Integer> convertSlotToRowColumn(final int slot,
final int columns) {
int row = Math.floorDiv(slot, columns);
int column = slot - row * columns;
return new Pair<>(row + 1, column + 1);
}
/**
* Convert row and column to 0-53 slot.
*
* @param row The row.
* @param column The column.
* @param columns The columns in the menu.
* @return The slot.
*/
public static int rowColumnToSlot(final int row,
final int column,
final int columns) {
return (column - 1) + ((row - 1) * columns);
}
/**
* Get a player's open menu.
*
* @param player The player.
* @return The menu, or null if none open.
*/
@Nullable
public static Menu getOpenMenu(@NotNull final Player player) {
return Eco.get().getOpenMenu(player);
}
private MenuUtils() {

View File

@@ -32,7 +32,7 @@ public final class NamespacedKeyUtils {
@NotNull
public static NamespacedKey create(@NotNull final String namespace,
@NotNull final String key) {
return Eco.getHandler().createNamespacedKey(
return Eco.get().createNamespacedKey(
namespace,
key
);

View File

@@ -1,16 +1,17 @@
package com.willfp.eco.util;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.placeholder.AdditionalPlayer;
import com.willfp.eco.core.placeholder.InjectablePlaceholder;
import com.willfp.eco.core.placeholder.PlaceholderInjectable;
import com.willfp.eco.core.placeholder.StaticPlaceholder;
import org.apache.commons.lang.Validate;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -26,11 +27,6 @@ public final class NumberUtils {
*/
private static final double[] SIN_LOOKUP = new double[65536];
/**
* Crunch handler.
*/
private static CrunchHandler crunch = null;
/**
* Set of roman numerals to look up.
*/
@@ -263,7 +259,8 @@ public final class NumberUtils {
}
@Override
public @NotNull List<InjectablePlaceholder> getPlaceholderInjections() {
public @NotNull
List<InjectablePlaceholder> getPlaceholderInjections() {
return Collections.emptyList();
}
});
@@ -282,7 +279,7 @@ public final class NumberUtils {
public static double evaluateExpression(@NotNull final String expression,
@Nullable final Player player,
@NotNull final Iterable<StaticPlaceholder> statics) {
return crunch.evaluate(expression, player, new PlaceholderInjectable() {
return evaluateExpression(expression, player, new PlaceholderInjectable() {
@Override
public void clearInjectedPlaceholders() {
// Do nothing.
@@ -310,36 +307,23 @@ public final class NumberUtils {
public static double evaluateExpression(@NotNull final String expression,
@Nullable final Player player,
@NotNull final PlaceholderInjectable context) {
return crunch.evaluate(expression, player, context);
return evaluateExpression(expression, player, context, new ArrayList<>());
}
/**
* Init crunch handler.
*
* @param handler The handler.
*/
@ApiStatus.Internal
public static void initCrunch(@NotNull final CrunchHandler handler) {
Validate.isTrue(crunch == null, "Already initialized!");
crunch = handler;
}
/**
* Bridge component for crunch.
*/
@ApiStatus.Internal
public interface CrunchHandler {
/**
* Evaluate an expression.
* Evaluate an expression with respect to a player (for placeholders).
*
* @param expression The expression.
* @param player The player.
* @param injectable The injectable placeholders.
* @param context The injectable placeholders.
* @param additionalPlayers Additional players to parse placeholders for.
* @return The value of the expression, or zero if invalid.
*/
double evaluate(@NotNull String expression,
@Nullable Player player,
@NotNull PlaceholderInjectable injectable);
public static double evaluateExpression(@NotNull final String expression,
@Nullable final Player player,
@NotNull final PlaceholderInjectable context,
@NotNull final Collection<AdditionalPlayer> additionalPlayers) {
return Eco.get().evaluate(expression, player, context, additionalPlayers);
}
private NumberUtils() {

View File

@@ -42,7 +42,7 @@ public final class PlayerUtils {
*/
@NotNull
public static Audience getAudience(@NotNull final Player player) {
BukkitAudiences adventure = Eco.getHandler().getAdventure();
BukkitAudiences adventure = Eco.get().getAdventure();
if (Prerequisite.HAS_PAPER.isMet()) {
if (player instanceof Audience) {
@@ -67,7 +67,7 @@ public final class PlayerUtils {
*/
@NotNull
public static Audience getAudience(@NotNull final CommandSender sender) {
BukkitAudiences adventure = Eco.getHandler().getAdventure();
BukkitAudiences adventure = Eco.get().getAdventure();
if (Prerequisite.HAS_PAPER.isMet()) {
if (sender instanceof Audience) {

View File

@@ -1,29 +1,18 @@
package com.willfp.eco.util;
import org.apache.commons.lang.Validate;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.util.function.Supplier;
import com.willfp.eco.core.Eco;
/**
* Utilities / API methods for the server.
*/
public final class ServerUtils {
/**
* The TPS supplier.
*/
private static Supplier<Double> tpsSupplier = null;
/**
* Get the current server TPS.
*
* @return The TPS.
*/
public static double getTps() {
Validate.notNull(tpsSupplier, "Not initialized!");
double tps = tpsSupplier.get();
double tps = Eco.get().getTPS();
if (tps > 20) {
return 20;
@@ -32,18 +21,6 @@ public final class ServerUtils {
}
}
/**
* Initialize the tps supplier function.
*
* @param function The function.
*/
@ApiStatus.Internal
public static void initialize(@NotNull final Supplier<Double> function) {
Validate.isTrue(tpsSupplier == null, "Already initialized!");
tpsSupplier = function;
}
private ServerUtils() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}

View File

@@ -1,33 +1,14 @@
package com.willfp.eco.util;
import org.apache.commons.lang.Validate;
import com.willfp.eco.core.Eco;
import org.bukkit.inventory.meta.SkullMeta;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.BiConsumer;
import java.util.function.Function;
/**
* Utilities / API methods for player heads.
*/
public final class SkullUtils {
/**
* If the meta set function has been set.
*/
private static boolean initialized = false;
/**
* The meta set function.
*/
private static BiConsumer<SkullMeta, String> metaSetConsumer = null;
/**
* The meta get function.
*/
private static Function<SkullMeta, String> metaGetConsumer = null;
/**
* Set the texture of a skull from base64.
*
@@ -36,10 +17,7 @@ public final class SkullUtils {
*/
public static void setSkullTexture(@NotNull final SkullMeta meta,
@NotNull final String base64) {
Validate.isTrue(initialized, "Must be initialized!");
Validate.notNull(metaSetConsumer, "Must be initialized!");
metaSetConsumer.accept(meta, base64);
Eco.get().setSkullTexture(meta, base64);
}
/**
@@ -50,26 +28,7 @@ public final class SkullUtils {
*/
@Nullable
public static String getSkullTexture(@NotNull final SkullMeta meta) {
Validate.isTrue(initialized, "Must be initialized!");
Validate.notNull(metaGetConsumer, "Must be initialized!");
return metaGetConsumer.apply(meta);
}
/**
* Initialize the skull texture function.
*
* @param function The function.
* @param function2 Get function.
*/
@ApiStatus.Internal
public static void initialize(@NotNull final BiConsumer<SkullMeta, String> function,
@NotNull final Function<SkullMeta, String> function2) {
Validate.isTrue(!initialized, "Already initialized!");
metaSetConsumer = function;
metaGetConsumer = function2;
initialized = true;
return Eco.get().getSkullTexture(meta);
}
private SkullUtils() {

View File

@@ -339,7 +339,7 @@ public final class StringUtils {
}
private static String translateMiniMessage(@NotNull final String message) {
return Eco.getHandler().formatMiniMessage(message);
return Eco.get().formatMiniMessage(message);
}
private static String translateHexColorCodes(@NotNull final String message) {

View File

@@ -152,6 +152,20 @@ public final class VectorUtils {
return vectors.toArray(new Vector[0]);
}
/**
* Get if a vector is a safe velocity.
*
* @param vec The vector to check.
* @return If safe.
*/
public static boolean isSafeVelocity(@NotNull final Vector vec) {
double x = Math.abs(vec.getX());
double y = Math.abs(vec.getY());
double z = Math.abs(vec.getZ());
return x < 4 && y < 4 && z < 4;
}
private VectorUtils() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}

View File

@@ -4,34 +4,72 @@ package com.willfp.eco.core.gui
import com.willfp.eco.core.gui.menu.Menu
import com.willfp.eco.core.gui.menu.MenuBuilder
import com.willfp.eco.core.gui.menu.MenuType
import com.willfp.eco.core.gui.menu.MenuEvent
import com.willfp.eco.core.gui.menu.MenuEventHandler
import com.willfp.eco.core.gui.page.Page
import com.willfp.eco.core.gui.page.PageBuilder
import com.willfp.eco.core.gui.slot.Slot
import com.willfp.eco.core.gui.slot.SlotBuilder
import com.willfp.eco.core.items.TestableItem
import org.bukkit.entity.Player
import org.bukkit.event.inventory.ClickType
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.event.inventory.InventoryCloseEvent
import org.bukkit.inventory.ItemStack
/** Shorthand for the `event.whoClicked as Player` pattern used everywhere. */
val InventoryClickEvent.player: Player
get() = this.whoClicked as Player
/** @see SlotBuilder.onLeftClick */
fun SlotBuilder.onLeftClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
fun SlotBuilder.onLeftClick(action: (event: InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
this.onLeftClick { a, b, c -> action(a, b, c) }
/** @see SlotBuilder.onLeftClick */
fun SlotBuilder.onLeftClick(action: (Player, event: InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
this.onLeftClick { a, b, c -> action(a.player, a, b, c) }
/** @see SlotBuilder.onRightClick */
fun SlotBuilder.onRightClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
fun SlotBuilder.onRightClick(action: (event: InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
this.onRightClick { a, b, c -> action(a, b, c) }
/** @see SlotBuilder.onRightClick */
fun SlotBuilder.onRightClick(action: (Player, event: InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
this.onRightClick { a, b, c -> action(a.player, a, b, c) }
/** @see SlotBuilder.onShiftLeftClick */
fun SlotBuilder.onShiftLeftClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
fun SlotBuilder.onShiftLeftClick(action: (event: InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
this.onShiftLeftClick { a, b, c -> action(a, b, c) }
/** @see SlotBuilder.onShiftLeftClick */
fun SlotBuilder.onShiftLeftClick(action: (Player, event: InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
this.onShiftLeftClick { a, b, c -> action(a.player, a, b, c) }
/** @see SlotBuilder.onShiftRightClick */
fun SlotBuilder.onShiftRightClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
fun SlotBuilder.onShiftRightClick(action: (event: InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
this.onShiftRightClick { a, b, c -> action(a, b, c) }
/** @see SlotBuilder.onShiftRightClick */
fun SlotBuilder.onMiddleClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
fun SlotBuilder.onShiftRightClick(action: (Player, event: InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
this.onShiftRightClick { a, b, c -> action(a.player, a, b, c) }
/** @see SlotBuilder.onMiddleClick */
fun SlotBuilder.onMiddleClick(action: (event: InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
this.onMiddleClick { a, b, c -> action(a, b, c) }
/** @see SlotBuilder.onMiddleClick */
fun SlotBuilder.onMiddleClick(action: (Player, event: InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
this.onMiddleClick { a, b, c -> action(a.player, a, b, c) }
/** @see SlotBuilder.onClick */
fun SlotBuilder.onClick(clickType: ClickType, action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
this.onClick(clickType) { a, b, c -> action(a, b, c) }
/** @see SlotBuilder.onClick */
fun SlotBuilder.onClick(clickType: ClickType, action: (Player, InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
this.onClick(clickType) { a, b, c -> action(a.player, a, b, c) }
/** @see SlotBuilder.notCaptiveFor */
fun SlotBuilder.notCaptiveFor(test: (Player) -> Boolean): SlotBuilder =
this.notCaptiveFor { test(it) }
@@ -42,11 +80,11 @@ fun SlotBuilder.notCaptiveFor(test: (Player) -> Boolean): SlotBuilder =
*/
@Deprecated("Use SlotUpdater instead")
@Suppress("DEPRECATION")
fun SlotBuilder.setModifier(action: (Player, Menu, ItemStack) -> Unit): SlotBuilder =
fun SlotBuilder.setModifier(action: (Player, Menu, item: ItemStack) -> Unit): SlotBuilder =
this.setUpdater { a, b, c -> c.apply { action(a, b, c) } }
/** @see SlotBuilder.setUpdater */
fun SlotBuilder.setUpdater(action: (Player, Menu, ItemStack) -> ItemStack): SlotBuilder =
fun SlotBuilder.setUpdater(action: (Player, Menu, item: ItemStack) -> ItemStack): SlotBuilder =
this.setUpdater { a, b, c -> action(a, b, c) }
/** Kotlin builder for slots. */
@@ -85,6 +123,16 @@ fun slot(
item: ItemStack
): Slot = Slot.builder(item).build()
/** Kotlin builder for slots. */
fun slot(
item: TestableItem,
init: SlotBuilder.() -> Unit
): Slot {
val builder = Slot.builder(item)
init(builder)
return builder.build()
}
/** Kotlin builder for slots. */
fun slot(
item: TestableItem
@@ -106,17 +154,36 @@ fun slot(
): Slot = Slot.builder { a, b -> provider(a, b) }.build()
/** @see MenuBuilder.onClose */
fun MenuBuilder.onClose(action: (InventoryCloseEvent, Menu) -> Unit): MenuBuilder =
fun MenuBuilder.onClose(action: (event: InventoryCloseEvent, Menu) -> Unit): MenuBuilder =
this.onClose { a, b -> action(a, b) }
/** @see MenuBuilder.onOpen */
fun MenuBuilder.onOpen(action: (Player, Menu) -> Unit): MenuBuilder =
this.onOpen { a, b -> action(a, b) }
/** @see MenuBuilder.modify */
fun MenuBuilder.modify(modifier: (MenuBuilder) -> Unit): MenuBuilder =
fun MenuBuilder.modify(modifier: (builder: MenuBuilder) -> Unit): MenuBuilder =
this.modfiy { modifier(it) }
/** @see MenuBuilder.onRender */
fun MenuBuilder.onRender(action: (Player, Menu) -> Unit): MenuBuilder =
this.onRender { a, b -> action(a, b) }
/** @see MenuBuilder.addPage */
fun MenuBuilder.addPage(page: Int, creation: PageBuilder.() -> Unit): MenuBuilder {
val builder = Menu.builder(this.rows)
creation(builder)
return this.addPage(Page(page, builder.build()))
}
/** @see MenuBuilder.onEvent */
inline fun <reified T : MenuEvent> MenuBuilder.onEvent(crossinline handler: (Player, Menu, event: T) -> Unit): MenuBuilder {
return this.onEvent(object : MenuEventHandler<T>(T::class.java) {
override fun handle(player: Player, menu: Menu, event: T) =
handler(player, menu, event)
})
}
/** Kotlin builder for menus. */
fun menu(
rows: Int,
@@ -126,3 +193,12 @@ fun menu(
init(builder)
return builder.build()
}
/** Kotlin builder for menus. */
fun dispenserMenu(
init: MenuBuilder.() -> Unit
): Menu {
val builder = Menu.builder(MenuType.DISPENSER)
init(builder)
return builder.build()
}

View File

@@ -3,6 +3,7 @@
package com.willfp.eco.core.integrations.economy
import org.bukkit.OfflinePlayer
import java.math.BigDecimal
/** @see EconomyManager */
var OfflinePlayer.balance: Double
@@ -21,3 +22,21 @@ var OfflinePlayer.balance: Double
EconomyManager.giveMoney(this, -diff)
}
}
/** @see EconomyManager */
var OfflinePlayer.exactBalance: BigDecimal
get() = EconomyManager.getBalance(this).toBigDecimal()
set(value) {
if (value <= BigDecimal.ZERO) {
EconomyManager.removeMoney(this, this.exactBalance)
return
}
val diff = this.exactBalance - value
if (diff > BigDecimal.ZERO) {
EconomyManager.removeMoney(this, diff)
} else if (diff < BigDecimal.ZERO) {
EconomyManager.giveMoney(this, -diff)
}
}

View File

@@ -0,0 +1,14 @@
@file:JvmName("ShopExtensions")
package com.willfp.eco.core.integrations.shop
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
/** @see ShopManager.getItemPrice **/
val ItemStack.price: Double
get() = ShopManager.getItemPrice(this)
/** @see ShopManager.getItemPrice **/
fun ItemStack.getPrice(player: Player): Double =
ShopManager.getItemPrice(this, player)

View File

@@ -31,3 +31,11 @@ var ItemStack.baseNBT: PersistentDataContainer
/** @see Items.setBaseNBT */
fun ItemStack.clearNBT() =
Items.setBaseNBT(this, null)
/** @see Items.toSNBT */
fun ItemStack.toSNBT() =
Items.toSNBT(this)
/** @see Items.isEmpty */
val ItemStack?.isEmpty: Boolean
get() = Items.isEmpty(this)

View File

@@ -0,0 +1,10 @@
@file:JvmName("MenuUtilsExtensions")
package com.willfp.eco.util
import com.willfp.eco.core.gui.menu.Menu
import org.bukkit.entity.Player
/** @see MenuUtils.getOpenMenu */
val Player.openMenu: Menu?
get() = MenuUtils.getOpenMenu(this)

View File

@@ -18,4 +18,4 @@ fun namespacedKeyOf(namespace: String, key: String) =
/** @see EcoPlugin.namespacedKeyFactory */
fun namespacedKeyOf(plugin: EcoPlugin, key: String) =
plugin.namespacedKeyFactory.create(key)
plugin.createNamespacedKey(key)

View File

@@ -11,3 +11,7 @@ val Vector.isFinite: Boolean
/** @see VectorUtils.simplifyVector */
fun Vector.simplify(): Vector =
VectorUtils.simplifyVector(this)
/** @see VectorUtils.isSafeVelocity */
val Vector.isSafeVelocity: Boolean
get() = VectorUtils.isSafeVelocity(this)

View File

@@ -10,4 +10,6 @@ dependencies {
compileOnly 'me.clip:placeholderapi:2.10.10'
compileOnly 'net.kyori:adventure-text-minimessage:4.10.0'
compileOnly 'net.kyori:adventure-platform-bukkit:4.1.0'
compileOnly 'org.yaml:snakeyaml:1.33'
compileOnly 'com.moandjiezana.toml:toml4j:0.7.2'
}

View File

@@ -1,32 +0,0 @@
package com.willfp.eco.internal
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.items.Items
import com.willfp.eco.core.proxy.Cleaner
import com.willfp.eco.internal.proxy.EcoProxyFactory
import java.net.URLClassLoader
class EcoCleaner: Cleaner {
override fun clean(plugin: EcoPlugin) {
if (plugin.proxyPackage.isNotEmpty()) {
val factory = plugin.proxyFactory as EcoProxyFactory
factory.clean()
}
Plugins.LOADED_ECO_PLUGINS.remove(plugin.name.lowercase())
for (customItem in Items.getCustomItems()) {
if (customItem.key.namespace.equals(plugin.name.lowercase(), ignoreCase = true)) {
Items.removeCustomItem(customItem.key)
}
}
val classLoader = plugin::class.java.classLoader
if (classLoader is URLClassLoader) {
classLoader.close()
}
System.gc()
}
}

View File

@@ -1,7 +0,0 @@
package com.willfp.eco.internal
import com.willfp.eco.core.EcoPlugin
object Plugins {
val LOADED_ECO_PLUGINS = HashMap<String, EcoPlugin>()
}

View File

@@ -2,6 +2,8 @@
package com.willfp.eco.internal.config
import com.moandjiezana.toml.Toml
import com.moandjiezana.toml.TomlWriter
import com.willfp.eco.core.config.ConfigType
import org.bukkit.configuration.file.YamlConstructor
import org.yaml.snakeyaml.DumperOptions
@@ -65,7 +67,11 @@ fun Reader.readToString(): String {
}
private val ConfigType.handler: ConfigTypeHandler
get() = if (this == ConfigType.JSON) JSONConfigTypeHandler else YamlConfigTypeHandler
get() = when (this) {
ConfigType.JSON -> JSONConfigTypeHandler
ConfigType.YAML -> YamlConfigTypeHandler
ConfigType.TOML -> TOMLConfigTypeHandler
}
private abstract class ConfigTypeHandler(
val type: ConfigType
@@ -91,6 +97,12 @@ private object YamlConfigTypeHandler : ConfigTypeHandler(ConfigType.YAML) {
loaderOptions.maxAliasesForCollections = Int.MAX_VALUE
loaderOptions.isAllowDuplicateKeys = false
// Jank incoming!
try {
loaderOptions.codePointLimit = 256 * 1024 * 1024
} catch (e: NoSuchMethodError) {
// Ignore it
}
yamlOptions.indent = 2
yamlOptions.defaultFlowStyle = DumperOptions.FlowStyle.BLOCK
@@ -123,3 +135,16 @@ private object JSONConfigTypeHandler : ConfigTypeHandler(ConfigType.JSON) {
return EcoGsonSerializer.gson.toJson(map)
}
}
private object TOMLConfigTypeHandler : ConfigTypeHandler(ConfigType.TOML) {
override fun parseToMap(input: String): Map<*, *> {
return Toml().read(input).toMap()
}
override fun toString(map: Map<String, Any?>): String {
val writer = TomlWriter.Builder()
.build()
return writer.write(map)
}
}

View File

@@ -154,7 +154,9 @@ open class EcoConfig(
format: Boolean,
option: StringUtils.FormatOption
): List<String>? {
val strings = (get(path) as? Iterable<*>)?.map { it.toString() }?.toMutableList() ?: return null
val strings = (get(path) as? Iterable<*>)
?.map { it?.toString() ?: "" }
?.toMutableList() ?: return null
if (placeholderInjections.isNotEmpty() && format && option == StringUtils.FormatOption.WITH_PLACEHOLDERS) {
strings.replaceAll {
var string = it

View File

@@ -1,61 +0,0 @@
package com.willfp.eco.internal.config
import com.willfp.eco.core.PluginLike
import com.willfp.eco.core.config.ConfigType
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.eco.core.config.interfaces.LoadableConfig
import com.willfp.eco.core.config.wrapper.ConfigFactory
import org.bukkit.configuration.ConfigurationSection
object EcoConfigFactory : ConfigFactory {
override fun createConfig(bukkit: ConfigurationSection): Config {
val config = createConfig(emptyMap(), ConfigType.YAML)
for (key in bukkit.getKeys(true)) {
config.set(key, bukkit.get(key))
}
return config
}
override fun createConfig(values: Map<String, Any>, type: ConfigType): Config =
EcoConfigSection(type, values)
override fun createConfig(contents: String, type: ConfigType): Config =
EcoConfigSection(type, type.toMap(contents))
override fun createLoadableConfig(
configName: String,
plugin: PluginLike,
subDirectoryPath: String,
source: Class<*>,
type: ConfigType,
requiresChangesToSave: Boolean
): LoadableConfig = EcoLoadableConfig(
type,
configName,
plugin,
subDirectoryPath,
source,
requiresChangesToSave
)
override fun createUpdatableConfig(
configName: String,
plugin: PluginLike,
subDirectoryPath: String,
source: Class<*>,
removeUnused: Boolean,
type: ConfigType,
requiresChangesToSave: Boolean,
vararg updateBlacklist: String
): LoadableConfig = EcoUpdatableConfig(
type,
configName,
plugin,
subDirectoryPath,
source,
removeUnused,
requiresChangesToSave,
*updateBlacklist
)
}

View File

@@ -5,6 +5,7 @@ import org.yaml.snakeyaml.nodes.Node
import org.yaml.snakeyaml.representer.Represent
import org.yaml.snakeyaml.representer.Representer
@Suppress("DEPRECATION")
class EcoRepresenter : Representer() {
init {
multiRepresenters[Config::class.java] = RepresentConfig(multiRepresenters[Map::class.java]!!)

View File

@@ -1,102 +0,0 @@
package com.willfp.eco.internal.display
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.display.Display
import com.willfp.eco.core.display.DisplayHandler
import com.willfp.eco.core.display.DisplayModule
import com.willfp.eco.core.fast.fast
import org.bukkit.NamespacedKey
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
import org.bukkit.persistence.PersistentDataType
class EcoDisplayHandler(plugin: EcoPlugin) : DisplayHandler {
private val registeredModules = sortedMapOf<Int, MutableList<DisplayModule>>()
private val finalizeKey: NamespacedKey = plugin.namespacedKeyFactory.create("finalized")
override fun registerDisplayModule(module: DisplayModule) {
val modules = registeredModules[module.weight] ?: mutableListOf()
modules.removeIf {
it.pluginName.equals(module.pluginName, ignoreCase = true)
}
modules.add(module)
registeredModules[module.weight] = modules
}
override fun display(itemStack: ItemStack, player: Player?): ItemStack {
val pluginVarArgs = mutableMapOf<String, Array<Any>>()
for ((_, modules) in registeredModules) {
for (module in modules) {
pluginVarArgs[module.pluginName] = module.generateVarArgs(itemStack)
}
}
Display.revert(itemStack)
if (!itemStack.hasItemMeta()) {
return itemStack
}
for ((_, modules) in registeredModules) {
for (module in modules) {
val varargs = pluginVarArgs[module.pluginName] ?: continue
module.display(itemStack, *varargs)
if (player != null) {
module.display(itemStack, player as Player?, *varargs)
}
}
}
return itemStack
}
override fun revert(itemStack: ItemStack): ItemStack {
if (Display.isFinalized(itemStack)) {
Display.unfinalize(itemStack)
}
val fast = itemStack.fast()
val lore = fast.lore
if (lore.isNotEmpty() && lore.removeIf { line: String ->
line.startsWith(
Display.PREFIX
)
}) { // Only modify lore if needed.
fast.lore = lore
}
for ((_, modules) in registeredModules) {
for (module in modules) {
module.revert(itemStack)
}
}
return itemStack
}
override fun finalize(itemStack: ItemStack): ItemStack {
if (itemStack.type.maxStackSize > 1) {
return itemStack
}
itemStack.fast().persistentDataContainer.set(finalizeKey, PersistentDataType.INTEGER, 1)
return itemStack
}
override fun unfinalize(itemStack: ItemStack): ItemStack {
itemStack.fast().persistentDataContainer.remove(finalizeKey)
return itemStack
}
override fun isFinalized(itemStack: ItemStack): Boolean {
return itemStack.fast().persistentDataContainer.has(finalizeKey, PersistentDataType.INTEGER)
}
}

View File

@@ -1,11 +0,0 @@
package com.willfp.eco.internal.drops
import com.willfp.eco.core.EcoPlugin
object DropManager {
var type = DropQueueType.COLLATED
fun update(plugin: EcoPlugin) {
type = if (plugin.configYml.getBool("use-fast-collated-drops")) DropQueueType.COLLATED else DropQueueType.STANDARD
}
}

View File

@@ -1,5 +0,0 @@
package com.willfp.eco.internal.drops
enum class DropQueueType {
STANDARD, COLLATED
}

View File

@@ -1,6 +1,6 @@
package com.willfp.eco.internal.drops.impl
package com.willfp.eco.internal.drops
import com.willfp.eco.core.drops.InternalDropQueue
import com.willfp.eco.core.drops.DropQueue
import com.willfp.eco.core.events.DropQueuePushEvent
import com.willfp.eco.core.integrations.antigrief.AntigriefManager
import com.willfp.eco.util.TelekinesisUtils
@@ -13,33 +13,33 @@ import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
import org.bukkit.util.Vector
open class EcoDropQueue(val player: Player) : InternalDropQueue {
open class EcoDropQueue(val player: Player) : DropQueue() {
val items = mutableListOf<ItemStack>()
var xp: Int = 0
var location: Location
var hasTelekinesis = false
override fun addItem(item: ItemStack): InternalDropQueue {
override fun addItem(item: ItemStack): DropQueue {
items.add(item)
return this
}
override fun addItems(itemStacks: Collection<ItemStack>): InternalDropQueue {
override fun addItems(itemStacks: Collection<ItemStack>): DropQueue {
items.addAll(itemStacks)
return this
}
override fun addXP(amount: Int): InternalDropQueue {
override fun addXP(amount: Int): DropQueue {
xp += amount
return this
}
override fun setLocation(location: Location): InternalDropQueue {
override fun setLocation(location: Location): DropQueue {
this.location = location
return this
}
override fun forceTelekinesis(): InternalDropQueue {
override fun forceTelekinesis(): DropQueue {
hasTelekinesis = true
return this
}

View File

@@ -1,15 +0,0 @@
package com.willfp.eco.internal.drops
import com.willfp.eco.core.drops.DropQueueFactory
import com.willfp.eco.core.drops.InternalDropQueue
import com.willfp.eco.internal.drops.impl.EcoDropQueue
import com.willfp.eco.internal.drops.impl.EcoFastCollatedDropQueue
import org.bukkit.entity.Player
object EcoDropQueueFactory : DropQueueFactory {
override fun create(player: Player): InternalDropQueue {
return if (DropManager.type == DropQueueType.COLLATED) EcoFastCollatedDropQueue(player) else EcoDropQueue(
player
)
}
}

View File

@@ -1,4 +1,4 @@
package com.willfp.eco.internal.drops.impl
package com.willfp.eco.internal.drops
import org.bukkit.Location
import org.bukkit.entity.Player
@@ -29,7 +29,6 @@ class EcoFastCollatedDropQueue(player: Player) : EcoDropQueue(player) {
var xp: Int,
var telekinetic: Boolean
) {
fun addDrops(toAdd: List<ItemStack>): CollatedDrops {
drops.addAll(toAdd)
return this

Some files were not shown because too many files have changed in this diff Show More