Rewrite book handling, Fixes SPIGOT-182 and part of SPIGOT-164

This commit is contained in:
Thinkofdeath 2014-12-11 19:38:09 +00:00
parent fe41b017ca
commit 84699b36a8
7 changed files with 190 additions and 72 deletions

View File

@ -826,10 +826,10 @@ public class CraftEventFactory {
// If they've got the same item in their hand, it'll need to be updated. // If they've got the same item in their hand, it'll need to be updated.
if (itemInHand != null && itemInHand.getItem() == Items.WRITABLE_BOOK) { if (itemInHand != null && itemInHand.getItem() == Items.WRITABLE_BOOK) {
if (!editBookEvent.isCancelled()) { if (!editBookEvent.isCancelled()) {
CraftItemStack.setItemMeta(itemInHand, editBookEvent.getNewBookMeta());
if (editBookEvent.isSigning()) { if (editBookEvent.isSigning()) {
itemInHand.setItem(Items.WRITTEN_BOOK); itemInHand.setItem(Items.WRITTEN_BOOK);
} }
CraftItemStack.setItemMeta(itemInHand, editBookEvent.getNewBookMeta());
} }
// Client will have updated its idea of the book item; we need to overwrite that // Client will have updated its idea of the book item; we need to overwrite that

View File

@ -62,8 +62,9 @@ public final class CraftItemFactory implements ItemFactory {
case AIR: case AIR:
return null; return null;
case WRITTEN_BOOK: case WRITTEN_BOOK:
return meta instanceof CraftMetaBookSigned ? meta : new CraftMetaBookSigned(meta);
case BOOK_AND_QUILL: case BOOK_AND_QUILL:
return meta instanceof CraftMetaBook ? meta : new CraftMetaBook(meta); return meta != null && meta.getClass().equals(CraftMetaBook.class) ? meta : new CraftMetaBook(meta);
case SKULL_ITEM: case SKULL_ITEM:
return meta instanceof CraftMetaSkull ? meta : new CraftMetaSkull(meta); return meta instanceof CraftMetaSkull ? meta : new CraftMetaSkull(meta);
case LEATHER_HELMET: case LEATHER_HELMET:

View File

@ -326,6 +326,7 @@ public final class CraftItemStack extends ItemStack {
} }
switch (getType(item)) { switch (getType(item)) {
case WRITTEN_BOOK: case WRITTEN_BOOK:
return new CraftMetaBookSigned(item.getTag());
case BOOK_AND_QUILL: case BOOK_AND_QUILL:
return new CraftMetaBook(item.getTag()); return new CraftMetaBook(item.getTag());
case SKULL_ITEM: case SKULL_ITEM:
@ -394,46 +395,14 @@ public final class CraftItemStack extends ItemStack {
return false; return false;
} }
itemMeta = CraftItemFactory.instance().asMetaFor(itemMeta, getType(item));
if (itemMeta == null) return true;
NBTTagCompound tag = new NBTTagCompound(); NBTTagCompound tag = new NBTTagCompound();
item.setTag(tag); item.setTag(tag);
((CraftMetaItem) itemMeta).applyToItem(tag); ((CraftMetaItem) itemMeta).applyToItem(tag);
// Hacky fix for books
// TODO: Not use a hacky fix for books
if (tag.getBoolean(CraftMetaBook.RESOLVED.NBT) && item.getItem() == Items.WRITABLE_BOOK) {
if (tag.hasKey(CraftMetaBook.BOOK_PAGES.NBT)) {
NBTTagList pages = tag.getList(CraftMetaBook.BOOK_PAGES.NBT, 8);
for (int i = 0; i < pages.size(); i++) {
String page = pages.getString(i);
page = CraftChatMessage.fromComponent(ChatSerializer.a(page));
pages.a(i, new NBTTagString(page));
}
tag.set(CraftMetaBook.BOOK_PAGES.NBT, pages);
}
tag.setBoolean(CraftMetaBook.RESOLVED.NBT, false);
} else if (!tag.getBoolean(CraftMetaBook.RESOLVED.NBT) && item.getItem() == Items.WRITTEN_BOOK) {
if (tag.hasKey(CraftMetaBook.BOOK_PAGES.NBT)) {
NBTTagList pages = tag.getList(CraftMetaBook.BOOK_PAGES.NBT, 8);
for (int i = 0; i < pages.size(); i++) {
String page = pages.getString(i);
page = ChatSerializer.a(CraftChatMessage.fromString(page, true)[0]);
pages.a(i, new NBTTagString(page));
}
tag.set(CraftMetaBook.BOOK_PAGES.NBT, pages);
}
tag.setBoolean(CraftMetaBook.RESOLVED.NBT, true);
if (!tag.hasKey(CraftMetaBook.BOOK_TITLE.NBT)) {
tag.setString(CraftMetaBook.BOOK_TITLE.NBT, "");
}
if (!tag.hasKey(CraftMetaBook.BOOK_AUTHOR.NBT)) {
tag.setString(CraftMetaBook.BOOK_AUTHOR.NBT, "");
}
}
return true; return true;
} }

View File

@ -30,27 +30,28 @@ class CraftMetaBook extends CraftMetaItem implements BookMeta {
static final int MAX_PAGE_LENGTH = 256; static final int MAX_PAGE_LENGTH = 256;
static final int MAX_TITLE_LENGTH = 0xffff; static final int MAX_TITLE_LENGTH = 0xffff;
private String title; protected String title;
private String author; protected String author;
private List<String> pages = new ArrayList<String>(); protected List<String> pages = new ArrayList<String>();
private Boolean resolved; protected Integer generation;
private Integer generation;
CraftMetaBook(CraftMetaItem meta) { CraftMetaBook(CraftMetaItem meta) {
super(meta); super(meta);
if (!(meta instanceof CraftMetaBook)) { if (meta instanceof CraftMetaBook) {
return;
}
CraftMetaBook bookMeta = (CraftMetaBook) meta; CraftMetaBook bookMeta = (CraftMetaBook) meta;
this.title = bookMeta.title; this.title = bookMeta.title;
this.author = bookMeta.author; this.author = bookMeta.author;
pages.addAll(bookMeta.pages); pages.addAll(bookMeta.pages);
this.resolved = bookMeta.resolved;
this.generation = bookMeta.generation; this.generation = bookMeta.generation;
} }
}
CraftMetaBook(NBTTagCompound tag) { CraftMetaBook(NBTTagCompound tag) {
this(tag, true);
}
CraftMetaBook(NBTTagCompound tag, boolean handlePages) {
super(tag); super(tag);
if (tag.hasKey(BOOK_TITLE.NBT)) { if (tag.hasKey(BOOK_TITLE.NBT)) {
@ -61,6 +62,7 @@ class CraftMetaBook extends CraftMetaItem implements BookMeta {
this.author = tag.getString(BOOK_AUTHOR.NBT); this.author = tag.getString(BOOK_AUTHOR.NBT);
} }
boolean resolved = false;
if (tag.hasKey(RESOLVED.NBT)) { if (tag.hasKey(RESOLVED.NBT)) {
resolved = tag.getBoolean(RESOLVED.NBT); resolved = tag.getBoolean(RESOLVED.NBT);
} }
@ -69,13 +71,13 @@ class CraftMetaBook extends CraftMetaItem implements BookMeta {
generation = tag.getInt(GENERATION.NBT); generation = tag.getInt(GENERATION.NBT);
} }
if (tag.hasKey(BOOK_PAGES.NBT)) { if (tag.hasKey(BOOK_PAGES.NBT) && handlePages) {
NBTTagList pages = tag.getList(BOOK_PAGES.NBT, 8); NBTTagList pages = tag.getList(BOOK_PAGES.NBT, 8);
String[] pageArray = new String[pages.size()]; String[] pageArray = new String[pages.size()];
for (int i = 0; i < pages.size(); i++) { for (int i = 0; i < pages.size(); i++) {
String page = pages.getString(i); String page = pages.getString(i);
if (resolved != null && resolved) { if (resolved) {
page = CraftChatMessage.fromComponent(ChatSerializer.a(page)); page = CraftChatMessage.fromComponent(ChatSerializer.a(page));
} }
pageArray[i] = page; pageArray[i] = page;
@ -95,12 +97,15 @@ class CraftMetaBook extends CraftMetaItem implements BookMeta {
Iterable<?> pages = SerializableMeta.getObject(Iterable.class, map, BOOK_PAGES.BUKKIT, true); Iterable<?> pages = SerializableMeta.getObject(Iterable.class, map, BOOK_PAGES.BUKKIT, true);
CraftMetaItem.safelyAdd(pages, this.pages, MAX_PAGE_LENGTH); CraftMetaItem.safelyAdd(pages, this.pages, MAX_PAGE_LENGTH);
resolved = SerializableMeta.getObject(Boolean.class, map, RESOLVED.BUKKIT, true);
generation = SerializableMeta.getObject(Integer.class, map, GENERATION.BUKKIT, true); generation = SerializableMeta.getObject(Integer.class, map, GENERATION.BUKKIT, true);
} }
@Override @Override
void applyToItem(NBTTagCompound itemData) { void applyToItem(NBTTagCompound itemData) {
applyToItem(itemData, true);
}
void applyToItem(NBTTagCompound itemData, boolean handlePages) {
super.applyToItem(itemData); super.applyToItem(itemData);
if (hasTitle()) { if (hasTitle()) {
@ -111,22 +116,16 @@ class CraftMetaBook extends CraftMetaItem implements BookMeta {
itemData.setString(BOOK_AUTHOR.NBT, this.author); itemData.setString(BOOK_AUTHOR.NBT, this.author);
} }
if (handlePages) {
if (hasPages()) { if (hasPages()) {
NBTTagList list = new NBTTagList(); NBTTagList list = new NBTTagList();
for (String page : pages) { for (String page : pages) {
if (resolved != null && resolved) {
list.add(new NBTTagString(
ChatSerializer.a(CraftChatMessage.fromString(page, true)[0])
));
} else {
list.add(new NBTTagString(page)); list.add(new NBTTagString(page));
} }
}
itemData.set(BOOK_PAGES.NBT, list); itemData.set(BOOK_PAGES.NBT, list);
} }
if (resolved != null) { itemData.remove(RESOLVED.NBT);
itemData.setBoolean(RESOLVED.NBT, resolved);
} }
if (generation != null) { if (generation != null) {
@ -297,10 +296,6 @@ class CraftMetaBook extends CraftMetaItem implements BookMeta {
builder.put(BOOK_PAGES.BUKKIT, pages); builder.put(BOOK_PAGES.BUKKIT, pages);
} }
if (resolved != null) {
builder.put(RESOLVED.BUKKIT, resolved);
}
if (generation != null) { if (generation != null) {
builder.put(GENERATION.BUKKIT, generation); builder.put(GENERATION.BUKKIT, generation);
} }

View File

@ -0,0 +1,142 @@
package org.bukkit.craftbukkit.inventory;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import net.minecraft.server.NBTTagCompound;
import net.minecraft.server.NBTTagList;
import org.bukkit.Material;
import org.bukkit.configuration.serialization.DelegateDeserialization;
import org.bukkit.craftbukkit.inventory.CraftMetaItem.SerializableMeta;
import org.bukkit.inventory.meta.BookMeta;
import com.google.common.collect.ImmutableMap.Builder;
import net.minecraft.server.ChatSerializer;
import net.minecraft.server.NBTTagString;
import org.bukkit.craftbukkit.util.CraftChatMessage;
@DelegateDeserialization(SerializableMeta.class)
class CraftMetaBookSigned extends CraftMetaBook implements BookMeta {
CraftMetaBookSigned(CraftMetaItem meta) {
super(meta);
}
CraftMetaBookSigned(NBTTagCompound tag) {
super(tag, false);
boolean resolved = true;
if (tag.hasKey(RESOLVED.NBT)) {
resolved = tag.getBoolean(RESOLVED.NBT);
}
if (tag.hasKey(BOOK_PAGES.NBT)) {
NBTTagList pages = tag.getList(BOOK_PAGES.NBT, 8);
String[] pageArray = new String[pages.size()];
for (int i = 0; i < pages.size(); i++) {
String page = pages.getString(i);
if (resolved) {
page = CraftChatMessage.fromComponent(ChatSerializer.a(page));
}
pageArray[i] = page;
}
addPage(pageArray);
}
}
CraftMetaBookSigned(Map<String, Object> map) {
super(map);
setAuthor(SerializableMeta.getString(map, BOOK_AUTHOR.BUKKIT, true));
setTitle(SerializableMeta.getString(map, BOOK_TITLE.BUKKIT, true));
Iterable<?> pages = SerializableMeta.getObject(Iterable.class, map, BOOK_PAGES.BUKKIT, true);
CraftMetaItem.safelyAdd(pages, this.pages, MAX_PAGE_LENGTH);
generation = SerializableMeta.getObject(Integer.class, map, GENERATION.BUKKIT, true);
}
@Override
void applyToItem(NBTTagCompound itemData) {
super.applyToItem(itemData, false);
if (hasTitle()) {
itemData.setString(BOOK_TITLE.NBT, this.title);
} else {
itemData.setString(BOOK_TITLE.NBT, " ");
}
if (hasAuthor()) {
itemData.setString(BOOK_AUTHOR.NBT, this.author);
} else {
itemData.setString(BOOK_AUTHOR.NBT, " ");
}
if (hasPages()) {
NBTTagList list = new NBTTagList();
for (String page : pages) {
list.add(new NBTTagString(
ChatSerializer.a(CraftChatMessage.fromString(page, true)[0])
));
}
itemData.set(BOOK_PAGES.NBT, list);
}
itemData.setBoolean(RESOLVED.NBT, true);
if (generation != null) {
itemData.setInt(GENERATION.NBT, generation);
} else {
itemData.setInt(GENERATION.NBT, 0);
}
}
@Override
boolean isEmpty() {
return super.isEmpty();
}
@Override
boolean applicableTo(Material type) {
switch (type) {
case WRITTEN_BOOK:
case BOOK_AND_QUILL:
return true;
default:
return false;
}
}
@Override
public CraftMetaBookSigned clone() {
CraftMetaBookSigned meta = (CraftMetaBookSigned) super.clone();
return meta;
}
@Override
int applyHash() {
final int original;
int hash = original = super.applyHash();
return original != hash ? CraftMetaBookSigned.class.hashCode() ^ hash : hash;
}
@Override
boolean equalsCommon(CraftMetaItem meta) {
return super.equalsCommon(meta);
}
@Override
boolean notUncommon(CraftMetaItem meta) {
return super.notUncommon(meta) && (meta instanceof CraftMetaBookSigned || isBookEmpty());
}
@Override
Builder<String, Object> serialize(Builder<String, Object> builder) {
super.serialize(builder);
return builder;
}
}

View File

@ -99,6 +99,7 @@ class CraftMetaItem implements ItemMeta, Repairable {
.put(CraftMetaBanner.class, "BANNER") .put(CraftMetaBanner.class, "BANNER")
.put(CraftMetaTileEntity.class, "TILE_ENTITY") .put(CraftMetaTileEntity.class, "TILE_ENTITY")
.put(CraftMetaBook.class, "BOOK") .put(CraftMetaBook.class, "BOOK")
.put(CraftMetaBookSigned.class, "BOOK_SIGNED")
.put(CraftMetaSkull.class, "SKULL") .put(CraftMetaSkull.class, "SKULL")
.put(CraftMetaLeatherArmor.class, "LEATHER_ARMOR") .put(CraftMetaLeatherArmor.class, "LEATHER_ARMOR")
.put(CraftMetaMap.class, "MAP") .put(CraftMetaMap.class, "MAP")

View File

@ -138,6 +138,16 @@ public class ItemMetaTest extends AbstractTestingBase {
return cleanStack; return cleanStack;
} }
}, },
new StackProvider(Material.WRITTEN_BOOK) {
@Override ItemStack operate(final ItemStack cleanStack) {
final BookMeta meta = (BookMeta) cleanStack.getItemMeta();
meta.setAuthor("Some author");
meta.setPages("Page 1", "Page 2");
meta.setTitle("A title");
cleanStack.setItemMeta(meta);
return cleanStack;
}
},
/* Skulls rely on a running server instance /* Skulls rely on a running server instance
new StackProvider(Material.SKULL_ITEM) { new StackProvider(Material.SKULL_ITEM) {
@Override ItemStack operate(final ItemStack cleanStack) { @Override ItemStack operate(final ItemStack cleanStack) {