Major rework of underlying conversion logic

This shouldn't affect plugins utlilizing the API, but will make updates and adding wrappers to PacketWrapper easier. In case you're wondering, major changes include:

- Added AutoWrapper
- Added Covnerters utility class
- Removed generic type parameter from EquivalentConverter
This commit is contained in:
Dan Mulloy 2017-07-24 14:15:56 -04:00
parent e1ea295600
commit 9e5bdf4124
27 changed files with 887 additions and 662 deletions

View File

@ -69,11 +69,7 @@ import com.comphenix.protocol.reflect.instances.DefaultInstances;
import com.comphenix.protocol.utility.MinecraftMethods;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.StreamSerializer;
import com.comphenix.protocol.wrappers.BlockPosition;
import com.comphenix.protocol.wrappers.BukkitConverters;
import com.comphenix.protocol.wrappers.ChunkCoordIntPair;
import com.comphenix.protocol.wrappers.ChunkPosition;
import com.comphenix.protocol.wrappers.EnumWrappers;
import com.comphenix.protocol.wrappers.*;
import com.comphenix.protocol.wrappers.EnumWrappers.ChatType;
import com.comphenix.protocol.wrappers.EnumWrappers.ChatVisibility;
import com.comphenix.protocol.wrappers.EnumWrappers.ClientCommand;
@ -94,16 +90,6 @@ import com.comphenix.protocol.wrappers.EnumWrappers.ScoreboardAction;
import com.comphenix.protocol.wrappers.EnumWrappers.SoundCategory;
import com.comphenix.protocol.wrappers.EnumWrappers.TitleAction;
import com.comphenix.protocol.wrappers.EnumWrappers.WorldBorderAction;
import com.comphenix.protocol.wrappers.MultiBlockChangeInfo;
import com.comphenix.protocol.wrappers.PlayerInfoData;
import com.comphenix.protocol.wrappers.WrappedAttribute;
import com.comphenix.protocol.wrappers.WrappedBlockData;
import com.comphenix.protocol.wrappers.WrappedChatComponent;
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
import com.comphenix.protocol.wrappers.WrappedGameProfile;
import com.comphenix.protocol.wrappers.WrappedServerPing;
import com.comphenix.protocol.wrappers.WrappedStatistic;
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
import com.comphenix.protocol.wrappers.nbt.NbtBase;
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
@ -134,30 +120,29 @@ public class PacketContainer implements Serializable {
private static ConcurrentMap<Class<?>, Method> readMethods = Maps.newConcurrentMap();
// Used to clone packets
private static final AggregateCloner DEEP_CLONER = AggregateCloner.newBuilder().
instanceProvider(DefaultInstances.DEFAULT).
andThen(BukkitCloner.class).
andThen(ImmutableDetector.class).
andThen(OptionalCloner.class).
andThen(CollectionCloner.class).
andThen(getSpecializedDeepClonerFactory()).
build();
private static final AggregateCloner DEEP_CLONER = AggregateCloner
.newBuilder()
.instanceProvider(DefaultInstances.DEFAULT)
.andThen(BukkitCloner.class)
.andThen(ImmutableDetector.class)
.andThen(OptionalCloner.class)
.andThen(CollectionCloner.class)
.andThen(getSpecializedDeepClonerFactory())
.build();
private static final AggregateCloner SHALLOW_CLONER = AggregateCloner.newBuilder().
instanceProvider(DefaultInstances.DEFAULT).
andThen(new Function<BuilderParameters, Cloner>() {
@Override
public Cloner apply(@Nullable BuilderParameters param) {
if (param == null)
throw new IllegalArgumentException("Cannot be NULL.");
return new FieldCloner(param.getAggregateCloner(), param.getInstanceProvider()) {{
// Use a default writer with no concept of cloning
writer = new ObjectWriter();
}};
}
}).
build();
private static final AggregateCloner SHALLOW_CLONER = AggregateCloner
.newBuilder()
.instanceProvider(DefaultInstances.DEFAULT)
.andThen(param -> {
if (param == null)
throw new IllegalArgumentException("Cannot be NULL.");
return new FieldCloner(param.getAggregateCloner(), param.getInstanceProvider()) {{
// Use a default writer with no concept of cloning
writer = new ObjectWriter();
}};
})
.build();
// Packets that cannot be cloned by our default deep cloner
private static final Set<PacketType> CLONING_UNSUPPORTED = Sets.newHashSet(
@ -385,8 +370,9 @@ public class PacketContainer implements Serializable {
*/
public StructureModifier<ItemStack> getItemModifier() {
// Convert to and from the Bukkit wrapper
return structureModifier.<ItemStack>withType(
MinecraftReflection.getItemStackClass(), BukkitConverters.getItemStackConverter());
return structureModifier.withType(
MinecraftReflection.getItemStackClass(),
BukkitConverters.getItemStackConverter());
}
/**
@ -398,9 +384,9 @@ public class PacketContainer implements Serializable {
*/
public StructureModifier<ItemStack[]> getItemArrayModifier() {
// Convert to and from the Bukkit wrapper
return structureModifier.<ItemStack[]>withType(
return structureModifier.withType(
MinecraftReflection.getItemStackArrayClass(),
BukkitConverters.getIgnoreNull(new ItemStackArrayConverter()));
Converters.ignoreNull(new ItemStackArrayConverter()));
}
/**
@ -414,10 +400,7 @@ public class PacketContainer implements Serializable {
// Convert to and from the Bukkit wrapper
return structureModifier.withType(
List.class,
BukkitConverters.getListConverter(
MinecraftReflection.getItemStackClass(),
BukkitConverters.getItemStackConverter()
)
BukkitConverters.getListConverter(BukkitConverters.getItemStackConverter())
);
}
@ -428,12 +411,9 @@ public class PacketContainer implements Serializable {
* @return A modifier for maps of statistics.
*/
public StructureModifier<Map<WrappedStatistic, Integer>> getStatisticMaps() {
return structureModifier.withType(Map.class,
BukkitConverters.<WrappedStatistic, Integer>getMapConverter(
MinecraftReflection.getStatisticClass(),
BukkitConverters.getWrappedStatisticConverter()
)
);
return getMaps(
BukkitConverters.getWrappedStatisticConverter(),
Converters.passthrough(Integer.class));
}
/**
@ -445,7 +425,7 @@ public class PacketContainer implements Serializable {
*/
public StructureModifier<WorldType> getWorldTypeModifier() {
// Convert to and from the Bukkit wrapper
return structureModifier.<WorldType>withType(
return structureModifier.withType(
MinecraftReflection.getWorldTypeClass(),
BukkitConverters.getWorldTypeConverter());
}
@ -456,7 +436,7 @@ public class PacketContainer implements Serializable {
*/
public StructureModifier<WrappedDataWatcher> getDataWatcherModifier() {
// Convert to and from the Bukkit wrapper
return structureModifier.<WrappedDataWatcher>withType(
return structureModifier.withType(
MinecraftReflection.getDataWatcherClass(),
BukkitConverters.getDataWatcherConverter());
}
@ -475,7 +455,7 @@ public class PacketContainer implements Serializable {
public StructureModifier<Entity> getEntityModifier(@Nonnull World world) {
Preconditions.checkNotNull(world, "world cannot be NULL.");
// Convert to and from the Bukkit wrapper
return structureModifier.<Entity>withType(
return structureModifier.withType(
int.class, BukkitConverters.getEntityConverter(world));
}
@ -547,10 +527,7 @@ public class PacketContainer implements Serializable {
// Convert to and from the ProtocolLib wrapper
return structureModifier.withType(
Collection.class,
BukkitConverters.getListConverter(
MinecraftReflection.getNBTBaseClass(),
BukkitConverters.getNbtConverter()
)
BukkitConverters.getListConverter(BukkitConverters.getNbtConverter())
);
}
@ -576,9 +553,7 @@ public class PacketContainer implements Serializable {
// Convert to and from the ProtocolLib wrapper
return structureModifier.withType(
Collection.class,
BukkitConverters.getListConverter(
MinecraftReflection.getAttributeSnapshotClass(),
BukkitConverters.getWrappedAttributeConverter())
BukkitConverters.getListConverter(BukkitConverters.getWrappedAttributeConverter())
);
}
@ -594,10 +569,7 @@ public class PacketContainer implements Serializable {
// Convert to and from the ProtocolLib wrapper
return structureModifier.withType(
Collection.class,
BukkitConverters.getListConverter(
MinecraftReflection.getChunkPositionClass(),
ChunkPosition.getConverter())
);
BukkitConverters.getListConverter(ChunkPosition.getConverter()));
}
/**
@ -612,10 +584,7 @@ public class PacketContainer implements Serializable {
// Convert to and from the ProtocolLib wrapper
return structureModifier.withType(
Collection.class,
BukkitConverters.getListConverter(
MinecraftReflection.getBlockPositionClass(),
BlockPosition.getConverter())
);
BukkitConverters.getListConverter(BlockPosition.getConverter()));
}
/**
@ -629,10 +598,7 @@ public class PacketContainer implements Serializable {
// Convert to and from the ProtocolLib wrapper
return structureModifier.withType(
Collection.class,
BukkitConverters.getListConverter(
MinecraftReflection.getDataWatcherItemClass(),
BukkitConverters.getWatchableObjectConverter())
);
BukkitConverters.getListConverter(BukkitConverters.getWatchableObjectConverter()));
}
/**
@ -644,7 +610,7 @@ public class PacketContainer implements Serializable {
*/
public StructureModifier<Material> getBlocks() {
// Convert to and from the Bukkit wrapper
return structureModifier.<Material>withType(
return structureModifier.withType(
MinecraftReflection.getBlockClass(), BukkitConverters.getBlockConverter());
}
@ -657,7 +623,7 @@ public class PacketContainer implements Serializable {
*/
public StructureModifier<WrappedGameProfile> getGameProfiles() {
// Convert to and from the Bukkit wrapper
return structureModifier.<WrappedGameProfile>withType(
return structureModifier.withType(
MinecraftReflection.getGameProfileClass(), BukkitConverters.getWrappedGameProfileConverter());
}
@ -670,7 +636,7 @@ public class PacketContainer implements Serializable {
*/
public StructureModifier<WrappedBlockData> getBlockData() {
// Convert to and from our wrapper
return structureModifier.<WrappedBlockData>withType(
return structureModifier.withType(
MinecraftReflection.getIBlockDataClass(), BukkitConverters.getWrappedBlockDataConverter());
}
@ -685,7 +651,7 @@ public class PacketContainer implements Serializable {
ChunkCoordIntPair chunk = getChunkCoordIntPairs().read(0);
// Convert to and from our wrapper
return structureModifier.<MultiBlockChangeInfo[]>withType(
return structureModifier.withType(
MinecraftReflection.getMultiBlockChangeInfoArrayClass(), MultiBlockChangeInfo.getArrayConverter(chunk));
}
@ -698,7 +664,7 @@ public class PacketContainer implements Serializable {
*/
public StructureModifier<WrappedChatComponent> getChatComponents() {
// Convert to and from the Bukkit wrapper
return structureModifier.<WrappedChatComponent>withType(
return structureModifier.withType(
MinecraftReflection.getIChatBaseComponentClass(), BukkitConverters.getWrappedChatComponentConverter());
}
@ -715,22 +681,23 @@ public class PacketContainer implements Serializable {
*/
public StructureModifier<WrappedChatComponent[]> getChatComponentArrays() {
// Convert to and from the Bukkit wrapper
return structureModifier.<WrappedChatComponent[]>withType(
return structureModifier.withType(
ComponentArrayConverter.getGenericType(),
BukkitConverters.getIgnoreNull(new ComponentArrayConverter()));
Converters.ignoreNull(new ComponentArrayConverter()));
}
/**
* Retrieve a read/write structure for the ServerPing fields in the following packet: <br>
* <ul>
* <li>{@link PacketType.Status.Server#OUT_SERVER_INFO}
* <li>{@link PacketType.Status.Server#SERVER_INFO}
* </ul>
* @return A modifier for ServerPing fields.
*/
public StructureModifier<WrappedServerPing> getServerPings() {
// Convert to and from the wrapper
return structureModifier.<WrappedServerPing>withType(
MinecraftReflection.getServerPingClass(), BukkitConverters.getWrappedServerPingConverter());
return structureModifier.withType(
MinecraftReflection.getServerPingClass(),
BukkitConverters.getWrappedServerPingConverter());
}
/**
@ -744,10 +711,7 @@ public class PacketContainer implements Serializable {
// Convert to and from the ProtocolLib wrapper
return structureModifier.withType(
Collection.class,
BukkitConverters.getListConverter(
MinecraftReflection.getPlayerInfoDataClass(),
PlayerInfoData.getConverter())
);
BukkitConverters.getListConverter(PlayerInfoData.getConverter()));
}
/**
@ -756,8 +720,9 @@ public class PacketContainer implements Serializable {
*/
public StructureModifier<Protocol> getProtocols() {
// Convert to and from the wrapper
return structureModifier.<Protocol>withType(
EnumWrappers.getProtocolClass(), EnumWrappers.getProtocolConverter());
return structureModifier.withType(
EnumWrappers.getProtocolClass(),
EnumWrappers.getProtocolConverter());
}
/**
@ -766,8 +731,9 @@ public class PacketContainer implements Serializable {
*/
public StructureModifier<ClientCommand> getClientCommands() {
// Convert to and from the wrapper
return structureModifier.<ClientCommand>withType(
EnumWrappers.getClientCommandClass(), EnumWrappers.getClientCommandConverter());
return structureModifier.withType(
EnumWrappers.getClientCommandClass(),
EnumWrappers.getClientCommandConverter());
}
/**
@ -776,8 +742,9 @@ public class PacketContainer implements Serializable {
*/
public StructureModifier<ChatVisibility> getChatVisibilities() {
// Convert to and from the wrapper
return structureModifier.<ChatVisibility>withType(
EnumWrappers.getChatVisibilityClass(), EnumWrappers.getChatVisibilityConverter());
return structureModifier.withType(
EnumWrappers.getChatVisibilityClass(),
EnumWrappers.getChatVisibilityConverter());
}
/**
@ -786,8 +753,9 @@ public class PacketContainer implements Serializable {
*/
public StructureModifier<Difficulty> getDifficulties() {
// Convert to and from the wrapper
return structureModifier.<Difficulty>withType(
EnumWrappers.getDifficultyClass(), EnumWrappers.getDifficultyConverter());
return structureModifier.withType(
EnumWrappers.getDifficultyClass(),
EnumWrappers.getDifficultyConverter());
}
/**
@ -796,8 +764,9 @@ public class PacketContainer implements Serializable {
*/
public StructureModifier<EntityUseAction> getEntityUseActions() {
// Convert to and from the wrapper
return structureModifier.<EntityUseAction>withType(
EnumWrappers.getEntityUseActionClass(), EnumWrappers.getEntityUseActionConverter());
return structureModifier.withType(
EnumWrappers.getEntityUseActionClass(),
EnumWrappers.getEntityUseActionConverter());
}
/**
@ -806,8 +775,9 @@ public class PacketContainer implements Serializable {
*/
public StructureModifier<NativeGameMode> getGameModes() {
// Convert to and from the wrapper
return structureModifier.<NativeGameMode>withType(
EnumWrappers.getGameModeClass(), EnumWrappers.getGameModeConverter());
return structureModifier.withType(
EnumWrappers.getGameModeClass(),
EnumWrappers.getGameModeConverter());
}
/**
@ -816,8 +786,9 @@ public class PacketContainer implements Serializable {
*/
public StructureModifier<ResourcePackStatus> getResourcePackStatus() {
// Convert to and from the wrapper
return structureModifier.<ResourcePackStatus>withType(
EnumWrappers.getResourcePackStatusClass(), EnumWrappers.getResourcePackStatusConverter());
return structureModifier.withType(
EnumWrappers.getResourcePackStatusClass(),
EnumWrappers.getResourcePackStatusConverter());
}
/**
@ -826,8 +797,9 @@ public class PacketContainer implements Serializable {
*/
public StructureModifier<PlayerInfoAction> getPlayerInfoAction() {
// Convert to and from the wrapper
return structureModifier.<PlayerInfoAction>withType(
EnumWrappers.getPlayerInfoActionClass(), EnumWrappers.getPlayerInfoActionConverter());
return structureModifier.withType(
EnumWrappers.getPlayerInfoActionClass(),
EnumWrappers.getPlayerInfoActionConverter());
}
/**
@ -836,8 +808,9 @@ public class PacketContainer implements Serializable {
*/
public StructureModifier<TitleAction> getTitleActions() {
// Convert to and from the wrapper
return structureModifier.<TitleAction>withType(
EnumWrappers.getTitleActionClass(), EnumWrappers.getTitleActionConverter());
return structureModifier.withType(
EnumWrappers.getTitleActionClass(),
EnumWrappers.getTitleActionConverter());
}
/**
@ -846,8 +819,9 @@ public class PacketContainer implements Serializable {
*/
public StructureModifier<WorldBorderAction> getWorldBorderActions() {
// Convert to and from the wrapper
return structureModifier.<WorldBorderAction>withType(
EnumWrappers.getWorldBorderActionClass(), EnumWrappers.getWorldBorderActionConverter());
return structureModifier.withType(
EnumWrappers.getWorldBorderActionClass(),
EnumWrappers.getWorldBorderActionConverter());
}
/**
@ -856,8 +830,9 @@ public class PacketContainer implements Serializable {
*/
public StructureModifier<CombatEventType> getCombatEvents() {
// Convert to and from the wrapper
return structureModifier.<CombatEventType>withType(
EnumWrappers.getCombatEventTypeClass(), EnumWrappers.getCombatEventTypeConverter());
return structureModifier.withType(
EnumWrappers.getCombatEventTypeClass(),
EnumWrappers.getCombatEventTypeConverter());
}
/**
@ -866,8 +841,9 @@ public class PacketContainer implements Serializable {
*/
public StructureModifier<PlayerDigType> getPlayerDigTypes() {
// Convert to and from the wrapper
return structureModifier.<PlayerDigType>withType(
EnumWrappers.getPlayerDigTypeClass(), EnumWrappers.getPlayerDiggingActionConverter());
return structureModifier.withType(
EnumWrappers.getPlayerDigTypeClass(),
EnumWrappers.getPlayerDiggingActionConverter());
}
/**
@ -876,8 +852,9 @@ public class PacketContainer implements Serializable {
*/
public StructureModifier<PlayerAction> getPlayerActions() {
// Convert to and from the wrapper
return structureModifier.<PlayerAction>withType(
EnumWrappers.getPlayerActionClass(), EnumWrappers.getEntityActionConverter());
return structureModifier.withType(
EnumWrappers.getPlayerActionClass(),
EnumWrappers.getEntityActionConverter());
}
/**
@ -886,8 +863,9 @@ public class PacketContainer implements Serializable {
*/
public StructureModifier<ScoreboardAction> getScoreboardActions() {
// Convert to and from the wrapper
return structureModifier.<ScoreboardAction>withType(
EnumWrappers.getScoreboardActionClass(), EnumWrappers.getUpdateScoreActionConverter());
return structureModifier.withType(
EnumWrappers.getScoreboardActionClass(),
EnumWrappers.getUpdateScoreActionConverter());
}
/**
@ -896,8 +874,9 @@ public class PacketContainer implements Serializable {
*/
public StructureModifier<Particle> getParticles() {
// Convert to and from the wrapper
return structureModifier.<Particle>withType(
EnumWrappers.getParticleClass(), EnumWrappers.getParticleConverter());
return structureModifier.withType(
EnumWrappers.getParticleClass(),
EnumWrappers.getParticleConverter());
}
/**
@ -906,8 +885,9 @@ public class PacketContainer implements Serializable {
*/
public StructureModifier<PotionEffectType> getEffectTypes() {
// Convert to and from Bukkit
return structureModifier.<PotionEffectType>withType(
MinecraftReflection.getMobEffectListClass(), BukkitConverters.getEffectTypeConverter());
return structureModifier.withType(
MinecraftReflection.getMobEffectListClass(),
BukkitConverters.getEffectTypeConverter());
}
/**
@ -916,8 +896,9 @@ public class PacketContainer implements Serializable {
*/
public StructureModifier<SoundCategory> getSoundCategories() {
// Convert to and from the enums
return structureModifier.<SoundCategory>withType(
EnumWrappers.getSoundCategoryClass(), EnumWrappers.getSoundCategoryConverter());
return structureModifier.withType(
EnumWrappers.getSoundCategoryClass(),
EnumWrappers.getSoundCategoryConverter());
}
/**
@ -926,8 +907,9 @@ public class PacketContainer implements Serializable {
*/
public StructureModifier<Sound> getSoundEffects() {
// Convert to and from Bukkit
return structureModifier.<Sound>withType(
MinecraftReflection.getSoundEffectClass(), BukkitConverters.getSoundConverter());
return structureModifier.withType(
MinecraftReflection.getSoundEffectClass(),
BukkitConverters.getSoundConverter());
}
/**
@ -935,8 +917,9 @@ public class PacketContainer implements Serializable {
* @return A modifier for ItemSlot enum fields.
*/
public StructureModifier<ItemSlot> getItemSlots() {
return structureModifier.<ItemSlot>withType(
EnumWrappers.getItemSlotClass(), EnumWrappers.getItemSlotConverter());
return structureModifier.withType(
EnumWrappers.getItemSlotClass(),
EnumWrappers.getItemSlotConverter());
}
/**
@ -944,8 +927,9 @@ public class PacketContainer implements Serializable {
* @return A modifier for Hand enum fields.
*/
public StructureModifier<Hand> getHands() {
return structureModifier.<Hand>withType(
EnumWrappers.getHandClass(), EnumWrappers.getHandConverter());
return structureModifier.withType(
EnumWrappers.getHandClass(),
EnumWrappers.getHandConverter());
}
/**
@ -953,8 +937,9 @@ public class PacketContainer implements Serializable {
* @return A modifier for Direction enum fields.
*/
public StructureModifier<Direction> getDirections() {
return structureModifier.<Direction>withType(
EnumWrappers.getDirectionClass(), EnumWrappers.getDirectionConverter());
return structureModifier.withType(
EnumWrappers.getDirectionClass(),
EnumWrappers.getDirectionConverter());
}
/**
@ -962,8 +947,52 @@ public class PacketContainer implements Serializable {
* @return A modifier for ChatType enum fields.
*/
public StructureModifier<ChatType> getChatTypes() {
return structureModifier.<ChatType>withType(
EnumWrappers.getChatTypeClass(), EnumWrappers.getChatTypeConverter());
return structureModifier.withType(
EnumWrappers.getChatTypeClass(),
EnumWrappers.getChatTypeConverter());
}
/**
* Retrieve a read/write structure for the MinecraftKey class.
* @return A modifier for MinecraftKey fields.
*/
public StructureModifier<MinecraftKey> getMinecraftKeys() {
return structureModifier.withType(
MinecraftReflection.getMinecraftKeyClass(),
MinecraftKey.getConverter());
}
/**
* Retrieve a read/write structure for the Map class.
* @param keyConverter Converter for map keys
* @param valConverter Converter for map values
* @param <K> Key param
* @param <V> Value param
* @return A modifier for Map fields.
*
* @see BukkitConverters
* @see EquivalentConverter
*/
public <K, V> StructureModifier<Map<K, V>> getMaps(EquivalentConverter<K> keyConverter,
EquivalentConverter<V> valConverter) {
return structureModifier.withType(
Map.class,
BukkitConverters.getMapConverter(keyConverter, valConverter));
}
/**
* Retrieve a read/write structure for the Set class.
* @param converter Converter for elements
* @param <E> Element param
* @return A modifier for Set fields
*
* @see BukkitConverters
* @see EquivalentConverter
*/
public <E> StructureModifier<Set<E>> getSets(EquivalentConverter<E> converter) {
return structureModifier.withType(
Set.class,
BukkitConverters.getSetConverter(converter));
}
/**
@ -977,7 +1006,9 @@ public class PacketContainer implements Serializable {
* @return The modifier
*/
public <T extends Enum<T>> StructureModifier<T> getEnumModifier(Class<T> enumClass, Class<?> nmsClass) {
return structureModifier.<T>withType(nmsClass, new EnumConverter<T>(enumClass));
return structureModifier.withType(
nmsClass,
new EnumConverter<>(nmsClass, enumClass));
}
/**
@ -990,7 +1021,9 @@ public class PacketContainer implements Serializable {
* @see #getEnumModifier(Class, Class)
*/
public <T extends Enum<T>> StructureModifier<T> getEnumModifier(Class<T> enumClass, int index) {
return getEnumModifier(enumClass, structureModifier.getField(index).getType());
return getEnumModifier(
enumClass,
structureModifier.getField(index).getType());
}
/**
@ -1036,7 +1069,7 @@ public class PacketContainer implements Serializable {
* @return A deep copy of the current packet.
*/
public PacketContainer deepClone() {
Object clonedPacket = null;
Object clonedPacket;
// Fall back on the alternative (but slower) method of reading and writing back the packet
if (CLONING_UNSUPPORTED.contains(type)) {
@ -1183,7 +1216,7 @@ public class PacketContainer implements Serializable {
*/
public void addMetadata(String key, Object value) {
if (metadata == null) {
metadata = new HashMap<String, Object>();
metadata = new HashMap<>();
}
metadata.put(key, value);
@ -1259,13 +1292,13 @@ public class PacketContainer implements Serializable {
final EquivalentConverter<ItemStack> stackConverter = BukkitConverters.getItemStackConverter();
@Override
public Object getGeneric(Class<?>genericType, ItemStack[] specific) {
public Object getGeneric(ItemStack[] specific) {
Class<?> nmsStack = MinecraftReflection.getItemStackClass();
Object[] result = (Object[]) Array.newInstance(nmsStack, specific.length);
// Unwrap every item
for (int i = 0; i < result.length; i++) {
result[i] = stackConverter.getGeneric(nmsStack, specific[i]);
result[i] = stackConverter.getGeneric(specific[i]);
}
return result;
}
@ -1296,13 +1329,13 @@ public class PacketContainer implements Serializable {
final EquivalentConverter<WrappedChatComponent> componentConverter = BukkitConverters.getWrappedChatComponentConverter();
@Override
public Object getGeneric(Class<?> genericType, WrappedChatComponent[] specific) {
public Object getGeneric(WrappedChatComponent[] specific) {
Class<?> nmsComponent = MinecraftReflection.getIChatBaseComponentClass();
Object[] result = (Object[]) Array.newInstance(nmsComponent, specific.length);
// Unwrap every item
for (int i = 0; i < result.length; i++) {
result[i] = componentConverter.getGeneric(nmsComponent, specific[i]);
result[i] = componentConverter.getGeneric(specific[i]);
}
return result;
}
@ -1351,7 +1384,7 @@ public class PacketContainer implements Serializable {
}
@Override
public Object getGeneric(Class<?> genericType, WrappedChatComponent[] specific) {
public Object getGeneric(WrappedChatComponent[] specific) {
NbtCompound compound = NbtFactory.ofCompound("");
for (int i = 0; i < lines; i++) {
@ -1365,7 +1398,7 @@ public class PacketContainer implements Serializable {
compound.put("Text" + (i + 1), component.getJson());
}
return nbtConverter.getGeneric(genericType, compound);
return nbtConverter.getGeneric(compound);
}
@Override
@ -1394,8 +1427,8 @@ public class PacketContainer implements Serializable {
}
@Override
public Object getGeneric(Class<?> genericType, WrappedChatComponent[] specific) {
return DELEGATE.getGeneric(genericType, specific);
public Object getGeneric(WrappedChatComponent[] specific) {
return DELEGATE.getGeneric(specific);
}
@Override

View File

@ -21,32 +21,12 @@ package com.comphenix.protocol.reflect;
* Interface that converts generic objects into types and back.
*
* @author Kristian
* @param <TType> The specific type.
* @param <T> The specific type.
*/
public interface EquivalentConverter<TType> {
public interface EquivalentConverter<T> extends SpecificConverter<T>, GenericConverter<T> {
/**
* Retrieve a copy of the specific type using an instance of the generic type.
* <p>
* This is usually a wrapper type in the Bukkit API.
* @param generic - the generic type.
* @return The new specific type.
*/
public TType getSpecific(Object generic);
/**
* Retrieve a copy of the generic type from a specific type.
* <p>
* This is usually a native net.minecraft.server type in Minecraft.
* @param genericType - class or super class of the generic type.
* @param specific - the specific type we need to copy.
* @return A copy of the specific type.
*/
public Object getGeneric(Class<?> genericType, TType specific);
/**
* Due to type erasion, we need to explicitly keep a reference to the specific type.
* Due to type erasure, we need to explicitly keep a reference to the specific type.
* @return The specific type.
*/
public Class<TType> getSpecificType();
}
Class<T> getSpecificType();
}

View File

@ -0,0 +1,33 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2017 Dan Mulloy
*
* 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.reflect;
/**
* Converts specific objects into generic objects.
* @author Dan
* @param <T> Specific type
*/
public interface GenericConverter<T> {
/**
* Retrieve a copy of the generic type from a specific type.
* <p>
* This is usually a native net.minecraft.server type in Minecraft.
* @param specific - the specific type we need to copy.
* @return A copy of the specific type.
*/
Object getGeneric(T specific);
}

View File

@ -0,0 +1,33 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2017 Dan Mulloy
*
* 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.reflect;
/**
* Converts generic objects into specific objects.
* @author Dan
* @param <T> The specific type
*/
public interface SpecificConverter<T> {
/**
* Retrieve a copy of the specific type using an instance of the generic type.
* <p>
* This is usually a wrapper type in the Bukkit API or ProtocolLib API.
* @param generic - the generic type.
* @return The new specific type.
*/
T getSpecific(Object generic);
}

View File

@ -352,7 +352,7 @@ public class StructureModifier<TField> {
throw new FieldAccessException(String.format("Field index out of bounds. (Index: %s, Size: %s)", fieldIndex, data.size()));
// Use the converter, if it exists
Object obj = needConversion() ? converter.getGeneric(getFieldType(fieldIndex), value) : value;
Object obj = needConversion() ? converter.getGeneric(value) : value;
try {
FieldUtils.writeField(data.get(fieldIndex), target, obj, true);

View File

@ -113,24 +113,24 @@ public class BukkitCloner implements Cloner {
return MinecraftReflection.getMinecraftItemStack(MinecraftReflection.getBukkitItemStack(source).clone());
case 1:
EquivalentConverter<WrappedDataWatcher> dataConverter = BukkitConverters.getDataWatcherConverter();
return dataConverter.getGeneric(clonableClasses.get(1), dataConverter.getSpecific(source).deepClone());
return dataConverter.getGeneric(dataConverter.getSpecific(source).deepClone());
case 2:
EquivalentConverter<BlockPosition> blockConverter = BlockPosition.getConverter();
return blockConverter.getGeneric(clonableClasses.get(2), blockConverter.getSpecific(source));
return blockConverter.getGeneric(blockConverter.getSpecific(source));
case 3:
EquivalentConverter<ChunkPosition> chunkConverter = ChunkPosition.getConverter();
return chunkConverter.getGeneric(clonableClasses.get(3), chunkConverter.getSpecific(source));
return chunkConverter.getGeneric(chunkConverter.getSpecific(source));
case 4:
EquivalentConverter<WrappedServerPing> serverConverter = BukkitConverters.getWrappedServerPingConverter();
return serverConverter.getGeneric(clonableClasses.get(4), serverConverter.getSpecific(source).deepClone());
return serverConverter.getGeneric(serverConverter.getSpecific(source).deepClone());
case 5:
return source;
case 6:
EquivalentConverter<MinecraftKey> keyConverter = MinecraftKey.getConverter();
return keyConverter.getGeneric(clonableClasses.get(6), keyConverter.getSpecific(source));
return keyConverter.getGeneric(keyConverter.getSpecific(source));
case 7:
EquivalentConverter<WrappedBlockData> blockDataConverter = BukkitConverters.getWrappedBlockDataConverter();
return blockDataConverter.getGeneric(clonableClasses.get(7), blockDataConverter.getSpecific(source).deepClone());
return blockDataConverter.getGeneric(blockDataConverter.getSpecific(source).deepClone());
case 8:
return nonNullListCloner().clone(source);
default:

View File

@ -110,7 +110,7 @@ public abstract class CompiledStructureModifier extends StructureModifier<Object
@Override
public StructureModifier<Object> write(int index, Object value) throws FieldAccessException {
if (converter != null)
value = converter.getGeneric(getFieldType(index), value);
value = converter.getGeneric(value);
return writeGenerated(index, value);
}

View File

@ -0,0 +1,163 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2017 Dan Mulloy
*
* 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 java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import com.comphenix.protocol.reflect.EquivalentConverter;
/**
* Automatically wraps an internal NMS class to a non-versioned, deofbuscated class.
* Requirements:
* <ul>
* <li>The wrapper must be public</li>
* <li>If the wrapper is an internal class, it must be static</li>
* <li>The wrapper must have one public constructor with no arguments (the default constructor is acceptable)</li>
* <li>The wrapper must have the the same number of fields as the NMS class</li>
* <li>Each field should correspond, in order, to its NMS counterpart</li>
* <li>Non-generic fields must have a converter</li>
* </ul>
*
* @author dmulloy2
*/
public class AutoWrapper<T> implements EquivalentConverter<T> {
private Map<Integer, Function<Object, Object>> wrappers = new HashMap<>();
private Map<Integer, Function<Object, Object>> unwrappers = new HashMap<>();
private Class<T> wrapperClass;
private Class<?> nmsClass;
private AutoWrapper(Class<T> wrapperClass, Class<?> nmsClass) {
this.wrapperClass = wrapperClass;
this.nmsClass = nmsClass;
}
public static <T> AutoWrapper<T> wrap(Class<T> wrapperClass, Class<?> nmsClass) {
return new AutoWrapper<>(wrapperClass, nmsClass);
}
public AutoWrapper<T> field(int index, Function<Object, Object> wrapper, Function<Object, Object> unwrapper) {
wrappers.put(index, wrapper);
unwrappers.put(index, unwrapper);
return this;
}
public AutoWrapper<T> field(int index, EquivalentConverter converter) {
return field(index, converter::getSpecific, specific -> converter.getGeneric(specific));
}
public T wrap(Object nmsObject) {
T instance;
try {
instance = wrapperClass.newInstance();
} catch (ReflectiveOperationException ex) {
throw new InvalidWrapperException(wrapperClass.getSimpleName() + " is not accessible!", ex);
}
Field[] wrapperFields = wrapperClass.getDeclaredFields();
Field[] nmsFields = nmsClass.getDeclaredFields();
for (int i = 0; i < wrapperFields.length; i++) {
try {
Field wrapperField = wrapperFields[i];
Field nmsField = nmsFields[i];
if (!nmsField.isAccessible())
nmsField.setAccessible(true);
Object value = nmsField.get(nmsObject);
if (wrappers.containsKey(i))
value = wrappers.get(i).apply(value);
wrapperField.set(instance, value);
} catch (ReflectiveOperationException ex) {
throw new InvalidWrapperException("Failed to wrap field", ex);
}
}
return instance;
}
public Object unwrap(Object wrapper) {
Object instance;
try {
instance = nmsClass.newInstance();
} catch (ReflectiveOperationException ex) {
throw new InvalidWrapperException("Failed to construct new " + nmsClass.getSimpleName(), ex);
}
Field[] wrapperFields = wrapperClass.getDeclaredFields();
Field[] nmsFields = nmsClass.getDeclaredFields();
for (int i = 0; i < wrapperFields.length; i++) {
try {
Field wrapperField = wrapperFields[i];
Field nmsField = nmsFields[i];
if (!nmsField.isAccessible())
nmsField.setAccessible(true);
if (Modifier.isFinal(nmsField.getModifiers()))
unsetFinal(nmsField);
Object value = wrapperField.get(wrapper);
if (unwrappers.containsKey(i))
value = unwrappers.get(i).apply(value);
nmsField.set(instance, value);
} catch (ReflectiveOperationException ex) {
throw new InvalidWrapperException("Failed to unwrap field", ex);
}
}
return instance;
}
private void unsetFinal(Field field) throws ReflectiveOperationException {
Field modifiers = Field.class.getDeclaredField("modifiers");
modifiers.setAccessible(true);
modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL);
}
// ---- Equivalent conversion
@Override
public T getSpecific(Object generic) {
return wrap(generic);
}
@Override
public Object getGeneric(Object specific) {
return unwrap(specific);
}
@Override
public Class<T> getSpecificType() {
return wrapperClass;
}
public static class InvalidWrapperException extends RuntimeException {
private InvalidWrapperException(String message, Throwable cause) {
super(message, cause);
}
}
}

View File

@ -164,7 +164,7 @@ public class BlockPosition {
public static EquivalentConverter<BlockPosition> getConverter() {
return new EquivalentConverter<BlockPosition>() {
@Override
public Object getGeneric(Class<?> genericType, BlockPosition specific) {
public Object getGeneric(BlockPosition specific) {
if (blockPositionConstructor == null) {
try {
blockPositionConstructor = MinecraftReflection.getBlockPositionClass().
@ -187,7 +187,7 @@ public class BlockPosition {
public BlockPosition getSpecific(Object generic) {
if (MinecraftReflection.isBlockPosition(generic)) {
// Use a structure modifier
intModifier = new StructureModifier<Object>(generic.getClass(), null, false).withType(int.class);
intModifier = new StructureModifier<>(generic.getClass(), null, false).withType(int.class);
// Damn it all
if (intModifier.size() < 3) {

View File

@ -67,7 +67,7 @@ public class ChunkCoordIntPair {
public static EquivalentConverter<ChunkCoordIntPair> getConverter() {
return new EquivalentConverter<ChunkCoordIntPair>() {
@Override
public Object getGeneric(Class<?> genericType, ChunkCoordIntPair specific) {
public Object getGeneric(ChunkCoordIntPair specific) {
if (COORD_CONSTRUCTOR == null) {
COORD_CONSTRUCTOR = Accessors.getConstructorAccessor(COORD_PAIR_CLASS, int.class, int.class);
}

View File

@ -154,7 +154,7 @@ public class ChunkPosition {
public static EquivalentConverter<ChunkPosition> getConverter() {
return new EquivalentConverter<ChunkPosition>() {
@Override
public Object getGeneric(Class<?> genericType, ChunkPosition specific) {
public Object getGeneric(ChunkPosition specific) {
if (chunkPositionConstructor == null) {
try {
chunkPositionConstructor = MinecraftReflection.getChunkPositionClass().
@ -177,7 +177,7 @@ public class ChunkPosition {
public ChunkPosition getSpecific(Object generic) {
if (MinecraftReflection.isChunkPosition(generic)) {
// Use a structure modifier
intModifier = new StructureModifier<Object>(generic.getClass(), null, false).withType(int.class);
intModifier = new StructureModifier<>(generic.getClass(), null, false).withType(int.class);
// Damn it all
if (intModifier.size() < 3) {

View File

@ -0,0 +1,106 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2017 Dan Mulloy
*
* 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 java.util.function.Function;
import com.comphenix.protocol.reflect.EquivalentConverter;
/**
* Utility class for converters
* @author dmulloy2
*/
public class Converters {
/**
* Returns a converter that ignores null elements, so that the underlying converter doesn't have to worry about them.
* @param converter Underlying converter
* @param <T> Element type
* @return An ignore null converter
*/
public static <T> EquivalentConverter<T> ignoreNull(final EquivalentConverter<T> converter) {
return new EquivalentConverter<T>() {
@Override
public T getSpecific(Object generic) {
return generic != null ? converter.getSpecific(generic) : null;
}
@Override
public Object getGeneric(T specific) {
return specific != null ? converter.getGeneric(specific) : null;
}
@Override
public Class<T> getSpecificType() {
return converter.getSpecificType();
}
};
}
/**
* Returns a converter that passes generic and specific values through without converting.
* @param clazz Element class
* @param <T> Element type
* @return A passthrough converter
*/
public static <T> EquivalentConverter<T> passthrough(final Class<T> clazz) {
return ignoreNull(new EquivalentConverter<T>() {
@Override
public T getSpecific(Object generic) {
return (T) generic;
}
@Override
public Object getGeneric(T specific) {
return specific;
}
@Override
public Class<T> getSpecificType() {
return clazz;
}
});
}
/**
* Creates a simple converter for wrappers with {@code getHandle()} and {@code fromHandle(...)} methods. With Java 8,
* converters can be reduced to a single line (see {@link BukkitConverters#getWrappedGameProfileConverter()}).
* @param toHandle Function from wrapper to handle (i.e. {@code getHandle()})
* @param fromHandle Function from handle to wrapper (i.e. {@code fromHandle(Object)})
* @param <T> Wrapper type
* @return A handle converter
*/
public static <T> EquivalentConverter<T> handle(final Function<T, Object> toHandle,
final Function<Object, T> fromHandle) {
return new EquivalentConverter<T>() {
@Override
public T getSpecific(Object generic) {
return fromHandle.apply(generic);
}
@Override
public Object getGeneric(T specific) {
return toHandle.apply(specific);
}
@Override
public Class<T> getSpecificType() {
return null;
}
};
}
}

View File

@ -3,6 +3,7 @@ package com.comphenix.protocol.wrappers;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.function.Function;
import org.bukkit.GameMode;
@ -562,117 +563,119 @@ public abstract class EnumWrappers {
// Get the converters
public static EquivalentConverter<Protocol> getProtocolConverter() {
return new EnumConverter<Protocol>(Protocol.class);
return new EnumConverter<>(getProtocolClass(), Protocol.class);
}
public static EquivalentConverter<ClientCommand> getClientCommandConverter() {
return new EnumConverter<ClientCommand>(ClientCommand.class);
return new EnumConverter<>(getClientCommandClass(), ClientCommand.class);
}
public static EquivalentConverter<ChatVisibility> getChatVisibilityConverter() {
return new EnumConverter<ChatVisibility>(ChatVisibility.class);
return new EnumConverter<>(getChatVisibilityClass(), ChatVisibility.class);
}
public static EquivalentConverter<Difficulty> getDifficultyConverter() {
return new EnumConverter<Difficulty>(Difficulty.class);
return new EnumConverter<>(getDifficultyClass(), Difficulty.class);
}
public static EquivalentConverter<EntityUseAction> getEntityUseActionConverter() {
return new EnumConverter<EntityUseAction>(EntityUseAction.class);
return new EnumConverter<>(getEntityUseActionClass(), EntityUseAction.class);
}
public static EquivalentConverter<NativeGameMode> getGameModeConverter() {
return new EnumConverter<NativeGameMode>(NativeGameMode.class);
return new EnumConverter<>(getGameModeClass(), NativeGameMode.class);
}
public static EquivalentConverter<ResourcePackStatus> getResourcePackStatusConverter() {
return new EnumConverter<ResourcePackStatus>(ResourcePackStatus.class);
return new EnumConverter<>(getResourcePackStatusClass(), ResourcePackStatus.class);
}
public static EquivalentConverter<PlayerInfoAction> getPlayerInfoActionConverter() {
return new EnumConverter<PlayerInfoAction>(PlayerInfoAction.class);
return new EnumConverter<>(getPlayerInfoActionClass(), PlayerInfoAction.class);
}
public static EquivalentConverter<TitleAction> getTitleActionConverter() {
return new EnumConverter<TitleAction>(TitleAction.class);
return new EnumConverter<>(getTitleActionClass(), TitleAction.class);
}
public static EquivalentConverter<WorldBorderAction> getWorldBorderActionConverter() {
return new EnumConverter<WorldBorderAction>(WorldBorderAction.class);
return new EnumConverter<>(getWorldBorderActionClass(), WorldBorderAction.class);
}
public static EquivalentConverter<CombatEventType> getCombatEventTypeConverter() {
return new EnumConverter<CombatEventType>(CombatEventType.class);
return new EnumConverter<>(getCombatEventTypeClass(), CombatEventType.class);
}
public static EquivalentConverter<PlayerDigType> getPlayerDiggingActionConverter() {
return new EnumConverter<PlayerDigType>(PlayerDigType.class);
return new EnumConverter<>(getPlayerDigTypeClass(), PlayerDigType.class);
}
public static EquivalentConverter<PlayerAction> getEntityActionConverter() {
return new EnumConverter<PlayerAction>(PlayerAction.class);
return new EnumConverter<>(getPlayerActionClass(), PlayerAction.class);
}
public static EquivalentConverter<ScoreboardAction> getUpdateScoreActionConverter() {
return new EnumConverter<ScoreboardAction>(ScoreboardAction.class);
return new EnumConverter<>(getScoreboardActionClass(), ScoreboardAction.class);
}
public static EquivalentConverter<Particle> getParticleConverter() {
return new EnumConverter<Particle>(Particle.class);
return new EnumConverter<>(getParticleClass(), Particle.class);
}
public static EquivalentConverter<SoundCategory> getSoundCategoryConverter() {
return new EnumConverter<SoundCategory>(SoundCategory.class);
return new EnumConverter<>(getSoundCategoryClass(), SoundCategory.class);
}
public static EquivalentConverter<ItemSlot> getItemSlotConverter() {
return new EnumConverter<ItemSlot>(ItemSlot.class);
return new EnumConverter<>(getItemSlotClass(), ItemSlot.class);
}
public static EquivalentConverter<Hand> getHandConverter() {
return new EnumConverter<Hand>(Hand.class);
return new EnumConverter<>(getHandClass(), Hand.class);
}
public static EquivalentConverter<Direction> getDirectionConverter() {
return new EnumConverter<Direction>(Direction.class);
return new EnumConverter<>(getDirectionClass(), Direction.class);
}
public static EquivalentConverter<ChatType> getChatTypeConverter() {
return new EnumConverter<ChatType>(ChatType.class);
return new EnumConverter<>(getChatTypeClass(), ChatType.class);
}
/**
* Retrieve a generic enum converter for use with StructureModifiers.
* @param enumClass - Enum class
* @param genericClass - Generic nms enum class
* @param specificType - Specific enum class
* @return A generic enum converter
*/
public static <T extends Enum<T>> EquivalentConverter<T> getGenericConverter(Class<T> enumClass) {
return new EnumConverter<T>(enumClass);
public static <T extends Enum<T>> EquivalentConverter<T> getGenericConverter(Class<?> genericClass, Class<T> specificType) {
return new EnumConverter<>(genericClass, specificType);
}
// The common enum converter
@SuppressWarnings({ "rawtypes", "unchecked" })
public static class EnumConverter<T extends Enum<T>> implements EquivalentConverter<T> {
private Class<?> genericType;
private Class<T> specificType;
public EnumConverter(Class<T> specificType) {
public EnumConverter(Class<?> genericType, Class<T> specificType) {
this.genericType = genericType;
this.specificType = specificType;
}
@Override
public T getSpecific(Object generic) {
// We know its an enum already!
return Enum.valueOf(specificType, ((Enum) generic).name());
}
@Override
public Object getGeneric(Class<?> genericType, T specific) {
public Object getGeneric(T specific) {
return Enum.valueOf((Class) genericType, specific.name());
}
@Override
public Class<T> getSpecificType() {
return specificType;
return null;
}
}
}

View File

@ -122,7 +122,7 @@ public class MinecraftKey {
}
@Override
public Object getGeneric(Class<?> genericType, MinecraftKey specific) {
public Object getGeneric(MinecraftKey specific) {
if (constructor == null) {
try {
constructor = MinecraftReflection.getMinecraftKeyClass().getConstructor(String.class, String.class);

View File

@ -190,7 +190,7 @@ public class MultiBlockChangeInfo {
@Override
public MultiBlockChangeInfo getSpecific(Object generic) {
StructureModifier<Object> modifier = new StructureModifier<Object>(generic.getClass(), null, false).withTarget(generic);
StructureModifier<Object> modifier = new StructureModifier<>(generic.getClass(), null, false).withTarget(generic);
StructureModifier<Short> shorts = modifier.withType(short.class);
short location = shorts.read(0);
@ -203,7 +203,7 @@ public class MultiBlockChangeInfo {
}
@Override
public Object getGeneric(Class<?> genericType, MultiBlockChangeInfo specific) {
public Object getGeneric(MultiBlockChangeInfo specific) {
try {
if (constructor == null) {
constructor = nmsClass.getConstructor(
@ -216,7 +216,7 @@ public class MultiBlockChangeInfo {
return constructor.newInstance(
null,
specific.location,
BukkitConverters.getWrappedBlockDataConverter().getGeneric(MinecraftReflection.getIBlockDataClass(), specific.data)
BukkitConverters.getWrappedBlockDataConverter().getGeneric(specific.data)
);
} catch (Throwable ex) {
throw new RuntimeException("Failed to construct MultiBlockChangeInfo instance.", ex);
@ -248,12 +248,12 @@ public class MultiBlockChangeInfo {
}
@Override
public Object getGeneric(Class<?> genericType, MultiBlockChangeInfo[] specific) {
public Object getGeneric(MultiBlockChangeInfo[] specific) {
Object[] result = (Object[]) Array.newInstance(nmsClass, specific.length);
// Wrap every item
for (int i = 0; i < result.length; i++) {
result[i] = converter.getGeneric(nmsClass, specific[i]);
result[i] = converter.getGeneric(specific[i]);
}
return result;

View File

@ -91,7 +91,7 @@ public class PlayerInfoData {
public static EquivalentConverter<PlayerInfoData> getConverter() {
return new EquivalentConverter<PlayerInfoData>() {
@Override
public Object getGeneric(Class<?> genericType, PlayerInfoData specific) {
public Object getGeneric(PlayerInfoData specific) {
if (constructor == null) {
try {
// public PlayerInfoData(Packet, GameProfile, int, GameMode, ChatComponent)
@ -116,7 +116,7 @@ public class PlayerInfoData {
null,
specific.profile.handle,
specific.latency,
EnumWrappers.getGameModeConverter().getGeneric(EnumWrappers.getGameModeClass(), specific.gameMode),
EnumWrappers.getGameModeConverter().getGeneric(specific.gameMode),
specific.displayName != null ? specific.displayName.handle : null
);
return result;
@ -128,7 +128,7 @@ public class PlayerInfoData {
@Override
public PlayerInfoData getSpecific(Object generic) {
if (MinecraftReflection.isPlayerInfoData(generic)) {
StructureModifier<Object> modifier = new StructureModifier<Object>(generic.getClass(), null, false)
StructureModifier<Object> modifier = new StructureModifier<>(generic.getClass(), null, false)
.withTarget(generic);
StructureModifier<WrappedGameProfile> gameProfiles = modifier.withType(

View File

@ -91,15 +91,14 @@ public class Vector3F {
}
public static EquivalentConverter<Vector3F> getConverter() {
return new IgnoreNullConverter<Vector3F>() {
return Converters.ignoreNull(new EquivalentConverter<Vector3F>() {
@Override
public Class<Vector3F> getSpecificType() {
return Vector3F.class;
}
@Override
protected Object getGenericValue(Class<?> genericType, Vector3F specific) {
public Object getGeneric(Vector3F specific) {
if (constructor == null) {
try {
constructor = clazz.getConstructor(float.class, float.class, float.class);
@ -107,7 +106,7 @@ public class Vector3F {
throw new RuntimeException("Failed to find constructor for Vector3f", ex);
}
}
try {
return constructor.newInstance(specific.x, specific.y, specific.z);
} catch (ReflectiveOperationException ex) {
@ -116,7 +115,7 @@ public class Vector3F {
}
@Override
protected Vector3F getSpecificValue(Object generic) {
public Vector3F getSpecific(Object generic) {
StructureModifier<Float> modifier = new StructureModifier<Float>(generic.getClass())
.withTarget(generic).withType(float.class);
float x = modifier.read(0);
@ -124,6 +123,6 @@ public class Vector3F {
float z = modifier.read(2);
return new Vector3F(x, y, z);
}
};
});
}
}

View File

@ -280,7 +280,7 @@ public class WrappedServerPing extends AbstractWrapper {
public void setPlayers(Iterable<? extends WrappedGameProfile> profile) {
if (players == null)
resetPlayers();
PLAYERS_PROFILES.set(players, (profile != null) ? PROFILE_CONVERT.getGeneric(GAME_PROFILE_ARRAY, profile) : null);
PLAYERS_PROFILES.set(players, (profile != null) ? PROFILE_CONVERT.getGeneric(profile) : null);
}
/**

View File

@ -273,22 +273,22 @@ public class WrappedWatchableObject extends AbstractWrapper {
if (wrapped instanceof WrappedChatComponent) {
return ((WrappedChatComponent) wrapped).getHandle();
} else if (wrapped instanceof ItemStack) {
return BukkitConverters.getItemStackConverter().getGeneric(MinecraftReflection.getItemStackClass(), (ItemStack) wrapped);
return BukkitConverters.getItemStackConverter().getGeneric((ItemStack) wrapped);
} else if (wrapped instanceof WrappedBlockData) {
return BukkitConverters.getWrappedBlockDataConverter().getGeneric(MinecraftReflection.getIBlockDataClass(), (WrappedBlockData) wrapped);
return BukkitConverters.getWrappedBlockDataConverter().getGeneric((WrappedBlockData) wrapped);
} else if (wrapped instanceof Vector3F) {
return Vector3F.getConverter().getGeneric(Vector3F.getMinecraftClass(), (Vector3F) wrapped);
return Vector3F.getConverter().getGeneric((Vector3F) wrapped);
} else if (wrapped instanceof BlockPosition) {
return BlockPosition.getConverter().getGeneric(MinecraftReflection.getBlockPositionClass(), (BlockPosition) wrapped);
return BlockPosition.getConverter().getGeneric((BlockPosition) wrapped);
} else if (wrapped instanceof Direction) {
return EnumWrappers.getDirectionConverter().getGeneric(EnumWrappers.getDirectionClass(), (Direction) wrapped);
return EnumWrappers.getDirectionConverter().getGeneric((Direction) wrapped);
} else if (wrapped instanceof NbtCompound) {
return NbtFactory.fromBase((NbtCompound) wrapped).getHandle();
}
// Legacy classes
if (wrapped instanceof ChunkPosition) {
return ChunkPosition.getConverter().getGeneric(MinecraftReflection.getChunkPositionClass(), (ChunkPosition) wrapped);
return ChunkPosition.getConverter().getGeneric((ChunkPosition) wrapped);
} else if (wrapped instanceof WrappedChunkCoordinate) {
return ((WrappedChunkCoordinate) wrapped).getHandle();
}

View File

@ -38,6 +38,7 @@ public class BukkitInitialization {
try {
LogManager.getLogger();
} catch (Throwable ex) {
// Happens only on my Jenkins, but if it errors here it works when it matters
ex.printStackTrace();
}
@ -69,6 +70,7 @@ public class BukkitInitialization {
try {
LogManager.getLogger();
} catch (Throwable ex) {
// Happens only on my Jenkins, but if it errors here it works when it matters
ex.printStackTrace();
}

View File

@ -24,7 +24,7 @@ public class ChunkCoordIntPairTest {
net.minecraft.server.v1_12_R1.ChunkCoordIntPair roundtrip =
(net.minecraft.server.v1_12_R1.ChunkCoordIntPair) ChunkCoordIntPair.getConverter().
getGeneric(net.minecraft.server.v1_12_R1.ChunkCoordIntPair.class, specific);
getGeneric(specific);
assertEquals(1, roundtrip.x);
assertEquals(2, roundtrip.z);

View File

@ -55,7 +55,6 @@ public class EnumWrappersTest {
FieldAccessor accessor = Accessors.getFieldAccessor(target.getClass(), fieldName, true);
return (T) converter.getGeneric(
accessor.getField().getType(),
converter.getSpecific(accessor.get(target))
);
}

View File

@ -58,7 +58,7 @@ public class MultiBlockChangeTest {
MultiBlockChangeInfo[] array = { info, info };
EquivalentConverter<MultiBlockChangeInfo[]> converter = MultiBlockChangeInfo.getArrayConverter(chunk);
Object generic = converter.getGeneric(MinecraftReflection.getMultiBlockChangeInfoArrayClass(), array);
Object generic = converter.getGeneric(array);
MultiBlockChangeInfo[] back = converter.getSpecific(generic);
// Make sure our conversions are correct

View File

@ -43,7 +43,7 @@ public class PlayerInfoDataTest {
WrappedChatComponent displayName = WrappedChatComponent.fromText("Name's Name");
PlayerInfoData data = new PlayerInfoData(profile, 42, NativeGameMode.CREATIVE, displayName);
Object generic = PlayerInfoData.getConverter().getGeneric(MinecraftReflection.getPlayerInfoDataClass(), data);
Object generic = PlayerInfoData.getConverter().getGeneric(data);
PlayerInfoData back = PlayerInfoData.getConverter().getSpecific(generic);
assertEquals(data, back);

View File

@ -47,7 +47,7 @@ public class WrappedBlockDataTest {
assertEquals(wrapper.getType(), type);
assertEquals(wrapper.getData(), data);
Object generic = BukkitConverters.getWrappedBlockDataConverter().getGeneric(MinecraftReflection.getIBlockDataClass(), wrapper);
Object generic = BukkitConverters.getWrappedBlockDataConverter().getGeneric(wrapper);
WrappedBlockData back = BukkitConverters.getWrappedBlockDataConverter().getSpecific(generic);
assertEquals(wrapper.getType(), back.getType());

View File

@ -8,7 +8,7 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<minorVersion>4.3.1-SNAPSHOT</minorVersion>
<minorVersion>4.4.0-SNAPSHOT</minorVersion>
<spigotVersion>1.12-R0.1-SNAPSHOT</spigotVersion>
</properties>
@ -45,7 +45,7 @@
</repositories>
<dependencies>
<!-- Compile with the old version of Netty -->
<!-- Compile with the old version of Netty for backwards compat -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>