mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2026-01-06 15:52:03 +00:00
重构物品配置读取
This commit is contained in:
@@ -2,13 +2,14 @@ package net.momirealms.craftengine.bukkit.item;
|
|||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
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.*;
|
||||||
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
|
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
|
||||||
import net.momirealms.craftengine.core.item.modifier.ItemDataModifier;
|
import net.momirealms.craftengine.core.item.modifier.ItemDataModifier;
|
||||||
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
|
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
|
||||||
import net.momirealms.craftengine.core.plugin.context.function.Function;
|
import net.momirealms.craftengine.core.plugin.context.function.Function;
|
||||||
import net.momirealms.craftengine.core.plugin.event.EventTrigger;
|
import net.momirealms.craftengine.core.plugin.event.EventTrigger;
|
||||||
|
import net.momirealms.craftengine.core.registry.Holder;
|
||||||
import net.momirealms.craftengine.core.util.Key;
|
import net.momirealms.craftengine.core.util.Key;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
@@ -17,7 +18,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class BukkitCustomItem implements CustomItem<ItemStack> {
|
public class BukkitCustomItem implements CustomItem<ItemStack> {
|
||||||
private final Key id;
|
private final Holder<Key> id;
|
||||||
private final Key materialKey;
|
private final Key materialKey;
|
||||||
private final Material material;
|
private final Material material;
|
||||||
private final ItemDataModifier<ItemStack>[] modifiers;
|
private final ItemDataModifier<ItemStack>[] modifiers;
|
||||||
@@ -30,7 +31,7 @@ public class BukkitCustomItem implements CustomItem<ItemStack> {
|
|||||||
private final EnumMap<EventTrigger, List<Function<PlayerOptionalContext>>> events;
|
private final EnumMap<EventTrigger, List<Function<PlayerOptionalContext>>> events;
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public BukkitCustomItem(Key id,
|
public BukkitCustomItem(Holder<Key> id,
|
||||||
Key materialKey,
|
Key materialKey,
|
||||||
Material material,
|
Material material,
|
||||||
List<ItemDataModifier<ItemStack>> modifiers,
|
List<ItemDataModifier<ItemStack>> modifiers,
|
||||||
@@ -78,6 +79,11 @@ public class BukkitCustomItem implements CustomItem<ItemStack> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Key id() {
|
public Key id() {
|
||||||
|
return this.id.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Holder<Key> idHolder() {
|
||||||
return this.id;
|
return this.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,22 +153,27 @@ public class BukkitCustomItem implements CustomItem<ItemStack> {
|
|||||||
return this.behaviors;
|
return this.behaviors;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Builder<ItemStack> builder() {
|
public static Builder<ItemStack> builder(Material material) {
|
||||||
return new BuilderImpl();
|
return new BuilderImpl(material);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class BuilderImpl implements Builder<ItemStack> {
|
public static class BuilderImpl implements Builder<ItemStack> {
|
||||||
private Key id;
|
private Holder<Key> id;
|
||||||
private Material material;
|
|
||||||
private Key materialKey;
|
private Key materialKey;
|
||||||
private ItemSettings settings;
|
private final Material material;
|
||||||
private EnumMap<EventTrigger, List<Function<PlayerOptionalContext>>> events = new EnumMap<>(EventTrigger.class);
|
private final EnumMap<EventTrigger, List<Function<PlayerOptionalContext>>> events = new EnumMap<>(EventTrigger.class);
|
||||||
private final List<ItemBehavior> behaviors = new ArrayList<>();
|
private final List<ItemBehavior> behaviors = new ArrayList<>();
|
||||||
private final List<ItemDataModifier<ItemStack>> modifiers = new ArrayList<>();
|
private final List<ItemDataModifier<ItemStack>> modifiers = new ArrayList<>();
|
||||||
private final List<ItemDataModifier<ItemStack>> clientBoundModifiers = new ArrayList<>();
|
private final List<ItemDataModifier<ItemStack>> clientBoundModifiers = new ArrayList<>();
|
||||||
|
private ItemSettings settings;
|
||||||
|
|
||||||
|
public BuilderImpl(Material material) {
|
||||||
|
this.material = material;
|
||||||
|
this.materialKey = KeyUtils.namespacedKey2Key(material.getKey());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Builder<ItemStack> id(Key id) {
|
public Builder<ItemStack> id(Holder<Key> id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -170,7 +181,6 @@ public class BukkitCustomItem implements CustomItem<ItemStack> {
|
|||||||
@Override
|
@Override
|
||||||
public Builder<ItemStack> material(Key material) {
|
public Builder<ItemStack> material(Key material) {
|
||||||
this.materialKey = material;
|
this.materialKey = material;
|
||||||
this.material = MaterialUtils.getMaterial(material.value());
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,14 +228,14 @@ public class BukkitCustomItem implements CustomItem<ItemStack> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Builder<ItemStack> events(EnumMap<EventTrigger, List<Function<PlayerOptionalContext>>> events) {
|
public Builder<ItemStack> events(EnumMap<EventTrigger, List<Function<PlayerOptionalContext>>> events) {
|
||||||
this.events = events;
|
this.events.putAll(events);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CustomItem<ItemStack> build() {
|
public CustomItem<ItemStack> build() {
|
||||||
this.modifiers.addAll(this.settings.modifiers());
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,45 +13,32 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
|||||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||||
import net.momirealms.craftengine.bukkit.util.ItemUtils;
|
import net.momirealms.craftengine.bukkit.util.ItemUtils;
|
||||||
import net.momirealms.craftengine.bukkit.util.KeyUtils;
|
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.bukkit.util.Reflections;
|
||||||
import net.momirealms.craftengine.core.entity.player.Player;
|
import net.momirealms.craftengine.core.entity.player.Player;
|
||||||
import net.momirealms.craftengine.core.item.*;
|
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.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.context.ContextHolder;
|
||||||
import net.momirealms.craftengine.core.plugin.event.EventFunctions;
|
|
||||||
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
|
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
|
||||||
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
|
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
|
||||||
import net.momirealms.craftengine.core.registry.Holder;
|
import net.momirealms.craftengine.core.registry.Holder;
|
||||||
import net.momirealms.craftengine.core.registry.WritableRegistry;
|
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.Bukkit;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.Registry;
|
import org.bukkit.Registry;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.incendo.cloud.suggestion.Suggestion;
|
|
||||||
import org.incendo.cloud.type.Either;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.nio.file.Path;
|
import java.util.ArrayList;
|
||||||
import java.util.*;
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
||||||
@@ -68,7 +55,7 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
|||||||
private final ItemEventListener itemEventListener;
|
private final ItemEventListener itemEventListener;
|
||||||
private final DebugStickListener debugStickListener;
|
private final DebugStickListener debugStickListener;
|
||||||
private final ArmorEventListener armorEventListener;
|
private final ArmorEventListener armorEventListener;
|
||||||
private final ItemParser itemParser;
|
|
||||||
|
|
||||||
public BukkitItemManager(BukkitCraftEngine plugin) {
|
public BukkitItemManager(BukkitCraftEngine plugin) {
|
||||||
super(plugin);
|
super(plugin);
|
||||||
@@ -78,7 +65,6 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
|||||||
this.itemEventListener = new ItemEventListener(plugin);
|
this.itemEventListener = new ItemEventListener(plugin);
|
||||||
this.debugStickListener = new DebugStickListener(plugin);
|
this.debugStickListener = new DebugStickListener(plugin);
|
||||||
this.armorEventListener = new ArmorEventListener();
|
this.armorEventListener = new ArmorEventListener();
|
||||||
this.itemParser = new ItemParser();
|
|
||||||
this.registerAllVanillaItems();
|
this.registerAllVanillaItems();
|
||||||
if (plugin.hasMod()) {
|
if (plugin.hasMod()) {
|
||||||
Class<?> clazz$CustomStreamCodec = ReflectionUtils.getClazz("net.momirealms.craftengine.mod.item.CustomStreamCodec");
|
Class<?> clazz$CustomStreamCodec = ReflectionUtils.getClazz("net.momirealms.craftengine.mod.item.CustomStreamCodec");
|
||||||
@@ -177,11 +163,6 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
|||||||
return this.factory.wrap(ItemTagStream.INSTANCE.fromBytes(bytes));
|
return this.factory.wrap(ItemTagStream.INSTANCE.fromBytes(bytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public ConfigParser parser() {
|
|
||||||
return this.itemParser;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemStack buildCustomItemStack(Key id, Player player) {
|
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);
|
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<ItemStack> {
|
|||||||
return wrapped.id();
|
return wrapped.id();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ItemParser implements ConfigParser {
|
@Override
|
||||||
public static final String[] CONFIG_SECTION_NAME = new String[] {"items", "item"};
|
protected CustomItem.Builder<ItemStack> createPlatformItemBuilder(Key materialId) {
|
||||||
|
Material material = ResourceConfigUtils.requireNonNullOrThrow(Registry.MATERIAL.get(KeyUtils.toNamespacedKey(materialId)), () -> new LocalizedResourceConfigException("warning.config.item.invalid_material", materialId.toString()));
|
||||||
@Override
|
return BukkitCustomItem.builder(material);
|
||||||
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<String, Object> section) {
|
|
||||||
if (customItems.containsKey(id)) {
|
|
||||||
throw new LocalizedResourceConfigException("warning.config.item.duplicate");
|
|
||||||
}
|
|
||||||
|
|
||||||
// register for recipes
|
|
||||||
Holder.Reference<Key> holder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(id)
|
|
||||||
.orElseGet(() -> ((WritableRegistry<Key>) 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<ItemStack> 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<Map<String, Object>> behavior = (List<Map<String, Object>>) behaviorConfig;
|
|
||||||
List<ItemBehavior> behaviors = new ArrayList<>();
|
|
||||||
for (Map<String, Object> behaviorMap : behavior) {
|
|
||||||
behaviors.add(ItemBehaviors.fromMap(pack, path, id, behaviorMap));
|
|
||||||
}
|
|
||||||
itemBuilder.behaviors(behaviors);
|
|
||||||
} else if (behaviorConfig instanceof Map<?, ?>) {
|
|
||||||
Map<String, Object> behaviorSection = MiscUtils.castToMap(section.get("behavior"), true);
|
|
||||||
if (behaviorSection != null) {
|
|
||||||
itemBuilder.behavior(ItemBehaviors.fromMap(pack, path, id, behaviorSection));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get item data
|
|
||||||
Map<String, Object> dataSection = MiscUtils.castToMap(section.get("data"), true);
|
|
||||||
if (dataSection != null) {
|
|
||||||
for (Map.Entry<String, Object> 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<String, Object> clientSideDataSection = MiscUtils.castToMap(section.get("client-bound-data"), true);
|
|
||||||
if (clientSideDataSection != null) {
|
|
||||||
for (Map.Entry<String, Object> 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<ItemStack> 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<Key> 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<String, Object> 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<Integer, Key> 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<Integer, ItemModel> map = modernOverrides.computeIfAbsent(materialId, k -> new TreeMap<>());
|
|
||||||
map.put(customModelData, model);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Config.packMinVersion() < 21.39f) {
|
|
||||||
// TODO 手动指定旧版格式
|
|
||||||
List<LegacyOverridesModel> legacyOverridesModels = new ArrayList<>();
|
|
||||||
processModelRecursively(model, new LinkedHashMap<>(), legacyOverridesModels, materialId, customModelData);
|
|
||||||
TreeSet<LegacyOverridesModel> 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<LegacyOverridesModel> 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<String, Object> accumulatedPredicates,
|
|
||||||
List<LegacyOverridesModel> 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<String, Object> parentPredicates,
|
|
||||||
List<LegacyOverridesModel> resultList,
|
|
||||||
Key materialId,
|
|
||||||
int customModelData
|
|
||||||
) {
|
|
||||||
if (model.property() instanceof LegacyModelPredicate predicate) {
|
|
||||||
String predicateId = predicate.legacyPredicateId(materialId);
|
|
||||||
Map<String, Object> truePredicates = mergePredicates(
|
|
||||||
parentPredicates,
|
|
||||||
predicateId,
|
|
||||||
predicate.toLegacyValue(true)
|
|
||||||
);
|
|
||||||
processModelRecursively(
|
|
||||||
model.onTrue(),
|
|
||||||
truePredicates,
|
|
||||||
resultList,
|
|
||||||
materialId,
|
|
||||||
customModelData
|
|
||||||
);
|
|
||||||
Map<String, Object> falsePredicates = mergePredicates(
|
|
||||||
parentPredicates,
|
|
||||||
predicateId,
|
|
||||||
predicate.toLegacyValue(false)
|
|
||||||
);
|
|
||||||
processModelRecursively(
|
|
||||||
model.onFalse(),
|
|
||||||
falsePredicates,
|
|
||||||
resultList,
|
|
||||||
materialId,
|
|
||||||
customModelData
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
|
||||||
private void handleRangeModel(
|
|
||||||
RangeDispatchItemModel model,
|
|
||||||
Map<String, Object> parentPredicates,
|
|
||||||
List<LegacyOverridesModel> resultList,
|
|
||||||
Key materialId,
|
|
||||||
int customModelData
|
|
||||||
) {
|
|
||||||
if (model.property() instanceof LegacyModelPredicate predicate) {
|
|
||||||
String predicateId = predicate.legacyPredicateId(materialId);
|
|
||||||
for (Map.Entry<Float, ItemModel> entry : model.entries().entrySet()) {
|
|
||||||
Map<String, Object> merged = mergePredicates(
|
|
||||||
parentPredicates,
|
|
||||||
predicateId,
|
|
||||||
predicate.toLegacyValue(entry.getKey())
|
|
||||||
);
|
|
||||||
processModelRecursively(
|
|
||||||
entry.getValue(),
|
|
||||||
merged,
|
|
||||||
resultList,
|
|
||||||
materialId,
|
|
||||||
customModelData
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (model.fallBack() != null) {
|
|
||||||
Map<String, Object> merged = mergePredicates(
|
|
||||||
parentPredicates,
|
|
||||||
predicateId,
|
|
||||||
predicate.toLegacyValue(0f)
|
|
||||||
);
|
|
||||||
processModelRecursively(
|
|
||||||
model.fallBack(),
|
|
||||||
merged,
|
|
||||||
resultList,
|
|
||||||
materialId,
|
|
||||||
customModelData
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
|
||||||
private void handleSelectModel(
|
|
||||||
SelectItemModel model,
|
|
||||||
Map<String, Object> parentPredicates,
|
|
||||||
List<LegacyOverridesModel> resultList,
|
|
||||||
Key materialId,
|
|
||||||
int customModelData
|
|
||||||
) {
|
|
||||||
if (model.property() instanceof LegacyModelPredicate predicate) {
|
|
||||||
String predicateId = predicate.legacyPredicateId(materialId);
|
|
||||||
for (Map.Entry<Either<String, List<String>>, ItemModel> entry : model.whenMap().entrySet()) {
|
|
||||||
List<String> 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<String, Object> 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<String, Object> mergePredicates(
|
|
||||||
Map<String, Object> existing,
|
|
||||||
String newKey,
|
|
||||||
Number newValue
|
|
||||||
) {
|
|
||||||
Map<String, Object> merged = new LinkedHashMap<>(existing);
|
|
||||||
if (newKey == null) return merged;
|
|
||||||
merged.put(newKey, newValue);
|
|
||||||
return merged;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
|||||||
@@ -1,35 +1,48 @@
|
|||||||
package net.momirealms.craftengine.core.item;
|
package net.momirealms.craftengine.core.item;
|
||||||
|
|
||||||
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
|
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.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.misc.EquipmentGeneration;
|
||||||
import net.momirealms.craftengine.core.pack.model.ItemModel;
|
import net.momirealms.craftengine.core.pack.model.*;
|
||||||
import net.momirealms.craftengine.core.pack.model.LegacyOverridesModel;
|
|
||||||
import net.momirealms.craftengine.core.pack.model.generation.AbstractModelGenerator;
|
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.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.registry.Holder;
|
||||||
import net.momirealms.craftengine.core.util.Key;
|
import net.momirealms.craftengine.core.registry.WritableRegistry;
|
||||||
import net.momirealms.craftengine.core.util.MiscUtils;
|
import net.momirealms.craftengine.core.util.*;
|
||||||
import net.momirealms.craftengine.core.util.TypeUtils;
|
|
||||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
|
||||||
import org.incendo.cloud.suggestion.Suggestion;
|
import org.incendo.cloud.suggestion.Suggestion;
|
||||||
|
import org.incendo.cloud.type.Either;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public abstract class AbstractItemManager<I> extends AbstractModelGenerator implements ItemManager<I> {
|
public abstract class AbstractItemManager<I> extends AbstractModelGenerator implements ItemManager<I> {
|
||||||
protected static final Map<Key, List<ItemBehavior>> VANILLA_ITEM_EXTRA_BEHAVIORS = new HashMap<>();
|
protected static final Map<Key, List<ItemBehavior>> VANILLA_ITEM_EXTRA_BEHAVIORS = new HashMap<>();
|
||||||
protected static final List<Key> VANILLA_ITEMS = new ArrayList<>();
|
protected static final Set<Key> VANILLA_ITEMS = new HashSet<>(1024);
|
||||||
protected static final Map<Key, List<Holder<Key>>> VANILLA_ITEM_TAGS = new HashMap<>();
|
protected static final Map<Key, List<Holder<Key>>> VANILLA_ITEM_TAGS = new HashMap<>();
|
||||||
|
|
||||||
|
private final ItemParser itemParser;
|
||||||
protected final Map<String, ExternalItemProvider<I>> externalItemProviders = new HashMap<>();
|
protected final Map<String, ExternalItemProvider<I>> externalItemProviders = new HashMap<>();
|
||||||
protected final Map<String, Function<Object, ItemDataModifier<I>>> dataFunctions = new HashMap<>();
|
protected final Map<String, Function<Object, ItemDataModifier<I>>> dataFunctions = new HashMap<>();
|
||||||
protected final Map<Key, CustomItem<I>> customItems = new HashMap<>();
|
protected final Map<Key, CustomItem<I>> customItems = new HashMap<>();
|
||||||
protected final Map<Key, List<Holder<Key>>> customItemTags;
|
protected final Map<Key, List<Holder<Key>>> customItemTags;
|
||||||
protected final Map<Key, Map<Integer, Key>> cmdConflictChecker;
|
protected final Map<Key, Map<Integer, Key>> cmdConflictChecker;
|
||||||
protected final Map<Key, ItemModel> modernItemModels1_21_4;
|
protected final Map<Key, ItemModel> modernItemModels1_21_4;
|
||||||
protected final Map<Key, List<LegacyOverridesModel>> modernItemModels1_21_2;
|
protected final Map<Key, TreeSet<LegacyOverridesModel>> modernItemModels1_21_2;
|
||||||
protected final Map<Key, TreeSet<LegacyOverridesModel>> legacyOverrides;
|
protected final Map<Key, TreeSet<LegacyOverridesModel>> legacyOverrides;
|
||||||
protected final Map<Key, TreeMap<Integer, ItemModel>> modernOverrides;
|
protected final Map<Key, TreeMap<Integer, ItemModel>> modernOverrides;
|
||||||
protected final Set<EquipmentGeneration> equipmentsToGenerate;
|
protected final Set<EquipmentGeneration> equipmentsToGenerate;
|
||||||
@@ -37,6 +50,19 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
|
|||||||
protected final List<Suggestion> cachedSuggestions = new ArrayList<>();
|
protected final List<Suggestion> cachedSuggestions = new ArrayList<>();
|
||||||
protected final List<Suggestion> cachedTotemSuggestions = new ArrayList<>();
|
protected final List<Suggestion> 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<Object, ItemDataModifier<I>> function, String... alias) {
|
protected void registerDataFunction(Function<Object, ItemDataModifier<I>> function, String... alias) {
|
||||||
for (String a : alias) {
|
for (String a : alias) {
|
||||||
dataFunctions.put(a, function);
|
dataFunctions.put(a, function);
|
||||||
@@ -49,6 +75,25 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void applyDataFunctions(Map<String, Object> dataSection, Consumer<ItemDataModifier<I>> consumer) {
|
||||||
|
if (dataSection != null) {
|
||||||
|
for (Map.Entry<String, Object> 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
|
@Override
|
||||||
public ExternalItemProvider<I> getExternalItemProvider(String name) {
|
public ExternalItemProvider<I> getExternalItemProvider(String name) {
|
||||||
return this.externalItemProviders.get(name);
|
return this.externalItemProviders.get(name);
|
||||||
@@ -81,16 +126,35 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
|
|||||||
return Optional.ofNullable(this.customItems.get(key));
|
return Optional.ofNullable(this.customItems.get(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
public AbstractItemManager(CraftEngine plugin) {
|
@Override
|
||||||
super(plugin);
|
public boolean addCustomItem(CustomItem<I> customItem) {
|
||||||
this.registerFunctions();
|
Key id = customItem.id();
|
||||||
this.legacyOverrides = new HashMap<>();
|
if (this.customItems.containsKey(id)) return false;
|
||||||
this.modernOverrides = new HashMap<>();
|
this.customItems.put(id, customItem);
|
||||||
this.customItemTags = new HashMap<>();
|
// cache command suggestions
|
||||||
this.cmdConflictChecker = new HashMap<>();
|
this.cachedSuggestions.add(Suggestion.suggestion(id.toString()));
|
||||||
this.modernItemModels1_21_4 = new HashMap<>();
|
// totem animations
|
||||||
this.modernItemModels1_21_2 = new HashMap<>();
|
if (VersionHelper.isOrAbove1_21_2()) {
|
||||||
this.equipmentsToGenerate = new HashSet<>();
|
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<Key> 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
|
@Override
|
||||||
@@ -100,7 +164,7 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
|
|||||||
if (holders != null) {
|
if (holders != null) {
|
||||||
items.addAll(holders);
|
items.addAll(holders);
|
||||||
}
|
}
|
||||||
List<Holder<Key>> customItems = customItemTags.get(tag);
|
List<Holder<Key>> customItems = this.customItemTags.get(tag);
|
||||||
if (customItems != null) {
|
if (customItems != null) {
|
||||||
items.addAll(customItems);
|
items.addAll(customItems);
|
||||||
}
|
}
|
||||||
@@ -160,7 +224,7 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<Key, List<LegacyOverridesModel>> modernItemModels1_21_2() {
|
public Map<Key, TreeSet<LegacyOverridesModel>> modernItemModels1_21_2() {
|
||||||
return Collections.unmodifiableMap(this.modernItemModels1_21_2);
|
return Collections.unmodifiableMap(this.modernItemModels1_21_2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,6 +248,157 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
|
|||||||
return Collections.unmodifiableCollection(this.equipmentsToGenerate);
|
return Collections.unmodifiableCollection(this.equipmentsToGenerate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isVanillaItem(Key item) {
|
||||||
|
return VANILLA_ITEMS.contains(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract CustomItem.Builder<I> 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<String, Object> section) {
|
||||||
|
if (customItems.containsKey(id)) {
|
||||||
|
throw new LocalizedResourceConfigException("warning.config.item.duplicate");
|
||||||
|
}
|
||||||
|
|
||||||
|
// register for recipes
|
||||||
|
Holder.Reference<Key> holder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(id)
|
||||||
|
.orElseGet(() -> ((WritableRegistry<Key>) 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<I> 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<I> 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<String, Object> 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<LegacyOverridesModel> 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<Integer, Key> 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<Integer, ItemModel> map = modernOverrides.computeIfAbsent(material, k -> new TreeMap<>());
|
||||||
|
map.put(customModelData, model);
|
||||||
|
}
|
||||||
|
if (Config.packMinVersion() < 21.4f) {
|
||||||
|
TreeSet<LegacyOverridesModel> 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() {
|
private void registerFunctions() {
|
||||||
registerDataFunction((obj) -> {
|
registerDataFunction((obj) -> {
|
||||||
Map<String, Object> data = MiscUtils.castToMap(obj, false);
|
Map<String, Object> data = MiscUtils.castToMap(obj, false);
|
||||||
@@ -258,4 +473,193 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
|
|||||||
}, "equippable");
|
}, "equippable");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void processModelRecursively(
|
||||||
|
ItemModel currentModel,
|
||||||
|
Map<String, Object> accumulatedPredicates,
|
||||||
|
Collection<LegacyOverridesModel> 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<String, Object> parentPredicates,
|
||||||
|
Collection<LegacyOverridesModel> resultList,
|
||||||
|
Key materialId,
|
||||||
|
int customModelData
|
||||||
|
) {
|
||||||
|
if (model.property() instanceof LegacyModelPredicate predicate) {
|
||||||
|
String predicateId = predicate.legacyPredicateId(materialId);
|
||||||
|
Map<String, Object> truePredicates = mergePredicates(
|
||||||
|
parentPredicates,
|
||||||
|
predicateId,
|
||||||
|
predicate.toLegacyValue(true)
|
||||||
|
);
|
||||||
|
processModelRecursively(
|
||||||
|
model.onTrue(),
|
||||||
|
truePredicates,
|
||||||
|
resultList,
|
||||||
|
materialId,
|
||||||
|
customModelData
|
||||||
|
);
|
||||||
|
Map<String, Object> falsePredicates = mergePredicates(
|
||||||
|
parentPredicates,
|
||||||
|
predicateId,
|
||||||
|
predicate.toLegacyValue(false)
|
||||||
|
);
|
||||||
|
processModelRecursively(
|
||||||
|
model.onFalse(),
|
||||||
|
falsePredicates,
|
||||||
|
resultList,
|
||||||
|
materialId,
|
||||||
|
customModelData
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
|
private void handleRangeModel(
|
||||||
|
RangeDispatchItemModel model,
|
||||||
|
Map<String, Object> parentPredicates,
|
||||||
|
Collection<LegacyOverridesModel> resultList,
|
||||||
|
Key materialId,
|
||||||
|
int customModelData
|
||||||
|
) {
|
||||||
|
if (model.property() instanceof LegacyModelPredicate predicate) {
|
||||||
|
String predicateId = predicate.legacyPredicateId(materialId);
|
||||||
|
for (Map.Entry<Float, ItemModel> entry : model.entries().entrySet()) {
|
||||||
|
Map<String, Object> merged = mergePredicates(
|
||||||
|
parentPredicates,
|
||||||
|
predicateId,
|
||||||
|
predicate.toLegacyValue(entry.getKey())
|
||||||
|
);
|
||||||
|
processModelRecursively(
|
||||||
|
entry.getValue(),
|
||||||
|
merged,
|
||||||
|
resultList,
|
||||||
|
materialId,
|
||||||
|
customModelData
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (model.fallBack() != null) {
|
||||||
|
Map<String, Object> merged = mergePredicates(
|
||||||
|
parentPredicates,
|
||||||
|
predicateId,
|
||||||
|
predicate.toLegacyValue(0f)
|
||||||
|
);
|
||||||
|
processModelRecursively(
|
||||||
|
model.fallBack(),
|
||||||
|
merged,
|
||||||
|
resultList,
|
||||||
|
materialId,
|
||||||
|
customModelData
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
|
private void handleSelectModel(
|
||||||
|
SelectItemModel model,
|
||||||
|
Map<String, Object> parentPredicates,
|
||||||
|
Collection<LegacyOverridesModel> resultList,
|
||||||
|
Key materialId,
|
||||||
|
int customModelData
|
||||||
|
) {
|
||||||
|
if (model.property() instanceof LegacyModelPredicate predicate) {
|
||||||
|
String predicateId = predicate.legacyPredicateId(materialId);
|
||||||
|
for (Map.Entry<Either<String, List<String>>, ItemModel> entry : model.whenMap().entrySet()) {
|
||||||
|
List<String> 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<String, Object> 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<String, Object> mergePredicates(
|
||||||
|
Map<String, Object> existing,
|
||||||
|
String newKey,
|
||||||
|
Number newValue
|
||||||
|
) {
|
||||||
|
Map<String, Object> merged = new LinkedHashMap<>(existing);
|
||||||
|
if (newKey == null) return merged;
|
||||||
|
merged.put(newKey, newValue);
|
||||||
|
return merged;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.PlayerOptionalContext;
|
||||||
import net.momirealms.craftengine.core.plugin.context.function.Function;
|
import net.momirealms.craftengine.core.plugin.context.function.Function;
|
||||||
import net.momirealms.craftengine.core.plugin.event.EventTrigger;
|
import net.momirealms.craftengine.core.plugin.event.EventTrigger;
|
||||||
|
import net.momirealms.craftengine.core.registry.Holder;
|
||||||
import net.momirealms.craftengine.core.util.Key;
|
import net.momirealms.craftengine.core.util.Key;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
@@ -17,6 +18,8 @@ public interface CustomItem<I> extends BuildableItem<I> {
|
|||||||
|
|
||||||
Key id();
|
Key id();
|
||||||
|
|
||||||
|
Holder<Key> idHolder();
|
||||||
|
|
||||||
Key material();
|
Key material();
|
||||||
|
|
||||||
NetworkItemDataProcessor<I>[] networkItemDataProcessors();
|
NetworkItemDataProcessor<I>[] networkItemDataProcessors();
|
||||||
@@ -49,7 +52,7 @@ public interface CustomItem<I> extends BuildableItem<I> {
|
|||||||
List<ItemBehavior> behaviors();
|
List<ItemBehavior> behaviors();
|
||||||
|
|
||||||
interface Builder<I> {
|
interface Builder<I> {
|
||||||
Builder<I> id(Key id);
|
Builder<I> id(Holder<Key> id);
|
||||||
|
|
||||||
Builder<I> material(Key material);
|
Builder<I> material(Key material);
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ public class ItemKeys {
|
|||||||
public static final Key BUCKET = Key.of("minecraft:bucket");
|
public static final Key BUCKET = Key.of("minecraft:bucket");
|
||||||
public static final Key BONE_MEAL = Key.of("minecraft:bone_meal");
|
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 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[] {
|
public static final Key[] AXES = new Key[] {
|
||||||
WOODEN_AXE, STONE_AXE, IRON_AXE, GOLDEN_AXE, DIAMOND_AXE, NETHERITE_AXE
|
WOODEN_AXE, STONE_AXE, IRON_AXE, GOLDEN_AXE, DIAMOND_AXE, NETHERITE_AXE
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ public interface ItemManager<T> extends Manageable, ModelGenerator {
|
|||||||
|
|
||||||
Map<Key, ItemModel> modernItemModels1_21_4();
|
Map<Key, ItemModel> modernItemModels1_21_4();
|
||||||
|
|
||||||
Map<Key, List<LegacyOverridesModel>> modernItemModels1_21_2();
|
Map<Key, TreeSet<LegacyOverridesModel>> modernItemModels1_21_2();
|
||||||
|
|
||||||
Collection<Key> vanillaItems();
|
Collection<Key> vanillaItems();
|
||||||
|
|
||||||
@@ -67,6 +67,8 @@ public interface ItemManager<T> extends Manageable, ModelGenerator {
|
|||||||
return getVanillaItem(key);
|
return getVanillaItem(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean addCustomItem(CustomItem<T> customItem);
|
||||||
|
|
||||||
List<Holder<Key>> tagToItems(Key tag);
|
List<Holder<Key>> tagToItems(Key tag);
|
||||||
|
|
||||||
List<Holder<Key>> tagToVanillaItems(Key tag);
|
List<Holder<Key>> tagToVanillaItems(Key tag);
|
||||||
@@ -80,4 +82,6 @@ public interface ItemManager<T> extends Manageable, ModelGenerator {
|
|||||||
Collection<Suggestion> cachedSuggestions();
|
Collection<Suggestion> cachedSuggestions();
|
||||||
|
|
||||||
Collection<Suggestion> cachedTotemSuggestions();
|
Collection<Suggestion> cachedTotemSuggestions();
|
||||||
|
|
||||||
|
boolean isVanillaItem(Key item);
|
||||||
}
|
}
|
||||||
@@ -7,10 +7,13 @@ import net.momirealms.craftengine.core.registry.Holder;
|
|||||||
import net.momirealms.craftengine.core.registry.Registries;
|
import net.momirealms.craftengine.core.registry.Registries;
|
||||||
import net.momirealms.craftengine.core.registry.WritableRegistry;
|
import net.momirealms.craftengine.core.registry.WritableRegistry;
|
||||||
import net.momirealms.craftengine.core.util.Key;
|
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.ResourceConfigUtils;
|
||||||
import net.momirealms.craftengine.core.util.ResourceKey;
|
import net.momirealms.craftengine.core.util.ResourceKey;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class ItemBehaviors {
|
public class ItemBehaviors {
|
||||||
@@ -32,4 +35,23 @@ public class ItemBehaviors {
|
|||||||
}
|
}
|
||||||
return factory.create(pack, path, id, map);
|
return factory.create(pack, path, id, map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<ItemBehavior> fromList(Pack pack, Path path, Key id, List<Map<String, Object>> list) {
|
||||||
|
List<ItemBehavior> behaviors = new ArrayList<>(list.size());
|
||||||
|
for (Map<String, Object> map : list) {
|
||||||
|
behaviors.add(fromMap(pack, path, id, map));
|
||||||
|
}
|
||||||
|
return behaviors;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static List<ItemBehavior> 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<Map<String, Object>>) behaviorObj);
|
||||||
|
} else {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -43,6 +43,7 @@ import java.lang.reflect.Constructor;
|
|||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
|
import java.nio.file.FileSystem;
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
@@ -918,9 +919,9 @@ public abstract class AbstractPackManager implements PackManager {
|
|||||||
if (Config.packMinVersion() > 21.39f) return;
|
if (Config.packMinVersion() > 21.39f) return;
|
||||||
|
|
||||||
// 此段代码生成1.21.2专用的item model文件,情况非常复杂!
|
// 此段代码生成1.21.2专用的item model文件,情况非常复杂!
|
||||||
for (Map.Entry<Key, List<LegacyOverridesModel>> entry : this.plugin.itemManager().modernItemModels1_21_2().entrySet()) {
|
for (Map.Entry<Key, TreeSet<LegacyOverridesModel>> entry : this.plugin.itemManager().modernItemModels1_21_2().entrySet()) {
|
||||||
Key itemModelPath = entry.getKey();
|
Key itemModelPath = entry.getKey();
|
||||||
List<LegacyOverridesModel> legacyOverridesModels = entry.getValue();
|
TreeSet<LegacyOverridesModel> legacyOverridesModels = entry.getValue();
|
||||||
|
|
||||||
// 检测item model合法性
|
// 检测item model合法性
|
||||||
if (PRESET_MODERN_MODELS_ITEM.containsKey(itemModelPath) || PRESET_LEGACY_MODELS_ITEM.containsKey(itemModelPath)) {
|
if (PRESET_MODERN_MODELS_ITEM.containsKey(itemModelPath) || PRESET_LEGACY_MODELS_ITEM.containsKey(itemModelPath)) {
|
||||||
|
|||||||
@@ -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.pack.conflict.PathContext;
|
||||||
import net.momirealms.craftengine.core.plugin.context.Condition;
|
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.context.condition.ConditionFactory;
|
||||||
import net.momirealms.craftengine.core.plugin.locale.LocalizedException;
|
import net.momirealms.craftengine.core.plugin.locale.LocalizedException;
|
||||||
import net.momirealms.craftengine.core.util.CharacterUtils;
|
import net.momirealms.craftengine.core.util.CharacterUtils;
|
||||||
|
|||||||
@@ -16,6 +16,14 @@ public class HasComponentConditionProperty implements ConditionProperty {
|
|||||||
this.ignoreDefault = ignoreDefault;
|
this.ignoreDefault = ignoreDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String component() {
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean ignoreDefault() {
|
||||||
|
return ignoreDefault;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Key type() {
|
public Key type() {
|
||||||
return ConditionProperties.HAS_COMPONENT;
|
return ConditionProperties.HAS_COMPONENT;
|
||||||
|
|||||||
@@ -1,14 +1,9 @@
|
|||||||
package net.momirealms.craftengine.core.util;
|
package net.momirealms.craftengine.core.util;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.DirectoryStream;
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayDeque;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Deque;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class FileUtils {
|
public class FileUtils {
|
||||||
|
|||||||
Reference in New Issue
Block a user