Support for MerchantRecipeList (#894)

* Added support for MerchantRecipeList found in OPEN_WINDOW_MERCHANT of MC versions 1.13+
This commit is contained in:
Tarrant 2020-07-26 18:33:05 -05:00 committed by GitHub
parent 8c51b175c4
commit 80f4c7b9a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 65 additions and 0 deletions

View File

@ -61,6 +61,7 @@ import org.bukkit.WorldType;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.MerchantRecipe;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.util.Vector;
@ -937,6 +938,17 @@ public class PacketContainer implements Serializable {
BukkitConverters.getDimensionIDConverter()
);
}
/**
* Retrieve a read/write structure for the MerchantRecipeList class.
* @return A modifier for MerchantRecipeList fields.
*/
public StructureModifier<List<MerchantRecipe>> getMerchantRecipeLists() {
return structureModifier.withType(
MinecraftReflection.getMinecraftClass("MerchantRecipeList"),
BukkitConverters.getMerchantRecipeListConverter()
);
}
/**
* Retrieve a read/write structure for ItemSlot/ItemStack pair lists in 1.16+

View File

@ -25,6 +25,7 @@ import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
@ -38,6 +39,7 @@ import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
@ -60,6 +62,7 @@ import org.bukkit.advancement.Advancement;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.MerchantRecipe;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.util.Vector;
@ -1237,4 +1240,54 @@ public class BukkitConverters {
}
});
}
private static ConstructorAccessor merchantRecipeListConstructor = null;
private static MethodAccessor bukkitMerchantRecipeToCraft = null;
private static MethodAccessor craftMerchantRecipeToNMS = null;
private static MethodAccessor nmsMerchantRecipeToBukkit = null;
/**
* Creates a converter from a MerchantRecipeList (which is just an ArrayList of MerchantRecipe wrapper)
* to a {@link List} of {@link MerchantRecipe}. Primarily for the packet OPEN_WINDOW_MERCHANT which is present
* in 1.13+.
*
* @return The MerchantRecipeList converter.
*/
public static EquivalentConverter<List<MerchantRecipe>> getMerchantRecipeListConverter() {
return ignoreNull(new EquivalentConverter<List<MerchantRecipe>>() {
@Override
public Object getGeneric(List<MerchantRecipe> specific) {
if (merchantRecipeListConstructor == null) {
Class<?> merchantRecipeListClass = MinecraftReflection.getMinecraftClass("MerchantRecipeList");
merchantRecipeListConstructor = Accessors.getConstructorAccessor(merchantRecipeListClass);
Class<?> craftMerchantRecipeClass = MinecraftReflection.getCraftBukkitClass("inventory.CraftMerchantRecipe");
FuzzyReflection reflection = FuzzyReflection.fromClass(craftMerchantRecipeClass, false);
bukkitMerchantRecipeToCraft = Accessors.getMethodAccessor(reflection.getMethodByName("fromBukkit"));
craftMerchantRecipeToNMS = Accessors.getMethodAccessor(reflection.getMethodByName("toMinecraft"));
}
return specific.stream().map(recipe -> craftMerchantRecipeToNMS.invoke(bukkitMerchantRecipeToCraft.invoke(null, recipe)))
.collect(() -> (List<Object>)merchantRecipeListConstructor.invoke(), List::add, List::addAll);
}
@Override
public List<MerchantRecipe> getSpecific(Object generic) {
if (nmsMerchantRecipeToBukkit == null) {
Class<?> merchantRecipeClass = MinecraftReflection.getMinecraftClass("MerchantRecipe");
FuzzyReflection reflection = FuzzyReflection.fromClass(merchantRecipeClass, false);
nmsMerchantRecipeToBukkit = Accessors.getMethodAccessor(reflection.getMethodByName("asBukkit"));
}
return ((List<Object>)generic).stream().map(o -> (MerchantRecipe)nmsMerchantRecipeToBukkit.invoke(o)).collect(Collectors.toList());
}
@Override
public Class<List<MerchantRecipe>> getSpecificType() {
// Damn you Java
Class<?> dummy = List.class;
return (Class<List<MerchantRecipe>>) dummy;
}
});
}
}