Archiviert
13
0

Add wrapper for MinecraftKey, more work on data watchers

Dieser Commit ist enthalten in:
Dan Mulloy 2016-03-04 21:24:12 -05:00
Ursprung 5efc4ffee3
Commit ec8fa0d1fe
6 geänderte Dateien mit 171 neuen und 30 gelöschten Zeilen

Datei anzeigen

@ -216,7 +216,9 @@ class EntityUtilities {
throw new FieldAccessException("Cannot access 'trackedEntities' field due to security limitations.", e);
}
return WrappedIntHashMap.fromHandle(trackedEntities).get(entityID);
Object trackerEntry = WrappedIntHashMap.fromHandle(trackedEntities).get(entityID);
Class<?> entryClass = MinecraftReflection.getEntityTrackerClass();
return entryClass.cast(trackerEntry);
}
/**

Datei anzeigen

@ -31,6 +31,7 @@ import java.util.Map.Entry;
import java.util.Set;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.World;
import org.bukkit.WorldType;
import org.bukkit.entity.Entity;
@ -963,6 +964,43 @@ public class BukkitConverters {
};
}
private static MethodAccessor soundGetter = null;
private static FieldAccessor soundKey = null;
public static EquivalentConverter<Sound> getSoundConverter() {
return new IgnoreNullConverter<Sound>() {
@Override
public Class<Sound> getSpecificType() {
return Sound.class;
}
@Override
protected Object getGenericValue(Class<?> genericType, Sound specific) {
if (soundGetter == null) {
Class<?> soundEffects = MinecraftReflection.getMinecraftClass("SoundEffects");
FuzzyReflection fuzzy = FuzzyReflection.fromClass(soundEffects, true);
soundGetter = Accessors.getMethodAccessor(fuzzy.getMethodByParameters("getSound", MinecraftReflection.getMinecraftClass("SoundEffect"), String.class));
}
MinecraftKey key = MinecraftKey.fromEnum(specific);
return soundGetter.invoke(null, key.getFullKey());
}
@Override
protected Sound getSpecificValue(Object generic) {
if (soundKey == null) {
Class<?> soundEffect = generic.getClass();
FuzzyReflection fuzzy = FuzzyReflection.fromClass(soundEffect, true);
soundKey = Accessors.getFieldAccessor(fuzzy.getFieldByType("key", MinecraftReflection.getMinecraftClass("MinecraftKey")));
}
MinecraftKey key = MinecraftKey.fromHandle(soundKey.get(generic));
return Sound.valueOf(key.getEnumFormat());
}
};
}
/**
* Wraps a given equivalent converter in NULL checks, ensuring that such values are ignored.
* @param <TType> Type

Datei anzeigen

@ -0,0 +1,62 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2016 dmulloy2
*
* 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.
*
* 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.
*
* 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
*/
package com.comphenix.protocol.wrappers;
import com.comphenix.protocol.reflect.StructureModifier;
/**
* @author dmulloy2
*/
public class MinecraftKey {
private final String prefix;
private final String key;
public MinecraftKey(String prefix, String key) {
this.prefix = prefix;
this.key = key;
}
public MinecraftKey(String key) {
this("minecraft", key);
}
public static MinecraftKey fromHandle(Object handle) {
StructureModifier<String> modifier = new StructureModifier<String>(handle.getClass()).withTarget(handle).withType(String.class);
return new MinecraftKey(modifier.read(0), modifier.read(1));
}
public static MinecraftKey fromEnum(Enum<?> value) {
return new MinecraftKey(value.name().toLowerCase().replace("_", "."));
}
public String getPrefix() {
return prefix;
}
public String getKey() {
return key;
}
public String getFullKey() {
return prefix + ":" + key;
}
public String getEnumFormat() {
return key.toUpperCase().replace(".", "_");
}
}

Datei anzeigen

@ -52,9 +52,9 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
private static MethodAccessor GETTER = null;
private static MethodAccessor SETTER = null;
private static FieldAccessor ENTITY_FIELD = null;
private static FieldAccessor MAP_FIELD = null;
private static Field ENTITY_DATA_FIELD = null;
private static Field ENTITY_FIELD = null;
private static ConstructorAccessor constructor = null;
private static ConstructorAccessor lightningConstructor = null;
@ -77,7 +77,14 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
*/
public WrappedDataWatcher() {
this(newHandle(fakeEntity()));
clear();
}
/**
* Constructs a new DataWatcher using a real entity.
* @param entity The entity
*/
public WrappedDataWatcher(Entity entity) {
this(newHandle(BukkitUnwrapper.getInstance().unwrapItem(entity)));
}
private static Object newHandle(Object entity) {
@ -160,10 +167,6 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
return getMap().size();
}
private void clear() {
getMap().clear();
}
/**
* Gets the watchable object at a given index.
* @param index Index
@ -313,8 +316,13 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
* @return A cloned data watcher.
*/
public WrappedDataWatcher deepClone() {
// TODO This
return null;
WrappedDataWatcher clone = new WrappedDataWatcher(getEntity());
for (Entry<Integer, WrappedWatchableObject> entry : asMap().entrySet()) {
clone.setObject(entry.getKey(), entry.getValue());
}
return clone;
}
/**
@ -354,6 +362,10 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
if (!MinecraftReflection.isUsingNetty())
throw new IllegalStateException("This method is only supported on 1.7.2 and above.");
if (ENTITY_FIELD == null) {
ENTITY_FIELD = Accessors.getFieldAccessor(HANDLE_TYPE, MinecraftReflection.getEntityClass(), true);
}
try {
return (Entity) MinecraftReflection.getBukkitEntity(ENTITY_FIELD.get(handle));
} catch (Exception e) {
@ -372,6 +384,10 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
if (!MinecraftReflection.isUsingNetty())
throw new IllegalStateException("This method is only supported on 1.7.2 and above.");
if (ENTITY_FIELD == null) {
ENTITY_FIELD = Accessors.getFieldAccessor(HANDLE_TYPE, MinecraftReflection.getEntityClass(), true);
}
try {
ENTITY_FIELD.set(handle, BukkitUnwrapper.getInstance().unwrapItem(entity));
} catch (Exception e) {

Datei anzeigen

@ -19,6 +19,8 @@ package com.comphenix.protocol.wrappers;
import org.bukkit.inventory.ItemStack;
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;
import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject;
@ -28,6 +30,9 @@ import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObje
*/
public class WrappedWatchableObject extends AbstractWrapper {
private static final Class<?> HANDLE_TYPE = MinecraftReflection.getDataWatcherItemClass();
private static ConstructorAccessor constructor;
private final StructureModifier<Object> modifier;
/**
@ -35,12 +40,28 @@ public class WrappedWatchableObject extends AbstractWrapper {
* @param handle Data watcher item
*/
public WrappedWatchableObject(Object handle) {
super(MinecraftReflection.getDataWatcherItemClass());
super(HANDLE_TYPE);
setHandle(handle);
this.modifier = new StructureModifier<Object>(handleType).withTarget(handle);
}
/**
* Constructs a wrapped watchable object with a given watcher object and initial value.
* @param watcherObject Watcher object
* @param value Initial value
*/
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]);
}
return constructor.invoke(watcherObject.getHandle(), value);
}
// ---- Getter methods
/**

Datei anzeigen

@ -20,9 +20,12 @@ import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import net.minecraft.server.v1_9_R1.AttributeModifier;
@ -47,10 +50,12 @@ import org.powermock.core.classloader.annotations.PowerMockIgnore;
import com.comphenix.protocol.BukkitInitialization;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.PacketType.Sender;
import com.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.Util;
import com.comphenix.protocol.wrappers.BlockPosition;
import com.comphenix.protocol.wrappers.BukkitConverters;
import com.comphenix.protocol.wrappers.WrappedBlockData;
import com.comphenix.protocol.wrappers.WrappedChatComponent;
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
@ -66,8 +71,8 @@ import com.google.common.collect.Lists;
//@PrepareForTest(CraftItemFactory.class)
public class PacketContainerTest {
// Helper converters
// private EquivalentConverter<WrappedDataWatcher> watchConvert = BukkitConverters.getDataWatcherConverter();
// private EquivalentConverter<ItemStack> itemConvert = BukkitConverters.getItemStackConverter();
private EquivalentConverter<WrappedDataWatcher> watchConvert = BukkitConverters.getDataWatcherConverter();
private EquivalentConverter<ItemStack> itemConvert = BukkitConverters.getItemStackConverter();
@BeforeClass
public static void initializeBukkit() throws IllegalAccessException {
@ -458,14 +463,11 @@ public class PacketContainerTest {
assertEquals(effect.hasParticles(), packet.getBytes().read(2) == (effect.hasParticles() ? 1 : 0));
}*/
// This is usually the last one, since it requires all the API stuff to be worked out
/*private static final List<PacketType> BLACKLISTED = Util.asList(
PacketType.Play.Client.CUSTOM_PAYLOAD, PacketType.Play.Server.CUSTOM_PAYLOAD, PacketType.Play.Server.MAP_CHUNK,
PacketType.Play.Server.UPDATE_ATTRIBUTES
private static final List<PacketType> BLACKLISTED = Util.asList(
PacketType.Play.Client.CUSTOM_PAYLOAD, PacketType.Play.Server.CUSTOM_PAYLOAD,
PacketType.Play.Server.SET_COOLDOWN, PacketType.Play.Server.NAMED_SOUND_EFFECT
);
@Test
public void testDeepClone() {
// Try constructing all the packets
@ -518,7 +520,7 @@ public class PacketContainerTest {
throw new RuntimeException("Failed to serialize packet " + type, e);
}
}
}*/
}
@Test
public void testPacketType() {
@ -526,7 +528,7 @@ public class PacketContainerTest {
}
// Convert to objects that support equals()
/*private void testEquality(Object a, Object b) {
private void testEquality(Object a, Object b) {
if (a != null && b != null) {
if (MinecraftReflection.isDataWatcher(a)) {
a = watchConvert.getSpecific(a);
@ -542,20 +544,20 @@ public class PacketContainerTest {
return;
}
} else {
if (a.equals(b) || Objects.equal(a, b) || a.toString().equals(b.toString())) {
if (a.equals(b) || Objects.equals(a, b) || a.toString().equals(b.toString())) {
return;
}
}
assertEquals(a, b);
}*/
}
/**
* Get the underlying array as an object array.
* @param val - array wrapped as an Object.
* @return An object array.
*/
/*private Object[] getArray(Object val) {
private Object[] getArray(Object val) {
if (val instanceof Object[])
return (Object[]) val;
if (val == null)
@ -567,5 +569,5 @@ public class PacketContainerTest {
for (int i = 0; i < arrlength; ++i)
outputArray[i] = Array.get(val, i);
return outputArray;
}*/
}
}