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

View File

@ -21,32 +21,12 @@ package com.comphenix.protocol.reflect;
* Interface that converts generic objects into types and back. * Interface that converts generic objects into types and back.
* *
* @author Kristian * @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. * Due to type erasure, we need to explicitly keep a reference to the specific 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.
* @return 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())); throw new FieldAccessException(String.format("Field index out of bounds. (Index: %s, Size: %s)", fieldIndex, data.size()));
// Use the converter, if it exists // Use the converter, if it exists
Object obj = needConversion() ? converter.getGeneric(getFieldType(fieldIndex), value) : value; Object obj = needConversion() ? converter.getGeneric(value) : value;
try { try {
FieldUtils.writeField(data.get(fieldIndex), target, obj, true); 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()); return MinecraftReflection.getMinecraftItemStack(MinecraftReflection.getBukkitItemStack(source).clone());
case 1: case 1:
EquivalentConverter<WrappedDataWatcher> dataConverter = BukkitConverters.getDataWatcherConverter(); EquivalentConverter<WrappedDataWatcher> dataConverter = BukkitConverters.getDataWatcherConverter();
return dataConverter.getGeneric(clonableClasses.get(1), dataConverter.getSpecific(source).deepClone()); return dataConverter.getGeneric(dataConverter.getSpecific(source).deepClone());
case 2: case 2:
EquivalentConverter<BlockPosition> blockConverter = BlockPosition.getConverter(); EquivalentConverter<BlockPosition> blockConverter = BlockPosition.getConverter();
return blockConverter.getGeneric(clonableClasses.get(2), blockConverter.getSpecific(source)); return blockConverter.getGeneric(blockConverter.getSpecific(source));
case 3: case 3:
EquivalentConverter<ChunkPosition> chunkConverter = ChunkPosition.getConverter(); EquivalentConverter<ChunkPosition> chunkConverter = ChunkPosition.getConverter();
return chunkConverter.getGeneric(clonableClasses.get(3), chunkConverter.getSpecific(source)); return chunkConverter.getGeneric(chunkConverter.getSpecific(source));
case 4: case 4:
EquivalentConverter<WrappedServerPing> serverConverter = BukkitConverters.getWrappedServerPingConverter(); EquivalentConverter<WrappedServerPing> serverConverter = BukkitConverters.getWrappedServerPingConverter();
return serverConverter.getGeneric(clonableClasses.get(4), serverConverter.getSpecific(source).deepClone()); return serverConverter.getGeneric(serverConverter.getSpecific(source).deepClone());
case 5: case 5:
return source; return source;
case 6: case 6:
EquivalentConverter<MinecraftKey> keyConverter = MinecraftKey.getConverter(); EquivalentConverter<MinecraftKey> keyConverter = MinecraftKey.getConverter();
return keyConverter.getGeneric(clonableClasses.get(6), keyConverter.getSpecific(source)); return keyConverter.getGeneric(keyConverter.getSpecific(source));
case 7: case 7:
EquivalentConverter<WrappedBlockData> blockDataConverter = BukkitConverters.getWrappedBlockDataConverter(); EquivalentConverter<WrappedBlockData> blockDataConverter = BukkitConverters.getWrappedBlockDataConverter();
return blockDataConverter.getGeneric(clonableClasses.get(7), blockDataConverter.getSpecific(source).deepClone()); return blockDataConverter.getGeneric(blockDataConverter.getSpecific(source).deepClone());
case 8: case 8:
return nonNullListCloner().clone(source); return nonNullListCloner().clone(source);
default: default:

View File

@ -110,7 +110,7 @@ public abstract class CompiledStructureModifier extends StructureModifier<Object
@Override @Override
public StructureModifier<Object> write(int index, Object value) throws FieldAccessException { public StructureModifier<Object> write(int index, Object value) throws FieldAccessException {
if (converter != null) if (converter != null)
value = converter.getGeneric(getFieldType(index), value); value = converter.getGeneric(value);
return writeGenerated(index, 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() { public static EquivalentConverter<BlockPosition> getConverter() {
return new EquivalentConverter<BlockPosition>() { return new EquivalentConverter<BlockPosition>() {
@Override @Override
public Object getGeneric(Class<?> genericType, BlockPosition specific) { public Object getGeneric(BlockPosition specific) {
if (blockPositionConstructor == null) { if (blockPositionConstructor == null) {
try { try {
blockPositionConstructor = MinecraftReflection.getBlockPositionClass(). blockPositionConstructor = MinecraftReflection.getBlockPositionClass().
@ -187,7 +187,7 @@ public class BlockPosition {
public BlockPosition getSpecific(Object generic) { public BlockPosition getSpecific(Object generic) {
if (MinecraftReflection.isBlockPosition(generic)) { if (MinecraftReflection.isBlockPosition(generic)) {
// Use a structure modifier // 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 // Damn it all
if (intModifier.size() < 3) { if (intModifier.size() < 3) {

View File

@ -67,7 +67,7 @@ public class ChunkCoordIntPair {
public static EquivalentConverter<ChunkCoordIntPair> getConverter() { public static EquivalentConverter<ChunkCoordIntPair> getConverter() {
return new EquivalentConverter<ChunkCoordIntPair>() { return new EquivalentConverter<ChunkCoordIntPair>() {
@Override @Override
public Object getGeneric(Class<?> genericType, ChunkCoordIntPair specific) { public Object getGeneric(ChunkCoordIntPair specific) {
if (COORD_CONSTRUCTOR == null) { if (COORD_CONSTRUCTOR == null) {
COORD_CONSTRUCTOR = Accessors.getConstructorAccessor(COORD_PAIR_CLASS, int.class, int.class); 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() { public static EquivalentConverter<ChunkPosition> getConverter() {
return new EquivalentConverter<ChunkPosition>() { return new EquivalentConverter<ChunkPosition>() {
@Override @Override
public Object getGeneric(Class<?> genericType, ChunkPosition specific) { public Object getGeneric(ChunkPosition specific) {
if (chunkPositionConstructor == null) { if (chunkPositionConstructor == null) {
try { try {
chunkPositionConstructor = MinecraftReflection.getChunkPositionClass(). chunkPositionConstructor = MinecraftReflection.getChunkPositionClass().
@ -177,7 +177,7 @@ public class ChunkPosition {
public ChunkPosition getSpecific(Object generic) { public ChunkPosition getSpecific(Object generic) {
if (MinecraftReflection.isChunkPosition(generic)) { if (MinecraftReflection.isChunkPosition(generic)) {
// Use a structure modifier // 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 // Damn it all
if (intModifier.size() < 3) { 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.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.function.Function;
import org.bukkit.GameMode; import org.bukkit.GameMode;
@ -562,117 +563,119 @@ public abstract class EnumWrappers {
// Get the converters // Get the converters
public static EquivalentConverter<Protocol> getProtocolConverter() { public static EquivalentConverter<Protocol> getProtocolConverter() {
return new EnumConverter<Protocol>(Protocol.class); return new EnumConverter<>(getProtocolClass(), Protocol.class);
} }
public static EquivalentConverter<ClientCommand> getClientCommandConverter() { public static EquivalentConverter<ClientCommand> getClientCommandConverter() {
return new EnumConverter<ClientCommand>(ClientCommand.class); return new EnumConverter<>(getClientCommandClass(), ClientCommand.class);
} }
public static EquivalentConverter<ChatVisibility> getChatVisibilityConverter() { public static EquivalentConverter<ChatVisibility> getChatVisibilityConverter() {
return new EnumConverter<ChatVisibility>(ChatVisibility.class); return new EnumConverter<>(getChatVisibilityClass(), ChatVisibility.class);
} }
public static EquivalentConverter<Difficulty> getDifficultyConverter() { public static EquivalentConverter<Difficulty> getDifficultyConverter() {
return new EnumConverter<Difficulty>(Difficulty.class); return new EnumConverter<>(getDifficultyClass(), Difficulty.class);
} }
public static EquivalentConverter<EntityUseAction> getEntityUseActionConverter() { public static EquivalentConverter<EntityUseAction> getEntityUseActionConverter() {
return new EnumConverter<EntityUseAction>(EntityUseAction.class); return new EnumConverter<>(getEntityUseActionClass(), EntityUseAction.class);
} }
public static EquivalentConverter<NativeGameMode> getGameModeConverter() { public static EquivalentConverter<NativeGameMode> getGameModeConverter() {
return new EnumConverter<NativeGameMode>(NativeGameMode.class); return new EnumConverter<>(getGameModeClass(), NativeGameMode.class);
} }
public static EquivalentConverter<ResourcePackStatus> getResourcePackStatusConverter() { public static EquivalentConverter<ResourcePackStatus> getResourcePackStatusConverter() {
return new EnumConverter<ResourcePackStatus>(ResourcePackStatus.class); return new EnumConverter<>(getResourcePackStatusClass(), ResourcePackStatus.class);
} }
public static EquivalentConverter<PlayerInfoAction> getPlayerInfoActionConverter() { public static EquivalentConverter<PlayerInfoAction> getPlayerInfoActionConverter() {
return new EnumConverter<PlayerInfoAction>(PlayerInfoAction.class); return new EnumConverter<>(getPlayerInfoActionClass(), PlayerInfoAction.class);
} }
public static EquivalentConverter<TitleAction> getTitleActionConverter() { public static EquivalentConverter<TitleAction> getTitleActionConverter() {
return new EnumConverter<TitleAction>(TitleAction.class); return new EnumConverter<>(getTitleActionClass(), TitleAction.class);
} }
public static EquivalentConverter<WorldBorderAction> getWorldBorderActionConverter() { public static EquivalentConverter<WorldBorderAction> getWorldBorderActionConverter() {
return new EnumConverter<WorldBorderAction>(WorldBorderAction.class); return new EnumConverter<>(getWorldBorderActionClass(), WorldBorderAction.class);
} }
public static EquivalentConverter<CombatEventType> getCombatEventTypeConverter() { public static EquivalentConverter<CombatEventType> getCombatEventTypeConverter() {
return new EnumConverter<CombatEventType>(CombatEventType.class); return new EnumConverter<>(getCombatEventTypeClass(), CombatEventType.class);
} }
public static EquivalentConverter<PlayerDigType> getPlayerDiggingActionConverter() { public static EquivalentConverter<PlayerDigType> getPlayerDiggingActionConverter() {
return new EnumConverter<PlayerDigType>(PlayerDigType.class); return new EnumConverter<>(getPlayerDigTypeClass(), PlayerDigType.class);
} }
public static EquivalentConverter<PlayerAction> getEntityActionConverter() { public static EquivalentConverter<PlayerAction> getEntityActionConverter() {
return new EnumConverter<PlayerAction>(PlayerAction.class); return new EnumConverter<>(getPlayerActionClass(), PlayerAction.class);
} }
public static EquivalentConverter<ScoreboardAction> getUpdateScoreActionConverter() { public static EquivalentConverter<ScoreboardAction> getUpdateScoreActionConverter() {
return new EnumConverter<ScoreboardAction>(ScoreboardAction.class); return new EnumConverter<>(getScoreboardActionClass(), ScoreboardAction.class);
} }
public static EquivalentConverter<Particle> getParticleConverter() { public static EquivalentConverter<Particle> getParticleConverter() {
return new EnumConverter<Particle>(Particle.class); return new EnumConverter<>(getParticleClass(), Particle.class);
} }
public static EquivalentConverter<SoundCategory> getSoundCategoryConverter() { public static EquivalentConverter<SoundCategory> getSoundCategoryConverter() {
return new EnumConverter<SoundCategory>(SoundCategory.class); return new EnumConverter<>(getSoundCategoryClass(), SoundCategory.class);
} }
public static EquivalentConverter<ItemSlot> getItemSlotConverter() { public static EquivalentConverter<ItemSlot> getItemSlotConverter() {
return new EnumConverter<ItemSlot>(ItemSlot.class); return new EnumConverter<>(getItemSlotClass(), ItemSlot.class);
} }
public static EquivalentConverter<Hand> getHandConverter() { public static EquivalentConverter<Hand> getHandConverter() {
return new EnumConverter<Hand>(Hand.class); return new EnumConverter<>(getHandClass(), Hand.class);
} }
public static EquivalentConverter<Direction> getDirectionConverter() { public static EquivalentConverter<Direction> getDirectionConverter() {
return new EnumConverter<Direction>(Direction.class); return new EnumConverter<>(getDirectionClass(), Direction.class);
} }
public static EquivalentConverter<ChatType> getChatTypeConverter() { 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. * 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 * @return A generic enum converter
*/ */
public static <T extends Enum<T>> EquivalentConverter<T> getGenericConverter(Class<T> enumClass) { public static <T extends Enum<T>> EquivalentConverter<T> getGenericConverter(Class<?> genericClass, Class<T> specificType) {
return new EnumConverter<T>(enumClass); return new EnumConverter<>(genericClass, specificType);
} }
// The common enum converter // The common enum converter
@SuppressWarnings({ "rawtypes", "unchecked" }) @SuppressWarnings({ "rawtypes", "unchecked" })
public static class EnumConverter<T extends Enum<T>> implements EquivalentConverter<T> { public static class EnumConverter<T extends Enum<T>> implements EquivalentConverter<T> {
private Class<?> genericType;
private Class<T> specificType; private Class<T> specificType;
public EnumConverter(Class<T> specificType) { public EnumConverter(Class<?> genericType, Class<T> specificType) {
this.genericType = genericType;
this.specificType = specificType; this.specificType = specificType;
} }
@Override @Override
public T getSpecific(Object generic) { public T getSpecific(Object generic) {
// We know its an enum already!
return Enum.valueOf(specificType, ((Enum) generic).name()); return Enum.valueOf(specificType, ((Enum) generic).name());
} }
@Override @Override
public Object getGeneric(Class<?> genericType, T specific) { public Object getGeneric(T specific) {
return Enum.valueOf((Class) genericType, specific.name()); return Enum.valueOf((Class) genericType, specific.name());
} }
@Override @Override
public Class<T> getSpecificType() { public Class<T> getSpecificType() {
return specificType; return null;
} }
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -280,7 +280,7 @@ public class WrappedServerPing extends AbstractWrapper {
public void setPlayers(Iterable<? extends WrappedGameProfile> profile) { public void setPlayers(Iterable<? extends WrappedGameProfile> profile) {
if (players == null) if (players == null)
resetPlayers(); 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) { if (wrapped instanceof WrappedChatComponent) {
return ((WrappedChatComponent) wrapped).getHandle(); return ((WrappedChatComponent) wrapped).getHandle();
} else if (wrapped instanceof ItemStack) { } else if (wrapped instanceof ItemStack) {
return BukkitConverters.getItemStackConverter().getGeneric(MinecraftReflection.getItemStackClass(), (ItemStack) wrapped); return BukkitConverters.getItemStackConverter().getGeneric((ItemStack) wrapped);
} else if (wrapped instanceof WrappedBlockData) { } else if (wrapped instanceof WrappedBlockData) {
return BukkitConverters.getWrappedBlockDataConverter().getGeneric(MinecraftReflection.getIBlockDataClass(), (WrappedBlockData) wrapped); return BukkitConverters.getWrappedBlockDataConverter().getGeneric((WrappedBlockData) wrapped);
} else if (wrapped instanceof Vector3F) { } else if (wrapped instanceof Vector3F) {
return Vector3F.getConverter().getGeneric(Vector3F.getMinecraftClass(), (Vector3F) wrapped); return Vector3F.getConverter().getGeneric((Vector3F) wrapped);
} else if (wrapped instanceof BlockPosition) { } else if (wrapped instanceof BlockPosition) {
return BlockPosition.getConverter().getGeneric(MinecraftReflection.getBlockPositionClass(), (BlockPosition) wrapped); return BlockPosition.getConverter().getGeneric((BlockPosition) wrapped);
} else if (wrapped instanceof Direction) { } else if (wrapped instanceof Direction) {
return EnumWrappers.getDirectionConverter().getGeneric(EnumWrappers.getDirectionClass(), (Direction) wrapped); return EnumWrappers.getDirectionConverter().getGeneric((Direction) wrapped);
} else if (wrapped instanceof NbtCompound) { } else if (wrapped instanceof NbtCompound) {
return NbtFactory.fromBase((NbtCompound) wrapped).getHandle(); return NbtFactory.fromBase((NbtCompound) wrapped).getHandle();
} }
// Legacy classes // Legacy classes
if (wrapped instanceof ChunkPosition) { if (wrapped instanceof ChunkPosition) {
return ChunkPosition.getConverter().getGeneric(MinecraftReflection.getChunkPositionClass(), (ChunkPosition) wrapped); return ChunkPosition.getConverter().getGeneric((ChunkPosition) wrapped);
} else if (wrapped instanceof WrappedChunkCoordinate) { } else if (wrapped instanceof WrappedChunkCoordinate) {
return ((WrappedChunkCoordinate) wrapped).getHandle(); return ((WrappedChunkCoordinate) wrapped).getHandle();
} }

View File

@ -38,6 +38,7 @@ public class BukkitInitialization {
try { try {
LogManager.getLogger(); LogManager.getLogger();
} catch (Throwable ex) { } catch (Throwable ex) {
// Happens only on my Jenkins, but if it errors here it works when it matters
ex.printStackTrace(); ex.printStackTrace();
} }
@ -69,6 +70,7 @@ public class BukkitInitialization {
try { try {
LogManager.getLogger(); LogManager.getLogger();
} catch (Throwable ex) { } catch (Throwable ex) {
// Happens only on my Jenkins, but if it errors here it works when it matters
ex.printStackTrace(); 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 roundtrip =
(net.minecraft.server.v1_12_R1.ChunkCoordIntPair) ChunkCoordIntPair.getConverter(). (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(1, roundtrip.x);
assertEquals(2, roundtrip.z); assertEquals(2, roundtrip.z);

View File

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

View File

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

View File

@ -43,7 +43,7 @@ public class PlayerInfoDataTest {
WrappedChatComponent displayName = WrappedChatComponent.fromText("Name's Name"); WrappedChatComponent displayName = WrappedChatComponent.fromText("Name's Name");
PlayerInfoData data = new PlayerInfoData(profile, 42, NativeGameMode.CREATIVE, displayName); 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); PlayerInfoData back = PlayerInfoData.getConverter().getSpecific(generic);
assertEquals(data, back); assertEquals(data, back);

View File

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

View File

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