mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-25 01:49:30 +00:00
盔甲重构part1
This commit is contained in:
@@ -15,10 +15,7 @@ import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Arrow;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.entity.ThrowableProjectile;
|
||||
import org.bukkit.entity.*;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.HandlerList;
|
||||
@@ -32,6 +29,7 @@ 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;
|
||||
@@ -47,11 +45,22 @@ public class BukkitProjectileManager implements Listener, ProjectileManager {
|
||||
@Override
|
||||
public void delayedInit() {
|
||||
Bukkit.getPluginManager().registerEvents(this, this.plugin.javaPlugin());
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
List<Entity> entities = world.getEntities();
|
||||
for (Entity entity : entities) {
|
||||
if (entity instanceof Projectile projectile) {
|
||||
handleProjectileLoad(projectile);
|
||||
if (VersionHelper.isFolia()) {
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
List<Entity> entities = world.getEntities();
|
||||
for (Entity entity : entities) {
|
||||
if (entity instanceof Projectile projectile) {
|
||||
projectile.getScheduler().run(this.plugin.javaPlugin(), (t) -> handleProjectileLoad(projectile), () -> {});
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
List<Entity> entities = world.getEntities();
|
||||
for (Entity entity : entities) {
|
||||
if (entity instanceof Projectile projectile) {
|
||||
handleProjectileLoad(projectile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,6 +149,7 @@ public class BukkitCustomItem extends AbstractCustomItem<ItemStack> {
|
||||
@Override
|
||||
public CustomItem<ItemStack> build() {
|
||||
this.modifiers.addAll(this.settings.modifiers());
|
||||
this.clientBoundModifiers.addAll(this.settings.clientBoundModifiers());
|
||||
return new BukkitCustomItem(this.id, this.item, this.clientBoundItem, this.itemKey, this.clientBoundItemKey, List.copyOf(this.behaviors),
|
||||
List.copyOf(this.modifiers), List.copyOf(this.clientBoundModifiers), this.settings, this.events);
|
||||
}
|
||||
|
||||
@@ -11,11 +11,14 @@ 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;
|
||||
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
|
||||
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
|
||||
@@ -33,9 +36,7 @@ import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
||||
static {
|
||||
@@ -50,6 +51,8 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
||||
private final DebugStickListener debugStickListener;
|
||||
private final ArmorEventListener armorEventListener;
|
||||
private final NetworkItemHandler<ItemStack> networkItemHandler;
|
||||
private final Object bedrockItemHolder;
|
||||
private boolean registeredTrimMaterial;
|
||||
|
||||
public BukkitItemManager(BukkitCraftEngine plugin) {
|
||||
super(plugin);
|
||||
@@ -61,6 +64,7 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
||||
this.armorEventListener = new ArmorEventListener();
|
||||
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();;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -134,6 +138,78 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
||||
HandlerList.unregisterAll(this.armorEventListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerArmorTrimPattern(Collection<TrimBasedEquipment> equipments) {
|
||||
if (equipments.isEmpty()) return;
|
||||
this.registerCustomTrimMaterial();
|
||||
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());
|
||||
Object previous = FastNMS.INSTANCE.method$Registry$getValue(registry, resourceLocation);
|
||||
if (previous == null) {
|
||||
Object trimPattern = createTrimPattern(equipment.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());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
this.plugin.logger().warn("Failed to register armor trim pattern.", e);
|
||||
} finally {
|
||||
try {
|
||||
CoreReflections.field$MappedRegistry$frozen.set(registry, true);
|
||||
} catch (ReflectiveOperationException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 previous = FastNMS.INSTANCE.method$Registry$getValue(registry, resourceLocation);
|
||||
if (previous == null) {
|
||||
try {
|
||||
CoreReflections.field$MappedRegistry$frozen.set(registry, false);
|
||||
Object trimMaterial = createTrimMaterial();
|
||||
Object holder = CoreReflections.method$Registry$registerForHolder.invoke(null, registry, resourceLocation, trimMaterial);
|
||||
CoreReflections.method$Holder$Reference$bindValue.invoke(holder, trimMaterial);
|
||||
CoreReflections.field$Holder$Reference$tags.set(holder, Set.of());
|
||||
} catch (Exception e) {
|
||||
this.plugin.logger().warn("Failed to register trim material.", e);
|
||||
} finally {
|
||||
try {
|
||||
CoreReflections.field$MappedRegistry$frozen.set(registry, true);
|
||||
} catch (ReflectiveOperationException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
this.registeredTrimMaterial = true;
|
||||
}
|
||||
|
||||
private Object createTrimPattern(Key key) throws ReflectiveOperationException {
|
||||
if (VersionHelper.isOrAbove1_21_5()) {
|
||||
return CoreReflections.constructor$TrimPattern.newInstance(KeyUtils.toResourceLocation(key), CoreReflections.instance$Component$empty, false);
|
||||
} else if (VersionHelper.isOrAbove1_20_2()) {
|
||||
return CoreReflections.constructor$TrimPattern.newInstance(KeyUtils.toResourceLocation(key), this.bedrockItemHolder, CoreReflections.instance$Component$empty, false);
|
||||
} else {
|
||||
return CoreReflections.constructor$TrimPattern.newInstance(KeyUtils.toResourceLocation(key), this.bedrockItemHolder, CoreReflections.instance$Component$empty);
|
||||
}
|
||||
}
|
||||
|
||||
private Object createTrimMaterial() throws ReflectiveOperationException {
|
||||
if (VersionHelper.isOrAbove1_21_5()) {
|
||||
Object assetGroup = CoreReflections.method$MaterialAssetGroup$create.invoke(null, "custom");
|
||||
return CoreReflections.constructor$TrimMaterial.newInstance(assetGroup, CoreReflections.instance$Component$empty);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public Item<ItemStack> fromByteArray(byte[] bytes) {
|
||||
|
||||
@@ -2,9 +2,17 @@ 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 {
|
||||
@@ -52,6 +60,18 @@ public class ComponentItemFactory1_21_2 extends ComponentItemFactory1_21 {
|
||||
|
||||
@Override
|
||||
protected Optional<EquipmentData> equippable(ComponentItemWrapper item) {
|
||||
throw new UnsupportedOperationException("Not implemented yet.");
|
||||
Optional<Object> optionalData = item.getJavaComponent(ComponentTypes.EQUIPPABLE);
|
||||
if (optionalData.isEmpty()) return Optional.empty();
|
||||
Map<String, Object> data = MiscUtils.castToMap(optionalData.get(), false);
|
||||
String slot = data.get("slot").toString();
|
||||
return Optional.of(new EquipmentData(
|
||||
EquipmentSlot.valueOf(slot.toUpperCase(Locale.ENGLISH)),
|
||||
data.containsKey("asset_id") ? Key.of((String) data.get("asset_id")) : null,
|
||||
(boolean) data.getOrDefault("dispensable", true),
|
||||
(boolean) data.getOrDefault("swappable", true),
|
||||
(boolean) data.getOrDefault("damage_on_hurt", true),
|
||||
(boolean) data.getOrDefault("equip_on_interact", false),
|
||||
data.containsKey("camera_overlay") ? Key.of((String) data.get("camera_overlay")) : null
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -3588,12 +3588,37 @@ public final class CoreReflections {
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$TrimPattern = requireNonNull(
|
||||
VersionHelper.isOrAbove1_21_2() ?
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"world.item.equipment.trim.TrimPattern",
|
||||
"world.item.equipment.trim.TrimPattern"
|
||||
) :
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"world.item.armortrim.TrimPattern",
|
||||
"world.item.armortrim.TrimPattern"
|
||||
)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$TrimMaterial = requireNonNull(
|
||||
VersionHelper.isOrAbove1_21_2() ?
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"world.item.equipment.trim.TrimMaterial",
|
||||
"world.item.equipment.trim.TrimMaterial"
|
||||
) :
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"world.item.armortrim.TrimMaterial",
|
||||
"world.item.armortrim.TrimMaterial"
|
||||
)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$MaterialAssetGroup = BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"world.item.equipment.trim.MaterialAssetGroup",
|
||||
"world.item.equipment.trim.MaterialAssetGroup"
|
||||
);
|
||||
|
||||
public static final Method method$MaterialAssetGroup$create = Optional.ofNullable(clazz$MaterialAssetGroup)
|
||||
.map(it -> ReflectionUtils.getStaticMethod(it, it, String.class)).orElse(null);
|
||||
|
||||
public static final Constructor<?> constructor$TrimPattern = requireNonNull(
|
||||
VersionHelper.isOrAbove1_21_5() ?
|
||||
ReflectionUtils.getConstructor(clazz$TrimPattern, clazz$ResourceLocation, clazz$Component, boolean.class) :
|
||||
@@ -3601,4 +3626,12 @@ public final class CoreReflections {
|
||||
ReflectionUtils.getConstructor(clazz$TrimPattern, clazz$ResourceLocation, clazz$Holder, clazz$Component, boolean.class) :
|
||||
ReflectionUtils.getConstructor(clazz$TrimPattern, clazz$ResourceLocation, clazz$Holder, clazz$Component)
|
||||
);
|
||||
|
||||
public static final Constructor<?> constructor$TrimMaterial = requireNonNull(
|
||||
VersionHelper.isOrAbove1_21_5() ?
|
||||
ReflectionUtils.getConstructor(clazz$TrimMaterial, clazz$MaterialAssetGroup, clazz$Component) :
|
||||
VersionHelper.isOrAbove1_21_4() ?
|
||||
ReflectionUtils.getConstructor(clazz$TrimMaterial, String.class, clazz$Holder, Map.class, clazz$Component) :
|
||||
ReflectionUtils.getConstructor(clazz$TrimMaterial, String.class, clazz$Holder, float.class, Map.class, clazz$Component)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ public final class MRegistries {
|
||||
public static final Object CONFIGURED_FEATURE;
|
||||
public static final Object PLACED_FEATURE;
|
||||
public static final Object TRIM_PATTERN;
|
||||
public static final Object TRIM_MATERIAL;
|
||||
@Nullable // 1.21+
|
||||
public static final Object JUKEBOX_SONG;
|
||||
@Nullable // 1.21+
|
||||
@@ -48,6 +49,7 @@ public final class MRegistries {
|
||||
Object registries$JukeboxSong = null;
|
||||
Object registries$Recipe = null;
|
||||
Object registries$TrimPattern = null;
|
||||
Object registries$TrimMaterial = null;
|
||||
for (Field field : fields) {
|
||||
Type fieldType = field.getGenericType();
|
||||
if (fieldType instanceof ParameterizedType paramType) {
|
||||
@@ -91,6 +93,8 @@ public final class MRegistries {
|
||||
registries$PlacedFeature = field.get(null);
|
||||
} else if (type == CoreReflections.clazz$TrimPattern) {
|
||||
registries$TrimPattern = field.get(null);
|
||||
} else if (type == CoreReflections.clazz$TrimMaterial) {
|
||||
registries$TrimMaterial = field.get(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -111,6 +115,7 @@ public final class MRegistries {
|
||||
CONFIGURED_FEATURE = requireNonNull(registries$ConfiguredFeature);
|
||||
PLACED_FEATURE = requireNonNull(registries$PlacedFeature);
|
||||
TRIM_PATTERN = requireNonNull(registries$TrimPattern);
|
||||
TRIM_MATERIAL = requireNonNull(registries$TrimMaterial);
|
||||
JUKEBOX_SONG = registries$JukeboxSong;
|
||||
RECIPE = registries$Recipe;
|
||||
} catch (ReflectiveOperationException e) {
|
||||
|
||||
@@ -30,10 +30,10 @@ public class BukkitSoundManager extends AbstractSoundManager {
|
||||
@Override
|
||||
protected void registerSongs(Map<Key, JukeboxSong> songs) {
|
||||
if (songs.isEmpty()) return;
|
||||
Object registry = FastNMS.INSTANCE.method$RegistryAccess$lookupOrThrow(FastNMS.INSTANCE.registryAccess(), MRegistries.JUKEBOX_SONG);
|
||||
try {
|
||||
// 获取 JUKEBOX_SONG 注册表
|
||||
Object registry = FastNMS.INSTANCE.method$RegistryAccess$lookupOrThrow(FastNMS.INSTANCE.registryAccess(), MRegistries.JUKEBOX_SONG);
|
||||
unfreezeRegistry(registry);
|
||||
CoreReflections.field$MappedRegistry$frozen.set(registry, false);
|
||||
for (Map.Entry<Key, JukeboxSong> entry : songs.entrySet()) {
|
||||
Key id = entry.getKey();
|
||||
JukeboxSong jukeboxSong = entry.getValue();
|
||||
@@ -54,17 +54,12 @@ public class BukkitSoundManager extends AbstractSoundManager {
|
||||
CoreReflections.field$Holder$Reference$tags.set(holder, Set.of());
|
||||
}
|
||||
}
|
||||
freezeRegistry(registry);
|
||||
} catch (Exception e) {
|
||||
plugin.logger().warn("Failed to register jukebox songs.", e);
|
||||
this.plugin.logger().warn("Failed to register jukebox songs.", e);
|
||||
} finally {
|
||||
try {
|
||||
CoreReflections.field$MappedRegistry$frozen.set(registry, true);
|
||||
} catch (ReflectiveOperationException ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
private void unfreezeRegistry(Object registry) throws IllegalAccessException {
|
||||
CoreReflections.field$MappedRegistry$frozen.set(registry, false);
|
||||
}
|
||||
|
||||
private void freezeRegistry(Object registry) throws IllegalAccessException {
|
||||
CoreReflections.field$MappedRegistry$frozen.set(registry, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,6 +138,10 @@ resource-pack:
|
||||
resolution:
|
||||
type: merge_atlas
|
||||
|
||||
item:
|
||||
# Make custom-model-data and item-model clientside by default
|
||||
client-bound-model: false
|
||||
|
||||
equipment:
|
||||
# The sacrificed-vanilla-armor argument determines which vanilla armor gets completely removed (loses all its trims)
|
||||
# when you create new armor using trim types, freeing up a slot for your custom armor.
|
||||
|
||||
@@ -153,27 +153,6 @@ items#topaz_gears:
|
||||
template: default:model/simplified_handheld
|
||||
arguments:
|
||||
path: minecraft:item/custom/topaz_sword
|
||||
$$>=1.21.2#armor:
|
||||
default:topaz_helmet:
|
||||
template: default:armor/topaz
|
||||
arguments:
|
||||
part: helmet
|
||||
slot: head
|
||||
default:topaz_chestplate:
|
||||
template: default:armor/topaz
|
||||
arguments:
|
||||
part: chestplate
|
||||
slot: chest
|
||||
default:topaz_leggings:
|
||||
template: default:armor/topaz
|
||||
arguments:
|
||||
part: leggings
|
||||
slot: legs
|
||||
default:topaz_boots:
|
||||
template: default:armor/topaz
|
||||
arguments:
|
||||
part: boots
|
||||
slot: feet
|
||||
$$>=1.21.4#topaz_trident:
|
||||
default:topaz_trident:
|
||||
material: trident
|
||||
@@ -288,6 +267,38 @@ items#topaz_gears:
|
||||
tints:
|
||||
- type: minecraft:dye
|
||||
default: -6265536
|
||||
default:topaz_helmet:
|
||||
template:
|
||||
- default:armor/topaz
|
||||
- default:model/armor_trim
|
||||
arguments:
|
||||
part: helmet
|
||||
slot: head
|
||||
material: topaz
|
||||
default:topaz_chestplate:
|
||||
template:
|
||||
- default:armor/topaz
|
||||
- default:model/armor_trim
|
||||
arguments:
|
||||
part: chestplate
|
||||
slot: chest
|
||||
material: topaz
|
||||
default:topaz_leggings:
|
||||
template:
|
||||
- default:armor/topaz
|
||||
- default:model/armor_trim
|
||||
arguments:
|
||||
part: leggings
|
||||
slot: legs
|
||||
material: topaz
|
||||
default:topaz_boots:
|
||||
template:
|
||||
- default:armor/topaz
|
||||
- default:model/armor_trim
|
||||
arguments:
|
||||
part: boots
|
||||
slot: feet
|
||||
material: topaz
|
||||
templates:
|
||||
default:armor/topaz:
|
||||
material: chainmail_${part}
|
||||
@@ -298,122 +309,18 @@ templates:
|
||||
settings:
|
||||
tags:
|
||||
- default:topaz_tools
|
||||
equippable:
|
||||
slot: ${slot}
|
||||
asset-id: topaz
|
||||
humanoid: minecraft:topaz
|
||||
humanoid-leggings: minecraft:topaz
|
||||
model:
|
||||
type: minecraft:select
|
||||
property: minecraft:trim_material
|
||||
fallback:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/topaz_${part}
|
||||
generation:
|
||||
parent: minecraft:item/generated
|
||||
textures:
|
||||
layer0: minecraft:item/custom/topaz_${part}
|
||||
cases:
|
||||
- when: minecraft:quartz
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/topaz_${part}_quartz_trim
|
||||
generation:
|
||||
parent: minecraft:item/generated
|
||||
textures:
|
||||
layer0: minecraft:item/custom/topaz_${part}
|
||||
layer1: minecraft:trims/items/${part}_trim_quartz
|
||||
- when: minecraft:iron
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/topaz_${part}_iron_trim
|
||||
generation:
|
||||
parent: minecraft:item/generated
|
||||
textures:
|
||||
layer0: minecraft:item/custom/topaz_${part}
|
||||
layer1: minecraft:trims/items/${part}_trim_iron
|
||||
- when: minecraft:netherite
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/topaz_${part}_netherite_trim
|
||||
generation:
|
||||
parent: minecraft:item/generated
|
||||
textures:
|
||||
layer0: minecraft:item/custom/topaz_${part}
|
||||
layer1: minecraft:trims/items/${part}_trim_netherite
|
||||
- when: minecraft:redstone
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/topaz_${part}_redstone_trim
|
||||
generation:
|
||||
parent: minecraft:item/generated
|
||||
textures:
|
||||
layer0: minecraft:item/custom/topaz_${part}
|
||||
layer1: minecraft:trims/items/${part}_trim_redstone
|
||||
- when: minecraft:copper
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/topaz_${part}_copper_trim
|
||||
generation:
|
||||
parent: minecraft:item/generated
|
||||
textures:
|
||||
layer0: minecraft:item/custom/topaz_${part}
|
||||
layer1: minecraft:trims/items/${part}_trim_copper
|
||||
- when: minecraft:gold
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/topaz_${part}_gold_trim
|
||||
generation:
|
||||
parent: minecraft:item/generated
|
||||
textures:
|
||||
layer0: minecraft:item/custom/topaz_${part}
|
||||
layer1: minecraft:trims/items/${part}_trim_gold
|
||||
- when: minecraft:emerald
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/topaz_${part}_emerald_trim
|
||||
generation:
|
||||
parent: minecraft:item/generated
|
||||
textures:
|
||||
layer0: minecraft:item/custom/topaz_${part}
|
||||
layer1: minecraft:trims/items/${part}_trim_emerald
|
||||
- when: minecraft:diamond
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/topaz_${part}_diamond_trim
|
||||
generation:
|
||||
parent: minecraft:item/generated
|
||||
textures:
|
||||
layer0: minecraft:item/custom/topaz_${part}
|
||||
layer1: minecraft:trims/items/${part}_trim_diamond
|
||||
- when: minecraft:lapis
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/topaz_${part}_lapis_trim
|
||||
generation:
|
||||
parent: minecraft:item/generated
|
||||
textures:
|
||||
layer0: minecraft:item/custom/topaz_${part}
|
||||
layer1: minecraft:trims/items/${part}_trim_lapis
|
||||
- when: minecraft:amethyst
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/topaz_${part}_amethyst_trim
|
||||
generation:
|
||||
parent: minecraft:item/generated
|
||||
textures:
|
||||
layer0: minecraft:item/custom/topaz_${part}
|
||||
layer1: minecraft:trims/items/${part}_trim_amethyst
|
||||
- when: minecraft:resin
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/topaz_${part}_resin_trim
|
||||
generation:
|
||||
parent: minecraft:item/generated
|
||||
textures:
|
||||
layer0: minecraft:item/custom/topaz_${part}
|
||||
layer1: minecraft:trims/items/${part}_trim_resin
|
||||
recipes#topaz_gears:
|
||||
equipment:
|
||||
asset-id: default:topaz
|
||||
properties:
|
||||
slot: ${slot}
|
||||
equipments#topaz:
|
||||
default:topaz:
|
||||
type:
|
||||
$$>=1.21.2: component
|
||||
$$<1.21.2: trim
|
||||
humanoid: minecraft:entity/equipment/humanoid/topaz
|
||||
humanoid-leggings: minecraft:entity/equipment/humanoid_leggings/topaz
|
||||
recipes#topaz:
|
||||
default:topaz_shovel:
|
||||
type: shaped
|
||||
pattern:
|
||||
|
||||
@@ -1,22 +1,5 @@
|
||||
# This file contains some useful template data. If you have good ideas, you are welcome to contribute your template!
|
||||
|
||||
# These templates let you ditch the real custom_model_data on the server side.
|
||||
# Instead, we use client side components sent via packets to control how items look.
|
||||
default:item/client_bound_custom_model_data:
|
||||
custom-model-data: ${custom_model_data}
|
||||
data:
|
||||
remove-components:
|
||||
- minecraft:custom_model_data
|
||||
client-bound-data:
|
||||
custom-model-data: ${custom_model_data}
|
||||
default:item/client_bound_item_model:
|
||||
item-model: ${item_model}
|
||||
data:
|
||||
remove-components:
|
||||
- minecraft:item_model
|
||||
client-bound-data:
|
||||
item-model: ${item_model}
|
||||
|
||||
# blocks
|
||||
templates#models#block:
|
||||
# template: default:model/cube_all
|
||||
@@ -162,6 +145,120 @@ templates#models#2d:
|
||||
texture: ${path}
|
||||
broken_model: ${broken_path}
|
||||
broken_texture: ${broken_path}
|
||||
# template: default:model/armor_trim
|
||||
# arguments:
|
||||
# material: armor material type
|
||||
# part: slot type
|
||||
default:model/armor_trim:
|
||||
type: minecraft:select
|
||||
property: minecraft:trim_material
|
||||
fallback:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/${material}_${part}
|
||||
generation:
|
||||
parent: minecraft:item/generated
|
||||
textures:
|
||||
layer0: minecraft:item/custom/${material}_${part}
|
||||
cases:
|
||||
- when: minecraft:quartz
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/${material}_${part}_quartz_trim
|
||||
generation:
|
||||
parent: minecraft:item/generated
|
||||
textures:
|
||||
layer0: minecraft:item/custom/${material}_${part}
|
||||
layer1: minecraft:trims/items/${part}_trim_quartz
|
||||
- when: minecraft:iron
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/${material}_${part}_iron_trim
|
||||
generation:
|
||||
parent: minecraft:item/generated
|
||||
textures:
|
||||
layer0: minecraft:item/custom/${material}_${part}
|
||||
layer1: minecraft:trims/items/${part}_trim_iron
|
||||
- when: minecraft:netherite
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/${material}_${part}_netherite_trim
|
||||
generation:
|
||||
parent: minecraft:item/generated
|
||||
textures:
|
||||
layer0: minecraft:item/custom/${material}_${part}
|
||||
layer1: minecraft:trims/items/${part}_trim_netherite
|
||||
- when: minecraft:redstone
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/${material}_${part}_redstone_trim
|
||||
generation:
|
||||
parent: minecraft:item/generated
|
||||
textures:
|
||||
layer0: minecraft:item/custom/${material}_${part}
|
||||
layer1: minecraft:trims/items/${part}_trim_redstone
|
||||
- when: minecraft:copper
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/${material}_${part}_copper_trim
|
||||
generation:
|
||||
parent: minecraft:item/generated
|
||||
textures:
|
||||
layer0: minecraft:item/custom/${material}_${part}
|
||||
layer1: minecraft:trims/items/${part}_trim_copper
|
||||
- when: minecraft:gold
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/${material}_${part}_gold_trim
|
||||
generation:
|
||||
parent: minecraft:item/generated
|
||||
textures:
|
||||
layer0: minecraft:item/custom/${material}_${part}
|
||||
layer1: minecraft:trims/items/${part}_trim_gold
|
||||
- when: minecraft:emerald
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/${material}_${part}_emerald_trim
|
||||
generation:
|
||||
parent: minecraft:item/generated
|
||||
textures:
|
||||
layer0: minecraft:item/custom/${material}_${part}
|
||||
layer1: minecraft:trims/items/${part}_trim_emerald
|
||||
- when: minecraft:diamond
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/${material}_${part}_diamond_trim
|
||||
generation:
|
||||
parent: minecraft:item/generated
|
||||
textures:
|
||||
layer0: minecraft:item/custom/${material}_${part}
|
||||
layer1: minecraft:trims/items/${part}_trim_diamond
|
||||
- when: minecraft:lapis
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/${material}_${part}_lapis_trim
|
||||
generation:
|
||||
parent: minecraft:item/generated
|
||||
textures:
|
||||
layer0: minecraft:item/custom/${material}_${part}
|
||||
layer1: minecraft:trims/items/${part}_trim_lapis
|
||||
- when: minecraft:amethyst
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/${material}_${part}_amethyst_trim
|
||||
generation:
|
||||
parent: minecraft:item/generated
|
||||
textures:
|
||||
layer0: minecraft:item/custom/${material}_${part}
|
||||
layer1: minecraft:trims/items/${part}_trim_amethyst
|
||||
- when: minecraft:resin
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: minecraft:item/custom/${material}_${part}_resin_trim
|
||||
generation:
|
||||
parent: minecraft:item/generated
|
||||
textures:
|
||||
layer0: minecraft:item/custom/${material}_${part}
|
||||
layer1: minecraft:trims/items/${part}_trim_resin
|
||||
|
||||
# shield
|
||||
templates#models#shield:
|
||||
|
||||
@@ -155,7 +155,9 @@ warning.config.furniture.hitbox.custom.invalid_entity: "<yellow>Issue found in f
|
||||
warning.config.item.duplicate: "<yellow>Issue found in file <arg:0> - Duplicated item '<arg:1>'. Please check if there is the same configuration in other files.</yellow>"
|
||||
warning.config.item.settings.unknown: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is using an unknown setting type '<arg:2>'.</yellow>"
|
||||
warning.config.item.settings.invulnerable.invalid_damage_source: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is using an unknown damage source '<arg:2>'. Allowed sources: [<arg:3>].</yellow>"
|
||||
warning.config.item.settings.equippable.missing_slot: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is missing the required 'slot' argument for 'equippable' settings.</yellow>"
|
||||
warning.config.item.settings.equipment.missing_asset_id: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is missing the required 'asset-id' argument for 'equipment' settings.</yellow>"
|
||||
warning.config.item.settings.equipment.invalid_asset_id: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is using an invalid 'asset-id' argument for 'equipment' settings. This might be because you haven't created this equipment configuration or misspelled the asset-id.</yellow>"
|
||||
warning.config.item.settings.projectile.missing_item: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is missing the required 'item' argument for 'projectile' settings.</yellow>"
|
||||
warning.config.item.missing_material: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is missing the required 'material' argument.</yellow>"
|
||||
warning.config.item.invalid_material: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is using an invalid material type '<arg:2>'.</yellow>"
|
||||
warning.config.item.invalid_custom_model_data: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is using a negative custom model data '<arg:2>' which is invalid.</yellow>"
|
||||
@@ -387,4 +389,7 @@ warning.config.resource_pack.generation.missing_item_model: "<yellow>Item '<arg:
|
||||
warning.config.resource_pack.generation.missing_block_model: "<yellow>Block state '<arg:0>' is missing model file: '<arg:1>'</yellow>"
|
||||
warning.config.resource_pack.generation.missing_parent_model: "<yellow>Model '<arg:0>' cannot find parent model: '<arg:1>'</yellow>"
|
||||
warning.config.resource_pack.generation.malformatted_json: "<yellow>Json file '<arg:0>' is malformatted.</yellow>"
|
||||
warning.config.resource_pack.invalid_overlay_format: "<yellow>Issue found in config.yml at 'resource-pack.overlay-format' - Invalid overlay format '<arg:0>'. Overlay format must contain the placeholder '{version}'.</yellow>"
|
||||
warning.config.resource_pack.invalid_overlay_format: "<yellow>Issue found in config.yml at 'resource-pack.overlay-format' - Invalid overlay format '<arg:0>'. Overlay format must contain the placeholder '{version}'.</yellow>"
|
||||
warning.config.equipment.duplicate: ""
|
||||
warning.config.equipment.missing_type: ""
|
||||
warning.config.equipment.invalid_type: ""
|
||||
@@ -156,7 +156,9 @@ warning.config.furniture.hitbox.custom.invalid_entity: "<yellow>在文件 <arg:0
|
||||
warning.config.item.duplicate: "<yellow>在文件 <arg:0> 发现问题 - 重复的物品 '<arg:1>' 请检查其他文件中是否存在相同配置</yellow>"
|
||||
warning.config.item.settings.unknown: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 使用了未知的设置类型 '<arg:2>'</yellow>"
|
||||
warning.config.item.settings.invulnerable.invalid_damage_source: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 物品使用了未知的伤害来源类型 '<arg:2>' 允许的来源: [<arg:3>]</yellow>"
|
||||
warning.config.item.settings.equippable.missing_slot: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 缺少了 'equippable' 设置所需的 'slot' 参数.</yellow>"
|
||||
warning.config.item.settings.equipment.missing_asset_id: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 缺少 'equipment' 设置所需的 'asset-id' 参数.</yellow>"
|
||||
warning.config.item.settings.equipment.invalid_asset_id: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 为 'equipment' 设置配置了无效的 'asset-id'. 这可能是因为你没有创建装备配置或是错误地拼写了 asset-id.</yellow>"
|
||||
warning.config.item.settings.projectile.missing_item: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 缺少 'projectile' 设置所需的 'item' 参数.</yellow>"
|
||||
warning.config.item.missing_material: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 缺少必需的 'material' 参数</yellow>"
|
||||
warning.config.item.invalid_material: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 使用了无效的材料类型 '<arg:2>'</yellow>"
|
||||
warning.config.item.invalid_custom_model_data: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 使用了无效的负数模型值 '<arg:2>'.</yellow>"
|
||||
|
||||
@@ -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