Compare commits

..

47 Commits

Author SHA1 Message Date
Auxilor
dd14fc666a Updated to 6.38.2 2022-07-27 19:42:19 +01:00
Auxilor
ae0150f012 Bumped ShopGUI+ 2022-07-27 19:42:06 +01:00
Auxilor
04418fa038 Updated ProtocolLib for compatibility 2022-07-27 19:40:08 +01:00
Auxilor
bcb9523315 Updated to 6.38.1 2022-07-25 16:51:55 +01:00
Auxilor
43e7972ca3 Improved menu re-renders 2022-07-25 16:51:38 +01:00
Auxilor
7ea61eb393 Removed source/target compatibility no longer required by kotlin 1.7.x 2022-07-22 14:08:33 +01:00
Auxilor
5245a9b1d8 Updated to 6.38.0 2022-07-22 14:05:53 +01:00
Auxilor
195932463c Added DisplayProperties to DisplayModule 2022-07-22 14:04:42 +01:00
Auxilor
3cf60a7e2c Added MenuUtils#getOpenMenu 2022-07-22 13:54:45 +01:00
Auxilor
0f9f57fca2 Merge remote-tracking branch 'origin/master' 2022-07-22 13:47:03 +01:00
Will FP
fe21616dd5 Merge pull request #161 from Syrent/master
Add MythicMobs 5.X support.
2022-07-22 13:46:53 +01:00
Auxilor
396144abaa Added Vector#isSafeVelocity 2022-07-22 13:46:08 +01:00
Auxilor
50b4fa59ab Added onOpen to menu 2022-07-22 13:42:48 +01:00
Auxilor
a6754379e8 Updated to 6.37.3 2022-07-07 22:55:03 +01:00
Auxilor
bbd0182c2a Fixed weird bug 2022-07-07 22:54:54 +01:00
Auxilor
0370e9f454 Fixed startup order 2022-07-03 16:49:26 +01:00
Auxilor
8d585b58cb Fixed initializing text 2022-07-03 16:45:44 +01:00
Auxilor
0bfbd4c036 Updated to 6.37.2 2022-07-03 16:38:32 +01:00
Auxilor
881839955e Added player health fixer 2022-07-03 16:38:21 +01:00
Syrent
8ffc5f9c0f Add MythicMobs 5.X support. 2022-06-28 08:07:05 +04:30
Auxilor
709de3bb5f Updated to 6.37.1 2022-06-14 12:43:11 +01:00
Auxilor
f2aa2ffd9b Removed ExactTestableItem 2022-06-14 12:43:04 +01:00
Auxilor
5ce70399f0 Improved SNBT lookups 2022-06-14 12:42:49 +01:00
Auxilor
3f8759b08a Updated to 6.37.0 2022-06-14 12:14:33 +01:00
Auxilor
abecaa6e9f Added SNBT parsing 2022-06-14 12:13:48 +01:00
Auxilor
4744bfc78b Updated to 6.36.5 2022-06-09 19:24:49 +01:00
Auxilor
487e68221a Added 1.19 support 2022-06-09 19:24:37 +01:00
Auxilor
1c68992a8e Updated to 6.36.4 2022-05-29 17:46:52 +01:00
Auxilor
c5b7d0b644 Fixed conflict finder breaking the polymart autoupdater 2022-05-29 17:46:24 +01:00
Auxilor
0f91aec3b7 Slots can now be not captive for some players 2022-05-29 11:34:32 +01:00
Auxilor
d2bf38c5c9 Updated to 6.36.3 2022-05-29 11:11:33 +01:00
Auxilor
2c96b79aba Improved slots 2022-05-29 11:11:16 +01:00
Auxilor
d539b9e59e Improvements to captive items 2022-05-28 17:33:06 +01:00
Auxilor
b0b06ef402 Updated to 6.36.2 2022-05-28 17:20:35 +01:00
Auxilor
7a84c3de3b Captive from empty, take 2 2022-05-28 17:20:23 +01:00
Auxilor
9431321e1c Revert "Added captive defaults"
This reverts commit 7adcdd572d.
2022-05-28 17:08:36 +01:00
Auxilor
4816284fba Revert "Added captive default kotlin extension"
This reverts commit 2bcbf181a9.
2022-05-28 17:08:01 +01:00
Auxilor
a9874c9386 Revert "Updated to 6.37.0"
This reverts commit fc3c80f633.
2022-05-28 17:08:01 +01:00
Auxilor
fe68760184 Revert "Fixed backwards compatibility"
This reverts commit 1f7cf78491.
2022-05-28 17:08:01 +01:00
Auxilor
5ae8e72a98 Revert "Fixed captive default"
This reverts commit 15fc6053c8.
2022-05-28 17:08:01 +01:00
Auxilor
15fc6053c8 Fixed captive default 2022-05-28 16:54:58 +01:00
Auxilor
1f7cf78491 Fixed backwards compatibility 2022-05-28 16:43:35 +01:00
Auxilor
fc3c80f633 Updated to 6.37.0 2022-05-28 16:41:30 +01:00
Auxilor
2bcbf181a9 Added captive default kotlin extension 2022-05-28 16:41:20 +01:00
Auxilor
7adcdd572d Added captive defaults 2022-05-28 16:40:14 +01:00
Auxilor
f6eba21006 Updated to 6.36.1 2022-05-28 16:10:40 +01:00
Auxilor
cc02f26807 Fixed key registry 2022-05-28 16:10:30 +01:00
56 changed files with 1290 additions and 75 deletions

View File

@@ -4,7 +4,7 @@ buildscript {
} }
dependencies { dependencies {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10")
} }
} }
@@ -13,7 +13,7 @@ plugins {
id("com.github.johnrengelman.shadow") version "7.1.2" id("com.github.johnrengelman.shadow") version "7.1.2"
id("maven-publish") id("maven-publish")
id("java") id("java")
kotlin("jvm") version "1.6.21" kotlin("jvm") version "1.7.10"
} }
dependencies { dependencies {
@@ -24,6 +24,7 @@ dependencies {
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(path = ":eco-core:core-nms:v1_18_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")) implementation(project(path = ":eco-core:core-nms:v1_18_R2", configuration = "reobf"))
implementation(project(path = ":eco-core:core-nms:v1_19_R1", configuration = "reobf"))
} }
allprojects { allprojects {
@@ -80,8 +81,8 @@ allprojects {
dependencies { dependencies {
// Kotlin // Kotlin
implementation(kotlin("stdlib", version = "1.6.21")) implementation(kotlin("stdlib", version = "1.7.10"))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.1") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.2")
// Included in spigot jar, no need to move to implementation // Included in spigot jar, no need to move to implementation
compileOnly("org.jetbrains:annotations:23.0.0") compileOnly("org.jetbrains:annotations:23.0.0")
@@ -128,8 +129,6 @@ allprojects {
kotlinOptions { kotlinOptions {
jvmTarget = "17" jvmTarget = "17"
} }
targetCompatibility = "17"
sourceCompatibility = "17"
} }
shadowJar { shadowJar {

View File

@@ -304,6 +304,11 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
this.color = props.getColor(); this.color = props.getColor();
this.supportingExtensions = props.isSupportingExtensions(); this.supportingExtensions = props.isSupportingExtensions();
this.proxyFactory = this.proxyPackage.equalsIgnoreCase("") ? null : Eco.getHandler().createProxyFactory(this);
this.logger = Eco.getHandler().createLogger(this);
this.getLogger().info("Initializing " + this.getColor() + this.getName());
this.scheduler = Eco.getHandler().createScheduler(this); this.scheduler = Eco.getHandler().createScheduler(this);
this.eventManager = Eco.getHandler().createEventManager(this); this.eventManager = Eco.getHandler().createEventManager(this);
this.namespacedKeyFactory = Eco.getHandler().createNamespacedKeyFactory(this); this.namespacedKeyFactory = Eco.getHandler().createNamespacedKeyFactory(this);
@@ -311,16 +316,12 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
this.runnableFactory = Eco.getHandler().createRunnableFactory(this); this.runnableFactory = Eco.getHandler().createRunnableFactory(this);
this.extensionLoader = Eco.getHandler().createExtensionLoader(this); this.extensionLoader = Eco.getHandler().createExtensionLoader(this);
this.configHandler = Eco.getHandler().createConfigHandler(this); this.configHandler = Eco.getHandler().createConfigHandler(this);
this.logger = Eco.getHandler().createLogger(this);
this.proxyFactory = this.proxyPackage.equalsIgnoreCase("") ? null : Eco.getHandler().createProxyFactory(this);
this.langYml = this.createLangYml(); this.langYml = this.createLangYml();
this.configYml = this.createConfigYml(); this.configYml = this.createConfigYml();
Eco.getHandler().addNewPlugin(this); Eco.getHandler().addNewPlugin(this);
this.getLogger().info("Initializing " + this.getColor() + this.getName());
/* /*
The minimum eco version check was moved here because it's very common The minimum eco version check was moved here because it's very common
to add a lot of code in the constructor of plugins; meaning that the plugin to add a lot of code in the constructor of plugins; meaning that the plugin

View File

@@ -15,6 +15,7 @@ import com.willfp.eco.core.factory.RunnableFactory;
import com.willfp.eco.core.fast.FastItemStack; import com.willfp.eco.core.fast.FastItemStack;
import com.willfp.eco.core.gui.GUIFactory; import com.willfp.eco.core.gui.GUIFactory;
import com.willfp.eco.core.integrations.placeholder.PlaceholderIntegration; import com.willfp.eco.core.integrations.placeholder.PlaceholderIntegration;
import com.willfp.eco.core.items.SNBTHandler;
import com.willfp.eco.core.proxy.Cleaner; import com.willfp.eco.core.proxy.Cleaner;
import com.willfp.eco.core.proxy.ProxyFactory; import com.willfp.eco.core.proxy.ProxyFactory;
import com.willfp.eco.core.scheduling.Scheduler; import com.willfp.eco.core.scheduling.Scheduler;
@@ -282,8 +283,7 @@ public interface Handler {
* @param <T> The mob type. * @param <T> The mob type.
* @return The controlled entity. * @return The controlled entity.
*/ */
@NotNull @NotNull <T extends Mob> EntityController<T> createEntityController(@NotNull T mob);
<T extends Mob> EntityController<T> createEntityController(@NotNull T mob);
/** /**
* Adapt base PDC to extended PDC. * Adapt base PDC to extended PDC.
@@ -301,4 +301,12 @@ public interface Handler {
*/ */
@NotNull @NotNull
PersistentDataContainer newPdc(); PersistentDataContainer newPdc();
/**
* Get SNBT handler.
*
* @return The SNBT handler.
*/
@NotNull
SNBTHandler getSNBTHandler();
} }

View File

@@ -41,11 +41,19 @@ public class Prerequisite {
"Requires server to have vault" "Requires server to have vault"
); );
/**
* Requires the server to be running 1.19.
*/
public static final Prerequisite HAS_1_19 = new Prerequisite(
() -> ProxyConstants.NMS_VERSION.contains("19"),
"Requires server to be running 1.19+"
);
/** /**
* Requires the server to be running 1.18. * Requires the server to be running 1.18.
*/ */
public static final Prerequisite HAS_1_18 = new Prerequisite( public static final Prerequisite HAS_1_18 = new Prerequisite(
() -> ProxyConstants.NMS_VERSION.contains("18"), () -> ProxyConstants.NMS_VERSION.contains("18") || HAS_1_19.isMet(),
"Requires server to be running 1.18+" "Requires server to be running 1.18+"
); );

View File

@@ -64,6 +64,21 @@ public abstract class DisplayModule extends PluginDependent<EcoPlugin> {
// Technically optional. // Technically optional.
} }
/**
* Display an item.
*
* @param itemStack The item.
* @param player The player.
* @param properties The properties.
* @param args Optional args for display.
*/
public void display(@NotNull final ItemStack itemStack,
@Nullable final Player player,
@NotNull final DisplayProperties properties,
@NotNull final Object... args) {
// Technically optional.
}
/** /**
* Revert an item. * Revert an item.
* *

View File

@@ -0,0 +1,18 @@
package com.willfp.eco.core.display;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
/**
* Extra properties passed into {@link DisplayModule}.
*
* @param inInventory If the item was in an inventory.
* @param inGui If the item is assumed to be in a gui. (Not perfectly accurate).
* @param originalItem The original item, not to be modified.
*/
public record DisplayProperties(
boolean inInventory,
boolean inGui,
@NotNull ItemStack originalItem
) {
}

View File

@@ -68,6 +68,14 @@ public interface MenuBuilder {
*/ */
MenuBuilder onClose(@NotNull CloseHandler action); MenuBuilder onClose(@NotNull CloseHandler action);
/**
* Set the menu open handler.
*
* @param action The handler.
* @return The builder.
*/
MenuBuilder onOpen(@NotNull OpenHandler action);
/** /**
* Set the action to run on render. * Set the action to run on render.
* *

View File

@@ -0,0 +1,19 @@
package com.willfp.eco.core.gui.menu;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
/**
* Interface to run on menu open.
*/
@FunctionalInterface
public interface OpenHandler {
/**
* Performs this operation on the given arguments.
*
* @param player The player.
* @param menu The menu.
*/
void handle(@NotNull Player player,
@NotNull Menu menu);
}

View File

@@ -28,6 +28,26 @@ public interface Slot {
*/ */
boolean isCaptive(); boolean isCaptive();
/**
* If the slot is not captive for a player.
*
* @param player The player.
* @return If not captive for the player.
*/
default boolean isNotCaptiveFor(@NotNull Player player) {
return false;
}
/**
* If the slot is captive from empty.
* If true, a captive item will be returned even if the item is the same as the rendered item.
*
* @return If captive from empty.
*/
default boolean isCaptiveFromEmpty() {
return false;
}
/** /**
* Create a builder for an ItemStack. * Create a builder for an ItemStack.
* *

View File

@@ -3,10 +3,12 @@ package com.willfp.eco.core.gui.slot;
import com.willfp.eco.core.gui.slot.functional.SlotHandler; import com.willfp.eco.core.gui.slot.functional.SlotHandler;
import com.willfp.eco.core.gui.slot.functional.SlotModifier; import com.willfp.eco.core.gui.slot.functional.SlotModifier;
import com.willfp.eco.core.gui.slot.functional.SlotUpdater; import com.willfp.eco.core.gui.slot.functional.SlotUpdater;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryClickEvent;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Predicate;
/** /**
* Builder to create slots. * Builder to create slots.
@@ -102,6 +104,14 @@ public interface SlotBuilder {
*/ */
SlotBuilder onMiddleClick(@NotNull SlotHandler handler); SlotBuilder onMiddleClick(@NotNull SlotHandler handler);
/**
* Prevent captive for players that match a predicate.
*
* @param predicate The predicate. Returns true when the slot should not be captive.
* @return The builder.
*/
SlotBuilder notCaptiveFor(@NotNull Predicate<Player> predicate);
/** /**
* Modify the ItemStack. * Modify the ItemStack.
* *
@@ -130,7 +140,17 @@ public interface SlotBuilder {
* *
* @return The builder. * @return The builder.
*/ */
SlotBuilder setCaptive(); default SlotBuilder setCaptive() {
return setCaptive(false);
}
/**
* Set slot to be a captive slot.
*
* @param fromEmpty If an item with the same output as the rendered item counts as captive.
* @return The builder.
*/
SlotBuilder setCaptive(boolean fromEmpty);
/** /**
* Build the slot. * Build the slot.

View File

@@ -2,6 +2,7 @@ package com.willfp.eco.core.items;
import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache; import com.github.benmanes.caffeine.cache.LoadingCache;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.fast.FastItemStack; import com.willfp.eco.core.fast.FastItemStack;
import com.willfp.eco.core.items.args.LookupArgParser; import com.willfp.eco.core.items.args.LookupArgParser;
import com.willfp.eco.core.items.provider.ItemProvider; import com.willfp.eco.core.items.provider.ItemProvider;
@@ -185,6 +186,10 @@ public final class Items {
*/ */
@NotNull @NotNull
public static TestableItem lookup(@NotNull final String key) { public static TestableItem lookup(@NotNull final String key) {
if (key.startsWith("{")) {
return Eco.getHandler().getSNBTHandler().createTestable(key);
}
return ITEMS_LOOKUP_HANDLER.parseKey(key); return ITEMS_LOOKUP_HANDLER.parseKey(key);
} }
@@ -520,6 +525,28 @@ public final class Items {
return fis.unwrap(); return fis.unwrap();
} }
/**
* Convert item to SNBT.
*
* @param itemStack The item.
* @return The NBT string.
*/
@NotNull
public static String toSNBT(@NotNull final ItemStack itemStack) {
return Eco.getHandler().getSNBTHandler().toSNBT(itemStack);
}
/**
* Get item from SNBT.
*
* @param snbt The NBT string.
* @return The ItemStack, or null if invalid.
*/
@Nullable
public static ItemStack fromSNBT(@NotNull final String snbt) {
return Eco.getHandler().getSNBTHandler().fromSNBT(snbt);
}
private Items() { private Items() {
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

@@ -0,0 +1,41 @@
package com.willfp.eco.core.items;
import com.willfp.eco.core.Eco;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* API to handle SNBT conversion.
*/
@ApiStatus.Internal
@Eco.HandlerComponent
public interface SNBTHandler {
/**
* Get item from SNBT.
*
* @param snbt The NBT string.
* @return The ItemStack, or null if invalid.
*/
@Nullable
ItemStack fromSNBT(@NotNull String snbt);
/**
* Convert item to SNBT.
*
* @param itemStack The item.
* @return The NBT string.
*/
@NotNull
String toSNBT(@NotNull ItemStack itemStack);
/**
* Make TestableItem from SNBT.
*
* @param snbt The NBT string.
* @return The TestableItem.
*/
@NotNull
TestableItem createTestable(@NotNull String snbt);
}

View File

@@ -20,7 +20,8 @@ public final class ProxyConstants {
public static final List<String> SUPPORTED_VERSIONS = Arrays.asList( public static final List<String> SUPPORTED_VERSIONS = Arrays.asList(
"v1_17_R1", "v1_17_R1",
"v1_18_R1", "v1_18_R1",
"v1_18_R2" "v1_18_R2",
"v1_19_R1"
); );
private ProxyConstants() { private ProxyConstants() {

View File

@@ -1,12 +1,24 @@
package com.willfp.eco.util; package com.willfp.eco.util;
import com.willfp.eco.core.gui.menu.Menu;
import com.willfp.eco.core.tuples.Pair; import com.willfp.eco.core.tuples.Pair;
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.util.function.Function;
/** /**
* Utilities / API methods for menus. * Utilities / API methods for menus.
*/ */
public final class MenuUtils { public final class MenuUtils {
/**
* The menu supplier.
*/
private static Function<Player, Menu> menuGetter = null;
/** /**
* Convert 0-53 slot to row and column pair. * Convert 0-53 slot to row and column pair.
* *
@@ -20,6 +32,40 @@ public final class MenuUtils {
return new Pair<>(row + 1, column + 1); return new Pair<>(row + 1, column + 1);
} }
/**
* Convert row and column to 0-53 slot.
*
* @param row The row.
* @param column The column.
* @return The slot.
*/
public static int rowColumnToSlot(final int row, final int column) {
return (column - 1) + ((row - 1) * 9);
}
/**
* Get a player's open menu.
*
* @param player The player.
* @return The menu, or null if none open.
*/
@Nullable
public static Menu getOpenMenu(@NotNull final Player player) {
return menuGetter.apply(player);
}
/**
* Initialize the tps supplier function.
*
* @param function The function.
*/
@ApiStatus.Internal
public static void initialize(@NotNull final Function<Player, Menu> function) {
Validate.isTrue(menuGetter == null, "Already initialized!");
menuGetter = function;
}
private MenuUtils() { private MenuUtils() {
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

@@ -152,6 +152,20 @@ public final class VectorUtils {
return vectors.toArray(new Vector[0]); return vectors.toArray(new Vector[0]);
} }
/**
* Get if a vector is a safe velocity.
*
* @param vec The vector to check.
* @return If safe.
*/
public static boolean isSafeVelocity(@NotNull final Vector vec) {
double x = Math.abs(vec.getX());
double y = Math.abs(vec.getY());
double z = Math.abs(vec.getZ());
return x < 4 && y < 4 && z < 4;
}
private VectorUtils() { private VectorUtils() {
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

@@ -32,6 +32,10 @@ fun SlotBuilder.onShiftRightClick(action: (InventoryClickEvent, Slot, Menu) -> U
fun SlotBuilder.onMiddleClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder = fun SlotBuilder.onMiddleClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
this.onMiddleClick { a, b, c -> action(a, b, c) } this.onMiddleClick { a, b, c -> action(a, b, c) }
/** @see SlotBuilder.notCaptiveFor */
fun SlotBuilder.notCaptiveFor(test: (Player) -> Boolean): SlotBuilder =
this.notCaptiveFor { test(it) }
/** /**
* @see SlotBuilder.setModifier * @see SlotBuilder.setModifier
* @deprecated Use SlotUpdater instead. * @deprecated Use SlotUpdater instead.
@@ -105,6 +109,10 @@ fun slot(
fun MenuBuilder.onClose(action: (InventoryCloseEvent, Menu) -> Unit): MenuBuilder = fun MenuBuilder.onClose(action: (InventoryCloseEvent, Menu) -> Unit): MenuBuilder =
this.onClose { a, b -> action(a, b) } this.onClose { a, b -> action(a, b) }
/** @see MenuBuilder.onOpen */
fun MenuBuilder.onOpen(action: (Player, Menu) -> Unit): MenuBuilder =
this.onOpen { a, b -> action(a, b) }
/** @see MenuBuilder.modify */ /** @see MenuBuilder.modify */
fun MenuBuilder.modify(modifier: (MenuBuilder) -> Unit): MenuBuilder = fun MenuBuilder.modify(modifier: (MenuBuilder) -> Unit): MenuBuilder =
this.modfiy { modifier(it) } this.modfiy { modifier(it) }

View File

@@ -0,0 +1,10 @@
@file:JvmName("MenuUtilsExtensions")
package com.willfp.eco.util
import com.willfp.eco.core.gui.menu.Menu
import org.bukkit.entity.Player
/** @see MenuUtils.getOpenMenu */
val Player.openMenu: Menu?
get() = MenuUtils.getOpenMenu(this)

View File

@@ -11,3 +11,7 @@ val Vector.isFinite: Boolean
/** @see VectorUtils.simplifyVector */ /** @see VectorUtils.simplifyVector */
fun Vector.simplify(): Vector = fun Vector.simplify(): Vector =
VectorUtils.simplifyVector(this) VectorUtils.simplifyVector(this)
/** @see VectorUtils.isSafeVelocity */
val Vector.isSafeVelocity: Boolean
get() = VectorUtils.isSafeVelocity(this)

View File

@@ -4,6 +4,7 @@ import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.display.Display import com.willfp.eco.core.display.Display
import com.willfp.eco.core.display.DisplayHandler import com.willfp.eco.core.display.DisplayHandler
import com.willfp.eco.core.display.DisplayModule import com.willfp.eco.core.display.DisplayModule
import com.willfp.eco.core.display.DisplayProperties
import com.willfp.eco.core.fast.fast import com.willfp.eco.core.fast.fast
import org.bukkit.NamespacedKey import org.bukkit.NamespacedKey
import org.bukkit.entity.Player import org.bukkit.entity.Player
@@ -32,13 +33,21 @@ class EcoDisplayHandler(plugin: EcoPlugin) : DisplayHandler {
} }
} }
Display.revert(itemStack) Display.revert(itemStack)
if (!itemStack.hasItemMeta()) { if (!itemStack.hasItemMeta()) {
return itemStack return itemStack
} }
val original = itemStack.clone()
val inventory = player?.openInventory?.topInventory
val inInventory = inventory?.contains(original) ?: false
val props = DisplayProperties(
inInventory,
inInventory && inventory?.holder == null,
original
)
for ((_, modules) in registeredModules) { for ((_, modules) in registeredModules) {
for (module in modules) { for (module in modules) {
@@ -48,6 +57,7 @@ class EcoDisplayHandler(plugin: EcoPlugin) : DisplayHandler {
if (player != null) { if (player != null) {
module.display(itemStack, player as Player?, *varargs) module.display(itemStack, player as Player?, *varargs)
module.display(itemStack, player as Player?, props, *varargs)
} }
} }
} }

View File

@@ -2,6 +2,7 @@ package com.willfp.eco.internal.gui.menu
import com.willfp.eco.core.gui.menu.CloseHandler import com.willfp.eco.core.gui.menu.CloseHandler
import com.willfp.eco.core.gui.menu.Menu import com.willfp.eco.core.gui.menu.Menu
import com.willfp.eco.core.gui.menu.OpenHandler
import com.willfp.eco.core.gui.slot.Slot import com.willfp.eco.core.gui.slot.Slot
import com.willfp.eco.internal.gui.slot.EcoSlot import com.willfp.eco.internal.gui.slot.EcoSlot
import com.willfp.eco.util.NamespacedKeyUtils import com.willfp.eco.util.NamespacedKeyUtils
@@ -19,7 +20,8 @@ class EcoMenu(
val slots: List<MutableList<EcoSlot>>, val slots: List<MutableList<EcoSlot>>,
private val title: String, private val title: String,
private val onClose: CloseHandler, private val onClose: CloseHandler,
private val onRender: (Player, Menu) -> Unit private val onRender: (Player, Menu) -> Unit,
private val onOpen: OpenHandler
) : Menu { ) : Menu {
override fun getSlot(row: Int, column: Int): Slot { override fun getSlot(row: Int, column: Int): Slot {
if (row < 1 || row > this.rows) { if (row < 1 || row > this.rows) {
@@ -49,11 +51,14 @@ class EcoMenu(
player.openInventory(inventory) player.openInventory(inventory)
MenuHandler.registerInventory(inventory, this, player) MenuHandler.registerInventory(inventory, this, player)
onOpen.handle(player, this)
inventory.asRenderedInventory()?.generateCaptive()
return inventory return inventory
} }
fun handleClose(event: InventoryCloseEvent) { fun handleClose(event: InventoryCloseEvent) {
onClose.handle(event, this) onClose.handle(event, this)
event.inventory.asRenderedInventory()?.generateCaptive()
MenuHandler.unregisterInventory(event.inventory) MenuHandler.unregisterInventory(event.inventory)
} }

View File

@@ -3,6 +3,7 @@ package com.willfp.eco.internal.gui.menu
import com.willfp.eco.core.gui.menu.CloseHandler import com.willfp.eco.core.gui.menu.CloseHandler
import com.willfp.eco.core.gui.menu.Menu import com.willfp.eco.core.gui.menu.Menu
import com.willfp.eco.core.gui.menu.MenuBuilder import com.willfp.eco.core.gui.menu.MenuBuilder
import com.willfp.eco.core.gui.menu.OpenHandler
import com.willfp.eco.core.gui.slot.FillerMask import com.willfp.eco.core.gui.slot.FillerMask
import com.willfp.eco.core.gui.slot.FillerSlot import com.willfp.eco.core.gui.slot.FillerSlot
import com.willfp.eco.core.gui.slot.Slot import com.willfp.eco.core.gui.slot.Slot
@@ -21,6 +22,7 @@ class EcoMenuBuilder(private val rows: Int ) : MenuBuilder {
private var maskSlots: List<MutableList<Slot?>> private var maskSlots: List<MutableList<Slot?>>
private val slots: List<MutableList<Slot?>> = ListUtils.create2DList(rows, 9) private val slots: List<MutableList<Slot?>> = ListUtils.create2DList(rows, 9)
private var onClose = CloseHandler { _, _ -> } private var onClose = CloseHandler { _, _ -> }
private var onOpen = OpenHandler { _, _ -> }
private var onRender: (Player, Menu) -> Unit = { _, _ -> } private var onRender: (Player, Menu) -> Unit = { _, _ -> }
override fun setTitle(title: String): MenuBuilder { override fun setTitle(title: String): MenuBuilder {
@@ -54,6 +56,11 @@ class EcoMenuBuilder(private val rows: Int ) : MenuBuilder {
return this return this
} }
override fun onOpen(action: OpenHandler): MenuBuilder {
onOpen = action
return this
}
override fun onRender(action: BiConsumer<Player, Menu>): MenuBuilder { override fun onRender(action: BiConsumer<Player, Menu>): MenuBuilder {
onRender = { a, b -> action.accept(a, b) } onRender = { a, b -> action.accept(a, b) }
return this return this
@@ -83,7 +90,7 @@ class EcoMenuBuilder(private val rows: Int ) : MenuBuilder {
finalSlots.add(tempRow) finalSlots.add(tempRow)
} }
return EcoMenu(rows, finalSlots, title, onClose, onRender) return EcoMenu(rows, finalSlots, title, onClose, onRender, onOpen)
} }
init { init {

View File

@@ -34,7 +34,7 @@ class MenuRenderedInventory(
menu.runOnRender(player) menu.runOnRender(player)
} }
private fun generateCaptive() { fun generateCaptive() {
captiveItems.clear() captiveItems.clear()
for (i in 0 until inventory.size) { for (i in 0 until inventory.size) {
val (row, column) = MenuUtils.convertSlotToRowColumn(i) val (row, column) = MenuUtils.convertSlotToRowColumn(i)
@@ -43,7 +43,17 @@ class MenuRenderedInventory(
val renderedItem = slot.getItemStack(player) val renderedItem = slot.getItemStack(player)
val itemStack = inventory.getItem(i) ?: continue val itemStack = inventory.getItem(i) ?: continue
if (itemStack == renderedItem || itemStack.type.isAir || itemStack.amount == 0) { if (slot.isNotCaptiveFor(player)) {
continue
}
if (!slot.isCaptiveFromEmpty) {
if (itemStack == renderedItem) {
continue
}
}
if (itemStack.type.isAir || itemStack.amount == 0) {
continue continue
} }

View File

@@ -2,23 +2,36 @@ package com.willfp.eco.internal.gui.slot
import com.willfp.eco.core.gui.slot.functional.SlotHandler import com.willfp.eco.core.gui.slot.functional.SlotHandler
import com.willfp.eco.core.gui.slot.functional.SlotProvider import com.willfp.eco.core.gui.slot.functional.SlotProvider
import org.bukkit.entity.Player
class EcoCaptiveSlot( class EcoCaptiveSlot(
provider: SlotProvider provider: SlotProvider,
private val captiveFromEmpty: Boolean,
private val notCaptiveFor: (Player) -> Boolean
) : EcoSlot( ) : EcoSlot(
provider, provider,
allowMovingItem, captiveWithTest(notCaptiveFor),
allowMovingItem, captiveWithTest(notCaptiveFor),
allowMovingItem, captiveWithTest(notCaptiveFor),
allowMovingItem, captiveWithTest(notCaptiveFor),
allowMovingItem, captiveWithTest(notCaptiveFor),
{ _, _, prev -> prev } { _, _, prev -> prev }
) { ) {
override fun isCaptive(): Boolean { override fun isCaptive(): Boolean {
return true return true
} }
override fun isCaptiveFromEmpty(): Boolean {
return captiveFromEmpty
}
override fun isNotCaptiveFor(player: Player): Boolean {
return notCaptiveFor(player)
}
} }
private val allowMovingItem = SlotHandler { event, _, _ -> private fun captiveWithTest(test: (Player) -> Boolean): SlotHandler {
event.isCancelled = false return SlotHandler { event, _, _ ->
event.isCancelled = test(event.whoClicked as Player)
}
} }

View File

@@ -38,7 +38,7 @@ open class EcoSlot(
} }
override fun getItemStack(player: Player): ItemStack { override fun getItemStack(player: Player): ItemStack {
val menu = player.openInventory.topInventory.getMenu()!! val menu = player.openInventory.topInventory.getMenu() ?: return ItemStack(Material.AIR)
val prev = provider.provide(player, menu) val prev = provider.provide(player, menu)
return updater.update(player, menu, prev) ?: ItemStack(Material.AIR) return updater.update(player, menu, prev) ?: ItemStack(Material.AIR)
} }

View File

@@ -1,25 +1,39 @@
package com.willfp.eco.internal.gui.slot package com.willfp.eco.internal.gui.slot
import com.willfp.eco.core.gui.menu.Menu
import com.willfp.eco.core.gui.slot.Slot import com.willfp.eco.core.gui.slot.Slot
import com.willfp.eco.core.gui.slot.SlotBuilder import com.willfp.eco.core.gui.slot.SlotBuilder
import com.willfp.eco.core.gui.slot.functional.SlotHandler import com.willfp.eco.core.gui.slot.functional.SlotHandler
import com.willfp.eco.core.gui.slot.functional.SlotProvider import com.willfp.eco.core.gui.slot.functional.SlotProvider
import com.willfp.eco.core.gui.slot.functional.SlotUpdater import com.willfp.eco.core.gui.slot.functional.SlotUpdater
import org.bukkit.entity.Player
import org.bukkit.event.inventory.InventoryClickEvent
import java.util.function.Predicate
internal object NoOpSlot : SlotHandler {
override fun handle(event: InventoryClickEvent, slot: Slot, menu: Menu) {
}
override fun equals(other: Any?): Boolean {
return other is NoOpSlot
}
}
internal class NoOpForPlayer
class EcoSlotBuilder(private val provider: SlotProvider) : SlotBuilder { class EcoSlotBuilder(private val provider: SlotProvider) : SlotBuilder {
private var captive = false private var captive = false
private var captiveFromEmpty = false
private var updater: SlotUpdater = SlotUpdater { player, menu, _ -> provider.provide(player, menu) } private var updater: SlotUpdater = SlotUpdater { player, menu, _ -> provider.provide(player, menu) }
private var onLeftClick = private var onLeftClick: SlotHandler = NoOpSlot
SlotHandler { _, _, _ -> run { } } private var onRightClick: SlotHandler = NoOpSlot
private var onRightClick = private var onShiftLeftClick: SlotHandler = NoOpSlot
SlotHandler { _, _, _ -> run { } } private var onShiftRightClick: SlotHandler = NoOpSlot
private var onShiftLeftClick = private var onMiddleClick: SlotHandler = NoOpSlot
SlotHandler { _, _, _ -> run { } }
private var onShiftRightClick = private var notCaptiveFor: (Player) -> Boolean = { false }
SlotHandler { _, _, _ -> run { } }
private var onMiddleClick =
SlotHandler { _, _, _ -> run { } }
override fun onLeftClick(action: SlotHandler): SlotBuilder { override fun onLeftClick(action: SlotHandler): SlotBuilder {
onLeftClick = action onLeftClick = action
@@ -46,8 +60,14 @@ class EcoSlotBuilder(private val provider: SlotProvider) : SlotBuilder {
return this return this
} }
override fun setCaptive(): SlotBuilder { override fun notCaptiveFor(predicate: Predicate<Player>): SlotBuilder {
notCaptiveFor = { predicate.test(it) }
return this
}
override fun setCaptive(fromEmpty: Boolean): SlotBuilder {
captive = true captive = true
captiveFromEmpty = fromEmpty
return this return this
} }
@@ -58,9 +78,21 @@ class EcoSlotBuilder(private val provider: SlotProvider) : SlotBuilder {
override fun build(): Slot { override fun build(): Slot {
return if (captive) { return if (captive) {
EcoCaptiveSlot(provider) EcoCaptiveSlot(
provider,
captiveFromEmpty,
notCaptiveFor
)
} else { } else {
EcoSlot(provider, onLeftClick, onRightClick, onShiftLeftClick, onShiftRightClick, onMiddleClick, updater) EcoSlot(
provider,
onLeftClick,
onRightClick,
onShiftLeftClick,
onShiftRightClick,
onMiddleClick,
updater
)
} }
} }
} }

View File

@@ -0,0 +1,54 @@
package com.willfp.eco.internal.spigot.proxy.v1_17_R1
import com.willfp.eco.core.items.TestableItem
import com.willfp.eco.core.recipe.parts.EmptyTestableItem
import com.willfp.eco.internal.spigot.proxy.SNBTConverterProxy
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.SnbtPrinterTagVisitor
import net.minecraft.nbt.TagParser
import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack
import org.bukkit.inventory.ItemStack
class SNBTConverter : SNBTConverterProxy {
override fun fromSNBT(snbt: String): ItemStack? {
val nbt = runCatching { TagParser.parseTag(snbt) }.getOrNull() ?: return null
val nms = net.minecraft.world.item.ItemStack.of(nbt)
return CraftItemStack.asBukkitCopy(nms)
}
override fun toSNBT(itemStack: ItemStack): String {
val nms = CraftItemStack.asNMSCopy(itemStack)
return SnbtPrinterTagVisitor().visit(nms.save(CompoundTag()))
}
override fun makeSNBTTestable(snbt: String): TestableItem {
val nbt = runCatching { TagParser.parseTag(snbt) }.getOrNull() ?: return EmptyTestableItem()
val nms = net.minecraft.world.item.ItemStack.of(nbt)
if (nms == net.minecraft.world.item.ItemStack.EMPTY) {
return EmptyTestableItem()
}
nbt.remove("Count")
return SNBTTestableItem(nbt)
}
class SNBTTestableItem(
private val tag: CompoundTag
) : TestableItem {
override fun matches(itemStack: ItemStack?): Boolean {
if (itemStack == null) {
return false
}
val nms = CraftItemStack.asNMSCopy(itemStack)
val nmsTag = nms.save(CompoundTag())
nmsTag.remove("Count")
return tag.copy().merge(nmsTag) == nmsTag
}
override fun getItem(): ItemStack {
return CraftItemStack.asBukkitCopy(net.minecraft.world.item.ItemStack.of(tag))
}
}
}

View File

@@ -0,0 +1,54 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R1
import com.willfp.eco.core.items.TestableItem
import com.willfp.eco.core.recipe.parts.EmptyTestableItem
import com.willfp.eco.internal.spigot.proxy.SNBTConverterProxy
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.SnbtPrinterTagVisitor
import net.minecraft.nbt.TagParser
import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftItemStack
import org.bukkit.inventory.ItemStack
class SNBTConverter : SNBTConverterProxy {
override fun fromSNBT(snbt: String): ItemStack? {
val nbt = runCatching { TagParser.parseTag(snbt) }.getOrNull() ?: return null
val nms = net.minecraft.world.item.ItemStack.of(nbt)
return CraftItemStack.asBukkitCopy(nms)
}
override fun toSNBT(itemStack: ItemStack): String {
val nms = CraftItemStack.asNMSCopy(itemStack)
return SnbtPrinterTagVisitor().visit(nms.save(CompoundTag()))
}
override fun makeSNBTTestable(snbt: String): TestableItem {
val nbt = runCatching { TagParser.parseTag(snbt) }.getOrNull() ?: return EmptyTestableItem()
val nms = net.minecraft.world.item.ItemStack.of(nbt)
if (nms == net.minecraft.world.item.ItemStack.EMPTY) {
return EmptyTestableItem()
}
nbt.remove("Count")
return SNBTTestableItem(nbt)
}
class SNBTTestableItem(
private val tag: CompoundTag
) : TestableItem {
override fun matches(itemStack: ItemStack?): Boolean {
if (itemStack == null) {
return false
}
val nms = CraftItemStack.asNMSCopy(itemStack)
val nmsTag = nms.save(CompoundTag())
nmsTag.remove("Count")
return tag.copy().merge(nmsTag) == nmsTag
}
override fun getItem(): ItemStack {
return CraftItemStack.asBukkitCopy(net.minecraft.world.item.ItemStack.of(tag))
}
}
}

View File

@@ -0,0 +1,54 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R2
import com.willfp.eco.core.items.TestableItem
import com.willfp.eco.core.recipe.parts.EmptyTestableItem
import com.willfp.eco.internal.spigot.proxy.SNBTConverterProxy
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.SnbtPrinterTagVisitor
import net.minecraft.nbt.TagParser
import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack
import org.bukkit.inventory.ItemStack
class SNBTConverter : SNBTConverterProxy {
override fun fromSNBT(snbt: String): ItemStack? {
val nbt = runCatching { TagParser.parseTag(snbt) }.getOrNull() ?: return null
val nms = net.minecraft.world.item.ItemStack.of(nbt)
return CraftItemStack.asBukkitCopy(nms)
}
override fun toSNBT(itemStack: ItemStack): String {
val nms = CraftItemStack.asNMSCopy(itemStack)
return SnbtPrinterTagVisitor().visit(nms.save(CompoundTag()))
}
override fun makeSNBTTestable(snbt: String): TestableItem {
val nbt = runCatching { TagParser.parseTag(snbt) }.getOrNull() ?: return EmptyTestableItem()
val nms = net.minecraft.world.item.ItemStack.of(nbt)
if (nms == net.minecraft.world.item.ItemStack.EMPTY) {
return EmptyTestableItem()
}
nbt.remove("Count")
return SNBTTestableItem(nbt)
}
class SNBTTestableItem(
private val tag: CompoundTag
) : TestableItem {
override fun matches(itemStack: ItemStack?): Boolean {
if (itemStack == null) {
return false
}
val nms = CraftItemStack.asNMSCopy(itemStack)
val nmsTag = nms.save(CompoundTag())
nmsTag.remove("Count")
return tag.copy().merge(nmsTag) == nmsTag
}
override fun getItem(): ItemStack {
return CraftItemStack.asBukkitCopy(net.minecraft.world.item.ItemStack.of(tag))
}
}
}

View File

@@ -0,0 +1,39 @@
plugins {
id("io.papermc.paperweight.userdev") version "1.3.6"
}
group = "com.willfp"
version = rootProject.version
dependencies {
implementation(project(":eco-core:core-nms:nms-common"))
paperDevBundle("1.19-R0.1-SNAPSHOT")
implementation("net.kyori:adventure-text-minimessage:4.11.0") {
version {
strictly("4.11.0")
}
exclude(group = "net.kyori", module = "adventure-api")
}
}
tasks {
build {
dependsOn(reobfJar)
}
reobfJar {
mustRunAfter(shadowJar)
}
shadowJar {
relocate(
"com.willfp.eco.internal.spigot.proxy.common",
"com.willfp.eco.internal.spigot.proxy.v1_19_R1.common"
)
relocate(
"net.kyori.adventure.text.minimessage",
"com.willfp.eco.internal.spigot.proxy.v1_19_R1.minimessage"
)
}
}

View File

@@ -0,0 +1,15 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_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,93 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_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_19_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.binaryTagHolder(
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,135 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R1
import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy
import com.willfp.eco.internal.spigot.proxy.common.CommonsProvider
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.PathfinderMob
import org.bukkit.Bukkit
import org.bukkit.NamespacedKey
import org.bukkit.craftbukkit.v1_19_R1.CraftServer
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftEntity
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftMob
import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack
import org.bukkit.craftbukkit.v1_19_R1.persistence.CraftPersistentDataContainer
import org.bukkit.craftbukkit.v1_19_R1.persistence.CraftPersistentDataTypeRegistry
import org.bukkit.craftbukkit.v1_19_R1.util.CraftMagicNumbers
import org.bukkit.craftbukkit.v1_19_R1.util.CraftNamespacedKey
import org.bukkit.entity.LivingEntity
import org.bukkit.entity.Mob
import org.bukkit.inventory.ItemStack
import org.bukkit.persistence.PersistentDataContainer
import java.lang.reflect.Field
class CommonsInitializer : CommonsInitializerProxy {
override fun init() {
CommonsProvider.setIfNeeded(CommonsProviderImpl)
}
object CommonsProviderImpl : CommonsProvider {
private val cisHandle: Field = CraftItemStack::class.java.getDeclaredField("handle").apply {
isAccessible = true
}
private val pdcRegsitry = Class.forName("org.bukkit.craftbukkit.v1_19_R1.inventory.CraftMetaItem")
.getDeclaredField("DATA_TYPE_REGISTRY")
.apply { isAccessible = true }
.get(null) as CraftPersistentDataTypeRegistry
override val nbtTagString = CraftMagicNumbers.NBT.TAG_STRING
override fun toPathfinderMob(mob: Mob): PathfinderMob? {
val craft = mob as? CraftMob ?: return null
return craft.handle as? PathfinderMob
}
override fun toResourceLocation(namespacedKey: NamespacedKey): ResourceLocation =
CraftNamespacedKey.toMinecraft(namespacedKey)
override fun asNMSStack(itemStack: ItemStack): net.minecraft.world.item.ItemStack {
return if (itemStack !is CraftItemStack) {
CraftItemStack.asNMSCopy(itemStack)
} else {
cisHandle[itemStack] as net.minecraft.world.item.ItemStack? ?: CraftItemStack.asNMSCopy(itemStack)
}
}
override fun asBukkitStack(itemStack: net.minecraft.world.item.ItemStack): ItemStack {
return CraftItemStack.asBukkitCopy(itemStack)
}
override fun mergeIfNeeded(itemStack: ItemStack, nmsStack: net.minecraft.world.item.ItemStack) {
if (itemStack !is CraftItemStack) {
itemStack.itemMeta = CraftItemStack.asCraftMirror(nmsStack).itemMeta
}
}
override fun toBukkitEntity(entity: net.minecraft.world.entity.LivingEntity): LivingEntity? =
CraftEntity.getEntity(Bukkit.getServer() as CraftServer, entity) as? LivingEntity
override fun makePdc(tag: CompoundTag, base: Boolean): PersistentDataContainer {
fun emptyPdc(): CraftPersistentDataContainer = CraftPersistentDataContainer(pdcRegsitry)
fun CompoundTag?.toPdc(): PersistentDataContainer {
val pdc = emptyPdc()
this ?: return pdc
val keys = this.allKeys
for (key in keys) {
pdc.put(key, this[key])
}
return pdc
}
return if (base) {
tag.toPdc()
} else {
if (tag.contains("PublicBukkitValues")) {
tag.getCompound("PublicBukkitValues").toPdc()
} else {
emptyPdc()
}
}
}
override fun setPdc(
tag: CompoundTag,
pdc: PersistentDataContainer?,
item: net.minecraft.world.item.ItemStack?
) {
fun CraftPersistentDataContainer.toTag(): CompoundTag {
val compound = CompoundTag()
val rawPublicMap: Map<String, Tag> = this.raw
for ((key, value) in rawPublicMap) {
compound.put(key, value)
}
return compound
}
val container = when (pdc) {
is CraftPersistentDataContainer? -> pdc
else -> null
}
if (item != null) {
if (container != null && !container.isEmpty) {
for (key in tag.allKeys.toSet()) {
tag.remove(key)
}
tag.merge(container.toTag())
} else {
item.setTag(null)
}
} else {
if (container != null && !container.isEmpty) {
tag.put("PublicBukkitValues", container.toTag())
} else {
tag.remove("PublicBukkitValues")
}
}
}
}
}

View File

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

View File

@@ -0,0 +1,12 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R1
import com.willfp.eco.core.entities.ai.EntityController
import com.willfp.eco.internal.spigot.proxy.EntityControllerFactoryProxy
import com.willfp.eco.internal.spigot.proxy.common.ai.EcoEntityController
import org.bukkit.entity.Mob
class EntityControllerFactory : EntityControllerFactoryProxy {
override fun <T : Mob> createEntityController(entity: T): EntityController<T> {
return EcoEntityController(entity)
}
}

View File

@@ -0,0 +1,70 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R1
import com.willfp.eco.core.data.ExtendedPersistentDataContainer
import com.willfp.eco.internal.spigot.proxy.ExtendedPersistentDataContainerFactoryProxy
import net.minecraft.nbt.Tag
import org.bukkit.craftbukkit.v1_19_R1.persistence.CraftPersistentDataContainer
import org.bukkit.craftbukkit.v1_19_R1.persistence.CraftPersistentDataTypeRegistry
import org.bukkit.persistence.PersistentDataContainer
import org.bukkit.persistence.PersistentDataType
class ExtendedPersistentDataContainerFactory: ExtendedPersistentDataContainerFactoryProxy {
@Suppress("UNCHECKED_CAST")
private val registry: CraftPersistentDataTypeRegistry =
CraftPersistentDataContainer::class.java.getDeclaredField("registry")
.apply { isAccessible = true }.get(null) as CraftPersistentDataTypeRegistry
override fun adapt(pdc: PersistentDataContainer): ExtendedPersistentDataContainer {
return when (pdc) {
is CraftPersistentDataContainer -> EcoPersistentDataContainer(pdc)
else -> throw IllegalArgumentException("Custom PDC instance is not supported!")
}
}
override fun newPdc(): PersistentDataContainer {
return CraftPersistentDataContainer(registry)
}
inner class EcoPersistentDataContainer(
val handle: CraftPersistentDataContainer
) : ExtendedPersistentDataContainer {
@Suppress("UNCHECKED_CAST")
private val customDataTags: MutableMap<String, Tag> =
CraftPersistentDataContainer::class.java.getDeclaredField("customDataTags")
.apply { isAccessible = true }.get(handle) as MutableMap<String, Tag>
override fun <T : Any, Z : Any> set(key: String, dataType: PersistentDataType<T, Z>, value: Z) {
customDataTags[key] = registry.wrap(dataType.primitiveType, dataType.toPrimitive(value, handle.adapterContext))
}
override fun <T : Any, Z : Any> has(key: String, dataType: PersistentDataType<T, Z>): Boolean {
val value = customDataTags[key] ?: return false
return registry.isInstanceOf(dataType.primitiveType, value)
}
override fun <T : Any, Z : Any> get(key: String, dataType: PersistentDataType<T, Z>): Z? {
val value = customDataTags[key] ?: return null
return dataType.fromPrimitive(registry.extract(dataType.primitiveType, value), handle.adapterContext)
}
override fun <T : Any, Z : Any> getOrDefault(
key: String,
dataType: PersistentDataType<T, Z>,
defaultValue: Z
): Z {
return get(key, dataType) ?: defaultValue
}
override fun remove(key: String) {
customDataTags.remove(key)
}
override fun getAllKeys(): MutableSet<String> {
return customDataTags.keys
}
override fun getBase(): PersistentDataContainer {
return handle
}
}
}

View File

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

View File

@@ -0,0 +1,33 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R1
import com.willfp.eco.core.display.Display
import com.willfp.eco.internal.spigot.proxy.MiniMessageTranslatorProxy
import com.willfp.eco.util.toLegacy
import net.kyori.adventure.text.minimessage.MiniMessage
class MiniMessageTranslator : MiniMessageTranslatorProxy {
override fun format(message: String): String {
var mut = message
val startsWithPrefix = mut.startsWith(Display.PREFIX)
if (startsWithPrefix) {
mut = mut.substring(2)
}
mut = mut.replace('§', '&')
val miniMessage = runCatching {
MiniMessage.miniMessage().deserialize(
mut
).toLegacy()
}.getOrNull() ?: mut
mut = if (startsWithPrefix) {
Display.PREFIX + miniMessage
} else {
miniMessage
}
return mut
}
}

View File

@@ -0,0 +1,54 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R1
import com.willfp.eco.core.items.TestableItem
import com.willfp.eco.core.recipe.parts.EmptyTestableItem
import com.willfp.eco.internal.spigot.proxy.SNBTConverterProxy
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.SnbtPrinterTagVisitor
import net.minecraft.nbt.TagParser
import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack
import org.bukkit.inventory.ItemStack
class SNBTConverter : SNBTConverterProxy {
override fun fromSNBT(snbt: String): ItemStack? {
val nbt = runCatching { TagParser.parseTag(snbt) }.getOrNull() ?: return null
val nms = net.minecraft.world.item.ItemStack.of(nbt)
return CraftItemStack.asBukkitCopy(nms)
}
override fun toSNBT(itemStack: ItemStack): String {
val nms = CraftItemStack.asNMSCopy(itemStack)
return SnbtPrinterTagVisitor().visit(nms.save(CompoundTag()))
}
override fun makeSNBTTestable(snbt: String): TestableItem {
val nbt = runCatching { TagParser.parseTag(snbt) }.getOrNull() ?: return EmptyTestableItem()
val nms = net.minecraft.world.item.ItemStack.of(nbt)
if (nms == net.minecraft.world.item.ItemStack.EMPTY) {
return EmptyTestableItem()
}
nbt.remove("Count")
return SNBTTestableItem(nbt)
}
class SNBTTestableItem(
private val tag: CompoundTag
) : TestableItem {
override fun matches(itemStack: ItemStack?): Boolean {
if (itemStack == null) {
return false
}
val nms = CraftItemStack.asNMSCopy(itemStack)
val nmsTag = nms.save(CompoundTag())
nmsTag.remove("Count")
return tag.copy().merge(nmsTag) == nmsTag
}
override fun getItem(): ItemStack {
return CraftItemStack.asBukkitCopy(net.minecraft.world.item.ItemStack.of(tag))
}
}
}

View File

@@ -0,0 +1,48 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_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
}
if (base64.length < 20) {
return
}
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_19_R1
import com.willfp.eco.internal.spigot.proxy.TPSProxy
import org.bukkit.Bukkit
import org.bukkit.craftbukkit.v1_19_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_19_R1
import com.willfp.eco.core.display.Display
import com.willfp.eco.internal.spigot.proxy.VillagerTradeProxy
import net.minecraft.nbt.CompoundTag
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.trading.MerchantOffer
import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack
import org.bukkit.craftbukkit.v1_19_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 {
recipe as CraftMerchantRecipe
val nbt = getHandle(recipe).createTag()
for (tag in arrayOf("buy", "buyB", "sell")) {
val nms = ItemStack.of(nbt.getCompound(tag))
val displayed = Display.display(CraftItemStack.asBukkitCopy(nms), player)
val itemNBT = CraftItemStack.asNMSCopy(displayed).save(CompoundTag())
nbt.put(tag, itemNBT)
}
return CraftMerchantRecipe(MerchantOffer(nbt))
}
private fun getHandle(recipe: CraftMerchantRecipe): MerchantOffer {
return handle[recipe] as MerchantOffer
}
init {
handle.isAccessible = true
}
}

View File

@@ -22,7 +22,7 @@ dependencies {
compileOnly 'io.papermc.paper:paper-api:1.17.1-R0.1-SNAPSHOT' compileOnly 'io.papermc.paper:paper-api:1.17.1-R0.1-SNAPSHOT'
// Plugin dependencies // Plugin dependencies
compileOnly 'com.comphenix.protocol:ProtocolLib:4.6.1-SNAPSHOT' compileOnly 'com.comphenix.protocol:ProtocolLib:5.0.0-SNAPSHOT'
compileOnly 'com.sk89q.worldguard:worldguard-bukkit:7.0.7-SNAPSHOT' compileOnly 'com.sk89q.worldguard:worldguard-bukkit:7.0.7-SNAPSHOT'
compileOnly 'com.github.TechFortress:GriefPrevention:16.17.1' compileOnly 'com.github.TechFortress:GriefPrevention:16.17.1'
compileOnly 'com.massivecraft:Factions:1.6.9.5-U0.5.10' compileOnly 'com.massivecraft:Factions:1.6.9.5-U0.5.10'
@@ -36,7 +36,7 @@ dependencies {
compileOnly 'com.gmail.nossr50.mcMMO:mcMMO:2.1.202' compileOnly 'com.gmail.nossr50.mcMMO:mcMMO:2.1.202'
compileOnly 'me.clip:placeholderapi:2.10.10' compileOnly 'me.clip:placeholderapi:2.10.10'
compileOnly 'com.github.oraxen:oraxen:bd81ace154' compileOnly 'com.github.oraxen:oraxen:bd81ace154'
compileOnly 'com.github.brcdev-minecraft:shopgui-api:2.2.0' compileOnly 'com.github.brcdev-minecraft:shopgui-api:3.0.0'
compileOnly 'com.github.LoneDev6:API-ItemsAdder:2.4.7' compileOnly 'com.github.LoneDev6:API-ItemsAdder:2.4.7'
compileOnly 'com.arcaniax:HeadDatabase-API:1.3.0' compileOnly 'com.arcaniax:HeadDatabase-API:1.3.0'
compileOnly 'com.gmail.filoghost.holographicdisplays:holographicdisplays-api:2.4.0' compileOnly 'com.gmail.filoghost.holographicdisplays:holographicdisplays-api:2.4.0'

View File

@@ -16,7 +16,11 @@ object ConflictFinder {
continue continue
} }
val conflict = plugin.getConflict() val conflict = try {
plugin.getConflict()
} catch (e: Exception) {
continue
} // Really can't be fucked to do this properly.
if (conflict != null) { if (conflict != null) {
conflicts.add(conflict) conflicts.add(conflict)
@@ -47,7 +51,13 @@ private fun Plugin.getConflict(): Conflict? {
return Conflict(this, ConflictType.LIB_LOADER) return Conflict(this, ConflictType.LIB_LOADER)
} }
val zip = ZipFile(File(this::class.java.protectionDomain.codeSource.location.toURI())) val file = File(this::class.java.protectionDomain.codeSource.location.toURI())
if (!file.exists() || file.name.contains("PolymartHelper")) {
return null
}
val zip = ZipFile(file)
for (entry in zip.entries()) { for (entry in zip.entries()) {
if (entry.name.startsWith("kotlin/") || entry.name.startsWith("kotlinx/")) { if (entry.name.startsWith("kotlin/") || entry.name.startsWith("kotlinx/")) {

View File

@@ -7,6 +7,7 @@ import com.willfp.eco.core.data.ExtendedPersistentDataContainer
import com.willfp.eco.core.entities.ai.EntityController import com.willfp.eco.core.entities.ai.EntityController
import com.willfp.eco.core.fast.FastItemStack import com.willfp.eco.core.fast.FastItemStack
import com.willfp.eco.core.integrations.placeholder.PlaceholderIntegration import com.willfp.eco.core.integrations.placeholder.PlaceholderIntegration
import com.willfp.eco.core.items.SNBTHandler
import com.willfp.eco.internal.EcoCleaner import com.willfp.eco.internal.EcoCleaner
import com.willfp.eco.internal.EcoPropsParser import com.willfp.eco.internal.EcoPropsParser
import com.willfp.eco.internal.Plugins import com.willfp.eco.internal.Plugins
@@ -31,6 +32,7 @@ import com.willfp.eco.internal.spigot.data.EcoKeyRegistry
import com.willfp.eco.internal.spigot.data.EcoProfileHandler import com.willfp.eco.internal.spigot.data.EcoProfileHandler
import com.willfp.eco.internal.spigot.data.storage.HandlerType import com.willfp.eco.internal.spigot.data.storage.HandlerType
import com.willfp.eco.internal.spigot.integrations.bstats.MetricHandler import com.willfp.eco.internal.spigot.integrations.bstats.MetricHandler
import com.willfp.eco.internal.spigot.items.EcoSNBTHandler
import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy
import com.willfp.eco.internal.spigot.proxy.DummyEntityFactoryProxy import com.willfp.eco.internal.spigot.proxy.DummyEntityFactoryProxy
import com.willfp.eco.internal.spigot.proxy.EntityControllerFactoryProxy import com.willfp.eco.internal.spigot.proxy.EntityControllerFactoryProxy
@@ -70,6 +72,8 @@ class EcoHandler : EcoSpigotPlugin(), Handler {
}, this }, this
) )
private val snbtHandler = EcoSNBTHandler(this)
@Suppress("RedundantNullableReturnType") @Suppress("RedundantNullableReturnType")
private val keyFactory: InternalNamespacedKeyFactory? = private val keyFactory: InternalNamespacedKeyFactory? =
if (this.configYml.getBool("use-safer-namespacedkey-creation")) if (this.configYml.getBool("use-safer-namespacedkey-creation"))
@@ -170,4 +174,7 @@ class EcoHandler : EcoSpigotPlugin(), Handler {
override fun newPdc(): PersistentDataContainer = override fun newPdc(): PersistentDataContainer =
getProxy(ExtendedPersistentDataContainerFactoryProxy::class.java).newPdc() getProxy(ExtendedPersistentDataContainerFactoryProxy::class.java).newPdc()
override fun getSNBTHandler(): SNBTHandler =
snbtHandler
} }

View File

@@ -38,6 +38,7 @@ import com.willfp.eco.internal.entities.EntityArgParserSilent
import com.willfp.eco.internal.entities.EntityArgParserSize import com.willfp.eco.internal.entities.EntityArgParserSize
import com.willfp.eco.internal.entities.EntityArgParserSpawnReinforcements import com.willfp.eco.internal.entities.EntityArgParserSpawnReinforcements
import com.willfp.eco.internal.entities.EntityArgParserSpeed import com.willfp.eco.internal.entities.EntityArgParserSpeed
import com.willfp.eco.internal.gui.menu.getMenu
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
@@ -111,6 +112,7 @@ import com.willfp.eco.internal.spigot.integrations.shop.ShopEconomyShopGUI
import com.willfp.eco.internal.spigot.integrations.shop.ShopShopGuiPlus import com.willfp.eco.internal.spigot.integrations.shop.ShopShopGuiPlus
import com.willfp.eco.internal.spigot.integrations.shop.ShopZShop import com.willfp.eco.internal.spigot.integrations.shop.ShopZShop
import com.willfp.eco.internal.spigot.math.evaluateExpression import com.willfp.eco.internal.spigot.math.evaluateExpression
import com.willfp.eco.internal.spigot.player.PlayerHealthFixer
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
@@ -120,6 +122,7 @@ import com.willfp.eco.internal.spigot.recipes.listeners.ComplexInComplex
import com.willfp.eco.internal.spigot.recipes.listeners.ComplexInVanilla import com.willfp.eco.internal.spigot.recipes.listeners.ComplexInVanilla
import com.willfp.eco.internal.spigot.recipes.stackhandlers.ShapedCraftingRecipeStackHandler import com.willfp.eco.internal.spigot.recipes.stackhandlers.ShapedCraftingRecipeStackHandler
import com.willfp.eco.internal.spigot.recipes.stackhandlers.ShapelessCraftingRecipeStackHandler import com.willfp.eco.internal.spigot.recipes.stackhandlers.ShapelessCraftingRecipeStackHandler
import com.willfp.eco.util.MenuUtils
import com.willfp.eco.util.NumberUtils 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
@@ -182,6 +185,8 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
NumberUtils.initCrunch { expression, player, context -> evaluateExpression(expression, player, context) } NumberUtils.initCrunch { expression, player, context -> evaluateExpression(expression, player, context) }
MenuUtils.initialize { it.openInventory.topInventory.getMenu() }
CustomItemsManager.registerProviders() CustomItemsManager.registerProviders()
postInit() postInit()
@@ -358,7 +363,8 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
ArrowDataListener(this), ArrowDataListener(this),
ArmorChangeEventListeners(this), ArmorChangeEventListeners(this),
DataListener(this), DataListener(this),
PlayerBlockListener(this) PlayerBlockListener(this),
PlayerHealthFixer(this)
) )
if (Prerequisite.HAS_PAPER.isMet) { if (Prerequisite.HAS_PAPER.isMet) {

View File

@@ -29,19 +29,24 @@ class EcoKeyRegistry : KeyRegistry {
} }
private fun <T> validateKey(key: PersistentDataKey<T>) { private fun <T> validateKey(key: PersistentDataKey<T>) {
val default = key.defaultValue
when (key.type) { when (key.type) {
PersistentDataKeyType.INT -> if (key.defaultValue !is Int) { PersistentDataKeyType.INT -> if (default !is Int) {
throw IllegalArgumentException("Invalid Data Type! Should be Int") throw IllegalArgumentException("Invalid Data Type! Should be Int")
} }
PersistentDataKeyType.DOUBLE -> if (key.defaultValue !is Double) { PersistentDataKeyType.DOUBLE -> if (default !is Double) {
throw IllegalArgumentException("Invalid Data Type! Should be Double") throw IllegalArgumentException("Invalid Data Type! Should be Double")
} }
PersistentDataKeyType.BOOLEAN -> if (key.defaultValue !is Boolean) { PersistentDataKeyType.BOOLEAN -> if (default !is Boolean) {
throw IllegalArgumentException("Invalid Data Type! Should be Boolean") throw IllegalArgumentException("Invalid Data Type! Should be Boolean")
} }
PersistentDataKeyType.STRING -> if (key.defaultValue !is String) { PersistentDataKeyType.STRING -> if (default !is String) {
throw IllegalArgumentException("Invalid Data Type! Should be String") throw IllegalArgumentException("Invalid Data Type! Should be String")
} }
PersistentDataKeyType.STRING_LIST -> if (default !is List<*> || default.firstOrNull() !is String?) {
throw IllegalArgumentException("Invalid Data Type! Should be String List")
}
else -> throw NullPointerException("Null value found!") else -> throw NullPointerException("Null value found!")
} }

View File

@@ -17,11 +17,13 @@ class PacketSetSlot(plugin: EcoPlugin) : AbstractPacketAdapter(plugin, PacketTyp
player: Player, player: Player,
event: PacketEvent event: PacketEvent
) { ) {
packet.itemModifier.modify(0) { item: ItemStack? -> packet.itemModifier.modify(0, object : VersionCompatiblePLibFunction<ItemStack> {
Display.display( override fun apply(item: ItemStack) =
item!!, player Display.display(
) item,
} player
)
})
player.lastDisplayFrame = DisplayFrame.EMPTY player.lastDisplayFrame = DisplayFrame.EMPTY
} }

View File

@@ -0,0 +1,8 @@
package com.willfp.eco.internal.spigot.display
import com.google.common.base.Function
import java.util.function.UnaryOperator
interface VersionCompatiblePLibFunction<T> : Function<T, T>, UnaryOperator<T> {
}

View File

@@ -13,6 +13,7 @@ import org.bukkit.event.EventPriority
import org.bukkit.event.Listener import org.bukkit.event.Listener
import org.bukkit.event.inventory.InventoryClickEvent import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.event.inventory.InventoryCloseEvent import org.bukkit.event.inventory.InventoryCloseEvent
import org.bukkit.event.player.PlayerItemHeldEvent
class GUIListener(private val plugin: EcoPlugin) : Listener { class GUIListener(private val plugin: EcoPlugin) : Listener {
@EventHandler(priority = EventPriority.HIGH) @EventHandler(priority = EventPriority.HIGH)
@@ -45,7 +46,6 @@ class GUIListener(private val plugin: EcoPlugin) : Listener {
} }
val menu = inv.getMenu() ?: return val menu = inv.getMenu() ?: return
val rendered = inv.asRenderedInventory() ?: return
val (row, column) = MenuUtils.convertSlotToRowColumn(inv.firstEmpty()) val (row, column) = MenuUtils.convertSlotToRowColumn(inv.firstEmpty())
@@ -54,8 +54,6 @@ class GUIListener(private val plugin: EcoPlugin) : Listener {
if (!slot.isCaptive) { if (!slot.isCaptive) {
event.isCancelled = true event.isCancelled = true
} }
plugin.scheduler.run { rendered.render() }
} }
@EventHandler(priority = EventPriority.HIGH) @EventHandler(priority = EventPriority.HIGH)
@@ -66,4 +64,25 @@ class GUIListener(private val plugin: EcoPlugin) : Listener {
plugin.scheduler.run { MenuHandler.unregisterInventory(event.inventory) } plugin.scheduler.run { MenuHandler.unregisterInventory(event.inventory) }
} }
@EventHandler
fun forceRender(event: InventoryClickEvent) {
val player = event.whoClicked as? Player ?: return
player.renderActiveMenu()
}
@EventHandler
fun forceRender(event: PlayerItemHeldEvent) {
val player = event.player
player.renderActiveMenu()
}
private fun Player.renderActiveMenu() {
val inv = this.openInventory.topInventory
val rendered = inv.asRenderedInventory() ?: return
rendered.render()
plugin.scheduler.run { rendered.render() }
}
} }

View File

@@ -4,16 +4,16 @@ import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.integrations.customitems.CustomItemsIntegration import com.willfp.eco.core.integrations.customitems.CustomItemsIntegration
import com.willfp.eco.core.items.Items import com.willfp.eco.core.items.Items
import com.willfp.eco.core.recipe.parts.EmptyTestableItem import com.willfp.eco.core.recipe.parts.EmptyTestableItem
import io.lumine.mythic.api.adapters.AbstractItemStack
import io.lumine.mythic.api.config.MythicLineConfig import io.lumine.mythic.api.config.MythicLineConfig
import io.lumine.mythic.api.drops.DropMetadata import io.lumine.mythic.api.drops.DropMetadata
import io.lumine.mythic.api.drops.IMultiDrop import io.lumine.mythic.api.drops.IItemDrop
import io.lumine.mythic.bukkit.adapters.BukkitItemStack import io.lumine.mythic.bukkit.adapters.BukkitItemStack
import io.lumine.mythic.bukkit.events.MythicDropLoadEvent import io.lumine.mythic.bukkit.events.MythicDropLoadEvent
import io.lumine.mythic.core.drops.Drop import org.bukkit.Material
import io.lumine.mythic.core.drops.LootBag
import io.lumine.mythic.core.drops.droppables.ItemDrop
import org.bukkit.event.EventHandler import org.bukkit.event.EventHandler
import org.bukkit.event.Listener import org.bukkit.event.Listener
import org.bukkit.inventory.ItemStack
class CustomItemsMythicMobs( class CustomItemsMythicMobs(
private val plugin: EcoPlugin private val plugin: EcoPlugin
@@ -39,19 +39,16 @@ class CustomItemsMythicMobs(
private class MythicMobsDrop( private class MythicMobsDrop(
private val plugin: EcoPlugin, private val plugin: EcoPlugin,
itemConfig: MythicLineConfig itemConfig: MythicLineConfig
) : Drop(itemConfig.line, itemConfig), IMultiDrop { ) : IItemDrop {
private val id = itemConfig.getString(arrayOf("type", "t", "item", "i"), this.dropVar) private val id = itemConfig.getString(arrayOf("type", "t", "item", "i"), "eco")
override fun get(data: DropMetadata): LootBag {
val bag = LootBag(data)
override fun getDrop(data: DropMetadata, v: Double): AbstractItemStack {
val item = Items.lookup(id) val item = Items.lookup(id)
if (item is EmptyTestableItem) { if (item is EmptyTestableItem) {
plugin.logger.warning("Item with ID $id is invalid, check your configs!") plugin.logger.warning("Item with ID $id is invalid, check your configs!")
return bag return BukkitItemStack(ItemStack(Material.AIR))
} }
bag.add(data, ItemDrop(this.line, this.config, BukkitItemStack(item.item))) return BukkitItemStack(item.item.apply { amount = v.toInt() })
return bag
} }
} }
} }

View File

@@ -0,0 +1,20 @@
package com.willfp.eco.internal.spigot.items
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.items.SNBTHandler
import com.willfp.eco.core.items.TestableItem
import com.willfp.eco.internal.spigot.proxy.SNBTConverterProxy
import org.bukkit.inventory.ItemStack
class EcoSNBTHandler(
private val plugin: EcoPlugin
) : SNBTHandler {
override fun fromSNBT(snbt: String): ItemStack? =
plugin.getProxy(SNBTConverterProxy::class.java).fromSNBT(snbt)
override fun toSNBT(itemStack: ItemStack): String =
plugin.getProxy(SNBTConverterProxy::class.java).toSNBT(itemStack)
override fun createTestable(snbt: String): TestableItem =
plugin.getProxy(SNBTConverterProxy::class.java).makeSNBTTestable(snbt)
}

View File

@@ -0,0 +1,42 @@
package com.willfp.eco.internal.spigot.player
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.data.keys.PersistentDataKey
import com.willfp.eco.core.data.keys.PersistentDataKeyType
import com.willfp.eco.core.data.profile
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.player.PlayerJoinEvent
import org.bukkit.event.player.PlayerQuitEvent
class PlayerHealthFixer(
private val plugin: EcoPlugin
): Listener {
private val lastHealthKey = PersistentDataKey(
plugin.namespacedKeyFactory.create("last_health"),
PersistentDataKeyType.DOUBLE,
0.0
)
@EventHandler
fun onLeave(event: PlayerQuitEvent) {
if (!plugin.configYml.getBool("health-fixer")) {
return
}
val player = event.player
player.profile.write(lastHealthKey, player.health)
}
@EventHandler
fun onJoin(event: PlayerJoinEvent) {
if (!plugin.configYml.getBool("health-fixer")) {
return
}
val player = event.player
plugin.scheduler.runLater(2) {
player.health = player.profile.read(lastHealthKey)
}
}
}

View File

@@ -77,3 +77,6 @@ log-full-extension-errors: false
# render items nicely, which may degrade the user experience on your server. If you use # render items nicely, which may degrade the user experience on your server. If you use
# a custom crafting table, though, this won't affect anything, and you should disable the option. # a custom crafting table, though, this won't affect anything, and you should disable the option.
displayed-recipes: true displayed-recipes: true
# Save health on leave and set it back on join - works around attribute modifiers.
health-fixer: false

View File

@@ -0,0 +1,10 @@
package com.willfp.eco.internal.spigot.proxy
import com.willfp.eco.core.items.TestableItem
import org.bukkit.inventory.ItemStack
interface SNBTConverterProxy {
fun toSNBT(itemStack: ItemStack): String
fun fromSNBT(snbt: String): ItemStack?
fun makeSNBTTestable(snbt: String): TestableItem
}

View File

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

View File

@@ -15,6 +15,7 @@ include(":eco-core:core-nms:nms-common")
include(":eco-core:core-nms:v1_17_R1") include(":eco-core:core-nms:v1_17_R1")
include(":eco-core:core-nms:v1_18_R1") include(":eco-core:core-nms:v1_18_R1")
include(":eco-core:core-nms:v1_18_R2") include(":eco-core:core-nms:v1_18_R2")
include(":eco-core:core-nms:v1_19_R1")
include(":eco-core:core-proxy") include(":eco-core:core-proxy")
include(":eco-core:core-plugin") include(":eco-core:core-plugin")
include(":eco-core:core-backend") include(":eco-core:core-backend")