SPIGOT-6025: Do not NPE when target world of a compass no longer exists

This commit is contained in:
Brokkonaut 2020-08-31 17:12:48 +10:00 committed by md_5
parent 00bff02703
commit 6008e6660a
No known key found for this signature in database
GPG key ID: E8E901AC7C617C11

View file

@ -9,7 +9,9 @@ import net.minecraft.server.DynamicOpsNBT;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.NBTBase; import net.minecraft.server.NBTBase;
import net.minecraft.server.NBTTagCompound; import net.minecraft.server.NBTTagCompound;
import net.minecraft.server.NBTTagString;
import net.minecraft.server.ResourceKey; import net.minecraft.server.ResourceKey;
import net.minecraft.server.WorldServer;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
@ -22,9 +24,16 @@ public class CraftMetaCompass extends CraftMetaItem implements CompassMeta {
static final ItemMetaKey LODESTONE_DIMENSION = new ItemMetaKey("LodestoneDimension"); static final ItemMetaKey LODESTONE_DIMENSION = new ItemMetaKey("LodestoneDimension");
static final ItemMetaKey LODESTONE_POS = new ItemMetaKey("LodestonePos", "lodestone"); static final ItemMetaKey LODESTONE_POS = new ItemMetaKey("LodestonePos", "lodestone");
static final ItemMetaKey LODESTONE_POS_WORLD = new ItemMetaKey("LodestonePosWorld");
static final ItemMetaKey LODESTONE_POS_X = new ItemMetaKey("LodestonePosX");
static final ItemMetaKey LODESTONE_POS_Y = new ItemMetaKey("LodestonePosY");
static final ItemMetaKey LODESTONE_POS_Z = new ItemMetaKey("LodestonePosZ");
static final ItemMetaKey LODESTONE_TRACKED = new ItemMetaKey("LodestoneTracked"); static final ItemMetaKey LODESTONE_TRACKED = new ItemMetaKey("LodestoneTracked");
private Location lodestone; private NBTTagString lodestoneWorld;
private int lodestoneX;
private int lodestoneY;
private int lodestoneZ;
private Boolean tracked; private Boolean tracked;
CraftMetaCompass(CraftMetaItem meta) { CraftMetaCompass(CraftMetaItem meta) {
@ -33,21 +42,21 @@ public class CraftMetaCompass extends CraftMetaItem implements CompassMeta {
return; return;
} }
CraftMetaCompass compassMeta = (CraftMetaCompass) meta; CraftMetaCompass compassMeta = (CraftMetaCompass) meta;
lodestone = compassMeta.lodestone.clone(); lodestoneWorld = compassMeta.lodestoneWorld;
lodestoneX = compassMeta.lodestoneX;
lodestoneY = compassMeta.lodestoneY;
lodestoneZ = compassMeta.lodestoneZ;
tracked = compassMeta.tracked; tracked = compassMeta.tracked;
} }
CraftMetaCompass(NBTTagCompound tag) { CraftMetaCompass(NBTTagCompound tag) {
super(tag); super(tag);
if (tag.hasKey(LODESTONE_DIMENSION.NBT) && tag.hasKey(LODESTONE_POS.NBT)) { if (tag.hasKey(LODESTONE_DIMENSION.NBT) && tag.hasKey(LODESTONE_POS.NBT)) {
Optional<ResourceKey<net.minecraft.server.World>> key = net.minecraft.server.World.f.parse(DynamicOpsNBT.a, tag.get(LODESTONE_DIMENSION.NBT)).result(); lodestoneWorld = (NBTTagString) tag.get(LODESTONE_DIMENSION.NBT);
NBTTagCompound pos = tag.getCompound(LODESTONE_POS.NBT);
if (key.isPresent()) { lodestoneX = pos.getInt("X");
World world = MinecraftServer.getServer().getWorldServer(key.get()).getWorld(); lodestoneY = pos.getInt("Y");
lodestoneZ = pos.getInt("Z");
NBTTagCompound pos = tag.getCompound(LODESTONE_POS.NBT);
lodestone = new Location(world, pos.getInt("X"), pos.getInt("Y"), pos.getInt("Z"));
}
} }
if (tag.hasKey(LODESTONE_TRACKED.NBT)) { if (tag.hasKey(LODESTONE_TRACKED.NBT)) {
tracked = tag.getBoolean(LODESTONE_TRACKED.NBT); tracked = tag.getBoolean(LODESTONE_TRACKED.NBT);
@ -56,8 +65,19 @@ public class CraftMetaCompass extends CraftMetaItem implements CompassMeta {
CraftMetaCompass(Map<String, Object> map) { CraftMetaCompass(Map<String, Object> map) {
super(map); super(map);
String lodestoneWorldString = SerializableMeta.getString(map, LODESTONE_POS_WORLD.BUKKIT, true);
lodestone = SerializableMeta.getObject(Location.class, map, LODESTONE_POS.BUKKIT, true); if (lodestoneWorldString != null) {
lodestoneWorld = NBTTagString.a(lodestoneWorldString);
lodestoneX = (Integer) map.get(LODESTONE_POS_X.BUKKIT);
lodestoneY = (Integer) map.get(LODESTONE_POS_Y.BUKKIT);
lodestoneZ = (Integer) map.get(LODESTONE_POS_Z.BUKKIT);
} else {
// legacy
Location lodestone = SerializableMeta.getObject(Location.class, map, LODESTONE_POS.BUKKIT, true);
if (lodestone != null && lodestone.getWorld() != null) {
setLodestone(lodestone);
}
}
tracked = SerializableMeta.getBoolean(map, LODESTONE_TRACKED.BUKKIT); tracked = SerializableMeta.getBoolean(map, LODESTONE_TRACKED.BUKKIT);
} }
@ -65,17 +85,13 @@ public class CraftMetaCompass extends CraftMetaItem implements CompassMeta {
void applyToItem(NBTTagCompound tag) { void applyToItem(NBTTagCompound tag) {
super.applyToItem(tag); super.applyToItem(tag);
if (lodestone != null) { if (lodestoneWorld != null) {
NBTTagCompound pos = new NBTTagCompound(); NBTTagCompound pos = new NBTTagCompound();
pos.setInt("X", lodestone.getBlockX()); pos.setInt("X", lodestoneX);
pos.setInt("Y", lodestone.getBlockY()); pos.setInt("Y", lodestoneY);
pos.setInt("Z", lodestone.getBlockZ()); pos.setInt("Z", lodestoneZ);
tag.set(LODESTONE_POS.NBT, pos); tag.set(LODESTONE_POS.NBT, pos);
tag.set(LODESTONE_DIMENSION.NBT, lodestoneWorld);
ResourceKey<net.minecraft.server.World> key = ((CraftWorld) lodestone.getWorld()).getHandle().getDimensionKey();
DataResult<NBTBase> dataresult = net.minecraft.server.World.f.encodeStart(DynamicOpsNBT.a, key);
tag.set(LODESTONE_DIMENSION.NBT, dataresult.get().orThrow());
} }
if (tracked != null) { if (tracked != null) {
@ -100,25 +116,38 @@ public class CraftMetaCompass extends CraftMetaItem implements CompassMeta {
@Override @Override
public CraftMetaCompass clone() { public CraftMetaCompass clone() {
CraftMetaCompass clone = ((CraftMetaCompass) super.clone()); CraftMetaCompass clone = ((CraftMetaCompass) super.clone());
clone.lodestone = (lodestone == null) ? null : lodestone.clone();
clone.tracked = tracked;
return clone; return clone;
} }
@Override @Override
public boolean hasLodestone() { public boolean hasLodestone() {
return lodestone != null; return lodestoneWorld != null;
} }
@Override @Override
public Location getLodestone() { public Location getLodestone() {
return lodestone; if (lodestoneWorld == null) {
return null;
}
Optional<ResourceKey<net.minecraft.server.World>> key = net.minecraft.server.World.f.parse(DynamicOpsNBT.a, lodestoneWorld).result();
WorldServer worldServer = key.isPresent() ? MinecraftServer.getServer().getWorldServer(key.get()) : null;
World world = worldServer != null ? worldServer.getWorld() : null;
return new Location(world, lodestoneX, lodestoneY, lodestoneZ); // world may be null here, if the referenced world is not loaded
} }
@Override @Override
public void setLodestone(Location lodestone) { public void setLodestone(Location lodestone) {
Preconditions.checkArgument(lodestone != null && lodestone.getWorld() != null, "Location or world null"); Preconditions.checkArgument(lodestone == null || lodestone.getWorld() != null, "world is null");
this.lodestone = lodestone; if (lodestone == null) {
this.lodestoneWorld = null;
} else {
ResourceKey<net.minecraft.server.World> key = ((CraftWorld) lodestone.getWorld()).getHandle().getDimensionKey();
DataResult<NBTBase> dataresult = net.minecraft.server.World.f.encodeStart(DynamicOpsNBT.a, key);
this.lodestoneWorld = (NBTTagString) dataresult.get().orThrow();
this.lodestoneX = lodestone.getBlockX();
this.lodestoneY = lodestone.getBlockY();
this.lodestoneZ = lodestone.getBlockZ();
}
} }
boolean hasLodestoneTracked() { boolean hasLodestoneTracked() {
@ -140,7 +169,10 @@ public class CraftMetaCompass extends CraftMetaItem implements CompassMeta {
final int original; final int original;
int hash = original = super.applyHash(); int hash = original = super.applyHash();
if (hasLodestone()) { if (hasLodestone()) {
hash = 73 * hash + lodestone.hashCode(); hash = 73 * hash + lodestoneWorld.hashCode();
hash = 73 * hash + lodestoneX;
hash = 73 * hash + lodestoneY;
hash = 73 * hash + lodestoneZ;
} }
if (hasLodestoneTracked()) { if (hasLodestoneTracked()) {
hash = 73 * hash + (isLodestoneTracked() ? 1231 : 1237); hash = 73 * hash + (isLodestoneTracked() ? 1231 : 1237);
@ -157,7 +189,9 @@ public class CraftMetaCompass extends CraftMetaItem implements CompassMeta {
if (meta instanceof CraftMetaCompass) { if (meta instanceof CraftMetaCompass) {
CraftMetaCompass that = (CraftMetaCompass) meta; CraftMetaCompass that = (CraftMetaCompass) meta;
return (this.hasLodestone() ? that.hasLodestone() && this.lodestone.equals(that.lodestone) : !that.hasLodestone()) return (this.hasLodestone() ? that.hasLodestone() && this.lodestoneWorld.asString().equals(that.lodestoneWorld.asString())
&& this.lodestoneX == that.lodestoneX && this.lodestoneY == that.lodestoneY
&& this.lodestoneZ == that.lodestoneZ : !that.hasLodestone())
&& this.tracked == that.tracked; && this.tracked == that.tracked;
} }
return true; return true;
@ -173,7 +207,10 @@ public class CraftMetaCompass extends CraftMetaItem implements CompassMeta {
super.serialize(builder); super.serialize(builder);
if (hasLodestone()) { if (hasLodestone()) {
builder.put(LODESTONE_POS.BUKKIT, lodestone); builder.put(LODESTONE_POS_WORLD.BUKKIT, lodestoneWorld.asString());
builder.put(LODESTONE_POS_X.BUKKIT, lodestoneX);
builder.put(LODESTONE_POS_Y.BUKKIT, lodestoneY);
builder.put(LODESTONE_POS_Z.BUKKIT, lodestoneZ);
} }
if (hasLodestoneTracked()) { if (hasLodestoneTracked()) {
builder.put(LODESTONE_TRACKED.BUKKIT, tracked); builder.put(LODESTONE_TRACKED.BUKKIT, tracked);