SPIGOT-4802: Add CrossbowMeta

This commit is contained in:
md_5 2019-05-01 20:18:01 +10:00
parent d5c2e3ccb6
commit 1fa9a81514
5 changed files with 219 additions and 1 deletions

View file

@ -252,6 +252,8 @@ public final class CraftItemFactory implements ItemFactory {
return new CraftMetaBlockState(meta, material); return new CraftMetaBlockState(meta, material);
case TROPICAL_FISH_BUCKET: case TROPICAL_FISH_BUCKET:
return meta instanceof CraftMetaTropicalFishBucket ? meta : new CraftMetaTropicalFishBucket(meta); return meta instanceof CraftMetaTropicalFishBucket ? meta : new CraftMetaTropicalFishBucket(meta);
case CROSSBOW:
return meta instanceof CraftMetaCrossbow ? meta : new CraftMetaCrossbow(meta);
default: default:
return new CraftMetaItem(meta); return new CraftMetaItem(meta);
} }

View file

@ -503,6 +503,8 @@ public final class CraftItemStack extends ItemStack {
return new CraftMetaBlockState(item.getTag(), CraftMagicNumbers.getMaterial(item.getItem())); return new CraftMetaBlockState(item.getTag(), CraftMagicNumbers.getMaterial(item.getItem()));
case TROPICAL_FISH_BUCKET: case TROPICAL_FISH_BUCKET:
return new CraftMetaTropicalFishBucket(item.getTag()); return new CraftMetaTropicalFishBucket(item.getTag());
case CROSSBOW:
return new CraftMetaCrossbow(item.getTag());
default: default:
return new CraftMetaItem(item.getTag()); return new CraftMetaItem(item.getTag());
} }

View file

@ -0,0 +1,202 @@
package org.bukkit.craftbukkit.inventory;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import net.minecraft.server.ItemArrow;
import net.minecraft.server.NBTTagCompound;
import net.minecraft.server.NBTTagList;
import org.bukkit.Material;
import org.bukkit.configuration.serialization.DelegateDeserialization;
import org.bukkit.craftbukkit.util.CraftMagicNumbers;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.CrossbowMeta;
@DelegateDeserialization(CraftMetaItem.SerializableMeta.class)
public class CraftMetaCrossbow extends CraftMetaItem implements CrossbowMeta {
static final ItemMetaKey CHARGED = new ItemMetaKey("Charged", "charged");
static final ItemMetaKey CHARGED_PROJECTILES = new ItemMetaKey("ChargedProjectiles", "charged-projectiles");
//
private boolean charged;
private List<ItemStack> chargedProjectiles;
CraftMetaCrossbow(CraftMetaItem meta) {
super(meta);
if (!(meta instanceof CraftMetaCrossbow)) {
return;
}
CraftMetaCrossbow crossbow = (CraftMetaCrossbow) meta;
this.charged = crossbow.charged;
if (crossbow.hasChargedProjectiles()) {
this.chargedProjectiles = new ArrayList<>(crossbow.chargedProjectiles);
}
}
CraftMetaCrossbow(NBTTagCompound tag) {
super(tag);
charged = tag.getBoolean(CHARGED.NBT);
if (tag.hasKeyOfType(CHARGED_PROJECTILES.NBT, CraftMagicNumbers.NBT.TAG_LIST)) {
NBTTagList list = tag.getList(CHARGED_PROJECTILES.NBT, CraftMagicNumbers.NBT.TAG_COMPOUND);
if (list != null && !list.isEmpty()) {
chargedProjectiles = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
NBTTagCompound nbttagcompound1 = list.getCompound(i);
chargedProjectiles.add(CraftItemStack.asCraftMirror(net.minecraft.server.ItemStack.a(nbttagcompound1)));
}
}
}
}
CraftMetaCrossbow(Map<String, Object> map) {
super(map);
Boolean charged = SerializableMeta.getObject(Boolean.class, map, CHARGED.BUKKIT, true);
if (charged != null) {
this.charged = charged;
}
Iterable<?> projectiles = SerializableMeta.getObject(Iterable.class, map, CHARGED_PROJECTILES.BUKKIT, true);
if (projectiles != null) {
for (Object stack : projectiles) {
if (stack instanceof ItemStack) {
addChargedProjectile((ItemStack) stack);
}
}
}
}
@Override
void applyToItem(NBTTagCompound tag) {
super.applyToItem(tag);
tag.setBoolean(CHARGED.NBT, charged);
if (hasChargedProjectiles()) {
NBTTagList list = new NBTTagList();
for (ItemStack item : chargedProjectiles) {
NBTTagCompound saved = new NBTTagCompound();
CraftItemStack.asNMSCopy(item).save(saved);
list.add(saved);
}
tag.set(CHARGED_PROJECTILES.NBT, list);
}
}
@Override
boolean applicableTo(Material type) {
switch (type) {
case CROSSBOW:
return true;
default:
return false;
}
}
@Override
boolean isEmpty() {
return super.isEmpty() && isCrossbowEmpty();
}
boolean isCrossbowEmpty() {
return !(hasChargedProjectiles());
}
@Override
public boolean hasChargedProjectiles() {
return chargedProjectiles != null;
}
@Override
public List<ItemStack> getChargedProjectiles() {
return (chargedProjectiles == null) ? null : ImmutableList.copyOf(chargedProjectiles);
}
@Override
public void setChargedProjectiles(List<ItemStack> projectiles) {
chargedProjectiles = null;
charged = false;
if (projectiles == null) {
return;
}
for (ItemStack i : projectiles) {
addChargedProjectile(i);
}
}
@Override
public void addChargedProjectile(ItemStack item) {
Preconditions.checkArgument(item != null, "item");
Preconditions.checkArgument(CraftMagicNumbers.getItem(item.getType()) instanceof ItemArrow, "Item %s is not an arrow", item);
if (chargedProjectiles == null) {
chargedProjectiles = new ArrayList<>();
}
charged = true;
chargedProjectiles.add(item);
}
@Override
boolean equalsCommon(CraftMetaItem meta) {
if (!super.equalsCommon(meta)) {
return false;
}
if (meta instanceof CraftMetaCrossbow) {
CraftMetaCrossbow that = (CraftMetaCrossbow) meta;
return this.charged == that.charged
&& (hasChargedProjectiles() ? that.hasChargedProjectiles() && this.chargedProjectiles.equals(that.chargedProjectiles) : !that.hasChargedProjectiles());
}
return true;
}
@Override
boolean notUncommon(CraftMetaItem meta) {
return super.notUncommon(meta) && (meta instanceof CraftMetaCrossbow || isCrossbowEmpty());
}
@Override
int applyHash() {
final int original;
int hash = original = super.applyHash();
if (hasChargedProjectiles()) {
hash = 61 * hash + (this.charged ? 1 : 0);
hash = 61 * hash + chargedProjectiles.hashCode();
}
return original != hash ? CraftMetaCrossbow.class.hashCode() ^ hash : hash;
}
@Override
public CraftMetaCrossbow clone() {
return (CraftMetaCrossbow) super.clone();
}
@Override
ImmutableMap.Builder<String, Object> serialize(ImmutableMap.Builder<String, Object> builder) {
super.serialize(builder);
builder.put(CHARGED.BUKKIT, charged);
if (hasChargedProjectiles()) {
builder.put(CHARGED_PROJECTILES.BUKKIT, chargedProjectiles);
}
return builder;
}
}

View file

@ -153,6 +153,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
.put(CraftMetaCharge.class, "FIREWORK_EFFECT") .put(CraftMetaCharge.class, "FIREWORK_EFFECT")
.put(CraftMetaKnowledgeBook.class, "KNOWLEDGE_BOOK") .put(CraftMetaKnowledgeBook.class, "KNOWLEDGE_BOOK")
.put(CraftMetaTropicalFishBucket.class, "TROPICAL_FISH_BUCKET") .put(CraftMetaTropicalFishBucket.class, "TROPICAL_FISH_BUCKET")
.put(CraftMetaCrossbow.class, "CROSSBOW")
.put(CraftMetaItem.class, "UNSPECIFIC") .put(CraftMetaItem.class, "UNSPECIFIC")
.build(); .build();
@ -1403,7 +1404,9 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
CraftMetaCharge.EXPLOSION.NBT, CraftMetaCharge.EXPLOSION.NBT,
CraftMetaBlockState.BLOCK_ENTITY_TAG.NBT, CraftMetaBlockState.BLOCK_ENTITY_TAG.NBT,
CraftMetaKnowledgeBook.BOOK_RECIPES.NBT, CraftMetaKnowledgeBook.BOOK_RECIPES.NBT,
CraftMetaTropicalFishBucket.VARIANT.NBT CraftMetaTropicalFishBucket.VARIANT.NBT,
CraftMetaCrossbow.CHARGED.NBT,
CraftMetaCrossbow.CHARGED_PROJECTILES.NBT
)); ));
} }
return HANDLED_TAGS; return HANDLED_TAGS;

View file

@ -35,6 +35,7 @@ import org.bukkit.inventory.meta.BannerMeta;
import org.bukkit.inventory.meta.BlockDataMeta; import org.bukkit.inventory.meta.BlockDataMeta;
import org.bukkit.inventory.meta.BlockStateMeta; import org.bukkit.inventory.meta.BlockStateMeta;
import org.bukkit.inventory.meta.BookMeta; import org.bukkit.inventory.meta.BookMeta;
import org.bukkit.inventory.meta.CrossbowMeta;
import org.bukkit.inventory.meta.EnchantmentStorageMeta; import org.bukkit.inventory.meta.EnchantmentStorageMeta;
import org.bukkit.inventory.meta.FireworkEffectMeta; import org.bukkit.inventory.meta.FireworkEffectMeta;
import org.bukkit.inventory.meta.FireworkMeta; import org.bukkit.inventory.meta.FireworkMeta;
@ -335,6 +336,14 @@ public class ItemMetaTest extends AbstractTestingBase {
cleanStack.setItemMeta(meta); cleanStack.setItemMeta(meta);
return cleanStack; return cleanStack;
} }
},
new StackProvider(Material.CROSSBOW) {
@Override ItemStack operate(ItemStack cleanStack) {
final CrossbowMeta meta = (CrossbowMeta) cleanStack.getItemMeta();
meta.addChargedProjectile(new ItemStack(Material.ARROW));
cleanStack.setItemMeta(meta);
return cleanStack;
}
} }
); );