Compare commits

..

103 Commits

Author SHA1 Message Date
Auxilor
c69bb6904f Minor fixes 2022-04-20 11:31:37 +01:00
Auxilor
9f193b7206 Fixed val using annotations 2022-04-20 11:28:55 +01:00
Auxilor
6fce2c13fe Updated to 6.34.0 2022-04-20 11:25:19 +01:00
Auxilor
02342c11a6 Added utility methods for base NBT 2022-04-20 11:25:00 +01:00
Auxilor
2fde56df0d Added ability to modify full item NBT via PersistentDataContainers and FastItemStack 2022-04-20 11:19:24 +01:00
Auxilor
cb64dedd74 Updated to kotlin 1.6.21 2022-04-20 10:57:27 +01:00
Auxilor
a7c489413e Moved IridiumSkyblock to use jar 2022-04-20 10:56:47 +01:00
Auxilor
f9ed174e31 Added PersistentDataHolder to FastItemStack 2022-04-13 13:21:37 +01:00
Auxilor
496d878a14 Added missing FIS method 2022-04-13 12:55:48 +01:00
Auxilor
00853d4a92 Fixed getSkullTexture 2022-04-13 12:39:32 +01:00
Auxilor
5eb0d2380a Updated to 6.33.0 2022-04-13 12:37:19 +01:00
Auxilor
d19cff9a42 Added component methods to FastItemStack 2022-04-13 12:36:49 +01:00
Auxilor
234b5fdd8e Fixed newbiehelper and bentobox 2022-04-11 15:02:29 +01:00
Auxilor
2dbe6c7fe4 Updated to 6.32.2 2022-04-11 14:55:48 +01:00
Auxilor
9d4d1ace08 Fixed use_spell and tempt 2022-04-11 14:55:35 +01:00
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
Auxilor
a9c906843d Updated to 6.28.3 2022-03-13 16:59:14 +00:00
Auxilor
85861971d3 Added wildcard material testable items 2022-03-13 16:59:02 +00:00
Auxilor
bdb24e5a14 Updated to 6.28.2 2022-03-12 21:03:59 +00:00
Auxilor
cb481d4532 Fixed 1.17.1 and 1.18.1 errors 2022-03-12 21:03:45 +00:00
Auxilor
97fba3e243 Updated to 6.28.1 2022-03-11 16:29:15 +00:00
Auxilor
e47c6387a2 Injecting placeholders now clears config cache 2022-03-11 16:29:05 +00:00
Auxilor
00df39097c Fixed statics in expressions 2022-03-11 16:28:21 +00:00
Auxilor
efcb406e9a Revert "Updated to 6.28.1"
This reverts commit 9e92ea6062.
2022-03-11 10:52:36 +00:00
Auxilor
9e92ea6062 Updated to 6.28.1 2022-03-11 10:41:43 +00:00
116 changed files with 1872 additions and 2085 deletions

View File

@@ -4,7 +4,7 @@ buildscript {
}
dependencies {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21")
}
}
@@ -13,7 +13,7 @@ plugins {
id("com.github.johnrengelman.shadow") version "7.1.2"
id("maven-publish")
id("java")
kotlin("jvm") version "1.6.10"
kotlin("jvm") version "1.6.21"
}
dependencies {
@@ -71,9 +71,6 @@ allprojects {
// CombatLogX
maven("https://nexus.sirblobman.xyz/repository/public/")
// IridiumSkyblock
maven("https://nexus.iridiumdevelopment.net/repository/maven-releases/")
// MythicMobs
maven("https://mvn.lumine.io/repository/maven-public/")
@@ -85,21 +82,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.21"))
}
tasks.withType<JavaCompile> {
@@ -115,10 +116,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 +135,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

@@ -1,10 +1,13 @@
package com.willfp.eco.core.fast;
import com.willfp.eco.core.Eco;
import net.kyori.adventure.text.Component;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataHolder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -16,7 +19,7 @@ import java.util.Set;
/**
* FastItemStack contains methods to modify and read items faster than in default bukkit.
*/
public interface FastItemStack {
public interface FastItemStack extends PersistentDataHolder {
/**
* Get all enchantments on an item.
*
@@ -24,7 +27,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);
}
@@ -45,17 +48,54 @@ public interface FastItemStack {
* @param checkStored If stored enchantments should be accounted for.
* @return A map of all enchantments.
*/
@NotNull
Map<Enchantment, Integer> getEnchants(boolean checkStored);
/**
* Get the level of an enchantment on an item.
*
* @param enchantment The enchantment.
* @return The enchantment level, or 0 if not found.
* @deprecated Poorly named method. Use getEnchantmentLevel instead.
*/
@Deprecated(since = "6.34.0", forRemoval = true)
default int getLevelOnItem(@NotNull Enchantment enchantment) {
return getEnchantmentLevel(enchantment, false);
}
/**
* Get the level of an enchantment on an item.
*
* @param enchantment The enchantment.
* @param checkStored If the stored NBT should also be checked.
* @return The enchantment level, or 0 if not found.
* @deprecated Poorly named method. Use getEnchantmentLevel instead.
*/
int getLevelOnItem(@NotNull Enchantment enchantment,
boolean checkStored);
@Deprecated(since = "6.34.0", forRemoval = true)
default int getLevelOnItem(@NotNull Enchantment enchantment,
boolean checkStored) {
return getEnchantmentLevel(enchantment, checkStored);
}
/**
* Get the level of an enchantment.
*
* @param enchantment The enchantment.
* @return The enchantment level, or 0 if not found.
*/
default int getEnchantmentLevel(@NotNull Enchantment enchantment) {
return getLevelOnItem(enchantment, false);
}
/**
* Get the level of an enchantment.
*
* @param enchantment The enchantment.
* @param checkStored If the stored NBT should also be checked.
* @return The enchantment level, or 0 if not found.
*/
int getEnchantmentLevel(@NotNull Enchantment enchantment,
boolean checkStored);
/**
* Set the item lore.
@@ -64,6 +104,13 @@ public interface FastItemStack {
*/
void setLore(@Nullable List<String> lore);
/**
* Set the item lore.
*
* @param lore The lore.
*/
void setLoreComponents(@Nullable List<Component> lore);
/**
* Get the item lore.
*
@@ -71,6 +118,40 @@ public interface FastItemStack {
*/
List<String> getLore();
/**
* Get the item lore.
*
* @return The lore.
*/
List<Component> getLoreComponents();
/**
* Set the item name.
*
* @param name The name.
*/
void setDisplayName(@Nullable Component name);
/**
* Set the item name.
*
* @param name The name.
*/
void setDisplayName(@Nullable String name);
/**
* Get the item display name.
*
* @return The display name.
*/
Component getDisplayNameComponent();
/**
* Get the item display name.
*
* @return The display name.
*/
String getDisplayName();
/**
* Set the rework penalty.
@@ -81,7 +162,6 @@ public interface FastItemStack {
/**
* Get the rework penalty.
* .
*
* @return The rework penalty found on the item.
*/
@@ -116,11 +196,28 @@ public interface FastItemStack {
*/
boolean hasItemFlag(@NotNull ItemFlag flag);
/**
* Get the base NBT tag (Not PublicBukkitValues, the base) as a PersistentDataContainer.
* <p>
* The returned PersistentDataContainer will not modify the item until the tag is set.
*
* @return The base NBT tag.
*/
PersistentDataContainer getBaseTag();
/**
* Set the base NBT tag (Not PublicBukkitValues, the base) from a PersistentDataContainer.
*
* @param container The PersistentDataContainer.
*/
void setBaseTag(@Nullable PersistentDataContainer container);
/**
* Get the Bukkit ItemStack again.
*
* @return The ItemStack.
*/
@NotNull
ItemStack unwrap();
/**

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

@@ -2,18 +2,22 @@ package com.willfp.eco.core.items;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.willfp.eco.core.fast.FastItemStack;
import com.willfp.eco.core.items.args.LookupArgParser;
import com.willfp.eco.core.items.provider.ItemProvider;
import com.willfp.eco.core.recipe.parts.EmptyTestableItem;
import com.willfp.eco.core.recipe.parts.MaterialTestableItem;
import com.willfp.eco.core.recipe.parts.ModifiedTestableItem;
import com.willfp.eco.core.recipe.parts.TestableStack;
import com.willfp.eco.core.recipe.parts.UnrestrictedMaterialTestableItem;
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.bukkit.persistence.PersistentDataContainer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -114,6 +118,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>
@@ -155,11 +201,16 @@ public final class Items {
String[] split = args[0].toLowerCase().split(":");
if (split.length == 1) {
Material material = Material.getMaterial(args[0].toUpperCase());
String itemType = args[0];
boolean isWildcard = itemType.startsWith("*");
if (isWildcard) {
itemType = itemType.substring(1);
}
Material material = Material.getMaterial(itemType.toUpperCase());
if (material == null || material == Material.AIR) {
return new EmptyTestableItem();
}
item = new MaterialTestableItem(material);
item = isWildcard ? new UnrestrictedMaterialTestableItem(material) : new MaterialTestableItem(material);
}
if (split.length == 2) {
@@ -183,11 +234,16 @@ public final class Items {
This has been superseded by id amount
*/
if (part == null) {
Material material = Material.getMaterial(split[0].toUpperCase());
String itemType = split[0];
boolean isWildcard = itemType.startsWith("*");
if (isWildcard) {
itemType = itemType.substring(1);
}
Material material = Material.getMaterial(itemType.toUpperCase());
if (material == null || material == Material.AIR) {
return new EmptyTestableItem();
}
item = new MaterialTestableItem(material);
item = isWildcard ? new UnrestrictedMaterialTestableItem(material) : new MaterialTestableItem(material);
stackAmount = Integer.parseInt(split[1]);
} else {
item = part;
@@ -377,6 +433,90 @@ 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;
}
/**
* Get the base NBT tag on an item.
*
* @param itemStack The ItemStack.
* @return The base NBT.
*/
@NotNull
public static PersistentDataContainer getBaseNBT(@NotNull final ItemStack itemStack) {
return FastItemStack.wrap(itemStack).getBaseTag();
}
/**
* Set the base NBT tag on an item.
*
* @param itemStack The ItemStack.
* @param container The base NBT tag.
* @return The ItemStack, modified. Not required to use, as this modifies the instance.¬
*/
@NotNull
public static ItemStack setBaseNBT(@NotNull final ItemStack itemStack,
@Nullable final PersistentDataContainer container) {
FastItemStack fis = FastItemStack.wrap(itemStack);
fis.setBaseTag(container);
return fis.unwrap();
}
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

@@ -0,0 +1,32 @@
package com.willfp.eco.core.recipe.parts;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Same as material testable items, but doesn't filter out custom items.
*/
public class UnrestrictedMaterialTestableItem extends MaterialTestableItem {
/**
* Create a new simple recipe part.
*
* @param material The material.
*/
public UnrestrictedMaterialTestableItem(@NotNull final Material material) {
super(material);
}
/**
* If the item matches the material.
*
* @param itemStack The item to test.
* @return If the item is of the specified material.
*/
@Override
public boolean matches(@Nullable final ItemStack itemStack) {
return itemStack != null && itemStack.getType() == this.getMaterial();
}
}

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

@@ -1,5 +1,6 @@
package com.willfp.eco.util;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
@@ -76,33 +77,37 @@ public final class StringUtils {
.build(StringUtils::processFormatting);
/**
* Json -> Legacy Cache.
* Json -> Component Cache.
*/
private static final LoadingCache<String, String> JSON_TO_LEGACY = Caffeine.newBuilder()
private static final Cache<String, Component> JSON_TO_COMPONENT = Caffeine.newBuilder()
.expireAfterAccess(10, TimeUnit.SECONDS)
.build(
json -> {
try {
Component component = GSON_COMPONENT_SERIALIZER.deserialize(json);
return LEGACY_COMPONENT_SERIALIZER.serialize(component);
} catch (JsonSyntaxException e) {
return json;
}
}
);
.build();
/**
* Legacy -> Json Cache.
* Component -> Json Cache.
*/
private static final LoadingCache<String, String> LEGACY_TO_JSON = Caffeine.newBuilder()
private static final Cache<Component, String> COMPONENT_TO_JSON = Caffeine.newBuilder()
.expireAfterAccess(10, TimeUnit.SECONDS)
.build(
legacy -> GSON_COMPONENT_SERIALIZER.serialize(
Component.empty().decoration(TextDecoration.ITALIC, false).append(
LEGACY_COMPONENT_SERIALIZER.deserialize(legacy)
)
)
);
.build();
/**
* Legacy -> Component Cache.
*/
private static final Cache<String, Component> LEGACY_TO_COMPONENT = Caffeine.newBuilder()
.expireAfterAccess(10, TimeUnit.SECONDS)
.build();
/**
* Component -> Legacy Cache.
*/
private static final Cache<Component, String> COMPONENT_TO_LEGACY = Caffeine.newBuilder()
.expireAfterAccess(10, TimeUnit.SECONDS)
.build();
/**
* Empty JSON.
*/
private static final String EMPTY_JSON = GSON_COMPONENT_SERIALIZER.serialize(Component.empty());
/**
* Color map.
@@ -483,12 +488,7 @@ public final class StringUtils {
*/
@NotNull
public static String legacyToJson(@Nullable final String legacy) {
String processed = legacy;
if (legacy == null) {
processed = "";
}
return LEGACY_TO_JSON.get(processed);
return componentToJson(toComponent(legacy));
}
/**
@@ -499,11 +499,53 @@ public final class StringUtils {
*/
@NotNull
public static String jsonToLegacy(@Nullable final String json) {
if (json == null || json.isEmpty()) {
return "";
return toLegacy(jsonToComponent(json));
}
/**
* Convert Component to JSON String.
*
* @param component The Component.
* @return The JSON string.
*/
@NotNull
public static String componentToJson(@Nullable final Component component) {
if (component == null) {
return EMPTY_JSON;
}
return JSON_TO_LEGACY.get(json);
return COMPONENT_TO_JSON.get(component, it -> {
try {
return GSON_COMPONENT_SERIALIZER.serialize(
Component.empty().decoration(TextDecoration.ITALIC, false).append(
it
)
);
} catch (JsonSyntaxException e) {
return GSON_COMPONENT_SERIALIZER.serialize(Component.empty());
}
});
}
/**
* Convert JSON String to Component.
*
* @param json The JSON String.
* @return The component.
*/
@NotNull
public static Component jsonToComponent(@Nullable final String json) {
if (json == null || json.isEmpty()) {
return Component.empty();
}
return JSON_TO_COMPONENT.get(json, it -> {
try {
return GSON_COMPONENT_SERIALIZER.deserialize(it);
} catch (JsonSyntaxException e) {
return Component.empty();
}
});
}
/**
@@ -514,12 +556,7 @@ public final class StringUtils {
*/
@NotNull
public static Component toComponent(@Nullable final String legacy) {
String processed = legacy;
if (legacy == null) {
processed = "";
}
return LEGACY_COMPONENT_SERIALIZER.deserialize(processed);
return LEGACY_TO_COMPONENT.get(legacy == null ? "" : legacy, LEGACY_COMPONENT_SERIALIZER::deserialize);
}
/**
@@ -530,7 +567,7 @@ public final class StringUtils {
*/
@NotNull
public static String toLegacy(@NotNull final Component component) {
return LEGACY_COMPONENT_SERIALIZER.serialize(component);
return COMPONENT_TO_LEGACY.get(component, LEGACY_COMPONENT_SERIALIZER::serialize);
}
/**

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,41 @@
@file:JvmName("ItemsExtensions")
package com.willfp.eco.core.items
import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.ItemMeta
import org.bukkit.persistence.PersistentDataContainer
/**
* @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)
/**
* @see Items.getBaseNBT
* @see Items.setBaseNBT
*/
var ItemStack.baseNBT: PersistentDataContainer
get() = Items.getBaseNBT(this)
set(value) {
Items.setBaseNBT(this, value)
}
/**
* @see Items.setBaseNBT
*/
fun ItemStack.clearNBT() =
Items.setBaseNBT(this, null)

View File

@@ -11,12 +11,24 @@ import org.bukkit.entity.Player
fun String.toComponent(): Component =
StringUtils.toComponent(this)
/**
* @see StringUtils.jsonToComponent
*/
fun String.jsonToComponent(): Component =
StringUtils.jsonToComponent(this)
/**
* @see StringUtils.toLegacy
*/
fun Component.toLegacy(): String =
StringUtils.toLegacy(this)
/**
* @see StringUtils.componentToJson
*/
fun Component.toJSON(): String =
StringUtils.componentToJson(this)
/**
* @see StringUtils.format
*/

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,231 +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)
}
override fun getInjectedPlaceholders(): List<StaticPlaceholder> {
return injections.toList()
}
override fun clearInjectedPlaceholders() {
injections.clear()
}
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,257 +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)
}
override fun getInjectedPlaceholders(): List<StaticPlaceholder> {
return injections.toList()
}
override fun clearInjectedPlaceholders() {
injections.clear()
}
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

@@ -4,12 +4,17 @@ import com.willfp.eco.core.entities.ai.EntityGoal
import com.willfp.eco.core.entities.ai.TargetGoal
import com.willfp.eco.internal.spigot.proxy.common.ai.EntityGoalFactory
import com.willfp.eco.internal.spigot.proxy.common.ai.TargetGoalFactory
import net.minecraft.core.Registry
import net.minecraft.nbt.CompoundTag
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.item.Item
import org.bukkit.Material
import org.bukkit.NamespacedKey
import org.bukkit.entity.Mob
import org.bukkit.inventory.ItemStack
import org.bukkit.persistence.PersistentDataContainer
private lateinit var impl: CommonsProvider
@@ -39,9 +44,27 @@ fun <T : EntityGoal<*>> T.getVersionSpecificEntityGoalFactory(): EntityGoalFacto
fun <T : TargetGoal<*>> T.getVersionSpecificEntityGoalFactory(): TargetGoalFactory<T>? =
impl.getVersionSpecificTargetGoalFactory(this)
private val MATERIAL_TO_ITEM = mutableMapOf<Material, Item>()
fun Material.toItem(): Item =
MATERIAL_TO_ITEM.getOrPut(this) {
Registry.ITEM.getOptional(this.key.toResourceLocation())
.orElseThrow { IllegalArgumentException("Material is not item!") }
}
fun CompoundTag.makePdc(base: Boolean = false): PersistentDataContainer =
impl.makePdc(this, base)
fun CompoundTag.setPdc(pdc: PersistentDataContainer?, item: net.minecraft.world.item.ItemStack? = null) =
impl.setPdc(this, pdc, item)
interface CommonsProvider {
val nbtTagString: Int
fun makePdc(tag: CompoundTag, base: Boolean): PersistentDataContainer
fun setPdc(tag: CompoundTag, pdc: PersistentDataContainer?, item: net.minecraft.world.item.ItemStack? = null)
fun toPathfinderMob(mob: Mob): PathfinderMob?
fun toResourceLocation(namespacedKey: NamespacedKey): ResourceLocation

View File

@@ -10,9 +10,6 @@ import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.entity.ai.goal.Goal
import net.minecraft.world.entity.ai.goal.TemptGoal
import net.minecraft.world.entity.ai.targeting.TargetingConditions
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftLivingEntity
import org.bukkit.craftbukkit.v1_17_R1.event.CraftEventFactory
import org.bukkit.event.entity.EntityTargetEvent
import java.util.EnumSet
import kotlin.math.abs
@@ -57,19 +54,6 @@ class EnhancedTemptGoal(
false
} else {
player = mob.level.getNearestPlayer(targetingConditions, mob as LivingEntity)
// CraftBukkit start
if (player != null) {
val event = CraftEventFactory.callEntityTargetLivingEvent(
mob,
player,
EntityTargetEvent.TargetReason.TEMPT
)
if (event.isCancelled) {
return false
}
player = if (event.target == null) null else (event.target as CraftLivingEntity?)!!.handle
}
// CraftBukkit end
player != null
}
}

View File

@@ -5,7 +5,6 @@ import net.minecraft.world.entity.EntityType
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.goal.Goal
import net.minecraft.world.entity.monster.SpellcasterIllager
import org.bukkit.craftbukkit.v1_17_R1.event.CraftEventFactory
@Suppress("UNCHECKED_CAST")
class DelegatedSpellcaster(private val handle: SpellcasterIllager) : SpellcasterIllager(
@@ -66,15 +65,6 @@ abstract class OpenUseSpellGoal(
override fun tick() {
--attackWarmupDelay
if (attackWarmupDelay == 0) {
// CraftBukkit start
if (!CraftEventFactory.handleEntitySpellCastEvent(
handle,
spell
)
) {
return
}
// CraftBukkit end
performSpellCasting()
handle.playSound(openHandle.openCastingSoundEvent, 1.0f, 1.0f)
}

View File

@@ -3,25 +3,34 @@ package com.willfp.eco.internal.spigot.proxy.common.fast
import com.willfp.eco.core.fast.FastItemStack
import com.willfp.eco.internal.spigot.proxy.common.NBT_TAG_STRING
import com.willfp.eco.internal.spigot.proxy.common.asNMSStack
import com.willfp.eco.internal.spigot.proxy.common.makePdc
import com.willfp.eco.internal.spigot.proxy.common.mergeIfNeeded
import com.willfp.eco.internal.spigot.proxy.common.setPdc
import com.willfp.eco.internal.spigot.proxy.common.toItem
import com.willfp.eco.util.NamespacedKeyUtils
import com.willfp.eco.util.StringUtils
import com.willfp.eco.util.toComponent
import com.willfp.eco.util.toLegacy
import net.kyori.adventure.text.Component
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
import net.minecraft.nbt.StringTag
import net.minecraft.world.item.EnchantedBookItem
import net.minecraft.world.item.Item
import net.minecraft.world.item.Items
import org.bukkit.NamespacedKey
import org.bukkit.enchantments.Enchantment
import org.bukkit.inventory.ItemFlag
import org.bukkit.persistence.PersistentDataContainer
import org.bukkit.persistence.PersistentDataType
import kotlin.experimental.and
@Suppress("UsePropertyAccessSyntax")
class EcoFastItemStack(
private val bukkit: org.bukkit.inventory.ItemStack
) : FastItemStack {
private var loreCache: List<String>? = null
private val handle = bukkit.asNMSStack()
private val pdc = (if (handle.hasTag()) handle.getTag()!! else CompoundTag()).makePdc()
override fun getEnchants(checkStored: Boolean): Map<Enchantment, Int> {
val enchantmentNBT =
@@ -41,7 +50,7 @@ class EcoFastItemStack(
return foundEnchantments
}
override fun getLevelOnItem(
override fun getEnchantmentLevel(
enchantment: Enchantment,
checkStored: Boolean
): Int {
@@ -60,13 +69,14 @@ class EcoFastItemStack(
return 0
}
override fun setLore(lore: List<String>?) {
loreCache = null
val jsonLore: MutableList<String> = ArrayList()
override fun setLore(lore: List<String>?) = setLoreComponents(lore?.map { it.toComponent() })
override fun setLoreComponents(lore: List<Component>?) {
val jsonLore = mutableListOf<String>()
if (lore != null) {
for (s in lore) {
jsonLore.add(StringUtils.legacyToJson(s))
jsonLore.add(StringUtils.componentToJson(s))
}
}
@@ -87,17 +97,7 @@ class EcoFastItemStack(
apply()
}
override fun getLore(): List<String> {
if (loreCache != null) {
return loreCache!!
}
val lore = this.getLoreJSON().map { StringUtils.jsonToLegacy(it) }
loreCache = lore
return lore
}
private fun getLoreJSON(): List<String> {
override fun getLoreComponents(): List<Component> {
val displayTag = handle.getTagElement("display") ?: return emptyList()
if (!displayTag.contains("Lore")) {
@@ -105,15 +105,47 @@ class EcoFastItemStack(
}
val loreTag = displayTag.getList("Lore", NBT_TAG_STRING)
val lore = ArrayList<String>(loreTag.size)
val jsonLore = mutableListOf<String>()
for (i in loreTag.indices) {
lore.add(loreTag.getString(i))
jsonLore.add(loreTag.getString(i))
}
return lore
return jsonLore.map { StringUtils.jsonToComponent(it) }
}
override fun getLore(): List<String> =
getLoreComponents().map { StringUtils.toLegacy(it) }
override fun setDisplayName(name: Component?) {
val displayTag = handle.getOrCreateTagElement("display")
displayTag.remove("Name")
if (name != null) {
displayTag.put("Name", StringTag.valueOf(StringUtils.componentToJson(name)))
}
apply()
}
override fun setDisplayName(name: String?) = setDisplayName(name?.toComponent())
override fun getDisplayNameComponent(): Component {
val displayTag =
handle.getTagElement("display") ?: return Component.translatable(bukkit.type.toItem().getDescriptionId())
if (!displayTag.contains("Name")) {
return Component.translatable(bukkit.type.toItem().getDescriptionId())
}
val nameTag = displayTag.getString("Name")
return StringUtils.jsonToComponent(nameTag)
}
override fun getDisplayName(): String = displayNameComponent.toLegacy()
override fun addItemFlags(vararg hideFlags: ItemFlag) {
for (flag in hideFlags) {
this.flagBits = this.flagBits or getBitModifier(flag)
@@ -151,6 +183,14 @@ class EcoFastItemStack(
return this.flagBits and bitModifier == bitModifier
}
override fun getBaseTag(): PersistentDataContainer =
(if (handle.hasTag()) handle.getTag()!! else CompoundTag()).makePdc(base = true)
override fun setBaseTag(container: PersistentDataContainer?) {
(if (handle.hasTag()) handle.getTag()!! else CompoundTag()).setPdc(container, item = handle)
apply()
}
@Suppress("UNNECESSARY_NOT_NULL_ASSERTION")
private var flagBits: Int
get() =
@@ -170,6 +210,10 @@ class EcoFastItemStack(
handle.setRepairCost(cost)
}
override fun getPersistentDataContainer(): PersistentDataContainer {
return ContinuallyAppliedPersistentDataContainer(this.pdc, this)
}
override fun equals(other: Any?): Boolean {
if (other !is EcoFastItemStack) {
return false
@@ -183,7 +227,11 @@ class EcoFastItemStack(
return handle.getTag()?.hashCode() ?: (0b00010101 * 31 + Item.getId(handle.getItem()))
}
private fun apply() {
internal fun apply() {
if (handle.hasTag()) {
handle.getTag()?.setPdc(this.pdc)
}
bukkit.mergeIfNeeded(handle)
}
@@ -195,3 +243,18 @@ class EcoFastItemStack(
return bukkit
}
}
private class ContinuallyAppliedPersistentDataContainer(
val handle: PersistentDataContainer,
val fis: EcoFastItemStack
) : PersistentDataContainer by handle {
override fun <T : Any, Z : Any> set(key: NamespacedKey, type: PersistentDataType<T, Z>, value: Z) {
handle.set(key, type, value)
fis.apply()
}
override fun remove(key: NamespacedKey) {
handle.remove(key)
fis.apply()
}
}

View File

@@ -62,7 +62,8 @@ class ChatComponent : ChatComponentProxy {
}
val newShowItem = showItem.nbt(
BinaryTagHolder.binaryTagHolder(
@Suppress("UnstableApiUsage", "DEPRECATION")
BinaryTagHolder.of(
CraftItemStack.asNMSCopy(
Display.display(
CraftItemStack.asBukkitCopy(

View File

@@ -2,6 +2,8 @@ package com.willfp.eco.internal.spigot.proxy.v1_17_R1
import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy
import com.willfp.eco.internal.spigot.proxy.common.CommonsProvider
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.PathfinderMob
import org.bukkit.Bukkit
@@ -10,11 +12,14 @@ import org.bukkit.craftbukkit.v1_17_R1.CraftServer
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEntity
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftMob
import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack
import org.bukkit.craftbukkit.v1_17_R1.persistence.CraftPersistentDataContainer
import org.bukkit.craftbukkit.v1_17_R1.persistence.CraftPersistentDataTypeRegistry
import org.bukkit.craftbukkit.v1_17_R1.util.CraftMagicNumbers
import org.bukkit.craftbukkit.v1_17_R1.util.CraftNamespacedKey
import org.bukkit.entity.LivingEntity
import org.bukkit.entity.Mob
import org.bukkit.inventory.ItemStack
import org.bukkit.persistence.PersistentDataContainer
import java.lang.reflect.Field
class CommonsInitializer : CommonsInitializerProxy {
@@ -27,6 +32,11 @@ class CommonsInitializer : CommonsInitializerProxy {
isAccessible = true
}
private val pdcRegsitry = Class.forName("org.bukkit.craftbukkit.v1_17_R1.inventory.CraftMetaItem")
.getDeclaredField("DATA_TYPE_REGISTRY")
.apply { isAccessible = true }
.get(null) as CraftPersistentDataTypeRegistry
override val nbtTagString = CraftMagicNumbers.NBT.TAG_STRING
override fun toPathfinderMob(mob: Mob): PathfinderMob? {
@@ -57,5 +67,66 @@ class CommonsInitializer : CommonsInitializerProxy {
override fun toBukkitEntity(entity: net.minecraft.world.entity.LivingEntity): LivingEntity? =
CraftEntity.getEntity(Bukkit.getServer() as CraftServer, entity) as? LivingEntity
override fun makePdc(tag: CompoundTag, base: Boolean): PersistentDataContainer {
fun emptyPdc(): CraftPersistentDataContainer = CraftPersistentDataContainer(pdcRegsitry)
fun CompoundTag?.toPdc(): PersistentDataContainer {
val pdc = emptyPdc()
this ?: return pdc
val keys = this.allKeys
for (key in keys) {
pdc.put(key, this[key])
}
return pdc
}
return if (base) {
tag.toPdc()
} else {
if (tag.contains("PublicBukkitValues")) {
tag.getCompound("PublicBukkitValues").toPdc()
} else {
emptyPdc()
}
}
}
override fun setPdc(
tag: CompoundTag,
pdc: PersistentDataContainer?,
item: net.minecraft.world.item.ItemStack?
) {
fun CraftPersistentDataContainer.toTag(): CompoundTag {
val compound = CompoundTag()
val rawPublicMap: Map<String, Tag> = this.raw
for ((key, value) in rawPublicMap) {
compound.put(key, value)
}
return compound
}
pdc as CraftPersistentDataContainer?
if (item != null) {
if (pdc != null && !pdc.isEmpty) {
for (key in tag.allKeys.toSet()) {
tag.remove(key)
}
tag.merge(pdc.toTag())
} else {
item.setTag(null)
}
} else {
if (pdc != null && !pdc.isEmpty) {
tag.put("PublicBukkitValues", pdc.toTag())
} else {
tag.remove("PublicBukkitValues")
}
}
}
}
}

View File

@@ -39,6 +39,6 @@ class Skull : SkullProxy {
val profile = profile[meta] as GameProfile? ?: return null
val properties = profile.properties ?: return null
val prop = properties["textures"] ?: return null
return prop.toMutableList().firstOrNull()?.name
return prop.toMutableList().firstOrNull()?.value
}
}

View File

@@ -62,7 +62,8 @@ class ChatComponent : ChatComponentProxy {
}
val newShowItem = showItem.nbt(
BinaryTagHolder.binaryTagHolder(
@Suppress("UnstableApiUsage", "DEPRECATION")
BinaryTagHolder.of(
CraftItemStack.asNMSCopy(
Display.display(
CraftItemStack.asBukkitCopy(

View File

@@ -2,6 +2,8 @@ package com.willfp.eco.internal.spigot.proxy.v1_18_R1
import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy
import com.willfp.eco.internal.spigot.proxy.common.CommonsProvider
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.PathfinderMob
import org.bukkit.Bukkit
@@ -10,11 +12,14 @@ import org.bukkit.craftbukkit.v1_18_R1.CraftServer
import org.bukkit.craftbukkit.v1_18_R1.entity.CraftEntity
import org.bukkit.craftbukkit.v1_18_R1.entity.CraftMob
import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftItemStack
import org.bukkit.craftbukkit.v1_18_R1.persistence.CraftPersistentDataContainer
import org.bukkit.craftbukkit.v1_18_R1.persistence.CraftPersistentDataTypeRegistry
import org.bukkit.craftbukkit.v1_18_R1.util.CraftMagicNumbers
import org.bukkit.craftbukkit.v1_18_R1.util.CraftNamespacedKey
import org.bukkit.entity.LivingEntity
import org.bukkit.entity.Mob
import org.bukkit.inventory.ItemStack
import org.bukkit.persistence.PersistentDataContainer
import java.lang.reflect.Field
class CommonsInitializer : CommonsInitializerProxy {
@@ -27,6 +32,11 @@ class CommonsInitializer : CommonsInitializerProxy {
isAccessible = true
}
private val pdcRegsitry = Class.forName("org.bukkit.craftbukkit.v1_18_R1.inventory.CraftMetaItem")
.getDeclaredField("DATA_TYPE_REGISTRY")
.apply { isAccessible = true }
.get(null) as CraftPersistentDataTypeRegistry
override val nbtTagString = CraftMagicNumbers.NBT.TAG_STRING
override fun toPathfinderMob(mob: Mob): PathfinderMob? {
@@ -57,5 +67,66 @@ class CommonsInitializer : CommonsInitializerProxy {
override fun toBukkitEntity(entity: net.minecraft.world.entity.LivingEntity): LivingEntity? =
CraftEntity.getEntity(Bukkit.getServer() as CraftServer, entity) as? LivingEntity
override fun makePdc(tag: CompoundTag, base: Boolean): PersistentDataContainer {
fun emptyPdc(): CraftPersistentDataContainer = CraftPersistentDataContainer(pdcRegsitry)
fun CompoundTag?.toPdc(): PersistentDataContainer {
val pdc = emptyPdc()
this ?: return pdc
val keys = this.allKeys
for (key in keys) {
pdc.put(key, this[key])
}
return pdc
}
return if (base) {
tag.toPdc()
} else {
if (tag.contains("PublicBukkitValues")) {
tag.getCompound("PublicBukkitValues").toPdc()
} else {
emptyPdc()
}
}
}
override fun setPdc(
tag: CompoundTag,
pdc: PersistentDataContainer?,
item: net.minecraft.world.item.ItemStack?
) {
fun CraftPersistentDataContainer.toTag(): CompoundTag {
val compound = CompoundTag()
val rawPublicMap: Map<String, Tag> = this.raw
for ((key, value) in rawPublicMap) {
compound.put(key, value)
}
return compound
}
pdc as CraftPersistentDataContainer?
if (item != null) {
if (pdc != null && !pdc.isEmpty) {
for (key in tag.allKeys.toSet()) {
tag.remove(key)
}
tag.merge(pdc.toTag())
} else {
item.setTag(null)
}
} else {
if (pdc != null && !pdc.isEmpty) {
tag.put("PublicBukkitValues", pdc.toTag())
} else {
tag.remove("PublicBukkitValues")
}
}
}
}
}

View File

@@ -39,6 +39,6 @@ class Skull : SkullProxy {
val profile = profile[meta] as GameProfile? ?: return null
val properties = profile.properties ?: return null
val prop = properties["textures"] ?: return null
return prop.toMutableList().firstOrNull()?.name
return prop.toMutableList().firstOrNull()?.value
}
}

View File

@@ -2,6 +2,8 @@ package com.willfp.eco.internal.spigot.proxy.v1_18_R2
import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy
import com.willfp.eco.internal.spigot.proxy.common.CommonsProvider
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.PathfinderMob
import org.bukkit.Bukkit
@@ -10,11 +12,14 @@ import org.bukkit.craftbukkit.v1_18_R2.CraftServer
import org.bukkit.craftbukkit.v1_18_R2.entity.CraftEntity
import org.bukkit.craftbukkit.v1_18_R2.entity.CraftMob
import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack
import org.bukkit.craftbukkit.v1_18_R2.persistence.CraftPersistentDataContainer
import org.bukkit.craftbukkit.v1_18_R2.persistence.CraftPersistentDataTypeRegistry
import org.bukkit.craftbukkit.v1_18_R2.util.CraftMagicNumbers
import org.bukkit.craftbukkit.v1_18_R2.util.CraftNamespacedKey
import org.bukkit.entity.LivingEntity
import org.bukkit.entity.Mob
import org.bukkit.inventory.ItemStack
import org.bukkit.persistence.PersistentDataContainer
import java.lang.reflect.Field
class CommonsInitializer : CommonsInitializerProxy {
@@ -27,6 +32,11 @@ class CommonsInitializer : CommonsInitializerProxy {
isAccessible = true
}
private val pdcRegsitry = Class.forName("org.bukkit.craftbukkit.v1_18_R2.inventory.CraftMetaItem")
.getDeclaredField("DATA_TYPE_REGISTRY")
.apply { isAccessible = true }
.get(null) as CraftPersistentDataTypeRegistry
override val nbtTagString = CraftMagicNumbers.NBT.TAG_STRING
override fun toPathfinderMob(mob: Mob): PathfinderMob? {
@@ -57,5 +67,66 @@ class CommonsInitializer : CommonsInitializerProxy {
override fun toBukkitEntity(entity: net.minecraft.world.entity.LivingEntity): LivingEntity? =
CraftEntity.getEntity(Bukkit.getServer() as CraftServer, entity) as? LivingEntity
override fun makePdc(tag: CompoundTag, base: Boolean): PersistentDataContainer {
fun emptyPdc(): CraftPersistentDataContainer = CraftPersistentDataContainer(pdcRegsitry)
fun CompoundTag?.toPdc(): PersistentDataContainer {
val pdc = emptyPdc()
this ?: return pdc
val keys = this.allKeys
for (key in keys) {
pdc.put(key, this[key])
}
return pdc
}
return if (base) {
tag.toPdc()
} else {
if (tag.contains("PublicBukkitValues")) {
tag.getCompound("PublicBukkitValues").toPdc()
} else {
emptyPdc()
}
}
}
override fun setPdc(
tag: CompoundTag,
pdc: PersistentDataContainer?,
item: net.minecraft.world.item.ItemStack?
) {
fun CraftPersistentDataContainer.toTag(): CompoundTag {
val compound = CompoundTag()
val rawPublicMap: Map<String, Tag> = this.raw
for ((key, value) in rawPublicMap) {
compound.put(key, value)
}
return compound
}
pdc as CraftPersistentDataContainer?
if (item != null) {
if (pdc != null && !pdc.isEmpty) {
for (key in tag.allKeys.toSet()) {
tag.remove(key)
}
tag.merge(pdc.toTag())
} else {
item.setTag(null)
}
} else {
if (pdc != null && !pdc.isEmpty) {
tag.put("PublicBukkitValues", pdc.toTag())
} else {
tag.remove("PublicBukkitValues")
}
}
}
}
}

View File

@@ -39,6 +39,6 @@ class Skull : SkullProxy {
val profile = profile[meta] as GameProfile? ?: return null
val properties = profile.properties ?: return null
val prop = properties["textures"] ?: return null
return prop.toMutableList().firstOrNull()?.name
return prop.toMutableList().firstOrNull()?.value
}
}

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,33 +36,28 @@ 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'
compileOnly 'com.github.MilkBowl:VaultAPI:1.7'
compileOnly 'world.bentobox:bentobox:1.17.3-SNAPSHOT'
compileOnly 'com.iridium:IridiumSkyblock:3.1.2'
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'
compileOnly 'com.SirBlobman.combatlogx.expansions:NewbieHelper:10.0.0.0-SNAPSHOT'
// CombatLogX V11 + NewbieHelper Expansion
compileOnly 'com.github.sirblobman.combatlogx:api:11.0.0.0-SNAPSHOT'
compileOnly 'com.github.sirblobman.combatlogx.expansion:newbie-helper:11.0.0.0-SNAPSHOT'
// 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
}
}

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