Compare commits

..

106 Commits
6.2.1 ... 6.4.0

Author SHA1 Message Date
Auxilor
ebc76bba76 Changed display 2021-08-12 16:30:15 +01:00
Auxilor
378218b7da Minor display change 2021-08-12 16:13:59 +01:00
Auxilor
e053514b94 Added mask materials option 2021-08-12 13:56:29 +01:00
Auxilor
341a30e6da Removed unused var 2021-08-12 13:40:19 +01:00
Auxilor
70eb6d4420 Removed logging 2021-08-12 13:40:01 +01:00
Auxilor
aa368909ae Finished GUI 2021-08-12 13:38:14 +01:00
Auxilor
606a54bcf8 Your brain gets smart but your head gets dumb 2021-08-12 13:17:52 +01:00
Auxilor
7f8fb3d87b Didn't make sense not to live for fun 2021-08-12 13:00:31 +01:00
Auxilor
e97d454ff6 Fed to the rules and I hit the ground running 2021-08-12 01:51:47 +01:00
Auxilor
109b9aa3f3 And the changes start coming and they don't stop coming 2021-08-12 01:46:32 +01:00
Auxilor
4a90385b27 The gui changes don't stop 2021-08-12 01:38:20 +01:00
Auxilor
0edd50832c Even more GUI 2021-08-12 01:05:47 +01:00
Auxilor
46415268b7 More GUI 2021-08-12 00:24:35 +01:00
Auxilor
b652dbad2d Added captivator slots 2021-08-11 23:56:09 +01:00
Auxilor
50550d077a Added ? syntax to recipes 2021-08-11 23:07:25 +01:00
Auxilor
60c3b58a33 Updated to 6.3.3 2021-08-10 18:19:46 +01:00
Auxilor
7216d0b09f Fixed component serialization 2021-08-10 18:18:09 +01:00
Auxilor
97eeea8d48 Updated to 6.3.2 2021-08-10 16:18:49 +01:00
Auxilor
82061ee6a3 Added get/set repair cost methods to FastItemStack 2021-08-09 17:30:09 +01:00
Auxilor
f274b9045e Being absolutely sure 2021-08-07 23:17:39 +01:00
Auxilor
2241a5c90f I'm actually going to die 2021-08-07 23:16:59 +01:00
Auxilor
bbc38ae801 Frantic-est fixing 2021-08-07 23:08:12 +01:00
Auxilor
e77346ed62 Even frantic-er fixing 2021-08-07 23:07:06 +01:00
Auxilor
6117abca56 Frantic fixing 2021-08-07 23:00:23 +01:00
Auxilor
2e2a061ebe Updated to 6.3.1 2021-08-07 22:11:08 +01:00
Auxilor
cdc89ac397 Fixed FastItemStack 2021-08-07 22:10:54 +01:00
Auxilor
e758cebe77 Fixed FastItemStack bug 2021-08-07 22:09:50 +01:00
Auxilor
a408e3436a Fixed italic lore 2021-08-07 15:44:16 +01:00
Auxilor
3df977c1bc Fixed FastItemStack#setLore being italicised 2021-08-07 15:10:54 +01:00
Auxilor
136f1841b4 Fixed FastItemStack#setLore being italicised 2021-08-07 15:07:29 +01:00
Auxilor
1086a59a6a Added message about deprecated events 2021-08-07 14:02:52 +01:00
Auxilor
d9147f9918 Changed bStats message 2021-08-07 13:44:21 +01:00
Auxilor
d144df4048 Fixed proxy interface package 2021-08-07 13:33:58 +01:00
Auxilor
061f77e911 Fixed 1.16 proxy package 2021-08-07 13:32:44 +01:00
Auxilor
5cebe2fce8 Moved metric handler 2021-08-07 13:27:12 +01:00
Auxilor
1e712dcae6 Skull.kt now uses lateinit var 2021-08-07 13:24:36 +01:00
Auxilor
09d444da58 Added format cache to yaml configs 2021-08-07 13:18:36 +01:00
Auxilor
09f45c0ab5 Cleaned up FastItemStack 2021-08-07 13:11:09 +01:00
Auxilor
f64d69f084 Switched proxy interfaces to kotlin 2021-08-07 13:02:44 +01:00
Auxilor
86a948738f Moved EcoProxyFactory to kotlin, removing java from eco-backend 2021-08-07 02:29:36 +01:00
Auxilor
8f9c5e7ed8 Moved most 1.16.5 proxies off to kotlin 2021-08-06 23:27:30 +01:00
Auxilor
ae897b7493 Moved most 1.17 proxies to kotlin 2021-08-06 23:22:32 +01:00
Auxilor
f1a7c9d50e Moved FastItemStackUtils to companion object 2021-08-06 23:16:53 +01:00
Auxilor
83ee8fe4cd Fixed 1.17 mapping bug with kotlin 2021-08-06 23:14:25 +01:00
Auxilor
465f885e22 Fixed kotlin bugs 2021-08-06 23:09:47 +01:00
Auxilor
d4141735a9 Moved 1_17_R1 NMSFastItemStack to kotlin for testing reasons 2021-08-06 22:47:26 +01:00
Auxilor
b9b4ce1937 Fixed NumberUtils 2021-08-06 22:31:51 +01:00
Auxilor
56234e6c83 Added tests for NumberUtilsTest 2021-08-06 22:22:18 +01:00
Auxilor
2dda34097e Fixed .gitignore 2021-08-06 22:02:34 +01:00
Auxilor
155a349569 Removed saveAllConfigs on disable 2021-08-06 22:00:04 +01:00
Auxilor
ce231934a3 Fixed DropManager.kt 2021-08-06 21:53:19 +01:00
Auxilor
5cbb7bfe47 Added warnings to servers without bStats 2021-08-06 21:49:12 +01:00
Auxilor
06e0ec0295 Updated bStats 2021-08-06 21:30:29 +01:00
Auxilor
02ed583674 Updated gitignore 2021-08-06 20:21:36 +01:00
Auxilor
8e4cbdd1aa Kotlin cleaning 2021-08-06 20:20:50 +01:00
Auxilor
8828f8e45d Moved EcoConfigHandler to kotlin 2021-08-06 20:05:57 +01:00
Auxilor
d15524ee9e Moved extension loader to kotlin 2021-08-06 19:57:38 +01:00
Auxilor
d45e66d71e Kotlin cleanup 2021-08-06 19:43:48 +01:00
Auxilor
6b1dde7540 Removed lombok from kotlin 2021-08-06 17:40:00 +01:00
Auxilor
abf2964c48 Fixed kotlin class names 2021-08-06 17:37:49 +01:00
Auxilor
db51c4c761 Moved integrations to kotlin 2021-08-06 17:28:21 +01:00
Auxilor
cbb574acec Switched most event listeners to kotlin 2021-08-06 17:25:34 +01:00
Auxilor
93c044ef09 Fixed kotlin errors and warnings 2021-08-06 16:46:48 +01:00
Auxilor
1cc39fe40a Fixed EcoMenuBuilder.kt 2021-08-06 16:45:10 +01:00
Auxilor
edfd561fcd EcoMenu error fix 2021-08-06 16:41:29 +01:00
Auxilor
bd7f22cb02 Fixed kotlin errors 2021-08-06 16:40:47 +01:00
Auxilor
3233bad307 More backend kotlinining 2021-08-06 16:38:12 +01:00
Auxilor
3cefcbe0bb Switched most internals to kotlin 2021-08-06 16:15:29 +01:00
Auxilor
49bce53724 Rename .java to .kt 2021-08-06 16:15:29 +01:00
Auxilor
2b86159b30 Fixed handler 2021-08-06 03:15:50 +01:00
Auxilor
d028511a48 Fixed kotlin being shaded 2021-08-06 03:14:43 +01:00
Auxilor
5ad1ef33b8 Kotlining 2021-08-06 03:10:00 +01:00
Auxilor
634d6194d6 Began kotlin 2021-08-06 03:08:00 +01:00
Auxilor
7f7eb4f45a Fixed trailing spaces 2021-08-05 00:43:18 +01:00
Auxilor
bd90ae996b Fixed deprecation warnings 2021-08-04 17:52:09 +01:00
Auxilor
1bc57dec08 Fixed annotations 2021-08-04 15:22:52 +01:00
Auxilor
ce44d40f0f Reverted BlockUtils 2021-08-04 14:53:16 +01:00
Auxilor
68824fb4d0 Updated gradient regexes 2021-08-04 14:38:18 +01:00
Auxilor
fd96b0d2cf Fixed HAS_VAULT 2021-08-04 14:36:24 +01:00
Auxilor
2669569e81 Removed vault and loadbefore 2021-08-04 14:36:10 +01:00
Auxilor
067f740bcc Improved ArmorEquipEvent javadoc 2021-08-04 14:29:17 +01:00
Auxilor
2ce96ab0b1 Added FastItemStack#unwrap again 2021-08-04 14:27:45 +01:00
Auxilor
027f9be194 Definitely not code smells 2021-08-04 00:25:07 +01:00
Auxilor
a09018d1f0 Added vault and Prerequisite#HAS_VAULT 2021-08-03 23:55:13 +01:00
Auxilor
a1da83173d Deprecated ArmorEquipEvent 2021-08-03 23:43:17 +01:00
Auxilor
8ac30283f8 Deprecated ArmorEquipEvent 2021-08-03 23:42:58 +01:00
Auxilor
6099b5d64d Removed javadoc for private methods 2021-08-03 23:35:53 +01:00
Auxilor
19d2e0788b Added PlaceholderEntry#register 2021-08-03 23:34:39 +01:00
Auxilor
1b223b3736 Added null safety to Customitem 2021-08-03 23:30:31 +01:00
Auxilor
d6d1f01704 FastItemStack refactoring 2021-08-03 20:47:01 +01:00
Auxilor
51231939c0 Added <gradient:#> support 2021-08-03 19:59:21 +01:00
Auxilor
72fb20ecd9 Switched to adventure for legacy / json conversions 2021-08-03 19:57:52 +01:00
Auxilor
58a386922c Removed FastItemStack benchmarks 2021-08-03 19:19:06 +01:00
Auxilor
12824c7f6c FastItemStack cache changes 2021-08-03 19:10:22 +01:00
Auxilor
b5236b8db6 More FastItemStack 2021-08-03 18:54:45 +01:00
Auxilor
3ffbb861d1 More FastItemStack changes 2021-08-03 17:00:49 +01:00
Auxilor
f8fad15f0b More FastItemStack changes 2021-08-03 16:48:13 +01:00
Auxilor
a0e96fca35 Fixed typo 2021-08-03 16:21:19 +01:00
Auxilor
6cf9a53a65 Continued FastItemStack development 2021-08-03 16:20:05 +01:00
Auxilor
a4909453d7 Codestyle 2021-08-01 23:39:04 +01:00
Auxilor
a10666f792 Renamed to EcoFastItemStack 2021-08-01 23:38:42 +01:00
Auxilor
a845cda9ed Fixed mapped jar output issues 2021-08-01 23:18:06 +01:00
Auxilor
ed5f1ccb5e Switched to 1.17 mojang mappings and began FastItemStack 2021-08-01 22:09:18 +01:00
Auxilor
c6e59e1d62 Updated to 6.3.0 2021-08-01 19:16:43 +01:00
Auxilor
ed24b6278e Began FastItemStack shti 2021-08-01 19:16:33 +01:00
Auxilor
3aea7b4077 Fixed CombatLogX codestyle 2021-08-01 17:00:04 +01:00
211 changed files with 5025 additions and 4728 deletions

1
.gitignore vendored
View File

@@ -14,6 +14,7 @@ bin/
# Gradle
.gradle
**/build/
**/out/
!eco-api/src/**/build/
.gradletasknamecache
!gradle-wrapper.jar

View File

@@ -99,7 +99,7 @@ Here's a list of some (not all) of the features of eco:
- ArmorEquipEvent
- EntityDeathByEntityEvent
- NaturalExpGainEvent
- Plugin extensions (Plugins for plugins)
- Plugin extensions (com.willfp.eco.internal.Plugins for plugins)
- GUI System
- Integration system for external plugins
- Anticheat support

View File

@@ -7,7 +7,11 @@ plugins {
dependencies {
implementation project(":eco-api")
implementation project(":eco-core").getSubprojects()
implementation project(":eco-core:core-plugin")
implementation project(":eco-core:core-proxy")
implementation project(":eco-core:core-backend")
implementation project(":eco-core:core-nms:v1_16_R3")
implementation project(path: ":eco-core:core-nms:v1_17_R1", configuration: 'mapped')
}
allprojects {
@@ -57,6 +61,10 @@ allprojects {
annotationProcessor 'org.projectlombok:lombok:1.18.20'
testCompileOnly 'org.projectlombok:lombok:1.18.20'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.20'
// Test
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1'
}
tasks.withType(JavaCompile) {
@@ -75,7 +83,7 @@ allprojects {
}
shadowJar {
relocate('org.bstats.bukkit', 'com.willfp.eco.shaded.bstats')
relocate('org.bstats', 'com.willfp.eco.shaded.bstats')
}
jar {
@@ -92,6 +100,18 @@ allprojects {
withSourcesJar()
}
test {
useJUnitPlatform()
// Always run tests, even when nothing changed.
dependsOn cleanTest
// Show test results.
testLogging {
events "passed", "skipped", "failed"
}
}
compileJava.options.encoding = 'UTF-8'
compileJava.dependsOn clean

View File

@@ -45,7 +45,7 @@
-->
<property name="severity" value="error"/>
<property name="fileExtensions" value="java, properties, xml"/>
<property name="fileExtensions" value="java, properties, xml, kt"/>
<!-- Excludes all 'module-info.java' files -->
<!-- See https://checkstyle.org/config_filefilters.html -->
@@ -66,6 +66,7 @@
<module name="FileLength"/>
<module name="LineLength">
<property name="fileExtensions" value="java"/>
<property name="fileExtensions" value="kt"/>
<property name="max" value="200"/>
</module>

View File

@@ -8,17 +8,16 @@ version rootProject.version
dependencies {
compileOnly 'org.spigotmc:spigot-api:1.17-R0.1-SNAPSHOT'
compileOnly 'org.apache.maven:maven-artifact:3.0.3'
compileOnly 'org.bstats:bstats-bukkit:1.7'
compileOnly 'com.comphenix.protocol:ProtocolLib:4.6.0-SNAPSHOT'
compileOnly 'com.google.code.gson:gson:2.8.7'
compileOnly 'net.kyori:adventure-text-serializer-gson:4.8.1'
compileOnly 'net.kyori:adventure-text-serializer-legacy:4.8.1'
}
java {
withJavadocJar()
}
compileJava.options.encoding = 'UTF-8'
compileJava.dependsOn clean
build.dependsOn publishToMavenLocal

View File

@@ -20,7 +20,6 @@ import com.willfp.eco.core.web.UpdateChecker;
import lombok.Getter;
import org.apache.commons.lang.Validate;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.event.Listener;
@@ -348,7 +347,7 @@ public abstract class EcoPlugin extends JavaPlugin {
}
if (this.getBStatsId() != 0) {
new Metrics(this, this.getBStatsId());
Eco.getHandler().registerBStats(this);
}
Set<String> enabledPlugins = Arrays.stream(Bukkit.getPluginManager().getPlugins()).map(Plugin::getName).collect(Collectors.toSet());
@@ -406,7 +405,6 @@ public abstract class EcoPlugin extends JavaPlugin {
this.getEventManager().unregisterAllListeners();
this.getScheduler().cancelAll();
this.getConfigHandler().saveAllConfigs();
this.handleDisable();
@@ -615,7 +613,7 @@ public abstract class EcoPlugin extends JavaPlugin {
* @param <T> The proxy type.
* @return The proxy.
*/
public <T extends AbstractProxy> T getProxy(@NotNull final Class<T> proxyClass) {
public final <T extends AbstractProxy> T getProxy(@NotNull final Class<T> proxyClass) {
Validate.notNull(proxyFactory, "Plugin does not support proxy!");
return proxyFactory.getProxy(proxyClass);

View File

@@ -8,11 +8,13 @@ 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.proxy.Cleaner;
import com.willfp.eco.core.proxy.ProxyFactory;
import com.willfp.eco.core.scheduling.Scheduler;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.List;
@@ -158,4 +160,19 @@ public interface Handler {
* @return A list of plugin names in lowercase.
*/
List<String> getLoadedPlugins();
/**
* Create a FastItemStack.
*
* @param itemStack The base ItemStack.
* @return The FastItemStack.
*/
FastItemStack createFastItemStack(@NotNull ItemStack itemStack);
/**
* Register bStats metrics.
*
* @param plugin The plugin.
*/
void registerBStats(@NotNull EcoPlugin plugin);
}

View File

@@ -30,6 +30,14 @@ public class Prerequisite {
"Requires server to be running paper (or a fork)"
);
/**
* Requires the server to be running an implementation of paper.
*/
public static final Prerequisite HAS_VAULT = new Prerequisite(
() -> ClassUtils.exists("net.milkbowl.vault.economy.Economy"),
"Requires server to have vault"
);
/**
* Requires the server to be running 1.17.
*/

View File

@@ -71,10 +71,6 @@ public class Display {
*/
public ItemStack display(@NotNull final ItemStack itemStack,
@Nullable final Player player) {
if (!itemStack.hasItemMeta()) {
return itemStack; // return early if there's no customization of the item
}
Map<String, Object[]> pluginVarArgs = new HashMap<>();
for (DisplayPriority priority : DisplayPriority.values()) {
@@ -139,10 +135,6 @@ public class Display {
unfinalize(itemStack);
}
if (!itemStack.hasItemMeta()) {
return itemStack;
}
ItemMeta meta = itemStack.getItemMeta();
if (meta == null) {

View File

@@ -6,6 +6,7 @@ import lombok.Getter;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Class for all plugin-specific client-side item display modules.
@@ -48,7 +49,7 @@ public abstract class DisplayModule extends PluginDependent<EcoPlugin> {
* @param args Optional args for display.
*/
protected void display(@NotNull final ItemStack itemStack,
@NotNull final Player player,
@Nullable final Player player,
@NotNull final Object... args) {
// Technically optional.
}

View File

@@ -13,7 +13,10 @@ import org.jetbrains.annotations.NotNull;
* <p>
* The event is called before the player's inventory actually updates,
* so you can check a tick later to see the new contents.
*
* @see ArmorChangeEvent
*/
@Deprecated
public class ArmorEquipEvent extends PlayerEvent {
/**
* Bukkit parity.

View File

@@ -0,0 +1,81 @@
package com.willfp.eco.core.fast;
import com.willfp.eco.core.Eco;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* FastItemStack contains methods to modify and read items faster than in default bukkit.
*/
public interface FastItemStack {
/**
* Get all enchantments on an item.
*
* @param checkStored If stored NBT should also be checked.
* @return A map of all enchantments.
*/
Map<Enchantment, Integer> getEnchantmentsOnItem(boolean checkStored);
/**
* Get the level of an enchantment on an item.
*
* @param enchantment The enchantment.
* @param checkStored If the stored NBT should also be checked.
* @return The enchantment level, or 0 if not found.
*/
int getLevelOnItem(@NotNull Enchantment enchantment,
boolean checkStored);
/**
* Set the item lore.
*
* @param lore The lore.
*/
void setLore(@Nullable List<String> lore);
/**
* Get the item lore.
*
* @return The lore.
*/
List<String> getLore();
/**
* Set the rework penalty.
*
* @param cost The rework penalty to set.
*/
void setRepairCost(int cost);
/**
* Get the rework penalty.
*.
* @return The rework penalty found on the item.
*/
int getRepairCost();
/**
* Get the Bukkit ItemStack again.
*
* @return The ItemStack.
*/
ItemStack unwrap();
/**
* Wrap an ItemStack to create a FastItemStack.
*
* @param itemStack The ItemStack.
* @return The FastItemStack.
*/
static FastItemStack wrap(final ItemStack itemStack) {
return Eco.getHandler().createFastItemStack(Objects.requireNonNullElseGet(itemStack, () -> new ItemStack(Material.AIR)));
}
}

View File

@@ -2,12 +2,10 @@ package com.willfp.eco.core.gui;
import com.willfp.eco.core.gui.menu.MenuBuilder;
import com.willfp.eco.core.gui.slot.SlotBuilder;
import org.bukkit.entity.Player;
import com.willfp.eco.core.gui.slot.functional.SlotProvider;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.function.Function;
/**
* 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)}.
@@ -19,7 +17,7 @@ public interface GUIFactory {
* @param provider The provider.
* @return The builder.
*/
SlotBuilder createSlotBuilder(@NotNull Function<Player, ItemStack> provider);
SlotBuilder createSlotBuilder(@NotNull SlotProvider provider);
/**
* Create menu builder.

View File

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

View File

@@ -4,8 +4,11 @@ import com.willfp.eco.core.Eco;
import com.willfp.eco.core.gui.slot.Slot;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* GUI version of {@link Inventory}.
* <p>
@@ -44,6 +47,14 @@ public interface Menu {
*/
Inventory open(@NotNull Player player);
/**
* Get captive items.
*
* @param player The player.
* @return The items.
*/
List<ItemStack> getCaptiveItems(@NotNull Player player);
/**
* Create a builder with a given amount of rows.
*

View File

@@ -31,6 +31,14 @@ public interface MenuBuilder {
int column,
@NotNull Slot slot);
/**
* Run function to modify the builder.
*
* @param modifier The modifier.
* @return The builder.
*/
MenuBuilder modfiy(@NotNull Consumer<MenuBuilder> modifier);
/**
* Set the menu mask.
*
@@ -45,7 +53,18 @@ public interface MenuBuilder {
* @param action The handler.
* @return The builder.
*/
MenuBuilder onClose(@NotNull Consumer<InventoryCloseEvent> action);
default MenuBuilder onClose(@NotNull Consumer<InventoryCloseEvent> action) {
onClose((event, menu) -> action.accept(event));
return this;
}
/**
* Set the menu close handler.
*
* @param action The handler.
* @return The builder.
*/
MenuBuilder onClose(@NotNull CloseHandler action);
/**
* Build the menu.

View File

@@ -7,6 +7,7 @@ import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.List;
/**
@@ -39,35 +40,46 @@ public class FillerMask {
*/
public FillerMask(@NotNull final Material material,
@NotNull final String... pattern) {
if (material == Material.AIR) {
throw new IllegalArgumentException("Material cannot be air!");
this(new MaskMaterials(material), pattern);
}
/**
* Create a new filler mask.
*
* @param materials The mask materials.
* @param pattern The pattern.
*/
public FillerMask(@NotNull final MaskMaterials materials,
@NotNull final String... pattern) {
if (Arrays.stream(materials.materials()).anyMatch(material -> material == Material.AIR)) {
throw new IllegalArgumentException("Materials cannot be air!");
}
mask = ListUtils.create2DList(6, 9);
ItemStack itemStack = new ItemStackBuilder(material)
.setDisplayName("&r")
.build();
for (int i = 0; i < materials.materials().length; i++) {
ItemStack itemStack = new ItemStackBuilder(materials.materials()[i])
.setDisplayName("&r")
.build();
int row = 0;
int row = 0;
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);
} else if (c == '1') {
mask.get(row).set(column, new FillerSlot(itemStack));
} else {
throw new IllegalArgumentException("Invalid character in pattern! (Must only be 0 and 1)");
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);
} else if (c == Character.forDigit(i + 1, 10)) {
mask.get(row).set(column, new FillerSlot(itemStack));
}
column++;
column++;
}
row++;
}
row++;
}
}
}

View File

@@ -30,4 +30,9 @@ public class FillerSlot implements Slot {
public ItemStack getItemStack(@NotNull final Player player) {
return itemStack;
}
@Override
public boolean isCaptive() {
return false;
}
}

View File

@@ -0,0 +1,14 @@
package com.willfp.eco.core.gui.slot;
import org.bukkit.Material;
import org.jetbrains.annotations.NotNull;
/**
* Mask materials store a set of materials which can be accessed by
* a filler mask.
*
* @param materials The materials.
*/
public record MaskMaterials(@NotNull Material... materials) {
}

View File

@@ -1,6 +1,8 @@
package com.willfp.eco.core.gui.slot;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.gui.slot.functional.SlotProvider;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
@@ -19,6 +21,22 @@ public interface Slot {
*/
ItemStack getItemStack(@NotNull Player player);
/**
* If the slot is captive. (Can items be placed in it).
*
* @return If captive.
*/
boolean isCaptive();
/**
* Create a builder for an ItemStack.
*
* @return The builder.
*/
static SlotBuilder builder() {
return Eco.getHandler().getGUIFactory().createSlotBuilder((player, menu) -> new ItemStack(Material.AIR));
}
/**
* Create a builder for an ItemStack.
*
@@ -26,7 +44,7 @@ public interface Slot {
* @return The builder.
*/
static SlotBuilder builder(@NotNull final ItemStack itemStack) {
return Eco.getHandler().getGUIFactory().createSlotBuilder(player -> itemStack);
return Eco.getHandler().getGUIFactory().createSlotBuilder((player, menu) -> itemStack);
}
/**
@@ -36,6 +54,16 @@ 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));
}
/**
* Create a builder for a player-specific ItemStack.
*
* @param provider The provider.
* @return The builder.
*/
static SlotBuilder builder(@NotNull final SlotProvider provider) {
return Eco.getHandler().getGUIFactory().createSlotBuilder(provider);
}
}

View File

@@ -1,5 +1,7 @@
package com.willfp.eco.core.gui.slot;
import com.willfp.eco.core.gui.slot.functional.SlotHandler;
import com.willfp.eco.core.gui.slot.functional.SlotModifier;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.jetbrains.annotations.NotNull;
@@ -15,7 +17,17 @@ public interface SlotBuilder {
* @param action The handler.
* @return The builder.
*/
SlotBuilder onLeftClick(@NotNull BiConsumer<InventoryClickEvent, Slot> action);
default SlotBuilder onLeftClick(@NotNull BiConsumer<InventoryClickEvent, Slot> action) {
return onLeftClick((event, slot, menu) -> action.accept(event, slot));
}
/**
* Set click handler.
*
* @param handler The handler.
* @return The builder.
*/
SlotBuilder onLeftClick(@NotNull SlotHandler handler);
/**
* Set click handler.
@@ -23,7 +35,17 @@ public interface SlotBuilder {
* @param action The handler.
* @return The builder.
*/
SlotBuilder onRightClick(@NotNull BiConsumer<InventoryClickEvent, Slot> action);
default SlotBuilder onRightClick(@NotNull BiConsumer<InventoryClickEvent, Slot> action) {
return onRightClick((event, slot, menu) -> action.accept(event, slot));
}
/**
* Set click handler.
*
* @param handler The handler.
* @return The builder.
*/
SlotBuilder onRightClick(@NotNull SlotHandler handler);
/**
* Set click handler.
@@ -31,7 +53,17 @@ public interface SlotBuilder {
* @param action The handler.
* @return The builder.
*/
SlotBuilder onShiftLeftClick(@NotNull BiConsumer<InventoryClickEvent, Slot> action);
default SlotBuilder onShiftLeftClick(@NotNull BiConsumer<InventoryClickEvent, Slot> action) {
return onShiftLeftClick((event, slot, menu) -> action.accept(event, slot));
}
/**
* Set click handler.
*
* @param handler The handler.
* @return The builder.
*/
SlotBuilder onShiftLeftClick(@NotNull SlotHandler handler);
/**
* Set click handler.
@@ -39,7 +71,17 @@ public interface SlotBuilder {
* @param action The handler.
* @return The builder.
*/
SlotBuilder onShiftRightClick(@NotNull BiConsumer<InventoryClickEvent, Slot> action);
default SlotBuilder onShiftRightClick(@NotNull BiConsumer<InventoryClickEvent, Slot> action) {
return onShiftRightClick((event, slot, menu) -> action.accept(event, slot));
}
/**
* Set click handler.
*
* @param handler The handler.
* @return The builder.
*/
SlotBuilder onShiftRightClick(@NotNull SlotHandler handler);
/**
* Set click handler.
@@ -47,7 +89,32 @@ public interface SlotBuilder {
* @param action The handler.
* @return The builder.
*/
SlotBuilder onMiddleClick(@NotNull BiConsumer<InventoryClickEvent, Slot> action);
default SlotBuilder onMiddleClick(@NotNull BiConsumer<InventoryClickEvent, Slot> action) {
return onMiddleClick((event, slot, menu) -> action.accept(event, slot));
}
/**
* Set click handler.
*
* @param handler The handler.
* @return The builder.
*/
SlotBuilder onMiddleClick(@NotNull SlotHandler handler);
/**
* Modify the ItemStack.
*
* @param modifier The modifier.
* @return The builder.
*/
SlotBuilder setModifier(@NotNull SlotModifier modifier);
/**
* Set slot to be a captive slot.
*
* @return The builder.
*/
SlotBuilder setCaptive();
/**
* Build the slot.

View File

@@ -0,0 +1,23 @@
package com.willfp.eco.core.gui.slot.functional;
import com.willfp.eco.core.gui.menu.Menu;
import com.willfp.eco.core.gui.slot.Slot;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.jetbrains.annotations.NotNull;
/**
* Interface to run on slot click.
*/
@FunctionalInterface
public interface SlotHandler {
/**
* Performs this operation on the given arguments.
*
* @param event The click event.
* @param slot The slot
* @param menu The menu.
*/
void handle(@NotNull InventoryClickEvent event,
@NotNull Slot slot,
@NotNull Menu menu);
}

View File

@@ -0,0 +1,23 @@
package com.willfp.eco.core.gui.slot.functional;
import com.willfp.eco.core.gui.menu.Menu;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
/**
* Interface to run on slot modify.
*/
@FunctionalInterface
public interface SlotModifier {
/**
* Performs this operation on the given arguments.
*
* @param player The player.
* @param menu The menu.
* @param previous The previous ItemStack.
*/
void modify(@NotNull Player player,
@NotNull Menu menu,
@NotNull ItemStack previous);
}

View File

@@ -0,0 +1,22 @@
package com.willfp.eco.core.gui.slot.functional;
import com.willfp.eco.core.gui.menu.Menu;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
/**
* Interface to run on slot display.
*/
@FunctionalInterface
public interface SlotProvider {
/**
* Performs this operation on the given arguments.
*
* @param player The player.
* @param menu The menu.
* @return The ItemStack.
*/
ItemStack provide(@NotNull Player player,
@NotNull Menu menu);
}

View File

@@ -77,4 +77,11 @@ public class PlaceholderEntry {
public boolean requiresPlayer() {
return requiresPlayer;
}
/**
* Register the placeholder.
*/
public void register() {
PlaceholderManager.registerPlaceholder(this);
}
}

View File

@@ -27,7 +27,7 @@ public class CustomItem implements TestableItem {
/**
* The test for ItemStacks to pass.
*/
private final Predicate<ItemStack> test;
private final Predicate<@NotNull ItemStack> test;
/**
* Example Item: what the user should see.
@@ -42,7 +42,7 @@ public class CustomItem implements TestableItem {
* @param item The example ItemStacks.
*/
public CustomItem(@NotNull final NamespacedKey key,
@NotNull final Predicate<ItemStack> test,
@NotNull final Predicate<@NotNull ItemStack> test,
@NotNull final ItemStack item) {
this.key = key;
this.test = test;
@@ -51,6 +51,10 @@ public class CustomItem implements TestableItem {
@Override
public boolean matches(@Nullable final ItemStack itemStack) {
if (itemStack == null) {
return false;
}
return test.test(itemStack);
}

View File

@@ -60,6 +60,18 @@ public final class Items {
* @return The found testable item, or an empty item if not found.
*/
public TestableItem lookup(@NotNull final String key) {
if (key.contains("?")) {
String[] options = key.split("\\?");
for (String option : options) {
TestableItem lookup = lookup(option);
if (!(lookup instanceof EmptyTestableItem)) {
return lookup;
}
}
return new EmptyTestableItem();
}
String[] args = key.split(" ");
if (args.length == 0) {
return new EmptyTestableItem();

View File

@@ -1,6 +1,5 @@
package com.willfp.eco.util;
import com.willfp.eco.core.tuples.Pair;
import lombok.experimental.UtilityClass;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
@@ -32,12 +31,10 @@ public class BlockUtils {
*/
private BiConsumer<Player, Block> blockBreakConsumer = null;
private Pair<Block, Set<Block>> getNearbyBlocksRecursively(@NotNull final Block start,
@NotNull final List<Material> allowedMaterials,
@NotNull final Set<Block> blocks,
final int limit) {
Block last = start;
private Set<Block> getNearbyBlocks(@NotNull final Block start,
@NotNull final List<Material> allowedMaterials,
@NotNull final Set<Block> blocks,
final int limit) {
for (BlockFace face : BlockFace.values()) {
Block block = start.getRelative(face);
if (blocks.contains(block)) {
@@ -46,46 +43,15 @@ public class BlockUtils {
if (allowedMaterials.contains(block.getType())) {
blocks.add(block);
last = block;
if (blocks.size() > limit) {
return new Pair<>(last, blocks);
if (blocks.size() > limit || blocks.size() > 2500) {
return blocks;
}
Pair<Block, Set<Block>> pair = getNearbyBlocksRecursively(last, allowedMaterials, blocks, limit);
assert pair.getSecond() != null;
blocks.addAll(pair.getSecond());
blocks.addAll(getNearbyBlocks(block, allowedMaterials, blocks, limit));
}
}
return new Pair<>(last, blocks);
}
private Set<Block> getNearbyBlocks(@NotNull final Block start,
@NotNull final List<Material> allowedMaterials,
@NotNull final Set<Block> blocks,
final int limit) {
/*
Prevent stack overflow.
*/
int cycles = (int) Math.ceil(limit / 1024D);
int cap = limit;
Block iterStart = start;
for (int i = 0; i < cycles; i++) {
assert iterStart != null;
Pair<Block, Set<Block>> pair = getNearbyBlocksRecursively(iterStart, allowedMaterials, blocks, cap);
assert pair.getSecond() != null;
iterStart = pair.getFirst();
blocks.addAll(pair.getSecond());
cap -= 1024;
}
return blocks;
}

View File

@@ -0,0 +1,22 @@
package com.willfp.eco.util;
import com.willfp.eco.core.tuples.Pair;
import lombok.experimental.UtilityClass;
/**
* Utilities / API methods for menus.
*/
@UtilityClass
public class MenuUtils {
/**
* Convert 0-53 slot to row and column pair.
*
* @param slot The slot.
* @return The pair of row and columns.
*/
public 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);
}
}

View File

@@ -131,7 +131,7 @@ public class NumberUtils {
if (numeral.isEmpty()) {
return 0;
}
for (Map.Entry<Integer, String> entry : NUMERALS.entrySet()) {
for (Map.Entry<Integer, String> entry : NUMERALS.descendingMap().entrySet()) {
if (numeral.startsWith(entry.getValue())) {
return entry.getKey() + fromNumeral(numeral.substring(entry.getValue().length()));
}

View File

@@ -3,6 +3,10 @@ package com.willfp.eco.util;
import com.google.common.collect.ImmutableList;
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager;
import lombok.experimental.UtilityClass;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.TextDecoration;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
@@ -27,9 +31,9 @@ public class StringUtils {
* Regexes for gradients.
*/
private static final List<Pattern> GRADIENT_PATTERNS = new ImmutableList.Builder<Pattern>()
.add(Pattern.compile("<GRADIENT:([0-9A-Fa-f]{6})>(.*?)</GRADIENT:([0-9A-Fa-f]{6})>"))
.add(Pattern.compile("<gradient:([0-9A-Fa-f]{6})>(.*?)</gradient:([0-9A-Fa-f]{6})>"))
.add(Pattern.compile("<G:([0-9A-Fa-f]{6})>(.*?)</G:([0-9A-Fa-f]{6})>"))
.add(Pattern.compile("<GRADIENT:([0-9A-Fa-f]{6})>(.*?)</GRADIENT:([0-9A-Fa-f]{6})>", Pattern.CASE_INSENSITIVE))
.add(Pattern.compile("<GRADIENT:#([0-9A-Fa-f]{6})>(.*?)</GRADIENT:#([0-9A-Fa-f]{6})>", Pattern.CASE_INSENSITIVE))
.add(Pattern.compile("<G:([0-9A-Fa-f]{6})>(.*?)</G:([0-9A-Fa-f]{6})>", Pattern.CASE_INSENSITIVE))
.add(Pattern.compile("<#:([0-9A-Fa-f]{6})>(.*?)</#:([0-9A-Fa-f]{6})>"))
.add(Pattern.compile("\\{#:([0-9A-Fa-f]{6})}(.*?)\\{/#:([0-9A-Fa-f]{6})}"))
.build();
@@ -43,6 +47,15 @@ public class StringUtils {
.add(Pattern.compile("<#" + "([A-Fa-f0-9]{6})" + ">"))
.build();
/**
* Legacy serializer.
*/
private static final LegacyComponentSerializer LEGACY_COMPONENT_SERIALIZER = LegacyComponentSerializer.builder()
.character('\u00a7')
.useUnusualXRepeatedCharacterHexFormat()
.hexColors()
.build();
/**
* Format a list of strings - converts Placeholders and Color codes.
*
@@ -122,14 +135,6 @@ public class StringUtils {
return matcher.appendTail(builder).toString();
}
/**
* Colors a string with a gradient.
*
* @param string The string to color.
* @param start The start color.
* @param end The end color.
* @return The string, colored.
*/
private static String processGradients(@NotNull final String string,
@NotNull final Color start,
@NotNull final Color end) {
@@ -167,14 +172,6 @@ public class StringUtils {
return stringBuilder.toString();
}
/**
* Creates chatColors for gradients.
*
* @param start The start color.
* @param end The end color.
* @param step How many colors are returned.
* @return Array of chat colors.
*/
private static ChatColor[] getGradientColors(@NotNull final Color start,
@NotNull final Color end,
final int step) {
@@ -195,12 +192,6 @@ public class StringUtils {
return colors;
}
/**
* Add gradients to a string.
*
* @param string The string.
* @return The string, colorized.
*/
private static String translateGradients(@NotNull final String string) {
String processedString = string;
for (Pattern pattern : GRADIENT_PATTERNS) {
@@ -254,4 +245,30 @@ public class StringUtils {
}
return string;
}
/**
* Convert legacy string to JSON.
*
* @param legacy The legacy string.
* @return The JSON String.
*/
public String legacyToJson(@NotNull final String legacy) {
return GsonComponentSerializer.gson().serialize(
Component.empty().decoration(TextDecoration.ITALIC, false).append(
LEGACY_COMPONENT_SERIALIZER.deserialize(legacy)
)
);
}
/**
* Convert JSON string to legacy.
*
* @param json The JSON string.
* @return The legacy string.
*/
public String jsonToLegacy(@NotNull final String json) {
return LEGACY_COMPONENT_SERIALIZER.serialize(
GsonComponentSerializer.gson().deserialize(json)
);
}
}

View File

@@ -0,0 +1,24 @@
import com.willfp.eco.util.NumberUtils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class NumberUtilsTest {
@Test
public void testFormatDouble() {
Assertions.assertEquals("3", NumberUtils.format(3.0D));
Assertions.assertEquals("3.20", NumberUtils.format(3.2D));
}
@Test
public void testLog2() {
Assertions.assertEquals(1, NumberUtils.log2(2));
}
@Test
public void testNumerals() {
Assertions.assertEquals(4, NumberUtils.fromNumeral("IV"));
Assertions.assertEquals(9, NumberUtils.fromNumeral("IX"));
Assertions.assertEquals("XIV", NumberUtils.toNumeral(14));
Assertions.assertEquals("XXI", NumberUtils.toNumeral(21));
}
}

View File

@@ -1,8 +1,21 @@
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.21"
}
}
group 'com.willfp'
version rootProject.version
subprojects {
apply plugin: "kotlin"
dependencies {
compileOnly project(":eco-api")
compileOnly 'org.jetbrains.kotlin:kotlin-stdlib:1.5.21'
}
}

View File

@@ -1,39 +0,0 @@
package com.willfp.eco.internal;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.items.CustomItem;
import com.willfp.eco.core.items.Items;
import com.willfp.eco.core.proxy.Cleaner;
import com.willfp.eco.internal.proxy.EcoProxyFactory;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.net.URLClassLoader;
public class EcoCleaner implements Cleaner {
@Override
public void clean(@NotNull final EcoPlugin plugin) {
if (!plugin.getProxyPackage().equalsIgnoreCase("")) {
EcoProxyFactory factory = (EcoProxyFactory) plugin.getProxyFactory();
factory.clean();
}
Plugins.LOADED_ECO_PLUGINS.remove(plugin.getName().toLowerCase());
for (CustomItem customItem : Items.getCustomItems()) {
if (customItem.getKey().getNamespace().equalsIgnoreCase(plugin.getName().toLowerCase())) {
Items.removeCustomItem(customItem.getKey());
}
}
if (plugin.getClass().getClassLoader() instanceof URLClassLoader urlClassLoader) {
try {
urlClassLoader.close();
} catch (IOException e) {
// Do nothing.
}
}
System.gc();
}
}

View File

@@ -1,12 +0,0 @@
package com.willfp.eco.internal;
import com.willfp.eco.core.EcoPlugin;
import lombok.experimental.UtilityClass;
import java.util.HashMap;
import java.util.Map;
@UtilityClass
public class Plugins {
public static final Map<String, EcoPlugin> LOADED_ECO_PLUGINS = new HashMap<>();
}

View File

@@ -1,70 +0,0 @@
package com.willfp.eco.internal.config;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.config.interfaces.Config;
import com.willfp.eco.core.config.interfaces.JSONConfig;
import com.willfp.eco.core.config.wrapper.ConfigFactory;
import com.willfp.eco.internal.config.json.EcoJSONConfigSection;
import com.willfp.eco.internal.config.json.EcoLoadableJSONConfig;
import com.willfp.eco.internal.config.yaml.EcoLoadableYamlConfig;
import com.willfp.eco.internal.config.yaml.EcoUpdatableYamlConfig;
import com.willfp.eco.internal.config.yaml.EcoYamlConfigSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
public class EcoConfigFactory implements ConfigFactory {
@Override
public Config createUpdatableYamlConfig(@NotNull final String configName,
@NotNull final EcoPlugin plugin,
@NotNull final String subDirectoryPath,
@NotNull final Class<?> source,
final boolean removeUnused,
@NotNull final String... updateBlacklist) {
return new EcoUpdatableYamlConfig(
configName,
plugin,
subDirectoryPath,
source,
removeUnused,
updateBlacklist
);
}
@Override
public JSONConfig createLoadableJSONConfig(@NotNull final String configName,
@NotNull final EcoPlugin plugin,
@NotNull final String subDirectoryPath,
@NotNull final Class<?> source) {
return new EcoLoadableJSONConfig(
configName,
plugin,
subDirectoryPath,
source
);
}
@Override
public Config createLoadableYamlConfig(@NotNull final String configName,
@NotNull final EcoPlugin plugin,
@NotNull final String subDirectoryPath,
@NotNull final Class<?> source) {
return new EcoLoadableYamlConfig(
configName,
plugin,
subDirectoryPath,
source
);
}
@Override
public Config createYamlConfig(@NotNull final YamlConfiguration config) {
return new EcoYamlConfigSection(config);
}
@Override
public JSONConfig createJSONConfig(@NotNull final Map<String, Object> values) {
return new EcoJSONConfigSection(values);
}
}

View File

@@ -1,11 +0,0 @@
package com.willfp.eco.internal.config.json;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
public class EcoJSONConfigSection extends EcoJSONConfigWrapper {
public EcoJSONConfigSection(@NotNull final Map<String, Object> values) {
this.init(values);
}
}

View File

@@ -1,368 +0,0 @@
package com.willfp.eco.internal.config.json;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.willfp.eco.core.config.interfaces.JSONConfig;
import com.willfp.eco.util.StringUtils;
import lombok.Getter;
import org.apache.commons.lang.Validate;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@SuppressWarnings({"unchecked", "unused"})
public class EcoJSONConfigWrapper implements JSONConfig {
@Getter
private final Gson handle = new GsonBuilder().setPrettyPrinting().create();
@Getter
private final Map<String, Object> values = new HashMap<>();
@Getter
private final Map<String, Object> cache = new HashMap<>();
public EcoJSONConfigWrapper() {
}
public void init(@NotNull final Map<String, Object> values) {
this.values.clear();
this.values.putAll(values);
}
@Override
public final void clearCache() {
cache.clear();
}
@Override
public String toPlaintext() {
return this.getHandle().toJson(this.getValues());
}
@Override
public boolean has(@NotNull final String path) {
return getOfKnownType(path, Object.class) != null;
}
@Nullable
protected <T> T getOfKnownType(@NotNull final String path,
@NotNull final Class<T> clazz) {
return getOfKnownType(path, clazz, true);
}
@Nullable
protected <T> T getOfKnownType(@NotNull final String path,
@NotNull final Class<T> clazz,
final boolean isBase) {
String closestPath = path;
if (cache.containsKey(path) && isBase) {
return (T) cache.get(path);
}
if (path.contains(".")) {
String[] split = path.split("\\.");
closestPath = split[0];
}
if (values.get(closestPath) instanceof Map && !path.equals(closestPath)) {
EcoJSONConfigSection section = new EcoJSONConfigSection((Map<String, Object>) values.get(closestPath));
return section.getOfKnownType(path.substring(closestPath.length() + 1), clazz, false);
} else {
if (values.containsKey(closestPath)) {
return (T) values.get(closestPath);
} else {
return null;
}
}
}
@NotNull
@Override
public List<String> getKeys(final boolean deep) {
if (deep) {
return new ArrayList<>(getDeepKeys(new HashSet<>(), ""));
} else {
return new ArrayList<>(values.keySet());
}
}
protected Set<String> getDeepKeys(@NotNull final Set<String> list,
@NotNull final String root) {
for (String key : values.keySet()) {
list.add(root + key);
if (values.get(key) instanceof Map) {
EcoJSONConfigSection section = new EcoJSONConfigSection((Map<String, Object>) values.get(key));
list.addAll(section.getDeepKeys(list, root + key + "."));
}
}
return list;
}
@Override
@Nullable
public Object get(@NotNull final String path) {
return getOfKnownType(path, Object.class);
}
@Override
public void set(@NotNull final String path,
@Nullable final Object object) {
setRecursively(path, object, true);
clearCache();
}
protected void setRecursively(@NotNull final String path,
@Nullable final Object object,
final boolean isBase) {
String closestPath = path;
if (path.contains(".")) {
String[] split = path.split("\\.");
closestPath = split[0];
}
if (values.get(closestPath) instanceof Map && !path.equals(closestPath)) {
EcoJSONConfigSection section = new EcoJSONConfigSection((Map<String, Object>) values.get(closestPath));
section.setRecursively(path.substring(closestPath.length() + 1), object, false);
values.put(closestPath, section.getValues());
} else {
Object obj = object;
if (object instanceof JSONConfig) {
obj = ((EcoJSONConfigWrapper) object).getValues();
}
values.put(path, obj);
}
}
@Override
@NotNull
public JSONConfig getSubsection(@NotNull final String path) {
JSONConfig subsection = getSubsectionOrNull(path);
Validate.notNull(subsection);
return subsection;
}
@Override
@Nullable
public JSONConfig getSubsectionOrNull(@NotNull final String path) {
if (values.containsKey(path)) {
Map<String, Object> subsection = (Map<String, Object>) values.get(path);
return new EcoJSONConfigSection(subsection);
} else {
return null;
}
}
@Override
@NotNull
public List<JSONConfig> getSubsections(@NotNull final String path) {
List<JSONConfig> subsections = getSubsectionsOrNull(path);
return subsections == null ? new ArrayList<>() : subsections;
}
@Override
@Nullable
public List<JSONConfig> getSubsectionsOrNull(@NotNull final String path) {
List<Map<String, Object>> maps = (List<Map<String, Object>>) getOfKnownType(path, Object.class);
if (maps == null) {
return null;
}
List<JSONConfig> configs = new ArrayList<>();
for (Map<String, Object> map : maps) {
configs.add(new EcoJSONConfigSection(map));
}
return configs;
}
@Override
public int getInt(@NotNull final String path) {
// ew
return Objects.requireNonNullElse(getOfKnownType(path, Double.class), 0D).intValue();
}
@Override
@Nullable
public Integer getIntOrNull(@NotNull final String path) {
if (has(path)) {
return getInt(path);
} else {
return null;
}
}
@Override
public int getInt(@NotNull final String path,
final int def) {
return Objects.requireNonNullElse(getOfKnownType(path, Integer.class), def);
}
@Override
@NotNull
public List<Integer> getInts(@NotNull final String path) {
return (List<Integer>) Objects.requireNonNullElse(getOfKnownType(path, Object.class), new ArrayList<>());
}
@Override
@Nullable
public List<Integer> getIntsOrNull(@NotNull final String path) {
if (has(path)) {
return getInts(path);
} else {
return null;
}
}
@Override
public boolean getBool(@NotNull final String path) {
return Objects.requireNonNullElse(getOfKnownType(path, Boolean.class), false);
}
@Override
@Nullable
public Boolean getBoolOrNull(@NotNull final String path) {
if (has(path)) {
return getBool(path);
} else {
return null;
}
}
@Override
@NotNull
public List<Boolean> getBools(@NotNull final String path) {
return (List<Boolean>) Objects.requireNonNullElse(getOfKnownType(path, Object.class), new ArrayList<>());
}
@Override
@Nullable
public List<Boolean> getBoolsOrNull(@NotNull final String path) {
if (has(path)) {
return getBools(path);
} else {
return null;
}
}
@Override
@NotNull
public String getString(@NotNull final String path) {
return getString(path, true);
}
@Override
@NotNull
public String getString(@NotNull final String path,
final boolean format) {
String string = Objects.requireNonNullElse(getOfKnownType(path, String.class), "");
return format ? StringUtils.format(string) : string;
}
@Override
@Nullable
public String getStringOrNull(@NotNull final String path) {
if (has(path)) {
return getString(path);
} else {
return null;
}
}
@Override
@Nullable
public String getStringOrNull(@NotNull final String path,
final boolean format) {
if (has(path)) {
return getString(path, format);
} else {
return null;
}
}
@Override
@NotNull
public List<String> getStrings(@NotNull final String path) {
return getStrings(path, true);
}
@Override
@NotNull
public List<String> getStrings(@NotNull final String path,
final boolean format) {
List<String> strings = (List<String>) Objects.requireNonNullElse(getOfKnownType(path, Object.class), new ArrayList<>());
return format ? StringUtils.formatList(strings) : strings;
}
@Override
@Nullable
public List<String> getStringsOrNull(@NotNull final String path) {
if (has(path)) {
return getStrings(path);
} else {
return null;
}
}
@Override
public @Nullable List<String> getStringsOrNull(@NotNull final String path,
final boolean format) {
if (has(path)) {
return getStrings(path, format);
} else {
return null;
}
}
@Override
public double getDouble(@NotNull final String path) {
return Objects.requireNonNullElse(getOfKnownType(path, Double.class), 0D);
}
@Override
@Nullable
public Double getDoubleOrNull(@NotNull final String path) {
if (has(path)) {
return getDouble(path);
} else {
return null;
}
}
@Override
@NotNull
public List<Double> getDoubles(@NotNull final String path) {
return (List<Double>) Objects.requireNonNullElse(getOfKnownType(path, Object.class), new ArrayList<>());
}
@Override
@Nullable
public List<Double> getDoublesOrNull(@NotNull final String path) {
if (has(path)) {
return getDoubles(path);
} else {
return null;
}
}
@Override
public JSONConfig clone() {
return new EcoJSONConfigSection(new HashMap<>(this.getValues()));
}
}

View File

@@ -1,128 +0,0 @@
package com.willfp.eco.internal.config.json;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.config.interfaces.LoadableConfig;
import lombok.AccessLevel;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.HashMap;
@SuppressWarnings({"unchecked", "unused"})
public class EcoLoadableJSONConfig extends EcoJSONConfigWrapper implements LoadableConfig {
@Getter
private final File configFile;
@Getter(AccessLevel.PROTECTED)
private final EcoPlugin plugin;
@Getter
private final String name;
@Getter(AccessLevel.PROTECTED)
private final String subDirectoryPath;
@Getter(AccessLevel.PROTECTED)
private final Class<?> source;
public EcoLoadableJSONConfig(@NotNull final String configName,
@NotNull final EcoPlugin plugin,
@NotNull final String subDirectoryPath,
@NotNull final Class<?> source) {
this.plugin = plugin;
this.name = configName + ".json";
this.source = source;
this.subDirectoryPath = subDirectoryPath;
File directory = new File(this.getPlugin().getDataFolder(), subDirectoryPath);
if (!directory.exists()) {
directory.mkdirs();
}
if (!new File(directory, this.name).exists()) {
createFile();
}
this.configFile = new File(directory, this.name);
try {
init(this.configFile);
} catch (IOException e) {
e.printStackTrace();
}
plugin.getConfigHandler().addConfig(this);
}
public void reloadFromFile() {
try {
init(this.configFile);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void createFile() {
String resourcePath = getResourcePath();
InputStream in = source.getResourceAsStream(resourcePath);
File outFile = new File(this.getPlugin().getDataFolder(), resourcePath);
int lastIndex = resourcePath.lastIndexOf('/');
File outDir = new File(this.getPlugin().getDataFolder(), resourcePath.substring(0, Math.max(lastIndex, 0)));
if (!outDir.exists()) {
outDir.mkdirs();
}
try {
if (!outFile.exists()) {
OutputStream out = new FileOutputStream(outFile);
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
out.close();
in.close();
}
} catch (IOException ignored) {
}
}
@Override
public String getResourcePath() {
String resourcePath;
if (subDirectoryPath.isEmpty()) {
resourcePath = name;
} else {
resourcePath = subDirectoryPath + name;
}
return "/" + resourcePath;
}
@Override
public void save() throws IOException {
if (configFile.delete()) {
Files.write(configFile.toPath(), this.toPlaintext().getBytes(), StandardOpenOption.CREATE, StandardOpenOption.WRITE);
}
}
public void init(@NotNull final File file) throws FileNotFoundException {
super.init(this.getHandle().fromJson(new FileReader(file), HashMap.class));
}
}

View File

@@ -1,89 +0,0 @@
package com.willfp.eco.internal.config.updating;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginDependent;
import com.willfp.eco.core.config.interfaces.LoadableConfig;
import com.willfp.eco.core.config.updating.ConfigHandler;
import com.willfp.eco.core.config.updating.ConfigUpdater;
import com.willfp.eco.internal.config.json.EcoLoadableJSONConfig;
import com.willfp.eco.internal.config.updating.exceptions.InvalidUpdateMethodException;
import com.willfp.eco.internal.config.yaml.EcoLoadableYamlConfig;
import com.willfp.eco.internal.config.yaml.EcoUpdatableYamlConfig;
import org.jetbrains.annotations.NotNull;
import org.reflections.Reflections;
import org.reflections.scanners.MethodAnnotationsScanner;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
public class EcoConfigHandler extends PluginDependent<EcoPlugin> implements ConfigHandler {
private final List<LoadableConfig> configs = new ArrayList<>();
private final Reflections reflections;
public EcoConfigHandler(@NotNull final EcoPlugin plugin) {
super(plugin);
this.reflections = new Reflections(
this.getPlugin().getClass().getClassLoader(),
new MethodAnnotationsScanner()
);
}
@Override
public void callUpdate() {
for (Method method : reflections.getMethodsAnnotatedWith(ConfigUpdater.class)) {
if (!Modifier.isStatic(method.getModifiers())) {
throw new InvalidUpdateMethodException("Update method must be static.");
}
try {
if (method.getParameterCount() == 0) {
method.invoke(null);
} else if (method.getParameterCount() == 1) {
method.invoke(null, this.getPlugin());
} else {
throw new InvalidUpdateMethodException("Update method must have 0 parameters or a plugin parameter.");
}
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
throw new InvalidUpdateMethodException("Update method generated an exception.");
}
}
}
@Override
public void saveAllConfigs() {
try {
for (LoadableConfig config : configs) {
config.save();
}
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void addConfig(@NotNull final LoadableConfig config) {
configs.add(config);
}
@Override
public void updateConfigs() {
for (LoadableConfig config : configs) {
if (config instanceof EcoUpdatableYamlConfig updatableYamlConfig) {
updatableYamlConfig.update();
}
if (config instanceof EcoLoadableYamlConfig ecoLoadableYamlConfig) {
ecoLoadableYamlConfig.reloadFromFile();
}
if (config instanceof EcoLoadableJSONConfig ecoLoadableJSONConfig) {
ecoLoadableJSONConfig.reloadFromFile();
}
}
}
}

View File

@@ -1,9 +0,0 @@
package com.willfp.eco.internal.config.updating.exceptions;
import org.jetbrains.annotations.NotNull;
public class InvalidUpdateMethodException extends RuntimeException {
public InvalidUpdateMethodException(@NotNull final String message) {
super(message);
}
}

View File

@@ -1,118 +0,0 @@
package com.willfp.eco.internal.config.yaml;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.config.interfaces.LoadableConfig;
import com.willfp.eco.core.config.interfaces.WrappedYamlConfiguration;
import lombok.AccessLevel;
import lombok.Getter;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class EcoLoadableYamlConfig extends EcoYamlConfigWrapper<YamlConfiguration> implements WrappedYamlConfiguration, LoadableConfig {
@Getter
private final File configFile;
@Getter(AccessLevel.PROTECTED)
private final EcoPlugin plugin;
@Getter
private final String name;
@Getter(AccessLevel.PROTECTED)
private final String subDirectoryPath;
@Getter(AccessLevel.PROTECTED)
private final Class<?> source;
public EcoLoadableYamlConfig(@NotNull final String configName,
@NotNull final EcoPlugin plugin,
@NotNull final String subDirectoryPath,
@NotNull final Class<?> source) {
this.plugin = plugin;
this.name = configName + ".yml";
this.source = source;
this.subDirectoryPath = subDirectoryPath;
File directory = new File(this.getPlugin().getDataFolder(), subDirectoryPath);
if (!directory.exists()) {
directory.mkdirs();
}
if (!new File(directory, this.name).exists()) {
createFile();
}
this.configFile = new File(directory, this.name);
this.getPlugin().getConfigHandler().addConfig(this);
init(YamlConfiguration.loadConfiguration(configFile));
}
public void reloadFromFile() {
try {
this.getHandle().load(this.getConfigFile());
} catch (IOException | InvalidConfigurationException e) {
e.printStackTrace();
}
}
@Override
public void createFile() {
String resourcePath = getResourcePath();
InputStream in = source.getResourceAsStream(resourcePath);
File outFile = new File(this.getPlugin().getDataFolder(), resourcePath);
int lastIndex = resourcePath.lastIndexOf('/');
File outDir = new File(this.getPlugin().getDataFolder(), resourcePath.substring(0, Math.max(lastIndex, 0)));
if (!outDir.exists()) {
outDir.mkdirs();
}
try {
if (!outFile.exists()) {
OutputStream out = new FileOutputStream(outFile);
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
out.close();
in.close();
}
} catch (IOException ignored) {
}
plugin.getConfigHandler().addConfig(this);
}
@Override
public String getResourcePath() {
String resourcePath;
if (subDirectoryPath.isEmpty()) {
resourcePath = name;
} else {
resourcePath = subDirectoryPath + name;
}
return "/" + resourcePath;
}
@Override
public void save() throws IOException {
this.getHandle().save(this.getConfigFile());
}
@Override
public YamlConfiguration getBukkitHandle() {
return this.getHandle();
}
}

View File

@@ -1,91 +0,0 @@
package com.willfp.eco.internal.config.yaml;
import com.willfp.eco.core.EcoPlugin;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class EcoUpdatableYamlConfig extends EcoLoadableYamlConfig {
private final boolean removeUnused;
private final List<String> updateBlacklist;
public EcoUpdatableYamlConfig(@NotNull final String configName,
@NotNull final EcoPlugin plugin,
@NotNull final String subDirectoryPath,
@NotNull final Class<?> source,
final boolean removeUnused,
@NotNull final String... updateBlacklist) {
super(configName, plugin, subDirectoryPath, source);
this.removeUnused = removeUnused;
this.updateBlacklist = new ArrayList<>(Arrays.asList(updateBlacklist));
this.updateBlacklist.removeIf(String::isEmpty);
plugin.getConfigHandler().addConfig(this);
update();
}
public void update() {
super.clearCache();
try {
this.getHandle().load(this.getConfigFile());
YamlConfiguration newConfig = this.getConfigInJar();
if (newConfig.getKeys(true).equals(this.getHandle().getKeys(true))) {
return;
}
newConfig.getKeys(true).forEach((s -> {
if (!this.getHandle().getKeys(true).contains(s)) {
if (updateBlacklist.stream().noneMatch(s::contains)) {
this.getHandle().set(s, newConfig.get(s));
}
}
}));
if (this.removeUnused) {
this.getHandle().getKeys(true).forEach((s -> {
if (!newConfig.getKeys(true).contains(s)) {
if (updateBlacklist.stream().noneMatch(s::contains)) {
this.getHandle().set(s, null);
}
}
}));
}
this.getHandle().save(this.getConfigFile());
} catch (IOException | InvalidConfigurationException e) {
e.printStackTrace();
}
}
public YamlConfiguration getConfigInJar() {
InputStream newIn = this.getSource().getResourceAsStream(getResourcePath());
if (newIn == null) {
throw new NullPointerException(this.getName() + " is null?");
}
BufferedReader reader = new BufferedReader(new InputStreamReader(newIn, StandardCharsets.UTF_8));
YamlConfiguration newConfig = new YamlConfiguration();
try {
newConfig.load(reader);
} catch (IOException | InvalidConfigurationException e) {
e.printStackTrace();
}
return newConfig;
}
}

View File

@@ -1,10 +0,0 @@
package com.willfp.eco.internal.config.yaml;
import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.NotNull;
public class EcoYamlConfigSection extends EcoYamlConfigWrapper<ConfigurationSection> {
public EcoYamlConfigSection(@NotNull final ConfigurationSection section) {
this.init(section);
}
}

View File

@@ -1,316 +0,0 @@
package com.willfp.eco.internal.config.yaml;
import com.willfp.eco.core.config.interfaces.Config;
import com.willfp.eco.util.StringUtils;
import lombok.Getter;
import org.apache.commons.lang.Validate;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@SuppressWarnings({"unchecked", "unused"})
public class EcoYamlConfigWrapper<T extends ConfigurationSection> implements Config {
@Getter
private T handle = null;
private final Map<String, Object> cache = new HashMap<>();
public EcoYamlConfigWrapper() {
}
protected Config init(@NotNull final T config) {
this.handle = config;
return this;
}
@Override
public String toPlaintext() {
YamlConfiguration temp = new YamlConfiguration();
for (String key : handle.getKeys(true)) {
temp.set(key, handle.get(key));
}
return temp.saveToString();
}
@Override
public final void clearCache() {
cache.clear();
}
@Override
public boolean has(@NotNull final String path) {
return handle.contains(path);
}
@NotNull
@Override
public List<String> getKeys(final boolean deep) {
return new ArrayList<>(handle.getKeys(deep));
}
@Override
@Nullable
public Object get(@NotNull final String path) {
return handle.get(path);
}
@Override
public void set(@NotNull final String path,
@Nullable final Object object) {
cache.remove(path);
handle.set(path, object);
}
@Override
@NotNull
public Config getSubsection(@NotNull final String path) {
Config subsection = getSubsectionOrNull(path);
Validate.notNull(subsection);
return subsection;
}
@Override
@Nullable
public Config getSubsectionOrNull(@NotNull final String path) {
if (cache.containsKey(path)) {
return (Config) cache.get(path);
} else {
ConfigurationSection raw = handle.getConfigurationSection(path);
if (raw == null) {
cache.put(path, null);
} else {
cache.put(path, new EcoYamlConfigSection(raw));
}
return getSubsectionOrNull(path);
}
}
@Override
public int getInt(@NotNull final String path) {
if (cache.containsKey(path)) {
return (int) cache.get(path);
} else {
cache.put(path, handle.getInt(path, 0));
return getInt(path);
}
}
@Override
@Nullable
public Integer getIntOrNull(@NotNull final String path) {
if (has(path)) {
return getInt(path);
} else {
return null;
}
}
@Override
public int getInt(@NotNull final String path,
final int def) {
if (cache.containsKey(path)) {
return (int) cache.get(path);
} else {
cache.put(path, handle.getInt(path, def));
return getInt(path);
}
}
@Override
@NotNull
public List<Integer> getInts(@NotNull final String path) {
if (cache.containsKey(path)) {
return (List<Integer>) cache.get(path);
} else {
cache.put(path, has(path) ? new ArrayList<>(handle.getIntegerList(path)) : new ArrayList<>());
return getInts(path);
}
}
@Override
@Nullable
public List<Integer> getIntsOrNull(@NotNull final String path) {
if (has(path)) {
return getInts(path);
} else {
return null;
}
}
@Override
public boolean getBool(@NotNull final String path) {
if (cache.containsKey(path)) {
return (boolean) cache.get(path);
} else {
cache.put(path, handle.getBoolean(path));
return getBool(path);
}
}
@Override
@Nullable
public Boolean getBoolOrNull(@NotNull final String path) {
if (has(path)) {
return getBool(path);
} else {
return null;
}
}
@Override
@NotNull
public List<Boolean> getBools(@NotNull final String path) {
if (cache.containsKey(path)) {
return (List<Boolean>) cache.get(path);
} else {
cache.put(path, has(path) ? new ArrayList<>(handle.getBooleanList(path)) : new ArrayList<>());
return getBools(path);
}
}
@Override
@Nullable
public List<Boolean> getBoolsOrNull(@NotNull final String path) {
if (has(path)) {
return getBools(path);
} else {
return null;
}
}
@Override
@NotNull
public String getString(@NotNull final String path) {
if (cache.containsKey(path)) {
return (String) cache.get(path);
} else {
cache.put(path, StringUtils.format(Objects.requireNonNull(handle.getString(path, ""))));
return getString(path);
}
}
@Override
public @NotNull String getString(@NotNull final String path,
final boolean format) {
if (cache.containsKey(path)) {
return (String) cache.get(path);
} else {
String string = Objects.requireNonNull(handle.getString(path, ""));
cache.put(path, format ? StringUtils.format(string) : string);
return getString(path);
}
}
@Override
@Nullable
public String getStringOrNull(@NotNull final String path) {
if (has(path)) {
return getString(path);
} else {
return null;
}
}
@Override
public @Nullable String getStringOrNull(@NotNull final String path,
final boolean format) {
if (has(path)) {
return getString(path, format);
} else {
return null;
}
}
@Override
@NotNull
public List<String> getStrings(@NotNull final String path) {
return getStrings(path, true);
}
@Override
@NotNull
public List<String> getStrings(@NotNull final String path,
final boolean format) {
if (cache.containsKey(path)) {
return format ? StringUtils.formatList((List<String>) cache.get(path)) : (List<String>) cache.get(path);
} else {
cache.put(path, has(path) ? new ArrayList<>(handle.getStringList(path)) : new ArrayList<>());
return getStrings(path);
}
}
@Override
@Nullable
public List<String> getStringsOrNull(@NotNull final String path) {
if (has(path)) {
return getStrings(path);
} else {
return null;
}
}
@Override
public @Nullable List<String> getStringsOrNull(@NotNull final String path,
final boolean format) {
if (has(path)) {
return getStrings(path, format);
} else {
return null;
}
}
@Override
public double getDouble(@NotNull final String path) {
if (cache.containsKey(path)) {
return (double) cache.get(path);
} else {
cache.put(path, handle.getDouble(path));
return getDouble(path);
}
}
@Override
@Nullable
public Double getDoubleOrNull(@NotNull final String path) {
if (has(path)) {
return getDouble(path);
} else {
return null;
}
}
@Override
@NotNull
public List<Double> getDoubles(@NotNull final String path) {
if (cache.containsKey(path)) {
return (List<Double>) cache.get(path);
} else {
cache.put(path, has(path) ? new ArrayList<>(handle.getDoubleList(path)) : new ArrayList<>());
return getDoubles(path);
}
}
@Override
@Nullable
public List<Double> getDoublesOrNull(@NotNull final String path) {
if (has(path)) {
return getDoubles(path);
} else {
return null;
}
}
@Override
public Config clone() {
return new EcoYamlConfigSection(YamlConfiguration.loadConfiguration(new StringReader(this.toPlaintext())));
}
}

View File

@@ -1,18 +0,0 @@
package com.willfp.eco.internal.drops;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.config.updating.ConfigUpdater;
import lombok.Getter;
import lombok.experimental.UtilityClass;
import org.jetbrains.annotations.NotNull;
@UtilityClass
public final class DropManager {
@Getter
private DropQueueType type = DropQueueType.COLLATED;
@ConfigUpdater
public static void update(@NotNull final EcoPlugin plugin) {
type = plugin.getConfigYml().getBool("use-fast-collated-drops") ? DropQueueType.COLLATED : DropQueueType.STANDARD;
}
}

View File

@@ -1,6 +0,0 @@
package com.willfp.eco.internal.drops;
public enum DropQueueType {
STANDARD,
COLLATED
}

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;
import org.jetbrains.annotations.NotNull;
public class EcoDropQueueFactory implements DropQueueFactory {
@Override
public InternalDropQueue create(@NotNull final Player player) {
return DropManager.getType() == DropQueueType.COLLATED ? new EcoFastCollatedDropQueue(player) : new EcoDropQueue(player);
}
}

View File

@@ -1,114 +0,0 @@
package com.willfp.eco.internal.drops.impl;
import com.willfp.eco.core.drops.InternalDropQueue;
import com.willfp.eco.util.TelekinesisUtils;
import lombok.AccessLevel;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.ExperienceOrb;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerExpChangeEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
public class EcoDropQueue implements InternalDropQueue {
@Getter(AccessLevel.PROTECTED)
private final List<ItemStack> items;
@Getter(AccessLevel.PROTECTED)
private int xp;
@Getter(AccessLevel.PROTECTED)
private final Player player;
@Getter(AccessLevel.PROTECTED)
private Location loc;
@Getter(AccessLevel.PROTECTED)
private boolean hasTelekinesis = false;
public EcoDropQueue(@NotNull final Player player) {
this.items = new ArrayList<>();
this.xp = 0;
this.player = player;
this.loc = player.getLocation();
}
@Override
public InternalDropQueue addItem(@NotNull final ItemStack item) {
this.items.add(item);
return this;
}
@Override
public InternalDropQueue addItems(@NotNull final Collection<ItemStack> itemStacks) {
this.items.addAll(itemStacks);
return this;
}
@Override
public InternalDropQueue addXP(final int amount) {
this.xp += amount;
return this;
}
@Override
public InternalDropQueue setLocation(@NotNull final Location location) {
this.loc = location;
return this;
}
@Override
public InternalDropQueue forceTelekinesis() {
this.hasTelekinesis = true;
return this;
}
@Override
public void push() {
if (!hasTelekinesis) {
hasTelekinesis = TelekinesisUtils.testPlayer(player);
}
World world = loc.getWorld();
assert world != null;
loc = loc.add(0.5, 0.5, 0.5);
items.removeIf(itemStack -> itemStack.getType() == Material.AIR);
if (items.isEmpty()) {
return;
}
if (hasTelekinesis) {
HashMap<Integer, ItemStack> leftover = player.getInventory().addItem(items.toArray(new ItemStack[0]));
for (ItemStack drop : leftover.values()) {
world.dropItem(loc, drop).setVelocity(new Vector());
}
if (xp > 0) {
PlayerExpChangeEvent event = new PlayerExpChangeEvent(player, xp);
Bukkit.getPluginManager().callEvent(event);
ExperienceOrb orb = (ExperienceOrb) world.spawnEntity(player.getLocation().add(0, 0.2, 0), EntityType.EXPERIENCE_ORB);
orb.setVelocity(new Vector(0, 0, 0));
orb.setExperience(event.getAmount());
}
} else {
for (ItemStack drop : items) {
world.dropItem(loc, drop).setVelocity(new Vector());
}
if (xp > 0) {
ExperienceOrb orb = (ExperienceOrb) world.spawnEntity(loc, EntityType.EXPERIENCE_ORB);
orb.setExperience(xp);
}
}
}
}

View File

@@ -1,61 +0,0 @@
package com.willfp.eco.internal.drops.impl;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.Accessors;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class EcoFastCollatedDropQueue extends EcoDropQueue {
public static final Map<Player, CollatedDrops> COLLATED_MAP = new ConcurrentHashMap<>();
public EcoFastCollatedDropQueue(@NotNull final Player player) {
super(player);
}
@Override
public void push() {
CollatedDrops fetched = COLLATED_MAP.get(getPlayer());
CollatedDrops collatedDrops = fetched == null ? new CollatedDrops(getItems(), getLoc(), getXp()) : fetched.addDrops(getItems()).setLocation(getLoc()).addXp(getXp());
COLLATED_MAP.put(this.getPlayer(), collatedDrops);
}
@ToString
public static final class CollatedDrops {
@Getter
private final List<ItemStack> drops;
@Getter
@Setter
@Accessors(chain = true)
private Location location;
@Getter
private int xp;
private CollatedDrops(@NotNull final List<ItemStack> drops,
@NotNull final Location location,
final int xp) {
this.drops = drops;
this.location = location;
this.xp = xp;
}
public CollatedDrops addDrops(@NotNull final List<ItemStack> toAdd) {
drops.addAll(toAdd);
return this;
}
public CollatedDrops addXp(final int xp) {
this.xp += xp;
return this;
}
}
}

View File

@@ -1,32 +0,0 @@
package com.willfp.eco.internal.events;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginDependent;
import com.willfp.eco.core.events.EventManager;
import org.bukkit.Bukkit;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
public class EcoEventManager extends PluginDependent<EcoPlugin> implements EventManager {
@ApiStatus.Internal
public EcoEventManager(@NotNull final EcoPlugin plugin) {
super(plugin);
}
@Override
public void registerListener(@NotNull final Listener listener) {
Bukkit.getPluginManager().registerEvents(listener, this.getPlugin());
}
@Override
public void unregisterListener(@NotNull final Listener listener) {
HandlerList.unregisterAll(listener);
}
@Override
public void unregisterAllListeners() {
HandlerList.unregisterAll(this.getPlugin());
}
}

View File

@@ -1,138 +0,0 @@
package com.willfp.eco.internal.extensions;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginDependent;
import com.willfp.eco.core.config.interfaces.Config;
import com.willfp.eco.core.config.yaml.YamlTransientConfig;
import com.willfp.eco.core.extensions.Extension;
import com.willfp.eco.core.extensions.ExtensionLoader;
import com.willfp.eco.core.extensions.ExtensionMetadata;
import com.willfp.eco.core.extensions.MalformedExtensionException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class EcoExtensionLoader extends PluginDependent<EcoPlugin> implements ExtensionLoader {
private final Map<Extension, ClassLoader> extensions = new HashMap<>();
public EcoExtensionLoader(@NotNull final EcoPlugin plugin) {
super(plugin);
}
@Override
public void loadExtensions() {
File dir = new File(this.getPlugin().getDataFolder(), "/extensions");
if (!dir.exists()) {
dir.mkdirs();
}
File[] extensionJars = dir.listFiles();
if (extensionJars == null) {
return;
}
for (File extensionJar : extensionJars) {
if (!extensionJar.isFile()) {
continue;
}
try {
loadExtension(extensionJar);
} catch (MalformedExtensionException e) {
this.getPlugin().getLogger().warning(extensionJar.getName() + " caused an error!");
}
}
}
private void loadExtension(@NotNull final File extensionJar) throws MalformedExtensionException {
URL url = null;
try {
url = extensionJar.toURI().toURL();
} catch (MalformedURLException e) {
e.printStackTrace();
}
ClassLoader classLoader = new URLClassLoader(new URL[]{url}, this.getPlugin().getClass().getClassLoader());
InputStream ymlIn = classLoader.getResourceAsStream("extension.yml");
if (ymlIn == null) {
throw new MalformedExtensionException("No extension.yml found in " + extensionJar.getName());
}
Config extensionYml = new YamlTransientConfig(YamlConfiguration.loadConfiguration(new InputStreamReader(ymlIn)));
String mainClass = extensionYml.getStringOrNull("main");
String name = extensionYml.getStringOrNull("name");
String version = extensionYml.getStringOrNull("version");
String author = extensionYml.getStringOrNull("author");
if (mainClass == null) {
throw new MalformedExtensionException("Invalid extension.yml found in " + extensionJar.getName());
}
if (name == null) {
this.getPlugin().getLogger().warning(extensionJar.getName() + " doesn't have a name!");
name = "Unnamed Extension " + extensionJar.getName();
}
if (version == null) {
this.getPlugin().getLogger().warning(extensionJar.getName() + " doesn't have a version!");
version = "1.0.0";
}
if (author == null) {
this.getPlugin().getLogger().warning(extensionJar.getName() + " doesn't have an author!");
author = "Unnamed Author";
}
ExtensionMetadata metadata = new ExtensionMetadata(version, name, author);
Class<?> cls;
Object object = null;
try {
cls = classLoader.loadClass(mainClass);
object = cls.getConstructor(EcoPlugin.class).newInstance(this.getPlugin());
} catch (ReflectiveOperationException e) {
e.printStackTrace();
}
if (!(object instanceof Extension extension)) {
throw new MalformedExtensionException(extensionJar.getName() + " is invalid");
}
extension.setMetadata(metadata);
extension.enable();
extensions.put(extension, classLoader);
}
@Override
public void unloadExtensions() {
extensions.keySet().forEach(Extension::disable);
for (ClassLoader loader : extensions.values()) {
try {
((URLClassLoader) loader).close();
} catch (IOException e) {
// Do nothing.
}
}
extensions.clear();
}
@Override
public Set<Extension> getLoadedExtensions() {
return extensions.keySet();
}
}

View File

@@ -1,18 +0,0 @@
package com.willfp.eco.internal.factory;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginDependent;
import com.willfp.eco.core.factory.MetadataValueFactory;
import org.bukkit.metadata.FixedMetadataValue;
import org.jetbrains.annotations.NotNull;
public class EcoMetadataValueFactory extends PluginDependent<EcoPlugin> implements MetadataValueFactory {
public EcoMetadataValueFactory(@NotNull final EcoPlugin plugin) {
super(plugin);
}
@Override
public FixedMetadataValue create(@NotNull final Object value) {
return new FixedMetadataValue(this.getPlugin(), value);
}
}

View File

@@ -1,18 +0,0 @@
package com.willfp.eco.internal.factory;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginDependent;
import com.willfp.eco.core.factory.NamespacedKeyFactory;
import org.bukkit.NamespacedKey;
import org.jetbrains.annotations.NotNull;
public class EcoNamespacedKeyFactory extends PluginDependent<EcoPlugin> implements NamespacedKeyFactory {
public EcoNamespacedKeyFactory(@NotNull final EcoPlugin plugin) {
super(plugin);
}
@Override
public NamespacedKey create(@NotNull final String key) {
return new NamespacedKey(this.getPlugin(), key);
}
}

View File

@@ -1,26 +0,0 @@
package com.willfp.eco.internal.factory;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginDependent;
import com.willfp.eco.core.factory.RunnableFactory;
import com.willfp.eco.core.scheduling.RunnableTask;
import com.willfp.eco.internal.scheduling.EcoRunnableTask;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
public class EcoRunnableFactory extends PluginDependent<EcoPlugin> implements RunnableFactory {
public EcoRunnableFactory(@NotNull final EcoPlugin plugin) {
super(plugin);
}
@Override
public RunnableTask create(@NotNull final Consumer<RunnableTask> consumer) {
return new EcoRunnableTask(this.getPlugin()) {
@Override
public void run() {
consumer.accept(this);
}
};
}
}

View File

@@ -1,24 +0,0 @@
package com.willfp.eco.internal.gui;
import com.willfp.eco.core.gui.GUIFactory;
import com.willfp.eco.core.gui.menu.MenuBuilder;
import com.willfp.eco.core.gui.slot.SlotBuilder;
import com.willfp.eco.internal.gui.menu.EcoMenuBuilder;
import com.willfp.eco.internal.gui.slot.EcoSlotBuilder;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.function.Function;
public class EcoGUIFactory implements GUIFactory {
@Override
public SlotBuilder createSlotBuilder(@NotNull final Function<Player, ItemStack> provider) {
return new EcoSlotBuilder(provider);
}
@Override
public MenuBuilder createMenuBuilder(final int rows) {
return new EcoMenuBuilder(rows);
}
}

View File

@@ -1,98 +0,0 @@
package com.willfp.eco.internal.gui.menu;
import com.willfp.eco.core.gui.menu.Menu;
import com.willfp.eco.core.gui.slot.FillerSlot;
import com.willfp.eco.core.gui.slot.Slot;
import com.willfp.eco.internal.gui.slot.EcoFillerSlot;
import com.willfp.eco.util.StringUtils;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.function.Consumer;
public class EcoMenu implements Menu {
@Getter
private final int rows;
private final List<List<Slot>> slots;
@Getter
private final String title;
private final Consumer<InventoryCloseEvent> onClose;
public EcoMenu(final int rows,
@NotNull final List<List<Slot>> slots,
@NotNull final String title,
@NotNull final Consumer<InventoryCloseEvent> onClose) {
this.rows = rows;
this.slots = slots;
this.title = title;
this.onClose = onClose;
}
@Override
public Slot getSlot(final int row,
final int column) {
if (row < 1 || row > this.rows) {
throw new IllegalArgumentException("Invalid row number!");
}
if (column < 1 || column > 9) {
throw new IllegalArgumentException("Invalid column number!");
}
Slot slot = slots.get(row - 1).get(column - 1);
if (slot instanceof FillerSlot fillerSlot) {
slots.get(row - 1).set(
column - 1,
new EcoFillerSlot(fillerSlot.getItemStack())
);
return getSlot(row, column);
}
return slots.get(row - 1).get(column - 1);
}
@Override
public Inventory open(@NotNull final Player player) {
Inventory inventory = Bukkit.createInventory(null, rows * 9, title);
int i = 0;
for (List<Slot> row : slots) {
for (Slot item : row) {
if (i == rows * 9) {
break;
}
ItemStack slotItem = item.getItemStack(player);
ItemMeta meta = slotItem.getItemMeta();
if (meta != null) {
List<String> lore = meta.getLore();
if (lore != null) {
lore.replaceAll(s -> StringUtils.format(s, player));
meta.setLore(lore);
}
slotItem.setItemMeta(meta);
}
inventory.setItem(i, slotItem);
i++;
}
}
player.openInventory(inventory);
MenuHandler.registerMenu(inventory, this);
return inventory;
}
public void handleClose(@NotNull final InventoryCloseEvent event) {
onClose.accept(event);
}
}

View File

@@ -1,92 +0,0 @@
package com.willfp.eco.internal.gui.menu;
import com.willfp.eco.core.gui.menu.Menu;
import com.willfp.eco.core.gui.menu.MenuBuilder;
import com.willfp.eco.core.gui.slot.FillerMask;
import com.willfp.eco.core.gui.slot.Slot;
import com.willfp.eco.internal.gui.slot.EcoFillerSlot;
import com.willfp.eco.util.ListUtils;
import com.willfp.eco.util.StringUtils;
import org.bukkit.Material;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.function.Consumer;
public class EcoMenuBuilder implements MenuBuilder {
private final int rows;
private String title = "Menu";
private List<List<Slot>> maskSlots;
private final List<List<Slot>> slots;
private Consumer<InventoryCloseEvent> onClose = (event) -> {
};
public EcoMenuBuilder(final int rows) {
this.rows = rows;
this.slots = ListUtils.create2DList(rows, 9);
this.maskSlots = ListUtils.create2DList(rows, 9);
}
@Override
public MenuBuilder setTitle(@NotNull final String title) {
this.title = StringUtils.format(title);
return this;
}
@Override
public MenuBuilder setSlot(final int row,
final int column,
@NotNull final Slot slot) {
if (row < 1 || row > this.rows) {
throw new IllegalArgumentException("Invalid row number!");
}
if (column < 1 || column > 9) {
throw new IllegalArgumentException("Invalid column number!");
}
slots.get(row - 1).set(column - 1, slot);
return this;
}
@Override
public MenuBuilder setMask(@NotNull final FillerMask mask) {
this.maskSlots = mask.getMask();
return this;
}
@Override
public MenuBuilder onClose(@NotNull final Consumer<InventoryCloseEvent> action) {
this.onClose = action;
return this;
}
@Override
public Menu build() {
List<List<Slot>> finalSlots = maskSlots;
for (int i = 0; i < slots.size(); i++) {
for (int j = 0; j < slots.get(i).size(); j++) {
Slot slot = slots.get(i).get(j);
if (slot != null) {
finalSlots.get(i).set(j, slot);
}
}
}
for (List<Slot> finalSlot : finalSlots) {
for (int j = 0; j < finalSlot.size(); j++) {
if (finalSlot.get(j) == null) {
finalSlot.set(j, new EcoFillerSlot(new ItemStack(Material.AIR)));
}
}
}
return new EcoMenu(rows, finalSlots, title, onClose);
}
}

View File

@@ -1,29 +0,0 @@
package com.willfp.eco.internal.gui.menu;
import com.willfp.eco.core.gui.menu.Menu;
import lombok.experimental.UtilityClass;
import org.bukkit.inventory.Inventory;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
@UtilityClass
public class MenuHandler {
private static final Map<Inventory, Menu> MENUS = new HashMap<>();
public void registerMenu(@NotNull final Inventory inventory,
@NotNull final Menu menu) {
MENUS.put(inventory, menu);
}
public void unregisterMenu(@NotNull final Inventory inventory) {
MENUS.remove(inventory);
}
@Nullable
public Menu getMenu(@NotNull final Inventory inventory) {
return MENUS.get(inventory);
}
}

View File

@@ -1,10 +0,0 @@
package com.willfp.eco.internal.gui.slot;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
public class EcoFillerSlot extends EcoSlot {
public EcoFillerSlot(@NotNull final ItemStack itemStack) {
super((player) -> itemStack, null, null, null, null, null);
}
}

View File

@@ -1,63 +0,0 @@
package com.willfp.eco.internal.gui.slot;
import com.willfp.eco.core.gui.slot.Slot;
import lombok.Getter;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.BiConsumer;
import java.util.function.Function;
public class EcoSlot implements Slot {
@Getter
private final Function<Player, ItemStack> provider;
private final BiConsumer<InventoryClickEvent, Slot> onLeftClick;
private final BiConsumer<InventoryClickEvent, Slot> onRightClick;
private final BiConsumer<InventoryClickEvent, Slot> onShiftLeftClick;
private final BiConsumer<InventoryClickEvent, Slot> onShiftRightClick;
private final BiConsumer<InventoryClickEvent, Slot> onMiddleClick;
public EcoSlot(@NotNull final Function<Player, ItemStack> provider,
@Nullable final BiConsumer<InventoryClickEvent, Slot> onLeftClick,
@Nullable final BiConsumer<InventoryClickEvent, Slot> onRightClick,
@Nullable final BiConsumer<InventoryClickEvent, Slot> onShiftLeftClick,
@Nullable final BiConsumer<InventoryClickEvent, Slot> onShiftRightClick,
@Nullable final BiConsumer<InventoryClickEvent, Slot> onMiddleClick) {
this.provider = provider;
this.onLeftClick = onLeftClick == null ? ((event, slot) -> {
}) : onLeftClick;
this.onRightClick = onRightClick == null ? ((event, slot) -> {
}) : onRightClick;
this.onShiftLeftClick = onShiftLeftClick == null ? ((event, slot) -> {
}) : onShiftLeftClick;
this.onShiftRightClick = onShiftRightClick == null ? ((event, slot) -> {
}) : onShiftRightClick;
this.onMiddleClick = onMiddleClick == null ? ((event, slot) -> {
}) : onMiddleClick;
}
public void handleInventoryClick(@NotNull final InventoryClickEvent event) {
switch (event.getClick()) {
case LEFT -> this.onLeftClick.accept(event, this);
case RIGHT -> this.onRightClick.accept(event, this);
case SHIFT_LEFT -> this.onShiftLeftClick.accept(event, this);
case SHIFT_RIGHT -> this.onShiftRightClick.accept(event, this);
case MIDDLE -> this.onMiddleClick.accept(event, this);
default -> {
}
}
}
@Override
public ItemStack getItemStack(@NotNull final Player player) {
return provider.apply(player);
}
}

View File

@@ -1,58 +0,0 @@
package com.willfp.eco.internal.gui.slot;
import com.willfp.eco.core.gui.slot.Slot;
import com.willfp.eco.core.gui.slot.SlotBuilder;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.function.BiConsumer;
import java.util.function.Function;
public class EcoSlotBuilder implements SlotBuilder {
private final Function<Player, ItemStack> provider;
private BiConsumer<InventoryClickEvent, Slot> onLeftClick = null;
private BiConsumer<InventoryClickEvent, Slot> onRightClick = null;
private BiConsumer<InventoryClickEvent, Slot> onShiftLeftClick = null;
private BiConsumer<InventoryClickEvent, Slot> onShiftRightClick = null;
private BiConsumer<InventoryClickEvent, Slot> onMiddleClick = null;
public EcoSlotBuilder(@NotNull final Function<Player, ItemStack> provider) {
this.provider = provider;
}
public SlotBuilder onLeftClick(@NotNull final BiConsumer<InventoryClickEvent, Slot> action) {
this.onLeftClick = action;
return this;
}
public SlotBuilder onRightClick(@NotNull final BiConsumer<InventoryClickEvent, Slot> action) {
this.onRightClick = action;
return this;
}
public SlotBuilder onShiftLeftClick(@NotNull final BiConsumer<InventoryClickEvent, Slot> action) {
this.onShiftLeftClick = action;
return this;
}
public SlotBuilder onShiftRightClick(@NotNull final BiConsumer<InventoryClickEvent, Slot> action) {
this.onShiftRightClick = action;
return this;
}
public SlotBuilder onMiddleClick(@NotNull final BiConsumer<InventoryClickEvent, Slot> action) {
this.onMiddleClick = action;
return this;
}
public Slot build() {
return new EcoSlot(provider, onLeftClick, onRightClick, onShiftLeftClick, onShiftRightClick, onMiddleClick);
}
}

View File

@@ -1,65 +0,0 @@
package com.willfp.eco.internal.integrations;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.integrations.placeholder.PlaceholderIntegration;
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager;
import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class PlaceholderIntegrationPAPI extends PlaceholderExpansion implements PlaceholderIntegration {
private final EcoPlugin plugin;
public PlaceholderIntegrationPAPI(@NotNull final EcoPlugin plugin) {
this.plugin = plugin;
}
@Override
public boolean persist() {
return true;
}
@Override
public boolean canRegister() {
return true;
}
@Override
public @NotNull String getAuthor() {
return String.join(", ", plugin.getDescription().getAuthors());
}
@Override
public @NotNull String getIdentifier() {
return plugin.getDescription().getName().toLowerCase();
}
@Override
public @NotNull String getVersion() {
return plugin.getDescription().getVersion();
}
@Override
public String onPlaceholderRequest(@Nullable final Player player,
@NotNull final String identifier) {
return PlaceholderManager.getResult(player, identifier);
}
@Override
public void registerIntegration() {
this.register();
}
@Override
public String getPluginName() {
return "PlaceholderAPI";
}
@Override
public String translate(@NotNull final String text,
@Nullable final Player player) {
return PlaceholderAPI.setPlaceholders(player, text);
}
}

View File

@@ -1,32 +0,0 @@
package com.willfp.eco.internal.logging;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.util.StringUtils;
import org.jetbrains.annotations.NotNull;
import java.util.logging.Level;
import java.util.logging.Logger;
public class EcoLogger extends Logger {
public EcoLogger(@NotNull final EcoPlugin plugin) {
super(plugin.getName(), (String) null);
String prefix = plugin.getDescription().getPrefix();
this.setParent(plugin.getServer().getLogger());
this.setLevel(Level.ALL);
}
@Override
public void info(@NotNull final String msg) {
super.info(StringUtils.format(msg));
}
@Override
public void warning(@NotNull final String msg) {
super.warning(StringUtils.format(msg));
}
@Override
public void severe(@NotNull final String msg) {
super.severe(StringUtils.format(msg));
}
}

View File

@@ -1,103 +0,0 @@
package com.willfp.eco.internal.proxy;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginDependent;
import com.willfp.eco.core.proxy.AbstractProxy;
import com.willfp.eco.core.proxy.ProxyConstants;
import com.willfp.eco.core.proxy.ProxyFactory;
import com.willfp.eco.core.proxy.exceptions.ProxyError;
import com.willfp.eco.core.proxy.exceptions.UnsupportedVersionException;
import org.apache.commons.lang.Validate;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
public class EcoProxyFactory extends PluginDependent<EcoPlugin> implements ProxyFactory {
private static final List<String> SUPPORTED_VERSIONS = Arrays.asList(
"v1_16_R3",
"v1_17_R1"
);
private final ClassLoader proxyClassLoader;
private final Map<Class<? extends AbstractProxy>, AbstractProxy> cache = new IdentityHashMap<>();
public EcoProxyFactory(@NotNull final EcoPlugin plugin) {
super(plugin);
Validate.isTrue(
!plugin.getProxyPackage().equalsIgnoreCase(""),
"Specified plugin has no proxy support!"
);
this.proxyClassLoader = plugin.getClass().getClassLoader();
}
@Override
public <T extends AbstractProxy> @NotNull T getProxy(@NotNull final Class<T> proxyClass) {
try {
T cachedProxy = attemptCache(proxyClass);
if (cachedProxy != null) {
return cachedProxy;
}
String className = this.getPlugin().getProxyPackage() + "." + ProxyConstants.NMS_VERSION + "." + proxyClass.getSimpleName().replace("Proxy", "");
Class<?> clazz = this.getPlugin().getClass().getClassLoader().loadClass(className);
Object instance = clazz.getDeclaredConstructor().newInstance();
if (proxyClass.isAssignableFrom(clazz) && proxyClass.isInstance(instance)) {
T proxy = proxyClass.cast(instance);
cache.put(proxyClass, proxy);
return proxy;
}
} catch (Exception e) {
throwError(e);
}
throwError(new IllegalArgumentException());
throw new RuntimeException("Something went wrong.");
}
private void throwError(@Nullable final Exception e) {
if (e != null) {
e.printStackTrace();
}
if (!SUPPORTED_VERSIONS.contains(ProxyConstants.NMS_VERSION)) {
throw new UnsupportedVersionException("You're running an unsupported server version: " + ProxyConstants.NMS_VERSION);
} else {
throw new ProxyError("Error with proxies - here's a stacktrace. Only god can help you now.");
}
}
private <T extends AbstractProxy> T attemptCache(@NotNull final Class<T> proxyClass) {
Object proxy = cache.get(proxyClass);
if (proxy == null) {
return null;
}
if (proxyClass.isInstance(proxy)) {
return proxyClass.cast(proxy);
}
return null;
}
public void clean() {
try {
if (proxyClassLoader instanceof URLClassLoader urlClassLoader) {
urlClassLoader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
cache.clear();
}
}

View File

@@ -1,57 +0,0 @@
package com.willfp.eco.internal.scheduling;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.scheduling.RunnableTask;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scheduler.BukkitTask;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
public abstract class EcoRunnableTask extends BukkitRunnable implements RunnableTask {
private final EcoPlugin plugin;
@ApiStatus.Internal
public EcoRunnableTask(@NotNull final EcoPlugin plugin) {
this.plugin = plugin;
}
protected final EcoPlugin getPlugin() {
return this.plugin;
}
@Override
@NotNull
public final synchronized BukkitTask runTask() {
return super.runTask(plugin);
}
@Override
@NotNull
public final synchronized BukkitTask runTaskAsynchronously() {
return super.runTaskAsynchronously(plugin);
}
@Override
@NotNull
public final synchronized BukkitTask runTaskLater(final long delay) {
return super.runTaskLater(plugin, delay);
}
@Override
@NotNull
public final synchronized BukkitTask runTaskLaterAsynchronously(final long delay) {
return super.runTaskLaterAsynchronously(plugin, delay);
}
@Override
@NotNull
public final synchronized BukkitTask runTaskTimer(final long delay, final long period) {
return super.runTaskTimer(plugin, delay, period);
}
@Override
@NotNull
public final synchronized BukkitTask runTaskTimerAsynchronously(final long delay, final long period) {
return super.runTaskTimerAsynchronously(plugin, delay, period);
}
}

View File

@@ -1,58 +0,0 @@
package com.willfp.eco.internal.scheduling;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginDependent;
import com.willfp.eco.core.scheduling.Scheduler;
import org.bukkit.Bukkit;
import org.bukkit.scheduler.BukkitTask;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
public class EcoScheduler extends PluginDependent<EcoPlugin> implements Scheduler {
@ApiStatus.Internal
public EcoScheduler(@NotNull final EcoPlugin plugin) {
super(plugin);
}
@Override
public BukkitTask runLater(@NotNull final Runnable runnable,
final long ticksLater) {
return Bukkit.getScheduler().runTaskLater(this.getPlugin(), runnable, ticksLater);
}
@Override
public BukkitTask runTimer(@NotNull final Runnable runnable,
final long delay,
final long repeat) {
return Bukkit.getScheduler().runTaskTimer(this.getPlugin(), runnable, delay, repeat);
}
@Override
public BukkitTask runAsyncTimer(@NotNull final Runnable runnable,
final long delay,
final long repeat) {
return Bukkit.getScheduler().runTaskTimerAsynchronously(this.getPlugin(), runnable, delay, repeat);
}
@Override
public BukkitTask run(@NotNull final Runnable runnable) {
return Bukkit.getScheduler().runTask(this.getPlugin(), runnable);
}
@Override
public BukkitTask runAsync(@NotNull final Runnable runnable) {
return Bukkit.getScheduler().runTaskAsynchronously(this.getPlugin(), runnable);
}
@Override
public int syncRepeating(@NotNull final Runnable runnable,
final long delay,
final long repeat) {
return Bukkit.getScheduler().scheduleSyncRepeatingTask(this.getPlugin(), runnable, delay, repeat);
}
@Override
public void cancelAll() {
Bukkit.getScheduler().cancelTasks(this.getPlugin());
}
}

View File

@@ -0,0 +1,32 @@
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

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

View File

@@ -0,0 +1,68 @@
package com.willfp.eco.internal.config
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.eco.core.config.interfaces.JSONConfig
import com.willfp.eco.core.config.wrapper.ConfigFactory
import com.willfp.eco.internal.config.json.EcoJSONConfigSection
import com.willfp.eco.internal.config.json.EcoLoadableJSONConfig
import com.willfp.eco.internal.config.yaml.EcoLoadableYamlConfig
import com.willfp.eco.internal.config.yaml.EcoUpdatableYamlConfig
import com.willfp.eco.internal.config.yaml.EcoYamlConfigSection
import org.bukkit.configuration.file.YamlConfiguration
class EcoConfigFactory : ConfigFactory {
override fun createUpdatableYamlConfig(
configName: String,
plugin: EcoPlugin,
subDirectoryPath: String,
source: Class<*>,
removeUnused: Boolean,
vararg updateBlacklist: String
): Config {
return EcoUpdatableYamlConfig(
configName,
plugin,
subDirectoryPath,
source,
removeUnused,
*updateBlacklist
)
}
override fun createLoadableJSONConfig(
configName: String,
plugin: EcoPlugin,
subDirectoryPath: String,
source: Class<*>
): JSONConfig {
return EcoLoadableJSONConfig(
configName,
plugin,
subDirectoryPath,
source
)
}
override fun createLoadableYamlConfig(
configName: String,
plugin: EcoPlugin,
subDirectoryPath: String,
source: Class<*>
): Config {
return EcoLoadableYamlConfig(
configName,
plugin,
subDirectoryPath,
source
)
}
override fun createYamlConfig(config: YamlConfiguration): Config {
return EcoYamlConfigSection(config)
}
override fun createJSONConfig(values: Map<String, Any>): JSONConfig {
return EcoJSONConfigSection(values)
}
}

View File

@@ -0,0 +1,7 @@
package com.willfp.eco.internal.config.json
class EcoJSONConfigSection(values: Map<String, Any?>) : EcoJSONConfigWrapper() {
init {
init(values)
}
}

View File

@@ -0,0 +1,299 @@
package com.willfp.eco.internal.config.json
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.willfp.eco.core.config.interfaces.JSONConfig
import com.willfp.eco.util.StringUtils
import org.apache.commons.lang.Validate
import java.util.*
@Suppress("UNCHECKED_CAST")
open class EcoJSONConfigWrapper : JSONConfig {
val handle: Gson = GsonBuilder().setPrettyPrinting().create()
val values: MutableMap<String, Any?> = HashMap()
private val cache: MutableMap<String, Any> = HashMap()
fun init(values: Map<String, Any?>) {
this.values.clear()
this.values.putAll(values)
}
override fun clearCache() {
cache.clear()
}
override fun toPlaintext(): String {
return this.handle.toJson(this.values)
}
override fun has(path: String): Boolean {
return getOfKnownType(path, Any::class.java) != null
}
private fun <T: Any?> getOfKnownType(
path: String,
clazz: Class<T>
): T? {
return getOfKnownType(path, clazz, true)
}
protected fun <T> getOfKnownType(
path: String,
clazz: Class<T>,
isBase: Boolean
): T? {
var closestPath = path
if (cache.containsKey(path) && isBase) {
return cache[path] as T?
}
if (path.contains(".")) {
val split = path.split("\\.".toRegex()).toTypedArray()
closestPath = split[0]
}
return if (values[closestPath] is Map<*, *> && path != closestPath) {
val section =
EcoJSONConfigSection((values[closestPath] as Map<String, Any?>?)!!)
section.getOfKnownType(path.substring(closestPath.length + 1), clazz, false)
} else {
if (values.containsKey(closestPath)) {
values[closestPath] as T?
} else {
null
}
}
}
override fun getKeys(deep: Boolean): List<String> {
return if (deep) {
ArrayList(getDeepKeys(HashSet(), ""))
} else {
ArrayList(values.keys)
}
}
protected fun getDeepKeys(
list: MutableSet<String>,
root: String
): Set<String> {
for (key in values.keys) {
list.add(root + key)
if (values[key] is Map<*, *>) {
val section = EcoJSONConfigSection((values[key] as Map<String, Any?>?)!!)
list.addAll(section.getDeepKeys(list, "$root$key."))
}
}
return list
}
override fun get(path: String): Any? {
return getOfKnownType(path, Any::class.java)
}
override fun set(
path: String,
`object`: Any?
) {
setRecursively(path, `object`)
clearCache()
}
protected fun setRecursively(
path: String,
obj: Any?
) {
var closestPath = path
if (path.contains(".")) {
val split = path.split("\\.".toRegex()).toTypedArray()
closestPath = split[0]
}
if (values[closestPath] is Map<*, *> && path != closestPath) {
val section = EcoJSONConfigSection((values[closestPath] as Map<String, Any?>?)!!)
section.setRecursively(path.substring(closestPath.length + 1), obj)
values[closestPath] = section.values
} else {
var ob = obj
if (ob is JSONConfig) {
ob = (obj as EcoJSONConfigWrapper).values
}
values[path] = ob
}
}
override fun getSubsection(path: String): JSONConfig {
val subsection = getSubsectionOrNull(path)
Validate.notNull(subsection)
return subsection!!
}
override fun getSubsectionOrNull(path: String): JSONConfig? {
return if (values.containsKey(path)) {
val subsection = values[path] as Map<String, Any>?
EcoJSONConfigSection(subsection!!)
} else {
null
}
}
override fun getSubsections(path: String): List<JSONConfig> {
val subsections = getSubsectionsOrNull(path)
return subsections ?: ArrayList()
}
override fun getSubsectionsOrNull(path: String): List<JSONConfig>? {
val maps = getOfKnownType(path, Any::class.java) as List<Map<String, Any>>?
?: return null
val configs: MutableList<JSONConfig> = ArrayList()
for (map in maps) {
configs.add(EcoJSONConfigSection(map))
}
return configs
}
override fun getInt(path: String): Int {
return (getOfKnownType(path, Double::class.java) ?: 0.0).toInt()
}
override fun getIntOrNull(path: String): Int? {
return if (has(path)) {
getInt(path)
} else {
null
}
}
override fun getInt(
path: String,
def: Int
): Int {
return Objects.requireNonNullElse(getOfKnownType(path, Int::class.java), def)
}
override fun getInts(path: String): List<Int> {
return Objects.requireNonNullElse(getOfKnownType(path, Any::class.java), ArrayList<Any>()) as List<Int>
}
override fun getIntsOrNull(path: String): List<Int>? {
return if (has(path)) {
getInts(path)
} else {
null
}
}
override fun getBool(path: String): Boolean {
return Objects.requireNonNullElse(getOfKnownType(path, Boolean::class.java), false)
}
override fun getBoolOrNull(path: String): Boolean? {
return if (has(path)) {
getBool(path)
} else {
null
}
}
override fun getBools(path: String): List<Boolean> {
return Objects.requireNonNullElse(getOfKnownType(path, Any::class.java), ArrayList<Any>()) as List<Boolean>
}
override fun getBoolsOrNull(path: String): List<Boolean>? {
return if (has(path)) {
getBools(path)
} else {
null
}
}
override fun getString(path: String): String {
return getString(path, true)
}
override fun getString(
path: String,
format: Boolean
): String {
val string = getOfKnownType(path, String::class.java) ?: ""
return if (format) StringUtils.format(string) else string
}
override fun getStringOrNull(path: String): String? {
return if (has(path)) {
getString(path)
} else {
null
}
}
override fun getStringOrNull(
path: String,
format: Boolean
): String? {
return if (has(path)) {
getString(path, format)
} else {
null
}
}
override fun getStrings(path: String): List<String> {
return getStrings(path, true)
}
override fun getStrings(
path: String,
format: Boolean
): List<String> {
val strings =
Objects.requireNonNullElse(getOfKnownType(path, Any::class.java), ArrayList<Any>()) as List<String>
return if (format) StringUtils.formatList(strings) else strings
}
override fun getStringsOrNull(path: String): List<String>? {
return if (has(path)) {
getStrings(path)
} else {
null
}
}
override fun getStringsOrNull(
path: String,
format: Boolean
): List<String>? {
return if (has(path)) {
getStrings(path, format)
} else {
null
}
}
override fun getDouble(path: String): Double {
return Objects.requireNonNullElse(getOfKnownType(path, Double::class.java), 0.0)
}
override fun getDoubleOrNull(path: String): Double? {
return if (has(path)) {
getDouble(path)
} else {
null
}
}
override fun getDoubles(path: String): List<Double> {
return Objects.requireNonNullElse(getOfKnownType(path, Any::class.java), ArrayList<Any>()) as List<Double>
}
override fun getDoublesOrNull(path: String): List<Double>? {
return if (has(path)) {
getDoubles(path)
} else {
null
}
}
override fun clone(): JSONConfig {
return EcoJSONConfigSection(HashMap<String, Any>(this.values))
}
}

View File

@@ -0,0 +1,100 @@
package com.willfp.eco.internal.config.json
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.config.interfaces.LoadableConfig
import org.jetbrains.annotations.NotNull
import java.io.*
import java.nio.file.Files
import java.nio.file.StandardOpenOption
@Suppress("UNCHECKED_CAST")
class EcoLoadableJSONConfig(
configName: String,
private val plugin: EcoPlugin,
private val subDirectoryPath: String,
private val source: Class<*>
) : EcoJSONConfigWrapper(), LoadableConfig {
private val configFile: File
private val name: String = "$configName.json"
fun reloadFromFile() {
try {
init(configFile)
} catch (e: IOException) {
e.printStackTrace()
}
}
override fun createFile() {
val resourcePath = resourcePath
val inputStream = source.getResourceAsStream(resourcePath)!!
val outFile = File(this.plugin.dataFolder, resourcePath)
val lastIndex = resourcePath.lastIndexOf('/')
val outDir = File(this.plugin.dataFolder, resourcePath.substring(0, lastIndex.coerceAtLeast(0)))
if (!outDir.exists()) {
outDir.mkdirs()
}
if (!outFile.exists()) {
val out: OutputStream = FileOutputStream(outFile)
val buf = ByteArray(1024)
var len: Int
while (inputStream.read(buf).also { len = it } > 0) {
out.write(buf, 0, len)
}
out.close()
inputStream.close()
}
}
override fun getResourcePath(): String {
val resourcePath: String = if (subDirectoryPath.isEmpty()) {
name
} else {
subDirectoryPath + name
}
return "/$resourcePath"
}
@Throws(IOException::class)
override fun save() {
if (configFile.delete()) {
Files.write(
configFile.toPath(),
toPlaintext().toByteArray(),
StandardOpenOption.CREATE,
StandardOpenOption.WRITE
)
}
}
@Throws(FileNotFoundException::class)
fun init(file: File) {
super.init(handle.fromJson(FileReader(file), Map::class.java) as @NotNull MutableMap<String, Any>)
}
override fun getName(): String {
return name
}
override fun getConfigFile(): File {
return configFile
}
init {
val directory: File = File(this.plugin.dataFolder, subDirectoryPath)
if (!directory.exists()) {
directory.mkdirs()
}
if (!File(directory, name).exists()) {
createFile()
}
configFile = File(directory, name)
try {
init(configFile)
} catch (e: IOException) {
e.printStackTrace()
}
plugin.configHandler.addConfig(this)
}
}

View File

@@ -0,0 +1,64 @@
package com.willfp.eco.internal.config.updating
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.PluginDependent
import com.willfp.eco.core.config.interfaces.LoadableConfig
import com.willfp.eco.core.config.updating.ConfigHandler
import com.willfp.eco.core.config.updating.ConfigUpdater
import com.willfp.eco.internal.config.json.EcoLoadableJSONConfig
import com.willfp.eco.internal.config.updating.exceptions.InvalidUpdateMethodException
import com.willfp.eco.internal.config.yaml.EcoLoadableYamlConfig
import com.willfp.eco.internal.config.yaml.EcoUpdatableYamlConfig
import org.reflections.Reflections
import org.reflections.scanners.MethodAnnotationsScanner
import java.lang.reflect.Modifier
class EcoConfigHandler(
plugin: EcoPlugin
) : PluginDependent<EcoPlugin>(plugin), ConfigHandler {
private val reflections: Reflections = Reflections(
this.plugin::class.java.classLoader,
MethodAnnotationsScanner()
)
private val configs: MutableList<LoadableConfig> = ArrayList()
override fun callUpdate() {
for (method in reflections.getMethodsAnnotatedWith(ConfigUpdater::class.java)) {
if (!Modifier.isStatic(method.modifiers)) {
throw InvalidUpdateMethodException("Update method in ${method.declaringClass.name} must be static.")
}
try {
when (method.parameterCount) {
0 -> method.invoke(null)
1 -> method.invoke(null, this.plugin)
else -> throw InvalidUpdateMethodException("Update method must have 0 parameters or a plugin parameter.")
}
} catch (e: ReflectiveOperationException) {
e.printStackTrace()
throw InvalidUpdateMethodException("Update method generated an exception")
}
}
}
override fun saveAllConfigs() {
for (config in configs) {
config.save()
}
}
override fun addConfig(config: LoadableConfig) {
configs.add(config)
}
override fun updateConfigs() {
for (config in configs) {
when (config) {
is EcoUpdatableYamlConfig -> config.update()
is EcoLoadableYamlConfig -> config.reloadFromFile()
is EcoLoadableJSONConfig -> config.reloadFromFile()
}
}
}
}

View File

@@ -0,0 +1,3 @@
package com.willfp.eco.internal.config.updating.exceptions
class InvalidUpdateMethodException(message: String) : RuntimeException(message)

View File

@@ -0,0 +1,93 @@
package com.willfp.eco.internal.config.yaml
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.config.interfaces.LoadableConfig
import com.willfp.eco.core.config.interfaces.WrappedYamlConfiguration
import org.bukkit.configuration.InvalidConfigurationException
import org.bukkit.configuration.file.YamlConfiguration
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.OutputStream
open class EcoLoadableYamlConfig(
configName: String,
private val plugin: EcoPlugin,
private val subDirectoryPath: String,
val source: Class<*>
) : EcoYamlConfigWrapper<YamlConfiguration>(), WrappedYamlConfiguration, LoadableConfig {
private val configFile: File
private val name: String = "$configName.yml"
fun reloadFromFile() {
try {
handle.load(getConfigFile())
} catch (e: IOException) {
e.printStackTrace()
} catch (e: InvalidConfigurationException) {
e.printStackTrace()
}
}
final override fun createFile() {
val resourcePath = resourcePath
val inputStream = source.getResourceAsStream(resourcePath)!!
val outFile = File(this.plugin.dataFolder, resourcePath)
val lastIndex = resourcePath.lastIndexOf('/')
val outDir = File(this.plugin.dataFolder, resourcePath.substring(0, lastIndex.coerceAtLeast(0)))
if (!outDir.exists()) {
outDir.mkdirs()
}
if (!outFile.exists()) {
val out: OutputStream = FileOutputStream(outFile)
val buf = ByteArray(1024)
var len: Int
while (inputStream.read(buf).also { len = it } > 0) {
out.write(buf, 0, len)
}
out.close()
inputStream.close()
}
plugin.configHandler.addConfig(this)
}
override fun getResourcePath(): String {
val resourcePath: String = if (subDirectoryPath.isEmpty()) {
name
} else {
subDirectoryPath + name
}
return "/$resourcePath"
}
@Throws(IOException::class)
override fun save() {
handle.save(getConfigFile())
}
override fun getBukkitHandle(): YamlConfiguration {
return handle
}
override fun getName(): String {
return name
}
override fun getConfigFile(): File {
return configFile
}
init {
val directory = File(this.plugin.dataFolder, subDirectoryPath)
if (!directory.exists()) {
directory.mkdirs()
}
if (!File(directory, name).exists()) {
createFile()
}
configFile = File(directory, name)
this.plugin.configHandler.addConfig(this)
init(YamlConfiguration.loadConfiguration(configFile))
}
}

View File

@@ -0,0 +1,74 @@
package com.willfp.eco.internal.config.yaml
import com.willfp.eco.core.EcoPlugin
import org.bukkit.configuration.InvalidConfigurationException
import org.bukkit.configuration.file.YamlConfiguration
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import java.nio.charset.StandardCharsets
class EcoUpdatableYamlConfig(
configName: String,
plugin: EcoPlugin,
subDirectoryPath: String,
source: Class<*>,
private val removeUnused: Boolean,
vararg updateBlacklist: String
) : EcoLoadableYamlConfig(configName, plugin, subDirectoryPath, source) {
private val updateBlacklist: MutableList<String> = mutableListOf(*updateBlacklist)
fun update() {
super.clearCache()
try {
this.handle.load(configFile)
val newConfig = configInJar
if (newConfig.getKeys(true) == this.handle.getKeys(true)) {
return
}
newConfig.getKeys(true).forEach { key: String ->
if (!this.handle.getKeys(true).contains(key)) {
if (updateBlacklist.stream().noneMatch { s: String -> key.contains(s) }) {
this.handle.set(key, newConfig[key])
}
}
}
if (removeUnused) {
this.handle.getKeys(true).forEach { s ->
if (!newConfig.getKeys(true).contains(s)) {
if (updateBlacklist.stream().noneMatch(s::contains)) {
this.handle.set(s, null)
}
}
}
}
this.handle.save(configFile)
} catch (e: IOException) {
e.printStackTrace()
} catch (e: InvalidConfigurationException) {
e.printStackTrace()
}
}
private val configInJar: YamlConfiguration
get() {
val newIn = source.getResourceAsStream(resourcePath) ?: throw NullPointerException("$name is null?")
val reader = BufferedReader(InputStreamReader(newIn, StandardCharsets.UTF_8))
val newConfig = YamlConfiguration()
try {
newConfig.load(reader)
} catch (e: IOException) {
e.printStackTrace()
} catch (e: InvalidConfigurationException) {
e.printStackTrace()
}
return newConfig
}
init {
this.updateBlacklist.removeIf { obj: String -> obj.isEmpty() }
plugin.configHandler.addConfig(this)
update()
}
}

View File

@@ -0,0 +1,9 @@
package com.willfp.eco.internal.config.yaml
import org.bukkit.configuration.ConfigurationSection
class EcoYamlConfigSection(section: ConfigurationSection) : EcoYamlConfigWrapper<ConfigurationSection>() {
init {
init(section)
}
}

View File

@@ -0,0 +1,287 @@
package com.willfp.eco.internal.config.yaml
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.eco.util.StringUtils
import org.apache.commons.lang.Validate
import org.bukkit.configuration.ConfigurationSection
import org.bukkit.configuration.file.YamlConfiguration
import java.io.StringReader
@Suppress("UNCHECKED_CAST")
open class EcoYamlConfigWrapper<T : ConfigurationSection> : Config {
lateinit var handle: T
private val cache: MutableMap<String, Any?> = HashMap()
protected fun init(config: T): Config {
handle = config
return this
}
override fun toPlaintext(): String {
val temp = YamlConfiguration()
for (key in handle.getKeys(true)) {
temp[key] = handle[key]
}
return temp.saveToString()
}
override fun clearCache() {
cache.clear()
}
override fun has(path: String): Boolean {
return handle.contains(path)
}
override fun getKeys(deep: Boolean): List<String> {
return ArrayList(handle.getKeys(deep))
}
override fun get(path: String): Any? {
return handle[path]
}
override fun set(
path: String,
obj: Any?
) {
cache.remove(path)
handle[path] = obj
}
override fun getSubsection(path: String): Config {
val subsection = getSubsectionOrNull(path)
Validate.notNull(subsection)
return subsection!!
}
override fun getSubsectionOrNull(path: String): Config? {
return if (cache.containsKey(path)) {
cache[path] as Config?
} else {
val raw = handle.getConfigurationSection(path)
if (raw == null) {
cache[path] = null
} else {
cache[path] = EcoYamlConfigSection(raw)
}
getSubsectionOrNull(path)
}
}
override fun getInt(path: String): Int {
return if (cache.containsKey(path)) {
cache[path] as Int
} else {
cache[path] = handle.getInt(path, 0)
getInt(path)
}
}
override fun getIntOrNull(path: String): Int? {
return if (has(path)) {
getInt(path)
} else {
null
}
}
override fun getInt(
path: String,
def: Int
): Int {
return if (cache.containsKey(path)) {
cache[path] as Int
} else {
cache[path] = handle.getInt(path, def)
getInt(path)
}
}
override fun getInts(path: String): List<Int> {
return if (cache.containsKey(path)) {
cache[path] as List<Int>
} else {
cache[path] = if (has(path)) ArrayList(handle.getIntegerList(path)) else ArrayList<Any>()
getInts(path)
}
}
override fun getIntsOrNull(path: String): List<Int>? {
return if (has(path)) {
getInts(path)
} else {
null
}
}
override fun getBool(path: String): Boolean {
return if (cache.containsKey(path)) {
cache[path] as Boolean
} else {
cache[path] = handle.getBoolean(path)
getBool(path)
}
}
override fun getBoolOrNull(path: String): Boolean? {
return if (has(path)) {
getBool(path)
} else {
null
}
}
override fun getBools(path: String): List<Boolean> {
return if (cache.containsKey(path)) {
cache[path] as List<Boolean>
} else {
cache[path] =
if (has(path)) ArrayList(handle.getBooleanList(path)) else ArrayList<Any>()
getBools(path)
}
}
override fun getBoolsOrNull(path: String): List<Boolean>? {
return if (has(path)) {
getBools(path)
} else {
null
}
}
override fun getString(path: String): String {
return getString(path, true)
}
override fun getString(
path: String,
format: Boolean
): String {
if (format) {
return if (cache.containsKey("$path\$FMT")) {
cache["$path\$FMT"] as String
} else {
val string: String = handle.getString(path, "")!!
cache["$path\$FMT"] = StringUtils.format(string)
getString(path, format)
}
} else {
return if (cache.containsKey(path)) {
cache[path] as String
} else {
cache[path] = handle.getString(path, "")!!
getString(path)
}
}
}
override fun getStringOrNull(path: String): String? {
return if (has(path)) {
getString(path)
} else {
null
}
}
override fun getStringOrNull(
path: String,
format: Boolean
): String? {
return if (has(path)) {
getString(path, format)
} else {
null
}
}
override fun getStrings(path: String): List<String> {
return getStrings(path, true)
}
override fun getStrings(
path: String,
format: Boolean
): List<String> {
if (format) {
return if (cache.containsKey("$path\$FMT")) {
cache["$path\$FMT"] as List<String>
} else {
val list = if (has(path)) handle.getStringList(path) else ArrayList()
cache["$path\$FMT"] = StringUtils.formatList(list);
getStrings(path, true)
}
} else {
return if (cache.containsKey(path)) {
cache[path] as List<String>
} else {
cache[path] =
if (has(path)) ArrayList(handle.getStringList(path)) else ArrayList<Any>()
getStrings(path, false)
}
}
}
override fun getStringsOrNull(path: String): List<String>? {
return if (has(path)) {
getStrings(path)
} else {
null
}
}
override fun getStringsOrNull(
path: String,
format: Boolean
): List<String>? {
return if (has(path)) {
getStrings(path, format)
} else {
null
}
}
override fun getDouble(path: String): Double {
return if (cache.containsKey(path)) {
cache[path] as Double
} else {
cache[path] = handle.getDouble(path)
getDouble(path)
}
}
override fun getDoubleOrNull(path: String): Double? {
return if (has(path)) {
getDouble(path)
} else {
null
}
}
override fun getDoubles(path: String): List<Double> {
return if (cache.containsKey(path)) {
cache[path] as List<Double>
} else {
cache[path] = if (has(path)) ArrayList(handle.getDoubleList(path)) else ArrayList<Any>()
getDoubles(path)
}
}
override fun getDoublesOrNull(path: String): List<Double>? {
return if (has(path)) {
getDoubles(path)
} else {
null
}
}
override fun clone(): Config {
return EcoYamlConfigSection(
YamlConfiguration.loadConfiguration(
StringReader(
toPlaintext()
)
)
)
}
}

View File

@@ -0,0 +1,11 @@
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

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

View File

@@ -0,0 +1,15 @@
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
class EcoDropQueueFactory : DropQueueFactory {
override fun create(player: Player): InternalDropQueue {
return if (DropManager.type == DropQueueType.COLLATED) EcoFastCollatedDropQueue(player) else EcoDropQueue(
player
)
}
}

View File

@@ -0,0 +1,87 @@
package com.willfp.eco.internal.drops.impl
import com.willfp.eco.core.drops.InternalDropQueue
import com.willfp.eco.util.TelekinesisUtils
import org.bukkit.Bukkit
import org.bukkit.Location
import org.bukkit.Material
import org.bukkit.entity.EntityType
import org.bukkit.entity.ExperienceOrb
import org.bukkit.entity.Player
import org.bukkit.event.player.PlayerExpChangeEvent
import org.bukkit.inventory.ItemStack
import org.bukkit.util.Vector
open class EcoDropQueue(player: Player) : InternalDropQueue {
val items: MutableList<ItemStack>
var xp: Int
val player: Player
var loc: Location
var hasTelekinesis = false
override fun addItem(item: ItemStack): InternalDropQueue {
items.add(item)
return this
}
override fun addItems(itemStacks: Collection<ItemStack>): InternalDropQueue {
items.addAll(itemStacks)
return this
}
override fun addXP(amount: Int): InternalDropQueue {
xp += amount
return this
}
override fun setLocation(location: Location): InternalDropQueue {
loc = location
return this
}
override fun forceTelekinesis(): InternalDropQueue {
hasTelekinesis = true
return this
}
override fun push() {
if (!hasTelekinesis) {
hasTelekinesis = TelekinesisUtils.testPlayer(player)
}
val world = loc.world!!
loc = loc.add(0.5, 0.5, 0.5)
items.removeIf { itemStack: ItemStack -> itemStack.type == Material.AIR }
if (items.isEmpty()) {
return
}
if (hasTelekinesis) {
val leftover = player.inventory.addItem(*items.toTypedArray())
for (drop in leftover.values) {
world.dropItem(loc, drop!!).velocity = Vector()
}
if (xp > 0) {
val event = PlayerExpChangeEvent(player, xp)
Bukkit.getPluginManager().callEvent(event)
val orb =
world.spawnEntity(player.location.add(0.0, 0.2, 0.0), EntityType.EXPERIENCE_ORB) as ExperienceOrb
orb.velocity = Vector(0, 0, 0)
orb.experience = event.amount
}
} else {
for (drop in items) {
world.dropItem(loc, drop).velocity = Vector()
}
if (xp > 0) {
val orb = world.spawnEntity(loc, EntityType.EXPERIENCE_ORB) as ExperienceOrb
orb.experience = xp
}
}
}
init {
items = ArrayList()
xp = 0
this.player = player
loc = player.location
}
}

View File

@@ -0,0 +1,51 @@
package com.willfp.eco.internal.drops.impl
import org.bukkit.Location
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
import java.util.concurrent.ConcurrentHashMap
class EcoFastCollatedDropQueue(player: Player) : EcoDropQueue(player) {
override fun push() {
val fetched = COLLATED_MAP[player]
if (fetched == null) {
COLLATED_MAP[player] = CollatedDrops(items, loc, xp, hasTelekinesis)
} else {
fetched.addDrops(items)
fetched.location = loc
fetched.addXp(xp)
if (this.hasTelekinesis) {
fetched.forceTelekinesis()
}
COLLATED_MAP[player] = fetched
}
}
class CollatedDrops(
val drops: MutableList<ItemStack>,
var location: Location,
var xp: Int,
var telekinetic: Boolean
) {
fun addDrops(toAdd: List<ItemStack>): CollatedDrops {
drops.addAll(toAdd)
return this
}
fun addXp(xp: Int): CollatedDrops {
this.xp += xp
return this
}
fun forceTelekinesis() {
telekinetic = true
}
}
companion object {
val COLLATED_MAP: MutableMap<Player, CollatedDrops> = ConcurrentHashMap()
}
}

View File

@@ -0,0 +1,22 @@
package com.willfp.eco.internal.events
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.PluginDependent
import com.willfp.eco.core.events.EventManager
import org.bukkit.Bukkit
import org.bukkit.event.HandlerList
import org.bukkit.event.Listener
class EcoEventManager constructor(plugin: EcoPlugin) : PluginDependent<EcoPlugin>(plugin), EventManager {
override fun registerListener(listener: Listener) {
Bukkit.getPluginManager().registerEvents(listener, plugin)
}
override fun unregisterListener(listener: Listener) {
HandlerList.unregisterAll(listener)
}
override fun unregisterAllListeners() {
HandlerList.unregisterAll(plugin)
}
}

View File

@@ -0,0 +1,107 @@
package com.willfp.eco.internal.extensions
import com.google.common.collect.ImmutableSet
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.PluginDependent
import com.willfp.eco.core.config.yaml.YamlTransientConfig
import com.willfp.eco.core.extensions.Extension
import com.willfp.eco.core.extensions.ExtensionLoader
import com.willfp.eco.core.extensions.ExtensionMetadata
import com.willfp.eco.core.extensions.MalformedExtensionException
import org.bukkit.configuration.file.YamlConfiguration
import java.io.File
import java.io.InputStreamReader
import java.net.MalformedURLException
import java.net.URL
import java.net.URLClassLoader
class EcoExtensionLoader(
plugin: EcoPlugin
) : PluginDependent<EcoPlugin>(plugin), ExtensionLoader {
private val extensions: MutableMap<Extension, URLClassLoader> = HashMap()
override fun loadExtensions() {
val dir = File(this.plugin.dataFolder, "/extensions")
if (!dir.exists()) {
dir.mkdirs()
}
val extensionJars = dir.listFiles() ?: return
for (extensionJar in extensionJars) {
if (!extensionJar.isFile) {
continue
}
try {
loadExtension(extensionJar)
} catch (e: MalformedExtensionException) {
this.plugin.logger.warning(extensionJar.name + " caused an error!")
}
}
}
@Throws(MalformedExtensionException::class)
private fun loadExtension(extensionJar: File) {
lateinit var url : URL
try {
url = extensionJar.toURI().toURL()
} catch (e: MalformedURLException) {
e.printStackTrace()
}
val classLoader = URLClassLoader(arrayOf(url), this.plugin::class.java.classLoader)
val ymlIn = classLoader.getResourceAsStream("extension.yml")
?: throw MalformedExtensionException ("No extension.yml found in " + extensionJar.name)
val extensionYml = YamlTransientConfig(YamlConfiguration.loadConfiguration(InputStreamReader(ymlIn)))
val mainClass = extensionYml.getStringOrNull("main")
var name = extensionYml.getStringOrNull("name")
var version = extensionYml.getStringOrNull("version")
var author = extensionYml.getStringOrNull("author")
if (mainClass == null) {
throw MalformedExtensionException ("Invalid extension.yml found in " + extensionJar.name)
}
if (name == null) {
this.plugin.logger.warning(extensionJar.name + " doesn't have a name!")
name = "Unnamed Extension " + extensionJar.name
}
if (version == null) {
this.plugin.logger.warning(extensionJar.name + " doesn't have a version!")
version = "1.0.0"
}
if (author == null) {
this.plugin.logger.warning(extensionJar.name + " doesn't have an author!")
author = "Unnamed Author"
}
val metadata = ExtensionMetadata(version, name, author)
val cls: Class<*> = classLoader.loadClass(mainClass)
val extension: Extension = cls.getConstructor(EcoPlugin::class.java).newInstance(this.plugin) as Extension
extension.setMetadata(metadata)
extension.enable()
extensions[extension] = classLoader
}
override fun getLoadedExtensions(): MutableSet<Extension> {
return ImmutableSet.copyOf(extensions.keys)
}
override fun unloadExtensions() {
extensions.keys.forEach { e -> e.disable() }
for (urlClassLoader in extensions.values) {
urlClassLoader.close()
}
extensions.clear()
}
}

View File

@@ -0,0 +1,12 @@
package com.willfp.eco.internal.factory
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.PluginDependent
import com.willfp.eco.core.factory.MetadataValueFactory
import org.bukkit.metadata.FixedMetadataValue
class EcoMetadataValueFactory(plugin: EcoPlugin) : PluginDependent<EcoPlugin>(plugin), MetadataValueFactory {
override fun create(value: Any): FixedMetadataValue {
return FixedMetadataValue(plugin, value)
}
}

View File

@@ -0,0 +1,12 @@
package com.willfp.eco.internal.factory
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.PluginDependent
import com.willfp.eco.core.factory.NamespacedKeyFactory
import org.bukkit.NamespacedKey
class EcoNamespacedKeyFactory(plugin: EcoPlugin) : PluginDependent<EcoPlugin>(plugin), NamespacedKeyFactory {
override fun create(key: String): NamespacedKey {
return NamespacedKey(plugin, key)
}
}

View File

@@ -0,0 +1,18 @@
package com.willfp.eco.internal.factory
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.PluginDependent
import com.willfp.eco.core.factory.RunnableFactory
import com.willfp.eco.core.scheduling.RunnableTask
import com.willfp.eco.internal.scheduling.EcoRunnableTask
import java.util.function.Consumer
class EcoRunnableFactory(plugin: EcoPlugin) : PluginDependent<EcoPlugin>(plugin), RunnableFactory {
override fun create(consumer: Consumer<RunnableTask>): RunnableTask {
return object : EcoRunnableTask(plugin) {
override fun run() {
consumer.accept(this)
}
}
}
}

View File

@@ -0,0 +1,13 @@
package com.willfp.eco.internal.fast
import com.willfp.eco.core.fast.FastItemStack
import org.bukkit.inventory.ItemStack
abstract class EcoFastItemStack<T: Any>(
val handle: T,
val bukkit: ItemStack
) : FastItemStack {
override fun unwrap(): ItemStack {
return bukkit
}
}

View File

@@ -0,0 +1,18 @@
package com.willfp.eco.internal.gui
import com.willfp.eco.core.gui.GUIFactory
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 com.willfp.eco.internal.gui.menu.EcoMenuBuilder
import com.willfp.eco.internal.gui.slot.EcoSlotBuilder
class EcoGUIFactory : GUIFactory {
override fun createSlotBuilder(provider: SlotProvider): SlotBuilder {
return EcoSlotBuilder(provider)
}
override fun createMenuBuilder(rows: Int): MenuBuilder {
return EcoMenuBuilder(rows)
}
}

View File

@@ -0,0 +1,78 @@
package com.willfp.eco.internal.gui.menu
import com.willfp.eco.core.gui.menu.CloseHandler
import com.willfp.eco.core.gui.menu.Menu
import com.willfp.eco.core.gui.slot.Slot
import com.willfp.eco.internal.gui.slot.EcoSlot
import com.willfp.eco.util.StringUtils
import org.bukkit.Bukkit
import org.bukkit.entity.Player
import org.bukkit.event.inventory.InventoryCloseEvent
import org.bukkit.inventory.Inventory
import org.bukkit.inventory.ItemStack
class EcoMenu(
private val rows: Int,
val slots: List<MutableList<EcoSlot>>,
private val title: String,
private val onClose: CloseHandler
): Menu {
override fun getSlot(row: Int, column: Int): Slot {
if (row < 1 || row > this.rows) {
throw IllegalArgumentException("Invalid row number!")
}
if (column < 1 || column > 9) {
throw IllegalArgumentException("Invalid column number!")
}
return slots[row - 1][column - 1]
}
override fun open(player: Player): Inventory {
val inventory = Bukkit.createInventory(null, rows * 9, title)
var i = 0
for (row in slots) {
for (item in row) {
if (i == rows * 9) {
break
}
val slotItem = item.getItemStack(player, this)
val meta = slotItem.itemMeta
if (meta != null) {
val lore = meta.lore
if (lore != null) {
lore.replaceAll{ s -> StringUtils.format(s, player) }
meta.lore = lore
}
slotItem.itemMeta = meta
}
inventory.setItem(i, slotItem)
i++
}
}
player.openInventory(inventory)
MenuHandler.registerMenu(inventory, this)
return inventory
}
fun handleClose(event: InventoryCloseEvent) {
onClose.handle(event, this)
}
override fun getRows(): Int {
return rows
}
override fun getTitle(): String {
return title
}
override fun getCaptiveItems(player: Player): MutableList<ItemStack> {
val inventory = MenuHandler.getExtendedInventory(player.openInventory.topInventory)
inventory ?: return ArrayList()
return inventory.captiveItems
}
}

View File

@@ -0,0 +1,84 @@
package com.willfp.eco.internal.gui.menu
import com.willfp.eco.core.gui.menu.CloseHandler
import com.willfp.eco.core.gui.menu.Menu
import com.willfp.eco.core.gui.menu.MenuBuilder
import com.willfp.eco.core.gui.slot.FillerMask
import com.willfp.eco.core.gui.slot.FillerSlot
import com.willfp.eco.core.gui.slot.Slot
import com.willfp.eco.internal.gui.slot.EcoFillerSlot
import com.willfp.eco.internal.gui.slot.EcoSlot
import com.willfp.eco.util.ListUtils
import com.willfp.eco.util.StringUtils
import org.bukkit.Material
import org.bukkit.inventory.ItemStack
import java.util.function.Consumer
class EcoMenuBuilder(private val rows: Int) : MenuBuilder {
private var title = "Menu"
private var maskSlots: List<MutableList<Slot?>>
private val slots: List<MutableList<Slot?>> = ListUtils.create2DList(rows, 9)
private var onClose = CloseHandler { _, _ -> }
override fun setTitle(title: String): MenuBuilder {
this.title = StringUtils.format(title)
return this
}
override fun setSlot(
row: Int,
column: Int,
slot: Slot
): MenuBuilder {
require(!(row < 1 || row > rows)) { "Invalid row number!" }
require(!(column < 1 || column > 9)) { "Invalid column number!" }
slots[row - 1][column - 1] = slot
return this
}
override fun modfiy(modifier: Consumer<MenuBuilder>): MenuBuilder {
modifier.accept(this)
return this
}
override fun setMask(mask: FillerMask): MenuBuilder {
maskSlots = mask.mask
return this
}
override fun onClose(action: CloseHandler): MenuBuilder {
onClose = action
return this
}
override fun build(): Menu {
val tempSlots: MutableList<MutableList<Slot?>> = ArrayList(maskSlots)
for (i in slots.indices) {
for (j in slots[i].indices) {
val slot = slots[i][j] ?: continue
tempSlots[i][j] = slot
}
}
val finalSlots: MutableList<MutableList<EcoSlot>> = ArrayList()
for (row in tempSlots) {
val tempRow = ArrayList<EcoSlot>()
for (slot in row) {
var tempSlot = slot
if (tempSlot is FillerSlot) {
tempSlot = EcoFillerSlot(tempSlot.itemStack)
}
tempRow.add((tempSlot ?: EcoFillerSlot(ItemStack(Material.AIR))) as EcoSlot)
}
finalSlots.add(tempRow)
}
return EcoMenu(rows, finalSlots, title, onClose)
}
init {
maskSlots = ListUtils.create2DList(rows, 9)
}
}

View File

@@ -0,0 +1,55 @@
package com.willfp.eco.internal.gui.menu
import com.willfp.eco.internal.gui.slot.EcoCaptivatorSlot
import com.willfp.eco.util.MenuUtils
import com.willfp.eco.util.StringUtils
import org.bukkit.entity.Player
import org.bukkit.inventory.Inventory
import org.bukkit.inventory.ItemStack
class ExtendedInventory(
val inventory: Inventory,
private val menu: EcoMenu
) {
val captiveItems: MutableList<ItemStack> = ArrayList()
fun refresh(player: Player) {
captiveItems.clear()
for (i in 0 until inventory.size) {
val pair = MenuUtils.convertSlotToRowColumn(i)
val row = pair.first!!
val column = pair.second!!
val slot = menu.getSlot(row, column)
if (slot is EcoCaptivatorSlot) {
val defaultItem = slot.getItemStack(player)
val item = inventory.getItem(i) ?: continue
if (item != defaultItem) {
captiveItems.add(item)
}
}
}
var i = 0
for (row in menu.slots) {
for (slot in row) {
if (i == menu.rows * 9) {
break
}
val slotItem = slot.getItemStack(player, menu)
val meta = slotItem.itemMeta
if (meta != null) {
val lore = meta.lore
if (lore != null) {
lore.replaceAll{ s -> StringUtils.format(s, player) }
meta.lore = lore
}
slotItem.itemMeta = meta
}
if (!slot.isCaptive) {
inventory.setItem(i, slotItem)
}
i++
}
}
}
}

View File

@@ -0,0 +1,31 @@
package com.willfp.eco.internal.gui.menu
import com.willfp.eco.core.gui.menu.Menu
import org.bukkit.inventory.Inventory
object MenuHandler {
private val MENUS: MutableMap<ExtendedInventory, EcoMenu> = HashMap()
private val INVS: MutableMap<Inventory, ExtendedInventory> = HashMap()
fun registerMenu(
inventory: Inventory,
menu: EcoMenu
) {
val extendedInventory = ExtendedInventory(inventory, menu)
INVS[inventory] = extendedInventory
MENUS[extendedInventory] = menu
}
fun unregisterMenu(inventory: Inventory) {
MENUS.remove(INVS[inventory])
INVS.remove(inventory)
}
fun getMenu(inventory: Inventory): Menu? {
return MENUS[INVS[inventory]]
}
fun getExtendedInventory(inventory: Inventory): ExtendedInventory? {
return INVS[inventory]
}
}

View File

@@ -0,0 +1,28 @@
package com.willfp.eco.internal.gui.slot
import com.willfp.eco.core.Eco
import com.willfp.eco.core.gui.slot.functional.SlotHandler
import org.bukkit.Material
import org.bukkit.inventory.ItemStack
class EcoCaptivatorSlot : EcoSlot(
{ _, _ -> ItemStack(Material.AIR) },
allowMovingItem,
allowMovingItem,
allowMovingItem,
allowMovingItem,
allowMovingItem,
{ _, _, _ -> }
) {
companion object {
val plugin = Eco.getHandler().ecoPlugin!!
val allowMovingItem = SlotHandler { event, _, _ ->
event.isCancelled = false
}
}
override fun isCaptive(): Boolean {
return true
}
}

View File

@@ -0,0 +1,13 @@
package com.willfp.eco.internal.gui.slot
import org.bukkit.inventory.ItemStack
class EcoFillerSlot(itemStack: ItemStack) : EcoSlot(
{ _, _ -> itemStack },
{ _, _, _ -> },
{ _, _, _ -> },
{ _, _, _ -> },
{ _, _, _ -> },
{ _, _, _ -> },
{ _, _, _ -> }
)

View File

@@ -0,0 +1,58 @@
package com.willfp.eco.internal.gui.slot
import com.willfp.eco.core.gui.menu.Menu
import com.willfp.eco.core.gui.slot.Slot
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.SlotProvider
import com.willfp.eco.internal.gui.menu.MenuHandler
import org.bukkit.entity.Player
import org.bukkit.event.inventory.ClickType
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.inventory.ItemStack
open class EcoSlot(
private val provider: SlotProvider,
private val onLeftClick: SlotHandler,
private val onRightClick: SlotHandler,
private val onShiftLeftClick: SlotHandler,
private val onShiftRightClick: SlotHandler,
private val onMiddleClick: SlotHandler,
private val modifier: SlotModifier
) : Slot {
fun handleInventoryClick(
event: InventoryClickEvent,
menu: Menu
) {
when (event.click) {
ClickType.LEFT -> this.onLeftClick.handle(event, this, menu)
ClickType.RIGHT -> this.onRightClick.handle(event, this, menu)
ClickType.SHIFT_LEFT -> this.onShiftLeftClick.handle(event, this, menu)
ClickType.SHIFT_RIGHT -> this.onShiftRightClick.handle(event, this, menu)
ClickType.MIDDLE -> this.onMiddleClick.handle(event, this, menu)
else -> {
}
}
}
override fun getItemStack(player: Player): ItemStack {
val menu = MenuHandler.getMenu(player.openInventory.topInventory)!!
val prev = provider.provide(player, menu)
modifier.modify(player, menu, prev)
return prev
}
fun getItemStack(
player: Player,
menu: Menu
): ItemStack {
val prev = provider.provide(player, menu)
modifier.modify(player, menu, prev)
return prev
}
override fun isCaptive(): Boolean {
return false
}
}

View File

@@ -0,0 +1,66 @@
package com.willfp.eco.internal.gui.slot
import com.willfp.eco.core.gui.slot.Slot
import com.willfp.eco.core.gui.slot.SlotBuilder
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.SlotProvider
class EcoSlotBuilder(private val provider: SlotProvider) : SlotBuilder {
private var captive = false
var modifier: SlotModifier = SlotModifier{ player, menu, _ -> provider.provide(player, menu)}
private var onLeftClick =
SlotHandler { _, _, _ -> run { } }
private var onRightClick =
SlotHandler { _, _, _ -> run { } }
private var onShiftLeftClick =
SlotHandler { _, _, _ -> run { } }
private var onShiftRightClick =
SlotHandler { _, _, _ -> run { } }
private var onMiddleClick =
SlotHandler { _, _, _ -> run { } }
override fun onLeftClick(action: SlotHandler): SlotBuilder {
onLeftClick = action
return this
}
override fun onRightClick(action: SlotHandler): SlotBuilder {
onRightClick = action
return this
}
override fun onShiftLeftClick(action: SlotHandler): SlotBuilder {
onShiftLeftClick = action
return this
}
override fun onShiftRightClick(action: SlotHandler): SlotBuilder {
onShiftRightClick = action
return this
}
override fun onMiddleClick(action: SlotHandler): SlotBuilder {
onMiddleClick = action
return this
}
override fun setCaptive(): SlotBuilder {
captive = true
return this
}
override fun setModifier(modifier: SlotModifier): SlotBuilder {
this.modifier = modifier
return this
}
override fun build(): Slot {
return if (captive) {
EcoCaptivatorSlot()
} else {
EcoSlot(provider, onLeftClick, onRightClick, onShiftLeftClick, onShiftRightClick, onMiddleClick, modifier)
}
}
}

View File

@@ -0,0 +1,52 @@
package com.willfp.eco.internal.integrations
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.integrations.placeholder.PlaceholderIntegration
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager
import me.clip.placeholderapi.PlaceholderAPI
import me.clip.placeholderapi.expansion.PlaceholderExpansion
import org.bukkit.entity.Player
class PlaceholderIntegrationPAPI(private val plugin: EcoPlugin) : PlaceholderExpansion(), PlaceholderIntegration {
override fun persist(): Boolean {
return true
}
override fun canRegister(): Boolean {
return true
}
override fun getAuthor(): String {
return java.lang.String.join(", ", plugin.description.authors)
}
override fun getIdentifier(): String {
return plugin.description.name.lowercase()
}
override fun getVersion(): String {
return plugin.description.version
}
override fun onPlaceholderRequest(
player: Player?,
identifier: String
): String {
return PlaceholderManager.getResult(player, identifier)
}
override fun registerIntegration() {
register()
}
override fun getPluginName(): String {
return "PlaceholderAPI"
}
override fun translate(
text: String,
player: Player?
): String {
return PlaceholderAPI.setPlaceholders(player, text)
}
}

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