Compare commits

..

102 Commits

Author SHA1 Message Date
Will FP
5e4ae1f932 Removed uses of Sound.valueOf 2025-01-21 14:23:45 +00:00
Will FP
e1849fe307 Updated paperweight userdev 2025-01-20 14:05:51 +00:00
Will FP
afd794e443 Fixed version compatibility issues on FastItemStack 2025-01-20 13:38:03 +00:00
Will FP
91eff08c25 Updated gradle 2024-12-23 12:46:32 +00:00
Will FP
8aef6e90b0 Updated to 6.75.0 2024-12-23 11:34:43 +00:00
Will FP
ce334cb3fd Added cross-version sound fix 2024-12-23 11:34:32 +00:00
Will FP
f45b510036 Added 1.21.4 support 2024-12-06 13:55:16 +00:00
Will FP
64672904e5 Revert "Janky fix for third party plugin"
This reverts commit 8ce07d772e.
2024-12-06 13:48:28 +00:00
Will FP
810aa75143 Revert "Janky thing with Items#getCustomItem"
This reverts commit 7502355e15.
2024-12-06 13:48:28 +00:00
Will FP
7502355e15 Janky thing with Items#getCustomItem 2024-12-05 22:23:01 +00:00
Will FP
2a85c5ae6b Updated to 6.74.5 2024-12-05 22:19:58 +00:00
Will FP
8ce07d772e Janky fix for third party plugin 2024-12-05 22:19:50 +00:00
Will FP
22fd12a23f Added .kotlin to gitignore 2024-12-05 17:12:43 +00:00
Will FP
d0b7e1d7a4 Enabled parallel compilation 2024-12-05 17:10:50 +00:00
Will FP
d87fcc96bb Trying async cache for DelegatedExpressionHandler 2024-12-05 16:31:30 +00:00
Will FP
2158be40cd Updated gradle compilation config 2024-12-05 16:29:08 +00:00
Will FP
1e2d87c9fa Updated to Kotlin 2.1.0 2024-12-05 16:22:00 +00:00
Will FP
fa6753c7c1 Updated build configuration 2024-12-05 15:33:23 +00:00
Will FP
be970bd5a0 Disabled java-ci artifact temporarily 2024-11-04 17:25:22 +00:00
Will FP
b47b3834a4 Added 1.21.3 support 2024-11-04 17:23:14 +00:00
Will FP
81de46a1c1 Fixed skull on 1.21 2024-09-22 16:49:08 +01:00
Auxilor
9814e594e8 Updated to 6.74.1 2024-09-02 11:52:55 +01:00
Auxilor
5b9fffe14a Fixed nearest_attackable target goal 2024-09-02 11:52:48 +01:00
Auxilor
4e6960fab5 Updated withRetries for MySQL 2024-08-27 16:03:55 +01:00
Auxilor
c95c1f032d Updated mysql connector 2024-08-26 22:28:54 +01:00
Auxilor
1d9fc3413d PersistentDataHandler#serializeProfile now runs in parallel for all keys 2024-08-26 16:54:08 +01:00
Auxilor
19c099e2ef Changed exception type 2024-08-26 16:29:19 +01:00
Auxilor
91e224020b Changed MySQL column names 2024-08-26 16:27:11 +01:00
Auxilor
19fc168034 Added legacy mongodb handler for migration 2024-08-26 16:16:31 +01:00
Auxilor
a11815af82 Another reserved keyword 2024-08-25 21:57:57 +01:00
Auxilor
2a63c62800 Another reserved keyword 2024-08-25 21:36:41 +01:00
Auxilor
fd806621cf Removed reserved keyword 2024-08-25 20:01:30 +01:00
Auxilor
f1b831bfb4 Updated to 6.74.0 2024-08-25 17:57:10 +01:00
Will FP
aa3dae1d4e Merge pull request #375 from Auxilor/new-data-handlers
Rewrote persistent data system
2024-08-25 18:56:40 +02:00
Auxilor
413ae4e94d Persistent data tweaks and improvements 2024-08-25 17:29:40 +01:00
Auxilor
1a816b0f14 Fixed list write deadlock for mysql 2024-08-25 17:20:15 +01:00
Auxilor
c2935a45dc Tweaked MySQL retries 2024-08-25 17:09:58 +01:00
Auxilor
1338c0fadc Small cleanup 2024-08-25 17:05:15 +01:00
Auxilor
2ccdbe4bc2 Removed bson-kotlinx 2024-08-25 16:58:47 +01:00
Auxilor
3d78bad4b1 Implemented new MongoDB handler 2024-08-25 16:45:38 +01:00
Auxilor
84d481d753 Fixed several bugs with the new data system 2024-08-24 19:39:54 +01:00
Auxilor
e87b7ceb77 Implemented new data backend 2024-08-24 17:46:31 +01:00
Auxilor
fd031e21f5 Added new data handlers 2024-08-24 16:14:20 +01:00
Auxilor
449bcc1ff8 Merge branch 'refs/heads/master' into new-data-handlers 2024-08-24 14:03:17 +01:00
Auxilor
93bcf6ce44 Updated to 6.73.7 2024-08-24 14:01:20 +01:00
Auxilor
afcbcfa527 Fixed PacketAutoRecipe 2024-08-24 14:01:02 +01:00
Auxilor
2ed1f2bb2f Updated to 6.73.6 2024-08-23 15:18:30 +01:00
Auxilor
9cb596e746 Fixed FastItemStack#getEnchants(true) giving incorrect results when the enchantment component was removed from an item 2024-08-23 15:18:21 +01:00
Auxilor
763a3e9a87 Merge branch 'refs/heads/develop' 2024-08-21 18:23:59 +01:00
Auxilor
f01691663a Fixed ProtocolLib 2024-08-21 18:23:33 +01:00
Auxilor
6c91b4e41f Updated to 6.73.5 2024-08-21 18:08:50 +01:00
Auxilor
06fdb25925 Patch for ArgParserEnchantment 2024-08-21 18:08:39 +01:00
Auxilor
f1b71c2ac9 Started work on new persistent data 2024-08-21 18:07:09 +01:00
Will FP
665857a00f Merge pull request #371 from MCCasper/master
Update config.yml
2024-08-16 00:14:13 +02:00
Nikolai Connolly
f18016b2de Update config.yml 2024-08-15 14:53:23 -05:00
Auxilor
88633f94cb Updated to 6.73.4 2024-08-12 21:48:27 +01:00
Auxilor
903084e574 Added 1.21.1 support 2024-08-12 21:48:04 +01:00
Auxilor
dab0ce2ed2 Updated to 6.73.3 2024-07-30 15:58:04 +01:00
Auxilor
c89edd05f5 Updated to 6.73.2 2024-07-29 18:46:53 +01:00
Auxilor
ce2a53e689 Fixed FancyHolograms integration 2024-07-29 18:46:47 +01:00
Auxilor
6658824f9a Updated to 6.73.1 2024-07-24 15:24:59 +01:00
Auxilor
956d4fa10c Enchantment arg parser is now case insensitive 2024-07-24 15:24:49 +01:00
Will FP
f01e18950c Merge pull request #365 from Exanthiax/develop 2024-07-24 10:44:03 +01:00
Exanthiax
d4a6bf105b Update ParticleFactoryRGB.kt 2024-07-24 01:55:20 +01:00
Auxilor
6a7a825376 Added extra apis to VanillaItemTag 2024-07-21 12:57:55 +01:00
Auxilor
cd232e804c Improved enchantment arg parser 2024-07-21 11:38:35 +01:00
Auxilor
7cf2fa4b4b Improved consistency with custom model data arg parser 2024-07-21 11:22:40 +01:00
Auxilor
cbf88ce678 Improved item tags 2024-07-20 15:36:26 +01:00
Auxilor
79db5978bd Improved ItemTag 2024-07-20 15:16:47 +01:00
Auxilor
0f11f9846c CustomItemTag is now an abstract class 2024-07-20 15:09:26 +01:00
Auxilor
1f460d7a00 Updated to 6.73.0 2024-07-20 15:07:55 +01:00
Auxilor
2fb9525175 Added Item Tags 2024-07-20 15:07:55 +01:00
Auxilor
a9a961ff2b Added FancyHolograms integration 2024-07-20 12:49:07 +01:00
Auxilor
25d572c0db Added AutocrafterPatch 2024-07-20 09:59:58 +01:00
Auxilor
8a4243e434 Fixed XP price 2024-07-19 20:01:20 +01:00
Auxilor
6c40670f5e Updated to 6.72.0 2024-07-19 19:46:26 +01:00
Auxilor
6e94f3cee8 Added support for multiple display modules per plugin 2024-07-19 19:46:26 +01:00
Auxilor
4968d3ff22 Updated to 6.71.6 2024-07-14 16:04:21 +01:00
Auxilor
eecd80be1c Fixed display name 2024-07-14 16:04:14 +01:00
Auxilor
52c1b52f6d Fixed tab completion bug 2024-07-12 18:18:40 +01:00
Auxilor
f321296227 Updated to 6.71.5 2024-07-12 18:08:35 +01:00
Auxilor
ddd12db420 Fixed ExtendedPersistentDataContainerFactory 2024-07-12 18:07:53 +01:00
Auxilor
bd09791b5b Improved command tab-completion 2024-07-08 18:49:29 +01:00
Auxilor
ce9549f03d Updated to 6.71.4 2024-07-08 15:14:24 +01:00
Auxilor
52367dbb95 Fixed Java 17 compatibility 2024-07-08 15:14:18 +01:00
Auxilor
0080c32c23 Updated to 6.71.3 2024-06-25 02:30:45 +01:00
Auxilor
581094a930 Fixed DurabilityUtils 2024-06-25 02:30:37 +01:00
Auxilor
5d9c8775e8 Updated to 6.71.2 2024-06-24 18:44:16 +01:00
Auxilor
9ab51d2c87 Added fix for TopInventory on pre-1.21 2024-06-24 18:42:32 +01:00
Auxilor
b0de341d7f Updated to 6.71.1 2024-06-23 16:45:17 +01:00
Auxilor
1bada835ea Added 1.21 item arg parsers 2024-06-23 14:20:49 +01:00
Auxilor
de04833f0c Updated custom name and lore on 1.21 2024-06-22 23:44:29 +01:00
Auxilor
75dd6be539 Fixed custom name on 1.21 2024-06-22 22:52:01 +01:00
Auxilor
9b47e4777a Dropped 1.20.6 support and made modern commons module for 1.21+ 2024-06-22 22:23:51 +01:00
Will FP
e2a6d6d9ac Merge pull request #359 from MCCasper/master
fix empty nbt
2024-06-22 22:11:36 +01:00
Nikolai Connolly
4c1bc76ee2 fix empty nbt 2024-06-22 17:09:23 -04:00
Auxilor
61c90d85ac Fixed 1.20.6+ getEnchants 2024-06-20 23:14:09 +01:00
Auxilor
6faaac2257 Fixed 1.20.6+ getEnchants 2024-06-20 23:13:52 +01:00
Auxilor
9ad489b9d9 Updated to 6.71.0 2024-06-20 18:48:19 +01:00
Auxilor
3a0e1eaf4d Added 1.21 support and fixed paperweight issues for Java 17 versions 2024-06-18 20:53:04 +01:00
Jason Penilla
80afa9127f Explicitly declare toolchains/make compile work consistently
Signed-off-by: WillFP <william.favierparsons1@gmail.com>
2024-06-18 20:53:04 +01:00
Auxilor
ad44891f5f 1.21 groundwork 2024-06-18 20:53:04 +01:00
235 changed files with 5050 additions and 1514 deletions

View File

@@ -30,7 +30,7 @@ jobs:
- run: ./gradlew build --full-stacktrace
- uses: actions/upload-artifact@v2
with:
name: eco-dev-${{ steps.vars.outputs.sha_short }}
path: build/libs
# - uses: actions/upload-artifact@v2
# with:
# name: eco-dev-${{ steps.vars.outputs.sha_short }}
# path: build/libs

3
.gitignore vendored
View File

@@ -22,3 +22,6 @@ gradle-app.setting
# Mac OSX
.DS_Store
# Kotlin
.kotlin

View File

@@ -1,20 +1,21 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.21")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:2.1.0")
}
}
plugins {
id("java-library")
id("io.github.goooler.shadow") version "8.1.7"
id("com.gradleup.shadow") version "8.3.5"
id("maven-publish")
id("java")
kotlin("jvm") version "1.9.21"
kotlin("plugin.serialization") version "1.9.21"
kotlin("jvm") version "2.1.0"
}
dependencies {
@@ -22,6 +23,7 @@ dependencies {
implementation(project(path = ":eco-core:core-plugin", configuration = "shadow"))
implementation(project(":eco-core:core-proxy"))
implementation(project(":eco-core:core-backend"))
implementation(project(":eco-core:core-backend-modern"))
implementation(project(path = ":eco-core:core-nms:v1_17_R1", configuration = "reobf"))
implementation(project(path = ":eco-core:core-nms:v1_18_R1", configuration = "reobf"))
implementation(project(path = ":eco-core:core-nms:v1_18_R2", configuration = "reobf"))
@@ -31,22 +33,29 @@ dependencies {
implementation(project(path = ":eco-core:core-nms:v1_20_R1", configuration = "reobf"))
implementation(project(path = ":eco-core:core-nms:v1_20_R2", configuration = "reobf"))
implementation(project(path = ":eco-core:core-nms:v1_20_R3", configuration = "reobf"))
implementation(project(path = ":eco-core:core-nms:v1_20_6", configuration = "reobf"))
implementation(project(path = ":eco-core:core-nms:v1_21", configuration = "reobf"))
implementation(project(path = ":eco-core:core-nms:v1_21_3", configuration = "reobf"))
implementation(project(path = ":eco-core:core-nms:v1_21_4", configuration = "reobf"))
}
allprojects {
apply(plugin = "java")
apply(plugin = "java-library")
apply(plugin = "maven-publish")
apply(plugin = "io.github.goooler.shadow")
apply(plugin = "com.gradleup.shadow")
apply(plugin = "kotlin")
apply(plugin = "org.jetbrains.kotlin.plugin.serialization")
repositories {
mavenCentral()
mavenLocal()
maven("https://repo.auxilor.io/repository/maven-public/")
maven("https://jitpack.io")
maven("https://jitpack.io") {
content { includeGroupByRegex("com\\.github\\..*") }
}
// Paper
maven("https://repo.papermc.io/repository/maven-public/")
// SuperiorSkyblock2
maven("https://repo.bg-software.com/repository/api/")
@@ -61,7 +70,7 @@ allprojects {
maven("https://repo.extendedclip.com/content/repositories/placeholderapi/")
// ProtocolLib
//maven("https://repo.dmulloy2.net/nexus/repository/public/")
maven("https://repo.dmulloy2.net/nexus/repository/public/")
// WorldGuard
maven("https://maven.enginehub.org/repo/")
@@ -95,16 +104,19 @@ allprojects {
// HuskPlugins
maven("https://repo.william278.net/releases")
// FancyHolograms
maven("https://repo.fancyplugins.de/releases")
}
dependencies {
// Kotlin
implementation(kotlin("stdlib", version = "1.9.21"))
implementation(kotlin("stdlib", version = "2.1.0"))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
// Included in spigot jar, no need to move to implementation
compileOnly("org.jetbrains:annotations:23.0.0")
compileOnly("com.google.guava:guava:31.1-jre")
compileOnly("com.google.guava:guava:32.0.0-jre")
// Test
testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.2")
@@ -148,8 +160,8 @@ allprojects {
}
compileKotlin {
kotlinOptions {
jvmTarget = "17"
compilerOptions {
jvmTarget.set(JvmTarget.JVM_17)
}
}
@@ -158,12 +170,6 @@ allprojects {
options.encoding = "UTF-8"
}
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
withSourcesJar()
}
test {
useJUnitPlatform()
@@ -176,6 +182,17 @@ allprojects {
build {
dependsOn(shadowJar)
}
withType<JavaCompile>().configureEach {
options.release.set(17)
}
}
java {
withSourcesJar()
toolchain {
languageVersion.set(JavaLanguageVersion.of(21))
}
}
}
@@ -202,7 +219,6 @@ tasks {
//relocate("com.mysql", "com.willfp.eco.libs.mysql")
relocate("com.mongodb", "com.willfp.eco.libs.mongodb")
relocate("org.bson", "com.willfp.eco.libs.bson")
relocate("org.litote", "com.willfp.eco.libs.litote")
relocate("org.reactivestreams", "com.willfp.eco.libs.reactivestreams")
relocate("reactor.", "com.willfp.eco.libs.reactor.") // Dot in name to be safe
relocate("com.moandjiezana.toml", "com.willfp.eco.libs.toml")
@@ -215,12 +231,5 @@ tasks {
}
}
// Root is Java 21 to support 1.20.6+, rest use Java 17
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
withSourcesJar()
}
group = "com.willfp"
version = findProperty("version")!!

View File

@@ -1,5 +1,6 @@
package com.willfp.eco.core;
import com.google.common.collect.ImmutableList;
import com.willfp.eco.core.command.impl.PluginCommand;
import com.willfp.eco.core.config.base.ConfigYml;
import com.willfp.eco.core.config.base.LangYml;
@@ -36,6 +37,8 @@ import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
@@ -120,9 +123,17 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike, Regist
/**
* The display module for the plugin.
*
* @deprecated Plugins can now have multiple display modules.
*/
@Deprecated(since = "6.72.0")
private DisplayModule displayModule;
/**
* The display modules for the plugin.
*/
private List<DisplayModule> displayModules = new ArrayList<>();
/**
* The logger for the plugin.
*/
@@ -555,10 +566,15 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike, Regist
* Default code to be executed after the server is up.
*/
public final void afterLoad() {
this.displayModule = createDisplayModule();
DisplayModule module = createDisplayModule();
if (module != null) {
Display.registerDisplayModule(module);
this.displayModules.add(module);
}
if (this.getDisplayModule() != null) {
Display.registerDisplayModule(this.getDisplayModule());
for (DisplayModule displayModule : this.loadDisplayModules()) {
Display.registerDisplayModule(displayModule);
this.displayModules.add(displayModule);
}
if (Prerequisite.HAS_PROTOCOLLIB.isMet()) {
@@ -899,14 +915,25 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike, Regist
* Create the display module for the plugin.
*
* @return The display module, or null.
* @deprecated Use {@link #loadDisplayModules()} instead.
*/
@Nullable
@Deprecated(since = "6.72.0")
protected DisplayModule createDisplayModule() {
Validate.isTrue(this.getDisplayModule() == null, "Display module exists!");
return null;
}
/**
* Load display modules.
*
* @return The display modules.
*/
protected List<DisplayModule> loadDisplayModules() {
return new ArrayList<>();
}
/**
* Get the minimum version of eco to use the plugin.
*
@@ -1156,12 +1183,23 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike, Regist
* Get the plugin's display module.
*
* @return The display module.
* @deprecated Use {@link #getDisplayModules()} instead.
*/
@Nullable
@Deprecated(since = "6.72.0", forRemoval = true)
public DisplayModule getDisplayModule() {
return this.displayModule;
}
/**
* Get the plugin's display modules.
*
* @return The display modules.
*/
public List<DisplayModule> getDisplayModules() {
return ImmutableList.copyOf(this.displayModules);
}
/**
* Get if the plugin is outdated.
*

View File

@@ -38,15 +38,32 @@ public class Prerequisite {
);
/**
* Requires the server to be running 1.20.5.
* Requires the server to be running at least 1.21.3.
*/
public static final Prerequisite HAS_1_21_3 = new Prerequisite(
() -> ProxyConstants.NMS_VERSION.contains("1_21_3"),
"Requires server to be running 1.21.3+"
);
/**
* Requires the server to be running at least 1.21.
*/
public static final Prerequisite HAS_1_21 = new Prerequisite(
() -> ProxyConstants.NMS_VERSION.contains("1_21") || HAS_1_21_3.isMet(),
"Requires server to be running 1.21+"
);
/**
* Requires the server to be running at least 1.20.5.
*/
public static final Prerequisite HAS_1_20_5 = new Prerequisite(
() -> ProxyConstants.NMS_VERSION.contains("1_20_") && !ProxyConstants.NMS_VERSION.contains("R"),
() -> (ProxyConstants.NMS_VERSION.contains("1_20_") && !ProxyConstants.NMS_VERSION.contains("R"))
|| HAS_1_21.isMet(),
"Requires server to be running 1.20.5+"
);
/**
* Requires the server to be running 1.20.3.
* Requires the server to be running at least 1.20.3.
*/
public static final Prerequisite HAS_1_20_3 = new Prerequisite(
() -> ProxyConstants.NMS_VERSION.contains("20_R3") || HAS_1_20_5.isMet(),
@@ -54,7 +71,7 @@ public class Prerequisite {
);
/**
* Requires the server to be running 1.20.
* Requires the server to be running at least 1.20.
*/
public static final Prerequisite HAS_1_20 = new Prerequisite(
() -> ProxyConstants.NMS_VERSION.contains("20") || HAS_1_20_3.isMet(),
@@ -62,7 +79,7 @@ public class Prerequisite {
);
/**
* Requires the server to be running 1.19.4.
* Requires the server to be running at least 1.19.4.
*/
public static final Prerequisite HAS_1_19_4 = new Prerequisite(
() -> ProxyConstants.NMS_VERSION.contains("19_R3") || HAS_1_20.isMet(),
@@ -70,7 +87,7 @@ public class Prerequisite {
);
/**
* Requires the server to be running 1.19.
* Requires the server to be running at least 1.19.
*/
public static final Prerequisite HAS_1_19 = new Prerequisite(
() -> ProxyConstants.NMS_VERSION.contains("19") || HAS_1_20.isMet(),
@@ -78,7 +95,7 @@ public class Prerequisite {
);
/**
* Requires the server to be running 1.18.
* Requires the server to be running at least 1.18.
*/
public static final Prerequisite HAS_1_18 = new Prerequisite(
() -> ProxyConstants.NMS_VERSION.contains("18") || HAS_1_19.isMet(),

View File

@@ -0,0 +1,44 @@
package com.willfp.eco.core.data.handlers;
import com.willfp.eco.core.data.keys.PersistentDataKey;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.UUID;
/**
* Handles data read/write for a {@link com.willfp.eco.core.data.keys.PersistentDataKeyType} for a specific
* data handler.
*
* @param <T> The type of data.
*/
public abstract class DataTypeSerializer<T> {
/**
* Create a new data type serializer.
*/
protected DataTypeSerializer() {
}
/**
* Read a value.
*
* @param uuid The uuid.
* @param key The key.
* @return The value.
*/
@Nullable
public abstract T readAsync(@NotNull final UUID uuid,
@NotNull final PersistentDataKey<T> key);
/**
* Write a value.
*
* @param uuid The uuid.
* @param key The key.
* @param value The value.
*/
public abstract void writeAsync(@NotNull final UUID uuid,
@NotNull final PersistentDataKey<T> key,
@NotNull final T value);
}

View File

@@ -0,0 +1,180 @@
package com.willfp.eco.core.data.handlers;
import com.willfp.eco.core.data.keys.PersistentDataKey;
import com.willfp.eco.core.registry.Registrable;
import com.willfp.eco.core.tuples.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* Handles persistent data.
*/
public abstract class PersistentDataHandler implements Registrable {
/**
* The id.
*/
private final String id;
/**
* The executor.
*/
private final ExecutorService executor = Executors.newCachedThreadPool();
/**
* Create a new persistent data handler.
*
* @param id The id.
*/
protected PersistentDataHandler(@NotNull final String id) {
this.id = id;
}
/**
* Get all UUIDs with saved data.
* <p>
* This is a blocking operation.
*
* @return All saved UUIDs.
*/
public abstract Set<UUID> getSavedUUIDs();
/**
* Save to disk.
* <p>
* If write commits to disk, this method does not need to be overridden.
* <p>
* This method is called asynchronously.
*/
protected void doSave() {
// Save to disk
}
/**
* If the handler should autosave.
*
* @return If the handler should autosave.
*/
public boolean shouldAutosave() {
return true;
}
/**
* Save the data.
*/
public final void save() {
executor.submit(this::doSave);
}
/**
* Read a key from persistent data.
*
* @param uuid The uuid.
* @param key The key.
* @param <T> The type of the key.
* @return The value, or null if not found.
*/
@Nullable
public final <T> T read(@NotNull final UUID uuid,
@NotNull final PersistentDataKey<T> key) {
DataTypeSerializer<T> serializer = key.getType().getSerializer(this);
Future<T> future = executor.submit(() -> serializer.readAsync(uuid, key));
try {
return future.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
return null;
}
}
/**
* Write a key to persistent data.
*
* @param uuid The uuid.
* @param key The key.
* @param value The value.
* @param <T> The type of the key.
*/
public final <T> void write(@NotNull final UUID uuid,
@NotNull final PersistentDataKey<T> key,
@NotNull final T value) {
DataTypeSerializer<T> serializer = key.getType().getSerializer(this);
executor.submit(() -> serializer.writeAsync(uuid, key, value));
}
/**
* Serialize profile.
*
* @param uuid The uuid to serialize.
* @param keys The keys to serialize.
* @return The serialized data.
*/
@NotNull
public final SerializedProfile serializeProfile(@NotNull final UUID uuid,
@NotNull final Set<PersistentDataKey<?>> keys) {
Map<PersistentDataKey<?>, CompletableFuture<Object>> futures = keys.stream()
.collect(Collectors.toMap(
key -> key,
key -> CompletableFuture.supplyAsync(() -> read(uuid, key), executor)
));
Map<PersistentDataKey<?>, Object> data = futures.entrySet().stream()
.map(entry -> new Pair<PersistentDataKey<?>, Object>(entry.getKey(), entry.getValue().join()))
.filter(entry -> entry.getSecond() != null)
.collect(Collectors.toMap(Pair::getFirst, Pair::getSecond));
return new SerializedProfile(uuid, data);
}
/**`
* Load profile data.
*
* @param profile The profile.
*/
@SuppressWarnings("unchecked")
public final void loadSerializedProfile(@NotNull final SerializedProfile profile) {
for (Map.Entry<PersistentDataKey<?>, Object> entry : profile.data().entrySet()) {
PersistentDataKey<?> key = entry.getKey();
Object value = entry.getValue();
// This cast is safe because the data is serialized
write(profile.uuid(), (PersistentDataKey<? super Object>) key, value);
}
}
/**
* Save and shutdown the handler.
*
* @throws InterruptedException If the writes could not be awaited.
*/
public final void shutdown() throws InterruptedException {
doSave();
if (executor.isShutdown()) {
return;
}
executor.shutdown();
while (!executor.awaitTermination(2, TimeUnit.MINUTES)) {
// Wait
}
}
@Override
@NotNull
public final String getID() {
return id;
}
}

View File

@@ -0,0 +1,20 @@
package com.willfp.eco.core.data.handlers;
import com.willfp.eco.core.data.keys.PersistentDataKey;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
import java.util.UUID;
/**
* Serialized profile.
*
* @param uuid The uuid.
* @param data The data.
*/
public record SerializedProfile(
@NotNull UUID uuid,
@NotNull Map<PersistentDataKey<?>, Object> data
) {
}

View File

@@ -34,6 +34,19 @@ public final class PersistentDataKey<T> {
*/
private final boolean isLocal;
/**
* Create a new Persistent Data Key.
*
* @param key The key.
* @param type The data type.
* @param defaultValue The default value.
*/
public PersistentDataKey(@NotNull final NamespacedKey key,
@NotNull final PersistentDataKeyType<T> type,
@NotNull final T defaultValue) {
this(key, type, defaultValue, false);
}
/**
* Create a new Persistent Data Key.
*
@@ -54,24 +67,6 @@ public final class PersistentDataKey<T> {
Eco.get().registerPersistentKey(this);
}
/**
* Create a new Persistent Data Key.
*
* @param key The key.
* @param type The data type.
* @param defaultValue The default value.
*/
public PersistentDataKey(@NotNull final NamespacedKey key,
@NotNull final PersistentDataKeyType<T> type,
@NotNull final T defaultValue) {
this.key = key;
this.defaultValue = defaultValue;
this.type = type;
this.isLocal = false;
Eco.get().registerPersistentKey(this);
}
@Override
public String toString() {
return "PersistentDataKey{"

View File

@@ -1,12 +1,17 @@
package com.willfp.eco.core.data.keys;
import com.willfp.eco.core.config.interfaces.Config;
import com.willfp.eco.core.data.handlers.DataTypeSerializer;
import com.willfp.eco.core.data.handlers.PersistentDataHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
/**
@@ -61,13 +66,9 @@ public final class PersistentDataKeyType<T> {
private final String name;
/**
* Get the name of the key type.
*
* @return The name.
* The serializers for this key type.
*/
public String name() {
return name;
}
private final Map<PersistentDataHandler, DataTypeSerializer<T>> serializers = new HashMap<>();
/**
* Create new PersistentDataKeyType.
@@ -80,6 +81,44 @@ public final class PersistentDataKeyType<T> {
this.name = name;
}
/**
* Get the name of the key type.
*
* @return The name.
*/
@NotNull
public String name() {
return name;
}
/**
* Register a serializer for this key type.
*
* @param handler The handler.
* @param serializer The serializer.
*/
public void registerSerializer(@NotNull final PersistentDataHandler handler,
@NotNull final DataTypeSerializer<T> serializer) {
this.serializers.put(handler, serializer);
}
/**
* Get the serializer for a handler.
*
* @param handler The handler.
* @return The serializer.
*/
@NotNull
public DataTypeSerializer<T> getSerializer(@NotNull final PersistentDataHandler handler) {
DataTypeSerializer<T> serializer = this.serializers.get(handler);
if (serializer == null) {
throw new NoSuchElementException("No serializer for handler: " + handler);
}
return serializer;
}
@Override
public boolean equals(@Nullable final Object that) {
if (this == that) {

View File

@@ -211,12 +211,22 @@ public final class Display {
new ArrayList<>()
);
modules.removeIf(it -> it.getPluginName().equalsIgnoreCase(module.getPluginName()));
modules.add(module);
REGISTERED_MODULES.put(module.getWeight(), modules);
}
/**
* Unregister a display module.
*
* @param module The module.
*/
public static void unregisterDisplayModule(@NotNull final DisplayModule module) {
for (List<DisplayModule> modules : REGISTERED_MODULES.values()) {
modules.remove(module);
}
}
private Display() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}

View File

@@ -6,6 +6,7 @@ import com.willfp.eco.core.entities.TestableEntity;
import com.willfp.eco.core.entities.ai.EntityGoal;
import com.willfp.eco.core.items.Items;
import com.willfp.eco.core.serialization.KeyedDeserializer;
import com.willfp.eco.util.SoundUtils;
import org.bukkit.NamespacedKey;
import org.bukkit.Sound;
import org.bukkit.entity.LivingEntity;
@@ -50,9 +51,15 @@ public record EntityGoalUseItem(
TestableEntity filter = Entities.lookup(config.getString("condition"));
Sound sound = SoundUtils.getSound(config.getString("sound"));
if (sound == null) {
return null;
}
return new EntityGoalUseItem(
Items.lookup(config.getString("item")).getItem(),
Sound.valueOf(config.getString("sound").toUpperCase()),
sound,
filter::matches
);
}

View File

@@ -11,19 +11,22 @@ import org.bukkit.entity.Raider;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* Allows an entity to attack the closest target within a given subset of specific target types.
*
* @param target The type of entities to attack.
* @param targets The type of entities to attack.
* @param checkVisibility If visibility should be checked.
* @param checkCanNavigate If navigation should be checked.
* @param reciprocalChance 1 in reciprocalChance chance of not activating on any tick.
* @param targetFilter The filter for targets to match.
*/
public record TargetGoalNearestAttackable(
@NotNull TestableEntity target,
@NotNull Set<TestableEntity> targets,
boolean checkVisibility,
boolean checkCanNavigate,
int reciprocalChance,
@@ -32,16 +35,16 @@ public record TargetGoalNearestAttackable(
/**
* Create a new target goal.
*
* @param target The type of entities to attack.
* @param targets The type of entities to attack.
* @param checkVisibility If visibility should be checked.
* @param checkCanNavigate If navigation should be checked.
* @param reciprocalChance 1 in reciprocalChance chance of not activating on any tick.
*/
public TargetGoalNearestAttackable(@NotNull final TestableEntity target,
public TargetGoalNearestAttackable(@NotNull final Set<TestableEntity> targets,
final boolean checkVisibility,
final boolean checkCanNavigate,
final int reciprocalChance) {
this(target, checkVisibility, checkCanNavigate, reciprocalChance, it -> true);
this(targets, checkVisibility, checkCanNavigate, reciprocalChance, it -> true);
}
/**
@@ -65,11 +68,15 @@ public record TargetGoalNearestAttackable(
return null;
}
Set<TestableEntity> targets = config.getStrings("target").stream()
.map(Entities::lookup)
.collect(Collectors.toSet());
if (config.has("targetFilter")) {
TestableEntity filter = Entities.lookup(config.getString("targetFilter"));
return new TargetGoalNearestAttackable(
Entities.lookup(config.getString("target")),
targets,
config.getBool("checkVisibility"),
config.getBool("checkCanNavigate"),
config.getInt("reciprocalChance"),
@@ -77,7 +84,7 @@ public record TargetGoalNearestAttackable(
);
} else {
return new TargetGoalNearestAttackable(
Entities.lookup(config.getString("target")),
targets,
config.getBool("checkVisibility"),
config.getBool("checkCanNavigate"),
config.getInt("reciprocalChance")

View File

@@ -6,6 +6,7 @@ import com.willfp.eco.core.Eco;
import com.willfp.eco.core.fast.FastItemStack;
import com.willfp.eco.core.items.args.LookupArgParser;
import com.willfp.eco.core.items.provider.ItemProvider;
import com.willfp.eco.core.items.tag.ItemTag;
import com.willfp.eco.core.recipe.parts.EmptyTestableItem;
import com.willfp.eco.core.recipe.parts.MaterialTestableItem;
import com.willfp.eco.core.recipe.parts.ModifiedTestableItem;
@@ -13,7 +14,6 @@ import com.willfp.eco.core.recipe.parts.TestableStack;
import com.willfp.eco.core.recipe.parts.UnrestrictedMaterialTestableItem;
import com.willfp.eco.util.NamespacedKeyUtils;
import com.willfp.eco.util.NumberUtils;
import kotlin.Suppress;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.enchantments.Enchantment;
@@ -93,6 +93,11 @@ public final class Items {
*/
private static final Map<String, Material> FRIENDLY_MATERIAL_NAMES = new HashMap<>();
/**
* All tags.
*/
private static final Map<String, ItemTag> TAGS = new HashMap<>();
/**
* Register a new custom item.
*
@@ -217,7 +222,20 @@ public final class Items {
String[] split = args[0].toLowerCase().split(":");
if (split.length == 1) {
String base = split[0];
boolean isTag = base.startsWith("#");
if (isTag) {
String tag = base.substring(1);
ItemTag itemTag = TAGS.get(tag);
if (itemTag == null) {
return new EmptyTestableItem();
}
item = itemTag.toTestableItem();
}
if (split.length == 1 && !isTag) {
String itemType = args[0];
boolean isWildcard = itemType.startsWith("*");
if (isWildcard) {
@@ -230,7 +248,7 @@ public final class Items {
item = isWildcard ? new UnrestrictedMaterialTestableItem(material) : new MaterialTestableItem(material);
}
if (split.length == 2) {
if (split.length == 2 && !isTag) {
String namespace = split[0];
String keyID = split[1];
NamespacedKey namespacedKey = NamespacedKeyUtils.create(namespace, keyID);
@@ -274,7 +292,7 @@ public final class Items {
Legacy namespace:id:amount format
This has been superseded by namespace:id amount
*/
if (split.length == 3) {
if (split.length == 3 && !isTag) {
TestableItem part = REGISTRY.get(NamespacedKeyUtils.create(split[0], split[1]));
if (part == null) {
return new EmptyTestableItem();
@@ -306,7 +324,8 @@ public final class Items {
List<Predicate<ItemStack>> predicates = new ArrayList<>();
for (LookupArgParser argParser : ARG_PARSERS) {
for (
LookupArgParser argParser : ARG_PARSERS) {
Predicate<ItemStack> predicate = argParser.parseArguments(modifierArgs, meta);
if (predicate != null) {
predicates.add(argParser.parseArguments(modifierArgs, meta));
@@ -611,6 +630,24 @@ public final class Items {
return false;
}
/**
* Register a new item tag.
*
* @param tag The tag.
*/
public static void registerTag(@NotNull final ItemTag tag) {
TAGS.put(tag.getIdentifier(), tag);
}
/**
* Get all tags.
*
* @return All tags.
*/
public static Collection<ItemTag> getTags() {
return TAGS.values();
}
private Items() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}

View File

@@ -0,0 +1,29 @@
package com.willfp.eco.core.items.tag;
import org.bukkit.NamespacedKey;
import org.jetbrains.annotations.NotNull;
/**
* A custom item tag.
*/
public abstract class CustomItemTag implements ItemTag {
/**
* The key.
*/
private final NamespacedKey key;
/**
* Create a new custom item tag.
*
* @param key The key.
*/
public CustomItemTag(@NotNull final NamespacedKey key) {
this.key = key;
}
@Override
@NotNull
public String getIdentifier() {
return key.toString();
}
}

View File

@@ -0,0 +1,66 @@
package com.willfp.eco.core.items.tag;
import com.willfp.eco.core.items.TestableItem;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* A group of items that share a common trait.
*/
public interface ItemTag {
/**
* Get the identifier of the tag.
*
* @return The identifier.
*/
@NotNull
String getIdentifier();
/**
* Check if an item matches the tag.
*
* @param itemStack The item to check.
* @return If the item matches the tag.
*/
boolean matches(@NotNull ItemStack itemStack);
/**
* Get an example item.
*
* @return The example item.
*/
@Nullable
default ItemStack getExampleItem() {
return null;
}
/**
* Convert this tag to a testable item.
*
* @return The testable item.
*/
@NotNull
default TestableItem toTestableItem() {
return new TestableItem() {
@Override
public boolean matches(@Nullable final ItemStack itemStack) {
return itemStack != null && ItemTag.this.matches(itemStack);
}
@Override
public @NotNull ItemStack getItem() {
ItemStack example = ItemTag.this.getExampleItem();
return example == null ? new ItemStack(Material.STONE) : example;
}
@Override
public String toString() {
return "ItemTagTestableItem{" +
"tag=" + ItemTag.this.getIdentifier() +
'}';
}
};
}
}

View File

@@ -0,0 +1,58 @@
package com.willfp.eco.core.items.tag;
import org.bukkit.Material;
import org.bukkit.Tag;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
/**
* A vanilla item tag.
*/
public final class VanillaItemTag implements ItemTag {
/**
* The identifier.
*/
private final String identifier;
/**
* The tag.
*/
private final Tag<Material> tag;
/**
* Create a new vanilla item tag.
*
* @param identifier The identifier.
* @param tag The tag.
*/
public VanillaItemTag(@NotNull final String identifier,
@NotNull final Tag<Material> tag) {
this.identifier = identifier;
this.tag = tag;
}
/**
* Get the tag.
*
* @return The tag.
*/
public Tag<Material> getTag() {
return tag;
}
@Override
@NotNull
public String getIdentifier() {
return identifier;
}
@Override
public boolean matches(@NotNull final ItemStack itemStack) {
return tag.isTagged(itemStack.getType());
}
@Override
public @NotNull ItemStack getExampleItem() {
return new ItemStack(tag.getValues().stream().findFirst().orElse(Material.STONE));
}
}

View File

@@ -2,6 +2,7 @@ package com.willfp.eco.core.proxy;
import com.willfp.eco.core.version.Version;
import org.bukkit.Bukkit;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.List;
@@ -28,13 +29,23 @@ public final class ProxyConstants {
"v1_20_R1",
"v1_20_R2",
"v1_20_R3",
"v1_20_6"
"v1_21",
"v1_21_3",
"v1_21_4"
);
private ProxyConstants() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}
private static String convertVersion(@NotNull final String version) {
return switch (version) {
case "v1_21_1" -> "v1_21";
case "v1_21_2" -> "v1_21_3";
default -> version;
};
}
static {
String currentMinecraftVersion = Bukkit.getServer().getBukkitVersion().split("-")[0];
String nmsVersion;
@@ -45,6 +56,6 @@ public final class ProxyConstants {
nmsVersion = "v" + currentMinecraftVersion.replace(".", "_");
}
NMS_VERSION = nmsVersion;
NMS_VERSION = convertVersion(nmsVersion);
}
}

View File

@@ -2,6 +2,7 @@ package com.willfp.eco.core.sound;
import com.willfp.eco.core.config.interfaces.Config;
import com.willfp.eco.core.serialization.ConfigDeserializer;
import com.willfp.eco.util.SoundUtils;
import org.bukkit.Location;
import org.bukkit.Sound;
import org.bukkit.World;
@@ -82,8 +83,11 @@ public record PlayableSound(@NotNull Sound sound,
return null;
}
try {
Sound sound = Sound.valueOf(config.getString("sound").toUpperCase());
Sound sound = SoundUtils.getSound(config.getString("sound"));
if (sound == null) {
return null;
}
double pitch = Objects.requireNonNullElse(config.getDoubleOrNull("pitch"), 1.0);
double volume = Objects.requireNonNullElse(config.getDoubleOrNull("volume"), 1.0);
@@ -93,9 +97,6 @@ public record PlayableSound(@NotNull Sound sound,
pitch,
volume
);
} catch (IllegalArgumentException e) {
return null;
}
}
}
}

View File

@@ -158,11 +158,8 @@ public final class DurabilityUtils {
}
if (item.getItemMeta() instanceof Damageable meta) {
meta.setDamage(meta.getDamage() - repair);
meta.setDamage(Math.max(0, meta.getDamage() - repair));
if (meta.getDamage() < 0) {
meta.setDamage(0);
}
item.setItemMeta((ItemMeta) meta);
}
}

View File

@@ -0,0 +1,50 @@
package com.willfp.eco.util;
import com.willfp.eco.core.Prerequisite;
import org.bukkit.NamespacedKey;
import org.bukkit.Registry;
import org.bukkit.Sound;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Field;
/**
* Utilities / API methods for sounds.
*/
public final class SoundUtils {
/**
* Get a sound in a version-compatible way.
*
* @param name The name of the sound, case-insensitive.
* @return The sound, or null if not found.
*/
@Nullable
public static Sound getSound(@NotNull final String name) {
if (!Prerequisite.HAS_1_21_3.isMet()) {
try {
return Sound.valueOf(name.toUpperCase());
} catch (IllegalArgumentException e) {
return null;
}
}
// First try from registry (preferred)
Sound fromRegistry = Registry.SOUNDS.get(NamespacedKey.minecraft(name.toLowerCase()));
if (fromRegistry != null) {
return fromRegistry;
}
// Next try using reflection (for legacy enum names)
try {
Field field = Sound.class.getDeclaredField(name.toUpperCase());
return (Sound) field.get(null);
} catch (ReflectiveOperationException e) {
return null;
}
}
private SoundUtils() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}
}

View File

@@ -3,7 +3,10 @@
package com.willfp.eco.core.entities
import com.willfp.eco.core.entities.ai.EntityController
import com.willfp.eco.core.items.Items
import com.willfp.eco.core.items.TestableItem
import org.bukkit.entity.Mob
import org.bukkit.inventory.ItemStack
/** @see EntityController.getFor */
val <T : Mob> T.controller: EntityController<T>

View File

@@ -0,0 +1,21 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
group = "com.willfp"
version = rootProject.version
dependencies {
compileOnly(project(":eco-core:core-backend"))
compileOnly("io.papermc.paper:paper-api:1.21.1-R0.1-SNAPSHOT")
}
tasks {
compileJava {
options.release.set(21)
}
compileKotlin {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_21)
}
}
}

View File

@@ -0,0 +1,13 @@
package com.willfp.eco.internal.compat.modern.entities
import com.willfp.eco.core.entities.Entities
import com.willfp.eco.internal.compat.modern.entities.parsers.EntityArgParserJumpStrength
import com.willfp.eco.internal.compat.modern.entities.parsers.EntityArgParserScale
import com.willfp.eco.internal.entities.ModernEntityArgParsers
class ModernEntityArgParsersImpl: ModernEntityArgParsers {
override fun registerAll() {
Entities.registerArgParser(EntityArgParserScale)
Entities.registerArgParser(EntityArgParserJumpStrength)
}
}

View File

@@ -1,4 +1,4 @@
package com.willfp.eco.internal.entities
package com.willfp.eco.internal.compat.modern.entities.parsers
import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser
@@ -28,7 +28,7 @@ object EntityArgParserJumpStrength : EntityArgParser {
return@EntityArgParseResult false
}
val inst = it.getAttribute(Attribute.HORSE_JUMP_STRENGTH) ?: return@EntityArgParseResult false
val inst = it.getAttribute(Attribute.GENERIC_JUMP_STRENGTH) ?: return@EntityArgParseResult false
inst.value >= attributeValue
},
{
@@ -36,7 +36,7 @@ object EntityArgParserJumpStrength : EntityArgParser {
return@EntityArgParseResult
}
it.getAttribute(Attribute.HORSE_JUMP_STRENGTH)?.baseValue = attributeValue
it.getAttribute(Attribute.GENERIC_JUMP_STRENGTH)?.baseValue = attributeValue
}
)
}

View File

@@ -0,0 +1,45 @@
package com.willfp.eco.internal.compat.modern.entities.parsers
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
import org.bukkit.entity.Phantom
import org.bukkit.entity.Slime
object EntityArgParserScale : 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("scale", 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_SCALE) ?: return@EntityArgParseResult false
inst.value >= attributeValue
},
{
if (it !is LivingEntity) {
return@EntityArgParseResult
}
it.getAttribute(Attribute.GENERIC_SCALE)?.baseValue = attributeValue
}
)
}
}

View File

@@ -0,0 +1,21 @@
package com.willfp.eco.internal.compat.modern.items
import com.willfp.eco.core.items.Items
import com.willfp.eco.internal.compat.modern.items.parsers.ArgParserFireResistant
import com.willfp.eco.internal.compat.modern.items.parsers.ArgParserGlint
import com.willfp.eco.internal.compat.modern.items.parsers.ArgParserItemName
import com.willfp.eco.internal.compat.modern.items.parsers.ArgParserMaxDamage
import com.willfp.eco.internal.compat.modern.items.parsers.ArgParserMaxStackSize
import com.willfp.eco.internal.compat.modern.items.parsers.ArgParserTrim
import com.willfp.eco.internal.items.ModernItemArgParsers
class ModernItemArgParsersImpl : ModernItemArgParsers {
override fun registerAll() {
Items.registerArgParser(ArgParserTrim)
Items.registerArgParser(ArgParserFireResistant)
Items.registerArgParser(ArgParserGlint)
Items.registerArgParser(ArgParserItemName)
Items.registerArgParser(ArgParserMaxDamage)
Items.registerArgParser(ArgParserMaxStackSize)
}
}

View File

@@ -0,0 +1,14 @@
package com.willfp.eco.internal.compat.modern.items.parsers
import com.willfp.eco.internal.items.templates.FlagArgParser
import org.bukkit.inventory.meta.ItemMeta
object ArgParserFireResistant : FlagArgParser("fire_resistant") {
override fun apply(meta: ItemMeta) {
meta.isFireResistant = true
}
override fun test(meta: ItemMeta): Boolean {
return meta.isFireResistant
}
}

View File

@@ -0,0 +1,14 @@
package com.willfp.eco.internal.compat.modern.items.parsers
import com.willfp.eco.internal.items.templates.FlagArgParser
import org.bukkit.inventory.meta.ItemMeta
object ArgParserGlint : FlagArgParser("glint") {
override fun apply(meta: ItemMeta) {
meta.setEnchantmentGlintOverride(true)
}
override fun test(meta: ItemMeta): Boolean {
return meta.hasEnchantmentGlintOverride()
}
}

View File

@@ -0,0 +1,27 @@
package com.willfp.eco.internal.compat.modern.items.parsers
import com.willfp.eco.internal.items.templates.ValueArgParser
import com.willfp.eco.util.StringUtils
import net.kyori.adventure.text.Component
import net.kyori.adventure.text.minimessage.MiniMessage
import org.bukkit.inventory.meta.ItemMeta
object ArgParserItemName : ValueArgParser<Component>("item_name") {
override fun parse(arg: String): Component {
return StringUtils.formatToComponent(arg)
}
override fun apply(meta: ItemMeta, value: Component) {
meta.itemName(value)
}
override fun test(meta: ItemMeta): String? {
if (!meta.hasItemName()) {
return null
}
val name = MiniMessage.miniMessage().serialize(meta.itemName())
return name
}
}

View File

@@ -0,0 +1,31 @@
package com.willfp.eco.internal.compat.modern.items.parsers
import com.willfp.eco.internal.items.templates.ValueArgParser
import org.bukkit.inventory.meta.Damageable
import org.bukkit.inventory.meta.ItemMeta
object ArgParserMaxDamage : ValueArgParser<Int>("max_damage") {
override fun parse(arg: String): Int? {
return arg.toIntOrNull()
}
override fun apply(meta: ItemMeta, value: Int) {
if (meta !is Damageable) {
return
}
meta.setMaxDamage(value)
}
override fun test(meta: ItemMeta): String? {
if (meta !is Damageable) {
return null
}
if (!meta.hasMaxDamage()) {
return null
}
return meta.maxDamage.toString()
}
}

View File

@@ -0,0 +1,22 @@
package com.willfp.eco.internal.compat.modern.items.parsers
import com.willfp.eco.internal.items.templates.ValueArgParser
import org.bukkit.inventory.meta.ItemMeta
object ArgParserMaxStackSize : ValueArgParser<Int>("max_stack_size") {
override fun parse(arg: String): Int? {
return arg.toIntOrNull()
}
override fun apply(meta: ItemMeta, value: Int) {
meta.setMaxStackSize(value)
}
override fun test(meta: ItemMeta): String? {
if (!meta.hasMaxStackSize()) {
return null
}
return meta.maxStackSize.toString()
}
}

View File

@@ -1,4 +1,4 @@
package com.willfp.eco.internal.items
package com.willfp.eco.internal.compat.modern.items.parsers
import com.willfp.eco.core.items.args.LookupArgParser
import org.bukkit.NamespacedKey
@@ -23,7 +23,11 @@ object ArgParserTrim : LookupArgParser {
if (!argSplit[0].equals("trim", ignoreCase = true)) {
continue
}
@Suppress("DEPRECATION")
material = Registry.TRIM_MATERIAL.get(NamespacedKey.minecraft(argSplit.getOrElse(1) {""}))
@Suppress("DEPRECATION")
pattern = Registry.TRIM_PATTERN.get(NamespacedKey.minecraft(argSplit.getOrElse(2) {""}))
}
@@ -43,6 +47,11 @@ object ArgParserTrim : LookupArgParser {
override fun serializeBack(meta: ItemMeta): String? {
val trim = (meta as? ArmorMeta)?.trim ?: return null
return "trim:${trim.material.key.key.lowercase()}:${trim.pattern.key.key.lowercase()}"
@Suppress("DEPRECATION")
val materialKey = Registry.TRIM_MATERIAL.getKey(trim.material) ?: return null
@Suppress("DEPRECATION")
val patternKey = Registry.TRIM_PATTERN.getKey(trim.pattern) ?: return null
return "trim:${materialKey.key.lowercase()}:${patternKey.key.lowercase()}"
}
}

View File

@@ -0,0 +1,19 @@
@file:Suppress("UnstableApiUsage")
package com.willfp.eco.internal.compat.modern.recipes
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.internal.recipes.AutocrafterPatch
import org.bukkit.event.EventHandler
import org.bukkit.event.block.CrafterCraftEvent
class AutocrafterPatchImpl: AutocrafterPatch {
@EventHandler
fun preventEcoRecipes(event: CrafterCraftEvent) {
if (!EcoPlugin.getPluginNames().contains(event.recipe.key.namespace)) {
return
}
event.isCancelled = true
}
}

View File

@@ -1,3 +1,5 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
group = "com.willfp"
version = rootProject.version
@@ -7,9 +9,21 @@ dependencies {
implementation("org.objenesis:objenesis:3.2")
compileOnly("io.papermc.paper:paper-api:1.20.2-R0.1-SNAPSHOT")
compileOnly("me.clip:placeholderapi:2.11.4")
compileOnly("me.clip:placeholderapi:2.11.6")
compileOnly("net.kyori:adventure-text-minimessage:4.10.0")
compileOnly("net.kyori:adventure-platform-bukkit:4.1.0")
compileOnly("org.yaml:snakeyaml:1.33")
compileOnly("com.moandjiezana.toml:toml4j:0.7.2")
}
tasks {
compileJava {
options.release.set(17)
}
compileKotlin {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_17)
}
}
}

View File

@@ -126,14 +126,19 @@ abstract class HandledCommand(
* @return The tab completion results.
*/
private fun CommandBase.handleTabComplete(sender: CommandSender, args: List<String>): List<String> {
if (!sender.hasPermission(permission)) return emptyList()
if (!sender.hasPermission(permission)) {
return emptyList()
}
if (args.size == 1) {
val completions = subcommands.filter { sender.hasPermission(it.permission) }.map { it.name }
val completions = mutableListOf<String>()
val list = mutableListOf<String>()
StringUtil.copyPartialMatches(
args[0],
subcommands.filter { sender.hasPermission(it.permission) }.map { it.name },
completions
)
StringUtil.copyPartialMatches(args[0], completions, list)
if (completions.isNotEmpty()) {
return completions
}
@@ -156,9 +161,11 @@ abstract class HandledCommand(
}
val completions = tabComplete(sender, args).toMutableList()
if (sender is Player) {
completions.addAll(tabComplete(sender, args))
}
return completions.sorted()
}
}

View File

@@ -0,0 +1,68 @@
package com.willfp.eco.internal.compat
import com.willfp.eco.core.Prerequisite
import com.willfp.eco.core.proxy.exceptions.ProxyError
private const val BASE_PACKAGE = "com.willfp.eco.internal.compat.modern"
private val isModern = Prerequisite.HAS_PAPER.isMet && Prerequisite.HAS_1_21.isMet
internal annotation class ModernCompatibilityProxy(
val location: String
)
private val cache = mutableMapOf<Class<*>, Any>()
object ModernCompatibilityScope {
inline fun <reified T> loadProxy(): T {
return loadCompatibilityProxy(T::class.java)
}
inline fun <reified T> useProxy(block: T.() -> Any?) {
val proxy = loadProxy<T>()
with(proxy) {
block()
}
}
}
fun <R> ifModern(block: ModernCompatibilityScope.() -> R) {
if (!isModern) {
return
}
block(ModernCompatibilityScope)
}
fun <T> loadCompatibilityProxy(clazz: Class<T>): T {
@Suppress("UNCHECKED_CAST")
return cache.getOrPut(clazz) {
loadProxyUncached(clazz)
} as T
}
private fun loadProxyUncached(clazz: Class<*>): Any {
val proxy = clazz.getAnnotation(ModernCompatibilityProxy::class.java)
val location = proxy?.location ?: throw IllegalArgumentException("Class ${clazz.name} is not a proxy")
val className = "$BASE_PACKAGE.$location"
try {
val found = Class.forName(className)
val constructor = found.getConstructor()
val instance = constructor.newInstance()
if (!clazz.isInstance(instance)) {
throw ProxyError(
"Modern compatibility proxy class $className does not implement ${clazz.name}",
ClassCastException()
)
}
return instance
} catch (e: ClassNotFoundException) {
throw ProxyError("Could not find modern compatibility proxy class $className", e)
} catch (e: NoSuchMethodException) {
throw ProxyError("Could not find no-args constructor for modern compatibility proxy class $className", e)
}
}

View File

@@ -0,0 +1,8 @@
package com.willfp.eco.internal.entities
import com.willfp.eco.internal.compat.ModernCompatibilityProxy
@ModernCompatibilityProxy("entities.ModernEntityArgParsersImpl")
interface ModernEntityArgParsers {
fun registerAll()
}

View File

@@ -80,9 +80,11 @@ class EcoEventManager(private val plugin: EcoPlugin) : EventManager {
}
override fun registerPacketListener(listener: PacketListener) {
listeners[listener.priority] += RegisteredPacketListener(
listeners[listener.priority].add(
RegisteredPacketListener(
plugin,
listener
)
)
}
}

View File

@@ -1,5 +1,7 @@
package com.willfp.eco.internal.gui.menu
import com.willfp.eco.core.Eco
import com.willfp.eco.core.Prerequisite
import com.willfp.eco.core.gui.menu.events.CaptiveItemChangeEvent
import com.willfp.eco.core.items.isEcoEmpty
import com.willfp.eco.core.recipe.parts.EmptyTestableItem
@@ -20,9 +22,23 @@ fun Player.forceRenderedInventory(menu: RenderedInventory) {
trackedForceRendered[this.uniqueId] = menu
}
// Workaround because 1.21 has OpenInventory as an interface instead of an abstract class like in previous versions
interface TopInventoryProxy {
fun getTopInventory(player: Player): Inventory
}
private val Player.topInventory: Inventory
get() {
return if (!Prerequisite.HAS_1_21.isMet) {
Eco.get().ecoPlugin.getProxy(TopInventoryProxy::class.java).getTopInventory(this)
} else {
this.openInventory.topInventory
}
}
val Player.renderedInventory: RenderedInventory?
get() = trackedForceRendered[this.uniqueId]
?: this.openInventory.topInventory.asRenderedInventory()
?: this.topInventory.asRenderedInventory()
class RenderedInventory(
val menu: EcoMenu,

View File

@@ -23,7 +23,7 @@ class EcoSlotBuilder(private val provider: SlotProvider) : SlotBuilder {
private var notCaptiveFor: (Player) -> Boolean = { _ -> false}
override fun onClick(type: ClickType, action: SlotHandler): SlotBuilder {
handlers[type] += action
handlers[type].add(action)
return this
}

View File

@@ -7,20 +7,12 @@ import java.util.function.Predicate
object ArgParserCustomModelData : LookupArgParser {
override fun parseArguments(args: Array<out String>, meta: ItemMeta): Predicate<ItemStack>? {
var modelData: Int? = null
val arg = args.firstOrNull {
it.startsWith("custom-model-data:", ignoreCase = true)
|| it.startsWith("custom_model_data:", ignoreCase = true)
} ?: return null
for (arg in args) {
val argSplit = arg.split(":")
if (!argSplit[0].equals("custom-model-data", ignoreCase = true)) {
continue
}
if (argSplit.size < 2) {
continue
}
modelData = argSplit[1].toIntOrNull()
}
modelData ?: return null
val modelData = arg.split(":")[1].toIntOrNull() ?: return null
meta.setCustomModelData(modelData)
@@ -40,6 +32,6 @@ object ArgParserCustomModelData : LookupArgParser {
return null
}
return "custom-model-data:${meta.customModelData}"
return "custom_model_data:${meta.customModelData}"
}
}

View File

@@ -2,7 +2,7 @@ package com.willfp.eco.internal.items
import com.willfp.eco.core.fast.fast
import com.willfp.eco.core.items.args.LookupArgParser
import com.willfp.eco.util.NamespacedKeyUtils
import org.bukkit.NamespacedKey
import org.bukkit.enchantments.Enchantment
import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.EnchantmentStorageMeta
@@ -14,17 +14,15 @@ object ArgParserEnchantment : LookupArgParser {
val enchants = mutableMapOf<Enchantment, Int>()
for (arg in args) {
try {
val argSplit = arg.split(":")
if (argSplit.size < 2) {
continue
}
val enchant = Enchantment.getByKey(NamespacedKey.minecraft(argSplit[0].lowercase())) ?: continue
val level = argSplit.getOrNull(1)?.toIntOrNull() ?: enchant.maxLevel
val enchant = Enchantment.getByKey(NamespacedKeyUtils.create("minecraft", argSplit[0]))
val level = argSplit[1].toIntOrNull()
if (enchant != null && level != null) {
enchants[enchant] = level
} catch (e: IllegalArgumentException) {
continue
}
}

View File

@@ -1,44 +1,30 @@
package com.willfp.eco.internal.items
import com.willfp.eco.core.items.args.LookupArgParser
import com.willfp.eco.internal.items.templates.ValueArgParser
import com.willfp.eco.util.StringUtils
import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.ItemMeta
import java.util.function.Predicate
object ArgParserName : LookupArgParser {
override fun parseArguments(args: Array<out String>, meta: ItemMeta): Predicate<ItemStack>? {
var name: String? = null
for (arg in args) {
if (!arg.lowercase().startsWith("name:")) {
continue
}
name = arg.substring(5, arg.length)
object ArgParserName : ValueArgParser<String>("name") {
override fun parse(arg: String): String {
return arg
}
name ?: return null
val formatted = StringUtils.format(name)
override fun apply(meta: ItemMeta, value: String) {
val formatted = StringUtils.format(value)
// I don't know why it says it's redundant, the compiler yells at me
@Suppress("UsePropertyAccessSyntax", "RedundantSuppression", "DEPRECATION")
meta.setDisplayName(formatted)
return Predicate {
val testMeta = it.itemMeta ?: return@Predicate false
@Suppress("DEPRECATION")
testMeta.displayName == formatted
}
}
override fun serializeBack(meta: ItemMeta): String? {
override fun test(meta: ItemMeta): String? {
if (!meta.hasDisplayName()) {
return null
}
@Suppress("DEPRECATION")
return "name:\"${meta.displayName}\""
return meta.displayName
}
}

View File

@@ -1,38 +1,14 @@
package com.willfp.eco.internal.items
import com.willfp.eco.core.items.args.LookupArgParser
import org.bukkit.inventory.ItemStack
import com.willfp.eco.internal.items.templates.FlagArgParser
import org.bukkit.inventory.meta.ItemMeta
import java.util.function.Predicate
object ArgParserUnbreakable : LookupArgParser {
override fun parseArguments(args: Array<out String>, meta: ItemMeta): Predicate<ItemStack>? {
var unbreakable = false
for (arg in args) {
if (arg.equals("unbreakable", true)) {
unbreakable = true
}
}
if (!unbreakable) {
return null
}
object ArgParserUnbreakable : FlagArgParser("unbreakable") {
override fun apply(meta: ItemMeta) {
meta.isUnbreakable = true
return Predicate {
val testMeta = it.itemMeta ?: return@Predicate false
testMeta.isUnbreakable
}
}
override fun serializeBack(meta: ItemMeta): String? {
if (!meta.isUnbreakable) {
return null
}
return "unbreakable"
override fun test(meta: ItemMeta): Boolean {
return meta.isUnbreakable
}
}

View File

@@ -0,0 +1,8 @@
package com.willfp.eco.internal.items
import com.willfp.eco.internal.compat.ModernCompatibilityProxy
@ModernCompatibilityProxy("items.ModernItemArgParsersImpl")
interface ModernItemArgParsers {
fun registerAll()
}

View File

@@ -0,0 +1,39 @@
package com.willfp.eco.internal.items.tags
import com.willfp.eco.core.items.Items
import com.willfp.eco.core.items.tag.VanillaItemTag
import org.bukkit.Keyed
import org.bukkit.Material
import org.bukkit.Tag
object VanillaItemTags {
fun register() {
// Get all tags
val allTags = Tag::class.java.declaredFields
.filter { it.type == Tag::class.java }
.mapNotNull {
val tag = it.get(null) as? Tag<*>
if (tag == null) {
null
} else {
NamedTag(it.name.lowercase(), tag)
}
}
// Register all tags
for (tag in allTags) {
if (tag.isMaterial) {
Items.registerTag(
@Suppress("UNCHECKED_CAST")
VanillaItemTag(tag.name, tag.tag as Tag<Material>)
)
}
}
}
private data class NamedTag<T : Keyed>(val name: String, val tag: Tag<T>) {
// Check if tag is material
val isMaterial: Boolean
get() = tag.values.firstOrNull() is Material
}
}

View File

@@ -0,0 +1,44 @@
package com.willfp.eco.internal.items.templates
import com.willfp.eco.core.items.args.LookupArgParser
import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.ItemMeta
import java.util.function.Predicate
abstract class FlagArgParser(
protected val flag: String
) : LookupArgParser {
abstract fun apply(meta: ItemMeta)
abstract fun test(meta: ItemMeta): Boolean
override fun parseArguments(args: Array<out String>, meta: ItemMeta): Predicate<ItemStack>? {
var has = false
for (arg in args) {
if (arg.equals(flag, true)) {
has = true
}
}
if (!has) {
return null
}
apply(meta)
return Predicate {
val testMeta = it.itemMeta ?: return@Predicate false
test(testMeta)
}
}
override fun serializeBack(meta: ItemMeta): String? {
if (!test(meta)) {
return null
}
return flag
}
}

View File

@@ -0,0 +1,50 @@
package com.willfp.eco.internal.items.templates
import com.willfp.eco.core.items.args.LookupArgParser
import com.willfp.eco.util.StringUtils
import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.ItemMeta
import java.util.function.Predicate
abstract class ValueArgParser<T: Any>(
protected val flag: String
) : LookupArgParser {
abstract fun parse(arg: String): T?
abstract fun apply(meta: ItemMeta, value: T)
abstract fun test(meta: ItemMeta): String?
override fun parseArguments(args: Array<out String>, meta: ItemMeta): Predicate<ItemStack>? {
var argument: String? = null
for (arg in args) {
if (!arg.lowercase().startsWith("${flag}:")) {
continue
}
argument = arg.substring(flag.length + 1, arg.length)
}
argument ?: return null
val parsed = parse(argument) ?: return null
apply(meta, parsed)
return Predicate {
val testMeta = it.itemMeta ?: return@Predicate false
test(testMeta) == parsed
}
}
override fun serializeBack(meta: ItemMeta): String? {
val test = test(meta)
if (test.isNullOrBlank()) {
return null
}
return "${flag}:\"$test\""
}
}

View File

@@ -1,5 +1,6 @@
package com.willfp.eco.internal.particle
import com.willfp.eco.core.Prerequisite
import com.willfp.eco.core.particle.ParticleFactory
import com.willfp.eco.core.particle.SpawnableParticle
import org.bukkit.Color
@@ -7,6 +8,14 @@ import org.bukkit.Location
import org.bukkit.Particle
object ParticleFactoryRGB : ParticleFactory {
private val dustParticle = runCatching {
if (Prerequisite.HAS_1_20_5.isMet) {
Particle.valueOf("DUST")
} else {
Particle.valueOf("REDSTONE")
}
}.getOrNull()
override fun getNames() = listOf(
"color",
"rgb",
@@ -30,7 +39,9 @@ object ParticleFactoryRGB : ParticleFactory {
override fun spawn(location: Location, amount: Int) {
val world = location.world ?: return
world.spawnParticle(Particle.REDSTONE, location, amount, 0.0, 0.0, 0.0, 0.0, options)
val particle = dustParticle ?: return
world.spawnParticle(particle, location, amount, 0.0, 0.0, 0.0, 0.0, options)
}
}
}

View File

@@ -8,6 +8,11 @@ import org.bukkit.entity.Player
import java.util.UUID
import kotlin.math.roundToInt
private fun getXPNeededForLevel(level: Int): Int {
// XP Formula from NMS Player
return if (level >= 30) 112 + (level - 30) * 9 else (if (level >= 15) 37 + (level - 15) * 5 else 7 + level * 2)
}
object PriceFactoryXP : PriceFactory {
override fun getNames() = listOf(
"xp",
@@ -25,15 +30,37 @@ object PriceFactoryXP : PriceFactory {
) : Price {
private val multipliers = mutableMapOf<UUID, Double>()
override fun canAfford(player: Player, multiplier: Double): Boolean =
player.totalExperience >= getValue(player, multiplier)
override fun canAfford(player: Player, multiplier: Double): Boolean {
var totalExperience = 0
for (level in 0 until player.level) {
totalExperience += getXPNeededForLevel(level)
}
totalExperience += (player.exp * getXPNeededForLevel(player.level)).toInt()
return totalExperience >= getValue(player, multiplier).roundToInt()
}
override fun pay(player: Player, multiplier: Double) {
player.totalExperience -= getValue(player, multiplier).roundToInt()
takeXP(player, getValue(player, multiplier).roundToInt())
}
private fun takeXP(player: Player, amount: Int) {
val currentLevel = player.level
val currentExp = player.exp * getXPNeededForLevel(currentLevel)
if (currentExp >= amount) {
player.exp = (currentExp - amount) / getXPNeededForLevel(currentLevel)
} else {
// Handle recursive level down
player.exp = 1f
player.level = (currentLevel - 1).coerceAtLeast(0)
takeXP(player, (amount - currentExp).toInt())
}
}
override fun giveTo(player: Player, multiplier: Double) {
player.totalExperience += getValue(player, multiplier).roundToInt()
player.giveExp(getValue(player, multiplier).roundToInt())
}
override fun getValue(player: Player, multiplier: Double): Double {

View File

@@ -50,8 +50,7 @@ class EcoProxyFactory(
)
} else {
ProxyError(
"Could not initialize proxy. If you're seeing this error message"
+ ", something has gone badly wrong. This almost definitely isn't user error, blame the developer.",
"Could not initialize proxy. Are you running a supported server version?",
e
)
}

View File

@@ -0,0 +1,7 @@
package com.willfp.eco.internal.recipes
import com.willfp.eco.internal.compat.ModernCompatibilityProxy
import org.bukkit.event.Listener
@ModernCompatibilityProxy("recipes.AutocrafterPatchImpl")
interface AutocrafterPatch: Listener

View File

@@ -1,5 +1,5 @@
plugins {
id("io.papermc.paperweight.userdev") version "1.7.1" apply false
id("io.papermc.paperweight.userdev") version "2.0.0-beta.14" apply false
}

View File

@@ -7,4 +7,11 @@ version = rootProject.version
dependencies {
paperweight.paperDevBundle("1.17.1-R0.1-SNAPSHOT")
pluginRemapper("net.fabricmc:tiny-remapper:0.10.3:fat")
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}

View File

@@ -48,7 +48,7 @@ var SkullMeta.texture: String?
* at java.lang.String.checkBoundsBeginEnd(String.java:4604) ~[?:?]
* at java.lang.String.substring(String.java:2707) ~[?:?]
* at java.lang.String.substring(String.java:2680) ~[?:?]
* at com.willfp.eco.internal.spigot.proxy.v1_19_R1.common.SkullKt.setTexture(Skull.kt:36)
* at com.willfp.eco.internal.spigot.proxy.v1_19_R1.common.SkullKt.setTexture(ModernSkull.kt:36)
*
if (base64.length < 20) {
return

View File

@@ -54,8 +54,6 @@ class EcoEntityController<T : Mob>(
priority, goal.getGoalFactory()?.create(goal, nms) ?: return this
)
nms.targetSelector
return this
}

View File

@@ -10,7 +10,7 @@ import net.minecraft.world.entity.monster.RangedAttackMob
object RangedBowAttackGoalFactory : EntityGoalFactory<EntityGoalRangedBowAttack> {
override fun create(apiGoal: EntityGoalRangedBowAttack, entity: PathfinderMob): Goal? {
(if (entity !is Monster) return null)
if (entity !is Monster) return null
if (entity !is RangedAttackMob) return null
return RangedBowAttackGoal(

View File

@@ -11,7 +11,7 @@ import net.minecraft.world.entity.monster.RangedAttackMob
object RangedCrossbowAttackGoalFactory : EntityGoalFactory<EntityGoalRangedCrossbowAttack> {
override fun create(apiGoal: EntityGoalRangedCrossbowAttack, entity: PathfinderMob): Goal? {
(if (entity !is Monster) return null)
if (entity !is Monster) return null
if (entity !is RangedAttackMob) return null
if (entity !is CrossbowAttackMob) return null

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