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:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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")) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user