diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java index 84af9f97c..c80f2a553 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java @@ -15,7 +15,10 @@ import net.momirealms.craftengine.core.util.VersionHelper; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.*; +import org.bukkit.entity.Arrow; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Projectile; +import org.bukkit.entity.ThrowableProjectile; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; @@ -29,7 +32,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; -import java.util.function.BiConsumer; public class BukkitProjectileManager implements Listener, ProjectileManager { private static BukkitProjectileManager instance; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java index 90da4c838..2f72badf9 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java @@ -11,12 +11,10 @@ import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries; -import net.momirealms.craftengine.bukkit.util.ComponentUtils; import net.momirealms.craftengine.bukkit.util.ItemUtils; import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.*; -import net.momirealms.craftengine.core.item.equipment.TrimBasedEquipment; import net.momirealms.craftengine.core.item.modifier.IdModifier; import net.momirealms.craftengine.core.pack.AbstractPackManager; import net.momirealms.craftengine.core.plugin.config.Config; @@ -52,7 +50,7 @@ public class BukkitItemManager extends AbstractItemManager { private final ArmorEventListener armorEventListener; private final NetworkItemHandler networkItemHandler; private final Object bedrockItemHolder; - private boolean registeredTrimMaterial; + private Set lastRegisteredPatterns = Set.of(); public BukkitItemManager(BukkitCraftEngine plugin) { super(plugin); @@ -65,6 +63,8 @@ public class BukkitItemManager extends AbstractItemManager { this.networkItemHandler = VersionHelper.isOrAbove1_20_5() ? new ModernNetworkItemHandler() : new LegacyNetworkItemHandler(); this.registerAllVanillaItems(); this.bedrockItemHolder = FastNMS.INSTANCE.method$Registry$getHolderByResourceKey(MBuiltInRegistries.ITEM, FastNMS.INSTANCE.method$ResourceKey$create(MRegistries.ITEM, KeyUtils.toResourceLocation(Key.of("minecraft:bedrock")))).get();; + this.registerCustomTrimMaterial(); + this.loadLastRegisteredPatterns(); } @Override @@ -136,20 +136,22 @@ public class BukkitItemManager extends AbstractItemManager { HandlerList.unregisterAll(this.itemEventListener); HandlerList.unregisterAll(this.debugStickListener); HandlerList.unregisterAll(this.armorEventListener); + this.persistLastRegisteredPatterns(); } @Override - protected void registerArmorTrimPattern(Collection equipments) { + protected void registerArmorTrimPattern(Collection equipments) { if (equipments.isEmpty()) return; - this.registerCustomTrimMaterial(); + this.lastRegisteredPatterns = new HashSet<>(equipments); + this.lastRegisteredPatterns.add(Config.sacrificedAssetId()); Object registry = FastNMS.INSTANCE.method$RegistryAccess$lookupOrThrow(FastNMS.INSTANCE.registryAccess(), MRegistries.TRIM_PATTERN); try { CoreReflections.field$MappedRegistry$frozen.set(registry, false); - for (TrimBasedEquipment equipment : equipments) { - Object resourceLocation = KeyUtils.toResourceLocation(equipment.assetId()); + for (Key assetId : this.lastRegisteredPatterns) { + Object resourceLocation = KeyUtils.toResourceLocation(assetId); Object previous = FastNMS.INSTANCE.method$Registry$getValue(registry, resourceLocation); if (previous == null) { - Object trimPattern = createTrimPattern(equipment.assetId()); + Object trimPattern = createTrimPattern(assetId); Object holder = CoreReflections.method$Registry$registerForHolder.invoke(null, registry, resourceLocation, trimPattern); CoreReflections.method$Holder$Reference$bindValue.invoke(holder, trimPattern); CoreReflections.field$Holder$Reference$tags.set(holder, Set.of()); @@ -165,10 +167,15 @@ public class BukkitItemManager extends AbstractItemManager { } } + private void persistLastRegisteredPatterns() { + } + + private void loadLastRegisteredPatterns() { + } + private void registerCustomTrimMaterial() { - if (this.registeredTrimMaterial) return; Object registry = FastNMS.INSTANCE.method$RegistryAccess$lookupOrThrow(FastNMS.INSTANCE.registryAccess(), MRegistries.TRIM_MATERIAL); - Object resourceLocation = KeyUtils.toResourceLocation(Key.of("minecraft", AbstractPackManager.TRIM_MATERIAL)); + Object resourceLocation = KeyUtils.toResourceLocation(Key.of("minecraft", AbstractPackManager.NEW_TRIM_MATERIAL)); Object previous = FastNMS.INSTANCE.method$Registry$getValue(registry, resourceLocation); if (previous == null) { try { @@ -186,7 +193,6 @@ public class BukkitItemManager extends AbstractItemManager { } } } - this.registeredTrimMaterial = true; } private Object createTrimPattern(Key key) throws ReflectiveOperationException { @@ -206,7 +212,7 @@ public class BukkitItemManager extends AbstractItemManager { } else if (VersionHelper.isOrAbove1_21_4()) { return CoreReflections.constructor$TrimMaterial.newInstance("custom", this.bedrockItemHolder, Map.of(), CoreReflections.instance$Component$empty); } else { - return CoreReflections.constructor$TrimMaterial.newInstance("custom", this.bedrockItemHolder, 1_000_000.0f, Map.of(), CoreReflections.instance$Component$empty); + return CoreReflections.constructor$TrimMaterial.newInstance("custom", this.bedrockItemHolder, 0f, Map.of(), CoreReflections.instance$Component$empty); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_2.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_2.java index 42d08779b..99263f9d8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_2.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_2.java @@ -3,16 +3,13 @@ package net.momirealms.craftengine.bukkit.item.factory; import net.momirealms.craftengine.bukkit.item.ComponentItemWrapper; import net.momirealms.craftengine.bukkit.item.ComponentTypes; import net.momirealms.craftengine.core.entity.EquipmentSlot; -import net.momirealms.craftengine.core.item.equipment.Equipments; import net.momirealms.craftengine.core.item.setting.EquipmentData; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; -import net.momirealms.sparrow.nbt.CompoundTag; import java.util.Locale; import java.util.Map; -import java.util.Objects; import java.util.Optional; public class ComponentItemFactory1_21_2 extends ComponentItemFactory1_21 { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/sound/BukkitSoundManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/sound/BukkitSoundManager.java index 5b15587d7..dce7ca633 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/sound/BukkitSoundManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/sound/BukkitSoundManager.java @@ -12,7 +12,6 @@ import net.momirealms.craftengine.core.sound.JukeboxSong; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; -import java.util.IdentityHashMap; import java.util.Map; import java.util.Optional; import java.util.Set; diff --git a/common-files/src/main/resources/resources/default/configuration/items.yml b/common-files/src/main/resources/resources/default/configuration/items.yml index 4e28a3ee9..5bd344e6e 100644 --- a/common-files/src/main/resources/resources/default/configuration/items.yml +++ b/common-files/src/main/resources/resources/default/configuration/items.yml @@ -270,7 +270,6 @@ items#topaz_gears: default:topaz_helmet: template: - default:armor/topaz - - default:model/armor_trim arguments: part: helmet slot: head @@ -278,7 +277,6 @@ items#topaz_gears: default:topaz_chestplate: template: - default:armor/topaz - - default:model/armor_trim arguments: part: chestplate slot: chest @@ -286,7 +284,6 @@ items#topaz_gears: default:topaz_leggings: template: - default:armor/topaz - - default:model/armor_trim arguments: part: leggings slot: legs @@ -294,7 +291,6 @@ items#topaz_gears: default:topaz_boots: template: - default:armor/topaz - - default:model/armor_trim arguments: part: boots slot: feet @@ -311,8 +307,8 @@ templates: - default:topaz_tools equipment: asset-id: default:topaz - properties: - slot: ${slot} + model: + template: default:model/armor_trim equipments#topaz: default:topaz: type: diff --git a/common-files/src/main/resources/resources/legacy_armor/configuration/chainmail.yml b/common-files/src/main/resources/resources/legacy_armor/configuration/chainmail.yml new file mode 100644 index 000000000..aefcab72b --- /dev/null +++ b/common-files/src/main/resources/resources/legacy_armor/configuration/chainmail.yml @@ -0,0 +1,22 @@ +# Since we removed the chainmail armor textures, we need to add a client-side trim type for the vanilla chainmail armor to make it display properly. +items: + minecraft:chainmail_helmet: + client-bound-data: + trim: + pattern: chainmail + material: custom + minecraft:chainmail_chestplate: + client-bound-data: + trim: + pattern: chainmail + material: custom + minecraft:chainmail_leggings: + client-bound-data: + trim: + pattern: chainmail + material: custom + minecraft:chainmail_boots: + client-bound-data: + trim: + pattern: chainmail + material: custom \ No newline at end of file diff --git a/common-files/src/main/resources/resources/legacy_armor/pack.yml b/common-files/src/main/resources/resources/legacy_armor/pack.yml new file mode 100644 index 000000000..d5addb0cb --- /dev/null +++ b/common-files/src/main/resources/resources/legacy_armor/pack.yml @@ -0,0 +1,7 @@ +author: XiaoMoMi +version: 0.0.1 +description: +namespace: minecraft +enable: + $$>=1.21.2: false + $$<1.21.2: true diff --git a/common-files/src/main/resources/resources/legacy_armor/resourcepack/assets/minecraft/textures/trims/entity/humanoid/chainmail.png b/common-files/src/main/resources/resources/legacy_armor/resourcepack/assets/minecraft/textures/trims/entity/humanoid/chainmail.png new file mode 100644 index 000000000..cd9ed23eb Binary files /dev/null and b/common-files/src/main/resources/resources/legacy_armor/resourcepack/assets/minecraft/textures/trims/entity/humanoid/chainmail.png differ diff --git a/common-files/src/main/resources/resources/legacy_armor/resourcepack/assets/minecraft/textures/trims/entity/humanoid_leggings/chainmail.png b/common-files/src/main/resources/resources/legacy_armor/resourcepack/assets/minecraft/textures/trims/entity/humanoid_leggings/chainmail.png new file mode 100644 index 000000000..0d47920d9 Binary files /dev/null and b/common-files/src/main/resources/resources/legacy_armor/resourcepack/assets/minecraft/textures/trims/entity/humanoid_leggings/chainmail.png differ diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index d20276d63..a9b53c713 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -65,6 +65,7 @@ command.send_resource_pack.success.single: "Sent resource pack to command.send_resource_pack.success.multiple: "Send resource packs to players." warning.config.pack.duplicated_files: "Duplicated files Found. Please resolve them through config.yml 'resource-pack.duplicated-files-handler' section." warning.config.yaml.duplicated_key: "Issue found in file - Found duplicated key '' at line , this might cause unexpected results." +warning.config.yaml.inconsistent_value_type: "Issue found in file - Found duplicated key '' at line with different value types, this might cause unexpected results." warning.config.type.int: "Issue found in file - Failed to load '': Cannot cast '' to integer type for option ''." warning.config.type.boolean: "Issue found in file - Failed to load '': Cannot cast '' to boolean type for option ''." warning.config.type.float: "Issue found in file - Failed to load '': Cannot cast '' to float type for option ''." @@ -390,6 +391,7 @@ warning.config.resource_pack.generation.missing_block_model: "Block stat warning.config.resource_pack.generation.missing_parent_model: "Model '' cannot find parent model: ''" warning.config.resource_pack.generation.malformatted_json: "Json file '' is malformatted." warning.config.resource_pack.invalid_overlay_format: "Issue found in config.yml at 'resource-pack.overlay-format' - Invalid overlay format ''. Overlay format must contain the placeholder '{version}'." -warning.config.equipment.duplicate: "" -warning.config.equipment.missing_type: "" -warning.config.equipment.invalid_type: "" \ No newline at end of file +warning.config.equipment.duplicate: "Issue found in file - Duplicated equipment ''. Please check if there is the same configuration in other files." +warning.config.equipment.missing_type: "Issue found in file - The equipment '' is missing the required 'type' argument." +warning.config.equipment.invalid_type: "Issue found in file - The equipment '' is using an invalid 'type' argument." +warning.config.equipment.invalid_sacrificed_armor: "Issue found in config.yml at 'equipment.sacrificed-vanilla-armor' - Invalid vanilla armor type ''." \ No newline at end of file diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 9107fa290..5302a77f9 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -65,7 +65,7 @@ command.send_resource_pack.success.single: "发送资源包给 发送资源包给 个玩家" warning.config.pack.duplicated_files: "发现重复文件 请通过 config.yml 的 'resource-pack.duplicated-files-handler' 部分解决" warning.config.yaml.duplicated_key: "在文件 发现问题 - 在第行发现重复的键 '', 这可能会导致一些意料之外的问题." -warning.config.yaml.key_path_conflict: "在文件 发现问题 - 在第行发现重复且值类型不同的键 '', 这可能会导致一些意料之外的问题." +warning.config.yaml.inconsistent_value_type: "在文件 发现问题 - 在第行发现重复且值类型不同的键 '', 这可能会导致一些意料之外的问题." warning.config.type.int: "在文件 发现问题 - 无法加载 '': 无法将 '' 转换为整数类型 (选项 '')" warning.config.type.float: "在文件 发现问题 - 无法加载 '': 无法将 '' 转换为浮点数类型 (选项 '')" warning.config.type.boolean: "在文件 发现问题 - 无法加载 '': 无法将 '' 转换为布尔类型 (选项 '')" @@ -390,4 +390,8 @@ warning.config.resource_pack.generation.missing_item_model: "物品'方块状态''缺少模型文件: ''" warning.config.resource_pack.generation.missing_parent_model: "模型''找不到父级模型文件: ''" warning.config.resource_pack.generation.malformatted_json: "Json文件 '' 格式错误." -warning.config.resource_pack.invalid_overlay_format: "在 config.yml 的 'resource-pack.overlay-format' 处发现问题 - 无效的overlay格式 ''. Overlay格式必须包含占位符 '{version}'." \ No newline at end of file +warning.config.resource_pack.invalid_overlay_format: "在 config.yml 的 'resource-pack.overlay-format' 处发现问题 - 无效的overlay格式 ''. Overlay格式必须包含占位符 '{version}'." +warning.config.equipment.duplicate: "Issue found in file - Duplicated equipment ''. Please check if there is the same configuration in other files." +warning.config.equipment.missing_type: "Issue found in file - The equipment '' is missing the required 'type' argument." +warning.config.equipment.invalid_type: "Issue found in file - The equipment '' is using an invalid 'type' argument." +warning.config.equipment.invalid_sacrificed_armor: "Issue found in config.yml at 'equipment.sacrificed-vanilla-armor' - Invalid vanilla armor type ''." \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java index 06b87e5b2..2b3ca7080 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java @@ -51,7 +51,6 @@ public abstract class AbstractCustomItem implements CustomItem { this.modifierMap = modifierMapBuilder.build(); ImmutableMap.Builder> clientSideModifierMapBuilder = ImmutableMap.builder(); this.clientBoundModifierMap = clientSideModifierMapBuilder.build(); - } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java index 291a7a4c0..3150379ae 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java @@ -255,7 +255,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl protected abstract CustomItem.Builder createPlatformItemBuilder(Holder id, Key material, Key clientBoundMaterial); - protected abstract void registerArmorTrimPattern(Collection equipments); + protected abstract void registerArmorTrimPattern(Collection equipments); public class EquipmentParser implements ConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"equipments", "equipment"}; @@ -281,12 +281,11 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl @Override public void postProcess() { - registerArmorTrimPattern( - AbstractItemManager.this.equipments.values().stream() - .filter(TrimBasedEquipment.class::isInstance) - .map(TrimBasedEquipment.class::cast) - .toList() - ); + List trims = AbstractItemManager.this.equipments.values().stream() + .filter(TrimBasedEquipment.class::isInstance) + .map(Equipment::assetId) + .toList(); + registerArmorTrimPattern(trims); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/equipment/TrimBasedEquipment.java b/core/src/main/java/net/momirealms/craftengine/core/item/equipment/TrimBasedEquipment.java index f1536d567..e5f2513c3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/equipment/TrimBasedEquipment.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/equipment/TrimBasedEquipment.java @@ -37,7 +37,7 @@ public class TrimBasedEquipment extends AbstractEquipment { @Override public ItemDataModifier modifier() { - return new TrimModifier<>(AbstractPackManager.TRIM_MATERIAL, this.assetId.toString()); + return new TrimModifier<>(AbstractPackManager.NEW_TRIM_MATERIAL, this.assetId.toString()); } public static class Factory implements EquipmentFactory { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/setting/EquipmentData.java b/core/src/main/java/net/momirealms/craftengine/core/item/setting/EquipmentData.java index 01fbe40b3..4d9b15e11 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/setting/EquipmentData.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/setting/EquipmentData.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.core.item.setting; import net.momirealms.craftengine.core.entity.EquipmentSlot; -import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.VersionHelper; @@ -9,7 +8,6 @@ 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; diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index 26ee625fd..d222feb78 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -5,7 +5,6 @@ import com.google.common.collect.Multimap; import com.google.common.jimfs.Configuration; import com.google.common.jimfs.Jimfs; import com.google.gson.*; -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; @@ -68,16 +67,20 @@ public abstract class AbstractPackManager implements PackManager { public static final Map PRESET_ITEMS = new HashMap<>(); public static final Set VANILLA_TEXTURES = new HashSet<>(); public static final Set VANILLA_MODELS = new HashSet<>(); - public static final String TRIM_MATERIAL = "custom"; + public static final String NEW_TRIM_MATERIAL = "custom"; + public static final Set ALLOWED_VANILLA_EQUIPMENT = Set.of("chainmail", "diamond", "gold", "iron", "netherite"); private static final byte[] EMPTY_IMAGE; + private static final byte[] EMPTY_EQUIPMENT_IMAGE; static { - var stream = new ByteArrayOutputStream(); - try { - ImageIO.write(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB), "png", stream); + try (ByteArrayOutputStream stream1 = new ByteArrayOutputStream(); + ByteArrayOutputStream stream2 = new ByteArrayOutputStream()) { + ImageIO.write(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB), "png", stream1); + EMPTY_IMAGE = stream1.toByteArray(); + ImageIO.write(new BufferedImage(64, 32, BufferedImage.TYPE_INT_ARGB), "png", stream2); + EMPTY_EQUIPMENT_IMAGE = stream2.toByteArray(); } catch (IOException e) { - throw new RuntimeException(e); + throw new RuntimeException("Failed to create empty images.", e); } - EMPTY_IMAGE = stream.toByteArray(); } private final CraftEngine plugin; @@ -312,12 +315,17 @@ public abstract class AbstractPackManager implements PackManager { String author = null; boolean enable = true; if (Files.exists(metaFile) && Files.isRegularFile(metaFile)) { - YamlDocument metaYML = Config.instance().loadYamlData(metaFile); - enable = metaYML.getBoolean("enable", true); - namespace = metaYML.getString("namespace", namespace); - description = metaYML.getString("description"); - version = metaYML.getString("version"); - author = metaYML.getString("author"); + Yaml yaml = new Yaml(new StringKeyConstructor(path, new LoaderOptions())); + try (InputStream is = Files.newInputStream(metaFile)) { + Map data = yaml.load(is); + enable = ResourceConfigUtils.getAsBoolean(data.getOrDefault("enable", true), "enable"); + namespace = data.getOrDefault("namespace", namespace).toString(); + description = Optional.ofNullable(data.get("description")).map(String::valueOf).orElse(null); + version = Optional.ofNullable(data.get("version")).map(String::valueOf).orElse(null); + author = Optional.ofNullable(data.get("author")).map(String::valueOf).orElse(null); + } catch (IOException e) { + this.plugin.logger().warn("Failed to load " + metaFile, e); + } } Pack pack = new Pack(path, new PackMeta(author, description, version, namespace), enable); this.loadedPacks.put(path.getFileName().toString(), pack); @@ -336,6 +344,10 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/remove_shulker_head/resourcepack/1_20_5_remove_shulker_head_overlay/minecraft/shaders/core/rendertype_entity_solid.fsh"); plugin.saveResource("resources/remove_shulker_head/resourcepack/assets/minecraft/textures/entity/shulker/shulker_white.png"); plugin.saveResource("resources/remove_shulker_head/pack.yml"); + plugin.saveResource("resources/legacy_armor/resourcepack/assets/minecraft/textures/trims/entity/humanoid/chainmail.png"); + plugin.saveResource("resources/legacy_armor/resourcepack/assets/minecraft/textures/trims/entity/humanoid_leggings/chainmail.png"); + plugin.saveResource("resources/legacy_armor/configuration/chainmail.yml"); + plugin.saveResource("resources/legacy_armor/pack.yml"); plugin.saveResource("resources/internal/pack.yml"); // i18n plugin.saveResource("resources/internal/configuration/i18n.yml"); @@ -1246,130 +1258,10 @@ public abstract class AbstractPackManager implements PackManager { } } 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); - } - } + Pair result = processTrimBasedEquipment(trimBasedEquipment, generatedPackPath); + if (result != null) { + collectedTrims.add(Tuple.of(assetId, result.left(), result.right())); } - 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)); } } @@ -1388,7 +1280,7 @@ public abstract class AbstractPackManager implements PackManager { } catch (Exception ignored) { } } - // 准备新版本atlas + // 准备新版本atlas和覆盖纹理 JsonObject modernTrimAtlasJson = null; if (needModernCompatibility) { modernTrimAtlasJson = new JsonObject(); @@ -1398,21 +1290,51 @@ public abstract class AbstractPackManager implements PackManager { 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); + single1.addProperty("resource", tuple.left().namespace() + ":trims/entity/humanoid/" + tuple.left().value() + "_" + NEW_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); + single2.addProperty("resource", tuple.left().namespace() + ":trims/entity/humanoid_leggings/" + tuple.left().value() + "_" + NEW_TRIM_MATERIAL); sourcesArray.add(single2); } } if (previousAtlasSources != null) { sourcesArray.addAll(previousAtlasSources); } + Path vanillaArmorPath1 = generatedPackPath + .resolve("assets") + .resolve("minecraft") + .resolve("textures") + .resolve("entity") + .resolve("equipment") + .resolve("humanoid") + .resolve(Config.sacrificedVanillaArmorType() + ".png"); + Path vanillaArmorPath2 = generatedPackPath + .resolve("assets") + .resolve("minecraft") + .resolve("textures") + .resolve("entity") + .resolve("equipment") + .resolve("humanoid_leggings") + .resolve(Config.sacrificedVanillaArmorType() + ".png"); + try { + Files.createDirectories(vanillaArmorPath1.getParent()); + Files.createDirectories(vanillaArmorPath2.getParent()); + Files.write(vanillaArmorPath1, EMPTY_EQUIPMENT_IMAGE); + Files.write(vanillaArmorPath2, EMPTY_EQUIPMENT_IMAGE); + } catch (IOException e) { + this.plugin.logger().warn("Failed to write empty vanilla armor texture file", e); + } } - // 准备旧版本atlas + + // 修复被干碎的原版盔甲 + Key vanillaFixTrimType = Key.of("minecraft", Config.sacrificedVanillaArmorType()); + collectedTrims.add(Tuple.of(vanillaFixTrimType, true, true)); + processTrimBasedEquipment(new TrimBasedEquipment(vanillaFixTrimType, Config.sacrificedHumanoid(), Config.sacrificedHumanoidLeggings()), generatedPackPath); + + // 准备旧版本atlas和覆盖纹理 JsonObject legacyTrimAtlasJson = null; if (needLegacyCompatibility) { legacyTrimAtlasJson = new JsonObject(); @@ -1422,19 +1344,40 @@ public abstract class AbstractPackManager implements PackManager { 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); + single1.addProperty("resource", tuple.left().namespace() + ":trims/models/armor/" + tuple.left().value() + "_" + NEW_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); + single2.addProperty("resource", tuple.left().namespace() + ":trims/models/armor/" + tuple.left().value() + "_leggings_" + NEW_TRIM_MATERIAL); sourcesArray.add(single2); } } if (previousAtlasSources != null) { sourcesArray.addAll(previousAtlasSources); } + Path vanillaArmorPath1 = generatedPackPath + .resolve("assets") + .resolve("minecraft") + .resolve("textures") + .resolve("models") + .resolve("armor") + .resolve(Config.sacrificedVanillaArmorType() + "_layer_1.png"); + Path vanillaArmorPath2 = generatedPackPath + .resolve("assets") + .resolve("minecraft") + .resolve("textures") + .resolve("models") + .resolve("armor") + .resolve(Config.sacrificedVanillaArmorType() + "_layer_2.png"); + try { + Files.createDirectories(vanillaArmorPath1.getParent()); + Files.write(vanillaArmorPath1, EMPTY_EQUIPMENT_IMAGE); + Files.write(vanillaArmorPath2, EMPTY_EQUIPMENT_IMAGE); + } catch (IOException e) { + this.plugin.logger().warn("Failed to write empty vanilla armor texture file", e); + } } // 创建atlas文件夹 try { @@ -1479,6 +1422,137 @@ public abstract class AbstractPackManager implements PackManager { } } + @Nullable + private Pair processTrimBasedEquipment(TrimBasedEquipment trimBasedEquipment, Path generatedPackPath) { + 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 说话 + return null; + } + boolean shouldPreserve = false; + if (Config.packMinVersion().isBelow(MinecraftVersions.V1_21_2)) { + Path legacyTarget = generatedPackPath + .resolve("assets") + .resolve(assetId.namespace()) + .resolve("textures") + .resolve("trims") + .resolve("models") + .resolve("armor") + .resolve(assetId.value() + "_" + NEW_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 (Config.packMaxVersion().isAtOrAbove(MinecraftVersions.V1_21_2)) { + Path modernTarget = generatedPackPath + .resolve("assets") + .resolve(assetId.namespace()) + .resolve("textures") + .resolve("trims") + .resolve("entity") + .resolve("humanoid") + .resolve(assetId.value() + "_" + NEW_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 说话 + return null; + } + boolean shouldPreserve = false; + if (Config.packMinVersion().isBelow(MinecraftVersions.V1_21_2)) { + Path legacyTarget = generatedPackPath + .resolve("assets") + .resolve(assetId.namespace()) + .resolve("textures") + .resolve("trims") + .resolve("models") + .resolve("armor") + .resolve(assetId.value() + "_leggings_" + NEW_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 (Config.packMaxVersion().isAtOrAbove(MinecraftVersions.V1_21_2)) { + Path modernTarget = generatedPackPath + .resolve("assets") + .resolve(assetId.namespace()) + .resolve("textures") + .resolve("trims") + .resolve("entity") + .resolve("humanoid_leggings") + .resolve(assetId.value() + "_" + NEW_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); + } + } + } + + return Pair.of(hasLayer1, hasLayer2); + } + private void generateClientLang(Path generatedPackPath) { for (Map.Entry entry : this.plugin.translationManager().clientLangData().entrySet()) { JsonObject json = new JsonObject(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java index 7b9e261a0..bbd0aa9eb 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java @@ -13,6 +13,7 @@ import dev.dejvokep.boostedyaml.settings.updater.UpdaterSettings; import dev.dejvokep.boostedyaml.utils.format.NodeRole; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.entity.furniture.ColliderType; +import net.momirealms.craftengine.core.pack.AbstractPackManager; import net.momirealms.craftengine.core.pack.conflict.resolution.ResolutionConditional; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.PluginProperties; @@ -329,10 +330,15 @@ public class Config { 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$type = config.getString("equipment.sacrificed-vanilla-armor.type", "chainmail").toLowerCase(Locale.ENGLISH); + if (!AbstractPackManager.ALLOWED_VANILLA_EQUIPMENT.contains(equipment$sacrificed_vanilla_armor$type)) { + TranslationManager.instance().log("warning.config.equipment.invalid_sacrificed_armor", equipment$sacrificed_vanilla_armor$type); + 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")); + equipment$sacrificed_vanilla_armor$humanoid = Key.of(config.getString("equipment.sacrificed-vanilla-armor.humanoid", "minecraft:trims/entity/humanoid/chainmail")); + equipment$sacrificed_vanilla_armor$humanoid_leggings = Key.of(config.getString("equipment.sacrificed-vanilla-armor.humanoid-leggings", "minecraft:trims/entity/humanoid_leggings/chainmail")); // item item$client_bound_model = config.getBoolean("item.client-bound-model", false); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/StringKeyConstructor.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/StringKeyConstructor.java index 127c2220c..568679a97 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/StringKeyConstructor.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/StringKeyConstructor.java @@ -118,7 +118,7 @@ public class StringKeyConstructor extends SafeConstructor { // 如果路径中存在一个非map的值, 这意味着 // 当存在了 {aa: bb}, 又想要写入 {aa::bb::c: value} 时, 会触发这个警告, 然后会覆盖之前的. - if (existingValue != null) logWarning("key_path_conflict", keyPart, keyNode); + if (existingValue != null) logWarning("inconsistent_value_type", keyPart, keyNode); // 创建层级 Map newMap = new LinkedHashMap<>(); diff --git a/gradle.properties b/gradle.properties index f643b98b1..ae2ad91b3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] project_version=0.0.59.2 -config_version=40 +config_version=41 lang_version=21 project_group=net.momirealms latest_supported_version=1.21.7