Make metadata (almost) fail-safe

This could mean life and death, see
`new Metadata(17, MetaType1_14.Float, event.meta()).value()`
vs.
`new Metadata(17, MetaType1_14.Float, event.meta().value())`
This commit is contained in:
KennyTV 2021-05-25 16:27:46 +02:00
parent a6b4b16fd3
commit 57769c5671
No known key found for this signature in database
GPG Key ID: 6BE3B555EBC5982B
3 changed files with 45 additions and 10 deletions

View File

@ -22,6 +22,9 @@
*/
package com.viaversion.viaversion.api.minecraft.metadata;
import com.google.common.base.Preconditions;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.Objects;
public final class Metadata {
@ -29,10 +32,20 @@ public final class Metadata {
private MetaType metaType;
private Object value;
public Metadata(int id, MetaType metaType, Object value) {
/**
* Creates a new metadata instance.
*
* @param id metadata index
* @param metaType metadata type
* @param value value if present
* @throws NullPointerException if the given metaType is null
* @throws IllegalArgumentException if the value and metaType are incompatible
*/
public Metadata(int id, MetaType metaType, @Nullable Object value) {
Preconditions.checkNotNull(metaType);
this.id = id;
this.metaType = metaType;
this.value = value;
this.value = checkValue(value);
}
public int id() {
@ -47,7 +60,14 @@ public final class Metadata {
return metaType;
}
/**
* Sets the metadata type.
* Update the value with {@link #setValue(Object)} in case value and type are no longer compatible.
*
* @param metaType metadata type
*/
public void setMetaType(MetaType metaType) {
Preconditions.checkNotNull(metaType);
this.metaType = metaType;
}
@ -55,12 +75,26 @@ public final class Metadata {
return (T) value;
}
public Object getValue() {
public @Nullable Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
/**
* Sets the metadata value.
* Always call {@link #setMetaType(MetaType)} first if the output type changes.
*
* @param value value
* @throws IllegalArgumentException if the value and metaType are incompatible
*/
public void setValue(@Nullable Object value) {
this.value = checkValue(value);
}
private Object checkValue(Object value) {
if (value != null && !metaType.type().getOutputClass().isAssignableFrom(value.getClass())) {
throw new IllegalArgumentException("Metadata value and metaType are incompatible. Type=" + metaType + ", value=" + value);
}
return value;
}
@Override

View File

@ -46,7 +46,7 @@ public abstract class AbstractProtocol<C1 extends ClientboundPacketType, C2 exte
implements Protocol<C1, C2, S1, S2> {
private final Map<Packet, ProtocolPacket> serverbound = new HashMap<>();
private final Map<Packet, ProtocolPacket> clientbound = new HashMap<>();
private final Map<Class, Object> storedObjects = new HashMap<>(); // currently only used for MetadataRewriters
private final Map<Class<?>, Object> storedObjects = new HashMap<>(); // currently only used for MetadataRewriters
protected final Class<C1> oldClientboundPacketEnum;
protected final Class<C2> newClientboundPacketEnum;
protected final Class<S1> oldServerboundPacketEnum;

View File

@ -139,14 +139,14 @@ public class MetadataRewriter1_14To1_13_2 extends EntityRewriter<Protocol1_14To1
} else if (type.is(Entity1_14Types.VILLAGER)) {
if (metadata.id() == 15) {
// plains
metadata.setValue(new VillagerData(2, getNewProfessionId((int) metadata.getValue()), 0));
metadata.setMetaType(MetaType1_14.VillagerData);
metadata.setValue(new VillagerData(2, getNewProfessionId((int) metadata.getValue()), 0));
}
} else if (type.is(Entity1_14Types.ZOMBIE_VILLAGER)) {
if (metadata.id() == 18) {
// plains
metadata.setValue(new VillagerData(2, getNewProfessionId((int) metadata.getValue()), 0));
metadata.setMetaType(MetaType1_14.VillagerData);
metadata.setValue(new VillagerData(2, getNewProfessionId((int) metadata.getValue()), 0));
}
} else if (type.isOrHasParent(Entity1_14Types.ABSTRACT_ARROW)) {
if (metadata.id() >= 9) { // New piercing
@ -154,9 +154,10 @@ public class MetadataRewriter1_14To1_13_2 extends EntityRewriter<Protocol1_14To1
}
} else if (type.is(Entity1_14Types.FIREWORK_ROCKET)) {
if (metadata.id() == 8) {
if (metadata.getValue().equals(0))
metadata.setValue(null); // https://bugs.mojang.com/browse/MC-111480
metadata.setMetaType(MetaType1_14.OptVarInt);
if (metadata.getValue().equals(0)) {
metadata.setValue(null); // https://bugs.mojang.com/browse/MC-111480
}
}
} else if (type.isOrHasParent(Entity1_14Types.ABSTRACT_SKELETON)) {
if (metadata.id() == 14) {