mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-25 01:49:30 +00:00
盔甲重构part4
This commit is contained in:
@@ -137,6 +137,7 @@ public class BukkitFurniture implements Furniture {
|
||||
@NotNull
|
||||
public Object spawnPacket(Player player) {
|
||||
// TODO hasPermission might be slow, can we use a faster way in the future?
|
||||
// TODO Make it based on conditions. So we can dynamically control which furniture should be sent to the player
|
||||
if (!this.minimized || player.hasPermission(FurnitureManager.FURNITURE_ADMIN_NODE)) {
|
||||
return this.cachedSpawnPacket;
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package net.momirealms.craftengine.bukkit.item;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import net.momirealms.craftengine.bukkit.item.behavior.AxeItemBehavior;
|
||||
import net.momirealms.craftengine.bukkit.item.behavior.FlintAndSteelItemBehavior;
|
||||
import net.momirealms.craftengine.bukkit.item.factory.BukkitItemFactory;
|
||||
@@ -23,6 +27,7 @@ import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigExce
|
||||
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
|
||||
import net.momirealms.craftengine.core.registry.Holder;
|
||||
import net.momirealms.craftengine.core.registry.WritableRegistry;
|
||||
import net.momirealms.craftengine.core.util.GsonHelper;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.ResourceKey;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
@@ -34,6 +39,9 @@ import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
||||
@@ -143,7 +151,9 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
||||
protected void registerArmorTrimPattern(Collection<Key> equipments) {
|
||||
if (equipments.isEmpty()) return;
|
||||
this.lastRegisteredPatterns = new HashSet<>(equipments);
|
||||
this.lastRegisteredPatterns.add(Config.sacrificedAssetId());
|
||||
// 可能还没加载
|
||||
if (Config.sacrificedAssetId() != null)
|
||||
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);
|
||||
@@ -168,9 +178,50 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
||||
}
|
||||
|
||||
private void persistLastRegisteredPatterns() {
|
||||
Path persistTrimPatternPath = this.plugin.dataFolderPath()
|
||||
.resolve("cache")
|
||||
.resolve("trim_patterns.json");
|
||||
try {
|
||||
Files.createDirectories(persistTrimPatternPath.getParent());
|
||||
JsonObject json = new JsonObject();
|
||||
JsonArray jsonElements = new JsonArray();
|
||||
for (Key key : this.lastRegisteredPatterns) {
|
||||
jsonElements.add(new JsonPrimitive(key.toString()));
|
||||
}
|
||||
json.add("patterns", jsonElements);
|
||||
if (jsonElements.isEmpty()) {
|
||||
if (Files.exists(persistTrimPatternPath)) {
|
||||
Files.delete(persistTrimPatternPath);
|
||||
}
|
||||
} else {
|
||||
GsonHelper.writeJsonFile(json, persistTrimPatternPath);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
this.plugin.logger().warn("Failed to persist registered trim patterns.", e);
|
||||
}
|
||||
}
|
||||
|
||||
// 需要持久化存储上一次注册的新trim类型,如果注册晚了,加载世界可能导致一些物品损坏
|
||||
private void loadLastRegisteredPatterns() {
|
||||
Path persistTrimPatternPath = this.plugin.dataFolderPath()
|
||||
.resolve("cache")
|
||||
.resolve("trim_patterns.json");
|
||||
if (Files.exists(persistTrimPatternPath) && Files.isRegularFile(persistTrimPatternPath)) {
|
||||
try {
|
||||
JsonObject cache = GsonHelper.readJsonFile(persistTrimPatternPath).getAsJsonObject();
|
||||
JsonArray patterns = cache.getAsJsonArray("patterns");
|
||||
Set<Key> trims = new HashSet<>();
|
||||
for (JsonElement element : patterns) {
|
||||
if (element instanceof JsonPrimitive primitive) {
|
||||
trims.add(Key.of(primitive.getAsString()));
|
||||
}
|
||||
}
|
||||
this.registerArmorTrimPattern(trims);
|
||||
this.lastRegisteredPatterns = trims;
|
||||
} catch (IOException e) {
|
||||
this.plugin.logger().warn("Failed to load registered trim patterns.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void registerCustomTrimMaterial() {
|
||||
|
||||
@@ -27,7 +27,7 @@ import java.util.Optional;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
public class LegacyNetworkItemHandler implements NetworkItemHandler<ItemStack> {
|
||||
public final class LegacyNetworkItemHandler implements NetworkItemHandler<ItemStack> {
|
||||
|
||||
@Override
|
||||
public Optional<Item<ItemStack>> c2s(Item<ItemStack> wrapped) {
|
||||
|
||||
@@ -15,12 +15,14 @@ import net.momirealms.craftengine.bukkit.util.ComponentUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.ItemUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.LegacyInventoryUtils;
|
||||
import net.momirealms.craftengine.core.item.*;
|
||||
import net.momirealms.craftengine.core.item.equipment.TrimBasedEquipment;
|
||||
import net.momirealms.craftengine.core.item.recipe.*;
|
||||
import net.momirealms.craftengine.core.item.recipe.Recipe;
|
||||
import net.momirealms.craftengine.core.item.recipe.input.CraftingInput;
|
||||
import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput;
|
||||
import net.momirealms.craftengine.core.item.recipe.input.SmithingInput;
|
||||
import net.momirealms.craftengine.core.item.setting.AnvilRepairItem;
|
||||
import net.momirealms.craftengine.core.item.setting.ItemEquipment;
|
||||
import net.momirealms.craftengine.core.plugin.config.Config;
|
||||
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
|
||||
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
|
||||
@@ -933,6 +935,24 @@ public class RecipeEventListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onSmithingTrim(PrepareSmithingEvent event) {
|
||||
SmithingInventory inventory = event.getInventory();
|
||||
if (!(inventory.getRecipe() instanceof SmithingTrimRecipe)) return;
|
||||
ItemStack equipment = inventory.getInputEquipment();
|
||||
if (equipment == null) return;
|
||||
Item<ItemStack> wrappedEquipment = this.itemManager.wrap(equipment);
|
||||
Optional<CustomItem<ItemStack>> optionalCustomItem = wrappedEquipment.getCustomItem();
|
||||
if (optionalCustomItem.isEmpty()) return;
|
||||
CustomItem<ItemStack> customItem = optionalCustomItem.get();
|
||||
ItemEquipment itemEquipmentSettings = customItem.settings().equipment();
|
||||
if (itemEquipmentSettings == null) return;
|
||||
// 不允许trim类型的盔甲再次被使用trim
|
||||
if (itemEquipmentSettings.equipment() instanceof TrimBasedEquipment) {
|
||||
event.setResult(null);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onSmithingTransform(PrepareSmithingEvent event) {
|
||||
if (!Config.enableRecipeSystem()) return;
|
||||
|
||||
@@ -138,6 +138,7 @@ public class BukkitCraftEngine extends CraftEngine {
|
||||
super.onPluginLoad();
|
||||
super.blockManager.init();
|
||||
super.networkManager = new BukkitNetworkManager(this);
|
||||
super.itemManager = new BukkitItemManager(this);
|
||||
this.successfullyLoaded = true;
|
||||
super.compatibilityManager().onLoad();
|
||||
}
|
||||
@@ -182,7 +183,6 @@ public class BukkitCraftEngine extends CraftEngine {
|
||||
PacketConsumers.initEntities(RegistryUtils.currentEntityTypeRegistrySize());
|
||||
super.packManager = new BukkitPackManager(this);
|
||||
super.senderFactory = new BukkitSenderFactory(this);
|
||||
super.itemManager = new BukkitItemManager(this);
|
||||
super.recipeManager = new BukkitRecipeManager(this);
|
||||
super.commandManager = new BukkitCommandManager(this);
|
||||
super.itemBrowserManager = new ItemBrowserManagerImpl(this);
|
||||
|
||||
@@ -76,9 +76,7 @@ resource-pack:
|
||||
# Send the resource pack on joining the server
|
||||
send-on-join: true
|
||||
kick-if-declined: true
|
||||
prompt: |
|
||||
<yellow>To fully experience our server,
|
||||
please accept our custom resource pack.</yellow>
|
||||
prompt: "<yellow>To fully experience our server,<newline>please accept our custom resource pack.</yellow>"
|
||||
# If you are hosting the resource pack by yourself, replace `localhost` with your server ip otherwise it would only work on your local pc
|
||||
# If using BungeeCord or Velocity, consider using a proxy-side plugin to handle resource pack delivery.
|
||||
# Read this page for more host types: https://mo-mi.gitbook.io/xiaomomi-plugins/craftengine/plugin-wiki/craftengine/resource-pack/host
|
||||
@@ -140,7 +138,7 @@ resource-pack:
|
||||
|
||||
item:
|
||||
# Make custom-model-data and item-model clientside by default
|
||||
client-bound-model: false
|
||||
client-bound-model: true
|
||||
|
||||
equipment:
|
||||
# The sacrificed-vanilla-armor argument determines which vanilla armor gets completely removed (loses all its trims)
|
||||
|
||||
@@ -307,15 +307,21 @@ templates:
|
||||
- default:topaz_tools
|
||||
equipment:
|
||||
asset-id: default:topaz
|
||||
$$>=1.21.2:
|
||||
slot: ${slot}
|
||||
model:
|
||||
template: default:model/armor_trim
|
||||
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
|
||||
$$>=1.21.2:
|
||||
default:topaz:
|
||||
type: component
|
||||
humanoid: minecraft:topaz
|
||||
humanoid-leggings: minecraft:topaz
|
||||
$$<1.21.2:
|
||||
default:topaz:
|
||||
type: trim
|
||||
humanoid: minecraft:entity/equipment/humanoid/topaz
|
||||
humanoid-leggings: minecraft:entity/equipment/humanoid_leggings/topaz
|
||||
recipes#topaz:
|
||||
default:topaz_shovel:
|
||||
type: shaped
|
||||
@@ -377,49 +383,48 @@ recipes#topaz:
|
||||
result:
|
||||
id: default:topaz_pickaxe
|
||||
count: 1
|
||||
$$>=1.21.2#armor:
|
||||
default:topaz_helmet:
|
||||
type: shaped
|
||||
pattern:
|
||||
- AAA
|
||||
- A A
|
||||
ingredients:
|
||||
A: default:topaz
|
||||
result:
|
||||
id: default:topaz_helmet
|
||||
count: 1
|
||||
default:topaz_chestplate:
|
||||
type: shaped
|
||||
pattern:
|
||||
- A A
|
||||
- AAA
|
||||
- AAA
|
||||
ingredients:
|
||||
A: default:topaz
|
||||
result:
|
||||
id: default:topaz_chestplate
|
||||
count: 1
|
||||
default:topaz_leggings:
|
||||
type: shaped
|
||||
pattern:
|
||||
- AAA
|
||||
- A A
|
||||
- A A
|
||||
ingredients:
|
||||
A: default:topaz
|
||||
result:
|
||||
id: default:topaz_leggings
|
||||
count: 1
|
||||
default:topaz_boots:
|
||||
type: shaped
|
||||
pattern:
|
||||
- A A
|
||||
- A A
|
||||
ingredients:
|
||||
A: default:topaz
|
||||
result:
|
||||
id: default:topaz_boots
|
||||
count: 1
|
||||
default:topaz_helmet:
|
||||
type: shaped
|
||||
pattern:
|
||||
- AAA
|
||||
- A A
|
||||
ingredients:
|
||||
A: default:topaz
|
||||
result:
|
||||
id: default:topaz_helmet
|
||||
count: 1
|
||||
default:topaz_chestplate:
|
||||
type: shaped
|
||||
pattern:
|
||||
- A A
|
||||
- AAA
|
||||
- AAA
|
||||
ingredients:
|
||||
A: default:topaz
|
||||
result:
|
||||
id: default:topaz_chestplate
|
||||
count: 1
|
||||
default:topaz_leggings:
|
||||
type: shaped
|
||||
pattern:
|
||||
- AAA
|
||||
- A A
|
||||
- A A
|
||||
ingredients:
|
||||
A: default:topaz
|
||||
result:
|
||||
id: default:topaz_leggings
|
||||
count: 1
|
||||
default:topaz_boots:
|
||||
type: shaped
|
||||
pattern:
|
||||
- A A
|
||||
- A A
|
||||
ingredients:
|
||||
A: default:topaz
|
||||
result:
|
||||
id: default:topaz_boots
|
||||
count: 1
|
||||
default:topaz_bow:
|
||||
type: smithing_transform
|
||||
base: minecraft:bow
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
author: XiaoMoMi
|
||||
version: 0.0.1
|
||||
description:
|
||||
description: Fix broken vanilla armor
|
||||
namespace: minecraft
|
||||
enable:
|
||||
$$>=1.21.2: false
|
||||
|
||||
@@ -390,6 +390,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.generation.missing_equipment_texture: "<yellow>Equipment '<arg:0>' is missing texture '<arg:1>'</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: "<yellow>Issue found in file <arg:0> - Duplicated equipment '<arg:1>'. Please check if there is the same configuration in other files.</yellow>"
|
||||
warning.config.equipment.missing_type: "<yellow>Issue found in file <arg:0> - The equipment '<arg:1>' is missing the required 'type' argument.</yellow>"
|
||||
|
||||
@@ -304,7 +304,7 @@ warning.config.loot_table.entry.item.missing_item: "<yellow>在文件 <arg:0>
|
||||
warning.config.loot_table.condition.missing_type: "<yellow>在文件 <arg:0> 发现问题 - '<arg:1>' 的战利品表配置错误 某个条件缺少必需的 'type' 参数</yellow>"
|
||||
warning.config.loot_table.condition.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - '<arg:1>' 的战利品表配置错误 某个条件使用了无效的条件类型 '<arg:2>'</yellow>"
|
||||
warning.config.host.missing_type: "<yellow>在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 缺少必需的 'type' 参数</yellow>"
|
||||
warning.config.host.invalid_type: "<yellow>在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 无效的托管类型 '' 请参考 https://mo-mi.gitbook.io/xiaomomi-plugins/craftengine/plugin-wiki/craftengine/resource-pack/host</yellow>"
|
||||
warning.config.host.invalid_type: "<yellow>在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 无效的托管类型 '<arg:0>' 请参考 https://mo-mi.gitbook.io/xiaomomi-plugins/craftengine/plugin-wiki/craftengine/resource-pack/host</yellow>"
|
||||
warning.config.host.external.missing_url: "<yellow>在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 外部托管缺少必需的 'url' 参数</yellow>"
|
||||
warning.config.host.alist.missing_api_url: "<yellow>在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - Alist 托管缺少必需的 'api-url' 参数</yellow>"
|
||||
warning.config.host.alist.missing_username: "<yellow>在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - Alist 托管缺少必需的 'username' 参数或环境变量 'CE_ALIST_USERNAME'</yellow>"
|
||||
@@ -390,8 +390,9 @@ warning.config.resource_pack.generation.missing_item_model: "<yellow>物品'<arg
|
||||
warning.config.resource_pack.generation.missing_block_model: "<yellow>方块状态'<arg:0>'缺少模型文件: '<arg:1>'</yellow>"
|
||||
warning.config.resource_pack.generation.missing_parent_model: "<yellow>模型'<arg:0>'找不到父级模型文件: '<arg:1>'</yellow>"
|
||||
warning.config.resource_pack.generation.malformatted_json: "<yellow>Json文件 '<arg:0>' 格式错误.</yellow>"
|
||||
warning.config.resource_pack.generation.missing_equipment_texture: "<yellow>装备 '<arg:0>' 缺少纹理 '<arg:1>'</yellow>"
|
||||
warning.config.resource_pack.invalid_overlay_format: "<yellow>在 config.yml 的 'resource-pack.overlay-format' 处发现问题 - 无效的overlay格式 '<arg:0>'. Overlay格式必须包含占位符 '{version}'.</yellow>"
|
||||
warning.config.equipment.duplicate: "<yellow>Issue found in file <arg:0> - Duplicated equipment '<arg:1>'. Please check if there is the same configuration in other files.</yellow>"
|
||||
warning.config.equipment.missing_type: "<yellow>Issue found in file <arg:0> - The equipment '<arg:1>' is missing the required 'type' argument.</yellow>"
|
||||
warning.config.equipment.invalid_type: "<yellow>Issue found in file <arg:0> - The equipment '<arg:1>' is using an invalid 'type' argument.</yellow>"
|
||||
warning.config.equipment.invalid_sacrificed_armor: "<yellow>Issue found in config.yml at 'equipment.sacrificed-vanilla-armor' - Invalid vanilla armor type '<arg:0>'.</yellow>"
|
||||
warning.config.equipment.duplicate: "<yellow>在文件 <arg:0> 发现问题 - 重复的装备配置 '<arg:1>'。请检查其他文件中是否存在相同配置</yellow>"
|
||||
warning.config.equipment.missing_type: "<yellow>在文件 <arg:0> 发现问题 - 装备 '<arg:1>' 缺少必需的 'type' 参数</yellow>"
|
||||
warning.config.equipment.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - 装备 '<arg:1>' 使用了无效的 'type' 参数</yellow>"
|
||||
warning.config.equipment.invalid_sacrificed_armor: "<yellow>在 config.yml 的 'equipment.sacrificed-vanilla-armor' 处发现问题 - 无效的原版盔甲类型 '<arg:0>'</yellow>"
|
||||
@@ -1,6 +1,5 @@
|
||||
package net.momirealms.craftengine.core.item;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
|
||||
import net.momirealms.craftengine.core.item.modifier.ItemDataModifier;
|
||||
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
|
||||
@@ -20,9 +19,7 @@ public abstract class AbstractCustomItem<I> implements CustomItem<I> {
|
||||
protected final Key material;
|
||||
protected final Key clientBoundMaterial;
|
||||
protected final ItemDataModifier<I>[] modifiers;
|
||||
protected final Map<String, ItemDataModifier<I>> modifierMap;
|
||||
protected final ItemDataModifier<I>[] clientBoundModifiers;
|
||||
protected final Map<String, ItemDataModifier<I>> clientBoundModifierMap;
|
||||
protected final List<ItemBehavior> behaviors;
|
||||
protected final ItemSettings settings;
|
||||
protected final Map<EventTrigger, List<Function<PlayerOptionalContext>>> events;
|
||||
@@ -44,13 +41,6 @@ public abstract class AbstractCustomItem<I> implements CustomItem<I> {
|
||||
this.clientBoundModifiers = clientBoundModifiers.toArray(new ItemDataModifier[0]);
|
||||
this.behaviors = List.copyOf(behaviors);
|
||||
this.settings = settings;
|
||||
ImmutableMap.Builder<String, ItemDataModifier<I>> modifierMapBuilder = ImmutableMap.builder();
|
||||
for (ItemDataModifier<I> modifier : modifiers) {
|
||||
modifierMapBuilder.put(modifier.name(), modifier);
|
||||
}
|
||||
this.modifierMap = modifierMapBuilder.build();
|
||||
ImmutableMap.Builder<String, ItemDataModifier<I>> clientSideModifierMapBuilder = ImmutableMap.builder();
|
||||
this.clientBoundModifierMap = clientSideModifierMapBuilder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -85,11 +75,6 @@ public abstract class AbstractCustomItem<I> implements CustomItem<I> {
|
||||
return this.modifiers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ItemDataModifier<I>> dataModifierMap() {
|
||||
return this.modifierMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasClientBoundDataModifier() {
|
||||
return this.clientBoundModifiers.length != 0;
|
||||
@@ -100,11 +85,6 @@ public abstract class AbstractCustomItem<I> implements CustomItem<I> {
|
||||
return this.clientBoundModifiers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ItemDataModifier<I>> clientBoundDataModifierMap() {
|
||||
return this.clientBoundModifierMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemSettings settings() {
|
||||
return this.settings;
|
||||
|
||||
@@ -4,9 +4,7 @@ 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.equipment.*;
|
||||
import net.momirealms.craftengine.core.item.modifier.*;
|
||||
import net.momirealms.craftengine.core.item.setting.EquipmentData;
|
||||
import net.momirealms.craftengine.core.pack.LoadingSequence;
|
||||
@@ -289,6 +287,17 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
|
||||
}
|
||||
}
|
||||
|
||||
public void addOrMergeEquipment(ComponentBasedEquipment equipment) {
|
||||
Equipment previous = this.equipments.get(equipment.assetId());
|
||||
if (previous instanceof ComponentBasedEquipment another) {
|
||||
for (Map.Entry<EquipmentLayerType, List<ComponentBasedEquipment.Layer>> entry : equipment.layers().entrySet()) {
|
||||
another.addLayer(entry.getKey(), entry.getValue());
|
||||
}
|
||||
} else {
|
||||
this.equipments.put(equipment.assetId(), equipment);
|
||||
}
|
||||
}
|
||||
|
||||
public class ItemParser implements ConfigParser {
|
||||
public static final String[] CONFIG_SECTION_NAME = new String[] {"items", "item"};
|
||||
|
||||
|
||||
@@ -25,14 +25,10 @@ public interface CustomItem<I> extends BuildableItem<I> {
|
||||
|
||||
ItemDataModifier<I>[] dataModifiers();
|
||||
|
||||
Map<String, ItemDataModifier<I>> dataModifierMap();
|
||||
|
||||
boolean hasClientBoundDataModifier();
|
||||
|
||||
ItemDataModifier<I>[] clientBoundDataModifiers();
|
||||
|
||||
Map<String, ItemDataModifier<I>> clientBoundDataModifierMap();
|
||||
|
||||
ItemSettings settings();
|
||||
|
||||
default boolean is(Key tag) {
|
||||
|
||||
@@ -320,6 +320,7 @@ public class ItemSettings {
|
||||
Map<String, Object> args = MiscUtils.castToMap(value, false);
|
||||
EquipmentData data = EquipmentData.fromMap(args);
|
||||
ComponentBasedEquipment componentBasedEquipment = ComponentBasedEquipment.FACTORY.create(data.assetId(), args);
|
||||
((AbstractItemManager<?>) CraftEngine.instance().itemManager()).addOrMergeEquipment(componentBasedEquipment);
|
||||
ItemEquipment itemEquipment = new ItemEquipment(Tristate.FALSE, data, componentBasedEquipment);
|
||||
return settings -> settings.equipment(itemEquipment);
|
||||
}));
|
||||
|
||||
@@ -11,7 +11,10 @@ import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.sparrow.nbt.CompoundTag;
|
||||
import net.momirealms.sparrow.nbt.Tag;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
|
||||
@@ -1188,74 +1188,7 @@ public abstract class AbstractPackManager implements PackManager {
|
||||
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().severe("Error creating " + equipmentPath.toAbsolutePath());
|
||||
return;
|
||||
}
|
||||
try {
|
||||
GsonHelper.writeJsonFile(equipmentJson, equipmentPath);
|
||||
} catch (IOException e) {
|
||||
this.plugin.logger().severe("Error writing equipment file", e);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
processComponentBasedEquipment(componentBasedEquipment, generatedPackPath);
|
||||
} else if (equipment instanceof TrimBasedEquipment trimBasedEquipment) {
|
||||
Key assetId = trimBasedEquipment.assetId();
|
||||
Pair<Boolean, Boolean> result = processTrimBasedEquipment(trimBasedEquipment, generatedPackPath);
|
||||
@@ -1423,6 +1356,77 @@ public abstract class AbstractPackManager implements PackManager {
|
||||
}
|
||||
}
|
||||
|
||||
private void processComponentBasedEquipment(ComponentBasedEquipment componentBasedEquipment, Path generatedPackPath) {
|
||||
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().severe("Error creating " + equipmentPath.toAbsolutePath());
|
||||
return;
|
||||
}
|
||||
try {
|
||||
GsonHelper.writeJsonFile(equipmentJson, equipmentPath);
|
||||
} catch (IOException e) {
|
||||
this.plugin.logger().severe("Error writing equipment file", e);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Pair<Boolean, Boolean> processTrimBasedEquipment(TrimBasedEquipment trimBasedEquipment, Path generatedPackPath) {
|
||||
Key assetId = trimBasedEquipment.assetId();
|
||||
@@ -1439,7 +1443,7 @@ public abstract class AbstractPackManager implements PackManager {
|
||||
.resolve("textures")
|
||||
.resolve(humanoidResourceLocation.value() + ".png");
|
||||
if (!Files.exists(texture) || !Files.isRegularFile(texture)) {
|
||||
// todo 说话
|
||||
TranslationManager.instance().log("warning.config.resource_pack.generation.missing_equipment_texture", assetId.asString(), texture.toString());
|
||||
return null;
|
||||
}
|
||||
boolean shouldPreserve = false;
|
||||
@@ -1498,7 +1502,7 @@ public abstract class AbstractPackManager implements PackManager {
|
||||
.resolve("textures")
|
||||
.resolve(humanoidLeggingsResourceLocation.value() + ".png");
|
||||
if (!Files.exists(texture) && !Files.isRegularFile(texture)) {
|
||||
// todo 说话
|
||||
TranslationManager.instance().log("warning.config.resource_pack.generation.missing_equipment_texture", assetId.asString(), texture.toString());
|
||||
return null;
|
||||
}
|
||||
boolean shouldPreserve = false;
|
||||
|
||||
@@ -77,17 +77,14 @@ public class AlistHost implements ResourcePackHost {
|
||||
}
|
||||
|
||||
private void readCacheFromDisk() {
|
||||
Path cachePath = CraftEngine.instance().dataFolderPath().resolve("alist.cache");
|
||||
if (!Files.exists(cachePath)) return;
|
||||
|
||||
Path cachePath = CraftEngine.instance().dataFolderPath().resolve("cache").resolve("alist.json");
|
||||
if (!Files.exists(cachePath) || !Files.isRegularFile(cachePath)) return;
|
||||
try (InputStream is = Files.newInputStream(cachePath)) {
|
||||
Map<String, String> cache = GsonHelper.get().fromJson(
|
||||
new InputStreamReader(is),
|
||||
new TypeToken<Map<String, String>>(){}.getType()
|
||||
);
|
||||
|
||||
this.cachedSha1 = cache.get("sha1");
|
||||
|
||||
CraftEngine.instance().logger().info("[Alist] Loaded cached resource pack metadata");
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().warn("[Alist] Failed to load cache " + cachePath, e);
|
||||
@@ -97,9 +94,9 @@ public class AlistHost implements ResourcePackHost {
|
||||
private void saveCacheToDisk() {
|
||||
Map<String, String> cache = new HashMap<>();
|
||||
cache.put("sha1", this.cachedSha1 != null ? this.cachedSha1 : "");
|
||||
|
||||
Path cachePath = CraftEngine.instance().dataFolderPath().resolve("alist.cache");
|
||||
Path cachePath = CraftEngine.instance().dataFolderPath().resolve("cache").resolve("alist.json");
|
||||
try {
|
||||
Files.createDirectories(cachePath.getParent());
|
||||
Files.writeString(
|
||||
cachePath,
|
||||
GsonHelper.get().toJson(cache),
|
||||
|
||||
@@ -49,18 +49,15 @@ public class DropboxHost implements ResourcePackHost {
|
||||
}
|
||||
|
||||
public void readCacheFromDisk() {
|
||||
Path cachePath = CraftEngine.instance().dataFolderPath().resolve("dropbox.cache");
|
||||
Path cachePath = CraftEngine.instance().dataFolderPath().resolve("cache").resolve("dropbox.json");
|
||||
if (!Files.exists(cachePath)) return;
|
||||
|
||||
try (InputStream is = Files.newInputStream(cachePath)) {
|
||||
JsonObject cache = GsonHelper.parseJsonToJsonObject(new String(is.readAllBytes(), StandardCharsets.UTF_8));
|
||||
|
||||
this.url = getString(cache, "url");
|
||||
this.sha1 = getString(cache, "sha1");
|
||||
this.refreshToken = getString(cache, "refresh_token");
|
||||
this.accessToken = getString(cache, "access_token");
|
||||
this.expiresAt = getLong(cache, "expires_at");
|
||||
|
||||
CraftEngine.instance().logger().info("[Dropbox] Loaded cached resource pack info");
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().warn("[Dropbox] Failed to load cache " + cachePath, e);
|
||||
@@ -74,9 +71,9 @@ public class DropboxHost implements ResourcePackHost {
|
||||
cache.addProperty("refresh_token", this.refreshToken);
|
||||
cache.addProperty("access_token", this.accessToken);
|
||||
cache.addProperty("expires_at", this.expiresAt);
|
||||
|
||||
Path cachePath = CraftEngine.instance().dataFolderPath().resolve("dropbox.cache");
|
||||
Path cachePath = CraftEngine.instance().dataFolderPath().resolve("cache").resolve("dropbox.json");
|
||||
try {
|
||||
Files.createDirectories(cachePath);
|
||||
Files.writeString(
|
||||
cachePath,
|
||||
GsonHelper.get().toJson(cache),
|
||||
|
||||
@@ -45,23 +45,19 @@ public class GitLabHost implements ResourcePackHost {
|
||||
}
|
||||
|
||||
public void readCacheFromDisk() {
|
||||
Path cachePath = CraftEngine.instance().dataFolderPath().resolve("gitlab.cache");
|
||||
if (!Files.exists(cachePath)) return;
|
||||
|
||||
Path cachePath = CraftEngine.instance().dataFolderPath().resolve("cache").resolve("gitlab.json");
|
||||
if (!Files.exists(cachePath) || !Files.isRegularFile(cachePath)) return;
|
||||
try (InputStream is = Files.newInputStream(cachePath)) {
|
||||
Map<String, String> cache = GsonHelper.get().fromJson(
|
||||
new InputStreamReader(is),
|
||||
new TypeToken<Map<String, String>>(){}.getType()
|
||||
);
|
||||
|
||||
this.url = cache.get("url");
|
||||
this.sha1 = cache.get("sha1");
|
||||
|
||||
String uuidString = cache.get("uuid");
|
||||
if (uuidString != null && !uuidString.isEmpty()) {
|
||||
this.uuid = UUID.fromString(uuidString);
|
||||
}
|
||||
|
||||
CraftEngine.instance().logger().info("[GitLab] Loaded cached resource pack info");
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().warn(
|
||||
@@ -74,9 +70,9 @@ public class GitLabHost implements ResourcePackHost {
|
||||
cache.put("url", this.url);
|
||||
cache.put("sha1", this.sha1);
|
||||
cache.put("uuid", this.uuid != null ? this.uuid.toString() : "");
|
||||
|
||||
Path cachePath = CraftEngine.instance().dataFolderPath().resolve("gitlab.cache");
|
||||
Path cachePath = CraftEngine.instance().dataFolderPath().resolve("cache").resolve("gitlab.json");
|
||||
try {
|
||||
Files.createDirectories(cachePath.getParent());
|
||||
Files.writeString(
|
||||
cachePath,
|
||||
GsonHelper.get().toJson(cache),
|
||||
|
||||
@@ -56,23 +56,19 @@ public class LobFileHost implements ResourcePackHost {
|
||||
}
|
||||
|
||||
public void readCacheFromDisk() {
|
||||
Path cachePath = CraftEngine.instance().dataFolderPath().resolve("lobfile.cache");
|
||||
if (!Files.exists(cachePath)) return;
|
||||
|
||||
Path cachePath = CraftEngine.instance().dataFolderPath().resolve("cache").resolve("lobfile.json");
|
||||
if (!Files.exists(cachePath) || !Files.isRegularFile(cachePath)) return;
|
||||
try (InputStream is = Files.newInputStream(cachePath)) {
|
||||
Map<String, String> cache = GsonHelper.get().fromJson(
|
||||
new InputStreamReader(is),
|
||||
new TypeToken<Map<String, String>>(){}.getType()
|
||||
);
|
||||
|
||||
this.url = cache.get("url");
|
||||
this.sha1 = cache.get("sha1");
|
||||
|
||||
String uuidString = cache.get("uuid");
|
||||
if (uuidString != null && !uuidString.isEmpty()) {
|
||||
this.uuid = UUID.fromString(uuidString);
|
||||
}
|
||||
|
||||
CraftEngine.instance().logger().info("[LobFile] Loaded cached resource pack info");
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().warn(
|
||||
@@ -85,9 +81,9 @@ public class LobFileHost implements ResourcePackHost {
|
||||
cache.put("url", this.url);
|
||||
cache.put("sha1", this.sha1);
|
||||
cache.put("uuid", this.uuid != null ? this.uuid.toString() : "");
|
||||
|
||||
Path cachePath = CraftEngine.instance().dataFolderPath().resolve("lobfile.cache");
|
||||
Path cachePath = CraftEngine.instance().dataFolderPath().resolve("cache").resolve("lobfile.json");
|
||||
try {
|
||||
Files.createDirectories(cachePath.getParent());
|
||||
Files.writeString(
|
||||
cachePath,
|
||||
GsonHelper.get().toJson(cache),
|
||||
|
||||
@@ -61,9 +61,8 @@ public class OneDriveHost implements ResourcePackHost {
|
||||
}
|
||||
|
||||
public void readCacheFromDisk() {
|
||||
Path cachePath = CraftEngine.instance().dataFolderPath().resolve("onedrive.cache");
|
||||
if (!Files.exists(cachePath)) return;
|
||||
|
||||
Path cachePath = CraftEngine.instance().dataFolderPath().resolve("cache").resolve("onedrive.json");
|
||||
if (!Files.exists(cachePath) || !Files.isRegularFile(cachePath)) return;
|
||||
try (InputStream is = Files.newInputStream(cachePath)) {
|
||||
Map<String, String> cache = GsonHelper.get().fromJson(
|
||||
new InputStreamReader(is),
|
||||
@@ -91,9 +90,9 @@ public class OneDriveHost implements ResourcePackHost {
|
||||
cache.put("refresh-token-expires-in", String.valueOf(this.refreshToken.right().getTime()));
|
||||
cache.put("sha1", this.sha1);
|
||||
cache.put("file-id", this.fileId);
|
||||
|
||||
Path cachePath = CraftEngine.instance().dataFolderPath().resolve("onedrive.cache");
|
||||
Path cachePath = CraftEngine.instance().dataFolderPath().resolve("cache").resolve("onedrive.json");
|
||||
try {
|
||||
Files.createDirectories(cachePath.getParent());
|
||||
Files.writeString(
|
||||
cachePath,
|
||||
GsonHelper.get().toJson(cache),
|
||||
|
||||
@@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G
|
||||
|
||||
# Project settings
|
||||
# Rule: [major update].[feature update].[bug fix]
|
||||
project_version=0.0.59.2
|
||||
project_version=0.0.59.3
|
||||
config_version=41
|
||||
lang_version=21
|
||||
project_group=net.momirealms
|
||||
|
||||
Reference in New Issue
Block a user