Compare commits

..

31 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
Auxilor
ef922f6d3f Fixed dynamic commands 2023-01-31 18:58:05 +00:00
Auxilor
026bc55ffb Updated to 6.50.2 2023-01-31 18:35:17 +00:00
Will FP
270fdbb18c Merge pull request #238
Update oraxen dependency
2023-01-31 18:35:02 +00:00
casper
fbf5967d17 Update oraxen dependency 2023-01-31 12:21:41 -06:00
Auxilor
4102be1201 Updated to 6.50.1 2023-01-27 17:47:21 +00:00
Will FP
f6bdb9cc65 Merge pull request #236 from 0ft3n/develop
Fixed fix
2023-01-27 17:46:19 +00:00
Will FP
c8282d1acf Merge branch 'develop' into develop 2023-01-27 17:46:13 +00:00
_OfTeN_
b056b537ef Fixed fix x2 2023-01-27 20:31:00 +03:00
_OfTeN_
f69b458731 Fixed fix 2023-01-27 19:48:28 +03:00
Auxilor
b035fa8940 Changed deprecations 2023-01-27 12:52:55 +00:00
Auxilor
25c087592d Cached placeholder lookups 2023-01-27 12:45:57 +00:00
Auxilor
083cb39771 Cleanups, fixes 2023-01-27 12:20:51 +00:00
Auxilor
eb3e0f5c09 Updated to 6.50.0 2023-01-27 12:18:01 +00:00
Auxilor
08f43ddafd Added dynamic placeholders 2023-01-27 12:17:51 +00:00
124 changed files with 1639 additions and 1426 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

@@ -1,13 +1,16 @@
package com.willfp.eco.core.integrations.placeholder; package com.willfp.eco.core.integrations.placeholder;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache; import com.github.benmanes.caffeine.cache.LoadingCache;
import com.willfp.eco.core.Eco; import com.willfp.eco.core.Eco;
import com.willfp.eco.core.EcoPlugin; import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.placeholder.AdditionalPlayer; import com.willfp.eco.core.placeholder.AdditionalPlayer;
import com.willfp.eco.core.placeholder.DynamicPlaceholder;
import com.willfp.eco.core.placeholder.InjectablePlaceholder; import com.willfp.eco.core.placeholder.InjectablePlaceholder;
import com.willfp.eco.core.placeholder.Placeholder; import com.willfp.eco.core.placeholder.Placeholder;
import com.willfp.eco.core.placeholder.PlaceholderInjectable; import com.willfp.eco.core.placeholder.PlaceholderInjectable;
import com.willfp.eco.core.placeholder.PlayerDynamicPlaceholder;
import com.willfp.eco.core.placeholder.PlayerPlaceholder; import com.willfp.eco.core.placeholder.PlayerPlaceholder;
import com.willfp.eco.core.placeholder.PlayerStaticPlaceholder; import com.willfp.eco.core.placeholder.PlayerStaticPlaceholder;
import com.willfp.eco.core.placeholder.PlayerlessPlaceholder; import com.willfp.eco.core.placeholder.PlayerlessPlaceholder;
@@ -24,6 +27,7 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher; import java.util.regex.Matcher;
@@ -37,13 +41,20 @@ public final class PlaceholderManager {
/** /**
* All registered placeholders. * All registered placeholders.
*/ */
private static final Map<EcoPlugin, Map<String, Placeholder>> REGISTERED_PLACEHOLDERS = new HashMap<>(); private static final Map<EcoPlugin, Map<Pattern, Placeholder>> REGISTERED_PLACEHOLDERS = new HashMap<>();
/** /**
* All registered placeholder integrations. * All registered placeholder integrations.
*/ */
private static final Set<PlaceholderIntegration> REGISTERED_INTEGRATIONS = new HashSet<>(); private static final Set<PlaceholderIntegration> REGISTERED_INTEGRATIONS = new HashSet<>();
/**
* Placeholder Lookup Cache.
*/
private static final Cache<PlaceholderLookup, Optional<Placeholder>> PLACEHOLDER_LOOKUP_CACHE = Caffeine.newBuilder()
.expireAfterWrite(1, TimeUnit.SECONDS)
.build();
/** /**
* Placeholder Cache. * Placeholder Cache.
*/ */
@@ -51,10 +62,17 @@ public final class PlaceholderManager {
.expireAfterWrite(50, TimeUnit.MILLISECONDS) .expireAfterWrite(50, TimeUnit.MILLISECONDS)
.build(key -> key.entry.getValue(key.player)); .build(key -> key.entry.getValue(key.player));
/**
* Dynamic Placeholder Cache.
*/
private static final LoadingCache<DynamicEntryWithPlayer, String> DYNAMIC_PLACEHOLDER_CACHE = Caffeine.newBuilder()
.expireAfterWrite(50, TimeUnit.MILLISECONDS)
.build(key -> key.entry.getValue(key.args, key.player));
/** /**
* The default PlaceholderAPI pattern; brought in for compatibility. * The default PlaceholderAPI pattern; brought in for compatibility.
*/ */
private static final Pattern PATTERN = Pattern.compile("[%]([^% ]+)[%]"); private static final Pattern PATTERN = Pattern.compile("%([^% ]+)%");
/** /**
* Empty injectable object. * Empty injectable object.
@@ -88,14 +106,17 @@ public final class PlaceholderManager {
* @param placeholder The placeholder to register. * @param placeholder The placeholder to register.
*/ */
public static void registerPlaceholder(@NotNull final Placeholder placeholder) { public static void registerPlaceholder(@NotNull final Placeholder placeholder) {
if (placeholder instanceof StaticPlaceholder) { if (placeholder instanceof StaticPlaceholder || placeholder instanceof PlayerStaticPlaceholder) {
throw new IllegalArgumentException("Static placeholders cannot be registered!"); throw new IllegalArgumentException("Static placeholders cannot be registered!");
} }
EcoPlugin plugin = placeholder.getPlugin() == null ? Eco.get().getEcoPlugin() : placeholder.getPlugin(); EcoPlugin plugin = placeholder.getPlugin() == null ? Eco.get().getEcoPlugin() : placeholder.getPlugin();
Map<String, Placeholder> pluginPlaceholders = REGISTERED_PLACEHOLDERS
Map<Pattern, Placeholder> pluginPlaceholders = REGISTERED_PLACEHOLDERS
.getOrDefault(plugin, new HashMap<>()); .getOrDefault(plugin, new HashMap<>());
pluginPlaceholders.put(placeholder.getIdentifier(), placeholder);
pluginPlaceholders.put(placeholder.getPattern(), placeholder);
REGISTERED_PLACEHOLDERS.put(plugin, pluginPlaceholders); REGISTERED_PLACEHOLDERS.put(plugin, pluginPlaceholders);
} }
@@ -136,21 +157,47 @@ public final class PlaceholderManager {
public static String getResult(@Nullable final Player player, public static String getResult(@Nullable final Player player,
@NotNull final String identifier, @NotNull final String identifier,
@Nullable final EcoPlugin plugin) { @Nullable final EcoPlugin plugin) {
EcoPlugin owner = plugin == null ? Eco.get().getEcoPlugin() : plugin; // This is really janky, and it sucks, but it works so?
Placeholder placeholder = REGISTERED_PLACEHOLDERS.getOrDefault(owner, new HashMap<>()).get(identifier.toLowerCase()); // Compensating for regex being slow so that's why we get it.
Placeholder placeholder = PLACEHOLDER_LOOKUP_CACHE.get(
new PlaceholderLookup(identifier, plugin),
(it) -> {
EcoPlugin owner = plugin == null ? Eco.get().getEcoPlugin() : plugin;
if (placeholder == null && plugin != null) { // I hate the streams API.
Placeholder alternate = REGISTERED_PLACEHOLDERS.getOrDefault(Eco.get().getEcoPlugin(), new HashMap<>()) Optional<Placeholder> found = REGISTERED_PLACEHOLDERS
.get(identifier.toLowerCase()); .getOrDefault(owner, new HashMap<>())
if (alternate != null) { .entrySet()
placeholder = alternate; .stream().filter(entry -> entry.getKey().matcher(identifier).matches())
} .map(Map.Entry::getValue)
} .findFirst();
if (found.isEmpty() && plugin != null) {
// Here we go again! Something about legacy support? I don't remember.
// I won't touch it though, I'm scared of the placeholder system.
found = REGISTERED_PLACEHOLDERS
.getOrDefault(Eco.get().getEcoPlugin(), new HashMap<>())
.entrySet()
.stream().filter(entry -> entry.getKey().matcher(identifier).matches())
.map(Map.Entry::getValue)
.findFirst();
}
return found;
}
).orElse(null);
if (placeholder == null) { if (placeholder == null) {
return ""; return "";
} }
/*
This code here is *really* not very good. It's mega externalized logic hacked
together and made worse by the addition of dynamic placeholders. But it works,
and it means I don't have to rewrite the whole placeholder system. So it's
good enough for me.
*/
if (placeholder instanceof PlayerPlaceholder playerPlaceholder) { if (placeholder instanceof PlayerPlaceholder playerPlaceholder) {
if (player == null) { if (player == null) {
return ""; return "";
@@ -159,6 +206,14 @@ public final class PlaceholderManager {
} }
} else if (placeholder instanceof PlayerlessPlaceholder playerlessPlaceholder) { } else if (placeholder instanceof PlayerlessPlaceholder playerlessPlaceholder) {
return playerlessPlaceholder.getValue(); return playerlessPlaceholder.getValue();
} else if (placeholder instanceof PlayerDynamicPlaceholder playerDynamicPlaceholder) {
if (player == null) {
return "";
} else {
return DYNAMIC_PLACEHOLDER_CACHE.get(new DynamicEntryWithPlayer(playerDynamicPlaceholder, identifier, player));
}
} else if (placeholder instanceof DynamicPlaceholder dynamicPlaceholder) {
return dynamicPlaceholder.getValue(identifier);
} else { } else {
return ""; return "";
} }
@@ -245,8 +300,10 @@ public final class PlaceholderManager {
for (PlaceholderIntegration integration : REGISTERED_INTEGRATIONS) { for (PlaceholderIntegration integration : REGISTERED_INTEGRATIONS) {
processed = integration.translate(processed, player); processed = integration.translate(processed, player);
} }
for (InjectablePlaceholder injection : context.getPlaceholderInjections()) { for (InjectablePlaceholder injection : context.getPlaceholderInjections()) {
// Do I know this is a bad way of doing this? Yes. // Do I know this is a bad way of doing this? Yes.
// I know it's deprecated, but it's fast.
if (injection instanceof StaticPlaceholder placeholder) { if (injection instanceof StaticPlaceholder placeholder) {
processed = processed.replace("%" + placeholder.getIdentifier() + "%", placeholder.getValue()); processed = processed.replace("%" + placeholder.getIdentifier() + "%", placeholder.getValue());
} else if (injection instanceof PlayerStaticPlaceholder placeholder && player != null) { } else if (injection instanceof PlayerStaticPlaceholder placeholder && player != null) {
@@ -280,11 +337,22 @@ public final class PlaceholderManager {
return new ArrayList<>(found); return new ArrayList<>(found);
} }
private record PlaceholderLookup(@NotNull String identifier,
@Nullable EcoPlugin plugin) {
}
private record EntryWithPlayer(@NotNull PlayerPlaceholder entry, private record EntryWithPlayer(@NotNull PlayerPlaceholder entry,
@NotNull Player player) { @NotNull Player player) {
} }
private record DynamicEntryWithPlayer(@NotNull PlayerDynamicPlaceholder entry,
@NotNull String args,
@NotNull Player player) {
}
private PlaceholderManager() { private PlaceholderManager() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
} }

View File

@@ -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,102 @@
package com.willfp.eco.core.placeholder;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.function.Function;
import java.util.regex.Pattern;
/**
* A placeholder that does not require a player and supports dynamic styles.
*/
public final class DynamicPlaceholder implements Placeholder {
/**
* The placeholder pattern.
*/
private final Pattern pattern;
/**
* The function to retrieve the output of the placeholder.
*/
private final Function<String, String> function;
/**
* The plugin for the placeholder.
*/
private final EcoPlugin plugin;
/**
* Create a new dynamic placeholder.
*
* @param plugin The plugin.
* @param pattern The pattern.
* @param function The function to retrieve the value.
*/
public DynamicPlaceholder(@NotNull final EcoPlugin plugin,
@NotNull final Pattern pattern,
@NotNull final Function<String, String> function) {
this.plugin = plugin;
this.pattern = pattern;
this.function = function;
}
/**
* Get the value of the placeholder.
*
* @param args The args.
* @return The value.
*/
@NotNull
public String getValue(@NotNull final String args) {
return function.apply(args);
}
/**
* Register the placeholder.
*
* @return The placeholder.
*/
public DynamicPlaceholder register() {
PlaceholderManager.registerPlaceholder(this);
return this;
}
@Override
public @NotNull EcoPlugin getPlugin() {
return this.plugin;
}
@Override
@Deprecated
public @NotNull String getIdentifier() {
return "dynamic";
}
@NotNull
@Override
public Pattern getPattern() {
return this.pattern;
}
@Override
public boolean equals(@Nullable final Object o) {
if (this == o) {
return true;
}
if (!(o instanceof DynamicPlaceholder that)) {
return false;
}
return Objects.equals(this.getPattern(), that.getPattern())
&& Objects.equals(this.getPlugin(), that.getPlugin());
}
@Override
public int hashCode() {
return Objects.hash(this.getIdentifier(), this.getPlugin());
}
}

View File

@@ -2,13 +2,14 @@ package com.willfp.eco.core.placeholder;
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 org.jetbrains.annotations.NotNull;
/** /**
* Placeholders that can be injected into {@link PlaceholderInjectable} objects. * Placeholders that can be injected into {@link PlaceholderInjectable} objects.
*/ */
public sealed interface InjectablePlaceholder extends Placeholder permits PlayerStaticPlaceholder, StaticPlaceholder { public sealed interface InjectablePlaceholder extends Placeholder permits PlayerStaticPlaceholder, StaticPlaceholder {
@Override @Override
default EcoPlugin getPlugin() { default @NotNull EcoPlugin getPlugin() {
return Eco.get().getEcoPlugin(); return Eco.get().getEcoPlugin();
} }
} }

View File

@@ -1,16 +1,22 @@
package com.willfp.eco.core.placeholder; package com.willfp.eco.core.placeholder;
import com.willfp.eco.core.EcoPlugin; import com.willfp.eco.core.EcoPlugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.regex.Pattern;
/** /**
* A placeholder represents a string that can hold a value. * A placeholder represents a string that can hold a value.
*/ */
public sealed interface Placeholder permits PlayerPlaceholder, PlayerlessPlaceholder, InjectablePlaceholder { public sealed interface Placeholder permits PlayerPlaceholder, PlayerlessPlaceholder,
DynamicPlaceholder, PlayerDynamicPlaceholder, InjectablePlaceholder {
/** /**
* Get the plugin that holds the placeholder. * Get the plugin that holds the placeholder.
* *
* @return The plugin. * @return The plugin.
*/ */
@Nullable
EcoPlugin getPlugin(); EcoPlugin getPlugin();
/** /**
@@ -18,5 +24,16 @@ public sealed interface Placeholder permits PlayerPlaceholder, PlayerlessPlaceho
* *
* @return The identifier. * @return The identifier.
*/ */
@NotNull
String getIdentifier(); String getIdentifier();
/**
* Get the pattern for the placeholder.
*
* @return The pattern.
*/
@NotNull
default Pattern getPattern() {
return Pattern.compile(this.getIdentifier());
}
} }

View File

@@ -0,0 +1,105 @@
package com.willfp.eco.core.placeholder;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.regex.Pattern;
/**
* A placeholder that does not require a player and supports dynamic styles.
*/
public final class PlayerDynamicPlaceholder implements Placeholder {
/**
* The placeholder pattern.
*/
private final Pattern pattern;
/**
* The function to retrieve the output of the placeholder.
*/
private final BiFunction<String, Player, String> function;
/**
* The plugin for the placeholder.
*/
private final EcoPlugin plugin;
/**
* Create a new dynamic placeholder.
*
* @param plugin The plugin.
* @param pattern The pattern.
* @param function The function to retrieve the value.
*/
public PlayerDynamicPlaceholder(@NotNull final EcoPlugin plugin,
@NotNull final Pattern pattern,
@NotNull final BiFunction<String, Player, String> function) {
this.plugin = plugin;
this.pattern = pattern;
this.function = function;
}
/**
* Get the value of the placeholder.
*
* @param args The args.
* @param player The player.
* @return The value.
*/
@NotNull
public String getValue(@NotNull final String args,
@NotNull final Player player) {
return function.apply(args, player);
}
/**
* Register the placeholder.
*
* @return The placeholder.
*/
public PlayerDynamicPlaceholder register() {
PlaceholderManager.registerPlaceholder(this);
return this;
}
@Override
public @NotNull EcoPlugin getPlugin() {
return this.plugin;
}
@Override
@Deprecated
public @NotNull String getIdentifier() {
return "dynamic";
}
@NotNull
@Override
public Pattern getPattern() {
return this.pattern;
}
@Override
public boolean equals(@Nullable final Object o) {
if (this == o) {
return true;
}
if (!(o instanceof PlayerDynamicPlaceholder that)) {
return false;
}
return Objects.equals(this.getPattern(), that.getPattern())
&& Objects.equals(this.getPlugin(), that.getPlugin());
}
@Override
public int hashCode() {
return Objects.hash(this.getIdentifier(), this.getPlugin());
}
}

View File

@@ -8,6 +8,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.Objects; import java.util.Objects;
import java.util.function.Function; import java.util.function.Function;
import java.util.regex.Pattern;
/** /**
* A placeholder that requires a player. * A placeholder that requires a player.
@@ -18,6 +19,11 @@ public final class PlayerPlaceholder implements Placeholder {
*/ */
private final String identifier; private final String identifier;
/**
* The placeholder pattern.
*/
private final Pattern pattern;
/** /**
* The function to retrieve the output of the placeholder given a player. * The function to retrieve the output of the placeholder given a player.
*/ */
@@ -40,6 +46,7 @@ public final class PlayerPlaceholder implements Placeholder {
@NotNull final Function<Player, String> function) { @NotNull final Function<Player, String> function) {
this.plugin = plugin; this.plugin = plugin;
this.identifier = identifier; this.identifier = identifier;
this.pattern = Pattern.compile(identifier);
this.function = function; this.function = function;
} }
@@ -49,6 +56,7 @@ public final class PlayerPlaceholder implements Placeholder {
* @param player The player. * @param player The player.
* @return The value. * @return The value.
*/ */
@NotNull
public String getValue(@NotNull final Player player) { public String getValue(@NotNull final Player player) {
return function.apply(player); return function.apply(player);
} }
@@ -64,15 +72,21 @@ public final class PlayerPlaceholder implements Placeholder {
} }
@Override @Override
public EcoPlugin getPlugin() { public @NotNull EcoPlugin getPlugin() {
return this.plugin; return this.plugin;
} }
@Override @Override
public String getIdentifier() { public @NotNull String getIdentifier() {
return this.identifier; return this.identifier;
} }
@NotNull
@Override
public Pattern getPattern() {
return this.pattern;
}
@Override @Override
public boolean equals(@Nullable final Object o) { public boolean equals(@Nullable final Object o) {
if (this == o) { if (this == o) {

View File

@@ -6,6 +6,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.Objects; import java.util.Objects;
import java.util.function.Function; import java.util.function.Function;
import java.util.regex.Pattern;
/** /**
* A placeholder that cannot be registered, and exists purely in injection. * A placeholder that cannot be registered, and exists purely in injection.
@@ -16,6 +17,11 @@ public final class PlayerStaticPlaceholder implements InjectablePlaceholder {
*/ */
private final String identifier; private final String identifier;
/**
* The placeholder pattern.
*/
private final Pattern pattern;
/** /**
* The function to retrieve the output of the placeholder. * The function to retrieve the output of the placeholder.
*/ */
@@ -30,6 +36,7 @@ public final class PlayerStaticPlaceholder implements InjectablePlaceholder {
public PlayerStaticPlaceholder(@NotNull final String identifier, public PlayerStaticPlaceholder(@NotNull final String identifier,
@NotNull final Function<Player, String> function) { @NotNull final Function<Player, String> function) {
this.identifier = identifier; this.identifier = identifier;
this.pattern = Pattern.compile(identifier);
this.function = function; this.function = function;
} }
@@ -39,15 +46,22 @@ public final class PlayerStaticPlaceholder implements InjectablePlaceholder {
* @param player The player. * @param player The player.
* @return The value. * @return The value.
*/ */
@NotNull
public String getValue(@NotNull final Player player) { public String getValue(@NotNull final Player player) {
return function.apply(player); return function.apply(player);
} }
@Override @Override
public String getIdentifier() { public @NotNull String getIdentifier() {
return this.identifier; return this.identifier;
} }
@NotNull
@Override
public Pattern getPattern() {
return this.pattern;
}
@Override @Override
public boolean equals(@Nullable final Object o) { public boolean equals(@Nullable final Object o) {
if (this == o) { if (this == o) {

View File

@@ -7,16 +7,22 @@ import org.jetbrains.annotations.Nullable;
import java.util.Objects; import java.util.Objects;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.regex.Pattern;
/** /**
* A placeholder that does not require a player. * A placeholder that does not require a player.
*/ */
public final class PlayerlessPlaceholder implements Placeholder { public final class PlayerlessPlaceholder implements Placeholder {
/** /**
* The name of the placeholder. * The placeholder identifier.
*/ */
private final String identifier; private final String identifier;
/**
* The placeholder pattern.
*/
private final Pattern pattern;
/** /**
* The function to retrieve the output of the placeholder. * The function to retrieve the output of the placeholder.
*/ */
@@ -39,6 +45,7 @@ public final class PlayerlessPlaceholder implements Placeholder {
@NotNull final Supplier<String> function) { @NotNull final Supplier<String> function) {
this.plugin = plugin; this.plugin = plugin;
this.identifier = identifier; this.identifier = identifier;
this.pattern = Pattern.compile(identifier);
this.function = function; this.function = function;
} }
@@ -62,15 +69,21 @@ public final class PlayerlessPlaceholder implements Placeholder {
} }
@Override @Override
public EcoPlugin getPlugin() { public @NotNull EcoPlugin getPlugin() {
return this.plugin; return this.plugin;
} }
@Override @Override
public String getIdentifier() { public @NotNull String getIdentifier() {
return this.identifier; return this.identifier;
} }
@NotNull
@Override
public Pattern getPattern() {
return this.pattern;
}
@Override @Override
public boolean equals(@Nullable final Object o) { public boolean equals(@Nullable final Object o) {
if (this == o) { if (this == o) {

View File

@@ -5,6 +5,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.Objects; import java.util.Objects;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.regex.Pattern;
/** /**
* A placeholder that cannot be registered, and exists purely in injection. * A placeholder that cannot be registered, and exists purely in injection.
@@ -15,6 +16,11 @@ public final class StaticPlaceholder implements InjectablePlaceholder {
*/ */
private final String identifier; private final String identifier;
/**
* The placeholder pattern.
*/
private final Pattern pattern;
/** /**
* The function to retrieve the output of the placeholder. * The function to retrieve the output of the placeholder.
*/ */
@@ -29,6 +35,7 @@ public final class StaticPlaceholder implements InjectablePlaceholder {
public StaticPlaceholder(@NotNull final String identifier, public StaticPlaceholder(@NotNull final String identifier,
@NotNull final Supplier<String> function) { @NotNull final Supplier<String> function) {
this.identifier = identifier; this.identifier = identifier;
this.pattern = Pattern.compile(identifier);
this.function = function; this.function = function;
} }
@@ -37,15 +44,22 @@ public final class StaticPlaceholder implements InjectablePlaceholder {
* *
* @return The value. * @return The value.
*/ */
@NotNull
public String getValue() { public String getValue() {
return function.get(); return function.get();
} }
@Override @Override
public String getIdentifier() { public @NotNull String getIdentifier() {
return this.identifier; return this.identifier;
} }
@NotNull
@Override
public Pattern getPattern() {
return this.pattern;
}
@Override @Override
public boolean equals(@Nullable final Object o) { public boolean equals(@Nullable final Object o) {
if (this == o) { if (this == o) {

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,8 +8,11 @@ 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 false return delegate.onCommand(sender, this, label, args)
} }
override fun onTabComplete( override fun onTabComplete(
@@ -18,11 +21,21 @@ class DelegatedBukkitCommand(
label: String, label: String,
args: Array<out String>? args: Array<out String>?
): List<String> { ): List<String> {
return mutableListOf() // Mutable in case bukkit requires this (I haven't checked.) return delegate.onTabComplete(sender, this, label, args) ?: emptyList()
} }
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,27 +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()
} }
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

@@ -50,8 +50,8 @@ abstract class HandledCommand(
command: Command, command: Command,
label: String, label: String,
args: Array<out String>? args: Array<out String>?
): MutableList<String>? { ): List<String>? {
return handleTabComplete(sender, args?.toList() ?: listOf()).toMutableList() return handleTabComplete(sender, args?.toList() ?: listOf())
} }
override fun getPlugin() = this.plugin override fun getPlugin() = this.plugin

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
}
} }
} }

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