mirror of
https://github.com/IntellectualSites/PlotSquared.git
synced 2025-10-28 16:13:44 +01:00
Compare commits
4 Commits
fix/genera
...
chore/flex
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c06d5f11d | ||
|
|
df15203f2b | ||
|
|
f5696b7671 | ||
|
|
9ed0c7fa13 |
@@ -80,7 +80,7 @@ tasks.named<ShadowJar>("shadowJar") {
|
||||
relocate("net.kyori.examination", "com.plotsquared.core.configuration.examination")
|
||||
relocate("io.papermc.lib", "com.plotsquared.bukkit.paperlib")
|
||||
relocate("org.bstats", "com.plotsquared.metrics")
|
||||
relocate("org.enginehub.squirrelid", "com.plotsquared.squirrelid")
|
||||
relocate("org.enginehub", "com.plotsquared.squirrelid")
|
||||
relocate("org.khelekore.prtree", "com.plotsquared.prtree")
|
||||
relocate("com.google.inject", "com.plotsquared.google")
|
||||
relocate("org.aopalliance", "com.plotsquared.core.aopalliance")
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.google.inject.Injector;
|
||||
import com.google.inject.Key;
|
||||
import com.google.inject.Singleton;
|
||||
import com.google.inject.Stage;
|
||||
import com.plotsquared.bukkit.entity.EntityType;
|
||||
import com.plotsquared.bukkit.generator.BukkitPlotGenerator;
|
||||
import com.plotsquared.bukkit.inject.BackupModule;
|
||||
import com.plotsquared.bukkit.inject.BukkitModule;
|
||||
@@ -46,7 +47,6 @@ import com.plotsquared.bukkit.listener.WorldEvents;
|
||||
import com.plotsquared.bukkit.placeholder.PAPIPlaceholders;
|
||||
import com.plotsquared.bukkit.placeholder.PlaceholderFormatter;
|
||||
import com.plotsquared.bukkit.player.BukkitPlayerManager;
|
||||
import com.plotsquared.bukkit.schematic.StateWrapper;
|
||||
import com.plotsquared.bukkit.util.BukkitUtil;
|
||||
import com.plotsquared.bukkit.util.BukkitWorld;
|
||||
import com.plotsquared.bukkit.util.SetGenCB;
|
||||
@@ -290,18 +290,6 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl
|
||||
}
|
||||
}
|
||||
|
||||
// Validate compatibility of StateWrapper with the current running server version
|
||||
// Do this always, even if it's not required, to prevent running servers which fail to restore plot backups or
|
||||
// inserting broken plot / road templates.
|
||||
try {
|
||||
var instance = StateWrapper.INSTANCE;
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Failed to initialize required classes for restoring tile entities. " +
|
||||
"PlotSquared will disable itself to prevent possible damages.", e);
|
||||
getServer().getPluginManager().disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
|
||||
// We create the injector after PlotSquared has been initialized, so that we have access
|
||||
// to generated instances and settings
|
||||
this.injector = Guice
|
||||
@@ -807,60 +795,29 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl
|
||||
if (entity.getMetadata("ps_custom_spawned").stream().anyMatch(MetadataValue::asBoolean)) {
|
||||
continue;
|
||||
}
|
||||
// TODO: use (type) pattern matching when targeting java 21
|
||||
switch (entity.getType().toString()) {
|
||||
case "EGG":
|
||||
case "FISHING_HOOK", "FISHING_BOBBER":
|
||||
case "ENDER_SIGNAL", "EYE_OF_ENDER":
|
||||
case "AREA_EFFECT_CLOUD":
|
||||
case "EXPERIENCE_ORB":
|
||||
case "LEASH_HITCH", "LEASH_KNOT":
|
||||
case "FIREWORK", "FIREWORK_ROCKET":
|
||||
case "LIGHTNING", "LIGHTNING_BOLT":
|
||||
case "WITHER_SKULL":
|
||||
case "UNKNOWN":
|
||||
case "PLAYER":
|
||||
|
||||
switch (EntityType.of(entity.getType())) {
|
||||
case EGG, FISHING_BOBBER, EYE_OF_ENDER, AREA_EFFECT_CLOUD, EXPERIENCE_ORB, LEASH_KNOT, FIREWORK_ROCKET,
|
||||
LIGHTNING_BOLT, WITHER_SKULL, UNKNOWN, PLAYER, MANNEQUIN, BLOCK_DISPLAY, INTERACTION, ITEM_DISPLAY,
|
||||
GLOW_ITEM_FRAME, TEXT_DISPLAY, OMINOUS_ITEM_SPAWNER, MARKER -> {
|
||||
// non moving / unmovable
|
||||
continue;
|
||||
case "THROWN_EXP_BOTTLE", "EXPERIENCE_BOTTLE":
|
||||
case "SPLASH_POTION", "POTION":
|
||||
case "SNOWBALL":
|
||||
case "SHULKER_BULLET":
|
||||
case "SPECTRAL_ARROW":
|
||||
case "ENDER_PEARL":
|
||||
case "ARROW":
|
||||
case "LLAMA_SPIT":
|
||||
case "TRIDENT":
|
||||
}
|
||||
case EXPERIENCE_BOTTLE, SPLASH_POTION, LINGERING_POTION, SNOWBALL, SHULKER_BULLET, SPECTRAL_ARROW,
|
||||
ENDER_PEARL, ARROW, LLAMA_SPIT, TRIDENT -> {
|
||||
// managed elsewhere | projectile
|
||||
continue;
|
||||
case "ITEM_FRAME":
|
||||
case "PAINTING":
|
||||
}
|
||||
case TNT, FALLING_BLOCK -> {
|
||||
// managed elsewhere
|
||||
}
|
||||
case ITEM_FRAME, PAINTING -> {
|
||||
// Not vehicles
|
||||
continue;
|
||||
case "ARMOR_STAND":
|
||||
// Temporarily classify as vehicle
|
||||
case "MINECART":
|
||||
case "MINECART_CHEST":
|
||||
case "CHEST_MINECART":
|
||||
case "MINECART_COMMAND":
|
||||
case "COMMAND_BLOCK_MINECART":
|
||||
case "MINECART_FURNACE":
|
||||
case "FURNACE_MINECART":
|
||||
case "MINECART_HOPPER":
|
||||
case "HOPPER_MINECART":
|
||||
case "MINECART_MOB_SPAWNER":
|
||||
case "SPAWNER_MINECART":
|
||||
case "END_CRYSTAL":
|
||||
case "ENDER_CRYSTAL": // Backwards compatibility for 1.20.4
|
||||
case "MINECART_TNT":
|
||||
case "TNT_MINECART":
|
||||
case "CHEST_BOAT":
|
||||
case "BOAT":
|
||||
case "ACACIA_BOAT", "BIRCH_BOAT", "CHERRY_BOAT", "DARK_OAK_BOAT", "JUNGLE_BOAT", "MANGROVE_BOAT",
|
||||
"OAK_BOAT", "PALE_OAK_BOAT", "SPRUCE_BOAT", "BAMBOO_RAFT":
|
||||
case "ACACIA_CHEST_BOAT", "BIRCH_CHEST_BOAT", "CHERRY_CHEST_BOAT", "DARK_OAK_CHEST_BOAT",
|
||||
"JUNGLE_CHEST_BOAT", "MANGROVE_CHEST_BOAT", "OAK_CHEST_BOAT", "PALE_OAK_CHEST_BOAT",
|
||||
"SPRUCE_CHEST_BOAT", "BAMBOO_CHEST_RAFT":
|
||||
}
|
||||
// ARMOR_STAND temporarily classified as vehicle
|
||||
case ARMOR_STAND, MINECART, CHEST_MINECART, COMMAND_BLOCK_MINECART, FURNACE_MINECART, HOPPER_MINECART,
|
||||
SPAWNER_MINECART, END_CRYSTAL, TNT_MINECART, ACACIA_BOAT, BIRCH_BOAT, CHERRY_BOAT, DARK_OAK_BOAT,
|
||||
JUNGLE_BOAT, MANGROVE_BOAT, OAK_BOAT, PALE_OAK_BOAT, SPRUCE_BOAT, BAMBOO_RAFT, ACACIA_CHEST_BOAT,
|
||||
BIRCH_CHEST_BOAT, CHERRY_CHEST_BOAT, DARK_OAK_CHEST_BOAT, JUNGLE_CHEST_BOAT, MANGROVE_CHEST_BOAT,
|
||||
OAK_CHEST_BOAT, PALE_OAK_CHEST_BOAT, SPRUCE_CHEST_BOAT, BAMBOO_CHEST_RAFT -> {
|
||||
if (Settings.Enabled_Components.KILL_ROAD_VEHICLES) {
|
||||
com.plotsquared.core.location.Location location = BukkitUtil.adapt(entity.getLocation());
|
||||
Plot plot = location.getPlot();
|
||||
@@ -885,22 +842,15 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl
|
||||
this.removeRoadEntity(entity, iterator);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
case "SMALL_FIREBALL":
|
||||
case "FIREBALL":
|
||||
case "DRAGON_FIREBALL":
|
||||
case "DROPPED_ITEM", "ITEM":
|
||||
}
|
||||
case SMALL_FIREBALL, FIREBALL, DRAGON_FIREBALL, ITEM, WIND_CHARGE, BREEZE_WIND_CHARGE -> {
|
||||
if (Settings.Enabled_Components.KILL_ROAD_ITEMS
|
||||
&& plotArea.getOwnedPlotAbs(BukkitUtil.adapt(entity.getLocation())) == null) {
|
||||
this.removeRoadEntity(entity, iterator);
|
||||
}
|
||||
// dropped item
|
||||
continue;
|
||||
case "PRIMED_TNT", "TNT":
|
||||
case "FALLING_BLOCK":
|
||||
// managed elsewhere
|
||||
continue;
|
||||
case "SHULKER":
|
||||
}
|
||||
case SHULKER -> {
|
||||
if (Settings.Enabled_Components.KILL_ROAD_MOBS && (Settings.Enabled_Components.KILL_NAMED_ROAD_MOBS || entity.getCustomName() == null)) {
|
||||
LivingEntity livingEntity = (LivingEntity) entity;
|
||||
List<MetadataValue> meta = entity.getMetadata("shulkerPlot");
|
||||
@@ -941,80 +891,16 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
case "ZOMBIFIED_PIGLIN":
|
||||
case "PIGLIN_BRUTE":
|
||||
case "LLAMA":
|
||||
case "DONKEY":
|
||||
case "MULE":
|
||||
case "ZOMBIE_HORSE":
|
||||
case "SKELETON_HORSE":
|
||||
case "HUSK":
|
||||
case "ELDER_GUARDIAN":
|
||||
case "WITHER_SKELETON":
|
||||
case "STRAY":
|
||||
case "ZOMBIE_VILLAGER":
|
||||
case "EVOKER":
|
||||
case "EVOKER_FANGS":
|
||||
case "VEX":
|
||||
case "VINDICATOR":
|
||||
case "POLAR_BEAR":
|
||||
case "BAT":
|
||||
case "BLAZE":
|
||||
case "CAVE_SPIDER":
|
||||
case "CHICKEN":
|
||||
case "COW":
|
||||
case "CREEPER":
|
||||
case "ENDERMAN":
|
||||
case "ENDERMITE":
|
||||
case "ENDER_DRAGON":
|
||||
case "GHAST":
|
||||
case "HAPPY_GHAST": // 1.21.6+
|
||||
case "GHASTLING": // 1.21.6+
|
||||
case "GIANT":
|
||||
case "GUARDIAN":
|
||||
case "HORSE":
|
||||
case "IRON_GOLEM":
|
||||
case "MAGMA_CUBE":
|
||||
case "MUSHROOM_COW", "MOOSHROOM":
|
||||
case "OCELOT":
|
||||
case "PIG":
|
||||
case "PIG_ZOMBIE":
|
||||
case "RABBIT":
|
||||
case "SHEEP":
|
||||
case "SILVERFISH":
|
||||
case "SKELETON":
|
||||
case "SLIME":
|
||||
case "SNOWMAN", "SNOW_GOLEM":
|
||||
case "SPIDER":
|
||||
case "SQUID":
|
||||
case "VILLAGER":
|
||||
case "WITCH":
|
||||
case "WITHER":
|
||||
case "WOLF":
|
||||
case "ZOMBIE":
|
||||
case "PARROT":
|
||||
case "SALMON":
|
||||
case "DOLPHIN":
|
||||
case "TROPICAL_FISH":
|
||||
case "DROWNED":
|
||||
case "COD":
|
||||
case "TURTLE":
|
||||
case "PUFFERFISH":
|
||||
case "PHANTOM":
|
||||
case "ILLUSIONER":
|
||||
case "CAT":
|
||||
case "PANDA":
|
||||
case "FOX":
|
||||
case "PILLAGER":
|
||||
case "TRADER_LLAMA":
|
||||
case "WANDERING_TRADER":
|
||||
case "RAVAGER":
|
||||
case "BEE":
|
||||
case "HOGLIN":
|
||||
case "PIGLIN":
|
||||
case "ZOGLIN":
|
||||
default: {
|
||||
}
|
||||
case ZOMBIFIED_PIGLIN, PIGLIN_BRUTE, LLAMA, DONKEY, MULE, ZOMBIE_HORSE, SKELETON_HORSE, HUSK,
|
||||
ELDER_GUARDIAN, WITHER_SKELETON, STRAY, ZOMBIE_VILLAGER, EVOKER, EVOKER_FANGS, VEX, VINDICATOR,
|
||||
POLAR_BEAR, BAT, BLAZE, CAVE_SPIDER, CHICKEN, COW, CREEPER, ENDERMAN, ENDERMITE, ENDER_DRAGON, GHAST,
|
||||
HAPPY_GHAST, GIANT, GUARDIAN, HORSE, IRON_GOLEM, MAGMA_CUBE, MOOSHROOM, OCELOT, PIG, RABBIT, SHEEP,
|
||||
SILVERFISH, SKELETON, SLIME, SNOW_GOLEM, SPIDER, SQUID, VILLAGER, WITCH, WITHER, WOLF, ZOMBIE,
|
||||
PARROT, SALMON, DOLPHIN, TROPICAL_FISH, DROWNED, COD, TURTLE, PUFFERFISH, PHANTOM, ILLUSIONER, CAT,
|
||||
PANDA, FOX, PILLAGER, TRADER_LLAMA, WANDERING_TRADER, RAVAGER, BEE, HOGLIN, PIGLIN, ZOGLIN, FROG,
|
||||
GOAT, WARDEN, TADPOLE, ALLAY, ARMADILLO, AXOLOTL, STRIDER, SNIFFER, CAMEL, BOGGED, COPPER_GOLEM,
|
||||
GLOW_SQUID, BREEZE, CREAKING -> {
|
||||
if (Settings.Enabled_Components.KILL_ROAD_MOBS) {
|
||||
Location location = entity.getLocation();
|
||||
if (BukkitUtil.adapt(location).isPlotRoad()) {
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
package com.plotsquared.bukkit.entity;
|
||||
|
||||
import com.sk89q.worldedit.util.Enums;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.EnumMap;
|
||||
|
||||
/**
|
||||
* Wrapper Class for Bukkit {@link org.bukkit.entity.EntityType EntityTypes}.
|
||||
* <br>
|
||||
* Intended for a backwards compatible way to interact with entity types. Enum Constants should always be named after the
|
||||
* constants of bukkits EntityType enum in the latest supported versions. Backwards compatible enum constants identifiers
|
||||
* should have a comment assigned to them, so they can be removed in future versions.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
public enum EntityType {
|
||||
|
||||
ACACIA_BOAT,
|
||||
ACACIA_CHEST_BOAT,
|
||||
ALLAY,
|
||||
AREA_EFFECT_CLOUD,
|
||||
ARMADILLO,
|
||||
ARMOR_STAND,
|
||||
ARROW,
|
||||
AXOLOTL,
|
||||
BAMBOO_CHEST_RAFT,
|
||||
BAMBOO_RAFT,
|
||||
BAT,
|
||||
BEE,
|
||||
BIRCH_BOAT,
|
||||
BIRCH_CHEST_BOAT,
|
||||
BLAZE,
|
||||
BLOCK_DISPLAY,
|
||||
BOGGED,
|
||||
BREEZE,
|
||||
BREEZE_WIND_CHARGE,
|
||||
CAMEL,
|
||||
CAT,
|
||||
CAVE_SPIDER,
|
||||
CHERRY_BOAT,
|
||||
CHERRY_CHEST_BOAT,
|
||||
// 1.20.5: MINECART_CHEST -> CHEST_MINECART
|
||||
CHEST_MINECART("MINECART_CHEST"),
|
||||
CHICKEN,
|
||||
COD,
|
||||
// 1.20.5: MINECART_COMMAND -> COMMAND_BLOCK_MINECART
|
||||
COMMAND_BLOCK_MINECART("MINECART_COMMAND"),
|
||||
COPPER_GOLEM,
|
||||
COW,
|
||||
CREAKING,
|
||||
CREEPER,
|
||||
DARK_OAK_BOAT,
|
||||
DARK_OAK_CHEST_BOAT,
|
||||
DOLPHIN,
|
||||
DONKEY,
|
||||
DRAGON_FIREBALL,
|
||||
DROWNED,
|
||||
EGG,
|
||||
ELDER_GUARDIAN,
|
||||
// 1.20.5: ENDER_CRYSTAL -> END_CRYSTAL
|
||||
END_CRYSTAL("ENDER_CRYSTAL"),
|
||||
ENDER_DRAGON,
|
||||
ENDER_PEARL,
|
||||
ENDERMAN,
|
||||
ENDERMITE,
|
||||
EVOKER,
|
||||
EVOKER_FANGS,
|
||||
// 1.20.5: THROWN_EXP_BOTTLE -> EXPERIENCE_BOTTLE
|
||||
EXPERIENCE_BOTTLE("THROWN_EXP_BOTTLE"),
|
||||
EXPERIENCE_ORB,
|
||||
// 1.20.5: ENDER_SIGNAL -> EYE_OF_ENDER
|
||||
EYE_OF_ENDER("ENDER_SIGNAL"),
|
||||
FALLING_BLOCK,
|
||||
FIREBALL,
|
||||
// 1.20.5: FIREWORK -> FIREWORK_ROCKET
|
||||
FIREWORK_ROCKET("FIREWORK"),
|
||||
// 1.20.5: FISHING_HOOK -> FISHING_BOBBER
|
||||
FISHING_BOBBER("FISHING_HOOK"),
|
||||
FOX,
|
||||
FROG,
|
||||
// 1.20.5: MINECART_FURNACE -> FURNACE_MINECART
|
||||
FURNACE_MINECART("MINECART_FURNACE"),
|
||||
GHAST,
|
||||
GIANT,
|
||||
GLOW_ITEM_FRAME,
|
||||
GLOW_SQUID,
|
||||
GOAT,
|
||||
GUARDIAN,
|
||||
HAPPY_GHAST,
|
||||
HOGLIN,
|
||||
// 1.20.5: MINECART_HOPPER -> HOPPER_MINECART
|
||||
HOPPER_MINECART("MINECART_HOPPER"),
|
||||
HORSE,
|
||||
HUSK,
|
||||
ILLUSIONER,
|
||||
INTERACTION,
|
||||
IRON_GOLEM,
|
||||
// 1.20.5: DROPPED_ITEM -> ITEM
|
||||
ITEM("DROPPED_ITEM"),
|
||||
ITEM_DISPLAY,
|
||||
ITEM_FRAME,
|
||||
JUNGLE_BOAT,
|
||||
JUNGLE_CHEST_BOAT,
|
||||
// 1.20.5: LEASH_HITCH -> LEASH_KNOT
|
||||
LEASH_KNOT("LEASH_HITCH"),
|
||||
// 1.20.5: LIGHTNING -> LIGHTNING_BOLT
|
||||
LIGHTNING_BOLT("LIGHTNING"),
|
||||
LINGERING_POTION,
|
||||
LLAMA,
|
||||
LLAMA_SPIT,
|
||||
MAGMA_CUBE,
|
||||
MANGROVE_BOAT,
|
||||
MANGROVE_CHEST_BOAT,
|
||||
MANNEQUIN,
|
||||
MARKER,
|
||||
MINECART,
|
||||
// 1.20.5: MUSHROOM_COW -> MOOSHROOM
|
||||
MOOSHROOM("MUSHROOM_COW"),
|
||||
MULE,
|
||||
// 1.21.3: BOAT -> boat subvariants (oak, dark_oak, ...)
|
||||
OAK_BOAT("BOAT"),
|
||||
// 1.21.3: CHEST_BOAT -> chest boat subvariants (oak, dark_oak, ...)
|
||||
OAK_CHEST_BOAT("CHEST_BOAT"),
|
||||
OCELOT,
|
||||
OMINOUS_ITEM_SPAWNER,
|
||||
PAINTING,
|
||||
PALE_OAK_BOAT,
|
||||
PALE_OAK_CHEST_BOAT,
|
||||
PANDA,
|
||||
PARROT,
|
||||
PHANTOM,
|
||||
PIG,
|
||||
PIGLIN,
|
||||
PIGLIN_BRUTE,
|
||||
PILLAGER,
|
||||
PLAYER,
|
||||
POLAR_BEAR,
|
||||
PUFFERFISH,
|
||||
RABBIT,
|
||||
RAVAGER,
|
||||
SALMON,
|
||||
SHEEP,
|
||||
SHULKER,
|
||||
SHULKER_BULLET,
|
||||
SILVERFISH,
|
||||
SKELETON,
|
||||
SKELETON_HORSE,
|
||||
SLIME,
|
||||
SMALL_FIREBALL,
|
||||
SNIFFER,
|
||||
// 1.20.5: SNOWMAN -> SNOW_GOLEM
|
||||
SNOW_GOLEM("SNOWMAN"),
|
||||
SNOWBALL,
|
||||
// 1.20.5: MINECART_MOB_SPAWNER -> SPAWNER_MINECART
|
||||
SPAWNER_MINECART("MINECART_MOB_SPAWNER"),
|
||||
SPECTRAL_ARROW,
|
||||
SPIDER,
|
||||
// 1.21.5: POTION -> SPLASH_POTION + LINGERING_POTION (use SPLASH_POTION FOR compatibility)
|
||||
SPLASH_POTION("POTION"),
|
||||
SPRUCE_BOAT,
|
||||
SPRUCE_CHEST_BOAT,
|
||||
SQUID,
|
||||
STRAY,
|
||||
STRIDER,
|
||||
TADPOLE,
|
||||
TEXT_DISPLAY,
|
||||
// 1.20.5: PRIMED_TNT -> TNT
|
||||
TNT("PRIMED_TNT"),
|
||||
// 1.20.5: MINECART_TNT -> TNT_MINECART
|
||||
TNT_MINECART("MINECART_TNT"),
|
||||
TRADER_LLAMA,
|
||||
TRIDENT,
|
||||
TROPICAL_FISH,
|
||||
TURTLE,
|
||||
UNKNOWN,
|
||||
VEX,
|
||||
VILLAGER,
|
||||
VINDICATOR,
|
||||
WANDERING_TRADER,
|
||||
WARDEN,
|
||||
WIND_CHARGE,
|
||||
WITCH,
|
||||
WITHER,
|
||||
WITHER_SKELETON,
|
||||
WITHER_SKULL,
|
||||
WOLF,
|
||||
ZOGLIN,
|
||||
ZOMBIE,
|
||||
ZOMBIE_HORSE,
|
||||
ZOMBIE_VILLAGER,
|
||||
ZOMBIFIED_PIGLIN;
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("PlotSquared/" + EntityType.class.getSimpleName());
|
||||
private static final EnumMap<org.bukkit.entity.EntityType, EntityType> BUKKIT_TO_INTERNAL =
|
||||
new EnumMap<>(org.bukkit.entity.EntityType.class);
|
||||
|
||||
private final org.bukkit.entity.EntityType bukkitType;
|
||||
|
||||
EntityType(final String... additionalBukkitEnumFields) {
|
||||
org.bukkit.entity.EntityType temp = null;
|
||||
try {
|
||||
temp = org.bukkit.entity.EntityType.valueOf(name());
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
if (additionalBukkitEnumFields.length > 0) {
|
||||
temp = Enums.findByValue(org.bukkit.entity.EntityType.class, additionalBukkitEnumFields);
|
||||
}
|
||||
}
|
||||
bukkitType = temp;
|
||||
}
|
||||
|
||||
public @Nullable org.bukkit.entity.EntityType bukkitType() {
|
||||
return bukkitType;
|
||||
}
|
||||
|
||||
public boolean isAlive() {
|
||||
return this.bukkitType != null && this.bukkitType.isAlive();
|
||||
}
|
||||
|
||||
public boolean isSpawnable() {
|
||||
return this.bukkitType != null && this.bukkitType.isSpawnable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "EntityType{name=" + name() + "}";
|
||||
}
|
||||
|
||||
public static EntityType of(org.bukkit.entity.EntityType bukkitType) {
|
||||
return BUKKIT_TO_INTERNAL.get(bukkitType);
|
||||
}
|
||||
|
||||
public static EntityType of(Entity entity) {
|
||||
return of(entity.getType());
|
||||
}
|
||||
|
||||
static {
|
||||
// Register all entity types with their aliases
|
||||
for (final EntityType value : values()) {
|
||||
org.bukkit.entity.EntityType bukkitType = value.bukkitType();
|
||||
if (bukkitType != null) {
|
||||
BUKKIT_TO_INTERNAL.put(bukkitType, value);
|
||||
}
|
||||
}
|
||||
// Make sure this wrapper contains EVERY possible entity type available by the server
|
||||
for (final org.bukkit.entity.EntityType bukkitType : org.bukkit.entity.EntityType.values()) {
|
||||
if (!BUKKIT_TO_INTERNAL.containsKey(bukkitType)) {
|
||||
LOGGER.error(
|
||||
"EntityType {} provided by server has no wrapper equivalent. Is this server version supported? " +
|
||||
"Falling back to 'UNKNOWN' type.",
|
||||
bukkitType
|
||||
);
|
||||
BUKKIT_TO_INTERNAL.put(bukkitType, EntityType.UNKNOWN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,7 +21,6 @@ package com.plotsquared.bukkit.entity;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
public abstract class EntityWrapper {
|
||||
@@ -36,7 +35,7 @@ public abstract class EntityWrapper {
|
||||
|
||||
EntityWrapper(final @NonNull Entity entity) {
|
||||
this.entity = entity;
|
||||
this.type = entity.getType();
|
||||
this.type = EntityType.of(entity.getType());
|
||||
|
||||
final Location location = entity.getLocation();
|
||||
this.x = location.getX();
|
||||
@@ -49,7 +48,7 @@ public abstract class EntityWrapper {
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("[%s, x=%s, y=%s, z=%s]", type.getName(), x, y, z);
|
||||
return String.format("[%s, x=%s, y=%s, z=%s]", type, x, y, z);
|
||||
}
|
||||
|
||||
public abstract Entity spawn(World world, int xOffset, int zOffset);
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.bukkit.entity.ChestBoat;
|
||||
import org.bukkit.entity.ChestedHorse;
|
||||
import org.bukkit.entity.EnderDragon;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.GlowItemFrame;
|
||||
import org.bukkit.entity.IronGolem;
|
||||
import org.bukkit.entity.Item;
|
||||
import org.bukkit.entity.ItemFrame;
|
||||
@@ -52,6 +53,7 @@ import org.bukkit.util.EulerAngle;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public final class ReplicatingEntityWrapper extends EntityWrapper {
|
||||
|
||||
@@ -85,7 +87,7 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
|
||||
return;
|
||||
}
|
||||
List<Entity> passengers = entity.getPassengers();
|
||||
if (passengers.size() > 0) {
|
||||
if (!passengers.isEmpty()) {
|
||||
this.base.passenger = new ReplicatingEntityWrapper(passengers.get(0), depth);
|
||||
}
|
||||
this.base.fall = entity.getFallDistance();
|
||||
@@ -101,44 +103,40 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
|
||||
if (!entity.hasGravity()) {
|
||||
this.noGravity = true;
|
||||
}
|
||||
switch (entity.getType().toString()) {
|
||||
case "BOAT", "ACACIA_BOAT", "BIRCH_BOAT", "CHERRY_BOAT", "DARK_OAK_BOAT", "JUNGLE_BOAT", "MANGROVE_BOAT",
|
||||
"OAK_BOAT", "PALE_OAK_BOAT", "SPRUCE_BOAT", "BAMBOO_RAFT" -> {
|
||||
switch (EntityType.of(entity.getType())) {
|
||||
case ACACIA_BOAT, BIRCH_BOAT, CHERRY_BOAT, DARK_OAK_BOAT, JUNGLE_BOAT, MANGROVE_BOAT,
|
||||
OAK_BOAT, PALE_OAK_BOAT, SPRUCE_BOAT, BAMBOO_RAFT -> {
|
||||
Boat boat = (Boat) entity;
|
||||
this.dataByte = getOrdinal(Boat.Type.values(), boat.getBoatType());
|
||||
return;
|
||||
}
|
||||
case "ACACIA_CHEST_BOAT", "BIRCH_CHEST_BOAT", "CHERRY_CHEST_BOAT", "DARK_OAK_CHEST_BOAT",
|
||||
"JUNGLE_CHEST_BOAT", "MANGROVE_CHEST_BOAT", "OAK_CHEST_BOAT", "PALE_OAK_CHEST_BOAT",
|
||||
"SPRUCE_CHEST_BOAT", "BAMBOO_CHEST_RAFT" -> {
|
||||
case ACACIA_CHEST_BOAT, BIRCH_CHEST_BOAT, CHERRY_CHEST_BOAT, DARK_OAK_CHEST_BOAT,
|
||||
JUNGLE_CHEST_BOAT, MANGROVE_CHEST_BOAT, OAK_CHEST_BOAT, PALE_OAK_CHEST_BOAT,
|
||||
SPRUCE_CHEST_BOAT, BAMBOO_CHEST_RAFT -> {
|
||||
ChestBoat boat = (ChestBoat) entity;
|
||||
this.dataByte = getOrdinal(Boat.Type.values(), boat.getBoatType());
|
||||
storeInventory(boat);
|
||||
}
|
||||
case "ARROW", "EGG", "END_CRYSTAL", "ENDER_CRYSTAL", "ENDER_PEARL", "ENDER_SIGNAL", "EXPERIENCE_ORB", "FALLING_BLOCK", "FIREBALL",
|
||||
"FIREWORK", "FISHING_HOOK", "LEASH_HITCH", "LIGHTNING", "MINECART", "MINECART_COMMAND", "MINECART_MOB_SPAWNER",
|
||||
"MINECART_TNT", "PLAYER", "PRIMED_TNT", "SLIME", "SMALL_FIREBALL", "SNOWBALL", "MINECART_FURNACE", "SPLASH_POTION",
|
||||
"THROWN_EXP_BOTTLE", "WITHER_SKULL", "UNKNOWN", "SPECTRAL_ARROW", "SHULKER_BULLET", "DRAGON_FIREBALL", "AREA_EFFECT_CLOUD",
|
||||
"TRIDENT", "LLAMA_SPIT" -> {
|
||||
case ARROW, EGG, END_CRYSTAL, ENDER_PEARL, EYE_OF_ENDER, EXPERIENCE_ORB, FALLING_BLOCK, FIREBALL,
|
||||
FIREWORK_ROCKET, FISHING_BOBBER, LEASH_KNOT, LIGHTNING_BOLT, MINECART, COMMAND_BLOCK_MINECART,
|
||||
SPAWNER_MINECART, TNT_MINECART, PLAYER, TNT, SLIME, SMALL_FIREBALL, SNOWBALL, FURNACE_MINECART, SPLASH_POTION,
|
||||
EXPERIENCE_BOTTLE, WITHER_SKULL, UNKNOWN, SPECTRAL_ARROW, SHULKER_BULLET, DRAGON_FIREBALL, AREA_EFFECT_CLOUD,
|
||||
TRIDENT, LLAMA_SPIT -> {
|
||||
// Do this stuff later
|
||||
return;
|
||||
}
|
||||
// MISC //
|
||||
case "DROPPED_ITEM", "ITEM" -> {
|
||||
case ITEM -> {
|
||||
Item item = (Item) entity;
|
||||
this.stack = item.getItemStack();
|
||||
return;
|
||||
}
|
||||
case "ITEM_FRAME" -> {
|
||||
case ITEM_FRAME, GLOW_ITEM_FRAME -> {
|
||||
this.x = Math.floor(this.getX());
|
||||
this.y = Math.floor(this.getY());
|
||||
this.z = Math.floor(this.getZ());
|
||||
ItemFrame itemFrame = (ItemFrame) entity;
|
||||
this.dataByte = getOrdinal(Rotation.values(), itemFrame.getRotation());
|
||||
this.stack = itemFrame.getItem().clone();
|
||||
return;
|
||||
}
|
||||
case "PAINTING" -> {
|
||||
case PAINTING -> {
|
||||
this.x = Math.floor(this.getX());
|
||||
this.y = Math.floor(this.getY());
|
||||
this.z = Math.floor(this.getZ());
|
||||
@@ -150,18 +148,16 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
|
||||
this.y -= 1;
|
||||
}
|
||||
this.dataString = art.name();
|
||||
return;
|
||||
}
|
||||
// END MISC //
|
||||
// INVENTORY HOLDER //
|
||||
case "MINECART_CHEST", "CHEST_MINECART", "MINECART_HOPPER", "HOPPER_MINECART" -> {
|
||||
case CHEST_MINECART, HOPPER_MINECART -> {
|
||||
storeInventory((InventoryHolder) entity);
|
||||
return;
|
||||
}
|
||||
// START LIVING ENTITY //
|
||||
// START AGEABLE //
|
||||
// START TAMEABLE //
|
||||
case "CAMEL", "HORSE", "DONKEY", "LLAMA", "TRADER_LLAMA", "MULE", "SKELETON_HORSE", "ZOMBIE_HORSE" -> {
|
||||
case CAMEL, HORSE, DONKEY, LLAMA, TRADER_LLAMA, MULE, SKELETON_HORSE, ZOMBIE_HORSE -> {
|
||||
AbstractHorse horse = (AbstractHorse) entity;
|
||||
this.horse = new HorseStats();
|
||||
this.horse.jump = horse.getJumpStrength();
|
||||
@@ -176,17 +172,15 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
|
||||
storeBreedable(horse);
|
||||
storeLiving(horse);
|
||||
storeInventory(horse);
|
||||
return;
|
||||
}
|
||||
// END INVENTORY HOLDER //
|
||||
case "WOLF", "OCELOT", "CAT", "PARROT" -> {
|
||||
case WOLF, OCELOT, CAT, PARROT -> {
|
||||
storeTameable((Tameable) entity);
|
||||
storeBreedable((Breedable) entity);
|
||||
storeLiving((LivingEntity) entity);
|
||||
return;
|
||||
}
|
||||
// END TAMEABLE //
|
||||
case "SHEEP" -> {
|
||||
case SHEEP -> {
|
||||
Sheep sheep = (Sheep) entity;
|
||||
if (sheep.isSheared()) {
|
||||
this.dataByte = (byte) 1;
|
||||
@@ -196,21 +190,18 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
|
||||
this.dataByte2 = getOrdinal(DyeColor.values(), sheep.getColor());
|
||||
storeBreedable(sheep);
|
||||
storeLiving(sheep);
|
||||
return;
|
||||
}
|
||||
case "VILLAGER", "CHICKEN", "COW", "MUSHROOM_COW", "PIG", "TURTLE", "POLAR_BEAR" -> {
|
||||
case VILLAGER, CHICKEN, COW, MOOSHROOM, PIG, TURTLE, POLAR_BEAR -> {
|
||||
storeBreedable((Breedable) entity);
|
||||
storeLiving((LivingEntity) entity);
|
||||
return;
|
||||
}
|
||||
case "RABBIT" -> {
|
||||
case RABBIT -> {
|
||||
this.dataByte = getOrdinal(Rabbit.Type.values(), ((Rabbit) entity).getRabbitType());
|
||||
storeBreedable((Breedable) entity);
|
||||
storeLiving((LivingEntity) entity);
|
||||
return;
|
||||
}
|
||||
// END AGEABLE //
|
||||
case "ARMOR_STAND" -> {
|
||||
case ARMOR_STAND -> {
|
||||
ArmorStand stand = (ArmorStand) entity;
|
||||
this.inventory =
|
||||
new ItemStack[]{stand.getItemInHand().clone(), stand.getHelmet().clone(),
|
||||
@@ -254,31 +245,26 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
|
||||
if (stand.isSmall()) {
|
||||
this.stand.small = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
case "ENDERMITE" -> {
|
||||
return;
|
||||
case ENDERMITE -> {
|
||||
}
|
||||
case "BAT" -> {
|
||||
case BAT -> {
|
||||
if (((Bat) entity).isAwake()) {
|
||||
this.dataByte = (byte) 1;
|
||||
} else {
|
||||
this.dataByte = (byte) 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
case "ENDER_DRAGON" -> {
|
||||
case ENDER_DRAGON -> {
|
||||
EnderDragon entity1 = (EnderDragon) entity;
|
||||
this.dataByte = (byte) entity1.getPhase().ordinal();
|
||||
return;
|
||||
}
|
||||
case "SKELETON", "WITHER_SKELETON", "GUARDIAN", "ELDER_GUARDIAN", "GHAST", "HAPPY_GHAST", "GHASTLING", "MAGMA_CUBE", "SQUID", "PIG_ZOMBIE", "HOGLIN",
|
||||
"ZOMBIFIED_PIGLIN", "PIGLIN", "PIGLIN_BRUTE", "ZOMBIE", "WITHER", "WITCH", "SPIDER", "CAVE_SPIDER", "SILVERFISH",
|
||||
"GIANT", "ENDERMAN", "CREEPER", "BLAZE", "SHULKER", "SNOWMAN", "SNOW_GOLEM" -> {
|
||||
case SKELETON, WITHER_SKELETON, GUARDIAN, ELDER_GUARDIAN, GHAST, HAPPY_GHAST, MAGMA_CUBE,
|
||||
SQUID, HOGLIN, ZOMBIFIED_PIGLIN, PIGLIN, PIGLIN_BRUTE, ZOMBIE, WITHER, WITCH, SPIDER, CAVE_SPIDER, SILVERFISH,
|
||||
GIANT, ENDERMAN, CREEPER, BLAZE, SHULKER, SNOW_GOLEM -> {
|
||||
storeLiving((LivingEntity) entity);
|
||||
return;
|
||||
}
|
||||
case "IRON_GOLEM" -> {
|
||||
case IRON_GOLEM -> {
|
||||
if (((IronGolem) entity).isPlayerCreated()) {
|
||||
this.dataByte = (byte) 1;
|
||||
} else {
|
||||
@@ -390,8 +376,8 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #restoreBreedable(Breedable)} instead
|
||||
* @since 7.1.0
|
||||
* @deprecated Use {@link #restoreBreedable(Breedable)} instead
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "7.1.0")
|
||||
private void restoreAgeable(Ageable entity) {
|
||||
@@ -405,8 +391,8 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #storeBreedable(Breedable)} instead
|
||||
* @since 7.1.0
|
||||
* @deprecated Use {@link #storeBreedable(Breedable)} instead
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "7.1.0")
|
||||
public void storeAgeable(Ageable aged) {
|
||||
@@ -455,16 +441,17 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
|
||||
return null;
|
||||
}
|
||||
Entity entity;
|
||||
switch (this.getType().toString()) {
|
||||
case "DROPPED_ITEM", "ITEM" -> {
|
||||
switch (this.getType()) {
|
||||
case ITEM -> {
|
||||
return world.dropItem(location, this.stack);
|
||||
}
|
||||
case "PLAYER", "LEASH_HITCH" -> {
|
||||
case PLAYER, LEASH_KNOT -> {
|
||||
return null;
|
||||
}
|
||||
case "ITEM_FRAME" -> entity = world.spawn(location, ItemFrame.class);
|
||||
case "PAINTING" -> entity = world.spawn(location, Painting.class);
|
||||
default -> entity = world.spawnEntity(location, this.getType());
|
||||
case ITEM_FRAME -> entity = world.spawn(location, ItemFrame.class);
|
||||
case GLOW_ITEM_FRAME -> entity = world.spawn(location, GlowItemFrame.class);
|
||||
case PAINTING -> entity = world.spawn(location, Painting.class);
|
||||
default -> entity = world.spawnEntity(location, Objects.requireNonNull(this.getType().bukkitType()));
|
||||
}
|
||||
if (this.depth == 0) {
|
||||
return entity;
|
||||
@@ -491,16 +478,16 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
|
||||
if (this.noGravity) {
|
||||
entity.setGravity(false);
|
||||
}
|
||||
switch (entity.getType().toString()) {
|
||||
case "BOAT", "ACACIA_BOAT", "BIRCH_BOAT", "CHERRY_BOAT", "DARK_OAK_BOAT", "JUNGLE_BOAT", "MANGROVE_BOAT",
|
||||
"OAK_BOAT", "PALE_OAK_BOAT", "SPRUCE_BOAT", "BAMBOO_RAFT" -> {
|
||||
switch (EntityType.of(entity.getType())) {
|
||||
case ACACIA_BOAT, BIRCH_BOAT, CHERRY_BOAT, DARK_OAK_BOAT, JUNGLE_BOAT, MANGROVE_BOAT,
|
||||
OAK_BOAT, PALE_OAK_BOAT, SPRUCE_BOAT, BAMBOO_RAFT -> {
|
||||
Boat boat = (Boat) entity;
|
||||
boat.setBoatType(Boat.Type.values()[dataByte]);
|
||||
return entity;
|
||||
}
|
||||
case "ACACIA_CHEST_BOAT", "BIRCH_CHEST_BOAT", "CHERRY_CHEST_BOAT", "DARK_OAK_CHEST_BOAT",
|
||||
"JUNGLE_CHEST_BOAT", "MANGROVE_CHEST_BOAT", "OAK_CHEST_BOAT", "PALE_OAK_CHEST_BOAT",
|
||||
"SPRUCE_CHEST_BOAT", "BAMBOO_CHEST_RAFT" -> {
|
||||
case ACACIA_CHEST_BOAT, BIRCH_CHEST_BOAT, CHERRY_CHEST_BOAT, DARK_OAK_CHEST_BOAT,
|
||||
JUNGLE_CHEST_BOAT, MANGROVE_CHEST_BOAT, OAK_CHEST_BOAT, PALE_OAK_CHEST_BOAT,
|
||||
SPRUCE_CHEST_BOAT, BAMBOO_CHEST_RAFT -> {
|
||||
ChestBoat boat = (ChestBoat) entity;
|
||||
boat.setBoatType(Boat.Type.values()[dataByte]);
|
||||
restoreInventory(boat);
|
||||
@@ -511,22 +498,22 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
|
||||
((Slime) entity).setSize(this.dataByte);
|
||||
return entity;
|
||||
} */
|
||||
case "ARROW", "EGG", "END_CRYSTAL", "ENDER_CRYSTAL", "ENDER_PEARL", "ENDER_SIGNAL", "DROPPED_ITEM", "EXPERIENCE_ORB", "FALLING_BLOCK",
|
||||
"FIREBALL", "FIREWORK", "FISHING_HOOK", "LEASH_HITCH", "LIGHTNING", "MINECART", "MINECART_COMMAND",
|
||||
"MINECART_MOB_SPAWNER", "MINECART_TNT", "PLAYER", "PRIMED_TNT", "SMALL_FIREBALL", "SNOWBALL",
|
||||
"SPLASH_POTION", "THROWN_EXP_BOTTLE", "SPECTRAL_ARROW", "SHULKER_BULLET", "AREA_EFFECT_CLOUD",
|
||||
"DRAGON_FIREBALL", "WITHER_SKULL", "MINECART_FURNACE", "LLAMA_SPIT", "TRIDENT", "UNKNOWN" -> {
|
||||
case ARROW, EGG, END_CRYSTAL, ENDER_PEARL, EYE_OF_ENDER, ITEM, EXPERIENCE_ORB, FALLING_BLOCK, FIREBALL,
|
||||
FIREWORK_ROCKET, FISHING_BOBBER, LEASH_KNOT, LIGHTNING_BOLT, MINECART, COMMAND_BLOCK_MINECART, SPAWNER_MINECART,
|
||||
TNT_MINECART, PLAYER, TNT, SMALL_FIREBALL, SNOWBALL, SPLASH_POTION, EXPERIENCE_BOTTLE, SPECTRAL_ARROW,
|
||||
SHULKER_BULLET, AREA_EFFECT_CLOUD, DRAGON_FIREBALL, WITHER_SKULL, FURNACE_MINECART, LLAMA_SPIT, TRIDENT,
|
||||
UNKNOWN -> {
|
||||
// Do this stuff later
|
||||
return entity;
|
||||
}
|
||||
// MISC //
|
||||
case "ITEM_FRAME" -> {
|
||||
case ITEM_FRAME, GLOW_ITEM_FRAME -> {
|
||||
ItemFrame itemframe = (ItemFrame) entity;
|
||||
itemframe.setRotation(Rotation.values()[this.dataByte]);
|
||||
itemframe.setItem(this.stack);
|
||||
return entity;
|
||||
}
|
||||
case "PAINTING" -> {
|
||||
case PAINTING -> {
|
||||
Painting painting = (Painting) entity;
|
||||
painting.setFacingDirection(BlockFace.values()[this.dataByte], true);
|
||||
painting.setArt(Art.getByName(this.dataString), true);
|
||||
@@ -534,14 +521,14 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
|
||||
}
|
||||
// END MISC //
|
||||
// INVENTORY HOLDER //
|
||||
case "MINECART_CHEST", "CHEST_MINECART", "MINECART_HOPPER", "HOPPER_MINECART" -> {
|
||||
case CHEST_MINECART, HOPPER_MINECART -> {
|
||||
restoreInventory((InventoryHolder) entity);
|
||||
return entity;
|
||||
}
|
||||
// START LIVING ENTITY //
|
||||
// START AGEABLE //
|
||||
// START TAMEABLE //
|
||||
case "CAMEL", "HORSE", "DONKEY", "LLAMA", "TRADER_LLAMA", "MULE", "SKELETON_HORSE", "ZOMBIE_HORSE" -> {
|
||||
case CAMEL, HORSE, DONKEY, LLAMA, TRADER_LLAMA, MULE, SKELETON_HORSE, ZOMBIE_HORSE -> {
|
||||
AbstractHorse horse = (AbstractHorse) entity;
|
||||
horse.setJumpStrength(this.horse.jump);
|
||||
if (horse instanceof ChestedHorse) {
|
||||
@@ -558,14 +545,14 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
|
||||
return entity;
|
||||
}
|
||||
// END INVENTORY HOLDER //
|
||||
case "WOLF", "OCELOT", "CAT", "PARROT" -> {
|
||||
case WOLF, OCELOT, CAT, PARROT -> {
|
||||
restoreTameable((Tameable) entity);
|
||||
restoreBreedable((Breedable) entity);
|
||||
restoreLiving((LivingEntity) entity);
|
||||
return entity;
|
||||
}
|
||||
// END AGEABLE //
|
||||
case "SHEEP" -> {
|
||||
case SHEEP -> {
|
||||
Sheep sheep = (Sheep) entity;
|
||||
if (this.dataByte == 1) {
|
||||
sheep.setSheared(true);
|
||||
@@ -577,13 +564,13 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
|
||||
restoreLiving(sheep);
|
||||
return sheep;
|
||||
}
|
||||
case "VILLAGER", "CHICKEN", "COW", "TURTLE", "POLAR_BEAR", "MUSHROOM_COW", "PIG" -> {
|
||||
case VILLAGER, CHICKEN, COW, TURTLE, POLAR_BEAR, MOOSHROOM, PIG -> {
|
||||
restoreBreedable((Breedable) entity);
|
||||
restoreLiving((LivingEntity) entity);
|
||||
return entity;
|
||||
}
|
||||
// END AGEABLE //
|
||||
case "RABBIT" -> {
|
||||
case RABBIT -> {
|
||||
if (this.dataByte != 0) {
|
||||
((Rabbit) entity).setRabbitType(Rabbit.Type.values()[this.dataByte]);
|
||||
}
|
||||
@@ -591,7 +578,7 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
|
||||
restoreLiving((LivingEntity) entity);
|
||||
return entity;
|
||||
}
|
||||
case "ARMOR_STAND" -> {
|
||||
case ARMOR_STAND -> {
|
||||
// CHECK positions
|
||||
ArmorStand stand = (ArmorStand) entity;
|
||||
if (this.inventory[0] != null) {
|
||||
@@ -610,41 +597,27 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
|
||||
stand.setBoots(this.inventory[4]);
|
||||
}
|
||||
if (this.stand.head[0] != 0 || this.stand.head[1] != 0 || this.stand.head[2] != 0) {
|
||||
EulerAngle pose =
|
||||
new EulerAngle(this.stand.head[0], this.stand.head[1], this.stand.head[2]);
|
||||
EulerAngle pose = new EulerAngle(this.stand.head[0], this.stand.head[1], this.stand.head[2]);
|
||||
stand.setHeadPose(pose);
|
||||
}
|
||||
if (this.stand.body[0] != 0 || this.stand.body[1] != 0 || this.stand.body[2] != 0) {
|
||||
EulerAngle pose =
|
||||
new EulerAngle(this.stand.body[0], this.stand.body[1], this.stand.body[2]);
|
||||
EulerAngle pose = new EulerAngle(this.stand.body[0], this.stand.body[1], this.stand.body[2]);
|
||||
stand.setBodyPose(pose);
|
||||
}
|
||||
if (this.stand.leftLeg[0] != 0 || this.stand.leftLeg[1] != 0
|
||||
|| this.stand.leftLeg[2] != 0) {
|
||||
EulerAngle pose = new EulerAngle(this.stand.leftLeg[0], this.stand.leftLeg[1],
|
||||
this.stand.leftLeg[2]
|
||||
);
|
||||
if (this.stand.leftLeg[0] != 0 || this.stand.leftLeg[1] != 0 || this.stand.leftLeg[2] != 0) {
|
||||
EulerAngle pose = new EulerAngle(this.stand.leftLeg[0], this.stand.leftLeg[1], this.stand.leftLeg[2]);
|
||||
stand.setLeftLegPose(pose);
|
||||
}
|
||||
if (this.stand.rightLeg[0] != 0 || this.stand.rightLeg[1] != 0
|
||||
|| this.stand.rightLeg[2] != 0) {
|
||||
EulerAngle pose = new EulerAngle(this.stand.rightLeg[0], this.stand.rightLeg[1],
|
||||
this.stand.rightLeg[2]
|
||||
);
|
||||
if (this.stand.rightLeg[0] != 0 || this.stand.rightLeg[1] != 0 || this.stand.rightLeg[2] != 0) {
|
||||
EulerAngle pose = new EulerAngle(this.stand.rightLeg[0], this.stand.rightLeg[1], this.stand.rightLeg[2]);
|
||||
stand.setRightLegPose(pose);
|
||||
}
|
||||
if (this.stand.leftArm[0] != 0 || this.stand.leftArm[1] != 0
|
||||
|| this.stand.leftArm[2] != 0) {
|
||||
EulerAngle pose = new EulerAngle(this.stand.leftArm[0], this.stand.leftArm[1],
|
||||
this.stand.leftArm[2]
|
||||
);
|
||||
if (this.stand.leftArm[0] != 0 || this.stand.leftArm[1] != 0 || this.stand.leftArm[2] != 0) {
|
||||
EulerAngle pose = new EulerAngle(this.stand.leftArm[0], this.stand.leftArm[1], this.stand.leftArm[2]);
|
||||
stand.setLeftArmPose(pose);
|
||||
}
|
||||
if (this.stand.rightArm[0] != 0 || this.stand.rightArm[1] != 0
|
||||
|| this.stand.rightArm[2] != 0) {
|
||||
EulerAngle pose = new EulerAngle(this.stand.rightArm[0], this.stand.rightArm[1],
|
||||
this.stand.rightArm[2]
|
||||
);
|
||||
if (this.stand.rightArm[0] != 0 || this.stand.rightArm[1] != 0 || this.stand.rightArm[2] != 0) {
|
||||
EulerAngle pose = new EulerAngle(this.stand.rightArm[0], this.stand.rightArm[1], this.stand.rightArm[2]);
|
||||
stand.setRightArmPose(pose);
|
||||
}
|
||||
if (this.stand.invisible) {
|
||||
@@ -662,25 +635,28 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
|
||||
restoreLiving(stand);
|
||||
return stand;
|
||||
}
|
||||
case "BAT" -> {
|
||||
case BAT -> {
|
||||
if (this.dataByte != 0) {
|
||||
((Bat) entity).setAwake(true);
|
||||
}
|
||||
restoreLiving((LivingEntity) entity);
|
||||
return entity;
|
||||
}
|
||||
case "ENDER_DRAGON" -> {
|
||||
case ENDER_DRAGON -> {
|
||||
if (this.dataByte != 0) {
|
||||
((EnderDragon) entity).setPhase(EnderDragon.Phase.values()[this.dataByte]);
|
||||
}
|
||||
restoreLiving((LivingEntity) entity);
|
||||
return entity;
|
||||
}
|
||||
case "ENDERMITE", "GHAST", "HAPPY_GHAST", "GHASTLING", "MAGMA_CUBE", "SQUID", "PIG_ZOMBIE", "HOGLIN", "PIGLIN", "ZOMBIFIED_PIGLIN", "PIGLIN_BRUTE", "ZOMBIE", "WITHER", "WITCH", "SPIDER", "CAVE_SPIDER", "SILVERFISH", "GIANT", "ENDERMAN", "CREEPER", "BLAZE", "SNOWMAN", "SHULKER", "GUARDIAN", "ELDER_GUARDIAN", "SKELETON", "WITHER_SKELETON" -> {
|
||||
case ENDERMITE, GHAST, HAPPY_GHAST, MAGMA_CUBE, SQUID, HOGLIN, PIGLIN,
|
||||
ZOMBIFIED_PIGLIN, PIGLIN_BRUTE, ZOMBIE, WITHER, WITCH, SPIDER, CAVE_SPIDER, SILVERFISH, GIANT,
|
||||
ENDERMAN, CREEPER, BLAZE, SNOW_GOLEM, SHULKER, GUARDIAN, ELDER_GUARDIAN, SKELETON,
|
||||
WITHER_SKELETON -> {
|
||||
restoreLiving((LivingEntity) entity);
|
||||
return entity;
|
||||
}
|
||||
case "IRON_GOLEM" -> {
|
||||
case IRON_GOLEM -> {
|
||||
if (this.dataByte != 0) {
|
||||
((IronGolem) entity).setPlayerCreated(true);
|
||||
}
|
||||
|
||||
@@ -90,7 +90,12 @@ public class BukkitPlotGenerator extends ChunkGenerator implements GeneratorWrap
|
||||
this.plotGenerator = generator;
|
||||
this.platformGenerator = this;
|
||||
this.populators = new ArrayList<>();
|
||||
this.populators.add(new BlockStatePopulator(this.plotGenerator));
|
||||
int minecraftMinorVersion = PlotSquared.platform().serverVersion()[1];
|
||||
if (minecraftMinorVersion >= 17) {
|
||||
this.populators.add(new BlockStatePopulator(this.plotGenerator));
|
||||
} else {
|
||||
this.populators.add(new LegacyBlockStatePopulator(this.plotGenerator));
|
||||
}
|
||||
this.full = true;
|
||||
this.useNewGenerationMethods = PlotSquared.platform().serverVersion()[1] >= 19;
|
||||
this.biomeProvider = new BukkitPlotBiomeProvider();
|
||||
|
||||
@@ -36,7 +36,6 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
@Deprecated(since = "TODO")
|
||||
final class LegacyBlockStatePopulator extends BlockPopulator {
|
||||
|
||||
private final IndependentPlotGenerator plotGenerator;
|
||||
|
||||
@@ -219,7 +219,7 @@ public class BlockEventListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void blockDestroy(BlockBreakEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
Location location = BukkitUtil.adapt(event.getBlock().getLocation());
|
||||
|
||||
@@ -20,6 +20,7 @@ package com.plotsquared.bukkit.listener;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.plotsquared.bukkit.BukkitPlatform;
|
||||
import com.plotsquared.bukkit.entity.EntityType;
|
||||
import com.plotsquared.bukkit.player.BukkitPlayer;
|
||||
import com.plotsquared.bukkit.util.BukkitEntityUtil;
|
||||
import com.plotsquared.bukkit.util.BukkitUtil;
|
||||
@@ -52,7 +53,6 @@ import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Ageable;
|
||||
import org.bukkit.entity.Boat;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.FallingBlock;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Projectile;
|
||||
@@ -148,8 +148,8 @@ public class EntityEventListener implements Listener {
|
||||
if (area == null) {
|
||||
return;
|
||||
}
|
||||
// Armour-stands are handled elsewhere and should not be handled by area-wide entity-spawn options
|
||||
if (entity.getType() == EntityType.ARMOR_STAND) {
|
||||
// Armor-stands are handled elsewhere and should not be handled by area-wide entity-spawn options
|
||||
if (EntityType.of(event.getEntityType()) == EntityType.ARMOR_STAND) {
|
||||
return;
|
||||
}
|
||||
CreatureSpawnEvent.SpawnReason reason = event.getSpawnReason();
|
||||
@@ -212,7 +212,7 @@ public class EntityEventListener implements Listener {
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
|
||||
public void onEntityFall(EntityChangeBlockEvent event) {
|
||||
if (event.getEntityType() != EntityType.FALLING_BLOCK) {
|
||||
if (EntityType.of(event.getEntityType()) != EntityType.FALLING_BLOCK) {
|
||||
return;
|
||||
}
|
||||
Block block = event.getBlock();
|
||||
@@ -278,7 +278,7 @@ public class EntityEventListener implements Listener {
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onDamage(EntityDamageEvent event) {
|
||||
if (event.getEntityType() != EntityType.PLAYER) {
|
||||
if (EntityType.of(event.getEntityType()) != EntityType.PLAYER) {
|
||||
return;
|
||||
}
|
||||
Location location = BukkitUtil.adapt(event.getEntity().getLocation());
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package com.plotsquared.bukkit.listener;
|
||||
|
||||
import com.plotsquared.bukkit.entity.EntityType;
|
||||
import com.plotsquared.bukkit.util.BukkitEntityUtil;
|
||||
import com.plotsquared.bukkit.util.BukkitUtil;
|
||||
import com.plotsquared.core.PlotSquared;
|
||||
@@ -33,7 +34,6 @@ import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.ArmorStand;
|
||||
import org.bukkit.entity.EnderCrystal;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Item;
|
||||
import org.bukkit.entity.Vehicle;
|
||||
import org.bukkit.event.EventHandler;
|
||||
@@ -84,6 +84,7 @@ public class EntitySpawnListener implements Listener {
|
||||
public static void test(Entity entity) {
|
||||
@NonNull World world = entity.getWorld();
|
||||
List<MetadataValue> meta = entity.getMetadata(KEY);
|
||||
final EntityType entityType = EntityType.of(entity);
|
||||
if (meta.isEmpty()) {
|
||||
if (PlotSquared.get().getPlotAreaManager().hasPlotArea(world.getName())) {
|
||||
entity.setMetadata(KEY, new FixedMetadataValue((Plugin) PlotSquared.platform(), entity.getLocation()));
|
||||
@@ -94,7 +95,7 @@ public class EntitySpawnListener implements Listener {
|
||||
if (!originWorld.equals(world)) {
|
||||
if (!ignoreTP) {
|
||||
if (!world.getName().equalsIgnoreCase(originWorld + "_the_end")) {
|
||||
if (entity.getType() == EntityType.PLAYER) {
|
||||
if (entityType == EntityType.PLAYER) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
@@ -108,7 +109,7 @@ public class EntitySpawnListener implements Listener {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (entity.getType() == EntityType.PLAYER) {
|
||||
if (entityType == EntityType.PLAYER) {
|
||||
return;
|
||||
}
|
||||
entity.remove();
|
||||
@@ -132,7 +133,7 @@ public class EntitySpawnListener implements Listener {
|
||||
}
|
||||
}
|
||||
Plot plot = location.getOwnedPlotAbs();
|
||||
EntityType type = entity.getType();
|
||||
EntityType type = EntityType.of(entity);
|
||||
if (plot == null) {
|
||||
if (entity instanceof Item) {
|
||||
if (Settings.Enabled_Components.KILL_ROAD_ITEMS) {
|
||||
@@ -201,15 +202,16 @@ public class EntitySpawnListener implements Listener {
|
||||
final PlotArea fromArea = fromLocLocation.getPlotArea();
|
||||
Location toLocLocation = BukkitUtil.adapt(toLocation.getLocation());
|
||||
PlotArea toArea = toLocLocation.getPlotArea();
|
||||
final EntityType entityType = EntityType.of(entity);
|
||||
|
||||
if (toArea == null) {
|
||||
if (fromLocation.getType() == EntityType.SHULKER && fromArea != null) {
|
||||
if (entityType == EntityType.SHULKER && fromArea != null) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
Plot toPlot = toArea.getOwnedPlot(toLocLocation);
|
||||
if (fromLocation.getType() == EntityType.SHULKER && fromArea != null) {
|
||||
if (entityType == EntityType.SHULKER && fromArea != null) {
|
||||
final Plot fromPlot = fromArea.getOwnedPlot(fromLocLocation);
|
||||
|
||||
if (fromPlot != null || toPlot != null) {
|
||||
@@ -231,7 +233,7 @@ public class EntitySpawnListener implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void spawn(CreatureSpawnEvent event) {
|
||||
if (event.getEntityType() == EntityType.ARMOR_STAND) {
|
||||
if (EntityType.of(event.getEntityType()) == EntityType.ARMOR_STAND) {
|
||||
testCreate(event.getEntity());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.destroystokyo.paper.event.entity.SlimePathfindEvent;
|
||||
import com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent;
|
||||
import com.destroystokyo.paper.event.server.AsyncTabCompleteEvent;
|
||||
import com.google.inject.Inject;
|
||||
import com.plotsquared.bukkit.entity.EntityType;
|
||||
import com.plotsquared.bukkit.util.BukkitUtil;
|
||||
import com.plotsquared.core.PlotSquared;
|
||||
import com.plotsquared.core.command.Command;
|
||||
@@ -55,11 +56,9 @@ import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.tag.Tag;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.TileState;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.entity.Slime;
|
||||
@@ -84,9 +83,6 @@ import java.util.regex.Pattern;
|
||||
@SuppressWarnings("unused")
|
||||
public class PaperListener implements Listener {
|
||||
|
||||
private static final NamespacedKey ITEM = NamespacedKey.minecraft("item");
|
||||
private static final NamespacedKey FISHING_BOBBER = NamespacedKey.minecraft("fishing_bobber");
|
||||
|
||||
private final PlotAreaManager plotAreaManager;
|
||||
private Chunk lastChunk;
|
||||
|
||||
@@ -128,7 +124,7 @@ public class PaperListener implements Listener {
|
||||
return;
|
||||
}
|
||||
|
||||
handleEntityMovement(event, event.getEntity().getLocation(), b.getLocation());
|
||||
handleEntityMovement(event, event.getEntity().getLocation(), b.getLocation());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@@ -182,8 +178,9 @@ public class PaperListener implements Listener {
|
||||
if (area == null) {
|
||||
return;
|
||||
}
|
||||
// Armour-stands are handled elsewhere and should not be handled by area-wide entity-spawn options
|
||||
if (event.getType() == EntityType.ARMOR_STAND) {
|
||||
final EntityType entityType = EntityType.of(event.getType());
|
||||
// Armor-stands are handled elsewhere and should not be handled by area-wide entity-spawn options
|
||||
if (entityType == EntityType.ARMOR_STAND) {
|
||||
return;
|
||||
}
|
||||
// If entities are spawning... the chunk should be loaded?
|
||||
@@ -202,7 +199,8 @@ public class PaperListener implements Listener {
|
||||
return;
|
||||
}
|
||||
}
|
||||
case "REINFORCEMENTS", "NATURAL", "MOUNT", "PATROL", "RAID", "SILVERFISH_BLOCK", "ENDER_PEARL", "TRAP", "VILLAGE_DEFENSE", "VILLAGE_INVASION", "BEEHIVE", "CHUNK_GEN" -> {
|
||||
case "REINFORCEMENTS", "NATURAL", "MOUNT", "PATROL", "RAID", "SILVERFISH_BLOCK", "ENDER_PEARL", "TRAP",
|
||||
"VILLAGE_DEFENSE", "VILLAGE_INVASION", "BEEHIVE", "CHUNK_GEN" -> {
|
||||
if (!area.isMobSpawning()) {
|
||||
event.setShouldAbortSpawn(true);
|
||||
event.setCancelled(true);
|
||||
@@ -233,24 +231,23 @@ public class PaperListener implements Listener {
|
||||
}
|
||||
Plot plot = location.getOwnedPlotAbs();
|
||||
if (plot == null) {
|
||||
EntityType type = event.getType();
|
||||
// PreCreatureSpawnEvent **should** not be called for DROPPED_ITEM, just for the sake of consistency
|
||||
if (type.getKey().equals(ITEM)) {
|
||||
if (entityType == EntityType.ITEM) {
|
||||
if (Settings.Enabled_Components.KILL_ROAD_ITEMS) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!area.isMobSpawning()) {
|
||||
if (type == EntityType.PLAYER) {
|
||||
if (entityType == EntityType.PLAYER) {
|
||||
return;
|
||||
}
|
||||
if (type.isAlive()) {
|
||||
if (entityType.isAlive()) {
|
||||
event.setShouldAbortSpawn(true);
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
if (!area.isMiscSpawnUnowned() && !type.isAlive()) {
|
||||
if (!area.isMiscSpawnUnowned() && !entityType.isAlive()) {
|
||||
event.setShouldAbortSpawn(true);
|
||||
event.setCancelled(true);
|
||||
}
|
||||
@@ -322,6 +319,7 @@ public class PaperListener implements Listener {
|
||||
return;
|
||||
}
|
||||
Projectile entity = event.getProjectile();
|
||||
EntityType entityType = EntityType.of(entity);
|
||||
ProjectileSource shooter = entity.getShooter();
|
||||
if (!(shooter instanceof Player)) {
|
||||
return;
|
||||
@@ -361,7 +359,7 @@ public class PaperListener implements Listener {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
} else if (!plot.isAdded(pp.getUUID())) {
|
||||
if (entity.getType().getKey().equals(FISHING_BOBBER)) {
|
||||
if (entityType == EntityType.FISHING_BOBBER) {
|
||||
if (plot.getFlag(FishingFlag.class)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ package com.plotsquared.bukkit.listener;
|
||||
import com.destroystokyo.paper.MaterialTags;
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.inject.Inject;
|
||||
import com.plotsquared.bukkit.entity.EntityType;
|
||||
import com.plotsquared.bukkit.player.BukkitPlayer;
|
||||
import com.plotsquared.bukkit.util.BukkitEntityUtil;
|
||||
import com.plotsquared.bukkit.util.BukkitUtil;
|
||||
@@ -79,7 +80,6 @@ import com.plotsquared.core.util.task.TaskManager;
|
||||
import com.plotsquared.core.util.task.TaskTime;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.util.Enums;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import io.papermc.lib.PaperLib;
|
||||
@@ -98,7 +98,6 @@ import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.entity.ArmorStand;
|
||||
import org.bukkit.entity.Boat;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
import org.bukkit.entity.ItemFrame;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
@@ -160,7 +159,6 @@ import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
@@ -186,14 +184,6 @@ public class PlayerEventListener implements Listener {
|
||||
Material.WRITTEN_BOOK
|
||||
);
|
||||
|
||||
/**
|
||||
* The correct EntityType for End Crystal, determined once at class loading time.
|
||||
* Tries END_CRYSTAL first (1.21+), falls back to ENDER_CRYSTAL (1.20.4 and older).
|
||||
*/
|
||||
private static final EntityType END_CRYSTAL_ENTITY_TYPE = Objects.requireNonNull(
|
||||
Enums.findByValue(EntityType.class, "END_CRYSTAL", "ENDER_CRYSTAL")
|
||||
);
|
||||
|
||||
private static final Set<String> DYES;
|
||||
|
||||
static {
|
||||
@@ -1328,7 +1318,7 @@ public class PlayerEventListener implements Listener {
|
||||
// reset the player's hand item if spawning needs to be cancelled.
|
||||
if (type == Material.ARMOR_STAND || type == Material.END_CRYSTAL) {
|
||||
Plot plot = location.getOwnedPlotAbs();
|
||||
EntityType entityType = type == Material.ARMOR_STAND ? EntityType.ARMOR_STAND : END_CRYSTAL_ENTITY_TYPE;
|
||||
EntityType entityType = type == Material.ARMOR_STAND ? EntityType.ARMOR_STAND : EntityType.END_CRYSTAL;
|
||||
if (BukkitEntityUtil.checkEntity(entityType, plot)) {
|
||||
event.setCancelled(true);
|
||||
break;
|
||||
@@ -1709,7 +1699,7 @@ public class PlayerEventListener implements Listener {
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
|
||||
if (event.getRightClicked().getType() == EntityType.UNKNOWN) {
|
||||
if (EntityType.of(event.getRightClicked().getType()) == EntityType.UNKNOWN) {
|
||||
return;
|
||||
}
|
||||
Location location = BukkitUtil.adapt(event.getRightClicked().getLocation());
|
||||
|
||||
@@ -52,7 +52,6 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class BukkitQueueCoordinator extends BasicQueueCoordinator {
|
||||
@@ -211,13 +210,8 @@ public class BukkitQueueCoordinator extends BasicQueueCoordinator {
|
||||
BaseBlock block = getWorld().getBlock(blockVector3).toBaseBlock(tag);
|
||||
getWorld().setBlock(blockVector3, block, getSideEffectSet(SideEffectState.NONE));
|
||||
} catch (WorldEditException ignored) {
|
||||
StateWrapper.INSTANCE.restore(
|
||||
getWorld().getName(),
|
||||
blockVector3.getX(),
|
||||
blockVector3.getY(),
|
||||
blockVector3.getZ(),
|
||||
tag
|
||||
);
|
||||
StateWrapper sw = new StateWrapper(tag);
|
||||
sw.restoreTag(getWorld().getName(), blockVector3.getX(), blockVector3.getY(), blockVector3.getZ());
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -301,7 +295,9 @@ public class BukkitQueueCoordinator extends BasicQueueCoordinator {
|
||||
existing.setBlockData(blockData, false);
|
||||
if (block.hasNbtData()) {
|
||||
CompoundTag tag = block.getNbtData();
|
||||
StateWrapper.INSTANCE.restore(existing, Objects.requireNonNull(tag));
|
||||
StateWrapper sw = new StateWrapper(tag);
|
||||
|
||||
sw.restoreTag(existing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,8 +34,6 @@ import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.generator.LimitedRegion;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Wraps a {@link LimitedRegion} inside a {@link com.plotsquared.core.queue.QueueCoordinator} so it can be written to.
|
||||
*
|
||||
@@ -46,6 +44,7 @@ public class LimitedRegionWrapperQueue extends DelegateQueueCoordinator {
|
||||
private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + LimitedRegionWrapperQueue.class.getSimpleName());
|
||||
|
||||
private final LimitedRegion limitedRegion;
|
||||
private boolean useOtherRestoreTagMethod = false;
|
||||
|
||||
/**
|
||||
* @since 6.9.0
|
||||
@@ -65,11 +64,20 @@ public class LimitedRegionWrapperQueue extends DelegateQueueCoordinator {
|
||||
boolean result = setBlock(x, y, z, id.toImmutableState());
|
||||
if (result && id.hasNbtData()) {
|
||||
CompoundTag tag = id.getNbtData();
|
||||
StateWrapper sw = new StateWrapper(tag);
|
||||
try {
|
||||
StateWrapper.INSTANCE.restore(limitedRegion.getBlockState(x, y, z).getBlock(), Objects.requireNonNull(tag));
|
||||
if (useOtherRestoreTagMethod && getWorld() != null) {
|
||||
sw.restoreTag(getWorld().getName(), x, y, z);
|
||||
} else {
|
||||
sw.restoreTag(limitedRegion.getBlockState(x, y, z).getBlock());
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOGGER.error("Error attempting to populate tile entity into the world at location {},{},{}", x, y, z, e);
|
||||
return false;
|
||||
} catch (IllegalStateException e) {
|
||||
useOtherRestoreTagMethod = true;
|
||||
LOGGER.warn("IllegalStateException attempting to populate tile entity into the world at location {},{},{}. " +
|
||||
"Possibly on <=1.17.1, switching to secondary method.", x, y, z, e);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -105,8 +113,9 @@ public class LimitedRegionWrapperQueue extends DelegateQueueCoordinator {
|
||||
|
||||
@Override
|
||||
public boolean setTile(final int x, final int y, final int z, @NonNull final CompoundTag tag) {
|
||||
StateWrapper sw = new StateWrapper(tag);
|
||||
try {
|
||||
return StateWrapper.INSTANCE.restore(limitedRegion.getBlockState(x, y, z).getBlock(), tag);
|
||||
return sw.restoreTag(limitedRegion.getBlockState(x, y, z).getBlock());
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOGGER.error("Error attempting to populate tile entity into the world at location {},{},{}", x, y, z, e);
|
||||
return false;
|
||||
|
||||
@@ -27,8 +27,6 @@ import com.plotsquared.core.util.WorldUtil;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Schematic Handler.
|
||||
*/
|
||||
@@ -41,8 +39,8 @@ public class BukkitSchematicHandler extends SchematicHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean restoreTile(QueueCoordinator queue, CompoundTag tag, int x, int y, int z) {
|
||||
return StateWrapper.INSTANCE.restore(Objects.requireNonNull(queue.getWorld()).getName(), x, y, z, tag);
|
||||
public boolean restoreTile(QueueCoordinator queue, CompoundTag ct, int x, int y, int z) {
|
||||
return new StateWrapper(ct).restoreTag(queue.getWorld().getName(), x, y, z);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,35 +18,332 @@
|
||||
*/
|
||||
package com.plotsquared.bukkit.schematic;
|
||||
|
||||
import com.destroystokyo.paper.profile.PlayerProfile;
|
||||
import com.destroystokyo.paper.profile.ProfileProperty;
|
||||
import com.plotsquared.bukkit.util.BukkitUtil;
|
||||
import com.sk89q.jnbt.ByteTag;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.ShortTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.DyeColor;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Banner;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.Container;
|
||||
import org.bukkit.block.Sign;
|
||||
import org.bukkit.block.Skull;
|
||||
import org.bukkit.block.banner.Pattern;
|
||||
import org.bukkit.block.banner.PatternType;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public sealed interface StateWrapper permits StateWrapperSpigot {
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
StateWrapper INSTANCE = Factory.createStateWrapper();
|
||||
public class StateWrapper {
|
||||
|
||||
boolean restore(final @NonNull Block block, final @NonNull CompoundTag data);
|
||||
public CompoundTag tag;
|
||||
|
||||
default boolean restore(final String worldName, final int x, final int y, final int z, final CompoundTag data) {
|
||||
final World world = BukkitUtil.getWorld(worldName);
|
||||
private boolean paperErrorTextureSent = false;
|
||||
private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + StateWrapper.class.getSimpleName());
|
||||
|
||||
public StateWrapper(CompoundTag tag) {
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
public static String jsonToColourCode(String str) {
|
||||
str = str.replace("{\"extra\":", "").replace("],\"text\":\"\"}", "]")
|
||||
.replace("[{\"color\":\"black\",\"text\":\"", "&0")
|
||||
.replace("[{\"color\":\"dark_blue\",\"text\":\"", "&1")
|
||||
.replace("[{\"color\":\"dark_green\",\"text\":\"", "&2")
|
||||
.replace("[{\"color\":\"dark_aqua\",\"text\":\"", "&3")
|
||||
.replace("[{\"color\":\"dark_red\",\"text\":\"", "&4")
|
||||
.replace("[{\"color\":\"dark_purple\",\"text\":\"", "&5")
|
||||
.replace("[{\"color\":\"gold\",\"text\":\"", "&6")
|
||||
.replace("[{\"color\":\"gray\",\"text\":\"", "&7")
|
||||
.replace("[{\"color\":\"dark_gray\",\"text\":\"", "&8")
|
||||
.replace("[{\"color\":\"blue\",\"text\":\"", "&9")
|
||||
.replace("[{\"color\":\"green\",\"text\":\"", "&a")
|
||||
.replace("[{\"color\":\"aqua\",\"text\":\"", "&b")
|
||||
.replace("[{\"color\":\"red\",\"text\":\"", "&c")
|
||||
.replace("[{\"color\":\"light_purple\",\"text\":\"", "&d")
|
||||
.replace("[{\"color\":\"yellow\",\"text\":\"", "&e")
|
||||
.replace("[{\"color\":\"white\",\"text\":\"", "&f")
|
||||
.replace("[{\"obfuscated\":true,\"text\":\"", "&k")
|
||||
.replace("[{\"bold\":true,\"text\":\"", "&l")
|
||||
.replace("[{\"strikethrough\":true,\"text\":\"", "&m")
|
||||
.replace("[{\"underlined\":true,\"text\":\"", "&n")
|
||||
.replace("[{\"italic\":true,\"text\":\"", "&o").replace("[{\"color\":\"black\",", "&0")
|
||||
.replace("[{\"color\":\"dark_blue\",", "&1")
|
||||
.replace("[{\"color\":\"dark_green\",", "&2")
|
||||
.replace("[{\"color\":\"dark_aqua\",", "&3").replace("[{\"color\":\"dark_red\",", "&4")
|
||||
.replace("[{\"color\":\"dark_purple\",", "&5").replace("[{\"color\":\"gold\",", "&6")
|
||||
.replace("[{\"color\":\"gray\",", "&7").replace("[{\"color\":\"dark_gray\",", "&8")
|
||||
.replace("[{\"color\":\"blue\",", "&9").replace("[{\"color\":\"green\",", "&a")
|
||||
.replace("[{\"color\":\"aqua\",", "&b").replace("[{\"color\":\"red\",", "&c")
|
||||
.replace("[{\"color\":\"light_purple\",", "&d").replace("[{\"color\":\"yellow\",", "&e")
|
||||
.replace("[{\"color\":\"white\",", "&f").replace("[{\"obfuscated\":true,", "&k")
|
||||
.replace("[{\"bold\":true,", "&l").replace("[{\"strikethrough\":true,", "&m")
|
||||
.replace("[{\"underlined\":true,", "&n").replace("[{\"italic\":true,", "&o")
|
||||
.replace("{\"color\":\"black\",\"text\":\"", "&0")
|
||||
.replace("{\"color\":\"dark_blue\",\"text\":\"", "&1")
|
||||
.replace("{\"color\":\"dark_green\",\"text\":\"", "&2")
|
||||
.replace("{\"color\":\"dark_aqua\",\"text\":\"", "&3")
|
||||
.replace("{\"color\":\"dark_red\",\"text\":\"", "&4")
|
||||
.replace("{\"color\":\"dark_purple\",\"text\":\"", "&5")
|
||||
.replace("{\"color\":\"gold\",\"text\":\"", "&6")
|
||||
.replace("{\"color\":\"gray\",\"text\":\"", "&7")
|
||||
.replace("{\"color\":\"dark_gray\",\"text\":\"", "&8")
|
||||
.replace("{\"color\":\"blue\",\"text\":\"", "&9")
|
||||
.replace("{\"color\":\"green\",\"text\":\"", "&a")
|
||||
.replace("{\"color\":\"aqua\",\"text\":\"", "&b")
|
||||
.replace("{\"color\":\"red\",\"text\":\"", "&c")
|
||||
.replace("{\"color\":\"light_purple\",\"text\":\"", "&d")
|
||||
.replace("{\"color\":\"yellow\",\"text\":\"", "&e")
|
||||
.replace("{\"color\":\"white\",\"text\":\"", "&f")
|
||||
.replace("{\"obfuscated\":true,\"text\":\"", "&k")
|
||||
.replace("{\"bold\":true,\"text\":\"", "&l")
|
||||
.replace("{\"strikethrough\":true,\"text\":\"", "&m")
|
||||
.replace("{\"underlined\":true,\"text\":\"", "&n")
|
||||
.replace("{\"italic\":true,\"text\":\"", "&o").replace("{\"color\":\"black\",", "&0")
|
||||
.replace("{\"color\":\"dark_blue\",", "&1").replace("{\"color\":\"dark_green\",", "&2")
|
||||
.replace("{\"color\":\"dark_aqua\",", "&3").replace("{\"color\":\"dark_red\",", "&4")
|
||||
.replace("{\"color\":\"dark_purple\",", "&5").replace("{\"color\":\"gold\",", "&6")
|
||||
.replace("{\"color\":\"gray\",", "&7").replace("{\"color\":\"dark_gray\",", "&8")
|
||||
.replace("{\"color\":\"blue\",", "&9").replace("{\"color\":\"green\",", "&a")
|
||||
.replace("{\"color\":\"aqua\",", "&b").replace("{\"color\":\"red\",", "&c")
|
||||
.replace("{\"color\":\"light_purple\",", "&d").replace("{\"color\":\"yellow\",", "&e")
|
||||
.replace("{\"color\":\"white\",", "&f").replace("{\"obfuscated\":true,", "&k")
|
||||
.replace("{\"bold\":true,", "&l").replace("{\"strikethrough\":true,", "&m")
|
||||
.replace("{\"underlined\":true,", "&n").replace("{\"italic\":true,", "&o")
|
||||
.replace("\"color\":\"black\",\"text\":\"", "&0")
|
||||
.replace("\"color\":\"dark_blue\",\"text\":\"", "&1")
|
||||
.replace("\"color\":\"dark_green\",\"text\":\"", "&2")
|
||||
.replace("\"color\":\"dark_aqua\",\"text\":\"", "&3")
|
||||
.replace("\"color\":\"dark_red\",\"text\":\"", "&4")
|
||||
.replace("\"color\":\"dark_purple\",\"text\":\"", "&5")
|
||||
.replace("\"color\":\"gold\",\"text\":\"", "&6")
|
||||
.replace("\"color\":\"gray\",\"text\":\"", "&7")
|
||||
.replace("\"color\":\"dark_gray\",\"text\":\"", "&8")
|
||||
.replace("\"color\":\"blue\",\"text\":\"", "&9")
|
||||
.replace("\"color\":\"green\",\"text\":\"", "&a")
|
||||
.replace("\"color\":\"aqua\",\"text\":\"", "&b")
|
||||
.replace("\"color\":\"red\",\"text\":\"", "&c")
|
||||
.replace("\"color\":\"light_purple\",\"text\":\"", "&d")
|
||||
.replace("\"color\":\"yellow\",\"text\":\"", "&e")
|
||||
.replace("\"color\":\"white\",\"text\":\"", "&f")
|
||||
.replace("\"obfuscated\":true,\"text\":\"", "&k")
|
||||
.replace("\"bold\":true,\"text\":\"", "&l")
|
||||
.replace("\"strikethrough\":true,\"text\":\"", "&m")
|
||||
.replace("\"underlined\":true,\"text\":\"", "&n")
|
||||
.replace("\"italic\":true,\"text\":\"", "&o").replace("\"color\":\"black\",", "&0")
|
||||
.replace("\"color\":\"dark_blue\",", "&1").replace("\"color\":\"dark_green\",", "&2")
|
||||
.replace("\"color\":\"dark_aqua\",", "&3").replace("\"color\":\"dark_red\",", "&4")
|
||||
.replace("\"color\":\"dark_purple\",", "&5").replace("\"color\":\"gold\",", "&6")
|
||||
.replace("\"color\":\"gray\",", "&7").replace("\"color\":\"dark_gray\",", "&8")
|
||||
.replace("\"color\":\"blue\",", "&9").replace("\"color\":\"green\",", "&a")
|
||||
.replace("\"color\":\"aqua\",", "&b").replace("\"color\":\"red\",", "&c")
|
||||
.replace("\"color\":\"light_purple\",", "&d").replace("\"color\":\"yellow\",", "&e")
|
||||
.replace("\"color\":\"white\",", "&f").replace("\"obfuscated\":true,", "&k")
|
||||
.replace("\"bold\":true,", "&l").replace("\"strikethrough\":true,", "&m")
|
||||
.replace("\"underlined\":true,", "&n").replace("\"italic\":true,", "&o")
|
||||
.replace("[{\"text\":\"", "&0").replace("{\"text\":\"", "&0").replace("\"},", "")
|
||||
.replace("\"}]", "").replace("\"}", "");
|
||||
str = ChatColor.translateAlternateColorCodes('&', str);
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the TileEntity data to the given world at the given coordinates.
|
||||
*
|
||||
* @param worldName World name
|
||||
* @param x x position
|
||||
* @param y y position
|
||||
* @param z z position
|
||||
* @return true if successful
|
||||
*/
|
||||
public boolean restoreTag(String worldName, int x, int y, int z) {
|
||||
World world = BukkitUtil.getWorld(worldName);
|
||||
if (world == null) {
|
||||
return false;
|
||||
}
|
||||
return this.restore(world.getBlockAt(x, y, z), data);
|
||||
return restoreTag(world.getBlockAt(x, y, z));
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
final class Factory {
|
||||
|
||||
private static StateWrapper createStateWrapper() {
|
||||
return new StateWrapperSpigot();
|
||||
/**
|
||||
* Restore the TileEntity data to the given block
|
||||
*
|
||||
* @param block Block to restore to
|
||||
* @return true if successful
|
||||
*/
|
||||
@SuppressWarnings("deprecation") // #setLine is needed for Spigot compatibility
|
||||
public boolean restoreTag(@NonNull Block block) {
|
||||
if (this.tag == null) {
|
||||
return false;
|
||||
}
|
||||
org.bukkit.block.BlockState state = block.getState();
|
||||
switch (getId()) {
|
||||
case "chest", "beacon", "brewingstand", "dispenser", "dropper", "furnace", "hopper", "shulkerbox" -> {
|
||||
if (!(state instanceof Container container)) {
|
||||
return false;
|
||||
}
|
||||
List<Tag> itemsTag = this.tag.getListTag("Items").getValue();
|
||||
Inventory inv = container.getSnapshotInventory();
|
||||
for (Tag itemTag : itemsTag) {
|
||||
CompoundTag itemComp = (CompoundTag) itemTag;
|
||||
ItemType type = ItemType.REGISTRY.get(itemComp.getString("id").toLowerCase());
|
||||
if (type == null) {
|
||||
continue;
|
||||
}
|
||||
int count = itemComp.getByte("Count");
|
||||
int slot = itemComp.getByte("Slot");
|
||||
CompoundTag tag = (CompoundTag) itemComp.getValue().get("tag");
|
||||
BaseItemStack baseItemStack = new BaseItemStack(type, tag, count);
|
||||
ItemStack itemStack = BukkitAdapter.adapt(baseItemStack);
|
||||
inv.setItem(slot, itemStack);
|
||||
}
|
||||
container.update(true, false);
|
||||
return true;
|
||||
}
|
||||
case "sign" -> {
|
||||
if (state instanceof Sign sign) {
|
||||
sign.setLine(0, jsonToColourCode(tag.getString("Text1")));
|
||||
sign.setLine(1, jsonToColourCode(tag.getString("Text2")));
|
||||
sign.setLine(2, jsonToColourCode(tag.getString("Text3")));
|
||||
sign.setLine(3, jsonToColourCode(tag.getString("Text4")));
|
||||
state.update(true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case "skull" -> {
|
||||
if (state instanceof Skull skull) {
|
||||
CompoundTag skullOwner = ((CompoundTag) this.tag.getValue().get("SkullOwner"));
|
||||
if (skullOwner == null) {
|
||||
return true;
|
||||
}
|
||||
String player = skullOwner.getString("Name");
|
||||
|
||||
if (player != null && !player.isEmpty()) {
|
||||
try {
|
||||
skull.setOwningPlayer(Bukkit.getOfflinePlayer(player));
|
||||
skull.update(true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
final CompoundTag properties = (CompoundTag) skullOwner.getValue().get("Properties");
|
||||
if (properties == null) {
|
||||
return false;
|
||||
}
|
||||
final ListTag textures = properties.getListTag("textures");
|
||||
if (textures.getValue().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
final CompoundTag textureCompound = (CompoundTag) textures.getValue().get(0);
|
||||
if (textureCompound == null) {
|
||||
return false;
|
||||
}
|
||||
String textureValue = textureCompound.getString("Value");
|
||||
if (textureValue == null) {
|
||||
return false;
|
||||
}
|
||||
if (!PaperLib.isPaper()) {
|
||||
if (!paperErrorTextureSent) {
|
||||
paperErrorTextureSent = true;
|
||||
LOGGER.error("Failed to populate skull data in your road schematic - This is a Spigot limitation.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
final PlayerProfile profile = Bukkit.createProfile(UUID.randomUUID());
|
||||
profile.setProperty(new ProfileProperty("textures", textureValue));
|
||||
skull.setPlayerProfile(profile);
|
||||
skull.update(true);
|
||||
return true;
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case "banner" -> {
|
||||
if (state instanceof Banner banner) {
|
||||
List<Tag> patterns = this.tag.getListTag("Patterns").getValue();
|
||||
if (patterns == null || patterns.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
banner.setPatterns(patterns.stream().map(t -> (CompoundTag) t).map(compoundTag -> {
|
||||
DyeColor color = DyeColor.getByWoolData((byte) compoundTag.getInt("Color"));
|
||||
PatternType patternType = PatternType.getByIdentifier(compoundTag.getString("Pattern"));
|
||||
if (color == null || patternType == null) {
|
||||
return null;
|
||||
}
|
||||
return new Pattern(color, patternType);
|
||||
}).filter(Objects::nonNull).toList());
|
||||
banner.update(true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
String tileid = this.tag.getString("id").toLowerCase();
|
||||
if (tileid.startsWith("minecraft:")) {
|
||||
tileid = tileid.replace("minecraft:", "");
|
||||
}
|
||||
return tileid;
|
||||
}
|
||||
|
||||
public List<CompoundTag> serializeInventory(ItemStack[] items) {
|
||||
List<CompoundTag> tags = new ArrayList<>();
|
||||
for (int i = 0; i < items.length; ++i) {
|
||||
if (items[i] != null) {
|
||||
Map<String, Tag> tagData = serializeItem(items[i]);
|
||||
tagData.put("Slot", new ByteTag((byte) i));
|
||||
tags.add(new CompoundTag(tagData));
|
||||
}
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
|
||||
public Map<String, Tag> serializeItem(ItemStack item) {
|
||||
Map<String, Tag> data = new HashMap<>();
|
||||
data.put("id", new StringTag(item.getType().name()));
|
||||
data.put("Damage", new ShortTag(item.getDurability()));
|
||||
data.put("Count", new ByteTag((byte) item.getAmount()));
|
||||
if (!item.getEnchantments().isEmpty()) {
|
||||
List<CompoundTag> enchantmentList = new ArrayList<>();
|
||||
for (Entry<Enchantment, Integer> entry : item.getEnchantments().entrySet()) {
|
||||
Map<String, Tag> enchantment = new HashMap<>();
|
||||
enchantment.put("id", new StringTag(entry.getKey().toString()));
|
||||
enchantment.put("lvl", new ShortTag(entry.getValue().shortValue()));
|
||||
enchantmentList.add(new CompoundTag(enchantment));
|
||||
}
|
||||
Map<String, Tag> auxData = new HashMap<>();
|
||||
auxData.put("ench", new ListTag(CompoundTag.class, enchantmentList));
|
||||
data.put("tag", new CompoundTag(auxData));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,263 +0,0 @@
|
||||
/*
|
||||
* PlotSquared, a land and world management plugin for Minecraft.
|
||||
* Copyright (C) IntellectualSites <https://intellectualsites.com>
|
||||
* Copyright (C) IntellectualSites team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.plotsquared.bukkit.schematic;
|
||||
|
||||
import com.plotsquared.core.util.ReflectionHelper;
|
||||
import com.plotsquared.core.util.ReflectionUtils;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.Refraction;
|
||||
import com.sk89q.worldedit.extension.platform.NoCapablePlatformException;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.Sign;
|
||||
import org.bukkit.block.sign.Side;
|
||||
import org.bukkit.block.sign.SignSide;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
final class StateWrapperSpigot implements StateWrapper {
|
||||
|
||||
private static final boolean FORCE_UPDATE_STATE = true;
|
||||
private static final boolean UPDATE_TRIGGER_PHYSICS = false;
|
||||
private static final String CRAFTBUKKIT_PACKAGE = Bukkit.getServer().getClass().getPackageName();
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + StateWrapperSpigot.class.getSimpleName());
|
||||
private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
|
||||
|
||||
private static BukkitImplAdapter ADAPTER = null;
|
||||
private static Class<?> LIN_TAG_CLASS = null;
|
||||
private static Class<?> CRAFT_BLOCK_ENTITY_STATE_CLASS = null;
|
||||
private static Field CRAFT_SIGN_SIDE_SIGN_TEXT = null;
|
||||
private static Field CRAFT_SIGN_SIDE_LINES = null;
|
||||
private static MethodHandle PAPERWEIGHT_ADAPTER_FROM_NATIVE = null;
|
||||
private static MethodHandle CRAFT_BLOCK_ENTITY_STATE_LOAD_DATA = null;
|
||||
private static MethodHandle CRAFT_BLOCK_ENTITY_STATE_UPDATE = null;
|
||||
private static MethodHandle CRAFT_BLOCK_ENTITY_STATE_GET_SNAPSHOT = null;
|
||||
private static MethodHandle SIGN_BLOCK_ENTITY_SET_TEXT = null;
|
||||
private static MethodHandle DECODER_PARSE = null;
|
||||
private static MethodHandle DATA_RESULT_RESULT = null;
|
||||
private static MethodHandle TO_LIN_TAG = null;
|
||||
|
||||
private static Object SIGN_TEXT_DIRECT_CODEC = null;
|
||||
private static Object NBT_OPS_INSTANCE = null;
|
||||
|
||||
public StateWrapperSpigot() {
|
||||
try {
|
||||
ReflectionUtils.RefClass worldEditPluginRefClass = ReflectionUtils.getRefClass(WorldEditPlugin.class);
|
||||
WorldEditPlugin worldEditPlugin = (WorldEditPlugin) worldEditPluginRefClass
|
||||
.getMethod("getInstance")
|
||||
.of(null)
|
||||
.call();
|
||||
ADAPTER = (BukkitImplAdapter) worldEditPluginRefClass
|
||||
.getMethod("getBukkitImplAdapter")
|
||||
.of(worldEditPlugin)
|
||||
.call();
|
||||
LIN_TAG_CLASS = Class.forName("org.enginehub.linbus.tree.LinTag"); // provided WE / FAWE version is too old
|
||||
PAPERWEIGHT_ADAPTER_FROM_NATIVE = findPaperweightAdapterFromNativeMethodHandle(ADAPTER.getClass());
|
||||
TO_LIN_TAG = findToLinTagMethodHandle();
|
||||
} catch (NoSuchMethodException | ClassNotFoundException | IllegalAccessException | NoCapablePlatformException e) {
|
||||
throw new RuntimeException("Failed to access required WorldEdit classes or methods", e);
|
||||
}
|
||||
try {
|
||||
final Class<?> SIGN_TEXT_CLASS = Class.forName("net.minecraft.world.level.block.entity.SignText");
|
||||
final Class<?> CRAFT_SIGN_SIDE_CLASS = Class.forName(CRAFTBUKKIT_PACKAGE + ".block.sign.CraftSignSide");
|
||||
CRAFT_SIGN_SIDE_SIGN_TEXT = CRAFT_SIGN_SIDE_CLASS.getDeclaredField("signText");
|
||||
CRAFT_SIGN_SIDE_SIGN_TEXT.setAccessible(true);
|
||||
CRAFT_SIGN_SIDE_LINES = CRAFT_SIGN_SIDE_CLASS.getDeclaredField("lines");
|
||||
CRAFT_SIGN_SIDE_LINES.setAccessible(true);
|
||||
CRAFT_BLOCK_ENTITY_STATE_CLASS = Class.forName(CRAFTBUKKIT_PACKAGE + ".block.CraftBlockEntityState");
|
||||
CRAFT_BLOCK_ENTITY_STATE_LOAD_DATA = findCraftBlockEntityStateLoadDataMethodHandle(CRAFT_BLOCK_ENTITY_STATE_CLASS);
|
||||
CRAFT_BLOCK_ENTITY_STATE_UPDATE = findCraftBlockEntityStateUpdateMethodHandle(CRAFT_BLOCK_ENTITY_STATE_CLASS);
|
||||
CRAFT_BLOCK_ENTITY_STATE_GET_SNAPSHOT = findCraftBlockEntityStateSnapshotMethodHandle(CRAFT_BLOCK_ENTITY_STATE_CLASS);
|
||||
SIGN_BLOCK_ENTITY_SET_TEXT = findSignBlockEntitySetTextMethodHandle(
|
||||
Class.forName(Refraction.pickName(
|
||||
"net.minecraft.world.level.block.entity.SignBlockEntity",
|
||||
"net.minecraft.world.level.block.entity.TileEntitySign"
|
||||
)),
|
||||
SIGN_TEXT_CLASS
|
||||
);
|
||||
final Class<?> CODEC_CLASS = Class.forName("com.mojang.serialization.Codec");
|
||||
final Class<?> DECODER_CLASS = Class.forName("com.mojang.serialization.Decoder");
|
||||
final Class<?> DATA_RESULT_CLASS = Class.forName("com.mojang.serialization.DataResult");
|
||||
final Class<?> DYNAMIC_OPS_CLASS = Class.forName("com.mojang.serialization.DynamicOps");
|
||||
final Class<?> NBT_OPS_CLASS = Class.forName(Refraction.pickName(
|
||||
"net.minecraft.nbt.NbtOps",
|
||||
"net.minecraft.nbt.DynamicOpsNBT"
|
||||
));
|
||||
SIGN_TEXT_DIRECT_CODEC = Arrays.stream(SIGN_TEXT_CLASS.getFields())
|
||||
.filter(field -> Modifier.isStatic(field.getModifiers()) && Modifier.isPublic(field.getModifiers()))
|
||||
.filter(field -> field.getType() == CODEC_CLASS)
|
||||
.findFirst().orElseThrow().get(null);
|
||||
DECODER_PARSE = LOOKUP.findVirtual(
|
||||
DECODER_CLASS, "parse", MethodType.methodType(
|
||||
DATA_RESULT_CLASS, DYNAMIC_OPS_CLASS, Object.class
|
||||
)
|
||||
);
|
||||
NBT_OPS_INSTANCE = Arrays.stream(NBT_OPS_CLASS.getFields())
|
||||
.filter(field -> Modifier.isStatic(field.getModifiers()) && Modifier.isPublic(field.getModifiers()))
|
||||
.filter(field -> field.getType() == NBT_OPS_CLASS)
|
||||
.findFirst().orElseThrow().get(null);
|
||||
DATA_RESULT_RESULT = LOOKUP.findVirtual(
|
||||
DATA_RESULT_CLASS, "result",
|
||||
MethodType.methodType(Optional.class)
|
||||
);
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException("Failed to initialize required native method accessors", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean restore(final @NonNull Block block, final @NonNull CompoundTag data) {
|
||||
try {
|
||||
final BlockState blockState = block.getState();
|
||||
if (!CRAFT_BLOCK_ENTITY_STATE_CLASS.isAssignableFrom(blockState.getClass())) {
|
||||
return false;
|
||||
}
|
||||
// get native tag
|
||||
Object nativeTag = PAPERWEIGHT_ADAPTER_FROM_NATIVE.invoke(ADAPTER, TO_LIN_TAG.invoke(data));
|
||||
// load block entity data
|
||||
CRAFT_BLOCK_ENTITY_STATE_LOAD_DATA.invoke(blockState, nativeTag);
|
||||
|
||||
// signs need to be handled explicitly (at least during worldgen)
|
||||
if (blockState instanceof Sign sign) {
|
||||
if (data.getValue().get("front_text") instanceof CompoundTag textTag) {
|
||||
setSignContents(true, sign.getSide(Side.FRONT), blockState, textTag);
|
||||
}
|
||||
if (data.getValue().get("back_text") instanceof CompoundTag textTag) {
|
||||
setSignContents(false, sign.getSide(Side.BACK), blockState, textTag);
|
||||
}
|
||||
}
|
||||
|
||||
CRAFT_BLOCK_ENTITY_STATE_UPDATE.invoke(blockState, FORCE_UPDATE_STATE, UPDATE_TRIGGER_PHYSICS);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Failed to update tile entity", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void setSignContents(boolean front, SignSide side, BlockState blockState, CompoundTag data) throws Throwable {
|
||||
Object nativeTag = PAPERWEIGHT_ADAPTER_FROM_NATIVE.invoke(ADAPTER, TO_LIN_TAG.invoke(data));
|
||||
Object dataResult = DECODER_PARSE.invoke(SIGN_TEXT_DIRECT_CODEC, NBT_OPS_INSTANCE, nativeTag);
|
||||
//noinspection rawtypes
|
||||
Object signText = ((Optional) DATA_RESULT_RESULT.invoke(dataResult)).orElseThrow();
|
||||
|
||||
// set the SignText on the underlying tile entity snapshot (SignBlockEntity)
|
||||
SIGN_BLOCK_ENTITY_SET_TEXT.invoke(CRAFT_BLOCK_ENTITY_STATE_GET_SNAPSHOT.invoke(blockState), signText, front);
|
||||
// and update the SignText field on the CraftSignSide - changes are otherwise not reflected
|
||||
CRAFT_SIGN_SIDE_SIGN_TEXT.set(side, signText);
|
||||
|
||||
// reset cached lines to null, so it can be re-retrieved from SignText (for API access etc.)
|
||||
CRAFT_SIGN_SIDE_LINES.set(side, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the {@code toLinTag} method on the {@code ToLinTag} interface, if lin-bus is available in the classpath.
|
||||
* <br />
|
||||
* Required to access the underlying lin tag of the used JNBT tag by PlotSquared, so it can be converted into the platforms
|
||||
* native tag later.
|
||||
*
|
||||
* @return the MethodHandle for {@code toLinTag}, or {@code null} if lin-bus is not available in the classpath.
|
||||
* @throws ClassNotFoundException if the {@code ToLinTag} class could not be found.
|
||||
* @throws NoSuchMethodException if no {@code toLinTag} method exists.
|
||||
* @throws IllegalAccessException shouldn't happen.
|
||||
*/
|
||||
private static MethodHandle findToLinTagMethodHandle() throws ClassNotFoundException,
|
||||
NoSuchMethodException, IllegalAccessException {
|
||||
return LOOKUP.findVirtual(
|
||||
Class.forName("org.enginehub.linbus.tree.ToLinTag"),
|
||||
"toLinTag",
|
||||
MethodType.methodType(LIN_TAG_CLASS)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the method (handle) to convert from native (= WE/FAWE) NBT tags to minecraft NBT tags.
|
||||
* <br />
|
||||
* Depending on the used version of WE/FAWE, this differs:
|
||||
* <ul>
|
||||
* <li>On WE versions post LinBus introduction: {@code fromNative(org.enginehub.linbus.tree.LinTag)}</li>
|
||||
* <li>On FAWE versions post LinBus introduction: {@code fromNativeLin(org.enginehub.linbus.tree.LinTag)}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param adapterClass The bukkit adapter implementation class
|
||||
* @return the method.
|
||||
* @throws IllegalAccessException shouldn't happen as private lookup is used.
|
||||
* @throws NoSuchMethodException if the method couldn't be found.
|
||||
*/
|
||||
private static MethodHandle findPaperweightAdapterFromNativeMethodHandle(Class<?> adapterClass) throws
|
||||
IllegalAccessException, NoSuchMethodException {
|
||||
final MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(adapterClass, LOOKUP);
|
||||
try {
|
||||
// FAWE
|
||||
return lookup.findVirtual(adapterClass, "fromNativeLin", MethodType.methodType(Object.class, LIN_TAG_CLASS));
|
||||
} catch (NoSuchMethodException e) {
|
||||
// WE
|
||||
return lookup.findVirtual(adapterClass, "fromNative", MethodType.methodType(Object.class, LIN_TAG_CLASS));
|
||||
}
|
||||
}
|
||||
|
||||
private static MethodHandle findCraftBlockEntityStateLoadDataMethodHandle(Class<?> craftBlockEntityStateClass) throws
|
||||
NoSuchMethodException, IllegalAccessException {
|
||||
for (final Method method : craftBlockEntityStateClass.getMethods()) {
|
||||
if (method.getName().equals("loadData") && method.getParameterCount() == 1) {
|
||||
return LOOKUP.unreflect(method);
|
||||
}
|
||||
}
|
||||
throw new NoSuchMethodException("Couldn't find #loadData(CompoundTag) in " + craftBlockEntityStateClass.getName());
|
||||
}
|
||||
|
||||
private static MethodHandle findCraftBlockEntityStateUpdateMethodHandle(Class<?> craftBlockEntityStateClass) throws
|
||||
NoSuchMethodException, IllegalAccessException {
|
||||
return LOOKUP.unreflect(ReflectionHelper.findMethod(
|
||||
craftBlockEntityStateClass,
|
||||
MethodType.methodType(Boolean.TYPE, Boolean.TYPE, Boolean.TYPE),
|
||||
Modifier.PUBLIC
|
||||
).orElseThrow(() -> new NoSuchMethodException("Couldn't lookup CraftBlockEntityState#update(boolean, boolean) boolean")));
|
||||
}
|
||||
|
||||
private static MethodHandle findCraftBlockEntityStateSnapshotMethodHandle(Class<?> craftBlockEntityStateClass) throws
|
||||
IllegalAccessException, NoSuchMethodException {
|
||||
// doesn't seem to be obfuscated, but protected
|
||||
final MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(craftBlockEntityStateClass, LOOKUP);
|
||||
return lookup.unreflect(craftBlockEntityStateClass.getDeclaredMethod("getSnapshot"));
|
||||
}
|
||||
|
||||
private static MethodHandle findSignBlockEntitySetTextMethodHandle(Class<?> signBlockEntity, Class<?> signText) throws
|
||||
NoSuchMethodException, IllegalAccessException {
|
||||
return LOOKUP.unreflect(ReflectionHelper.findMethod(
|
||||
signBlockEntity,
|
||||
MethodType.methodType(Boolean.TYPE, signText, Boolean.TYPE),
|
||||
Modifier.PUBLIC
|
||||
).orElseThrow(() -> new NoSuchMethodException("Couldn't lookup SignBlockEntity#setText(SignText, boolean) boolean")));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package com.plotsquared.bukkit.util;
|
||||
|
||||
import com.plotsquared.bukkit.entity.EntityType;
|
||||
import com.plotsquared.bukkit.player.BukkitPlayer;
|
||||
import com.plotsquared.core.configuration.Settings;
|
||||
import com.plotsquared.core.configuration.caption.TranslatableCaption;
|
||||
@@ -48,7 +49,6 @@ import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
import org.bukkit.entity.Arrow;
|
||||
import org.bukkit.entity.Creature;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Firework;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Projectile;
|
||||
@@ -189,7 +189,7 @@ public class BukkitEntityUtil {
|
||||
);
|
||||
return false;
|
||||
}
|
||||
} else if (victim.getType() == EntityType.ARMOR_STAND) {
|
||||
} else if (EntityType.of(victim.getType()) == EntityType.ARMOR_STAND) {
|
||||
if (plot != null && (plot.getFlag(MiscBreakFlag.class) || plot
|
||||
.isAdded(plotPlayer.getUUID()))) {
|
||||
return true;
|
||||
@@ -354,7 +354,7 @@ public class BukkitEntityUtil {
|
||||
}
|
||||
|
||||
public static boolean checkEntity(Entity entity, Plot plot) {
|
||||
return checkEntity(entity.getType(), plot);
|
||||
return checkEntity(EntityType.of(entity.getType()), plot);
|
||||
}
|
||||
|
||||
public static boolean checkEntity(EntityType type, Plot plot) {
|
||||
@@ -364,7 +364,7 @@ public class BukkitEntityUtil {
|
||||
}
|
||||
|
||||
final com.sk89q.worldedit.world.entity.EntityType entityType =
|
||||
BukkitAdapter.adapt(type);
|
||||
BukkitAdapter.adapt(type.bukkitType());
|
||||
|
||||
if (EntityCategories.PLAYER.contains(entityType)) {
|
||||
return false;
|
||||
|
||||
@@ -435,6 +435,11 @@ public class Settings extends Config {
|
||||
|
||||
public static String SCHEMATICS = "schematics";
|
||||
public static String TEMPLATES = "templates";
|
||||
@Comment({"If schematics used for generation should be searched for in the path.schematics location",
|
||||
" - This setting exists and is `false` by default for backwards compatibility.",
|
||||
" - If false then generation schematics must be located in `schematics`",
|
||||
" - Schematics must still always be under GEN_ROAD_SCHEMATIC/<world> etc."})
|
||||
public static boolean USE_SCHEMATICS_PATH_FOR_GEN_SCHEMATICS = false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -140,7 +140,8 @@ public class HybridPlotWorld extends ClassicPlotWorld {
|
||||
@NonNull
|
||||
@Override
|
||||
protected PlotManager createManager() {
|
||||
return new HybridPlotManager(this, PlotSquared.platform().regionManager(),
|
||||
return new HybridPlotManager(
|
||||
this, PlotSquared.platform().regionManager(),
|
||||
PlotSquared.platform().injector().getInstance(ProgressSubscriberFactory.class)
|
||||
);
|
||||
}
|
||||
@@ -215,15 +216,16 @@ public class HybridPlotWorld extends ClassicPlotWorld {
|
||||
|
||||
// Try to determine root. This means that plot areas can have separate schematic
|
||||
// directories
|
||||
String schematicFolder = Settings.Paths.USE_SCHEMATICS_PATH_FOR_GEN_SCHEMATICS ? Settings.Paths.SCHEMATICS : "schematics";
|
||||
if (!(root =
|
||||
FileUtils.getFile(
|
||||
PlotSquared.platform().getDirectory(),
|
||||
"schematics/GEN_ROAD_SCHEMATIC/" + this.getWorldName() + "/" + this.getId()
|
||||
schematicFolder + File.separator + "GEN_ROAD_SCHEMATIC" + File.separator + this.getWorldName() + File.separator + this.getId()
|
||||
))
|
||||
.exists()) {
|
||||
root = FileUtils.getFile(
|
||||
PlotSquared.platform().getDirectory(),
|
||||
"schematics/GEN_ROAD_SCHEMATIC/" + this.getWorldName()
|
||||
schematicFolder + File.separator + "GEN_ROAD_SCHEMATIC" + File.separator + this.getWorldName()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* PlotSquared, a land and world management plugin for Minecraft.
|
||||
* Copyright (C) IntellectualSites <https://intellectualsites.com>
|
||||
* Copyright (C) IntellectualSites team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.plotsquared.core.util;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Optional;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public final class ReflectionHelper {
|
||||
|
||||
/**
|
||||
* Find a (declared) method with an unknown or potentially obfuscated name by its signature and optional modifiers.
|
||||
* <br>
|
||||
* The method - if private - is not made accessible. Either call {@link Method#setAccessible(boolean)} or
|
||||
* use a {@link java.lang.invoke.MethodHandles.Lookup#privateLookupIn(Class, MethodHandles.Lookup) private lookup}.
|
||||
*
|
||||
* @param holder The class providing the method.
|
||||
* @param signature The signature of the method, identified by parameter types and the return type.
|
||||
* @param modifiers All possible modifiers of the method that should be validated.
|
||||
* @return The method, if one has been found. Otherwise, an empty Optional.
|
||||
* @throws RuntimeException if multiple matching methods have been found.
|
||||
* @see java.lang.reflect.Modifier
|
||||
*/
|
||||
public static Optional<Method> findMethod(Class<?> holder, MethodType signature, int... modifiers) {
|
||||
Method found = null;
|
||||
outer:
|
||||
for (final Method method : holder.getDeclaredMethods()) {
|
||||
if (method.getParameterCount() != signature.parameterCount()) {
|
||||
continue;
|
||||
}
|
||||
if (!signature.returnType().isAssignableFrom(method.getReturnType())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (final int modifier : modifiers) {
|
||||
if ((method.getModifiers() & modifier) == 0) {
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
|
||||
Class<?>[] parameterTypes = signature.parameterArray();
|
||||
for (int i = 0; i < parameterTypes.length; i++) {
|
||||
// validate expected parameter is either the same type or subtype of actual parameter
|
||||
if (!parameterTypes[i].isAssignableFrom(method.getParameterTypes()[i])) {
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
if (found != null) {
|
||||
throw new RuntimeException("Found ambiguous method by selector: " + method + " vs " + found);
|
||||
}
|
||||
found = method;
|
||||
}
|
||||
return Optional.ofNullable(found);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -204,6 +204,9 @@ public final class PlaceholderRegistry {
|
||||
this.createPlaceholder("currentplot_x", (player, plot) -> Integer.toString(plot.getId().getX()));
|
||||
this.createPlaceholder("currentplot_y", (player, plot) -> Integer.toString(plot.getId().getY()));
|
||||
this.createPlaceholder("currentplot_xy", (player, plot) -> plot.getId().toString());
|
||||
this.createPlaceholder("currentplot_abs_x", (player, plot) -> Integer.toString(plot.getId().getX()), true);
|
||||
this.createPlaceholder("currentplot_abs_y", (player, plot) -> Integer.toString(plot.getId().getY()), true);
|
||||
this.createPlaceholder("currentplot_abs_xy", (player, plot) -> plot.getId().toString(), true);
|
||||
this.createPlaceholder("currentplot_rating", (player, plot) -> {
|
||||
if (Double.isNaN(plot.getAverageRating())) {
|
||||
return legacyComponent(TranslatableCaption.of("placeholder.nan"), player);
|
||||
@@ -253,7 +256,23 @@ public final class PlaceholderRegistry {
|
||||
final @NonNull String key,
|
||||
final @NonNull BiFunction<PlotPlayer<?>, Plot, String> placeholderFunction
|
||||
) {
|
||||
this.registerPlaceholder(new PlotSpecificPlaceholder(key) {
|
||||
this.createPlaceholder(key, placeholderFunction, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a functional placeholder
|
||||
*
|
||||
* @param key Placeholder key
|
||||
* @param placeholderFunction Placeholder generator. Cannot return null
|
||||
* @param requireAbsolute If the plot given to the placeholder should be the absolute (not base) plot
|
||||
* @since TODO
|
||||
*/
|
||||
public void createPlaceholder(
|
||||
final @NonNull String key,
|
||||
final @NonNull BiFunction<PlotPlayer<?>, Plot, String> placeholderFunction,
|
||||
final boolean requireAbsolute
|
||||
) {
|
||||
this.registerPlaceholder(new PlotSpecificPlaceholder(key, requireAbsolute) {
|
||||
@Override
|
||||
public @NonNull String getValue(final @NonNull PlotPlayer<?> player, final @NonNull Plot plot) {
|
||||
return placeholderFunction.apply(player, plot);
|
||||
|
||||
@@ -27,14 +27,28 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
*/
|
||||
public abstract class PlotSpecificPlaceholder extends Placeholder {
|
||||
|
||||
private final boolean requireAbsolute;
|
||||
|
||||
public PlotSpecificPlaceholder(final @NonNull String key) {
|
||||
this(key, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a functional placeholder
|
||||
*
|
||||
* @param key Placeholder key
|
||||
* @param requireAbsolute If the plot given to the placeholder should be the absolute (not base) plot
|
||||
* @since TODO
|
||||
*/
|
||||
public PlotSpecificPlaceholder(final @NonNull String key, final boolean requireAbsolute) {
|
||||
super(key);
|
||||
this.requireAbsolute = requireAbsolute;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull
|
||||
final String getValue(final @NonNull PlotPlayer<?> player) {
|
||||
final Plot plot = player.getCurrentPlot();
|
||||
final Plot plot = requireAbsolute ? player.getLocation().getPlotAbs() : player.getCurrentPlot();
|
||||
if (plot == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* PlotSquared, a land and world management plugin for Minecraft.
|
||||
* Copyright (C) IntellectualSites <https://intellectualsites.com>
|
||||
* Copyright (C) IntellectualSites team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.plotsquared.core.util;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
class ReflectionHelperTest {
|
||||
|
||||
@Test
|
||||
void findMethod() throws NoSuchMethodException {
|
||||
assertThrows(
|
||||
RuntimeException.class, () ->
|
||||
ReflectionHelper.findMethod(MethodTesterClass.class, MethodType.methodType(String.class))
|
||||
);
|
||||
assertEquals(
|
||||
MethodTesterClass.class.getMethod("methodThree"),
|
||||
ReflectionHelper.findMethod(MethodTesterClass.class, MethodType.methodType(String.class), Modifier.PUBLIC)
|
||||
.orElse(null)
|
||||
);
|
||||
assertEquals(
|
||||
MethodTesterClass.class.getDeclaredMethod("methodFour", String.class, Collection.class),
|
||||
ReflectionHelper.findMethod(MethodTesterClass.class, MethodType.methodType(
|
||||
String.class, String.class, Collection.class
|
||||
)).orElse(null)
|
||||
);
|
||||
// check that helper allows super classes of parameters when searching
|
||||
assertEquals(
|
||||
MethodTesterClass.class.getDeclaredMethod("methodFour", String.class, Collection.class),
|
||||
ReflectionHelper.findMethod(MethodTesterClass.class, MethodType.methodType(
|
||||
String.class, String.class, Object.class
|
||||
)).orElse(null)
|
||||
);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static class MethodTesterClass {
|
||||
|
||||
private static String methodOne() {
|
||||
return "";
|
||||
}
|
||||
|
||||
private static String methodTwo() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public static String methodThree() {
|
||||
return "";
|
||||
}
|
||||
|
||||
protected static String methodFour(String param, Collection<String> paramList) {
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user