9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-25 09:59:20 +00:00

trim配方

This commit is contained in:
XiaoMoMi
2025-07-13 23:28:44 +08:00
parent 1a9f690e3b
commit 5244524d4b
13 changed files with 215 additions and 71 deletions

View File

@@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.item.recipe;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import io.papermc.paper.potion.PotionMix;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
@@ -273,6 +274,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
private Object stolenFeatureFlagSet;
// Some delayed tasks on main thread
private final List<Runnable> delayedTasksOnMainThread = new ArrayList<>();
private final Map<Key, PotionMix> brewingRecipes = new HashMap<>();
public BukkitRecipeManager(BukkitCraftEngine plugin) {
instance = this;
@@ -324,24 +326,16 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
@Override
public void unload() {
if (!Config.enableRecipeSystem()) return;
super.unload();
if (VersionHelper.isOrAbove1_21_2()) {
if (Bukkit.getServer().isStopping()) {
try {
CoreReflections.method$RecipeManager$finalizeRecipeLoading.invoke(nmsRecipeManager);
} catch (ReflectiveOperationException e) {
this.plugin.logger().warn("Failed to unregister recipes", e);
}
} else {
this.plugin.scheduler().executeSync(() -> {
try {
CoreReflections.method$RecipeManager$finalizeRecipeLoading.invoke(nmsRecipeManager);
} catch (ReflectiveOperationException e) {
this.plugin.logger().warn("Failed to unregister recipes", e);
}
});
// 安排卸载任务这些任务会在load后执行。如果没有load说明服务器已经关闭了那就不需要管卸载了。
if (!Bukkit.isStopping()) {
for (Map.Entry<Key, Recipe<ItemStack>> entry : this.byId.entrySet()) {
Key id = entry.getKey();
if (isDataPackRecipe(id)) continue;
boolean isBrewingRecipe = entry.getValue() instanceof CustomBrewingRecipe<ItemStack>;
this.delayedTasksOnMainThread.add(() -> this.unregisterPlatformRecipe(id, isBrewingRecipe));
}
}
super.unload();
}
@Override
@@ -354,6 +348,12 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
public void disable() {
unload();
CE_RECIPE_2_NMS_HOLDER.clear();
// 不是服务器关闭造成disable那么需要把配方卸载干净
if (!Bukkit.isStopping()) {
for (Runnable task : this.delayedTasksOnMainThread) {
task.run();
}
}
HandlerList.unregisterAll(this.recipeEventListener);
if (this.crafterEventListener != null) {
HandlerList.unregisterAll(this.crafterEventListener);
@@ -361,21 +361,42 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
}
@Override
protected void unregisterPlatformRecipe(Key key) {
unregisterNMSRecipe(new NamespacedKey(key.namespace(), key.value()));
protected void unregisterPlatformRecipe(Key key, boolean isBrewingRecipe) {
if (isBrewingRecipe) {
Bukkit.getPotionBrewer().removePotionMix(new NamespacedKey(key.namespace(), key.value()));
} else {
unregisterNMSRecipe(new NamespacedKey(key.namespace(), key.value()));
}
}
@Override
protected void registerPlatformRecipe(Key id, Recipe<ItemStack> recipe) {
try {
Runnable converted = findNMSRecipeConvertor(recipe).convert(id, recipe);
if (converted != null) {
this.delayedTasksOnMainThread.add(converted);
if (recipe instanceof CustomBrewingRecipe<ItemStack> brewingRecipe) {
PotionMix potionMix = new PotionMix(new NamespacedKey(id.namespace(), id.value()),
brewingRecipe.result(ItemBuildContext.EMPTY),
PotionMix.createPredicateChoice(container -> {
Item<ItemStack> wrapped = this.plugin.itemManager().wrap(container);
return brewingRecipe.container().test(new UniqueIdItem<>(wrapped.recipeIngredientId(), wrapped));
}),
PotionMix.createPredicateChoice(ingredient -> {
Item<ItemStack> wrapped = this.plugin.itemManager().wrap(ingredient);
return brewingRecipe.ingredient().test(new UniqueIdItem<>(wrapped.recipeIngredientId(), wrapped));
})
);
this.delayedTasksOnMainThread.add(() -> {
Bukkit.getPotionBrewer().addPotionMix(potionMix);
});
} else {
try {
Runnable converted = findNMSRecipeConvertor(recipe).convert(id, recipe);
if (converted != null) {
this.delayedTasksOnMainThread.add(converted);
}
} catch (InvalidRecipeIngredientException e) {
throw new LocalizedResourceConfigException("warning.config.recipe.invalid_ingredient", e.ingredient());
} catch (Exception e) {
this.plugin.logger().warn("Failed to convert recipe " + id, e);
}
} catch (InvalidRecipeIngredientException e) {
throw new LocalizedResourceConfigException("warning.config.recipe.invalid_ingredient", e.ingredient());
} catch (Exception e) {
this.plugin.logger().warn("Failed to convert recipe " + id, e);
}
}
@@ -420,11 +441,11 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
// continue;
// }
if (Config.disableAllVanillaRecipes()) {
this.delayedTasksOnMainThread.add(() -> unregisterPlatformRecipe(id));
this.delayedTasksOnMainThread.add(() -> unregisterPlatformRecipe(id, false));
continue;
}
if (hasDisabledAny && Config.disabledVanillaRecipes().contains(id)) {
this.delayedTasksOnMainThread.add(() -> unregisterPlatformRecipe(id));
this.delayedTasksOnMainThread.add(() -> unregisterPlatformRecipe(id, false));
continue;
}
markAsDataPackRecipe(id);

View File

@@ -140,6 +140,8 @@ warning.config.recipe.smithing_trim.missing_base: "<yellow>Issue found in file <
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.recipe.brewing.missing_container: "<yellow>Issue found in file <arg:0> - The brewing recipe '<arg:1>' is missing the required 'container' argument.</yellow>"
warning.config.recipe.brewing.missing_ingredient: "<yellow>Issue found in file <arg:0> - The brewing recipe '<arg:1>' is missing the required 'ingredient' 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

@@ -27,7 +27,6 @@ public abstract class AbstractRecipeManager<T> implements RecipeManager<T> {
protected final Map<Key, List<Recipe<T>>> byResult = new HashMap<>();
protected final Map<Key, List<Recipe<T>>> byIngredient = new HashMap<>();
protected final Set<Key> dataPackRecipes = new HashSet<>();
protected final Set<Key> customRecipes = new HashSet<>();
protected final RecipeParser recipeParser;
protected boolean isReloading;
@@ -60,20 +59,12 @@ public abstract class AbstractRecipeManager<T> implements RecipeManager<T> {
this.byId.clear();
this.byResult.clear();
this.byIngredient.clear();
for (Key key : this.customRecipes) {
unregisterPlatformRecipe(key);
}
this.customRecipes.clear();
}
protected void markAsDataPackRecipe(Key key) {
this.dataPackRecipes.add(key);
}
protected void markAsCustomRecipe(Key key) {
this.customRecipes.add(key);
}
@Override
public boolean isDataPackRecipe(Key key) {
if (this.isReloading) return false;
@@ -175,7 +166,6 @@ public abstract class AbstractRecipeManager<T> implements RecipeManager<T> {
}
Recipe<T> recipe = RecipeTypes.fromMap(id, section);
try {
markAsCustomRecipe(id);
registerInternalRecipe(id, recipe);
registerPlatformRecipe(id, recipe);
} catch (LocalizedResourceConfigException e) {
@@ -186,7 +176,7 @@ public abstract class AbstractRecipeManager<T> implements RecipeManager<T> {
}
}
protected abstract void unregisterPlatformRecipe(Key key);
protected abstract void unregisterPlatformRecipe(Key key, boolean isBrewingRecipe);
protected abstract void registerPlatformRecipe(Key key, Recipe<T> recipe);
}

View File

@@ -0,0 +1,102 @@
package net.momirealms.craftengine.core.item.recipe;
import net.momirealms.craftengine.core.item.ItemBuildContext;
import net.momirealms.craftengine.core.item.recipe.input.BrewingInput;
import net.momirealms.craftengine.core.item.recipe.input.RecipeInput;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MiscUtils;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class CustomBrewingRecipe<T> implements FixedResultRecipe<T> {
public static final Factory<?> FACTORY = new Factory<>();
private final Key id;
private final Ingredient<T> container;
private final Ingredient<T> ingredient;
private final CustomRecipeResult<T> result;
public CustomBrewingRecipe(@NotNull Key id,
@NotNull Ingredient<T> container,
@NotNull Ingredient<T> ingredient,
@NotNull CustomRecipeResult<T> result) {
this.id = id;
this.container = container;
this.ingredient = ingredient;
this.result = result;
}
@Override
public CustomRecipeResult<T> result() {
return this.result;
}
@Override
public T result(ItemBuildContext context) {
return this.result.buildItemStack(context);
}
@SuppressWarnings("unchecked")
@Override
public boolean matches(RecipeInput input) {
BrewingInput<T> brewingInput = (BrewingInput<T>) input;
return this.container.test(brewingInput.container()) && this.ingredient.test(brewingInput.ingredient());
}
@Override
public T assemble(RecipeInput input, ItemBuildContext context) {
return this.result(context);
}
@Override
public List<Ingredient<T>> ingredientsInUse() {
List<Ingredient<T>> ingredients = new ArrayList<>();
ingredients.add(this.container);
ingredients.add(this.ingredient);
return ingredients;
}
@Override
public @NotNull Key type() {
return RecipeTypes.BREWING;
}
@NotNull
public Ingredient<T> container() {
return this.container;
}
@NotNull
public Ingredient<T> ingredient() {
return this.ingredient;
}
@Override
public Key id() {
return this.id;
}
@SuppressWarnings({"DuplicatedCode"})
public static class Factory<A> implements RecipeFactory<A> {
@Override
public Recipe<A> create(Key id, Map<String, Object> arguments) {
List<String> container = MiscUtils.getAsStringList(arguments.get("container"));
if (container.isEmpty()) {
throw new LocalizedResourceConfigException("warning.config.recipe.brewing.missing_container");
}
List<String> ingredient = MiscUtils.getAsStringList(arguments.get("ingredient"));
if (ingredient.isEmpty()) {
throw new LocalizedResourceConfigException("warning.config.recipe.brewing.missing_ingredient");
}
return new CustomBrewingRecipe<>(id,
ResourceConfigUtils.requireNonNullOrThrow(toIngredient(container), "warning.config.recipe.brewing.missing_container"),
ResourceConfigUtils.requireNonNullOrThrow(toIngredient(ingredient), "warning.config.recipe.brewing.missing_ingredient"),
parseResult(arguments));
}
}
}

View File

@@ -13,7 +13,9 @@ import net.momirealms.craftengine.core.util.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class CustomSmithingTransformRecipe<T> implements FixedResultRecipe<T> {
public static final Factory<?> FACTORY = new Factory<>();
@@ -147,18 +149,6 @@ public class CustomSmithingTransformRecipe<T> implements FixedResultRecipe<T> {
ItemDataProcessors.fromMapList(processors)
);
}
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 holders.isEmpty() ? null : Ingredient.of(holders);
}
}
public static class ItemDataProcessors {

View File

@@ -6,11 +6,16 @@ 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 net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MiscUtils;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.util.VersionHelper;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class CustomSmithingTrimRecipe<T> implements Recipe<T> {
public static final Factory<?> FACTORY = new Factory<>();
@@ -122,19 +127,11 @@ public class CustomSmithingTrimRecipe<T> implements Recipe<T> {
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);
return new CustomSmithingTrimRecipe<>(id,
ResourceConfigUtils.requireNonNullOrThrow(toIngredient(base), "warning.config.recipe.smithing_trim.missing_base"),
ResourceConfigUtils.requireNonNullOrThrow(toIngredient(template), "warning.config.recipe.smithing_trim.missing_template_type"),
ResourceConfigUtils.requireNonNullOrThrow(toIngredient(addition), "warning.config.recipe.smithing_trim.missing_addition"),
pattern);
}
}
}

View File

@@ -5,8 +5,12 @@ import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigExce
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MiscUtils;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.util.UniqueKey;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public interface RecipeFactory<T> {
@@ -26,4 +30,16 @@ public interface RecipeFactory<T> {
count
);
}
default Ingredient<T> 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 holders.isEmpty() ? null : Ingredient.of(holders);
}
}

View File

@@ -20,6 +20,7 @@ public class RecipeTypes {
public static final Key STONECUTTING = Key.of("minecraft:stonecutting");
public static final Key SMITHING_TRANSFORM = Key.of("minecraft:smithing_transform");
public static final Key SMITHING_TRIM = Key.of("minecraft:smithing_trim");
public static final Key BREWING = Key.of("minecraft:brewing");
static {
register(SHAPED, CustomShapedRecipe.FACTORY);
@@ -31,6 +32,7 @@ public class RecipeTypes {
register(STONECUTTING, CustomStoneCuttingRecipe.FACTORY);
register(SMITHING_TRANSFORM, CustomSmithingTransformRecipe.FACTORY);
register(SMITHING_TRIM, CustomSmithingTrimRecipe.FACTORY);
register(BREWING, CustomBrewingRecipe.FACTORY);
}
public static <T> void register(Key key, RecipeFactory<T> factory) {

View File

@@ -0,0 +1,21 @@
package net.momirealms.craftengine.core.item.recipe.input;
import net.momirealms.craftengine.core.item.recipe.UniqueIdItem;
public final class BrewingInput<T> implements RecipeInput {
private final UniqueIdItem<T> container;
private final UniqueIdItem<T> ingredient;
public BrewingInput(UniqueIdItem<T> container, UniqueIdItem<T> ingredient) {
this.container = container;
this.ingredient = ingredient;
}
public UniqueIdItem<T> container() {
return container;
}
public UniqueIdItem<T> ingredient() {
return ingredient;
}
}

View File

@@ -7,7 +7,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CraftingInput<T> implements RecipeInput {
public final class CraftingInput<T> implements RecipeInput {
private final int width;
private final int height;
private final List<UniqueIdItem<T>> items;

View File

@@ -4,7 +4,7 @@ import net.momirealms.craftengine.core.item.recipe.UniqueIdItem;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class SmithingInput<T> implements RecipeInput {
public final class SmithingInput<T> implements RecipeInput {
private final UniqueIdItem<T> base;
private final UniqueIdItem<T> template;
private final UniqueIdItem<T> addition;

View File

@@ -211,6 +211,9 @@ public abstract class AbstractPackManager implements PackManager {
}
TranslationManager.instance().log(e.node(), e.arguments());
this.resourcePackHost = NoneHost.INSTANCE;
} catch (Exception e) {
this.plugin.logger().warn("Failed to load resource pack host", e);
this.resourcePackHost = NoneHost.INSTANCE;
}
}

View File

@@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G
# Project settings
# Rule: [major update].[feature update].[bug fix]
project_version=0.0.59.9
project_version=0.0.59.10
config_version=41
lang_version=22
project_group=net.momirealms
@@ -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.32
nms_helper_version=1.0.33
evalex_version=3.5.0
reactive_streams_version=1.0.4
amazon_awssdk_version=2.31.23