diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java index 5fc635efe..413fc8cb3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java @@ -1,7 +1,7 @@ package net.momirealms.craftengine.bukkit.block; import com.google.common.collect.ImmutableList; -import it.unimi.dsi.fastutil.ints.IntArrayList; +import net.momirealms.craftengine.bukkit.block.behavior.UnsafeCompositeBlockBehavior; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.injector.BlockGenerator; @@ -16,15 +16,18 @@ import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.bukkit.util.RegistryUtils; import net.momirealms.craftengine.bukkit.util.TagUtils; import net.momirealms.craftengine.core.block.*; +import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior; +import net.momirealms.craftengine.core.block.behavior.BlockBehaviors; import net.momirealms.craftengine.core.block.behavior.EmptyBlockBehavior; import net.momirealms.craftengine.core.block.parser.BlockStateParser; +import net.momirealms.craftengine.core.loot.LootTable; 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.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; +import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.plugin.logger.Debugger; -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.sound.SoundData; import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.world.chunk.PalettedContainer; @@ -61,7 +64,7 @@ public final class BukkitBlockManager extends AbstractBlockManager { super(plugin, RegistryUtils.currentBlockRegistrySize(), Config.serverSideBlocks()); this.plugin = plugin; this.registerServerSideCustomBlocks(Config.serverSideBlocks()); - this.registerEmptyBlock(); + EmptyBlock.initialize(); instance = this; } @@ -114,6 +117,21 @@ public final class BukkitBlockManager extends AbstractBlockManager { super.delayedLoad(); } + @Override + public BlockBehavior createBlockBehavior(CustomBlock customBlock, List> behaviorConfig) { + if (behaviorConfig == null || behaviorConfig.isEmpty()) { + return new EmptyBlockBehavior(); + } else if (behaviorConfig.size() == 1) { + return BlockBehaviors.fromMap(customBlock, behaviorConfig.getFirst()); + } else { + List behaviors = new ArrayList<>(); + for (Map config : behaviorConfig) { + behaviors.add((AbstractBlockBehavior) BlockBehaviors.fromMap(customBlock, config)); + } + return new UnsafeCompositeBlockBehavior(customBlock, behaviors); + } + } + @Override protected void resendTags() { // if there's no change @@ -258,17 +276,6 @@ public final class BukkitBlockManager extends AbstractBlockManager { BlockRegistryMirror.init(states, new BukkitBlockStateWrapper(MBlocks.STONE$defaultState, BlockStateUtils.blockStateToId(MBlocks.STONE$defaultState))); } - private void registerEmptyBlock() { - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.BLOCK).registerForHolder(ResourceKey.create(BuiltInRegistries.BLOCK.key().location(), Key.withDefaultNamespace("empty"))); - EmptyBlock emptyBlock = new EmptyBlock(Key.withDefaultNamespace("empty"), holder); - holder.bindValue(emptyBlock); - } - - @Override - protected CustomBlock.Builder platformBuilder(Key id) { - return BukkitCustomBlock.builder(id); - } - // 注册服务端侧的真实方块 private void registerServerSideCustomBlocks(int count) { // 这个会影响全局调色盘 @@ -379,6 +386,14 @@ public final class BukkitBlockManager extends AbstractBlockManager { return this.vanillaBlockStateCount; } + @Override + protected CustomBlock createCustomBlock(@NotNull Holder.Reference holder, + @NotNull BlockStateVariantProvider variantProvider, + @NotNull Map>> events, + @Nullable LootTable lootTable) { + return new BukkitCustomBlock(holder, variantProvider, events, lootTable); + } + public boolean isOpenableBlockSoundRemoved(Object blockOwner) { return false; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java index b831a0cde..360e121ad 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java @@ -1,139 +1,27 @@ package net.momirealms.craftengine.bukkit.block; -import net.momirealms.craftengine.bukkit.block.behavior.UnsafeCompositeBlockBehavior; -import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MFluids; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries; -import net.momirealms.craftengine.bukkit.util.BlockStateUtils; -import net.momirealms.craftengine.bukkit.util.KeyUtils; -import net.momirealms.craftengine.bukkit.util.SoundUtils; -import net.momirealms.craftengine.core.block.*; -import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior; -import net.momirealms.craftengine.core.block.behavior.BlockBehaviors; -import net.momirealms.craftengine.core.block.behavior.EmptyBlockBehavior; -import net.momirealms.craftengine.core.block.properties.Property; +import net.momirealms.craftengine.core.block.AbstractCustomBlock; +import net.momirealms.craftengine.core.block.BlockStateVariantProvider; +import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.loot.LootTable; -import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.plugin.context.function.Function; -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.*; -import org.bukkit.Bukkit; -import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.List; +import java.util.Map; public final class BukkitCustomBlock extends AbstractCustomBlock { - private BukkitCustomBlock( - @NotNull Key id, + public BukkitCustomBlock( @NotNull Holder.Reference holder, - @NotNull Map> properties, - @NotNull Map appearances, - @NotNull Map variantMapper, - @NotNull BlockSettings settings, + @NotNull BlockStateVariantProvider variantProvider, @NotNull Map>> events, - @Nullable List> behavior, @Nullable LootTable lootTable ) { - super(id, holder, properties, appearances, variantMapper, settings, events, behavior, lootTable); - } - - @Override - protected BlockBehavior setupBehavior(List> behaviorConfig) { - if (behaviorConfig == null || behaviorConfig.isEmpty()) { - return new EmptyBlockBehavior(); - } else if (behaviorConfig.size() == 1) { - return BlockBehaviors.fromMap(this, behaviorConfig.getFirst()); - } else { - List behaviors = new ArrayList<>(); - for (Map config : behaviorConfig) { - behaviors.add((AbstractBlockBehavior) BlockBehaviors.fromMap(this, config)); - } - return new UnsafeCompositeBlockBehavior(this, behaviors); - } - } - - @SuppressWarnings("unchecked") - @Nullable - @Override - public LootTable lootTable() { - return (LootTable) super.lootTable(); - } - - public static Builder builder(Key id) { - return new BuilderImpl(id); - } - - public static class BuilderImpl implements Builder { - protected final Key id; - protected Map> properties; - protected Map appearances; - protected Map variantMapper; - protected BlockSettings settings; - protected List> behavior; - protected LootTable lootTable; - protected Map>> events; - - public BuilderImpl(Key id) { - this.id = id; - } - - @Override - public Builder events(Map>> events) { - this.events = events; - return this; - } - - @Override - public Builder appearances(Map appearances) { - this.appearances = appearances; - return this; - } - - @Override - public Builder behavior(List> behavior) { - this.behavior = behavior; - return this; - } - - @Override - public Builder lootTable(LootTable lootTable) { - this.lootTable = lootTable; - return this; - } - - @Override - public Builder properties(Map> properties) { - this.properties = properties; - return this; - } - - @Override - public Builder settings(BlockSettings settings) { - this.settings = settings; - return this; - } - - @Override - public Builder variantMapper(Map variantMapper) { - this.variantMapper = variantMapper; - return this; - } - - @Override - public @NotNull CustomBlock build() { - // create or get block holder - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.BLOCK).getOrRegisterForHolder(ResourceKey.create(BuiltInRegistries.BLOCK.key().location(), this.id)); - return new BukkitCustomBlock(this.id, holder, this.properties, this.appearances, this.variantMapper, this.settings, this.events, this.behavior, this.lootTable); - } + super(holder, variantProvider, events, lootTable); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java index a71c46f64..f8cb7dfcb 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java @@ -23,6 +23,7 @@ import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.pack.PendingConfigSection; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.context.ContextHolder; @@ -232,6 +233,15 @@ public class BlockItemBehavior extends BlockBoundItemBehavior { return this.blockId; } + static void addPendingSection(Pack pack, Path path, String node, Key key, Map map) { + if (map.containsKey(key.toString())) { + // 防呆 + BukkitBlockManager.instance().blockParser().addPendingConfigSection(new PendingConfigSection(pack, path, node, key, MiscUtils.castToMap(map.get(key.toString()), false))); + } else { + BukkitBlockManager.instance().blockParser().addPendingConfigSection(new PendingConfigSection(pack, path, node, key, MiscUtils.castToMap(map, false))); + } + } + public static class Factory implements ItemBehaviorFactory { @Override public ItemBehavior create(Pack pack, Path path, String node, Key key, Map arguments) { @@ -240,12 +250,7 @@ public class BlockItemBehavior extends BlockBoundItemBehavior { throw new LocalizedResourceConfigException("warning.config.item.behavior.block.missing_block", new IllegalArgumentException("Missing required parameter 'block' for block_item behavior")); } if (id instanceof Map map) { - if (map.containsKey(key.toString())) { - // 防呆 - BukkitBlockManager.instance().blockParser().parseSection(pack, path, node, key, MiscUtils.castToMap(map.get(key.toString()), false)); - } else { - BukkitBlockManager.instance().blockParser().parseSection(pack, path, node, key, MiscUtils.castToMap(map, false)); - } + addPendingSection(pack, path, node, key, map); return new BlockItemBehavior(key); } else { return new BlockItemBehavior(Key.of(id.toString())); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java index 403d8eea3..7ad5a1bed 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java @@ -9,6 +9,7 @@ import net.momirealms.craftengine.core.block.UpdateOption; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.pack.PendingConfigSection; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; @@ -43,15 +44,10 @@ public class DoubleHighBlockItemBehavior extends BlockItemBehavior { public ItemBehavior create(Pack pack, Path path, String node, Key key, Map arguments) { Object id = arguments.get("block"); if (id == null) { - throw new LocalizedResourceConfigException("warning.config.item.behavior.double_high.missing_block", new IllegalArgumentException("Missing required parameter 'block' for double_high_block_item behavior")); + throw new LocalizedResourceConfigException("warning.config.item.behavior.double_high.missing_block"); } if (id instanceof Map map) { - if (map.containsKey(key.toString())) { - // 防呆 - BukkitBlockManager.instance().blockParser().parseSection(pack, path, node, key, MiscUtils.castToMap(map.get(key.toString()), false)); - } else { - BukkitBlockManager.instance().blockParser().parseSection(pack, path, node, key, MiscUtils.castToMap(map, false)); - } + addPendingSection(pack, path, node, key, map); return new DoubleHighBlockItemBehavior(key); } else { return new DoubleHighBlockItemBehavior(Key.of(id.toString())); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/WallBlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/WallBlockItemBehavior.java index 8f8232d4f..6e46af6cd 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/WallBlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/WallBlockItemBehavior.java @@ -41,12 +41,7 @@ public class WallBlockItemBehavior extends BlockItemBehavior { throw new LocalizedResourceConfigException("warning.config.item.behavior.wall_block.missing_block", new IllegalArgumentException("Missing required parameter 'block' for wall_block_item behavior")); } if (id instanceof Map map) { - if (map.containsKey(key.toString())) { - // 防呆 - BukkitBlockManager.instance().blockParser().parseSection(pack, path, node, key, MiscUtils.castToMap(map.get(key.toString()), false)); - } else { - BukkitBlockManager.instance().blockParser().parseSection(pack, path, node, key, MiscUtils.castToMap(map, false)); - } + addPendingSection(pack, path, node, key, map); return new WallBlockItemBehavior(key); } else { return new WallBlockItemBehavior(Key.of(id.toString())); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugAppearanceStateUsageCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugAppearanceStateUsageCommand.java index ce6029653..2192b12d4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugAppearanceStateUsageCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugAppearanceStateUsageCommand.java @@ -1,26 +1,10 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.event.HoverEvent; -import net.kyori.adventure.text.format.NamedTextColor; -import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; -import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; -import net.momirealms.craftengine.core.util.Key; import org.bukkit.command.CommandSender; -import org.checkerframework.checker.nullness.qual.NonNull; import org.incendo.cloud.Command; -import org.incendo.cloud.context.CommandContext; -import org.incendo.cloud.context.CommandInput; -import org.incendo.cloud.parser.standard.StringParser; -import org.incendo.cloud.suggestion.Suggestion; -import org.incendo.cloud.suggestion.SuggestionProvider; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; public class DebugAppearanceStateUsageCommand extends BukkitCommandFeature { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugRealStateUsageCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugRealStateUsageCommand.java index 04b7d0ce2..d30863b8c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugRealStateUsageCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugRealStateUsageCommand.java @@ -1,26 +1,10 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.event.HoverEvent; -import net.kyori.adventure.text.format.NamedTextColor; -import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; -import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; -import net.momirealms.craftengine.core.util.Key; import org.bukkit.command.CommandSender; -import org.checkerframework.checker.nullness.qual.NonNull; import org.incendo.cloud.Command; -import org.incendo.cloud.context.CommandContext; -import org.incendo.cloud.context.CommandInput; -import org.incendo.cloud.parser.standard.StringParser; -import org.incendo.cloud.suggestion.Suggestion; -import org.incendo.cloud.suggestion.SuggestionProvider; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; public class DebugRealStateUsageCommand extends BukkitCommandFeature { diff --git a/common-files/src/main/resources/resources/internal/configuration/gui.yml b/common-files/src/main/resources/resources/internal/configuration/gui.yml index 42c53dee6..344d37d55 100644 --- a/common-files/src/main/resources/resources/internal/configuration/gui.yml +++ b/common-files/src/main/resources/resources/internal/configuration/gui.yml @@ -74,6 +74,7 @@ images: templates: internal:icon/2d: material: arrow + custom-model-data: ${model_data} data: item-name: ${name} lore: ${lore} @@ -92,6 +93,7 @@ items: internal:next_page_0: template: internal:icon/2d arguments: + model_data: 1000 texture: next_page_0 name: <#FAFAD2> lore: @@ -99,6 +101,7 @@ items: internal:next_page_1: template: internal:icon/2d arguments: + model_data: 1001 texture: next_page_1 name: <#808080> lore: @@ -106,6 +109,7 @@ items: internal:previous_page_0: template: internal:icon/2d arguments: + model_data: 1002 texture: previous_page_0 name: <#FAFAD2> lore: @@ -113,6 +117,7 @@ items: internal:previous_page_1: template: internal:icon/2d arguments: + model_data: 1003 texture: previous_page_1 name: <#808080> lore: @@ -120,29 +125,34 @@ items: internal:return: template: internal:icon/2d arguments: + model_data: 1004 texture: return name: <#DAA520> lore: null internal:next_recipe_0: material: arrow + custom-model-data: 1000 data: item-name: <#FAFAD2> lore: - <#F5F5F5>/ internal:next_recipe_1: material: arrow + custom-model-data: 1001 data: item-name: <#808080> lore: - <#696969>/ internal:previous_recipe_0: material: arrow + custom-model-data: 1002 data: item-name: <#FAFAD2> lore: - <#F5F5F5>/ internal:previous_recipe_1: material: arrow + custom-model-data: 1003 data: item-name: <#808080> lore: @@ -150,6 +160,7 @@ items: internal:get_item: template: internal:icon/2d arguments: + model_data: 1005 texture: get_item name: <#DAA520> lore: @@ -158,6 +169,7 @@ items: internal:cooking_info: template: internal:icon/2d arguments: + model_data: 1006 texture: cooking_info name: <#FF8C00> lore: @@ -166,6 +178,7 @@ items: internal:exit: template: internal:icon/2d arguments: + model_data: 1007 texture: exit name: <#DAA520> lore: null \ No newline at end of file diff --git a/common-files/src/main/resources/translations/de.yml b/common-files/src/main/resources/translations/de.yml index 4e28bf879..1513a684b 100644 --- a/common-files/src/main/resources/translations/de.yml +++ b/common-files/src/main/resources/translations/de.yml @@ -184,7 +184,7 @@ warning.config.item.invalid_material: "Problem in Datei gefunden warning.config.item.invalid_custom_model_data: "Problem in Datei gefunden - Das Item '' verwendet eine negative Custom-Model-Data '', was ungültig ist." warning.config.item.bad_custom_model_data: "Problem in Datei gefunden - Das Item '' verwendet eine Custom-Model-Data '', die zu groß ist. Es wird empfohlen, einen Wert unter 16.777.216 zu verwenden." warning.config.item.item_model.conflict: "Problem in Datei gefunden - Das Item '' verwendet eine ungültige 'item-model'-Option, da dieses Item-Model bereits von einem Vanilla-Item belegt ist." -warning.config.item.custom_model_data_conflict: "Problem in Datei gefunden - Das Item '' verwendet eine Custom-Model-Data '', die bereits von Item '' belegt ist." +warning.config.item.custom_model_data.conflict: "Problem in Datei gefunden - Das Item '' verwendet eine Custom-Model-Data '', die bereits von Item '' belegt ist." warning.config.item.invalid_component: "Problem in Datei gefunden - Das Item '' verwendet einen nicht existierenden Component-Typ ''." warning.config.item.missing_model_id: "Problem in Datei gefunden - Beim Item '' fehlt das erforderliche 'custom-model-data'- oder 'item-model'-Argument." warning.config.item.missing_model: "Problem in Datei gefunden - Beim Item '' fehlt der erforderliche 'model'-Abschnitt für die Unterstützung von Resource Packs ab 1.21.4+." @@ -252,18 +252,15 @@ warning.config.block.state.property.missing_type: "Problem in Datei Problem in Datei gefunden - Der Block '' verwendet das ungültige Typ-Argument '' für die Property ''." warning.config.block.state.property.integer.invalid_range: "Problem in Datei gefunden - Der Block '' verwendet das ungültige 'range'-Argument '' für die Integer-Property ''. Korrekte Syntax: 1~2." warning.config.block.state.property.invalid_format: "Problem in Datei gefunden - Der Block '' verwendet ein ungültiges Block-State-Property-Format ''." -warning.config.block.state.missing_real_id: "Problem in Datei gefunden - Beim Block '' fehlt das erforderliche 'id'-Argument für 'state'. 'id' ist die serverseitige Block-ID, die für jeden Block-State-Typ eindeutig ist. Wenn du einen serverseitigen Block mit 'note_block' und ID 30 erstellst, wäre die echte Block-ID 'craftengine:note_block_30'." warning.config.block.state.missing_state: "Problem in Datei gefunden - Beim Block '' fehlt das erforderliche 'state'-Argument für 'state'." warning.config.block.state.missing_properties: "Problem in Datei gefunden - Beim Block '' fehlt der erforderliche 'properties'-Abschnitt für 'states'." warning.config.block.state.missing_appearances: "Problem in Datei gefunden - Beim Block '' fehlt der erforderliche 'appearances'-Abschnitt für 'states'." warning.config.block.state.missing_variants: "Problem in Datei gefunden - Beim Block '' fehlt der erforderliche 'variants'-Abschnitt für 'states'." -warning.config.block.state.variant.missing_appearance: "Problem in Datei gefunden - Beim Block '' fehlt das erforderliche 'appearance'-Argument für die Variante ''." warning.config.block.state.variant.invalid_appearance: "Problem in Datei gefunden - Der Block '' hat einen Fehler, dass die Variante '' eine nicht existierende Appearance '' verwendet." warning.config.block.state.invalid_vanilla: "Problem in Datei gefunden - Der Block '' verwendet einen ungültigen Vanilla-Block-State ''." warning.config.block.state.unavailable_vanilla: "Problem in Datei gefunden - Der Block '' verwendet einen nicht verfügbaren Vanilla-Block-State ''. Bitte gib diesen State in der mappings.yml frei." warning.config.block.state.invalid_vanilla_id: "Problem in Datei gefunden - Der Block '' verwendet einen Vanilla-Block-State '', der den verfügbaren Slot-Bereich '0~' überschreitet." -warning.config.block.state.conflict: "Problem in Datei gefunden - Der Block '' verwendet einen Vanilla-Block-State '', der bereits von '' belegt ist." -warning.config.block.state.bind_failed: "Problem in Datei gefunden - Der Block '' konnte den echten Block-State für '' nicht binden, da der State bereits von '' belegt ist." +warning.config.block.state.id.conflict: "Problem in Datei gefunden - Der Block '' konnte den echten Block-State für '' nicht binden, da der State bereits von '' belegt ist." warning.config.block.state.model.missing_path: "Problem in Datei gefunden - Beim Block '' fehlt die erforderliche 'path'-Option für 'model'." warning.config.block.state.model.invalid_path: "Problem in Datei gefunden - Der Block '' hat ein 'path'-Argument '', das ungültige Zeichen enthält. Bitte lies https://minecraft.wiki/w/Resource_location#Legal_characters." warning.config.block.state.model.conflict: "Problem in Datei gefunden - Der Block '' versucht, das Model '' an den Block-State '' zu binden, der bereits an das Model '' gebunden ist." diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index eaf5c8740..652e823a8 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -192,8 +192,8 @@ warning.config.item.invalid_material: "Issue found in file - The warning.config.item.invalid_custom_model_data: "Issue found in file - The item '' is using a negative custom model data '' which is invalid." warning.config.item.bad_custom_model_data: "Issue found in file - The item '' is using a custom model data '' that is too large. It's recommended to use a value lower than 16,777,216." warning.config.item.item_model.conflict: "Issue found in file - The item '' is using an invalid 'item-model' option because this item model has been occupied by a vanilla item." -warning.config.item.custom_model_data_conflict: "Issue found in file - The item '' is using a custom model data '' that has been occupied by item ''." -warning.config.item.custom_model_data_exhausted: "Issue found in file - Cannot allocate custom model data for item '' as the custom model data has already been exhausted." +warning.config.item.custom_model_data.conflict: "Issue found in file - The item '' is using a custom model data '' that has been occupied by item ''." +warning.config.item.custom_model_data.exhausted: "Issue found in file - Cannot allocate custom model data for item '' as the custom model data has already been exhausted." warning.config.item.invalid_component: "Issue found in file - The item '' is using a non-existing component type ''." warning.config.item.missing_model_id: "Issue found in file - The item '' is missing the required 'custom-model-data' or 'item-model' argument." warning.config.item.missing_model: "Issue found in file - The item '' is missing the required 'model' section for 1.21.4+ resource pack support." @@ -264,7 +264,6 @@ warning.config.block.state.property.missing_type: "Issue found in file < warning.config.block.state.property.invalid_type: "Issue found in file - The block '' is using the invalid type argument '' for property ''." warning.config.block.state.property.integer.invalid_range: "Issue found in file - The block '' is using the invalid 'range' argument '' for integer property ''. Correct syntax: 1~2." warning.config.block.state.property.invalid_format: "Issue found in file - The block '' is using an invalid block state property format ''." -warning.config.block.state.missing_real_id: "Issue found in file - The block '' is missing the required 'id' argument for 'state'. 'id' is the serverside block id which is unique for each type of block state. If you create a serverside side block with 'note_block' and id 30, then the real block id would be 'craftengine:note_block_30'." warning.config.block.state.missing_state: "Issue found in file - The block '' is missing the required 'state' argument for 'state'." warning.config.block.state.missing_properties: "Issue found in file - The block '' is missing the required 'properties' section for 'states'." warning.config.block.state.missing_appearances: "Issue found in file - The block '' is missing the required 'appearances' section for 'states'." @@ -274,14 +273,13 @@ warning.config.block.state.entity_renderer.item_display.missing_item: "I warning.config.block.state.entity_renderer.text_display.missing_text: "Issue found in file - The block '' is missing the required 'text' argument for 'text_display' entity renderer." warning.config.block.state.entity_renderer.better_model.missing_model: "Issue found in file - The block '' is missing the required 'model' argument for 'better_model' entity renderer." warning.config.block.state.entity_renderer.model_engine.missing_model: "Issue found in file - The block '' is missing the required 'model' argument for 'model_engine' entity renderer." -warning.config.block.state.variant.missing_appearance: "Issue found in file - The block '' is missing the required 'appearance' argument for variant ''." warning.config.block.state.variant.invalid_appearance: "Issue found in file - The block '' has an error that the variant '' is using a non-existing appearance ''." warning.config.block.state.invalid_vanilla: "Issue found in file - The block '' is using an invalid vanilla block state ''." warning.config.block.state.unavailable_vanilla: "Issue found in file - The block '' is using an unavailable vanilla block state ''. Please free that state in mappings.yml." warning.config.block.state.invalid_vanilla_id: "Issue found in file - The block '' is using a vanilla block state '' that exceeds the available slot range '0~'." -warning.config.block.state.conflict: "Issue found in file - The block '' is using a vanilla block state '' that has been occupied by ''." -warning.config.block.state.bind_failed: "Issue found in file - The block '' failed to bind real block state '' for '' as the state has been occupied by ''." -warning.config.block.state.invalid_real_id: "Issue found in file - The block '' is using a real block state '' that exceeds the available slot range '0~'. Consider adding more serverside blocks in 'config.yml' if the slots are used up." +warning.config.block.state.invalid_id: "Issue found in file - The block state ID range () used by block '' is outside the valid range of 0 to . Please add more server-side blocks in 'config.yml' if the current slots are exhausted." +warning.config.block.state.id.conflict: "Issue found in file - The block '' failed to bind real block state '' for '' as the state has been occupied by ''." +warning.config.block.state.id.exhausted: "Issue found in file - Cannot allocate enough real block state for block ''. Please add more server-side blocks in 'config.yml' and restart if the current slots are exhausted." warning.config.block.state.model.missing_path: "Issue found in file - The block '' is missing the required 'path' option for 'model'." warning.config.block.state.model.invalid_path: "Issue found in file - The block '' has a 'path' argument '' that contains illegal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters." warning.config.block.state.model.conflict: "Issue found in file - The block '' is trying to bind model '' to block state '' which has already been bound to model ''" diff --git a/common-files/src/main/resources/translations/es.yml b/common-files/src/main/resources/translations/es.yml index 0429bbb86..d65bc899a 100644 --- a/common-files/src/main/resources/translations/es.yml +++ b/common-files/src/main/resources/translations/es.yml @@ -121,7 +121,7 @@ warning.config.item.settings.unknown: "Problema encontrado en el archivo warning.config.item.missing_material: "Problema encontrado en el archivo - El objeto '' carece del argumento requerido 'material'." warning.config.item.invalid_material: "Problema encontrado en el archivo - El objeto '' está usando un tipo de material inválido ''." warning.config.item.bad_custom_model_data: "Problema encontrado en el archivo - El objeto '' está usando un dato de modelo personalizado demasiado grande ''. Se recomienda usar un valor menor a 16.777.216." -warning.config.item.custom_model_data_conflict: "Problema encontrado en el archivo - El objeto '' está usando un dato de modelo personalizado '' que está ocupado por el objeto ''." +warning.config.item.custom_model_data.conflict: "Problema encontrado en el archivo - El objeto '' está usando un dato de modelo personalizado '' que está ocupado por el objeto ''." warning.config.item.missing_model_id: "Problema encontrado en el archivo - El objeto '' carece del argumento requerido 'custom-model-data' o 'item-model'." warning.config.item.behavior.missing_type: "Problema encontrado en el archivo - El objeto '' carece del argumento requerido 'type' para el comportamiento del objeto." warning.config.item.behavior.invalid_type: "Problema encontrado en el archivo - El objeto '' está usando un tipo de comportamiento de objeto inválido ''." @@ -175,18 +175,15 @@ warning.config.block.state.property.missing_type: "Problema encontrado e warning.config.block.state.property.invalid_type: "Problema encontrado en el archivo - El bloque '' está usando un argumento 'type' inválido '' para la propiedad ''." warning.config.block.state.property.integer.invalid_range: "Problema encontrado en el archivo - El bloque '' está usando un argumento 'range' inválido '' para la propiedad entero ''. Sintaxis correcta: 1~2." warning.config.block.state.property.invalid_format: "Problema encontrado en el archivo - El bloque '' está usando un formato de propiedad de estado de bloque inválido ''." -warning.config.block.state.missing_real_id: "Problema encontrado en el archivo - El bloque '' carece del argumento requerido 'id' para 'state'. 'id' es el id de bloque del lado del servidor que es único para cada tipo de estado de bloque. Si creas un bloque del lado del servidor con 'note_block' e id 30, el id de bloque real será 'craftengine:note_block_30'." warning.config.block.state.missing_state: "Problema encontrado en el archivo - El bloque '' carece del argumento requerido 'state' para 'state'." warning.config.block.state.missing_properties: "Problema encontrado en el archivo - El bloque '' carece de la sección requerida 'properties' para 'states'." warning.config.block.state.missing_appearances: "Problema encontrado en el archivo - El bloque '' carece de la sección requerida 'appearances' para 'states'." warning.config.block.state.missing_variants: "Problema encontrado en el archivo - El bloque '' carece de la sección requerida 'variants' para 'states'." -warning.config.block.state.variant.missing_appearance: "Problema encontrado en el archivo - El bloque '' carece del argumento requerido 'appearance' para la variante ''." warning.config.block.state.variant.invalid_appearance: "Problema encontrado en el archivo - Hay un error en el bloque '' donde la variante '' está usando una apariencia inexistente ''." warning.config.block.state.invalid_vanilla: "Problema encontrado en el archivo - El bloque '' está usando un estado de bloque vanilla inválido ''." warning.config.block.state.unavailable_vanilla: "Problema encontrado en el archivo - El bloque '' está usando un estado de bloque vanilla no disponible ''. Por favor libera este estado en el archivo mappings.yml." warning.config.block.state.invalid_vanilla_id: "Problema encontrado en el archivo - El bloque '' está usando un estado de bloque vanilla '' que excede el rango de slots disponible '0~'." -warning.config.block.state.conflict: "Problema encontrado en el archivo - El bloque '' está usando un estado de bloque vanilla '' que está ocupado por ''." -warning.config.block.state.bind_failed: "Problema encontrado en el archivo - El bloque '' falló al vincular el estado de bloque real para '' porque está ocupado por el estado ''." +warning.config.block.state.id.conflict: "Problema encontrado en el archivo - El bloque '' falló al vincular el estado de bloque real para '' porque está ocupado por el estado ''." warning.config.block.state.model.missing_path: "Problema encontrado en el archivo - El bloque '' carece de la opción requerida 'path' para 'model'." warning.config.block.state.model.invalid_path: "Problema encontrado en el archivo - El bloque '' tiene un argumento 'path' '' que contiene caracteres prohibidos. Por favor lee https://minecraft.wiki/w/Resource_location#Legal_characters" warning.config.block.settings.unknown: "Problema encontrado en el archivo - El bloque '' está usando un tipo de configuración desconocido ''." diff --git a/common-files/src/main/resources/translations/ru_ru.yml b/common-files/src/main/resources/translations/ru_ru.yml index dcb624e7a..be8170d1a 100644 --- a/common-files/src/main/resources/translations/ru_ru.yml +++ b/common-files/src/main/resources/translations/ru_ru.yml @@ -161,7 +161,7 @@ warning.config.item.missing_material: "Проблема найдена warning.config.item.invalid_material: "Проблема найдена в файле - Предмет '' использует недопустимый тип материала ''." warning.config.item.invalid_custom_model_data: "Проблема найдена в файле - Предмет '' использует отрицательные данные пользовательской модели '', что недействительно." warning.config.item.bad_custom_model_data: "Проблема найдена в файле - Предмет '' использует пользовательскую модель данных '', которая имеет слишком большое значение. Рекомендуется использовать значение ниже 16,777,216." -warning.config.item.custom_model_data_conflict: "Проблема найдена в файле - Предмет '' использует пользовательскую модель данных '', которая занята элементом ''." +warning.config.item.custom_model_data.conflict: "Проблема найдена в файле - Предмет '' использует пользовательскую модель данных '', которая занята элементом ''." warning.config.item.invalid_component: "Проблема найдена в файле - Предмет '' использует несуществующий тип компонента ''." warning.config.item.missing_model_id: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'custom-model-data' или 'item-model' аргумент." warning.config.item.missing_model: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'model' раздел для поддержки пакета ресурсов 1.21.4+." @@ -225,18 +225,15 @@ warning.config.block.state.property.missing_type: "Проблема на warning.config.block.state.property.invalid_type: "Проблема найдена в файле - Блок '' использует недопустимый аргумент типа '' для свойства ''." warning.config.block.state.property.integer.invalid_range: "Проблема найдена в файле - Блок '' использует недействительный 'range' аргумент '' для integer свойства ''. Правильный синтаксис: 1~2." warning.config.block.state.property.invalid_format: "Проблема найдена в файле - Блок '' имеет недействительный формат свойства состояния блока ''." -warning.config.block.state.missing_real_id: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'id' аргумент для 'state'. 'id' это идентификатор блока на стороне сервера, который уникален для каждого типа состояния блока. Если вы создаете блок на стороне сервера с 'note_block' и идентификатор 30, тогда реальный идентификатор блока будет 'craftengine:note_block_30'." warning.config.block.state.missing_state: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'state' аргумент для 'state'." warning.config.block.state.missing_properties: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'properties' раздел для 'states'." warning.config.block.state.missing_appearances: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'appearances' раздел для 'states'." warning.config.block.state.missing_variants: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'variants' раздел для 'states'." -warning.config.block.state.variant.missing_appearance: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'appearance' аргумент для варианта ''." warning.config.block.state.variant.invalid_appearance: "Проблема найдена в файле - Блок '' имеет ошибку, что вариант '' использует несуществующий внешний вид ''." warning.config.block.state.invalid_vanilla: "Проблема найдена в файле - Блок '' имеет недействительное состояние ванильного блока ''." warning.config.block.state.unavailable_vanilla: "Проблема найдена в файле - Блок '' использует недоступное состояние ванильного блока ''. Пожалуйста, освободите это состояние в mappings.yml." warning.config.block.state.invalid_vanilla_id: "Проблема найдена в файле - Блок '' использует состояние ванильного блока '', что превышает доступный диапазон слотов '0~'." -warning.config.block.state.conflict: "Проблема найдена в файле - Блок '' использует состояние ванильного блока '' которое занято ''." -warning.config.block.state.bind_failed: "Проблема найдена в файле - Блоку '' не удалось привязать реальное состояние блока для '', так как состояние занято ''." +warning.config.block.state.id.conflict: "Проблема найдена в файле - Блоку '' не удалось привязать реальное состояние блока для '', так как состояние занято ''." warning.config.block.state.model.missing_path: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'path' опция для 'model'." warning.config.block.state.model.invalid_path: "Проблема найдена в файле - Блок '' имеет 'path' аргумент '' содержит недопустимые символы. Пожалуйста, прочтите https://minecraft.wiki/w/Resource_location#Legal_characters." warning.config.block.settings.unknown: "Проблема найдена в файле - Блок '' использует неизвестный тип настройки ''." diff --git a/common-files/src/main/resources/translations/tr.yml b/common-files/src/main/resources/translations/tr.yml index e5b79c186..d283b67c1 100644 --- a/common-files/src/main/resources/translations/tr.yml +++ b/common-files/src/main/resources/translations/tr.yml @@ -120,7 +120,7 @@ warning.config.item.settings.unknown: " dosyasında sorun bulundu warning.config.item.missing_material: " dosyasında sorun bulundu - '' eşyası gerekli 'material' argümanı eksik." warning.config.item.invalid_material: " dosyasında sorun bulundu - '' eşyası geçersiz bir malzeme türü '' kullanıyor." warning.config.item.bad_custom_model_data: " dosyasında sorun bulundu - '' eşyası çok büyük bir özel model verisi '' kullanıyor. 16.777.216'dan düşük bir değer kullanmanız önerilir." -warning.config.item.custom_model_data_conflict: " dosyasında sorun bulundu - '' eşyası, '' eşyası tarafından işgal edilmiş bir özel model verisi '' kullanıyor." +warning.config.item.custom_model_data.conflict: " dosyasında sorun bulundu - '' eşyası, '' eşyası tarafından işgal edilmiş bir özel model verisi '' kullanıyor." warning.config.item.missing_model_id: " dosyasında sorun bulundu - '' eşyası gerekli 'custom-model-data' veya 'item-model' argümanı eksik." warning.config.item.behavior.missing_type: " dosyasında sorun bulundu - '' eşyası, eşya davranışı için gerekli 'type' argümanı eksik." warning.config.item.behavior.invalid_type: " dosyasında sorun bulundu - '' eşyası geçersiz bir eşya davranış türü '' kullanıyor." @@ -173,18 +173,15 @@ warning.config.block.state.property.missing_type: " dosyasında s warning.config.block.state.property.invalid_type: " dosyasında sorun bulundu - '' bloğu, '' özelliği için geçersiz bir 'type' argümanı '' kullanıyor." warning.config.block.state.property.integer.invalid_range: " dosyasında sorun bulundu - '' bloğu, '' tamsayı özelliği için geçersiz bir 'range' argümanı '' kullanıyor. Doğru sözdizimi: 1~2." warning.config.block.state.property.invalid_format: " dosyasında sorun bulundu - '' bloğu, geçersiz bir blok durum özelliği formatı '' kullanıyor." -warning.config.block.state.missing_real_id: " dosyasında sorun bulundu - '' bloğu, 'state' için gerekli 'id' argümanı eksik. 'id', her blok durumu türü için benzersiz olan sunucu tarafı blok kimliğidir. 'note_block' ve id 30 ile bir sunucu tarafı blok oluşturursanız, gerçek blok kimliği 'craftengine:note_block_30' olur." warning.config.block.state.missing_state: " dosyasında sorun bulundu - '' bloğu, 'state' için gerekli 'state' argümanı eksik." warning.config.block.state.missing_properties: " dosyasında sorun bulundu - '' bloğu, 'states' için gerekli 'properties' bölümü eksik." warning.config.block.state.missing_appearances: " dosyasında sorun bulundu - '' bloğu, 'states' için gerekli 'appearances' bölümü eksik." warning.config.block.state.missing_variants: " dosyasında sorun bulundu - '' bloğu, 'states' için gerekli 'variants' bölümü eksik." -warning.config.block.state.variant.missing_appearance: " dosyasında sorun bulundu - '' bloğu, '' varyantı için gerekli 'appearance' argümanı eksik." warning.config.block.state.variant.invalid_appearance: " dosyasında sorun bulundu - '' bloğunda, '' varyantının var olmayan bir görünüm '' kullandığı bir hata var." warning.config.block.state.invalid_vanilla: " dosyasında sorun bulundu - '' bloğu geçersiz bir vanilya blok durumu '' kullanıyor." warning.config.block.state.unavailable_vanilla: " dosyasında sorun bulundu - '' bloğu kullanılamayan bir vanilya blok durumu '' kullanıyor. Lütfen bu durumu mappings.yml dosyasında serbest bırakın." warning.config.block.state.invalid_vanilla_id: " dosyasında sorun bulundu - '' bloğu, mevcut yuva aralığı '0~' aşan bir vanilya blok durumu '' kullanıyor." -warning.config.block.state.conflict: " dosyasında sorun bulundu - '' bloğu, '' tarafından işgal edilmiş bir vanilya blok durumu '' kullanıyor." -warning.config.block.state.bind_failed: " dosyasında sorun bulundu - '' bloğu, durum '' tarafından işgal edildiği için '' için gerçek blok durumu bağlamada başarısız oldu." +warning.config.block.state.id.conflict: " dosyasında sorun bulundu - '' bloğu, durum '' tarafından işgal edildiği için '' için gerçek blok durumu bağlamada başarısız oldu." warning.config.block.state.model.missing_path: " dosyasında sorun bulundu - '' bloğu, 'model' için gerekli 'path' seçeneği eksik." warning.config.block.state.model.invalid_path: " dosyasında sorun bulundu - '' bloğunun, yasak karakterler içeren bir 'path' argümanı '' var. Lütfen https://minecraft.wiki/w/Resource_location#Legal_characters sayfasını okuyun." warning.config.block.settings.unknown: " dosyasında sorun bulundu - '' bloğu bilinmeyen bir ayar türü '' kullanıyor." diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 56720fb27..04bea5c58 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -192,7 +192,7 @@ warning.config.item.invalid_material: "在文件 发现问题 - warning.config.item.invalid_custom_model_data: "在文件 发现问题 - 物品 '' 使用了无效的负数模型值 ''" warning.config.item.bad_custom_model_data: "在文件 发现问题 - 物品 '' 使用的自定义模型数据 '' 数值过大 建议使用小于 16,777,216 的值" warning.config.item.item_model.conflict: "在文件 发现问题 - 物品 '' 使用了无效的 'item-model' 选项. 这个 item-model 已经存在对应的原版物品" -warning.config.item.custom_model_data_conflict: "在文件 发现问题 - 物品 '' 使用的自定义模型数据 '' 已被物品 '' 占用" +warning.config.item.custom_model_data.conflict: "在文件 发现问题 - 物品 '' 使用的自定义模型数据 '' 已被物品 '' 占用" warning.config.item.invalid_component: "在文件 发现问题 - 物品 '' 使用了未知的数据组件 ''" warning.config.item.missing_model_id: "在文件 发现问题 - 物品 '' 缺少必需的 'custom-model-data' 或 'item-model' 参数" warning.config.item.missing_model: "在文件 中发现问题 - 物品 '' 缺少支持 1.21.4+ 资源包必需的 'model' 配置项" @@ -260,19 +260,16 @@ warning.config.block.state.property.missing_type: "在文件 发 warning.config.block.state.property.invalid_type: "在文件 发现问题 - 方块 '' 的属性 '' 使用了无效的类型参数 ''" warning.config.block.state.property.integer.invalid_range: "在文件 发现问题 - 方块 '' 的整数属性 '' 使用了无效的范围参数 '' 正确语法: 1~2" warning.config.block.state.property.invalid_format: "在文件 发现问题 - 方块 '' 使用了无效的方块状态属性格式 ''" -warning.config.block.state.missing_real_id: "在文件 发现问题 - 方块 '' 的 'state' 缺少必需的 'id' 参数 该 ID 是服务端方块 ID 用于唯一标识每种方块状态类型" warning.config.block.state.missing_state: "在文件 发现问题 - 方块 '' 的 'state' 缺少必需的 'state' 参数" warning.config.block.state.missing_properties: "在文件 发现问题 - 方块 '' 的 'states' 缺少必需的 'properties' 段落" warning.config.block.state.missing_appearances: "在文件 发现问题 - 方块 '' 的 'states' 缺少必需的 'appearances' 段落" warning.config.block.state.missing_variants: "在文件 发现问题 - 方块 '' 的 'states' 缺少必需的 'variants' 段落" -warning.config.block.state.variant.missing_appearance: "在文件 发现问题 - 方块 '' 的变体 '' 缺少必需的 'appearance' 参数" warning.config.block.state.variant.invalid_appearance: "在文件 发现问题 - 方块 '' 的变体 '' 使用了不存在的 appearance ''" warning.config.block.state.invalid_vanilla: "在文件 发现问题 - 方块 '' 使用了无效的原版方块状态 ''" warning.config.block.state.unavailable_vanilla: "在文件 发现问题 - 方块 '' 使用了不可用的原版方块状态 '' 请在 mappings.yml 中释放该状态" warning.config.block.state.invalid_vanilla_id: "在文件 发现问题 - 方块 '' 使用的原版方块状态 '' 超出可用槽位范围 '0~'" -warning.config.block.state.conflict: "在文件 发现问题 - 方块 '' 使用的原版方块状态 '' 已被 '' 占用" -warning.config.block.state.bind_failed: "在文件 发现问题 - 方块 '' 无法为 '' 绑定真实方块状态 '' 因该状态已被 '' 占用" -warning.config.block.state.invalid_real_id: "在文件 发现问题 - 方块 '' 使用的真实方块状态 '' 超出可用槽位范围 '0~' 如果槽位已用尽 请在 config.yml 中添加更多服务端侧方块" +warning.config.block.state.id.conflict: "在文件 发现问题 - 方块 '' 无法为 '' 绑定真实方块状态 '' 因该状态已被 '' 占用" +warning.config.block.state.invalid_id: "在文件 发现问题 - 方块 '' 使用的真实方块状态 '' 超出可用槽位范围 '0~' 如果槽位已用尽 请在 config.yml 中添加更多服务端侧方块" warning.config.block.state.model.missing_path: "在文件 发现问题 - 方块 '' 的 'model' 缺少必需的 'path' 选项" warning.config.block.state.model.invalid_path: "在文件 发现问题 - 方块 '' 的 'path' 参数 '' 包含非法字符 请参考 https://zh.minecraft.wiki/w/%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4ID#%E5%90%88%E6%B3%95%E5%AD%97%E7%AC%A6" warning.config.block.state.model.conflict: "在文件 发现问题 - 方块 '' 正尝试将模型 '' 绑定到方块状态 '' 上, 但是此状态已绑定了另一个模型 ''" diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java index 9cb662404..bd39b0a59 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java @@ -1,32 +1,54 @@ package net.momirealms.craftengine.core.block; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Maps; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; +import net.momirealms.craftengine.core.block.behavior.EntityBlockBehavior; import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement; import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfig; import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfigs; +import net.momirealms.craftengine.core.block.parser.BlockNbtParser; import net.momirealms.craftengine.core.block.properties.Properties; import net.momirealms.craftengine.core.block.properties.Property; +import net.momirealms.craftengine.core.item.AbstractItemManager; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.pack.PendingConfigSection; import net.momirealms.craftengine.core.pack.ResourceLocation; +import net.momirealms.craftengine.core.pack.cache.IdAllocator; import net.momirealms.craftengine.core.pack.model.generation.AbstractModelGenerator; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.plugin.config.*; +import net.momirealms.craftengine.core.plugin.config.Config; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; +import net.momirealms.craftengine.core.plugin.config.IdSectionConfigParser; +import net.momirealms.craftengine.core.plugin.config.SectionConfigParser; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.event.EventFunctions; +import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; +import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.plugin.logger.Debugger; +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.*; +import net.momirealms.sparrow.nbt.CompoundTag; import org.incendo.cloud.suggestion.Suggestion; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.IOException; import java.nio.file.Path; import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import java.util.function.Predicate; public abstract class AbstractBlockManager extends AbstractModelGenerator implements BlockManager { @@ -50,6 +72,8 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem protected final Map soundReplacements = new HashMap<>(512, 0.5f); // 用于note_block:0这样格式的自动分配 protected final Map> blockStateArranger = new HashMap<>(); + // 根据registry id找note_block:x中的x值 + protected final Map reversedBlockStateArranger = new HashMap<>(); // 全方块状态映射文件,用于网络包映射 protected final int[] blockStateMappings; // 原版方块状态数量 @@ -103,6 +127,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem this.byId.clear(); this.soundReplacements.clear(); this.blockStateArranger.clear(); + this.reversedBlockStateArranger.clear(); this.appearanceToRealState.clear(); Arrays.fill(this.blockStateMappings, -1); Arrays.fill(this.immutableBlockStates, EmptyBlock.STATE); @@ -125,20 +150,12 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem return Optional.ofNullable(this.byId.get(id)); } - protected void addBlockInternal(Key id, CustomBlock customBlock) { - ExceptionCollector exceptionCollector = new ExceptionCollector<>(); + protected void addBlockInternal(CustomBlock customBlock) { // 绑定外观状态等 for (ImmutableBlockState state : customBlock.variantProvider().states()) { int internalId = state.customBlockState().registryId(); int appearanceId = state.vanillaBlockState().registryId(); int index = internalId - this.vanillaBlockStateCount; - ImmutableBlockState previous = this.immutableBlockStates[index]; - // todo 应当提前判断位置 - if (previous != null && !previous.isEmpty()) { - exceptionCollector.add(new LocalizedResourceConfigException("warning.config.block.state.bind_failed", - state.toString(), previous.toString(), getBlockOwnerId(previous.customBlockState()).toString())); - continue; - } this.immutableBlockStates[index] = state; this.blockStateMappings[internalId] = appearanceId; this.appearanceToRealState.computeIfAbsent(appearanceId, k -> new IntArrayList()).add(internalId); @@ -147,8 +164,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem this.modBlockStateOverrides.put(getBlockOwnerId(state.customBlockState()), this.tempVanillaBlockStateModels.get(appearanceId)); } } - this.byId.put(id, customBlock); - exceptionCollector.throwIfPresent(); + this.byId.put(customBlock.id(), customBlock); } @Override @@ -210,17 +226,22 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem return Optional.ofNullable(this.appearanceToRealState.get(appearanceStateId)).orElse(List.of()); } + public abstract BlockBehavior createBlockBehavior(CustomBlock customBlock, List> behaviorConfig); + protected abstract void resendTags(); protected abstract boolean isVanillaBlock(Key id); protected abstract Key getBlockOwnerId(int id); - protected abstract CustomBlock.Builder platformBuilder(Key id); - protected abstract void setVanillaBlockTags(Key id, List tags); - public abstract int vanillaBlockStateCount(); + protected abstract int vanillaBlockStateCount(); + + protected abstract CustomBlock createCustomBlock(@NotNull Holder.Reference holder, + @NotNull BlockStateVariantProvider variantProvider, + @NotNull Map>> events, + @Nullable LootTable lootTable); public class BlockStateMappingParser implements SectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[]{"block-state-mappings", "block-state-mapping"}; @@ -261,7 +282,9 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem continue; } AbstractBlockManager.this.blockStateMappings[beforeState.registryId()] = afterState.registryId(); - AbstractBlockManager.this.blockStateArranger.computeIfAbsent(getBlockOwnerId(beforeState), k -> new ArrayList<>()).add(afterState); + List blockStateWrappers = AbstractBlockManager.this.blockStateArranger.computeIfAbsent(getBlockOwnerId(beforeState), k -> new ArrayList<>()); + blockStateWrappers.add(beforeState); + AbstractBlockManager.this.reversedBlockStateArranger.put(beforeState.registryId(), blockStateWrappers.size() - 1); } exceptionCollector.throwIfPresent(); } @@ -269,6 +292,63 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem public class BlockParser implements IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[]{"blocks", "block"}; + private final IdAllocator internalIdAllocator; + private final Map appearanceIdAllocators = new HashMap<>(); + private final List pendingConfigSections = new ArrayList<>(); + + public BlockParser() { + this.internalIdAllocator = new IdAllocator(AbstractBlockManager.this.plugin.dataFolderPath().resolve("cache").resolve("custom-block-states.json")); + } + + public void addPendingConfigSection(PendingConfigSection section) { + this.pendingConfigSections.add(section); + } + + @Override + public void postProcess() { + this.internalIdAllocator.processPendingAllocations(); + try { + this.internalIdAllocator.saveToCache(); + } catch (IOException e) { + AbstractBlockManager.this.plugin.logger().warn("Error while saving custom block state allocation", e); + } + } + + @Override + public void preProcess() { + this.internalIdAllocator.reset(0, Config.serverSideBlocks() - 1); + try { + this.internalIdAllocator.loadFromCache(); + } catch (IOException e) { + AbstractBlockManager.this.plugin.logger().warn("Error while loading custom block state allocation cache", e); + } + for (PendingConfigSection section : this.pendingConfigSections) { + ResourceConfigUtils.runCatching( + section.path(), + section.node(), + () -> parseSection(section.pack(), section.path(), section.node(), section.id(), section.config()), + () -> GsonHelper.get().toJson(section.config()) + ); + } + this.pendingConfigSections.clear(); + } + + @Nullable + public IdAllocator getOrCreateAppearanceIdAllocator(Key type) { + if (!AbstractBlockManager.this.blockStateArranger.containsKey(type)) { + return null; + } + return this.appearanceIdAllocators.computeIfAbsent(type, k -> { + IdAllocator newAllocator = new IdAllocator(plugin.dataFolderPath().resolve("cache").resolve("visual-block-states").resolve(k.value() + ".json")); + newAllocator.reset(0, AbstractBlockManager.this.blockStateArranger.get(type).size()); + try { + newAllocator.loadFromCache(); + } catch (IOException e) { + AbstractBlockManager.this.plugin.logger().warn("Error while loading visual block states cache for block " + k.asString(), e); + } + return newAllocator; + }); + } @Override public String[] sectionId() { @@ -289,7 +369,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem if (AbstractBlockManager.this.byId.containsKey(id)) { throw new LocalizedResourceConfigException("warning.config.block.duplicate"); } - parseCustomBlock(id, section); + parseCustomBlock(path, node, id, section); } } @@ -304,86 +384,171 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem } } - private void parseCustomBlock(Key id, Map section) { - // 获取方块设置 + private void parseCustomBlock(Path path, String node, Key id, Map section) { + // 获取共享方块设置 BlockSettings settings = BlockSettings.fromMap(id, MiscUtils.castToMap(section.get("settings"), true)); - // 读取基础外观配置 - Map> properties; - Map appearances; - Map variants; // 读取states区域 - Map stateSection = MiscUtils.castToMap(ResourceConfigUtils.requireNonNullOrThrow( - ResourceConfigUtils.get(section, "state", "states"), "warning.config.block.missing_state"), true); + Map stateSection = MiscUtils.castToMap(ResourceConfigUtils.requireNonNullOrThrow(ResourceConfigUtils.get(section, "state", "states"), "warning.config.block.missing_state"), true); boolean singleState = !stateSection.containsKey("properties"); - // 单方块状态 - if (singleState) { - int internalId = ResourceConfigUtils.getAsInt(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("id"), "warning.config.block.state.missing_real_id"), "id"); - // 获取原版外观的注册表id - BlockStateWrapper appearanceState = parsePluginFormattedBlockState(ResourceConfigUtils.requireNonEmptyStringOrThrow(stateSection.get("state"), "warning.config.block.state.missing_state")); - Optional[]> blockEntityRenderer = parseBlockEntityRender(stateSection.get("entity-renderer")); - // 为原版外观赋予外观模型并检查模型冲突 - this.arrangeModelForStateAndVerify(appearanceState, ResourceConfigUtils.get(stateSection, "model", "models")); - // 设置参数 - properties = Map.of(); - appearances = Map.of("", new BlockStateAppearance(appearanceState, blockEntityRenderer)); - variants = Map.of("", new BlockStateVariant("", settings, getInternalBlockState(internalId))); - } - // 多方块状态 - else { - properties = parseBlockProperties(ResourceConfigUtils.getAsMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("properties"), "warning.config.block.state.missing_properties"), "properties")); - appearances = parseBlockAppearances(ResourceConfigUtils.getAsMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("appearances"), "warning.config.block.state.missing_appearances"), "appearances")); - variants = parseBlockVariants( - ResourceConfigUtils.getAsMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("variants"), "warning.config.block.state.missing_variants"), "variants"), - appearances::containsKey, settings - ); - } + // 读取方块的property,通过property决定 + Map> properties = singleState ? Map.of() : parseBlockProperties(ResourceConfigUtils.getAsMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("properties"), "warning.config.block.state.missing_properties"), "properties")); + // 注册方块容器 + Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.BLOCK).getOrRegisterForHolder(ResourceKey.create(BuiltInRegistries.BLOCK.key().location(), id)); - addBlockInternal(id, platformBuilder(id) - .appearances(appearances) - .variantMapper(variants) - .properties(properties) - .settings(settings) - .lootTable(LootTable.fromMap(ResourceConfigUtils.getAsMapOrNull(section.get("loot"), "loot"))) - .behavior(MiscUtils.getAsMapList(ResourceConfigUtils.get(section, "behavior", "behaviors"))) - .events(EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event"))) - .build()); - } + // 根据properties生成variant provider + BlockStateVariantProvider variantProvider = new BlockStateVariantProvider(holder, (owner, propertyMap) -> { + ImmutableBlockState blockState = new ImmutableBlockState(owner, propertyMap); + blockState.setSettings(settings); + return blockState; + }, properties); - private Map parseBlockVariants(Map variantsSection, - Predicate appearanceValidator, - BlockSettings parentSettings) { - Map variants = new HashMap<>(); - for (Map.Entry entry : variantsSection.entrySet()) { - Map variantSection = ResourceConfigUtils.getAsMap(entry.getValue(), entry.getKey()); - String variantNBT = entry.getKey(); - String appearance = ResourceConfigUtils.requireNonEmptyStringOrThrow(variantSection.get("appearance"), "warning.config.block.state.variant.missing_appearance"); - if (!appearanceValidator.test(appearance)) { - throw new LocalizedResourceConfigException("warning.config.block.state.variant.invalid_appearance", variantNBT, appearance); + ImmutableList states = variantProvider.states(); + List> internalIdAllocators = new ArrayList<>(states.size()); + + // 如果用户指定了起始id + if (stateSection.containsKey("id")) { + int startingId = ResourceConfigUtils.getAsInt(stateSection.get("id"), "id"); + int endingId = startingId + states.size() - 1; + if (startingId < 0 || endingId >= Config.serverSideBlocks()) { + throw new LocalizedResourceConfigException("warning.config.block.state.invalid_id", startingId + "~" + endingId, String.valueOf(Config.serverSideBlocks() - 1)); + } + // 先检测范围冲突 + List> conflicts = this.internalIdAllocator.getFixedIdsBetween(startingId, endingId); + if (!conflicts.isEmpty()) { + ExceptionCollector exceptionCollector = new ExceptionCollector<>(); + for (Pair conflict : conflicts) { + int internalId = conflict.right(); + int index = internalId - startingId; + exceptionCollector.add(new LocalizedResourceConfigException("warning.config.block.state.id.conflict", states.get(index).toString(), conflict.left(), BlockManager.createCustomBlockKey(internalId).toString())); + } + exceptionCollector.throwIfPresent(); + } + // 强行分配id + for (ImmutableBlockState blockState : states) { + String blockStateId = blockState.toString(); + internalIdAllocators.add(this.internalIdAllocator.assignFixedId(blockStateId, startingId++)); + } + } + // 未指定,则使用自动分配 + else { + for (ImmutableBlockState blockState : states) { + String blockStateId = blockState.toString(); + internalIdAllocators.add(this.internalIdAllocator.requestAutoId(blockStateId)); } - BlockStateWrapper internalBlockState = getInternalBlockState(ResourceConfigUtils.getAsInt(ResourceConfigUtils.requireNonNullOrThrow(variantSection.get("id"), "warning.config.block.state.missing_real_id"), "id")); - Map anotherSetting = ResourceConfigUtils.getAsMapOrNull(variantSection.get("settings"), "settings"); - variants.put(variantNBT, new BlockStateVariant(appearance, anotherSetting == null ? parentSettings : BlockSettings.ofFullCopy(parentSettings, anotherSetting), internalBlockState)); } - return variants; - } - private BlockStateWrapper getInternalBlockState(int internalId) { - if (internalId >= Config.serverSideBlocks()) { - throw new LocalizedResourceConfigException("warning.config.block.state.invalid_real_id", BlockManager.createCustomBlockKey(internalId).asString(), String.valueOf(Config.serverSideBlocks() - 1)); - } - return BlockRegistryMirror.byId(internalId + vanillaBlockStateCount()); - } + CompletableFutures.allOf(internalIdAllocators).thenRun(() -> ResourceConfigUtils.runCatching(path, node, () -> { + for (int i = 0; i < internalIdAllocators.size(); i++) { + CompletableFuture future = internalIdAllocators.get(i); + try { + int internalId = future.get(); + states.get(i).setCustomBlockState(BlockRegistryMirror.byId(internalId + AbstractBlockManager.this.vanillaBlockStateCount)); + } catch (ExecutionException e) { + Throwable cause = e.getCause(); + // 这里不会有conflict了,因为之前已经判断过了 + if (cause instanceof IdAllocator.IdExhaustedException) { + throw new LocalizedResourceConfigException("warning.config.block.state.id.exhausted"); + } else { + Debugger.BLOCK.warn(() -> "Unknown error while allocating internal block state id.", cause); + return; + } + } catch (InterruptedException e) { + AbstractBlockManager.this.plugin.logger().warn("Interrupted while parsing allocating internal block state", e); + return; + } + } - private Map parseBlockAppearances(Map appearancesSection) { - Map appearances = new HashMap<>(); - for (Map.Entry entry : appearancesSection.entrySet()) { - Map appearanceSection = ResourceConfigUtils.getAsMap(entry.getValue(), entry.getKey()); - BlockStateWrapper appearanceId = parsePluginFormattedBlockState(ResourceConfigUtils.requireNonEmptyStringOrThrow( - appearanceSection.get("state"), "warning.config.block.state.missing_state")); - this.arrangeModelForStateAndVerify(appearanceId, ResourceConfigUtils.get(appearanceSection, "model", "models")); - appearances.put(entry.getKey(), new BlockStateAppearance(appearanceId, parseBlockEntityRender(appearanceSection.get("entity-renderer")))); - } - return appearances; + // 创建自定义方块 + AbstractCustomBlock customBlock = (AbstractCustomBlock) createCustomBlock( + holder, + variantProvider, + EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event")), + LootTable.fromMap(ResourceConfigUtils.getAsMapOrNull(section.get("loot"), "loot")) + ); + BlockBehavior blockBehavior = createBlockBehavior(customBlock, MiscUtils.getAsMapList(ResourceConfigUtils.get(section, "behavior", "behaviors"))); + customBlock.setBehavior(blockBehavior); + holder.bindValue(customBlock); + + // 单状态 + if (singleState) { + BlockStateWrapper appearanceState = parsePluginFormattedBlockState(ResourceConfigUtils.requireNonEmptyStringOrThrow(stateSection.get("state"), "warning.config.block.state.missing_state")); + this.arrangeModelForStateAndVerify(appearanceState, ResourceConfigUtils.get(stateSection, "model", "models")); + ImmutableBlockState onlyState = states.getFirst(); + // 为唯一的状态绑定外观 + onlyState.setVanillaBlockState(appearanceState); + parseBlockEntityRender(stateSection.get("entity-renderer")).ifPresent(onlyState::setConstantRenderers); + } else { + BlockStateWrapper anyAppearanceState = null; + Map appearancesSection = ResourceConfigUtils.getAsMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("appearances"), "warning.config.block.state.missing_appearances"), "appearances"); + // 也不能为空 + if (appearancesSection.isEmpty()) { + throw new LocalizedResourceConfigException("warning.config.block.state.missing_appearances"); + } + Map appearances = Maps.newHashMap(); + // 先解析所有的外观 + for (Map.Entry entry : appearancesSection.entrySet()) { + Map appearanceSection = ResourceConfigUtils.getAsMap(entry.getValue(), entry.getKey()); + // 解析对应的视觉方块 + BlockStateWrapper appearanceState = parsePluginFormattedBlockState(ResourceConfigUtils.requireNonEmptyStringOrThrow(appearanceSection.get("state"), "warning.config.block.state.missing_state")); + this.arrangeModelForStateAndVerify(appearanceState, ResourceConfigUtils.get(appearanceSection, "model", "models")); + appearances.put(entry.getKey(), new BlockStateAppearance(appearanceState, parseBlockEntityRender(appearanceSection.get("entity-renderer")))); + if (anyAppearanceState == null) { + anyAppearanceState = appearanceState; + } + } + // 解析变体 + Map variantsSection = ResourceConfigUtils.getAsMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("variants"), "warning.config.block.state.missing_variants"), "variants"); + for (Map.Entry entry : variantsSection.entrySet()) { + Map variantSection = ResourceConfigUtils.getAsMap(entry.getValue(), entry.getKey()); + String variantNBT = entry.getKey(); + // 先解析nbt,找到需要修改的方块状态 + CompoundTag tag = BlockNbtParser.deserialize(variantProvider, variantNBT); + if (tag == null) { + throw new LocalizedResourceConfigException("warning.config.block.state.property.invalid_format", variantNBT); + } + List possibleStates = variantProvider.getPossibleStates(tag); + Map anotherSetting = ResourceConfigUtils.getAsMapOrNull(variantSection.get("settings"), "settings"); + if (anotherSetting != null) { + for (ImmutableBlockState possibleState : possibleStates) { + possibleState.setSettings(BlockSettings.ofFullCopy(possibleState.settings(), anotherSetting)); + } + } + String appearanceName = ResourceConfigUtils.getAsString(variantSection.get("appearance")); + if (appearanceName != null) { + BlockStateAppearance appearance = appearances.get(appearanceName); + if (appearance == null) { + throw new LocalizedResourceConfigException("warning.config.block.state.variant.invalid_appearance", variantNBT, appearanceName); + } + for (ImmutableBlockState possibleState : possibleStates) { + possibleState.setVanillaBlockState(appearance.blockState()); + appearance.blockEntityRenderer().ifPresent(possibleState::setConstantRenderers); + } + } + } + // 为没有外观的方块状态填充 + for (ImmutableBlockState blockState : states) { + if (blockState.vanillaBlockState() == null) { + blockState.setVanillaBlockState(anyAppearanceState); + } + } + } + + // 获取方块实体行为 + EntityBlockBehavior entityBlockBehavior = blockBehavior.getEntityBehavior(); + boolean isEntityBlock = entityBlockBehavior != null; + + // 绑定行为 + for (ImmutableBlockState blockState : states) { + blockState.setBehavior(blockBehavior); + if (isEntityBlock) { + blockState.setBlockEntityType(entityBlockBehavior.blockEntityType()); + } + } + + // 添加方块 + addBlockInternal(customBlock); + + }, () -> GsonHelper.get().toJson(section))); } @SuppressWarnings("unchecked") diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java index d62c103d8..298de8ccd 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java @@ -1,9 +1,6 @@ package net.momirealms.craftengine.core.block; -import com.google.common.collect.ImmutableMap; import net.momirealms.craftengine.core.block.behavior.EmptyBlockBehavior; -import net.momirealms.craftengine.core.block.behavior.EntityBlockBehavior; -import net.momirealms.craftengine.core.block.parser.BlockNbtParser; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.loot.LootTable; @@ -11,7 +8,6 @@ import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.plugin.context.function.Function; -import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; import net.momirealms.sparrow.nbt.CompoundTag; @@ -23,79 +19,31 @@ import java.util.*; import java.util.function.BiFunction; public abstract class AbstractCustomBlock implements CustomBlock { - protected final Holder holder; - protected final Key id; + protected final Holder.Reference holder; protected final BlockStateVariantProvider variantProvider; - protected final Map> properties; - protected final BlockBehavior behavior; protected final BiFunction placementFunction; protected final ImmutableBlockState defaultState; protected final Map>> events; @Nullable protected final LootTable lootTable; + protected BlockBehavior behavior = EmptyBlockBehavior.INSTANCE; protected AbstractCustomBlock( - @NotNull Key id, @NotNull Holder.Reference holder, - @NotNull Map> properties, - @NotNull Map appearances, - @NotNull Map variantMapper, - @NotNull BlockSettings settings, + @NotNull BlockStateVariantProvider variantProvider, @NotNull Map>> events, - @Nullable List> behaviorConfig, @Nullable LootTable lootTable ) { - holder.bindValue(this); this.holder = holder; - this.id = id; this.lootTable = lootTable; - this.properties = ImmutableMap.copyOf(properties); this.events = events; - this.variantProvider = new BlockStateVariantProvider(holder, ImmutableBlockState::new, properties); + this.variantProvider = variantProvider; this.defaultState = this.variantProvider.getDefaultState(); - this.behavior = setupBehavior(behaviorConfig); List> placements = new ArrayList<>(4); - for (Map.Entry> propertyEntry : this.properties.entrySet()) { + for (Map.Entry> propertyEntry : this.variantProvider.properties().entrySet()) { placements.add(Property.createStateForPlacement(propertyEntry.getKey(), propertyEntry.getValue())); } this.placementFunction = composite(placements); - EntityBlockBehavior entityBlockBehavior = this.behavior.getEntityBehavior(); - boolean isEntityBlock = entityBlockBehavior != null; - - for (Map.Entry entry : variantMapper.entrySet()) { - String nbtString = entry.getKey(); - CompoundTag tag = BlockNbtParser.deserialize(this, nbtString); - if (tag == null) { - throw new LocalizedResourceConfigException("warning.config.block.state.property.invalid_format", nbtString); - } - List possibleStates = this.getPossibleStates(tag); - if (possibleStates.size() != 1) { - throw new LocalizedResourceConfigException("warning.config.block.state.property.invalid_format", nbtString); - } - BlockStateVariant blockStateVariant = entry.getValue(); - BlockStateAppearance blockStateAppearance = appearances.get(blockStateVariant.appearance()); - // Late init states - ImmutableBlockState state = possibleStates.getFirst(); - state.setSettings(blockStateVariant.settings()); - state.setVanillaBlockState(blockStateAppearance.blockState()); - state.setCustomBlockState(blockStateVariant.blockState()); - blockStateAppearance.blockEntityRenderer().ifPresent(state::setConstantRenderers); - } - - // double check if there's any invalid state - for (ImmutableBlockState state : this.variantProvider().states()) { - state.setBehavior(this.behavior); - if (state.settings() == null) { - state.setSettings(settings); - } - if (isEntityBlock) { - state.setBlockEntityType(entityBlockBehavior.blockEntityType()); - } - } - } - - protected BlockBehavior setupBehavior(List> behaviorConfig) { - return EmptyBlockBehavior.INSTANCE; } private static BiFunction composite(List> placements) { @@ -137,28 +85,16 @@ public abstract class AbstractCustomBlock implements CustomBlock { @NotNull @Override public final Key id() { - return this.id; + return this.holder.key().location(); + } + + public void setBehavior(@Nullable BlockBehavior behavior) { + this.behavior = behavior; } @Override public List getPossibleStates(CompoundTag nbt) { - List tempStates = new ArrayList<>(); - tempStates.add(defaultState()); - for (Property property : this.variantProvider.getDefaultState().getProperties()) { - Tag value = nbt.get(property.name()); - if (value != null) { - tempStates.replaceAll(immutableBlockState -> ImmutableBlockState.with(immutableBlockState, property, property.unpack(value))); - } else { - List newStates = new ArrayList<>(); - for (ImmutableBlockState state : tempStates) { - for (Object possibleValue : property.possibleValues()) { - newStates.add(ImmutableBlockState.with(state, property, possibleValue)); - } - } - tempStates = newStates; - } - } - return tempStates; + return this.variantProvider.getPossibleStates(nbt); } @Override @@ -179,12 +115,12 @@ public abstract class AbstractCustomBlock implements CustomBlock { @Override public @Nullable Property getProperty(String name) { - return this.properties.get(name); + return this.variantProvider.getProperty(name); } @Override public @NotNull Collection> properties() { - return this.properties.values(); + return this.variantProvider.properties().values(); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockSounds.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockSounds.java index d393d4b9d..2997c5dfa 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockSounds.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockSounds.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.core.block; import net.momirealms.craftengine.core.sound.SoundData; -import net.momirealms.craftengine.core.util.Key; import java.util.Map; diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateHolder.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateHolder.java index 445f9c518..eaa50da56 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateHolder.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateHolder.java @@ -9,11 +9,11 @@ import java.util.*; import java.util.stream.Collectors; public class BlockStateHolder { - protected final Holder owner; + protected final Holder.Reference owner; private final Reference2ObjectArrayMap, Comparable> propertyMap; private Map, ImmutableBlockState[]> withMap; - public BlockStateHolder(Holder owner, Reference2ObjectArrayMap, Comparable> propertyMap) { + public BlockStateHolder(Holder.Reference owner, Reference2ObjectArrayMap, Comparable> propertyMap) { this.owner = owner; this.propertyMap = new Reference2ObjectArrayMap<>(propertyMap); } @@ -39,9 +39,9 @@ public class BlockStateHolder { @Override public String toString() { if (this.propertyMap.isEmpty()) { - return this.owner.value().id().toString(); + return this.owner.key().location().toString(); } - return this.owner.value().id() + "[" + getPropertiesAsString() + "]"; + return this.owner.key().location() + "[" + getPropertiesAsString() + "]"; } public String getPropertiesAsString() { diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateVariant.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateVariant.java deleted file mode 100644 index 8a27403c8..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateVariant.java +++ /dev/null @@ -1,25 +0,0 @@ -package net.momirealms.craftengine.core.block; - -public class BlockStateVariant { - private final String appearance; - private final BlockSettings settings; - private final BlockStateWrapper blockState; - - public BlockStateVariant(String appearance, BlockSettings settings, BlockStateWrapper blockState) { - this.appearance = appearance; - this.settings = settings; - this.blockState = blockState; - } - - public String appearance() { - return appearance; - } - - public BlockSettings settings() { - return settings; - } - - public BlockStateWrapper blockState() { - return blockState; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateVariantProvider.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateVariantProvider.java index 8b131563f..75c6c9080 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateVariantProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateVariantProvider.java @@ -8,6 +8,8 @@ import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Pair; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.Tag; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -23,7 +25,7 @@ public final class BlockStateVariantProvider { private final ImmutableList states; private final Holder owner; - public BlockStateVariantProvider(Holder owner, Factory, ImmutableBlockState> factory, Map> propertiesMap) { + public BlockStateVariantProvider(Holder.Reference owner, Factory, ImmutableBlockState> factory, Map> propertiesMap) { this.owner = owner; this.properties = ImmutableSortedMap.copyOf(propertiesMap); @@ -59,6 +61,27 @@ public final class BlockStateVariantProvider { this.states = ImmutableList.copyOf(list); } + public List getPossibleStates(CompoundTag nbt) { + List tempStates = new ArrayList<>(); + ImmutableBlockState defaultState = getDefaultState(); + tempStates.add(defaultState); + for (Property property : defaultState.getProperties()) { + Tag value = nbt.get(property.name()); + if (value != null) { + tempStates.replaceAll(immutableBlockState -> ImmutableBlockState.with(immutableBlockState, property, property.unpack(value))); + } else { + List newStates = new ArrayList<>(); + for (ImmutableBlockState state : tempStates) { + for (Object possibleValue : property.possibleValues()) { + newStates.add(ImmutableBlockState.with(state, property, possibleValue)); + } + } + tempStates = newStates; + } + } + return tempStates; + } + public interface Factory { S create(O owner, Reference2ObjectArrayMap, Comparable> propertyMap); } @@ -80,6 +103,11 @@ public final class BlockStateVariantProvider { return this.owner; } + @NotNull + public ImmutableSortedMap> properties() { + return this.properties; + } + @Nullable public Property getProperty(String name) { return this.properties.get(name); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java index 744d0f4c9..8f71a3707 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java @@ -40,23 +40,4 @@ public interface CustomBlock { ImmutableBlockState getStateForPlacement(BlockPlaceContext context); void setPlacedBy(BlockPlaceContext context, ImmutableBlockState state); - - interface Builder { - - Builder events(Map>> events); - - Builder appearances(Map appearances); - - Builder behavior(List> behavior); - - Builder lootTable(LootTable lootTable); - - Builder properties(Map> properties); - - Builder settings(BlockSettings settings); - - Builder variantMapper(Map variantMapper); - - @NotNull CustomBlock build(); - } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/EmptyBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/EmptyBlock.java index a6aa4e0f6..a095e3dc4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/EmptyBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/EmptyBlock.java @@ -1,18 +1,32 @@ package net.momirealms.craftengine.core.block; +import net.momirealms.craftengine.core.block.behavior.EmptyBlockBehavior; +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.Key; +import net.momirealms.craftengine.core.util.ResourceKey; -import java.util.List; import java.util.Map; public final class EmptyBlock extends AbstractCustomBlock { - public static EmptyBlock INSTANCE; - public static ImmutableBlockState STATE; + public static final EmptyBlock INSTANCE; + public static final ImmutableBlockState STATE; - public EmptyBlock(Key id, Holder.Reference holder) { - super(id, holder, Map.of(), Map.of(), Map.of(), BlockSettings.of(), Map.of(), List.of(), null); - INSTANCE = this; - STATE = defaultState(); + static { + Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.BLOCK) + .registerForHolder(ResourceKey.create(BuiltInRegistries.BLOCK.key().location(), Key.withDefaultNamespace("empty"))); + INSTANCE = new EmptyBlock(holder); + holder.bindValue(INSTANCE); + STATE = INSTANCE.defaultState(); + STATE.setSettings(BlockSettings.of()); + STATE.setBehavior(EmptyBlockBehavior.INSTANCE); + } + + private EmptyBlock(Holder.Reference holder) { + super(holder, new BlockStateVariantProvider(holder, ImmutableBlockState::new, Map.of()), Map.of(), null); + } + + public static void initialize() { } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java b/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java index 18e6460d2..8a68b9527 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java @@ -35,7 +35,7 @@ public final class ImmutableBlockState extends BlockStateHolder { private BlockEntityElementConfig[] renderers; ImmutableBlockState( - Holder owner, + Holder.Reference owner, Reference2ObjectArrayMap, Comparable> propertyMap ) { super(owner, propertyMap); @@ -129,7 +129,7 @@ public final class ImmutableBlockState extends BlockStateHolder { public CompoundTag toNbtToSave(CompoundTag properties) { CompoundTag tag = new CompoundTag(); tag.put("properties", properties); - tag.put("id", NBT.createString(this.owner.value().id().asString())); + tag.put("id", NBT.createString(this.owner.key().location().asString())); return tag; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/InactiveCustomBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/InactiveCustomBlock.java index 3c16dcae3..abd181734 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/InactiveCustomBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/InactiveCustomBlock.java @@ -2,18 +2,16 @@ package net.momirealms.craftengine.core.block; import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; import net.momirealms.craftengine.core.registry.Holder; -import net.momirealms.craftengine.core.util.Key; import net.momirealms.sparrow.nbt.CompoundTag; import java.util.HashMap; -import java.util.List; import java.util.Map; public final class InactiveCustomBlock extends AbstractCustomBlock { private final Map cachedData = new HashMap<>(); - public InactiveCustomBlock(Key id, Holder.Reference holder) { - super(id, holder, Map.of(), Map.of(), Map.of(), BlockSettings.of(), Map.of(), List.of(), null); + public InactiveCustomBlock(Holder.Reference holder) { + super(holder, new BlockStateVariantProvider(holder, ImmutableBlockState::new, Map.of()), Map.of(), null); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/parser/BlockNbtParser.java b/core/src/main/java/net/momirealms/craftengine/core/block/parser/BlockNbtParser.java index 151709a49..176b0d177 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/parser/BlockNbtParser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/parser/BlockNbtParser.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.core.block.parser; +import net.momirealms.craftengine.core.block.BlockStateVariantProvider; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.util.StringReader; @@ -7,11 +8,13 @@ import net.momirealms.sparrow.nbt.CompoundTag; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.function.Function; + public final class BlockNbtParser { private BlockNbtParser() {} @Nullable - public static CompoundTag deserialize(@NotNull CustomBlock block, @NotNull String data) { + public static CompoundTag deserialize(@NotNull Function> propertyProvider, @NotNull String data) { StringReader reader = StringReader.simple(data); CompoundTag properties = new CompoundTag(); while (reader.canRead()) { @@ -24,7 +27,7 @@ public final class BlockNbtParser { if (propertyValue.isEmpty()) { return null; } - Property property = block.getProperty(propertyName); + Property property = propertyProvider.apply(propertyName); if (property != null) { property.createOptionalTag(propertyValue).ifPresent(tag -> { properties.put(propertyName, tag); @@ -38,4 +41,14 @@ public final class BlockNbtParser { } return properties; } + + @Nullable + public static CompoundTag deserialize(@NotNull CustomBlock block, @NotNull String data) { + return deserialize(block::getProperty, data); + } + + @Nullable + public static CompoundTag deserialize(@NotNull BlockStateVariantProvider variantProvider, @NotNull String data) { + return deserialize(variantProvider::getProperty, data); + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java index 0dee19193..c887cb246 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java @@ -28,6 +28,7 @@ import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.event.EventFunctions; import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.plugin.logger.Debugger; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.util.*; import org.incendo.cloud.suggestion.Suggestion; @@ -424,17 +425,27 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } // 当模型值完成分配的时候 - customModelDataFuture.whenComplete((customModelData, throwable) -> ResourceConfigUtils.runCatching(path, node, () -> { - + customModelDataFuture.whenComplete((cmd, throwable) -> ResourceConfigUtils.runCatching(path, node, () -> { + int customModelData; if (throwable != null) { // 检测custom model data 冲突 if (throwable instanceof IdAllocator.IdConflictException exception) { - throw new LocalizedResourceConfigException("warning.config.item.custom_model_data_conflict", String.valueOf(exception.id()), exception.previousOwner()); + if (section.containsKey("model") || section.containsKey("legacy-model")) { + throw new LocalizedResourceConfigException("warning.config.item.custom_model_data.conflict", String.valueOf(exception.id()), exception.previousOwner()); + } + customModelData = exception.id(); } // custom model data 已被用尽,不太可能 else if (throwable instanceof IdAllocator.IdExhaustedException) { - throw new LocalizedResourceConfigException("warning.config.item.custom_model_data_exhausted"); + throw new LocalizedResourceConfigException("warning.config.item.custom_model_data.exhausted"); } + // 未知错误 + else { + Debugger.ITEM.warn(() -> "Unknown error while allocating custom model data.", throwable); + return; + } + } else { + customModelData = cmd; } // item model diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviors.java b/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviors.java index 21399de3d..f27f4effd 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviors.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviors.java @@ -6,13 +6,10 @@ import net.momirealms.craftengine.core.registry.BuiltInRegistries; 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.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.ResourceKey; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; import java.util.Map; public class ItemBehaviors { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/PendingConfigSection.java b/core/src/main/java/net/momirealms/craftengine/core/pack/PendingConfigSection.java new file mode 100644 index 000000000..db74096e4 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/PendingConfigSection.java @@ -0,0 +1,9 @@ +package net.momirealms.craftengine.core.pack; + +import net.momirealms.craftengine.core.util.Key; + +import java.nio.file.Path; +import java.util.Map; + +public record PendingConfigSection(Pack pack, Path path, String node, Key id, Map config) { +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java b/core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java index a4fe866f6..5977120db 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java @@ -7,6 +7,7 @@ import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import net.momirealms.craftengine.core.util.FileUtils; import net.momirealms.craftengine.core.util.GsonHelper; +import net.momirealms.craftengine.core.util.Pair; import java.io.IOException; import java.nio.file.Files; @@ -57,6 +58,9 @@ public class IdAllocator { continue; } allocateId(id, future); + } else { + // 避免其他条目分配到过时的值上 + this.occupiedIdSet.set(entry.getValue()); } } @@ -120,6 +124,18 @@ public class IdAllocator { return CompletableFuture.completedFuture(id); } + public List> getFixedIdsBetween(int minId, int maxId) { + BiMap inverse = this.forcedIdMap.inverse(); + List> result = new ArrayList<>(); + for (int i = minId; i <= maxId; i++) { + String s = inverse.get(i); + if (s != null) { + result.add(Pair.of(s, i)); + } + } + return result; + } + /** * 请求自动分配ID * @param name 名称 @@ -205,8 +221,6 @@ public class IdAllocator { * 保存缓存到文件 */ public void saveToCache() throws IOException { - FileUtils.createDirectoriesSafe(this.cacheFilePath.getParent()); - // 创建按ID排序的TreeMap Map sortedById = new TreeMap<>(); for (Map.Entry entry : this.cachedIdMap.entrySet()) { @@ -219,7 +233,14 @@ public class IdAllocator { sortedJsonObject.addProperty(entry.getValue(), entry.getKey()); } - GsonHelper.writeJsonFile(sortedJsonObject, this.cacheFilePath); + if (sortedJsonObject.isEmpty()) { + if (Files.exists(this.cacheFilePath)) { + Files.delete(this.cacheFilePath); + } + } else { + FileUtils.createDirectoriesSafe(this.cacheFilePath.getParent()); + GsonHelper.writeJsonFile(sortedJsonObject, this.cacheFilePath); + } } public static class IdConflictException extends RuntimeException { diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/Holder.java b/core/src/main/java/net/momirealms/craftengine/core/registry/Holder.java index b1e319931..c746856fa 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/Holder.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/Holder.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.registry; import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceKey; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collection; @@ -89,7 +90,7 @@ public interface Holder { } @Override - public String toString() { + public @NotNull String toString() { return "Direct{" + this.value + "}"; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java index b1a135387..ee688e805 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java @@ -23,6 +23,13 @@ public final class ResourceConfigUtils { return raw != null ? function.apply(raw) : defaultValue; } + public static String getAsString(@Nullable Object raw) { + if (raw == null) { + return null; + } + return raw.toString(); + } + public static > E getAsEnum(Object o, Class clazz, E defaultValue) { if (o == null) { return defaultValue; diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/serialization/DefaultSectionSerializer.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/serialization/DefaultSectionSerializer.java index 36d420260..1f0ee3319 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/serialization/DefaultSectionSerializer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/serialization/DefaultSectionSerializer.java @@ -76,7 +76,7 @@ public final class DefaultSectionSerializer { Holder owner = BuiltInRegistries.BLOCK.get(key).orElseGet(() -> { Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.BLOCK).registerForHolder( ResourceKey.create(BuiltInRegistries.BLOCK.key().location(), key)); - InactiveCustomBlock inactiveBlock = new InactiveCustomBlock(key, holder); + InactiveCustomBlock inactiveBlock = new InactiveCustomBlock(holder); holder.bindValue(inactiveBlock); return holder; });