Compare commits

..

73 Commits

Author SHA1 Message Date
Auxilor
c3f88bf7b0 Fixed updatechecker formatting 2022-01-12 11:23:01 +00:00
Auxilor
eb6d76e0c6 Updated to 6.19.0 2022-01-12 11:17:32 +00:00
Auxilor
f2d0e8c368 Merge branch 'master' into develop 2022-01-12 11:17:23 +00:00
Auxilor
5e7b9573a1 Switched try/catch blocks to runCatching in kotlin and improved async packet encoding 2022-01-12 11:17:03 +00:00
Auxilor
7d457ea496 Added more safety checks to compiled expressions 2022-01-12 08:31:45 +00:00
Auxilor
806bf9a43f Added getDouble/IntFromExpression to Config 2022-01-11 17:05:22 +00:00
Auxilor
316f134b71 NumberUtils changes 2022-01-11 16:54:32 +00:00
Auxilor
0d363b9fb6 Added error safety to CrunchHandler 2022-01-11 16:51:38 +00:00
Auxilor
2890083eaa Excluded lang3 2022-01-11 16:47:57 +00:00
Auxilor
694646431b Fixed commons lang issue 2022-01-11 16:45:30 +00:00
Auxilor
86d5e9d09e Added support for evaluating mathematical expressions via Crunch 2022-01-11 16:43:36 +00:00
Auxilor
8635e5f7a5 Updated to 6.18.5 2022-01-11 10:01:49 +00:00
Auxilor
aa718649eb Fixed v1_18_R1 remapping bugs 2022-01-11 10:01:40 +00:00
Auxilor
1dc0fa449b Updated to 6.18.4 2022-01-11 09:20:52 +00:00
Auxilor
19e3061a13 Fixed MythicMobs NPE 2022-01-11 09:20:43 +00:00
Auxilor
ecafbd76de Updated to 6.18.3 2022-01-10 11:11:44 +00:00
Auxilor
3728f2fc7a Fixed apache commons lang not existing on classpath 2022-01-10 11:11:31 +00:00
Auxilor
56c124dbd2 Updated to 6.18.2 2022-01-09 18:19:29 +00:00
Auxilor
6730697fc5 Merge branch 'develop' 2022-01-09 18:19:15 +00:00
Auxilor
c8e1c83061 Merge remote-tracking branch 'origin/master' 2022-01-09 18:19:07 +00:00
Auxilor
a9fd5a9418 Merge remote-tracking branch 'origin/develop'
# Conflicts:
#	gradle.properties
2022-01-09 18:19:00 +00:00
Auxilor
7b1179f402 Fixed string getter for multiple-in-craft 2022-01-09 18:18:44 +00:00
Auxilor
f4907329d9 Updated to 6.18.2 2022-01-07 10:38:41 +00:00
Auxilor
1e23cbaa5e Fixed SuperiorSkyblockAPI build isseus 2022-01-07 10:38:09 +00:00
Auxilor
863818d2eb Fixed NoAI arg parser 2022-01-07 10:05:00 +00:00
Auxilor
d35285d0dc More config simplification 2022-01-07 09:26:06 +00:00
Auxilor
bc92f8a444 Added destructurability to EntityArgParseResult 2022-01-07 09:24:02 +00:00
Auxilor
2fafef17d7 Simplified internal config implementations 2022-01-07 09:22:32 +00:00
Auxilor
24078a2838 Merge remote-tracking branch 'origin/develop' into develop 2022-01-07 09:01:19 +00:00
Auxilor
73d13277be Made update checker less annoyign 2022-01-06 18:34:44 +00:00
Auxilor
0e4c23d70c Fixed potential remapping bugs 2022-01-06 18:21:51 +00:00
Auxilor
ddf5094c5a Added MythicMobs softdepend 2022-01-06 16:13:36 +00:00
Auxilor
925fc56cab MythicMobs integration uses apiHelper where possible 2022-01-06 16:13:17 +00:00
Auxilor
3208d0328f Added EmptyTestableEntity (dummy entities) for failed TestableEntity lookups 2022-01-06 16:05:10 +00:00
Auxilor
317824ae78 Removed broken test 2022-01-06 15:17:06 +00:00
Auxilor
41a4b4fc1a Scheduled old java arg parsers for removal in the next release 2022-01-06 15:01:36 +00:00
Auxilor
c528e4cd42 Referencing for-removal arg parsers at all will now log an error 2022-01-06 15:00:31 +00:00
Auxilor
2724f21d4e Referencing for-removal arg parsers at all will now log an error 2022-01-06 14:59:39 +00:00
Auxilor
5cb14e31b7 Finally updated Config string getters to not be formatted by default 2022-01-06 14:51:55 +00:00
Auxilor
6b9942f412 Updated to 6.18.0 2022-01-06 14:32:46 +00:00
Auxilor
fbe88ab0fd Added MythicMobs integration 2022-01-06 14:31:02 +00:00
Auxilor
d042211dbe Added Charged and Explosion radius arg parsers, fixed size arg parser 2022-01-06 14:10:20 +00:00
Auxilor
5781df011e Added adult arg parser 2022-01-06 14:03:59 +00:00
Auxilor
c191ff0767 Added baby arg parser 2022-01-06 14:03:06 +00:00
Auxilor
b9cbcbe7a0 Added Entity lookup system, TestableEntity, CustomEntity 2022-01-06 13:55:03 +00:00
Auxilor
6009122c48 Removed underscores from name arg parsers 2022-01-06 12:11:27 +00:00
Auxilor
7536794100 Added quote support to lookup strings (for names) 2022-01-06 12:05:38 +00:00
Auxilor
e80aa5f910 Added substrings (escaped with "") to arg parsers for cleaner syntax 2022-01-06 10:46:35 +00:00
Auxilor
b4aeeac570 Added tree growth to PlayerBlockListener.kt 2022-01-05 16:22:52 +00:00
Auxilor
33515aa5f7 Updated to 6.17.7 2022-01-05 13:44:47 +00:00
Auxilor
047b535a40 Merge remote-tracking branch 'origin/master' into develop 2022-01-05 13:44:22 +00:00
Auxilor
ef8093ec7f Updated to 6.17.6 2022-01-05 13:42:24 +00:00
Auxilor
9d0f95617d Fixed CrashClaim integration 2022-01-05 13:42:14 +00:00
Auxilor
b4f3988fc7 Updated to 6.17.7 2022-01-02 17:37:34 +00:00
Auxilor
e7e1751acc Disabled CrashClaim 2022-01-02 17:37:24 +00:00
Auxilor
e68d482aa5 Disabled CrashClaim 2022-01-02 17:37:19 +00:00
Auxilor
183b18c0ec Updated to 6.17.6 2021-12-29 18:47:44 +00:00
Auxilor
e026a767d9 Fixed v1_18_R1 bugs 2021-12-29 18:47:33 +00:00
Auxilor
d2966aa428 Updated to 6.17.5 2021-12-26 17:21:21 +00:00
Auxilor
9168e68b5a StringUtils#jsonToLegacy will now fail silently 2021-12-26 17:21:01 +00:00
Auxilor
51a61b65c6 Updated to 6.17.4 2021-12-26 16:57:54 +00:00
Auxilor
76be236dac Error catching to StringUtils#jsonToLegacy 2021-12-26 16:56:53 +00:00
Auxilor
f1bbac2dd0 Codestyle 2021-12-26 16:48:03 +00:00
Auxilor
6e88aef572 FastItemStack#getLore changes 2021-12-26 16:40:09 +00:00
Auxilor
804f187964 legacy <-> json changes 2021-12-26 16:34:52 +00:00
Auxilor
623b8a18f4 Codestyle 2021-12-26 16:20:38 +00:00
Auxilor
0d4e424582 Codestyle 2021-12-26 16:19:59 +00:00
Auxilor
452e499467 Added NumberUtils#logBase 2021-12-26 16:10:33 +00:00
Auxilor
b2950ab035 Added ListUtils#containsIgnoreCase 2021-12-26 12:53:57 +00:00
Auxilor
e47d05ccb2 NMS changes 2021-12-26 12:23:13 +00:00
Auxilor
b9e61b8c0d Merged v1_18_R1 thanks to paperweight update 2021-12-26 12:17:02 +00:00
Auxilor
0f35d5d16e Updated to 6.17.3 2021-12-21 12:20:33 +00:00
Stealth2800
3a7315d728 Make defensive copy of CustomItem's returned item 2021-12-20 20:24:21 -08:00
89 changed files with 2524 additions and 577 deletions

View File

@@ -12,7 +12,7 @@ dependencies {
implementation(project(":eco-core:core-backend")) implementation(project(":eco-core:core-backend"))
implementation(project(":eco-core:core-nms:v1_16_R3")) implementation(project(":eco-core:core-nms:v1_16_R3"))
implementation(project(path = ":eco-core:core-nms:v1_17_R1", configuration = "reobf")) implementation(project(path = ":eco-core:core-nms:v1_17_R1", configuration = "reobf"))
implementation(project(":eco-core:core-nms:v1_18_R1")) implementation(project(path = ":eco-core:core-nms:v1_18_R1", configuration = "reobf"))
} }
allprojects { allprojects {
@@ -61,6 +61,12 @@ allprojects {
// IridiumSkyblock // IridiumSkyblock
maven("https://nexus.iridiumdevelopment.net/repository/maven-releases/") maven("https://nexus.iridiumdevelopment.net/repository/maven-releases/")
// MythicMobs
maven("https://mvn.lumine.io/repository/maven-public/")
// Crunch
maven("https://redempt.dev")
} }
dependencies { dependencies {
@@ -88,12 +94,14 @@ allprojects {
exclude(group = "org.spongepowered", module = "configurate-hocon") exclude(group = "org.spongepowered", module = "configurate-hocon")
exclude(group = "com.darkblade12", module = "particleeffect") exclude(group = "com.darkblade12", module = "particleeffect")
exclude(group = "com.github.cryptomorin", module = "XSeries") exclude(group = "com.github.cryptomorin", module = "XSeries")
exclude(group = "org.apache.commons", module = "commons-lang3")
} }
tasks { tasks {
shadowJar { shadowJar {
relocate("org.bstats", "com.willfp.eco.shaded.bstats") relocate("org.bstats", "com.willfp.eco.shaded.bstats")
relocate("net.kyori.adventure.text.minimessage", "com.willfp.eco.shaded.minimessage") relocate("net.kyori.adventure.text.minimessage", "com.willfp.eco.shaded.minimessage")
relocate("redempt.crunch", "com.willfp.eco.shaded.crunch")
} }
compileJava { compileJava {

View File

@@ -15,6 +15,7 @@ dependencies {
compileOnly 'org.apache.maven:maven-artifact:3.8.1' compileOnly 'org.apache.maven:maven-artifact:3.8.1'
compileOnly 'com.comphenix.protocol:ProtocolLib:4.6.1-SNAPSHOT' compileOnly 'com.comphenix.protocol:ProtocolLib:4.6.1-SNAPSHOT'
compileOnly 'com.google.code.gson:gson:2.8.8' compileOnly 'com.google.code.gson:gson:2.8.8'
compileOnly 'org.apache.commons:commons-lang3:3.0'
} }
java { java {

View File

@@ -327,11 +327,9 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
DefaultArtifactVersion mostRecentVersion = new DefaultArtifactVersion(version); DefaultArtifactVersion mostRecentVersion = new DefaultArtifactVersion(version);
if (!(currentVersion.compareTo(mostRecentVersion) > 0 || currentVersion.equals(mostRecentVersion))) { if (!(currentVersion.compareTo(mostRecentVersion) > 0 || currentVersion.equals(mostRecentVersion))) {
this.outdated = true; this.outdated = true;
this.getScheduler().runTimer(() -> { this.getLogger().warning("&c" + this.getName() + " is out of date! (Version " + this.getDescription().getVersion() + ")");
this.getLogger().info("&c " + this.getName() + " is out of date! (Version " + this.getDescription().getVersion() + ")"); this.getLogger().warning("&cThe newest version is &f" + version);
this.getLogger().info("&cThe newest version is &f" + version); this.getLogger().warning("&cDownload the new version!");
this.getLogger().info("&cDownload the new version!");
}, 0, 864000);
} }
}); });
} }

View File

@@ -18,6 +18,8 @@ import com.willfp.eco.core.proxy.ProxyFactory;
import com.willfp.eco.core.requirement.RequirementFactory; import com.willfp.eco.core.requirement.RequirementFactory;
import com.willfp.eco.core.scheduling.Scheduler; import com.willfp.eco.core.scheduling.Scheduler;
import net.kyori.adventure.platform.bukkit.BukkitAudiences; import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -232,4 +234,13 @@ public interface Handler {
*/ */
@NotNull @NotNull
PlayerProfileHandler getPlayerProfileHandler(); PlayerProfileHandler getPlayerProfileHandler();
/**
* Create dummy entity - never spawned, exists purely in code.
*
* @param location The location.
* @return The entity.
*/
@NotNull
Entity createDummyEntity(@NotNull Location location);
} }

View File

@@ -1,11 +1,16 @@
package com.willfp.eco.core.config.interfaces; package com.willfp.eco.core.config.interfaces;
import com.willfp.eco.core.config.ConfigType; import com.willfp.eco.core.config.ConfigType;
import com.willfp.eco.core.config.TransientConfig;
import com.willfp.eco.util.NumberUtils;
import com.willfp.eco.util.StringUtils; import com.willfp.eco.util.StringUtils;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
/** /**
* All configs implement this interface. * All configs implement this interface.
@@ -67,10 +72,12 @@ public interface Config extends Cloneable {
* Get subsection from config. * Get subsection from config.
* *
* @param path The key to check. * @param path The key to check.
* @return The subsection. Throws NPE if not found. * @return The subsection. Returns an empty section if not found.
*/ */
@NotNull @NotNull
Config getSubsection(@NotNull String path); default Config getSubsection(@NotNull String path) {
return Objects.requireNonNullElse(getSubsectionOrNull(path), new TransientConfig());
}
/** /**
* Get subsection from config. * Get subsection from config.
@@ -87,7 +94,44 @@ public interface Config extends Cloneable {
* @param path The key to fetch the value from. * @param path The key to fetch the value from.
* @return The found value, or 0 if not found. * @return The found value, or 0 if not found.
*/ */
int getInt(@NotNull String path); default int getInt(@NotNull String path) {
return Objects.requireNonNullElse(getIntOrNull(path), 0);
}
/**
* Get an integer from config with a specified default (not found) value.
*
* @param path The key to fetch the value from.
* @param def The value to default to if not found.
* @return The found value, or the default.
*/
default int getInt(@NotNull String path,
int def) {
return Objects.requireNonNullElse(getIntOrNull(path), def);
}
/**
* Get a decimal value via a mathematical expression.
*
* @param path The key to fetch the value from.
* @return The computed value, or 0 if not found or invalid.
*/
default int getIntFromExpression(@NotNull String path) {
return getIntFromExpression(path, null);
}
/**
* Get a decimal value via a mathematical expression.
*
* @param path The key to fetch the value from.
* @param player The player to evaluate placeholders with respect to.
* @return The computed value, or 0 if not found or invalid.
*/
default int getIntFromExpression(@NotNull String path,
@Nullable Player player) {
return Double.valueOf(getDoubleFromExpression(path, player)).intValue();
}
/** /**
* Get an integer from config. * Get an integer from config.
@@ -98,16 +142,6 @@ public interface Config extends Cloneable {
@Nullable @Nullable
Integer getIntOrNull(@NotNull String path); Integer getIntOrNull(@NotNull String path);
/**
* Get an integer from config with a specified default (not found) value.
*
* @param path The key to fetch the value from.
* @param def The value to default to if not found.
* @return The found value, or the default.
*/
int getInt(@NotNull String path,
int def);
/** /**
* Get a list of integers from config. * Get a list of integers from config.
* *
@@ -115,7 +149,9 @@ public interface Config extends Cloneable {
* @return The found value, or a blank {@link java.util.ArrayList} if not found. * @return The found value, or a blank {@link java.util.ArrayList} if not found.
*/ */
@NotNull @NotNull
List<Integer> getInts(@NotNull String path); default List<Integer> getInts(@NotNull String path) {
return Objects.requireNonNullElse(getIntsOrNull(path), new ArrayList<>());
}
/** /**
* Get a list of integers from config. * Get a list of integers from config.
@@ -132,7 +168,9 @@ public interface Config extends Cloneable {
* @param path The key to fetch the value from. * @param path The key to fetch the value from.
* @return The found value, or false if not found. * @return The found value, or false if not found.
*/ */
boolean getBool(@NotNull String path); default boolean getBool(@NotNull String path) {
return Objects.requireNonNullElse(getBoolOrNull(path), false);
}
/** /**
* Get a boolean from config. * Get a boolean from config.
@@ -150,7 +188,9 @@ public interface Config extends Cloneable {
* @return The found value, or a blank {@link java.util.ArrayList} if not found. * @return The found value, or a blank {@link java.util.ArrayList} if not found.
*/ */
@NotNull @NotNull
List<Boolean> getBools(@NotNull String path); default List<Boolean> getBools(@NotNull String path) {
return Objects.requireNonNullElse(getBoolsOrNull(path), new ArrayList<>());
}
/** /**
* Get a list of booleans from config. * Get a list of booleans from config.
@@ -169,7 +209,7 @@ public interface Config extends Cloneable {
*/ */
@NotNull @NotNull
default String getFormattedString(@NotNull String path) { default String getFormattedString(@NotNull String path) {
return getString(path, true); return getString(path, true, StringUtils.FormatOption.WITH_PLACEHOLDERS);
} }
/** /**
@@ -188,25 +228,25 @@ public interface Config extends Cloneable {
/** /**
* Get a string from config. * Get a string from config.
* <p> * <p>
* Formatted by default. * Not formatted.
* *
* @param path The key to fetch the value from. * @param path The key to fetch the value from.
* @return The found value, or an empty string if not found. * @return The found value, or an empty string if not found.
*/ */
@NotNull @NotNull
default String getString(@NotNull String path) { default String getString(@NotNull String path) {
return getString(path, true); return getString(path, false);
} }
/** /**
* Get a string from config. * Get a string from config.
* <p>
* This will be deprecated when {@link Config#getString(String)} no longer formats by default.
* *
* @param path The key to fetch the value from. * @param path The key to fetch the value from.
* @param format If the string should be formatted. * @param format If the string should be formatted.
* @return The found value, or an empty string if not found. * @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, default String getString(@NotNull String path,
boolean format) { boolean format) {
return this.getString(path, format, StringUtils.FormatOption.WITH_PLACEHOLDERS); return this.getString(path, format, StringUtils.FormatOption.WITH_PLACEHOLDERS);
@@ -236,9 +276,11 @@ public interface Config extends Cloneable {
* @return The found value, or an empty string if not found. * @return The found value, or an empty string if not found.
*/ */
@NotNull @NotNull
String getString(@NotNull String path, default String getString(@NotNull String path,
boolean format, boolean format,
@NotNull StringUtils.FormatOption option); @NotNull StringUtils.FormatOption option) {
return Objects.requireNonNullElse(getStringOrNull(path, format, option), "");
}
/** /**
* Get a formatted string from config. * Get a formatted string from config.
@@ -248,7 +290,7 @@ public interface Config extends Cloneable {
*/ */
@Nullable @Nullable
default String getFormattedStringOrNull(@NotNull String path) { default String getFormattedStringOrNull(@NotNull String path) {
return getStringOrNull(path, true); return getStringOrNull(path, true, StringUtils.FormatOption.WITH_PLACEHOLDERS);
} }
/** /**
@@ -274,19 +316,19 @@ public interface Config extends Cloneable {
*/ */
@Nullable @Nullable
default String getStringOrNull(@NotNull String path) { default String getStringOrNull(@NotNull String path) {
return getStringOrNull(path, true); return getStringOrNull(path, false, StringUtils.FormatOption.WITH_PLACEHOLDERS);
} }
/** /**
* Get a string from config. * Get a string from config.
* <p>
* This will be deprecated when {@link Config#getStringOrNull(String)} no longer formats by default.
* *
* @param path The key to fetch the value from. * @param path The key to fetch the value from.
* @param format If the string should be formatted. * @param format If the string should be formatted.
* @return The found value, or null if not found. * @return The found value, or null if not found.
* @deprecated Since 6.18.0, {@link Config#getString(String)} is not formatted by default.
*/ */
@Nullable @Nullable
@Deprecated(since = "6.18.0")
default String getStringOrNull(@NotNull String path, default String getStringOrNull(@NotNull String path,
boolean format) { boolean format) {
return this.getStringOrNull(path, format, StringUtils.FormatOption.WITH_PLACEHOLDERS); return this.getStringOrNull(path, format, StringUtils.FormatOption.WITH_PLACEHOLDERS);
@@ -351,28 +393,26 @@ public interface Config extends Cloneable {
/** /**
* Get a list of strings from config. * Get a list of strings from config.
* <p> * <p>
* Formatted by default. * Not formatted.
* <p>
* This will be changed in newer versions to <b>not</b> format by default.
* *
* @param path The key to fetch the value from. * @param path The key to fetch the value from.
* @return The found value, or a blank {@link java.util.ArrayList} if not found. * @return The found value, or a blank {@link java.util.ArrayList} if not found.
*/ */
@NotNull @NotNull
default List<String> getStrings(@NotNull String path) { default List<String> getStrings(@NotNull String path) {
return getStrings(path, true); return getStrings(path, false, StringUtils.FormatOption.WITH_PLACEHOLDERS);
} }
/** /**
* Get a list of strings from config. * Get a list of strings from config.
* <p>
* This will be deprecated when {@link Config#getStrings(String)} no longer formats by default.
* *
* @param path The key to fetch the value from. * @param path The key to fetch the value from.
* @param format If the strings should be formatted. * @param format If the strings should be formatted.
* @return The found value, or a blank {@link java.util.ArrayList} if not found. * @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 @NotNull
@Deprecated(since = "6.18.0")
default List<String> getStrings(@NotNull String path, default List<String> getStrings(@NotNull String path,
boolean format) { boolean format) {
return this.getStrings(path, format, StringUtils.FormatOption.WITH_PLACEHOLDERS); return this.getStrings(path, format, StringUtils.FormatOption.WITH_PLACEHOLDERS);
@@ -390,7 +430,7 @@ public interface Config extends Cloneable {
@Deprecated @Deprecated
default List<String> getStrings(@NotNull String path, default List<String> getStrings(@NotNull String path,
@NotNull StringUtils.FormatOption option) { @NotNull StringUtils.FormatOption option) {
return getStrings(path, true, option); return getStrings(path, false, option);
} }
/** /**
@@ -402,14 +442,16 @@ public interface Config extends Cloneable {
* @return The found value, or a blank {@link java.util.ArrayList} if not found. * @return The found value, or a blank {@link java.util.ArrayList} if not found.
*/ */
@NotNull @NotNull
List<String> getStrings(@NotNull String path, default List<String> getStrings(@NotNull String path,
boolean format, boolean format,
@NotNull StringUtils.FormatOption option); @NotNull StringUtils.FormatOption option) {
return Objects.requireNonNullElse(getStringsOrNull(path, format, option), new ArrayList<>());
}
/** /**
* Get a list of strings from config. * Get a list of strings from config.
* <p> * <p>
* Formatted by default. * Formatted.
* *
* @param path The key to fetch the value from. * @param path The key to fetch the value from.
* @return The found value, or null if not found. * @return The found value, or null if not found.
@@ -422,7 +464,7 @@ public interface Config extends Cloneable {
/** /**
* Get a list of strings from config. * Get a list of strings from config.
* <p> * <p>
* Formatted by default. * Formatted.
* *
* @param path The key to fetch the value from. * @param path The key to fetch the value from.
* @param option The format option. * @param option The format option.
@@ -437,7 +479,7 @@ public interface Config extends Cloneable {
/** /**
* Get a list of strings from config. * Get a list of strings from config.
* <p> * <p>
* Formatted by default. * Not formatted.
* <p> * <p>
* This will be changed in newer versions to <b>not</b> format by default. * This will be changed in newer versions to <b>not</b> format by default.
* *
@@ -446,7 +488,7 @@ public interface Config extends Cloneable {
*/ */
@Nullable @Nullable
default List<String> getStringsOrNull(@NotNull String path) { default List<String> getStringsOrNull(@NotNull String path) {
return getStringsOrNull(path, true); return getStringsOrNull(path, false, StringUtils.FormatOption.WITH_PLACEHOLDERS);
} }
/** /**
@@ -455,8 +497,10 @@ public interface Config extends Cloneable {
* @param path The key to fetch the value from. * @param path The key to fetch the value from.
* @param format If the strings should be formatted. * @param format If the strings should be formatted.
* @return The found value, or null if not found. * @return The found value, or null if not found.
* @deprecated Since 6.18.0, {@link Config#getString(String)} is not formatted by default.
*/ */
@Nullable @Nullable
@Deprecated(since = "6.18.0")
default List<String> getStringsOrNull(@NotNull String path, default List<String> getStringsOrNull(@NotNull String path,
boolean format) { boolean format) {
return getStringsOrNull(path, format, StringUtils.FormatOption.WITH_PLACEHOLDERS); return getStringsOrNull(path, format, StringUtils.FormatOption.WITH_PLACEHOLDERS);
@@ -474,7 +518,7 @@ public interface Config extends Cloneable {
@Deprecated @Deprecated
default List<String> getStringsOrNull(@NotNull String path, default List<String> getStringsOrNull(@NotNull String path,
@NotNull StringUtils.FormatOption option) { @NotNull StringUtils.FormatOption option) {
return getStringsOrNull(path, true, option); return getStringsOrNull(path, false, option);
} }
/** /**
@@ -496,7 +540,31 @@ public interface Config extends Cloneable {
* @param path The key to fetch the value from. * @param path The key to fetch the value from.
* @return The found value, or 0 if not found. * @return The found value, or 0 if not found.
*/ */
double getDouble(@NotNull String path); default double getDouble(@NotNull String path) {
return Objects.requireNonNullElse(getDoubleOrNull(path), 0.0);
}
/**
* Get a decimal value via a mathematical expression.
*
* @param path The key to fetch the value from.
* @return The computed value, or 0 if not found or invalid.
*/
default double getDoubleFromExpression(@NotNull String path) {
return getDoubleFromExpression(path, null);
}
/**
* Get a decimal value via a mathematical expression.
*
* @param path The key to fetch the value from.
* @param player The player to evaluate placeholders with respect to.
* @return The computed value, or 0 if not found or invalid.
*/
default double getDoubleFromExpression(@NotNull String path,
@Nullable Player player) {
return NumberUtils.evaluateExpression(this.getString(path), player);
}
/** /**
* Get a decimal from config. * Get a decimal from config.
@@ -514,7 +582,9 @@ public interface Config extends Cloneable {
* @return The found value, or a blank {@link java.util.ArrayList} if not found. * @return The found value, or a blank {@link java.util.ArrayList} if not found.
*/ */
@NotNull @NotNull
List<Double> getDoubles(@NotNull String path); default List<Double> getDoubles(@NotNull String path) {
return Objects.requireNonNullElse(getDoublesOrNull(path), new ArrayList<>());
}
/** /**
* Get a list of decimals from config. * Get a list of decimals from config.
@@ -532,7 +602,9 @@ public interface Config extends Cloneable {
* @return The found value, or a blank {@link java.util.ArrayList} if not found. * @return The found value, or a blank {@link java.util.ArrayList} if not found.
*/ */
@NotNull @NotNull
List<? extends Config> getSubsections(@NotNull String path); default List<? extends Config> getSubsections(@NotNull String path) {
return Objects.requireNonNullElse(getSubsectionsOrNull(path), new ArrayList<>());
}
/** /**
* Get a list of subsections from config. * Get a list of subsections from config.

View File

@@ -3,7 +3,9 @@ package com.willfp.eco.core.config.interfaces;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
/** /**
* JSON config. * JSON config.
@@ -22,7 +24,9 @@ public interface JSONConfig extends Config {
* @return The found value, or a blank {@link java.util.ArrayList} if not found. * @return The found value, or a blank {@link java.util.ArrayList} if not found.
*/ */
@NotNull @NotNull
List<JSONConfig> getSubsections(@NotNull String path); default List<JSONConfig> getSubsections(@NotNull String path) {
return Objects.requireNonNullElse(getSubsectionsOrNull(path), new ArrayList<>());
}
/** /**
* Get a list of subsections from config. * Get a list of subsections from config.

View File

@@ -70,70 +70,31 @@ public abstract class ConfigWrapper<T extends Config> implements Config {
handle.set(path, object); handle.set(path, object);
} }
@Override
public @NotNull Config getSubsection(@NotNull final String path) {
return handle.getSubsection(path);
}
@Override @Override
public @Nullable Config getSubsectionOrNull(@NotNull final String path) { public @Nullable Config getSubsectionOrNull(@NotNull final String path) {
return handle.getSubsectionOrNull(path); return handle.getSubsectionOrNull(path);
} }
@Override
public int getInt(@NotNull final String path) {
return handle.getInt(path);
}
@Override @Override
public @Nullable Integer getIntOrNull(@NotNull final String path) { public @Nullable Integer getIntOrNull(@NotNull final String path) {
return handle.getIntOrNull(path); return handle.getIntOrNull(path);
} }
@Override
public int getInt(@NotNull final String path,
final int def) {
return handle.getInt(path, def);
}
@Override
public @NotNull List<Integer> getInts(@NotNull final String path) {
return handle.getInts(path);
}
@Override @Override
public @Nullable List<Integer> getIntsOrNull(@NotNull final String path) { public @Nullable List<Integer> getIntsOrNull(@NotNull final String path) {
return handle.getIntsOrNull(path); return handle.getIntsOrNull(path);
} }
@Override
public boolean getBool(@NotNull final String path) {
return handle.getBool(path);
}
@Override @Override
public @Nullable Boolean getBoolOrNull(@NotNull final String path) { public @Nullable Boolean getBoolOrNull(@NotNull final String path) {
return handle.getBoolOrNull(path); return handle.getBoolOrNull(path);
} }
@Override
public @NotNull List<Boolean> getBools(@NotNull final String path) {
return handle.getBools(path);
}
@Override @Override
public @Nullable List<Boolean> getBoolsOrNull(@NotNull final String path) { public @Nullable List<Boolean> getBoolsOrNull(@NotNull final String path) {
return handle.getBoolsOrNull(path); return handle.getBoolsOrNull(path);
} }
@Override
public @NotNull String getString(@NotNull final String path,
final boolean format,
@NotNull final StringUtils.FormatOption option) {
return handle.getString(path, format, option);
}
@Override @Override
public @Nullable String getStringOrNull(@NotNull final String path, public @Nullable String getStringOrNull(@NotNull final String path,
final boolean format, final boolean format,
@@ -141,13 +102,6 @@ public abstract class ConfigWrapper<T extends Config> implements Config {
return handle.getStringOrNull(path, format, option); return handle.getStringOrNull(path, format, option);
} }
@Override
public @NotNull List<String> getStrings(@NotNull final String path,
final boolean format,
@NotNull final StringUtils.FormatOption option) {
return handle.getStrings(path, format, option);
}
@Override @Override
public @Nullable List<String> getStringsOrNull(@NotNull final String path, public @Nullable List<String> getStringsOrNull(@NotNull final String path,
final boolean format, final boolean format,
@@ -155,31 +109,16 @@ public abstract class ConfigWrapper<T extends Config> implements Config {
return handle.getStringsOrNull(path, format, option); return handle.getStringsOrNull(path, format, option);
} }
@Override
public double getDouble(@NotNull final String path) {
return handle.getDouble(path);
}
@Override @Override
public @Nullable Double getDoubleOrNull(@NotNull final String path) { public @Nullable Double getDoubleOrNull(@NotNull final String path) {
return handle.getDoubleOrNull(path); return handle.getDoubleOrNull(path);
} }
@Override
public @NotNull List<Double> getDoubles(@NotNull final String path) {
return handle.getDoubles(path);
}
@Override @Override
public @Nullable List<Double> getDoublesOrNull(@NotNull final String path) { public @Nullable List<Double> getDoublesOrNull(@NotNull final String path) {
return handle.getDoublesOrNull(path); return handle.getDoublesOrNull(path);
} }
@Override
public @NotNull List<? extends Config> getSubsections(@NotNull final String path) {
return handle.getSubsections(path);
}
@Override @Override
public @Nullable List<? extends Config> getSubsectionsOrNull(@NotNull final String path) { public @Nullable List<? extends Config> getSubsectionsOrNull(@NotNull final String path) {
return handle.getSubsectionsOrNull(path); return handle.getSubsectionsOrNull(path);

View File

@@ -0,0 +1,84 @@
package com.willfp.eco.core.entities;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* A custom entity has 3 components.
*
* <ul>
* <li>The key to identify it</li>
* <li>The test to check if any entity is this custom entity</li>
* <li>The supplier to spawn the custom {@link org.bukkit.entity.Entity}</li>
* </ul>
*/
public class CustomEntity implements TestableEntity {
/**
* The key.
*/
private final NamespacedKey key;
/**
* The test for Entities to pass.
*/
private final Predicate<@NotNull Entity> test;
/**
* The provider to spawn the entity.
*/
private final Function<Location, Entity> provider;
/**
* Create a new custom entity.
*
* @param key The entity key.
* @param test The test.
* @param provider The provider to spawn the entity.
*/
public CustomEntity(@NotNull final NamespacedKey key,
@NotNull final Predicate<@NotNull Entity> test,
@NotNull final Function<Location, Entity> provider) {
this.key = key;
this.test = test;
this.provider = provider;
}
@Override
public boolean matches(@Nullable final Entity entity) {
if (entity == null) {
return false;
}
return test.test(entity);
}
@Override
public Entity spawn(@NotNull final Location location) {
Validate.notNull(location.getWorld());
return provider.apply(location);
}
/**
* Register the entity.
*/
public void register() {
Entities.registerCustomEntity(this.getKey(), this);
}
/**
* Get the key.
*
* @return The key.
*/
public NamespacedKey getKey() {
return this.key;
}
}

View File

@@ -0,0 +1,239 @@
package com.willfp.eco.core.entities;
import com.willfp.eco.core.entities.args.EntityArgParseResult;
import com.willfp.eco.core.entities.args.EntityArgParser;
import com.willfp.eco.core.entities.impl.EmptyTestableEntity;
import com.willfp.eco.core.entities.impl.ModifiedTestableEntity;
import com.willfp.eco.core.entities.impl.SimpleTestableEntity;
import com.willfp.eco.util.NamespacedKeyUtils;
import com.willfp.eco.util.StringUtils;
import org.bukkit.Location;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
/**
* Class to manage all custom and vanilla entities.
*/
public final class Entities {
/**
* All entities.
*/
private static final Map<NamespacedKey, TestableEntity> REGISTRY = new ConcurrentHashMap<>();
/**
* All entity parsers.
*/
private static final List<EntityArgParser> ARG_PARSERS = new ArrayList<>();
/**
* Register a new custom item.
*
* @param key The key of the item.
* @param item The item.
*/
public static void registerCustomEntity(@NotNull final NamespacedKey key,
@NotNull final TestableEntity item) {
REGISTRY.put(key, item);
}
/**
* Register a new arg parser.
*
* @param parser The parser.
*/
public static void registerArgParser(@NotNull final EntityArgParser parser) {
ARG_PARSERS.add(parser);
}
/**
* Remove an entity.
*
* @param key The key of the entity.
*/
public static void removeCustomEntity(@NotNull final NamespacedKey key) {
REGISTRY.remove(key);
}
/**
* This is the backbone of the entire eco entity system.
* <p>
* You can look up a TestableEntity for any type or custom entity,
* and it will return it with any modifiers passed as parameters.
* <p>
* If you want to get an Entity instance from this, then just call
* {@link TestableEntity#spawn(Location)}.
* <p>
* The advantages of the testable entity system are that there is the inbuilt
* {@link TestableEntity#matches(Entity)} - this allows to check if any entity
* is that testable entity; which may sound negligible, but actually it allows for
* much more power and flexibility. For example, you can have an entity with an
* extra metadata tag, extra lore lines, different display name - and it
* will still work as long as the test passes.
*
* @param key The lookup string.
* @return The testable entity, or an empty testable entity if not found.
*/
@NotNull
public static TestableEntity lookup(@NotNull final String key) {
if (key.contains("?")) {
String[] options = key.split("\\?");
for (String option : options) {
TestableEntity lookup = lookup(option);
if (!(lookup instanceof EmptyTestableEntity)) {
return lookup;
}
}
return new EmptyTestableEntity();
}
String[] args = StringUtils.parseTokens(key);
if (args.length == 0) {
return new EmptyTestableEntity();
}
TestableEntity entity;
String[] split = args[0].toLowerCase().split(":");
if (split.length == 1) {
EntityType type;
try {
type = EntityType.valueOf(args[0].toUpperCase());
} catch (IllegalArgumentException e) {
return new EmptyTestableEntity();
}
entity = new SimpleTestableEntity(type);
} else {
String namespace = split[0];
String keyID = split[1];
NamespacedKey namespacedKey = NamespacedKeyUtils.create(namespace, keyID);
TestableEntity part = REGISTRY.get(namespacedKey);
if (part == null) {
return new EmptyTestableEntity();
}
entity = part;
}
String[] modifierArgs = Arrays.copyOfRange(args, 1, args.length);
List<EntityArgParseResult> parseResults = new ArrayList<>();
for (EntityArgParser argParser : ARG_PARSERS) {
EntityArgParseResult result = argParser.parseArguments(modifierArgs);
if (result != null) {
parseResults.add(result);
}
}
Function<Location, Entity> spawner = entity::spawn;
if (!parseResults.isEmpty()) {
entity = new ModifiedTestableEntity(
entity,
test -> {
for (EntityArgParseResult parseResult : parseResults) {
if (!parseResult.test().test(test)) {
return false;
}
}
return true;
},
location -> {
Entity spawned = spawner.apply(location);
for (EntityArgParseResult parseResult : parseResults) {
parseResult.modifier().accept(spawned);
}
return spawned;
}
);
}
return entity;
}
/**
* Get a Testable Entity from an ItemStack.
* <p>
* Will search for registered entity first. If there are no matches in the registry,
* then it will return a {@link com.willfp.eco.core.entities.impl.SimpleTestableEntity} matching the entity type.
* <p>
* If the entity is not custom and has unknown type, this will return null.
*
* @param entity The Entity.
* @return The found Testable Entity.
*/
@Nullable
public static TestableEntity getEntity(@Nullable final Entity entity) {
if (entity == null) {
return null;
}
TestableEntity customEntity = getEntity(entity);
if (customEntity != null) {
return customEntity;
}
for (TestableEntity known : REGISTRY.values()) {
if (known.matches(entity)) {
return known;
}
}
if (entity.getType() == EntityType.UNKNOWN) {
return null;
}
return new SimpleTestableEntity(entity.getType());
}
/**
* Get if entity is a custom entity.
*
* @param entity The entity to check.
* @return If is custom.
*/
public static boolean isCustomEntity(@NotNull final Entity entity) {
for (TestableEntity testable : REGISTRY.values()) {
if (testable.matches(entity)) {
return true;
}
}
return false;
}
/**
* Get all registered custom items.
*
* @return A set of all items.
*/
public static Set<TestableEntity> getCustomEntities() {
return new HashSet<>(REGISTRY.values());
}
private Entities() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}
}

View File

@@ -0,0 +1,27 @@
package com.willfp.eco.core.entities;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* An item with a test to see if any item is that item.
*/
public interface TestableEntity {
/**
* If an Entity matches the test.
*
* @param entity The entity to test.
* @return If the entity matches.
*/
boolean matches(@Nullable Entity entity);
/**
* Spawn the entity.
*
* @param location The location.
* @return The entity.
*/
Entity spawn(@NotNull Location location);
}

View File

@@ -0,0 +1,33 @@
package com.willfp.eco.core.entities.args;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**
* @param test The test for the entity.
* @param modifier The modifier to apply to the entity.
* @see EntityArgParser
*/
public record EntityArgParseResult(@NotNull Predicate<Entity> test,
@NotNull Consumer<Entity> modifier) {
/**
* Kotlin destructuring support.
*
* @return The test.
*/
public Predicate<Entity> component1() {
return test;
}
/**
* Kotlin destructuring support.
*
* @return The modifier.
*/
public Consumer<Entity> component2() {
return modifier;
}
}

View File

@@ -0,0 +1,20 @@
package com.willfp.eco.core.entities.args;
import com.willfp.eco.core.entities.TestableEntity;
import org.bukkit.Location;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* An argument parser should generate the predicate as well
* as modify the Entity for {@link TestableEntity#spawn(Location)}.
*/
public interface EntityArgParser {
/**
* Parse the arguments.
*
* @param args The arguments.
* @return The predicate test to apply to the modified entity.
*/
@Nullable EntityArgParseResult parseArguments(@NotNull String[] args);
}

View File

@@ -0,0 +1,33 @@
package com.willfp.eco.core.entities.impl;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.entities.TestableEntity;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Empty entity.
*/
public class EmptyTestableEntity implements TestableEntity {
/**
* Create a new empty testable entity.
*/
public EmptyTestableEntity() {
}
@Override
public boolean matches(@Nullable final Entity entity) {
return false;
}
@Override
public Entity spawn(@NotNull final Location location) {
Validate.notNull(location.getWorld());
return Eco.getHandler().createDummyEntity(location);
}
}

View File

@@ -0,0 +1,69 @@
package com.willfp.eco.core.entities.impl;
import com.willfp.eco.core.entities.TestableEntity;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* Existing testable entity with an extra filter.
*
* @see com.willfp.eco.core.entities.CustomEntity
*/
public class ModifiedTestableEntity implements TestableEntity {
/**
* The item.
*/
private final TestableEntity handle;
/**
* The amount.
*/
private final Predicate<Entity> test;
/**
* The provider to spawn the entity.
*/
private final Function<Location, Entity> provider;
/**
* Create a new modified testable entity.
*
* @param entity The base entity.
* @param test The test.
* @param provider The provider to spawn the entity.
*/
public ModifiedTestableEntity(@NotNull final TestableEntity entity,
@NotNull final Predicate<@NotNull Entity> test,
@NotNull final Function<Location, Entity> provider) {
this.handle = entity;
this.test = test;
this.provider = provider;
}
@Override
public boolean matches(@Nullable final Entity entity) {
return entity != null && handle.matches(entity) && test.test(entity);
}
@Override
public Entity spawn(@NotNull final Location location) {
Validate.notNull(location.getWorld());
return provider.apply(location);
}
/**
* Get the handle.
*
* @return The handle.
*/
public TestableEntity getHandle() {
return this.handle;
}
}

View File

@@ -0,0 +1,53 @@
package com.willfp.eco.core.entities.impl;
import com.willfp.eco.core.entities.TestableEntity;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Default vanilla entities.
*/
public class SimpleTestableEntity implements TestableEntity {
/**
* The entity type.
*/
private final EntityType type;
/**
* Create a new simple testable entity.
*
* @param type The entity type.
*/
public SimpleTestableEntity(@NotNull final EntityType type) {
this.type = type;
Validate.notNull(type.getEntityClass(), "Entity cannot be of unknown type!");
}
@Override
public boolean matches(@Nullable final Entity entity) {
return entity != null && entity.getType() == type;
}
@Override
public Entity spawn(@NotNull final Location location) {
Validate.notNull(location.getWorld());
assert type.getEntityClass() != null;
return location.getWorld().spawn(location, type.getEntityClass());
}
/**
* Get the type.
*
* @return The type.
*/
public EntityType getType() {
return this.type;
}
}

View File

@@ -0,0 +1,40 @@
package com.willfp.eco.core.integrations.customentities;
import org.jetbrains.annotations.NotNull;
import java.util.HashSet;
import java.util.Set;
/**
* Class to handle custom entity integrations.
*/
public final class CustomEntitiesManager {
/**
* A set of all registered integrations.
*/
private static final Set<CustomEntitiesWrapper> REGISTERED = new HashSet<>();
/**
* Register a new integration.
*
* @param integration The integration to register.
*/
public static void register(@NotNull final CustomEntitiesWrapper integration) {
REGISTERED.add(integration);
}
/**
* Register all the custom entities for a specific plugin into eco.
*
* @see com.willfp.eco.core.entities.Entities
*/
public static void registerAllEntities() {
for (CustomEntitiesWrapper wrapper : REGISTERED) {
wrapper.registerAllEntities();
}
}
private CustomEntitiesManager() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}
}

View File

@@ -0,0 +1,15 @@
package com.willfp.eco.core.integrations.customentities;
import com.willfp.eco.core.integrations.Integration;
/**
* Wrapper class for custom item integrations.
*/
public interface CustomEntitiesWrapper extends Integration {
/**
* Register all the custom entities for a specific plugin into eco.
*
* @see com.willfp.eco.core.entities.Entities
*/
void registerAllEntities();
}

View File

@@ -5,6 +5,9 @@ import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/** /**
* Wrapper class for placeholder integrations. * Wrapper class for placeholder integrations.
*/ */
@@ -24,4 +27,14 @@ public interface PlaceholderIntegration extends Integration {
*/ */
String translate(@NotNull String text, String translate(@NotNull String text,
@Nullable Player player); @Nullable Player player);
/**
* Find all placeholders in a given text.
*
* @param text The text.
* @return The placeholders.
*/
default List<String> findPlaceholdersIn(@NotNull String text) {
return new ArrayList<>();
}
} }

View File

@@ -4,8 +4,10 @@ import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@@ -80,6 +82,21 @@ public final class PlaceholderManager {
return processed; return processed;
} }
/**
* Find all placeholders in a given text.
*
* @param text The text.
* @return The placeholders.
*/
public static List<String> findPlaceholdersIn(@NotNull final String text) {
List<String> found = new ArrayList<>();
for (PlaceholderIntegration integration : REGISTERED_INTEGRATIONS) {
found.addAll(integration.findPlaceholdersIn(text));
}
return found;
}
private PlaceholderManager() { private PlaceholderManager() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
} }

View File

@@ -66,7 +66,7 @@ public class CustomItem implements TestableItem {
@Override @Override
public ItemStack getItem() { public ItemStack getItem() {
return item; return item.clone();
} }
/** /**

View File

@@ -8,6 +8,7 @@ import com.willfp.eco.core.recipe.parts.ModifiedTestableItem;
import com.willfp.eco.core.recipe.parts.TestableStack; import com.willfp.eco.core.recipe.parts.TestableStack;
import com.willfp.eco.util.NamespacedKeyUtils; import com.willfp.eco.util.NamespacedKeyUtils;
import com.willfp.eco.util.NumberUtils; import com.willfp.eco.util.NumberUtils;
import com.willfp.eco.util.StringUtils;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
@@ -118,7 +119,8 @@ public final class Items {
return new EmptyTestableItem(); return new EmptyTestableItem();
} }
String[] args = key.split(" "); String[] args = StringUtils.parseTokens(key);
if (args.length == 0) { if (args.length == 0) {
return new EmptyTestableItem(); return new EmptyTestableItem();
} }

View File

@@ -3,6 +3,7 @@ package com.willfp.eco.core.items.args;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -14,6 +15,7 @@ import java.util.function.Predicate;
* @deprecated Moved to internals. * @deprecated Moved to internals.
*/ */
@Deprecated(since = "6.16.0", forRemoval = true) @Deprecated(since = "6.16.0", forRemoval = true)
@ApiStatus.ScheduledForRemoval(inVersion = "6.18.2")
public class ColorArgParser implements LookupArgParser { public class ColorArgParser implements LookupArgParser {
/** /**
* Instantiate arg parser. * Instantiate arg parser.
@@ -27,4 +29,8 @@ public class ColorArgParser implements LookupArgParser {
@NotNull final ItemMeta meta) { @NotNull final ItemMeta meta) {
return null; return null;
} }
static {
Bukkit.getLogger().severe("Referencing a class marked for removal! (" + ColorArgParser.class.getName() + "), this will throw an error in the next release!");
}
} }

View File

@@ -3,6 +3,7 @@ package com.willfp.eco.core.items.args;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -14,6 +15,7 @@ import java.util.function.Predicate;
* @deprecated Moved to internals. * @deprecated Moved to internals.
*/ */
@Deprecated(since = "6.16.0", forRemoval = true) @Deprecated(since = "6.16.0", forRemoval = true)
@ApiStatus.ScheduledForRemoval(inVersion = "6.18.2")
public class CustomModelDataArgParser implements LookupArgParser { public class CustomModelDataArgParser implements LookupArgParser {
/** /**
* Instantiate arg parser. * Instantiate arg parser.
@@ -27,4 +29,8 @@ public class CustomModelDataArgParser implements LookupArgParser {
@NotNull final ItemMeta meta) { @NotNull final ItemMeta meta) {
return null; return null;
} }
static {
Bukkit.getLogger().severe("Referencing a class marked for removal! (" + CustomModelDataArgParser.class.getName() + "), this will throw an error in the next release!");
}
} }

View File

@@ -3,6 +3,7 @@ package com.willfp.eco.core.items.args;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -14,6 +15,7 @@ import java.util.function.Predicate;
* @deprecated Moved to internals. * @deprecated Moved to internals.
*/ */
@Deprecated(since = "6.16.0", forRemoval = true) @Deprecated(since = "6.16.0", forRemoval = true)
@ApiStatus.ScheduledForRemoval(inVersion = "6.18.2")
public class EnchantmentArgParser implements LookupArgParser { public class EnchantmentArgParser implements LookupArgParser {
/** /**
* Instantiate arg parser. * Instantiate arg parser.
@@ -27,4 +29,8 @@ public class EnchantmentArgParser implements LookupArgParser {
@NotNull final ItemMeta meta) { @NotNull final ItemMeta meta) {
return null; return null;
} }
static {
Bukkit.getLogger().severe("Referencing a class marked for removal! (" + EnchantmentArgParser.class.getName() + "), this will throw an error in the next release!");
}
} }

View File

@@ -3,6 +3,7 @@ package com.willfp.eco.core.items.args;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -14,6 +15,7 @@ import java.util.function.Predicate;
* @deprecated Moved to internals. * @deprecated Moved to internals.
*/ */
@Deprecated(since = "6.16.0", forRemoval = true) @Deprecated(since = "6.16.0", forRemoval = true)
@ApiStatus.ScheduledForRemoval(inVersion = "6.18.2")
public class TextureArgParser implements LookupArgParser { public class TextureArgParser implements LookupArgParser {
/** /**
* Instantiate arg parser. * Instantiate arg parser.
@@ -27,4 +29,8 @@ public class TextureArgParser implements LookupArgParser {
@NotNull final ItemMeta meta) { @NotNull final ItemMeta meta) {
return null; return null;
} }
static {
Bukkit.getLogger().severe("Referencing a class marked for removal! (" + TextureArgParser.class.getName() + "), this will throw an error in the next release!");
}
} }

View File

@@ -39,7 +39,7 @@ public class EnchantedBookBuilder extends AbstractItemStackBuilder<EnchantmentSt
* @return The builder. * @return The builder.
*/ */
public EnchantedBookBuilder addStoredEnchantment(@NotNull final Supplier<Enchantment> enchantment, public EnchantedBookBuilder addStoredEnchantment(@NotNull final Supplier<Enchantment> enchantment,
final Supplier<Integer> level) { @NotNull final Supplier<Integer> level) {
return this.addStoredEnchantment(enchantment.get(), level.get()); return this.addStoredEnchantment(enchantment.get(), level.get());
} }
} }

View File

@@ -111,7 +111,7 @@ public final class ShapedCraftingRecipe extends PluginDependent<EcoPlugin> imple
List<String> lore = meta.hasLore() ? meta.getLore() : new ArrayList<>(); List<String> lore = meta.hasLore() ? meta.getLore() : new ArrayList<>();
assert lore != null; assert lore != null;
lore.add(""); lore.add("");
String add = Eco.getHandler().getEcoPlugin().getLangYml().getString("multiple-in-craft"); String add = Eco.getHandler().getEcoPlugin().getLangYml().getFormattedString("multiple-in-craft");
add = add.replace("%amount%", String.valueOf(item.getAmount())); add = add.replace("%amount%", String.valueOf(item.getAmount()));
lore.add(add); lore.add(add);
meta.setLore(lore); meta.setLore(lore);

View File

@@ -92,7 +92,7 @@ public class Paste {
conn.setRequestMethod("GET"); conn.setRequestMethod("GET");
try (var reader = new BufferedReader( try (var reader = new BufferedReader(
new InputStreamReader(conn.getInputStream()))) { new InputStreamReader(conn.getInputStream()))) {
for (String line; (line = reader.readLine()) != null; ) { for (String line; (line = reader.readLine()) != null;) {
result.append(line); result.append(line);
} }
} }

View File

@@ -91,6 +91,24 @@ public final class ListUtils {
return index >= 0 && index < list.size() ? list.get(index) : null; return index >= 0 && index < list.size() ? list.get(index) : null;
} }
/**
* Get if an iterable of strings contains a certain element regardless of case.
*
* @param list The list.
* @param element The element.
* @return If contained.
*/
public static boolean containsIgnoreCase(@NotNull final Iterable<String> list,
@NotNull final String element) {
for (String s : list) {
if (s.equalsIgnoreCase(element)) {
return true;
}
}
return false;
}
private ListUtils() { private ListUtils() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
} }

View File

@@ -1,11 +1,16 @@
package com.willfp.eco.util; package com.willfp.eco.util;
import org.apache.commons.lang.Validate;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
import java.util.function.BiFunction;
/** /**
* Utilities / API methods for numbers. * Utilities / API methods for numbers.
@@ -16,6 +21,11 @@ public final class NumberUtils {
*/ */
private static final double[] SIN_LOOKUP = new double[65536]; private static final double[] SIN_LOOKUP = new double[65536];
/**
* Crunch handler.
*/
private static BiFunction<String, Player, Double> crunch = null;
/** /**
* Set of roman numerals to look up. * Set of roman numerals to look up.
*/ */
@@ -83,7 +93,9 @@ public final class NumberUtils {
* @param toChange The value to test. * @param toChange The value to test.
* @param limit The maximum. * @param limit The maximum.
* @return The new value. * @return The new value.
* @deprecated Pointless method.
*/ */
@Deprecated(since = "6.19.0")
public static int equalIfOver(final int toChange, public static int equalIfOver(final int toChange,
final int limit) { final int limit) {
return Math.min(toChange, limit); return Math.min(toChange, limit);
@@ -95,7 +107,9 @@ public final class NumberUtils {
* @param toChange The value to test. * @param toChange The value to test.
* @param limit The maximum. * @param limit The maximum.
* @return The new value. * @return The new value.
* @deprecated Pointless method.
*/ */
@Deprecated(since = "6.19.0")
public static double equalIfOver(final double toChange, public static double equalIfOver(final double toChange,
final double limit) { final double limit) {
return Math.min(toChange, limit); return Math.min(toChange, limit);
@@ -185,11 +199,23 @@ public final class NumberUtils {
/** /**
* Get Log base 2 of a number. * Get Log base 2 of a number.
* *
* @param toLog The number. * @param a The number.
* @return The result. * @return The result.
*/ */
public static int log2(final int toLog) { public static int log2(final int a) {
return (int) (Math.log(toLog) / Math.log(2)); return (int) logBase(a, 2);
}
/**
* Log with a base.
*
* @param a The number.
* @param base The base.
* @return The logarithm.
*/
public static double logBase(final double a,
final double base) {
return Math.log(a) / Math.log(base);
} }
/** /**
@@ -206,6 +232,39 @@ public final class NumberUtils {
return formatted.endsWith("00") ? String.valueOf((int) toFormat) : formatted; return formatted.endsWith("00") ? String.valueOf((int) toFormat) : formatted;
} }
/**
* Evaluate an expression.
*
* @param expression The expression.
* @return The value of the expression, or zero if invalid.
*/
public static double evaluateExpression(@NotNull final String expression) {
return evaluateExpression(expression, null);
}
/**
* Evaluate an expression with respect to a player (for placeholders).
*
* @param expression The expression.
* @param player The player.
* @return The value of the expression, or zero if invalid.
*/
public static double evaluateExpression(@NotNull final String expression,
@Nullable final Player player) {
return crunch.apply(expression, player);
}
/**
* Init crunch handler.
*
* @param handler The handler.
*/
@ApiStatus.Internal
public static void initCrunch(@NotNull final BiFunction<String, Player, Double> handler) {
Validate.isTrue(crunch == null, "Already initialized!");
crunch = handler;
}
private NumberUtils() { private NumberUtils() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
} }

View File

@@ -2,6 +2,7 @@ package com.willfp.eco.util;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.gson.JsonSyntaxException;
import com.willfp.eco.core.Prerequisite; import com.willfp.eco.core.Prerequisite;
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager; import com.willfp.eco.core.integrations.placeholder.PlaceholderManager;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
@@ -58,6 +59,13 @@ public final class StringUtils {
.hexColors() .hexColors()
.build(); .build();
/**
* GSON serializer.
*/
private static final GsonComponentSerializer GSON_COMPONENT_SERIALIZER = GsonComponentSerializer.builder()
.emitLegacyHoverEvent()
.build();
/** /**
* Color map. * Color map.
*/ */
@@ -415,7 +423,7 @@ public final class StringUtils {
if (legacy == null) { if (legacy == null) {
processed = ""; processed = "";
} }
return GsonComponentSerializer.gson().serialize( return GSON_COMPONENT_SERIALIZER.serialize(
Component.empty().decoration(TextDecoration.ITALIC, false).append( Component.empty().decoration(TextDecoration.ITALIC, false).append(
LEGACY_COMPONENT_SERIALIZER.deserialize(processed) LEGACY_COMPONENT_SERIALIZER.deserialize(processed)
) )
@@ -429,10 +437,17 @@ public final class StringUtils {
* @return The legacy string. * @return The legacy string.
*/ */
@NotNull @NotNull
public static String jsonToLegacy(@NotNull final String json) { public static String jsonToLegacy(@Nullable final String json) {
return LEGACY_COMPONENT_SERIALIZER.serialize( if (json == null || json.isEmpty()) {
GsonComponentSerializer.gson().deserialize(json) return "";
); }
try {
Component component = GSON_COMPONENT_SERIALIZER.deserialize(json);
return LEGACY_COMPONENT_SERIALIZER.serialize(component);
} catch (JsonSyntaxException e) {
return json;
}
} }
/** /**
@@ -462,6 +477,53 @@ public final class StringUtils {
return LEGACY_COMPONENT_SERIALIZER.serialize(component); return LEGACY_COMPONENT_SERIALIZER.serialize(component);
} }
/**
* Parse string into tokens.
* <p>
* Handles quoted strings for names.
*
* @param lookup The lookup string.
* @return An array of tokens to be processed.
* @author Shawn (https://stackoverflow.com/questions/70606170/split-a-list-on-spaces-and-group-quoted-characters/70606653#70606653)
*/
@NotNull
public static String[] parseTokens(@NotNull final String lookup) {
char[] chars = lookup.toCharArray();
List<String> tokens = new ArrayList<>();
StringBuilder tokenBuilder = new StringBuilder();
for (int i = 0; i < chars.length; i++) {
if (chars[i] == ' ') {
/*
Take the current value of the argument builder, append it to the
list of found tokens, and then clear it for the next argument.
*/
tokens.add(tokenBuilder.toString());
tokenBuilder.setLength(0);
} else if (chars[i] == '"') {
/*
Work until the next unescaped quote to handle quotes with
spaces in them - assumes the input string is well-formatted
*/
for (i++; chars[i] != '"'; i++) {
/*
If the found quote is escaped, ignore it in the parsing
*/
if (chars[i] == '\\') {
i++;
}
tokenBuilder.append(chars[i]);
}
} else {
/*
If it's a regular character, just append it to the current argument.
*/
tokenBuilder.append(chars[i]);
}
}
tokens.add(tokenBuilder.toString()); // Adds the last argument to the tokens.
return tokens.toArray(new String[0]);
}
/** /**
* Options for formatting. * Options for formatting.
*/ */

View File

@@ -7,7 +7,6 @@ import com.google.gson.GsonBuilder
import com.willfp.eco.core.config.ConfigType import com.willfp.eco.core.config.ConfigType
import com.willfp.eco.core.config.interfaces.JSONConfig import com.willfp.eco.core.config.interfaces.JSONConfig
import com.willfp.eco.util.StringUtils import com.willfp.eco.util.StringUtils
import org.bukkit.configuration.file.YamlConfiguration
import java.util.Objects import java.util.Objects
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
@@ -131,24 +130,18 @@ open class EcoJSONConfigWrapper : JSONConfig {
} }
override fun getSubsection(path: String): JSONConfig { override fun getSubsection(path: String): JSONConfig {
val subsection = getSubsectionOrNull(path) return getSubsectionOrNull(path) ?: EcoJSONConfigSection(mutableMapOf())
return subsection ?: EcoJSONConfigSection(emptyMap())
} }
override fun getSubsectionOrNull(path: String): JSONConfig? { override fun getSubsectionOrNull(path: String): JSONConfig? {
return if (values.containsKey(path)) { return if (values.containsKey(path)) {
val subsection = values[path] as Map<String, Any>? val subsection = values[path] as Map<String, Any>
EcoJSONConfigSection(subsection!!) EcoJSONConfigSection(subsection)
} else { } else {
null null
} }
} }
override fun getSubsections(path: String): List<JSONConfig> {
val subsections = getSubsectionsOrNull(path)
return subsections ?: mutableListOf()
}
override fun getSubsectionsOrNull(path: String): List<JSONConfig>? { override fun getSubsectionsOrNull(path: String): List<JSONConfig>? {
val maps = getOfKnownType(path, Any::class.java) as List<Map<String, Any>>? val maps = getOfKnownType(path, Any::class.java) as List<Map<String, Any>>?
?: return null ?: return null
@@ -159,74 +152,20 @@ open class EcoJSONConfigWrapper : JSONConfig {
return configs.toMutableList() return configs.toMutableList()
} }
override fun getInt(path: String): Int {
return (getOfKnownType(path, Double::class.java) ?: 0.0).toInt()
}
override fun getIntOrNull(path: String): Int? { override fun getIntOrNull(path: String): Int? {
return if (has(path)) { return getOfKnownType(path, Double::class.java)?.toInt()
getInt(path)
} else {
null
}
}
override fun getInt(
path: String,
def: Int
): Int {
return Objects.requireNonNullElse(getOfKnownType(path, Int::class.java), def)
}
override fun getInts(path: String): MutableList<Int> {
return (Objects.requireNonNullElse(
getOfKnownType(path, Any::class.java),
emptyList<Int>()
) as List<Int>).toMutableList()
} }
override fun getIntsOrNull(path: String): MutableList<Int>? { override fun getIntsOrNull(path: String): MutableList<Int>? {
return if (has(path)) { return (getOfKnownType(path, Any::class.java) as Collection<Int>?)?.toMutableList()
getInts(path)
} else {
null
}
}
override fun getBool(path: String): Boolean {
return Objects.requireNonNullElse(getOfKnownType(path, Boolean::class.java), false)
} }
override fun getBoolOrNull(path: String): Boolean? { override fun getBoolOrNull(path: String): Boolean? {
return if (has(path)) { return getOfKnownType(path, Boolean::class.java)
getBool(path)
} else {
null
}
}
override fun getBools(path: String): MutableList<Boolean> {
return (Objects.requireNonNullElse(
getOfKnownType(path, Any::class.java),
emptyList<Boolean>()
) as List<Boolean>).toMutableList()
} }
override fun getBoolsOrNull(path: String): MutableList<Boolean>? { override fun getBoolsOrNull(path: String): MutableList<Boolean>? {
return if (has(path)) { return (getOfKnownType(path, Any::class.java) as Collection<Boolean>?)?.toMutableList()
getBools(path)
} else {
null
}
}
override fun getString(
path: String,
format: Boolean,
option: StringUtils.FormatOption
): String {
val string = getOfKnownType(path, String::class.java) ?: ""
return if (format) StringUtils.format(string, option) else string
} }
override fun getStringOrNull( override fun getStringOrNull(
@@ -235,62 +174,36 @@ open class EcoJSONConfigWrapper : JSONConfig {
option: StringUtils.FormatOption option: StringUtils.FormatOption
): String? { ): String? {
return if (has(path)) { return if (has(path)) {
getString(path, format, option) val string = getOfKnownType(path, String::class.java) ?: ""
return if (format) StringUtils.format(string, option) else string
} else { } else {
null null
} }
} }
override fun getStrings(
path: String,
format: Boolean,
option: StringUtils.FormatOption
): MutableList<String> {
val strings =
(Objects.requireNonNullElse(
getOfKnownType(path, Any::class.java),
emptyList<String>()
) as List<String>).toMutableList()
return if (format) StringUtils.formatList(strings, option) else strings
}
override fun getStringsOrNull( override fun getStringsOrNull(
path: String, path: String,
format: Boolean, format: Boolean,
option: StringUtils.FormatOption option: StringUtils.FormatOption
): MutableList<String>? { ): MutableList<String>? {
return if (has(path)) { return if (has(path)) {
getStrings(path, format, option) 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 { } else {
null null
} }
} }
override fun getDouble(path: String): Double {
return Objects.requireNonNullElse(getOfKnownType(path, Double::class.java), 0.0)
}
override fun getDoubleOrNull(path: String): Double? { override fun getDoubleOrNull(path: String): Double? {
return if (has(path)) { return getOfKnownType(path, Double::class.java)
getDouble(path)
} else {
null
}
}
override fun getDoubles(path: String): MutableList<Double> {
return (Objects.requireNonNullElse(
getOfKnownType(path, Any::class.java),
emptyList<Double>()
) as List<Double>).toMutableList()
} }
override fun getDoublesOrNull(path: String): MutableList<Double>? { override fun getDoublesOrNull(path: String): MutableList<Double>? {
return if (has(path)) { return (getOfKnownType(path, Any::class.java) as Collection<Double>?)?.toMutableList()
getDoubles(path)
} else {
null
}
} }
override fun getType(): ConfigType { override fun getType(): ConfigType {

View File

@@ -24,11 +24,7 @@ open class EcoLoadableJSONConfig(
private val name: String = "$configName.json" private val name: String = "$configName.json"
fun reloadFromFile() { fun reloadFromFile() {
try { runCatching { init(configFile) }.onFailure { it.printStackTrace() }
init(configFile)
} catch (e: IOException) {
e.printStackTrace()
}
} }
final override fun createFile() { final override fun createFile() {
@@ -94,11 +90,7 @@ open class EcoLoadableJSONConfig(
createFile() createFile()
} }
configFile = File(directory, name) configFile = File(directory, name)
try { init(configFile)
init(configFile)
} catch (e: IOException) {
e.printStackTrace()
}
plugin.configHandler.addConfig(this) plugin.configHandler.addConfig(this)
} }
} }

View File

@@ -1,10 +1,8 @@
package com.willfp.eco.internal.config.json package com.willfp.eco.internal.config.json
import com.willfp.eco.core.PluginLike import com.willfp.eco.core.PluginLike
import org.bukkit.configuration.InvalidConfigurationException
import org.bukkit.configuration.file.YamlConfiguration import org.bukkit.configuration.file.YamlConfiguration
import java.io.BufferedReader import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader import java.io.InputStreamReader
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
@@ -21,34 +19,28 @@ open class EcoUpdatableJSONConfig(
fun update() { fun update() {
super.clearCache() super.clearCache()
try { this.init(configFile)
this.init(configFile) val newConfig = configInJar
val newConfig = configInJar if (newConfig.getKeys(true) == this.getKeys(true)) {
if (newConfig.getKeys(true) == this.getKeys(true)) { return
return
}
newConfig.getKeys(true).forEach { key: String ->
if (!this.getKeys(true).contains(key)) {
if (updateBlacklist.stream().noneMatch { s: String -> key.contains(s) }) {
this.set(key, newConfig[key])
}
}
}
if (removeUnused) {
this.getKeys(true).forEach { s ->
if (!newConfig.getKeys(true).contains(s)) {
if (updateBlacklist.stream().noneMatch(s::contains)) {
this.set(s, null)
}
}
}
}
this.save()
} catch (e: IOException) {
e.printStackTrace()
} catch (e: InvalidConfigurationException) {
e.printStackTrace()
} }
newConfig.getKeys(true).forEach { key: String ->
if (!this.getKeys(true).contains(key)) {
if (updateBlacklist.stream().noneMatch { s: String -> key.contains(s) }) {
this.set(key, newConfig[key])
}
}
}
if (removeUnused) {
this.getKeys(true).forEach { s ->
if (!newConfig.getKeys(true).contains(s)) {
if (updateBlacklist.stream().noneMatch(s::contains)) {
this.set(s, null)
}
}
}
}
this.save()
} }
private val configInJar: YamlConfiguration private val configInJar: YamlConfiguration
@@ -56,13 +48,7 @@ open class EcoUpdatableJSONConfig(
val newIn = this.source.getResourceAsStream(resourcePath) ?: throw NullPointerException("$name is null?") val newIn = this.source.getResourceAsStream(resourcePath) ?: throw NullPointerException("$name is null?")
val reader = BufferedReader(InputStreamReader(newIn, StandardCharsets.UTF_8)) val reader = BufferedReader(InputStreamReader(newIn, StandardCharsets.UTF_8))
val newConfig = YamlConfiguration() val newConfig = YamlConfiguration()
try { newConfig.load(reader)
newConfig.load(reader)
} catch (e: IOException) {
e.printStackTrace()
} catch (e: InvalidConfigurationException) {
e.printStackTrace()
}
return newConfig return newConfig
} }

View File

@@ -24,15 +24,15 @@ class EcoConfigHandler(
override fun callUpdate() { override fun callUpdate() {
for (method in reflections.getMethodsAnnotatedWith(ConfigUpdater::class.java)) { for (method in reflections.getMethodsAnnotatedWith(ConfigUpdater::class.java)) {
try { kotlin.runCatching {
when (method.parameterCount) { when (method.parameterCount) {
0 -> method.invoke(null) 0 -> method.invoke(null)
1 -> method.invoke(null, this.plugin) 1 -> method.invoke(null, this.plugin)
else -> throw InvalidUpdateMethodException("Update method must have 0 parameters or a plugin parameter.") else -> throw InvalidUpdateMethodException("Update method must have 0 parameters or a plugin parameter.")
} }
} catch (e: ReflectiveOperationException) { }.onFailure {
e.printStackTrace() it.printStackTrace()
throw InvalidUpdateMethodException("Update method generated an exception") plugin.logger.severe("Update method ${method.toGenericString()} generated an exception")
} }
} }
} }

View File

@@ -5,7 +5,6 @@ package com.willfp.eco.internal.config.yaml
import com.willfp.eco.core.PluginLike import com.willfp.eco.core.PluginLike
import com.willfp.eco.core.config.interfaces.LoadableConfig import com.willfp.eco.core.config.interfaces.LoadableConfig
import com.willfp.eco.core.config.interfaces.WrappedYamlConfiguration import com.willfp.eco.core.config.interfaces.WrappedYamlConfiguration
import org.bukkit.configuration.InvalidConfigurationException
import org.bukkit.configuration.file.YamlConfiguration import org.bukkit.configuration.file.YamlConfiguration
import java.io.File import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
@@ -23,13 +22,7 @@ open class EcoLoadableYamlConfig(
private val name: String = "$configName.yml" private val name: String = "$configName.yml"
fun reloadFromFile() { fun reloadFromFile() {
try { handle.load(getConfigFile())
handle.load(getConfigFile())
} catch (e: IOException) {
e.printStackTrace()
} catch (e: InvalidConfigurationException) {
e.printStackTrace()
}
} }
final override fun createFile() { final override fun createFile() {

View File

@@ -1,10 +1,8 @@
package com.willfp.eco.internal.config.yaml package com.willfp.eco.internal.config.yaml
import com.willfp.eco.core.PluginLike import com.willfp.eco.core.PluginLike
import org.bukkit.configuration.InvalidConfigurationException
import org.bukkit.configuration.file.YamlConfiguration import org.bukkit.configuration.file.YamlConfiguration
import java.io.BufferedReader import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader import java.io.InputStreamReader
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
@@ -21,34 +19,28 @@ class EcoUpdatableYamlConfig(
fun update() { fun update() {
super.clearCache() super.clearCache()
try { this.handle.load(configFile)
this.handle.load(configFile) val newConfig = configInJar
val newConfig = configInJar if (newConfig.getKeys(true) == this.handle.getKeys(true)) {
if (newConfig.getKeys(true) == this.handle.getKeys(true)) { return
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)
} catch (e: IOException) {
e.printStackTrace()
} catch (e: InvalidConfigurationException) {
e.printStackTrace()
} }
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 private val configInJar: YamlConfiguration
@@ -56,13 +48,7 @@ class EcoUpdatableYamlConfig(
val newIn = source.getResourceAsStream(resourcePath) ?: throw NullPointerException("$name is null?") val newIn = source.getResourceAsStream(resourcePath) ?: throw NullPointerException("$name is null?")
val reader = BufferedReader(InputStreamReader(newIn, StandardCharsets.UTF_8)) val reader = BufferedReader(InputStreamReader(newIn, StandardCharsets.UTF_8))
val newConfig = YamlConfiguration() val newConfig = YamlConfiguration()
try { newConfig.load(reader)
newConfig.load(reader)
} catch (e: IOException) {
e.printStackTrace()
} catch (e: InvalidConfigurationException) {
e.printStackTrace()
}
return newConfig return newConfig
} }

View File

@@ -49,11 +49,6 @@ open class EcoYamlConfigWrapper<T : ConfigurationSection> : Config {
handle[path] = obj handle[path] = obj
} }
override fun getSubsection(path: String): Config {
val subsection = getSubsectionOrNull(path)
return subsection ?: EcoYamlConfigSection(YamlConfiguration())
}
override fun getSubsectionOrNull(path: String): Config? { override fun getSubsectionOrNull(path: String): Config? {
return if (cache.containsKey(path)) { return if (cache.containsKey(path)) {
cache[path] as Config? cache[path] as Config?
@@ -68,109 +63,55 @@ open class EcoYamlConfigWrapper<T : ConfigurationSection> : Config {
} }
} }
override fun getInt(path: String): Int {
return if (cache.containsKey(path)) {
(cache[path] as Number).toInt()
} else {
cache[path] = handle.getDouble(path, 0.0).toInt()
getInt(path)
}
}
override fun getIntOrNull(path: String): Int? { override fun getIntOrNull(path: String): Int? {
return if (has(path)) {
getInt(path)
} else {
null
}
}
override fun getInt(
path: String,
def: Int
): Int {
return if (cache.containsKey(path)) { return if (cache.containsKey(path)) {
(cache[path] as Number).toInt() (cache[path] as Number).toInt()
} else { } else {
cache[path] = handle.getDouble(path, def.toDouble()).toInt() if (has(path)) {
getInt(path) cache[path] = handle.getDouble(path).toInt()
} } else {
} return null
}
override fun getInts(path: String): MutableList<Int> { getIntOrNull(path)
return if (cache.containsKey(path)) {
(cache[path] as MutableList<Int>).toMutableList()
} else {
cache[path] = if (has(path)) ArrayList(handle.getIntegerList(path)) else mutableListOf<Int>()
getInts(path)
} }
} }
override fun getIntsOrNull(path: String): MutableList<Int>? { override fun getIntsOrNull(path: String): MutableList<Int>? {
return if (has(path)) {
getInts(path)
} else {
null
}
}
override fun getBool(path: String): Boolean {
return if (cache.containsKey(path)) { return if (cache.containsKey(path)) {
cache[path] as Boolean (cache[path] as Collection<Int>).toMutableList()
} else { } else {
cache[path] = handle.getBoolean(path) if (has(path)) {
getBool(path) cache[path] = handle.getIntegerList(path).toMutableList()
} else {
return null
}
getIntsOrNull(path)
} }
} }
override fun getBoolOrNull(path: String): Boolean? { override fun getBoolOrNull(path: String): Boolean? {
return if (has(path)) {
getBool(path)
} else {
null
}
}
override fun getBools(path: String): MutableList<Boolean> {
return if (cache.containsKey(path)) { return if (cache.containsKey(path)) {
(cache[path] as MutableList<Boolean>).toMutableList() cache[path] as Boolean
} else { } else {
cache[path] = if (has(path)) {
if (has(path)) ArrayList(handle.getBooleanList(path)) else mutableListOf<Boolean>() cache[path] = handle.getBoolean(path)
getBools(path) } else {
return null
}
getBoolOrNull(path)
} }
} }
override fun getBoolsOrNull(path: String): MutableList<Boolean>? { override fun getBoolsOrNull(path: String): MutableList<Boolean>? {
return if (has(path)) { return if (cache.containsKey(path)) {
getBools(path) (cache[path] as Collection<Boolean>).toMutableList()
} else { } else {
null if (has(path)) {
} cache[path] = handle.getBooleanList(path).toMutableList()
}
override fun getString(
path: String,
format: Boolean,
option: StringUtils.FormatOption
): String {
if (format && option == StringUtils.FormatOption.WITHOUT_PLACEHOLDERS) {
return if (cache.containsKey("$path\$FMT")) {
cache["$path\$FMT"] as String
} else { } else {
val string: String = handle.getString(path, "")!! return null
cache["$path\$FMT"] = StringUtils.format(string, option)
getString(path, format, option)
} }
} else { getBoolsOrNull(path)
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
} }
} }
@@ -180,108 +121,105 @@ open class EcoYamlConfigWrapper<T : ConfigurationSection> : Config {
option: StringUtils.FormatOption option: StringUtils.FormatOption
): String? { ): String? {
return if (has(path)) { return if (has(path)) {
getString(path, format, option) 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 { } else {
null null
} }
} }
override fun getStrings(
path: String,
format: Boolean,
option: StringUtils.FormatOption
): MutableList<String> {
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
}
}
}
override fun getStringsOrNull( override fun getStringsOrNull(
path: String, path: String,
format: Boolean, format: Boolean,
option: StringUtils.FormatOption option: StringUtils.FormatOption
): MutableList<String>? { ): MutableList<String>? {
return if (has(path)) { return if (has(path)) {
getStrings(path, format, option) 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 { } else {
null null
} }
} }
override fun getDouble(path: String): Double {
return if (cache.containsKey(path)) {
cache[path] as Double
} else {
cache[path] = handle.getDouble(path)
getDouble(path)
}
}
override fun getDoubleOrNull(path: String): Double? { override fun getDoubleOrNull(path: String): Double? {
return if (has(path)) {
getDouble(path)
} else {
null
}
}
override fun getDoubles(path: String): MutableList<Double> {
return if (cache.containsKey(path)) { return if (cache.containsKey(path)) {
(cache[path] as MutableList<Double>).toMutableList() (cache[path] as Number).toDouble()
} else { } else {
cache[path] = if (has(path)) ArrayList(handle.getDoubleList(path)) else emptyList<Double>() if (has(path)) {
getDoubles(path) cache[path] = handle.getDouble(path)
} else {
return null
}
getDoubleOrNull(path)
} }
} }
override fun getDoublesOrNull(path: String): MutableList<Double>? { override fun getDoublesOrNull(path: String): MutableList<Double>? {
return if (has(path)) {
getDoubles(path)
} else {
null
}
}
override fun getSubsections(path: String): MutableList<out Config> {
return if (cache.containsKey(path)) { return if (cache.containsKey(path)) {
(cache[path] as Collection<Config>).toMutableList() (cache[path] as Collection<Double>).toMutableList()
} else { } else {
val mapList = ArrayList(handle.getMapList(path)) as List<Map<String, Any?>> if (has(path)) {
val configList = mutableListOf<Config>() cache[path] = handle.getDoubleList(path).toMutableList()
for (map in mapList) { } else {
val temp = YamlConfiguration.loadConfiguration(StringReader("")) return null
temp.createSection("a", map)
configList.add(EcoYamlConfigSection(temp.getConfigurationSection("a")!!))
} }
getDoublesOrNull(path)
cache[path] = if (has(path)) configList else emptyList()
getSubsections(path)
} }
} }
override fun getSubsectionsOrNull(path: String): MutableList<out Config>? { override fun getSubsectionsOrNull(path: String): MutableList<out Config>? {
return if (has(path)) { return if (has(path)) {
getSubsections(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")!!))
}
cache[path] = if (has(path)) configList else emptyList()
getSubsections(path)
}
} else { } else {
null null
} }

View File

@@ -0,0 +1,34 @@
package com.willfp.eco.internal.entities
import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser
import org.bukkit.entity.Animals
class EntityArgParserAdult : EntityArgParser {
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
var baby = false
for (arg in args) {
if (arg.equals("adult", true)) {
baby = true
}
}
if (!baby) {
return null
}
return EntityArgParseResult(
{
if (it !is Animals) {
return@EntityArgParseResult false
}
it.isAdult
},
{
(it as? Animals)?.setAdult()
}
)
}
}

View File

@@ -0,0 +1,43 @@
package com.willfp.eco.internal.entities
import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser
import org.bukkit.attribute.Attribute
import org.bukkit.entity.LivingEntity
class EntityArgParserAttackDamage : EntityArgParser {
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
var attributeValue: Double? = null
for (arg in args) {
val argSplit = arg.split(":")
if (!argSplit[0].equals("attack-damage", ignoreCase = true)) {
continue
}
if (argSplit.size < 2) {
continue
}
attributeValue = argSplit[1].toDoubleOrNull()
}
attributeValue ?: return null
return EntityArgParseResult(
{
if (it !is LivingEntity) {
return@EntityArgParseResult false
}
val inst = it.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE) ?: return@EntityArgParseResult false
inst.value >= attributeValue
},
{
if (it !is LivingEntity) {
return@EntityArgParseResult
}
it.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE)?.baseValue = attributeValue
}
)
}
}

View File

@@ -0,0 +1,43 @@
package com.willfp.eco.internal.entities
import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser
import org.bukkit.attribute.Attribute
import org.bukkit.entity.LivingEntity
class EntityArgParserAttackSpeed : EntityArgParser {
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
var attributeValue: Double? = null
for (arg in args) {
val argSplit = arg.split(":")
if (!argSplit[0].equals("attack-speed", ignoreCase = true)) {
continue
}
if (argSplit.size < 2) {
continue
}
attributeValue = argSplit[1].toDoubleOrNull()
}
attributeValue ?: return null
return EntityArgParseResult(
{
if (it !is LivingEntity) {
return@EntityArgParseResult false
}
val inst = it.getAttribute(Attribute.GENERIC_ATTACK_SPEED) ?: return@EntityArgParseResult false
inst.value >= attributeValue
},
{
if (it !is LivingEntity) {
return@EntityArgParseResult
}
it.getAttribute(Attribute.GENERIC_ATTACK_SPEED)?.baseValue = attributeValue
}
)
}
}

View File

@@ -0,0 +1,34 @@
package com.willfp.eco.internal.entities
import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser
import org.bukkit.entity.Animals
class EntityArgParserBaby : EntityArgParser {
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
var baby = false
for (arg in args) {
if (arg.equals("baby", true)) {
baby = true
}
}
if (!baby) {
return null
}
return EntityArgParseResult(
{
if (it !is Animals) {
return@EntityArgParseResult false
}
!it.isAdult
},
{
(it as? Animals)?.setBaby()
}
)
}
}

View File

@@ -0,0 +1,34 @@
package com.willfp.eco.internal.entities
import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser
import org.bukkit.entity.Creeper
class EntityArgParserCharged : EntityArgParser {
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
var noAI = false
for (arg in args) {
if (arg.equals("charged", true)) {
noAI = true
}
}
if (!noAI) {
return null
}
return EntityArgParseResult(
{
if (it !is Creeper) {
return@EntityArgParseResult false
}
it.isPowered
},
{
(it as? Creeper)?.isPowered = true
}
)
}
}

View File

@@ -0,0 +1,38 @@
package com.willfp.eco.internal.entities
import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser
import org.bukkit.entity.Creeper
class EntityArgParserExplosionRadius : EntityArgParser {
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
var size: Int? = null
for (arg in args) {
val argSplit = arg.split(":")
if (!argSplit[0].equals("explosion-radius", ignoreCase = true)) {
continue
}
if (argSplit.size < 2) {
continue
}
size = argSplit[1].toIntOrNull()
}
size ?: return null
return EntityArgParseResult(
{
when (it) {
is Creeper -> it.explosionRadius == size
else -> false
}
},
{
when (it) {
is Creeper -> it.explosionRadius = size
}
}
)
}
}

View File

@@ -0,0 +1,43 @@
package com.willfp.eco.internal.entities
import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser
import org.bukkit.attribute.Attribute
import org.bukkit.entity.LivingEntity
class EntityArgParserFlySpeed : EntityArgParser {
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
var attributeValue: Double? = null
for (arg in args) {
val argSplit = arg.split(":")
if (!argSplit[0].equals("fly-speed", ignoreCase = true)) {
continue
}
if (argSplit.size < 2) {
continue
}
attributeValue = argSplit[1].toDoubleOrNull()
}
attributeValue ?: return null
return EntityArgParseResult(
{
if (it !is LivingEntity) {
return@EntityArgParseResult false
}
val inst = it.getAttribute(Attribute.GENERIC_FLYING_SPEED) ?: return@EntityArgParseResult false
inst.value >= attributeValue
},
{
if (it !is LivingEntity) {
return@EntityArgParseResult
}
it.getAttribute(Attribute.GENERIC_FLYING_SPEED)?.baseValue = attributeValue
}
)
}
}

View File

@@ -0,0 +1,43 @@
package com.willfp.eco.internal.entities
import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser
import org.bukkit.attribute.Attribute
import org.bukkit.entity.LivingEntity
class EntityArgParserFollowRange : EntityArgParser {
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
var attributeValue: Double? = null
for (arg in args) {
val argSplit = arg.split(":")
if (!argSplit[0].equals("follow-range", ignoreCase = true)) {
continue
}
if (argSplit.size < 2) {
continue
}
attributeValue = argSplit[1].toDoubleOrNull()
}
attributeValue ?: return null
return EntityArgParseResult(
{
if (it !is LivingEntity) {
return@EntityArgParseResult false
}
val inst = it.getAttribute(Attribute.GENERIC_FOLLOW_RANGE) ?: return@EntityArgParseResult false
inst.value >= attributeValue
},
{
if (it !is LivingEntity) {
return@EntityArgParseResult
}
it.getAttribute(Attribute.GENERIC_FOLLOW_RANGE)?.baseValue = attributeValue
}
)
}
}

View File

@@ -0,0 +1,43 @@
package com.willfp.eco.internal.entities
import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser
import org.bukkit.attribute.Attribute
import org.bukkit.entity.LivingEntity
class EntityArgParserHealth : EntityArgParser {
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
var health: Double? = null
for (arg in args) {
val argSplit = arg.split(":")
if (!argSplit[0].equals("health", ignoreCase = true)) {
continue
}
if (argSplit.size < 2) {
continue
}
health = argSplit[1].toDoubleOrNull()
}
health ?: return null
return EntityArgParseResult(
{
if (it !is LivingEntity) {
return@EntityArgParseResult false
}
it.health >= health
},
{
if (it !is LivingEntity) {
return@EntityArgParseResult
}
it.getAttribute(Attribute.GENERIC_MAX_HEALTH)?.baseValue = health
it.health = health
}
)
}
}

View File

@@ -0,0 +1,43 @@
package com.willfp.eco.internal.entities
import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser
import org.bukkit.attribute.Attribute
import org.bukkit.entity.LivingEntity
class EntityArgParserJumpStrength : EntityArgParser {
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
var attributeValue: Double? = null
for (arg in args) {
val argSplit = arg.split(":")
if (!argSplit[0].equals("jump-strength", ignoreCase = true)) {
continue
}
if (argSplit.size < 2) {
continue
}
attributeValue = argSplit[1].toDoubleOrNull()
}
attributeValue ?: return null
return EntityArgParseResult(
{
if (it !is LivingEntity) {
return@EntityArgParseResult false
}
val inst = it.getAttribute(Attribute.HORSE_JUMP_STRENGTH) ?: return@EntityArgParseResult false
inst.value >= attributeValue
},
{
if (it !is LivingEntity) {
return@EntityArgParseResult
}
it.getAttribute(Attribute.HORSE_JUMP_STRENGTH)?.baseValue = attributeValue
}
)
}
}

View File

@@ -0,0 +1,43 @@
package com.willfp.eco.internal.entities
import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser
import org.bukkit.attribute.Attribute
import org.bukkit.entity.LivingEntity
class EntityArgParserKnockback : EntityArgParser {
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
var attributeValue: Double? = null
for (arg in args) {
val argSplit = arg.split(":")
if (!argSplit[0].equals("knockback", ignoreCase = true)) {
continue
}
if (argSplit.size < 2) {
continue
}
attributeValue = argSplit[1].toDoubleOrNull()
}
attributeValue ?: return null
return EntityArgParseResult(
{
if (it !is LivingEntity) {
return@EntityArgParseResult false
}
val inst = it.getAttribute(Attribute.GENERIC_ATTACK_KNOCKBACK) ?: return@EntityArgParseResult false
inst.value >= attributeValue
},
{
if (it !is LivingEntity) {
return@EntityArgParseResult
}
it.getAttribute(Attribute.GENERIC_ATTACK_KNOCKBACK)?.baseValue = attributeValue
}
)
}
}

View File

@@ -0,0 +1,43 @@
package com.willfp.eco.internal.entities
import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser
import org.bukkit.attribute.Attribute
import org.bukkit.entity.LivingEntity
class EntityArgParserKnockbackResistance : EntityArgParser {
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
var attributeValue: Double? = null
for (arg in args) {
val argSplit = arg.split(":")
if (!argSplit[0].equals("knockback-resistance", ignoreCase = true)) {
continue
}
if (argSplit.size < 2) {
continue
}
attributeValue = argSplit[1].toDoubleOrNull()
}
attributeValue ?: return null
return EntityArgParseResult(
{
if (it !is LivingEntity) {
return@EntityArgParseResult false
}
val inst = it.getAttribute(Attribute.GENERIC_KNOCKBACK_RESISTANCE) ?: return@EntityArgParseResult false
inst.value >= attributeValue
},
{
if (it !is LivingEntity) {
return@EntityArgParseResult
}
it.getAttribute(Attribute.GENERIC_KNOCKBACK_RESISTANCE)?.baseValue = attributeValue
}
)
}
}

View File

@@ -0,0 +1,34 @@
package com.willfp.eco.internal.entities
import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser
import com.willfp.eco.util.StringUtils
class EntityArgParserName : EntityArgParser {
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
var name: String? = null
for (arg in args) {
val argSplit = arg.split(":")
if (!argSplit[0].equals("name", ignoreCase = true)) {
continue
}
if (argSplit.size < 2) {
continue
}
name = argSplit[1]
}
name ?: return null
val formatted = StringUtils.format(name)
return EntityArgParseResult(
{ it.customName == formatted },
{
it.isCustomNameVisible = true
it.customName = formatted
}
)
}
}

View File

@@ -0,0 +1,34 @@
package com.willfp.eco.internal.entities
import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser
import org.bukkit.entity.LivingEntity
class EntityArgParserNoAI : EntityArgParser {
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
var noAI = false
for (arg in args) {
if (arg.equals("no-ai", true)) {
noAI = true
}
}
if (!noAI) {
return null
}
return EntityArgParseResult(
{
if (it !is LivingEntity) {
return@EntityArgParseResult false
}
!it.hasAI()
},
{
(it as? LivingEntity)?.setAI(false)
}
)
}
}

View File

@@ -0,0 +1,41 @@
package com.willfp.eco.internal.entities
import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser
import org.bukkit.entity.Phantom
import org.bukkit.entity.Slime
class EntityArgParserSize : EntityArgParser {
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
var size: Int? = null
for (arg in args) {
val argSplit = arg.split(":")
if (!argSplit[0].equals("size", ignoreCase = true)) {
continue
}
if (argSplit.size < 2) {
continue
}
size = argSplit[1].toIntOrNull()
}
size ?: return null
return EntityArgParseResult(
{
when (it) {
is Slime -> it.size == size
is Phantom -> it.size == size
else -> false
}
},
{
when (it) {
is Slime -> it.size = size
is Phantom -> it.size = size
}
}
)
}
}

View File

@@ -0,0 +1,43 @@
package com.willfp.eco.internal.entities
import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser
import org.bukkit.attribute.Attribute
import org.bukkit.entity.LivingEntity
class EntityArgParserSpawnReinforcements : EntityArgParser {
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
var attributeValue: Double? = null
for (arg in args) {
val argSplit = arg.split(":")
if (!argSplit[0].equals("spawn-reinforcements", ignoreCase = true)) {
continue
}
if (argSplit.size < 2) {
continue
}
attributeValue = argSplit[1].toDoubleOrNull()
}
attributeValue ?: return null
return EntityArgParseResult(
{
if (it !is LivingEntity) {
return@EntityArgParseResult false
}
val inst = it.getAttribute(Attribute.ZOMBIE_SPAWN_REINFORCEMENTS) ?: return@EntityArgParseResult false
inst.value >= attributeValue
},
{
if (it !is LivingEntity) {
return@EntityArgParseResult
}
it.getAttribute(Attribute.ZOMBIE_SPAWN_REINFORCEMENTS)?.baseValue = attributeValue
}
)
}
}

View File

@@ -0,0 +1,43 @@
package com.willfp.eco.internal.entities
import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser
import org.bukkit.attribute.Attribute
import org.bukkit.entity.LivingEntity
class EntityArgParserSpeed : EntityArgParser {
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
var attributeValue: Double? = null
for (arg in args) {
val argSplit = arg.split(":")
if (!argSplit[0].equals("speed", ignoreCase = true)) {
continue
}
if (argSplit.size < 2) {
continue
}
attributeValue = argSplit[1].toDoubleOrNull()
}
attributeValue ?: return null
return EntityArgParseResult(
{
if (it !is LivingEntity) {
return@EntityArgParseResult false
}
val inst = it.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED) ?: return@EntityArgParseResult false
inst.value >= attributeValue
},
{
if (it !is LivingEntity) {
return@EntityArgParseResult
}
it.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED)?.baseValue = attributeValue
}
)
}
}

View File

@@ -10,8 +10,6 @@ import com.willfp.eco.core.extensions.MalformedExtensionException
import org.bukkit.configuration.file.YamlConfiguration import org.bukkit.configuration.file.YamlConfiguration
import java.io.File import java.io.File
import java.io.InputStreamReader import java.io.InputStreamReader
import java.net.MalformedURLException
import java.net.URL
import java.net.URLClassLoader import java.net.URLClassLoader
class EcoExtensionLoader( class EcoExtensionLoader(
@@ -32,9 +30,7 @@ class EcoExtensionLoader(
continue continue
} }
try { runCatching { loadExtension(extensionJar) }.onFailure {
loadExtension(extensionJar)
} catch (e: MalformedExtensionException) {
this.plugin.logger.warning(extensionJar.name + " caused an error!") this.plugin.logger.warning(extensionJar.name + " caused an error!")
} }
} }
@@ -42,13 +38,7 @@ class EcoExtensionLoader(
@Throws(MalformedExtensionException::class) @Throws(MalformedExtensionException::class)
private fun loadExtension(extensionJar: File) { private fun loadExtension(extensionJar: File) {
lateinit var url: URL val url = extensionJar.toURI().toURL()
try {
url = extensionJar.toURI().toURL()
} catch (e: MalformedURLException) {
e.printStackTrace()
}
val classLoader = URLClassLoader(arrayOf(url), this.plugin::class.java.classLoader) val classLoader = URLClassLoader(arrayOf(url), this.plugin::class.java.classLoader)
val ymlIn = classLoader.getResourceAsStream("extension.yml") val ymlIn = classLoader.getResourceAsStream("extension.yml")

View File

@@ -49,4 +49,14 @@ class PlaceholderIntegrationPAPI(private val plugin: EcoPlugin) : PlaceholderExp
): String { ): String {
return PlaceholderAPI.setPlaceholders(player, text) return PlaceholderAPI.setPlaceholders(player, text)
} }
override fun findPlaceholdersIn(text: String): MutableList<String> {
val placeholders = mutableListOf<String>()
val matcher = PlaceholderAPI.getPlaceholderPattern().matcher(text)
while (matcher.find()) {
placeholders.add(matcher.group())
}
return placeholders
}
} }

View File

@@ -11,12 +11,7 @@ class ArgParserFlag : LookupArgParser {
val flags = mutableSetOf<ItemFlag>() val flags = mutableSetOf<ItemFlag>()
for (arg in args) { for (arg in args) {
val flag = try { val flag = kotlin.runCatching { ItemFlag.valueOf(arg.uppercase()) }.getOrNull() ?: continue
ItemFlag.valueOf(arg.uppercase())
} catch (e: Exception) {
null
} ?: continue
flags.add(flag) flags.add(flag)
} }

View File

@@ -18,7 +18,7 @@ class ArgParserName : LookupArgParser {
if (argSplit.size < 2) { if (argSplit.size < 2) {
continue continue
} }
name = argSplit[1].replace("_", "") name = argSplit[1]
} }
name ?: return null name ?: return null

View File

@@ -0,0 +1,15 @@
package com.willfp.eco.internal.spigot.proxy.v1_16_R3
import com.willfp.eco.internal.spigot.proxy.DummyEntityProxy
import org.bukkit.Location
import org.bukkit.craftbukkit.v1_16_R3.CraftWorld
import org.bukkit.entity.Entity
import org.bukkit.entity.EntityType
class DummyEntity : DummyEntityProxy {
override fun createDummyEntity(location: Location): Entity {
val world = location.world as CraftWorld
@Suppress("UsePropertyAccessSyntax")
return world.createEntity(location, EntityType.ZOMBIE.entityClass).getBukkitEntity()
}
}

View File

@@ -1,4 +1,5 @@
package com.willfp.eco.internal.spigot.proxy.v1_16_R3 package com.willfp.eco.internal.spigot.proxy.v1_16_R3
import com.willfp.eco.core.display.Display import com.willfp.eco.core.display.Display
import com.willfp.eco.internal.spigot.proxy.VillagerTradeProxy import com.willfp.eco.internal.spigot.proxy.VillagerTradeProxy
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftMerchantRecipe import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftMerchantRecipe
@@ -30,21 +31,11 @@ class VillagerTrade : VillagerTradeProxy {
} }
private fun getHandle(recipe: CraftMerchantRecipe): net.minecraft.server.v1_16_R3.MerchantRecipe { private fun getHandle(recipe: CraftMerchantRecipe): net.minecraft.server.v1_16_R3.MerchantRecipe {
try { return handle[recipe] as net.minecraft.server.v1_16_R3.MerchantRecipe
return handle[recipe] as net.minecraft.server.v1_16_R3.MerchantRecipe
} catch (e: IllegalAccessException) {
e.printStackTrace()
}
throw IllegalArgumentException("Not CMR")
} }
init { init {
try { handle = CraftMerchantRecipe::class.java.getDeclaredField("handle")
handle = CraftMerchantRecipe::class.java.getDeclaredField("handle") handle.isAccessible = true
handle.isAccessible = true
} catch (e: NoSuchFieldException) {
e.printStackTrace()
throw RuntimeException("Error!")
}
} }
} }

View File

@@ -1,5 +1,5 @@
plugins { plugins {
id("io.papermc.paperweight.userdev") version "1.2.0" id("io.papermc.paperweight.userdev") version "1.3.3"
} }
group = "com.willfp" group = "com.willfp"

View File

@@ -0,0 +1,15 @@
package com.willfp.eco.internal.spigot.proxy.v1_17_R1
import com.willfp.eco.internal.spigot.proxy.DummyEntityProxy
import org.bukkit.Location
import org.bukkit.craftbukkit.v1_17_R1.CraftWorld
import org.bukkit.entity.Entity
import org.bukkit.entity.EntityType
class DummyEntity : DummyEntityProxy {
override fun createDummyEntity(location: Location): Entity {
val world = location.world as CraftWorld
@Suppress("UsePropertyAccessSyntax")
return world.createEntity(location, EntityType.ZOMBIE.entityClass).getBukkitEntity()
}
}

View File

@@ -87,33 +87,29 @@ class NMSFastItemStack(itemStack: org.bukkit.inventory.ItemStack) : EcoFastItemS
override fun getLore(): List<String> { override fun getLore(): List<String> {
if (loreCache != null) { if (loreCache != null) {
return loreCache as List<String> return loreCache!!
}
val lore: MutableList<String> = ArrayList()
for (s in getLoreJSON()) {
lore.add(StringUtils.jsonToLegacy(s))
} }
val lore = this.getLoreJSON().map { StringUtils.jsonToLegacy(it) }
loreCache = lore loreCache = lore
return lore return lore
} }
private fun getLoreJSON(): List<String> { private fun getLoreJSON(): List<String> {
val displayTag = handle.getTagElement("display") ?: return emptyList() val displayTag = handle.getTagElement("display") ?: return emptyList()
return if (displayTag.contains("Lore")) {
val loreTag = displayTag.getList("Lore", CraftMagicNumbers.NBT.TAG_STRING)
val lore: MutableList<String> = ArrayList(loreTag.size)
for (i in loreTag.indices) { if (!displayTag.contains("Lore")) {
lore.add(loreTag.getString(i)) return emptyList()
}
lore
} else {
emptyList()
} }
val loreTag = displayTag.getList("Lore", CraftMagicNumbers.NBT.TAG_STRING)
val lore = mutableListOf<String>()
for (i in loreTag.indices) {
lore.add(loreTag.getString(i))
}
return lore
} }
override fun addItemFlags(vararg hideFlags: ItemFlag) { override fun addItemFlags(vararg hideFlags: ItemFlag) {
@@ -155,11 +151,11 @@ class NMSFastItemStack(itemStack: org.bukkit.inventory.ItemStack) : EcoFastItemS
private var flagBits: Int private var flagBits: Int
get() = get() =
if (handle.hasTag() && handle.tag!!.contains( if (handle.hasTag() && handle.tag.contains(
"HideFlags", "HideFlags",
99 99
) )
) handle.tag!!.getInt("HideFlags") else 0 ) handle.tag.getInt("HideFlags") else 0
set(value) = set(value) =
handle.orCreateTag.putInt("HideFlags", value) handle.orCreateTag.putInt("HideFlags", value)

View File

@@ -1,6 +1,16 @@
plugins {
id("io.papermc.paperweight.userdev") version "1.3.3"
}
group = "com.willfp" group = "com.willfp"
version = rootProject.version version = rootProject.version
dependencies { dependencies {
implementation(files("./impl.jar")) paperDevBundle("1.18.1-R0.1-SNAPSHOT")
}
tasks {
build {
dependsOn(reobfJar)
}
} }

Binary file not shown.

View File

@@ -0,0 +1,15 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R1
import com.willfp.eco.internal.spigot.proxy.AutoCraftProxy
import net.minecraft.network.protocol.game.ClientboundPlaceGhostRecipePacket
import net.minecraft.resources.ResourceLocation
class AutoCraft : AutoCraftProxy {
override fun modifyPacket(packet: Any) {
val recipePacket = packet as ClientboundPlaceGhostRecipePacket
val fKey = recipePacket.javaClass.getDeclaredField("b")
fKey.isAccessible = true
val key = fKey[recipePacket] as ResourceLocation
fKey[recipePacket] = ResourceLocation(key.namespace, key.path + "_displayed")
}
}

View File

@@ -0,0 +1,14 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R1
import com.willfp.eco.internal.spigot.proxy.BlockBreakProxy
import org.bukkit.block.Block
import org.bukkit.entity.Player
class BlockBreak : BlockBreakProxy {
override fun breakBlock(
player: Player,
block: Block
) {
player.breakBlock(block)
}
}

View File

@@ -0,0 +1,93 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R1
import com.willfp.eco.core.display.Display
import com.willfp.eco.internal.spigot.proxy.ChatComponentProxy
import net.kyori.adventure.nbt.api.BinaryTagHolder
import net.kyori.adventure.text.BuildableComponent
import net.kyori.adventure.text.Component
import net.kyori.adventure.text.TranslatableComponent
import net.kyori.adventure.text.event.HoverEvent
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer
import net.minecraft.nbt.TagParser
import org.bukkit.Material
import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftItemStack
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
@Suppress("UNCHECKED_CAST")
class ChatComponent : ChatComponentProxy {
private val gsonComponentSerializer = GsonComponentSerializer.gson()
override fun modifyComponent(obj: Any, player: Player): Any {
if (obj !is net.minecraft.network.chat.Component) {
return obj
}
val component = gsonComponentSerializer.deserialize(
net.minecraft.network.chat.Component.Serializer.toJson(
obj
)
).asComponent() as BuildableComponent<*, *>
val newComponent = modifyBaseComponent(component, player)
return net.minecraft.network.chat.Component.Serializer.fromJson(
gsonComponentSerializer.serialize(newComponent.asComponent())
) ?: obj
}
private fun modifyBaseComponent(baseComponent: Component, player: Player): Component {
var component = baseComponent
if (component is TranslatableComponent) {
val args = mutableListOf<Component>()
for (arg in component.args()) {
args.add(modifyBaseComponent(arg, player))
}
component = component.args(args)
}
val children = mutableListOf<Component>()
for (child in component.children()) {
children.add(modifyBaseComponent(child, player))
}
component = component.children(children)
val hoverEvent: HoverEvent<Any> = component.style().hoverEvent() as HoverEvent<Any>? ?: return component
val showItem = hoverEvent.value()
if (showItem !is HoverEvent.ShowItem) {
return component
}
val newShowItem = showItem.nbt(
BinaryTagHolder.of(
CraftItemStack.asNMSCopy(
Display.display(
CraftItemStack.asBukkitCopy(
CraftItemStack.asNMSCopy(
ItemStack(
Material.matchMaterial(
showItem.item()
.toString()
) ?: return component,
showItem.count()
)
).apply {
this.tag = TagParser.parseTag(
showItem.nbt()?.string() ?: return component
) ?: return component
}
),
player
)
).orCreateTag.toString()
)
)
val newHover = hoverEvent.value(newShowItem)
val style = component.style().hoverEvent(newHover)
return component.style(style)
}
}

View File

@@ -0,0 +1,15 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R1
import com.willfp.eco.internal.spigot.proxy.DummyEntityProxy
import org.bukkit.Location
import org.bukkit.craftbukkit.v1_18_R1.CraftWorld
import org.bukkit.entity.Entity
import org.bukkit.entity.EntityType
class DummyEntity : DummyEntityProxy {
override fun createDummyEntity(location: Location): Entity {
val world = location.world as CraftWorld
@Suppress("UsePropertyAccessSyntax")
return world.createEntity(location, EntityType.ZOMBIE.entityClass).getBukkitEntity()
}
}

View File

@@ -0,0 +1,12 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R1
import com.willfp.eco.core.fast.FastItemStack
import com.willfp.eco.internal.spigot.proxy.v1_18_R1.fast.NMSFastItemStack
import com.willfp.eco.internal.spigot.proxy.FastItemStackFactoryProxy
import org.bukkit.inventory.ItemStack
class FastItemStackFactory : FastItemStackFactoryProxy {
override fun create(itemStack: ItemStack): FastItemStack {
return NMSFastItemStack(itemStack)
}
}

View File

@@ -0,0 +1,44 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R1
import com.mojang.authlib.GameProfile
import com.mojang.authlib.properties.Property
import com.willfp.eco.internal.spigot.proxy.SkullProxy
import org.bukkit.inventory.meta.SkullMeta
import java.lang.reflect.Field
import java.lang.reflect.Method
import java.util.UUID
class Skull : SkullProxy {
private lateinit var setProfile: Method
private lateinit var profile: Field
override fun setSkullTexture(
meta: SkullMeta,
base64: String
) {
if (!this::setProfile.isInitialized) {
setProfile = meta.javaClass.getDeclaredMethod("setProfile", GameProfile::class.java)
setProfile.isAccessible = true
}
val uuid = UUID(
base64.substring(base64.length - 20).hashCode().toLong(),
base64.substring(base64.length - 10).hashCode().toLong()
)
val profile = GameProfile(uuid, "eco")
profile.properties.put("textures", Property("textures", base64))
setProfile.invoke(meta, profile)
}
override fun getSkullTexture(
meta: SkullMeta
): String? {
if (!this::profile.isInitialized) {
profile = meta.javaClass.getDeclaredField("profile")
profile.isAccessible = true
}
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
}
}

View File

@@ -0,0 +1,11 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R1
import com.willfp.eco.internal.spigot.proxy.TPSProxy
import org.bukkit.Bukkit
import org.bukkit.craftbukkit.v1_18_R1.CraftServer
class TPS : TPSProxy {
override fun getTPS(): Double {
return (Bukkit.getServer() as CraftServer).handle.server.recentTps[0]
}
}

View File

@@ -0,0 +1,41 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R1
import com.willfp.eco.core.display.Display
import com.willfp.eco.internal.spigot.proxy.VillagerTradeProxy
import net.minecraft.world.item.trading.MerchantOffer
import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftMerchantRecipe
import org.bukkit.entity.Player
import org.bukkit.inventory.MerchantRecipe
import java.lang.reflect.Field
class VillagerTrade : VillagerTradeProxy {
private val handle: Field = CraftMerchantRecipe::class.java.getDeclaredField("handle")
override fun displayTrade(
recipe: MerchantRecipe,
player: Player
): MerchantRecipe {
val oldRecipe = recipe as CraftMerchantRecipe
val newRecipe = CraftMerchantRecipe(
Display.display(recipe.getResult().clone(), player),
recipe.getUses(),
recipe.getMaxUses(),
recipe.hasExperienceReward(),
recipe.getVillagerExperience(),
recipe.getPriceMultiplier()
)
for (ingredient in recipe.getIngredients()) {
newRecipe.addIngredient(Display.display(ingredient.clone(), player))
}
getHandle(newRecipe).setSpecialPriceDiff(getHandle(oldRecipe).getSpecialPriceDiff())
return newRecipe
}
private fun getHandle(recipe: CraftMerchantRecipe): MerchantOffer {
return handle[recipe] as MerchantOffer
}
init {
handle.isAccessible = true
}
}

View File

@@ -0,0 +1,17 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R1.fast
import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftItemStack
import org.bukkit.inventory.ItemStack
import java.lang.reflect.Field
private val field: Field = CraftItemStack::class.java.getDeclaredField("handle").apply {
isAccessible = true
}
fun ItemStack.getNMSStack(): net.minecraft.world.item.ItemStack {
return if (this !is CraftItemStack) {
CraftItemStack.asNMSCopy(this)
} else {
field[this] as net.minecraft.world.item.ItemStack? ?: CraftItemStack.asNMSCopy(this)
}
}

View File

@@ -0,0 +1,188 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R1.fast
import com.willfp.eco.internal.fast.EcoFastItemStack
import com.willfp.eco.util.StringUtils
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.ItemStack
import net.minecraft.world.item.Items
import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftItemStack
import org.bukkit.craftbukkit.v1_18_R1.util.CraftMagicNumbers
import org.bukkit.craftbukkit.v1_18_R1.util.CraftNamespacedKey
import org.bukkit.enchantments.Enchantment
import org.bukkit.inventory.ItemFlag
import kotlin.experimental.and
@Suppress("UsePropertyAccessSyntax")
class NMSFastItemStack(itemStack: org.bukkit.inventory.ItemStack) : EcoFastItemStack<ItemStack>(
itemStack.getNMSStack(), itemStack
) {
private var loreCache: List<String>? = null
override fun getEnchantmentsOnItem(checkStored: Boolean): Map<Enchantment, Int> {
val enchantmentNBT =
if (checkStored && handle.getItem() === Items.ENCHANTED_BOOK) EnchantedBookItem.getEnchantments(
handle
) else handle.getEnchantmentTags()
val foundEnchantments: MutableMap<Enchantment, Int> = HashMap()
for (base in enchantmentNBT) {
val compound = base as CompoundTag
val key = compound.getString("id")
val level = ('\uffff'.code.toShort() and compound.getShort("lvl")).toInt()
val found = Enchantment.getByKey(CraftNamespacedKey.fromStringOrNull(key))
if (found != null) {
foundEnchantments[found] = level
}
}
return foundEnchantments
}
override fun getLevelOnItem(
enchantment: Enchantment,
checkStored: Boolean
): Int {
val enchantmentNBT =
if (checkStored && handle.getItem() === Items.ENCHANTED_BOOK) EnchantedBookItem.getEnchantments(
handle
) else handle.getEnchantmentTags()
for (base in enchantmentNBT) {
val compound = base as CompoundTag
val key = compound.getString("id")
if (key != enchantment.key.toString()) {
continue
}
return ('\uffff'.code.toShort() and compound.getShort("lvl")).toInt()
}
return 0
}
override fun setLore(lore: List<String>?) {
loreCache = null
val jsonLore: MutableList<String> = ArrayList()
if (lore != null) {
for (s in lore) {
jsonLore.add(StringUtils.legacyToJson(s))
}
}
val displayTag = handle.getOrCreateTagElement("display")
if (!displayTag.contains("Lore")) {
displayTag.put("Lore", ListTag())
}
val loreTag = displayTag.getList("Lore", CraftMagicNumbers.NBT.TAG_STRING)
loreTag.clear()
for (s in jsonLore) {
loreTag.add(StringTag.valueOf(s))
}
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> {
val displayTag = handle.getTagElement("display") ?: return emptyList()
if (!displayTag.contains("Lore")) {
return emptyList()
}
val loreTag = displayTag.getList("Lore", CraftMagicNumbers.NBT.TAG_STRING)
val lore = ArrayList<String>(loreTag.size)
for (i in loreTag.indices) {
lore.add(loreTag.getString(i))
}
return lore
}
override fun addItemFlags(vararg hideFlags: ItemFlag) {
for (flag in hideFlags) {
this.flagBits = this.flagBits or getBitModifier(flag)
}
apply()
}
override fun removeItemFlags(vararg hideFlags: ItemFlag) {
for (flag in hideFlags) {
this.flagBits = this.flagBits and getBitModifier(flag)
}
apply()
}
override fun getItemFlags(): MutableSet<ItemFlag> {
val flags = mutableSetOf<ItemFlag>()
var flagArr: Array<ItemFlag>
val size = ItemFlag.values().also { flagArr = it }.size
for (i in 0 until size) {
val flag = flagArr[i]
if (this.hasItemFlag(flag)) {
flags.add(flag)
}
}
return flags
}
override fun hasItemFlag(flag: ItemFlag): Boolean {
val bitModifier = getBitModifier(flag)
return this.flagBits and bitModifier == bitModifier
}
private var flagBits: Int
get() =
if (handle.hasTag() && handle.getTag()!!.contains(
"HideFlags",
99
)
) handle.getTag()!!.getInt("HideFlags") else 0
set(value) =
handle.getOrCreateTag().putInt("HideFlags", value)
override fun getRepairCost(): Int {
return handle.getBaseRepairCost()
}
override fun setRepairCost(cost: Int) {
handle.setRepairCost(cost)
}
override fun equals(other: Any?): Boolean {
if (other !is NMSFastItemStack) {
return false
}
return other.hashCode() == this.hashCode()
}
override fun hashCode(): Int {
return handle.getTag()?.hashCode() ?: (0b00010101 * 31 + Item.getId(handle.getItem()))
}
private fun apply() {
if (bukkit !is CraftItemStack) {
bukkit.itemMeta = CraftItemStack.asCraftMirror(handle).itemMeta
}
}
}

View File

@@ -5,6 +5,7 @@ dependencies {
implementation('net.kyori:adventure-text-minimessage:4.1.0-SNAPSHOT') { implementation('net.kyori:adventure-text-minimessage:4.1.0-SNAPSHOT') {
exclude group: 'net.kyori', module: 'adventure-api' exclude group: 'net.kyori', module: 'adventure-api'
} }
implementation 'com.github.Redempt:Crunch:1.0'
compileOnly 'net.kyori:adventure-platform-bukkit:4.0.0' compileOnly 'net.kyori:adventure-platform-bukkit:4.0.0'
compileOnly 'org.apache.maven:maven-artifact:3.8.1' compileOnly 'org.apache.maven:maven-artifact:3.8.1'
compileOnly 'com.google.code.gson:gson:2.8.8' compileOnly 'com.google.code.gson:gson:2.8.8'
@@ -35,14 +36,15 @@ dependencies {
compileOnly 'com.zaxxer:HikariCP:5.0.0' compileOnly 'com.zaxxer:HikariCP:5.0.0'
compileOnly 'com.gmail.filoghost.holographicdisplays:holographicdisplays-api:2.4.0' compileOnly 'com.gmail.filoghost.holographicdisplays:holographicdisplays-api:2.4.0'
compileOnly 'com.github.EssentialsX:Essentials:2.19.0' compileOnly 'com.github.EssentialsX:Essentials:2.19.0'
compileOnly 'com.bgsoftware:SuperiorSkyblockAPI:latest' compileOnly 'com.bgsoftware:SuperiorSkyblockAPI:1.8.3'
compileOnly 'com.github.MilkBowl:VaultAPI:1.7' compileOnly 'com.github.MilkBowl:VaultAPI:1.7'
compileOnly 'world.bentobox:bentobox:1.17.3-SNAPSHOT' compileOnly 'world.bentobox:bentobox:1.17.3-SNAPSHOT'
compileOnly 'com.google.guava:guava:31.0.1-jre' compileOnly 'com.google.guava:guava:31.0.1-jre'
compileOnly 'com.iridium:IridiumSkyblock:3.1.2' compileOnly 'com.iridium:IridiumSkyblock:3.1.2'
compileOnly 'com.github.WillFP:CrashClaim:1.0.19' compileOnly 'com.github.WhipDevelopment:CrashClaim:f9cd7d92eb'
compileOnly 'com.wolfyscript.wolfyutilities:wolfyutilities:1.7.8.1' compileOnly 'com.wolfyscript.wolfyutilities:wolfyutilities:1.7.8.1'
compileOnly 'com.github.decentsoftware-eu:decentholograms:2.1.2' compileOnly 'com.github.decentsoftware-eu:decentholograms:2.1.2'
compileOnly 'io.lumine.xikage:MythicMobs:4.9.1'
// CombatLogX V10 + NewbieHelper Expansion // CombatLogX V10 + NewbieHelper Expansion
compileOnly 'com.SirBlobman.combatlogx:CombatLogX-API:10.0.0.0-SNAPSHOT' compileOnly 'com.SirBlobman.combatlogx:CombatLogX-API:10.0.0.0-SNAPSHOT'

View File

@@ -25,8 +25,11 @@ import com.willfp.eco.internal.spigot.data.EcoPlayerProfileHandler
import com.willfp.eco.internal.spigot.data.storage.MySQLDataHandler import com.willfp.eco.internal.spigot.data.storage.MySQLDataHandler
import com.willfp.eco.internal.spigot.data.storage.YamlDataHandler import com.willfp.eco.internal.spigot.data.storage.YamlDataHandler
import com.willfp.eco.internal.spigot.integrations.bstats.MetricHandler import com.willfp.eco.internal.spigot.integrations.bstats.MetricHandler
import com.willfp.eco.internal.spigot.proxy.DummyEntityProxy
import com.willfp.eco.internal.spigot.proxy.FastItemStackFactoryProxy import com.willfp.eco.internal.spigot.proxy.FastItemStackFactoryProxy
import net.kyori.adventure.platform.bukkit.BukkitAudiences import net.kyori.adventure.platform.bukkit.BukkitAudiences
import org.bukkit.Location
import org.bukkit.entity.Entity
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import java.util.logging.Logger import java.util.logging.Logger
@@ -140,4 +143,8 @@ class EcoHandler : EcoSpigotPlugin(), Handler {
fun setAdventure(adventure: BukkitAudiences) { fun setAdventure(adventure: BukkitAudiences) {
this.adventure = adventure this.adventure = adventure
} }
override fun createDummyEntity(location: Location): Entity {
return getProxy(DummyEntityProxy::class.java).createDummyEntity(location)
}
} }

View File

@@ -5,10 +5,12 @@ import com.willfp.eco.core.Eco
import com.willfp.eco.core.EcoPlugin import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.Prerequisite import com.willfp.eco.core.Prerequisite
import com.willfp.eco.core.display.Display import com.willfp.eco.core.display.Display
import com.willfp.eco.core.entities.Entities
import com.willfp.eco.core.integrations.IntegrationLoader import com.willfp.eco.core.integrations.IntegrationLoader
import com.willfp.eco.core.integrations.afk.AFKManager import com.willfp.eco.core.integrations.afk.AFKManager
import com.willfp.eco.core.integrations.anticheat.AnticheatManager import com.willfp.eco.core.integrations.anticheat.AnticheatManager
import com.willfp.eco.core.integrations.antigrief.AntigriefManager import com.willfp.eco.core.integrations.antigrief.AntigriefManager
import com.willfp.eco.core.integrations.customentities.CustomEntitiesManager
import com.willfp.eco.core.integrations.customitems.CustomItemsManager import com.willfp.eco.core.integrations.customitems.CustomItemsManager
import com.willfp.eco.core.integrations.economy.EconomyManager import com.willfp.eco.core.integrations.economy.EconomyManager
import com.willfp.eco.core.integrations.hologram.HologramManager import com.willfp.eco.core.integrations.hologram.HologramManager
@@ -17,6 +19,23 @@ import com.willfp.eco.core.integrations.shop.ShopManager
import com.willfp.eco.core.items.Items import com.willfp.eco.core.items.Items
import com.willfp.eco.internal.display.EcoDisplayHandler import com.willfp.eco.internal.display.EcoDisplayHandler
import com.willfp.eco.internal.drops.DropManager import com.willfp.eco.internal.drops.DropManager
import com.willfp.eco.internal.entities.EntityArgParserAdult
import com.willfp.eco.internal.entities.EntityArgParserAttackDamage
import com.willfp.eco.internal.entities.EntityArgParserAttackSpeed
import com.willfp.eco.internal.entities.EntityArgParserBaby
import com.willfp.eco.internal.entities.EntityArgParserCharged
import com.willfp.eco.internal.entities.EntityArgParserExplosionRadius
import com.willfp.eco.internal.entities.EntityArgParserFlySpeed
import com.willfp.eco.internal.entities.EntityArgParserFollowRange
import com.willfp.eco.internal.entities.EntityArgParserHealth
import com.willfp.eco.internal.entities.EntityArgParserJumpStrength
import com.willfp.eco.internal.entities.EntityArgParserKnockback
import com.willfp.eco.internal.entities.EntityArgParserKnockbackResistance
import com.willfp.eco.internal.entities.EntityArgParserName
import com.willfp.eco.internal.entities.EntityArgParserNoAI
import com.willfp.eco.internal.entities.EntityArgParserSize
import com.willfp.eco.internal.entities.EntityArgParserSpawnReinforcements
import com.willfp.eco.internal.entities.EntityArgParserSpeed
import com.willfp.eco.internal.items.ArgParserColor import com.willfp.eco.internal.items.ArgParserColor
import com.willfp.eco.internal.items.ArgParserCustomModelData import com.willfp.eco.internal.items.ArgParserCustomModelData
import com.willfp.eco.internal.items.ArgParserEnchantment import com.willfp.eco.internal.items.ArgParserEnchantment
@@ -55,7 +74,6 @@ import com.willfp.eco.internal.spigot.integrations.anticheat.AnticheatVulcan
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefBentoBox import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefBentoBox
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefCombatLogXV10 import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefCombatLogXV10
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefCombatLogXV11 import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefCombatLogXV11
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefCrashClaim
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefDeluxeCombat import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefDeluxeCombat
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefFactionsUUID import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefFactionsUUID
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefGriefPrevention import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefGriefPrevention
@@ -65,6 +83,7 @@ import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefLands
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefSuperiorSkyblock2 import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefSuperiorSkyblock2
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefTowny import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefTowny
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefWorldGuard import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefWorldGuard
import com.willfp.eco.internal.spigot.integrations.customentities.CustomEntitiesMythicMobs
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsHeadDatabase import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsHeadDatabase
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsItemsAdder import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsItemsAdder
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsOraxen import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsOraxen
@@ -75,12 +94,14 @@ import com.willfp.eco.internal.spigot.integrations.hologram.HologramHolographicD
import com.willfp.eco.internal.spigot.integrations.mcmmo.McmmoIntegrationImpl import com.willfp.eco.internal.spigot.integrations.mcmmo.McmmoIntegrationImpl
import com.willfp.eco.internal.spigot.integrations.multiverseinventories.MultiverseInventoriesIntegration import com.willfp.eco.internal.spigot.integrations.multiverseinventories.MultiverseInventoriesIntegration
import com.willfp.eco.internal.spigot.integrations.shop.ShopShopGuiPlus import com.willfp.eco.internal.spigot.integrations.shop.ShopShopGuiPlus
import com.willfp.eco.internal.spigot.math.evaluateExpression
import com.willfp.eco.internal.spigot.proxy.BlockBreakProxy import com.willfp.eco.internal.spigot.proxy.BlockBreakProxy
import com.willfp.eco.internal.spigot.proxy.FastItemStackFactoryProxy import com.willfp.eco.internal.spigot.proxy.FastItemStackFactoryProxy
import com.willfp.eco.internal.spigot.proxy.SkullProxy import com.willfp.eco.internal.spigot.proxy.SkullProxy
import com.willfp.eco.internal.spigot.proxy.TPSProxy import com.willfp.eco.internal.spigot.proxy.TPSProxy
import com.willfp.eco.internal.spigot.recipes.ShapedRecipeListener import com.willfp.eco.internal.spigot.recipes.ShapedRecipeListener
import com.willfp.eco.util.BlockUtils import com.willfp.eco.util.BlockUtils
import com.willfp.eco.util.NumberUtils
import com.willfp.eco.util.ServerUtils import com.willfp.eco.util.ServerUtils
import com.willfp.eco.util.SkullUtils import com.willfp.eco.util.SkullUtils
import net.kyori.adventure.platform.bukkit.BukkitAudiences import net.kyori.adventure.platform.bukkit.BukkitAudiences
@@ -105,6 +126,24 @@ abstract class EcoSpigotPlugin : EcoPlugin(
Items.registerArgParser(ArgParserUnbreakable()) Items.registerArgParser(ArgParserUnbreakable())
Items.registerArgParser(ArgParserName()) Items.registerArgParser(ArgParserName())
Entities.registerArgParser(EntityArgParserName())
Entities.registerArgParser(EntityArgParserNoAI())
Entities.registerArgParser(EntityArgParserAttackDamage())
Entities.registerArgParser(EntityArgParserAttackSpeed())
Entities.registerArgParser(EntityArgParserFlySpeed())
Entities.registerArgParser(EntityArgParserFollowRange())
Entities.registerArgParser(EntityArgParserHealth())
Entities.registerArgParser(EntityArgParserJumpStrength())
Entities.registerArgParser(EntityArgParserKnockback())
Entities.registerArgParser(EntityArgParserKnockbackResistance())
Entities.registerArgParser(EntityArgParserSize())
Entities.registerArgParser(EntityArgParserSpawnReinforcements())
Entities.registerArgParser(EntityArgParserSpeed())
Entities.registerArgParser(EntityArgParserBaby())
Entities.registerArgParser(EntityArgParserAdult())
Entities.registerArgParser(EntityArgParserCharged())
Entities.registerArgParser(EntityArgParserExplosionRadius())
val skullProxy = getProxy(SkullProxy::class.java) val skullProxy = getProxy(SkullProxy::class.java)
SkullUtils.initialize( SkullUtils.initialize(
{ meta, base64 -> skullProxy.setSkullTexture(meta, base64) }, { meta, base64 -> skullProxy.setSkullTexture(meta, base64) },
@@ -117,6 +156,8 @@ abstract class EcoSpigotPlugin : EcoPlugin(
val tpsProxy = getProxy(TPSProxy::class.java) val tpsProxy = getProxy(TPSProxy::class.java)
ServerUtils.initialize { tpsProxy.getTPS() } ServerUtils.initialize { tpsProxy.getTPS() }
NumberUtils.initCrunch { exp, player -> evaluateExpression(exp, player) }
postInit() postInit()
} }
@@ -158,6 +199,7 @@ abstract class EcoSpigotPlugin : EcoPlugin(
override fun handleAfterLoad() { override fun handleAfterLoad() {
CustomItemsManager.registerAllItems() CustomItemsManager.registerAllItems()
CustomEntitiesManager.registerAllEntities()
ShopManager.registerEcoProvider() ShopManager.registerEcoProvider()
} }
@@ -174,7 +216,7 @@ abstract class EcoSpigotPlugin : EcoPlugin(
IntegrationLoader("Towny") { AntigriefManager.register(AntigriefTowny()) }, IntegrationLoader("Towny") { AntigriefManager.register(AntigriefTowny()) },
IntegrationLoader("Lands") { AntigriefManager.register(AntigriefLands(this)) }, IntegrationLoader("Lands") { AntigriefManager.register(AntigriefLands(this)) },
IntegrationLoader("Kingdoms") { AntigriefManager.register(AntigriefKingdoms()) }, IntegrationLoader("Kingdoms") { AntigriefManager.register(AntigriefKingdoms()) },
IntegrationLoader("CrashClaim") { AntigriefManager.register(AntigriefCrashClaim()) }, //IntegrationLoader("CrashClaim") { AntigriefManager.register(AntigriefCrashClaim()) },
IntegrationLoader("CombatLogX") { IntegrationLoader("CombatLogX") {
val pluginManager = Bukkit.getPluginManager() val pluginManager = Bukkit.getPluginManager()
val combatLogXPlugin = pluginManager.getPlugin("CombatLogX") ?: return@IntegrationLoader val combatLogXPlugin = pluginManager.getPlugin("CombatLogX") ?: return@IntegrationLoader
@@ -195,6 +237,9 @@ abstract class EcoSpigotPlugin : EcoPlugin(
IntegrationLoader("Vulcan") { AnticheatManager.register(this, AnticheatVulcan()) }, IntegrationLoader("Vulcan") { AnticheatManager.register(this, AnticheatVulcan()) },
IntegrationLoader("Alice") { AnticheatManager.register(this, AnticheatAlice()) }, IntegrationLoader("Alice") { AnticheatManager.register(this, AnticheatAlice()) },
// Custom Entities
IntegrationLoader("MythicMobs") { CustomEntitiesManager.register(CustomEntitiesMythicMobs()) },
// Custom Items // Custom Items
IntegrationLoader("Oraxen") { CustomItemsManager.register(CustomItemsOraxen()) }, IntegrationLoader("Oraxen") { CustomItemsManager.register(CustomItemsOraxen()) },
IntegrationLoader("ItemsAdder") { CustomItemsManager.register(CustomItemsItemsAdder()) }, IntegrationLoader("ItemsAdder") { CustomItemsManager.register(CustomItemsItemsAdder()) },

View File

@@ -12,6 +12,7 @@ import org.bukkit.event.block.BlockMultiPlaceEvent
import org.bukkit.event.block.BlockPistonExtendEvent import org.bukkit.event.block.BlockPistonExtendEvent
import org.bukkit.event.block.BlockPistonRetractEvent import org.bukkit.event.block.BlockPistonRetractEvent
import org.bukkit.event.block.BlockPlaceEvent import org.bukkit.event.block.BlockPlaceEvent
import org.bukkit.event.world.StructureGrowEvent
import org.bukkit.persistence.PersistentDataType import org.bukkit.persistence.PersistentDataType
class PlayerBlockListener( class PlayerBlockListener(
@@ -40,6 +41,15 @@ class PlayerBlockListener(
} }
} }
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
fun onGrow(event: StructureGrowEvent) {
val block = event.location.block
this.plugin.scheduler.run {
removeKey(block)
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
fun onExtend(event: BlockPistonExtendEvent) { fun onExtend(event: BlockPistonExtendEvent) {
val locs = mutableListOf<Location>() val locs = mutableListOf<Location>()

View File

@@ -55,7 +55,7 @@ class MySQLDataHandler(
} }
// Get Exposed to shut the hell up // Get Exposed to shut the hell up
try { runCatching {
exposedLogger::class.java.getDeclaredField("logger").apply { isAccessible = true } exposedLogger::class.java.getDeclaredField("logger").apply { isAccessible = true }
.apply { .apply {
get(exposedLogger).apply { get(exposedLogger).apply {
@@ -63,8 +63,6 @@ class MySQLDataHandler(
.invoke(this, Level.OFF) .invoke(this, Level.OFF)
} }
} }
} catch (e: Exception) {
Eco.getHandler().ecoPlugin.logger.warning("Failed to silence Exposed logger! You might get some console spam")
} }
} }

View File

@@ -8,7 +8,6 @@ import com.willfp.eco.core.AbstractPacketAdapter
import com.willfp.eco.core.EcoPlugin import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.internal.spigot.proxy.AutoCraftProxy import com.willfp.eco.internal.spigot.proxy.AutoCraftProxy
import org.bukkit.entity.Player import org.bukkit.entity.Player
import java.lang.reflect.InvocationTargetException
class PacketAutoRecipe(plugin: EcoPlugin) : AbstractPacketAdapter(plugin, PacketType.Play.Server.AUTO_RECIPE, false) { class PacketAutoRecipe(plugin: EcoPlugin) : AbstractPacketAdapter(plugin, PacketType.Play.Server.AUTO_RECIPE, false) {
override fun onSend( override fun onSend(
@@ -27,10 +26,6 @@ class PacketAutoRecipe(plugin: EcoPlugin) : AbstractPacketAdapter(plugin, Packet
getPlugin().getProxy(AutoCraftProxy::class.java).modifyPacket(packet.handle) getPlugin().getProxy(AutoCraftProxy::class.java).modifyPacket(packet.handle)
val newAutoRecipe = PacketContainer(PacketType.Play.Server.AUTO_RECIPE) val newAutoRecipe = PacketContainer(PacketType.Play.Server.AUTO_RECIPE)
newAutoRecipe.minecraftKeys.write(0, packet.minecraftKeys.read(0)) newAutoRecipe.minecraftKeys.write(0, packet.minecraftKeys.read(0))
try { ProtocolLibrary.getProtocolManager().sendServerPacket(player, newAutoRecipe)
ProtocolLibrary.getProtocolManager().sendServerPacket(player, newAutoRecipe)
} catch (e: InvocationTargetException) {
e.printStackTrace()
}
} }
} }

View File

@@ -47,34 +47,42 @@ class PacketWindowItems(plugin: EcoPlugin) : AbstractPacketAdapter(plugin, Packe
handleRateLimit(player) handleRateLimit(player)
if (usingAsync(player)) { if (usingAsync(player)) {
val newPacket = packet.shallowClone()
fun modifyAndSend(itemStacks: MutableList<ItemStack>, windowId: Int, player: Player) {
modifyWindowItems(itemStacks, windowId, player)
newPacket.itemListModifier.write(0, itemStacks)
ignorePacketList.add(player.name)
ProtocolLibrary.getProtocolManager().sendServerPacket(player, newPacket)
}
executor.execute { executor.execute {
try { runCatching {
modifyAndSend(itemStacks, windowId, player) modifyAndSend(packet.shallowClone(), itemStacks, windowId, player)
} catch (e: Exception) { }.onFailure {
if (this.getPlugin().configYml.getBool("async-display.log-errors")) { if (this.getPlugin().configYml.getBool("async-display.log-errors")) {
this.getPlugin().logger.warning("Error happened in async processing! Disable async display (/plugins/eco/config.yml)" + this.getPlugin().logger.warning(
"if this is a frequent issue. (Remember to disable ratelimit and emergency too)") "Error happened in async processing! Disable async display (/plugins/eco/config.yml)" +
} "if this is a frequent issue. (Remember to disable ratelimit and emergency too)"
)
this.getPlugin().scheduler.run {
modifyAndSend(itemStacks, windowId, player)
} }
} }
} }
} else { } else {
packet.itemListModifier.write(0, modifyWindowItems(itemStacks, windowId, player)) modifyPacket(packet, itemStacks, windowId, player)
}
}
private fun modifyPacket(
packet: PacketContainer,
itemStacks: MutableList<ItemStack>,
windowId: Int,
player: Player
) {
packet.itemListModifier.write(0, modifyWindowItems(itemStacks, windowId, player))
}
private fun modifyAndSend(
packet: PacketContainer,
itemStacks: MutableList<ItemStack>,
windowId: Int,
player: Player
) {
modifyPacket(packet, itemStacks, windowId, player)
ignorePacketList.add(player.name)
this.getPlugin().scheduler.run {
ProtocolLibrary.getProtocolManager().sendServerPacket(player, packet)
} }
} }
@@ -100,7 +108,7 @@ class PacketWindowItems(plugin: EcoPlugin) : AbstractPacketAdapter(plugin, Packe
} }
private fun usingAsync(player: Player): Boolean { private fun usingAsync(player: Player): Boolean {
if (this.getPlugin().configYml.getStrings("async-display.disable-on-types", false) if (this.getPlugin().configYml.getStrings("async-display.disable-on-types")
.map { it.lowercase() }.contains(player.openInventory.type.name.lowercase()) .map { it.lowercase() }.contains(player.openInventory.type.name.lowercase())
) { ) {
return false return false

View File

@@ -14,7 +14,7 @@ class AntigriefCrashClaim : AntigriefWrapper {
block: Block block: Block
): Boolean { ): Boolean {
val api = CrashClaim.getPlugin().api ?: return true val api = CrashClaim.getPlugin().api ?: return true
val claim = api.getClaim(block.location).getNow(null) ?: return true val claim = api.getClaim(block.location) ?: return true
return claim.hasPermission(player.uniqueId, block.location, PermissionRoute.BUILD) return claim.hasPermission(player.uniqueId, block.location, PermissionRoute.BUILD)
} }
@@ -23,7 +23,7 @@ class AntigriefCrashClaim : AntigriefWrapper {
location: Location location: Location
): Boolean { ): Boolean {
val api = CrashClaim.getPlugin().api ?: return true val api = CrashClaim.getPlugin().api ?: return true
val claim = api.getClaim(location).getNow(null) ?: return true val claim = api.getClaim(location) ?: return true
return claim.hasPermission(player.uniqueId, location, PermissionRoute.EXPLOSIONS) return claim.hasPermission(player.uniqueId, location, PermissionRoute.EXPLOSIONS)
} }
@@ -32,7 +32,7 @@ class AntigriefCrashClaim : AntigriefWrapper {
block: Block block: Block
): Boolean { ): Boolean {
val api = CrashClaim.getPlugin().api ?: return true val api = CrashClaim.getPlugin().api ?: return true
val claim = api.getClaim(block.location).getNow(null) ?: return true val claim = api.getClaim(block.location) ?: return true
return claim.hasPermission(player.uniqueId, block.location, PermissionRoute.BUILD) return claim.hasPermission(player.uniqueId, block.location, PermissionRoute.BUILD)
} }
@@ -41,7 +41,7 @@ class AntigriefCrashClaim : AntigriefWrapper {
victim: LivingEntity victim: LivingEntity
): Boolean { ): Boolean {
val api = CrashClaim.getPlugin().api ?: return true val api = CrashClaim.getPlugin().api ?: return true
val claim = api.getClaim(victim.location).getNow(null) ?: return true val claim = api.getClaim(victim.location) ?: return true
return when (victim) { return when (victim) {
is Player -> false is Player -> false
else -> claim.hasPermission(player.uniqueId, victim.location, PermissionRoute.ENTITIES) else -> claim.hasPermission(player.uniqueId, victim.location, PermissionRoute.ENTITIES)

View File

@@ -0,0 +1,32 @@
package com.willfp.eco.internal.spigot.integrations.customentities
import com.willfp.eco.core.entities.CustomEntity
import com.willfp.eco.core.integrations.customentities.CustomEntitiesWrapper
import io.lumine.xikage.mythicmobs.MythicMobs
import org.bukkit.NamespacedKey
class CustomEntitiesMythicMobs : CustomEntitiesWrapper {
override fun registerAllEntities() {
val mobManager = MythicMobs.inst().mobManager
val api = MythicMobs.inst().apiHelper
for (id in mobManager.mobNames) {
val key = NamespacedKey.fromString("mythicmobs:${id.lowercase()}")
key ?: continue
CustomEntity(
key,
{
val entityId = api.getMythicMobInstance(it)?.type?.entityType ?: return@CustomEntity false
entityId.equals(id, ignoreCase = true)
},
{
api.spawnMythicMob(id, it)
}
).register()
}
}
override fun getPluginName(): String {
return "MythicMobs"
}
}

View File

@@ -0,0 +1,38 @@
package com.willfp.eco.internal.spigot.math
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager
import org.bukkit.entity.Player
import redempt.crunch.CompiledExpression
import redempt.crunch.Crunch
import redempt.crunch.data.FastNumberParsing
import redempt.crunch.functional.EvaluationEnvironment
private val cache = mutableMapOf<String, CompiledExpression>()
private val goToZero = Crunch.compileExpression("0")
fun evaluateExpression(expression: String, player: Player?): Double {
val placeholderValues = PlaceholderManager.findPlaceholdersIn(expression)
.map { PlaceholderManager.getResult(player, expression) }
.map { runCatching { FastNumberParsing.parseDouble(it) }.getOrDefault(0.0) }
.toDoubleArray()
val compiled = generateExpression(expression)
return runCatching { compiled.evaluate(*placeholderValues) }.getOrDefault(0.0)
}
private fun generateExpression(expression: String): CompiledExpression {
val cached = cache[expression]
if (cached != null) {
return cached
}
val placeholders = PlaceholderManager.findPlaceholdersIn(expression)
val env = EvaluationEnvironment()
env.setVariableNames(*placeholders.toTypedArray())
val compiled = runCatching { Crunch.compileExpression(expression, env) }.getOrDefault(goToZero)
cache[expression] = compiled
return compiled
}

View File

@@ -39,6 +39,7 @@ softdepend:
- SuperiorSkyblock2 - SuperiorSkyblock2
- CrashClaim - CrashClaim
- DecentHolograms - DecentHolograms
- MythicMobs
libraries: libraries:
- 'org.reflections:reflections:0.9.12' - 'org.reflections:reflections:0.9.12'
- 'org.apache.maven:maven-artifact:3.0.3' - 'org.apache.maven:maven-artifact:3.0.3'
@@ -53,3 +54,4 @@ libraries:
- 'mysql:mysql-connector-java:8.0.25' - 'mysql:mysql-connector-java:8.0.25'
- 'com.google.guava:guava:31.0.1-jre' - 'com.google.guava:guava:31.0.1-jre'
- 'com.zaxxer:HikariCP:5.0.0' - 'com.zaxxer:HikariCP:5.0.0'
- 'org.apache.commons:commons-lang3:3.0'

View File

@@ -0,0 +1,10 @@
package com.willfp.eco.internal.spigot.proxy
import org.bukkit.Location
import org.bukkit.entity.Entity
interface DummyEntityProxy {
fun createDummyEntity(
location: Location
): Entity
}

View File

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