9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-30 12:29:15 +00:00

trim配方(未测试)

This commit is contained in:
XiaoMoMi
2025-07-13 03:35:28 +08:00
parent 1d7f70a60c
commit ca6a13edba
61 changed files with 730 additions and 218 deletions

View File

@@ -6,9 +6,9 @@ import io.papermc.paper.event.player.AsyncChatCommandDecorateEvent;
import io.papermc.paper.event.player.AsyncChatDecorateEvent;
import net.kyori.adventure.text.Component;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.plugin.reflection.bukkit.CraftBukkitReflections;
import net.momirealms.craftengine.bukkit.plugin.reflection.paper.PaperReflections;
import net.momirealms.craftengine.bukkit.util.ComponentUtils;
import net.momirealms.craftengine.bukkit.util.InventoryUtils;
import net.momirealms.craftengine.bukkit.util.ItemStackUtils;
import net.momirealms.craftengine.bukkit.util.LegacyInventoryUtils;
import net.momirealms.craftengine.core.font.*;
@@ -132,14 +132,7 @@ public class BukkitFontManager extends AbstractFontManager implements Listener {
}
ItemStack result = event.getResult();
if (ItemStackUtils.isEmpty(result)) return;
Player player;
try {
player = (Player) CraftBukkitReflections.method$InventoryView$getPlayer.invoke(VersionHelper.isOrAbove1_21() ? event.getView() : LegacyInventoryUtils.getView(event));
} catch (ReflectiveOperationException e) {
this.plugin.logger().warn("Failed to get inventory viewer", e);
return;
}
Player player = InventoryUtils.getPlayerFromInventoryEvent(event);
String renameText;
if (VersionHelper.isOrAbove1_21_2()) {
AnvilView anvilView = event.getView();

View File

@@ -14,13 +14,13 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MItems;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries;
import net.momirealms.craftengine.bukkit.util.ItemStackUtils;
import net.momirealms.craftengine.bukkit.util.KeyUtils;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.item.*;
import net.momirealms.craftengine.core.item.modifier.IdModifier;
import net.momirealms.craftengine.core.item.recipe.UniqueIdItem;
import net.momirealms.craftengine.core.pack.AbstractPackManager;
import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
@@ -54,8 +54,8 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
private final ArmorEventListener armorEventListener;
private final NetworkItemHandler<ItemStack> networkItemHandler;
private final Object bedrockItemHolder;
private final Item<ItemStack> empty;
private final ItemStack emptyStack;
private final Item<ItemStack> emptyItem;
private final UniqueIdItem<ItemStack> emptyUniqueItem;
private Set<Key> lastRegisteredPatterns = Set.of();
public BukkitItemManager(BukkitCraftEngine plugin) {
@@ -71,8 +71,15 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
this.bedrockItemHolder = FastNMS.INSTANCE.method$Registry$getHolderByResourceKey(MBuiltInRegistries.ITEM, FastNMS.INSTANCE.method$ResourceKey$create(MRegistries.ITEM, KeyUtils.toResourceLocation(Key.of("minecraft:bedrock")))).get();;
this.registerCustomTrimMaterial();
this.loadLastRegisteredPatterns();
this.empty = this.wrap(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(CoreReflections.instance$ItemStack$EMPTY));
this.emptyStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(FastNMS.INSTANCE.constructor$ItemStack(MItems.AIR, 1));
ItemStack emptyStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(CoreReflections.instance$ItemStack$EMPTY);
this.emptyItem = this.wrap(emptyStack);
this.emptyUniqueItem = new UniqueIdItem<>(UniqueKey.AIR, this.emptyItem);
}
@Override
public UniqueIdItem<ItemStack> uniqueEmptyItem() {
return this.emptyUniqueItem;
}
@Override
@@ -104,18 +111,20 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
@Override
public Item<ItemStack> s2c(Item<ItemStack> item, Player player) {
if (item.isEmpty()) return item;
return this.networkItemHandler.s2c(item, player).orElse(item);
}
@Override
public Item<ItemStack> c2s(Item<ItemStack> item) {
if (item.isEmpty()) return item;
return this.networkItemHandler.c2s(item).orElse(item);
}
public Optional<ItemStack> s2c(ItemStack itemStack, Player player) {
try {
Item<ItemStack> wrapped = wrap(itemStack);
if (wrapped == null) return Optional.empty();
if (wrapped.isEmpty()) return Optional.empty();
return this.networkItemHandler.s2c(wrapped, player).map(Item::getItem);
} catch (Throwable e) {
Debugger.ITEM.warn(() -> "Failed to handle s2c items.", e);
@@ -126,7 +135,7 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
public Optional<ItemStack> c2s(ItemStack itemStack) {
try {
Item<ItemStack> wrapped = wrap(itemStack);
if (wrapped == null) return Optional.empty();
if (wrapped.isEmpty()) return Optional.empty();
return this.networkItemHandler.c2s(wrapped).map(Item::getItem);
} catch (Throwable e) {
Debugger.COMMON.warn(() -> "Failed to handle c2s items.", e);
@@ -332,7 +341,7 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
@Override
public @NotNull Item<ItemStack> wrap(ItemStack itemStack) {
if (itemStack == null) return this.empty;
if (itemStack == null) return this.emptyItem;
return this.factory.wrap(itemStack);
}
@@ -386,4 +395,45 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
plugin.logger().warn("Failed to init vanilla items", e);
}
}
// 1.20-1.21.4 template 不为空
// 1.21.5+ pattern 不为空
@Override
public Item<ItemStack> applyTrim(Item<ItemStack> base, Item<ItemStack> addition, Item<ItemStack> template, Key pattern) {
Optional<?> optionalMaterial = FastNMS.INSTANCE.method$TrimMaterials$getFromIngredient(addition.getLiteralObject());
Optional<?> optionalPattern = VersionHelper.isOrAbove1_21_5() ?
FastNMS.INSTANCE.method$Registry$getHolderByResourceLocation(FastNMS.INSTANCE.method$RegistryAccess$lookupOrThrow(FastNMS.INSTANCE.registryAccess(), MRegistries.TRIM_MATERIAL), KeyUtils.toResourceLocation(pattern)) :
FastNMS.INSTANCE.method$TrimPatterns$getFromTemplate(template.getLiteralObject());
if (optionalMaterial.isPresent() && optionalPattern.isPresent()) {
Object armorTrim = FastNMS.INSTANCE.constructor$ArmorTrim(optionalMaterial.get(), optionalPattern.get());
Object previousTrim;
if (VersionHelper.isOrAbove1_20_5()) {
previousTrim = base.getExactComponent(ComponentKeys.TRIM);
} else {
try {
previousTrim = VersionHelper.isOrAbove1_20_2() ?
((Optional<?>) CoreReflections.method$ArmorTrim$getTrim.invoke(null, FastNMS.INSTANCE.registryAccess(), base.getLiteralObject(), true)).orElse(null) :
((Optional<?>) CoreReflections.method$ArmorTrim$getTrim.invoke(null, FastNMS.INSTANCE.registryAccess(), base.getLiteralObject())).orElse(null);
} catch (ReflectiveOperationException e) {
this.plugin.logger().warn("Failed to get armor trim", e);
return this.emptyItem;
}
}
if (armorTrim.equals(previousTrim)) {
return this.emptyItem;
}
Item<ItemStack> newItem = base.copyWithCount(1);
if (VersionHelper.isOrAbove1_20_5()) {
newItem.setExactComponent(ComponentKeys.TRIM, armorTrim);
} else {
try {
CoreReflections.method$ArmorTrim$setTrim.invoke(null, FastNMS.INSTANCE.registryAccess(), base.getLiteralObject(), armorTrim);
} catch (ReflectiveOperationException e) {
this.plugin.logger().warn("Failed to set armor trim", e);
return this.emptyItem;
}
}
}
return this.emptyItem;
}
}

View File

@@ -72,6 +72,7 @@ public class LegacyItemWrapper implements ItemWrapper<ItemStack> {
getItem().setAmount(amount);
}
@SuppressWarnings("DuplicatedCode")
public Object getExactTag(Object... path) {
Object compoundTag = FastNMS.INSTANCE.method$ItemStack$getTag(this.nmsStack);
if (compoundTag == null) return null;

View File

@@ -45,7 +45,7 @@ public final class LegacyNetworkItemHandler implements NetworkItemHandler<ItemSt
return Optional.of(wrapped);
}
}
CompoundTag networkData = (CompoundTag) wrapped.getNBTTag(NETWORK_ITEM_TAG);
CompoundTag networkData = (CompoundTag) wrapped.getTag(NETWORK_ITEM_TAG);
if (networkData == null) return Optional.empty();
wrapped.removeTag(NETWORK_ITEM_TAG);
for (Map.Entry<String, Tag> entry : networkData.entrySet()) {
@@ -74,7 +74,7 @@ public final class LegacyNetworkItemHandler implements NetworkItemHandler<ItemSt
return new OtherItem(wrapped, hasDifferentMaterial).process();
} else {
CompoundTag tag = new CompoundTag();
Tag argumentTag = wrapped.getNBTTag(ArgumentModifier.ARGUMENTS_TAG);
Tag argumentTag = wrapped.getTag(ArgumentModifier.ARGUMENTS_TAG);
ItemBuildContext context;
if (argumentTag instanceof CompoundTag arguments) {
ContextHolder.Builder builder = ContextHolder.builder();

View File

@@ -146,6 +146,11 @@ public abstract class BukkitItemFactory<W extends ItemWrapper<ItemStack>> extend
throw new UnsupportedOperationException("This feature is only available on 1.20.5+");
}
@Override
protected void setExactComponent(W item, Object type, Object value) {
throw new UnsupportedOperationException("This feature is only available on 1.20.5+");
}
@Override
protected boolean hasComponent(W item, Object type) {
throw new UnsupportedOperationException("This feature is only available on 1.20.5+");

View File

@@ -72,8 +72,29 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory<ComponentItemW
return currentObj;
}
@SuppressWarnings("DuplicatedCode")
@Override
protected Tag getNBTTag(ComponentItemWrapper item, Object... path) {
protected Object getExactTag(ComponentItemWrapper item, Object... path) {
Object customData = getExactComponent(item, ComponentTypes.CUSTOM_DATA);
if (customData == null) return null;
Object currentTag = FastNMS.INSTANCE.method$CustomData$getUnsafe(customData);
for (int i = 0; i < path.length; i++) {
Object pathSegment = path[i];
if (pathSegment == null) return null;
currentTag = FastNMS.INSTANCE.method$CompoundTag$get(currentTag, path[i].toString());
if (currentTag == null) return null;
if (i == path.length - 1) {
return currentTag;
}
if (!CoreReflections.clazz$CompoundTag.isInstance(currentTag)) {
return null;
}
}
return null;
}
@Override
protected Tag getTag(ComponentItemWrapper item, Object... path) {
CompoundTag rootTag = (CompoundTag) item.getSparrowNBTComponent(ComponentTypes.CUSTOM_DATA).orElse(null);
if (rootTag == null) return null;
Tag currentTag = rootTag;
@@ -140,7 +161,7 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory<ComponentItemW
@Override
protected boolean hasTag(ComponentItemWrapper item, Object... path) {
return getNBTTag(item, path) != null;
return getTag(item, path) != null;
}
@Override
@@ -221,6 +242,11 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory<ComponentItemW
return item.getComponentExact(type);
}
@Override
protected void setExactComponent(ComponentItemWrapper item, Object type, Object value) {
item.setComponentExact(type, value);
}
@Override
protected Object getJavaComponent(ComponentItemWrapper item, Object type) {
return item.getJavaComponent(type).orElse(null);
@@ -475,8 +501,8 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory<ComponentItemW
item.resetComponent(ComponentTypes.TRIM);
} else {
item.setJavaComponent(ComponentTypes.TRIM, Map.of(
"pattern", trim.pattern(),
"material", trim.material()
"pattern", trim.pattern().asString(),
"material", trim.material().asString()
));
}
}
@@ -489,7 +515,7 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory<ComponentItemW
}
@SuppressWarnings("unchecked")
Map<String, String> trimMap = (Map<String, String>) trim.get();
return Optional.of(new Trim(trimMap.get("pattern"), trimMap.get("material")));
return Optional.of(new Trim(Key.of(trimMap.get("pattern")), Key.of(trimMap.get("material"))));
}
@SuppressWarnings("unchecked")

View File

@@ -43,10 +43,15 @@ public class UniversalItemFactory extends BukkitItemFactory<LegacyItemWrapper> {
}
@Override
protected Tag getNBTTag(LegacyItemWrapper item, Object... path) {
protected Tag getTag(LegacyItemWrapper item, Object... path) {
return item.getNBTTag(path);
}
@Override
protected Object getExactTag(LegacyItemWrapper item, Object... path) {
return item.getExactTag(path);
}
@Override
protected boolean hasTag(LegacyItemWrapper item, Object... path) {
return item.hasTag(path);
@@ -263,8 +268,8 @@ public class UniversalItemFactory extends BukkitItemFactory<LegacyItemWrapper> {
item.remove("Trim");
return;
}
item.setTag(trim.material(), "Trim", "material");
item.setTag(trim.pattern(), "Trim", "pattern");
item.setTag(trim.material().asString(), "Trim", "material");
item.setTag(trim.pattern().asString(), "Trim", "pattern");
}
@Override
@@ -304,7 +309,7 @@ public class UniversalItemFactory extends BukkitItemFactory<LegacyItemWrapper> {
String material = item.getJavaTag("Trim", "material");
String pattern = item.getJavaTag("Trim", "pattern");
if (material == null || pattern == null) return Optional.empty();
return Optional.of(new Trim(material, pattern));
return Optional.of(new Trim(Key.of(material), Key.of(pattern)));
}
@Override

View File

@@ -140,6 +140,27 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
return null;
}
});
MIXED_RECIPE_CONVERTORS.put(RecipeTypes.SMITHING_TRIM, (BukkitRecipeConvertor<CustomSmithingTrimRecipe<ItemStack>>) (id, recipe) -> {
try {
Object nmsRecipe = createMinecraftSmithingTrimRecipe(recipe);
if (VersionHelper.isOrAbove1_21_2()) {
nmsRecipe = CoreReflections.constructor$RecipeHolder.newInstance(
CraftBukkitReflections.method$CraftRecipe$toMinecraft.invoke(null, new NamespacedKey(id.namespace(), id.value())), nmsRecipe);
} else if (VersionHelper.isOrAbove1_20_2()) {
nmsRecipe = CoreReflections.constructor$RecipeHolder.newInstance(KeyUtils.toResourceLocation(id), nmsRecipe);
} else {
Object finalNmsRecipe0 = nmsRecipe;
return () -> registerNMSSmithingRecipe(finalNmsRecipe0);
}
Object finalNmsRecipe = nmsRecipe;
return () -> registerNMSSmithingRecipe(finalNmsRecipe);
} catch (InvalidRecipeIngredientException e) {
throw e;
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to convert smithing trim recipe", e);
return null;
}
});
// TODO DO NOT USE BUKKIT RECIPE AS BRIDGE IN FUTURE VERSIONS, WE SHOULD DIRECTLY CONSTRUCT THOSE NMS RECIPES
MIXED_RECIPE_CONVERTORS.put(RecipeTypes.SHAPED, (BukkitRecipeConvertor<CustomShapedRecipe<ItemStack>>) (id, recipe) -> {
ShapedRecipe shapedRecipe = new ShapedRecipe(new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY));
@@ -439,6 +460,10 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
VanillaSmithingTransformRecipe recipe = this.recipeReader.readSmithingTransform(jsonObject);
handleDataPackSmithingTransform(id, recipe, (this.delayedTasksOnMainThread::add));
}
case "minecraft:smithing_trim" -> {
VanillaSmithingTrimRecipe recipe = this.recipeReader.readSmithingTrim(jsonObject);
handleDataPackSmithingTrim(id, recipe, (this.delayedTasksOnMainThread::add));
}
case "minecraft:stonecutting" -> {
VanillaStoneCuttingRecipe recipe = this.recipeReader.readStoneCutting(jsonObject);
handleDataPackStoneCuttingRecipe(id, recipe);
@@ -649,6 +674,35 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
this.registerInternalRecipe(id, ceRecipe);
}
private void handleDataPackSmithingTrim(Key id, VanillaSmithingTrimRecipe recipe, Consumer<Runnable> callback) {
NamespacedKey key = new NamespacedKey(id.namespace(), id.value());
boolean hasCustomItemInTag;
Set<UniqueKey> additionHolders = new HashSet<>();
hasCustomItemInTag = readVanillaIngredients(false, recipe.addition(), additionHolders::add);
Set<UniqueKey> templateHolders = new HashSet<>();
hasCustomItemInTag = readVanillaIngredients(hasCustomItemInTag, recipe.template(), templateHolders::add);
Set<UniqueKey> baseHolders = new HashSet<>();
hasCustomItemInTag = readVanillaIngredients(hasCustomItemInTag, recipe.base(), baseHolders::add);
CustomSmithingTrimRecipe<ItemStack> ceRecipe = new CustomSmithingTrimRecipe<>(
id,
Ingredient.of(baseHolders),
Ingredient.of(templateHolders),
Ingredient.of(additionHolders),
Optional.ofNullable(recipe.pattern()).map(Key::of).orElse(null)
);
if (hasCustomItemInTag) {
Runnable converted = findNMSRecipeConvertor(ceRecipe).convert(id, ceRecipe);
callback.accept(() -> {
unregisterNMSRecipe(key);
converted.run();
});
}
this.registerInternalRecipe(id, ceRecipe);
}
private boolean readVanillaIngredients(boolean hasCustomItemInTag, List<String> ingredients, Consumer<UniqueKey> holderConsumer) {
for (String item : ingredients) {
if (item.charAt(0) == '#') {
@@ -903,4 +957,35 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
);
}
}
private static Object createMinecraftSmithingTrimRecipe(CustomSmithingTrimRecipe<ItemStack> recipe) throws ReflectiveOperationException {
if (VersionHelper.isOrAbove1_21_5()) {
Object registry = FastNMS.INSTANCE.method$RegistryAccess$lookupOrThrow(FastNMS.INSTANCE.registryAccess(), MRegistries.TRIM_PATTERN);
return CoreReflections.constructor$SmithingTrimRecipe.newInstance(
toMinecraftIngredient(recipe.template()),
toMinecraftIngredient(recipe.base()),
toMinecraftIngredient(recipe.addition()),
FastNMS.INSTANCE.method$Registry$getHolderByResourceLocation(registry, KeyUtils.toResourceLocation(recipe.pattern()))
);
} else if (VersionHelper.isOrAbove1_21_2()) {
return CoreReflections.constructor$SmithingTrimRecipe.newInstance(
toOptionalMinecraftIngredient(recipe.template()),
toOptionalMinecraftIngredient(recipe.base()),
toOptionalMinecraftIngredient(recipe.addition())
);
} else if (VersionHelper.isOrAbove1_20_2()) {
return CoreReflections.constructor$SmithingTrimRecipe.newInstance(
toMinecraftIngredient(recipe.template()),
toMinecraftIngredient(recipe.base()),
toMinecraftIngredient(recipe.addition())
);
} else {
return CoreReflections.constructor$SmithingTrimRecipe.newInstance(
KeyUtils.toResourceLocation(recipe.id()),
toMinecraftIngredient(recipe.template()),
toMinecraftIngredient(recipe.base()),
toMinecraftIngredient(recipe.addition())
);
}
}
}

View File

@@ -5,9 +5,9 @@ import net.momirealms.craftengine.bukkit.util.ItemStackUtils;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.ItemBuildContext;
import net.momirealms.craftengine.core.item.ItemManager;
import net.momirealms.craftengine.core.item.recipe.OptimizedIDItem;
import net.momirealms.craftengine.core.item.recipe.Recipe;
import net.momirealms.craftengine.core.item.recipe.RecipeTypes;
import net.momirealms.craftengine.core.item.recipe.UniqueIdItem;
import net.momirealms.craftengine.core.item.recipe.input.CraftingInput;
import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.util.Key;
@@ -52,33 +52,33 @@ public class CrafterEventListener implements Listener {
Inventory inventory = crafter.getInventory();
ItemStack[] ingredients = inventory.getStorageContents();
List<OptimizedIDItem<ItemStack>> optimizedIDItems = new ArrayList<>();
List<UniqueIdItem<ItemStack>> uniqueIdItems = new ArrayList<>();
for (ItemStack itemStack : ingredients) {
if (ItemStackUtils.isEmpty(itemStack)) {
optimizedIDItems.add(RecipeEventListener.EMPTY);
uniqueIdItems.add(this.itemManager.uniqueEmptyItem());
} else {
Item<ItemStack> wrappedItem = this.itemManager.wrap(itemStack);
optimizedIDItems.add(new OptimizedIDItem<>(wrappedItem.recipeIngredientId(), itemStack));
uniqueIdItems.add(new UniqueIdItem<>(wrappedItem.recipeIngredientId(), wrappedItem));
}
}
CraftingInput<ItemStack> input;
if (ingredients.length == 9) {
input = CraftingInput.of(3, 3, optimizedIDItems);
input = CraftingInput.of(3, 3, uniqueIdItems);
} else if (ingredients.length == 4) {
input = CraftingInput.of(2, 2, optimizedIDItems);
input = CraftingInput.of(2, 2, uniqueIdItems);
} else {
return;
}
Recipe<ItemStack> ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SHAPELESS, input);
if (ceRecipe != null) {
event.setResult(ceRecipe.result(ItemBuildContext.EMPTY));
event.setResult(ceRecipe.assemble(input, ItemBuildContext.EMPTY));
return;
}
ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SHAPED, input);
if (ceRecipe != null) {
event.setResult(ceRecipe.result(ItemBuildContext.EMPTY));
event.setResult(ceRecipe.assemble(input, ItemBuildContext.EMPTY));
return;
}
// clear result if not met

View File

@@ -12,6 +12,7 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflect
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRecipeTypes;
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
import net.momirealms.craftengine.bukkit.util.ComponentUtils;
import net.momirealms.craftengine.bukkit.util.InventoryUtils;
import net.momirealms.craftengine.bukkit.util.ItemStackUtils;
import net.momirealms.craftengine.bukkit.util.LegacyInventoryUtils;
import net.momirealms.craftengine.core.item.*;
@@ -49,7 +50,6 @@ import java.util.Optional;
@SuppressWarnings("DuplicatedCode")
public class RecipeEventListener implements Listener {
public static final OptimizedIDItem<ItemStack> EMPTY = new OptimizedIDItem<>(null, null);
private final ItemManager<ItemStack> itemManager;
private final BukkitRecipeManager recipeManager;
private final BukkitCraftEngine plugin;
@@ -74,7 +74,7 @@ public class RecipeEventListener implements Listener {
ItemStack item = event.getCurrentItem();
if (ItemStackUtils.isEmpty(item)) return;
if (ItemStackUtils.isEmpty(fuelStack)) {
SingleItemInput<ItemStack> input = new SingleItemInput<>(getOptimizedIDItem(item));
SingleItemInput<ItemStack> input = new SingleItemInput<>(getUniqueIdItem(item));
Key recipeType;
if (furnaceInventory.getType() == InventoryType.FURNACE) {
recipeType = RecipeTypes.SMELTING;
@@ -351,7 +351,7 @@ public class RecipeEventListener implements Listener {
if (optionalMCRecipe.isEmpty()) {
return;
}
SingleItemInput<ItemStack> input = new SingleItemInput<>(getOptimizedIDItem(itemStack));
SingleItemInput<ItemStack> input = new SingleItemInput<>(getUniqueIdItem(itemStack));
CustomCampfireRecipe<ItemStack> ceRecipe = (CustomCampfireRecipe<ItemStack>) this.recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input);
if (ceRecipe == null) {
event.setCancelled(true);
@@ -376,7 +376,7 @@ public class RecipeEventListener implements Listener {
}
ItemStack itemStack = event.getSource();
SingleItemInput<ItemStack> input = new SingleItemInput<>(getOptimizedIDItem(itemStack));
SingleItemInput<ItemStack> input = new SingleItemInput<>(getUniqueIdItem(itemStack));
CustomCampfireRecipe<ItemStack> ceRecipe = (CustomCampfireRecipe<ItemStack>) this.recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input);
if (ceRecipe == null) {
event.setTotalCookTime(Integer.MAX_VALUE);
@@ -404,7 +404,7 @@ public class RecipeEventListener implements Listener {
}
ItemStack itemStack = event.getSource();
SingleItemInput<ItemStack> input = new SingleItemInput<>(getOptimizedIDItem(itemStack));
SingleItemInput<ItemStack> input = new SingleItemInput<>(getUniqueIdItem(itemStack));
CustomCampfireRecipe<ItemStack> ceRecipe = (CustomCampfireRecipe<ItemStack>) this.recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input);
if (ceRecipe == null) {
event.setCancelled(true);
@@ -620,13 +620,7 @@ public class RecipeEventListener implements Listener {
LegacyInventoryUtils.setRepairCostAmount(inventory, actualConsumedAmount);
}
Player player;
try {
player = (Player) CraftBukkitReflections.method$InventoryView$getPlayer.invoke(VersionHelper.isOrAbove1_21() ? event.getView() : LegacyInventoryUtils.getView(event));
} catch (ReflectiveOperationException e) {
plugin.logger().warn("Failed to get inventory viewer", e);
return;
}
Player player = InventoryUtils.getPlayerFromInventoryEvent(event);
if (finalCost >= maxRepairCost && !plugin.adapt(player).canInstabuild()) {
hasResult = false;
@@ -732,13 +726,7 @@ public class RecipeEventListener implements Listener {
return;
}
Player player;
try {
player = (Player) CraftBukkitReflections.method$InventoryView$getPlayer.invoke(event.getView());
} catch (ReflectiveOperationException e) {
plugin.logger().warn("Failed to get inventory viewer", e);
return;
}
Player player = InventoryUtils.getPlayerFromInventoryEvent(event);
Optional<CustomItem<ItemStack>> customItemOptional = plugin.itemManager().getCustomItem(left.id());
if (customItemOptional.isEmpty()) {
@@ -860,34 +848,28 @@ public class RecipeEventListener implements Listener {
CraftingInventory inventory = event.getInventory();
ItemStack[] ingredients = inventory.getMatrix();
List<OptimizedIDItem<ItemStack>> optimizedIDItems = new ArrayList<>();
List<UniqueIdItem<ItemStack>> uniqueIdItems = new ArrayList<>();
for (ItemStack itemStack : ingredients) {
optimizedIDItems.add(getOptimizedIDItem(itemStack));
uniqueIdItems.add(getUniqueIdItem(itemStack));
}
CraftingInput<ItemStack> input;
if (ingredients.length == 9) {
input = CraftingInput.of(3, 3, optimizedIDItems);
input = CraftingInput.of(3, 3, uniqueIdItems);
} else if (ingredients.length == 4) {
input = CraftingInput.of(2, 2, optimizedIDItems);
input = CraftingInput.of(2, 2, uniqueIdItems);
} else {
return;
}
Player player;
try {
player = (Player) CraftBukkitReflections.method$InventoryView$getPlayer.invoke(event.getView());
} catch (ReflectiveOperationException e) {
this.plugin.logger().warn("Failed to get inventory viewer", e);
return;
}
Player player = InventoryUtils.getPlayerFromInventoryEvent(event);
BukkitServerPlayer serverPlayer = this.plugin.adapt(player);
Key lastRecipe = serverPlayer.lastUsedRecipe();
Recipe<ItemStack> ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SHAPELESS, input, lastRecipe);
if (ceRecipe != null) {
inventory.setResult(ceRecipe.result(new ItemBuildContext(serverPlayer, ContextHolder.EMPTY)));
inventory.setResult(ceRecipe.assemble(input, new ItemBuildContext(serverPlayer, ContextHolder.EMPTY)));
serverPlayer.setLastUsedRecipe(ceRecipe.id());
if (!ceRecipe.id().equals(recipeId)) {
correctCraftingRecipeUsed(inventory, ceRecipe);
@@ -896,7 +878,7 @@ public class RecipeEventListener implements Listener {
}
ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SHAPED, input, lastRecipe);
if (ceRecipe != null) {
inventory.setResult(ceRecipe.result(new ItemBuildContext(serverPlayer, ContextHolder.EMPTY)));
inventory.setResult(ceRecipe.assemble(input, new ItemBuildContext(serverPlayer, ContextHolder.EMPTY)));
serverPlayer.setLastUsedRecipe(ceRecipe.id());
if (!ceRecipe.id().equals(recipeId)) {
correctCraftingRecipeUsed(inventory, ceRecipe);
@@ -923,18 +905,48 @@ public class RecipeEventListener implements Listener {
@EventHandler(ignoreCancelled = true)
public void onSmithingTrim(PrepareSmithingEvent event) {
SmithingInventory inventory = event.getInventory();
if (!(inventory.getRecipe() instanceof SmithingTrimRecipe)) return;
if (!(inventory.getRecipe() instanceof SmithingTrimRecipe recipe)) return;
ItemStack equipment = inventory.getInputEquipment();
if (ItemStackUtils.isEmpty(equipment)) return;
Item<ItemStack> wrappedEquipment = this.itemManager.wrap(equipment);
Optional<CustomItem<ItemStack>> optionalCustomItem = wrappedEquipment.getCustomItem();
if (optionalCustomItem.isEmpty()) return;
CustomItem<ItemStack> customItem = optionalCustomItem.get();
ItemEquipment itemEquipmentSettings = customItem.settings().equipment();
if (itemEquipmentSettings == null) return;
// 不允许trim类型的盔甲再次被使用trim
if (itemEquipmentSettings.equipment() instanceof TrimBasedEquipment) {
if (!ItemStackUtils.isEmpty(equipment)) {
Item<ItemStack> wrappedEquipment = this.itemManager.wrap(equipment);
Optional<CustomItem<ItemStack>> optionalCustomItem = wrappedEquipment.getCustomItem();
if (optionalCustomItem.isPresent()) {
CustomItem<ItemStack> customItem = optionalCustomItem.get();
ItemEquipment itemEquipmentSettings = customItem.settings().equipment();
if (itemEquipmentSettings != null && itemEquipmentSettings.equipment() instanceof TrimBasedEquipment) {
// 不允许trim类型的盔甲再次被使用trim
event.setResult(null);
return;
}
}
}
Key recipeId = Key.of(recipe.getKey().namespace(), recipe.getKey().value());
boolean isCustom = this.recipeManager.isCustomRecipe(recipeId);
// Maybe it's recipe from other plugins, then we ignore it
if (!isCustom) {
return;
}
SmithingInput<ItemStack> input = new SmithingInput<>(
getUniqueIdItem(inventory.getInputEquipment()),
getUniqueIdItem(inventory.getInputTemplate()),
getUniqueIdItem(inventory.getInputMineral())
);
Recipe<ItemStack> ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SMITHING_TRIM, input);
if (ceRecipe == null) {
event.setResult(null);
return;
}
Player player = InventoryUtils.getPlayerFromInventoryEvent(event);
CustomSmithingTrimRecipe<ItemStack> trimRecipe = (CustomSmithingTrimRecipe<ItemStack>) ceRecipe;
ItemStack result = trimRecipe.assemble(input, new ItemBuildContext(this.plugin.adapt(player), ContextHolder.EMPTY));
event.setResult(result);
if (!ceRecipe.id().equals(recipeId)) {
correctSmithingRecipeUsed(inventory, ceRecipe);
}
}
@@ -956,9 +968,9 @@ public class RecipeEventListener implements Listener {
ItemStack addition = inventory.getInputMineral();
SmithingInput<ItemStack> input = new SmithingInput<>(
getOptimizedIDItem(base),
getOptimizedIDItem(template),
getOptimizedIDItem(addition)
getUniqueIdItem(base),
getUniqueIdItem(template),
getUniqueIdItem(addition)
);
Recipe<ItemStack> ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SMITHING_TRANSFORM, input);
@@ -967,16 +979,10 @@ public class RecipeEventListener implements Listener {
return;
}
Player player;
try {
player = (Player) CraftBukkitReflections.method$InventoryView$getPlayer.invoke(event.getView());
} catch (ReflectiveOperationException e) {
this.plugin.logger().warn("Failed to get inventory viewer", e);
return;
}
Player player = InventoryUtils.getPlayerFromInventoryEvent(event);
CustomSmithingTransformRecipe<ItemStack> transformRecipe = (CustomSmithingTransformRecipe<ItemStack>) ceRecipe;
ItemStack processed = transformRecipe.assemble(new ItemBuildContext(this.plugin.adapt(player), ContextHolder.EMPTY), this.itemManager.wrap(base));
ItemStack processed = transformRecipe.assemble(input, new ItemBuildContext(this.plugin.adapt(player), ContextHolder.EMPTY));
event.setResult(processed);
if (!ceRecipe.id().equals(recipeId)) {
correctSmithingRecipeUsed(inventory, ceRecipe);
@@ -996,12 +1002,12 @@ public class RecipeEventListener implements Listener {
}
}
private OptimizedIDItem<ItemStack> getOptimizedIDItem(@Nullable ItemStack itemStack) {
private UniqueIdItem<ItemStack> getUniqueIdItem(@Nullable ItemStack itemStack) {
if (ItemStackUtils.isEmpty(itemStack)) {
return EMPTY;
return this.itemManager.uniqueEmptyItem();
} else {
Item<ItemStack> wrappedItem = this.itemManager.wrap(itemStack);
return new OptimizedIDItem<>(wrappedItem.recipeIngredientId(), itemStack);
return new UniqueIdItem<>(wrappedItem.recipeIngredientId(), wrappedItem);
}
}
}

View File

@@ -20,8 +20,8 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries
import net.momirealms.craftengine.bukkit.util.KeyUtils;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.recipe.CustomCookingRecipe;
import net.momirealms.craftengine.core.item.recipe.OptimizedIDItem;
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.Key;
import net.momirealms.craftengine.core.util.ReflectionUtils;
@@ -133,7 +133,7 @@ public class RecipeInjector {
);
Item<ItemStack> wrappedItem = BukkitItemManager.instance().wrap(itemStack);
SingleItemInput<ItemStack> input = new SingleItemInput<>(new OptimizedIDItem<>(wrappedItem.recipeIngredientId(), itemStack));
SingleItemInput<ItemStack> input = new SingleItemInput<>(new UniqueIdItem<>(wrappedItem.recipeIngredientId(), wrappedItem));
CustomCookingRecipe<ItemStack> ceRecipe = (CustomCookingRecipe<ItemStack>) recipeManager.recipeByInput(injectedCacheCheck.customRecipeType(), input, injectedCacheCheck.lastCustomRecipe());
if (ceRecipe == null) {
return Optional.empty();
@@ -179,7 +179,7 @@ public class RecipeInjector {
}
Item<ItemStack> wrappedItem = BukkitItemManager.instance().wrap(itemStack);
SingleItemInput<ItemStack> input = new SingleItemInput<>(new OptimizedIDItem<>(wrappedItem.recipeIngredientId(), itemStack));
SingleItemInput<ItemStack> input = new SingleItemInput<>(new UniqueIdItem<>(wrappedItem.recipeIngredientId(), wrappedItem));
CustomCookingRecipe<ItemStack> ceRecipe = (CustomCookingRecipe<ItemStack>) recipeManager.recipeByInput(injectedCacheCheck.customRecipeType(), input, injectedCacheCheck.lastCustomRecipe());
if (ceRecipe == null) {
return Optional.empty();
@@ -220,7 +220,7 @@ public class RecipeInjector {
ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(FastNMS.INSTANCE.field$SingleRecipeInput$item(args[0]));
Item<ItemStack> wrappedItem = BukkitItemManager.instance().wrap(itemStack);
SingleItemInput<ItemStack> input = new SingleItemInput<>(new OptimizedIDItem<>(wrappedItem.recipeIngredientId(), itemStack));
SingleItemInput<ItemStack> input = new SingleItemInput<>(new UniqueIdItem<>(wrappedItem.recipeIngredientId(), wrappedItem));
CustomCookingRecipe<ItemStack> ceRecipe = (CustomCookingRecipe<ItemStack>) recipeManager.recipeByInput(injectedCacheCheck.customRecipeType(), input, injectedCacheCheck.lastCustomRecipe());
if (ceRecipe == null) {
return Optional.empty();
@@ -265,7 +265,7 @@ public class RecipeInjector {
// 获取唯一内存地址id
ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(FastNMS.INSTANCE.field$SingleRecipeInput$item(args[0]));
Item<ItemStack> wrappedItem = BukkitItemManager.instance().wrap(itemStack);
SingleItemInput<ItemStack> input = new SingleItemInput<>(new OptimizedIDItem<>(wrappedItem.recipeIngredientId(), itemStack));
SingleItemInput<ItemStack> input = new SingleItemInput<>(new UniqueIdItem<>(wrappedItem.recipeIngredientId(), wrappedItem));
CustomCookingRecipe<ItemStack> ceRecipe = (CustomCookingRecipe<ItemStack>) recipeManager.recipeByInput(injectedCacheCheck.customRecipeType(), input, injectedCacheCheck.lastCustomRecipe());
// 这个ce配方并不存在那么应该返回空
if (ceRecipe == null) {

View File

@@ -2290,12 +2290,24 @@ public final class CoreReflections {
public static final Constructor<?> constructor$SmithingTransformRecipe = requireNonNull(
VersionHelper.isOrAbove1_21_5()
? ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, Optional.class, clazz$Ingredient, Optional.class, clazz$TransmuteResult)
: VersionHelper.isOrAbove1_21_2()
? ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, Optional.class, Optional.class, Optional.class, clazz$ItemStack)
: VersionHelper.isOrAbove1_20_2()
? ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, clazz$Ingredient, clazz$Ingredient, clazz$Ingredient, clazz$ItemStack)
: ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, clazz$ResourceLocation, clazz$Ingredient, clazz$Ingredient, clazz$Ingredient, clazz$ItemStack)
? ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, Optional.class, clazz$Ingredient, Optional.class, clazz$TransmuteResult)
: VersionHelper.isOrAbove1_21_2()
? ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, Optional.class, Optional.class, Optional.class, clazz$ItemStack)
: VersionHelper.isOrAbove1_20_2()
? ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, clazz$Ingredient, clazz$Ingredient, clazz$Ingredient, clazz$ItemStack)
: ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, clazz$ResourceLocation, clazz$Ingredient, clazz$Ingredient, clazz$Ingredient, clazz$ItemStack)
);
public static final Class<?> clazz$SmithingTrimRecipe = requireNonNull(
ReflectionUtils.getClazz(BukkitReflectionUtils.assembleMCClass("world.item.crafting.SmithingTrimRecipe"))
);
public static final Constructor<?> constructor$SmithingTrimRecipe = requireNonNull(
VersionHelper.isOrAbove1_21_5() ?
ReflectionUtils.getConstructor(clazz$SmithingTrimRecipe, clazz$Ingredient, clazz$Ingredient, clazz$Ingredient, clazz$Holder) :
VersionHelper.isOrAbove1_20_2() ?
ReflectionUtils.getConstructor(clazz$SmithingTrimRecipe, clazz$Ingredient, clazz$Ingredient, clazz$Ingredient) :
ReflectionUtils.getConstructor(clazz$SmithingTrimRecipe, clazz$ResourceLocation, clazz$Ingredient, clazz$Ingredient, clazz$Ingredient)
);
public static final Method method$RecipeManager$addRecipe = requireNonNull(
@@ -3771,4 +3783,35 @@ public final class CoreReflections {
"world.item.BlockItem"
)
);
public static final Class<?> clazz$ArmorTrim = requireNonNull(
ReflectionUtils.getClazz(
VersionHelper.isOrAbove1_21_2() ?
BukkitReflectionUtils.assembleCBClass("world.item.equipment.trim.ArmorTrim") :
BukkitReflectionUtils.assembleMCClass("world.item.armortrim.ArmorTrim")
)
);
public static final Field field$ArmorTrim$CODEC = requireNonNull(
ReflectionUtils.getDeclaredField(clazz$ArmorTrim, Codec.class, 0)
);
public static final Codec<?> instance$ArmorTrim$CODEC;
static {
try {
instance$ArmorTrim$CODEC = (Codec<?>) field$ArmorTrim$CODEC.get(null);
} catch (ReflectiveOperationException e) {
throw new ReflectionInitException("Failed to initialize ArmorTrim CODEC", e);
}
}
public static final Method method$ArmorTrim$setTrim = ReflectionUtils.getStaticMethod(
clazz$ArmorTrim, boolean.class, clazz$RegistryAccess, clazz$ItemStack, clazz$ArmorTrim
);
public static final Method method$ArmorTrim$getTrim =
VersionHelper.isOrAbove1_20_2() ?
ReflectionUtils.getStaticMethod(clazz$ArmorTrim, Optional.class, clazz$RegistryAccess, clazz$ItemStack, boolean.class) :
ReflectionUtils.getStaticMethod(clazz$ArmorTrim, Optional.class, clazz$RegistryAccess, clazz$ItemStack);
}

View File

@@ -4,8 +4,8 @@ import net.momirealms.craftengine.bukkit.item.recipe.BukkitRecipeManager;
import net.momirealms.craftengine.core.block.BlockKeys;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.ItemKeys;
import net.momirealms.craftengine.core.item.recipe.OptimizedIDItem;
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.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.config.Config;
@@ -78,14 +78,14 @@ public class InteractUtils {
});
registerInteraction(BlockKeys.SOUL_CAMPFIRE, (player, item, blockState, result) -> {
if (!Config.enableRecipeSystem()) return false;
return BukkitRecipeManager.instance().recipeByInput(RecipeTypes.CAMPFIRE_COOKING, new SingleItemInput<>(new OptimizedIDItem<>(
item.recipeIngredientId(), item.getItem()
return BukkitRecipeManager.instance().recipeByInput(RecipeTypes.CAMPFIRE_COOKING, new SingleItemInput<>(new UniqueIdItem<>(
item.recipeIngredientId(), item
))) != null;
});
registerInteraction(BlockKeys.CAMPFIRE, (player, item, blockState, result) -> {
if (!Config.enableRecipeSystem()) return false;
return BukkitRecipeManager.instance().recipeByInput(RecipeTypes.CAMPFIRE_COOKING, new SingleItemInput<>(new OptimizedIDItem<>(
item.recipeIngredientId(), item.getItem()
return BukkitRecipeManager.instance().recipeByInput(RecipeTypes.CAMPFIRE_COOKING, new SingleItemInput<>(new UniqueIdItem<>(
item.recipeIngredientId(), item
))) != null;
});
registerInteraction(BlockKeys.DECORATED_POT, (player, item, blockState, result) -> true);

View File

@@ -1,5 +1,8 @@
package net.momirealms.craftengine.bukkit.util;
import net.momirealms.craftengine.core.util.VersionHelper;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
@@ -7,6 +10,14 @@ public class InventoryUtils {
private InventoryUtils() {}
public static Player getPlayerFromInventoryEvent(InventoryEvent event) {
if (VersionHelper.isOrAbove1_21()) {
return (Player) event.getView().getPlayer();
} else {
return LegacyInventoryUtils.getPlayerFromInventoryEvent(event);
}
}
public static int getSuitableHotBarSlot(PlayerInventory inventory) {
int selectedSlot = inventory.getHeldItemSlot();
int i;