9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-27 19:09:08 +00:00

盔甲重构part1

This commit is contained in:
XiaoMoMi
2025-07-03 05:55:57 +08:00
parent a27f1678fd
commit d9bf33ce11
30 changed files with 931 additions and 362 deletions

View File

@@ -4,13 +4,14 @@ import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
import net.momirealms.craftengine.core.item.behavior.ItemBehaviors;
import net.momirealms.craftengine.core.item.data.Enchantment;
import net.momirealms.craftengine.core.item.data.JukeboxPlayable;
import net.momirealms.craftengine.core.item.equipment.Equipment;
import net.momirealms.craftengine.core.item.equipment.Equipments;
import net.momirealms.craftengine.core.item.equipment.TrimBasedEquipment;
import net.momirealms.craftengine.core.item.modifier.*;
import net.momirealms.craftengine.core.item.setting.EquipmentData;
import net.momirealms.craftengine.core.item.setting.ItemEquipment;
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.Equipment;
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;
@@ -22,7 +23,6 @@ import net.momirealms.craftengine.core.plugin.config.ConfigParser;
import net.momirealms.craftengine.core.plugin.context.event.EventFunctions;
import net.momirealms.craftengine.core.plugin.context.text.TextProvider;
import net.momirealms.craftengine.core.plugin.context.text.TextProviders;
import net.momirealms.craftengine.core.plugin.locale.LocalizedException;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.plugin.locale.TranslationManager;
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
@@ -49,13 +49,13 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
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, ModernItemModel> modernItemModels1_21_4;
protected final Map<Key, TreeSet<LegacyOverridesModel>> modernItemModels1_21_2;
protected final Map<Key, TreeSet<LegacyOverridesModel>> legacyOverrides;
protected final Map<Key, TreeMap<Integer, ModernItemModel>> modernOverrides;
protected final Map<Key, Equipment> equipmentsToGenerate;
protected final Map<Key, List<Holder<Key>>> customItemTags = new HashMap<>();
protected final Map<Key, Map<Integer, Key>> cmdConflictChecker = new HashMap<>();
protected final Map<Key, ModernItemModel> modernItemModels1_21_4 = new HashMap<>();
protected final Map<Key, TreeSet<LegacyOverridesModel>> modernItemModels1_21_2 = new HashMap<>();
protected final Map<Key, TreeSet<LegacyOverridesModel>> legacyOverrides = new HashMap<>();
protected final Map<Key, TreeMap<Integer, ModernItemModel>> modernOverrides = new HashMap<>();
protected final Map<Key, Equipment> equipments = new HashMap<>();
// Cached command suggestions
protected final List<Suggestion> cachedSuggestions = new ArrayList<>();
protected final List<Suggestion> cachedTotemSuggestions = new ArrayList<>();
@@ -65,13 +65,6 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
this.itemParser = new ItemParser();
this.equipmentParser = new EquipmentParser();
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 HashMap<>();
}
@Override
@@ -127,12 +120,22 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
this.legacyOverrides.clear();
this.modernOverrides.clear();
this.customItemTags.clear();
this.equipmentsToGenerate.clear();
this.equipments.clear();
this.cmdConflictChecker.clear();
this.modernItemModels1_21_4.clear();
this.modernItemModels1_21_2.clear();
}
@Override
public Map<Key, Equipment> equipments() {
return Collections.unmodifiableMap(this.equipments);
}
@Override
public Optional<Equipment> getEquipment(Key key) {
return Optional.ofNullable(this.equipments.get(key));
}
@Override
public Optional<CustomItem<I>> getCustomItem(Key key) {
return Optional.ofNullable(this.customItems.get(key));
@@ -156,13 +159,6 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
for (Key tag : tags) {
this.customItemTags.computeIfAbsent(tag, k -> new ArrayList<>()).add(customItem.idHolder());
}
// equipment generation
ItemEquipment equipment = customItem.settings().equipment();
if (equipment != null) {
EquipmentData data = equipment.data();
Equipment equipmentJson = this.equipmentsToGenerate.computeIfAbsent(data.assetId(), k -> new Equipment());
equipmentJson.addAll(equipment);
}
return true;
}
@@ -252,11 +248,6 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
return Collections.unmodifiableMap(this.modernOverrides);
}
@Override
public Map<Key, Equipment> equipmentsToGenerate() {
return Collections.unmodifiableMap(this.equipmentsToGenerate);
}
@Override
public boolean isVanillaItem(Key item) {
return VANILLA_ITEMS.contains(item);
@@ -264,6 +255,8 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
protected abstract CustomItem.Builder<I> createPlatformItemBuilder(Holder<Key> id, Key material, Key clientBoundMaterial);
protected abstract void registerArmorTrimPattern(Collection<TrimBasedEquipment> equipments);
public class EquipmentParser implements ConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] {"equipments", "equipment"};
@@ -279,8 +272,21 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
@Override
public void parseSection(Pack pack, Path path, Key id, Map<String, Object> section) {
if (AbstractItemManager.this.equipments.containsKey(id)) {
throw new LocalizedResourceConfigException("warning.config.equipment.duplicate");
}
Equipment equipment = Equipments.fromMap(id, section);
AbstractItemManager.this.equipments.put(id, equipment);
}
@Override
public void postProcess() {
registerArmorTrimPattern(
AbstractItemManager.this.equipments.values().stream()
.filter(TrimBasedEquipment.class::isInstance)
.map(TrimBasedEquipment.class::cast)
.toList()
);
}
}
@@ -320,6 +326,7 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
Key material = Key.from(isVanillaItem ? id.value() : ResourceConfigUtils.requireNonEmptyStringOrThrow(section.get("material"), "warning.config.item.missing_material").toLowerCase(Locale.ENGLISH));
Key clientBoundMaterial = section.containsKey("client-bound-material") ? Key.from(section.get("client-bound-material").toString().toLowerCase(Locale.ENGLISH)) : material;
int customModelData = ResourceConfigUtils.getAsInt(section.getOrDefault("custom-model-data", 0), "custom-model-data");
boolean clientBoundModel = section.containsKey("client-bound-model") ? ResourceConfigUtils.getAsBoolean(section.get("client-bound-data"), "client-bound-data") : Config.globalClientboundModel();
if (customModelData < 0) {
throw new LocalizedResourceConfigException("warning.config.item.invalid_custom_model_data", String.valueOf(customModelData));
}
@@ -335,7 +342,11 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
// To get at least one model provider
// Sets some basic model info
if (customModelData > 0) {
itemBuilder.clientBoundDataModifier(new CustomModelDataModifier<>(customModelData));
if (clientBoundModel) {
itemBuilder.clientBoundDataModifier(new CustomModelDataModifier<>(customModelData));
} else {
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()) {
@@ -343,7 +354,11 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
// customize or use the id
itemModelKey = Key.from(section.getOrDefault("item-model", id.toString()).toString());
if (ResourceLocation.isValid(itemModelKey.toString())) {
itemBuilder.clientBoundDataModifier(new ItemModelModifier<>(itemModelKey));
if (clientBoundModel) {
itemBuilder.clientBoundDataModifier(new ItemModelModifier<>(itemModelKey));
} else {
itemBuilder.dataModifier(new ItemModelModifier<>(itemModelKey));
}
} else {
itemModelKey = null;
}
@@ -351,7 +366,11 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
if (hasItemModelSection && VersionHelper.isOrAbove1_21_2()) {
itemModelKey = Key.from(section.get("item-model").toString());
itemBuilder.clientBoundDataModifier(new ItemModelModifier<>(itemModelKey));
if (clientBoundModel) {
itemBuilder.clientBoundDataModifier(new ItemModelModifier<>(itemModelKey));
} else {
itemBuilder.dataModifier(new ItemModelModifier<>(itemModelKey));
}
}
// Get item data

View File

@@ -2,8 +2,8 @@ package net.momirealms.craftengine.core.item;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
import net.momirealms.craftengine.core.item.equipment.Equipment;
import net.momirealms.craftengine.core.item.modifier.ItemDataModifier;
import net.momirealms.craftengine.core.pack.misc.Equipment;
import net.momirealms.craftengine.core.pack.model.LegacyOverridesModel;
import net.momirealms.craftengine.core.pack.model.ModernItemModel;
import net.momirealms.craftengine.core.pack.model.generation.ModelGenerator;
@@ -21,14 +21,14 @@ public interface ItemManager<T> extends Manageable, ModelGenerator {
void registerDataType(Function<Object, ItemDataModifier<T>> factory, String... alias);
Map<Key, Equipment> equipments();
ConfigParser[] parsers();
Map<Key, TreeSet<LegacyOverridesModel>> legacyItemOverrides();
Map<Key, TreeMap<Integer, ModernItemModel>> modernItemOverrides();
Map<Key, Equipment> equipmentsToGenerate();
Map<Key, ModernItemModel> modernItemModels1_21_4();
Map<Key, TreeSet<LegacyOverridesModel>> modernItemModels1_21_2();
@@ -57,6 +57,8 @@ public interface ItemManager<T> extends Manageable, ModelGenerator {
boolean registerExternalItemProvider(ExternalItemProvider<T> externalItemProvider);
Optional<Equipment> getEquipment(Key key);
Optional<CustomItem<T>> getCustomItem(Key key);
Optional<List<ItemBehavior>> getItemBehavior(Key key);

View File

@@ -5,11 +5,13 @@ import net.momirealms.craftengine.core.entity.ItemDisplayContext;
import net.momirealms.craftengine.core.entity.projectile.ProjectileMeta;
import net.momirealms.craftengine.core.entity.projectile.ProjectileType;
import net.momirealms.craftengine.core.item.equipment.ComponentBasedEquipment;
import net.momirealms.craftengine.core.item.equipment.Equipment;
import net.momirealms.craftengine.core.item.modifier.EquippableModifier;
import net.momirealms.craftengine.core.item.modifier.FoodModifier;
import net.momirealms.craftengine.core.item.modifier.ItemDataModifier;
import net.momirealms.craftengine.core.item.setting.*;
import net.momirealms.craftengine.core.pack.misc.EquipmentLayerType;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.sound.SoundData;
import net.momirealms.craftengine.core.util.*;
@@ -23,8 +25,6 @@ import java.util.stream.Collectors;
public class ItemSettings {
int fuelTime;
Set<Key> tags = Set.of();
@Nullable
ItemEquipment equipment;
boolean canRepair = true;
List<AnvilRepairItem> anvilRepairItems = List.of();
boolean renameable = true;
@@ -38,13 +38,21 @@ public class ItemSettings {
List<DamageSource> invulnerable = List.of();
boolean canEnchant = true;
float compostProbability= 0.5f;
@Nullable
ItemEquipment equipment;
private ItemSettings() {}
public <I> List<ItemDataModifier<I>> modifiers() {
ArrayList<ItemDataModifier<I>> modifiers = new ArrayList<>();
if (VersionHelper.isOrAbove1_21_2() && this.equipment != null) {
modifiers.add(new EquippableModifier<>(this.equipment.data()));
if (this.equipment != null) {
EquipmentData data = this.equipment.equipmentData();
if (data != null) {
modifiers.add(new EquippableModifier<>(data));
}
if (!this.equipment.clientBoundModel().asBoolean(Config.globalClientboundModel())) {
modifiers.add(this.equipment.equipment().modifier());
}
}
if (VersionHelper.isOrAbove1_20_5() && this.foodData != null) {
modifiers.add(new FoodModifier<>(this.foodData.nutrition(), this.foodData.saturation(), false));
@@ -52,6 +60,16 @@ public class ItemSettings {
return modifiers;
}
public <I> List<ItemDataModifier<I>> clientBoundModifiers() {
ArrayList<ItemDataModifier<I>> modifiers = new ArrayList<>();
if (this.equipment != null) {
if (this.equipment.clientBoundModel().asBoolean(Config.globalClientboundModel())) {
modifiers.add(this.equipment.equipment().modifier());
}
}
return modifiers;
}
public static ItemSettings of() {
return new ItemSettings();
}
@@ -302,16 +320,31 @@ public class ItemSettings {
Map<String, Object> args = MiscUtils.castToMap(value, false);
EquipmentData data = EquipmentData.fromMap(args);
ComponentBasedEquipment componentBasedEquipment = ComponentBasedEquipment.FACTORY.create(data.assetId(), args);
ItemEquipment itemEquipment = new ItemEquipment(data, componentBasedEquipment);
ItemEquipment itemEquipment = new ItemEquipment(Tristate.FALSE, data, componentBasedEquipment);
return settings -> settings.equipment(itemEquipment);
}));
registerFactory("equipment", (value -> {
Map<String, Object> args = MiscUtils.castToMap(value, false);
Tristate clientBoundModel = Tristate.of((Boolean) args.get("client-bound-model"));
Key assetId = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(args.get("asset-id"), "warning.config.item.settings.equipment.missing_asset_id"));
Optional<Equipment> optionalEquipment = CraftEngine.instance().itemManager().getEquipment(assetId);
if (optionalEquipment.isEmpty()) {
throw new LocalizedResourceConfigException("warning.config.item.settings.equipment.invalid_asset_id");
}
if (VersionHelper.isOrAbove1_21_2() && args.containsKey("slot")) {
EquipmentData data = EquipmentData.fromMap(args);
return settings -> settings.equipment(new ItemEquipment(clientBoundModel, data, optionalEquipment.get()));
} else {
return settings -> settings.equipment(new ItemEquipment(clientBoundModel, null, optionalEquipment.get()));
}
}));
registerFactory("can-place", (value -> {
boolean bool = ResourceConfigUtils.getAsBoolean(value, "can-place");
return settings -> settings.canPlaceRelatedVanillaBlock(bool);
}));
registerFactory("projectile", (value -> {
Map<String, Object> args = MiscUtils.castToMap(value, false);
Key customTridentItemId = Key.of(Objects.requireNonNull(args.get("item"), "'item should not be null'").toString());
Key customTridentItemId = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(args.get("item"), "warning.config.item.settings.projectile.missing_item"));
ItemDisplayContext displayType = ItemDisplayContext.valueOf(args.getOrDefault("display-transform", "NONE").toString().toUpperCase(Locale.ENGLISH));
Billboard billboard = Billboard.valueOf(args.getOrDefault("billboard", "FIXED").toString().toUpperCase(Locale.ENGLISH));
Vector3f translation = MiscUtils.getAsVector3f(args.getOrDefault("translation", "0"), "translation");

View File

@@ -1,7 +1,9 @@
package net.momirealms.craftengine.core.item.equipment;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import net.momirealms.craftengine.core.pack.misc.EquipmentLayerType;
import net.momirealms.craftengine.core.item.modifier.EquippableAssetIdModifier;
import net.momirealms.craftengine.core.item.modifier.ItemDataModifier;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MiscUtils;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
@@ -14,7 +16,7 @@ import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
public class ComponentBasedEquipment extends AbstractEquipment {
public class ComponentBasedEquipment extends AbstractEquipment implements Supplier<JsonObject> {
public static final Factory FACTORY = new Factory();
private final EnumMap<EquipmentLayerType, List<Layer>> layers;
@@ -24,10 +26,15 @@ public class ComponentBasedEquipment extends AbstractEquipment {
}
@Override
public Key renderingMethod() {
public Key type() {
return Equipments.COMPONENT;
}
@Override
public <I> ItemDataModifier<I> modifier() {
return new EquippableAssetIdModifier<>(this.assetId);
}
public EnumMap<EquipmentLayerType, List<Layer>> layers() {
return layers;
}
@@ -36,6 +43,28 @@ public class ComponentBasedEquipment extends AbstractEquipment {
this.layers.put(layerType, layer);
}
@Override
public JsonObject get() {
JsonObject jsonObject = new JsonObject();
JsonObject layersJson = new JsonObject();
jsonObject.add("layers", layersJson);
for (Map.Entry<EquipmentLayerType, List<ComponentBasedEquipment.Layer>> entry : layers.entrySet()) {
EquipmentLayerType type = entry.getKey();
List<ComponentBasedEquipment.Layer> layerList = entry.getValue();
setLayers(layersJson, layerList, type.id());
}
return jsonObject;
}
private void setLayers(JsonObject layersJson, List<ComponentBasedEquipment.Layer> layers, String key) {
if (layers == null || layers.isEmpty()) return;
JsonArray layersArray = new JsonArray();
for (ComponentBasedEquipment.Layer layer : layers) {
layersArray.add(layer.get());
}
layersJson.add(key, layersArray);
}
public static class Factory implements EquipmentFactory {
@Override

View File

@@ -1,10 +1,13 @@
package net.momirealms.craftengine.core.item.equipment;
import net.momirealms.craftengine.core.item.modifier.ItemDataModifier;
import net.momirealms.craftengine.core.util.Key;
public interface Equipment {
Key assetId();
Key renderingMethod();
Key type();
<I> ItemDataModifier<I> modifier();
}

View File

@@ -1,4 +1,4 @@
package net.momirealms.craftengine.core.pack.misc;
package net.momirealms.craftengine.core.item.equipment;
import java.util.HashMap;
import java.util.Map;

View File

@@ -1,18 +1,23 @@
package net.momirealms.craftengine.core.item.equipment;
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.Registries;
import net.momirealms.craftengine.core.registry.WritableRegistry;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.util.ResourceKey;
public class Equipments {
import java.util.Map;
public final class Equipments {
public static final Key TRIM = Key.of("craftengine:trim");
public static final Key COMPONENT = Key.of("craftengine:component");
static {
register(TRIM, TrimBasedEquipment.FACTORY);
register(COMPONENT, ComponentBasedEquipment.FACTORY);
}
public static void register(Key key, EquipmentFactory factory) {
@@ -20,4 +25,14 @@ public class Equipments {
.registerForHolder(new ResourceKey<>(Registries.EQUIPMENT_FACTORY.location(), key));
holder.bindValue(factory);
}
public static Equipment fromMap(Key id, Map<String, Object> map) {
String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.equipment.missing_type");
Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE);
EquipmentFactory factory = BuiltInRegistries.EQUIPMENT_FACTORY.getValue(key);
if (factory == null) {
throw new LocalizedResourceConfigException("warning.config.equipment.invalid_type", type);
}
return factory.create(id, map);
}
}

View File

@@ -1,42 +1,52 @@
package net.momirealms.craftengine.core.item.equipment;
import net.momirealms.craftengine.core.item.modifier.ItemDataModifier;
import net.momirealms.craftengine.core.item.modifier.TrimModifier;
import net.momirealms.craftengine.core.pack.AbstractPackManager;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
import java.util.Optional;
public class TrimBasedEquipment extends AbstractEquipment {
public static final Factory FACTORY = new Factory();
private final Key humanoid;
private final Key humanoidLeggings;
public TrimBasedEquipment(Key assetId, Key humanoid, Key humanoidLeggings) {
public TrimBasedEquipment(Key assetId, @Nullable Key humanoid, @Nullable Key humanoidLeggings) {
super(assetId);
this.humanoid = humanoid;
this.humanoidLeggings = humanoidLeggings;
}
@Override
public Key renderingMethod() {
public Key type() {
return Equipments.TRIM;
}
@Nullable
public Key humanoid() {
return humanoid;
}
@Nullable
public Key humanoidLeggings() {
return humanoidLeggings;
}
@Override
public <I> ItemDataModifier<I> modifier() {
return new TrimModifier<>(AbstractPackManager.TRIM_MATERIAL, this.assetId.toString());
}
public static class Factory implements EquipmentFactory {
@Override
public Equipment create(Key id, Map<String, Object> args) {
// todo node
String humanoidId = ResourceConfigUtils.requireNonEmptyStringOrThrow(args.get("humanoid"), "");
String humanoidLeggingsId = ResourceConfigUtils.requireNonEmptyStringOrThrow(args.get("humanoid-leggings"), "");
// todo 验证resource location
return new TrimBasedEquipment(id, Key.of(humanoidId), Key.of(humanoidLeggingsId));
Key humanoidId = Optional.ofNullable((String) args.get("humanoid")).map(Key::of).orElse(null);
Key humanoidLeggingsId = Optional.ofNullable((String) args.get("humanoid-leggings")).map(Key::of).orElse(null);
return new TrimBasedEquipment(id, humanoidId, humanoidLeggingsId);
}
}
}

View File

@@ -0,0 +1,51 @@
package net.momirealms.craftengine.core.item.modifier;
import net.momirealms.craftengine.core.item.ComponentKeys;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.ItemBuildContext;
import net.momirealms.craftengine.core.item.NetworkItemHandler;
import net.momirealms.craftengine.core.item.setting.EquipmentData;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.sparrow.nbt.CompoundTag;
import net.momirealms.sparrow.nbt.Tag;
import java.util.Optional;
public class EquippableAssetIdModifier<I> implements ItemDataModifier<I> {
private final Key assetId;
public EquippableAssetIdModifier(Key assetsId) {
this.assetId = assetsId;
}
@Override
public String name() {
return "equippable-asset-id";
}
@Override
public Item<I> apply(Item<I> item, ItemBuildContext context) {
Optional<EquipmentData> optionalData = item.equippable();
optionalData.ifPresent(data -> item.equippable(new EquipmentData(
data.slot(),
this.assetId,
data.dispensable(),
data.swappable(),
data.damageOnHurt(),
data.equipOnInteract(),
data.cameraOverlay()
)));
return item;
}
@Override
public Item<I> prepareNetworkItem(Item<I> item, ItemBuildContext context, CompoundTag networkData) {
Tag previous = item.getNBTComponent(ComponentKeys.EQUIPPABLE);
if (previous != null) {
networkData.put(ComponentKeys.EQUIPPABLE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {
networkData.put(ComponentKeys.EQUIPPABLE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE));
}
return item;
}
}

View File

@@ -9,6 +9,7 @@ import net.momirealms.sparrow.nbt.CompoundTag;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Locale;
import java.util.Map;
@@ -44,8 +45,9 @@ public class EquipmentData {
public static EquipmentData fromMap(@NotNull final Map<String, Object> data) {
String slot = (String) data.get("slot");
if (slot == null) {
throw new LocalizedResourceConfigException("warning.config.item.settings.equippable.missing_slot");
throw new IllegalArgumentException("slot cannot be null");
}
// todo 重新写判断,不应该支持手部
EquipmentSlot slotEnum = EquipmentSlot.valueOf(slot.toUpperCase(Locale.ENGLISH));
EquipmentData.Builder builder = EquipmentData.builder().slot(slotEnum);
if (data.containsKey("asset-id")) {

View File

@@ -1,29 +1,33 @@
package net.momirealms.craftengine.core.item.setting;
import net.momirealms.craftengine.core.item.equipment.ComponentBasedEquipment;
import net.momirealms.craftengine.core.pack.misc.EquipmentLayerType;
import java.util.EnumMap;
import java.util.List;
import net.momirealms.craftengine.core.item.equipment.Equipment;
import net.momirealms.craftengine.core.util.Tristate;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class ItemEquipment {
private final EquipmentData data;
private final ComponentBasedEquipment equipment;
private final Tristate clientBoundModel;
private final Equipment equipment;
private final EquipmentData equipmentData;
public ItemEquipment(EquipmentData data, ComponentBasedEquipment equipment) {
this.data = data;
public ItemEquipment(Tristate clientBoundModel, @Nullable EquipmentData equipmentData, Equipment equipment) {
this.clientBoundModel = clientBoundModel;
this.equipment = equipment;
this.equipmentData = equipmentData;
}
public void addLayer(EquipmentLayerType layerType, List<ComponentBasedEquipment.Layer> layer) {
this.equipment.addLayer(layerType, layer);
@NotNull
public Equipment equipment() {
return this.equipment;
}
public EnumMap<EquipmentLayerType, List<ComponentBasedEquipment.Layer>> layers() {
return this.equipment.layers();
@Nullable
public EquipmentData equipmentData() {
return this.equipmentData;
}
public EquipmentData data() {
return data;
@NotNull
public Tristate clientBoundModel() {
return clientBoundModel;
}
}

View File

@@ -9,12 +9,14 @@ import dev.dejvokep.boostedyaml.YamlDocument;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import net.momirealms.craftengine.core.font.BitmapImage;
import net.momirealms.craftengine.core.font.Font;
import net.momirealms.craftengine.core.item.equipment.ComponentBasedEquipment;
import net.momirealms.craftengine.core.item.equipment.Equipment;
import net.momirealms.craftengine.core.item.equipment.TrimBasedEquipment;
import net.momirealms.craftengine.core.pack.conflict.PathContext;
import net.momirealms.craftengine.core.pack.conflict.resolution.ResolutionConditional;
import net.momirealms.craftengine.core.pack.host.ResourcePackHost;
import net.momirealms.craftengine.core.pack.host.ResourcePackHosts;
import net.momirealms.craftengine.core.pack.host.impl.NoneHost;
import net.momirealms.craftengine.core.pack.misc.Equipment;
import net.momirealms.craftengine.core.pack.model.ItemModel;
import net.momirealms.craftengine.core.pack.model.LegacyOverridesModel;
import net.momirealms.craftengine.core.pack.model.ModernItemModel;
@@ -25,6 +27,7 @@ import net.momirealms.craftengine.core.pack.model.rangedisptach.CustomModelDataR
import net.momirealms.craftengine.core.pack.obfuscation.ObfA;
import net.momirealms.craftengine.core.pack.obfuscation.ResourcePackGenerationException;
import net.momirealms.craftengine.core.pack.revision.Revision;
import net.momirealms.craftengine.core.pack.revision.Revisions;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.plugin.config.ConfigParser;
@@ -65,9 +68,8 @@ public abstract class AbstractPackManager implements PackManager {
public static final Map<Key, ModernItemModel> PRESET_ITEMS = new HashMap<>();
public static final Set<Key> VANILLA_TEXTURES = new HashSet<>();
public static final Set<Key> VANILLA_MODELS = new HashSet<>();
public static final String TRIM_MATERIAL = "custom";
private static final byte[] EMPTY_IMAGE;
private static final String[] TRIM_ITEMS = {"boots_trim","chestplate_trim","helmet_trim","leggings_trim"};
private static final String[] TRIM_COLOR_PALETTES = {"amethyst","copper","diamond","diamond_darker","emerald","gold","gold_darker","iron","iron_darker","lapis","netherite","netherite_darker","quartz","redstone","resin","trim_palette"};
static {
var stream = new ByteArrayOutputStream();
try {
@@ -545,6 +547,7 @@ public abstract class AbstractPackManager implements PackManager {
ConfigParser parser = entry.getKey();
if (!predicate.test(parser)) continue;
long t1 = System.nanoTime();
parser.preProcess();
for (CachedConfigSection cached : entry.getValue()) {
for (Map.Entry<String, Object> configEntry : cached.config().entrySet()) {
String key = configEntry.getKey();
@@ -578,6 +581,7 @@ public abstract class AbstractPackManager implements PackManager {
}
}
}
parser.postProcess();
long t2 = System.nanoTime();
this.plugin.logger().info("Loaded " + parser.sectionId()[0] + " in " + String.format("%.2f", ((t2 - t1) / 1_000_000.0)) + " ms");
}
@@ -632,7 +636,7 @@ public abstract class AbstractPackManager implements PackManager {
this.generateOverrideSounds(generatedPackPath);
this.generateCustomSounds(generatedPackPath);
this.generateClientLang(generatedPackPath);
this.generateEquipments(generatedPackPath);
this.generateEquipments(generatedPackPath, revisions::add);
this.generateParticle(generatedPackPath);
this.generatePackMetadata(generatedPackPath.resolve("pack.mcmeta"), revisions);
if (Config.excludeShaders()) {
@@ -1161,74 +1165,315 @@ public abstract class AbstractPackManager implements PackManager {
}
}
private void generateEquipments(Path generatedPackPath) {
for (Map.Entry<Key, Equipment> entry : this.plugin.itemManager().equipmentsToGenerate().entrySet()) {
Key assetId = entry.getKey();
if (Config.packMaxVersion().isAtOrAbove(MinecraftVersions.V1_21_4)) {
Path equipmentPath = generatedPackPath
.resolve("assets")
.resolve(assetId.namespace())
.resolve("equipment")
.resolve(assetId.value() + ".json");
private void generateEquipments(Path generatedPackPath, Consumer<Revision> callback) {
// asset id + 是否有上身 + 是否有腿
List<Tuple<Key, Boolean, Boolean>> collectedTrims = new ArrayList<>();
JsonObject equipmentJson = null;
if (Files.exists(equipmentPath)) {
try (BufferedReader reader = Files.newBufferedReader(equipmentPath)) {
equipmentJson = JsonParser.parseReader(reader).getAsJsonObject();
// 为trim类型提供的两个兼容性值
boolean needLegacyCompatibility = Config.packMinVersion().isBelow(MinecraftVersions.V1_21_2);
boolean needModernCompatibility = Config.packMaxVersion().isAtOrAbove(MinecraftVersions.V1_21_2);
for (Equipment equipment : this.plugin.itemManager().equipments().values()) {
if (equipment instanceof ComponentBasedEquipment componentBasedEquipment) {
// 现代的盔甲生成
Key assetId = componentBasedEquipment.assetId();
if (Config.packMaxVersion().isAtOrAbove(MinecraftVersions.V1_21_4)) {
Path equipmentPath = generatedPackPath
.resolve("assets")
.resolve(assetId.namespace())
.resolve("equipment")
.resolve(assetId.value() + ".json");
JsonObject equipmentJson = null;
if (Files.exists(equipmentPath)) {
try (BufferedReader reader = Files.newBufferedReader(equipmentPath)) {
equipmentJson = JsonParser.parseReader(reader).getAsJsonObject();
} catch (IOException e) {
plugin.logger().warn("Failed to load existing sounds.json", e);
return;
}
}
if (equipmentJson != null) {
equipmentJson = GsonHelper.deepMerge(equipmentJson, componentBasedEquipment.get());
} else {
equipmentJson = componentBasedEquipment.get();
}
try {
Files.createDirectories(equipmentPath.getParent());
} catch (IOException e) {
plugin.logger().warn("Failed to load existing sounds.json", e);
plugin.logger().severe("Error creating " + equipmentPath.toAbsolutePath());
return;
}
try {
GsonHelper.writeJsonFile(equipmentJson, equipmentPath);
} catch (IOException e) {
this.plugin.logger().severe("Error writing equipment file", e);
}
}
if (equipmentJson != null) {
equipmentJson = GsonHelper.deepMerge(equipmentJson, entry.getValue().get());
} else {
equipmentJson = entry.getValue().get();
if (Config.packMaxVersion().isAtOrAbove(MinecraftVersions.V1_21_2) && Config.packMinVersion().isBelow(MinecraftVersions.V1_21_4)) {
Path equipmentPath = generatedPackPath
.resolve("assets")
.resolve(assetId.namespace())
.resolve("models")
.resolve("equipment")
.resolve(assetId.value() + ".json");
JsonObject equipmentJson = null;
if (Files.exists(equipmentPath)) {
try (BufferedReader reader = Files.newBufferedReader(equipmentPath)) {
equipmentJson = JsonParser.parseReader(reader).getAsJsonObject();
} catch (IOException e) {
plugin.logger().warn("Failed to load existing sounds.json", e);
return;
}
}
if (equipmentJson != null) {
equipmentJson = GsonHelper.deepMerge(equipmentJson, componentBasedEquipment.get());
} else {
equipmentJson = componentBasedEquipment.get();
}
try {
Files.createDirectories(equipmentPath.getParent());
} catch (IOException e) {
plugin.logger().severe("Error creating " + equipmentPath.toAbsolutePath());
return;
}
try {
GsonHelper.writeJsonFile(equipmentJson, equipmentPath);
} catch (IOException e) {
this.plugin.logger().severe("Error writing equipment file", e);
}
}
} else if (equipment instanceof TrimBasedEquipment trimBasedEquipment) {
Key assetId = trimBasedEquipment.assetId();
Key humanoidResourceLocation = trimBasedEquipment.humanoid();
boolean hasLayer1 = humanoidResourceLocation != null;
Key humanoidLeggingsResourceLocation = trimBasedEquipment.humanoidLeggings();
boolean hasLayer2 = humanoidLeggingsResourceLocation != null;
if (hasLayer1) {
Path texture = generatedPackPath
.resolve("assets")
.resolve(humanoidResourceLocation.namespace())
.resolve("textures")
.resolve(humanoidResourceLocation.value() + ".png");
if (!Files.exists(texture) || !Files.isRegularFile(texture)) {
// todo 说话
continue;
}
boolean shouldPreserve = false;
if (needLegacyCompatibility) {
Path legacyTarget = generatedPackPath
.resolve("assets")
.resolve(assetId.namespace())
.resolve("textures")
.resolve("trims")
.resolve("models")
.resolve("armor")
.resolve(assetId.value() + "_" + TRIM_MATERIAL + ".png");
if (!legacyTarget.equals(texture)) {
try {
Files.createDirectories(legacyTarget.getParent());
Files.copy(texture, legacyTarget, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
plugin.logger().severe("Error writing armor texture file from " + texture + " to " + legacyTarget, e);
}
} else {
shouldPreserve = true;
}
}
if (needModernCompatibility) {
Path modernTarget = generatedPackPath
.resolve("assets")
.resolve(assetId.namespace())
.resolve("textures")
.resolve("trims")
.resolve("entity")
.resolve("humanoid")
.resolve(assetId.value() + "_" + TRIM_MATERIAL + ".png");
if (!modernTarget.equals(texture)) {
try {
Files.createDirectories(modernTarget.getParent());
Files.copy(texture, modernTarget, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
plugin.logger().severe("Error writing armor texture file from " + texture + " to " + modernTarget, e);
}
} else {
shouldPreserve = true;
}
}
if (!shouldPreserve) {
try {
Files.delete(texture);
} catch (IOException e) {
this.plugin.logger().severe("Error deleting armor texture file from " + texture, e);
}
}
}
if (hasLayer2) {
Path texture = generatedPackPath
.resolve("assets")
.resolve(humanoidLeggingsResourceLocation.namespace())
.resolve("textures")
.resolve(humanoidLeggingsResourceLocation.value() + ".png");
if (!Files.exists(texture) && !Files.isRegularFile(texture)) {
// todo 说话
continue;
}
boolean shouldPreserve = false;
if (needLegacyCompatibility) {
Path legacyTarget = generatedPackPath
.resolve("assets")
.resolve(assetId.namespace())
.resolve("textures")
.resolve("trims")
.resolve("models")
.resolve("armor")
.resolve(assetId.value() + "_leggings_" + TRIM_MATERIAL + ".png");
if (!legacyTarget.equals(texture)) {
try {
Files.createDirectories(legacyTarget.getParent());
Files.copy(texture, legacyTarget, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
this.plugin.logger().severe("Error writing armor texture file from " + texture + " to " + legacyTarget, e);
}
} else {
shouldPreserve = true;
}
}
if (needModernCompatibility) {
Path modernTarget = generatedPackPath
.resolve("assets")
.resolve(assetId.namespace())
.resolve("textures")
.resolve("trims")
.resolve("entity")
.resolve("humanoid_leggings")
.resolve(assetId.value() + "_" + TRIM_MATERIAL + ".png");
if (!modernTarget.equals(texture)) {
try {
Files.createDirectories(modernTarget.getParent());
Files.copy(texture, modernTarget, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
this.plugin.logger().severe("Error writing armor texture file from " + texture + " to " + modernTarget, e);
}
} else {
shouldPreserve = true;
}
}
if (!shouldPreserve) {
try {
Files.delete(texture);
} catch (IOException e) {
this.plugin.logger().severe("Error deleting armor texture file from " + texture, e);
}
}
}
collectedTrims.add(Tuple.of(assetId, hasLayer1, hasLayer2));
}
}
if (!collectedTrims.isEmpty()) {
// 获取基础atlas路径
Path atlasPath = generatedPackPath
.resolve("assets")
.resolve("minecraft")
.resolve("atlases")
.resolve("armor_trims.json");
// 读取先前sources内容
JsonArray previousAtlasSources = null;
if (Files.exists(atlasPath) && Files.isRegularFile(atlasPath)) {
try {
Files.createDirectories(equipmentPath.getParent());
} catch (IOException e) {
plugin.logger().severe("Error creating " + equipmentPath.toAbsolutePath());
return;
}
try {
GsonHelper.writeJsonFile(equipmentJson, equipmentPath);
} catch (IOException e) {
this.plugin.logger().severe("Error writing equipment file", e);
previousAtlasSources = GsonHelper.readJsonFile(atlasPath).getAsJsonObject().getAsJsonArray("sources");
} catch (Exception ignored) {
}
}
if (Config.packMaxVersion().isAtOrAbove(MinecraftVersions.V1_21_2) && Config.packMinVersion().isBelow(MinecraftVersions.V1_21_4)) {
Path equipmentPath = generatedPackPath
.resolve("assets")
.resolve(assetId.namespace())
.resolve("models")
.resolve("equipment")
.resolve(assetId.value() + ".json");
JsonObject equipmentJson = null;
if (Files.exists(equipmentPath)) {
try (BufferedReader reader = Files.newBufferedReader(equipmentPath)) {
equipmentJson = JsonParser.parseReader(reader).getAsJsonObject();
} catch (IOException e) {
plugin.logger().warn("Failed to load existing sounds.json", e);
return;
// 准备新版本atlas
JsonObject modernTrimAtlasJson = null;
if (needModernCompatibility) {
modernTrimAtlasJson = new JsonObject();
JsonArray sourcesArray = new JsonArray();
modernTrimAtlasJson.add("sources", sourcesArray);
for (Tuple<Key, Boolean, Boolean> tuple : collectedTrims) {
if (tuple.mid()) {
JsonObject single1 = new JsonObject();
single1.addProperty("type", "single");
single1.addProperty("resource", tuple.left().namespace() + ":trims/entity/humanoid/" + tuple.left().value() + "_" + TRIM_MATERIAL);
sourcesArray.add(single1);
}
if (tuple.right()) {
JsonObject single2 = new JsonObject();
single2.addProperty("type", "single");
single2.addProperty("resource", tuple.left().namespace() + ":trims/entity/humanoid_leggings/" + tuple.left().value() + "_" + TRIM_MATERIAL);
sourcesArray.add(single2);
}
}
if (equipmentJson != null) {
equipmentJson = GsonHelper.deepMerge(equipmentJson, entry.getValue().get());
} else {
equipmentJson = entry.getValue().get();
if (previousAtlasSources != null) {
sourcesArray.addAll(previousAtlasSources);
}
}
// 准备旧版本atlas
JsonObject legacyTrimAtlasJson = null;
if (needLegacyCompatibility) {
legacyTrimAtlasJson = new JsonObject();
JsonArray sourcesArray = new JsonArray();
legacyTrimAtlasJson.add("sources", sourcesArray);
for (Tuple<Key, Boolean, Boolean> tuple : collectedTrims) {
if (tuple.mid()) {
JsonObject single1 = new JsonObject();
single1.addProperty("type", "single");
single1.addProperty("resource", tuple.left().namespace() + ":trims/models/armor/" + tuple.left().value() + "_" + TRIM_MATERIAL);
sourcesArray.add(single1);
}
if (tuple.right()) {
JsonObject single2 = new JsonObject();
single2.addProperty("type", "single");
single2.addProperty("resource", tuple.left().namespace() + ":trims/models/armor/" + tuple.left().value() + "_leggings_" + TRIM_MATERIAL);
sourcesArray.add(single2);
}
}
if (previousAtlasSources != null) {
sourcesArray.addAll(previousAtlasSources);
}
}
// 创建atlas文件夹
try {
Files.createDirectories(atlasPath.getParent());
} catch (IOException e) {
this.plugin.logger().severe("Error creating " + atlasPath.toAbsolutePath(), e);
return;
}
// 写入atlas文件
try (BufferedWriter writer = Files.newBufferedWriter(atlasPath)) {
JsonObject selected = needLegacyCompatibility ? legacyTrimAtlasJson : modernTrimAtlasJson;
// 优先写入旧版
GsonHelper.get().toJson(selected, writer);
} catch (IOException e) {
this.plugin.logger().severe("Error writing " + atlasPath.toAbsolutePath(), e);
}
// 既要又要那么需要overlay
if (needLegacyCompatibility && needModernCompatibility) {
Revision revision = Revisions.SINCE_1_21_2;
callback.accept(revision);
Path overlayAtlasPath = generatedPackPath
.resolve(Config.createOverlayFolderName(revision.versionString()))
.resolve("assets")
.resolve("minecraft")
.resolve("atlases")
.resolve("armor_trims.json");
// 创建atlas文件夹
try {
Files.createDirectories(equipmentPath.getParent());
Files.createDirectories(overlayAtlasPath.getParent());
} catch (IOException e) {
plugin.logger().severe("Error creating " + equipmentPath.toAbsolutePath());
this.plugin.logger().severe("Error creating " + overlayAtlasPath.toAbsolutePath(), e);
return;
}
try {
GsonHelper.writeJsonFile(equipmentJson, equipmentPath);
// 写入atlas文件
try (BufferedWriter writer = Files.newBufferedWriter(overlayAtlasPath)) {
GsonHelper.get().toJson(modernTrimAtlasJson, writer);
callback.accept(revision);
} catch (IOException e) {
this.plugin.logger().severe("Error writing equipment file", e);
this.plugin.logger().severe("Error writing " + overlayAtlasPath.toAbsolutePath(), e);
}
}
}

View File

@@ -1,51 +0,0 @@
package net.momirealms.craftengine.core.pack.misc;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import net.momirealms.craftengine.core.item.equipment.ComponentBasedEquipment;
import net.momirealms.craftengine.core.item.setting.ItemEquipment;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
public class Equipment implements Supplier<JsonObject> {
private final EnumMap<EquipmentLayerType, List<ComponentBasedEquipment.Layer>> layers;
public Equipment() {
this.layers = new EnumMap<>(EquipmentLayerType.class);
}
public void addAll(ItemEquipment equipment) {
for (Map.Entry<EquipmentLayerType, List<ComponentBasedEquipment.Layer>> entry : equipment.layers().entrySet()) {
List<ComponentBasedEquipment.Layer> layers = entry.getValue();
List<ComponentBasedEquipment.Layer> previous = this.layers.put(entry.getKey(), layers);
if (previous != null && !previous.equals(layers)) {
// todo 是否异常
}
}
}
@Override
public JsonObject get() {
JsonObject jsonObject = new JsonObject();
JsonObject layersJson = new JsonObject();
jsonObject.add("layers", layersJson);
for (Map.Entry<EquipmentLayerType, List<ComponentBasedEquipment.Layer>> entry : layers.entrySet()) {
EquipmentLayerType type = entry.getKey();
List<ComponentBasedEquipment.Layer> layerList = entry.getValue();
setLayers(layersJson, layerList, type.id());
}
return jsonObject;
}
private void setLayers(JsonObject layersJson, List<ComponentBasedEquipment.Layer> layers, String key) {
if (layers == null || layers.isEmpty()) return;
JsonArray layersArray = new JsonArray();
for (ComponentBasedEquipment.Layer layer : layers) {
layersArray.add(layer.get());
}
layersJson.add(key, layersArray);
}
}

View File

@@ -6,4 +6,5 @@ public final class Revisions {
private Revisions() {}
public static final Revision SINCE_1_21_6 = Revision.since(MinecraftVersions.V1_21_6);
public static final Revision SINCE_1_21_2 = Revision.since(MinecraftVersions.V1_21_2);
}

View File

@@ -151,6 +151,8 @@ public abstract class CraftEngine implements Plugin {
} catch (Exception e) {
this.logger().warn("Failed to load resources folder", e);
}
// register trims
this.itemManager.delayedLoad();
// init suggestions and packet mapper
this.blockManager.delayedLoad();
// handle some special client lang for instance block_name

View File

@@ -143,6 +143,13 @@ public class Config {
protected boolean image$intercept_packets$set_score;
protected boolean image$intercept_packets$item;
protected boolean item$client_bound_model;
protected String equipment$sacrificed_vanilla_armor$type;
protected Key equipment$sacrificed_vanilla_armor$asset_id;
protected Key equipment$sacrificed_vanilla_armor$humanoid;
protected Key equipment$sacrificed_vanilla_armor$humanoid_leggings;
protected boolean emoji$chat;
protected boolean emoji$book;
protected boolean emoji$anvil;
@@ -321,6 +328,15 @@ public class Config {
furniture$hide_base_entity = config.getBoolean("furniture.hide-base-entity", true);
furniture$collision_entity_type = ColliderType.valueOf(config.getString("furniture.collision-entity-type", "interaction").toUpperCase(Locale.ENGLISH));
// equipment
equipment$sacrificed_vanilla_armor$type = config.getString("equipment.sacrificed-vanilla-armor.type", "chainmail");
equipment$sacrificed_vanilla_armor$asset_id = Key.of(config.getString("equipment.sacrificed-vanilla-armor.asset-id", "minecraft:chainmail"));
equipment$sacrificed_vanilla_armor$humanoid = Key.of(config.getString("equipment.sacrificed-vanilla-armor.humanoid"));
equipment$sacrificed_vanilla_armor$humanoid_leggings = Key.of(config.getString("equipment.sacrificed-vanilla-armor.humanoid-leggings"));
// item
item$client_bound_model = config.getBoolean("item.client-bound-model", false);
// block
block$sound_system$enable = config.getBoolean("block.sound-system.enable", true);
block$simplify_adventure_break_check = config.getBoolean("block.simplify-adventure-break-check", false);
@@ -739,6 +755,26 @@ public class Config {
return instance.resource_pack$overlay_format.replace("{version}", version);
}
public static Key sacrificedAssetId() {
return instance.equipment$sacrificed_vanilla_armor$asset_id;
}
public static Key sacrificedHumanoid() {
return instance.equipment$sacrificed_vanilla_armor$humanoid;
}
public static Key sacrificedHumanoidLeggings() {
return instance.equipment$sacrificed_vanilla_armor$humanoid_leggings;
}
public static String sacrificedVanillaArmorType() {
return instance.equipment$sacrificed_vanilla_armor$type;
}
public static boolean globalClientboundModel() {
return instance.item$client_bound_model;
}
public YamlDocument loadOrCreateYamlData(String fileName) {
Path path = this.plugin.dataFolderPath().resolve(fileName);
if (!Files.exists(path)) {

View File

@@ -29,4 +29,10 @@ public interface ConfigParser extends Comparable<ConfigParser> {
default int compareTo(@NotNull ConfigParser another) {
return Integer.compare(loadingSequence(), another.loadingSequence());
}
default void postProcess() {
}
default void preProcess() {
}
}

View File

@@ -24,4 +24,12 @@ public enum Tristate {
public boolean asBoolean() {
return this.booleanValue;
}
public boolean asBoolean(boolean defaultValue) {
if (this == UNDEFINED) {
return defaultValue;
} else {
return this.booleanValue;
}
}
}