Selling Spawners NBT Complication
A248 opened this issue · 4 comments
I'm currently testing #48 . Purchasing a spawner and attempting to resell it back to the shop throws a NPE. This error is not specific to the PR – it's caused by the same line of code as in master branch; merely, the error is refactored.
Error https://pastebin.com/PBpiuL6j
Notes Using Paper 1.8.8, latest version of GuiShop with changes from #48 applied
The Focus
if (item.getType().name().equals("SPAWNER") /* 1.13+ */
|| item.getType().name().equals("MOB_SPAWNER") /* 1.7 - 1.12 */
) {
NBTTagCompound cmp = ItemNBTUtil.getTag(item);
Object data = MobType.valueOf(cmp.getString("EntityId")); // the source of the NPE
return item.getType().toString().toUpperCase() + ":" + data.toString().toLowerCase();
}
return item.getType().toString().toUpperCase();
The NPE is caused because cmp.getString("EntityId")
is null. Hence, the enum reports "Name is null".
Explanation
Regarding mob spawner NBT, from what I've gathered, this is not the correct usage of item NBT. EntityId, by itself, is used for blocks (MC Wiki).
However, mob spawner items do not use EntityId simply. Rather, they use {BlockEntityTag:{EntityId:<type>}}
. This is demonstrated by the SilkSpawners source: 1_8_R3, 1_12_R1, 1_13_R2.
Partial Solution
GuiShop must use the BlockEntityTag
and its nested EntityId
. I'm unsure how to achieve this using IF's ItemNBTUtil.
At the very least, we can determine the mob type of spawners which were bought through GuiShop (identified by the "GUIShopSpawner" tag), like so:
Object data;
NBTTagCompound cmp = ItemNBTUtil.getTag(item);
if (cmp.hasKey("GUIShopSpawner")) {
data = cmp.getString("GUIShopSpawner");
} else {
data = MobType.valueOf(cmp.getString("EntityId"));
}
return item.getType().toString().toUpperCase() + ":" + data.toString().toLowerCase();
This snippet would not solve the entire problem – merely, it would be sufficient for servers where the only source of mob spawners is GuiShop.
On servers which grant mob spawners to players in a variety ways (besides GuiShop), the NBT call will have to be changed.
Added the described partial solution to PR #48 .
Full Solution
I'm currently testing this solution on Paper 1.8.8. This should use the nested BlockEntityTag/EntityId from the item's NBT. If it succeeds, I'll add the commit to #48 .
public static MobType getFromNbt(NBTTagCompound cmp) {
if (cmp.hasKey("GUIShopSpawner")) {
return valueOf(cmp.getString("GUIShopSpawner"));
} else if (cmp.hasKey("BlockEntityTag")) {
NBTTagCompound subCmp = (NBTTagCompound) cmp.get("BlockEntityTag");
return valueOf(subCmp.getString("EntityId").toUpperCase());
}
// default to pig
return PIG;
}