mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-26 10:29:20 +00:00
Merge branch 'Xiao-MoMi:dev' into dev
This commit is contained in:
@@ -1,35 +1,49 @@
|
||||
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.plugin.locale.TranslationManager;
|
||||
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<I> extends AbstractModelGenerator implements ItemManager<I> {
|
||||
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<>();
|
||||
|
||||
private final ItemParser itemParser;
|
||||
protected final Map<String, ExternalItemProvider<I>> externalItemProviders = 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, List<Holder<Key>>> customItemTags;
|
||||
protected final Map<Key, Map<Integer, Key>> cmdConflictChecker;
|
||||
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, TreeMap<Integer, ItemModel>> modernOverrides;
|
||||
protected final Set<EquipmentGeneration> equipmentsToGenerate;
|
||||
@@ -37,6 +51,19 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
|
||||
protected final List<Suggestion> cachedSuggestions = 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) {
|
||||
for (String a : alias) {
|
||||
dataFunctions.put(a, function);
|
||||
@@ -49,6 +76,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
|
||||
public ExternalItemProvider<I> getExternalItemProvider(String name) {
|
||||
return this.externalItemProviders.get(name);
|
||||
@@ -81,16 +127,35 @@ public abstract class AbstractItemManager<I> 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<I> 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<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
|
||||
@@ -100,7 +165,7 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
|
||||
if (holders != null) {
|
||||
items.addAll(holders);
|
||||
}
|
||||
List<Holder<Key>> customItems = customItemTags.get(tag);
|
||||
List<Holder<Key>> customItems = this.customItemTags.get(tag);
|
||||
if (customItems != null) {
|
||||
items.addAll(customItems);
|
||||
}
|
||||
@@ -160,7 +225,7 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Key, List<LegacyOverridesModel>> modernItemModels1_21_2() {
|
||||
public Map<Key, TreeSet<LegacyOverridesModel>> modernItemModels1_21_2() {
|
||||
return Collections.unmodifiableMap(this.modernItemModels1_21_2);
|
||||
}
|
||||
|
||||
@@ -184,6 +249,198 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
|
||||
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 (AbstractItemManager.this.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");
|
||||
if (customModelData < 0) {
|
||||
throw new LocalizedResourceConfigException("warning.config.item.invalid_custom_model_data", String.valueOf(customModelData));
|
||||
}
|
||||
if (customModelData > 16_777_216) {
|
||||
throw new LocalizedResourceConfigException("warning.config.item.bad_custom_model_data", String.valueOf(customModelData));
|
||||
}
|
||||
|
||||
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 && VersionHelper.isOrAbove1_21_2()) {
|
||||
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);
|
||||
Map<String, Object> legacyModelSection = MiscUtils.castToMap(section.get("legacy-model"), true);
|
||||
if (modelSection == null && legacyModelSection == null) {
|
||||
return;
|
||||
}
|
||||
// 如果设置了model,但是没有模型值?
|
||||
if (customModelData == 0 && itemModelKey == null) {
|
||||
throw new LocalizedResourceConfigException("warning.config.item.missing_model_id");
|
||||
}
|
||||
// 1.21.4+必须要配置model区域
|
||||
if (Config.packMaxVersion() >= 21.4f && modelSection == null) {
|
||||
throw new LocalizedResourceConfigException("warning.config.item.missing_model");
|
||||
}
|
||||
|
||||
// 新版格式
|
||||
ItemModel modernModel = null;
|
||||
// 旧版格式
|
||||
TreeSet<LegacyOverridesModel> legacyOverridesModels = null;
|
||||
|
||||
if (Config.packMaxVersion() >= 21.4f) {
|
||||
modernModel = ItemModels.fromMap(modelSection);
|
||||
for (ModelGeneration generation : modernModel.modelsToGenerate()) {
|
||||
prepareModelGeneration(generation);
|
||||
}
|
||||
// 如果最低支持版本低于1.21.4,则需要准备旧版overrides模型
|
||||
if (Config.packMinVersion() < 21.4f) {
|
||||
// 如果有旧版格式,就用旧版
|
||||
if (legacyModelSection != null) {
|
||||
LegacyItemModel legacyItemModel = LegacyItemModel.fromMap(legacyModelSection);
|
||||
for (ModelGeneration generation : legacyItemModel.modelsToGenerate()) {
|
||||
prepareModelGeneration(generation);
|
||||
}
|
||||
legacyOverridesModels = new TreeSet<>(legacyItemModel.overrides());
|
||||
} else {
|
||||
// 否则把新版格式并转换为旧版
|
||||
legacyOverridesModels = new TreeSet<>();
|
||||
processModelRecursively(modernModel, new LinkedHashMap<>(), legacyOverridesModels, material, customModelData);
|
||||
if (legacyOverridesModels.isEmpty()) {
|
||||
TranslationManager.instance().log("warning.config.item.legacy_model.cannot_convert", path.toString(), id.asString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 最高支持版本不超过1.21.4,所以新版model格式为非必需
|
||||
else {
|
||||
// 如果有旧版格式,就用旧版
|
||||
if (legacyModelSection != null) {
|
||||
LegacyItemModel legacyItemModel = LegacyItemModel.fromMap(legacyModelSection);
|
||||
for (ModelGeneration generation : legacyItemModel.modelsToGenerate()) {
|
||||
prepareModelGeneration(generation);
|
||||
}
|
||||
legacyOverridesModels = new TreeSet<>(legacyItemModel.overrides());
|
||||
} else {
|
||||
// 否则读新版格式并转换为旧版
|
||||
ItemModel model = ItemModels.fromMap(modelSection);
|
||||
for (ModelGeneration generation : model.modelsToGenerate()) {
|
||||
prepareModelGeneration(generation);
|
||||
}
|
||||
legacyOverridesModels = new TreeSet<>();
|
||||
processModelRecursively(model, new LinkedHashMap<>(), legacyOverridesModels, material, customModelData);
|
||||
if (legacyOverridesModels.isEmpty()) {
|
||||
TranslationManager.instance().log("warning.config.item.legacy_model.cannot_convert", path.toString(), id.asString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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());
|
||||
}
|
||||
conflict.put(customModelData, id);
|
||||
// Parse models
|
||||
if (Config.packMaxVersion() >= 21.4f && modernModel != null) {
|
||||
TreeMap<Integer, ItemModel> map = modernOverrides.computeIfAbsent(material, k -> new TreeMap<>());
|
||||
map.put(customModelData, modernModel);
|
||||
}
|
||||
if (Config.packMinVersion() < 21.4f && legacyOverridesModels != null && !legacyOverridesModels.isEmpty()) {
|
||||
TreeSet<LegacyOverridesModel> lom = legacyOverrides.computeIfAbsent(material, k -> new TreeSet<>());
|
||||
lom.addAll(legacyOverridesModels);
|
||||
}
|
||||
}
|
||||
|
||||
// use item model
|
||||
if (itemModelKey != null) {
|
||||
if (Config.packMaxVersion() >= 21.4f && modernModel != null) {
|
||||
modernItemModels1_21_4.put(itemModelKey, modernModel);
|
||||
}
|
||||
if (Config.packMaxVersion() >= 21.2f && Config.packMinVersion() < 21.4f && legacyOverridesModels != null && !legacyOverridesModels.isEmpty()) {
|
||||
modernItemModels1_21_2.put(itemModelKey, legacyOverridesModels);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void registerFunctions() {
|
||||
registerDataFunction((obj) -> {
|
||||
Map<String, Object> data = MiscUtils.castToMap(obj, false);
|
||||
@@ -258,4 +515,193 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
|
||||
}, "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.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<I> extends BuildableItem<I> {
|
||||
|
||||
Key id();
|
||||
|
||||
Holder<Key> idHolder();
|
||||
|
||||
Key material();
|
||||
|
||||
NetworkItemDataProcessor<I>[] networkItemDataProcessors();
|
||||
@@ -49,7 +52,7 @@ public interface CustomItem<I> extends BuildableItem<I> {
|
||||
List<ItemBehavior> behaviors();
|
||||
|
||||
interface Builder<I> {
|
||||
Builder<I> id(Key id);
|
||||
Builder<I> id(Holder<Key> id);
|
||||
|
||||
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 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
|
||||
|
||||
@@ -27,7 +27,7 @@ public interface ItemManager<T> extends Manageable, ModelGenerator {
|
||||
|
||||
Map<Key, ItemModel> modernItemModels1_21_4();
|
||||
|
||||
Map<Key, List<LegacyOverridesModel>> modernItemModels1_21_2();
|
||||
Map<Key, TreeSet<LegacyOverridesModel>> modernItemModels1_21_2();
|
||||
|
||||
Collection<Key> vanillaItems();
|
||||
|
||||
@@ -67,6 +67,8 @@ public interface ItemManager<T> extends Manageable, ModelGenerator {
|
||||
return getVanillaItem(key);
|
||||
}
|
||||
|
||||
boolean addCustomItem(CustomItem<T> customItem);
|
||||
|
||||
List<Holder<Key>> tagToItems(Key tag);
|
||||
|
||||
List<Holder<Key>> tagToVanillaItems(Key tag);
|
||||
@@ -80,4 +82,6 @@ public interface ItemManager<T> extends Manageable, ModelGenerator {
|
||||
Collection<Suggestion> cachedSuggestions();
|
||||
|
||||
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.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<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.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<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();
|
||||
List<LegacyOverridesModel> legacyOverridesModels = entry.getValue();
|
||||
TreeSet<LegacyOverridesModel> legacyOverridesModels = entry.getValue();
|
||||
|
||||
// 检测item model合法性
|
||||
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.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;
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package net.momirealms.craftengine.core.pack.model;
|
||||
|
||||
import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.MiscUtils;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class LegacyItemModel {
|
||||
private final List<ModelGeneration> modelsToGenerate;
|
||||
private final String path;
|
||||
private final List<LegacyOverridesModel> overrides;
|
||||
|
||||
public LegacyItemModel(String path, List<LegacyOverridesModel> overrides, List<ModelGeneration> modelsToGenerate) {
|
||||
this.modelsToGenerate = modelsToGenerate;
|
||||
this.path = path;
|
||||
this.overrides = overrides;
|
||||
}
|
||||
|
||||
public List<ModelGeneration> modelsToGenerate() {
|
||||
return modelsToGenerate;
|
||||
}
|
||||
|
||||
public List<LegacyOverridesModel> overrides() {
|
||||
return overrides;
|
||||
}
|
||||
|
||||
public String path() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public static LegacyItemModel fromMap(Map<String, Object> legacyModel) {
|
||||
String legacyModelPath = ResourceConfigUtils.requireNonEmptyStringOrThrow(legacyModel.get("path"), "warning.config.item.legacy_model.missing_path");
|
||||
Map<String, Object> generation = MiscUtils.castToMap(legacyModel.get("generation"), true);
|
||||
ModelGeneration modelGeneration = null;
|
||||
if (generation != null) {
|
||||
modelGeneration = ModelGeneration.of(Key.of(legacyModelPath), generation);
|
||||
}
|
||||
LegacyOverridesModel legacyOverridesModel = new LegacyOverridesModel();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user