Compare commits

..

79 Commits

Author SHA1 Message Date
Auxilor
364550d228 Pain 2022-04-06 13:47:01 +01:00
Auxilor
d5e8cbaf33 Updated to 6.32.1 2022-04-06 13:35:34 +01:00
Auxilor
c4d532fda9 Removed MySQL relocation 2022-04-06 13:34:33 +01:00
Auxilor
aa097cf7e2 Fixed wrong MySQL driver class 2022-04-06 13:08:29 +01:00
Auxilor
6f4ca40a94 Changed load order for custom items 2022-04-05 16:29:13 +01:00
Auxilor
2ef9b4033c Updated to 6.32.0 2022-04-05 15:38:44 +01:00
Auxilor
9aa22ffc86 Added Items#mergeFrom 2022-04-05 15:38:34 +01:00
Auxilor
d81c1e6fcb Added comment 2022-04-05 13:22:13 +01:00
Auxilor
ac72e0770a Undid last commit 2022-04-05 13:17:29 +01:00
Auxilor
5e3e09c4bc Moved adventure api to api configuration 2022-04-05 13:17:07 +01:00
Auxilor
ee945d5901 Updated to 6.31.4 2022-04-05 13:14:48 +01:00
Auxilor
7f747f3afc Fixed & color code 2022-04-05 13:12:49 +01:00
Auxilor
2d47593f51 More build changes 2022-04-05 13:12:29 +01:00
Auxilor
df529ba239 Minimized use of the lib-loader 2022-04-05 13:01:05 +01:00
Auxilor
2fea736631 Updated to 6.31.3 2022-04-02 14:36:23 +01:00
Auxilor
9df4fae2dc Fixed colors in console on new versions of paper 2022-04-02 14:36:14 +01:00
Auxilor
ca964a1a40 Updated to 6.31.2 and fixed default key values 2022-03-29 16:17:59 +01:00
Auxilor
ada2832839 Fixed data.yml 2022-03-28 21:24:34 +01:00
Auxilor
4d92cbb7ff Fixed PersistentDataKeyType equality 2022-03-28 14:33:28 +01:00
Auxilor
d6ab36929b Changed data reading 2022-03-28 14:29:56 +01:00
Auxilor
e06623d3fe Fixed some config constructors 2022-03-28 14:23:27 +01:00
Auxilor
8b70a37459 Updated to 6.31.1 2022-03-28 14:21:19 +01:00
Auxilor
daab3829bc Config changes 2022-03-28 14:21:09 +01:00
Auxilor
d09021707b Fixed name arg parser 2022-03-27 13:20:53 +01:00
Auxilor
bea8cb5757 Updated to 6.31.0 2022-03-27 13:20:21 +01:00
Auxilor
bde546efcb Added Items#toLookupString 2022-03-27 13:19:48 +01:00
Auxilor
e1ffc851a3 Updated to 6.30.2 2022-03-26 16:02:09 +00:00
Auxilor
828229b3e5 Updated to 6.30.1 2022-03-26 15:43:34 +00:00
Auxilor
f36e2f5349 Fixed config header duplication bug 2022-03-26 15:43:24 +00:00
Auxilor
cdbe5b141a Fixed yaml printing 2022-03-24 18:13:11 +00:00
Auxilor
08c3fc0cfa Fixed config removing 2022-03-24 15:53:12 +00:00
Auxilor
8f758fb100 Changed bukkit -> eco config mapping 2022-03-24 12:21:15 +00:00
Auxilor
ec339b0ecd Removed debug println 2022-03-24 12:13:49 +00:00
Auxilor
9dedfb86a5 Fixed more config things 2022-03-24 12:13:02 +00:00
Auxilor
0146cff8d3 More config work 2022-03-24 11:26:41 +00:00
Auxilor
2454d99d84 Reworked getKeys 2022-03-24 10:50:35 +00:00
Auxilor
7d9b1bc266 Removed debug toggle 2022-03-24 10:46:52 +00:00
Auxilor
77c56c46a8 Keep the reworks coming 2022-03-24 10:41:09 +00:00
Auxilor
85303098a7 Reworked configs (again) 2022-03-24 09:46:27 +00:00
Auxilor
821dc62d56 More anti-anchor prevention 2022-03-23 19:44:23 +00:00
Auxilor
f9af4a9e66 Removed debug 2022-03-23 16:26:51 +00:00
Auxilor
41b9d6b01d Config cleanup 2022-03-23 16:24:17 +00:00
Auxilor
7a521acccf More config improvements (and codestyle) 2022-03-23 15:50:25 +00:00
Auxilor
49233aef88 Comment headers are now preserved 2022-03-23 15:32:43 +00:00
Auxilor
c5b47ed073 And they dont stop coming 2022-03-23 14:21:25 +00:00
Auxilor
ddcef7cf0c The config rewrites never stop 2022-03-23 13:53:56 +00:00
Auxilor
0f86e1c1c1 More config rewrites 2022-03-23 12:59:53 +00:00
Auxilor
f0f7e229ea Began complete config rewrite 2022-03-23 12:28:34 +00:00
Auxilor
ea674a3757 Merge remote-tracking branch 'origin/develop' into develop 2022-03-23 10:51:50 +00:00
Auxilor
b7c51eba5e Fixed more config bugs 2022-03-22 19:55:19 +00:00
Auxilor
1127bf1700 Renamed ConfigBuilder to BuildableConfig 2022-03-22 16:59:20 +00:00
Auxilor
376e3284fb Fixed config bugs 2022-03-22 16:53:16 +00:00
Auxilor
12f355b205 Fixed GUI and rendering bugs 2022-03-22 16:46:32 +00:00
Auxilor
f4b02591e8 Clarified javadoc 2022-03-22 16:25:18 +00:00
Auxilor
f843725cf5 Fixed missing method 2022-03-22 16:16:58 +00:00
Auxilor
ed0536c188 Fixed stupidity 2022-03-22 14:14:45 +00:00
Auxilor
849e005095 More oraxen tweaks 2022-03-22 14:12:39 +00:00
Auxilor
927d61dd6b Marked ConfigUpdater as @Documented 2022-03-22 14:09:36 +00:00
Auxilor
9285cffc56 Updated ConfigUpdater javadoc 2022-03-22 14:08:25 +00:00
Auxilor
1b6c90e87d Updated to 6.30.0 2022-03-22 14:07:14 +00:00
Auxilor
c79de6fbc1 Marked more deprecated things as for removal 2022-03-22 14:06:59 +00:00
Auxilor
fc83ebbb34 Removed all long-deprecated config methods 2022-03-22 14:03:02 +00:00
Auxilor
f330cc954c Added ConfigBuilder and more TransientConfig constructors 2022-03-22 14:01:18 +00:00
Auxilor
df4f98251c Improved setting with JSON configs 2022-03-22 12:58:20 +00:00
Auxilor
74861e9c01 Improved config setters 2022-03-22 11:36:16 +00:00
Auxilor
7dad9d7875 Fixed config setters 2022-03-22 11:24:27 +00:00
Auxilor
338b9b2d4e Fixed configs 2022-03-22 11:02:01 +00:00
Auxilor
f6d83867f3 Updated to 6.29.3 2022-03-22 10:41:52 +00:00
Auxilor
bb632ac849 Codestyle 2022-03-22 10:40:02 +00:00
Auxilor
793f946b44 Removed long-deprecated, for-removal configs 2022-03-22 10:39:20 +00:00
Auxilor
519a59cc88 Reworked configs, marked all deprecated configs for removal 2022-03-22 10:35:44 +00:00
Auxilor
79b1bff547 Recoded GUI internals 2022-03-22 09:55:10 +00:00
Auxilor
17ee1ac2ff Updated to 6.29.2 2022-03-20 15:44:06 +00:00
Auxilor
a6fa446d95 Fixed Head Database integration 2022-03-20 15:43:55 +00:00
Auxilor
2f98c0ace5 Updated to 6.29.1 2022-03-18 09:40:35 +00:00
Auxilor
60d7abcda8 Fixed oraxen integration 2022-03-18 09:40:26 +00:00
Auxilor
69a5fa81b4 Updated MythicMobs 2022-03-16 20:48:42 +00:00
Auxilor
0316e627e1 Updated to 6.29.0 2022-03-16 13:22:17 +00:00
Auxilor
5bc5b47bf8 Added Menu#refresh 2022-03-16 13:22:05 +00:00
95 changed files with 1257 additions and 1974 deletions

View File

@@ -85,21 +85,25 @@ allprojects {
}
dependencies {
compileOnly(kotlin("stdlib", version = "1.6.10"))
// Included in spigot jar, no need to move to implementation
compileOnly("org.jetbrains:annotations:23.0.0")
compileOnly("com.google.guava:guava:31.1-jre")
// Test
testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.2")
// Adventure
compileOnly("net.kyori:adventure-api:4.10.0")
compileOnly("net.kyori:adventure-text-serializer-gson:4.10.0")
compileOnly("net.kyori:adventure-text-serializer-legacy:4.10.0")
implementation("net.kyori:adventure-api:4.10.1")
implementation("net.kyori:adventure-text-serializer-gson:4.10.1") {
exclude("com.google.code.gson", "gson") // Prevent shading into the jar
}
implementation("net.kyori:adventure-text-serializer-legacy:4.10.1")
// Other
compileOnly("com.google.guava:guava:31.1-jre")
compileOnly("com.github.ben-manes.caffeine:caffeine:3.0.5")
implementation("com.github.ben-manes.caffeine:caffeine:3.0.6")
implementation("org.apache.maven:maven-artifact:3.8.4")
implementation(kotlin("stdlib", version = "1.6.10"))
}
tasks.withType<JavaCompile> {
@@ -115,10 +119,11 @@ allprojects {
exclude(group = "com.darkblade12", module = "particleeffect")
exclude(group = "com.github.cryptomorin", module = "XSeries")
exclude(group = "net.wesjd", module = "anvilgui")
exclude(group = "org.slf4j", module = "slf4j-api")
}
configurations.testImplementation {
setExtendsFrom(listOf(configurations.compileOnly.get()))
setExtendsFrom(listOf(configurations.compileOnly.get(), configurations.implementation.get()))
}
tasks {
@@ -133,6 +138,28 @@ allprojects {
shadowJar {
relocate("org.bstats", "com.willfp.eco.libs.bstats")
relocate("redempt.crunch", "com.willfp.eco.libs.crunch")
relocate("org.apache.commons.lang3", "com.willfp.eco.libs.lang3")
relocate("org.apache.maven", "com.willfp.eco.libs.maven")
relocate("org.checkerframework", "com.willfp.eco.libs.checkerframework")
relocate("org.intellij", "com.willfp.eco.libs.intellij")
relocate("org.jetbrains.annotations", "com.willfp.eco.libs.jetbrains.annotations")
//relocate("org.jetbrains.exposed", "com.willfp.eco.libs.exposed")
relocate("org.objenesis", "com.willfp.eco.libs.objenesis")
relocate("org.reflections", "com.willfp.eco.libs.reflections")
relocate("javassist", "com.willfp.eco.libs.javassist")
relocate("javax.annotation", "com.willfp.eco.libs.annotation")
relocate("com.google.errorprone", "com.willfp.eco.libs.errorprone")
relocate("com.google.j2objc", "com.willfp.eco.libs.j2objc")
relocate("com.google.thirdparty", "com.willfp.eco.libs.google.thirdparty")
relocate("com.google.protobuf", "com.willfp.eco.libs.google.protobuf") // No I don't know either
relocate("google.protobuf", "com.willfp.eco.libs.protobuf") // Still don't know
relocate("com.zaxxer.hikari", "com.willfp.eco.libs.hikari")
//relocate("com.mysql", "com.willfp.eco.libs.mysql")
/*
Kotlin and caffeine are not shaded so that they can be accessed directly by eco plugins.
Also, not relocating adventure, because it's a pain in the ass, and it doesn't *seem* to be causing loader constraint violations.
*/
}
compileJava {

View File

@@ -4,7 +4,6 @@ dependencies {
// Other
compileOnly 'org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT'
compileOnly 'org.apache.maven:maven-artifact:3.8.1'
compileOnly 'com.comphenix.protocol:ProtocolLib:4.6.1-SNAPSHOT'
compileOnly 'com.google.code.gson:gson:2.8.8'
}

View File

@@ -353,9 +353,9 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
DefaultArtifactVersion mostRecentVersion = new DefaultArtifactVersion(version);
if (!(currentVersion.compareTo(mostRecentVersion) > 0 || currentVersion.equals(mostRecentVersion))) {
this.outdated = true;
this.getLogger().warning("&c" + this.getName() + " is out of date! (Version " + this.getDescription().getVersion() + ")");
this.getLogger().warning("&cThe newest version is &f" + version);
this.getLogger().warning("&cDownload the new version!");
this.getLogger().warning(this.getName() + " is out of date! (Version " + this.getDescription().getVersion() + ")");
this.getLogger().warning("The newest version is " + version);
this.getLogger().warning("Download the new version!");
}
});
}
@@ -489,9 +489,9 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
public final void reload() {
this.getConfigHandler().updateConfigs();
this.getScheduler().cancelAll();
this.getConfigHandler().callUpdate();
this.getConfigHandler().callUpdate(); // Call twice to fix issues
this.getScheduler().cancelAll();
this.handleReload();
@@ -694,7 +694,7 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
public final FileConfiguration getConfig() {
this.getLogger().warning("Call to default config method in eco plugin!");
return Objects.requireNonNull(this.getConfigYml().getBukkitHandle());
return Objects.requireNonNull(this.getConfigYml().toBukkit());
}
/**

View File

@@ -35,7 +35,7 @@ public class Prerequisite {
*
* @deprecated Use {@link EconomyManager#hasRegistrations()} instead.
*/
@Deprecated
@Deprecated(forRemoval = true)
public static final Prerequisite HAS_VAULT = new Prerequisite(
() -> ClassUtils.exists("net.milkbowl.vault.economy.Economy"),
"Requires server to have vault"
@@ -54,7 +54,7 @@ public class Prerequisite {
*
* @deprecated eco no longer supports versions before 1.17.
*/
@Deprecated(since = "6.25.2")
@Deprecated(since = "6.25.2", forRemoval = true)
public static final Prerequisite HAS_1_17 = new Prerequisite(
() -> ProxyConstants.NMS_VERSION.contains("17") || HAS_1_18.isMet(),
"Requires server to be running 1.17+"

View File

@@ -10,6 +10,7 @@ import java.util.List;
/**
* Interface for all command implementations.
*/
@SuppressWarnings("removal")
public interface CommandBase {
/**
* Get command name.
@@ -81,7 +82,7 @@ public interface CommandBase {
* @see CommandHandler
* @deprecated Use {@link CommandBase#onExecute(CommandSender, List)} instead.
*/
@Deprecated
@Deprecated(forRemoval = true)
CommandHandler getHandler();
/**
@@ -91,7 +92,7 @@ public interface CommandBase {
* @see CommandHandler
* @deprecated Handlers have been deprecated.
*/
@Deprecated
@Deprecated(forRemoval = true)
void setHandler(@NotNull CommandHandler handler);
/**
@@ -101,7 +102,7 @@ public interface CommandBase {
* @see TabCompleteHandler
* @deprecated Use {@link CommandBase#tabComplete(CommandSender, List)} instead.
*/
@Deprecated
@Deprecated(forRemoval = true)
TabCompleteHandler getTabCompleter();
/**
@@ -111,6 +112,6 @@ public interface CommandBase {
* @see TabCompleteHandler
* @deprecated Handlers have been deprecated.
*/
@Deprecated
@Deprecated(forRemoval = true)
void setTabCompleter(@NotNull TabCompleteHandler handler);
}

View File

@@ -16,7 +16,7 @@ import java.util.List;
* update to use the new system: {@link CommandBase#onExecute(CommandSender, List)}.
*/
@FunctionalInterface
@Deprecated(since = "6.17.0")
@Deprecated(since = "6.17.0", forRemoval = true)
public interface CommandHandler {
/**
* The code to be called on execution.

View File

@@ -16,7 +16,7 @@ import java.util.List;
* update to use the new system: {@link CommandBase#tabComplete(CommandSender, List)}
*/
@FunctionalInterface
@Deprecated(since = "6.17.0")
@Deprecated(since = "6.17.0", forRemoval = true)
public interface TabCompleteHandler {
/**
* Handle Tab Completion.

View File

@@ -2,8 +2,6 @@ package com.willfp.eco.core.command.impl;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.command.CommandBase;
import com.willfp.eco.core.command.CommandHandler;
import com.willfp.eco.core.command.TabCompleteHandler;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.util.StringUtil;
@@ -23,7 +21,7 @@ import java.util.stream.Collectors;
* in order to execute the command-specific code. It's essentially an internal
* layer, hence why it's a package-private class.
*/
@SuppressWarnings({"DeprecatedIsStillUsed"})
@SuppressWarnings({"DeprecatedIsStillUsed", "removal"})
abstract class HandledCommand implements CommandBase {
/**
* The plugin.
@@ -54,14 +52,14 @@ abstract class HandledCommand implements CommandBase {
*/
@Deprecated
@Nullable
private CommandHandler handler = null;
private com.willfp.eco.core.command.CommandHandler handler = null;
/**
* The tab completion code to be executed in the command.
*/
@Deprecated
@Nullable
private TabCompleteHandler tabCompleter = null;
private com.willfp.eco.core.command.TabCompleteHandler tabCompleter = null;
/**
* All subcommands for the command.
@@ -256,27 +254,27 @@ abstract class HandledCommand implements CommandBase {
return this.subcommands;
}
@Deprecated
@Deprecated(forRemoval = true)
@Override
public @Nullable CommandHandler getHandler() {
public @Nullable com.willfp.eco.core.command.CommandHandler getHandler() {
return this.handler;
}
@Deprecated
@Deprecated(forRemoval = true)
@Override
public @Nullable TabCompleteHandler getTabCompleter() {
public @Nullable com.willfp.eco.core.command.TabCompleteHandler getTabCompleter() {
return this.tabCompleter;
}
@Deprecated
@Deprecated(forRemoval = true)
@Override
public void setHandler(@Nullable final CommandHandler handler) {
public void setHandler(@Nullable final com.willfp.eco.core.command.CommandHandler handler) {
this.handler = handler;
}
@Deprecated
@Deprecated(forRemoval = true)
@Override
public void setTabCompleter(@Nullable final TabCompleteHandler tabCompleter) {
public void setTabCompleter(@Nullable final com.willfp.eco.core.command.TabCompleteHandler tabCompleter) {
this.tabCompleter = tabCompleter;
}
}

View File

@@ -23,13 +23,31 @@ public abstract class BaseConfig extends LoadableConfigWrapper {
@NotNull final PluginLike plugin,
final boolean removeUnused,
@NotNull final ConfigType type) {
this(configName, plugin, removeUnused, type, true);
}
/**
* Create new Base Config.
*
* @param plugin The plugin or extension.
* @param configName The config name (excluding extension).
* @param removeUnused If unused sections should be removed.
* @param type The config type.
* @param requiresChangeToSave If changes must be applied to save the config.
*/
protected BaseConfig(@NotNull final String configName,
@NotNull final PluginLike plugin,
final boolean removeUnused,
@NotNull final ConfigType type,
final boolean requiresChangeToSave) {
super(Eco.getHandler().getConfigFactory().createUpdatableConfig(
configName,
plugin,
"",
plugin.getClass(),
removeUnused,
type
type,
requiresChangeToSave
));
}
}

View File

@@ -0,0 +1,29 @@
package com.willfp.eco.core.config;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Builder for configs to create them programmatically.
*/
public class BuildableConfig extends TransientConfig {
/**
* Create a new empty config builder.
*/
public BuildableConfig() {
super();
}
/**
* Add to the config builder.
*
* @param path The path.
* @param object The object.
* @return The builder.
*/
public BuildableConfig add(@NotNull final String path,
@Nullable final Object object) {
set(path, object);
return this;
}
}

View File

@@ -1,5 +1,7 @@
package com.willfp.eco.core.config;
import org.jetbrains.annotations.NotNull;
/**
* Config types, classified by file extension.
*/
@@ -7,10 +9,28 @@ public enum ConfigType {
/**
* .json config.
*/
JSON,
JSON("json"),
/**
* .yml config.
*/
YAML
YAML("yml");
/**
* The file extension.
*/
private final String extension;
ConfigType(@NotNull final String extension) {
this.extension = extension;
}
/**
* Get the file extension.
*
* @return The extension.
*/
public String getExtension() {
return extension;
}
}

View File

@@ -38,6 +38,7 @@ public abstract class ExtendableConfig extends LoadableConfigWrapper {
source,
removeUnused,
type,
true,
updateBlacklist
));
}

View File

@@ -26,7 +26,8 @@ public abstract class StaticBaseConfig extends LoadableConfigWrapper {
plugin,
"",
plugin.getClass(),
type
type,
true
));
}
}

View File

@@ -3,12 +3,17 @@ package com.willfp.eco.core.config;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.config.interfaces.Config;
import com.willfp.eco.core.config.wrapper.ConfigWrapper;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;
/**
@@ -18,10 +23,19 @@ import java.util.Map;
*/
public class TransientConfig extends ConfigWrapper<Config> {
/**
* @param config The ConfigurationSection handle.
*/
public TransientConfig(@NotNull final ConfigurationSection config) {
super(Eco.getHandler().getConfigFactory().createConfig(config));
}
/**
* Exists for backwards compatibility, YamlConfigurations are ConfigurationSections.
*
* @param config The YamlConfiguration handle.
*/
public TransientConfig(@NotNull final YamlConfiguration config) {
super(Eco.getHandler().getConfigFactory().createConfig(config));
this((ConfigurationSection) config);
}
/**
@@ -33,20 +47,50 @@ public class TransientConfig extends ConfigWrapper<Config> {
)) : new TransientConfig());
}
/**
* @param file The File.
* @deprecated Specify the config type to prevent bugs.
*/
@Deprecated(since = "6.30.0", forRemoval = true)
public TransientConfig(@Nullable final File file) {
this(file, ConfigType.YAML);
}
/**
* @param file The file.
* @param type The config type to try read from.
*/
public TransientConfig(@Nullable final File file,
@NotNull final ConfigType type) {
super(file != null ? Eco.getHandler().getConfigFactory().createConfig(readFile(file), type)
: new TransientConfig());
}
/**
* Create a new empty transient config.
*
* @param values The values.
*/
public TransientConfig(@NotNull final Map<String, Object> values) {
super(Eco.getHandler().getConfigFactory().createConfig(values));
super(Eco.getHandler().getConfigFactory().createConfig(values, ConfigType.YAML));
}
/**
* Create a new empty transient config.
*
* @param values The values.
* @param type The type.
*/
public TransientConfig(@NotNull final Map<String, Object> values,
@NotNull final ConfigType type) {
super(Eco.getHandler().getConfigFactory().createConfig(values, type));
}
/**
* Create a new empty transient config.
*/
public TransientConfig() {
super(Eco.getHandler().getConfigFactory().createConfig("", ConfigType.YAML));
this(new HashMap<>(), ConfigType.JSON);
}
/**
@@ -57,4 +101,22 @@ public class TransientConfig extends ConfigWrapper<Config> {
@NotNull final ConfigType type) {
super(Eco.getHandler().getConfigFactory().createConfig(contents, type));
}
/**
* Read a file to a string.
*
* @param file The file.
* @return The string.
*/
private static String readFile(@Nullable final File file) {
if (file == null) {
return "";
}
try {
return Files.readString(file.toPath());
} catch (IOException e) {
return "";
}
}
}

View File

@@ -1,19 +1,25 @@
package com.willfp.eco.core.config.interfaces;
import com.willfp.eco.core.config.BuildableConfig;
import com.willfp.eco.core.config.ConfigType;
import com.willfp.eco.core.config.TransientConfig;
import com.willfp.eco.core.placeholder.PlaceholderInjectable;
import com.willfp.eco.core.placeholder.StaticPlaceholder;
import com.willfp.eco.util.NumberUtils;
import com.willfp.eco.util.StringUtils;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
/**
* All configs implement this interface.
@@ -24,8 +30,13 @@ import java.util.Objects;
public interface Config extends Cloneable, PlaceholderInjectable {
/**
* Clears cache.
* <p>
* Configs no longer have caches as they have in previous versions.
*/
void clearCache();
@Deprecated(since = "6.31.1", forRemoval = true)
default void clearCache() {
// Do nothing.
}
/**
* Convert the config into readable text.
@@ -51,6 +62,19 @@ public interface Config extends Cloneable, PlaceholderInjectable {
@NotNull
List<String> getKeys(boolean deep);
/**
* Recurse config keys.
*
* @param found The found keys.
* @param root The root.
* @return The keys.
*/
@NotNull
default List<String> recurseKeys(@NotNull Set<String> found,
@NotNull String root) {
return new ArrayList<>();
}
/**
* Get an object from config.
* Default implementations call {@link org.bukkit.configuration.file.YamlConfiguration#get(String)}.
@@ -241,35 +265,6 @@ public interface Config extends Cloneable, PlaceholderInjectable {
return getString(path, false, StringUtils.FormatOption.WITHOUT_PLACEHOLDERS);
}
/**
* Get a string from config.
*
* @param path The key to fetch the value from.
* @param format If the string should be formatted.
* @return The found value, or an empty string if not found.
* @deprecated Since 6.18.0, {@link Config#getString(String)} is not formatted by default.
*/
@Deprecated(since = "6.18.0")
default String getString(@NotNull String path,
boolean format) {
return this.getString(path, format, StringUtils.FormatOption.WITH_PLACEHOLDERS);
}
/**
* Get a string from config.
*
* @param path The key to fetch the value from.
* @param option The format option.
* @return The found value, or an empty string if not found.
* @deprecated Use {@link Config#getFormattedString(String, StringUtils.FormatOption)} instead.
*/
@NotNull
@Deprecated
default String getString(@NotNull String path,
@NotNull final StringUtils.FormatOption option) {
return this.getString(path, true, option);
}
/**
* Get a string from config.
*
@@ -322,36 +317,6 @@ public interface Config extends Cloneable, PlaceholderInjectable {
return getStringOrNull(path, false, StringUtils.FormatOption.WITH_PLACEHOLDERS);
}
/**
* Get a string from config.
*
* @param path The key to fetch the value from.
* @param format If the string should be formatted.
* @return The found value, or null if not found.
* @deprecated Since 6.18.0, {@link Config#getString(String)} is not formatted by default.
*/
@Nullable
@Deprecated(since = "6.18.0")
default String getStringOrNull(@NotNull String path,
boolean format) {
return this.getStringOrNull(path, format, StringUtils.FormatOption.WITH_PLACEHOLDERS);
}
/**
* Get a string from config.
*
* @param path The key to fetch the value from.
* @param option The format option.
* @return The found value, or null if not found.
* @deprecated Use {@link Config#getFormattedString(String, StringUtils.FormatOption)} instead.
*/
@Nullable
@Deprecated
default String getStringOrNull(@NotNull String path,
@NotNull StringUtils.FormatOption option) {
return this.getStringOrNull(path, true, option);
}
/**
* Get a string from config.
*
@@ -406,36 +371,6 @@ public interface Config extends Cloneable, PlaceholderInjectable {
return getStrings(path, false, StringUtils.FormatOption.WITH_PLACEHOLDERS);
}
/**
* Get a list of strings from config.
*
* @param path The key to fetch the value from.
* @param format If the strings should be formatted.
* @return The found value, or a blank {@link java.util.ArrayList} if not found.
* @deprecated Since 6.18.0, {@link Config#getString(String)} is not formatted by default.
*/
@NotNull
@Deprecated(since = "6.18.0")
default List<String> getStrings(@NotNull String path,
boolean format) {
return this.getStrings(path, format, StringUtils.FormatOption.WITH_PLACEHOLDERS);
}
/**
* Get a list of strings from config.
*
* @param path The key to fetch the value from.
* @param option The format option.
* @return The found value, or a blank {@link java.util.ArrayList} if not found.
* @deprecated Use {@link Config#getFormattedStrings(String, StringUtils.FormatOption)} instead.
*/
@NotNull
@Deprecated
default List<String> getStrings(@NotNull String path,
@NotNull StringUtils.FormatOption option) {
return getStrings(path, false, option);
}
/**
* Get a list of strings from config.
*
@@ -494,36 +429,6 @@ public interface Config extends Cloneable, PlaceholderInjectable {
return getStringsOrNull(path, false, StringUtils.FormatOption.WITH_PLACEHOLDERS);
}
/**
* Get a list of strings from config.
*
* @param path The key to fetch the value from.
* @param format If the strings should be formatted.
* @return The found value, or null if not found.
* @deprecated Since 6.18.0, {@link Config#getString(String)} is not formatted by default.
*/
@Nullable
@Deprecated(since = "6.18.0")
default List<String> getStringsOrNull(@NotNull String path,
boolean format) {
return getStringsOrNull(path, format, StringUtils.FormatOption.WITH_PLACEHOLDERS);
}
/**
* Get a list of strings from config.
*
* @param path The key to fetch the value from.
* @param option The format option.
* @return The found value, or null if not found.
* @deprecated Use {@link Config#getFormattedStringsOrNull(String, StringUtils.FormatOption)} instead.
*/
@Nullable
@Deprecated
default List<String> getStringsOrNull(@NotNull String path,
@NotNull StringUtils.FormatOption option) {
return getStringsOrNull(path, false, option);
}
/**
* Get a list of strings from config.
*
@@ -647,4 +552,33 @@ public interface Config extends Cloneable, PlaceholderInjectable {
default void clearInjectedPlaceholders() {
// Do nothing.
}
/**
* Convert the config to a map of values.
*
* @return The values.
*/
default Map<String, Object> toMap() {
return new HashMap<>();
}
/**
* Convert the config to a map of values.
*
* @return The values.
*/
default ConfigurationSection toBukkit() {
YamlConfiguration empty = new YamlConfiguration();
empty.createSection("temp", this.toMap());
return empty.getConfigurationSection("temp");
}
/**
* Create a new config builder.
*
* @return The builder.
*/
static BuildableConfig builder() {
return new BuildableConfig();
}
}

View File

@@ -1,63 +0,0 @@
package com.willfp.eco.core.config.interfaces;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* JSON config.
*
* @deprecated JSON and yml have full parity, use configs without a prefix instead,
* eg {@link com.willfp.eco.core.config.TransientConfig}, {@link com.willfp.eco.core.config.BaseConfig}.
* These configs will be removed eventually.
*/
@Deprecated(since = "6.17.0")
@SuppressWarnings("DeprecatedIsStillUsed")
public interface JSONConfig extends Config {
/**
* Get a list of subsections from config.
*
* @param path The key to fetch the value from.
* @return The found value, or a blank {@link java.util.ArrayList} if not found.
*/
@NotNull
default List<JSONConfig> getSubsections(@NotNull String path) {
return Objects.requireNonNullElse(getSubsectionsOrNull(path), new ArrayList<>());
}
/**
* Get a list of subsections from config.
*
* @param path The key to fetch the value from.
* @return The found value, or null if not found.
*/
@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

@@ -1,7 +1,7 @@
package com.willfp.eco.core.config.interfaces;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
@@ -47,14 +47,21 @@ public interface LoadableConfig extends Config {
/**
* Get bukkit {@link YamlConfiguration}.
* <p>
* This method is not recommended unless absolutely required as it
* only returns true if the type of config is {@link com.willfp.eco.core.config.ConfigType#YAML},
* and if the handle is an {@link YamlConfiguration} specifically. This depends on the internals
* and the implementation, and so may cause problems - it exists mostly for parity with
* {@link JavaPlugin#getConfig()}.
* This used to represent the underlying config, but since 6.30.0 configs use
* their own implementations internally, without relying on bukkit.
*
* @return The config, or null if config is not yaml-based.
* @deprecated Use toBukkit() instead.
*/
@Nullable
YamlConfiguration getBukkitHandle();
@Deprecated(since = "6.30.0", forRemoval = true)
default YamlConfiguration getBukkitHandle() {
return this.toBukkit();
}
/**
* Convert the config to a bukkit {@link YamlConfiguration}.
*/
@NotNull
YamlConfiguration toBukkit();
}

View File

@@ -1,21 +0,0 @@
package com.willfp.eco.core.config.interfaces;
import org.bukkit.configuration.file.YamlConfiguration;
/**
* Interface for configs that wrap an {@link YamlConfiguration}.
*
* @deprecated JSON and yml have full parity, use configs without a prefix instead,
* eg {@link com.willfp.eco.core.config.TransientConfig}, {@link com.willfp.eco.core.config.BaseConfig}.
* These configs will be removed eventually.
*/
@Deprecated(since = "6.17.0")
@SuppressWarnings("DeprecatedIsStillUsed")
public interface WrappedYamlConfiguration {
/**
* Get the ConfigurationSection handle.
*
* @return The handle.
*/
YamlConfiguration getBukkitHandle();
}

View File

@@ -1,90 +0,0 @@
package com.willfp.eco.core.config.json;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginLike;
import com.willfp.eco.core.config.ConfigType;
import com.willfp.eco.core.config.interfaces.JSONConfig;
import com.willfp.eco.core.config.json.wrapper.LoadableJSONConfigWrapper;
import org.jetbrains.annotations.NotNull;
/**
* Config implementation for configs present in the plugin's base directory (eg config.json).
* <p>
* Automatically updates.
*
* @deprecated JSON and yml have full parity, use configs without a prefix instead,
* eg {@link com.willfp.eco.core.config.TransientConfig}, {@link com.willfp.eco.core.config.BaseConfig}.
* These configs will be removed eventually.
*/
@Deprecated(since = "6.17.0")
public abstract class JSONBaseConfig extends LoadableJSONConfigWrapper {
/**
* @param configName The name of the config
* @param removeUnused Whether keys not present in the default config should be removed on update.
* @param plugin The plugin.
* @param updateBlacklist Substring of keys to not add/remove keys for.
*/
protected JSONBaseConfig(@NotNull final String configName,
final boolean removeUnused,
@NotNull final PluginLike plugin,
@NotNull final String... updateBlacklist) {
super(
(JSONConfig)
Eco.getHandler().getConfigFactory().createUpdatableConfig(
configName,
plugin,
"",
plugin.getClass(),
removeUnused,
ConfigType.JSON,
updateBlacklist
)
);
}
/**
* @param configName The name of the config
* @param removeUnused Whether keys not present in the default config should be removed on update.
* @param plugin The plugin.
*/
protected JSONBaseConfig(@NotNull final String configName,
final boolean removeUnused,
@NotNull final PluginLike plugin) {
super(
(JSONConfig)
Eco.getHandler().getConfigFactory().createUpdatableConfig(
configName,
plugin,
"",
plugin.getClass(),
removeUnused,
ConfigType.JSON
)
);
}
/**
* @param configName The name of the config
* @param removeUnused Whether keys not present in the default config should be removed on update.
* @param plugin The plugin.
* @param updateBlacklist Substring of keys to not add/remove keys for.
*/
protected JSONBaseConfig(@NotNull final String configName,
final boolean removeUnused,
@NotNull final EcoPlugin plugin,
@NotNull final String... updateBlacklist) {
this(configName, removeUnused, (PluginLike) plugin, updateBlacklist);
}
/**
* @param configName The name of the config
* @param removeUnused Whether keys not present in the default config should be removed on update.
* @param plugin The plugin.
*/
protected JSONBaseConfig(@NotNull final String configName,
final boolean removeUnused,
@NotNull final EcoPlugin plugin) {
this(configName, removeUnused, (PluginLike) plugin);
}
}

View File

@@ -1,70 +0,0 @@
package com.willfp.eco.core.config.json;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginLike;
import com.willfp.eco.core.config.ConfigType;
import com.willfp.eco.core.config.interfaces.JSONConfig;
import com.willfp.eco.core.config.json.wrapper.LoadableJSONConfigWrapper;
import org.jetbrains.annotations.NotNull;
/**
* Config implementation for configs present in one of two places:
* <ul>
* <li>Plugin base directory (eg config.yml, lang.yml)</li>
* <li>Other extension's configs</li>
* </ul>
* <p>
* Automatically updates.
*
* @deprecated JSON and yml have full parity, use configs without a prefix instead,
* eg {@link com.willfp.eco.core.config.TransientConfig}, {@link com.willfp.eco.core.config.BaseConfig}.
* These configs will be removed eventually.
*/
@Deprecated(since = "6.17.0")
public abstract class JSONExtendableConfig extends LoadableJSONConfigWrapper {
/**
* @param configName The name of the config
* @param removeUnused Whether keys not present in the default config should be removed on update.
* @param plugin The plugin.
* @param updateBlacklist Substring of keys to not add/remove keys for.
* @param subDirectoryPath The subdirectory path.
* @param source The class that owns the resource.
*/
protected JSONExtendableConfig(@NotNull final String configName,
final boolean removeUnused,
@NotNull final PluginLike plugin,
@NotNull final Class<?> source,
@NotNull final String subDirectoryPath,
@NotNull final String... updateBlacklist) {
super(
(JSONConfig)
Eco.getHandler().getConfigFactory().createUpdatableConfig(
configName,
plugin,
subDirectoryPath,
source,
removeUnused,
ConfigType.JSON,
updateBlacklist
)
);
}
/**
* @param configName The name of the config
* @param removeUnused Whether keys not present in the default config should be removed on update.
* @param plugin The plugin.
* @param updateBlacklist Substring of keys to not add/remove keys for.
* @param subDirectoryPath The subdirectory path.
* @param source The class that owns the resource.
*/
protected JSONExtendableConfig(@NotNull final String configName,
final boolean removeUnused,
@NotNull final EcoPlugin plugin,
@NotNull final Class<?> source,
@NotNull final String subDirectoryPath,
@NotNull final String... updateBlacklist) {
this(configName, removeUnused, (PluginLike) plugin, source, subDirectoryPath, updateBlacklist);
}
}

View File

@@ -1,45 +0,0 @@
package com.willfp.eco.core.config.json;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginLike;
import com.willfp.eco.core.config.ConfigType;
import com.willfp.eco.core.config.interfaces.JSONConfig;
import com.willfp.eco.core.config.json.wrapper.LoadableJSONConfigWrapper;
import org.jetbrains.annotations.NotNull;
/**
* Non-updatable JSON config that exists within a plugin jar.
*
* @deprecated JSON and yml have full parity, use configs without a prefix instead,
* eg {@link com.willfp.eco.core.config.TransientConfig}, {@link com.willfp.eco.core.config.BaseConfig}.
* These configs will be removed eventually.
*/
@Deprecated(since = "6.17.0")
public abstract class JSONStaticBaseConfig extends LoadableJSONConfigWrapper {
/**
* Config implementation for configs present in the plugin's base directory (eg config.json, lang.json).
* <p>
* Does not automatically update.
*
* @param configName The name of the config
* @param plugin The plugin.
*/
protected JSONStaticBaseConfig(@NotNull final String configName,
@NotNull final PluginLike plugin) {
super((JSONConfig) Eco.getHandler().getConfigFactory().createLoadableConfig(configName, plugin, "", plugin.getClass(), ConfigType.JSON));
}
/**
* Config implementation for configs present in the plugin's base directory (eg config.json, lang.json).
* <p>
* Does not automatically update.
*
* @param configName The name of the config
* @param plugin The plugin.
*/
protected JSONStaticBaseConfig(@NotNull final String configName,
@NotNull final EcoPlugin plugin) {
this(configName, (PluginLike) plugin);
}
}

View File

@@ -1,37 +0,0 @@
package com.willfp.eco.core.config.json;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.config.interfaces.JSONConfig;
import com.willfp.eco.core.config.json.wrapper.JSONConfigWrapper;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
/**
* Raw JSON config with a map of values at its core.
*
* @deprecated JSON and yml have full parity, use configs without a prefix instead,
* eg {@link com.willfp.eco.core.config.TransientConfig}, {@link com.willfp.eco.core.config.BaseConfig}.
* These configs will be removed eventually.
*/
@Deprecated(since = "6.17.0")
public class JSONTransientConfig extends JSONConfigWrapper {
/**
* Config implementation for passing maps.
* <p>
* Does not automatically update.
*
* @param values The map of values.
*/
public JSONTransientConfig(@NotNull final Map<String, Object> values) {
super((JSONConfig) Eco.getHandler().getConfigFactory().createConfig(values));
}
/**
* Empty JSON config.
*/
public JSONTransientConfig() {
super((JSONConfig) Eco.getHandler().getConfigFactory().createConfig(new HashMap<>()));
}
}

View File

@@ -1,53 +0,0 @@
package com.willfp.eco.core.config.json.wrapper;
import com.willfp.eco.core.config.interfaces.JSONConfig;
import com.willfp.eco.core.config.wrapper.ConfigWrapper;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
/**
* Wrapper to handle the backend JSON config implementations.
*
* @deprecated JSON and yml have full parity, use configs without a prefix instead,
* eg {@link com.willfp.eco.core.config.TransientConfig}, {@link com.willfp.eco.core.config.BaseConfig}.
* These configs will be removed eventually.
*/
@Deprecated(since = "6.17.0")
public abstract class JSONConfigWrapper extends ConfigWrapper<JSONConfig> implements JSONConfig {
/**
* Create a config wrapper.
*
* @param handle The handle.
*/
protected JSONConfigWrapper(@NotNull final JSONConfig handle) {
super(handle);
}
@Override
public @NotNull List<JSONConfig> getSubsections(@NotNull final String path) {
return this.getHandle().getSubsections(path);
}
@Override
public @Nullable List<JSONConfig> getSubsectionsOrNull(@NotNull final String path) {
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

@@ -1,63 +0,0 @@
package com.willfp.eco.core.config.json.wrapper;
import com.willfp.eco.core.config.interfaces.JSONConfig;
import com.willfp.eco.core.config.interfaces.LoadableConfig;
import org.apache.commons.lang.Validate;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
/**
* Wrapper to handle the backend loadable JSON config implementations.
*
* @deprecated JSON and yml have full parity, use configs without a prefix instead,
* eg {@link com.willfp.eco.core.config.TransientConfig}, {@link com.willfp.eco.core.config.BaseConfig}.
* These configs will be removed eventually.
*/
@Deprecated(since = "6.17.0")
public abstract class LoadableJSONConfigWrapper extends JSONConfigWrapper implements LoadableConfig {
/**
* Create a config wrapper.
*
* @param handle The handle.
*/
protected LoadableJSONConfigWrapper(@NotNull final JSONConfig handle) {
super(handle);
Validate.isTrue(handle instanceof LoadableConfig, "Wrapped config must be loadable!");
}
@Override
public void createFile() {
((LoadableConfig) this.getHandle()).createFile();
}
@Override
public String getResourcePath() {
return ((LoadableConfig) this.getHandle()).getResourcePath();
}
@Override
public void save() throws IOException {
((LoadableConfig) this.getHandle()).save();
}
@Override
public File getConfigFile() {
return ((LoadableConfig) this.getHandle()).getConfigFile();
}
@Override
public String getName() {
return ((LoadableConfig) this.getHandle()).getName();
}
@Override
public @Nullable YamlConfiguration getBukkitHandle() {
return null;
}
}

View File

@@ -1,5 +1,6 @@
package com.willfp.eco.core.config.updating;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -29,7 +30,8 @@ import java.lang.annotation.Target;
* }</pre>
* <p>
* If using kotlin, you have to annotate the method with {@code @JvmStatic}
* in order to prevent null pointer exceptions.
* in order to prevent null pointer exceptions - this also means that you cannot
* have config updater methods in companion objects.
* <p>
* Config update methods in all classes in a plugin jar will be called
* on reload.
@@ -39,5 +41,6 @@ import java.lang.annotation.Target;
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface ConfigUpdater {
}

View File

@@ -5,7 +5,7 @@ import com.willfp.eco.core.PluginLike;
import com.willfp.eco.core.config.ConfigType;
import com.willfp.eco.core.config.interfaces.Config;
import com.willfp.eco.core.config.interfaces.LoadableConfig;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
@@ -20,13 +20,14 @@ public interface ConfigFactory {
/**
* Updatable config.
*
* @param configName The name of the config
* @param plugin The plugin.
* @param subDirectoryPath The subdirectory path.
* @param source The class that owns the resource.
* @param removeUnused Whether keys not present in the default config should be removed on update.
* @param type The config type.
* @param updateBlacklist Substring of keys to not add/remove keys for.
* @param configName The name of the config
* @param plugin The plugin.
* @param subDirectoryPath The subdirectory path.
* @param source The class that owns the resource.
* @param removeUnused Whether keys not present in the default config should be removed on update.
* @param type The config type.
* @param updateBlacklist Substring of keys to not add/remove keys for.
* @param requiresChangesToSave If the config must be changed in order to save the config.
* @return The config implementation.
*/
LoadableConfig createUpdatableConfig(@NotNull String configName,
@@ -35,23 +36,26 @@ public interface ConfigFactory {
@NotNull Class<?> source,
boolean removeUnused,
@NotNull ConfigType type,
boolean requiresChangesToSave,
@NotNull String... updateBlacklist);
/**
* Loadable config.
*
* @param configName The name of the config
* @param plugin The plugin.
* @param subDirectoryPath The subdirectory path.
* @param source The class that owns the resource.
* @param type The config type.
* @param configName The name of the config
* @param plugin The plugin.
* @param subDirectoryPath The subdirectory path.
* @param source The class that owns the resource.
* @param type The config type.
* @param requiresChangesToSave If the config must be changed in order to save the config.
* @return The config implementation.
*/
LoadableConfig createLoadableConfig(@NotNull String configName,
@NotNull PluginLike plugin,
@NotNull String subDirectoryPath,
@NotNull Class<?> source,
@NotNull ConfigType type);
@NotNull ConfigType type,
boolean requiresChangesToSave);
/**
* Create config.
@@ -59,15 +63,17 @@ public interface ConfigFactory {
* @param config The handle.
* @return The config implementation.
*/
Config createConfig(@NotNull YamlConfiguration config);
Config createConfig(@NotNull ConfigurationSection config);
/**
* Create config.
*
* @param values The values.
* @param type The config type.
* @return The config implementation.
*/
Config createConfig(@NotNull Map<String, Object> values);
Config createConfig(@NotNull Map<String, Object> values,
@NotNull ConfigType type);
/**
* Create config.

View File

@@ -8,6 +8,8 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Configs from eco have an internal implementation,
@@ -17,7 +19,7 @@ import java.util.List;
*
* @param <T> The type of the handle.
*/
@SuppressWarnings("MethodDoesntCallSuperMethod")
@SuppressWarnings({"MethodDoesntCallSuperMethod", "removal"})
public abstract class ConfigWrapper<T extends Config> implements Config {
/**
* Configs from eco have an internal implementation,
@@ -41,6 +43,7 @@ public abstract class ConfigWrapper<T extends Config> implements Config {
}
@Override
@Deprecated(since = "6.31.1", forRemoval = true)
public void clearCache() {
handle.clearCache();
}
@@ -60,6 +63,12 @@ public abstract class ConfigWrapper<T extends Config> implements Config {
return handle.getKeys(deep);
}
@Override
public @NotNull List<String> recurseKeys(@NotNull final Set<String> found,
@NotNull final String root) {
return handle.recurseKeys(found, root);
}
@Override
public @Nullable Object get(@NotNull final String path) {
return handle.get(path);
@@ -155,6 +164,11 @@ public abstract class ConfigWrapper<T extends Config> implements Config {
handle.clearInjectedPlaceholders();
}
@Override
public Map<String, Object> toMap() {
return this.handle.toMap();
}
/**
* Get the handle.
*

View File

@@ -3,7 +3,6 @@ package com.willfp.eco.core.config.wrapper;
import com.willfp.eco.core.config.interfaces.LoadableConfig;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
@@ -47,7 +46,7 @@ public abstract class LoadableConfigWrapper extends ConfigWrapper<LoadableConfig
}
@Override
public @Nullable YamlConfiguration getBukkitHandle() {
return this.getHandle().getBukkitHandle();
public @NotNull YamlConfiguration toBukkit() {
return this.getHandle().toBukkit();
}
}

View File

@@ -1,87 +0,0 @@
package com.willfp.eco.core.config.yaml;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginLike;
import com.willfp.eco.core.config.ConfigType;
import com.willfp.eco.core.config.yaml.wrapper.LoadableYamlConfigWrapper;
import org.jetbrains.annotations.NotNull;
/**
* Config implementation for configs present in the plugin's base directory (eg config.yml, lang.yml).
* <p>
* Automatically updates.
*
* @deprecated JSON and yml have full parity, use configs without a prefix instead,
* eg {@link com.willfp.eco.core.config.TransientConfig}, {@link com.willfp.eco.core.config.BaseConfig}.
* These configs will be removed eventually.
*/
@Deprecated(since = "6.17.0")
public abstract class YamlBaseConfig extends LoadableYamlConfigWrapper {
/**
* @param configName The name of the config
* @param removeUnused Whether keys not present in the default config should be removed on update.
* @param plugin The plugin.
* @param updateBlacklist Substring of keys to not add/remove keys for.
*/
protected YamlBaseConfig(@NotNull final String configName,
final boolean removeUnused,
@NotNull final PluginLike plugin,
@NotNull final String... updateBlacklist) {
super(
Eco.getHandler().getConfigFactory().createUpdatableConfig(
configName,
plugin,
"",
plugin.getClass(),
removeUnused,
ConfigType.YAML,
updateBlacklist
)
);
}
/**
* @param configName The name of the config
* @param removeUnused Whether keys not present in the default config should be removed on update.
* @param plugin The plugin.
*/
protected YamlBaseConfig(@NotNull final String configName,
final boolean removeUnused,
@NotNull final PluginLike plugin) {
super(
Eco.getHandler().getConfigFactory().createUpdatableConfig(
configName,
plugin,
"",
plugin.getClass(),
removeUnused,
ConfigType.YAML
)
);
}
/**
* @param configName The name of the config
* @param removeUnused Whether keys not present in the default config should be removed on update.
* @param plugin The plugin.
* @param updateBlacklist Substring of keys to not add/remove keys for.
*/
protected YamlBaseConfig(@NotNull final String configName,
final boolean removeUnused,
@NotNull final EcoPlugin plugin,
@NotNull final String... updateBlacklist) {
this(configName, removeUnused, (PluginLike) plugin, updateBlacklist);
}
/**
* @param configName The name of the config
* @param removeUnused Whether keys not present in the default config should be removed on update.
* @param plugin The plugin.
*/
protected YamlBaseConfig(@NotNull final String configName,
final boolean removeUnused,
@NotNull final EcoPlugin plugin) {
this(configName, removeUnused, (PluginLike) plugin);
}
}

View File

@@ -1,68 +0,0 @@
package com.willfp.eco.core.config.yaml;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginLike;
import com.willfp.eco.core.config.ConfigType;
import com.willfp.eco.core.config.yaml.wrapper.LoadableYamlConfigWrapper;
import org.jetbrains.annotations.NotNull;
/**
* Config implementation for configs present in one of two places:
* <ul>
* <li>Plugin base directory (eg config.yml, lang.yml)</li>
* <li>Other extension's configs</li>
* </ul>
* <p>
* Automatically updates.
*
* @deprecated JSON and yml have full parity, use configs without a prefix instead,
* eg {@link com.willfp.eco.core.config.TransientConfig}, {@link com.willfp.eco.core.config.BaseConfig}.
* These configs will be removed eventually.
*/
@Deprecated(since = "6.17.0")
public abstract class YamlExtendableConfig extends LoadableYamlConfigWrapper {
/**
* @param configName The name of the config
* @param removeUnused Whether keys not present in the default config should be removed on update.
* @param plugin The plugin.
* @param updateBlacklist Substring of keys to not add/remove keys for.
* @param subDirectoryPath The subdirectory path.
* @param source The class that owns the resource.
*/
protected YamlExtendableConfig(@NotNull final String configName,
final boolean removeUnused,
@NotNull final PluginLike plugin,
@NotNull final Class<?> source,
@NotNull final String subDirectoryPath,
@NotNull final String... updateBlacklist) {
super(
Eco.getHandler().getConfigFactory().createUpdatableConfig(
configName,
plugin,
subDirectoryPath,
source,
removeUnused,
ConfigType.YAML,
updateBlacklist
)
);
}
/**
* @param configName The name of the config
* @param removeUnused Whether keys not present in the default config should be removed on update.
* @param plugin The plugin.
* @param updateBlacklist Substring of keys to not add/remove keys for.
* @param subDirectoryPath The subdirectory path.
* @param source The class that owns the resource.
*/
protected YamlExtendableConfig(@NotNull final String configName,
final boolean removeUnused,
@NotNull final EcoPlugin plugin,
@NotNull final Class<?> source,
@NotNull final String subDirectoryPath,
@NotNull final String... updateBlacklist) {
this(configName, removeUnused, (PluginLike) plugin, source, subDirectoryPath, updateBlacklist);
}
}

View File

@@ -1,44 +0,0 @@
package com.willfp.eco.core.config.yaml;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginLike;
import com.willfp.eco.core.config.ConfigType;
import com.willfp.eco.core.config.yaml.wrapper.LoadableYamlConfigWrapper;
import org.jetbrains.annotations.NotNull;
/**
* Non-updatable yaml config that exists within a plugin jar.
*
* @deprecated JSON and yml have full parity, use configs without a prefix instead,
* eg {@link com.willfp.eco.core.config.TransientConfig}, {@link com.willfp.eco.core.config.BaseConfig}.
* These configs will be removed eventually.
*/
@Deprecated(since = "6.17.0")
public abstract class YamlStaticBaseConfig extends LoadableYamlConfigWrapper {
/**
* Config implementation for configs present in the plugin's base directory (eg config.yml, lang.yml).
* <p>
* Does not automatically update.
*
* @param configName The name of the config
* @param plugin The plugin.
*/
protected YamlStaticBaseConfig(@NotNull final String configName,
@NotNull final PluginLike plugin) {
super(Eco.getHandler().getConfigFactory().createLoadableConfig(configName, plugin, "", plugin.getClass(), ConfigType.YAML));
}
/**
* Config implementation for configs present in the plugin's base directory (eg config.yml, lang.yml).
* <p>
* Does not automatically update.
*
* @param configName The name of the config
* @param plugin The plugin.
*/
protected YamlStaticBaseConfig(@NotNull final String configName,
@NotNull final EcoPlugin plugin) {
this(configName, (PluginLike) plugin);
}
}

View File

@@ -1,42 +0,0 @@
package com.willfp.eco.core.config.yaml;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.config.ConfigType;
import com.willfp.eco.core.config.yaml.wrapper.YamlConfigWrapper;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import java.io.StringReader;
/**
* Config implementation for passing YamlConfigurations.
* <p>
* Does not automatically update.
*
* @deprecated JSON and yml have full parity, use configs without a prefix instead,
* eg {@link com.willfp.eco.core.config.TransientConfig}, {@link com.willfp.eco.core.config.BaseConfig}.
* These configs will be removed eventually.
*/
@Deprecated(since = "6.17.0")
public class YamlTransientConfig extends YamlConfigWrapper {
/**
* @param config The YamlConfiguration handle.
*/
public YamlTransientConfig(@NotNull final YamlConfiguration config) {
super(Eco.getHandler().getConfigFactory().createConfig(config));
}
/**
* @param contents The contents of the config.
*/
public YamlTransientConfig(@NotNull final String contents) {
super(Eco.getHandler().getConfigFactory().createConfig(contents, ConfigType.YAML));
}
/**
* Create a new empty transient config.
*/
public YamlTransientConfig() {
super(Eco.getHandler().getConfigFactory().createConfig(YamlConfiguration.loadConfiguration(new StringReader(""))));
}
}

View File

@@ -1,63 +0,0 @@
package com.willfp.eco.core.config.yaml.wrapper;
import com.willfp.eco.core.config.interfaces.Config;
import com.willfp.eco.core.config.interfaces.LoadableConfig;
import org.apache.commons.lang.Validate;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
/**
* Wrapper to handle the backend loadable yaml config implementations.
*
* @deprecated JSON and yml have full parity, use configs without a prefix instead,
* eg {@link com.willfp.eco.core.config.TransientConfig}, {@link com.willfp.eco.core.config.BaseConfig}.
* These configs will be removed eventually.
*/
@Deprecated(since = "6.17.0")
public abstract class LoadableYamlConfigWrapper extends YamlConfigWrapper implements LoadableConfig {
/**
* Create a config wrapper.
*
* @param handle The handle.
*/
protected LoadableYamlConfigWrapper(@NotNull final Config handle) {
super(handle);
Validate.isTrue(handle instanceof LoadableConfig, "Wrapped config must be loadable!");
}
@Override
public void createFile() {
((LoadableConfig) this.getHandle()).createFile();
}
@Override
public String getResourcePath() {
return ((LoadableConfig) this.getHandle()).getResourcePath();
}
@Override
public void save() throws IOException {
((LoadableConfig) this.getHandle()).save();
}
@Override
public File getConfigFile() {
return ((LoadableConfig) this.getHandle()).getConfigFile();
}
@Override
public String getName() {
return ((LoadableConfig) this.getHandle()).getName();
}
@Override
public @Nullable YamlConfiguration getBukkitHandle() {
return ((LoadableConfig) this.getHandle()).getBukkitHandle();
}
}

View File

@@ -1,31 +0,0 @@
package com.willfp.eco.core.config.yaml.wrapper;
import com.willfp.eco.core.config.interfaces.Config;
import com.willfp.eco.core.config.interfaces.WrappedYamlConfiguration;
import com.willfp.eco.core.config.wrapper.ConfigWrapper;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
/**
* Wrapper to handle the backend yaml config implementations.
*
* @deprecated JSON and yml have full parity, use configs without a prefix instead,
* eg {@link com.willfp.eco.core.config.TransientConfig}, {@link com.willfp.eco.core.config.BaseConfig}.
* These configs will be removed eventually.
*/
@Deprecated(since = "6.17.0")
public abstract class YamlConfigWrapper extends ConfigWrapper<Config> implements WrappedYamlConfiguration {
/**
* Create a config wrapper.
*
* @param handle The handle.
*/
protected YamlConfigWrapper(@NotNull final Config handle) {
super(handle);
}
@Override
public YamlConfiguration getBukkitHandle() {
return ((WrappedYamlConfiguration) this.getHandle()).getBukkitHandle();
}
}

View File

@@ -5,6 +5,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* All storable data key types.
@@ -79,6 +80,22 @@ public final class PersistentDataKeyType<T> {
this.name = name;
}
@Override
public boolean equals(@Nullable final Object that) {
if (this == that) {
return true;
}
if (!(that instanceof PersistentDataKeyType type)) {
return false;
}
return Objects.equals(this.name, type.name);
}
@Override
public int hashCode() {
return Objects.hash(this.name);
}
/**
* Get all registered {@link PersistentDataKeyType}s.
*

View File

@@ -24,7 +24,7 @@ public interface FastItemStack {
* @return A map of all enchantments.
* @deprecated Poorly named method. Use getEnchants instead.
*/
@Deprecated(since = "6.24.0")
@Deprecated(since = "6.24.0", forRemoval = true)
default Map<Enchantment, Integer> getEnchantmentsOnItem(boolean checkStored) {
return getEnchants(checkStored);
}

View File

@@ -96,6 +96,13 @@ public interface Menu {
*/
Set<NamespacedKey> getKeys(@NotNull Player player);
/**
* Re-render the menu for a player.
*
* @param player The player.
*/
void refresh(@NotNull Player player);
/**
* Create a builder with a given amount of rows.
*

View File

@@ -34,6 +34,17 @@ public final class CustomItemsManager {
}
}
/**
* Register all the custom items for a specific plugin into eco.
*
* @see com.willfp.eco.core.items.Items
*/
public static void registerProviders() {
for (CustomItemsWrapper customItemsWrapper : REGISTERED) {
customItemsWrapper.registerProvider();
}
}
private CustomItemsManager() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}

View File

@@ -11,5 +11,14 @@ public interface CustomItemsWrapper extends Integration {
*
* @see com.willfp.eco.core.items.Items
*/
void registerAllItems();
default void registerAllItems() {
// Override when needed.
}
/**
* Register {@link com.willfp.eco.core.items.provider.ItemProvider}s.
*/
default void registerProvider() {
// Override when needed.
}
}

View File

@@ -13,6 +13,7 @@ import com.willfp.eco.util.NamespacedKeyUtils;
import com.willfp.eco.util.NumberUtils;
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;
@@ -115,6 +116,48 @@ public final class Items {
REGISTRY.remove(key);
}
/**
* Turn an ItemStack back into a lookup string.
*
* @param itemStack The ItemStack.
* @return The lookup string.
*/
@NotNull
public static String toLookupString(@Nullable final ItemStack itemStack) {
if (itemStack == null) {
return "";
}
StringBuilder builder = new StringBuilder();
CustomItem customItem = getCustomItem(itemStack);
if (customItem != null) {
builder.append(customItem.getKey());
} else {
builder.append(itemStack.getType().name().toLowerCase());
}
if (itemStack.getAmount() > 1) {
builder.append(" ")
.append(itemStack.getAmount());
}
ItemMeta meta = itemStack.getItemMeta();
if (meta != null) {
for (LookupArgParser parser : ARG_PARSERS) {
String parsed = parser.serializeBack(meta);
if (parsed != null) {
builder.append(" ")
.append(parsed);
}
}
}
return builder.toString();
}
/**
* This is the backbone of the entire eco item system.
* <p>
@@ -388,6 +431,64 @@ public final class Items {
return items;
}
/**
* Merge ItemStack onto another ItemStack.
*
* @param from The ItemStack to merge from.
* @param to The ItemStack to merge onto.
* @return The ItemStack, merged (same instance as to).
*/
@NotNull
public static ItemStack mergeFrom(@NotNull final ItemStack from,
@NotNull final ItemStack to) {
ItemMeta fromMeta = from.getItemMeta();
ItemMeta toMeta = to.getItemMeta();
if (fromMeta == null || toMeta == null) {
return to;
}
ItemMeta newMeta = mergeFrom(fromMeta, toMeta);
to.setItemMeta(newMeta);
to.setType(from.getType());
to.setAmount(from.getAmount());
return to;
}
/**
* Merge ItemMeta onto other ItemMeta.
*
* @param from The ItemMeta to merge from.
* @param to The ItemMeta to merge onto.
* @return The ItemMeta, merged (same instance as to).
*/
@NotNull
public static ItemMeta mergeFrom(@NotNull final ItemMeta from,
@NotNull final ItemMeta to) {
if (from.hasDisplayName()) {
to.setDisplayName(from.getDisplayName());
}
to.setLore(from.getLore());
for (Enchantment enchant : to.getEnchants().keySet()) {
to.removeEnchant(enchant);
}
for (Map.Entry<Enchantment, Integer> entry : from.getEnchants().entrySet()) {
to.addEnchant(entry.getKey(), entry.getValue(), true);
}
if (from.hasCustomModelData()) {
to.setCustomModelData(from.getCustomModelData());
} else {
to.setCustomModelData(null);
}
return to;
}
private Items() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}

View File

@@ -22,4 +22,14 @@ public interface LookupArgParser {
*/
@Nullable Predicate<ItemStack> parseArguments(@NotNull String[] args,
@NotNull ItemMeta meta);
/**
* Serialize the item back to a string.
*
* @param meta The ItemMeta.
* @return The string, or null if not required.
*/
default @Nullable String serializeBack(@NotNull final ItemMeta meta) {
return null;
}
}

View File

@@ -59,6 +59,10 @@ public abstract class AbstractItemStackBuilder<T extends ItemMeta, U extends Abs
* @param base The ItemStack to start with.
*/
protected AbstractItemStackBuilder(@NotNull final ItemStack base) {
if (base.getType() == Material.AIR) {
base.setType(Material.STONE); // Prevents NPEs.
}
this.base = base;
this.meta = (T) base.getItemMeta();
assert meta != null;

View File

@@ -23,7 +23,7 @@ public class ProxyError extends Error {
* @param message The message to send.
* @deprecated Proxy Errors should include a cause.
*/
@Deprecated
@Deprecated(forRemoval = true)
public ProxyError(@NotNull final String message) {
super(message);
}

View File

@@ -8,6 +8,7 @@ import org.jetbrains.annotations.NotNull;
*
* @deprecated Poorly named, exception when it's actually an error, contains doubly nested errors.
*/
@SuppressWarnings("removal")
@Deprecated(since = "6.24.0", forRemoval = true)
public class UnsupportedVersionException extends ProxyError {
/**
@@ -16,7 +17,7 @@ public class UnsupportedVersionException extends ProxyError {
* @param message The message to send.
* @deprecated Use the default constructor.
*/
@Deprecated(since = "6.24.0")
@Deprecated(since = "6.24.0", forRemoval = true)
public UnsupportedVersionException(@NotNull final String message) {
super(message);
}

View File

@@ -28,7 +28,7 @@ public final class DurabilityUtils {
* @param slot The slot in the inventory of the item.
* @deprecated The slot is not required.
*/
@Deprecated(since = "6.24.0")
@Deprecated(since = "6.24.0", forRemoval = true)
public static void damageItem(@NotNull final Player player,
@NotNull final ItemStack item,
final int damage,

View File

@@ -110,7 +110,7 @@ public final class NumberUtils {
* @return The new value.
* @deprecated Pointless method.
*/
@Deprecated(since = "6.19.0")
@Deprecated(since = "6.19.0", forRemoval = true)
public static double equalIfOver(final double toChange,
final double limit) {
return Math.min(toChange, limit);

View File

@@ -71,7 +71,7 @@ public final class TeamUtils {
* @deprecated Stupid method.
*/
@NotNull
@Deprecated(since = "6.24.0")
@Deprecated(since = "6.24.0", forRemoval = true)
public static Team getMaterialColorTeam(@NotNull final Material material) {
return fromChatColor(MATERIAL_COLORS.getOrDefault(material, ChatColor.WHITE));
}

View File

@@ -0,0 +1,24 @@
@file:JvmName("ItemsExtensions")
package com.willfp.eco.core.items
import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.ItemMeta
/**
* @see Items.toLookupString
*/
fun ItemStack?.toLookupString(): String =
Items.toLookupString(this)
/**
* @see Items.mergeFrom
*/
fun ItemStack.mergeFrom(other: ItemStack): ItemStack =
Items.mergeFrom(other, this)
/**
* @see Items.mergeFrom
*/
fun ItemMeta.mergeFrom(other: ItemMeta): ItemMeta =
Items.mergeFrom(other, this)

View File

@@ -2,10 +2,12 @@ group 'com.willfp'
version rootProject.version
dependencies {
// Libraries
implementation 'org.reflections:reflections:0.9.12'
implementation 'org.objenesis:objenesis:3.2'
compileOnly 'org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT'
compileOnly 'me.clip:placeholderapi:2.10.10'
compileOnly 'org.reflections:reflections:0.9.12'
compileOnly 'net.kyori:adventure-text-minimessage:4.10.0'
compileOnly 'net.kyori:adventure-platform-bukkit:4.1.0'
compileOnly 'org.objenesis:objenesis:3.2'
}

View File

@@ -0,0 +1,125 @@
@file:Suppress("UNCHECKED_CAST")
package com.willfp.eco.internal.config
import com.willfp.eco.core.config.ConfigType
import org.bukkit.configuration.file.YamlConstructor
import org.yaml.snakeyaml.DumperOptions
import org.yaml.snakeyaml.LoaderOptions
import org.yaml.snakeyaml.Yaml
import java.io.BufferedReader
import java.io.Reader
fun ConfigType.toMap(input: String?): Map<String, Any?> =
this.handler.toMap(input)
fun ConfigType.toString(map: Map<String, Any?>): String =
this.handler.toString(map)
fun Any?.constrainConfigTypes(type: ConfigType): Any? = when (this) {
is Map<*, *> -> EcoConfigSection(type, this.normalizeToConfig(type))
is Iterable<*> -> {
if (this.firstOrNull() == null) {
mutableListOf<Any>()
} else if (this.firstOrNull() is Map<*, *>) {
this as Iterable<Map<*, *>>
this.map { map -> EcoConfigSection(type, map.normalizeToConfig(type)) }
} else {
this.toMutableList()
}
}
else -> this
}
fun Map<*, *>.normalizeToConfig(type: ConfigType): Map<String, Any?> {
val building = mutableMapOf<String, Any?>()
for ((unprocessedKey, value) in this.entries) {
if (unprocessedKey == null || value == null) {
continue
}
val key = unprocessedKey.toString()
val constrained = value.constrainConfigTypes(type)
building[key] = constrained
}
return building
}
fun Reader.readToString(): String {
val input = this as? BufferedReader ?: BufferedReader(this)
val builder = StringBuilder()
var line: String?
input.use {
while (it.readLine().also { read -> line = read } != null) {
builder.append(line)
builder.append('\n')
}
}
return builder.toString()
}
private val ConfigType.handler: ConfigTypeHandler
get() = if (this == ConfigType.JSON) JSONConfigTypeHandler else YamlConfigTypeHandler
private abstract class ConfigTypeHandler(
val type: ConfigType
) {
fun toMap(input: String?): Map<String, Any?> {
if (input == null || input.isBlank()) {
return emptyMap()
}
return parseToMap(input).normalizeToConfig(type)
}
protected abstract fun parseToMap(input: String): Map<*, *>
abstract fun toString(map: Map<String, Any?>): String
}
private object YamlConfigTypeHandler : ConfigTypeHandler(ConfigType.YAML) {
private fun newYaml(): Yaml {
val yamlOptions = DumperOptions()
val loaderOptions = LoaderOptions()
val representer = EcoRepresenter()
loaderOptions.maxAliasesForCollections = Int.MAX_VALUE
loaderOptions.isAllowDuplicateKeys = false
yamlOptions.indent = 2
yamlOptions.defaultFlowStyle = DumperOptions.FlowStyle.BLOCK
representer.defaultFlowStyle = DumperOptions.FlowStyle.BLOCK
return Yaml(
YamlConstructor(),
representer,
yamlOptions,
loaderOptions,
)
}
override fun parseToMap(input: String): Map<*, *> {
return newYaml().load(input) ?: emptyMap<Any, Any>()
}
override fun toString(map: Map<String, Any?>): String {
return newYaml().dump(map)
}
}
private object JSONConfigTypeHandler : ConfigTypeHandler(ConfigType.JSON) {
override fun parseToMap(input: String): Map<*, *> {
return EcoGsonSerializer.gson.fromJson(input, Map::class.java)
}
override fun toString(map: Map<String, Any?>): String {
return EcoGsonSerializer.gson.toJson(map)
}
}

View File

@@ -0,0 +1,195 @@
package com.willfp.eco.internal.config
import com.willfp.eco.core.config.ConfigType
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.eco.core.placeholder.StaticPlaceholder
import com.willfp.eco.util.StringUtils
import org.bukkit.configuration.file.YamlConfiguration
import java.util.concurrent.ConcurrentHashMap
@Suppress("UNCHECKED_CAST")
open class EcoConfig(
private val configType: ConfigType
) : Config {
private val values = ConcurrentHashMap<String, Any?>()
@Transient
var injections = mutableListOf<StaticPlaceholder>()
fun init(values: Map<String, Any?>) {
this.values.clear()
this.values.putAll(values.normalizeToConfig(this.type))
}
override fun toPlaintext(): String {
return configType.toString(this.values)
}
override fun has(path: String): Boolean {
return get(path) != null
}
override fun getKeys(deep: Boolean): List<String> {
return if (deep) {
recurseKeys(mutableSetOf(), "")
} else {
values.keys.toList()
}
}
override fun recurseKeys(current: MutableSet<String>, root: String): List<String> {
val list = mutableSetOf<String>()
for (key in getKeys(false)) {
list.add("$root$key")
val found = get(key)
if (found is Config) {
list.addAll(found.recurseKeys(current, "$root$key."))
}
}
return list.toList()
}
override fun get(path: String): Any? {
val nearestPath = path.split(".")[0]
if (path.contains(".")) {
val remainingPath = path.removePrefix("${nearestPath}.")
if (remainingPath.isEmpty()) {
return null
}
val first = get(nearestPath)
return if (first is Config) {
first.get(remainingPath)
} else {
null
}
}
return values[nearestPath]
}
override fun set(
path: String,
obj: Any?
) {
val nearestPath = path.split(".")[0]
if (path.contains(".")) {
val remainingPath = path.removePrefix("${nearestPath}.")
if (remainingPath.isEmpty()) {
return
}
val section = getSubsection(nearestPath) // Creates a section if null, therefore it can be set.
section.set(remainingPath, obj)
values[nearestPath] = section // Set the value
return
}
if (obj == null) {
values.remove(nearestPath)
} else {
values[nearestPath] = obj.constrainConfigTypes(type)
}
}
override fun getSubsection(path: String): Config {
return getSubsectionOrNull(path) ?: EcoConfigSection(type, injections = injections)
}
override fun getSubsectionOrNull(path: String): Config? {
return get(path) as? Config
}
override fun getSubsectionsOrNull(path: String): List<Config>? {
return (get(path) as? Iterable<Config>)?.toList()
}
override fun getType(): ConfigType {
return configType
}
override fun getIntOrNull(path: String): Int? {
return (get(path) as? Number)?.toInt()
}
override fun getIntsOrNull(path: String): List<Int>? {
return (get(path) as? Iterable<Number>)?.map { it.toInt() }
}
override fun getBoolOrNull(path: String): Boolean? {
return get(path) as? Boolean
}
override fun getBoolsOrNull(path: String): List<Boolean>? {
return (get(path) as? Iterable<Boolean>)?.toList()
}
override fun getStringOrNull(
path: String,
format: Boolean,
option: StringUtils.FormatOption
): String? {
val string = get(path)?.toString() ?: return null
return if (format) StringUtils.format(string, option) else string
}
override fun getStringsOrNull(
path: String,
format: Boolean,
option: StringUtils.FormatOption
): List<String>? {
val strings = (get(path) as? Iterable<*>)?.map { it.toString() } ?: return null
return if (format) StringUtils.formatList(strings, option) else strings
}
override fun getDoubleOrNull(path: String): Double? {
return (get(path) as? Number)?.toDouble()
}
override fun getDoublesOrNull(path: String): List<Double>? {
return (get(path) as? Iterable<Number>)?.map { it.toDouble() }
}
override fun injectPlaceholders(placeholders: Iterable<StaticPlaceholder>) {
injections.removeIf { placeholders.any { placeholder -> it.identifier == placeholder.identifier } }
injections.addAll(placeholders)
}
override fun getInjectedPlaceholders(): List<StaticPlaceholder> {
return injections.toList()
}
override fun clearInjectedPlaceholders() {
injections.clear()
}
override fun toMap(): MutableMap<String, Any?> {
return values.toMutableMap()
}
override fun toBukkit(): YamlConfiguration {
val temp = YamlConfiguration()
temp.createSection("temp", this.values.toMap())
val section = temp.getConfigurationSection("temp")!!
val bukkit = YamlConfiguration()
for (key in section.getKeys(true)) {
bukkit.set(key, section.get(key))
}
return bukkit
}
override fun clone(): Config {
return EcoConfigSection(type, this.values.toMutableMap(), injections)
}
override fun toString(): String {
return this.toPlaintext()
}
}

View File

@@ -5,61 +5,39 @@ import com.willfp.eco.core.config.ConfigType
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.eco.core.config.interfaces.LoadableConfig
import com.willfp.eco.core.config.wrapper.ConfigFactory
import com.willfp.eco.internal.config.json.EcoJSONConfigSection
import com.willfp.eco.internal.config.json.EcoJSONConfigWrapper
import com.willfp.eco.internal.config.json.EcoLoadableJSONConfig
import com.willfp.eco.internal.config.json.EcoUpdatableJSONConfig
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 java.io.StringReader
import org.bukkit.configuration.ConfigurationSection
object EcoConfigFactory : ConfigFactory {
override fun createConfig(config: YamlConfiguration): Config {
return EcoYamlConfigSection(config)
}
override fun createConfig(values: MutableMap<String, Any>): Config {
return EcoJSONConfigSection(values)
}
override fun createConfig(contents: String, type: ConfigType): Config {
return if (type == ConfigType.JSON) {
@Suppress("UNCHECKED_CAST")
EcoJSONConfigSection(
EcoJSONConfigWrapper.gson.fromJson(
StringReader(contents), Map::class.java
) as MutableMap<String, Any>
)
} else {
EcoYamlConfigSection(YamlConfiguration.loadConfiguration(StringReader(contents)))
override fun createConfig(bukkit: ConfigurationSection): Config {
val config = createConfig(emptyMap(), ConfigType.YAML)
for (key in bukkit.getKeys(true)) {
config.set(key, bukkit.get(key))
}
return config
}
override fun createConfig(values: Map<String, Any>, type: ConfigType): Config =
EcoConfigSection(type, values)
override fun createConfig(contents: String, type: ConfigType): Config =
EcoConfigSection(type, type.toMap(contents))
override fun createLoadableConfig(
configName: String,
plugin: PluginLike,
subDirectoryPath: String,
source: Class<*>,
type: ConfigType
): LoadableConfig {
return if (type == ConfigType.JSON) {
EcoLoadableJSONConfig(
configName,
plugin,
subDirectoryPath,
source
)
} else {
EcoLoadableYamlConfig(
configName,
plugin,
subDirectoryPath,
source
)
}
}
type: ConfigType,
requiresChangesToSave: Boolean
): LoadableConfig = EcoLoadableConfig(
type,
configName,
plugin,
subDirectoryPath,
source,
requiresChangesToSave
)
override fun createUpdatableConfig(
configName: String,
@@ -68,26 +46,16 @@ object EcoConfigFactory : ConfigFactory {
source: Class<*>,
removeUnused: Boolean,
type: ConfigType,
requiresChangesToSave: Boolean,
vararg updateBlacklist: String
): LoadableConfig {
return if (type == ConfigType.JSON) {
EcoUpdatableJSONConfig(
configName,
plugin,
subDirectoryPath,
source,
removeUnused,
*updateBlacklist
)
} else {
EcoUpdatableYamlConfig(
configName,
plugin,
subDirectoryPath,
source,
removeUnused,
*updateBlacklist
)
}
}
}
): LoadableConfig = EcoUpdatableConfig(
type,
configName,
plugin,
subDirectoryPath,
source,
removeUnused,
requiresChangesToSave,
*updateBlacklist
)
}

View File

@@ -1,14 +1,9 @@
package com.willfp.eco.internal.config.updating
package com.willfp.eco.internal.config
import com.willfp.eco.core.EcoPlugin
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.json.EcoUpdatableJSONConfig
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
@@ -24,7 +19,7 @@ class EcoConfigHandler(
override fun callUpdate() {
for (method in reflections.getMethodsAnnotatedWith(ConfigUpdater::class.java)) {
kotlin.runCatching {
runCatching {
when (method.parameterCount) {
0 -> method.invoke(null)
1 -> method.invoke(null, this.plugin)
@@ -50,11 +45,11 @@ class EcoConfigHandler(
override fun updateConfigs() {
for (config in configs) {
when (config) {
is EcoUpdatableYamlConfig -> config.update()
is EcoUpdatableJSONConfig -> config.update()
is EcoLoadableYamlConfig -> config.reloadFromFile()
is EcoLoadableJSONConfig -> config.reloadFromFile()
is EcoUpdatableConfig -> config.update()
is EcoLoadableConfig -> config.reloadFromFile()
}
}
}
}
}
class InvalidUpdateMethodException(message: String) : RuntimeException(message)

View File

@@ -0,0 +1,16 @@
package com.willfp.eco.internal.config
import com.willfp.eco.core.config.ConfigType
import com.willfp.eco.core.placeholder.StaticPlaceholder
@Suppress("UNCHECKED_CAST")
class EcoConfigSection(
type: ConfigType,
values: Map<String, Any?> = emptyMap(),
injections: Collection<StaticPlaceholder> = emptyList()
) : EcoConfig(type) {
init {
this.init(values)
this.injections = injections.toMutableList()
}
}

View File

@@ -0,0 +1,20 @@
package com.willfp.eco.internal.config
import com.google.gson.GsonBuilder
import com.google.gson.JsonElement
import com.google.gson.JsonSerializationContext
import com.google.gson.JsonSerializer
import com.willfp.eco.core.config.interfaces.Config
import java.lang.reflect.Type
object EcoGsonSerializer : JsonSerializer<Config> {
val gson = GsonBuilder()
.setPrettyPrinting()
.disableHtmlEscaping()
.registerTypeAdapter(Config::class.java, this)
.create()
override fun serialize(src: Config, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
return gson.toJsonTree(src.toMap())
}
}

View File

@@ -1,27 +1,31 @@
package com.willfp.eco.internal.config.json
package com.willfp.eco.internal.config
import com.willfp.eco.core.PluginLike
import com.willfp.eco.core.config.ConfigType
import com.willfp.eco.core.config.interfaces.LoadableConfig
import org.bukkit.configuration.file.YamlConfiguration
import java.io.File
import java.io.FileNotFoundException
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.FileReader
import java.io.IOException
import java.io.InputStreamReader
import java.io.OutputStream
import java.io.Reader
import java.nio.file.Files
import java.nio.file.StandardOpenOption
@Suppress("UNCHECKED_CAST")
open class EcoLoadableJSONConfig(
open class EcoLoadableConfig(
type: ConfigType,
configName: String,
private val plugin: PluginLike,
private val subDirectoryPath: String,
val source: Class<*>
) : EcoJSONConfigWrapper(), LoadableConfig {
val source: Class<*>,
private val requiresChangesToSave: Boolean
) : EcoConfig(type), LoadableConfig {
private val configFile: File
private val name: String = "$configName.json"
private val name: String = "$configName.${type.extension}"
private var hasChanged = false
private val header = mutableListOf<String>()
fun reloadFromFile() {
runCatching { init(configFile) }.onFailure { it.printStackTrace() }
@@ -54,19 +58,68 @@ open class EcoLoadableJSONConfig(
@Throws(IOException::class)
override fun save() {
if (requiresChangesToSave) {
if (!hasChanged) { // In order to preserve comments
return
}
}
if (configFile.delete()) {
Files.write(
configFile.toPath(),
toPlaintext().toByteArray(),
this.toPlaintext().toByteArray(),
StandardOpenOption.CREATE,
StandardOpenOption.WRITE
)
}
}
@Throws(FileNotFoundException::class)
private fun makeHeader(contents: String) {
header.clear()
if (this.type == ConfigType.YAML) {
for (line in contents.lines()) {
if (!line.startsWith("#")) {
break
}
header.add(line)
}
}
}
protected fun init(reader: Reader) {
val string = reader.readToString()
makeHeader(string)
super.init(type.toMap(string))
}
fun init(file: File) {
super.init(gson.fromJson(FileReader(file), Map::class.java) as MutableMap<String, Any>)
init(InputStreamReader(FileInputStream(file), Charsets.UTF_8))
}
override fun toPlaintext(): String {
val contents = StringBuilder()
if (this.type == ConfigType.YAML) {
for (s in header) {
contents.append(s + "\n")
}
if (header.isNotEmpty()) {
contents.append("\n")
}
}
for (line in super.toPlaintext().lines()) {
if (line.startsWith("#")) {
continue
}
contents.append(line + "\n")
}
return contents.toString()
}
override fun getName(): String {
@@ -77,8 +130,9 @@ open class EcoLoadableJSONConfig(
return configFile
}
override fun getBukkitHandle(): YamlConfiguration? {
return null
override fun set(path: String, obj: Any?) {
hasChanged = true
super.set(path, obj)
}
init {
@@ -93,4 +147,4 @@ open class EcoLoadableJSONConfig(
init(configFile)
plugin.configHandler.addConfig(this)
}
}
}

View File

@@ -0,0 +1,21 @@
package com.willfp.eco.internal.config
import com.willfp.eco.core.config.interfaces.Config
import org.yaml.snakeyaml.nodes.Node
import org.yaml.snakeyaml.representer.Represent
import org.yaml.snakeyaml.representer.Representer
class EcoRepresenter : Representer() {
init {
multiRepresenters[Config::class.java] = RepresentConfig(multiRepresenters[Map::class.java]!!)
}
private class RepresentConfig(
val handle: Represent
) : Represent {
override fun representData(data: Any): Node {
data as Config
return handle.representData(data.toMap())
}
}
}

View File

@@ -1,24 +1,25 @@
package com.willfp.eco.internal.config.json
package com.willfp.eco.internal.config
import com.willfp.eco.core.PluginLike
import org.bukkit.configuration.file.YamlConfiguration
import com.willfp.eco.core.config.ConfigType
import com.willfp.eco.core.config.interfaces.Config
import java.io.BufferedReader
import java.io.InputStreamReader
import java.nio.charset.StandardCharsets
open class EcoUpdatableJSONConfig(
open class EcoUpdatableConfig(
type: ConfigType,
configName: String,
plugin: PluginLike,
subDirectoryPath: String,
source: Class<*>,
private val removeUnused: Boolean,
requiresChangesToSave: Boolean,
vararg updateBlacklist: String
) : EcoLoadableJSONConfig(configName, plugin, subDirectoryPath, source) {
private val updateBlacklist: MutableList<String> = mutableListOf(*updateBlacklist)
) : EcoLoadableConfig(type, configName, plugin, subDirectoryPath, source, requiresChangesToSave) {
private val updateBlacklist = mutableListOf(*updateBlacklist)
fun update() {
super.clearCache()
this.init(configFile)
val newConfig = configInJar ?: return
if (newConfig.getKeys(true) == this.getKeys(true)) {
@@ -43,13 +44,14 @@ open class EcoUpdatableJSONConfig(
this.save()
}
private val configInJar: YamlConfiguration?
private val configInJar: Config?
get() {
val newIn = this.source.getResourceAsStream(resourcePath) ?: return null
val reader = BufferedReader(InputStreamReader(newIn, StandardCharsets.UTF_8))
val newConfig = YamlConfiguration()
newConfig.load(reader)
return newConfig
val config = EcoConfigSection(type, emptyMap())
config.init(type.toMap(reader.readToString()))
return config
}
init {
@@ -57,4 +59,4 @@ open class EcoUpdatableJSONConfig(
plugin.configHandler.addConfig(this)
update()
}
}
}

View File

@@ -1,11 +0,0 @@
package com.willfp.eco.internal.config.json
import com.willfp.eco.core.placeholder.StaticPlaceholder
@Suppress("UNCHECKED_CAST")
class EcoJSONConfigSection(values: Map<String, Any?>, injections: Collection<StaticPlaceholder> = emptyList()) : EcoJSONConfigWrapper() {
init {
init(values)
this.injections = injections.toMutableList()
}
}

View File

@@ -1,233 +0,0 @@
@file:Suppress("DEPRECATION")
package com.willfp.eco.internal.config.json
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.willfp.eco.core.config.ConfigType
import com.willfp.eco.core.config.interfaces.JSONConfig
import com.willfp.eco.core.placeholder.StaticPlaceholder
import com.willfp.eco.util.StringUtils
import java.util.Objects
import java.util.concurrent.ConcurrentHashMap
@Suppress("UNCHECKED_CAST")
open class EcoJSONConfigWrapper : JSONConfig {
companion object {
val gson: Gson = GsonBuilder()
.setPrettyPrinting()
.disableHtmlEscaping()
.create()
}
val values = ConcurrentHashMap<String, Any?>()
private val cache = ConcurrentHashMap<String, Any>()
var injections = mutableListOf<StaticPlaceholder>()
fun init(values: Map<String, Any?>) {
this.values.clear()
this.values.putAll(values)
}
override fun clearCache() {
cache.clear()
}
override fun toPlaintext(): String {
return gson.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?>?)!!, injections)
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?>?)!!, injections)
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?>?)!!, injections)
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 {
return getSubsectionOrNull(path) ?: EcoJSONConfigSection(mutableMapOf(), injections)
}
override fun getSubsectionOrNull(path: String): JSONConfig? {
return if (values.containsKey(path)) {
val subsection = values[path] as Map<String, Any>
EcoJSONConfigSection(subsection, injections)
} else {
null
}
}
override fun getSubsectionsOrNull(path: String): List<JSONConfig>? {
val maps = getOfKnownType(path, Any::class.java) as List<Map<String, Any>>?
?: return null
val configs = mutableListOf<JSONConfig>()
for (map in maps) {
configs.add(EcoJSONConfigSection(map, injections))
}
return configs.toMutableList()
}
override fun getIntOrNull(path: String): Int? {
return getOfKnownType(path, Double::class.java)?.toInt()
}
override fun getIntsOrNull(path: String): MutableList<Int>? {
return (getOfKnownType(path, Any::class.java) as Collection<Int>?)?.toMutableList()
}
override fun getBoolOrNull(path: String): Boolean? {
return getOfKnownType(path, Boolean::class.java)
}
override fun getBoolsOrNull(path: String): MutableList<Boolean>? {
return (getOfKnownType(path, Any::class.java) as Collection<Boolean>?)?.toMutableList()
}
override fun getStringOrNull(
path: String,
format: Boolean,
option: StringUtils.FormatOption
): String? {
return if (has(path)) {
val string = getOfKnownType(path, String::class.java) ?: ""
return if (format) StringUtils.format(string, option) else string
} else {
null
}
}
override fun getStringsOrNull(
path: String,
format: Boolean,
option: StringUtils.FormatOption
): MutableList<String>? {
return if (has(path)) {
val strings =
(Objects.requireNonNullElse(
getOfKnownType(path, Any::class.java),
emptyList<String>()
) as List<String>).toMutableList()
return if (format) StringUtils.formatList(strings, option) else strings
} else {
null
}
}
override fun getDoubleOrNull(path: String): Double? {
return getOfKnownType(path, Double::class.java)
}
override fun getDoublesOrNull(path: String): MutableList<Double>? {
return (getOfKnownType(path, Any::class.java) as Collection<Double>?)?.toMutableList()
}
override fun injectPlaceholders(placeholders: Iterable<StaticPlaceholder>) {
injections.removeIf { placeholders.any { placeholder -> it.identifier == placeholder.identifier } }
injections.addAll(placeholders)
this.clearCache()
}
override fun getInjectedPlaceholders(): List<StaticPlaceholder> {
return injections.toList()
}
override fun clearInjectedPlaceholders() {
injections.clear()
this.clearCache()
}
override fun getType(): ConfigType {
return ConfigType.JSON
}
override fun clone(): JSONConfig {
return EcoJSONConfigSection(this.values.toMutableMap(), injections)
}
}

View File

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

View File

@@ -1,82 +0,0 @@
@file:Suppress("DEPRECATION")
package com.willfp.eco.internal.config.yaml
import com.willfp.eco.core.PluginLike
import com.willfp.eco.core.config.interfaces.LoadableConfig
import com.willfp.eco.core.config.interfaces.WrappedYamlConfiguration
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: PluginLike,
private val subDirectoryPath: String,
val source: Class<*>
) : EcoYamlConfigWrapper<YamlConfiguration>(), WrappedYamlConfiguration, LoadableConfig {
private val configFile: File
private val name: String = "$configName.yml"
fun reloadFromFile() {
handle.load(getConfigFile())
}
final override fun createFile() {
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)
inputStream.copyTo(out)
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() {
handle.save(getConfigFile())
}
override fun getName(): String {
return name
}
override fun getConfigFile(): File {
return configFile
}
override fun getBukkitHandle(): YamlConfiguration? {
return handle
}
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

@@ -1,60 +0,0 @@
package com.willfp.eco.internal.config.yaml
import com.willfp.eco.core.PluginLike
import org.bukkit.configuration.file.YamlConfiguration
import java.io.BufferedReader
import java.io.InputStreamReader
import java.nio.charset.StandardCharsets
class EcoUpdatableYamlConfig(
configName: String,
plugin: PluginLike,
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()
this.handle.load(configFile)
val newConfig = configInJar ?: return
if (newConfig.getKeys(true) == this.handle.getKeys(true)) {
return
}
newConfig.getKeys(true).forEach { key ->
if (!this.handle.getKeys(true).contains(key)) {
if (updateBlacklist.stream().noneMatch { key.contains(it) }) {
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)
}
private val configInJar: YamlConfiguration?
get() {
val newIn = source.getResourceAsStream(resourcePath) ?: return null
val reader = BufferedReader(InputStreamReader(newIn, StandardCharsets.UTF_8))
val newConfig = YamlConfiguration()
newConfig.load(reader)
return newConfig
}
init {
this.updateBlacklist.removeIf { it.isEmpty() }
plugin.configHandler.addConfig(this)
update()
}
}

View File

@@ -1,11 +0,0 @@
package com.willfp.eco.internal.config.yaml
import com.willfp.eco.core.placeholder.StaticPlaceholder
import org.bukkit.configuration.ConfigurationSection
class EcoYamlConfigSection(section: ConfigurationSection, injections: Collection<StaticPlaceholder> = emptyList()) : EcoYamlConfigWrapper<ConfigurationSection>() {
init {
init(section)
this.injections = injections.toMutableList()
}
}

View File

@@ -1,259 +0,0 @@
package com.willfp.eco.internal.config.yaml
import com.willfp.eco.core.config.ConfigType
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.eco.core.placeholder.StaticPlaceholder
import com.willfp.eco.util.StringUtils
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 = mutableMapOf<String, Any?>()
var injections = mutableListOf<StaticPlaceholder>()
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 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, injections)
}
getSubsectionOrNull(path)
}
}
override fun getIntOrNull(path: String): Int? {
return if (cache.containsKey(path)) {
(cache[path] as Number).toInt()
} else {
if (has(path)) {
cache[path] = handle.getDouble(path).toInt()
} else {
return null
}
getIntOrNull(path)
}
}
override fun getIntsOrNull(path: String): MutableList<Int>? {
return if (cache.containsKey(path)) {
(cache[path] as Collection<Int>).toMutableList()
} else {
if (has(path)) {
cache[path] = handle.getIntegerList(path).toMutableList()
} else {
return null
}
getIntsOrNull(path)
}
}
override fun getBoolOrNull(path: String): Boolean? {
return if (cache.containsKey(path)) {
cache[path] as Boolean
} else {
if (has(path)) {
cache[path] = handle.getBoolean(path)
} else {
return null
}
getBoolOrNull(path)
}
}
override fun getBoolsOrNull(path: String): MutableList<Boolean>? {
return if (cache.containsKey(path)) {
(cache[path] as Collection<Boolean>).toMutableList()
} else {
if (has(path)) {
cache[path] = handle.getBooleanList(path).toMutableList()
} else {
return null
}
getBoolsOrNull(path)
}
}
override fun getStringOrNull(
path: String,
format: Boolean,
option: StringUtils.FormatOption
): String? {
return if (has(path)) {
if (format && option == StringUtils.FormatOption.WITHOUT_PLACEHOLDERS) {
return if (cache.containsKey("$path\$FMT")) {
cache["$path\$FMT"] as String
} else {
val string: String = handle.getString(path, "")!!
cache["$path\$FMT"] = StringUtils.format(string, option)
getString(path, format, option)
}
} else {
val string = if (cache.containsKey(path)) {
cache[path] as String
} else {
cache[path] = handle.getString(path, "")!!
getString(path, format, option)
}
return if (format) StringUtils.format(string) else string
}
} else {
null
}
}
override fun getStringsOrNull(
path: String,
format: Boolean,
option: StringUtils.FormatOption
): MutableList<String>? {
return if (has(path)) {
if (format && option == StringUtils.FormatOption.WITHOUT_PLACEHOLDERS) {
return if (cache.containsKey("$path\$FMT")) {
(cache["$path\$FMT"] as MutableList<String>).toMutableList()
} else {
val list = if (has(path)) handle.getStringList(path) else mutableListOf<String>()
cache["$path\$FMT"] = StringUtils.formatList(list, option)
getStrings(path, true, option)
}
} else {
val strings = if (cache.containsKey(path)) {
(cache[path] as MutableList<String>).toMutableList()
} else {
cache[path] =
if (has(path)) ArrayList(handle.getStringList(path)) else mutableListOf<String>()
getStrings(path, false, option)
}
return if (format) {
StringUtils.formatList(strings, StringUtils.FormatOption.WITH_PLACEHOLDERS)
} else {
strings
}
}
} else {
null
}
}
override fun getDoubleOrNull(path: String): Double? {
return if (cache.containsKey(path)) {
(cache[path] as Number).toDouble()
} else {
if (has(path)) {
cache[path] = handle.getDouble(path)
} else {
return null
}
getDoubleOrNull(path)
}
}
override fun getDoublesOrNull(path: String): MutableList<Double>? {
return if (cache.containsKey(path)) {
(cache[path] as Collection<Double>).toMutableList()
} else {
if (has(path)) {
cache[path] = handle.getDoubleList(path).toMutableList()
} else {
return null
}
getDoublesOrNull(path)
}
}
override fun getSubsectionsOrNull(path: String): MutableList<out Config>? {
return if (has(path)) {
return if (cache.containsKey(path)) {
(cache[path] as Collection<Config>).toMutableList()
} else {
val mapList = ArrayList(handle.getMapList(path)) as List<Map<String, Any?>>
val configList = mutableListOf<Config>()
for (map in mapList) {
val temp = YamlConfiguration.loadConfiguration(StringReader(""))
temp.createSection("a", map)
configList.add(EcoYamlConfigSection(temp.getConfigurationSection("a")!!, injections))
}
cache[path] = if (has(path)) configList else emptyList()
getSubsections(path)
}
} else {
null
}
}
override fun injectPlaceholders(placeholders: Iterable<StaticPlaceholder>) {
injections.removeIf { placeholders.any { placeholder -> it.identifier == placeholder.identifier } }
injections.addAll(placeholders)
this.clearCache()
}
override fun getInjectedPlaceholders(): List<StaticPlaceholder> {
return injections.toList()
}
override fun clearInjectedPlaceholders() {
injections.clear()
this.clearCache()
}
override fun getType(): ConfigType {
return ConfigType.JSON
}
override fun clone(): Config {
return EcoYamlConfigSection(
YamlConfiguration.loadConfiguration(
StringReader(
toPlaintext()
)
),
injections
)
}
}

View File

@@ -4,7 +4,6 @@ import com.willfp.eco.core.gui.menu.CloseHandler
import com.willfp.eco.core.gui.menu.Menu
import com.willfp.eco.core.gui.slot.Slot
import com.willfp.eco.internal.gui.slot.EcoSlot
import com.willfp.eco.util.StringUtils
import org.bukkit.Bukkit
import org.bukkit.NamespacedKey
import org.bukkit.entity.Player
@@ -19,7 +18,7 @@ class EcoMenu(
val slots: List<MutableList<EcoSlot>>,
private val title: String,
private val onClose: CloseHandler
): Menu {
) : Menu {
override fun getSlot(row: Int, column: Int): Slot {
if (row < 1 || row > this.rows) {
return slots[0][0]
@@ -37,33 +36,23 @@ class EcoMenu(
var i = 0
for (row in slots) {
for (item in row) {
for (slot in row) {
if (i == rows * 9) {
break
}
val slotItem = item.getItemStack(player, this)
val meta = slotItem.itemMeta
if (meta != null) {
val lore = meta.lore
if (lore != null) {
lore.replaceAll{ s -> StringUtils.format(s, player) }
meta.lore = lore
}
slotItem.itemMeta = meta
}
inventory.setItem(i, slotItem)
inventory.setItem(i, slot.getItemStack(player, this))
i++
}
}
player.openInventory(inventory)
MenuHandler.registerMenu(inventory, this)
MenuHandler.registerInventory(inventory, this, player)
return inventory
}
fun handleClose(event: InventoryCloseEvent) {
onClose.handle(event, this)
MenuHandler.unregisterMenu(event.inventory)
MenuHandler.unregisterInventory(event.inventory)
}
override fun getRows(): Int {
@@ -74,9 +63,8 @@ class EcoMenu(
return title
}
override fun getCaptiveItems(player: Player): MutableList<ItemStack> {
val inventory = MenuHandler.getExtendedInventory(player.openInventory.topInventory)
inventory ?: return mutableListOf()
override fun getCaptiveItems(player: Player): List<ItemStack> {
val inventory = player.openInventory.topInventory.asRenderedInventory() ?: return emptyList()
return inventory.captiveItems
}
@@ -86,21 +74,22 @@ class EcoMenu(
type: PersistentDataType<T, Z>,
value: Z
) {
val inventory = MenuHandler.getExtendedInventory(player.openInventory.topInventory)
inventory ?: return
val inventory = player.openInventory.topInventory.asRenderedInventory() ?: return
inventory.data[key] = value
inventory.refresh(player)
inventory.render()
}
override fun <T : Any, Z : Any> readData(player: Player, key: NamespacedKey, type: PersistentDataType<T, Z>): T? {
val inventory = MenuHandler.getExtendedInventory(player.openInventory.topInventory)
inventory ?: return null
return inventory.data[key] as T?
val inventory = player.openInventory.topInventory.asRenderedInventory() ?: return null
return inventory.data[key] as? T?
}
override fun getKeys(player: Player): MutableSet<NamespacedKey> {
val inventory = MenuHandler.getExtendedInventory(player.openInventory.topInventory)
inventory ?: return HashSet()
override fun getKeys(player: Player): Set<NamespacedKey> {
val inventory = player.openInventory.topInventory.asRenderedInventory() ?: return emptySet()
return inventory.data.keys
}
}
override fun refresh(player: Player) {
player.openInventory.topInventory.asRenderedInventory()?.render()
}
}

View File

@@ -1,32 +1,29 @@
package com.willfp.eco.internal.gui.menu
import com.willfp.eco.core.gui.menu.Menu
import org.bukkit.entity.Player
import org.bukkit.inventory.Inventory
import java.util.WeakHashMap
object MenuHandler {
private val menus = WeakHashMap<ExtendedInventory, EcoMenu>()
private val inventories = WeakHashMap<Inventory, ExtendedInventory>()
private val inventories = WeakHashMap<Inventory, MenuRenderedInventory>()
fun registerMenu(
object MenuHandler {
fun registerInventory(
inventory: Inventory,
menu: EcoMenu
menu: EcoMenu,
player: Player
) {
val extendedInventory = ExtendedInventory(inventory, menu)
inventories[inventory] = extendedInventory
menus[extendedInventory] = menu
val rendered = MenuRenderedInventory(menu, inventory, player)
inventories[inventory] = rendered
}
fun unregisterMenu(inventory: Inventory) {
menus.remove(inventories[inventory])
fun unregisterInventory(inventory: Inventory) {
inventories.remove(inventory)
}
}
fun getMenu(inventory: Inventory): Menu? {
return menus[inventories[inventory]]
}
fun Inventory.asRenderedInventory(): MenuRenderedInventory? =
inventories[this]
fun getExtendedInventory(inventory: Inventory): ExtendedInventory? {
return inventories[inventory]
}
}
fun Inventory.getMenu(): Menu? =
this.asRenderedInventory()?.menu

View File

@@ -1,35 +1,21 @@
package com.willfp.eco.internal.gui.menu
import com.willfp.eco.util.MenuUtils
import com.willfp.eco.util.StringUtils
import org.bukkit.Material
import org.bukkit.NamespacedKey
import org.bukkit.entity.Player
import org.bukkit.inventory.Inventory
import org.bukkit.inventory.ItemStack
class ExtendedInventory(
class MenuRenderedInventory(
val menu: EcoMenu,
val inventory: Inventory,
private val menu: EcoMenu
val player: Player
) {
val captiveItems = mutableListOf<ItemStack>()
val data = mutableMapOf<NamespacedKey, Any>()
fun refresh(player: Player) {
captiveItems.clear()
for (i in 0 until inventory.size) {
val (row, column) = MenuUtils.convertSlotToRowColumn(i)
val slot = menu.getSlot(row, column)
if (slot.isCaptive) {
val defaultItem = slot.getItemStack(player)
val item = inventory.getItem(i) ?: continue
if (item == defaultItem && item.type == Material.AIR) {
continue
}
captiveItems.add(item)
}
}
fun render() {
generateCaptive()
var i = 0
for (row in menu.slots) {
@@ -37,21 +23,31 @@ class ExtendedInventory(
if (i == menu.rows * 9) {
break
}
val slotItem = slot.getItemStack(player, menu)
val meta = slotItem.itemMeta
if (meta != null) {
val lore = meta.lore
if (lore != null) {
lore.replaceAll{ s -> StringUtils.format(s, player) }
meta.lore = lore
}
slotItem.itemMeta = meta
}
if (!slot.isCaptive) {
inventory.setItem(i, slotItem)
inventory.setItem(i, slot.getItemStack(player, menu))
}
i++
}
}
}
}
private fun generateCaptive() {
captiveItems.clear()
for (i in 0 until inventory.size) {
val (row, column) = MenuUtils.convertSlotToRowColumn(i)
val slot = menu.getSlot(row, column)
if (slot.isCaptive) {
val renderedItem = slot.getItemStack(player)
val itemStack = inventory.getItem(i) ?: continue
if (itemStack == renderedItem || itemStack.type.isAir || itemStack.amount == 0) {
continue
}
captiveItems.add(itemStack)
}
}
}
}

View File

@@ -5,7 +5,8 @@ import com.willfp.eco.core.gui.slot.Slot
import com.willfp.eco.core.gui.slot.functional.SlotHandler
import com.willfp.eco.core.gui.slot.functional.SlotProvider
import com.willfp.eco.core.gui.slot.functional.SlotUpdater
import com.willfp.eco.internal.gui.menu.MenuHandler
import com.willfp.eco.internal.gui.menu.getMenu
import org.bukkit.Material
import org.bukkit.entity.Player
import org.bukkit.event.inventory.ClickType
import org.bukkit.event.inventory.InventoryClickEvent
@@ -20,11 +21,12 @@ open class EcoSlot(
private val onMiddleClick: SlotHandler,
private val updater: SlotUpdater
) : Slot {
fun handleInventoryClick(
event: InventoryClickEvent,
menu: Menu
) {
event.isCancelled = true
when (event.click) {
ClickType.LEFT -> this.onLeftClick.handle(event, this, menu)
ClickType.RIGHT -> this.onRightClick.handle(event, this, menu)
@@ -36,9 +38,9 @@ open class EcoSlot(
}
override fun getItemStack(player: Player): ItemStack {
val menu = MenuHandler.getMenu(player.openInventory.topInventory)!!
val menu = player.openInventory.topInventory.getMenu()!!
val prev = provider.provide(player, menu)
return updater.update(player, menu, prev)
return updater.update(player, menu, prev) ?: ItemStack(Material.AIR)
}
fun getItemStack(
@@ -46,7 +48,8 @@ open class EcoSlot(
menu: Menu
): ItemStack {
val prev = provider.provide(player, menu)
return updater.update(player, menu, prev)
val updated = updater.update(player, menu, prev)
return updated ?: ItemStack(Material.AIR)
}
override fun isCaptive(): Boolean {

View File

@@ -41,4 +41,12 @@ class ArgParserColor : LookupArgParser {
)
}
}
override fun serializeBack(meta: ItemMeta): String? {
if (meta !is LeatherArmorMeta) {
return null
}
return "color:#${Integer.toHexString(meta.color.asRGB())}"
}
}

View File

@@ -30,4 +30,12 @@ class ArgParserCustomModelData : LookupArgParser {
testMeta.customModelData == modelData
}
}
}
override fun serializeBack(meta: ItemMeta): String? {
if (!meta.hasCustomModelData()) {
return null
}
return "custom-model-data:${meta.customModelData}"
}
}

View File

@@ -52,4 +52,26 @@ class ArgParserEnchantment : LookupArgParser {
true
}
}
override fun serializeBack(meta: ItemMeta): String? {
val enchants = mutableMapOf<Enchantment, Int>()
if (meta is EnchantmentStorageMeta) {
enchants.putAll(meta.storedEnchants)
} else {
enchants.putAll(meta.enchants)
}
if (enchants.isEmpty()) {
return null
}
val builder = StringBuilder()
for ((enchant, level) in enchants) {
builder.append("${enchant.key.key}:$level ")
}
return builder.toString().trimEnd()
}
}

View File

@@ -11,7 +11,7 @@ class ArgParserFlag : LookupArgParser {
val flags = mutableSetOf<ItemFlag>()
for (arg in args) {
val flag = kotlin.runCatching { ItemFlag.valueOf(arg.uppercase()) }.getOrNull() ?: continue
val flag = runCatching { ItemFlag.valueOf(arg.uppercase()) }.getOrNull() ?: continue
flags.add(flag)
}
@@ -27,4 +27,14 @@ class ArgParserFlag : LookupArgParser {
testMeta.itemFlags.containsAll(flags)
}
}
}
override fun serializeBack(meta: ItemMeta): String? {
val flags = meta.itemFlags
if (flags.isEmpty()) {
return null
}
return flags.joinToString(" ") { it.name.lowercase() }
}
}

View File

@@ -30,4 +30,12 @@ class ArgParserName : LookupArgParser {
testMeta.displayName == formatted
}
}
override fun serializeBack(meta: ItemMeta): String? {
if (!meta.hasDisplayName()) {
return null
}
return "name:\"${meta.displayName}\""
}
}

View File

@@ -36,4 +36,12 @@ class ArgParserTexture : LookupArgParser {
texture == SkullUtils.getSkullTexture(testMeta)
}
}
override fun serializeBack(meta: ItemMeta): String? {
if (meta !is SkullMeta) {
return null
}
return "texture:${SkullUtils.getSkullTexture(meta)}"
}
}

View File

@@ -27,4 +27,12 @@ class ArgParserUnbreakable : LookupArgParser {
testMeta.isUnbreakable
}
}
override fun serializeBack(meta: ItemMeta): String? {
if (!meta.isUnbreakable) {
return null
}
return "unbreakable"
}
}

View File

@@ -2,24 +2,17 @@ package com.willfp.eco.internal.logging
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.util.StringUtils
import org.bukkit.Bukkit
import java.util.logging.Level
import java.util.logging.Logger
class EcoLogger(plugin: EcoPlugin) : Logger(plugin.name, null as String?) {
class EcoLogger(private val 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))
Bukkit.getConsoleSender().sendMessage("[${plugin.name}] ${StringUtils.format(msg)}")
}
init {
parent = plugin.server.logger
this.level = Level.ALL
}
}
}

View File

@@ -2,13 +2,23 @@ group 'com.willfp'
version rootProject.version
dependencies {
implementation 'com.github.Redempt:Crunch:1.1.2'
compileOnly 'net.kyori:adventure-platform-bukkit:4.1.0'
compileOnly 'org.apache.maven:maven-artifact:3.8.1'
compileOnly 'com.google.code.gson:gson:2.8.8'
compileOnly 'org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT'
compileOnly project(":eco-core:core-proxy")
compileOnly project(":eco-core:core-backend")
// Libraries
implementation 'com.github.Redempt:Crunch:1.1.2'
implementation 'mysql:mysql-connector-java:8.0.25'
implementation 'org.jetbrains.exposed:exposed-core:0.37.3'
implementation 'org.jetbrains.exposed:exposed-dao:0.37.3'
implementation 'org.jetbrains.exposed:exposed-jdbc:0.37.3'
implementation 'com.zaxxer:HikariCP:5.0.0'
implementation 'net.kyori:adventure-platform-bukkit:4.1.0'
// Included in spigot jar
compileOnly 'com.google.code.gson:gson:2.8.8'
compileOnly 'org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT'
// Plugin dependencies
compileOnly 'com.comphenix.protocol:ProtocolLib:4.6.1-SNAPSHOT'
compileOnly 'com.sk89q.worldguard:worldguard-bukkit:7.0.7-SNAPSHOT'
compileOnly 'com.github.TechFortress:GriefPrevention:16.17.1'
@@ -26,11 +36,6 @@ dependencies {
compileOnly 'com.github.brcdev-minecraft:shopgui-api:2.2.0'
compileOnly 'com.github.LoneDev6:API-ItemsAdder:2.4.7'
compileOnly 'com.arcaniax:HeadDatabase-API:1.3.0'
compileOnly 'org.jetbrains.exposed:exposed-core:0.37.3'
compileOnly 'org.jetbrains.exposed:exposed-dao:0.37.3'
compileOnly 'org.jetbrains.exposed:exposed-jdbc:0.37.3'
compileOnly 'mysql:mysql-connector-java:8.0.25'
compileOnly 'com.zaxxer:HikariCP:5.0.0'
compileOnly 'com.gmail.filoghost.holographicdisplays:holographicdisplays-api:2.4.0'
compileOnly 'com.github.EssentialsX:Essentials:2.18.2'
compileOnly 'com.bgsoftware:SuperiorSkyblockAPI:1.8.3'
@@ -40,7 +45,10 @@ dependencies {
compileOnly 'com.github.WhipDevelopment:CrashClaim:f9cd7d92eb'
compileOnly 'com.wolfyscript.wolfyutilities:wolfyutilities:3.16.0.0'
compileOnly 'com.github.decentsoftware-eu:decentholograms:2.1.2'
compileOnly 'io.lumine.xikage:MythicMobs:4.9.1'
// MythicMobs
compileOnly 'io.lumine:Mythic:5.0.1'
compileOnly 'io.lumine:LumineUtils:1.16.1-SNAPSHOT'
// CombatLogX V10 + NewbieHelper Expansion
compileOnly 'com.SirBlobman.combatlogx:CombatLogX-API:10.0.0.0-SNAPSHOT'
@@ -53,6 +61,7 @@ dependencies {
// LibsDisguises
compileOnly 'LibsDisguises:LibsDisguises:10.0.26'
// All other libs
compileOnly fileTree(dir: '../../lib', include: ['*.jar'])
}

View File

@@ -10,7 +10,7 @@ import com.willfp.eco.internal.EcoCleaner
import com.willfp.eco.internal.EcoPropsParser
import com.willfp.eco.internal.Plugins
import com.willfp.eco.internal.config.EcoConfigFactory
import com.willfp.eco.internal.config.updating.EcoConfigHandler
import com.willfp.eco.internal.config.EcoConfigHandler
import com.willfp.eco.internal.drops.EcoDropQueueFactory
import com.willfp.eco.internal.events.EcoEventManager
import com.willfp.eco.internal.extensions.EcoExtensionLoader

View File

@@ -178,6 +178,8 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
NumberUtils.initCrunch { expression, player, statics -> evaluateExpression(expression, player, statics) }
CustomItemsManager.registerProviders()
postInit()
}

View File

@@ -10,5 +10,6 @@ class DataYml(
"data",
plugin,
false,
ConfigType.YAML
ConfigType.YAML,
false
)

View File

@@ -27,7 +27,7 @@ abstract class EcoProfile(
return this.data[key] as T
}
this.data[key] = handler.read(uuid, key.key) ?: key.defaultValue
this.data[key] = handler.read(uuid, key) ?: key.defaultValue
return read(key)
}
@@ -36,11 +36,11 @@ abstract class EcoProfile(
return false
}
return this.data == other.data && this.uuid == other.uuid
return this.uuid == other.uuid
}
override fun hashCode(): Int {
return this.data.hashCode()
return this.uuid.hashCode()
}
companion object {

View File

@@ -23,5 +23,5 @@ interface DataHandler {
fun <T> write(uuid: UUID, key: NamespacedKey, value: T)
fun saveKeysFor(uuid: UUID, keys: Set<PersistentDataKey<*>>)
fun <T> read(uuid: UUID, key: NamespacedKey): T?
fun <T> read(uuid: UUID, key: PersistentDataKey<T>): T?
}

View File

@@ -45,6 +45,7 @@ class MySQLDataHandler(
private val serverHandler: ImplementedMySQLHandler
init {
val config = HikariConfig()
config.driverClassName = "com.mysql.cj.jdbc.Driver"
config.username = plugin.configYml.getString("mysql.user")
@@ -102,9 +103,9 @@ class MySQLDataHandler(
}
}
override fun <T> read(uuid: UUID, key: NamespacedKey): T? {
override fun <T> read(uuid: UUID, key: PersistentDataKey<T>): T? {
return applyFor(uuid) {
it.read(uuid, key)
it.read(uuid, key.key)
}
}

View File

@@ -1,6 +1,7 @@
package com.willfp.eco.internal.spigot.data.storage
import com.willfp.eco.core.data.keys.PersistentDataKey
import com.willfp.eco.core.data.keys.PersistentDataKeyType
import com.willfp.eco.internal.spigot.EcoSpigotPlugin
import com.willfp.eco.internal.spigot.data.EcoProfileHandler
import org.bukkit.NamespacedKey
@@ -37,7 +38,15 @@ class YamlDataHandler(
dataYml.set("player.$uuid.$key", value)
}
override fun <T> read(uuid: UUID, key: NamespacedKey): T? {
return dataYml.get("player.$uuid.$key") as T?
override fun <T> read(uuid: UUID, key: PersistentDataKey<T>): T? {
val value = when (key.type) {
PersistentDataKeyType.INT -> dataYml.getIntOrNull("player.$uuid.${key.key}")
PersistentDataKeyType.DOUBLE -> dataYml.getDoubleOrNull("player.$uuid.${key.key}")
PersistentDataKeyType.STRING -> dataYml.getStringOrNull("player.$uuid.${key.key}")
PersistentDataKeyType.BOOLEAN -> dataYml.getBoolOrNull("player.$uuid.${key.key}")
else -> null
} as? T?
return value
}
}

View File

@@ -1,67 +1,42 @@
package com.willfp.eco.internal.spigot.gui
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.drops.DropQueue
import com.willfp.eco.internal.gui.menu.EcoMenu
import com.willfp.eco.internal.gui.menu.MenuHandler
import com.willfp.eco.internal.gui.menu.asRenderedInventory
import com.willfp.eco.internal.gui.menu.getMenu
import com.willfp.eco.internal.gui.slot.EcoSlot
import com.willfp.eco.util.MenuUtils
import org.apache.commons.lang.Validate
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.Listener
import org.bukkit.event.inventory.ClickType
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.event.inventory.InventoryCloseEvent
class GUIListener(private val plugin: EcoPlugin) : Listener {
@EventHandler
@EventHandler(priority = EventPriority.HIGH)
fun handleSlotClick(event: InventoryClickEvent) {
val player = event.whoClicked
if (player !is Player) {
return
}
val menu = MenuHandler.getMenu(event.clickedInventory ?: return) ?: return
val rendered = event.clickedInventory?.asRenderedInventory() ?: return
val menu = rendered.menu
val (row, column) = MenuUtils.convertSlotToRowColumn(event.slot)
val slot = menu.getSlot(row, column)
Validate.isTrue(slot is EcoSlot, "Slot not instance of EcoSlot!")
val ecoSlot = menu.getSlot(row, column) as EcoSlot
event.isCancelled = true
ecoSlot.handleInventoryClick(event, menu)
if (event.clickedInventory == null) {
return
}
val slot = menu.getSlot(row, column) as? EcoSlot ?: return
val extendedInventory = MenuHandler.getExtendedInventory(event.clickedInventory!!) ?: return
slot.handleInventoryClick(event, menu)
plugin.scheduler.run { extendedInventory.refresh(player) }
plugin.scheduler.run { rendered.render() }
}
@EventHandler
fun handleCaptivatorSlots(event: InventoryClickEvent) {
val player = event.whoClicked
if (player !is Player) {
return
}
MenuHandler.getMenu(player.openInventory.topInventory) ?: return
MenuHandler.getExtendedInventory(player.openInventory.topInventory) ?: return
plugin.scheduler.run { MenuHandler.getExtendedInventory(player.openInventory.topInventory)?.refresh(player) }
}
@EventHandler
@EventHandler(priority = EventPriority.HIGH)
fun handleShiftClick(event: InventoryClickEvent) {
if (!(event.click == ClickType.SHIFT_RIGHT || event.click == ClickType.SHIFT_LEFT)) {
if (!event.isShiftClick) {
return
}
val player = event.whoClicked
if (player !is Player) {
return
}
val player = event.whoClicked as? Player ?: return
val inv = player.openInventory.topInventory
@@ -69,33 +44,26 @@ class GUIListener(private val plugin: EcoPlugin) : Listener {
return
}
val menu = MenuHandler.getMenu(inv) ?: return
val menu = inv.getMenu() ?: return
val rendered = inv.asRenderedInventory() ?: return
val (row, column) = MenuUtils.convertSlotToRowColumn(inv.firstEmpty())
val slot = menu.getSlot(row, column)
if (!slot.isCaptive) {
event.isCancelled = true
}
plugin.scheduler.run { rendered.render() }
}
@EventHandler(priority = EventPriority.HIGH)
fun handleClose(event: InventoryCloseEvent) {
val player = event.player
if (player !is Player) {
return
}
val menu = MenuHandler.getMenu(event.inventory) ?: return
Validate.isTrue(menu is EcoMenu, "Menu not instance of EcoMenu!")
val ecoMenu = menu as EcoMenu
ecoMenu.handleClose(event)
val menu = event.inventory.getMenu() as? EcoMenu ?: return
DropQueue(player)
.addItems(ecoMenu.getCaptiveItems(player))
.setLocation(player.location)
.forceTelekinesis()
.push()
menu.handleClose(event)
plugin.scheduler.run { MenuHandler.unregisterMenu(event.inventory) }
plugin.scheduler.run { MenuHandler.unregisterInventory(event.inventory) }
}
}
}

View File

@@ -2,13 +2,13 @@ package com.willfp.eco.internal.spigot.integrations.customentities
import com.willfp.eco.core.entities.CustomEntity
import com.willfp.eco.core.integrations.customentities.CustomEntitiesWrapper
import io.lumine.xikage.mythicmobs.MythicMobs
import io.lumine.mythic.bukkit.MythicBukkit
import org.bukkit.NamespacedKey
class CustomEntitiesMythicMobs : CustomEntitiesWrapper {
override fun registerAllEntities() {
val mobManager = MythicMobs.inst().mobManager
val api = MythicMobs.inst().apiHelper
val mobManager = MythicBukkit.inst().mobManager
val api = MythicBukkit.inst().apiHelper
for (id in mobManager.mobNames) {
val key = NamespacedKey.fromString("mythicmobs:${id.lowercase()}")

View File

@@ -14,7 +14,7 @@ import org.bukkit.inventory.ItemStack
import java.util.function.Predicate
class CustomItemsCustomCrafting : CustomItemsWrapper {
override fun registerAllItems() {
override fun registerProvider() {
Items.registerItemProvider(CustomCraftingProvider())
}

View File

@@ -11,7 +11,7 @@ import org.bukkit.inventory.ItemStack
import java.util.function.Predicate
class CustomItemsExecutableItems : CustomItemsWrapper {
override fun registerAllItems() {
override fun registerProvider() {
Items.registerItemProvider(ExecutableItemsProvider())
}

View File

@@ -23,7 +23,7 @@ class CustomItemsHeadDatabase(
plugin.eventManager.registerListener(provider)
}
override fun registerAllItems() {
override fun registerProvider() {
Items.registerItemProvider(HeadDBProvider())
}
@@ -35,7 +35,7 @@ class CustomItemsHeadDatabase(
private lateinit var api: HeadDatabaseAPI
override fun provideForKey(key: String): TestableItem? {
if (this::api.isInitialized) {
if (!this::api.isInitialized) {
return null
}

View File

@@ -11,7 +11,7 @@ import org.bukkit.inventory.ItemStack
import java.util.function.Predicate
class CustomItemsItemsAdder : CustomItemsWrapper {
override fun registerAllItems() {
override fun registerProvider() {
Items.registerItemProvider(ItemsAdderProvider())
}

View File

@@ -4,14 +4,14 @@ import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.integrations.customitems.CustomItemsWrapper
import com.willfp.eco.core.items.Items
import com.willfp.eco.core.recipe.parts.EmptyTestableItem
import io.lumine.xikage.mythicmobs.adapters.bukkit.BukkitItemStack
import io.lumine.xikage.mythicmobs.api.bukkit.events.MythicDropLoadEvent
import io.lumine.xikage.mythicmobs.drops.Drop
import io.lumine.xikage.mythicmobs.drops.DropMetadata
import io.lumine.xikage.mythicmobs.drops.IMultiDrop
import io.lumine.xikage.mythicmobs.drops.LootBag
import io.lumine.xikage.mythicmobs.drops.droppables.ItemDrop
import io.lumine.xikage.mythicmobs.io.MythicLineConfig
import io.lumine.mythic.api.config.MythicLineConfig
import io.lumine.mythic.api.drops.DropMetadata
import io.lumine.mythic.api.drops.IMultiDrop
import io.lumine.mythic.bukkit.adapters.BukkitItemStack
import io.lumine.mythic.bukkit.events.MythicDropLoadEvent
import io.lumine.mythic.core.drops.Drop
import io.lumine.mythic.core.drops.LootBag
import io.lumine.mythic.core.drops.droppables.ItemDrop
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
@@ -26,10 +26,6 @@ class CustomItemsMythicMobs(
return "MythicMobs"
}
override fun registerAllItems() {
// Do nothing.
}
@EventHandler
fun onLoad(event: MythicDropLoadEvent) {
val name = event.dropName
@@ -42,9 +38,9 @@ class CustomItemsMythicMobs(
private class MythicMobsDrop(
private val plugin: EcoPlugin,
private val config: MythicLineConfig
) : Drop(config.line, config), IMultiDrop {
private val id = config.getString(arrayOf("type", "t", "item", "i"), this.dropVar)
itemConfig: MythicLineConfig
) : Drop(itemConfig.line, itemConfig), IMultiDrop {
private val id = itemConfig.getString(arrayOf("type", "t", "item", "i"), this.dropVar)
override fun get(data: DropMetadata): LootBag {
val bag = LootBag(data)

View File

@@ -2,33 +2,31 @@ package com.willfp.eco.internal.spigot.integrations.customitems
import com.willfp.eco.core.integrations.customitems.CustomItemsWrapper
import com.willfp.eco.core.items.CustomItem
import com.willfp.eco.core.items.Items
import com.willfp.eco.core.items.TestableItem
import com.willfp.eco.core.items.provider.ItemProvider
import com.willfp.eco.util.NamespacedKeyUtils
import io.th0rgal.oraxen.items.OraxenItems
import org.bukkit.NamespacedKey
import org.bukkit.inventory.ItemStack
import java.util.Objects
import java.util.function.Predicate
class CustomItemsOraxen : CustomItemsWrapper {
override fun registerAllItems() {
for (item in OraxenItems.getItems()) {
val stack = item.build()
val id: String = Objects.requireNonNullElse(OraxenItems.getIdByItem(item), "")
if (id.isEmpty()) {
continue
}
val key: NamespacedKey = NamespacedKeyUtils.create("oraxen", id.lowercase())
CustomItem(
key, Predicate { test: ItemStack ->
val oraxenId: String = OraxenItems.getIdByItem(test) ?: return@Predicate false
oraxenId.equals(id, ignoreCase = true)
},
stack
).register()
}
override fun registerProvider() {
Items.registerItemProvider(OraxenProvider())
}
override fun getPluginName(): String {
return "Oraxen"
}
}
private class OraxenProvider : ItemProvider("oraxen") {
override fun provideForKey(key: String): TestableItem? {
val item = OraxenItems.getItemById(key) ?: return null
val id = OraxenItems.getIdByItem(item)
val namespacedKey = NamespacedKeyUtils.create("oraxen", id)
return CustomItem(
namespacedKey,
{ id.equals(OraxenItems.getIdByItem(it), ignoreCase = true) },
item.build()
)
}
}
}

View File

@@ -42,20 +42,4 @@ softdepend:
- MythicMobs
- CustomCrafting
- ExecutableItems
- RPGHorses
libraries:
- 'org.reflections:reflections:0.9.12'
- 'org.apache.maven:maven-artifact:3.0.3'
- 'org.jetbrains.kotlin:kotlin-stdlib:1.6.10'
- 'net.kyori:adventure-platform-bukkit:4.1.0'
- 'net.kyori:adventure-api:4.10.0'
- 'net.kyori:adventure-text-serializer-gson:4.10.0'
- 'net.kyori:adventure-text-serializer-legacy:4.10.0'
- 'org.jetbrains.exposed:exposed-core:0.37.3'
- 'org.jetbrains.exposed:exposed-dao:0.37.3'
- 'org.jetbrains.exposed:exposed-jdbc:0.37.3'
- 'mysql:mysql-connector-java:8.0.25'
- 'com.google.guava:guava:31.1-jre'
- 'com.zaxxer:HikariCP:5.0.0'
- 'org.objenesis:objenesis:3.2'
- 'com.github.ben-manes.caffeine:caffeine:3.0.5'
- RPGHorses

View File

@@ -1,3 +1,3 @@
version = 6.28.3
version = 6.32.1
plugin-name = eco
kotlin.code.style = official