Compare commits

..

17 Commits

Author SHA1 Message Date
Auxilor
264c591020 Fixed readme again 2023-02-15 13:49:01 +00:00
Auxilor
6bd3ca0f5c Updated README 2023-02-15 13:48:07 +00:00
Auxilor
98df14a23a Fixed javadoc 2023-02-15 13:43:46 +00:00
Auxilor
ccb6e38064 Cleaned up entity / target goal code 2023-02-15 13:07:16 +00:00
Auxilor
50f1ba6a19 Fix 2023-02-15 12:55:16 +00:00
Auxilor
501e7b05a6 Fucksake, reverted my bugfixes 2023-02-14 20:21:12 +00:00
Auxilor
ebf8abf764 Oops 2023-02-14 20:09:56 +00:00
Auxilor
aff8fa8e88 Javadoc 2023-02-14 20:07:12 +00:00
Auxilor
1accad88fe Added GUI Detection system with DeluxeMenus support 2023-02-14 20:00:39 +00:00
Auxilor
a3a5e4df38 Fixed packet injector 2023-02-14 17:42:52 +00:00
Auxilor
6e8dc1d729 Packet refactor 2023-02-14 17:26:01 +00:00
Auxilor
a8556008f9 Fixed EcoPlugin compiler warnings 2023-02-14 16:53:45 +00:00
Auxilor
ab18a8bd29 Updated to 6.51.0 2023-02-14 16:49:16 +00:00
Auxilor
a053f512f8 Moved away from ProtocolLib 2023-02-14 16:49:04 +00:00
Auxilor
add5390787 Removed ProtocolLib dependency 2023-02-14 12:29:55 +00:00
Auxilor
49687f9a91 Updated to 6.50.3 2023-02-05 16:32:56 +00:00
Auxilor
5480c70f8c Fixed dynamic commands 2023-02-05 16:32:48 +00:00
110 changed files with 1240 additions and 1353 deletions

View File

@@ -31,6 +31,7 @@ eco comes packed with all the tools you need in your plugins:
- Yaml/JSON/TOML config system - Yaml/JSON/TOML config system
- Persistent data storage API with Yaml/MySQL/MongoDB support - Persistent data storage API with Yaml/MySQL/MongoDB support
- Packet item display system - Packet item display system
- Lightweight event loop based packet API
- Entity AI API with near-1:1 NMS mappings - Entity AI API with near-1:1 NMS mappings
- More events - More events
- Extension API, essentially plugins for plugins - Extension API, essentially plugins for plugins
@@ -52,7 +53,6 @@ eco comes packed with all the tools you need in your plugins:
- And much more - And much more
# For server owners # For server owners
- Requires ProtocolLib to be installed: get the latest version [here](https://www.spigotmc.org/resources/protocollib.1997/)
- Supports 1.17+ - Supports 1.17+
## Downloads ## Downloads

View File

@@ -13,27 +13,30 @@ import java.util.Collections;
/** /**
* Wrapper class for ProtocolLib packets. * Wrapper class for ProtocolLib packets.
*
* @deprecated ProtocolLib is no longer used by eco. Use {@link com.willfp.eco.core.packet.PacketListener} instead.
*/ */
@Deprecated(since = "6.51.0")
public abstract class AbstractPacketAdapter extends PacketAdapter { public abstract class AbstractPacketAdapter extends PacketAdapter {
/** /**
* The packet type to listen for. * The handle type to listen for.
*/ */
private final PacketType type; private final PacketType type;
/** /**
* Whether the packet adapter should be registered after the server has loaded. * Whether the handle adapter should be registered after the server has loaded.
* <p> * <p>
* Useful for monitor priority adapters that <b>must</b> be ran last. * Useful for monitor priority adapters that <b>must</b> be ran last.
*/ */
private final boolean postLoad; private final boolean postLoad;
/** /**
* Create a new packet adapter for a specified plugin and type. * Create a new handle adapter for a specified plugin and type.
* *
* @param plugin The plugin that ProtocolLib should mark as the owner. * @param plugin The plugin that ProtocolLib should mark as the owner.
* @param type The {@link PacketType} to listen for. * @param type The {@link PacketType} to listen for.
* @param priority The priority at which the adapter should be ran on packet send/receive. * @param priority The priority at which the adapter should be ran on handle send/receive.
* @param postLoad If the packet adapter should be registered after the server has loaded. * @param postLoad If the handle adapter should be registered after the server has loaded.
*/ */
protected AbstractPacketAdapter(@NotNull final EcoPlugin plugin, protected AbstractPacketAdapter(@NotNull final EcoPlugin plugin,
@NotNull final PacketType type, @NotNull final PacketType type,
@@ -45,11 +48,11 @@ public abstract class AbstractPacketAdapter extends PacketAdapter {
} }
/** /**
* Create a new packet adapter for a specified plugin and type. * Create a new handle adapter for a specified plugin and type.
* *
* @param plugin The plugin that ProtocolLib should mark as the owner. * @param plugin The plugin that ProtocolLib should mark as the owner.
* @param type The {@link PacketType} to listen for. * @param type The {@link PacketType} to listen for.
* @param postLoad If the packet adapter should be registered after the server has loaded. * @param postLoad If the handle adapter should be registered after the server has loaded.
*/ */
protected AbstractPacketAdapter(@NotNull final EcoPlugin plugin, protected AbstractPacketAdapter(@NotNull final EcoPlugin plugin,
@NotNull final PacketType type, @NotNull final PacketType type,
@@ -58,9 +61,9 @@ public abstract class AbstractPacketAdapter extends PacketAdapter {
} }
/** /**
* The code that should be executed once the packet has been received. * The code that should be executed once the handle has been received.
* *
* @param packet The packet. * @param packet The handle.
* @param player The player. * @param player The player.
* @param event The event. * @param event The event.
*/ */
@@ -71,9 +74,9 @@ public abstract class AbstractPacketAdapter extends PacketAdapter {
} }
/** /**
* THe code that should be executed once the packet has been sent. * THe code that should be executed once the handle has been sent.
* *
* @param packet The packet. * @param packet The handle.
* @param player The player. * @param player The player.
* @param event The event. * @param event The event.
*/ */
@@ -84,7 +87,7 @@ public abstract class AbstractPacketAdapter extends PacketAdapter {
} }
/** /**
* Boilerplate to assert that the packet is of the specified type. * Boilerplate to assert that the handle is of the specified type.
* *
* @param event The ProtocolLib event. * @param event The ProtocolLib event.
*/ */
@@ -102,7 +105,7 @@ public abstract class AbstractPacketAdapter extends PacketAdapter {
} }
/** /**
* Boilerplate to assert that the packet is of the specified type. * Boilerplate to assert that the handle is of the specified type.
* *
* @param event The ProtocolLib event. * @param event The ProtocolLib event.
*/ */
@@ -125,7 +128,7 @@ public abstract class AbstractPacketAdapter extends PacketAdapter {
} }
/** /**
* Register the packet adapter with ProtocolLib. * Register the handle adapter with ProtocolLib.
*/ */
public final void register() { public final void register() {
if (!ProtocolLibrary.getProtocolManager().getPacketListeners().contains(this)) { if (!ProtocolLibrary.getProtocolManager().getPacketListeners().contains(this)) {
@@ -134,7 +137,7 @@ public abstract class AbstractPacketAdapter extends PacketAdapter {
} }
/** /**
* Get if the packet adapter should be loaded last. * Get if the handle adapter should be loaded last.
* *
* @return If post load. * @return If post load.
*/ */

View File

@@ -26,13 +26,13 @@ import com.willfp.eco.core.gui.slot.SlotBuilder;
import com.willfp.eco.core.gui.slot.functional.SlotProvider; import com.willfp.eco.core.gui.slot.functional.SlotProvider;
import com.willfp.eco.core.items.TestableItem; import com.willfp.eco.core.items.TestableItem;
import com.willfp.eco.core.math.MathContext; import com.willfp.eco.core.math.MathContext;
import com.willfp.eco.core.packet.Packet;
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;
import net.kyori.adventure.platform.bukkit.BukkitAudiences; import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.command.CommandMap;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.Mob; import org.bukkit.entity.Mob;
@@ -547,19 +547,21 @@ public interface Eco {
*/ */
void syncCommands(); void syncCommands();
/**
* Get the command map.
*
* @return The command map.
*/
@NotNull CommandMap getCommandMap();
/** /**
* Unregister a command. * Unregister a command.
* *
* @param command The command. * @param command The command.
*/ */
void unregisterCommand(@NotNull final PluginCommand command); void unregisterCommand(@NotNull PluginCommandBase command);
/**
* Send a packet.
*
* @param player The player.
* @param packet The packet.
*/
void sendPacket(@NotNull Player player,
@NotNull Packet packet);
/** /**
* Get the instance of eco; the bridge between the api frontend and the implementation backend. * Get the instance of eco; the bridge between the api frontend and the implementation backend.

View File

@@ -13,6 +13,7 @@ import com.willfp.eco.core.factory.MetadataValueFactory;
import com.willfp.eco.core.factory.NamespacedKeyFactory; import com.willfp.eco.core.factory.NamespacedKeyFactory;
import com.willfp.eco.core.factory.RunnableFactory; import com.willfp.eco.core.factory.RunnableFactory;
import com.willfp.eco.core.integrations.IntegrationLoader; import com.willfp.eco.core.integrations.IntegrationLoader;
import com.willfp.eco.core.packet.PacketListener;
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;
import com.willfp.eco.core.web.UpdateChecker; import com.willfp.eco.core.web.UpdateChecker;
@@ -52,7 +53,7 @@ import java.util.stream.Collectors;
* <b>IMPORTANT: When reloading a plugin, all runnables / tasks will * <b>IMPORTANT: When reloading a plugin, all runnables / tasks will
* be cancelled.</b> * be cancelled.</b>
*/ */
@SuppressWarnings("unused") @SuppressWarnings({"unused", "DeprecatedIsStillUsed", "deprecation", "RedundantSuppression"})
public abstract class EcoPlugin extends JavaPlugin implements PluginLike { public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
/** /**
* The polymart resource ID of the plugin. * The polymart resource ID of the plugin.
@@ -422,13 +423,16 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
Prerequisite.update(); Prerequisite.update();
this.loadPacketAdapters().forEach(abstractPacketAdapter -> { if (Prerequisite.HAS_PROTOCOLLIB.isMet()) {
if (!abstractPacketAdapter.isPostLoad()) { this.loadPacketAdapters().forEach(abstractPacketAdapter -> {
abstractPacketAdapter.register(); if (!abstractPacketAdapter.isPostLoad()) {
} abstractPacketAdapter.register();
}); }
});
}
this.loadListeners().forEach(listener -> this.getEventManager().registerListener(listener)); this.loadListeners().forEach(listener -> this.getEventManager().registerListener(listener));
this.loadPacketListeners().forEach(listener -> this.getEventManager().registerPacketListener(listener));
this.loadPluginCommands().forEach(PluginCommand::register); this.loadPluginCommands().forEach(PluginCommand::register);
@@ -520,11 +524,13 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
Display.registerDisplayModule(this.getDisplayModule()); Display.registerDisplayModule(this.getDisplayModule());
} }
this.loadPacketAdapters().forEach(abstractPacketAdapter -> { if (Prerequisite.HAS_PROTOCOLLIB.isMet()) {
if (abstractPacketAdapter.isPostLoad()) { this.loadPacketAdapters().forEach(abstractPacketAdapter -> {
abstractPacketAdapter.register(); if (abstractPacketAdapter.isPostLoad()) {
} abstractPacketAdapter.register();
}); }
});
}
if (!Prerequisite.HAS_PAPER.isMet()) { if (!Prerequisite.HAS_PAPER.isMet()) {
this.getLogger().severe(""); this.getLogger().severe("");
@@ -681,16 +687,27 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
} }
/** /**
* ProtocolLib packet adapters to be registered. * ProtocolLib handle adapters to be registered.
* <p> * <p>
* If the plugin does not require ProtocolLib this can be left empty. * If the plugin does not require ProtocolLib this can be left empty.
* *
* @return A list of packet adapters. * @return A list of handle adapters.
* @deprecated Use {@link #loadPacketListeners()} instead.
*/ */
@Deprecated(since = "6.51.0")
protected List<AbstractPacketAdapter> loadPacketAdapters() { protected List<AbstractPacketAdapter> loadPacketAdapters() {
return new ArrayList<>(); return new ArrayList<>();
} }
/**
* Packet Listeners to be registered.
*
* @return A list of handle listeners.
*/
protected List<PacketListener> loadPacketListeners() {
return new ArrayList<>();
}
/** /**
* All listeners to be registered. * All listeners to be registered.
* *

View File

@@ -30,6 +30,14 @@ public class Prerequisite {
"Requires server to be running paper (or a fork)" "Requires server to be running paper (or a fork)"
); );
/**
* Requires the server to be running an implementation of paper.
*/
public static final Prerequisite HAS_PROTOCOLLIB = new Prerequisite(
() -> ClassUtils.exists("com.comphenix.protocol.events.PacketAdapter"),
"Requires server to have ProtocolLib"
);
/** /**
* Requires the server to have vault installed. * Requires the server to have vault installed.
* *

View File

@@ -1,6 +1,7 @@
package com.willfp.eco.core.display; package com.willfp.eco.core.display;
import com.willfp.eco.core.fast.FastItemStack; import com.willfp.eco.core.fast.FastItemStack;
import com.willfp.eco.core.integrations.guidetection.GUIDetectionManager;
import com.willfp.eco.util.NamespacedKeyUtils; import com.willfp.eco.util.NamespacedKeyUtils;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@@ -18,6 +19,9 @@ import java.util.TreeMap;
/** /**
* Utility class to manage client-side item display. * Utility class to manage client-side item display.
* <p>
* Packet display is not done on the main thread, so make sure
* all your modules are thread-safe.
*/ */
public final class Display { public final class Display {
/** /**
@@ -71,7 +75,7 @@ public final class Display {
ItemStack original = itemStack.clone(); ItemStack original = itemStack.clone();
Inventory inventory = player == null ? null : player.getOpenInventory().getTopInventory(); Inventory inventory = player == null ? null : player.getOpenInventory().getTopInventory();
boolean inInventory = inventory != null && inventory.contains(original); boolean inInventory = inventory != null && inventory.contains(original);
boolean inGui = inventory != null && inventory.getHolder() == null; boolean inGui = player != null && GUIDetectionManager.hasGUIOpen(player);
DisplayProperties properties = new DisplayProperties( DisplayProperties properties = new DisplayProperties(
inInventory, inInventory,

View File

@@ -8,6 +8,8 @@ import org.jetbrains.annotations.Nullable;
/** /**
* Class for all plugin-specific client-side item display modules. * Class for all plugin-specific client-side item display modules.
* <p>
* Display modules are called in the netty thread, so make sure they are thread-safe.
*/ */
public abstract class DisplayModule { public abstract class DisplayModule {
/** /**

View File

@@ -13,10 +13,10 @@ import org.jetbrains.annotations.Nullable;
/** /**
* Avoid entities. * Avoid entities.
* *
* @param entity The entity type to avoid. * @param entity The entity type to avoid.
* @param distance The distance to flee to. * @param distance The distance to flee to.
* @param slowSpeed The slow movement speed. * @param slowSpeed The slow movement speed.
* @param fastSpeed The fast movement speed. * @param fastSpeed The fast movement speed.
*/ */
public record EntityGoalAvoidEntity( public record EntityGoalAvoidEntity(
@NotNull TestableEntity entity, @NotNull TestableEntity entity,
@@ -45,23 +45,14 @@ public record EntityGoalAvoidEntity(
return null; return null;
} }
try { TestableEntity entity = Entities.lookup(config.getString("entity"));
TestableEntity entity = Entities.lookup(config.getString("entity"));
return new EntityGoalAvoidEntity( return new EntityGoalAvoidEntity(
entity, entity,
config.getDouble("distance"), config.getDouble("distance"),
config.getDouble("slowSpeed"), config.getDouble("slowSpeed"),
config.getDouble("fastSpeed") config.getDouble("fastSpeed")
); );
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -34,18 +34,9 @@ public record EntityGoalBreakDoors(
return null; return null;
} }
try { return new EntityGoalBreakDoors(
return new EntityGoalBreakDoors( config.getInt("ticks")
config.getInt("ticks") );
);
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -34,18 +34,9 @@ public record EntityGoalBreed(
return null; return null;
} }
try { return new EntityGoalBreed(
return new EntityGoalBreed( config.getDouble("speed")
config.getDouble("speed") );
);
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -37,19 +37,10 @@ public record EntityGoalCatLieOnBed(
return null; return null;
} }
try { return new EntityGoalCatLieOnBed(
return new EntityGoalCatLieOnBed( config.getDouble("speed"),
config.getDouble("speed"), config.getInt("range")
config.getInt("range") );
);
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -34,18 +34,9 @@ public record EntityGoalCatSitOnBed(
return null; return null;
} }
try { return new EntityGoalCatSitOnBed(
return new EntityGoalCatSitOnBed( config.getDouble("speed")
config.getDouble("speed") );
);
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -34,18 +34,9 @@ public record EntityGoalFleeSun(
return null; return null;
} }
try { return new EntityGoalFleeSun(
return new EntityGoalFleeSun( config.getDouble("speed")
config.getDouble("speed") );
);
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -40,20 +40,11 @@ public record EntityGoalFollowMobs(
return null; return null;
} }
try { return new EntityGoalFollowMobs(
return new EntityGoalFollowMobs( config.getDouble("speed"),
config.getDouble("speed"), config.getDouble("minDistance"),
config.getDouble("minDistance"), config.getDouble("maxDistance")
config.getDouble("maxDistance") );
);
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -42,20 +42,11 @@ public record EntityGoalInteract(
return null; return null;
} }
try { return new EntityGoalInteract(
return new EntityGoalInteract( Entities.lookup(config.getString("target")),
Entities.lookup(config.getString("target")), config.getDouble("range"),
config.getDouble("range"), config.getDouble("chance")
config.getDouble("chance") );
);
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -34,18 +34,9 @@ public record EntityGoalLeapAtTarget(
return null; return null;
} }
try { return new EntityGoalLeapAtTarget(
return new EntityGoalLeapAtTarget( config.getDouble("velocity")
config.getDouble("velocity") );
);
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -37,19 +37,10 @@ public record EntityGoalLookAtPlayer(
return null; return null;
} }
try { return new EntityGoalLookAtPlayer(
return new EntityGoalLookAtPlayer( config.getDouble("range"),
config.getDouble("range"), config.getDouble("chance")
config.getDouble("chance") );
);
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -37,19 +37,10 @@ public record EntityGoalMeleeAttack(
return null; return null;
} }
try { return new EntityGoalMeleeAttack(
return new EntityGoalMeleeAttack( config.getDouble("speed"),
config.getDouble("speed"), config.getBool("pauseWhenMobIdle")
config.getBool("pauseWhenMobIdle") );
);
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -37,19 +37,10 @@ public record EntityGoalMoveBackToVillage(
return null; return null;
} }
try { return new EntityGoalMoveBackToVillage(
return new EntityGoalMoveBackToVillage( config.getDouble("speed"),
config.getDouble("speed"), config.getBool("canDespawn")
config.getBool("canDespawn") );
);
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -43,21 +43,12 @@ public record EntityGoalMoveThroughVillage(
return null; return null;
} }
try { return new EntityGoalMoveThroughVillage(
return new EntityGoalMoveThroughVillage( config.getDouble("speed"),
config.getDouble("speed"), config.getBool("onlyAtNight"),
config.getBool("onlyAtNight"), config.getInt("distance"),
config.getInt("distance"), config.getBool("canPassThroughDoors")
config.getBool("canPassThroughDoors") );
);
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -34,18 +34,9 @@ public record EntityGoalMoveTowardsRestriction(
return null; return null;
} }
try { return new EntityGoalMoveTowardsRestriction(
return new EntityGoalMoveTowardsRestriction( config.getDouble("speed")
config.getDouble("speed") );
);
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -37,19 +37,10 @@ public record EntityGoalMoveTowardsTarget(
return null; return null;
} }
try { return new EntityGoalMoveTowardsTarget(
return new EntityGoalMoveTowardsTarget( config.getDouble("speed"),
config.getDouble("speed"), config.getDouble("maxDistance")
config.getDouble("maxDistance") );
);
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -34,18 +34,9 @@ public record EntityGoalOpenDoors(
return null; return null;
} }
try { return new EntityGoalOpenDoors(
return new EntityGoalOpenDoors( config.getBool("delayClosing")
config.getBool("delayClosing") );
);
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -34,18 +34,9 @@ public record EntityGoalPanic(
return null; return null;
} }
try { return new EntityGoalPanic(
return new EntityGoalPanic( config.getDouble("speed")
config.getDouble("speed") );
);
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -40,20 +40,11 @@ public record EntityGoalRandomStroll(
return null; return null;
} }
try { return new EntityGoalRandomStroll(
return new EntityGoalRandomStroll( config.getDouble("speed"),
config.getDouble("speed"), config.getInt("interval"),
config.getInt("interval"), config.getBool("canDespawn")
config.getBool("canDespawn") );
);
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -37,19 +37,10 @@ public record EntityGoalRandomSwimming(
return null; return null;
} }
try { return new EntityGoalRandomSwimming(
return new EntityGoalRandomSwimming( config.getDouble("speed"),
config.getDouble("speed"), config.getInt("interval")
config.getInt("interval") );
);
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -45,21 +45,12 @@ public record EntityGoalRangedAttack(
return null; return null;
} }
try { return new EntityGoalRangedAttack(
return new EntityGoalRangedAttack( config.getDouble("speed"),
config.getDouble("speed"), config.getInt("minInterval"),
config.getInt("minInterval"), config.getInt("maxInterval"),
config.getInt("maxInterval"), config.getDouble("range")
config.getDouble("range") );
);
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -13,9 +13,9 @@ import org.jetbrains.annotations.Nullable;
* <p> * <p>
* Only supports monsters that have bow attacks. * Only supports monsters that have bow attacks.
* *
* @param speed The speed. * @param speed The speed.
* @param interval The interval between attacks (in ticks). * @param interval The interval between attacks (in ticks).
* @param range The max range at which to attack. * @param range The max range at which to attack.
*/ */
public record EntityGoalRangedBowAttack( public record EntityGoalRangedBowAttack(
double speed, double speed,
@@ -42,20 +42,11 @@ public record EntityGoalRangedBowAttack(
return null; return null;
} }
try { return new EntityGoalRangedBowAttack(
return new EntityGoalRangedBowAttack( config.getDouble("speed"),
config.getDouble("speed"), config.getInt("interval"),
config.getInt("interval"), config.getDouble("range")
config.getDouble("range") );
);
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -39,19 +39,10 @@ public record EntityGoalRangedCrossbowAttack(
return null; return null;
} }
try { return new EntityGoalRangedCrossbowAttack(
return new EntityGoalRangedCrossbowAttack( config.getDouble("speed"),
config.getDouble("speed"), config.getDouble("range")
config.getDouble("range") );
);
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -34,18 +34,9 @@ public record EntityGoalStrollThroughVillage(
return null; return null;
} }
try { return new EntityGoalStrollThroughVillage(
return new EntityGoalStrollThroughVillage( config.getInt("searchRange")
config.getInt("searchRange") );
);
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -58,25 +58,16 @@ public record EntityGoalTempt(
return null; return null;
} }
try { Collection<TestableItem> items = config.getStrings("items").stream()
Collection<TestableItem> items = config.getStrings("items").stream() .map(Items::lookup)
.map(Items::lookup) .filter(it -> !(it instanceof EmptyTestableItem))
.filter(it -> !(it instanceof EmptyTestableItem)) .collect(Collectors.toList());
.collect(Collectors.toList());
return new EntityGoalTempt( return new EntityGoalTempt(
config.getDouble("speed"), config.getDouble("speed"),
items, items,
config.getBool("canBeScared") config.getBool("canBeScared")
); );
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -48,22 +48,13 @@ public record EntityGoalUseItem(
return null; return null;
} }
try { TestableEntity filter = Entities.lookup(config.getString("condition"));
TestableEntity filter = Entities.lookup(config.getString("condition"));
return new EntityGoalUseItem( return new EntityGoalUseItem(
Items.lookup(config.getString("item")).getItem(), Items.lookup(config.getString("item")).getItem(),
Sound.valueOf(config.getString("sound").toUpperCase()), Sound.valueOf(config.getString("sound").toUpperCase()),
filter::matches filter::matches
); );
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -34,18 +34,9 @@ public record EntityGoalWaterAvoidingRandomFlying(
return null; return null;
} }
try { return new EntityGoalWaterAvoidingRandomFlying(
return new EntityGoalWaterAvoidingRandomFlying( config.getDouble("speed")
config.getDouble("speed") );
);
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -37,19 +37,10 @@ public record EntityGoalWaterAvoidingRandomStroll(
return null; return null;
} }
try { return new EntityGoalWaterAvoidingRandomStroll(
return new EntityGoalWaterAvoidingRandomStroll( config.getDouble("speed"),
config.getDouble("speed"), config.getDouble("chance")
config.getDouble("chance") );
);
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -34,18 +34,9 @@ public record EntityGoalWolfBeg(
return null; return null;
} }
try { return new EntityGoalWolfBeg(
return new EntityGoalWolfBeg( config.getDouble("distance")
config.getDouble("distance") );
);
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -37,18 +37,9 @@ public record TargetGoalHurtBy(
return null; return null;
} }
try { return new TargetGoalHurtBy(
return new TargetGoalHurtBy( Entities.lookup(config.getString("blacklist"))
Entities.lookup(config.getString("blacklist")) );
);
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -63,32 +63,23 @@ public record TargetGoalNearestAttackable(
return null; return null;
} }
try { if (config.has("targetFilter")) {
if (config.has("targetFilter")) { TestableEntity filter = Entities.lookup(config.getString("targetFilter"));
TestableEntity filter = Entities.lookup(config.getString("targetFilter"));
return new TargetGoalNearestAttackable( return new TargetGoalNearestAttackable(
Entities.lookup(config.getString("target")), Entities.lookup(config.getString("target")),
config.getBool("checkVisibility"), config.getBool("checkVisibility"),
config.getBool("checkCanNavigate"), config.getBool("checkCanNavigate"),
config.getInt("reciprocalChance"), config.getInt("reciprocalChance"),
filter::matches filter::matches
); );
} else { } else {
return new TargetGoalNearestAttackable( return new TargetGoalNearestAttackable(
Entities.lookup(config.getString("target")), Entities.lookup(config.getString("target")),
config.getBool("checkVisibility"), config.getBool("checkVisibility"),
config.getBool("checkCanNavigate"), config.getBool("checkCanNavigate"),
config.getInt("reciprocalChance") config.getInt("reciprocalChance")
); );
}
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
} }
} }

View File

@@ -63,32 +63,23 @@ public record TargetGoalNearestAttackableWitch(
return null; return null;
} }
try { if (config.has("targetFilter")) {
if (config.has("targetFilter")) { TestableEntity filter = Entities.lookup(config.getString("targetFilter"));
TestableEntity filter = Entities.lookup(config.getString("targetFilter"));
return new TargetGoalNearestAttackableWitch( return new TargetGoalNearestAttackableWitch(
Entities.lookup(config.getString("target")), Entities.lookup(config.getString("target")),
config.getBool("checkVisibility"), config.getBool("checkVisibility"),
config.getBool("checkCanNavigate"), config.getBool("checkCanNavigate"),
config.getInt("reciprocalChance"), config.getInt("reciprocalChance"),
filter::matches filter::matches
); );
} else { } else {
return new TargetGoalNearestAttackableWitch( return new TargetGoalNearestAttackableWitch(
Entities.lookup(config.getString("target")), Entities.lookup(config.getString("target")),
config.getBool("checkVisibility"), config.getBool("checkVisibility"),
config.getBool("checkCanNavigate"), config.getBool("checkCanNavigate"),
config.getInt("reciprocalChance") config.getInt("reciprocalChance")
); );
}
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
} }
} }

View File

@@ -53,28 +53,19 @@ public record TargetGoalNearestHealableRaider(
return null; return null;
} }
try { if (config.has("targetFilter")) {
if (config.has("targetFilter")) { TestableEntity filter = Entities.lookup(config.getString("targetFilter"));
TestableEntity filter = Entities.lookup(config.getString("targetFilter"));
return new TargetGoalNearestHealableRaider( return new TargetGoalNearestHealableRaider(
Entities.lookup(config.getString("target")), Entities.lookup(config.getString("target")),
config.getBool("checkVisibility"), config.getBool("checkVisibility"),
filter::matches filter::matches
); );
} else { } else {
return new TargetGoalNearestHealableRaider( return new TargetGoalNearestHealableRaider(
Entities.lookup(config.getString("target")), Entities.lookup(config.getString("target")),
config.getBool("checkVisibility") config.getBool("checkVisibility")
); );
}
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
} }
} }

View File

@@ -53,28 +53,19 @@ public record TargetGoalNonTameRandom(
return null; return null;
} }
try { if (config.has("targetFilter")) {
if (config.has("targetFilter")) { TestableEntity filter = Entities.lookup(config.getString("targetFilter"));
TestableEntity filter = Entities.lookup(config.getString("targetFilter"));
return new TargetGoalNonTameRandom( return new TargetGoalNonTameRandom(
Entities.lookup(config.getString("target")), Entities.lookup(config.getString("target")),
config.getBool("checkVisibility"), config.getBool("checkVisibility"),
filter::matches filter::matches
); );
} else { } else {
return new TargetGoalNonTameRandom( return new TargetGoalNonTameRandom(
Entities.lookup(config.getString("target")), Entities.lookup(config.getString("target")),
config.getBool("checkVisibility") config.getBool("checkVisibility")
); );
}
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
} }
} }

View File

@@ -36,18 +36,9 @@ public record TargetGoalResetUniversalAnger(
return null; return null;
} }
try { return new TargetGoalResetUniversalAnger(
return new TargetGoalResetUniversalAnger( config.getBool("triggerOthers")
config.getBool("triggerOthers") );
);
} catch (Exception e) {
/*
Exceptions could be caused by configs having values of a wrong type,
invalid enum parameters, etc. Serializers shouldn't throw exceptions,
so we encapsulate them as null.
*/
return null;
}
} }
@NotNull @NotNull

View File

@@ -1,5 +1,6 @@
package com.willfp.eco.core.events; package com.willfp.eco.core.events;
import com.willfp.eco.core.packet.PacketListener;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -25,4 +26,11 @@ public interface EventManager {
* Unregister all listeners associated with the plugin. * Unregister all listeners associated with the plugin.
*/ */
void unregisterAllListeners(); void unregisterAllListeners();
/**
* Register a packet listener.
*
* @param listener The listener.
*/
void registerPacketListener(@NotNull PacketListener listener);
} }

View File

@@ -0,0 +1,18 @@
package com.willfp.eco.core.integrations.guidetection;
import com.willfp.eco.core.integrations.Integration;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
/**
* Wrapper class for GUI integrations.
*/
public interface GUIDetectionIntegration extends Integration {
/**
* Determine if a player is in a GUI.
*
* @param player The player.
* @return If the player is in a GUI.
*/
boolean hasGUIOpen(@NotNull final Player player);
}

View File

@@ -0,0 +1,52 @@
package com.willfp.eco.core.integrations.guidetection;
import com.willfp.eco.util.MenuUtils;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.HashSet;
import java.util.Set;
/**
* Class to handle GUI detection.
*/
public final class GUIDetectionManager {
/**
* A set of all registered integrations.
*/
private static final Set<GUIDetectionIntegration> REGISTERED = new HashSet<>();
/**
* Register a new integration.
*
* @param integration The integration to register.
*/
public static void register(@NotNull final GUIDetectionIntegration integration) {
REGISTERED.removeIf(it -> it.getPluginName().equalsIgnoreCase(integration.getPluginName()));
REGISTERED.add(integration);
}
/**
* Get if a player is in a GUI.
*
* @param player The player.
* @return If the player has a GUI open.
*/
public static boolean hasGUIOpen(@NotNull final Player player) {
if (MenuUtils.getOpenMenu(player) != null) {
return true;
}
for (GUIDetectionIntegration integration : REGISTERED) {
if (integration.hasGUIOpen(player)) {
return true;
}
}
return false;
}
private GUIDetectionManager() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}
}

View File

@@ -0,0 +1,21 @@
package com.willfp.eco.core.packet;
import com.willfp.eco.core.Eco;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
/**
* Represents a packet.
*
* @param handle The NMS handle.
*/
public record Packet(@NotNull Object handle) {
/**
* Send to a player.
*
* @param player The player.
*/
void send(@NotNull final Player player) {
Eco.get().sendPacket(player, this);
}
}

View File

@@ -0,0 +1,67 @@
package com.willfp.eco.core.packet;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.jetbrains.annotations.NotNull;
/**
* Represents a packet being sent or received.
*/
public class PacketEvent implements Cancellable {
/**
* The packet.
*/
private final Packet packet;
/**
* The player.
*/
private final Player player;
/**
* If the event should be cancelled.
*/
private boolean cancelled = false;
/**
* Create a new packet event.
*
* @param packet The packet.
* @param player The player.
*/
public PacketEvent(@NotNull final Packet packet,
@NotNull final Player player) {
this.packet = packet;
this.player = player;
}
/**
* Get the packet.
*
* @return The packet.
*/
@NotNull
public Packet getPacket() {
return packet;
}
/**
* Get the player.
*
* @return The player.
*/
@NotNull
public Player getPlayer() {
return player;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(final boolean cancelled) {
this.cancelled = cancelled;
}
}

View File

@@ -0,0 +1,35 @@
package com.willfp.eco.core.packet;
import org.jetbrains.annotations.NotNull;
/**
* Listens to packets.
*/
public interface PacketListener {
/**
* Called when a handle is sent.
*
* @param event The event.
*/
default void onSend(@NotNull final PacketEvent event) {
// Override when needed.
}
/**
* Called when a handle is received.
*
* @param event The event.
*/
default void onReceive(@NotNull final PacketEvent event) {
// Override when needed.
}
/**
* Get the priority of the listener.
*
* @return The priority.
*/
default PacketPriority getPriority() {
return PacketPriority.NORMAL;
}
}

View File

@@ -0,0 +1,31 @@
package com.willfp.eco.core.packet;
/**
* The priority (order) of packet listeners.
*/
public enum PacketPriority {
/**
* Ran first.
*/
LOWEST,
/**
* Ran second.
*/
LOW,
/**
* Ran third.
*/
NORMAL,
/**
* Ran fourth.
*/
HIGH,
/**
* Ran last.
*/
HIGHEST
}

View File

@@ -0,0 +1,9 @@
@file:JvmName("PacketExtensions")
package com.willfp.eco.core.packet
import org.bukkit.entity.Player
/** @see Packet.send */
fun Player.sendPacket(packet: Packet) =
packet.send(this)

View File

@@ -8,6 +8,9 @@ import org.bukkit.command.TabCompleter
class DelegatedBukkitCommand( class DelegatedBukkitCommand(
private val delegate: EcoPluginCommand private val delegate: EcoPluginCommand
) : Command(delegate.name), TabCompleter, PluginIdentifiableCommand { ) : Command(delegate.name), TabCompleter, PluginIdentifiableCommand {
private var _aliases: List<String>? = null
private var _description: String? = null
override fun execute(sender: CommandSender, label: String, args: Array<out String>?): Boolean { override fun execute(sender: CommandSender, label: String, args: Array<out String>?): Boolean {
return delegate.onCommand(sender, this, label, args) return delegate.onCommand(sender, this, label, args)
} }
@@ -23,6 +26,16 @@ class DelegatedBukkitCommand(
override fun getPlugin() = delegate.plugin override fun getPlugin() = delegate.plugin
override fun getPermission() = delegate.permission override fun getPermission() = delegate.permission
override fun getDescription() = delegate.description ?: "" override fun getDescription() = _description ?: delegate.description ?: ""
override fun getAliases(): List<String> = delegate.aliases override fun getAliases(): List<String> = _aliases ?: delegate.aliases
override fun setDescription(description: String): Command {
this._description = description
return this
}
override fun setAliases(aliases: List<String>): Command {
this._aliases = aliases
return this
}
} }

View File

@@ -17,29 +17,25 @@ class EcoPluginCommand(
override fun register() { override fun register() {
val command = Bukkit.getPluginCommand(name) val command = Bukkit.getPluginCommand(name)
val knownDescription = command?.description ?: description ?: ""
val knownAliases = command?.aliases ?: aliases
if (command == null) { if (command == null) {
unregister() unregister()
commandMap.register(plugin.name.lowercase(), DelegatedBukkitCommand(this)) commandMap.register(plugin.name.lowercase(), DelegatedBukkitCommand(this))
} else { } else {
command.setExecutor(this) command.setExecutor(this)
command.tabCompleter = this
command.description = knownDescription
description?.let { command.aliases = knownAliases
command.setDescription(it)
}
if (aliases.isNotEmpty()) {
command.aliases = aliases
}
} }
Eco.get().syncCommands() Eco.get().syncCommands()
} }
override fun unregister() { override fun unregister() {
val found = commandMap.getCommand(name) commandMap.getCommand(name)?.unregister(commandMap)
found?.unregister(commandMap) Eco.get().unregisterCommand(this)
Eco.get().syncCommands() Eco.get().syncCommands()
} }

View File

@@ -2,11 +2,38 @@ package com.willfp.eco.internal.events
import com.willfp.eco.core.EcoPlugin import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.events.EventManager import com.willfp.eco.core.events.EventManager
import com.willfp.eco.core.packet.PacketEvent
import com.willfp.eco.core.packet.PacketListener
import com.willfp.eco.core.packet.PacketPriority
import org.bukkit.Bukkit import org.bukkit.Bukkit
import org.bukkit.event.HandlerList import org.bukkit.event.HandlerList
import org.bukkit.event.Listener import org.bukkit.event.Listener
class EcoEventManager (private val plugin: EcoPlugin) : EventManager {
private class RegisteredPacketListener(
val plugin: EcoPlugin,
val listener: PacketListener
)
private val listeners = mutableMapOf<PacketPriority, MutableList<RegisteredPacketListener>>()
fun PacketEvent.handleSend() {
for (priority in PacketPriority.values()) {
for (listener in listeners[priority] ?: continue) {
listener.listener.onSend(this)
}
}
}
fun PacketEvent.handleReceive() {
for (priority in PacketPriority.values()) {
for (listener in listeners[priority] ?: continue) {
listener.listener.onReceive(this)
}
}
}
class EcoEventManager(private val plugin: EcoPlugin) : EventManager {
override fun registerListener(listener: Listener) { override fun registerListener(listener: Listener) {
Bukkit.getPluginManager().registerEvents(listener, plugin) Bukkit.getPluginManager().registerEvents(listener, plugin)
} }
@@ -17,5 +44,17 @@ class EcoEventManager (private val plugin: EcoPlugin) : EventManager {
override fun unregisterAllListeners() { override fun unregisterAllListeners() {
HandlerList.unregisterAll(plugin) HandlerList.unregisterAll(plugin)
for (value in listeners.values) {
value.removeIf { it.plugin == plugin }
}
} }
}
override fun registerPacketListener(listener: PacketListener) {
listeners.getOrPut(listener.priority) { mutableListOf() }.add(
RegisteredPacketListener(
plugin,
listener
)
)
}
}

View File

@@ -6,12 +6,14 @@ import com.willfp.eco.internal.spigot.proxy.common.ai.EntityGoalFactory
import com.willfp.eco.internal.spigot.proxy.common.ai.TargetGoalFactory import com.willfp.eco.internal.spigot.proxy.common.ai.TargetGoalFactory
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.LivingEntity import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.PathfinderMob import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import org.bukkit.Material import org.bukkit.Material
import org.bukkit.NamespacedKey import org.bukkit.NamespacedKey
import org.bukkit.entity.Mob import org.bukkit.entity.Mob
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import org.bukkit.persistence.PersistentDataContainer import org.bukkit.persistence.PersistentDataContainer
@@ -63,6 +65,9 @@ fun CompoundTag.makePdc(base: Boolean = false): PersistentDataContainer =
fun CompoundTag.setPdc(pdc: PersistentDataContainer?, item: net.minecraft.world.item.ItemStack? = null) = fun CompoundTag.setPdc(pdc: PersistentDataContainer?, item: net.minecraft.world.item.ItemStack? = null) =
impl.setPdc(this, pdc, item) impl.setPdc(this, pdc, item)
fun Player.toNMS(): ServerPlayer =
impl.toNMS(this)
interface CommonsProvider { interface CommonsProvider {
val nbtTagString: Int val nbtTagString: Int
@@ -94,6 +99,8 @@ interface CommonsProvider {
fun itemToMaterial(item: Item): Material fun itemToMaterial(item: Item): Material
fun toNMS(player: Player): ServerPlayer
companion object { companion object {
fun setIfNeeded(provider: CommonsProvider) { fun setIfNeeded(provider: CommonsProvider) {
if (::impl.isInitialized) { if (::impl.isInitialized) {

View File

@@ -0,0 +1,48 @@
package com.willfp.eco.internal.spigot.proxy.common.packet
import com.willfp.eco.core.packet.Packet
import com.willfp.eco.core.packet.PacketEvent
import com.willfp.eco.internal.events.handleReceive
import com.willfp.eco.internal.events.handleSend
import io.netty.channel.ChannelDuplexHandler
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.ChannelPromise
import org.bukkit.Bukkit
import java.util.UUID
class EcoChannelDuplexHandler(
private val uuid: UUID
) : ChannelDuplexHandler() {
override fun channelRead(ctx: ChannelHandlerContext, msg: Any) {
val player = Bukkit.getPlayer(uuid)
if (player != null) {
val event = PacketEvent(Packet(msg), player)
event.handleReceive()
if (!event.isCancelled) {
super.channelRead(ctx, msg)
}
} else {
super.channelRead(ctx, msg)
}
}
override fun write(ctx: ChannelHandlerContext, msg: Any, promise: ChannelPromise) {
val player = Bukkit.getPlayer(uuid)
if (player != null) {
val event = PacketEvent(Packet(msg), player)
event.handleSend()
if (!event.isCancelled) {
super.write(ctx, msg, promise)
}
} else {
super.write(ctx, msg, promise)
}
}
}

View File

@@ -0,0 +1,31 @@
package com.willfp.eco.internal.spigot.proxy.common.packet
import com.willfp.eco.internal.spigot.proxy.common.toNMS
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.player.PlayerJoinEvent
import org.bukkit.event.player.PlayerQuitEvent
object PacketInjectorListener : Listener {
@EventHandler
fun onJoin(event: PlayerJoinEvent) {
val player = event.player
val channel = player.toNMS().connection.connection.channel
channel.pipeline().addBefore("packet_handler", "eco_packets", EcoChannelDuplexHandler(player.uniqueId))
}
@EventHandler
fun onLeave(event: PlayerQuitEvent) {
val player = event.player
val channel = player.toNMS().connection.connection.channel
channel.eventLoop().submit {
if (channel.pipeline().get("eco_packets") != null) {
channel.pipeline().remove("eco_packets")
}
}
}
}

View File

@@ -0,0 +1,32 @@
package com.willfp.eco.internal.spigot.proxy.common.packet.display
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.packet.PacketEvent
import com.willfp.eco.core.packet.PacketListener
import net.minecraft.network.protocol.game.ClientboundPlaceGhostRecipePacket
import net.minecraft.resources.ResourceLocation
class PacketAutoRecipe(
private val plugin: EcoPlugin
) : PacketListener {
override fun onSend(event: PacketEvent) {
val packet = event.packet.handle as? ClientboundPlaceGhostRecipePacket ?: return
if (!plugin.configYml.getBool("displayed-recipes")) {
return
}
if (!EcoPlugin.getPluginNames().contains(packet.recipe.namespace)) {
return
}
if (packet.recipe.path.contains("_displayed")) {
return
}
val fKey = packet.javaClass.getDeclaredField("b")
fKey.isAccessible = true
val key = fKey[packet] as ResourceLocation
fKey[packet] = ResourceLocation(key.namespace, key.path + "_displayed")
}
}

View File

@@ -0,0 +1,17 @@
package com.willfp.eco.internal.spigot.proxy.common.packet.display
import com.willfp.eco.core.packet.PacketEvent
import com.willfp.eco.core.packet.PacketListener
import com.willfp.eco.internal.spigot.proxy.common.packet.display.frame.DisplayFrame
import com.willfp.eco.internal.spigot.proxy.common.packet.display.frame.lastDisplayFrame
import net.minecraft.network.protocol.game.ServerboundSetCarriedItemPacket
object PacketHeldItemSlot : PacketListener {
override fun onReceive(event: PacketEvent) {
if (event.packet.handle !is ServerboundSetCarriedItemPacket) {
return
}
event.player.lastDisplayFrame = DisplayFrame.EMPTY
}
}

View File

@@ -0,0 +1,39 @@
package com.willfp.eco.internal.spigot.proxy.common.packet.display
import com.willfp.eco.core.display.Display
import com.willfp.eco.core.packet.PacketEvent
import com.willfp.eco.core.packet.PacketListener
import com.willfp.eco.internal.spigot.proxy.common.asBukkitStack
import com.willfp.eco.internal.spigot.proxy.common.asNMSStack
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.protocol.game.ClientboundMerchantOffersPacket
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.trading.MerchantOffer
import net.minecraft.world.item.trading.MerchantOffers
object PacketOpenWindowMerchant : PacketListener {
private val field = ClientboundMerchantOffersPacket::class.java
.declaredFields
.first { it.type == MerchantOffers::class.java }
.apply { isAccessible = true }
override fun onSend(event: PacketEvent) {
val packet = event.packet.handle as? ClientboundMerchantOffersPacket ?: return
val offers = MerchantOffers()
for (offer in packet.offers) {
val nbt = offer.createTag()
for (tag in arrayOf("buy", "buyB", "sell")) {
val nms = ItemStack.of(nbt.getCompound(tag))
val displayed = Display.display(nms.asBukkitStack(), event.player)
val itemNBT = displayed.asNMSStack().save(CompoundTag())
nbt.put(tag, itemNBT)
}
offers += MerchantOffer(nbt)
}
field.set(packet, offers)
}
}

View File

@@ -0,0 +1,19 @@
package com.willfp.eco.internal.spigot.proxy.common.packet.display
import com.willfp.eco.core.display.Display
import com.willfp.eco.core.packet.PacketEvent
import com.willfp.eco.core.packet.PacketListener
import com.willfp.eco.internal.spigot.proxy.common.asBukkitStack
import com.willfp.eco.internal.spigot.proxy.common.packet.display.frame.DisplayFrame
import com.willfp.eco.internal.spigot.proxy.common.packet.display.frame.lastDisplayFrame
import net.minecraft.network.protocol.game.ServerboundSetCreativeModeSlotPacket
object PacketSetCreativeSlot : PacketListener {
override fun onReceive(event: PacketEvent) {
val packet = event.packet.handle as? ServerboundSetCreativeModeSlotPacket ?: return
Display.revert(packet.item.asBukkitStack())
event.player.lastDisplayFrame = DisplayFrame.EMPTY
}
}

View File

@@ -0,0 +1,19 @@
package com.willfp.eco.internal.spigot.proxy.common.packet.display
import com.willfp.eco.core.display.Display
import com.willfp.eco.core.packet.PacketEvent
import com.willfp.eco.core.packet.PacketListener
import com.willfp.eco.internal.spigot.proxy.common.asBukkitStack
import com.willfp.eco.internal.spigot.proxy.common.packet.display.frame.DisplayFrame
import com.willfp.eco.internal.spigot.proxy.common.packet.display.frame.lastDisplayFrame
import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket
object PacketSetSlot : PacketListener {
override fun onSend(event: PacketEvent) {
val packet = event.packet.handle as? ClientboundContainerSetSlotPacket ?: return
Display.display(packet.item.asBukkitStack(), event.player)
event.player.lastDisplayFrame = DisplayFrame.EMPTY
}
}

View File

@@ -1,39 +1,40 @@
package com.willfp.eco.internal.spigot.display package com.willfp.eco.internal.spigot.proxy.common.packet.display
import com.comphenix.protocol.PacketType
import com.comphenix.protocol.events.PacketContainer
import com.comphenix.protocol.events.PacketEvent
import com.willfp.eco.core.AbstractPacketAdapter
import com.willfp.eco.core.EcoPlugin 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.items.HashedItem import com.willfp.eco.core.items.HashedItem
import com.willfp.eco.internal.spigot.display.frame.DisplayFrame import com.willfp.eco.core.packet.PacketEvent
import com.willfp.eco.internal.spigot.display.frame.lastDisplayFrame import com.willfp.eco.core.packet.PacketListener
import com.willfp.eco.internal.spigot.proxy.common.asBukkitStack
import com.willfp.eco.internal.spigot.proxy.common.asNMSStack
import com.willfp.eco.internal.spigot.proxy.common.packet.display.frame.DisplayFrame
import com.willfp.eco.internal.spigot.proxy.common.packet.display.frame.lastDisplayFrame
import net.minecraft.network.protocol.game.ClientboundContainerSetContentPacket
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import java.util.UUID
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
class PacketWindowItems(plugin: EcoPlugin) : AbstractPacketAdapter(plugin, PacketType.Play.Server.WINDOW_ITEMS, false) { class PacketWindowItems(
private val lastKnownWindowIDs = ConcurrentHashMap<String, Int>() private val plugin: EcoPlugin
) : PacketListener {
private val lastKnownWindowIDs = ConcurrentHashMap<UUID, Int>()
override fun onSend( private val field = ClientboundContainerSetContentPacket::class.java
packet: PacketContainer, .declaredFields
player: Player, .first { it.type == List::class.java }
event: PacketEvent .apply { isAccessible = true }
) {
packet.itemModifier.modify(0) {
Display.display(
it, player
)
}
val windowId = packet.integers.read(0) override fun onSend(event: PacketEvent) {
val packet = event.packet.handle as? ClientboundContainerSetContentPacket ?: return
val player = event.player
// Using name because UUID is unreliable with ProtocolLib players. Display.display(packet.carriedItem.asBukkitStack(), player)
val name = player.name
val lastKnownID = lastKnownWindowIDs[name] val windowId = packet.containerId
lastKnownWindowIDs[name] = windowId
val lastKnownID = lastKnownWindowIDs[player.uniqueId]
lastKnownWindowIDs[player.uniqueId] = windowId
// If there is any change in window ID at any point, // If there is any change in window ID at any point,
// Remove the last display frame to prevent any potential conflicts. // Remove the last display frame to prevent any potential conflicts.
@@ -43,17 +44,20 @@ class PacketWindowItems(plugin: EcoPlugin) : AbstractPacketAdapter(plugin, Packe
player.lastDisplayFrame = DisplayFrame.EMPTY player.lastDisplayFrame = DisplayFrame.EMPTY
} }
val itemStacks = packet.itemListModifier.read(0) ?: return val itemStacks = packet.items.map { it.asBukkitStack() }
packet.itemListModifier.write(0, modifyWindowItems(itemStacks, windowId, player)) val newItems = modifyWindowItems(itemStacks.toMutableList(), windowId, player)
field.set(packet, newItems.map { it.asNMSStack() })
} }
private fun modifyWindowItems( private fun modifyWindowItems(
itemStacks: MutableList<ItemStack>, itemStacks: MutableList<ItemStack>,
windowId: Int, windowId: Int,
player: Player player: Player
): MutableList<ItemStack> { ): MutableList<ItemStack> {
if (this.getPlugin().configYml.getBool("use-display-frame") && windowId == 0) { if (plugin.configYml.getBool("use-display-frame") && windowId == 0) {
val frameMap = mutableMapOf<Byte, HashedItem>() val frameMap = mutableMapOf<Byte, HashedItem>()
for (index in itemStacks.indices) { for (index in itemStacks.indices) {

View File

@@ -1,6 +1,5 @@
package com.willfp.eco.internal.spigot.display.frame package com.willfp.eco.internal.spigot.proxy.common.packet.display.frame
import com.comphenix.protocol.injector.temporary.TemporaryPlayer
import com.willfp.eco.core.items.HashedItem import com.willfp.eco.core.items.HashedItem
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
@@ -33,22 +32,12 @@ private val frames = ConcurrentHashMap<UUID, DisplayFrame>()
var Player.lastDisplayFrame: DisplayFrame var Player.lastDisplayFrame: DisplayFrame
get() { get() {
// ProtocolLib fix
if (this is TemporaryPlayer) {
return DisplayFrame.EMPTY
}
return frames[this.uniqueId] ?: DisplayFrame.EMPTY return frames[this.uniqueId] ?: DisplayFrame.EMPTY
} }
set(value) { set(value) {
// ProtocolLib fix
if (this is TemporaryPlayer) {
return
}
frames[this.uniqueId] = value frames[this.uniqueId] = value
} }
fun clearFrames() { fun clearFrames() {
frames.clear() frames.clear()
} }

View File

@@ -1,15 +0,0 @@
package com.willfp.eco.internal.spigot.proxy.v1_17_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

@@ -1,6 +1,6 @@
package com.willfp.eco.internal.spigot.proxy.v1_17_R1 package com.willfp.eco.internal.spigot.proxy.v1_17_R1
import com.willfp.eco.core.command.impl.PluginCommand import com.willfp.eco.core.command.PluginCommandBase
import com.willfp.eco.internal.spigot.proxy.BukkitCommandsProxy import com.willfp.eco.internal.spigot.proxy.BukkitCommandsProxy
import org.bukkit.Bukkit import org.bukkit.Bukkit
import org.bukkit.command.Command import org.bukkit.command.Command
@@ -28,7 +28,7 @@ class BukkitCommands : BukkitCommandsProxy {
(Bukkit.getServer() as CraftServer).syncCommands() (Bukkit.getServer() as CraftServer).syncCommands()
} }
override fun unregisterCommand(command: PluginCommand) { override fun unregisterCommand(command: PluginCommandBase) {
knownCommands.remove(command.name) knownCommands.remove(command.name)
knownCommands.remove("${command.plugin.name.lowercase()}:${command.name}") knownCommands.remove("${command.plugin.name.lowercase()}:${command.name}")
} }

View File

@@ -1,12 +1,15 @@
package com.willfp.eco.internal.spigot.proxy.v1_17_R1 package com.willfp.eco.internal.spigot.proxy.v1_17_R1
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy
import com.willfp.eco.internal.spigot.proxy.common.CommonsProvider import com.willfp.eco.internal.spigot.proxy.common.CommonsProvider
import com.willfp.eco.internal.spigot.proxy.common.packet.PacketInjectorListener
import com.willfp.eco.internal.spigot.proxy.common.toResourceLocation import com.willfp.eco.internal.spigot.proxy.common.toResourceLocation
import net.minecraft.core.Registry import net.minecraft.core.Registry
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag import net.minecraft.nbt.Tag
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.PathfinderMob import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import org.bukkit.Bukkit import org.bukkit.Bukkit
@@ -15,6 +18,7 @@ import org.bukkit.NamespacedKey
import org.bukkit.craftbukkit.v1_17_R1.CraftServer import org.bukkit.craftbukkit.v1_17_R1.CraftServer
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEntity import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEntity
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftMob import org.bukkit.craftbukkit.v1_17_R1.entity.CraftMob
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer
import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack
import org.bukkit.craftbukkit.v1_17_R1.persistence.CraftPersistentDataContainer import org.bukkit.craftbukkit.v1_17_R1.persistence.CraftPersistentDataContainer
import org.bukkit.craftbukkit.v1_17_R1.persistence.CraftPersistentDataTypeRegistry import org.bukkit.craftbukkit.v1_17_R1.persistence.CraftPersistentDataTypeRegistry
@@ -22,13 +26,17 @@ import org.bukkit.craftbukkit.v1_17_R1.util.CraftMagicNumbers
import org.bukkit.craftbukkit.v1_17_R1.util.CraftNamespacedKey import org.bukkit.craftbukkit.v1_17_R1.util.CraftNamespacedKey
import org.bukkit.entity.LivingEntity import org.bukkit.entity.LivingEntity
import org.bukkit.entity.Mob import org.bukkit.entity.Mob
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import org.bukkit.persistence.PersistentDataContainer import org.bukkit.persistence.PersistentDataContainer
import java.lang.reflect.Field import java.lang.reflect.Field
class CommonsInitializer : CommonsInitializerProxy { class CommonsInitializer : CommonsInitializerProxy {
override fun init() { override fun init(plugin: EcoPlugin) {
CommonsProvider.setIfNeeded(CommonsProviderImpl) CommonsProvider.setIfNeeded(CommonsProviderImpl)
plugin.onEnable {
plugin.eventManager.registerListener(PacketInjectorListener)
}
} }
object CommonsProviderImpl : CommonsProvider { object CommonsProviderImpl : CommonsProvider {
@@ -60,7 +68,7 @@ class CommonsInitializer : CommonsInitializerProxy {
} }
override fun asBukkitStack(itemStack: net.minecraft.world.item.ItemStack): ItemStack { override fun asBukkitStack(itemStack: net.minecraft.world.item.ItemStack): ItemStack {
return CraftItemStack.asBukkitCopy(itemStack) return CraftItemStack.asCraftMirror(itemStack)
} }
override fun mergeIfNeeded(itemStack: ItemStack, nmsStack: net.minecraft.world.item.ItemStack) { override fun mergeIfNeeded(itemStack: ItemStack, nmsStack: net.minecraft.world.item.ItemStack) {
@@ -143,5 +151,9 @@ class CommonsInitializer : CommonsInitializerProxy {
override fun itemToMaterial(item: Item) = override fun itemToMaterial(item: Item) =
Material.getMaterial(Registry.ITEM.getKey(item).path.uppercase()) Material.getMaterial(Registry.ITEM.getKey(item).path.uppercase())
?: throw IllegalArgumentException("Invalid material!") ?: throw IllegalArgumentException("Invalid material!")
override fun toNMS(player: Player): ServerPlayer {
return (player as CraftPlayer).handle
}
} }
} }

View File

@@ -0,0 +1,48 @@
package com.willfp.eco.internal.spigot.proxy.v1_17_R1
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.packet.PacketListener
import com.willfp.eco.internal.spigot.proxy.PacketHandlerProxy
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketAutoRecipe
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketHeldItemSlot
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketOpenWindowMerchant
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketSetCreativeSlot
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketSetSlot
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketWindowItems
import com.willfp.eco.internal.spigot.proxy.common.packet.display.frame.clearFrames
import com.willfp.eco.internal.spigot.proxy.v1_17_R1.display.PacketChat
import net.minecraft.network.protocol.Packet
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer
import org.bukkit.entity.Player
class PacketHandler : PacketHandlerProxy {
override fun sendPacket(player: Player, packet: com.willfp.eco.core.packet.Packet) {
if (player !is CraftPlayer) {
return
}
val handle = packet.handle
if (handle !is Packet<*>) {
return
}
player.handle.connection.send(handle)
}
override fun clearDisplayFrames() {
clearFrames()
}
override fun getPacketListeners(plugin: EcoPlugin): List<PacketListener> {
return listOf(
PacketAutoRecipe(plugin),
PacketHeldItemSlot,
PacketOpenWindowMerchant,
PacketSetCreativeSlot,
PacketSetSlot,
PacketWindowItems(plugin),
PacketChat
)
}
}

View File

@@ -1,41 +0,0 @@
package com.willfp.eco.internal.spigot.proxy.v1_17_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_17_R1.inventory.CraftItemStack
import org.bukkit.craftbukkit.v1_17_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

@@ -1,7 +1,8 @@
package com.willfp.eco.internal.spigot.proxy.v1_17_R1 package com.willfp.eco.internal.spigot.proxy.v1_17_R1.display
import com.willfp.eco.core.display.Display import com.willfp.eco.core.display.Display
import com.willfp.eco.internal.spigot.proxy.ChatComponentProxy import com.willfp.eco.core.packet.PacketEvent
import com.willfp.eco.core.packet.PacketListener
import net.kyori.adventure.nbt.api.BinaryTagHolder import net.kyori.adventure.nbt.api.BinaryTagHolder
import net.kyori.adventure.text.BuildableComponent import net.kyori.adventure.text.BuildableComponent
import net.kyori.adventure.text.Component import net.kyori.adventure.text.Component
@@ -9,20 +10,28 @@ import net.kyori.adventure.text.TranslatableComponent
import net.kyori.adventure.text.event.HoverEvent import net.kyori.adventure.text.event.HoverEvent
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer
import net.minecraft.nbt.TagParser import net.minecraft.nbt.TagParser
import net.minecraft.network.protocol.game.ClientboundChatPacket
import org.bukkit.Material import org.bukkit.Material
import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
@Suppress("UNCHECKED_CAST") object PacketChat : PacketListener {
class ChatComponent : ChatComponentProxy {
private val gsonComponentSerializer = GsonComponentSerializer.gson() private val gsonComponentSerializer = GsonComponentSerializer.gson()
override fun modifyComponent(obj: Any, player: Player): Any { private val field = ClientboundChatPacket::class.java.declaredFields
if (obj !is net.minecraft.network.chat.Component) { .first { it.type == net.minecraft.network.chat.Component::class.java }
return obj .apply { isAccessible = true }
}
override fun onSend(event: PacketEvent) {
val packet = event.packet.handle as? ClientboundChatPacket ?: return
val newMessage = modifyComponent(packet.message, event.player)
field.set(packet, newMessage)
}
private fun modifyComponent(obj: net.minecraft.network.chat.Component, player: Player): Any {
val component = gsonComponentSerializer.deserialize( val component = gsonComponentSerializer.deserialize(
net.minecraft.network.chat.Component.Serializer.toJson( net.minecraft.network.chat.Component.Serializer.toJson(
obj obj
@@ -53,6 +62,7 @@ class ChatComponent : ChatComponentProxy {
} }
component = component.children(children) component = component.children(children)
@Suppress("UNCHECKED_CAST")
val hoverEvent: HoverEvent<Any> = component.style().hoverEvent() as HoverEvent<Any>? ?: return component val hoverEvent: HoverEvent<Any> = component.style().hoverEvent() as HoverEvent<Any>? ?: return component
val showItem = hoverEvent.value() val showItem = hoverEvent.value()
@@ -91,4 +101,4 @@ class ChatComponent : ChatComponentProxy {
val style = component.style().hoverEvent(newHover) val style = component.style().hoverEvent(newHover)
return component.style(style) return component.style(style)
} }
} }

View File

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

View File

@@ -1,6 +1,6 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R1 package com.willfp.eco.internal.spigot.proxy.v1_18_R1
import com.willfp.eco.core.command.impl.PluginCommand import com.willfp.eco.core.command.PluginCommandBase
import com.willfp.eco.internal.spigot.proxy.BukkitCommandsProxy import com.willfp.eco.internal.spigot.proxy.BukkitCommandsProxy
import org.bukkit.Bukkit import org.bukkit.Bukkit
import org.bukkit.command.Command import org.bukkit.command.Command
@@ -28,7 +28,7 @@ class BukkitCommands : BukkitCommandsProxy {
(Bukkit.getServer() as CraftServer).syncCommands() (Bukkit.getServer() as CraftServer).syncCommands()
} }
override fun unregisterCommand(command: PluginCommand) { override fun unregisterCommand(command: PluginCommandBase) {
knownCommands.remove(command.name) knownCommands.remove(command.name)
knownCommands.remove("${command.plugin.name.lowercase()}:${command.name}") knownCommands.remove("${command.plugin.name.lowercase()}:${command.name}")
} }

View File

@@ -1,12 +1,15 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R1 package com.willfp.eco.internal.spigot.proxy.v1_18_R1
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy
import com.willfp.eco.internal.spigot.proxy.common.CommonsProvider import com.willfp.eco.internal.spigot.proxy.common.CommonsProvider
import com.willfp.eco.internal.spigot.proxy.common.packet.PacketInjectorListener
import com.willfp.eco.internal.spigot.proxy.common.toResourceLocation import com.willfp.eco.internal.spigot.proxy.common.toResourceLocation
import net.minecraft.core.Registry import net.minecraft.core.Registry
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag import net.minecraft.nbt.Tag
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.PathfinderMob import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import org.bukkit.Bukkit import org.bukkit.Bukkit
@@ -15,6 +18,7 @@ import org.bukkit.NamespacedKey
import org.bukkit.craftbukkit.v1_18_R1.CraftServer import org.bukkit.craftbukkit.v1_18_R1.CraftServer
import org.bukkit.craftbukkit.v1_18_R1.entity.CraftEntity import org.bukkit.craftbukkit.v1_18_R1.entity.CraftEntity
import org.bukkit.craftbukkit.v1_18_R1.entity.CraftMob import org.bukkit.craftbukkit.v1_18_R1.entity.CraftMob
import org.bukkit.craftbukkit.v1_18_R1.entity.CraftPlayer
import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftItemStack import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftItemStack
import org.bukkit.craftbukkit.v1_18_R1.persistence.CraftPersistentDataContainer import org.bukkit.craftbukkit.v1_18_R1.persistence.CraftPersistentDataContainer
import org.bukkit.craftbukkit.v1_18_R1.persistence.CraftPersistentDataTypeRegistry import org.bukkit.craftbukkit.v1_18_R1.persistence.CraftPersistentDataTypeRegistry
@@ -22,13 +26,17 @@ import org.bukkit.craftbukkit.v1_18_R1.util.CraftMagicNumbers
import org.bukkit.craftbukkit.v1_18_R1.util.CraftNamespacedKey import org.bukkit.craftbukkit.v1_18_R1.util.CraftNamespacedKey
import org.bukkit.entity.LivingEntity import org.bukkit.entity.LivingEntity
import org.bukkit.entity.Mob import org.bukkit.entity.Mob
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import org.bukkit.persistence.PersistentDataContainer import org.bukkit.persistence.PersistentDataContainer
import java.lang.reflect.Field import java.lang.reflect.Field
class CommonsInitializer : CommonsInitializerProxy { class CommonsInitializer : CommonsInitializerProxy {
override fun init() { override fun init(plugin: EcoPlugin) {
CommonsProvider.setIfNeeded(CommonsProviderImpl) CommonsProvider.setIfNeeded(CommonsProviderImpl)
plugin.onEnable {
plugin.eventManager.registerListener(PacketInjectorListener)
}
} }
object CommonsProviderImpl : CommonsProvider { object CommonsProviderImpl : CommonsProvider {
@@ -60,7 +68,7 @@ class CommonsInitializer : CommonsInitializerProxy {
} }
override fun asBukkitStack(itemStack: net.minecraft.world.item.ItemStack): ItemStack { override fun asBukkitStack(itemStack: net.minecraft.world.item.ItemStack): ItemStack {
return CraftItemStack.asBukkitCopy(itemStack) return CraftItemStack.asCraftMirror(itemStack)
} }
override fun mergeIfNeeded(itemStack: ItemStack, nmsStack: net.minecraft.world.item.ItemStack) { override fun mergeIfNeeded(itemStack: ItemStack, nmsStack: net.minecraft.world.item.ItemStack) {
@@ -143,5 +151,9 @@ class CommonsInitializer : CommonsInitializerProxy {
override fun itemToMaterial(item: Item) = override fun itemToMaterial(item: Item) =
Material.getMaterial(Registry.ITEM.getKey(item).path.uppercase()) Material.getMaterial(Registry.ITEM.getKey(item).path.uppercase())
?: throw IllegalArgumentException("Invalid material!") ?: throw IllegalArgumentException("Invalid material!")
override fun toNMS(player: Player): ServerPlayer {
return (player as CraftPlayer).handle
}
} }
} }

View File

@@ -0,0 +1,48 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R1
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.packet.PacketListener
import com.willfp.eco.internal.spigot.proxy.PacketHandlerProxy
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketAutoRecipe
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketHeldItemSlot
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketOpenWindowMerchant
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketSetCreativeSlot
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketSetSlot
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketWindowItems
import com.willfp.eco.internal.spigot.proxy.common.packet.display.frame.clearFrames
import com.willfp.eco.internal.spigot.proxy.v1_18_R1.display.PacketChat
import net.minecraft.network.protocol.Packet
import org.bukkit.craftbukkit.v1_18_R1.entity.CraftPlayer
import org.bukkit.entity.Player
class PacketHandler: PacketHandlerProxy {
override fun sendPacket(player: Player, packet: com.willfp.eco.core.packet.Packet) {
if (player !is CraftPlayer) {
return
}
val handle = packet.handle
if (handle !is Packet<*>) {
return
}
player.handle.connection.send(handle)
}
override fun clearDisplayFrames() {
clearFrames()
}
override fun getPacketListeners(plugin: EcoPlugin): List<PacketListener> {
return listOf(
PacketAutoRecipe(plugin),
PacketHeldItemSlot,
PacketOpenWindowMerchant,
PacketSetCreativeSlot,
PacketSetSlot,
PacketWindowItems(plugin),
PacketChat
)
}
}

View File

@@ -1,41 +0,0 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R1
import com.willfp.eco.core.display.Display
import com.willfp.eco.internal.spigot.proxy.VillagerTradeProxy
import net.minecraft.nbt.CompoundTag
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.trading.MerchantOffer
import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftItemStack
import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftMerchantRecipe
import org.bukkit.entity.Player
import org.bukkit.inventory.MerchantRecipe
import java.lang.reflect.Field
class VillagerTrade : VillagerTradeProxy {
private val handle: Field = CraftMerchantRecipe::class.java.getDeclaredField("handle")
override fun displayTrade(
recipe: MerchantRecipe,
player: Player
): MerchantRecipe {
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

@@ -1,7 +1,8 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R1 package com.willfp.eco.internal.spigot.proxy.v1_18_R1.display
import com.willfp.eco.core.display.Display import com.willfp.eco.core.display.Display
import com.willfp.eco.internal.spigot.proxy.ChatComponentProxy import com.willfp.eco.core.packet.PacketEvent
import com.willfp.eco.core.packet.PacketListener
import net.kyori.adventure.nbt.api.BinaryTagHolder import net.kyori.adventure.nbt.api.BinaryTagHolder
import net.kyori.adventure.text.BuildableComponent import net.kyori.adventure.text.BuildableComponent
import net.kyori.adventure.text.Component import net.kyori.adventure.text.Component
@@ -9,20 +10,28 @@ import net.kyori.adventure.text.TranslatableComponent
import net.kyori.adventure.text.event.HoverEvent import net.kyori.adventure.text.event.HoverEvent
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer
import net.minecraft.nbt.TagParser import net.minecraft.nbt.TagParser
import net.minecraft.network.protocol.game.ClientboundChatPacket
import org.bukkit.Material import org.bukkit.Material
import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftItemStack import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftItemStack
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
@Suppress("UNCHECKED_CAST") object PacketChat : PacketListener {
class ChatComponent : ChatComponentProxy {
private val gsonComponentSerializer = GsonComponentSerializer.gson() private val gsonComponentSerializer = GsonComponentSerializer.gson()
override fun modifyComponent(obj: Any, player: Player): Any { private val field = ClientboundChatPacket::class.java.declaredFields
if (obj !is net.minecraft.network.chat.Component) { .first { it.type == net.minecraft.network.chat.Component::class.java }
return obj .apply { isAccessible = true }
}
override fun onSend(event: PacketEvent) {
val packet = event.packet.handle as? ClientboundChatPacket ?: return
val newMessage = modifyComponent(packet.message, event.player)
field.set(packet, newMessage)
}
private fun modifyComponent(obj: net.minecraft.network.chat.Component, player: Player): Any {
val component = gsonComponentSerializer.deserialize( val component = gsonComponentSerializer.deserialize(
net.minecraft.network.chat.Component.Serializer.toJson( net.minecraft.network.chat.Component.Serializer.toJson(
obj obj
@@ -53,6 +62,7 @@ class ChatComponent : ChatComponentProxy {
} }
component = component.children(children) component = component.children(children)
@Suppress("UNCHECKED_CAST")
val hoverEvent: HoverEvent<Any> = component.style().hoverEvent() as HoverEvent<Any>? ?: return component val hoverEvent: HoverEvent<Any> = component.style().hoverEvent() as HoverEvent<Any>? ?: return component
val showItem = hoverEvent.value() val showItem = hoverEvent.value()
@@ -91,4 +101,4 @@ class ChatComponent : ChatComponentProxy {
val style = component.style().hoverEvent(newHover) val style = component.style().hoverEvent(newHover)
return component.style(style) return component.style(style)
} }
} }

View File

@@ -1,15 +0,0 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R2
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

@@ -1,6 +1,6 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R2 package com.willfp.eco.internal.spigot.proxy.v1_18_R2
import com.willfp.eco.core.command.impl.PluginCommand import com.willfp.eco.core.command.PluginCommandBase
import com.willfp.eco.internal.spigot.proxy.BukkitCommandsProxy import com.willfp.eco.internal.spigot.proxy.BukkitCommandsProxy
import org.bukkit.Bukkit import org.bukkit.Bukkit
import org.bukkit.command.Command import org.bukkit.command.Command
@@ -28,7 +28,7 @@ class BukkitCommands : BukkitCommandsProxy {
(Bukkit.getServer() as CraftServer).syncCommands() (Bukkit.getServer() as CraftServer).syncCommands()
} }
override fun unregisterCommand(command: PluginCommand) { override fun unregisterCommand(command: PluginCommandBase) {
knownCommands.remove(command.name) knownCommands.remove(command.name)
knownCommands.remove("${command.plugin.name.lowercase()}:${command.name}") knownCommands.remove("${command.plugin.name.lowercase()}:${command.name}")
} }

View File

@@ -1,12 +1,15 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R2 package com.willfp.eco.internal.spigot.proxy.v1_18_R2
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy
import com.willfp.eco.internal.spigot.proxy.common.CommonsProvider import com.willfp.eco.internal.spigot.proxy.common.CommonsProvider
import com.willfp.eco.internal.spigot.proxy.common.packet.PacketInjectorListener
import com.willfp.eco.internal.spigot.proxy.common.toResourceLocation import com.willfp.eco.internal.spigot.proxy.common.toResourceLocation
import net.minecraft.core.Registry import net.minecraft.core.Registry
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag import net.minecraft.nbt.Tag
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.PathfinderMob import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import org.bukkit.Bukkit import org.bukkit.Bukkit
@@ -15,6 +18,7 @@ import org.bukkit.NamespacedKey
import org.bukkit.craftbukkit.v1_18_R2.CraftServer import org.bukkit.craftbukkit.v1_18_R2.CraftServer
import org.bukkit.craftbukkit.v1_18_R2.entity.CraftEntity import org.bukkit.craftbukkit.v1_18_R2.entity.CraftEntity
import org.bukkit.craftbukkit.v1_18_R2.entity.CraftMob import org.bukkit.craftbukkit.v1_18_R2.entity.CraftMob
import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer
import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack
import org.bukkit.craftbukkit.v1_18_R2.persistence.CraftPersistentDataContainer import org.bukkit.craftbukkit.v1_18_R2.persistence.CraftPersistentDataContainer
import org.bukkit.craftbukkit.v1_18_R2.persistence.CraftPersistentDataTypeRegistry import org.bukkit.craftbukkit.v1_18_R2.persistence.CraftPersistentDataTypeRegistry
@@ -22,13 +26,17 @@ import org.bukkit.craftbukkit.v1_18_R2.util.CraftMagicNumbers
import org.bukkit.craftbukkit.v1_18_R2.util.CraftNamespacedKey import org.bukkit.craftbukkit.v1_18_R2.util.CraftNamespacedKey
import org.bukkit.entity.LivingEntity import org.bukkit.entity.LivingEntity
import org.bukkit.entity.Mob import org.bukkit.entity.Mob
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import org.bukkit.persistence.PersistentDataContainer import org.bukkit.persistence.PersistentDataContainer
import java.lang.reflect.Field import java.lang.reflect.Field
class CommonsInitializer : CommonsInitializerProxy { class CommonsInitializer : CommonsInitializerProxy {
override fun init() { override fun init(plugin: EcoPlugin) {
CommonsProvider.setIfNeeded(CommonsProviderImpl) CommonsProvider.setIfNeeded(CommonsProviderImpl)
plugin.onEnable {
plugin.eventManager.registerListener(PacketInjectorListener)
}
} }
object CommonsProviderImpl : CommonsProvider { object CommonsProviderImpl : CommonsProvider {
@@ -60,7 +68,7 @@ class CommonsInitializer : CommonsInitializerProxy {
} }
override fun asBukkitStack(itemStack: net.minecraft.world.item.ItemStack): ItemStack { override fun asBukkitStack(itemStack: net.minecraft.world.item.ItemStack): ItemStack {
return CraftItemStack.asBukkitCopy(itemStack) return CraftItemStack.asCraftMirror(itemStack)
} }
override fun mergeIfNeeded(itemStack: ItemStack, nmsStack: net.minecraft.world.item.ItemStack) { override fun mergeIfNeeded(itemStack: ItemStack, nmsStack: net.minecraft.world.item.ItemStack) {
@@ -143,5 +151,9 @@ class CommonsInitializer : CommonsInitializerProxy {
override fun itemToMaterial(item: Item) = override fun itemToMaterial(item: Item) =
Material.getMaterial(Registry.ITEM.getKey(item).path.uppercase()) Material.getMaterial(Registry.ITEM.getKey(item).path.uppercase())
?: throw IllegalArgumentException("Invalid material!") ?: throw IllegalArgumentException("Invalid material!")
override fun toNMS(player: Player): ServerPlayer {
return (player as CraftPlayer).handle
}
} }
} }

View File

@@ -0,0 +1,48 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R2
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.packet.PacketListener
import com.willfp.eco.internal.spigot.proxy.PacketHandlerProxy
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketAutoRecipe
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketHeldItemSlot
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketOpenWindowMerchant
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketSetCreativeSlot
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketSetSlot
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketWindowItems
import com.willfp.eco.internal.spigot.proxy.common.packet.display.frame.clearFrames
import com.willfp.eco.internal.spigot.proxy.v1_18_R2.display.PacketChat
import net.minecraft.network.protocol.Packet
import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer
import org.bukkit.entity.Player
class PacketHandler: PacketHandlerProxy {
override fun sendPacket(player: Player, packet: com.willfp.eco.core.packet.Packet) {
if (player !is CraftPlayer) {
return
}
val handle = packet.handle
if (handle !is Packet<*>) {
return
}
player.handle.connection.send(handle)
}
override fun clearDisplayFrames() {
clearFrames()
}
override fun getPacketListeners(plugin: EcoPlugin): List<PacketListener> {
return listOf(
PacketAutoRecipe(plugin),
PacketHeldItemSlot,
PacketOpenWindowMerchant,
PacketSetCreativeSlot,
PacketSetSlot,
PacketWindowItems(plugin),
PacketChat
)
}
}

View File

@@ -1,41 +0,0 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R2
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_18_R2.inventory.CraftItemStack
import org.bukkit.craftbukkit.v1_18_R2.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

@@ -1,7 +1,8 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R2 package com.willfp.eco.internal.spigot.proxy.v1_18_R2.display
import com.willfp.eco.core.display.Display import com.willfp.eco.core.display.Display
import com.willfp.eco.internal.spigot.proxy.ChatComponentProxy import com.willfp.eco.core.packet.PacketEvent
import com.willfp.eco.core.packet.PacketListener
import net.kyori.adventure.nbt.api.BinaryTagHolder import net.kyori.adventure.nbt.api.BinaryTagHolder
import net.kyori.adventure.text.BuildableComponent import net.kyori.adventure.text.BuildableComponent
import net.kyori.adventure.text.Component import net.kyori.adventure.text.Component
@@ -9,20 +10,28 @@ import net.kyori.adventure.text.TranslatableComponent
import net.kyori.adventure.text.event.HoverEvent import net.kyori.adventure.text.event.HoverEvent
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer
import net.minecraft.nbt.TagParser import net.minecraft.nbt.TagParser
import net.minecraft.network.protocol.game.ClientboundChatPacket
import org.bukkit.Material import org.bukkit.Material
import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
@Suppress("UNCHECKED_CAST") object PacketChat : PacketListener {
class ChatComponent : ChatComponentProxy {
private val gsonComponentSerializer = GsonComponentSerializer.gson() private val gsonComponentSerializer = GsonComponentSerializer.gson()
override fun modifyComponent(obj: Any, player: Player): Any { private val field = ClientboundChatPacket::class.java.declaredFields
if (obj !is net.minecraft.network.chat.Component) { .first { it.type == net.minecraft.network.chat.Component::class.java }
return obj .apply { isAccessible = true }
}
override fun onSend(event: PacketEvent) {
val packet = event.packet.handle as? ClientboundChatPacket ?: return
val newMessage = modifyComponent(packet.message, event.player)
field.set(packet, newMessage)
}
private fun modifyComponent(obj: net.minecraft.network.chat.Component, player: Player): Any {
val component = gsonComponentSerializer.deserialize( val component = gsonComponentSerializer.deserialize(
net.minecraft.network.chat.Component.Serializer.toJson( net.minecraft.network.chat.Component.Serializer.toJson(
obj obj
@@ -53,6 +62,7 @@ class ChatComponent : ChatComponentProxy {
} }
component = component.children(children) component = component.children(children)
@Suppress("UNCHECKED_CAST")
val hoverEvent: HoverEvent<Any> = component.style().hoverEvent() as HoverEvent<Any>? ?: return component val hoverEvent: HoverEvent<Any> = component.style().hoverEvent() as HoverEvent<Any>? ?: return component
val showItem = hoverEvent.value() val showItem = hoverEvent.value()
@@ -62,7 +72,8 @@ class ChatComponent : ChatComponentProxy {
} }
val newShowItem = showItem.nbt( val newShowItem = showItem.nbt(
BinaryTagHolder.binaryTagHolder( @Suppress("UnstableApiUsage", "DEPRECATION")
BinaryTagHolder.of(
CraftItemStack.asNMSCopy( CraftItemStack.asNMSCopy(
Display.display( Display.display(
CraftItemStack.asBukkitCopy( CraftItemStack.asBukkitCopy(
@@ -90,4 +101,4 @@ class ChatComponent : ChatComponentProxy {
val style = component.style().hoverEvent(newHover) val style = component.style().hoverEvent(newHover)
return component.style(style) return component.style(style)
} }
} }

View File

@@ -1,15 +0,0 @@
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

@@ -1,6 +1,6 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R1 package com.willfp.eco.internal.spigot.proxy.v1_19_R1
import com.willfp.eco.core.command.impl.PluginCommand import com.willfp.eco.core.command.PluginCommandBase
import com.willfp.eco.internal.spigot.proxy.BukkitCommandsProxy import com.willfp.eco.internal.spigot.proxy.BukkitCommandsProxy
import org.bukkit.Bukkit import org.bukkit.Bukkit
import org.bukkit.command.Command import org.bukkit.command.Command
@@ -28,7 +28,7 @@ class BukkitCommands : BukkitCommandsProxy {
(Bukkit.getServer() as CraftServer).syncCommands() (Bukkit.getServer() as CraftServer).syncCommands()
} }
override fun unregisterCommand(command: PluginCommand) { override fun unregisterCommand(command: PluginCommandBase) {
knownCommands.remove(command.name) knownCommands.remove(command.name)
knownCommands.remove("${command.plugin.name.lowercase()}:${command.name}") knownCommands.remove("${command.plugin.name.lowercase()}:${command.name}")
} }

View File

@@ -1,93 +0,0 @@
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

@@ -1,12 +1,15 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R1 package com.willfp.eco.internal.spigot.proxy.v1_19_R1
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy
import com.willfp.eco.internal.spigot.proxy.common.CommonsProvider import com.willfp.eco.internal.spigot.proxy.common.CommonsProvider
import com.willfp.eco.internal.spigot.proxy.common.packet.PacketInjectorListener
import com.willfp.eco.internal.spigot.proxy.common.toResourceLocation import com.willfp.eco.internal.spigot.proxy.common.toResourceLocation
import net.minecraft.core.Registry import net.minecraft.core.Registry
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag import net.minecraft.nbt.Tag
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.PathfinderMob import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import org.bukkit.Bukkit import org.bukkit.Bukkit
@@ -15,6 +18,7 @@ import org.bukkit.NamespacedKey
import org.bukkit.craftbukkit.v1_19_R1.CraftServer 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.CraftEntity
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftMob import org.bukkit.craftbukkit.v1_19_R1.entity.CraftMob
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer
import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack 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.CraftPersistentDataContainer
import org.bukkit.craftbukkit.v1_19_R1.persistence.CraftPersistentDataTypeRegistry import org.bukkit.craftbukkit.v1_19_R1.persistence.CraftPersistentDataTypeRegistry
@@ -22,13 +26,17 @@ import org.bukkit.craftbukkit.v1_19_R1.util.CraftMagicNumbers
import org.bukkit.craftbukkit.v1_19_R1.util.CraftNamespacedKey import org.bukkit.craftbukkit.v1_19_R1.util.CraftNamespacedKey
import org.bukkit.entity.LivingEntity import org.bukkit.entity.LivingEntity
import org.bukkit.entity.Mob import org.bukkit.entity.Mob
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import org.bukkit.persistence.PersistentDataContainer import org.bukkit.persistence.PersistentDataContainer
import java.lang.reflect.Field import java.lang.reflect.Field
class CommonsInitializer : CommonsInitializerProxy { class CommonsInitializer : CommonsInitializerProxy {
override fun init() { override fun init(plugin: EcoPlugin) {
CommonsProvider.setIfNeeded(CommonsProviderImpl) CommonsProvider.setIfNeeded(CommonsProviderImpl)
plugin.onEnable {
plugin.eventManager.registerListener(PacketInjectorListener)
}
} }
object CommonsProviderImpl : CommonsProvider { object CommonsProviderImpl : CommonsProvider {
@@ -60,7 +68,7 @@ class CommonsInitializer : CommonsInitializerProxy {
} }
override fun asBukkitStack(itemStack: net.minecraft.world.item.ItemStack): ItemStack { override fun asBukkitStack(itemStack: net.minecraft.world.item.ItemStack): ItemStack {
return CraftItemStack.asBukkitCopy(itemStack) return CraftItemStack.asCraftMirror(itemStack)
} }
override fun mergeIfNeeded(itemStack: ItemStack, nmsStack: net.minecraft.world.item.ItemStack) { override fun mergeIfNeeded(itemStack: ItemStack, nmsStack: net.minecraft.world.item.ItemStack) {
@@ -143,5 +151,9 @@ class CommonsInitializer : CommonsInitializerProxy {
override fun itemToMaterial(item: Item) = override fun itemToMaterial(item: Item) =
Material.getMaterial(Registry.ITEM.getKey(item).path.uppercase()) Material.getMaterial(Registry.ITEM.getKey(item).path.uppercase())
?: throw IllegalArgumentException("Invalid material!") ?: throw IllegalArgumentException("Invalid material!")
override fun toNMS(player: Player): ServerPlayer {
return (player as CraftPlayer).handle
}
} }
} }

View File

@@ -0,0 +1,46 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R1
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.packet.PacketListener
import com.willfp.eco.internal.spigot.proxy.PacketHandlerProxy
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketAutoRecipe
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketHeldItemSlot
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketOpenWindowMerchant
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketSetCreativeSlot
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketSetSlot
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketWindowItems
import com.willfp.eco.internal.spigot.proxy.common.packet.display.frame.clearFrames
import net.minecraft.network.protocol.Packet
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer
import org.bukkit.entity.Player
class PacketHandler : PacketHandlerProxy {
override fun sendPacket(player: Player, packet: com.willfp.eco.core.packet.Packet) {
if (player !is CraftPlayer) {
return
}
val handle = packet.handle
if (handle !is Packet<*>) {
return
}
player.handle.connection.send(handle)
}
override fun clearDisplayFrames() {
clearFrames()
}
override fun getPacketListeners(plugin: EcoPlugin): List<PacketListener> {
return listOf(
PacketAutoRecipe(plugin),
PacketHeldItemSlot,
PacketOpenWindowMerchant,
PacketSetCreativeSlot,
PacketSetSlot,
PacketWindowItems(plugin)
)
}
}

View File

@@ -1,41 +0,0 @@
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

@@ -1,15 +0,0 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R2
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

@@ -1,6 +1,6 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R2 package com.willfp.eco.internal.spigot.proxy.v1_19_R2
import com.willfp.eco.core.command.impl.PluginCommand import com.willfp.eco.core.command.PluginCommandBase
import com.willfp.eco.internal.spigot.proxy.BukkitCommandsProxy import com.willfp.eco.internal.spigot.proxy.BukkitCommandsProxy
import org.bukkit.Bukkit import org.bukkit.Bukkit
import org.bukkit.command.Command import org.bukkit.command.Command
@@ -28,7 +28,7 @@ class BukkitCommands : BukkitCommandsProxy {
(Bukkit.getServer() as CraftServer).syncCommands() (Bukkit.getServer() as CraftServer).syncCommands()
} }
override fun unregisterCommand(command: PluginCommand) { override fun unregisterCommand(command: PluginCommandBase) {
knownCommands.remove(command.name) knownCommands.remove(command.name)
knownCommands.remove("${command.plugin.name.lowercase()}:${command.name}") knownCommands.remove("${command.plugin.name.lowercase()}:${command.name}")
} }

View File

@@ -1,93 +0,0 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R2
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_R2.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

@@ -1,12 +1,15 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R2 package com.willfp.eco.internal.spigot.proxy.v1_19_R2
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy
import com.willfp.eco.internal.spigot.proxy.common.CommonsProvider import com.willfp.eco.internal.spigot.proxy.common.CommonsProvider
import com.willfp.eco.internal.spigot.proxy.common.packet.PacketInjectorListener
import com.willfp.eco.internal.spigot.proxy.common.toResourceLocation import com.willfp.eco.internal.spigot.proxy.common.toResourceLocation
import net.minecraft.core.registries.BuiltInRegistries import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag import net.minecraft.nbt.Tag
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.PathfinderMob import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import org.bukkit.Bukkit import org.bukkit.Bukkit
@@ -15,6 +18,7 @@ import org.bukkit.NamespacedKey
import org.bukkit.craftbukkit.v1_19_R2.CraftServer import org.bukkit.craftbukkit.v1_19_R2.CraftServer
import org.bukkit.craftbukkit.v1_19_R2.entity.CraftEntity import org.bukkit.craftbukkit.v1_19_R2.entity.CraftEntity
import org.bukkit.craftbukkit.v1_19_R2.entity.CraftMob import org.bukkit.craftbukkit.v1_19_R2.entity.CraftMob
import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer
import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftItemStack import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftItemStack
import org.bukkit.craftbukkit.v1_19_R2.persistence.CraftPersistentDataContainer import org.bukkit.craftbukkit.v1_19_R2.persistence.CraftPersistentDataContainer
import org.bukkit.craftbukkit.v1_19_R2.persistence.CraftPersistentDataTypeRegistry import org.bukkit.craftbukkit.v1_19_R2.persistence.CraftPersistentDataTypeRegistry
@@ -22,13 +26,17 @@ import org.bukkit.craftbukkit.v1_19_R2.util.CraftMagicNumbers
import org.bukkit.craftbukkit.v1_19_R2.util.CraftNamespacedKey import org.bukkit.craftbukkit.v1_19_R2.util.CraftNamespacedKey
import org.bukkit.entity.LivingEntity import org.bukkit.entity.LivingEntity
import org.bukkit.entity.Mob import org.bukkit.entity.Mob
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import org.bukkit.persistence.PersistentDataContainer import org.bukkit.persistence.PersistentDataContainer
import java.lang.reflect.Field import java.lang.reflect.Field
class CommonsInitializer : CommonsInitializerProxy { class CommonsInitializer : CommonsInitializerProxy {
override fun init() { override fun init(plugin: EcoPlugin) {
CommonsProvider.setIfNeeded(CommonsProviderImpl) CommonsProvider.setIfNeeded(CommonsProviderImpl)
plugin.onEnable {
plugin.eventManager.registerListener(PacketInjectorListener)
}
} }
object CommonsProviderImpl : CommonsProvider { object CommonsProviderImpl : CommonsProvider {
@@ -60,7 +68,7 @@ class CommonsInitializer : CommonsInitializerProxy {
} }
override fun asBukkitStack(itemStack: net.minecraft.world.item.ItemStack): ItemStack { override fun asBukkitStack(itemStack: net.minecraft.world.item.ItemStack): ItemStack {
return CraftItemStack.asBukkitCopy(itemStack) return CraftItemStack.asCraftMirror(itemStack)
} }
override fun mergeIfNeeded(itemStack: ItemStack, nmsStack: net.minecraft.world.item.ItemStack) { override fun mergeIfNeeded(itemStack: ItemStack, nmsStack: net.minecraft.world.item.ItemStack) {
@@ -143,5 +151,9 @@ class CommonsInitializer : CommonsInitializerProxy {
override fun itemToMaterial(item: Item) = override fun itemToMaterial(item: Item) =
Material.getMaterial(BuiltInRegistries.ITEM.getKey(item).path.uppercase()) Material.getMaterial(BuiltInRegistries.ITEM.getKey(item).path.uppercase())
?: throw IllegalArgumentException("Invalid material!") ?: throw IllegalArgumentException("Invalid material!")
override fun toNMS(player: Player): ServerPlayer {
return (player as CraftPlayer).handle
}
} }
} }

View File

@@ -0,0 +1,46 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R2
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.packet.PacketListener
import com.willfp.eco.internal.spigot.proxy.PacketHandlerProxy
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketAutoRecipe
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketHeldItemSlot
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketOpenWindowMerchant
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketSetCreativeSlot
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketSetSlot
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketWindowItems
import com.willfp.eco.internal.spigot.proxy.common.packet.display.frame.clearFrames
import net.minecraft.network.protocol.Packet
import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer
import org.bukkit.entity.Player
class PacketHandler : PacketHandlerProxy {
override fun sendPacket(player: Player, packet: com.willfp.eco.core.packet.Packet) {
if (player !is CraftPlayer) {
return
}
val handle = packet.handle
if (handle !is Packet<*>) {
return
}
player.handle.connection.send(handle)
}
override fun clearDisplayFrames() {
clearFrames()
}
override fun getPacketListeners(plugin: EcoPlugin): List<PacketListener> {
return listOf(
PacketAutoRecipe(plugin),
PacketHeldItemSlot,
PacketOpenWindowMerchant,
PacketSetCreativeSlot,
PacketSetSlot,
PacketWindowItems(plugin)
)
}
}

View File

@@ -1,41 +0,0 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R2
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_R2.inventory.CraftItemStack
import org.bukkit.craftbukkit.v1_19_R2.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

@@ -5,7 +5,7 @@ import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.PluginLike import com.willfp.eco.core.PluginLike
import com.willfp.eco.core.PluginProps import com.willfp.eco.core.PluginProps
import com.willfp.eco.core.command.CommandBase import com.willfp.eco.core.command.CommandBase
import com.willfp.eco.core.command.impl.PluginCommand import com.willfp.eco.core.command.PluginCommandBase
import com.willfp.eco.core.config.ConfigType import com.willfp.eco.core.config.ConfigType
import com.willfp.eco.core.config.interfaces.Config import com.willfp.eco.core.config.interfaces.Config
import com.willfp.eco.core.data.keys.PersistentDataKey import com.willfp.eco.core.data.keys.PersistentDataKey
@@ -14,6 +14,7 @@ import com.willfp.eco.core.gui.menu.MenuType
import com.willfp.eco.core.gui.slot.functional.SlotProvider import com.willfp.eco.core.gui.slot.functional.SlotProvider
import com.willfp.eco.core.items.Items import com.willfp.eco.core.items.Items
import com.willfp.eco.core.math.MathContext import com.willfp.eco.core.math.MathContext
import com.willfp.eco.core.packet.Packet
import com.willfp.eco.internal.EcoPropsParser import com.willfp.eco.internal.EcoPropsParser
import com.willfp.eco.internal.command.EcoPluginCommand import com.willfp.eco.internal.command.EcoPluginCommand
import com.willfp.eco.internal.command.EcoSubcommand import com.willfp.eco.internal.command.EcoSubcommand
@@ -49,12 +50,12 @@ import com.willfp.eco.internal.spigot.proxy.EntityControllerFactoryProxy
import com.willfp.eco.internal.spigot.proxy.ExtendedPersistentDataContainerFactoryProxy import com.willfp.eco.internal.spigot.proxy.ExtendedPersistentDataContainerFactoryProxy
import com.willfp.eco.internal.spigot.proxy.FastItemStackFactoryProxy import com.willfp.eco.internal.spigot.proxy.FastItemStackFactoryProxy
import com.willfp.eco.internal.spigot.proxy.MiniMessageTranslatorProxy import com.willfp.eco.internal.spigot.proxy.MiniMessageTranslatorProxy
import com.willfp.eco.internal.spigot.proxy.PacketHandlerProxy
import com.willfp.eco.internal.spigot.proxy.SNBTConverterProxy import com.willfp.eco.internal.spigot.proxy.SNBTConverterProxy
import com.willfp.eco.internal.spigot.proxy.SkullProxy import com.willfp.eco.internal.spigot.proxy.SkullProxy
import com.willfp.eco.internal.spigot.proxy.TPSProxy import com.willfp.eco.internal.spigot.proxy.TPSProxy
import org.bukkit.Location import org.bukkit.Location
import org.bukkit.NamespacedKey import org.bukkit.NamespacedKey
import org.bukkit.command.CommandMap
import org.bukkit.configuration.ConfigurationSection import org.bukkit.configuration.ConfigurationSection
import org.bukkit.entity.Entity import org.bukkit.entity.Entity
import org.bukkit.entity.Mob import org.bukkit.entity.Mob
@@ -77,7 +78,7 @@ class EcoImpl : EcoSpigotPlugin(), Eco {
) )
init { init {
getProxy(CommonsInitializerProxy::class.java).init() getProxy(CommonsInitializerProxy::class.java).init(this)
} }
@Suppress("RedundantNullableReturnType") @Suppress("RedundantNullableReturnType")
@@ -317,9 +318,9 @@ class EcoImpl : EcoSpigotPlugin(), Eco {
override fun syncCommands() = override fun syncCommands() =
this.getProxy(BukkitCommandsProxy::class.java).syncCommands() this.getProxy(BukkitCommandsProxy::class.java).syncCommands()
override fun getCommandMap(): CommandMap = override fun unregisterCommand(command: PluginCommandBase) =
this.getProxy(BukkitCommandsProxy::class.java).getCommandMap()
override fun unregisterCommand(command: PluginCommand) =
this.getProxy(BukkitCommandsProxy::class.java).unregisterCommand(command) this.getProxy(BukkitCommandsProxy::class.java).unregisterCommand(command)
override fun sendPacket(player: Player, packet: Packet) =
this.getProxy(PacketHandlerProxy::class.java).sendPacket(player, packet)
} }

View File

@@ -1,6 +1,5 @@
package com.willfp.eco.internal.spigot package com.willfp.eco.internal.spigot
import com.willfp.eco.core.AbstractPacketAdapter
import com.willfp.eco.core.Eco import com.willfp.eco.core.Eco
import com.willfp.eco.core.EcoPlugin import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.Prerequisite import com.willfp.eco.core.Prerequisite
@@ -17,6 +16,7 @@ import com.willfp.eco.core.integrations.mcmmo.McmmoManager
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager import com.willfp.eco.core.integrations.placeholder.PlaceholderManager
import com.willfp.eco.core.integrations.shop.ShopManager import com.willfp.eco.core.integrations.shop.ShopManager
import com.willfp.eco.core.items.Items import com.willfp.eco.core.items.Items
import com.willfp.eco.core.packet.PacketListener
import com.willfp.eco.core.particle.Particles import com.willfp.eco.core.particle.Particles
import com.willfp.eco.core.price.Prices import com.willfp.eco.core.price.Prices
import com.willfp.eco.internal.entities.EntityArgParserAdult import com.willfp.eco.internal.entities.EntityArgParserAdult
@@ -57,14 +57,6 @@ import com.willfp.eco.internal.spigot.data.DataYml
import com.willfp.eco.internal.spigot.data.PlayerBlockListener import com.willfp.eco.internal.spigot.data.PlayerBlockListener
import com.willfp.eco.internal.spigot.data.ProfileHandler import com.willfp.eco.internal.spigot.data.ProfileHandler
import com.willfp.eco.internal.spigot.data.storage.ProfileSaver import com.willfp.eco.internal.spigot.data.storage.ProfileSaver
import com.willfp.eco.internal.spigot.display.PacketAutoRecipe
import com.willfp.eco.internal.spigot.display.PacketChat
import com.willfp.eco.internal.spigot.display.PacketHeldItemSlot
import com.willfp.eco.internal.spigot.display.PacketOpenWindowMerchant
import com.willfp.eco.internal.spigot.display.PacketSetCreativeSlot
import com.willfp.eco.internal.spigot.display.PacketSetSlot
import com.willfp.eco.internal.spigot.display.PacketWindowItems
import com.willfp.eco.internal.spigot.display.frame.clearFrames
import com.willfp.eco.internal.spigot.drops.CollatedRunnable import com.willfp.eco.internal.spigot.drops.CollatedRunnable
import com.willfp.eco.internal.spigot.eventlisteners.EntityDeathByEntityListeners import com.willfp.eco.internal.spigot.eventlisteners.EntityDeathByEntityListeners
import com.willfp.eco.internal.spigot.eventlisteners.NaturalExpGainListenersPaper import com.willfp.eco.internal.spigot.eventlisteners.NaturalExpGainListenersPaper
@@ -121,6 +113,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.proxy.FastItemStackFactoryProxy import com.willfp.eco.internal.spigot.proxy.FastItemStackFactoryProxy
import com.willfp.eco.internal.spigot.proxy.PacketHandlerProxy
import com.willfp.eco.internal.spigot.recipes.CraftingRecipeListener import com.willfp.eco.internal.spigot.recipes.CraftingRecipeListener
import com.willfp.eco.internal.spigot.recipes.StackedRecipeListener import com.willfp.eco.internal.spigot.recipes.StackedRecipeListener
import com.willfp.eco.internal.spigot.recipes.listeners.ComplexInComplex import com.willfp.eco.internal.spigot.recipes.listeners.ComplexInComplex
@@ -247,7 +240,7 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
ProfileSaver(this, profileHandler) ProfileSaver(this, profileHandler)
this.scheduler.runTimer( this.scheduler.runTimer(
{ clearFrames() }, { getProxy(PacketHandlerProxy::class.java).clearDisplayFrames() },
this.configYml.getInt("display-frame-ttl").toLong(), this.configYml.getInt("display-frame-ttl").toLong(),
this.configYml.getInt("display-frame-ttl").toLong() this.configYml.getInt("display-frame-ttl").toLong()
) )
@@ -357,18 +350,6 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
) )
} }
override fun loadPacketAdapters(): List<AbstractPacketAdapter> {
return listOf(
PacketAutoRecipe(this),
PacketChat(this),
PacketSetCreativeSlot(this),
PacketSetSlot(this),
PacketWindowItems(this),
PacketHeldItemSlot(this),
PacketOpenWindowMerchant(this)
)
}
override fun loadListeners(): List<Listener> { override fun loadListeners(): List<Listener> {
val listeners = mutableListOf( val listeners = mutableListOf(
ArmorListener(), ArmorListener(),
@@ -393,4 +374,8 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
return listeners return listeners
} }
override fun loadPacketListeners(): List<PacketListener> {
return this.getProxy(PacketHandlerProxy::class.java).getPacketListeners(this)
}
} }

View File

@@ -1,35 +0,0 @@
package com.willfp.eco.internal.spigot.display
import com.comphenix.protocol.PacketType
import com.comphenix.protocol.ProtocolLibrary
import com.comphenix.protocol.events.PacketContainer
import com.comphenix.protocol.events.PacketEvent
import com.willfp.eco.core.AbstractPacketAdapter
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.internal.spigot.proxy.AutoCraftProxy
import org.bukkit.entity.Player
class PacketAutoRecipe(plugin: EcoPlugin) : AbstractPacketAdapter(plugin, PacketType.Play.Server.AUTO_RECIPE, false) {
override fun onSend(
packet: PacketContainer,
player: Player,
event: PacketEvent
) {
if (!this.getPlugin().configYml.getBool("displayed-recipes")) {
return
}
if (!EcoPlugin.getPluginNames()
.contains(packet.minecraftKeys.values[0].fullKey.split(":".toRegex()).toTypedArray()[0])
) {
return
}
if (packet.minecraftKeys.values[0].fullKey.split(":".toRegex()).toTypedArray()[1].contains("displayed")) {
return
}
getPlugin().getProxy(AutoCraftProxy::class.java).modifyPacket(packet.handle)
val newAutoRecipe = PacketContainer(PacketType.Play.Server.AUTO_RECIPE)
newAutoRecipe.minecraftKeys.write(0, packet.minecraftKeys.read(0))
ProtocolLibrary.getProtocolManager().sendServerPacket(player, newAutoRecipe)
}
}

View File

@@ -1,36 +0,0 @@
package com.willfp.eco.internal.spigot.display
import com.comphenix.protocol.PacketType
import com.comphenix.protocol.events.ListenerPriority
import com.comphenix.protocol.events.PacketContainer
import com.comphenix.protocol.events.PacketEvent
import com.comphenix.protocol.wrappers.WrappedChatComponent
import com.willfp.eco.core.AbstractPacketAdapter
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.internal.spigot.proxy.ChatComponentProxy
import org.bukkit.entity.Player
class PacketChat(plugin: EcoPlugin) :
AbstractPacketAdapter(plugin,
PacketType.Play.Server.CHAT,
if (plugin.configYml.getBool("use-lower-protocollib-priority")) ListenerPriority.NORMAL else ListenerPriority.HIGHEST,
true) {
override fun onSend(
packet: PacketContainer,
player: Player,
event: PacketEvent
) {
for (i in 0 until packet.chatComponents.size()) {
val component = packet.chatComponents.read(i) ?: continue
if (component.handle == null) {
return
}
val newComponent = WrappedChatComponent.fromHandle(
getPlugin().getProxy(
ChatComponentProxy::class.java
).modifyComponent(component.handle, player)
)
packet.chatComponents.write(i, newComponent)
}
}
}

View File

@@ -1,29 +0,0 @@
package com.willfp.eco.internal.spigot.display
import com.comphenix.protocol.PacketType
import com.comphenix.protocol.events.PacketContainer
import com.comphenix.protocol.events.PacketEvent
import com.willfp.eco.core.AbstractPacketAdapter
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.internal.spigot.display.frame.DisplayFrame
import com.willfp.eco.internal.spigot.display.frame.lastDisplayFrame
import org.bukkit.entity.Player
class PacketHeldItemSlot(plugin: EcoPlugin) :
AbstractPacketAdapter(plugin, PacketType.Play.Server.HELD_ITEM_SLOT, false) {
override fun onSend(
packet: PacketContainer,
player: Player,
event: PacketEvent
) {
player.lastDisplayFrame = DisplayFrame.EMPTY
}
override fun onReceive(
packet: PacketContainer,
player: Player,
event: PacketEvent
) {
player.lastDisplayFrame = DisplayFrame.EMPTY
}
}

View File

@@ -1,33 +0,0 @@
package com.willfp.eco.internal.spigot.display
import com.comphenix.protocol.PacketType
import com.comphenix.protocol.events.ListenerPriority
import com.comphenix.protocol.events.PacketContainer
import com.comphenix.protocol.events.PacketEvent
import com.willfp.eco.core.AbstractPacketAdapter
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.internal.spigot.proxy.VillagerTradeProxy
import org.bukkit.entity.Player
import org.bukkit.inventory.MerchantRecipe
class PacketOpenWindowMerchant(plugin: EcoPlugin) :
AbstractPacketAdapter(plugin,
PacketType.Play.Server.OPEN_WINDOW_MERCHANT,
if (plugin.configYml.getBool("use-lower-protocollib-priority")) ListenerPriority.NORMAL else ListenerPriority.MONITOR,
true) {
override fun onSend(
packet: PacketContainer,
player: Player,
event: PacketEvent
) {
val recipes = mutableListOf<MerchantRecipe>()
for (recipe in packet.merchantRecipeLists.read(0)) {
val newRecipe = getPlugin().getProxy(VillagerTradeProxy::class.java).displayTrade(
recipe!!, player
)
recipes.add(newRecipe)
}
packet.merchantRecipeLists.write(0, recipes)
}
}

View File

@@ -1,29 +0,0 @@
package com.willfp.eco.internal.spigot.display
import com.comphenix.protocol.PacketType
import com.comphenix.protocol.events.PacketContainer
import com.comphenix.protocol.events.PacketEvent
import com.willfp.eco.core.AbstractPacketAdapter
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.display.Display
import com.willfp.eco.internal.spigot.display.frame.DisplayFrame
import com.willfp.eco.internal.spigot.display.frame.lastDisplayFrame
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
class PacketSetCreativeSlot(plugin: EcoPlugin) :
AbstractPacketAdapter(plugin, PacketType.Play.Client.SET_CREATIVE_SLOT, false) {
override fun onReceive(
packet: PacketContainer,
player: Player,
event: PacketEvent
) {
packet.itemModifier.modify(0) { itemStack: ItemStack? ->
Display.revert(
itemStack!!
)
}
player.lastDisplayFrame = DisplayFrame.EMPTY
}
}

View File

@@ -1,28 +0,0 @@
package com.willfp.eco.internal.spigot.display
import com.comphenix.protocol.PacketType
import com.comphenix.protocol.events.PacketContainer
import com.comphenix.protocol.events.PacketEvent
import com.willfp.eco.core.AbstractPacketAdapter
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.display.Display
import com.willfp.eco.internal.spigot.display.frame.DisplayFrame
import com.willfp.eco.internal.spigot.display.frame.lastDisplayFrame
import org.bukkit.entity.Player
class PacketSetSlot(plugin: EcoPlugin) : AbstractPacketAdapter(plugin, PacketType.Play.Server.SET_SLOT, false) {
override fun onSend(
packet: PacketContainer,
player: Player,
event: PacketEvent
) {
packet.itemModifier.modify(0) {
Display.display(
it,
player
)
}
player.lastDisplayFrame = DisplayFrame.EMPTY
}
}

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