13
0
geforkt von Mirrors/Paper

SPIGOT-7809: Add ShieldMeta and fix setting shield base colours

By: Doc <nachito94@msn.com>
Also-by: md_5 <git@md-5.net>
Dieser Commit ist enthalten in:
CraftBukkit/Spigot 2024-07-20 10:15:22 +10:00
Ursprung 58a0878879
Commit 60eec22bd3
6 geänderte Dateien mit 350 neuen und 10 gelöschten Zeilen

Datei anzeigen

@ -24,6 +24,7 @@ import org.bukkit.inventory.meta.MapMeta;
import org.bukkit.inventory.meta.MusicInstrumentMeta; import org.bukkit.inventory.meta.MusicInstrumentMeta;
import org.bukkit.inventory.meta.OminousBottleMeta; import org.bukkit.inventory.meta.OminousBottleMeta;
import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.inventory.meta.ShieldMeta;
import org.bukkit.inventory.meta.SkullMeta; import org.bukkit.inventory.meta.SkullMeta;
import org.bukkit.inventory.meta.SpawnEggMeta; import org.bukkit.inventory.meta.SpawnEggMeta;
import org.bukkit.inventory.meta.SuspiciousStewMeta; import org.bukkit.inventory.meta.SuspiciousStewMeta;
@ -107,6 +108,10 @@ public final class CraftItemMetas {
item -> new CraftMetaBlockState(item.getComponentsPatch(), CraftItemType.minecraftToBukkit(item.getItem())), item -> new CraftMetaBlockState(item.getComponentsPatch(), CraftItemType.minecraftToBukkit(item.getItem())),
(type, meta) -> new CraftMetaBlockState(meta, type.asMaterial())); (type, meta) -> new CraftMetaBlockState(meta, type.asMaterial()));
private static final ItemMetaData<ShieldMeta> SHIELD_META_DATA = new ItemMetaData<>(ShieldMeta.class,
item -> new CraftMetaShield(item.getComponentsPatch()),
(type, meta) -> new CraftMetaShield(meta));
private static final ItemMetaData<TropicalFishBucketMeta> TROPICAL_FISH_BUCKET_META_DATA = new ItemMetaData<>(TropicalFishBucketMeta.class, private static final ItemMetaData<TropicalFishBucketMeta> TROPICAL_FISH_BUCKET_META_DATA = new ItemMetaData<>(TropicalFishBucketMeta.class,
item -> new CraftMetaTropicalFishBucket(item.getComponentsPatch()), item -> new CraftMetaTropicalFishBucket(item.getComponentsPatch()),
(type, meta) -> meta instanceof CraftMetaTropicalFishBucket tropicalFishBucket ? tropicalFishBucket : new CraftMetaTropicalFishBucket(meta)); (type, meta) -> meta instanceof CraftMetaTropicalFishBucket tropicalFishBucket ? tropicalFishBucket : new CraftMetaTropicalFishBucket(meta));
@ -258,8 +263,8 @@ public final class CraftItemMetas {
|| itemType == ItemType.COMMAND_BLOCK || itemType == ItemType.REPEATING_COMMAND_BLOCK || itemType == ItemType.COMMAND_BLOCK || itemType == ItemType.REPEATING_COMMAND_BLOCK
|| itemType == ItemType.CHAIN_COMMAND_BLOCK || itemType == ItemType.BEACON || itemType == ItemType.CHAIN_COMMAND_BLOCK || itemType == ItemType.BEACON
|| itemType == ItemType.DAYLIGHT_DETECTOR || itemType == ItemType.HOPPER || itemType == ItemType.DAYLIGHT_DETECTOR || itemType == ItemType.HOPPER
|| itemType == ItemType.COMPARATOR || itemType == ItemType.SHIELD || itemType == ItemType.COMPARATOR || itemType == ItemType.STRUCTURE_BLOCK
|| itemType == ItemType.STRUCTURE_BLOCK || (itemType.hasBlockType() && Tag.SHULKER_BOXES.isTagged(itemType.getBlockType().asMaterial())) || (itemType.hasBlockType() && Tag.SHULKER_BOXES.isTagged(itemType.getBlockType().asMaterial()))
|| itemType == ItemType.ENDER_CHEST || itemType == ItemType.BARREL || itemType == ItemType.ENDER_CHEST || itemType == ItemType.BARREL
|| itemType == ItemType.BELL || itemType == ItemType.BLAST_FURNACE || itemType == ItemType.BELL || itemType == ItemType.BLAST_FURNACE
|| itemType == ItemType.CAMPFIRE || itemType == ItemType.SOUL_CAMPFIRE || itemType == ItemType.CAMPFIRE || itemType == ItemType.SOUL_CAMPFIRE
@ -273,6 +278,9 @@ public final class CraftItemMetas {
|| itemType == ItemType.TRIAL_SPAWNER || itemType == ItemType.VAULT) { || itemType == ItemType.TRIAL_SPAWNER || itemType == ItemType.VAULT) {
return asType(BLOCK_STATE_META_DATA); return asType(BLOCK_STATE_META_DATA);
} }
if (itemType == ItemType.SHIELD) {
return asType(SHIELD_META_DATA);
}
if (itemType == ItemType.TROPICAL_FISH_BUCKET) { if (itemType == ItemType.TROPICAL_FISH_BUCKET) {
return asType(TROPICAL_FISH_BUCKET_META_DATA); return asType(TROPICAL_FISH_BUCKET_META_DATA);
} }

Datei anzeigen

@ -15,8 +15,10 @@ import net.minecraft.core.component.PatchedDataComponentMap;
import net.minecraft.core.component.TypedDataComponent; import net.minecraft.core.component.TypedDataComponent;
import net.minecraft.nbt.NBTBase; import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.item.EnumColor;
import net.minecraft.world.item.component.CustomData; import net.minecraft.world.item.component.CustomData;
import net.minecraft.world.level.block.entity.TileEntity; import net.minecraft.world.level.block.entity.TileEntity;
import org.bukkit.DyeColor;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.block.BlockState; import org.bukkit.block.BlockState;
import org.bukkit.configuration.serialization.DelegateDeserialization; import org.bukkit.configuration.serialization.DelegateDeserialization;
@ -202,7 +204,7 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta
private static CraftBlockEntityState<?> getBlockState(Material material, NBTTagCompound blockEntityTag) { private static CraftBlockEntityState<?> getBlockState(Material material, NBTTagCompound blockEntityTag) {
BlockPosition pos = BlockPosition.ZERO; BlockPosition pos = BlockPosition.ZERO;
Material stateMaterial = (material != Material.SHIELD) ? material : shieldToBannerHack(); // Only actually used for jigsaws Material stateMaterial = (material != Material.SHIELD) ? material : shieldToBannerHack(blockEntityTag); // Only actually used for jigsaws
if (blockEntityTag != null) { if (blockEntityTag != null) {
if (material == Material.SHIELD) { if (material == Material.SHIELD) {
blockEntityTag.putString("id", "minecraft:banner"); blockEntityTag.putString("id", "minecraft:banner");
@ -223,14 +225,25 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta
public void setBlockState(BlockState blockState) { public void setBlockState(BlockState blockState) {
Preconditions.checkArgument(blockState != null, "blockState must not be null"); Preconditions.checkArgument(blockState != null, "blockState must not be null");
Material stateMaterial = (material != Material.SHIELD) ? material : shieldToBannerHack(); Material stateMaterial = (material != Material.SHIELD) ? material : shieldToBannerHack(null);
Class<?> blockStateType = CraftBlockStates.getBlockStateType(stateMaterial); Class<?> blockStateType = CraftBlockStates.getBlockStateType(stateMaterial);
Preconditions.checkArgument(blockStateType == blockState.getClass() && blockState instanceof CraftBlockEntityState, "Invalid blockState for " + material); Preconditions.checkArgument(blockStateType == blockState.getClass() && blockState instanceof CraftBlockEntityState, "Invalid blockState for %s", material);
this.blockEntityTag = (CraftBlockEntityState<?>) blockState; this.blockEntityTag = (CraftBlockEntityState<?>) blockState;
} }
private static Material shieldToBannerHack() { private static Material shieldToBannerHack(NBTTagCompound tag) {
if (tag != null) {
if (tag.contains("components", CraftMagicNumbers.NBT.TAG_COMPOUND)) {
NBTTagCompound components = tag.getCompound("components");
if (components.contains("minecraft:base_color", CraftMagicNumbers.NBT.TAG_STRING)) {
DyeColor color = DyeColor.getByWoolData((byte) EnumColor.byName(components.getString("minecraft:base_color"), EnumColor.WHITE).getId());
return CraftMetaShield.shieldToBannerHack(color);
}
}
}
return Material.WHITE_BANNER; return Material.WHITE_BANNER;
} }
} }

Datei anzeigen

@ -1923,6 +1923,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
CraftMetaMap.MAP_COLOR.TYPE, CraftMetaMap.MAP_COLOR.TYPE,
CraftMetaMap.MAP_ID.TYPE, CraftMetaMap.MAP_ID.TYPE,
CraftMetaPotion.POTION_CONTENTS.TYPE, CraftMetaPotion.POTION_CONTENTS.TYPE,
CraftMetaShield.BASE_COLOR.TYPE,
CraftMetaSkull.SKULL_PROFILE.TYPE, CraftMetaSkull.SKULL_PROFILE.TYPE,
CraftMetaSkull.NOTE_BLOCK_SOUND.TYPE, CraftMetaSkull.NOTE_BLOCK_SOUND.TYPE,
CraftMetaSpawnEgg.ENTITY_TAG.TYPE, CraftMetaSpawnEgg.ENTITY_TAG.TYPE,

Datei anzeigen

@ -0,0 +1,302 @@
package org.bukkit.craftbukkit.inventory;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import net.minecraft.core.BlockPosition;
import net.minecraft.core.component.DataComponentPatch;
import net.minecraft.core.component.DataComponents;
import net.minecraft.world.item.EnumColor;
import net.minecraft.world.level.block.entity.BannerPatternLayers;
import org.bukkit.DyeColor;
import org.bukkit.Material;
import org.bukkit.block.Banner;
import org.bukkit.block.BlockState;
import org.bukkit.block.banner.Pattern;
import org.bukkit.block.banner.PatternType;
import org.bukkit.configuration.serialization.DelegateDeserialization;
import org.bukkit.craftbukkit.block.CraftBlockStates;
import org.bukkit.craftbukkit.block.banner.CraftPatternType;
import org.bukkit.inventory.meta.BlockStateMeta;
import org.bukkit.inventory.meta.ShieldMeta;
@DelegateDeserialization(SerializableMeta.class)
public class CraftMetaShield extends CraftMetaItem implements ShieldMeta, BlockStateMeta {
static final ItemMetaKeyType<EnumColor> BASE_COLOR = new ItemMetaKeyType<>(DataComponents.BASE_COLOR, "Base", "base-color");
private Banner banner;
CraftMetaShield(CraftMetaItem meta) {
super(meta);
if (meta instanceof CraftMetaShield craftMetaShield) {
if (craftMetaShield.banner != null) {
this.banner = (Banner) craftMetaShield.banner.copy();
}
} else if (meta instanceof CraftMetaBlockState state && state.hasBlockState() && state.getBlockState() instanceof Banner banner) {
this.banner = (Banner) banner.copy();
}
}
CraftMetaShield(DataComponentPatch tag) {
super(tag);
getOrEmpty(tag, BASE_COLOR).ifPresent((color) -> {
banner = getBlockState(DyeColor.getByWoolData((byte) color.getId()));
});
getOrEmpty(tag, CraftMetaBanner.PATTERNS).ifPresent((entityTag) -> {
List<BannerPatternLayers.b> patterns = entityTag.layers();
for (int i = 0; i < Math.min(patterns.size(), 20); i++) {
BannerPatternLayers.b p = patterns.get(i);
DyeColor color = DyeColor.getByWoolData((byte) p.color().getId());
PatternType pattern = CraftPatternType.minecraftHolderToBukkit(p.pattern());
if (color != null && pattern != null) {
addPattern(new Pattern(color, pattern));
}
}
});
}
CraftMetaShield(Map<String, Object> map) {
super(map);
String baseColor = SerializableMeta.getString(map, BASE_COLOR.BUKKIT, true);
if (baseColor != null) {
banner = getBlockState(DyeColor.valueOf(baseColor));
}
Iterable<?> rawPatternList = SerializableMeta.getObject(Iterable.class, map, CraftMetaBanner.PATTERNS.BUKKIT, true);
if (rawPatternList == null) {
return;
}
for (Object obj : rawPatternList) {
Preconditions.checkArgument(obj instanceof Pattern, "Object (%s) in pattern list is not valid", obj.getClass());
addPattern((Pattern) obj);
}
}
@Override
void applyToItem(CraftMetaItem.Applicator tag) {
super.applyToItem(tag);
if (banner != null) {
tag.put(BASE_COLOR, EnumColor.byId(banner.getBaseColor().getWoolData()));
if (banner.numberOfPatterns() > 0) {
List<BannerPatternLayers.b> newPatterns = new ArrayList<>();
for (Pattern p : banner.getPatterns()) {
newPatterns.add(new BannerPatternLayers.b(CraftPatternType.bukkitToMinecraftHolder(p.getPattern()), EnumColor.byId(p.getColor().getWoolData())));
}
tag.put(CraftMetaBanner.PATTERNS, new BannerPatternLayers(newPatterns));
}
}
}
@Override
public List<Pattern> getPatterns() {
if (banner == null) {
return new ArrayList<>();
}
return banner.getPatterns();
}
@Override
public void setPatterns(List<Pattern> patterns) {
if (banner == null) {
if (patterns.isEmpty()) {
return;
}
banner = getBlockState(null);
}
banner.setPatterns(patterns);
}
@Override
public void addPattern(Pattern pattern) {
if (banner == null) {
banner = getBlockState(null);
}
banner.addPattern(pattern);
}
@Override
public Pattern getPattern(int i) {
if (banner == null) {
throw new IndexOutOfBoundsException(i);
}
return banner.getPattern(i);
}
@Override
public Pattern removePattern(int i) {
if (banner == null) {
throw new IndexOutOfBoundsException(i);
}
return banner.removePattern(i);
}
@Override
public void setPattern(int i, Pattern pattern) {
if (banner == null) {
throw new IndexOutOfBoundsException(i);
}
banner.setPattern(i, pattern);
}
@Override
public int numberOfPatterns() {
if (banner == null) {
return 0;
}
return banner.numberOfPatterns();
}
@Override
public DyeColor getBaseColor() {
if (banner == null) {
return null;
}
return banner.getBaseColor();
}
@Override
public void setBaseColor(DyeColor baseColor) {
if (baseColor == null) {
if (banner.numberOfPatterns() > 0) {
banner.setBaseColor(DyeColor.WHITE);
} else {
banner = null;
}
} else {
if (banner == null) {
banner = getBlockState(baseColor);
}
banner.setBaseColor(baseColor);
}
}
@Override
ImmutableMap.Builder<String, Object> serialize(ImmutableMap.Builder<String, Object> builder) {
super.serialize(builder);
if (banner != null) {
builder.put(BASE_COLOR.BUKKIT, banner.getBaseColor().toString());
if (banner.numberOfPatterns() > 0) {
builder.put(CraftMetaBanner.PATTERNS.BUKKIT, banner.getPatterns());
}
}
return builder;
}
@Override
int applyHash() {
final int original;
int hash = original = super.applyHash();
if (banner != null) {
hash = 61 * hash + banner.hashCode();
}
return original != hash ? CraftMetaShield.class.hashCode() ^ hash : hash;
}
@Override
boolean equalsCommon(CraftMetaItem meta) {
if (!super.equalsCommon(meta)) {
return false;
}
if (meta instanceof CraftMetaShield that) {
return Objects.equal(this.banner, that.banner);
}
return true;
}
@Override
boolean notUncommon(CraftMetaItem meta) {
return super.notUncommon(meta) && (meta instanceof CraftMetaShield || this.banner == null);
}
@Override
boolean isEmpty() {
return super.isEmpty() && this.banner == null;
}
@Override
public boolean hasBlockState() {
return banner != null;
}
@Override
public BlockState getBlockState() {
return (banner != null) ? banner.copy() : getBlockState(null);
}
@Override
public void setBlockState(BlockState blockState) {
Preconditions.checkArgument(blockState != null, "blockState must not be null");
Preconditions.checkArgument(blockState instanceof Banner, "Invalid blockState");
this.banner = (Banner) blockState;
}
private static Banner getBlockState(DyeColor color) {
BlockPosition pos = BlockPosition.ZERO;
Material stateMaterial = shieldToBannerHack(color);
return (Banner) CraftBlockStates.getBlockState(pos, stateMaterial, null);
}
@Override
public CraftMetaShield clone() {
CraftMetaShield meta = (CraftMetaShield) super.clone();
if (this.banner != null) {
meta.banner = (Banner) banner.copy();
}
return meta;
}
static Material shieldToBannerHack(DyeColor color) {
if (color == null) {
return Material.WHITE_BANNER;
}
return switch (color) {
case WHITE -> Material.WHITE_BANNER;
case ORANGE -> Material.ORANGE_BANNER;
case MAGENTA -> Material.MAGENTA_BANNER;
case LIGHT_BLUE -> Material.LIGHT_BLUE_BANNER;
case YELLOW -> Material.YELLOW_BANNER;
case LIME -> Material.LIME_BANNER;
case PINK -> Material.PINK_BANNER;
case GRAY -> Material.GRAY_BANNER;
case LIGHT_GRAY -> Material.LIGHT_GRAY_BANNER;
case CYAN -> Material.CYAN_BANNER;
case PURPLE -> Material.PURPLE_BANNER;
case BLUE -> Material.BLUE_BANNER;
case BROWN -> Material.BROWN_BANNER;
case GREEN -> Material.GREEN_BANNER;
case RED -> Material.RED_BANNER;
case BLACK -> Material.BLACK_BANNER;
default -> throw new IllegalArgumentException("Unknown banner colour");
};
}
}

Datei anzeigen

@ -6,6 +6,7 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import org.bukkit.block.Banner;
import org.bukkit.configuration.serialization.ConfigurationSerializable; import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.configuration.serialization.SerializableAs; import org.bukkit.configuration.serialization.SerializableAs;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
@ -30,6 +31,7 @@ public final class SerializableMeta implements ConfigurationSerializable {
.put(CraftMetaColorableArmor.class, "COLORABLE_ARMOR") .put(CraftMetaColorableArmor.class, "COLORABLE_ARMOR")
.put(CraftMetaMap.class, "MAP") .put(CraftMetaMap.class, "MAP")
.put(CraftMetaPotion.class, "POTION") .put(CraftMetaPotion.class, "POTION")
.put(CraftMetaShield.class, "SHIELD")
.put(CraftMetaSpawnEgg.class, "SPAWN_EGG") .put(CraftMetaSpawnEgg.class, "SPAWN_EGG")
.put(CraftMetaEnchantedBook.class, "ENCHANTED") .put(CraftMetaEnchantedBook.class, "ENCHANTED")
.put(CraftMetaFirework.class, "FIREWORK") .put(CraftMetaFirework.class, "FIREWORK")
@ -72,10 +74,16 @@ public final class SerializableMeta implements ConfigurationSerializable {
} }
try { try {
return constructor.newInstance(map); CraftMetaItem meta = constructor.newInstance(map);
} catch (final InstantiationException e) {
throw new AssertionError(e); // Convert Shield CraftMetaBlockState to CraftMetaShield
} catch (final IllegalAccessException e) { if (meta instanceof CraftMetaBlockState state && state.hasBlockState() && state.getBlockState() instanceof Banner) {
meta = new CraftMetaShield(meta);
meta.unhandledTags.clear(CraftMetaShield.BASE_COLOR.TYPE);
}
return meta;
} catch (final InstantiationException | IllegalAccessException e) {
throw new AssertionError(e); throw new AssertionError(e);
} catch (final InvocationTargetException e) { } catch (final InvocationTargetException e) {
throw e.getCause(); throw e.getCause();

Datei anzeigen

@ -416,6 +416,14 @@ public class ItemMetaTest extends AbstractTestingBase {
cleanStack.setItemMeta(meta); cleanStack.setItemMeta(meta);
return cleanStack; return cleanStack;
} }
},
new StackProvider(Material.SHIELD) {
@Override ItemStack operate(ItemStack cleanStack) {
final CraftMetaShield meta = (CraftMetaShield) cleanStack.getItemMeta();
meta.setBaseColor(DyeColor.ORANGE);
cleanStack.setItemMeta(meta);
return cleanStack;
}
} }
); );