From eba3188c823e8f2f8dc661f47b8683288eee45bc Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 18 May 2025 05:23:59 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E7=89=A9=E5=93=81=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E8=AF=BB=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/item/BukkitCustomItem.java | 36 +- .../bukkit/item/BukkitItemManager.java | 452 +----------------- .../core/item/AbstractItemManager.java | 444 ++++++++++++++++- .../craftengine/core/item/CustomItem.java | 5 +- .../craftengine/core/item/ItemKeys.java | 1 + .../craftengine/core/item/ItemManager.java | 6 +- .../core/item/behavior/ItemBehaviors.java | 22 + .../core/pack/AbstractPackManager.java | 5 +- .../conflict/matcher/PathPatternMatcher.java | 1 - .../HasComponentConditionProperty.java | 8 + .../craftengine/core/util/FileUtils.java | 5 - 11 files changed, 503 insertions(+), 482 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java index f3ac95c70..7e2559198 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java @@ -2,13 +2,14 @@ package net.momirealms.craftengine.bukkit.item; import com.google.common.collect.ImmutableMap; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; -import net.momirealms.craftengine.bukkit.util.MaterialUtils; +import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.core.item.*; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.plugin.event.EventTrigger; +import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; @@ -17,7 +18,7 @@ import org.jetbrains.annotations.NotNull; import java.util.*; public class BukkitCustomItem implements CustomItem { - private final Key id; + private final Holder id; private final Key materialKey; private final Material material; private final ItemDataModifier[] modifiers; @@ -30,7 +31,7 @@ public class BukkitCustomItem implements CustomItem { private final EnumMap>> events; @SuppressWarnings("unchecked") - public BukkitCustomItem(Key id, + public BukkitCustomItem(Holder id, Key materialKey, Material material, List> modifiers, @@ -78,6 +79,11 @@ public class BukkitCustomItem implements CustomItem { @Override public Key id() { + return this.id.value(); + } + + @Override + public Holder idHolder() { return this.id; } @@ -147,22 +153,27 @@ public class BukkitCustomItem implements CustomItem { return this.behaviors; } - public static Builder builder() { - return new BuilderImpl(); + public static Builder builder(Material material) { + return new BuilderImpl(material); } public static class BuilderImpl implements Builder { - private Key id; - private Material material; + private Holder id; private Key materialKey; - private ItemSettings settings; - private EnumMap>> events = new EnumMap<>(EventTrigger.class); + private final Material material; + private final EnumMap>> events = new EnumMap<>(EventTrigger.class); private final List behaviors = new ArrayList<>(); private final List> modifiers = new ArrayList<>(); private final List> clientBoundModifiers = new ArrayList<>(); + private ItemSettings settings; + + public BuilderImpl(Material material) { + this.material = material; + this.materialKey = KeyUtils.namespacedKey2Key(material.getKey()); + } @Override - public Builder id(Key id) { + public Builder id(Holder id) { this.id = id; return this; } @@ -170,7 +181,6 @@ public class BukkitCustomItem implements CustomItem { @Override public Builder material(Key material) { this.materialKey = material; - this.material = MaterialUtils.getMaterial(material.value()); return this; } @@ -218,14 +228,14 @@ public class BukkitCustomItem implements CustomItem { @Override public Builder events(EnumMap>> events) { - this.events = events; + this.events.putAll(events); return this; } @Override public CustomItem build() { this.modifiers.addAll(this.settings.modifiers()); - return new BukkitCustomItem(this.id, this.materialKey, this.material, this.modifiers, this.clientBoundModifiers, this.behaviors, this.settings, this.events); + return new BukkitCustomItem(this.id, this.materialKey, this.material, List.copyOf(this.modifiers), List.copyOf(this.clientBoundModifiers), List.copyOf(this.behaviors), this.settings, this.events); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java index 5210f9e4a..d7fb27b85 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java @@ -13,45 +13,32 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.util.ItemUtils; import net.momirealms.craftengine.bukkit.util.KeyUtils; -import net.momirealms.craftengine.bukkit.util.MaterialUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.*; -import net.momirealms.craftengine.core.item.behavior.ItemBehavior; -import net.momirealms.craftengine.core.item.behavior.ItemBehaviors; -import net.momirealms.craftengine.core.item.modifier.CustomModelDataModifier; import net.momirealms.craftengine.core.item.modifier.IdModifier; -import net.momirealms.craftengine.core.item.modifier.ItemModelModifier; -import net.momirealms.craftengine.core.pack.LoadingSequence; -import net.momirealms.craftengine.core.pack.Pack; -import net.momirealms.craftengine.core.pack.ResourceLocation; -import net.momirealms.craftengine.core.pack.misc.EquipmentGeneration; -import net.momirealms.craftengine.core.pack.model.*; -import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; -import net.momirealms.craftengine.core.pack.model.select.ChargeTypeSelectProperty; -import net.momirealms.craftengine.core.pack.model.select.TrimMaterialSelectProperty; -import net.momirealms.craftengine.core.plugin.config.Config; -import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.context.ContextHolder; -import net.momirealms.craftengine.core.plugin.event.EventFunctions; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.WritableRegistry; -import net.momirealms.craftengine.core.util.*; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ReflectionUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.ResourceKey; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.event.HandlerList; import org.bukkit.inventory.ItemStack; -import org.incendo.cloud.suggestion.Suggestion; -import org.incendo.cloud.type.Either; import org.jetbrains.annotations.Nullable; import java.lang.reflect.Field; -import java.nio.file.Path; -import java.util.*; +import java.util.ArrayList; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; import java.util.function.Function; public class BukkitItemManager extends AbstractItemManager { @@ -68,7 +55,7 @@ public class BukkitItemManager extends AbstractItemManager { private final ItemEventListener itemEventListener; private final DebugStickListener debugStickListener; private final ArmorEventListener armorEventListener; - private final ItemParser itemParser; + public BukkitItemManager(BukkitCraftEngine plugin) { super(plugin); @@ -78,7 +65,6 @@ public class BukkitItemManager extends AbstractItemManager { this.itemEventListener = new ItemEventListener(plugin); this.debugStickListener = new DebugStickListener(plugin); this.armorEventListener = new ArmorEventListener(); - this.itemParser = new ItemParser(); this.registerAllVanillaItems(); if (plugin.hasMod()) { Class clazz$CustomStreamCodec = ReflectionUtils.getClazz("net.momirealms.craftengine.mod.item.CustomStreamCodec"); @@ -177,11 +163,6 @@ public class BukkitItemManager extends AbstractItemManager { return this.factory.wrap(ItemTagStream.INSTANCE.fromBytes(bytes)); } - @Override - public ConfigParser parser() { - return this.itemParser; - } - @Override public ItemStack buildCustomItemStack(Key id, Player player) { return Optional.ofNullable(customItems.get(id)).map(it -> it.buildItemStack(new ItemBuildContext(player, ContextHolder.EMPTY), 1)).orElse(null); @@ -238,417 +219,10 @@ public class BukkitItemManager extends AbstractItemManager { return wrapped.id(); } - public class ItemParser implements ConfigParser { - public static final String[] CONFIG_SECTION_NAME = new String[] {"items", "item"}; - - @Override - public String[] sectionId() { - return CONFIG_SECTION_NAME; - } - - @Override - public int loadingSequence() { - return LoadingSequence.ITEM; - } - - @Override - public void parseSection(Pack pack, Path path, Key id, Map section) { - if (customItems.containsKey(id)) { - throw new LocalizedResourceConfigException("warning.config.item.duplicate"); - } - - // register for recipes - Holder.Reference holder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(id) - .orElseGet(() -> ((WritableRegistry) BuiltInRegistries.OPTIMIZED_ITEM_ID) - .register(new ResourceKey<>(BuiltInRegistries.OPTIMIZED_ITEM_ID.key().location(), id), id)); - - boolean isVanillaItem = id.namespace().equals("minecraft") && Registry.MATERIAL.get(new NamespacedKey(id.namespace(), id.value())) != null; - String materialStringId; - if (isVanillaItem) { - materialStringId = id.value(); - } else { - materialStringId = ResourceConfigUtils.requireNonEmptyStringOrThrow(section.get("material"), "warning.config.item.missing_material"); - } - - Material material = MaterialUtils.getMaterial(materialStringId); - if (material == null) { - throw new LocalizedResourceConfigException("warning.config.item.invalid_material", materialStringId); - } - - Key materialId = Key.of(material.getKey().namespace(), material.getKey().value()); - int customModelData = ResourceConfigUtils.getAsInt(section.getOrDefault("custom-model-data", 0), "custom-model-data"); - Key itemModelKey = null; - - CustomItem.Builder itemBuilder = BukkitCustomItem.builder().id(id).material(materialId); - boolean hasItemModelSection = section.containsKey("item-model"); - - // To get at least one model provider - // Sets some basic model info - if (customModelData != 0) { - itemBuilder.dataModifier(new CustomModelDataModifier<>(customModelData)); - } - // Requires the item to have model before apply item-model - else if (!hasItemModelSection && section.containsKey("model") && VersionHelper.isOrAbove1_21_2()) { - // check server version here because components require 1.21.2+ - // customize or use the id - itemModelKey = Key.from(section.getOrDefault("item-model", id.toString()).toString()); - if (ResourceLocation.isValid(itemModelKey.toString())) { - itemBuilder.dataModifier(new ItemModelModifier<>(itemModelKey)); - } else { - itemModelKey = null; - } - } - - if (hasItemModelSection) { - itemModelKey = Key.from(section.get("item-model").toString()); - itemBuilder.dataModifier(new ItemModelModifier<>(itemModelKey)); - } - - // Get item behaviors - Object behaviorConfig = section.get("behavior"); - if (behaviorConfig instanceof List) { - @SuppressWarnings("unchecked") - List> behavior = (List>) behaviorConfig; - List behaviors = new ArrayList<>(); - for (Map behaviorMap : behavior) { - behaviors.add(ItemBehaviors.fromMap(pack, path, id, behaviorMap)); - } - itemBuilder.behaviors(behaviors); - } else if (behaviorConfig instanceof Map) { - Map behaviorSection = MiscUtils.castToMap(section.get("behavior"), true); - if (behaviorSection != null) { - itemBuilder.behavior(ItemBehaviors.fromMap(pack, path, id, behaviorSection)); - } - } - - // Get item data - Map dataSection = MiscUtils.castToMap(section.get("data"), true); - if (dataSection != null) { - for (Map.Entry dataEntry : dataSection.entrySet()) { - Optional.ofNullable(dataFunctions.get(dataEntry.getKey())).ifPresent(function -> { - try { - itemBuilder.dataModifier(function.apply(dataEntry.getValue())); - } catch (IllegalArgumentException e) { - plugin.logger().warn("Invalid data format", e); - } - }); - } - } - - // Add it here to make sure that ce id is always applied - if (!isVanillaItem) - itemBuilder.dataModifier(new IdModifier<>(id)); - - // Get item data - Map clientSideDataSection = MiscUtils.castToMap(section.get("client-bound-data"), true); - if (clientSideDataSection != null) { - for (Map.Entry dataEntry : clientSideDataSection.entrySet()) { - Optional.ofNullable(dataFunctions.get(dataEntry.getKey())).ifPresent(function -> { - try { - itemBuilder.clientBoundDataModifier(function.apply(dataEntry.getValue())); - } catch (IllegalArgumentException e) { - plugin.logger().warn("Invalid client bound data format", e); - } - }); - } - } - - ItemSettings itemSettings = ItemSettings.fromMap(MiscUtils.castToMap(section.get("settings"), true)); - if (isVanillaItem) { - itemSettings.canPlaceRelatedVanillaBlock(true); - } - itemBuilder.settings(itemSettings); - itemBuilder.events(EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event"))); - - CustomItem customItem = itemBuilder.build(); - customItems.put(id, customItem); - - // cache command suggestions - cachedSuggestions.add(Suggestion.suggestion(id.toString())); - - // TODO Deprecated 理论支持任意物品类型 - if (material == Material.TOTEM_OF_UNDYING) - cachedTotemSuggestions.add(Suggestion.suggestion(id.toString())); - - // post process - // register tags - Set tags = customItem.settings().tags(); - for (Key tag : tags) { - customItemTags.computeIfAbsent(tag, k -> new ArrayList<>()).add(holder); - } - - // create trims - EquipmentGeneration equipment = customItem.settings().equipment(); - if (equipment != null) { - EquipmentData modern = equipment.modernData(); - // 1.21.2+ - if (modern != null) { - equipmentsToGenerate.add(equipment); - } - // TODO 1.20 - } - - // add it to category - if (section.containsKey("category")) { - plugin.itemBrowserManager().addExternalCategoryMember(id, MiscUtils.getAsStringList(section.get("category")).stream().map(Key::of).toList()); - } - - // model part, can be null - // but if it exists, either custom model data or item model should be configured - Map modelSection = MiscUtils.castToMap(section.get("model"), true); - if (modelSection == null) { - return; - } - - ItemModel model = ItemModels.fromMap(modelSection); - boolean hasModel = false; - if (customModelData != 0) { - hasModel= true; - // use custom model data - // check conflict - Map conflict = cmdConflictChecker.computeIfAbsent(materialId, k -> new HashMap<>()); - if (conflict.containsKey(customModelData)) { - throw new LocalizedResourceConfigException("warning.config.item.custom_model_data_conflict", String.valueOf(customModelData), conflict.get(customModelData).toString()); - } - - if (customModelData > 16_777_216) { - throw new LocalizedResourceConfigException("warning.config.item.bad_custom_model_data", String.valueOf(customModelData)); - } - - conflict.put(customModelData, id); - - // Parse models - for (ModelGeneration generation : model.modelsToGenerate()) { - prepareModelGeneration(generation); - } - - if (Config.packMaxVersion() > 21.39f) { - TreeMap map = modernOverrides.computeIfAbsent(materialId, k -> new TreeMap<>()); - map.put(customModelData, model); - } - - if (Config.packMinVersion() < 21.39f) { - // TODO 手动指定旧版格式 - List legacyOverridesModels = new ArrayList<>(); - processModelRecursively(model, new LinkedHashMap<>(), legacyOverridesModels, materialId, customModelData); - TreeSet lom = legacyOverrides.computeIfAbsent(materialId, k -> new TreeSet<>()); - lom.addAll(legacyOverridesModels); - } - } - if (itemModelKey != null) { - hasModel = true; - for (ModelGeneration generation : model.modelsToGenerate()) { - prepareModelGeneration(generation); - } - - if (Config.packMaxVersion() > 21.39f) { - modernItemModels1_21_4.put(itemModelKey, model); - } - - if (Config.packMaxVersion() > 21.19f && Config.packMinVersion() < 21.39f) { - List legacyOverridesModels = new ArrayList<>(); - processModelRecursively(model, new LinkedHashMap<>(), legacyOverridesModels, materialId, 0); - if (!legacyOverridesModels.isEmpty()) { - legacyOverridesModels.sort(LegacyOverridesModel::compareTo); - modernItemModels1_21_2.put(itemModelKey, legacyOverridesModels); - } else { - plugin.debug(() -> "Can't convert " + id + "'s model to legacy format."); - } - } - } - if (!hasModel) { - throw new LocalizedResourceConfigException("warning.config.item.missing_model_id"); - } - } - } - - private void processModelRecursively( - ItemModel currentModel, - Map accumulatedPredicates, - List resultList, - Key materialId, - int customModelData - ) { - if (currentModel instanceof ConditionItemModel conditionModel) { - handleConditionModel(conditionModel, accumulatedPredicates, resultList, materialId, customModelData); - } else if (currentModel instanceof RangeDispatchItemModel rangeModel) { - handleRangeModel(rangeModel, accumulatedPredicates, resultList, materialId, customModelData); - } else if (currentModel instanceof SelectItemModel selectModel) { - handleSelectModel(selectModel, accumulatedPredicates, resultList, materialId, customModelData); - } else if (currentModel instanceof BaseItemModel baseModel) { - resultList.add(new LegacyOverridesModel( - new LinkedHashMap<>(accumulatedPredicates), - baseModel.path(), - customModelData - )); - } else if (currentModel instanceof SpecialItemModel specialModel) { - resultList.add(new LegacyOverridesModel( - new LinkedHashMap<>(accumulatedPredicates), - specialModel.base(), - customModelData - )); - } - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - private void handleConditionModel( - ConditionItemModel model, - Map parentPredicates, - List resultList, - Key materialId, - int customModelData - ) { - if (model.property() instanceof LegacyModelPredicate predicate) { - String predicateId = predicate.legacyPredicateId(materialId); - Map truePredicates = mergePredicates( - parentPredicates, - predicateId, - predicate.toLegacyValue(true) - ); - processModelRecursively( - model.onTrue(), - truePredicates, - resultList, - materialId, - customModelData - ); - Map falsePredicates = mergePredicates( - parentPredicates, - predicateId, - predicate.toLegacyValue(false) - ); - processModelRecursively( - model.onFalse(), - falsePredicates, - resultList, - materialId, - customModelData - ); - } - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - private void handleRangeModel( - RangeDispatchItemModel model, - Map parentPredicates, - List resultList, - Key materialId, - int customModelData - ) { - if (model.property() instanceof LegacyModelPredicate predicate) { - String predicateId = predicate.legacyPredicateId(materialId); - for (Map.Entry entry : model.entries().entrySet()) { - Map merged = mergePredicates( - parentPredicates, - predicateId, - predicate.toLegacyValue(entry.getKey()) - ); - processModelRecursively( - entry.getValue(), - merged, - resultList, - materialId, - customModelData - ); - } - if (model.fallBack() != null) { - Map merged = mergePredicates( - parentPredicates, - predicateId, - predicate.toLegacyValue(0f) - ); - processModelRecursively( - model.fallBack(), - merged, - resultList, - materialId, - customModelData - ); - } - } - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - private void handleSelectModel( - SelectItemModel model, - Map parentPredicates, - List resultList, - Key materialId, - int customModelData - ) { - if (model.property() instanceof LegacyModelPredicate predicate) { - String predicateId = predicate.legacyPredicateId(materialId); - for (Map.Entry>, ItemModel> entry : model.whenMap().entrySet()) { - List cases = entry.getKey().fallbackOrMapPrimary(List::of); - for (String caseValue : cases) { - Number legacyValue = predicate.toLegacyValue(caseValue); - if (predicate instanceof TrimMaterialSelectProperty property && property.isArmor(materialId)) { - if (legacyValue.floatValue() > 1f) { - continue; - } - } - Map merged = mergePredicates( - parentPredicates, - predicateId, - legacyValue - ); - // Additional check for crossbow - if (predicate instanceof ChargeTypeSelectProperty && materialId.equals(ItemKeys.CROSSBOW)) { - merged = mergePredicates( - merged, - "charged", - 1 - ); - } - processModelRecursively( - entry.getValue(), - merged, - resultList, - materialId, - customModelData - ); - } - } - // Additional check for crossbow - if (model.fallBack() != null) { - if (predicate instanceof ChargeTypeSelectProperty && materialId.equals(ItemKeys.CROSSBOW)) { - processModelRecursively( - model.fallBack(), - mergePredicates( - parentPredicates, - "charged", - 0 - ), - resultList, - materialId, - customModelData - ); - } else if (predicate instanceof TrimMaterialSelectProperty property && property.isArmor(materialId)) { - processModelRecursively( - model.fallBack(), - mergePredicates( - parentPredicates, - "trim_type", - 0f - ), - resultList, - materialId, - customModelData - ); - } - } - } - } - - private Map mergePredicates( - Map existing, - String newKey, - Number newValue - ) { - Map merged = new LinkedHashMap<>(existing); - if (newKey == null) return merged; - merged.put(newKey, newValue); - return merged; + @Override + protected CustomItem.Builder createPlatformItemBuilder(Key materialId) { + Material material = ResourceConfigUtils.requireNonNullOrThrow(Registry.MATERIAL.get(KeyUtils.toNamespacedKey(materialId)), () -> new LocalizedResourceConfigException("warning.config.item.invalid_material", materialId.toString())); + return BukkitCustomItem.builder(material); } @SuppressWarnings("unchecked") diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java index 4548fadab..8719601b8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java @@ -1,35 +1,48 @@ package net.momirealms.craftengine.core.item; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; +import net.momirealms.craftengine.core.item.behavior.ItemBehaviors; import net.momirealms.craftengine.core.item.modifier.*; +import net.momirealms.craftengine.core.pack.LoadingSequence; +import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.pack.ResourceLocation; import net.momirealms.craftengine.core.pack.misc.EquipmentGeneration; -import net.momirealms.craftengine.core.pack.model.ItemModel; -import net.momirealms.craftengine.core.pack.model.LegacyOverridesModel; +import net.momirealms.craftengine.core.pack.model.*; import net.momirealms.craftengine.core.pack.model.generation.AbstractModelGenerator; +import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; +import net.momirealms.craftengine.core.pack.model.select.ChargeTypeSelectProperty; +import net.momirealms.craftengine.core.pack.model.select.TrimMaterialSelectProperty; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.config.Config; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; +import net.momirealms.craftengine.core.plugin.event.EventFunctions; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.MiscUtils; -import net.momirealms.craftengine.core.util.TypeUtils; -import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.craftengine.core.registry.WritableRegistry; +import net.momirealms.craftengine.core.util.*; import org.incendo.cloud.suggestion.Suggestion; +import org.incendo.cloud.type.Either; +import java.nio.file.Path; import java.util.*; +import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Stream; public abstract class AbstractItemManager extends AbstractModelGenerator implements ItemManager { protected static final Map> VANILLA_ITEM_EXTRA_BEHAVIORS = new HashMap<>(); - protected static final List VANILLA_ITEMS = new ArrayList<>(); + protected static final Set VANILLA_ITEMS = new HashSet<>(1024); protected static final Map>> VANILLA_ITEM_TAGS = new HashMap<>(); + private final ItemParser itemParser; protected final Map> externalItemProviders = new HashMap<>(); protected final Map>> dataFunctions = new HashMap<>(); protected final Map> customItems = new HashMap<>(); protected final Map>> customItemTags; protected final Map> cmdConflictChecker; protected final Map modernItemModels1_21_4; - protected final Map> modernItemModels1_21_2; + protected final Map> modernItemModels1_21_2; protected final Map> legacyOverrides; protected final Map> modernOverrides; protected final Set equipmentsToGenerate; @@ -37,6 +50,19 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl protected final List cachedSuggestions = new ArrayList<>(); protected final List cachedTotemSuggestions = new ArrayList<>(); + protected AbstractItemManager(CraftEngine plugin) { + super(plugin); + this.itemParser = new ItemParser(); + this.registerFunctions(); + this.legacyOverrides = new HashMap<>(); + this.modernOverrides = new HashMap<>(); + this.customItemTags = new HashMap<>(); + this.cmdConflictChecker = new HashMap<>(); + this.modernItemModels1_21_4 = new HashMap<>(); + this.modernItemModels1_21_2 = new HashMap<>(); + this.equipmentsToGenerate = new HashSet<>(); + } + protected void registerDataFunction(Function> function, String... alias) { for (String a : alias) { dataFunctions.put(a, function); @@ -49,6 +75,25 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } } + protected void applyDataFunctions(Map dataSection, Consumer> consumer) { + if (dataSection != null) { + for (Map.Entry dataEntry : dataSection.entrySet()) { + Optional.ofNullable(dataFunctions.get(dataEntry.getKey())).ifPresent(function -> { + try { + consumer.accept(function.apply(dataEntry.getValue())); + } catch (IllegalArgumentException e) { + plugin.logger().warn("Invalid data format", e); + } + }); + } + } + } + + @Override + public ConfigParser parser() { + return this.itemParser; + } + @Override public ExternalItemProvider getExternalItemProvider(String name) { return this.externalItemProviders.get(name); @@ -81,16 +126,35 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl return Optional.ofNullable(this.customItems.get(key)); } - public AbstractItemManager(CraftEngine plugin) { - super(plugin); - this.registerFunctions(); - this.legacyOverrides = new HashMap<>(); - this.modernOverrides = new HashMap<>(); - this.customItemTags = new HashMap<>(); - this.cmdConflictChecker = new HashMap<>(); - this.modernItemModels1_21_4 = new HashMap<>(); - this.modernItemModels1_21_2 = new HashMap<>(); - this.equipmentsToGenerate = new HashSet<>(); + @Override + public boolean addCustomItem(CustomItem customItem) { + Key id = customItem.id(); + if (this.customItems.containsKey(id)) return false; + this.customItems.put(id, customItem); + // cache command suggestions + this.cachedSuggestions.add(Suggestion.suggestion(id.toString())); + // totem animations + if (VersionHelper.isOrAbove1_21_2()) { + this.cachedTotemSuggestions.add(Suggestion.suggestion(id.toString())); + } else if (customItem.material().equals(ItemKeys.TOTEM_OF_UNDYING)) { + this.cachedTotemSuggestions.add(Suggestion.suggestion(id.toString())); + } + // tags + Set tags = customItem.settings().tags(); + for (Key tag : tags) { + this.customItemTags.computeIfAbsent(tag, k -> new ArrayList<>()).add(customItem.idHolder()); + } + // equipment generation + EquipmentGeneration equipment = customItem.settings().equipment(); + if (equipment != null) { + EquipmentData modern = equipment.modernData(); + // 1.21.2+ + if (modern != null) { + this.equipmentsToGenerate.add(equipment); + } + // TODO 1.20 + } + return true; } @Override @@ -100,7 +164,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl if (holders != null) { items.addAll(holders); } - List> customItems = customItemTags.get(tag); + List> customItems = this.customItemTags.get(tag); if (customItems != null) { items.addAll(customItems); } @@ -160,7 +224,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } @Override - public Map> modernItemModels1_21_2() { + public Map> modernItemModels1_21_2() { return Collections.unmodifiableMap(this.modernItemModels1_21_2); } @@ -184,6 +248,157 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl return Collections.unmodifiableCollection(this.equipmentsToGenerate); } + @Override + public boolean isVanillaItem(Key item) { + return VANILLA_ITEMS.contains(item); + } + + protected abstract CustomItem.Builder createPlatformItemBuilder(Key material); + + public class ItemParser implements ConfigParser { + public static final String[] CONFIG_SECTION_NAME = new String[] {"items", "item"}; + + @Override + public String[] sectionId() { + return CONFIG_SECTION_NAME; + } + + @Override + public int loadingSequence() { + return LoadingSequence.ITEM; + } + + @Override + public void parseSection(Pack pack, Path path, Key id, Map section) { + if (customItems.containsKey(id)) { + throw new LocalizedResourceConfigException("warning.config.item.duplicate"); + } + + // register for recipes + Holder.Reference holder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(id) + .orElseGet(() -> ((WritableRegistry) BuiltInRegistries.OPTIMIZED_ITEM_ID) + .register(new ResourceKey<>(BuiltInRegistries.OPTIMIZED_ITEM_ID.key().location(), id), id)); + + boolean isVanillaItem = isVanillaItem(id); + Key material = Key.from(isVanillaItem ? id.value() : ResourceConfigUtils.requireNonEmptyStringOrThrow(section.get("material"), "warning.config.item.missing_material")); + int customModelData = ResourceConfigUtils.getAsInt(section.getOrDefault("custom-model-data", 0), "custom-model-data"); + // TODO give warnings if negative + + Key itemModelKey = null; + + CustomItem.Builder itemBuilder = createPlatformItemBuilder(material).id(holder); + boolean hasItemModelSection = section.containsKey("item-model"); + + // To get at least one model provider + // Sets some basic model info + if (customModelData > 0) { + itemBuilder.dataModifier(new CustomModelDataModifier<>(customModelData)); + } + // Requires the item to have model before apply item-model + else if (!hasItemModelSection && section.containsKey("model") && VersionHelper.isOrAbove1_21_2()) { + // check server version here because components require 1.21.2+ + // customize or use the id + itemModelKey = Key.from(section.getOrDefault("item-model", id.toString()).toString()); + if (ResourceLocation.isValid(itemModelKey.toString())) { + itemBuilder.dataModifier(new ItemModelModifier<>(itemModelKey)); + } else { + itemModelKey = null; + } + } + + if (hasItemModelSection) { + itemModelKey = Key.from(section.get("item-model").toString()); + itemBuilder.dataModifier(new ItemModelModifier<>(itemModelKey)); + } + + // Get item data + applyDataFunctions(MiscUtils.castToMap(section.get("data"), true), itemBuilder::dataModifier); + applyDataFunctions(MiscUtils.castToMap(section.get("client-bound-data"), true), itemBuilder::clientBoundDataModifier); + + // Add custom it here to make sure that id is always applied + if (!isVanillaItem) + itemBuilder.dataModifier(new IdModifier<>(id)); + + CustomItem customItem = itemBuilder + .behaviors(ItemBehaviors.fromObj(pack, path, id, ResourceConfigUtils.get(section, "behavior", "behaviors"))) + .settings(Optional.ofNullable(ResourceConfigUtils.get(section, "settings")) + .map(map -> ItemSettings.fromMap(MiscUtils.castToMap(map, true))) + .map(it -> isVanillaItem ? it.canPlaceRelatedVanillaBlock(true) : it) + .orElse(ItemSettings.of().canPlaceRelatedVanillaBlock(isVanillaItem))) + .events(EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event"))) + .build(); + + addCustomItem(customItem); + + // add it to category + if (section.containsKey("category")) { + plugin.itemBrowserManager().addExternalCategoryMember(id, MiscUtils.getAsStringList(section.get("category")).stream().map(Key::of).toList()); + } + + // model part, can be null + // but if it exists, either custom model data or item model should be configured + Map modelSection = MiscUtils.castToMap(section.get("model"), true); + if (modelSection == null) { + return; + } + if (customModelData <= 0 && itemModelKey == null) { + throw new LocalizedResourceConfigException("warning.config.item.missing_model_id"); + } + + ItemModel model = ItemModels.fromMap(modelSection); + for (ModelGeneration generation : model.modelsToGenerate()) { + prepareModelGeneration(generation); + } + + TreeSet legacyOverridesModels = null; + if (Config.packMinVersion() < 21.4f) { + legacyOverridesModels = new TreeSet<>(); + if (section.containsKey("legacy-model")) { + + } else { + processModelRecursively(model, new LinkedHashMap<>(), legacyOverridesModels, material, customModelData); + if (legacyOverridesModels.isEmpty()) { + // TODO give warnings + plugin.debug(() -> "Can't convert " + id + "'s model to legacy format."); + } + } + } + + // use custom model data + if (customModelData != 0) { + // use custom model data + // check conflict + Map conflict = cmdConflictChecker.computeIfAbsent(material, k -> new HashMap<>()); + if (conflict.containsKey(customModelData)) { + throw new LocalizedResourceConfigException("warning.config.item.custom_model_data_conflict", String.valueOf(customModelData), conflict.get(customModelData).toString()); + } + if (customModelData > 16_777_216) { + throw new LocalizedResourceConfigException("warning.config.item.bad_custom_model_data", String.valueOf(customModelData)); + } + conflict.put(customModelData, id); + // Parse models + if (Config.packMaxVersion() >= 21.4f) { + TreeMap map = modernOverrides.computeIfAbsent(material, k -> new TreeMap<>()); + map.put(customModelData, model); + } + if (Config.packMinVersion() < 21.4f) { + TreeSet lom = legacyOverrides.computeIfAbsent(material, k -> new TreeSet<>()); + lom.addAll(legacyOverridesModels); + } + } + + // use item model + if (itemModelKey != null) { + if (Config.packMaxVersion() >= 21.4f) { + modernItemModels1_21_4.put(itemModelKey, model); + } + if (Config.packMaxVersion() >= 21.2f && Config.packMinVersion() < 21.4f) { + modernItemModels1_21_2.put(itemModelKey, legacyOverridesModels); + } + } + } + } + private void registerFunctions() { registerDataFunction((obj) -> { Map data = MiscUtils.castToMap(obj, false); @@ -258,4 +473,193 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl }, "equippable"); } } + + protected void processModelRecursively( + ItemModel currentModel, + Map accumulatedPredicates, + Collection resultList, + Key materialId, + int customModelData + ) { + if (currentModel instanceof ConditionItemModel conditionModel) { + handleConditionModel(conditionModel, accumulatedPredicates, resultList, materialId, customModelData); + } else if (currentModel instanceof RangeDispatchItemModel rangeModel) { + handleRangeModel(rangeModel, accumulatedPredicates, resultList, materialId, customModelData); + } else if (currentModel instanceof SelectItemModel selectModel) { + handleSelectModel(selectModel, accumulatedPredicates, resultList, materialId, customModelData); + } else if (currentModel instanceof BaseItemModel baseModel) { + resultList.add(new LegacyOverridesModel( + new LinkedHashMap<>(accumulatedPredicates), + baseModel.path(), + customModelData + )); + } else if (currentModel instanceof SpecialItemModel specialModel) { + resultList.add(new LegacyOverridesModel( + new LinkedHashMap<>(accumulatedPredicates), + specialModel.base(), + customModelData + )); + } + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + private void handleConditionModel( + ConditionItemModel model, + Map parentPredicates, + Collection resultList, + Key materialId, + int customModelData + ) { + if (model.property() instanceof LegacyModelPredicate predicate) { + String predicateId = predicate.legacyPredicateId(materialId); + Map truePredicates = mergePredicates( + parentPredicates, + predicateId, + predicate.toLegacyValue(true) + ); + processModelRecursively( + model.onTrue(), + truePredicates, + resultList, + materialId, + customModelData + ); + Map falsePredicates = mergePredicates( + parentPredicates, + predicateId, + predicate.toLegacyValue(false) + ); + processModelRecursively( + model.onFalse(), + falsePredicates, + resultList, + materialId, + customModelData + ); + } + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + private void handleRangeModel( + RangeDispatchItemModel model, + Map parentPredicates, + Collection resultList, + Key materialId, + int customModelData + ) { + if (model.property() instanceof LegacyModelPredicate predicate) { + String predicateId = predicate.legacyPredicateId(materialId); + for (Map.Entry entry : model.entries().entrySet()) { + Map merged = mergePredicates( + parentPredicates, + predicateId, + predicate.toLegacyValue(entry.getKey()) + ); + processModelRecursively( + entry.getValue(), + merged, + resultList, + materialId, + customModelData + ); + } + if (model.fallBack() != null) { + Map merged = mergePredicates( + parentPredicates, + predicateId, + predicate.toLegacyValue(0f) + ); + processModelRecursively( + model.fallBack(), + merged, + resultList, + materialId, + customModelData + ); + } + } + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + private void handleSelectModel( + SelectItemModel model, + Map parentPredicates, + Collection resultList, + Key materialId, + int customModelData + ) { + if (model.property() instanceof LegacyModelPredicate predicate) { + String predicateId = predicate.legacyPredicateId(materialId); + for (Map.Entry>, ItemModel> entry : model.whenMap().entrySet()) { + List cases = entry.getKey().fallbackOrMapPrimary(List::of); + for (String caseValue : cases) { + Number legacyValue = predicate.toLegacyValue(caseValue); + if (predicate instanceof TrimMaterialSelectProperty property && property.isArmor(materialId)) { + if (legacyValue.floatValue() > 1f) { + continue; + } + } + Map merged = mergePredicates( + parentPredicates, + predicateId, + legacyValue + ); + // Additional check for crossbow + if (predicate instanceof ChargeTypeSelectProperty && materialId.equals(ItemKeys.CROSSBOW)) { + merged = mergePredicates( + merged, + "charged", + 1 + ); + } + processModelRecursively( + entry.getValue(), + merged, + resultList, + materialId, + customModelData + ); + } + } + // Additional check for crossbow + if (model.fallBack() != null) { + if (predicate instanceof ChargeTypeSelectProperty && materialId.equals(ItemKeys.CROSSBOW)) { + processModelRecursively( + model.fallBack(), + mergePredicates( + parentPredicates, + "charged", + 0 + ), + resultList, + materialId, + customModelData + ); + } else if (predicate instanceof TrimMaterialSelectProperty property && property.isArmor(materialId)) { + processModelRecursively( + model.fallBack(), + mergePredicates( + parentPredicates, + "trim_type", + 0f + ), + resultList, + materialId, + customModelData + ); + } + } + } + } + + private Map mergePredicates( + Map existing, + String newKey, + Number newValue + ) { + Map merged = new LinkedHashMap<>(existing); + if (newKey == null) return merged; + merged.put(newKey, newValue); + return merged; + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java index 8f92db2d7..783506671 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java @@ -6,6 +6,7 @@ import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.plugin.event.EventTrigger; +import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.NotNull; @@ -17,6 +18,8 @@ public interface CustomItem extends BuildableItem { Key id(); + Holder idHolder(); + Key material(); NetworkItemDataProcessor[] networkItemDataProcessors(); @@ -49,7 +52,7 @@ public interface CustomItem extends BuildableItem { List behaviors(); interface Builder { - Builder id(Key id); + Builder id(Holder id); Builder material(Key material); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java index 05c1c2f78..de7c072ac 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java @@ -28,6 +28,7 @@ public class ItemKeys { public static final Key BUCKET = Key.of("minecraft:bucket"); public static final Key BONE_MEAL = Key.of("minecraft:bone_meal"); public static final Key ENCHANTED_BOOK = Key.of("minecraft:enchanted_book"); + public static final Key TOTEM_OF_UNDYING = Key.of("minecraft:totem_of_undying"); public static final Key[] AXES = new Key[] { WOODEN_AXE, STONE_AXE, IRON_AXE, GOLDEN_AXE, DIAMOND_AXE, NETHERITE_AXE diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java index a5320e710..655270533 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java @@ -27,7 +27,7 @@ public interface ItemManager extends Manageable, ModelGenerator { Map modernItemModels1_21_4(); - Map> modernItemModels1_21_2(); + Map> modernItemModels1_21_2(); Collection vanillaItems(); @@ -67,6 +67,8 @@ public interface ItemManager extends Manageable, ModelGenerator { return getVanillaItem(key); } + boolean addCustomItem(CustomItem customItem); + List> tagToItems(Key tag); List> tagToVanillaItems(Key tag); @@ -80,4 +82,6 @@ public interface ItemManager extends Manageable, ModelGenerator { Collection cachedSuggestions(); Collection cachedTotemSuggestions(); + + boolean isVanillaItem(Key item); } \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviors.java b/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviors.java index 09d5eadc1..28c122108 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviors.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviors.java @@ -7,10 +7,13 @@ import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; 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.ResourceKey; import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; import java.util.Map; public class ItemBehaviors { @@ -32,4 +35,23 @@ public class ItemBehaviors { } return factory.create(pack, path, id, map); } + + public static List fromList(Pack pack, Path path, Key id, List> list) { + List behaviors = new ArrayList<>(list.size()); + for (Map map : list) { + behaviors.add(fromMap(pack, path, id, map)); + } + return behaviors; + } + + @SuppressWarnings("unchecked") + public static List fromObj(Pack pack, Path path, Key id, Object behaviorObj) { + if (behaviorObj instanceof Map) { + return List.of(fromMap(pack, path, id, MiscUtils.castToMap(behaviorObj, false))); + } else if (behaviorObj instanceof List) { + return fromList(pack, path, id, (List>) behaviorObj); + } else { + return List.of(); + } + } } \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index e5809d59f..4cd03a29b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -43,6 +43,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.nio.charset.StandardCharsets; import java.nio.file.*; +import java.nio.file.FileSystem; import java.nio.file.attribute.BasicFileAttributes; import java.util.*; import java.util.function.BiConsumer; @@ -918,9 +919,9 @@ public abstract class AbstractPackManager implements PackManager { if (Config.packMinVersion() > 21.39f) return; // 此段代码生成1.21.2专用的item model文件,情况非常复杂! - for (Map.Entry> entry : this.plugin.itemManager().modernItemModels1_21_2().entrySet()) { + for (Map.Entry> entry : this.plugin.itemManager().modernItemModels1_21_2().entrySet()) { Key itemModelPath = entry.getKey(); - List legacyOverridesModels = entry.getValue(); + TreeSet legacyOverridesModels = entry.getValue(); // 检测item model合法性 if (PRESET_MODERN_MODELS_ITEM.containsKey(itemModelPath) || PRESET_LEGACY_MODELS_ITEM.containsKey(itemModelPath)) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathPatternMatcher.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathPatternMatcher.java index 43c24a864..cf8c72a11 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathPatternMatcher.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathPatternMatcher.java @@ -2,7 +2,6 @@ package net.momirealms.craftengine.core.pack.conflict.matcher; import net.momirealms.craftengine.core.pack.conflict.PathContext; import net.momirealms.craftengine.core.plugin.context.Condition; -import net.momirealms.craftengine.core.plugin.context.ContextKey; import net.momirealms.craftengine.core.plugin.context.condition.ConditionFactory; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import net.momirealms.craftengine.core.util.CharacterUtils; diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/condition/HasComponentConditionProperty.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/condition/HasComponentConditionProperty.java index 7da522b40..660d7a264 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/condition/HasComponentConditionProperty.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/condition/HasComponentConditionProperty.java @@ -16,6 +16,14 @@ public class HasComponentConditionProperty implements ConditionProperty { this.ignoreDefault = ignoreDefault; } + public String component() { + return component; + } + + public boolean ignoreDefault() { + return ignoreDefault; + } + @Override public Key type() { return ConditionProperties.HAS_COMPONENT; diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java index 208adef5e..0de7bd17f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java @@ -1,14 +1,9 @@ package net.momirealms.craftengine.core.util; import java.io.IOException; -import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Deque; import java.util.List; -import java.util.stream.Collectors; import java.util.stream.Stream; public class FileUtils {