9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-27 02:49: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

@@ -1,6 +1,7 @@
package net.momirealms.craftengine.bukkit.util;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryEvent;
import org.bukkit.event.inventory.PrepareAnvilEvent;
import org.bukkit.inventory.AnvilInventory;
import org.bukkit.inventory.Inventory;
@@ -65,4 +66,8 @@ public class LegacyInventoryUtils {
public static void openWorkbench(Player player) {
player.openWorkbench(null, true);
}
public static Player getPlayerFromInventoryEvent(InventoryEvent event) {
return (Player) event.getView().getPlayer();
}
}

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;

View File

@@ -135,6 +135,11 @@ warning.config.recipe.smithing_transform.post_processor.missing_type: "<yellow>I
warning.config.recipe.smithing_transform.post_processor.invalid_type: "<yellow>Issue found in file <arg:0> - The smithing transform recipe '<arg:1>' is using an invalid post processor type '<arg:2>'.</yellow>"
warning.config.recipe.smithing_transform.post_processor.keep_component.missing_components: "<yellow>Issue found in file <arg:0> - The smithing transform recipe '<arg:1>' is missing the required argument 'components' for post-processors 'keep_components'.</yellow>"
warning.config.recipe.smithing_transform.post_processor.keep_component.missing_tags: "<yellow>Issue found in file <arg:0> - The smithing transform recipe '<arg:1>' is missing the required argument 'tags' for post-processors 'keep_tags'.</yellow>"
warning.config.recipe.smithing_transform.missing_base: "<yellow>Issue found in file <arg:0> - The smithing transform recipe '<arg:1>' is missing the required 'base' argument.</yellow>"
warning.config.recipe.smithing_trim.missing_base: "<yellow>Issue found in file <arg:0> - The smithing trim recipe '<arg:1>' is missing the required 'base' argument.</yellow>"
warning.config.recipe.smithing_trim.missing_template_type: "<yellow>Issue found in file <arg:0> - The smithing trim recipe '<arg:1>' is missing the required 'template-type' argument.</yellow>"
warning.config.recipe.smithing_trim.missing_addition: "<yellow>Issue found in file <arg:0> - The smithing trim recipe '<arg:1>' is missing the required 'addition' argument.</yellow>"
warning.config.recipe.smithing_trim.missing_pattern: "<yellow>Issue found in file <arg:0> - The smithing trim recipe '<arg:1>' is missing the required 'pattern' argument.</yellow>"
warning.config.i18n.unknown_locale: "<yellow>Issue found in file <arg:0> - Unknown locale '<arg:1>'.</yellow>"
warning.config.template.duplicate: "<yellow>Issue found in file <arg:0> - Duplicated template '<arg:1>'. Please check if there is the same configuration in other files.</yellow>"
warning.config.template.invalid: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid template '<arg:2>'.</yellow>"

View File

@@ -135,6 +135,11 @@ warning.config.recipe.smithing_transform.post_processor.missing_type: "<yellow>
warning.config.recipe.smithing_transform.post_processor.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - 锻造升级配方 '<arg:1>' 使用了无效的后处理器类型 '<arg:2>'</yellow>"
warning.config.recipe.smithing_transform.post_processor.keep_component.missing_components: "<yellow>在文件 <arg:0> 发现问题 - 锻造升级配方 '<arg:1>' 的 'keep_components' 后处理器缺少必需的 'components' 参数</yellow>"
warning.config.recipe.smithing_transform.post_processor.keep_component.missing_tags: "<yellow>在文件 <arg:0> 发现问题 - 锻造升级配方 '<arg:1>' 的 'keep_tags' 后处理器缺少必需的 'tags' 参数</yellow>"
warning.config.recipe.smithing_transform.missing_base: "<yellow>在文件 <arg:0> 发现问题 - 锻造升级配方 '<arg:1>' 缺少必需的 'base' 参数</yellow>"
warning.config.recipe.smithing_trim.missing_base: "<yellow>在文件 <arg:0> 发现问题 - 锻造纹饰配方 '<arg:1>' 缺少必需的 'base' 参数</yellow>"
warning.config.recipe.smithing_trim.missing_template_type: "<yellow>在文件 <arg:0> 发现问题 - 锻造纹饰配方 '<arg:1>' 缺少必需的 'template-type' 参数</yellow>"
warning.config.recipe.smithing_trim.missing_addition: "<yellow>在文件 <arg:0> 发现问题 - 锻造纹饰配方 '<arg:1>' 缺少必需的 'addition' 参数</yellow>"
warning.config.recipe.smithing_trim.missing_pattern: "<yellow>在文件 <arg:0> 发现问题 - 锻造纹饰配方 '<arg:1>' 缺少必需的 'pattern' 参数</yellow>"
warning.config.i18n.unknown_locale: "<yellow>在文件 <arg:0> 发现问题 - 未知的语言环境 '<arg:1>'</yellow>"
warning.config.template.duplicate: "<yellow>在文件 <arg:0> 发现问题 - 重复的模板 '<arg:1>' 请检查其他文件中是否存在相同配置</yellow>"
warning.config.template.argument.self_increase_int.invalid_range: "<yellow>在文件 <arg:0> 发现问题 - 模板 '<arg:1>' 在 'self_increase_int' 参数中使用了一个起始值 '<arg:2>' 大于终止值 '<arg:3>'</yellow>"

View File

@@ -331,8 +331,13 @@ public class AbstractItem<W extends ItemWrapper<I>, I> implements Item<I> {
}
@Override
public Tag getNBTTag(Object... path) {
return this.factory.getNBTTag(this.item, path);
public Tag getTag(Object... path) {
return this.factory.getTag(this.item, path);
}
@Override
public Object getExactTag(Object... path) {
return this.factory.getExactTag(this.item, path);
}
@Override
@@ -366,6 +371,11 @@ public class AbstractItem<W extends ItemWrapper<I>, I> implements Item<I> {
return this.factory.getExactComponent(this.item, type);
}
@Override
public void setExactComponent(Object type, Object value) {
this.factory.setExactComponent(this.item, type, value);
}
@Override
public Object getJavaComponent(Object type) {
return this.factory.getJavaComponent(this.item, type);

View File

@@ -600,7 +600,7 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
Map<String, Object> data = MiscUtils.castToMap(obj, false);
String material = data.get("material").toString().toLowerCase(Locale.ENGLISH);
String pattern = data.get("pattern").toString().toLowerCase(Locale.ENGLISH);
return new TrimModifier<>(material, pattern);
return new TrimModifier<>(Key.of(material), Key.of(pattern));
}, "trim");
registerDataType((obj) -> {
List<Key> components = MiscUtils.getAsStringList(obj).stream().map(Key::of).toList();

View File

@@ -141,7 +141,9 @@ public interface Item<I> {
Object getJavaTag(Object... path);
Tag getNBTTag(Object... path);
Tag getTag(Object... path);
Object getExactTag(Object... path);
Item<I> setTag(Object value, Object... path);
@@ -153,6 +155,8 @@ public interface Item<I> {
void removeComponent(Object type);
void setExactComponent(Object type, Object value);
Object getExactComponent(Object type);
Object getJavaComponent(Object type);

View File

@@ -38,7 +38,7 @@ public abstract class ItemFactory<W extends ItemWrapper<I>, I> {
protected abstract Object getJavaTag(W item, Object... path);
protected abstract Tag getNBTTag(W item, Object... path);
protected abstract Tag getTag(W item, Object... path);
protected abstract void setTag(W item, Object value, Object... path);
@@ -50,6 +50,10 @@ public abstract class ItemFactory<W extends ItemWrapper<I>, I> {
protected abstract Object getExactComponent(W item, Object type);
protected abstract Object getExactTag(W item, Object... path);
protected abstract void setExactComponent(W item, Object type, Object value);
protected abstract Object getJavaComponent(W item, Object type);
protected abstract JsonElement getJsonComponent(W item, Object type);

View File

@@ -4,6 +4,7 @@ import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
import net.momirealms.craftengine.core.item.equipment.Equipment;
import net.momirealms.craftengine.core.item.modifier.ItemDataModifier;
import net.momirealms.craftengine.core.item.recipe.UniqueIdItem;
import net.momirealms.craftengine.core.pack.model.LegacyOverridesModel;
import net.momirealms.craftengine.core.pack.model.ModernItemModel;
import net.momirealms.craftengine.core.pack.model.generation.ModelGenerator;
@@ -107,4 +108,8 @@ public interface ItemManager<T> extends Manageable, ModelGenerator {
Item<T> s2c(Item<T> item, Player player);
Item<T> c2s(Item<T> item);
UniqueIdItem<T> uniqueEmptyItem();
Item<T> applyTrim(Item<T> base, Item<T> addition, Item<T> template, Key pattern);
}

View File

@@ -1,4 +1,6 @@
package net.momirealms.craftengine.core.item.data;
public record Trim(String pattern, String material) {
import net.momirealms.craftengine.core.util.Key;
public record Trim(Key pattern, Key material) {
}

View File

@@ -41,7 +41,7 @@ public class TrimBasedEquipment extends AbstractEquipment {
@Override
public <I> List<ItemDataModifier<I>> modifiers() {
return List.of(
new TrimModifier<>(AbstractPackManager.NEW_TRIM_MATERIAL, this.assetId.toString()),
new TrimModifier<>(Key.of(AbstractPackManager.NEW_TRIM_MATERIAL), this.assetId),
new HideTooltipModifier<>(List.of(ComponentKeys.TRIM))
);
}

View File

@@ -178,7 +178,7 @@ public class AttributeModifiersModifier<I> implements ItemDataModifier<I> {
networkData.put(ComponentKeys.ATTRIBUTE_MODIFIERS.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE));
}
} else {
Tag previous = item.getNBTTag("AttributeModifiers");
Tag previous = item.getTag("AttributeModifiers");
if (previous != null) {
networkData.put("AttributeModifiers", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {

View File

@@ -59,7 +59,7 @@ public class ComponentModifier<I> implements ItemDataModifier<I> {
item.setNBTComponent(entry.left(), entry.right());
}
if (this.customData != null) {
CompoundTag tag = (CompoundTag) item.getNBTTag(ComponentKeys.CUSTOM_DATA);
CompoundTag tag = (CompoundTag) item.getTag(ComponentKeys.CUSTOM_DATA);
if (tag != null) {
for (Map.Entry<String, Tag> entry : this.customData.entrySet()) {
tag.put(entry.getKey(), entry.getValue());

View File

@@ -36,7 +36,7 @@ public class CustomModelDataModifier<I> implements ItemDataModifier<I> {
networkData.put(ComponentKeys.CUSTOM_MODEL_DATA.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE));
}
} else {
Tag previous = item.getNBTTag("CustomModelData");
Tag previous = item.getTag("CustomModelData");
if (previous != null) {
networkData.put("CustomModelData", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {

View File

@@ -46,7 +46,7 @@ public class CustomNameModifier<I> implements ItemDataModifier<I> {
networkData.put(ComponentKeys.CUSTOM_NAME.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE));
}
} else {
Tag previous = item.getNBTTag("display", "Name");
Tag previous = item.getTag("display", "Name");
if (previous != null) {
networkData.put("display.Name", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {

View File

@@ -36,7 +36,7 @@ public class DyedColorModifier<I> implements ItemDataModifier<I> {
networkData.put(ComponentKeys.DYED_COLOR.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE));
}
} else {
Tag previous = item.getNBTTag("display", "color");
Tag previous = item.getTag("display", "color");
if (previous != null) {
networkData.put("display.color", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {

View File

@@ -54,7 +54,7 @@ public class DynamicLoreModifier<I> implements ItemDataModifier<I> {
networkData.put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE));
}
} else {
Tag previous = item.getNBTTag("display", "Lore");
Tag previous = item.getTag("display", "Lore");
if (previous != null) {
networkData.put("display.Lore", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {

View File

@@ -41,7 +41,7 @@ public class EnchantmentModifier<I> implements ItemDataModifier<I> {
networkData.put(ComponentKeys.STORED_ENCHANTMENTS.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE));
}
} else {
Tag previous = item.getNBTTag("StoredEnchantments");
Tag previous = item.getTag("StoredEnchantments");
if (previous != null) {
networkData.put("StoredEnchantments", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {
@@ -57,7 +57,7 @@ public class EnchantmentModifier<I> implements ItemDataModifier<I> {
networkData.put(ComponentKeys.ENCHANTMENTS.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE));
}
} else {
Tag previous = item.getNBTTag("Enchantments");
Tag previous = item.getTag("Enchantments");
if (previous != null) {
networkData.put("Enchantments", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {

View File

@@ -94,7 +94,7 @@ public class HideTooltipModifier<I> implements ItemDataModifier<I> {
}
}
} else {
Tag previous = item.getNBTTag("HideFlags");
Tag previous = item.getTag("HideFlags");
if (previous != null) {
networkData.put("HideFlags", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {

View File

@@ -37,7 +37,7 @@ public class ItemNameModifier<I> implements ItemDataModifier<I> {
networkData.put(ComponentKeys.ITEM_NAME.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE));
}
} else {
Tag previous = item.getNBTTag("display", "Name");
Tag previous = item.getTag("display", "Name");
if (previous != null) {
networkData.put("display.Name", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {

View File

@@ -53,7 +53,7 @@ public class LoreModifier<I> implements ItemDataModifier<I> {
networkData.put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE));
}
} else {
Tag previous = item.getNBTTag("display", "Lore");
Tag previous = item.getTag("display", "Lore");
if (previous != null) {
networkData.put("display.Lore", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {

View File

@@ -41,7 +41,7 @@ public class TagsModifier<I> implements ItemDataModifier<I> {
@Override
public Item<I> prepareNetworkItem(Item<I> item, ItemBuildContext context, CompoundTag networkData) {
for (Map.Entry<String, Object> entry : this.arguments.entrySet()) {
Tag previous = item.getNBTTag(entry.getKey());
Tag previous = item.getTag(entry.getKey());
if (previous != null) {
networkData.put(entry.getKey(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {

View File

@@ -5,15 +5,16 @@ import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.ItemBuildContext;
import net.momirealms.craftengine.core.item.NetworkItemHandler;
import net.momirealms.craftengine.core.item.data.Trim;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.sparrow.nbt.CompoundTag;
import net.momirealms.sparrow.nbt.Tag;
public class TrimModifier<I> implements ItemDataModifier<I> {
private final String material;
private final String pattern;
private final Key material;
private final Key pattern;
public TrimModifier(String material, String pattern) {
public TrimModifier(Key material, Key pattern) {
this.material = material;
this.pattern = pattern;
}
@@ -39,7 +40,7 @@ public class TrimModifier<I> implements ItemDataModifier<I> {
networkData.put(ComponentKeys.TRIM.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE));
}
} else {
Tag previous = item.getNBTTag("Trim");
Tag previous = item.getTag("Trim");
if (previous != null) {
networkData.put("Trim", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {

View File

@@ -36,7 +36,7 @@ public class UnbreakableModifier<I> implements ItemDataModifier<I> {
networkData.put(ComponentKeys.UNBREAKABLE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE));
}
} else {
Tag previous = item.getNBTTag("Unbreakable");
Tag previous = item.getTag("Unbreakable");
if (previous != null) {
networkData.put("Unbreakable", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {

View File

@@ -1,10 +1,11 @@
package net.momirealms.craftengine.core.item.recipe;
import net.momirealms.craftengine.core.item.ItemBuildContext;
import net.momirealms.craftengine.core.item.recipe.input.RecipeInput;
import net.momirealms.craftengine.core.util.Key;
import org.jetbrains.annotations.Nullable;
public abstract class AbstractGroupedRecipe<T> implements Recipe<T> {
public abstract class AbstractGroupedRecipe<T> implements FixedResultRecipe<T> {
protected final String group;
protected final Key id;
protected final CustomRecipeResult<T> result;
@@ -15,6 +16,11 @@ public abstract class AbstractGroupedRecipe<T> implements Recipe<T> {
this.result = result;
}
@Override
public T assemble(RecipeInput input, ItemBuildContext context) {
return this.result(context);
}
@Nullable
public String group() {
return group;

View File

@@ -5,6 +5,7 @@ import net.momirealms.craftengine.core.item.recipe.vanilla.VanillaRecipeReader;
import net.momirealms.craftengine.core.item.recipe.vanilla.reader.VanillaRecipeReader1_20;
import net.momirealms.craftengine.core.item.recipe.vanilla.reader.VanillaRecipeReader1_20_5;
import net.momirealms.craftengine.core.item.recipe.vanilla.reader.VanillaRecipeReader1_21_2;
import net.momirealms.craftengine.core.item.recipe.vanilla.reader.VanillaRecipeReader1_21_5;
import net.momirealms.craftengine.core.pack.LoadingSequence;
import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.plugin.CraftEngine;
@@ -41,7 +42,9 @@ public abstract class AbstractRecipeManager<T> implements RecipeManager<T> {
}
private VanillaRecipeReader initVanillaRecipeReader() {
if (VersionHelper.isOrAbove1_21_2()) {
if (VersionHelper.isOrAbove1_21_5()) {
return new VanillaRecipeReader1_21_5();
} else if (VersionHelper.isOrAbove1_21_2()) {
return new VanillaRecipeReader1_21_2();
} else if (VersionHelper.isOrAbove1_20_5()) {
return new VanillaRecipeReader1_20_5();
@@ -137,7 +140,9 @@ public abstract class AbstractRecipeManager<T> implements RecipeManager<T> {
protected void registerInternalRecipe(Key id, Recipe<T> recipe) {
this.byType.computeIfAbsent(recipe.type(), k -> new ArrayList<>()).add(recipe);
this.byId.put(id, recipe);
this.byResult.computeIfAbsent(recipe.result().item().id(), k -> new ArrayList<>()).add(recipe);
if (recipe instanceof FixedResultRecipe<?> fixedResult) {
this.byResult.computeIfAbsent(fixedResult.result().item().id(), k -> new ArrayList<>()).add(recipe);
}
HashSet<Key> usedKeys = new HashSet<>();
for (Ingredient<T> ingredient : recipe.ingredientsInUse()) {
for (UniqueKey holder : ingredient.items()) {

View File

@@ -106,7 +106,7 @@ public class CustomShapedRecipe<T> extends CustomCraftingTableRecipe<T> {
} else {
optional = this.ingredients.get(j + i * this.width);
}
OptimizedIDItem<T> itemStack = input.getItem(j, i);
UniqueIdItem<T> itemStack = input.getItem(j, i);
if (!Ingredient.isInstance(optional, itemStack)) {
return false;
}

View File

@@ -15,7 +15,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.*;
public class CustomSmithingTransformRecipe<T> implements Recipe<T> {
public class CustomSmithingTransformRecipe<T> implements FixedResultRecipe<T> {
public static final Factory<?> FACTORY = new Factory<>();
private final Key id;
private final CustomRecipeResult<T> result;
@@ -51,7 +51,7 @@ public class CustomSmithingTransformRecipe<T> implements Recipe<T> {
&& checkIngredient(this.addition, smithingInput.addition());
}
private boolean checkIngredient(Ingredient<T> ingredient, OptimizedIDItem<T> item) {
private boolean checkIngredient(Ingredient<T> ingredient, UniqueIdItem<T> item) {
if (ingredient != null) {
if (item == null || item.isEmpty()) {
return false;
@@ -85,13 +85,16 @@ public class CustomSmithingTransformRecipe<T> implements Recipe<T> {
return this.id;
}
@Override
@Nullable
public T result(ItemBuildContext context) {
return this.result.buildItemStack(context);
}
@SuppressWarnings("unchecked")
public T assemble(ItemBuildContext context, Item<T> base) {
@Override
public T assemble(RecipeInput input, ItemBuildContext context) {
SmithingInput<T> smithingInput = ((SmithingInput<T>) input);
Item<T> base = smithingInput.base().item();
T result = this.result(context);
Item<T> wrappedResult = (Item<T>) CraftEngine.instance().itemManager().wrap(result);
Item<T> finalResult = wrappedResult;
@@ -104,7 +107,6 @@ public class CustomSmithingTransformRecipe<T> implements Recipe<T> {
return finalResult.getItem();
}
@Override
public CustomRecipeResult<T> result() {
return this.result;
}
@@ -130,6 +132,9 @@ public class CustomSmithingTransformRecipe<T> implements Recipe<T> {
@Override
public Recipe<A> create(Key id, Map<String, Object> arguments) {
List<String> base = MiscUtils.getAsStringList(arguments.get("base"));
if (base.isEmpty()) {
throw new LocalizedResourceConfigException("warning.config.recipe.smithing_transform.missing_base");
}
List<String> addition = MiscUtils.getAsStringList(arguments.get("addition"));
List<String> template = MiscUtils.getAsStringList(arguments.get("template-type"));
boolean mergeComponents = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("merge-components", true), "merge-components");

View File

@@ -0,0 +1,140 @@
package net.momirealms.craftengine.core.item.recipe;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.ItemBuildContext;
import net.momirealms.craftengine.core.item.recipe.input.RecipeInput;
import net.momirealms.craftengine.core.item.recipe.input.SmithingInput;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.util.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
public class CustomSmithingTrimRecipe<T> implements Recipe<T> {
public static final Factory<?> FACTORY = new Factory<>();
private final Key id;
private final Ingredient<T> base;
private final Ingredient<T> template;
private final Ingredient<T> addition;
@Nullable // 1.21.5
private final Key pattern;
public CustomSmithingTrimRecipe(@NotNull Key id,
@NotNull Ingredient<T> base,
@NotNull Ingredient<T> template,
@NotNull Ingredient<T> addition,
@Nullable Key pattern
) {
this.id = id;
this.base = base;
this.template = template;
this.addition = addition;
this.pattern = pattern;
if (pattern == null && VersionHelper.isOrAbove1_21_5()) {
throw new IllegalStateException("SmithingTrimRecipe cannot have a null pattern on 1.21.5 and above.");
}
}
@SuppressWarnings("unchecked")
@Override
public T assemble(RecipeInput input, ItemBuildContext context) {
SmithingInput<T> smithingInput = (SmithingInput<T>) input;
Item<T> processed = (Item<T>) CraftEngine.instance().itemManager().applyTrim((Item<Object>) smithingInput.base(), (Item<Object>) smithingInput.addition(), (Item<Object>) smithingInput.template(), this.pattern);
return processed.getItem();
}
@SuppressWarnings("unchecked")
@Override
public boolean matches(RecipeInput input) {
SmithingInput<T> smithingInput = (SmithingInput<T>) input;
return checkIngredient(this.base, smithingInput.base())
&& checkIngredient(this.template, smithingInput.template())
&& checkIngredient(this.addition, smithingInput.addition());
}
private boolean checkIngredient(Ingredient<T> ingredient, UniqueIdItem<T> item) {
if (ingredient != null) {
if (item == null || item.isEmpty()) {
return false;
}
return ingredient.test(item);
} else {
return item == null || item.isEmpty();
}
}
@Override
public List<Ingredient<T>> ingredientsInUse() {
List<Ingredient<T>> ingredients = new ArrayList<>();
ingredients.add(this.base);
ingredients.add(this.template);
ingredients.add(this.addition);
return ingredients;
}
@Override
public @NotNull Key type() {
return RecipeTypes.SMITHING_TRIM;
}
@Override
public Key id() {
return this.id;
}
@Nullable
public Ingredient<T> base() {
return this.base;
}
@Nullable
public Ingredient<T> template() {
return template;
}
@Nullable
public Ingredient<T> addition() {
return addition;
}
@Nullable
public Key pattern() {
return pattern;
}
@SuppressWarnings({"DuplicatedCode"})
public static class Factory<A> implements RecipeFactory<A> {
@Override
public Recipe<A> create(Key id, Map<String, Object> arguments) {
List<String> base = MiscUtils.getAsStringList(arguments.get("base"));
if (base.isEmpty()) {
throw new LocalizedResourceConfigException("warning.config.recipe.smithing_trim.missing_base");
}
List<String> addition = MiscUtils.getAsStringList(arguments.get("addition"));
if (addition.isEmpty()) {
throw new LocalizedResourceConfigException("warning.config.recipe.smithing_trim.missing_addition");
}
List<String> template = MiscUtils.getAsStringList(arguments.get("template-type"));
if (template.isEmpty()) {
throw new LocalizedResourceConfigException("warning.config.recipe.smithing_trim.missing_template_type");
}
Key pattern = VersionHelper.isOrAbove1_21_5() ? Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("pattern"), "warning.config.recipe.smithing_trim.missing_pattern")) : null;
return new CustomSmithingTrimRecipe<>(id, toIngredient(base), toIngredient(template), toIngredient(addition), pattern);
}
private Ingredient<A> toIngredient(List<String> items) {
Set<UniqueKey> holders = new HashSet<>();
for (String item : items) {
if (item.charAt(0) == '#') {
holders.addAll(CraftEngine.instance().itemManager().tagToItems(Key.of(item.substring(1))));
} else {
holders.add(UniqueKey.create(Key.of(item)));
}
}
return Ingredient.of(holders);
}
}
}

View File

@@ -0,0 +1,10 @@
package net.momirealms.craftengine.core.item.recipe;
import net.momirealms.craftengine.core.item.ItemBuildContext;
public interface FixedResultRecipe<T> extends Recipe<T> {
T result(ItemBuildContext context);
CustomRecipeResult<T> result();
}

View File

@@ -5,14 +5,14 @@ import net.momirealms.craftengine.core.util.UniqueKey;
import java.util.*;
import java.util.function.Predicate;
public class Ingredient<T> implements Predicate<OptimizedIDItem<T>>, StackedContents.IngredientInfo<UniqueKey> {
public class Ingredient<T> implements Predicate<UniqueIdItem<T>>, StackedContents.IngredientInfo<UniqueKey> {
private final List<UniqueKey> items;
public Ingredient(List<UniqueKey> items) {
this.items = items;
}
public static <T> boolean isInstance(Optional<Ingredient<T>> optionalIngredient, OptimizedIDItem<T> stack) {
public static <T> boolean isInstance(Optional<Ingredient<T>> optionalIngredient, UniqueIdItem<T> stack) {
return optionalIngredient.map((ingredient) -> ingredient.test(stack))
.orElseGet(stack::isEmpty);
}
@@ -26,9 +26,9 @@ public class Ingredient<T> implements Predicate<OptimizedIDItem<T>>, StackedCont
}
@Override
public boolean test(OptimizedIDItem<T> optimizedIDItem) {
public boolean test(UniqueIdItem<T> uniqueIdItem) {
for (UniqueKey item : this.items()) {
if (optimizedIDItem.is(item)) {
if (uniqueIdItem.is(item)) {
return true;
}
}

View File

@@ -1,36 +0,0 @@
package net.momirealms.craftengine.core.item.recipe;
import net.momirealms.craftengine.core.util.UniqueKey;
public class OptimizedIDItem<T> {
private final T rawItem;
private final UniqueKey uniqueId;
public OptimizedIDItem(UniqueKey uniqueId, T rawItem) {
this.uniqueId = uniqueId;
this.rawItem = rawItem;
}
public UniqueKey id() {
return uniqueId;
}
public T rawItem() {
return rawItem;
}
public boolean is(UniqueKey id) {
return uniqueId == id;
}
public boolean isEmpty() {
return uniqueId == null;
}
@Override
public String toString() {
return "OptimizedIDItem{" +
"uniqueId=" + uniqueId +
'}';
}
}

View File

@@ -11,9 +11,7 @@ public interface Recipe<T> {
boolean matches(RecipeInput input);
T result(ItemBuildContext context);
CustomRecipeResult<T> result();
T assemble(RecipeInput input, ItemBuildContext context);
List<Ingredient<T>> ingredientsInUse();

View File

@@ -7,7 +7,7 @@ import java.util.List;
public class RecipeFinder {
private final StackedContents<UniqueKey> stackedContents = new StackedContents<>();
public <T> void addInput(OptimizedIDItem<T> item) {
public <T> void addInput(UniqueIdItem<T> item) {
if (!item.isEmpty()) {
this.stackedContents.add(item.id(), 1);
}

View File

@@ -30,6 +30,7 @@ public class RecipeTypes {
register(CAMPFIRE_COOKING, CustomCampfireRecipe.FACTORY);
register(STONECUTTING, CustomStoneCuttingRecipe.FACTORY);
register(SMITHING_TRANSFORM, CustomSmithingTransformRecipe.FACTORY);
register(SMITHING_TRIM, CustomSmithingTrimRecipe.FACTORY);
}
public static <T> void register(Key key, RecipeFactory<T> factory) {

View File

@@ -0,0 +1,38 @@
package net.momirealms.craftengine.core.item.recipe;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.util.UniqueKey;
import org.jetbrains.annotations.NotNull;
public class UniqueIdItem<T> {
private final Item<T> rawItem;
private final UniqueKey uniqueId;
public UniqueIdItem(@NotNull UniqueKey uniqueId, @NotNull Item<T> rawItem) {
this.uniqueId = uniqueId;
this.rawItem = rawItem;
}
@NotNull
public UniqueKey id() {
return uniqueId;
}
@NotNull
public Item<T> item() {
return this.rawItem;
}
public boolean is(UniqueKey id) {
return this.uniqueId == id;
}
public boolean isEmpty() {
return this.uniqueId == UniqueKey.AIR;
}
@Override
public String toString() {
return "UniqueIdItem[" + "uniqueId=" + uniqueId + ", item=" + rawItem.getItem() + ']';
}
}

View File

@@ -1,7 +1,7 @@
package net.momirealms.craftengine.core.item.recipe.input;
import net.momirealms.craftengine.core.item.recipe.OptimizedIDItem;
import net.momirealms.craftengine.core.item.recipe.RecipeFinder;
import net.momirealms.craftengine.core.item.recipe.UniqueIdItem;
import java.util.ArrayList;
import java.util.Collections;
@@ -10,16 +10,16 @@ import java.util.List;
public class CraftingInput<T> implements RecipeInput {
private final int width;
private final int height;
private final List<OptimizedIDItem<T>> items;
private final List<UniqueIdItem<T>> items;
private final int ingredientCount;
private final RecipeFinder finder = new RecipeFinder();
private CraftingInput(int width, int height, List<OptimizedIDItem<T>> items) {
private CraftingInput(int width, int height, List<UniqueIdItem<T>> items) {
this.height = height;
this.width = width;
this.items = items;
int i = 0;
for (OptimizedIDItem<T> item : items) {
for (UniqueIdItem<T> item : items) {
if (!item.isEmpty()) {
i++;
this.finder.addInput(item);
@@ -32,7 +32,7 @@ public class CraftingInput<T> implements RecipeInput {
return finder;
}
public static <T> CraftingInput<T> of(int width, int height, List<OptimizedIDItem<T>> stacks) {
public static <T> CraftingInput<T> of(int width, int height, List<UniqueIdItem<T>> stacks) {
if (width <= 0 || height <= 0) {
return new CraftingInput<>(0, 0, Collections.emptyList());
}
@@ -43,7 +43,7 @@ public class CraftingInput<T> implements RecipeInput {
int maxRow = -1;
for (int index = 0; index < width * height; index++) {
OptimizedIDItem<T> item = stacks.get(index);
UniqueIdItem<T> item = stacks.get(index);
if (!item.isEmpty()) {
int row = index / width;
int col = index % width;
@@ -65,7 +65,7 @@ public class CraftingInput<T> implements RecipeInput {
return new CraftingInput<>(width, height, stacks);
}
List<OptimizedIDItem<T>> trimmed = new ArrayList<>(newWidth * newHeight);
List<UniqueIdItem<T>> trimmed = new ArrayList<>(newWidth * newHeight);
for (int row = minRow; row <= maxRow; row++) {
for (int col = minCol; col <= maxCol; col++) {
int originalIndex = col + row * width;
@@ -92,11 +92,11 @@ public class CraftingInput<T> implements RecipeInput {
return items.size();
}
public OptimizedIDItem<T> getItem(int x, int y) {
public UniqueIdItem<T> getItem(int x, int y) {
return this.items.get(x + y * width);
}
public OptimizedIDItem<T> getItem(int index) {
public UniqueIdItem<T> getItem(int index) {
return this.items.get(index);
}
}

View File

@@ -1,6 +1,6 @@
package net.momirealms.craftengine.core.item.recipe.input;
import net.momirealms.craftengine.core.item.recipe.OptimizedIDItem;
import net.momirealms.craftengine.core.item.recipe.UniqueIdItem;
public record SingleItemInput<T>(OptimizedIDItem<T> input) implements RecipeInput {
public record SingleItemInput<T>(UniqueIdItem<T> input) implements RecipeInput {
}

View File

@@ -1,33 +1,34 @@
package net.momirealms.craftengine.core.item.recipe.input;
import net.momirealms.craftengine.core.item.recipe.OptimizedIDItem;
import net.momirealms.craftengine.core.item.recipe.UniqueIdItem;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class SmithingInput<T> implements RecipeInput {
private final OptimizedIDItem<T> base;
private final OptimizedIDItem<T> template;
private final OptimizedIDItem<T> addition;
private final UniqueIdItem<T> base;
private final UniqueIdItem<T> template;
private final UniqueIdItem<T> addition;
public SmithingInput(@Nullable OptimizedIDItem<T> base,
@Nullable OptimizedIDItem<T> template,
@Nullable OptimizedIDItem<T> addition) {
public SmithingInput(@NotNull UniqueIdItem<T> base,
@Nullable UniqueIdItem<T> template,
@Nullable UniqueIdItem<T> addition) {
this.base = base;
this.template = template;
this.addition = addition;
}
@Nullable
public OptimizedIDItem<T> base() {
@NotNull
public UniqueIdItem<T> base() {
return base;
}
@Nullable
public OptimizedIDItem<T> template() {
public UniqueIdItem<T> template() {
return template;
}
@Nullable
public OptimizedIDItem<T> addition() {
public UniqueIdItem<T> addition() {
return addition;
}
}

View File

@@ -13,7 +13,6 @@ public abstract class VanillaGroupedRecipe implements VanillaRecipe {
return group;
}
@Override
public RecipeResult result() {
return result;
}

View File

@@ -5,6 +5,4 @@ import net.momirealms.craftengine.core.util.Key;
public interface VanillaRecipe {
Key type();
RecipeResult result();
}

View File

@@ -19,4 +19,6 @@ public interface VanillaRecipeReader {
VanillaStoneCuttingRecipe readStoneCutting(JsonObject json);
VanillaSmithingTransformRecipe readSmithingTransform(JsonObject json);
VanillaSmithingTrimRecipe readSmithingTrim(JsonObject json);
}

View File

@@ -23,7 +23,6 @@ public class VanillaSmithingTransformRecipe implements VanillaRecipe {
return RecipeTypes.SMITHING_TRANSFORM;
}
@Override
public RecipeResult result() {
return result;
}

View File

@@ -0,0 +1,45 @@
package net.momirealms.craftengine.core.item.recipe.vanilla;
import net.momirealms.craftengine.core.item.recipe.RecipeTypes;
import net.momirealms.craftengine.core.util.Key;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class VanillaSmithingTrimRecipe implements VanillaRecipe {
@Nullable // 1.21.5
private final String pattern;
private final List<String> base;
private final List<String> template;
private final List<String> addition;
public VanillaSmithingTrimRecipe(List<String> base, List<String> template, List<String> addition, @Nullable String pattern) {
this.base = base;
this.template = template;
this.addition = addition;
this.pattern = pattern;
}
@Override
public Key type() {
return RecipeTypes.SMITHING_TRIM;
}
public List<String> base() {
return base;
}
public List<String> template() {
return template;
}
public List<String> addition() {
return addition;
}
@Nullable
public String pattern() {
return pattern;
}
}

View File

@@ -101,6 +101,16 @@ public class VanillaRecipeReader1_20 extends AbstractRecipeReader {
);
}
@Override
public VanillaSmithingTrimRecipe readSmithingTrim(JsonObject json) {
return new VanillaSmithingTrimRecipe(
readSingleIngredient(json.get("base")),
readSingleIngredient(json.get("template")),
readSingleIngredient(json.get("addition")),
null
);
}
protected List<String> readSingleIngredient(JsonElement json) {
List<String> ingredients = new ArrayList<>();
if (json.isJsonObject()) {

View File

@@ -0,0 +1,17 @@
package net.momirealms.craftengine.core.item.recipe.vanilla.reader;
import com.google.gson.JsonObject;
import net.momirealms.craftengine.core.item.recipe.vanilla.VanillaSmithingTrimRecipe;
public class VanillaRecipeReader1_21_5 extends VanillaRecipeReader1_21_2 {
@Override
public VanillaSmithingTrimRecipe readSmithingTrim(JsonObject json) {
return new VanillaSmithingTrimRecipe(
readSingleIngredient(json.get("base")),
readSingleIngredient(json.get("template")),
readSingleIngredient(json.get("addition")),
json.get("pattern").getAsString()
);
}
}

View File

@@ -1,5 +1,6 @@
package net.momirealms.craftengine.core.util;
import net.momirealms.craftengine.core.item.ItemKeys;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
@@ -7,6 +8,8 @@ import java.util.Map;
public final class UniqueKey {
private static final Map<Key, UniqueKey> CACHE = new HashMap<>(4096, 0.5f);
public static final UniqueKey AIR = UniqueKey.create(ItemKeys.AIR);
private final Key key;
private UniqueKey(Key key) {
@@ -23,6 +26,11 @@ public final class UniqueKey {
}
public Key key() {
return key;
return this.key;
}
@Override
public String toString() {
return this.key.toString();
}
}

View File

@@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G
# Project settings
# Rule: [major update].[feature update].[bug fix]
project_version=0.0.59.8
project_version=0.0.59.9
config_version=41
lang_version=22
project_group=net.momirealms
@@ -23,10 +23,10 @@ jar_relocator_version=1.7
adventure_bundle_version=4.23.0
cloud_core_version=2.0.0
cloud_services_version=2.0.0
cloud_brigadier_version=2.0.0-beta.10
cloud_bukkit_version=2.0.0-beta.10
cloud_paper_version=2.0.0-beta.10
cloud_minecraft_extras_version=2.0.0-beta.10
cloud_brigadier_version=2.0.0-beta.11
cloud_bukkit_version=2.0.0-beta.11
cloud_paper_version=2.0.0-beta.11
cloud_minecraft_extras_version=2.0.0-beta.11
boosted_yaml_version=1.3.7
bstats_version=3.1.0
caffeine_version=3.2.0
@@ -50,7 +50,7 @@ byte_buddy_version=1.17.5
ahocorasick_version=0.6.3
snake_yaml_version=2.4
anti_grief_version=0.18
nms_helper_version=1.0.30
nms_helper_version=1.0.32
evalex_version=3.5.0
reactive_streams_version=1.0.4
amazon_awssdk_version=2.31.23