mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-30 12:29:15 +00:00
重构特殊配方
This commit is contained in:
@@ -468,7 +468,7 @@ public class ItemEventListener implements Listener {
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
||||
public void onEntityDamage(EntityDamageEvent event) {
|
||||
if (event.getEntity() instanceof org.bukkit.entity.Item item) {
|
||||
Optional.ofNullable(this.plugin.itemManager().wrap(item.getItemStack()))
|
||||
Optional.of(this.plugin.itemManager().wrap(item.getItemStack()))
|
||||
.flatMap(Item::getCustomItem)
|
||||
.ifPresent(it -> {
|
||||
if (it.settings().invulnerable().contains(DamageCauseUtils.fromBukkit(event.getCause()))) {
|
||||
|
||||
@@ -88,9 +88,15 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
|
||||
try {
|
||||
Key dyeRecipeId = Key.from("armor_dye");
|
||||
MINECRAFT_RECIPE_REMOVER.accept(dyeRecipeId);
|
||||
MINECRAFT_RECIPE_ADDER.accept(dyeRecipeId, RecipeInjector.createCustomDyeRecipe());
|
||||
MINECRAFT_RECIPE_ADDER.accept(dyeRecipeId, RecipeInjector.createCustomDyeRecipe(dyeRecipeId));
|
||||
Key repairRecipeId = Key.from("repair_item");
|
||||
MINECRAFT_RECIPE_REMOVER.accept(repairRecipeId);
|
||||
MINECRAFT_RECIPE_ADDER.accept(repairRecipeId, RecipeInjector.createRepairItemRecipe(repairRecipeId));
|
||||
Key fireworkStarFadeRecipeId = Key.from("firework_star_fade");
|
||||
MINECRAFT_RECIPE_REMOVER.accept(fireworkStarFadeRecipeId);
|
||||
MINECRAFT_RECIPE_ADDER.accept(fireworkStarFadeRecipeId, RecipeInjector.createFireworkStarFadeRecipe(fireworkStarFadeRecipeId));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new ReflectionInitException("Failed to inject dye recipes", e);
|
||||
throw new ReflectionInitException("Failed to inject special recipes", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -481,7 +481,7 @@ public class RecipeEventListener implements Listener {
|
||||
|
||||
// 如果禁止在铁砧使用两个相同物品修复
|
||||
firstCustom.ifPresent(it -> {
|
||||
if (!it.settings().canRepair()) {
|
||||
if (it.settings().canRepair() == Tristate.FALSE) {
|
||||
event.setResult(null);
|
||||
}
|
||||
});
|
||||
@@ -522,7 +522,7 @@ public class RecipeEventListener implements Listener {
|
||||
Key firstId = wrappedFirst.id();
|
||||
Optional<CustomItem<ItemStack>> optionalCustomTool = wrappedFirst.getCustomItem();
|
||||
// 物品无法被修复
|
||||
if (optionalCustomTool.isPresent() && !optionalCustomTool.get().settings().canRepair()) {
|
||||
if (optionalCustomTool.isPresent() && optionalCustomTool.get().settings().canRepair() == Tristate.FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -679,93 +679,52 @@ public class RecipeEventListener implements Listener {
|
||||
}
|
||||
|
||||
// only handle repair items for the moment
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
||||
public void onSpecialRecipe(PrepareItemCraftEvent event) {
|
||||
// if (!ConfigManager.enableRecipeSystem()) return;
|
||||
org.bukkit.inventory.Recipe recipe = event.getRecipe();
|
||||
if (recipe == null)
|
||||
return;
|
||||
if (!(recipe instanceof ComplexRecipe complexRecipe))
|
||||
return;
|
||||
CraftingInventory inventory = event.getInventory();
|
||||
ItemStack result = inventory.getResult();
|
||||
if (ItemStackUtils.isEmpty(result))
|
||||
return;
|
||||
boolean hasCustomItem = ItemStackUtils.hasCustomItem(inventory.getMatrix());
|
||||
if (!hasCustomItem) {
|
||||
if (!hasCustomItem)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CraftBukkitReflections.clazz$CraftComplexRecipe.isInstance(complexRecipe)) {
|
||||
inventory.setResult(null);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// TODO 全部改注入
|
||||
Object mcRecipe = CraftBukkitReflections.field$CraftComplexRecipe$recipe.get(complexRecipe);
|
||||
if (CoreReflections.clazz$ArmorDyeRecipe.isInstance(mcRecipe)) {
|
||||
if (CoreReflections.clazz$ArmorDyeRecipe.isInstance(mcRecipe) || CoreReflections.clazz$FireworkStarFadeRecipe.isInstance(mcRecipe)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Repair recipe
|
||||
// 处理修复配方,在此处理才能使用玩家参数构建物品
|
||||
if (CoreReflections.clazz$RepairItemRecipe.isInstance(mcRecipe)) {
|
||||
// repair item
|
||||
ItemStack[] itemStacks = inventory.getMatrix();
|
||||
Pair<ItemStack, ItemStack> onlyTwoItems = getTheOnlyTwoItem(itemStacks);
|
||||
if (onlyTwoItems.left() == null || onlyTwoItems.right() == null) {
|
||||
inventory.setResult(null);
|
||||
return;
|
||||
}
|
||||
|
||||
Item<ItemStack> left = plugin.itemManager().wrap(onlyTwoItems.left());
|
||||
Item<ItemStack> right = plugin.itemManager().wrap(onlyTwoItems.right());
|
||||
if (!left.id().equals(right.id())) {
|
||||
inventory.setResult(null);
|
||||
return;
|
||||
}
|
||||
|
||||
int totalDamage = right.damage().orElse(0) + left.damage().orElse(0);
|
||||
int totalMaxDamage = left.maxDamage() + right.maxDamage();
|
||||
// should be impossible, but take care
|
||||
if (totalDamage >= totalMaxDamage) {
|
||||
inventory.setResult(null);
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = InventoryUtils.getPlayerFromInventoryEvent(event);
|
||||
|
||||
Optional<CustomItem<ItemStack>> customItemOptional = plugin.itemManager().getCustomItem(left.id());
|
||||
Pair<ItemStack, ItemStack> theOnlyTwoItem = getTheOnlyTwoItem(inventory.getMatrix());
|
||||
if (theOnlyTwoItem == null) return;
|
||||
Item<ItemStack> first = BukkitItemManager.instance().wrap(theOnlyTwoItem.left());
|
||||
Item<ItemStack> right = BukkitItemManager.instance().wrap(theOnlyTwoItem.right());
|
||||
int max = Math.max(first.maxDamage(), right.maxDamage());
|
||||
int durability1 = first.maxDamage() - first.damage().orElse(0);
|
||||
int durability2 = right.maxDamage() - right.damage().orElse(0);
|
||||
int finalDurability = durability1 + durability2 + max * 5 / 100;
|
||||
Optional<CustomItem<ItemStack>> customItemOptional = plugin.itemManager().getCustomItem(first.id());
|
||||
if (customItemOptional.isEmpty()) {
|
||||
inventory.setResult(null);
|
||||
return;
|
||||
}
|
||||
|
||||
CustomItem<ItemStack> customItem = customItemOptional.get();
|
||||
if (!customItem.settings().canRepair()) {
|
||||
inventory.setResult(null);
|
||||
return;
|
||||
}
|
||||
|
||||
Item<ItemStack> newItem = customItem.buildItem(ItemBuildContext.of(plugin.adapt(player)));
|
||||
int remainingDurability = totalMaxDamage - totalDamage;
|
||||
int newItemDamage = Math.max(0, newItem.maxDamage() - remainingDurability);
|
||||
newItem.damage(newItemDamage);
|
||||
Player player = InventoryUtils.getPlayerFromInventoryEvent(event);
|
||||
Item<ItemStack> newItem = customItemOptional.get().buildItem(plugin.adapt(player));
|
||||
newItem.maxDamage(max);
|
||||
newItem.damage(Math.max(max - finalDurability, 0));
|
||||
inventory.setResult(newItem.getItem());
|
||||
} else if (CoreReflections.clazz$FireworkStarFadeRecipe.isInstance(mcRecipe)) {
|
||||
ItemStack[] itemStacks = inventory.getMatrix();
|
||||
for (ItemStack itemStack : itemStacks) {
|
||||
if (itemStack == null) continue;
|
||||
Item<ItemStack> item = plugin.itemManager().wrap(itemStack);
|
||||
Optional<CustomItem<ItemStack>> optionalCustomItem = item.getCustomItem();
|
||||
if (optionalCustomItem.isPresent() && optionalCustomItem.get().settings().dyeable() == Tristate.FALSE) {
|
||||
inventory.setResult(null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
inventory.setResult(null);
|
||||
return;
|
||||
}
|
||||
// 其他配方不允许使用自定义物品
|
||||
inventory.setResult(null);
|
||||
} catch (Exception e) {
|
||||
this.plugin.logger().warn("Failed to handle minecraft custom recipe", e);
|
||||
this.plugin.logger().warn("Failed to handle custom recipe", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -776,7 +735,10 @@ public class RecipeEventListener implements Listener {
|
||||
if (itemStack == null) continue;
|
||||
if (first == null) {
|
||||
first = itemStack;
|
||||
} else if (second == null) {
|
||||
} else {
|
||||
if (second != null) {
|
||||
return null;
|
||||
}
|
||||
second = itemStack;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package net.momirealms.craftengine.bukkit.plugin.injector;
|
||||
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import net.bytebuddy.ByteBuddy;
|
||||
import net.bytebuddy.ClassFileVersion;
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.description.modifier.Visibility;
|
||||
import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy;
|
||||
import net.bytebuddy.implementation.FieldAccessor;
|
||||
@@ -10,8 +13,10 @@ import net.bytebuddy.implementation.MethodDelegation;
|
||||
import net.bytebuddy.implementation.bind.annotation.AllArguments;
|
||||
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
|
||||
import net.bytebuddy.implementation.bind.annotation.This;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
import net.bytebuddy.matcher.ElementMatchers;
|
||||
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
|
||||
import net.momirealms.craftengine.bukkit.item.ComponentTypes;
|
||||
import net.momirealms.craftengine.bukkit.item.recipe.BukkitRecipeManager;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
@@ -21,12 +26,15 @@ import net.momirealms.craftengine.bukkit.util.ItemTags;
|
||||
import net.momirealms.craftengine.bukkit.util.KeyUtils;
|
||||
import net.momirealms.craftengine.core.item.CustomItem;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.item.ItemKeys;
|
||||
import net.momirealms.craftengine.core.item.data.FireworkExplosion;
|
||||
import net.momirealms.craftengine.core.item.recipe.CustomCookingRecipe;
|
||||
import net.momirealms.craftengine.core.item.recipe.RecipeTypes;
|
||||
import net.momirealms.craftengine.core.item.recipe.UniqueIdItem;
|
||||
import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput;
|
||||
import net.momirealms.craftengine.core.util.*;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
@@ -40,6 +48,8 @@ import java.util.function.Predicate;
|
||||
public class RecipeInjector {
|
||||
private static Class<?> clazz$InjectedCacheChecker;
|
||||
private static Class<?> clazz$InjectedArmorDyeRecipe;
|
||||
private static Class<?> clazz$InjectedRepairItemRecipe;
|
||||
private static Class<?> clazz$InjectedFireworkStarFadeRecipe;
|
||||
|
||||
public static void init() {
|
||||
ByteBuddy byteBuddy = new ByteBuddy(ClassFileVersion.JAVA_V17);
|
||||
@@ -48,64 +58,96 @@ public class RecipeInjector {
|
||||
.name("net.momirealms.craftengine.bukkit.entity.InjectedCacheChecker")
|
||||
.implement(CoreReflections.clazz$RecipeManager$CachedCheck)
|
||||
.implement(InjectedCacheCheck.class)
|
||||
|
||||
.defineField("recipeType", Object.class, Visibility.PUBLIC)
|
||||
.method(ElementMatchers.named("recipeType"))
|
||||
.intercept(FieldAccessor.ofField("recipeType"))
|
||||
|
||||
.defineField("customRecipeType", Key.class, Visibility.PUBLIC)
|
||||
.method(ElementMatchers.named("customRecipeType"))
|
||||
.intercept(FieldAccessor.ofField("customRecipeType"))
|
||||
|
||||
.defineField("lastRecipe", Object.class, Visibility.PUBLIC)
|
||||
.method(ElementMatchers.named("lastRecipe"))
|
||||
.intercept(FieldAccessor.ofField("lastRecipe"))
|
||||
|
||||
.defineField("lastCustomRecipe", Key.class, Visibility.PUBLIC)
|
||||
.method(ElementMatchers.named("lastCustomRecipe"))
|
||||
.intercept(FieldAccessor.ofField("lastCustomRecipe"))
|
||||
|
||||
.method(ElementMatchers.named("getRecipeFor").or(ElementMatchers.named("a")))
|
||||
.intercept(MethodDelegation.to(
|
||||
VersionHelper.isOrAbove1_21_2() ?
|
||||
GetRecipeForMethodInterceptor1_21_2.INSTANCE :
|
||||
(VersionHelper.isOrAbove1_21() ?
|
||||
GetRecipeForMethodInterceptor1_21.INSTANCE :
|
||||
VersionHelper.isOrAbove1_20_5() ?
|
||||
GetRecipeForMethodInterceptor1_20_5.INSTANCE :
|
||||
GetRecipeForMethodInterceptor1_20.INSTANCE)
|
||||
GetRecipeForMethodInterceptor1_21_2.INSTANCE :
|
||||
(VersionHelper.isOrAbove1_21() ?
|
||||
GetRecipeForMethodInterceptor1_21.INSTANCE :
|
||||
VersionHelper.isOrAbove1_20_5() ?
|
||||
GetRecipeForMethodInterceptor1_20_5.INSTANCE :
|
||||
GetRecipeForMethodInterceptor1_20.INSTANCE)
|
||||
))
|
||||
.make()
|
||||
.load(RecipeInjector.class.getClassLoader())
|
||||
.getLoaded();
|
||||
ElementMatcher.Junction<MethodDescription> matches = (VersionHelper.isOrAbove1_21() ?
|
||||
ElementMatchers.takesArguments(CoreReflections.clazz$CraftingInput, CoreReflections.clazz$Level) :
|
||||
ElementMatchers.takesArguments(CoreReflections.clazz$CraftingContainer, CoreReflections.clazz$Level)
|
||||
).and(ElementMatchers.returns(boolean.class));
|
||||
ElementMatcher.Junction<MethodDescription> assemble = (
|
||||
VersionHelper.isOrAbove1_21() ?
|
||||
ElementMatchers.takesArguments(CoreReflections.clazz$CraftingInput, CoreReflections.clazz$HolderLookup$Provider) :
|
||||
VersionHelper.isOrAbove1_20_5() ?
|
||||
ElementMatchers.takesArguments(CoreReflections.clazz$CraftingContainer, CoreReflections.clazz$HolderLookup$Provider) :
|
||||
ElementMatchers.takesArguments(CoreReflections.clazz$CraftingContainer, CoreReflections.clazz$RegistryAccess)
|
||||
).and(ElementMatchers.returns(CoreReflections.clazz$ItemStack));
|
||||
|
||||
clazz$InjectedArmorDyeRecipe = byteBuddy
|
||||
.subclass(CoreReflections.clazz$ArmorDyeRecipe, ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING)
|
||||
.name("net.momirealms.craftengine.bukkit.item.recipe.ArmorDyeRecipe")
|
||||
.method((VersionHelper.isOrAbove1_21() ?
|
||||
ElementMatchers.takesArguments(CoreReflections.clazz$CraftingInput, CoreReflections.clazz$Level) :
|
||||
ElementMatchers.takesArguments(CoreReflections.clazz$CraftingContainer, CoreReflections.clazz$Level)
|
||||
).and(ElementMatchers.returns(boolean.class)))
|
||||
.intercept(MethodDelegation.to(MatchesInterceptor.INSTANCE))
|
||||
.method((
|
||||
VersionHelper.isOrAbove1_21() ?
|
||||
ElementMatchers.takesArguments(CoreReflections.clazz$CraftingInput, CoreReflections.clazz$HolderLookup$Provider) :
|
||||
VersionHelper.isOrAbove1_20_5() ?
|
||||
ElementMatchers.takesArguments(CoreReflections.clazz$CraftingContainer, CoreReflections.clazz$HolderLookup$Provider) :
|
||||
ElementMatchers.takesArguments(CoreReflections.clazz$CraftingContainer, CoreReflections.clazz$RegistryAccess)
|
||||
).and(ElementMatchers.returns(CoreReflections.clazz$ItemStack)))
|
||||
.intercept(MethodDelegation.to(AssembleInterceptor.INSTANCE))
|
||||
.method(matches)
|
||||
.intercept(MethodDelegation.to(DyeMatchesInterceptor.INSTANCE))
|
||||
.method(assemble)
|
||||
.intercept(MethodDelegation.to(DyeAssembleInterceptor.INSTANCE))
|
||||
.make()
|
||||
.load(RecipeInjector.class.getClassLoader())
|
||||
.getLoaded();
|
||||
|
||||
clazz$InjectedFireworkStarFadeRecipe = byteBuddy
|
||||
.subclass(CoreReflections.clazz$FireworkStarFadeRecipe)
|
||||
.name("net.momirealms.craftengine.bukkit.item.recipe.FireworkStarFadeRecipe")
|
||||
.method(matches)
|
||||
.intercept(MethodDelegation.to(FireworkStarFadeMatchesInterceptor.INSTANCE))
|
||||
.method(assemble)
|
||||
.intercept(MethodDelegation.to(FireworkStarFadeAssembleInterceptor.INSTANCE))
|
||||
.make()
|
||||
.load(RecipeInjector.class.getClassLoader())
|
||||
.getLoaded();
|
||||
|
||||
clazz$InjectedRepairItemRecipe = byteBuddy
|
||||
.subclass(CoreReflections.clazz$RepairItemRecipe, ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING)
|
||||
.name("net.momirealms.craftengine.bukkit.item.recipe.RepairItemRecipe")
|
||||
// 只修改match逻辑,合并需要在事件里处理,否则无法应用变量
|
||||
.method(matches)
|
||||
.intercept(MethodDelegation.to(RepairMatchesInterceptor.INSTANCE))
|
||||
.make()
|
||||
.load(RecipeInjector.class.getClassLoader())
|
||||
.getLoaded();
|
||||
}
|
||||
|
||||
public static Object createCustomDyeRecipe() throws ReflectiveOperationException {
|
||||
public static Object createRepairItemRecipe(Key id) throws ReflectiveOperationException {
|
||||
return createSpecialRecipe(id, clazz$InjectedRepairItemRecipe);
|
||||
}
|
||||
|
||||
public static Object createCustomDyeRecipe(Key id) throws ReflectiveOperationException {
|
||||
return createSpecialRecipe(id, clazz$InjectedArmorDyeRecipe);
|
||||
}
|
||||
|
||||
public static Object createFireworkStarFadeRecipe(Key id) throws ReflectiveOperationException {
|
||||
return createSpecialRecipe(id, clazz$InjectedFireworkStarFadeRecipe);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Object createSpecialRecipe(Key id, Class<?> clazz$InjectedRepairItemRecipe) throws InstantiationException, IllegalAccessException, java.lang.reflect.InvocationTargetException {
|
||||
if (VersionHelper.isOrAbove1_20_2()) {
|
||||
Constructor<?> constructor = ReflectionUtils.getConstructor(clazz$InjectedArmorDyeRecipe, CoreReflections.clazz$CraftingBookCategory);
|
||||
Constructor<?> constructor = ReflectionUtils.getConstructor(clazz$InjectedRepairItemRecipe, CoreReflections.clazz$CraftingBookCategory);
|
||||
return constructor.newInstance(CoreReflections.instance$CraftingBookCategory$MISC);
|
||||
} else {
|
||||
Constructor<?> constructor = ReflectionUtils.getConstructor(clazz$InjectedArmorDyeRecipe, CoreReflections.clazz$ResourceLocation, CoreReflections.clazz$CraftingBookCategory);
|
||||
return constructor.newInstance(KeyUtils.toResourceLocation(Key.of("armor_dye")), CoreReflections.instance$CraftingBookCategory$MISC);
|
||||
Constructor<?> constructor = ReflectionUtils.getConstructor(clazz$InjectedRepairItemRecipe, CoreReflections.clazz$ResourceLocation, CoreReflections.clazz$CraftingBookCategory);
|
||||
return constructor.newInstance(KeyUtils.toResourceLocation(id), CoreReflections.instance$CraftingBookCategory$MISC);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,29 +180,161 @@ public class RecipeInjector {
|
||||
}
|
||||
}
|
||||
|
||||
private static final Function<Object, Boolean> INGREDIENT_COUNT_CHECKER =
|
||||
private static final Function<Object, Integer> INGREDIENT_SIZE_GETTER =
|
||||
VersionHelper.isOrAbove1_21() ?
|
||||
(input) -> FastNMS.INSTANCE.method$CraftingInput$ingredientCount(input) < 2 :
|
||||
(container) -> false;
|
||||
private static final Function<Object, Integer> INGREDIENT_COUNT_GETTER =
|
||||
VersionHelper.isOrAbove1_21() ?
|
||||
FastNMS.INSTANCE::method$CraftingInput$ingredientCount :
|
||||
FastNMS.INSTANCE::method$CraftingInput$size :
|
||||
FastNMS.INSTANCE::method$Container$getContainerSize;
|
||||
private static final BiFunction<Object, Integer, Object> INGREDIENT_GETTER =
|
||||
VersionHelper.isOrAbove1_21() ?
|
||||
FastNMS.INSTANCE::method$CraftingInput$getItem :
|
||||
FastNMS.INSTANCE::method$Container$getItem;
|
||||
|
||||
public static class MatchesInterceptor {
|
||||
public static final MatchesInterceptor INSTANCE = new MatchesInterceptor();
|
||||
private static final Function<Object, Boolean> REPAIR_INGREDIENT_COUNT_CHECKER =
|
||||
VersionHelper.isOrAbove1_21() ?
|
||||
(input) -> FastNMS.INSTANCE.method$CraftingInput$ingredientCount(input) != 2 :
|
||||
(container) -> false;
|
||||
|
||||
public static class FireworkStarFadeMatchesInterceptor {
|
||||
public static final FireworkStarFadeMatchesInterceptor INSTANCE = new FireworkStarFadeMatchesInterceptor();
|
||||
|
||||
@RuntimeType
|
||||
public Object intercept(@AllArguments Object[] args) {
|
||||
Object input = args[0];
|
||||
if (INGREDIENT_COUNT_CHECKER.apply(input)) {
|
||||
if (DYE_INGREDIENT_COUNT_CHECKER.apply(input)) {
|
||||
return false;
|
||||
}
|
||||
int size = INGREDIENT_COUNT_GETTER.apply(input);
|
||||
boolean hasDye = false;
|
||||
boolean hasFireworkStar = false;
|
||||
int size = INGREDIENT_SIZE_GETTER.apply(input);
|
||||
for (int i = 0; i < size; i++) {
|
||||
Object itemStack = INGREDIENT_GETTER.apply(input, i);
|
||||
if (FastNMS.INSTANCE.method$ItemStack$isEmpty(itemStack)) {
|
||||
continue;
|
||||
}
|
||||
Item<ItemStack> wrapped = BukkitItemManager.instance().wrap(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(itemStack));
|
||||
if (isFireworkDye(wrapped)) {
|
||||
hasDye = true;
|
||||
} else {
|
||||
if (!wrapped.id().equals(ItemKeys.FIREWORK_STAR)) {
|
||||
return false;
|
||||
}
|
||||
if (hasFireworkStar) {
|
||||
return false;
|
||||
}
|
||||
hasFireworkStar = true;
|
||||
}
|
||||
}
|
||||
return hasDye && hasFireworkStar;
|
||||
}
|
||||
}
|
||||
|
||||
public static class FireworkStarFadeAssembleInterceptor {
|
||||
public static final FireworkStarFadeAssembleInterceptor INSTANCE = new FireworkStarFadeAssembleInterceptor();
|
||||
|
||||
@RuntimeType
|
||||
public Object intercept(@AllArguments Object[] args) {
|
||||
IntList colors = new IntArrayList();
|
||||
Item<ItemStack> starItem = null;
|
||||
Object input = args[0];
|
||||
int size = INGREDIENT_SIZE_GETTER.apply(input);
|
||||
for (int i = 0; i < size; i++) {
|
||||
Object itemStack = INGREDIENT_GETTER.apply(input, i);
|
||||
if (FastNMS.INSTANCE.method$ItemStack$isEmpty(itemStack)) {
|
||||
continue;
|
||||
}
|
||||
Item<ItemStack> wrapped = BukkitItemManager.instance().wrap(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(itemStack));
|
||||
if (isFireworkDye(wrapped)) {
|
||||
Color color = getFireworkColor(wrapped);
|
||||
if (color == null) {
|
||||
return CoreReflections.instance$ItemStack$EMPTY;
|
||||
}
|
||||
colors.add(color.color());
|
||||
} else if (wrapped.id().equals(ItemKeys.FIREWORK_STAR)) {
|
||||
starItem = wrapped.copyWithCount(1);
|
||||
}
|
||||
}
|
||||
if (starItem == null || colors.isEmpty()) {
|
||||
return CoreReflections.instance$ItemStack$EMPTY;
|
||||
}
|
||||
FireworkExplosion explosion = starItem.fireworkExplosion().orElse(FireworkExplosion.DEFAULT);
|
||||
starItem.fireworkExplosion(explosion.withFadeColors(colors));
|
||||
return starItem.getLiteralObject();
|
||||
}
|
||||
}
|
||||
|
||||
public static class RepairMatchesInterceptor {
|
||||
public static final RepairMatchesInterceptor INSTANCE = new RepairMatchesInterceptor();
|
||||
|
||||
@RuntimeType
|
||||
public Object intercept(@AllArguments Object[] args) {
|
||||
Object input = args[0];
|
||||
if (REPAIR_INGREDIENT_COUNT_CHECKER.apply(input)) {
|
||||
return false;
|
||||
}
|
||||
return getItemsToCombine(input) != null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Pair<Item<ItemStack>, Item<ItemStack>> getItemsToCombine(Object input) {
|
||||
Item<ItemStack> item1 = null;
|
||||
Item<ItemStack> item2 = null;
|
||||
int size = INGREDIENT_SIZE_GETTER.apply(input);
|
||||
for (int i = 0; i < size; i++) {
|
||||
Object itemStack = INGREDIENT_GETTER.apply(input, i);
|
||||
if (FastNMS.INSTANCE.method$ItemStack$isEmpty(itemStack)) {
|
||||
continue;
|
||||
}
|
||||
Item<ItemStack> wrapped = BukkitItemManager.instance().wrap(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(itemStack));
|
||||
if (item1 == null) {
|
||||
item1 = wrapped;
|
||||
} else {
|
||||
if (item2 != null) {
|
||||
return null;
|
||||
}
|
||||
item2 = wrapped;
|
||||
}
|
||||
}
|
||||
if (item1 == null || item2 == null) {
|
||||
return null;
|
||||
}
|
||||
if (!canCombine(item1, item2)) {
|
||||
return null;
|
||||
}
|
||||
return new Pair<>(item1, item2);
|
||||
}
|
||||
|
||||
private static boolean canCombine(Item<ItemStack> input1, Item<ItemStack> input2) {
|
||||
if (input1.count() != 1 || !isDamageableItem(input1)) return false;
|
||||
if (input2.count() != 1 || !isDamageableItem(input2)) return false;
|
||||
if (!input1.id().equals(input2.id())) return false;
|
||||
Optional<CustomItem<ItemStack>> customItem = input1.getCustomItem();
|
||||
return customItem.isEmpty() || customItem.get().settings().canRepair() != Tristate.FALSE;
|
||||
}
|
||||
|
||||
private static boolean isDamageableItem(Item<ItemStack> item) {
|
||||
if (VersionHelper.isOrAbove1_20_5()) {
|
||||
return item.hasComponent(ComponentTypes.MAX_DAMAGE) && item.hasComponent(ComponentTypes.DAMAGE);
|
||||
} else {
|
||||
return FastNMS.INSTANCE.method$Item$canBeDepleted(FastNMS.INSTANCE.method$ItemStack$getItem(item.getLiteralObject()));
|
||||
}
|
||||
}
|
||||
|
||||
private static final Function<Object, Boolean> DYE_INGREDIENT_COUNT_CHECKER =
|
||||
VersionHelper.isOrAbove1_21() ?
|
||||
(input) -> FastNMS.INSTANCE.method$CraftingInput$ingredientCount(input) < 2 :
|
||||
(container) -> false;
|
||||
|
||||
public static class DyeMatchesInterceptor {
|
||||
public static final DyeMatchesInterceptor INSTANCE = new DyeMatchesInterceptor();
|
||||
|
||||
@RuntimeType
|
||||
public Object intercept(@AllArguments Object[] args) {
|
||||
Object input = args[0];
|
||||
if (DYE_INGREDIENT_COUNT_CHECKER.apply(input)) {
|
||||
return false;
|
||||
}
|
||||
int size = INGREDIENT_SIZE_GETTER.apply(input);
|
||||
Item<ItemStack> itemToDye = null;
|
||||
boolean hasDye = false;
|
||||
for (int i = 0; i < size; i++) {
|
||||
@@ -175,7 +349,7 @@ public class RecipeInjector {
|
||||
}
|
||||
itemToDye = wrapped;
|
||||
} else {
|
||||
if (!isDye(wrapped)) {
|
||||
if (!isArmorDye(wrapped)) {
|
||||
return false;
|
||||
}
|
||||
hasDye = true;
|
||||
@@ -185,15 +359,15 @@ public class RecipeInjector {
|
||||
}
|
||||
}
|
||||
|
||||
public static class AssembleInterceptor {
|
||||
public static final AssembleInterceptor INSTANCE = new AssembleInterceptor();
|
||||
public static class DyeAssembleInterceptor {
|
||||
public static final DyeAssembleInterceptor INSTANCE = new DyeAssembleInterceptor();
|
||||
|
||||
@RuntimeType
|
||||
public Object intercept(@AllArguments Object[] args) {
|
||||
List<Color> colors = new ArrayList<>();
|
||||
Item<ItemStack> itemToDye = null;
|
||||
Object input = args[0];
|
||||
int size = INGREDIENT_COUNT_GETTER.apply(input);
|
||||
int size = INGREDIENT_SIZE_GETTER.apply(input);
|
||||
for (int i = 0; i < size; i++) {
|
||||
Object itemStack = INGREDIENT_GETTER.apply(input, i);
|
||||
if (FastNMS.INSTANCE.method$ItemStack$isEmpty(itemStack)) {
|
||||
@@ -212,7 +386,7 @@ public class RecipeInjector {
|
||||
}
|
||||
}
|
||||
if (itemToDye == null || itemToDye.isEmpty() || colors.isEmpty()) {
|
||||
return null;
|
||||
return CoreReflections.instance$ItemStack$EMPTY;
|
||||
}
|
||||
return itemToDye.applyDyedColors(colors).getLiteralObject();
|
||||
}
|
||||
@@ -228,6 +402,16 @@ public class RecipeInjector {
|
||||
return getVanillaDyeColor(dyeItem);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Color getFireworkColor(final Item<ItemStack> dyeItem) {
|
||||
Optional<CustomItem<ItemStack>> optionalCustomItem = dyeItem.getCustomItem();
|
||||
if (optionalCustomItem.isPresent()) {
|
||||
CustomItem<ItemStack> customItem = optionalCustomItem.get();
|
||||
return Optional.ofNullable(customItem.settings().fireworkColor()).orElseGet(() -> getVanillaFireworkColor(dyeItem));
|
||||
}
|
||||
return getVanillaFireworkColor(dyeItem);
|
||||
}
|
||||
|
||||
private static final Predicate<Item<ItemStack>> IS_DYEABLE =
|
||||
VersionHelper.isOrAbove1_20_5() ?
|
||||
(item -> item.is(ItemTags.DYEABLE)) :
|
||||
@@ -258,7 +442,15 @@ public class RecipeInjector {
|
||||
return Color.fromDecimal(FastNMS.INSTANCE.method$DyeColor$getTextureDiffuseColor(FastNMS.INSTANCE.method$DyeItem$getDyeColor(dyeItem)));
|
||||
}
|
||||
|
||||
private static boolean isDye(Item<ItemStack> dyeItem) {
|
||||
@Nullable
|
||||
private static Color getVanillaFireworkColor(final Item<ItemStack> item) {
|
||||
Object itemStack = item.getLiteralObject();
|
||||
Object dyeItem = FastNMS.INSTANCE.method$ItemStack$getItem(itemStack);
|
||||
if (!CoreReflections.clazz$DyeItem.isInstance(dyeItem)) return null;
|
||||
return Color.fromDecimal(FastNMS.INSTANCE.method$DyeColor$getFireworkColor(FastNMS.INSTANCE.method$DyeItem$getDyeColor(dyeItem)));
|
||||
}
|
||||
|
||||
private static boolean isArmorDye(Item<ItemStack> dyeItem) {
|
||||
Optional<CustomItem<ItemStack>> optionalCustomItem = dyeItem.getCustomItem();
|
||||
if (optionalCustomItem.isPresent()) {
|
||||
CustomItem<ItemStack> customItem = optionalCustomItem.get();
|
||||
@@ -267,6 +459,15 @@ public class RecipeInjector {
|
||||
return isVanillaDyeItem(dyeItem);
|
||||
}
|
||||
|
||||
private static boolean isFireworkDye(Item<ItemStack> dyeItem) {
|
||||
Optional<CustomItem<ItemStack>> optionalCustomItem = dyeItem.getCustomItem();
|
||||
if (optionalCustomItem.isPresent()) {
|
||||
CustomItem<ItemStack> customItem = optionalCustomItem.get();
|
||||
return customItem.settings().fireworkColor() != null || isVanillaDyeItem(dyeItem);
|
||||
}
|
||||
return isVanillaDyeItem(dyeItem);
|
||||
}
|
||||
|
||||
private static boolean isVanillaDyeItem(Item<ItemStack> item) {
|
||||
return CoreReflections.clazz$DyeItem.isInstance(FastNMS.INSTANCE.method$ItemStack$getItem(item.getLiteralObject()));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user