2016-05-21 23:37:13 +02:00
|
|
|
/**
|
2022-07-24 16:16:05 +02:00
|
|
|
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2016 dmulloy2
|
|
|
|
* <p>
|
|
|
|
* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public
|
|
|
|
* License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later
|
|
|
|
* version.
|
|
|
|
* <p>
|
|
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
|
|
|
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
|
|
* details.
|
|
|
|
* <p>
|
|
|
|
* You should have received a copy of the GNU General Public License along with this program; if not, write to the Free
|
|
|
|
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
2016-05-21 23:37:13 +02:00
|
|
|
*/
|
|
|
|
package com.comphenix.protocol.wrappers;
|
|
|
|
|
2016-07-09 21:32:35 +02:00
|
|
|
import static com.comphenix.protocol.utility.MinecraftReflection.is;
|
|
|
|
|
2016-05-21 23:37:13 +02:00
|
|
|
import com.comphenix.protocol.reflect.StructureModifier;
|
|
|
|
import com.comphenix.protocol.reflect.accessors.Accessors;
|
|
|
|
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
|
|
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
2016-07-06 21:47:24 +02:00
|
|
|
import com.comphenix.protocol.wrappers.EnumWrappers.Direction;
|
|
|
|
import com.comphenix.protocol.wrappers.WrappedDataWatcher.Serializer;
|
2016-05-21 23:37:13 +02:00
|
|
|
import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject;
|
2017-05-24 20:35:22 +02:00
|
|
|
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
|
|
|
|
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
|
2022-07-24 16:16:05 +02:00
|
|
|
import java.util.Optional;
|
|
|
|
import org.bukkit.inventory.ItemStack;
|
2016-05-21 23:37:13 +02:00
|
|
|
|
|
|
|
/**
|
2022-07-24 16:16:05 +02:00
|
|
|
* Represents a DataWatcher Item in 1.8 to 1.10.
|
|
|
|
*
|
2016-05-21 23:37:13 +02:00
|
|
|
* @author dmulloy2
|
|
|
|
*/
|
|
|
|
public class WrappedWatchableObject extends AbstractWrapper {
|
2022-07-24 16:16:05 +02:00
|
|
|
|
2016-05-21 23:37:13 +02:00
|
|
|
private static final Class<?> HANDLE_TYPE = MinecraftReflection.getDataWatcherItemClass();
|
2016-07-12 19:37:55 +02:00
|
|
|
private static Integer VALUE_INDEX = null;
|
2016-05-21 23:37:13 +02:00
|
|
|
private static ConstructorAccessor constructor;
|
|
|
|
|
|
|
|
private final StructureModifier<Object> modifier;
|
|
|
|
|
|
|
|
/**
|
2016-07-12 19:37:55 +02:00
|
|
|
* Constructs a DataWatcher Item wrapper from an existing NMS data watcher item.
|
2022-07-24 16:16:05 +02:00
|
|
|
*
|
2016-05-21 23:37:13 +02:00
|
|
|
* @param handle Data watcher item
|
|
|
|
*/
|
|
|
|
public WrappedWatchableObject(Object handle) {
|
|
|
|
super(HANDLE_TYPE);
|
2022-07-24 16:16:05 +02:00
|
|
|
this.setHandle(handle);
|
|
|
|
this.modifier = new StructureModifier<>(this.handleType).withTarget(handle);
|
2016-05-21 23:37:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-07-12 19:37:55 +02:00
|
|
|
* Constructs a DataWatcher Item wrapper from a given index and initial value.
|
|
|
|
* <p>
|
|
|
|
* Not recommended in 1.9 and up.
|
2022-07-24 16:16:05 +02:00
|
|
|
*
|
2016-07-12 19:37:55 +02:00
|
|
|
* @param index Index of the Item
|
|
|
|
* @param value Initial value
|
|
|
|
*/
|
|
|
|
public WrappedWatchableObject(int index, Object value) {
|
|
|
|
this(newHandle(WrappedDataWatcherObject.fromIndex(index), value));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructs a DataWatcher Item wrapper from a given watcher object and initial value.
|
2022-07-24 16:16:05 +02:00
|
|
|
*
|
2016-05-21 23:37:13 +02:00
|
|
|
* @param watcherObject Watcher object
|
2022-07-24 16:16:05 +02:00
|
|
|
* @param value Initial value
|
2016-05-21 23:37:13 +02:00
|
|
|
*/
|
|
|
|
public WrappedWatchableObject(WrappedDataWatcherObject watcherObject, Object value) {
|
|
|
|
this(newHandle(watcherObject, value));
|
|
|
|
}
|
|
|
|
|
|
|
|
private static Object newHandle(WrappedDataWatcherObject watcherObject, Object value) {
|
|
|
|
if (constructor == null) {
|
|
|
|
constructor = Accessors.getConstructorAccessor(HANDLE_TYPE.getConstructors()[0]);
|
|
|
|
}
|
|
|
|
|
2016-07-12 19:37:55 +02:00
|
|
|
if (MinecraftReflection.watcherObjectExists()) {
|
|
|
|
return constructor.invoke(watcherObject.getHandle(), value);
|
|
|
|
} else {
|
|
|
|
// new WatchableObject(classId, index, value)
|
|
|
|
return constructor.invoke(WrappedDataWatcher.getTypeID(value.getClass()), watcherObject.getIndex(), value);
|
|
|
|
}
|
2016-05-21 23:37:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// ---- Getter methods
|
|
|
|
|
2022-07-24 16:16:05 +02:00
|
|
|
/**
|
|
|
|
* Retrieve the wrapped object value, if needed. All non-primitive objects with {@link Serializer}s should be covered
|
|
|
|
* by this.
|
|
|
|
*
|
|
|
|
* @param value - the raw NMS object to wrap.
|
|
|
|
* @return The wrapped object.
|
|
|
|
*/
|
|
|
|
static Object getWrapped(Object value) {
|
|
|
|
// Handle watcher items first
|
|
|
|
if (is(MinecraftReflection.getDataWatcherItemClass(), value)) {
|
|
|
|
return getWrapped(new WrappedWatchableObject(value).getRawValue());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Then deal with optionals
|
|
|
|
if (value instanceof Optional<?>) {
|
|
|
|
return ((Optional<?>) value).map(WrappedWatchableObject::getWrapped);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Current supported classes
|
|
|
|
if (is(MinecraftReflection.getIChatBaseComponentClass(), value)) {
|
|
|
|
return WrappedChatComponent.fromHandle(value);
|
|
|
|
} else if (is(MinecraftReflection.getItemStackClass(), value)) {
|
|
|
|
return BukkitConverters.getItemStackConverter().getSpecific(value);
|
|
|
|
} else if (is(MinecraftReflection.getIBlockDataClass(), value)) {
|
|
|
|
return BukkitConverters.getWrappedBlockDataConverter().getSpecific(value);
|
|
|
|
} else if (is(Vector3F.getMinecraftClass(), value)) {
|
|
|
|
return Vector3F.getConverter().getSpecific(value);
|
|
|
|
} else if (is(MinecraftReflection.getBlockPositionClass(), value)) {
|
|
|
|
return BlockPosition.getConverter().getSpecific(value);
|
|
|
|
} else if (is(EnumWrappers.getDirectionClass(), value)) {
|
|
|
|
return EnumWrappers.getDirectionConverter().getSpecific(value);
|
|
|
|
} else if (is(MinecraftReflection.getNBTCompoundClass(), value)) {
|
|
|
|
return NbtFactory.fromNMSCompound(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve the raw NMS value.
|
|
|
|
*
|
|
|
|
* @param wrapped - the wrapped position.
|
|
|
|
* @return The raw NMS object.
|
|
|
|
*/
|
|
|
|
// Must be kept in sync with getWrapped!
|
|
|
|
static Object getUnwrapped(Object wrapped) {
|
|
|
|
if (wrapped instanceof Optional<?>) {
|
|
|
|
return ((Optional<?>) wrapped).map(WrappedWatchableObject::getUnwrapped);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Current supported classes
|
|
|
|
if (wrapped instanceof WrappedChatComponent) {
|
|
|
|
return ((WrappedChatComponent) wrapped).getHandle();
|
|
|
|
} else if (wrapped instanceof ItemStack) {
|
|
|
|
return BukkitConverters.getItemStackConverter().getGeneric((ItemStack) wrapped);
|
|
|
|
} else if (wrapped instanceof WrappedBlockData) {
|
|
|
|
return BukkitConverters.getWrappedBlockDataConverter().getGeneric((WrappedBlockData) wrapped);
|
|
|
|
} else if (wrapped instanceof Vector3F) {
|
|
|
|
return Vector3F.getConverter().getGeneric((Vector3F) wrapped);
|
|
|
|
} else if (wrapped instanceof BlockPosition) {
|
|
|
|
return BlockPosition.getConverter().getGeneric((BlockPosition) wrapped);
|
|
|
|
} else if (wrapped instanceof Direction) {
|
|
|
|
return EnumWrappers.getDirectionConverter().getGeneric((Direction) wrapped);
|
|
|
|
} else if (wrapped instanceof NbtCompound) {
|
|
|
|
return NbtFactory.fromBase((NbtCompound) wrapped).getHandle();
|
|
|
|
}
|
|
|
|
|
|
|
|
return wrapped;
|
|
|
|
}
|
|
|
|
|
2016-05-21 23:37:13 +02:00
|
|
|
/**
|
|
|
|
* Gets this Item's watcher object, which contains the index and serializer.
|
2022-07-24 16:16:05 +02:00
|
|
|
*
|
2016-05-21 23:37:13 +02:00
|
|
|
* @return The watcher object
|
|
|
|
*/
|
|
|
|
public WrappedDataWatcherObject getWatcherObject() {
|
2022-07-24 16:16:05 +02:00
|
|
|
return new WrappedDataWatcherObject(this.modifier.read(0));
|
2016-05-21 23:37:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets this Item's index from the watcher object
|
2022-07-24 16:16:05 +02:00
|
|
|
*
|
2016-05-21 23:37:13 +02:00
|
|
|
* @return The index
|
|
|
|
*/
|
|
|
|
public int getIndex() {
|
2016-07-12 19:37:55 +02:00
|
|
|
if (MinecraftReflection.watcherObjectExists()) {
|
2022-07-24 16:16:05 +02:00
|
|
|
return this.getWatcherObject().getIndex();
|
2016-07-12 19:37:55 +02:00
|
|
|
}
|
|
|
|
|
2022-07-24 16:16:05 +02:00
|
|
|
return this.modifier.<Integer>withType(int.class).read(1);
|
2016-05-21 23:37:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets the wrapped value of this data watcher item.
|
2022-07-24 16:16:05 +02:00
|
|
|
*
|
2016-05-21 23:37:13 +02:00
|
|
|
* @return The wrapped value
|
|
|
|
*/
|
|
|
|
public Object getValue() {
|
2022-07-24 16:16:05 +02:00
|
|
|
return getWrapped(this.getRawValue());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the value of this item.
|
|
|
|
*
|
|
|
|
* @param value New value
|
|
|
|
*/
|
|
|
|
public void setValue(Object value) {
|
|
|
|
this.setValue(value, false);
|
2016-05-21 23:37:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets the raw value of this data watcher item.
|
2022-07-24 16:16:05 +02:00
|
|
|
*
|
2016-05-21 23:37:13 +02:00
|
|
|
* @return Raw value
|
|
|
|
*/
|
|
|
|
public Object getRawValue() {
|
2016-07-12 19:37:55 +02:00
|
|
|
if (VALUE_INDEX == null) {
|
|
|
|
VALUE_INDEX = MinecraftReflection.watcherObjectExists() ? 1 : 2;
|
|
|
|
}
|
|
|
|
|
2022-07-24 16:16:05 +02:00
|
|
|
return this.modifier.readSafely(VALUE_INDEX);
|
2016-05-21 23:37:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the value of this item.
|
2022-07-24 16:16:05 +02:00
|
|
|
*
|
|
|
|
* @param value New value
|
|
|
|
* @param updateClient Whether to update the client
|
2016-05-21 23:37:13 +02:00
|
|
|
*/
|
|
|
|
public void setValue(Object value, boolean updateClient) {
|
2016-07-12 19:37:55 +02:00
|
|
|
if (VALUE_INDEX == null) {
|
|
|
|
VALUE_INDEX = MinecraftReflection.watcherObjectExists() ? 1 : 2;
|
|
|
|
}
|
|
|
|
|
2022-07-24 16:16:05 +02:00
|
|
|
this.modifier.write(VALUE_INDEX, getUnwrapped(value));
|
2016-05-21 23:37:13 +02:00
|
|
|
if (updateClient) {
|
2022-07-24 16:16:05 +02:00
|
|
|
this.setDirtyState(true);
|
2016-05-21 23:37:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-07-24 16:16:05 +02:00
|
|
|
* Whether the value must be synchronized with the client.
|
|
|
|
*
|
2016-05-21 23:37:13 +02:00
|
|
|
* @return True if it must, false if not
|
|
|
|
*/
|
|
|
|
public boolean getDirtyState() {
|
2022-07-24 16:16:05 +02:00
|
|
|
return this.modifier.<Boolean>withType(boolean.class).read(0);
|
2016-05-21 23:37:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets this item's dirty state
|
2022-07-24 16:16:05 +02:00
|
|
|
*
|
2016-05-21 23:37:13 +02:00
|
|
|
* @param dirty New state
|
|
|
|
*/
|
|
|
|
public void setDirtyState(boolean dirty) {
|
2022-07-24 16:16:05 +02:00
|
|
|
this.modifier.<Boolean>withType(boolean.class).write(0, dirty);
|
2016-05-21 23:37:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean equals(Object obj) {
|
2022-07-24 16:16:05 +02:00
|
|
|
if (obj == this) {
|
|
|
|
return true;
|
|
|
|
}
|
2016-05-21 23:37:13 +02:00
|
|
|
|
|
|
|
if (obj instanceof WrappedWatchableObject) {
|
2016-07-12 19:37:55 +02:00
|
|
|
WrappedWatchableObject that = (WrappedWatchableObject) obj;
|
|
|
|
return this.getIndex() == that.getIndex() &&
|
|
|
|
this.getRawValue().equals(that.getRawValue()) &&
|
|
|
|
this.getDirtyState() == that.getDirtyState();
|
2016-05-21 23:37:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-08-06 19:19:14 +02:00
|
|
|
@Override
|
|
|
|
public int hashCode() {
|
|
|
|
final int prime = 31;
|
|
|
|
int result = 1;
|
2022-07-24 16:16:05 +02:00
|
|
|
result = prime * result + this.getIndex();
|
|
|
|
result = prime * result + this.getRawValue().hashCode();
|
|
|
|
result = prime * result + (this.getDirtyState() ? 1231 : 1237);
|
2016-08-06 19:19:14 +02:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2016-05-21 23:37:13 +02:00
|
|
|
@Override
|
|
|
|
public String toString() {
|
2022-07-24 16:16:05 +02:00
|
|
|
return "DataWatcherItem[index=" + this.getIndex() + ", value=" + this.getValue() + ", dirty=" + this.getDirtyState()
|
|
|
|
+ "]";
|
2016-06-21 02:41:40 +02:00
|
|
|
}
|
2016-05-21 23:37:13 +02:00
|
|
|
}
|