Update to Minecraft 1.21.4

By: md_5 <git@md-5.net>
This commit is contained in:
CraftBukkit/Spigot
2024-12-04 03:20:00 +11:00
parent 267ae64dd6
commit 5381ea78f7
125 changed files with 1383 additions and 1093 deletions

View File

@@ -14,7 +14,7 @@ import net.minecraft.core.particles.ParticleParamRedstone;
import net.minecraft.core.particles.ParticleType;
import net.minecraft.core.particles.SculkChargeParticleOptions;
import net.minecraft.core.particles.ShriekParticleOption;
import net.minecraft.core.particles.TargetColorParticleOption;
import net.minecraft.core.particles.TrailParticleOption;
import net.minecraft.core.particles.VibrationParticleOption;
import net.minecraft.core.registries.Registries;
import net.minecraft.world.entity.Entity;
@@ -190,10 +190,10 @@ public abstract class CraftParticle<D> implements Keyed {
}
};
BiFunction<NamespacedKey, net.minecraft.core.particles.Particle<?>, CraftParticle<?>> targetColorFunction = (name, particle) -> new CraftParticle<>(name, particle, Particle.TargetColor.class) {
BiFunction<NamespacedKey, net.minecraft.core.particles.Particle<?>, CraftParticle<?>> trailFunction = (name, particle) -> new CraftParticle<>(name, particle, Particle.Trail.class) {
@Override
public ParticleParam createParticleParam(Particle.TargetColor data) {
return new TargetColorParticleOption(CraftLocation.toVec3D(data.getTarget()), data.getColor().asRGB());
public ParticleParam createParticleParam(Particle.Trail data) {
return new TrailParticleOption(CraftLocation.toVec3D(data.getTarget()), data.getColor().asRGB(), data.getDuration());
}
};
@@ -209,7 +209,7 @@ public abstract class CraftParticle<D> implements Keyed {
add("entity_effect", colorFunction);
add("dust_pillar", blockDataFunction);
add("block_crumble", blockDataFunction);
add("trail", targetColorFunction);
add("trail", trailFunction);
}
private static void add(String name, BiFunction<NamespacedKey, net.minecraft.core.particles.Particle<?>, CraftParticle<?>> function) {

View File

@@ -1905,14 +1905,14 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@Override
public <T> void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, T data, boolean force) {
getHandle().sendParticles(
getHandle().sendParticlesSource(
null, // Sender
CraftParticle.createParticleParam(particle, data), // Particle
false, force,
x, y, z, // Position
count, // Count
offsetX, offsetY, offsetZ, // Random offset
extra, // Speed?
force
extra // Speed?
);
}

View File

@@ -190,11 +190,11 @@ public class Main {
useConsole = false;
}
if (false && Main.class.getPackage().getImplementationVendor() != null && System.getProperty("IReallyKnowWhatIAmDoingISwear") == null) {
if (Main.class.getPackage().getImplementationVendor() != null && System.getProperty("IReallyKnowWhatIAmDoingISwear") == null) {
Date buildDate = new Date(Integer.parseInt(Main.class.getPackage().getImplementationVendor()) * 1000L);
Calendar deadline = Calendar.getInstance();
deadline.add(Calendar.DAY_OF_YEAR, -14);
deadline.add(Calendar.DAY_OF_YEAR, -2);
if (buildDate.before(deadline.getTime())) {
System.err.println("*** Error, this build is outdated ***");
System.err.println("*** Please download a new build as per instructions from https://www.spigotmc.org/go/outdated-spigot ***");

View File

@@ -40,24 +40,24 @@ public abstract class CraftFurnace<T extends TileEntityFurnace> extends CraftCon
@Override
public short getBurnTime() {
return (short) this.getSnapshot().litTime;
return (short) this.getSnapshot().litTimeRemaining;
}
@Override
public void setBurnTime(short burnTime) {
this.getSnapshot().litTime = burnTime;
this.getSnapshot().litTimeRemaining = burnTime;
// SPIGOT-844: Allow lighting and relighting using this API
this.data = this.data.setValue(BlockFurnace.LIT, burnTime > 0);
}
@Override
public short getCookTime() {
return (short) this.getSnapshot().cookingProgress;
return (short) this.getSnapshot().cookingTimer;
}
@Override
public void setCookTime(short cookTime) {
this.getSnapshot().cookingProgress = cookTime;
this.getSnapshot().cookingTimer = cookTime;
}
@Override

View File

@@ -499,7 +499,6 @@ public class CraftBlockData implements BlockData {
register(net.minecraft.world.level.block.CaveVinesBlock.class, org.bukkit.craftbukkit.block.impl.CraftCaveVines::new);
register(net.minecraft.world.level.block.CaveVinesPlantBlock.class, org.bukkit.craftbukkit.block.impl.CraftCaveVinesPlant::new);
register(net.minecraft.world.level.block.CeilingHangingSignBlock.class, org.bukkit.craftbukkit.block.impl.CraftCeilingHangingSign::new);
register(net.minecraft.world.level.block.CherryLeavesBlock.class, org.bukkit.craftbukkit.block.impl.CraftCherryLeaves::new);
register(net.minecraft.world.level.block.ChiseledBookShelfBlock.class, org.bukkit.craftbukkit.block.impl.CraftChiseledBookShelf::new);
register(net.minecraft.world.level.block.CopperBulbBlock.class, org.bukkit.craftbukkit.block.impl.CraftCopperBulb::new);
register(net.minecraft.world.level.block.CrafterBlock.class, org.bukkit.craftbukkit.block.impl.CraftCrafter::new);
@@ -517,6 +516,8 @@ public class CraftBlockData implements BlockData {
register(net.minecraft.world.level.block.MangrovePropaguleBlock.class, org.bukkit.craftbukkit.block.impl.CraftMangrovePropagule::new);
register(net.minecraft.world.level.block.MangroveRootsBlock.class, org.bukkit.craftbukkit.block.impl.CraftMangroveRoots::new);
register(net.minecraft.world.level.block.MossyCarpetBlock.class, org.bukkit.craftbukkit.block.impl.CraftMossyCarpet::new);
register(net.minecraft.world.level.block.MultifaceBlock.class, org.bukkit.craftbukkit.block.impl.CraftMultiface::new);
register(net.minecraft.world.level.block.ParticleLeavesBlock.class, org.bukkit.craftbukkit.block.impl.CraftParticleLeaves::new);
register(net.minecraft.world.level.block.PiglinWallSkullBlock.class, org.bukkit.craftbukkit.block.impl.CraftPiglinWallSkull::new);
register(net.minecraft.world.level.block.PinkPetalsBlock.class, org.bukkit.craftbukkit.block.impl.CraftPinkPetals::new);
register(net.minecraft.world.level.block.PitcherCropBlock.class, org.bukkit.craftbukkit.block.impl.CraftPitcherCrop::new);

View File

@@ -5,15 +5,26 @@ import org.bukkit.craftbukkit.block.data.CraftBlockData;
public abstract class CraftCreakingHeart extends CraftBlockData implements CreakingHeart {
private static final net.minecraft.world.level.block.state.properties.BlockStateEnum<?> CREAKING = getEnum("creaking");
private static final net.minecraft.world.level.block.state.properties.BlockStateBoolean ACTIVE = getBoolean("active");
private static final net.minecraft.world.level.block.state.properties.BlockStateBoolean NATURAL = getBoolean("natural");
@Override
public org.bukkit.block.data.type.CreakingHeart.Creaking getCreaking() {
return get(CREAKING, org.bukkit.block.data.type.CreakingHeart.Creaking.class);
public boolean isActive() {
return get(ACTIVE);
}
@Override
public void setCreaking(org.bukkit.block.data.type.CreakingHeart.Creaking creaking) {
set(CREAKING, creaking);
public void setActive(boolean active) {
set(ACTIVE, active);
}
@Override
public boolean isNatural() {
return get(NATURAL);
}
@Override
public void setNatural(boolean natural) {
set(NATURAL, natural);
}
}

View File

@@ -15,16 +15,27 @@ public final class CraftCreakingHeart extends org.bukkit.craftbukkit.block.data.
// org.bukkit.craftbukkit.block.data.type.CraftCreakingHeart
private static final net.minecraft.world.level.block.state.properties.BlockStateEnum<?> CREAKING = getEnum(net.minecraft.world.level.block.CreakingHeartBlock.class, "creaking");
private static final net.minecraft.world.level.block.state.properties.BlockStateBoolean ACTIVE = getBoolean(net.minecraft.world.level.block.CreakingHeartBlock.class, "active");
private static final net.minecraft.world.level.block.state.properties.BlockStateBoolean NATURAL = getBoolean(net.minecraft.world.level.block.CreakingHeartBlock.class, "natural");
@Override
public org.bukkit.block.data.type.CreakingHeart.Creaking getCreaking() {
return get(CREAKING, org.bukkit.block.data.type.CreakingHeart.Creaking.class);
public boolean isActive() {
return get(ACTIVE);
}
@Override
public void setCreaking(org.bukkit.block.data.type.CreakingHeart.Creaking creaking) {
set(CREAKING, creaking);
public void setActive(boolean active) {
set(ACTIVE, active);
}
@Override
public boolean isNatural() {
return get(NATURAL);
}
@Override
public void setNatural(boolean natural) {
set(NATURAL, natural);
}
// org.bukkit.craftbukkit.block.data.CraftOrientable

View File

@@ -0,0 +1,79 @@
/**
* Automatically generated file, changes will be lost.
*/
package org.bukkit.craftbukkit.block.impl;
public final class CraftMultiface extends org.bukkit.craftbukkit.block.data.CraftBlockData implements org.bukkit.block.data.type.ResinClump, org.bukkit.block.data.MultipleFacing, org.bukkit.block.data.Waterlogged {
public CraftMultiface() {
super();
}
public CraftMultiface(net.minecraft.world.level.block.state.IBlockData state) {
super(state);
}
// org.bukkit.craftbukkit.block.data.CraftMultipleFacing
private static final net.minecraft.world.level.block.state.properties.BlockStateBoolean[] FACES = new net.minecraft.world.level.block.state.properties.BlockStateBoolean[]{
getBoolean(net.minecraft.world.level.block.MultifaceBlock.class, "north", true), getBoolean(net.minecraft.world.level.block.MultifaceBlock.class, "east", true), getBoolean(net.minecraft.world.level.block.MultifaceBlock.class, "south", true), getBoolean(net.minecraft.world.level.block.MultifaceBlock.class, "west", true), getBoolean(net.minecraft.world.level.block.MultifaceBlock.class, "up", true), getBoolean(net.minecraft.world.level.block.MultifaceBlock.class, "down", true)
};
@Override
public boolean hasFace(org.bukkit.block.BlockFace face) {
net.minecraft.world.level.block.state.properties.BlockStateBoolean state = FACES[face.ordinal()];
if (state == null) {
throw new IllegalArgumentException("Non-allowed face " + face + ". Check MultipleFacing.getAllowedFaces.");
}
return get(state);
}
@Override
public void setFace(org.bukkit.block.BlockFace face, boolean has) {
net.minecraft.world.level.block.state.properties.BlockStateBoolean state = FACES[face.ordinal()];
if (state == null) {
throw new IllegalArgumentException("Non-allowed face " + face + ". Check MultipleFacing.getAllowedFaces.");
}
set(state, has);
}
@Override
public java.util.Set<org.bukkit.block.BlockFace> getFaces() {
com.google.common.collect.ImmutableSet.Builder<org.bukkit.block.BlockFace> faces = com.google.common.collect.ImmutableSet.builder();
for (int i = 0; i < FACES.length; i++) {
if (FACES[i] != null && get(FACES[i])) {
faces.add(org.bukkit.block.BlockFace.values()[i]);
}
}
return faces.build();
}
@Override
public java.util.Set<org.bukkit.block.BlockFace> getAllowedFaces() {
com.google.common.collect.ImmutableSet.Builder<org.bukkit.block.BlockFace> faces = com.google.common.collect.ImmutableSet.builder();
for (int i = 0; i < FACES.length; i++) {
if (FACES[i] != null) {
faces.add(org.bukkit.block.BlockFace.values()[i]);
}
}
return faces.build();
}
// org.bukkit.craftbukkit.block.data.CraftWaterlogged
private static final net.minecraft.world.level.block.state.properties.BlockStateBoolean WATERLOGGED = getBoolean(net.minecraft.world.level.block.MultifaceBlock.class, "waterlogged");
@Override
public boolean isWaterlogged() {
return get(WATERLOGGED);
}
@Override
public void setWaterlogged(boolean waterlogged) {
set(WATERLOGGED, waterlogged);
}
}

View File

@@ -3,20 +3,20 @@
*/
package org.bukkit.craftbukkit.block.impl;
public final class CraftCherryLeaves extends org.bukkit.craftbukkit.block.data.CraftBlockData implements org.bukkit.block.data.type.Leaves, org.bukkit.block.data.Waterlogged {
public final class CraftParticleLeaves extends org.bukkit.craftbukkit.block.data.CraftBlockData implements org.bukkit.block.data.type.Leaves, org.bukkit.block.data.Waterlogged {
public CraftCherryLeaves() {
public CraftParticleLeaves() {
super();
}
public CraftCherryLeaves(net.minecraft.world.level.block.state.IBlockData state) {
public CraftParticleLeaves(net.minecraft.world.level.block.state.IBlockData state) {
super(state);
}
// org.bukkit.craftbukkit.block.data.type.CraftLeaves
private static final net.minecraft.world.level.block.state.properties.BlockStateInteger DISTANCE = getInteger(net.minecraft.world.level.block.CherryLeavesBlock.class, "distance");
private static final net.minecraft.world.level.block.state.properties.BlockStateBoolean PERSISTENT = getBoolean(net.minecraft.world.level.block.CherryLeavesBlock.class, "persistent");
private static final net.minecraft.world.level.block.state.properties.BlockStateInteger DISTANCE = getInteger(net.minecraft.world.level.block.ParticleLeavesBlock.class, "distance");
private static final net.minecraft.world.level.block.state.properties.BlockStateBoolean PERSISTENT = getBoolean(net.minecraft.world.level.block.ParticleLeavesBlock.class, "persistent");
@Override
public boolean isPersistent() {
@@ -40,7 +40,7 @@ public final class CraftCherryLeaves extends org.bukkit.craftbukkit.block.data.C
// org.bukkit.craftbukkit.block.data.CraftWaterlogged
private static final net.minecraft.world.level.block.state.properties.BlockStateBoolean WATERLOGGED = getBoolean(net.minecraft.world.level.block.CherryLeavesBlock.class, "waterlogged");
private static final net.minecraft.world.level.block.state.properties.BlockStateBoolean WATERLOGGED = getBoolean(net.minecraft.world.level.block.ParticleLeavesBlock.class, "waterlogged");
@Override
public boolean isWaterlogged() {

View File

@@ -1,21 +0,0 @@
package org.bukkit.craftbukkit.entity;
import net.minecraft.world.entity.monster.creaking.CreakingTransient;
import org.bukkit.craftbukkit.CraftServer;
public class CraftCreakingTransient extends CraftCreaking implements org.bukkit.entity.CreakingTransient {
public CraftCreakingTransient(CraftServer server, CreakingTransient entity) {
super(server, entity);
}
@Override
public CreakingTransient getHandle() {
return (CreakingTransient) entity;
}
@Override
public String toString() {
return "CraftCreakingTransient";
}
}

View File

@@ -83,7 +83,6 @@ import org.bukkit.entity.Chicken;
import org.bukkit.entity.Cod;
import org.bukkit.entity.Cow;
import org.bukkit.entity.Creaking;
import org.bukkit.entity.CreakingTransient;
import org.bukkit.entity.Creeper;
import org.bukkit.entity.Dolphin;
import org.bukkit.entity.Donkey;
@@ -351,7 +350,6 @@ public final class CraftEntityTypes {
register(new EntityTypeData<>(EntityType.BREEZE, Breeze.class, CraftBreeze::new, createLiving(EntityTypes.BREEZE)));
register(new EntityTypeData<>(EntityType.ARMADILLO, Armadillo.class, CraftArmadillo::new, createLiving(EntityTypes.ARMADILLO)));
register(new EntityTypeData<>(EntityType.CREAKING, Creaking.class, CraftCreaking::new, createLiving(EntityTypes.CREAKING)));
register(new EntityTypeData<>(EntityType.CREAKING_TRANSIENT, CreakingTransient.class, CraftCreakingTransient::new, createLiving(EntityTypes.CREAKING_TRANSIENT)));
Function<SpawnData, EntityEnderDragon> dragonFunction = createLiving(EntityTypes.ENDER_DRAGON);
register(new EntityTypeData<>(EntityType.ENDER_DRAGON, EnderDragon.class, CraftEnderDragon::new, spawnData -> {

View File

@@ -495,7 +495,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
launch = new EntityThrownExpBottle(world, getHandle(), new net.minecraft.world.item.ItemStack(Items.EXPERIENCE_BOTTLE));
((EntityProjectile) launch).shootFromRotation(getHandle(), getHandle().getXRot(), getHandle().getYRot(), -20.0F, 0.7F, 1.0F); // ItemExpBottle
} else if (FishHook.class.isAssignableFrom(projectile) && getHandle() instanceof EntityHuman) {
launch = new EntityFishingHook((EntityHuman) getHandle(), world, 0, 0, new net.minecraft.world.item.ItemStack(Items.FISHING_ROD));
launch = new EntityFishingHook((EntityHuman) getHandle(), world, 0, 0);
} else if (Fireball.class.isAssignableFrom(projectile)) {
Location location = getEyeLocation();
Vector direction = location.getDirection().multiply(10);
@@ -622,7 +622,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
if (!isLeashed()) {
return false;
}
((EntityInsentient) getHandle()).dropLeash(true, false);
((EntityInsentient) getHandle()).removeLeash();
return true;
}

View File

@@ -30,6 +30,16 @@ public final class CraftMinecartTNT extends CraftMinecart implements ExplosiveMi
getHandle().explosionPowerBase = yield;
}
@Override
public float getExplosionSpeedFactor() {
return getHandle().explosionSpeedFactor;
}
@Override
public void setExplosionSpeedFactor(float factor) {
getHandle().explosionSpeedFactor = factor;
}
@Override
public void setFuseTicks(int ticks) {
getHandle().fuse = ticks;

View File

@@ -2023,21 +2023,6 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
getHandle().onUpdateAbilities();
}
@Override
public int getNoDamageTicks() {
if (getHandle().spawnInvulnerableTime > 0) {
return Math.max(getHandle().spawnInvulnerableTime, getHandle().invulnerableTime);
} else {
return getHandle().invulnerableTime;
}
}
@Override
public void setNoDamageTicks(int ticks) {
super.setNoDamageTicks(ticks);
getHandle().spawnInvulnerableTime = ticks; // SPIGOT-5921: Update both for players, like the getter above
}
@Override
public void setFlySpeed(float value) {
validateSpeed(value);
@@ -2288,7 +2273,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
@Override
public <T> void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, T data, boolean force) {
PacketPlayOutWorldParticles packetplayoutworldparticles = new PacketPlayOutWorldParticles(CraftParticle.createParticleParam(particle, data), force, (float) x, (float) y, (float) z, (float) offsetX, (float) offsetY, (float) offsetZ, (float) extra, count);
PacketPlayOutWorldParticles packetplayoutworldparticles = new PacketPlayOutWorldParticles(CraftParticle.createParticleParam(particle, data), false, force, (float) x, (float) y, (float) z, (float) offsetX, (float) offsetY, (float) offsetZ, (float) extra, count);
getHandle().connection.send(packetplayoutworldparticles);
}

View File

@@ -8,6 +8,7 @@ import java.util.concurrent.CompletableFuture;
import net.minecraft.core.BlockPosition;
import net.minecraft.core.Holder;
import net.minecraft.core.IRegistryCustom;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.RegionLimitedWorldAccess;
import net.minecraft.server.level.WorldServer;
import net.minecraft.util.MathHelper;
@@ -17,6 +18,7 @@ import net.minecraft.world.level.BlockColumn;
import net.minecraft.world.level.GeneratorAccessSeed;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.StructureManager;
import net.minecraft.world.level.World;
import net.minecraft.world.level.biome.BiomeBase;
import net.minecraft.world.level.biome.BiomeManager;
import net.minecraft.world.level.biome.BiomeSettingsMobs;
@@ -115,14 +117,14 @@ public class CustomChunkGenerator extends InternalChunkGenerator {
}
@Override
public void createStructures(IRegistryCustom iregistrycustom, ChunkGeneratorStructureState chunkgeneratorstructurestate, StructureManager structuremanager, IChunkAccess ichunkaccess, StructureTemplateManager structuretemplatemanager) {
public void createStructures(IRegistryCustom iregistrycustom, ChunkGeneratorStructureState chunkgeneratorstructurestate, StructureManager structuremanager, IChunkAccess ichunkaccess, StructureTemplateManager structuretemplatemanager, ResourceKey<World> resourcekey) {
SeededRandom random = getSeededRandom();
int x = ichunkaccess.getPos().x;
int z = ichunkaccess.getPos().z;
random.setSeed(MathHelper.getSeed(x, "should-structures".hashCode(), z) ^ world.getSeed());
if (generator.shouldGenerateStructures(this.world.getWorld(), new RandomSourceWrapper.RandomWrapper(random), x, z)) {
super.createStructures(iregistrycustom, chunkgeneratorstructurestate, structuremanager, ichunkaccess, structuretemplatemanager);
super.createStructures(iregistrycustom, chunkgeneratorstructurestate, structuremanager, ichunkaccess, structuretemplatemanager, resourcekey);
}
}

View File

@@ -25,6 +25,7 @@ import org.bukkit.craftbukkit.CraftRegistry;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.entity.CraftEntity;
import org.bukkit.craftbukkit.entity.CraftEntityType;
import org.bukkit.craftbukkit.inventory.components.CraftCustomModelDataComponent;
import org.bukkit.craftbukkit.inventory.components.CraftEquippableComponent;
import org.bukkit.craftbukkit.inventory.components.CraftFoodComponent;
import org.bukkit.craftbukkit.inventory.components.CraftJukeboxComponent;
@@ -45,6 +46,7 @@ public final class CraftItemFactory implements ItemFactory {
static {
instance = new CraftItemFactory();
ConfigurationSerialization.registerClass(SerializableMeta.class);
ConfigurationSerialization.registerClass(CraftCustomModelDataComponent.class);
ConfigurationSerialization.registerClass(CraftEquippableComponent.class);
ConfigurationSerialization.registerClass(CraftFoodComponent.class);
ConfigurationSerialization.registerClass(CraftToolComponent.class);

View File

@@ -103,5 +103,10 @@ public class CraftMerchantCustom implements CraftMerchant {
public boolean isClientSide() {
return false;
}
@Override
public boolean stillValid(EntityHuman entityhuman) {
return this.tradingPlayer == entityhuman;
}
}
}

View File

@@ -98,6 +98,7 @@ import org.bukkit.craftbukkit.block.CraftBlockType;
import org.bukkit.craftbukkit.block.data.CraftBlockData;
import org.bukkit.craftbukkit.enchantments.CraftEnchantment;
import org.bukkit.craftbukkit.inventory.CraftMetaItem.ItemMetaKey.Specific;
import org.bukkit.craftbukkit.inventory.components.CraftCustomModelDataComponent;
import org.bukkit.craftbukkit.inventory.components.CraftEquippableComponent;
import org.bukkit.craftbukkit.inventory.components.CraftFoodComponent;
import org.bukkit.craftbukkit.inventory.components.CraftJukeboxComponent;
@@ -121,6 +122,7 @@ import org.bukkit.inventory.meta.BlockDataMeta;
import org.bukkit.inventory.meta.Damageable;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.Repairable;
import org.bukkit.inventory.meta.components.CustomModelDataComponent;
import org.bukkit.inventory.meta.components.EquippableComponent;
import org.bukkit.inventory.meta.components.FoodComponent;
import org.bukkit.inventory.meta.components.JukeboxPlayableComponent;
@@ -281,7 +283,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
private IChatBaseComponent displayName;
private IChatBaseComponent itemName;
private List<IChatBaseComponent> lore; // null and empty are two different states internally
private Integer customModelData;
private CraftCustomModelDataComponent customModelData;
private Integer enchantableValue;
private Map<String, String> blockData;
private Map<Enchantment, Integer> enchantments;
@@ -328,7 +330,9 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
this.lore = new ArrayList<IChatBaseComponent>(meta.lore);
}
this.customModelData = meta.customModelData;
if (meta.hasCustomModelData()) {
this.customModelData = new CraftCustomModelDataComponent(meta.customModelData);
}
this.enchantableValue = meta.enchantableValue;
this.blockData = meta.blockData;
@@ -398,7 +402,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
});
getOrEmpty(tag, CUSTOM_MODEL_DATA).ifPresent((i) -> {
customModelData = i.value();
customModelData = new CraftCustomModelDataComponent(i);
});
getOrEmpty(tag, ENCHANTABLE).ifPresent((i) -> {
enchantableValue = i.value();
@@ -582,9 +586,11 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
safelyAdd(lore, this.lore = new ArrayList<IChatBaseComponent>(), true);
}
Integer customModelData = SerializableMeta.getObject(Integer.class, map, CUSTOM_MODEL_DATA.BUKKIT, true);
if (customModelData != null) {
setCustomModelData(customModelData);
Object customModelData = SerializableMeta.getObject(Object.class, map, CUSTOM_MODEL_DATA.BUKKIT, true);
if (customModelData instanceof CustomModelDataComponent component) {
setCustomModelDataComponent(component);
} else {
setCustomModelData((Integer) customModelData);
}
Integer enchantmentValue = SerializableMeta.getObject(Integer.class, map, ENCHANTABLE.BUKKIT, true);
if (enchantmentValue != null) {
@@ -915,7 +921,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
}
if (hasCustomModelData()) {
itemTag.put(CUSTOM_MODEL_DATA, new CustomModelData(customModelData));
itemTag.put(CUSTOM_MODEL_DATA, customModelData.getHandle());
}
if (hasEnchantable()) {
@@ -1281,12 +1287,25 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
@Override
public int getCustomModelData() {
Preconditions.checkState(hasCustomModelData(), "We don't have CustomModelData! Check hasCustomModelData first!");
return customModelData;
List<Float> floats = customModelData.getFloats();
Preconditions.checkState(!floats.isEmpty(), "No numeric custom model data");
return floats.get(0).intValue();
}
@Override
public CustomModelDataComponent getCustomModelDataComponent() {
return (this.hasCustomModelData()) ? new CraftCustomModelDataComponent(this.customModelData) : new CraftCustomModelDataComponent(new CustomModelData(List.of(), List.of(), List.of(), List.of()));
}
@Override
public void setCustomModelData(Integer data) {
this.customModelData = data;
this.customModelData = (data == null) ? null : new CraftCustomModelDataComponent(new CustomModelData(List.of(data.floatValue()), List.of(), List.of(), List.of()));
}
@Override
public void setCustomModelDataComponent(CustomModelDataComponent customModelData) {
this.customModelData = (customModelData == null) ? null : new CraftCustomModelDataComponent((CraftCustomModelDataComponent) customModelData);
}
@Override
@@ -1883,7 +1902,9 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
if (this.lore != null) {
clone.lore = new ArrayList<IChatBaseComponent>(this.lore);
}
clone.customModelData = this.customModelData;
if (this.hasCustomModelData()) {
clone.customModelData = new CraftCustomModelDataComponent(customModelData);
}
clone.enchantableValue = this.enchantableValue;
clone.blockData = this.blockData;
if (this.enchantments != null) {

View File

@@ -4,10 +4,8 @@ import com.google.common.base.Preconditions;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.crafting.IRecipe;
import net.minecraft.world.item.crafting.RecipeItemStack;
import org.bukkit.NamespacedKey;
@@ -38,9 +36,8 @@ public interface CraftRecipe extends Recipe {
throw new IllegalArgumentException("Unknown recipe stack instance " + bukkit);
}
List<Holder<Item>> items = stack.items();
if (requireNotEmpty) {
Preconditions.checkArgument(!items.isEmpty(), "Recipe requires at least one non-air choice");
Preconditions.checkArgument(!stack.isEmpty(), "Recipe requires at least one non-air choice");
}
return stack;
@@ -51,9 +48,7 @@ public interface CraftRecipe extends Recipe {
}
public static RecipeChoice toBukkit(RecipeItemStack list) {
List<Holder<Item>> items = list.items();
if (items.isEmpty()) {
if (list.isEmpty()) {
return null;
}
@@ -65,10 +60,7 @@ public interface CraftRecipe extends Recipe {
return new RecipeChoice.ExactChoice(choices);
} else {
List<org.bukkit.Material> choices = new ArrayList<>(items.size());
for (Holder<Item> i : items) {
choices.add(CraftItemType.minecraftToBukkit(i.value()));
}
List<org.bukkit.Material> choices = list.items().map((i) -> CraftItemType.minecraftToBukkit(i.value())).toList();
return new RecipeChoice.MaterialChoice(choices);
}

View File

@@ -4,6 +4,8 @@ import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import org.bukkit.block.Banner;
@@ -136,4 +138,39 @@ public final class SerializableMeta implements ConfigurationSerializable {
}
throw new IllegalArgumentException(field + "(" + object + ") is not a valid " + clazz);
}
public static <T> List<T> getList(Class<T> clazz, Map<?, ?> map, Object field) {
List<T> result = new ArrayList<>();
List<?> list = SerializableMeta.getObject(List.class, map, field, true);
if (list == null || list.isEmpty()) {
return result;
}
for (Object object : list) {
T cast = null;
if (clazz.isInstance(object)) {
cast = clazz.cast(object);
}
// SPIGOT-7675 - More lenient conversion of floating point numbers from other number types:
if (clazz == Float.class || clazz == Double.class) {
if (Number.class.isInstance(object)) {
Number number = Number.class.cast(object);
if (clazz == Float.class) {
cast = clazz.cast(number.floatValue());
} else {
cast = clazz.cast(number.doubleValue());
}
}
}
if (cast != null) {
result.add(cast);
}
}
return result;
}
}

View File

@@ -0,0 +1,119 @@
package org.bukkit.craftbukkit.inventory.components;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import net.minecraft.world.item.component.CustomModelData;
import org.bukkit.Color;
import org.bukkit.configuration.serialization.SerializableAs;
import org.bukkit.craftbukkit.inventory.SerializableMeta;
import org.bukkit.inventory.meta.components.CustomModelDataComponent;
@SerializableAs("CustomModelData")
public final class CraftCustomModelDataComponent implements CustomModelDataComponent {
private CustomModelData handle;
public CraftCustomModelDataComponent(CustomModelData handle) {
this.handle = handle;
}
public CraftCustomModelDataComponent(CraftCustomModelDataComponent craft) {
this.handle = craft.handle;
}
public CraftCustomModelDataComponent(Map<String, Object> map) {
handle = new CustomModelData(
SerializableMeta.getList(Float.class, map, "floats"),
SerializableMeta.getList(Boolean.class, map, "flags"),
SerializableMeta.getList(String.class, map, "strings"),
SerializableMeta.getList(Color.class, map, "colors").stream().map(Color::asRGB).toList()
);
}
@Override
public Map<String, Object> serialize() {
Map<String, Object> result = new LinkedHashMap<>();
result.put("floats", getFloats());
result.put("flags", getFlags());
result.put("strings", getStrings());
result.put("colors", getColors());
return result;
}
public CustomModelData getHandle() {
return handle;
}
@Override
public List<Float> getFloats() {
return Collections.unmodifiableList(handle.floats());
}
@Override
public void setFloats(List<Float> floats) {
handle = new CustomModelData(new ArrayList<>(floats), handle.flags(), handle.strings(), handle.colors());
}
@Override
public List<Boolean> getFlags() {
return Collections.unmodifiableList(handle.flags());
}
@Override
public void setFlags(List<Boolean> flags) {
handle = new CustomModelData(handle.floats(), new ArrayList<>(handle.flags()), handle.strings(), handle.colors());
}
@Override
public List<String> getStrings() {
return Collections.unmodifiableList(handle.strings());
}
@Override
public void setStrings(List<String> strings) {
handle = new CustomModelData(handle.floats(), handle.flags(), new ArrayList<>(handle.strings()), handle.colors());
}
@Override
public List<Color> getColors() {
return getHandle().colors().stream().map(Color::fromRGB).toList();
}
@Override
public void setColors(List<Color> colors) {
handle = new CustomModelData(handle.floats(), handle.flags(), handle.strings(), new ArrayList<>(handle.colors()));
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final CraftCustomModelDataComponent other = (CraftCustomModelDataComponent) obj;
return Objects.equals(this.handle, other.handle);
}
@Override
public int hashCode() {
int hash = 7;
hash = 19 * hash + Objects.hashCode(this.handle);
return hash;
}
@Override
public String toString() {
return "CraftCustomModelDataComponent{" + "handle=" + handle + '}';
}
}

View File

@@ -12,9 +12,11 @@ import net.minecraft.core.HolderSet;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.MinecraftKey;
import net.minecraft.resources.ResourceKey;
import net.minecraft.sounds.SoundEffects;
import net.minecraft.world.entity.EntityTypes;
import net.minecraft.world.entity.EnumItemSlot;
import net.minecraft.world.item.equipment.EquipmentAssets;
import net.minecraft.world.item.equipment.Equippable;
import org.bukkit.NamespacedKey;
import org.bukkit.Registry;
@@ -68,7 +70,7 @@ public final class CraftEquippableComponent implements EquippableComponent {
this.handle = new Equippable(slot,
(equipSound != null) ? CraftSound.bukkitToMinecraftHolder(equipSound) : SoundEffects.ARMOR_EQUIP_GENERIC,
Optional.ofNullable(model).map(MinecraftKey::parse),
Optional.ofNullable(model).map(MinecraftKey::parse).map((k) -> ResourceKey.create(EquipmentAssets.ROOT_ID, k)),
Optional.ofNullable(cameraOverlay).map(MinecraftKey::parse),
Optional.ofNullable(allowedEntities),
(dispensable != null) ? dispensable : true,
@@ -116,7 +118,7 @@ public final class CraftEquippableComponent implements EquippableComponent {
@Override
public void setSlot(EquipmentSlot slot) {
handle = new Equippable(CraftEquipmentSlot.getNMS(slot), handle.equipSound(), handle.model(), handle.cameraOverlay(), handle.allowedEntities(), handle.dispensable(), handle.swappable(), handle.damageOnHurt());
handle = new Equippable(CraftEquipmentSlot.getNMS(slot), handle.equipSound(), handle.assetId(), handle.cameraOverlay(), handle.allowedEntities(), handle.dispensable(), handle.swappable(), handle.damageOnHurt());
}
@Override
@@ -126,17 +128,17 @@ public final class CraftEquippableComponent implements EquippableComponent {
@Override
public void setEquipSound(Sound sound) {
handle = new Equippable(handle.slot(), (sound != null) ? CraftSound.bukkitToMinecraftHolder(sound) : SoundEffects.ARMOR_EQUIP_GENERIC, handle.model(), handle.cameraOverlay(), handle.allowedEntities(), handle.dispensable(), handle.swappable(), handle.damageOnHurt());
handle = new Equippable(handle.slot(), (sound != null) ? CraftSound.bukkitToMinecraftHolder(sound) : SoundEffects.ARMOR_EQUIP_GENERIC, handle.assetId(), handle.cameraOverlay(), handle.allowedEntities(), handle.dispensable(), handle.swappable(), handle.damageOnHurt());
}
@Override
public NamespacedKey getModel() {
return handle.model().map(CraftNamespacedKey::fromMinecraft).orElse(null);
return handle.assetId().map((a) -> CraftNamespacedKey.fromMinecraft(a.location())).orElse(null);
}
@Override
public void setModel(NamespacedKey key) {
handle = new Equippable(handle.slot(), handle.equipSound(), Optional.ofNullable(key).map(CraftNamespacedKey::toMinecraft), handle.cameraOverlay(), handle.allowedEntities(), handle.dispensable(), handle.swappable(), handle.damageOnHurt());
handle = new Equippable(handle.slot(), handle.equipSound(), Optional.ofNullable(key).map(CraftNamespacedKey::toMinecraft).map((k) -> ResourceKey.create(EquipmentAssets.ROOT_ID, k)), handle.cameraOverlay(), handle.allowedEntities(), handle.dispensable(), handle.swappable(), handle.damageOnHurt());
}
@Override
@@ -146,7 +148,7 @@ public final class CraftEquippableComponent implements EquippableComponent {
@Override
public void setCameraOverlay(NamespacedKey key) {
handle = new Equippable(handle.slot(), handle.equipSound(), handle.model(), Optional.ofNullable(key).map(CraftNamespacedKey::toMinecraft), handle.allowedEntities(), handle.dispensable(), handle.swappable(), handle.damageOnHurt());
handle = new Equippable(handle.slot(), handle.equipSound(), handle.assetId(), Optional.ofNullable(key).map(CraftNamespacedKey::toMinecraft), handle.allowedEntities(), handle.dispensable(), handle.swappable(), handle.damageOnHurt());
}
@Override
@@ -156,7 +158,7 @@ public final class CraftEquippableComponent implements EquippableComponent {
@Override
public void setAllowedEntities(EntityType entities) {
handle = new Equippable(handle.slot(), handle.equipSound(), handle.model(), handle.cameraOverlay(),
handle = new Equippable(handle.slot(), handle.equipSound(), handle.assetId(), handle.cameraOverlay(),
(entities != null) ? Optional.of(HolderSet.direct(CraftEntityType.bukkitToMinecraftHolder(entities))) : Optional.empty(),
handle.dispensable(), handle.swappable(), handle.damageOnHurt()
);
@@ -164,7 +166,7 @@ public final class CraftEquippableComponent implements EquippableComponent {
@Override
public void setAllowedEntities(Collection<EntityType> entities) {
handle = new Equippable(handle.slot(), handle.equipSound(), handle.model(), handle.cameraOverlay(),
handle = new Equippable(handle.slot(), handle.equipSound(), handle.assetId(), handle.cameraOverlay(),
(entities != null) ? Optional.of(HolderSet.direct(entities.stream().map(CraftEntityType::bukkitToMinecraftHolder).collect(Collectors.toList()))) : Optional.empty(),
handle.dispensable(), handle.swappable(), handle.damageOnHurt()
);
@@ -174,7 +176,7 @@ public final class CraftEquippableComponent implements EquippableComponent {
public void setAllowedEntities(Tag<EntityType> tag) {
Preconditions.checkArgument(tag instanceof CraftEntityTag, "tag must be an entity tag");
handle = new Equippable(handle.slot(), handle.equipSound(), handle.model(), handle.cameraOverlay(),
handle = new Equippable(handle.slot(), handle.equipSound(), handle.assetId(), handle.cameraOverlay(),
(tag != null) ? Optional.of(((CraftEntityTag) tag).getHandle()) : Optional.empty(),
handle.dispensable(), handle.swappable(), handle.damageOnHurt()
);
@@ -187,7 +189,7 @@ public final class CraftEquippableComponent implements EquippableComponent {
@Override
public void setDispensable(boolean dispensable) {
handle = new Equippable(handle.slot(), handle.equipSound(), handle.model(), handle.cameraOverlay(), handle.allowedEntities(), dispensable, handle.swappable(), handle.damageOnHurt());
handle = new Equippable(handle.slot(), handle.equipSound(), handle.assetId(), handle.cameraOverlay(), handle.allowedEntities(), dispensable, handle.swappable(), handle.damageOnHurt());
}
@Override
@@ -197,7 +199,7 @@ public final class CraftEquippableComponent implements EquippableComponent {
@Override
public void setSwappable(boolean swappable) {
handle = new Equippable(handle.slot(), handle.equipSound(), handle.model(), handle.cameraOverlay(), handle.allowedEntities(), handle.dispensable(), swappable, handle.damageOnHurt());
handle = new Equippable(handle.slot(), handle.equipSound(), handle.assetId(), handle.cameraOverlay(), handle.allowedEntities(), handle.dispensable(), swappable, handle.damageOnHurt());
}
@Override
@@ -207,7 +209,7 @@ public final class CraftEquippableComponent implements EquippableComponent {
@Override
public void setDamageOnHurt(boolean damage) {
handle = new Equippable(handle.slot(), handle.equipSound(), handle.model(), handle.cameraOverlay(), handle.allowedEntities(), handle.dispensable(), handle.swappable(), damage);
handle = new Equippable(handle.slot(), handle.equipSound(), handle.assetId(), handle.cameraOverlay(), handle.allowedEntities(), handle.dispensable(), handle.swappable(), damage);
}
@Override

View File

@@ -16,7 +16,7 @@ public final class ApiVersion implements Comparable<ApiVersion>, Serializable {
static {
versions = new HashMap<>();
CURRENT = getOrCreateVersion("1.21.3");
CURRENT = getOrCreateVersion("1.21.4");
FLATTENING = getOrCreateVersion("1.13");
FIELD_NAME_PARITY = getOrCreateVersion("1.20.5");
NONE = getOrCreateVersion("none");

View File

@@ -233,7 +233,7 @@ public final class CraftMagicNumbers implements UnsafeValues {
* @return string
*/
public String getMappingsVersion() {
return "61a218cda78417b6039da56e08194083";
return "60ac387ca8007aa018e6aeb394a6988c";
}
@Override

View File

@@ -31,7 +31,7 @@ public class ChatTest {
CraftChatMessage.toJSON(components[0]));
components = CraftChatMessage.fromString("123 " + ChatColor.GOLD + "https://spigotmc.org " + ChatColor.BOLD + "test");
assertEquals("{\"text\":\"\",\"extra\":[\"123 \",{\"text\":\"https://spigotmc.org\",\"obfuscated\":false,\"clickEvent\":{\"action\":\"open_url\",\"value\":\"https://spigotmc.org\"},\"italic\":false,\"underlined\":false,\"strikethrough\":false,\"color\":\"gold\",\"bold\":false},{\"text\":\" \",\"obfuscated\":false,\"italic\":false,\"underlined\":false,\"strikethrough\":false,\"color\":\"gold\",\"bold\":false},{\"text\":\"test\",\"obfuscated\":false,\"italic\":false,\"underlined\":false,\"strikethrough\":false,\"color\":\"gold\",\"bold\":true}]}",
assertEquals("{\"text\":\"\",\"extra\":[\"123 \",{\"text\":\"https://spigotmc.org\",\"strikethrough\":false,\"obfuscated\":false,\"clickEvent\":{\"action\":\"open_url\",\"value\":\"https://spigotmc.org\"},\"bold\":false,\"italic\":false,\"underlined\":false,\"color\":\"gold\"},{\"text\":\" \",\"strikethrough\":false,\"obfuscated\":false,\"bold\":false,\"italic\":false,\"underlined\":false,\"color\":\"gold\"},{\"text\":\"test\",\"strikethrough\":false,\"obfuscated\":false,\"bold\":true,\"italic\":false,\"underlined\":false,\"color\":\"gold\"}]}",
CraftChatMessage.toJSON(components[0]));
components = CraftChatMessage.fromString("multiCase http://SpigotMC.ORg/SpOngeBobMeEMeGoESHeRE");

View File

@@ -13,7 +13,7 @@ import net.minecraft.core.particles.ParticleParamRedstone;
import net.minecraft.core.particles.ParticleType;
import net.minecraft.core.particles.SculkChargeParticleOptions;
import net.minecraft.core.particles.ShriekParticleOption;
import net.minecraft.core.particles.TargetColorParticleOption;
import net.minecraft.core.particles.TrailParticleOption;
import net.minecraft.core.particles.VibrationParticleOption;
import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.DynamicOpsNBT;
@@ -113,8 +113,8 @@ public class ParticleTest {
return;
}
if (bukkit.getDataType().equals(Particle.TargetColor.class)) {
testTargetColor(bukkit, minecraft);
if (bukkit.getDataType().equals(Particle.Trail.class)) {
testTrail(bukkit, minecraft);
return;
}
@@ -248,11 +248,11 @@ public class ParticleTest {
""", bukkit.getKey(), expected, actual)); // Print expected and got since we use assert true
}
private <T extends ParticleParam> void testTargetColor(Particle bukkit, net.minecraft.core.particles.Particle<T> minecraft) {
private <T extends ParticleParam> void testTrail(Particle bukkit, net.minecraft.core.particles.Particle<T> minecraft) {
Color color = Color.fromRGB(236, 28, 36);
Particle.TargetColor targetColor = new Particle.TargetColor(new Location(null, 1, 5, 9), color);
Particle.Trail trail = new Particle.Trail(new Location(null, 1, 5, 9), color, 20);
TargetColorParticleOption param = createAndTest(bukkit, minecraft, targetColor, TargetColorParticleOption.class);
TrailParticleOption param = createAndTest(bukkit, minecraft, trail, TrailParticleOption.class);
Vec3D pos = param.target();
assertEquals(new Vec3D(1.0, 5.0, 9.0), pos, String.format("""

View File

@@ -132,6 +132,9 @@ public class LegacyTest {
Material.CREAKING_SPAWN_EGG, Material.PALE_HANGING_MOSS, Material.PALE_MOSS_BLOCK, Material.PALE_MOSS_CARPET, Material.PALE_OAK_BOAT, Material.PALE_OAK_BUTTON, Material.PALE_OAK_CHEST_BOAT, Material.PALE_OAK_DOOR, Material.PALE_OAK_FENCE,
Material.PALE_OAK_FENCE_GATE, Material.PALE_OAK_HANGING_SIGN, Material.PALE_OAK_LEAVES, Material.PALE_OAK_LOG, Material.PALE_OAK_PLANKS, Material.PALE_OAK_PRESSURE_PLATE, Material.PALE_OAK_SAPLING, Material.PALE_OAK_SIGN, Material.PALE_OAK_SLAB,
Material.PALE_OAK_STAIRS, Material.PALE_OAK_TRAPDOOR, Material.PALE_OAK_WALL_SIGN, Material.PALE_OAK_WALL_HANGING_SIGN, Material.PALE_OAK_WOOD, Material.POTTED_PALE_OAK_SAPLING, Material.STRIPPED_PALE_OAK_LOG, Material.STRIPPED_PALE_OAK_WOOD,
// 1.21.4
Material.OPEN_EYEBLOSSOM, Material.CLOSED_EYEBLOSSOM, Material.RESIN_CLUMP, Material.RESIN_BLOCK, Material.RESIN_BRICKS, Material.RESIN_BRICK_STAIRS, Material.RESIN_BRICK_SLAB, Material.RESIN_BRICK_WALL, Material.CHISELED_RESIN_BRICKS,
Material.RESIN_BRICK, Material.POTTED_OPEN_EYEBLOSSOM, Material.POTTED_CLOSED_EYEBLOSSOM,
//
Material.LEGACY_AIR, Material.LEGACY_DEAD_BUSH, Material.LEGACY_BURNING_FURNACE, Material.LEGACY_WALL_SIGN, Material.LEGACY_REDSTONE_TORCH_OFF, Material.LEGACY_SKULL, Material.LEGACY_REDSTONE_COMPARATOR_ON, Material.LEGACY_WALL_BANNER, Material.LEGACY_MONSTER_EGG));