Compare commits

..

106 Commits
6.0.1 ... 6.3.0

Author SHA1 Message Date
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
Auxilor
f53c29cd56 Updated to 6.2.1 2021-07-31 16:59:46 +01:00
Auxilor
6845152a09 Fixed extension classloader bug with unclosed classloaders 2021-07-31 16:59:33 +01:00
Auxilor
7eaf2dc8ed Fixed Javadoc 2021-07-27 19:02:04 +01:00
Auxilor
310485402f Updated to 6.2.0 2021-07-27 19:01:08 +01:00
Auxilor
727dc25083 Added ArmorChangeEvent 2021-07-27 19:00:50 +01:00
Auxilor
364f36d502 Added player option to display, added setters to commands 2021-07-27 18:48:10 +01:00
Auxilor
b6086bc4bd JSON config changes 2021-07-27 18:36:51 +01:00
Auxilor
dd3beaa548 Added dynamic world height check 2021-07-27 18:34:23 +01:00
Auxilor
c36c0c247f Fixed enchant support in crafting recipes 2021-07-26 19:02:11 +01:00
Auxilor
6611a0f82c Fixed missing javadoc 2021-07-26 18:39:18 +01:00
Auxilor
625b981b81 Added support for enchantments in recipes 2021-07-26 18:38:12 +01:00
Auxilor
d8607917a1 Updated to 6.1.0 2021-07-26 18:26:13 +01:00
Auxilor
30d5f54459 Added EcoPlugin#reloadWithTime 2021-07-26 18:25:56 +01:00
Auxilor
a59c05174f Fixed bug with unloaded plugins 2021-07-26 18:21:52 +01:00
Auxilor
cf01abcf87 Added out of world check to blocks 2021-07-26 18:20:13 +01:00
Auxilor
70a4a06d4f Updated to 6.0.6 2021-07-24 01:12:55 +01:00
Auxilor
bbee18fd8a JSON config files now have same deletion behaviour as yaml config files 2021-07-24 01:12:46 +01:00
Auxilor
26ab9a327d Added warnings to invalid extensions 2021-07-23 22:14:14 +01:00
Auxilor
0676f5fa33 Updated to 6.0.5 2021-07-23 22:11:41 +01:00
Auxilor
051b95ad88 Extension loading change 2021-07-23 22:11:32 +01:00
Auxilor
d786014cbc Updated to 6.0.4 2021-07-22 18:40:17 +01:00
Auxilor
b62bb48bb6 Fixed loadable config reloading 2021-07-22 18:39:59 +01:00
Auxilor
b238a10209 Fixed EcoUpdatableYamlConfig not automatically registering itsefl 2021-07-22 18:34:00 +01:00
Auxilor
251049f1f1 Updated to 6.0.3 2021-07-22 16:42:00 +01:00
Auxilor
16d146dba0 Fixed ArrowUtils 2021-07-22 16:41:43 +01:00
Auxilor
214308da10 Updated to 6.0.2 2021-07-21 21:46:12 +01:00
Auxilor
2c12f78aa6 Fixed 'Menu not instance of EcoMenu!' bug 2021-07-21 21:45:59 +01:00
201 changed files with 4798 additions and 4646 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;
@@ -52,6 +51,7 @@ import java.util.stream.Collectors;
* <b>IMPORTANT: When reloading a plugin, all runnables / tasks will
* be cancelled.</b>
*/
@SuppressWarnings("unused")
public abstract class EcoPlugin extends JavaPlugin {
/**
* The spigot resource ID of the plugin.
@@ -347,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());
@@ -405,7 +405,6 @@ public abstract class EcoPlugin extends JavaPlugin {
this.getEventManager().unregisterAllListeners();
this.getScheduler().cancelAll();
this.getConfigHandler().saveAllConfigs();
this.handleDisable();
@@ -464,7 +463,7 @@ public abstract class EcoPlugin extends JavaPlugin {
}
/**
* Default code to be executed on plugin reload.
* Reload the plugin.
*/
public final void reload() {
this.getConfigHandler().updateConfigs();
@@ -476,6 +475,19 @@ public abstract class EcoPlugin extends JavaPlugin {
this.handleReload();
}
/**
* Reload the plugin and return the time taken to reload.
*
* @return The time.
*/
public final long reloadWithTime() {
long startTime = System.currentTimeMillis();
this.reload();
return System.currentTimeMillis() - startTime;
}
/**
* The plugin-specific code to be executed on enable.
* <p>
@@ -601,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

@@ -42,10 +42,24 @@ public interface CommandBase {
*/
CommandHandler getHandler();
/**
* Set the handler.
*
* @param handler The handler.
*/
void setHandler(@NotNull CommandHandler handler);
/**
* Get the tab completer.
*
* @return The tab completer.
*/
TabCompleteHandler getTabCompleter();
/**
* Set the tab completer.
*
* @param handler The handler.
*/
void setTabCompleter(@NotNull TabCompleteHandler handler);
}

View File

@@ -7,6 +7,7 @@ import com.willfp.eco.core.command.CommandHandler;
import com.willfp.eco.core.command.TabCompleteHandler;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.util.StringUtil;
@@ -48,6 +49,20 @@ abstract class HandledCommand extends PluginDependent<EcoPlugin> implements Comm
@Getter
private final boolean playersOnly;
/**
* The actual code to be executed in the command.
*/
@Getter
@Setter
private CommandHandler handler = (sender, args) -> { };
/**
* The tab completion code to be executed in the command.
*/
@Getter
@Setter
private TabCompleteHandler tabCompleter = (sender, args) -> new ArrayList<>();
/**
* All subcommands for the command.
*/
@@ -164,14 +179,6 @@ abstract class HandledCommand extends PluginDependent<EcoPlugin> implements Comm
return this.getTabCompleter().tabComplete(sender, Arrays.asList(args));
}
@Override
public abstract CommandHandler getHandler();
@Override
public TabCompleteHandler getTabCompleter() {
return (sender, args) -> new ArrayList<>();
}
/**
* If a sender can execute the command.
*

View File

@@ -29,6 +29,27 @@ public interface JSONConfig extends Config {
@Nullable
List<JSONConfig> getSubsectionsOrNull(@NotNull String path);
/**
* Get subsection from config.
*
* @param path The key to check.
* @return The subsection. Throws NPE if not found.
*/
@Override
@NotNull
JSONConfig getSubsection(@NotNull String path);
/**
* Get subsection from config.
*
* @param path The key to check.
* @return The subsection, or null if not found.
*/
@Override
@Nullable
JSONConfig getSubsectionOrNull(@NotNull String path);
@Override
JSONConfig clone();
}

View File

@@ -31,6 +31,16 @@ public abstract class JSONConfigWrapper extends ConfigWrapper<JSONConfig> implem
return this.getHandle().getSubsectionsOrNull(path);
}
@Override
public @NotNull JSONConfig getSubsection(@NotNull final String path) {
return this.getHandle().getSubsection(path);
}
@Override
public @Nullable JSONConfig getSubsectionOrNull(@NotNull final String path) {
return this.getHandle().getSubsectionOrNull(path);
}
@Override
public JSONConfig clone() {
return this.getHandle().clone();

View File

@@ -3,12 +3,14 @@ package com.willfp.eco.core.display;
import lombok.experimental.UtilityClass;
import org.apache.commons.lang.Validate;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
@@ -57,6 +59,18 @@ public class Display {
* @return The ItemStack.
*/
public ItemStack display(@NotNull final ItemStack itemStack) {
return display(itemStack, null);
}
/**
* Display on ItemStacks.
*
* @param itemStack The item.
* @param player The player.
* @return The ItemStack.
*/
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
}
@@ -83,6 +97,9 @@ public class Display {
for (DisplayModule module : modules) {
Object[] varargs = pluginVarArgs.get(module.getPluginName());
module.display(itemStack, varargs);
if (player != null) {
module.display(itemStack, player, varargs);
}
}
}
@@ -96,7 +113,19 @@ public class Display {
* @return The ItemStack.
*/
public ItemStack displayAndFinalize(@NotNull final ItemStack itemStack) {
return finalize(display(itemStack));
return finalize(display(itemStack, null));
}
/**
* Display on ItemStacks and then finalize.
*
* @param itemStack The item.
* @param player The player.
* @return The ItemStack.
*/
public ItemStack displayAndFinalize(@NotNull final ItemStack itemStack,
@Nullable final Player player) {
return finalize(display(itemStack, player));
}
/**

View File

@@ -3,8 +3,10 @@ package com.willfp.eco.core.display;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginDependent;
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.
@@ -39,6 +41,19 @@ public abstract class DisplayModule extends PluginDependent<EcoPlugin> {
// Technically optional.
}
/**
* Display an item.
*
* @param itemStack The item.
* @param player The player.
* @param args Optional args for display.
*/
protected void display(@NotNull final ItemStack itemStack,
@Nullable final Player player,
@NotNull final Object... args) {
// Technically optional.
}
/**
* Revert an item.
*

View File

@@ -0,0 +1,70 @@
package com.willfp.eco.core.events;
import lombok.Getter;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* The armor change event <b>does</b> contain information about the event.
* <p>
* Unlike {@link ArmorEquipEvent}, it is called the next tick and contains previous and current armor contents.
*/
public class ArmorChangeEvent extends PlayerEvent {
/**
* Bukkit parity.
*/
private static final HandlerList HANDLERS = new HandlerList();
/**
* The armor contents before. 0 is helmet, 3 is boots.
*/
@Getter
private final List<ItemStack> before;
/**
* The armor contents after. 0 is helmet, 3 is boots.
*/
@Getter
private final List<ItemStack> after;
/**
* Create a new ArmorChangeEvent.
*
* @param player The player.
* @param before The armor contents before.
* @param after The armor contents after.
*/
public ArmorChangeEvent(@NotNull final Player player,
@NotNull final List<ItemStack> before,
@NotNull final List<ItemStack> after) {
super(player);
this.before = before;
this.after = after;
}
/**
* Gets a list of handlers handling this event.
*
* @return A list of handlers handling this event.
*/
@Override
@NotNull
public HandlerList getHandlers() {
return HANDLERS;
}
/**
* Bukkit parity.
*
* @return The handler list.
*/
public static HandlerList getHandlerList() {
return HANDLERS;
}
}

View File

@@ -13,8 +13,14 @@ 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.
*/
private static final HandlerList HANDLERS = new HandlerList();
/**

View File

@@ -0,0 +1,64 @@
package com.willfp.eco.core.fast;
import com.willfp.eco.core.Eco;
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;
/**
* 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();
/**
* 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(@NotNull final ItemStack itemStack) {
return Eco.getHandler().createFastItemStack(itemStack);
}
}

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

@@ -1,15 +1,21 @@
package com.willfp.eco.core.items;
import com.willfp.eco.core.items.builder.ItemBuilder;
import com.willfp.eco.core.items.builder.ItemStackBuilder;
import com.willfp.eco.core.recipe.parts.EmptyTestableItem;
import com.willfp.eco.core.recipe.parts.MaterialTestableItem;
import com.willfp.eco.core.recipe.parts.ModifiedTestableItem;
import com.willfp.eco.core.recipe.parts.TestableStack;
import com.willfp.eco.util.NamespacedKeyUtils;
import lombok.experimental.UtilityClass;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -36,6 +42,15 @@ public final class Items {
REGISTRY.put(key, part);
}
/**
* Remove an item.
*
* @param key The key of the recipe part.
*/
public void removeCustomItem(@NotNull final NamespacedKey key) {
REGISTRY.remove(key);
}
/**
* Lookup item from string.
* <p>
@@ -45,14 +60,21 @@ public final class Items {
* @return The found testable item, or an empty item if not found.
*/
public TestableItem lookup(@NotNull final String key) {
String[] split = key.toLowerCase().split(":");
String[] args = key.split(" ");
if (args.length == 0) {
return new EmptyTestableItem();
}
TestableItem item = null;
String[] split = args[0].toLowerCase().split(":");
if (split.length == 1) {
Material material = Material.getMaterial(key.toUpperCase());
Material material = Material.getMaterial(args[0].toUpperCase());
if (material == null || material == Material.AIR) {
return new EmptyTestableItem();
}
return new MaterialTestableItem(material);
item = new MaterialTestableItem(material);
}
if (split.length == 2) {
@@ -63,18 +85,66 @@ public final class Items {
if (material == null || material == Material.AIR) {
return new EmptyTestableItem();
}
return new TestableStack(new MaterialTestableItem(material), Integer.parseInt(split[1]));
item = new TestableStack(new MaterialTestableItem(material), Integer.parseInt(split[1]));
} else {
return part;
item = part;
}
}
if (split.length == 3) {
CustomItem part = REGISTRY.get(NamespacedKeyUtils.create(split[0], split[1]));
return part == null ? new EmptyTestableItem() : new TestableStack(part, Integer.parseInt(split[2]));
item = part == null ? new EmptyTestableItem() : new TestableStack(part, Integer.parseInt(split[2]));
}
return new EmptyTestableItem();
if (item == null || item instanceof EmptyTestableItem) {
return new EmptyTestableItem();
}
String[] enchantArgs = Arrays.copyOfRange(args, 1, args.length);
Map<Enchantment, Integer> requiredEnchantments = new HashMap<>();
for (String enchantArg : enchantArgs) {
String[] enchantArgSplit = enchantArg.split(":");
Enchantment enchantment = Enchantment.getByKey(NamespacedKey.minecraft(enchantArgSplit[0].toLowerCase()));
int level = Integer.parseInt(enchantArgSplit[1]);
requiredEnchantments.put(enchantment, level);
}
if (requiredEnchantments.isEmpty()) {
return item;
}
ItemBuilder builder = new ItemStackBuilder(item.getItem());
requiredEnchantments.forEach(builder::addEnchantment);
ItemStack example = builder.build();
return new ModifiedTestableItem(
item,
itemStack -> {
if (!itemStack.hasItemMeta()) {
return false;
}
ItemMeta meta = itemStack.getItemMeta();
assert meta != null;
for (Map.Entry<Enchantment, Integer> entry : requiredEnchantments.entrySet()) {
if (!meta.hasEnchant(entry.getKey())) {
return false;
}
if (meta.getEnchantLevel(entry.getKey()) < entry.getValue()) {
return false;
}
}
return true;
},
example
);
}
/**

View File

@@ -0,0 +1,63 @@
package com.willfp.eco.core.recipe.parts;
import com.willfp.eco.core.items.TestableItem;
import lombok.Getter;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Predicate;
/**
* Existing testable items with an extra filter.
*
* @see com.willfp.eco.core.items.CustomItem
*/
public class ModifiedTestableItem implements TestableItem {
/**
* The item.
*/
private final TestableItem handle;
/**
* The amount.
*/
@Getter
private final Predicate<ItemStack> test;
/**
* The item for the modified test.
*/
private final ItemStack example;
/**
* Create a new modified testable item.
*
* @param item The item.
* @param test The test.
* @param example The example.
*/
public ModifiedTestableItem(@NotNull final TestableItem item,
@NotNull final Predicate<ItemStack> test,
@NotNull final ItemStack example) {
this.handle = item;
this.test = test;
this.example = example;
}
/**
* If the item matches the material.
*
* @param itemStack The item to test.
* @return If the item is of the specified material.
*/
@Override
public boolean matches(@Nullable final ItemStack itemStack) {
return itemStack != null && handle.matches(itemStack) && test.test(itemStack);
}
@Override
public ItemStack getItem() {
return example;
}
}

View File

@@ -29,10 +29,10 @@ public class ArrowUtils {
return null;
}
if (!(values.get(0) instanceof ItemStack)) {
if (!(values.get(0).value() instanceof ItemStack)) {
return null;
}
return (ItemStack) values.get(0);
return (ItemStack) values.get(0).value();
}
}

View File

@@ -1,9 +1,10 @@
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;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player;
@@ -30,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)) {
@@ -44,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;
}
@@ -112,6 +80,14 @@ public class BlockUtils {
Validate.isTrue(initialized, "Must be initialized!");
Validate.notNull(blockBreakConsumer, "Must be initialized!");
Location location = block.getLocation();
World world = location.getWorld();
assert world != null;
if (location.getY() < world.getMinHeight() || location.getY() > world.getMaxHeight()) {
return;
}
blockBreakConsumer.accept(player, block);
}

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();
@@ -122,14 +126,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 +163,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 +183,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 +236,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(
LegacyComponentSerializer.legacySection().deserialize(legacy)
)
);
}
/**
* Convert JSON string to legacy.
*
* @param json The JSON string.
* @return The legacy string.
*/
public String jsonToLegacy(@NotNull final String json) {
return LegacyComponentSerializer.legacySection().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,31 +0,0 @@
package com.willfp.eco.internal;
import com.willfp.eco.core.EcoPlugin;
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());
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,370 +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.Config;
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 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 (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);
Validate.notNull(subsections);
return 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,119 +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);
}
@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 {
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,81 +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.updating.exceptions.InvalidUpdateMethodException;
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();
}
}
}
}

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,107 +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.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);
init(YamlConfiguration.loadConfiguration(configFile));
}
@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,89 +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);
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,121 +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.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.apache.commons.lang.Validate;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class EcoExtensionLoader extends PluginDependent<EcoPlugin> implements ExtensionLoader {
private final Set<Extension> extensions = new HashSet<>();
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().severe(extensionJar.getName() + " caused MalformedExtensionException: " + e.getMessage());
}
}
}
private void loadExtension(@NotNull final File extensionJar) {
URL url = null;
try {
url = extensionJar.toURI().toURL();
} catch (MalformedURLException e) {
e.printStackTrace();
}
ClassLoader cl = new URLClassLoader(new URL[]{url}, this.getPlugin().getClass().getClassLoader());
InputStream ymlIn = cl.getResourceAsStream("extension.yml");
if (ymlIn == null) {
throw new MalformedExtensionException("No extension.yml found in " + extensionJar.getName());
}
YamlConfiguration extensionYml = YamlConfiguration.loadConfiguration(new InputStreamReader(ymlIn));
Set<String> keys = extensionYml.getKeys(false);
ArrayList<String> required = new ArrayList<>(Arrays.asList("main", "name", "version"));
required.removeAll(keys);
if (!required.isEmpty()) {
throw new MalformedExtensionException("Invalid extension.yml found in " + extensionJar.getName() + " - Missing: " + String.join(", ", required));
}
String mainClass = extensionYml.getString("main");
String name = extensionYml.getString("name");
String version = extensionYml.getString("version");
String author = extensionYml.getString("author");
Validate.notNull(name, "Name is missing!");
Validate.notNull(version, "Version is missing!");
Validate.notNull(author, "Author is missing!");
ExtensionMetadata metadata = new ExtensionMetadata(version, name, author);
Class<?> cls;
Object object = null;
try {
cls = cl.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.add(extension);
}
@Override
public void unloadExtensions() {
extensions.forEach(Extension::disable);
extensions.clear();
}
@Override
public Set<Extension> getLoadedExtensions() {
return extensions;
}
}

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,286 @@
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 {
cache["$path\$FMT"] = StringUtils.formatList(if (has(path)) ArrayList(handle.getStringList(path)) else ArrayList<String>())
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
private 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,42 @@
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)
} else {
fetched.addDrops(items)
fetched.location = loc
fetched.addXp(xp)
COLLATED_MAP[player] = fetched
}
}
class CollatedDrops(
val drops: MutableList<ItemStack>,
var location: Location,
var xp: Int
) {
fun addDrops(toAdd: List<ItemStack>): CollatedDrops {
drops.addAll(toAdd)
return this
}
fun addXp(xp: Int): CollatedDrops {
this.xp += xp
return this
}
}
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,20 @@
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 java.util.function.Function
class EcoGUIFactory : GUIFactory {
override fun createSlotBuilder(provider: Function<Player, ItemStack>): SlotBuilder {
return EcoSlotBuilder(provider)
}
override fun createMenuBuilder(rows: Int): MenuBuilder {
return EcoMenuBuilder(rows)
}
}

View File

@@ -0,0 +1,80 @@
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 org.bukkit.Bukkit
import org.bukkit.entity.Player
import org.bukkit.event.inventory.InventoryCloseEvent
import org.bukkit.inventory.Inventory
import java.util.function.Consumer
class EcoMenu(
private val rows: Int,
private val slots: List<MutableList<Slot>>,
private val title: String,
private val onClose: Consumer<InventoryCloseEvent>
): 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!")
}
val slot = slots[row - 1][column - 1]
if (slot is FillerSlot) {
slots[row - 1][column - 1] = EcoFillerSlot(slot.itemStack)
return getSlot(row, column)
}
return slot
}
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)
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.accept(event)
}
override fun getRows(): Int {
return rows
}
override fun getTitle(): String {
return title
}
}

View File

@@ -0,0 +1,72 @@
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 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 = Consumer { _: InventoryCloseEvent -> }
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 setMask(mask: FillerMask): MenuBuilder {
maskSlots = mask.mask
return this
}
override fun onClose(action: Consumer<InventoryCloseEvent>): MenuBuilder {
onClose = action
return this
}
override fun build(): Menu {
val finalSlots: MutableList<MutableList<Slot>> = ArrayList()
for (maskRow in maskSlots) {
val row = ArrayList<Slot>()
for (slot in maskRow) {
row.add(slot ?: EcoFillerSlot(ItemStack(Material.AIR)))
}
finalSlots.add(ArrayList())
finalSlots.add(row)
}
for (i in slots.indices) {
for (j in slots[i].indices) {
val slot = slots[i][j]
finalSlots[i][j] = slot
}
}
return EcoMenu(rows, finalSlots, title, onClose)
}
init {
maskSlots = ListUtils.create2DList(rows, 9)
}
}

View File

@@ -0,0 +1,23 @@
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<Inventory, Menu> = HashMap()
fun registerMenu(
inventory: Inventory,
menu: Menu
) {
MENUS[inventory] = menu
}
fun unregisterMenu(inventory: Inventory) {
MENUS.remove(inventory)
}
fun getMenu(inventory: Inventory): Menu? {
return MENUS[inventory]
}
}

View File

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

View File

@@ -0,0 +1,34 @@
package com.willfp.eco.internal.gui.slot
import com.willfp.eco.core.gui.slot.Slot
import org.bukkit.entity.Player
import org.bukkit.event.inventory.ClickType
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.inventory.ItemStack
import java.util.function.BiConsumer
import java.util.function.Function
open class EcoSlot(
private val provider: Function<Player, ItemStack>,
private val onLeftClick: BiConsumer<InventoryClickEvent, Slot>,
private val onRightClick: BiConsumer<InventoryClickEvent, Slot>,
private val onShiftLeftClick: BiConsumer<InventoryClickEvent, Slot>,
private val onShiftRightClick: BiConsumer<InventoryClickEvent, Slot>,
private val onMiddleClick: BiConsumer<InventoryClickEvent, Slot>
) : Slot {
fun handleInventoryClick(event: InventoryClickEvent) {
when (event.click) {
ClickType.LEFT -> this.onLeftClick.accept(event, this)
ClickType.RIGHT -> this.onRightClick.accept(event, this)
ClickType.SHIFT_LEFT -> this.onShiftLeftClick.accept(event, this)
ClickType.SHIFT_RIGHT -> this.onShiftRightClick.accept(event, this)
ClickType.MIDDLE -> this.onMiddleClick.accept(event, this)
else -> { }
}
}
override fun getItemStack(player: Player): ItemStack {
return provider.apply(player)
}
}

View File

@@ -0,0 +1,46 @@
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 java.util.function.BiConsumer
import java.util.function.Function
class EcoSlotBuilder(private val provider: Function<Player, ItemStack>) : SlotBuilder {
private var onLeftClick: BiConsumer<InventoryClickEvent, Slot> = BiConsumer { _, _ -> run { } }
private var onRightClick: BiConsumer<InventoryClickEvent, Slot> = BiConsumer { _, _ -> run { } }
private var onShiftLeftClick: BiConsumer<InventoryClickEvent, Slot> = BiConsumer { _, _ -> run { } }
private var onShiftRightClick: BiConsumer<InventoryClickEvent, Slot> = BiConsumer { _, _ -> run { } }
private var onMiddleClick: BiConsumer<InventoryClickEvent, Slot> = BiConsumer { _, _ -> run { } }
override fun onLeftClick(action: BiConsumer<InventoryClickEvent, Slot>): SlotBuilder {
onLeftClick = action
return this
}
override fun onRightClick(action: BiConsumer<InventoryClickEvent, Slot>): SlotBuilder {
onRightClick = action
return this
}
override fun onShiftLeftClick(action: BiConsumer<InventoryClickEvent, Slot>): SlotBuilder {
onShiftLeftClick = action
return this
}
override fun onShiftRightClick(action: BiConsumer<InventoryClickEvent, Slot>): SlotBuilder {
onShiftRightClick = action
return this
}
override fun onMiddleClick(action: BiConsumer<InventoryClickEvent, Slot>): SlotBuilder {
onMiddleClick = action
return this
}
override fun build(): Slot {
return EcoSlot(provider, onLeftClick, onRightClick, onShiftLeftClick, onShiftRightClick, onMiddleClick)
}
}

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)
}
}

View File

@@ -0,0 +1,25 @@
package com.willfp.eco.internal.logging
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.util.StringUtils
import java.util.logging.Level
import java.util.logging.Logger
class EcoLogger(plugin: EcoPlugin) : Logger(plugin.name, null as String?) {
override fun info(msg: String) {
super.info(StringUtils.format(msg))
}
override fun warning(msg: String) {
super.warning(StringUtils.format(msg))
}
override fun severe(msg: String) {
super.severe(StringUtils.format(msg))
}
init {
parent = plugin.server.logger
this.level = Level.ALL
}
}

View File

@@ -0,0 +1,81 @@
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 java.net.URLClassLoader
import java.util.*
class EcoProxyFactory(
plugin: EcoPlugin
) : PluginDependent<EcoPlugin>(plugin), ProxyFactory {
private val proxyClassLoader: ClassLoader = plugin::class.java.classLoader
private val cache: MutableMap<Class<out AbstractProxy>, AbstractProxy> = IdentityHashMap()
override fun <T : AbstractProxy> getProxy(proxyClass: Class<T>): T {
try {
val cachedProxy: T? = attemptCache(proxyClass)
if (cachedProxy != null) {
return cachedProxy
}
val className =
this.plugin.proxyPackage + "." + ProxyConstants.NMS_VERSION + "." + proxyClass.simpleName.replace(
"Proxy",
""
)
val clazz = this.plugin::class.java.classLoader.loadClass(className)
val instance = clazz.getDeclaredConstructor().newInstance()
if (proxyClass.isAssignableFrom(clazz) && proxyClass.isInstance(instance)) {
val proxy = proxyClass.cast(instance)
cache[proxyClass] = proxy
return proxy
}
} catch (e: Exception) {
throwError(e)
}
throwError(IllegalArgumentException())
throw RuntimeException("Something went wrong.")
}
private fun throwError(e: Exception?) {
e?.printStackTrace()
if (!SUPPORTED_VERSIONS.contains(ProxyConstants.NMS_VERSION)) {
throw UnsupportedVersionException("You're running an unsupported server version: " + ProxyConstants.NMS_VERSION)
} else {
throw ProxyError("Error with proxies - here's a stacktrace. Only god can help you now.")
}
}
private fun <T : AbstractProxy> attemptCache(proxyClass: Class<T>): T? {
val proxy = cache[proxyClass] ?: return null
if (proxyClass.isInstance(proxy)) {
return proxyClass.cast(proxy)
}
return null
}
fun clean() {
if (proxyClassLoader is URLClassLoader) {
proxyClassLoader.close()
}
cache.clear()
}
companion object {
val SUPPORTED_VERSIONS = listOf(
"v1_16_R3",
"v1_17_R1"
)
}
}

View File

@@ -0,0 +1,38 @@
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
abstract class EcoRunnableTask(protected val plugin: EcoPlugin) : BukkitRunnable(), RunnableTask {
@Synchronized
override fun runTask(): BukkitTask {
return super.runTask(plugin)
}
@Synchronized
override fun runTaskAsynchronously(): BukkitTask {
return super.runTaskAsynchronously(plugin)
}
@Synchronized
override fun runTaskLater(delay: Long): BukkitTask {
return super.runTaskLater(plugin, delay)
}
@Synchronized
override fun runTaskLaterAsynchronously(delay: Long): BukkitTask {
return super.runTaskLaterAsynchronously(plugin, delay)
}
@Synchronized
override fun runTaskTimer(delay: Long, period: Long): BukkitTask {
return super.runTaskTimer(plugin, delay, period)
}
@Synchronized
override fun runTaskTimerAsynchronously(delay: Long, period: Long): BukkitTask {
return super.runTaskTimerAsynchronously(plugin, delay, period)
}
}

View File

@@ -0,0 +1,52 @@
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
class EcoScheduler(plugin: EcoPlugin) : PluginDependent<EcoPlugin>(plugin), Scheduler {
override fun runLater(
runnable: Runnable,
ticksLater: Long
): BukkitTask {
return Bukkit.getScheduler().runTaskLater(plugin, runnable, ticksLater)
}
override fun runTimer(
runnable: Runnable,
delay: Long,
repeat: Long
): BukkitTask {
return Bukkit.getScheduler().runTaskTimer(plugin, runnable, delay, repeat)
}
override fun runAsyncTimer(
runnable: Runnable,
delay: Long,
repeat: Long
): BukkitTask {
return Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, runnable, delay, repeat)
}
override fun run(runnable: Runnable): BukkitTask {
return Bukkit.getScheduler().runTask(plugin, runnable)
}
override fun runAsync(runnable: Runnable): BukkitTask {
return Bukkit.getScheduler().runTaskAsynchronously(plugin, runnable)
}
override fun syncRepeating(
runnable: Runnable,
delay: Long,
repeat: Long
): Int {
return Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, runnable, delay, repeat)
}
override fun cancelAll() {
Bukkit.getScheduler().cancelTasks(plugin)
}
}

View File

@@ -5,5 +5,6 @@ subprojects {
dependencies {
compileOnly project(':eco-core:core-proxy')
compileOnly project(':eco-core:core-plugin')
compileOnly project(':eco-core:core-backend')
}
}

View File

@@ -1,19 +0,0 @@
package com.willfp.eco.proxy.v1_16_R3;
import com.willfp.eco.proxy.AutoCraftProxy;
import net.minecraft.server.v1_16_R3.MinecraftKey;
import net.minecraft.server.v1_16_R3.PacketPlayOutAutoRecipe;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.Field;
public final class AutoCraft implements AutoCraftProxy {
@Override
public void modifyPacket(@NotNull final Object packet) throws NoSuchFieldException, IllegalAccessException {
PacketPlayOutAutoRecipe recipePacket = (PacketPlayOutAutoRecipe) packet;
Field fKey = recipePacket.getClass().getDeclaredField("b");
fKey.setAccessible(true);
MinecraftKey key = (MinecraftKey) fKey.get(recipePacket);
fKey.set(recipePacket, new MinecraftKey(key.getNamespace(), key.getKey() + "_displayed"));
}
}

View File

@@ -1,20 +0,0 @@
package com.willfp.eco.proxy.v1_16_R3;
import com.willfp.eco.proxy.BlockBreakProxy;
import net.minecraft.server.v1_16_R3.BlockPosition;
import org.bukkit.block.Block;
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public final class BlockBreak implements BlockBreakProxy {
@Override
public void breakBlock(@NotNull final Player player,
@NotNull final Block block) {
if (!(player instanceof CraftPlayer)) {
return;
}
((CraftPlayer) player).getHandle().playerInteractManager.breakBlock(new BlockPosition(block.getX(), block.getY(), block.getZ()));
}
}

View File

@@ -14,6 +14,7 @@ import net.minecraft.server.v1_16_R3.IChatBaseComponent;
import net.minecraft.server.v1_16_R3.MojangsonParser;
import org.bukkit.Material;
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
@@ -21,9 +22,10 @@ import java.util.Arrays;
public final class ChatComponent implements ChatComponentProxy {
@Override
public Object modifyComponent(@NotNull final Object object) {
if (!(object instanceof IChatBaseComponent chatComponent)) {
return object;
public Object modifyComponent(@NotNull final Object obj,
@NotNull final Player player) {
if (!(obj instanceof IChatBaseComponent chatComponent)) {
return obj;
}
for (IChatBaseComponent iChatBaseComponent : chatComponent) {
@@ -31,25 +33,26 @@ public final class ChatComponent implements ChatComponentProxy {
continue;
}
modifyBaseComponent(iChatBaseComponent);
modifyBaseComponent(iChatBaseComponent, player);
}
return chatComponent;
}
private void modifyBaseComponent(@NotNull final IChatBaseComponent component) {
private void modifyBaseComponent(@NotNull final IChatBaseComponent component,
@NotNull final Player player) {
for (IChatBaseComponent sibling : component.getSiblings()) {
if (sibling == null) {
continue;
}
modifyBaseComponent(sibling);
modifyBaseComponent(sibling, player);
}
if (component instanceof ChatMessage) {
Arrays.stream(((ChatMessage) component).getArgs())
.filter(o -> o instanceof IChatBaseComponent)
.map(o -> (IChatBaseComponent) o)
.forEach(this::modifyBaseComponent);
.forEach(o -> this.modifyBaseComponent(o, player));
}
ChatHoverable hoverable = component.getChatModifier().getHoverEvent();
@@ -70,7 +73,7 @@ public final class ChatComponent implements ChatComponentProxy {
String tag = json.getAsJsonObject().get("tag").toString();
ItemStack itemStack = getFromTag(tag, id);
Display.displayAndFinalize(itemStack);
Display.displayAndFinalize(itemStack, player);
json.getAsJsonObject().remove("tag");
String newTag = toJson(itemStack);

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